[Wolfpack-svn] r6817 - in trunk: . WPGM WPGM/Components WPGM/Components/Graphics32 WPGM/Components/Graphics32/Examples WPGM/Components/Graphics32/Examples/Clx WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex WPGM/Components/Graphics32/Examples/Clx/Image32_Ex WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex WPGM/Components/Graphics32/Examples/Clx/Transform_Ex WPGM/Components/Graphics32/Examples/Vcl WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex WPGM/Components/Graphics32/Examples/Vcl/FineResampl! e_Ex WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex WPGM/Components/Graphics32/Packages WPGM/Components/VirtualTreeview WPGM/Components/VirtualTreeview/Demo WPGM/Components/VirtualTreeview/Demo/Advanced WPGM/Components/VirtualTreeview/Demo/Advanced/Res WPGM/Components/VirtualTreeview/Demo/Minimal WPGM/Components/VirtualTreeview/Demo/OLE WPGM! /Components/VirtualTreeview/Demo/OLE/Res WPGM/Components/Virtu! alTreevi
daseg at BerliOS
daseg at mail.berlios.de
Fri Jun 15 09:38:37 CEST 2007
Author: daseg
Date: 2007-06-15 09:30:36 +0200 (Fri, 15 Jun 2007)
New Revision: 6817
Added:
trunk/WPGM/
trunk/WPGM/Components/
trunk/WPGM/Components/Graphics32/
trunk/WPGM/Components/Graphics32/Changelog.txt
trunk/WPGM/Components/Graphics32/Contributors.txt
trunk/WPGM/Components/Graphics32/Examples/
trunk/WPGM/Components/Graphics32/Examples/Clx/
trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/FineResample_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/FineResample_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/GradLines_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/GradLines_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/Image32_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/Image32_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/ImgView_Layers_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/ImgView_Layers_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/NewImageUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/NewImageUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/RGBALoaderUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/RGBALoaderUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/LineStippling_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/LineStippling_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/PixelCombine_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/PixelCombine_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.cfg
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.dof
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/Polygons_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/Polygons_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/RenderText_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/RenderText_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/GR32_RotLayer.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/RotLayer_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/RotLayer_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/Rotate_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/Rotate_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/Sprites_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/Sprites_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/
trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/MainUnit.xfm
trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/Transform_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/Transform_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/
trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.drc
trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/FineResample_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/FineResample_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.drc
trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/NewImageUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/NewImageUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/RGBALoaderUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/RGBALoaderUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.cfg
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.dof
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex/G32_ProgressBar.dcr
trunk/WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex/G32_ProgressBar.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/GR32_RotLayer.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/RotLayer_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/RotLayer_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.bpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.cpp
trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/Sprites_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/Sprites_Ex.res
trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/
trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/MainUnit.dfm
trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/MainUnit.pas
trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/Transform_Ex.dpr
trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/Transform_Ex.res
trunk/WPGM/Components/Graphics32/GR32.dcu
trunk/WPGM/Components/Graphics32/GR32.inc
trunk/WPGM/Components/Graphics32/GR32.pas
trunk/WPGM/Components/Graphics32/GR32_Blend.dcu
trunk/WPGM/Components/Graphics32/GR32_Blend.pas
trunk/WPGM/Components/Graphics32/GR32_ByteMaps.dcu
trunk/WPGM/Components/Graphics32/GR32_ByteMaps.pas
trunk/WPGM/Components/Graphics32/GR32_DrawingEx.dcu
trunk/WPGM/Components/Graphics32/GR32_DrawingEx.pas
trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.dcu
trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.dfm
trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.pas
trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.xfm
trunk/WPGM/Components/Graphics32/GR32_Dsgn_Color.dcu
trunk/WPGM/Components/Graphics32/GR32_Dsgn_Color.pas
trunk/WPGM/Components/Graphics32/GR32_Filters.dcu
trunk/WPGM/Components/Graphics32/GR32_Filters.pas
trunk/WPGM/Components/Graphics32/GR32_Image.dcu
trunk/WPGM/Components/Graphics32/GR32_Image.pas
trunk/WPGM/Components/Graphics32/GR32_Layers.dcu
trunk/WPGM/Components/Graphics32/GR32_Layers.pas
trunk/WPGM/Components/Graphics32/GR32_LowLevel.dcu
trunk/WPGM/Components/Graphics32/GR32_LowLevel.pas
trunk/WPGM/Components/Graphics32/GR32_Polygons.dcu
trunk/WPGM/Components/Graphics32/GR32_Polygons.pas
trunk/WPGM/Components/Graphics32/GR32_RangeBars.dcu
trunk/WPGM/Components/Graphics32/GR32_RangeBars.pas
trunk/WPGM/Components/Graphics32/GR32_Reg.dcr
trunk/WPGM/Components/Graphics32/GR32_Reg.dcu
trunk/WPGM/Components/Graphics32/GR32_Reg.pas
trunk/WPGM/Components/Graphics32/GR32_System.dcu
trunk/WPGM/Components/Graphics32/GR32_System.pas
trunk/WPGM/Components/Graphics32/GR32_Transforms.dcu
trunk/WPGM/Components/Graphics32/GR32_Transforms.pas
trunk/WPGM/Components/Graphics32/Graphics32.chm
trunk/WPGM/Components/Graphics32/License.html
trunk/WPGM/Components/Graphics32/License.txt
trunk/WPGM/Components/Graphics32/Packages/
trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.bpk
trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.cpp
trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.res
trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.bpk
trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.cpp
trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.res
trunk/WPGM/Components/Graphics32/Packages/GR32_D4.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_D4.res
trunk/WPGM/Components/Graphics32/Packages/GR32_D5.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_D5.res
trunk/WPGM/Components/Graphics32/Packages/GR32_D6.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_D6.res
trunk/WPGM/Components/Graphics32/Packages/GR32_D6_CLX.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_D6_CLX.res
trunk/WPGM/Components/Graphics32/Packages/GR32_D7.dcu
trunk/WPGM/Components/Graphics32/Packages/GR32_D7.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_D7.res
trunk/WPGM/Components/Graphics32/Packages/GR32_D7_CLX.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_D7_CLX.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.bpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.cpp
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.bpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.cpp
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D4.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D4.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D5.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D5.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6_CLX.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6_CLX.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.dcu
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7_CLX.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7_CLX.res
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.conf
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.res
trunk/WPGM/Components/Graphics32/Packages/GR32_K.conf
trunk/WPGM/Components/Graphics32/Packages/GR32_K.dpk
trunk/WPGM/Components/Graphics32/Packages/GR32_K.res
trunk/WPGM/Components/Graphics32/Readme.txt
trunk/WPGM/Components/Graphics32/_clean.bat
trunk/WPGM/Components/PDJButton.dcu
trunk/WPGM/Components/PDJButton.pas
trunk/WPGM/Components/Pdjbutton.RES
trunk/WPGM/Components/VirtualTreeview/
trunk/WPGM/Components/VirtualTreeview/Compilers.inc
trunk/WPGM/Components/VirtualTreeview/Demo/
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Advanced.dpr
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Advanced.res
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/AlignDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/AlignDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/DrawTreeDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/DrawTreeDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Editors.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GeneralAbilitiesDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GeneralAbilitiesDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GridDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GridDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/HeaderCustomDrawDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/HeaderCustomDrawDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Main.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Main.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/NodeDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/NodeDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/PropertiesDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/PropertiesDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Arabic.uni
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Background.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Background2.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Book.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Chart.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Chinese.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Clipboard.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Cyrillic.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Earth.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Exit.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.aps
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.rc
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.res
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Eye.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Fist.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ForeignStrings.rc
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ForeignStrings.res
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Greek.uni
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Header.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Hebrew.uni
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Image list 24x24.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Image list 32x32.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Lorem ipsum.uni
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Multiline.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Omega.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Paintbrush.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Sheets.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Transcriptions.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/XP.bmp
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/SpeedDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/SpeedDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/States.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/States.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/VisibilityDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/VisibilityDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/WindowsXPStyleDemo.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/WindowsXPStyleDemo.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/
trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Main.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Main.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Minimal.dpr
trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Minimal.res
trunk/WPGM/Components/VirtualTreeview/Demo/OLE/
trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Main.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Main.pas
trunk/WPGM/Components/VirtualTreeview/Demo/OLE/OLE.dpr
trunk/WPGM/Components/VirtualTreeview/Demo/OLE/OLE.res
trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Res/
trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Res/Extra.res
trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Res/Text.rtf
trunk/WPGM/Components/VirtualTreeview/Demo/Objects/
trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemo.dpr
trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemo.res
trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemoMain.dfm
trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemoMain.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCPanel.pas
trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCTypes.pas
trunk/WPGM/Components/VirtualTreeview/Design/
trunk/WPGM/Components/VirtualTreeview/Design/CheckDark.bmp
trunk/WPGM/Components/VirtualTreeview/Design/CheckFlat.bmp
trunk/WPGM/Components/VirtualTreeview/Design/CheckLight.bmp
trunk/WPGM/Components/VirtualTreeview/Design/MoveAll.bmp
trunk/WPGM/Components/VirtualTreeview/Design/MoveAll.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveE.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveEW.bmp
trunk/WPGM/Components/VirtualTreeview/Design/MoveEW.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveN.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveNE.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveNS.bmp
trunk/WPGM/Components/VirtualTreeview/Design/MoveNS.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveNW.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveS.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveSE.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveSW.cur
trunk/WPGM/Components/VirtualTreeview/Design/MoveW.cur
trunk/WPGM/Components/VirtualTreeview/Design/TickDark.bmp
trunk/WPGM/Components/VirtualTreeview/Design/TickLight.bmp
trunk/WPGM/Components/VirtualTreeview/Design/XP.bmp
trunk/WPGM/Components/VirtualTreeview/Help/
trunk/WPGM/Components/VirtualTreeview/Help/Virtual Tree.chm
trunk/WPGM/Components/VirtualTreeview/Packages/
trunk/WPGM/Components/VirtualTreeview/Packages/StrEditD4.dfm
trunk/WPGM/Components/VirtualTreeview/Packages/StrEditD4.pas
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTrees.dcr
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4.dpk
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4.res
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4D.dpk
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4D.res
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.dcu
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.dpk
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.res
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.cfg
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dcu
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dof
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dpk
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.res
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6.dpk
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6.res
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6D.dpk
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6D.res
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.dcu
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.dpk
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.res
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.dcu
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.dpk
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.res
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesReg.dcu
trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesReg.pas
trunk/WPGM/Components/VirtualTreeview/VTHeaderPopup.dcu
trunk/WPGM/Components/VirtualTreeview/VTHeaderPopup.pas
trunk/WPGM/Components/VirtualTreeview/VirtualTrees.dcu
trunk/WPGM/Components/VirtualTreeview/VirtualTrees.pas
trunk/WPGM/Components/VirtualTreeview/VirtualTrees.res
trunk/WPGM/Components/VirtualTreeview/VirtualTrees.~pas
trunk/WPGM/ImportDefinitions/
trunk/WPGM/ImportDefinitions/ImportDefinitions.cfg
trunk/WPGM/ImportDefinitions/ImportDefinitions.dof
trunk/WPGM/ImportDefinitions/ImportDefinitions.dpr
trunk/WPGM/ImportDefinitions/ImportDefinitions.exe
trunk/WPGM/ImportDefinitions/ImportDefinitions.res
trunk/WPGM/ImportDefinitions/ImportDefinitions.~dpr
trunk/WPGM/ImportDefinitions/Main.dcu
trunk/WPGM/ImportDefinitions/Main.dfm
trunk/WPGM/ImportDefinitions/Main.pas
trunk/WPGM/ImportDefinitions/Main.~dfm
trunk/WPGM/ImportDefinitions/Main.~pas
trunk/WPGM/ImportDefinitions/Strlib.dcu
trunk/WPGM/ImportDefinitions/Strlib.pas
trunk/WPGM/ImportDefinitions/WpConfiguration.dcu
trunk/WPGM/ImportDefinitions/WpConfiguration.pas
trunk/WPGM/ImportDefinitions/WpConfiguration.~pas
trunk/WPGM/ImportDefinitions/XmlReader.dcu
trunk/WPGM/ImportDefinitions/XmlReader.pas
trunk/WPGM/ImportDefinitions/XmlReader.~pas
trunk/WPGM/Main.dcu
trunk/WPGM/Main.ddp
trunk/WPGM/Main.dfm
trunk/WPGM/Main.pas
trunk/WPGM/Main.~ddp
trunk/WPGM/Main.~dfm
trunk/WPGM/Main.~pas
trunk/WPGM/Overview.dcu
trunk/WPGM/Overview.ddp
trunk/WPGM/Overview.dfm
trunk/WPGM/Overview.pas
trunk/WPGM/Overview.~ddp
trunk/WPGM/Overview.~dfm
trunk/WPGM/Overview.~pas
trunk/WPGM/Progress.dcu
trunk/WPGM/Progress.dfm
trunk/WPGM/Progress.pas
trunk/WPGM/Progress.~dfm
trunk/WPGM/Progress.~pas
trunk/WPGM/SQLite.dcu
trunk/WPGM/SQLite.pas
trunk/WPGM/SQLiteTable.dcu
trunk/WPGM/SQLiteTable.pas
trunk/WPGM/Spawnregions.dcu
trunk/WPGM/Spawnregions.ddp
trunk/WPGM/Spawnregions.dfm
trunk/WPGM/Spawnregions.pas
trunk/WPGM/Spawnregions.~ddp
trunk/WPGM/Spawnregions.~dfm
trunk/WPGM/Spawnregions.~pas
trunk/WPGM/Strlib.dcu
trunk/WPGM/Strlib.pas
trunk/WPGM/UOCache.dcu
trunk/WPGM/UOCache.pas
trunk/WPGM/UOCache.~pas
trunk/WPGM/UOHues.dcu
trunk/WPGM/UOHues.pas
trunk/WPGM/UOHues.~pas
trunk/WPGM/UOLib/
trunk/WPGM/UOLib/UOAnim.dcu
trunk/WPGM/UOLib/UOAnim.pas
trunk/WPGM/UOLib/UOAnim.~pas
trunk/WPGM/UOLib/UOArt.dcu
trunk/WPGM/UOLib/UOArt.pas
trunk/WPGM/UOLib/UOArt.~pas
trunk/WPGM/UOLib/UOTiledata.dcu
trunk/WPGM/UOLib/UOTiledata.pas
trunk/WPGM/UOLib/UOTiledata.~pas
trunk/WPGM/UOLib/UOUtilities.dcu
trunk/WPGM/UOLib/UOUtilities.pas
trunk/WPGM/UOLib/UOUtilities.~pas
trunk/WPGM/UOMap.dcu
trunk/WPGM/UOMap.pas
trunk/WPGM/UOMap.~pas
trunk/WPGM/UORadarCol.dcu
trunk/WPGM/UORadarCol.pas
trunk/WPGM/UORadarCol.~pas
trunk/WPGM/UOStatics.dcu
trunk/WPGM/UOStatics.pas
trunk/WPGM/UOStatics.~pas
trunk/WPGM/WPGM.cfg
trunk/WPGM/WPGM.dof
trunk/WPGM/WPGM.dpr
trunk/WPGM/WPGM.exe
trunk/WPGM/WPGM.res
trunk/WPGM/WPGM.~dpr
trunk/WPGM/XMLReader.dcu
trunk/WPGM/XMLReader.pas
trunk/WPGM/arrow-down.bmp
trunk/WPGM/arrow-up.bmp
trunk/WPGM/categories.db
trunk/WPGM/categories.zip
trunk/WPGM/config.ini
trunk/WPGM/globe.gif
trunk/WPGM/import.pl
trunk/WPGM/import.py
trunk/WPGM/log.txt
trunk/WPGM/map0.bmp
trunk/WPGM/map1.bmp
trunk/WPGM/map2.bmp
trunk/WPGM/map3.bmp
trunk/WPGM/map4.bmp
trunk/WPGM/options.bmp
trunk/WPGM/search.bmp
trunk/WPGM/sqlite.dll
trunk/WPGM/sqlite.exe
trunk/WPGM/table.sql
trunk/WPGM/test.bmp
trunk/WPGM/uCenter.dcu
trunk/WPGM/uCenter.dfm
trunk/WPGM/uCenter.pas
trunk/WPGM/uCenter.~dfm
trunk/WPGM/uCenter.~pas
trunk/WPGM/uChooseHue.dcu
trunk/WPGM/uChooseHue.ddp
trunk/WPGM/uChooseHue.dfm
trunk/WPGM/uChooseHue.pas
trunk/WPGM/uChooseHue.~ddp
trunk/WPGM/uChooseHue.~dfm
trunk/WPGM/uChooseHue.~pas
trunk/WPGM/uConfig.dcu
trunk/WPGM/uConfig.pas
trunk/WPGM/uConfig.~pas
trunk/WPGM/uPatternColor.dcu
trunk/WPGM/uPatternColor.dfm
trunk/WPGM/uPatternColor.pas
trunk/WPGM/uPatternColor.~dfm
trunk/WPGM/uPatternColor.~pas
trunk/WPGM/wolfpack.ico
trunk/WPGM/wpgm-2004-08-19.zip
trunk/WPGM/wpgm-2004-08-21.zip
Log:
Added the Source of the WPGM
Note: WPGM is written in Delphi
I just added the source as i got it from Darkstorm
According to Darkstorm wpgm is also GPL
Added: trunk/WPGM/Components/Graphics32/Changelog.txt
===================================================================
--- trunk/WPGM/Components/Graphics32/Changelog.txt 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Changelog.txt 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,15 @@
+Changelog:
+
+1.6:
+
+- CLX/Kylix/QT/Linux port
+- fixed access violations in GR32_Transforms
+- new sfDraft stretchfilter with MMX and 3Dnow optimization
+- new sfCosine stretchfilter
+- new property PixelF/X, which replaces the old SetPixelF/X and also implements an interpolated getter
+- new color algebra ("blendmodes"), MMX optimized
+- feature to change antialiasing-level of polygons at runtime
+- new 4x supersampling antialias for polygons ("much faster but not a beauty")
+- Unicode support for TBitmap32.Text* and TBitmap32.Rendertext methods
+- Performance optimizations (MMX) in blending routines and Transforms
+- Many small additions
Added: trunk/WPGM/Components/Graphics32/Contributors.txt
===================================================================
--- trunk/WPGM/Components/Graphics32/Contributors.txt 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Contributors.txt 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,2 @@
+For a list of contributors please have a look into the
+Graphics32.chm file or the Graphics32 HTML documentation.
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/FineResample_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/FineResample_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/FineResample_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program FineResample_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/FineResample_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/FineResample_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,104 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Qt, Types, QForms, QControls, QGraphics, QStdCtrls, QExtCtrls,
+ {$IFDEF LINUX}Libc,{$ENDIF}
+ {$IFDEF MSWINDOWS}Windows, {$ENDIF}
+ Classes, SysUtils, GR32, GR32_Image, GR32_Transforms;
+
+type
+ TForm1 = class(TForm)
+ RadioGroup1: TRadioGroup;
+ CheckBox1: TCheckBox;
+ Image32: TImage32;
+ procedure FormCreate(Sender: TObject);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure CheckBox1Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.xfm}
+
+procedure TForm1.FormCreate(Sender: TObject);
+var
+ I, J: Integer;
+begin
+ Image32.Bitmap.SetSize(16, 16);
+ for I := 0 to 15 do
+ for J := 0 to 15 do
+ if (I + J) mod 2 = 0 then Image32.Bitmap.Pixel[I, J] := clBlack32
+ else Image32.Bitmap.Pixel[I, J] := clWhite32;
+ for I := 0 to 15 do
+ begin
+ Image32.Bitmap.Pixel[I, 9] := Gray32(I * 255 div 15);
+ Image32.Bitmap.Pixel[I, 10] := Gray32(I * 255 div 15);
+ end;
+
+ for I := 0 to 7 do
+ begin
+ Image32.Bitmap.Pixel[I * 2, 11] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2 + 1, 11] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2, 12] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2 + 1, 12] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2, 13] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2 + 1, 13] := Gray32(I * 255 div 7);
+ end;
+
+ with Image32.Bitmap do
+ begin
+ for I := 1 to 4 do
+ for J := 1 to 4 do
+ Pixels[I, J] := $FF5F5F5F;
+ for I := 2 to 3 do
+ for J := 2 to 3 do
+ Pixels[I, J] := $FFAFAFAF;
+ end;
+end;
+
+procedure TForm1.RadioGroup1Click(Sender: TObject);
+begin
+ Image32.Bitmap.StretchFilter := TStretchFilter(RadioGroup1.ItemIndex);
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ GR32_Transforms.FullEdge := CheckBox1.Checked;
+ Image32.Bitmap.Changed;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/MainUnit.xfm
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/MainUnit.xfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/FineResample_Ex/MainUnit.xfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,62 @@
+object Form1: TForm1
+ Left = 406
+ Top = 153
+ Width = 285
+ Height = 192
+ VertScrollBar.Range = 173
+ ActiveControl = CheckBox1
+ Caption = 'Form1'
+ Color = clButton
+ Font.Color = clText
+ Font.Height = 11
+ Font.Name = 'MS Sans Serif'
+ Font.Pitch = fpVariable
+ Font.Style = []
+ Font.Weight = 40
+ ParentFont = False
+ Scaled = False
+ OnCreate = FormCreate
+ PixelsPerInch = 75
+ object RadioGroup1: TRadioGroup
+ Left = 176
+ Top = 12
+ Width = 93
+ Height = 133
+ Items.Strings = (
+ 'sfNearest'
+ 'sfDraft'
+ 'sfLinear'
+ 'sfCosine'
+ 'sfSpline'
+ 'sfLanczos'
+ 'sfMitchell')
+ Anchors = [akTop, akRight]
+ Caption = 'RadioGroup1'
+ ItemIndex = 0
+ TabOrder = 1
+ OnClick = RadioGroup1Click
+ end
+ object CheckBox1: TCheckBox
+ Left = 176
+ Top = 156
+ Width = 93
+ Height = 17
+ Anchors = [akTop, akRight]
+ Caption = 'FullEdge'
+ Checked = True
+ State = cbChecked
+ TabOrder = 0
+ OnClick = CheckBox1Click
+ end
+ object Image32: TImage32
+ Left = 8
+ Top = 8
+ Width = 160
+ Height = 160
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BitmapAlign = baTopLeft
+ Scale = 1.000000000000000000
+ ScaleMode = smStretch
+ TabOrder = 2
+ end
+end
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/GradLines_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/GradLines_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/GradLines_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program GradLines_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/GradLines_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/GradLines_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,319 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mattias Andersson <mattias at centaurix.com>
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+// TPaintBox32 and DrawLineFSP example
+// Author: Alex Denissov
+// http://g32.org
+
+
+interface
+
+uses
+ SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
+ QStdCtrls, QExtCtrls, GR32, GR32_Blend, GR32_Image;
+
+type
+ TVector2f = record
+ X, Y: Single;
+ end;
+
+ TLine = class
+ public
+ Bitmap: TBitmap32;
+ P1, P2: TVector2f; // positions
+ V1, V2: TVector2f; // velocities
+ C1, C2, C3: TColor32; // colors that define gradient pattern
+ t1, t2, t3: Single;
+ MaxVelocity: Single;
+ constructor Create(ABitmap: TBitmap32);
+ procedure Advance(DeltaT: Single);
+ function GetLength: Single;
+ procedure Paint;
+ end;
+
+ TForm1 = class(TForm)
+ PaintBox: TPaintBox32;
+ Button1: TButton;
+ Button2: TButton;
+ Button3: TButton;
+ RadioGroup1: TRadioGroup;
+ RadioGroup2: TRadioGroup;
+ Label1: TLabel;
+ Panel1: TPanel;
+ procedure Button1Click(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure Button3Click(Sender: TObject);
+ procedure BitmapLayerMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure BitmapLayerMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure RadioGroup2Click(Sender: TObject);
+ protected
+ Lines: array of TLine;
+ P: TPoint; // mouse shift
+ M: Boolean; // mouse down flag
+ FadeCount: Integer;
+ Pass: Integer;
+ DrawPasses: Integer;
+ procedure AppEventsIdle(Sender: TObject; var Done: Boolean);
+ public
+ procedure AddLine;
+ procedure AddLines(N: Integer);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+uses Math;
+
+function vAdd(const A, B: TVector2f): TVector2f;
+begin
+ Result.X := A.X + B.X;
+ Result.Y := A.Y + B.Y;
+end;
+
+function vSub(const A, B: TVector2f): TVector2f;
+begin
+ Result.X := A.X - B.X;
+ Result.Y := A.Y - B.Y;
+end;
+
+function vLen(const A: TVector2f): Single;
+begin
+ Result := SqRt(SqR(A.X) + SqR(A.Y));
+end;
+
+function vDot(const A, B: TVector2f): Single;
+begin
+ Result := A.X * B.X + A.Y * B.Y;
+end;
+
+function vScale(const A: TVector2f; Factor: Single): TVector2f;
+begin
+ Result.X := A.X * Factor;
+ Result.Y := A.Y * Factor;
+end;
+
+{$R *.xfm}
+
+
+{ TLine }
+
+procedure TLine.Advance(DeltaT: Single);
+
+{}procedure AdvancePoint(var P, V: TVector2f; t: Single);
+ begin
+ { apply velocities }
+ P.X := P.X + V.X * t;
+ P.Y := P.Y + V.Y * t;
+
+ { reflect from walls }
+ if P.X < 0 then
+ begin
+ P.X := 0;
+ V.X := -V.X;
+ end;
+ if P.X >= Form1.PaintBox.Width then
+ begin
+ P.X := Form1.PaintBox.Width - 1;
+ V.X := - V.X;
+ end;
+ if P.Y < 0 then
+ begin
+ P.Y := 0;
+ V.Y := -V.Y;
+ end;
+ if P.Y >= Form1.PaintBox.Height then
+ begin
+ P.Y := Form1.PaintBox.Height - 1;
+ V.Y := - V.Y
+ end;
+
+ { change velocity a little bit }
+ V.X := V.X + t * (Random - 0.5) / 4;
+ V.Y := V.Y + t * (Random - 0.5) / 4;
+
+ { limit velocity }
+ if vLen(V1) > MaxVelocity then V1 := vScale(V1, 1 / vLen(V1));
+ if vLen(V2) > MaxVelocity then V2 := vScale(V2, 1 / vLen(V2));
+ end;
+begin
+ AdvancePoint(P1, V1, DeltaT);
+ AdvancePoint(P2, V2, DeltaT);
+
+ C1 := HSLtoRGB(t1, Sin(t1 / 1.8) * 0.4 + 0.6, 0.5);
+ C1 := SetAlpha(C1, Round(Sin(t1) * 25 + 50));
+ t1 := t1 + Random / 300;
+
+ C2 := HSLtoRGB(t2, Sin(t2 / 1.8) * 0.4 + 0.6, 0.5);
+ C2 := SetAlpha(C2, Round(Sin(t2) * 25 + 50));
+ t2 := t2 + Random / 400;
+
+ C3 := HSLtoRGB(t3, Sin(t3 / 1.8) * 0.4 + 0.6, 0.5);
+ C3 := SetAlpha(C3, Round(Sin(t3) * 25 + 50));
+ t3 := t3 + Random / 400;
+end;
+
+constructor TLine.Create(ABitmap: TBitmap32);
+begin
+ Bitmap := ABitmap;
+ MaxVelocity := 1;
+end;
+
+function TLine.GetLength: Single;
+begin
+ Result := vLen(vSub(P1, P2));
+end;
+
+procedure TLine.Paint;
+var
+ L: Single;
+begin
+ // this shows how to draw a gradient line
+ L := GetLength;
+ if L < 1 then Exit;
+ Bitmap.SetStipple([C1, C2, C3]);
+ Bitmap.StippleStep := 2 / L; {2 = 3 - 1 = Number of colors in a pattern - 1}
+ Bitmap.StippleCounter := 0;
+ Bitmap.LineFSP(P1.X, P1.Y, P2.X, P2.Y);
+end;
+
+{ TForm1 }
+
+procedure TForm1.AddLine;
+var
+ L: TLine;
+begin
+ SetLength(Lines, Length(Lines) + 1);
+ L := TLine.Create(PaintBox.Buffer);
+ Lines[High(Lines)] := L;
+ L.t1 := Random * 3;
+ L.t2 := Random * 3;
+ L.t3 := Random * 3;
+ L.P1.X := Random(PaintBox.Buffer.Width - 1);
+ L.P2.X := Random(PaintBox.Buffer.Width - 1);
+ L.P1.Y := Random(PaintBox.Buffer.Height - 1);
+ L.P2.Y := Random(PaintBox.Buffer.Height - 1);
+ Panel1.Caption := IntToStr(Length(Lines));
+end;
+
+procedure TForm1.AddLines(N: Integer);
+var
+ i: Integer;
+begin
+ for i := 0 to N - 1 do AddLine;
+end;
+
+procedure TForm1.AppEventsIdle(Sender: TObject; var Done: Boolean);
+var
+ I, J: Integer;
+ P: PColor32;
+begin
+ for J := 0 to DrawPasses - 1 do
+ for I := 0 to High(Lines) do
+ begin
+ Lines[I].Advance(1);
+ Lines[I].Paint;
+ end;
+
+ if FadeCount > 0 then
+ begin
+ if Pass = 0 then with PaintBox.Buffer do
+ begin
+ P := @Bits[0];
+ for I := 0 to Width * Height - 1 do
+ begin
+ BlendMem($10000000, P^);
+ Inc(P);
+ end;
+ EMMS;
+ end;
+ Dec(Pass);
+ if (Pass < 0) or (Pass > FadeCount) then Pass := FadeCount;
+ end;
+ PaintBox.Invalidate;
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ FadeCount := 7;
+ DrawPasses := 2;
+ Application.OnIdle := AppEventsIdle;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+begin
+ AddLine;
+end;
+
+procedure TForm1.Button2Click(Sender: TObject);
+begin
+ AddLines(10);
+end;
+
+procedure TForm1.Button3Click(Sender: TObject);
+var
+ I: Integer;
+begin
+ for I := High(Lines) downto 0 do Lines[I].Free;
+ Lines := nil;
+ PaintBox.Buffer.Clear;
+ Panel1.Caption := '0';
+end;
+
+procedure TForm1.BitmapLayerMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ // X and Y here are relative to layer origin
+ P := Point(X, Y);
+ M := True;
+end;
+
+procedure TForm1.BitmapLayerMouseUp(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ M := False;
+end;
+
+procedure TForm1.RadioGroup1Click(Sender: TObject);
+const
+ FC: array [0..2] of Integer = (0, 7, 1);
+begin
+ FadeCount := FC[RadioGroup1.ItemIndex];
+end;
+
+procedure TForm1.RadioGroup2Click(Sender: TObject);
+begin
+ DrawPasses := (RadioGroup2.ItemIndex + 1) * 3 - 2;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/GradLines_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/Image32_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/Image32_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/Image32_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Image32_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/Image32_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/Image32_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,89 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
+ QStdCtrls, QExtCtrls, GR32, GR32_Image, GR32_RangeBars;
+
+type
+ TForm1 = class(TForm)
+ Panel1: TPanel;
+ Panel2: TPanel;
+ Image: TImage32;
+ rgScaleMode: TRadioGroup;
+ rgStretchFilter: TRadioGroup;
+ rgBitmapAlign: TRadioGroup;
+ sbScale: TGaugeBar;
+ Label1: TLabel;
+ procedure rgBitmapAlignClick(Sender: TObject);
+ procedure sbScaleChange(Sender: TObject);
+ procedure rgScaleModeClick(Sender: TObject);
+ procedure rgStretchFilterClick(Sender: TObject);
+ public
+ Time: Single;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.xfm}
+
+procedure TForm1.rgBitmapAlignClick(Sender: TObject);
+const
+ BA_CONSTS: array [0..2] of TBitmapAlign = (baTopLeft, baCenter, baTile);
+begin
+ Image.BitmapAlign := BA_CONSTS[rgBitmapAlign.ItemIndex];
+end;
+
+procedure TForm1.sbScaleChange(Sender: TObject);
+begin
+ sbScale.Update;
+ Image.Scale := sbScale.Position / 100;
+end;
+
+procedure TForm1.rgScaleModeClick(Sender: TObject);
+const
+ SM_CONSTS: array [0..3] of TScaleMode = (smNormal, smStretch, smScale, smResize);
+begin
+ Image.ScaleMode := SM_CONSTS[rgScaleMode.ItemIndex];
+ sbScale.Enabled := rgScaleMode.ItemIndex = 2;
+ Label1.Enabled := rgScaleMode.ItemIndex = 2;
+end;
+
+procedure TForm1.rgStretchFilterClick(Sender: TObject);
+const
+ SF_CONSTS: array [0..5] of TStretchFilter =
+ (sfNearest, sfLinear, sfCosine, sfSpline, sfLanczos, sfMitchell);
+begin
+ Image.Bitmap.StretchFilter := SF_CONSTS[rgStretchFilter.ItemIndex];
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Image32_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/ImgView_Layers_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/ImgView_Layers_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/ImgView_Layers_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,19 @@
+program ImgView_Layers_Ex;
+
+{%File '..\..\GR32.inc'}
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {MainForm},
+ NewImageUnit in 'NewImageUnit.pas' {NewImageForm},
+ RGBALoaderUnit in 'RGBALoaderUnit.pas' {RGBALoaderForm};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TMainForm, MainForm);
+ Application.CreateForm(TNewImageForm, NewImageForm);
+ Application.CreateForm(TRGBALoaderForm, RGBALoaderForm);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/ImgView_Layers_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/ImgView_Layers_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,899 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Andre Beckedorf <Andre at metaException.de>
+ * Mattias Andersson <mattias at centaurix.com>
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Types, SysUtils, Classes, QForms, QDialogs, QMenus, QTypes, QStdCtrls,
+ QControls, QExtCtrls, QGraphics, GR32, GR32_Image, GR32_Layers,
+ GR32_RangeBars, GR32_Filters, GR32_Transforms;
+
+type
+ TMainForm = class(TForm)
+ ImgView: TImgView32;
+ SidePanel: TPanel;
+ MainMenu: TMainMenu;
+ mnFileNew: TMenuItem;
+ mnFile: TMenuItem;
+ mnFileOpen: TMenuItem;
+ mnLayers: TMenuItem;
+ mnNewBitmapLayer: TMenuItem;
+ mnDelete: TMenuItem;
+ pnlImage: TPanel;
+ ScaleCombo: TComboBox;
+ Label1: TLabel;
+ Panel2: TPanel;
+ ImageInterpolate: TCheckBox;
+ pnlBitmapLayer: TPanel;
+ Panel3: TPanel;
+ Label2: TLabel;
+ LayerOpacity: TGaugeBar;
+ LayerInterpolate: TCheckBox;
+ mnNewBitmapRGBA: TMenuItem;
+ LayerRescale: TButton;
+ LayerResetScale: TButton;
+ Cropped: TCheckBox;
+ mnNewCustomLayer: TMenuItem;
+ mnMagnifier: TMenuItem;
+ PnlMagn: TPanel;
+ Label3: TLabel;
+ Panel4: TPanel;
+ MagnOpacity: TGaugeBar;
+ SaveDialog1: TSaveDialog;
+ Label4: TLabel;
+ MagnMagnification: TGaugeBar;
+ Label5: TLabel;
+ MagnRotation: TGaugeBar;
+ MagnInterpolate: TCheckBox;
+ mnSimpleDrawing: TMenuItem;
+ mnArrange: TMenuItem;
+ mnBringFront: TMenuItem;
+ mnSendBack: TMenuItem;
+ N1: TMenuItem;
+ mnLevelUp: TMenuItem;
+ mnLevelDown: TMenuItem;
+ N2: TMenuItem;
+ mnScaled: TMenuItem;
+ N4: TMenuItem;
+ mnFlatten: TMenuItem;
+ N3: TMenuItem;
+ mnFlipHorz: TMenuItem;
+ mnFlipVert: TMenuItem;
+ N5: TMenuItem;
+ mnRotate90: TMenuItem;
+ mnRotate180: TMenuItem;
+ mnRotate270: TMenuItem;
+ N6: TMenuItem;
+ mnPrint: TMenuItem;
+ OpenPictureDialog1: TOpenDialog;
+ procedure mnFileNewClick(Sender: TObject);
+ procedure mnFileOpenClick(Sender: TObject);
+ procedure mnNewBitmapLayerClick(Sender: TObject);
+ procedure mnDeleteClick(Sender: TObject);
+ procedure mnLayersClick(Sender: TObject);
+ procedure mnNewBitmapRGBAClick(Sender: TObject);
+ procedure mnMagnifierClick(Sender: TObject);
+ procedure mnSimpleDrawingClick(Sender: TObject);
+ procedure mnArrangeClick(Sender: TObject);
+ procedure mnScaledClick(Sender: TObject);
+ procedure mnReorder(Sender: TObject);
+ procedure ScaleComboChange(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure ImageInterpolateClick(Sender: TObject);
+ procedure LayerOpacityChange(Sender: TObject);
+ procedure LayerInterpolateClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure LayerRescaleClick(Sender: TObject);
+ procedure LayerResetScaleClick(Sender: TObject);
+ procedure CroppedClick(Sender: TObject);
+ procedure MagnChange(Sender: TObject);
+ procedure ImgViewMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure ImgViewPaintStage(Sender: TObject; Buffer: TBitmap32;
+ StageNum: Cardinal);
+ procedure mnFlattenClick(Sender: TObject);
+ procedure ImgViewMouseWheelUp(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+ procedure ImgViewMouseWheelDown(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+ procedure mnFlipHorzClick(Sender: TObject);
+ procedure mnFlipVertClick(Sender: TObject);
+ procedure mnRotate90Click(Sender: TObject);
+ procedure mnRotate180Click(Sender: TObject);
+ procedure mnRotate270Click(Sender: TObject);
+ procedure mnFileClick(Sender: TObject);
+ procedure mnPrintClick(Sender: TObject);
+ private
+ FSelection: TPositionedLayer;
+ procedure SetSelection(Value: TPositionedLayer);
+ protected
+ RBLayer: TRubberbandLayer;
+ function CreatePositionedLayer: TPositionedLayer;
+ procedure LayerMouseDown(Sender: TObject; Buttons: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure RBResizing(Sender: TObject; const OldLocation: TFloatRect; var NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState);
+ procedure PaintMagnifierHandler(Sender: TObject; Buffer: TBitmap32);
+ procedure PaintSimpleDrawingHandler(Sender: TObject; Buffer: TBitmap32);
+ public
+ procedure CreateNewImage(AWidth, AHeight: Integer; FillColor: TColor32);
+ procedure OpenImage(const FileName: string);
+ property Selection: TPositionedLayer read FSelection write SetSelection;
+ end;
+
+var
+ MainForm: TMainForm;
+
+implementation
+
+uses NewImageUnit, RGBALoaderUnit, Math, GR32_LowLevel, QPrinters;
+
+{$R *.xfm}
+
+{ TForm1 }
+
+procedure TMainForm.CreateNewImage(AWidth, AHeight: Integer; FillColor: TColor32);
+begin
+ with ImgView do
+ begin
+ Selection := nil;
+ RBLayer := nil;
+ Layers.Clear;
+ Scale := 1;
+ Bitmap.SetSize(AWidth, AHeight);
+ Bitmap.Clear(FillColor);
+ pnlImage.Visible := not Bitmap.Empty;
+ end;
+end;
+
+function TMainForm.CreatePositionedLayer: TPositionedLayer;
+var
+ P: TPoint;
+begin
+ // get coordinates of the center of viewport
+ with ImgView.GetViewportRect do
+ P := ImgView.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));
+
+ Result := TPositionedLayer.Create(ImgView.Layers);
+ Result.Location := FloatRect(P.X - 32, P.Y - 32, P.X + 32, P.Y + 32);
+ Result.Scaled := True;
+ Result.MouseEvents := True;
+ Result.OnMouseDown := LayerMouseDown;
+end;
+
+procedure TMainForm.CroppedClick(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Cropped := Cropped.Checked;
+end;
+
+procedure TMainForm.FormCreate(Sender: TObject);
+begin
+ // by default, PST_CLEAR_BACKGND is executed at this stage,
+ // which, in turn, calls ExecClearBackgnd method of ImgView.
+ // Here I substitute PST_CLEAR_BACKGND with PST_CUSTOM, so force ImgView
+ // to call the OnPaintStage event instead of performing default action.
+ with ImgView.PaintStages[0]^ do
+ begin
+ if Stage = PST_CLEAR_BACKGND then Stage := PST_CUSTOM;
+ end;
+
+ OpenPictureDialog1.Filter := GraphicFilter(TGraphic, True);
+end;
+
+procedure TMainForm.FormDestroy(Sender: TObject);
+begin
+ Selection := nil;
+ RBLayer := nil;
+end;
+
+procedure TMainForm.ImageInterpolateClick(Sender: TObject);
+const
+ STRETCH_FILTER: array [Boolean] of TStretchFilter = (sfNearest, sfLinear);
+begin
+ ImgView.Bitmap.StretchFilter := STRETCH_FILTER[ImageInterpolate.Checked];
+end;
+
+procedure TMainForm.LayerInterpolateClick(Sender: TObject);
+const
+ STRETCH_FILTER: array [Boolean] of TStretchFilter = (sfNearest, sfLinear);
+begin
+ if Selection is TBitmapLayer then
+ begin
+ TBitmapLayer(Selection).Bitmap.StretchFilter := STRETCH_FILTER[LayerInterpolate.Checked];
+ end;
+end;
+
+procedure TMainForm.LayerMouseDown(Sender: TObject; Buttons: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+begin
+ if Sender <> nil then Selection := TPositionedLayer(Sender);
+end;
+
+procedure TMainForm.LayerOpacityChange(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Bitmap.MasterAlpha := LayerOpacity.Position;
+end;
+
+procedure TMainForm.LayerRescaleClick(Sender: TObject);
+var
+ T: TBitmap32;
+begin
+ // resize the layer's bitmap to the size of the layer
+ if Selection is TBitmapLayer then
+ with TBitmapLayer(Selection) do
+ begin
+ T := TBitmap32.Create;
+ T.Assign(Bitmap);
+ with MakeRect(Location) do
+ Bitmap.SetSize(Right - Left, Bottom - Top);
+ T.StretchFilter := sfLinear;
+ T.DrawMode := dmOpaque;
+ T.DrawTo(Bitmap, Rect(0, 0, Bitmap.Width, Bitmap.Height));
+ T.Free;
+ LayerResetScaleClick(Self);
+ end;
+end;
+
+procedure TMainForm.LayerResetScaleClick(Sender: TObject);
+var
+ L: TFloatRect;
+begin
+ // resize the layer to the size of its bitmap
+ if Selection is TBitmapLayer then
+ with RBLayer, TBitmapLayer(Selection).Bitmap do
+ begin
+ L := Location;
+ L.Right := L.Left + Width;
+ L.Bottom := L.Top + Height;
+ Location := L;
+ Changed;
+ end;
+end;
+
+procedure TMainForm.MagnChange(Sender: TObject);
+begin
+ ImgView.Invalidate;
+end;
+
+procedure TMainForm.mnArrangeClick(Sender: TObject);
+var
+ B: Boolean;
+begin
+ B := Selection <> nil;
+ mnBringFront.Enabled := B and (Selection.Index < ImgView.Layers.Count - 2);
+ mnSendBack.Enabled := B and (Selection.Index > 0);
+ mnLevelUp.Enabled := B and (Selection.Index < ImgView.Layers.Count - 2);
+ mnLevelDown.Enabled := B and (Selection.Index > 0);
+ mnScaled.Enabled := B;
+ mnScaled.Checked := B and Selection.Scaled;
+ mnDelete.Enabled := B;
+ B := B and (Selection is TBitmapLayer);
+ mnFlipHorz.Enabled := B;
+ mnFlipVert.Enabled := B;
+ mnRotate90.Enabled := B;
+ mnRotate180.Enabled := B;
+ mnRotate270.Enabled := B;
+end;
+
+procedure TMainForm.mnDeleteClick(Sender: TObject);
+var
+ ALayer: TPositionedLayer;
+begin
+ if Selection <> nil then
+ begin
+ ALayer := Selection;
+ Selection := nil;
+ ALayer.Free;
+ end;
+end;
+
+procedure TMainForm.mnFileNewClick(Sender: TObject);
+begin
+ with NewImageForm do
+ begin
+ ShowModal;
+ if ModalResult = mrOK then
+ CreateNewImage(StrToInt(ImageWidth.Text), StrToInt(ImageHeight.Text), Color32(Panel1.Color));
+ end;
+end;
+
+procedure TMainForm.mnFileOpenClick(Sender: TObject);
+begin
+ with OpenPictureDialog1 do
+ if Execute then OpenImage(FileName);
+end;
+
+procedure TMainForm.mnLayersClick(Sender: TObject);
+var
+ B: Boolean;
+begin
+ B := not ImgView.Bitmap.Empty;
+ mnNewBitmapLayer.Enabled := B;
+ mnNewBitmapRGBA.Enabled := B;
+ mnNewCustomLayer.Enabled := B;
+ mnFlatten.Enabled := B and (ImgView.Layers.Count > 0);
+end;
+
+procedure TMainForm.mnMagnifierClick(Sender: TObject);
+var
+ L: TPositionedLayer;
+begin
+ L := CreatePositionedLayer;
+ L.OnPaint := PaintMagnifierHandler;
+ L.Tag := 2;
+ Selection := L;
+end;
+
+procedure TMainForm.mnNewBitmapLayerClick(Sender: TObject);
+var
+ B: TBitmapLayer;
+ P: TPoint;
+ W, H: Single;
+begin
+ with OpenPictureDialog1 do
+ if Execute then
+ begin
+ B := TBitmapLayer.Create(ImgView.Layers);
+ with B do
+ try
+ Bitmap.LoadFromFile(FileName);
+ Bitmap.DrawMode := dmBlend;
+
+ with ImgView.GetViewportRect do
+ P := ImgView.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));
+
+ W := Bitmap.Width / 2;
+ H := Bitmap.Height / 2;
+
+ with ImgView.Bitmap do
+ Location := FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);
+
+ Scaled := True;
+ OnMouseDown := LayerMouseDown;
+ except
+ Free;
+ raise;
+ end;
+ Selection := B;
+ end;
+end;
+
+procedure TMainForm.mnNewBitmapRGBAClick(Sender: TObject);
+var
+ B: TBitmapLayer;
+ P: TPoint;
+ Tmp: TBitmap32;
+ W, H: Single;
+begin
+ with RGBALoaderForm do
+ begin
+ ImgRGB.Bitmap.Delete;
+ ImgRGB.Scale := 1;
+ ImgAlpha.Bitmap.Delete;
+ ImgAlpha.Scale := 1;
+ ShowModal;
+ if (ModalResult = mrOK) and not ImgRGB.Bitmap.Empty then
+ begin
+ B := TBitmapLayer.Create(ImgView.Layers);
+ B.Bitmap := ImgRGB.Bitmap;
+ B.Bitmap.DrawMode := dmBlend;
+
+ if not ImgAlpha.Bitmap.Empty then
+ begin
+ Tmp := TBitmap32.Create;
+ try
+ Tmp.SetSize(B.Bitmap.Width, B.Bitmap.Height);
+ ImgAlpha.Bitmap.DrawTo(Tmp, Rect(0, 0, Tmp.Width, Tmp.Height));
+
+ // combine Alpha into already loaded RGB colors
+ IntensityToAlpha(B.Bitmap, Tmp);
+ finally
+ Tmp.Free;
+ end;
+ end;
+
+ with ImgView.GetViewportRect do
+ P := ImgView.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));
+
+ with B do
+ begin
+ W := Bitmap.Width / 2;
+ H := Bitmap.Height / 2;
+
+ with ImgView.Bitmap do
+ Location := FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);
+
+ Scaled := True;
+ OnMouseDown := LayerMouseDown;
+ end;
+ Selection := B;
+ end;
+ end;
+end;
+
+procedure TMainForm.mnReorder(Sender: TObject);
+begin
+ // note that the top-most layer is occupied with the rubber-banding layer
+ if Selection <> nil then
+ case TMenuItem(Sender).Tag of
+ 1: // Bring to front, do not use BringToFront here, see note above
+ Selection.Index := ImgView.Layers.Count - 2;
+ 2: Selection.SendToBack;
+ 3: Selection.Index := Selection.Index + 1; // up one level
+ 4: Selection.Index := Selection.Index - 1; // down one level
+ end;
+end;
+
+procedure TMainForm.mnSimpleDrawingClick(Sender: TObject);
+var
+ L: TPositionedLayer;
+begin
+ L := CreatePositionedLayer;
+ L.OnPaint := PaintSimpleDrawingHandler;
+ L.Tag := 1;
+ Selection := L;
+end;
+
+procedure TMainForm.OpenImage(const FileName: string);
+begin
+ with ImgView do
+ try
+ Selection := nil;
+ RBLayer := nil;
+ Layers.Clear;
+ Scale := 1;
+ Bitmap.LoadFromFile(FileName);
+ finally
+ pnlImage.Visible := not Bitmap.Empty;
+ end;
+end;
+
+procedure TMainForm.PaintMagnifierHandler(Sender: TObject; Buffer: TBitmap32);
+var
+ Magnification, Rotation: Single;
+ SrcRect, DstRect: TFloatRect;
+ R: TRect;
+ T: TAffineTransformation;
+ B: TBitmap32;
+ W2, H2: Single;
+ I: Integer;
+begin
+ if Sender is TPositionedLayer then
+ with TPositionedLayer(Sender) do
+ begin
+ Magnification := Power(10, (MagnMagnification.Position / 50));
+ Rotation := -MagnRotation.Position;
+
+ DstRect := GetAdjustedLocation;
+ R := MakeRect(DstRect);
+ B := TBitmap32.Create;
+ try
+ with R do
+ begin
+ B.SetSize(Right - Left, Bottom - Top);
+ W2 := (Right - Left) / 2;
+ H2 := (Bottom - Top) / 2;
+ end;
+
+ SrcRect := DstRect;
+ with SrcRect do
+ begin
+ Left := Left - H2;
+ Right := Right + H2;
+ Top := Top - W2;
+ Bottom := Bottom + W2;
+ end;
+
+ T := TAffineTransformation.Create;
+ try
+ T.SrcRect := SrcRect;
+ T.Translate(-R.Left, -R.Top);
+
+ T.Translate(-W2, -H2);
+ T.Scale(Magnification, Magnification);
+ T.Rotate(0, 0, Rotation);
+ T.Translate(W2, H2);
+
+ if MagnInterpolate.Checked then
+ begin
+ Buffer.BeginUpdate;
+ Buffer.StretchFilter := sfLinear;
+ Transform(B, Buffer, T);
+ Buffer.StretchFilter := sfNearest;
+ Buffer.EndUpdate;
+ end
+ else
+ Transform(B, Buffer, T);
+
+ B.ResetAlpha;
+ B.DrawMode := dmBlend;
+ B.MasterAlpha := MagnOpacity.Position;
+ B.DrawTo(Buffer, R);
+
+ // draw frame
+ for I := 0 to 4 do
+ begin
+ with R do Buffer.RaiseRectTS(Left, Top, Right, Bottom, 35 - I * 8);
+ InflateRect(R, -1, -1);
+ end;
+ finally
+ T.Free;
+ end;
+ finally
+ B.Free;
+ end;
+ end;
+end;
+
+procedure TMainForm.PaintSimpleDrawingHandler(Sender: TObject; Buffer: TBitmap32);
+var
+ Cx, Cy: Single;
+ W2, H2: Single;
+ I: Integer;
+begin
+ if Sender is TPositionedLayer then
+ with TPositionedLayer(Sender).GetAdjustedLocation do
+ begin
+ W2 := (Right - Left) / 2;
+ H2 := (Bottom - Top) / 2;
+ Cx := Left + W2;
+ Cy := Top + H2;
+ Buffer.PenColor := clRed32;
+ Buffer.MoveToF(Cx,Cy);
+ for I := 0 to 240 do
+ begin
+ Buffer.LineToFS(Cx + W2 * I / 200 * Cos(I / 8), Cy + H2 * I / 200 * Sin(I / 8));
+ end;
+ end;
+end;
+
+procedure TMainForm.ScaleComboChange(Sender: TObject);
+var
+ S: string;
+ I: Integer;
+begin
+ S := ScaleCombo.Text;
+ S := StringReplace(S, '%', '', [rfReplaceAll]);
+ S := StringReplace(S, ' ', '', [rfReplaceAll]);
+ if S = '' then Exit;
+ I := StrToIntDef(S, -1);
+ if (I < 1) or (I > 2000) then I := Round(ImgView.Scale * 100)
+ else ImgView.Scale := I / 100;
+ ScaleCombo.Text := IntToStr(I) + '%';
+ ScaleCombo.SelStart := Length(ScaleCombo.Text) - 1;
+end;
+
+procedure TMainForm.SetSelection(Value: TPositionedLayer);
+begin
+ if Value <> FSelection then
+ begin
+ if RBLayer <> nil then
+ begin
+ RBLayer.ChildLayer := nil;
+ RBLayer.LayerOptions := LOB_NO_UPDATE;
+ pnlBitmapLayer.Visible := False;
+ pnlMagn.Visible := False;
+ ImgView.Invalidate;
+ end;
+
+ FSelection := Value;
+
+ if Value <> nil then
+ begin
+ if RBLayer = nil then
+ begin
+ RBLayer := TRubberBandLayer.Create(ImgView.Layers);
+ RBLayer.MinHeight := 1;
+ RBLayer.MinWidth := 1;
+ end
+ else RBLayer.BringToFront;
+ RBLayer.ChildLayer := Value;
+ RBLayer.LayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS or LOB_NO_UPDATE;
+ RBLayer.OnResizing := RBResizing;
+
+ if Value is TBitmapLayer then
+ with TBitmapLayer(Value) do
+ begin
+ pnlBitmapLayer.Visible := True;
+ LayerOpacity.Position := Bitmap.MasterAlpha;
+ LayerInterpolate.Checked := Bitmap.StretchFilter = sfLinear;
+ end
+ else if Value.Tag = 2 then
+ begin
+ // tag = 2 for magnifiers
+ pnlMagn.Visible := True;
+ end;
+ end;
+ end;
+end;
+
+procedure TMainForm.mnScaledClick(Sender: TObject);
+begin
+ if Selection <> nil then Selection.Scaled := not Selection.Scaled;
+ RBLayer.Scaled := Selection.Scaled;
+end;
+
+procedure TMainForm.ImgViewMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ if Layer = nil then
+ begin
+ Selection := nil;
+// ReleaseCapture;
+ end;
+end;
+
+procedure TMainForm.ImgViewPaintStage(Sender: TObject; Buffer: TBitmap32;
+ StageNum: Cardinal);
+const
+ Colors: array [0..1] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
+var
+ W, I, J, Parity: Integer;
+ Line1, Line2: TArrayOfColor32; // a buffer for a couple of scanlines
+begin
+ with ImgView.Buffer do
+ begin
+ W := Width;
+ SetLength(Line1, W);
+ SetLength(Line2, W);
+ for I := 0 to W - 1 do
+ begin
+ Parity := I shr 3 and $1;
+ Line1[I] := Colors[Parity];
+ Line2[I] := Colors[1 - Parity];
+ end;
+ for J := 0 to Height - 1 do
+ begin
+ Parity := J shr 3 and $1;
+ if Boolean(Parity) then MoveLongword(Line1[0], ScanLine[J]^, W)
+ else MoveLongword(Line2[0], ScanLine[J]^, W);
+ end;
+ end;
+end;
+
+procedure TMainForm.RBResizing(Sender: TObject;
+ const OldLocation: TFloatRect; var NewLocation: TFloatRect;
+ DragState: TDragState; Shift: TShiftState);
+var
+ w, h, cx, cy: Single;
+ nw, nh: Single;
+
+begin
+ if DragState = dsMove then Exit; // we are interested only in scale operations
+ if Shift = [] then Exit; // special processing is not required
+
+ if ssCtrl in Shift then
+ begin
+ { make changes symmetrical }
+
+ with OldLocation do
+ begin
+ cx := (Left + Right) / 2;
+ cy := (Top + Bottom) / 2;
+ w := Right - Left;
+ h := Bottom - Top;
+ end;
+
+ with NewLocation do
+ begin
+ nw := w / 2;
+ nh := h / 2;
+ case DragState of
+ dsSizeL: nw := cx - Left;
+ dsSizeT: nh := cy - Top;
+ dsSizeR: nw := Right - cx;
+ dsSizeB: nh := Bottom - cy;
+ dsSizeTL: begin nw := cx - Left; nh := cy - Top; end;
+ dsSizeTR: begin nw := Right - cx; nh := cy - Top; end;
+ dsSizeBL: begin nw := cx - Left; nh := Bottom - cy; end;
+ dsSizeBR: begin nw := Right - cx; nh := Bottom - cy; end;
+ end;
+ if nw < 2 then nw := 2;
+ if nh < 2 then nh := 2;
+
+ Left := cx - nw;
+ Right := cx + nw;
+ Top := cy - nh;
+ Bottom := cy + nh;
+ end;
+ end;
+end;
+
+procedure TMainForm.mnFlattenClick(Sender: TObject);
+var
+ B: TBitmap32;
+ W, H: Integer;
+begin
+ { deselect everything }
+ Selection := nil;
+ W := ImgView.Bitmap.Width;
+ H := ImgView.Bitmap.Height;
+
+ { Create a new bitmap to store a flattened image }
+ B := TBitmap32.Create;
+ try
+ B.SetSize(W, H);
+ ImgView.PaintTo(B, Rect(0, 0, W, H));
+
+ { destroy all the layers of the original image... }
+ ImgView.Layers.Clear;
+ RBLayer := nil; // note that RBLayer reference is destroyed here as well.
+ // The rubber band will be recreated during the next
+ // SetSelection call. Alternatively, you can delete
+ // all the layers except the rubber band.
+
+ { ...and overwrite it with the flattened one }
+ ImgView.Bitmap := B;
+ finally
+ B.Free;
+ end;
+end;
+
+procedure TMainForm.mnPrintClick(Sender: TObject);
+var
+ B: TBitmap32;
+ W, H: Integer;
+ R: TRect;
+
+ function GetCenteredRectToFit(const src, dst: TRect): TRect;
+ var
+ srcWidth, srcHeight, dstWidth, dstHeight, ScaledSide: Integer;
+ begin
+ with src do begin
+ srcWidth := Right - Left;
+ srcHeight := Bottom - Top;
+ end;
+ with dst do begin
+ dstWidth := Right - Left;
+ dstHeight := Bottom - Top;
+ end;
+ if (srcWidth = 0) or (srcHeight = 0) then exit;
+ if srcWidth / srcHeight > dstWidth / dstHeight then begin
+ ScaledSide := Round(dstWidth * srcHeight / srcWidth);
+ with Result do begin
+ Left := dst.Left;
+ Top := dst.Top + (dstHeight - ScaledSide) div 2;
+ Right := dst.Right;
+ Bottom := Top + ScaledSide;
+ end;
+ end else begin
+ ScaledSide := Round(dstHeight * srcWidth / srcHeight);
+ with Result do begin
+ Left := dst.Left + (dstWidth - ScaledSide) div 2;
+ Top := dst.Top;
+ Right := Left + ScaledSide;
+ Bottom := dst.Bottom;
+ end;
+ end;
+ end;
+
+begin
+ { deselect everything }
+ Selection := nil;
+ W := ImgView.Bitmap.Width;
+ H := ImgView.Bitmap.Height;
+
+ { Create a new bitmap to store a flattened image }
+ B := TBitmap32.Create;
+ Screen.Cursor := crHourGlass;
+ try
+ B.SetSize(W, H);
+ ImgView.PaintTo(B, Rect(0, 0, W, H));
+ Printer.BeginDoc;
+ Printer.Title := 'Graphics32 Demo';
+ B.StretchFilter := sfLinear;
+ R := GetCenteredRectToFit(Rect(0, 0, W, H), Rect(0, 0, Printer.PageWidth, Printer.PageHeight));
+ B.TileTo(Printer.Canvas.Handle, R, Rect(0, 0, W, H));
+ Printer.EndDoc;
+ finally
+ B.Free;
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+procedure TMainForm.ImgViewMouseWheelUp(Sender: TObject;
+ Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
+var
+ s: Single;
+begin
+ s := ImgView.Scale / 1.1;
+ if s < 0.2 then s := 0.2;
+ ImgView.Scale := s;
+ ScaleCombo.Text := IntToStr(Round(s * 100)) + '%';
+end;
+
+procedure TMainForm.ImgViewMouseWheelDown(Sender: TObject;
+ Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
+var
+ s: Single;
+begin
+ s := ImgView.Scale * 1.1;
+ if s > 20 then s := 20;
+ ImgView.Scale := s;
+ ScaleCombo.Text := IntToStr(Round(s * 100)) + '%';
+end;
+
+procedure TMainForm.mnFlipHorzClick(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Bitmap.FlipHorz;
+end;
+
+procedure TMainForm.mnFlipVertClick(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Bitmap.FlipVert;
+end;
+
+procedure TMainForm.mnRotate90Click(Sender: TObject);
+var
+ R: TFloatRect;
+ Cx, Cy, W2, H2: Single;
+begin
+ if Selection is TBitmapLayer then
+ begin
+ R := Selection.Location;
+ TBitmapLayer(Selection).Bitmap.Rotate90;
+ Cx := (R.Left + R.Right) / 2;
+ Cy := (R.Top + R.Bottom) / 2;
+ W2 := (R.Right - R.Left) / 2;
+ H2 := (R.Bottom - R.Top) / 2;
+ RBLayer.Location := FloatRect(Cx - H2, Cy - W2, Cx + H2, Cy + W2);
+ end;
+end;
+
+procedure TMainForm.mnRotate180Click(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Bitmap.Rotate180;
+end;
+
+procedure TMainForm.mnRotate270Click(Sender: TObject);
+var
+ R: TFloatRect;
+ Cx, Cy, W2, H2: Single;
+begin
+ if Selection is TBitmapLayer then
+ begin
+ R := Selection.Location;
+ TBitmapLayer(Selection).Bitmap.Rotate270;
+ Cx := (R.Left + R.Right) / 2;
+ Cy := (R.Top + R.Bottom) / 2;
+ W2 := (R.Right - R.Left) / 2;
+ H2 := (R.Bottom - R.Top) / 2;
+ RBLayer.Location := FloatRect(Cx - H2, Cy - W2, Cx + H2, Cy + W2);
+ end;
+end;
+
+procedure TMainForm.mnFileClick(Sender: TObject);
+begin
+ mnPrint.Enabled := not ImgView.Bitmap.Empty;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/NewImageUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/NewImageUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/NewImageUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,71 @@
+unit NewImageUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, QForms, QDialogs, QStdCtrls, QControls, QExtCtrls,
+ QComCtrls;
+
+type
+ TNewImageForm = class(TForm)
+ Label1: TLabel;
+ Label2: TLabel;
+ Label3: TLabel;
+ Label4: TLabel;
+ Label5: TLabel;
+ Panel1: TPanel;
+ Button1: TButton;
+ Button2: TButton;
+ Button3: TButton;
+ ImageWidth: TEdit;
+ ImageHeight: TEdit;
+ ColorDialog1: TColorDialog;
+ procedure Button1Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ NewImageForm: TNewImageForm;
+
+implementation
+
+{$R *.xfm}
+
+procedure TNewImageForm.Button1Click(Sender: TObject);
+begin
+ with ColorDialog1 do
+ begin
+ Color := Panel1.Color;
+ if Execute then Panel1.Color := Color;
+ end;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/NewImageUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/NewImageUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/RGBALoaderUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/RGBALoaderUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/RGBALoaderUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,122 @@
+unit RGBALoaderUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, QGraphics, QForms, QDialogs, QStdCtrls, QControls,
+ QExtCtrls, QButtons, GR32_Image, GR32_Filters;
+
+type
+ TRGBALoaderForm = class(TForm)
+ Panel1: TPanel;
+ Bevel1: TBevel;
+ Label1: TLabel;
+ Label2: TLabel;
+ ImgRGB: TImgView32;
+ Button1: TButton;
+ Label3: TLabel;
+ ImgAlpha: TImgView32;
+ Button2: TButton;
+ Label4: TLabel;
+ Button3: TButton;
+ Button4: TButton;
+ SpeedButton1: TSpeedButton;
+ SpeedButton2: TSpeedButton;
+ SpeedButton3: TSpeedButton;
+ SpeedButton4: TSpeedButton;
+ Button5: TButton;
+ OpenPictureDialog: TOpenDialog;
+ procedure Button1Click(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure SpeedButton1Click(Sender: TObject);
+ procedure SpeedButton2Click(Sender: TObject);
+ procedure SpeedButton3Click(Sender: TObject);
+ procedure SpeedButton4Click(Sender: TObject);
+ procedure Button5Click(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ RGBALoaderForm: TRGBALoaderForm;
+
+implementation
+
+{$R *.xfm}
+
+procedure TRGBALoaderForm.Button1Click(Sender: TObject);
+begin
+ with OpenPictureDialog do
+ if Execute then ImgRGB.Bitmap.LoadFromFile(FileName);
+end;
+
+procedure TRGBALoaderForm.Button2Click(Sender: TObject);
+begin
+ with OpenPictureDialog, ImgAlpha do
+ if Execute then
+ begin
+ Bitmap.LoadFromFile(FileName);
+ ColorToGrayscale(Bitmap, Bitmap);
+ end;
+end;
+
+procedure TRGBALoaderForm.SpeedButton1Click(Sender: TObject);
+begin
+ ImgRGB.Scale := ImgRGB.Scale * 1.5;
+end;
+
+procedure TRGBALoaderForm.SpeedButton2Click(Sender: TObject);
+begin
+ ImgRGB.Scale := ImgRGB.Scale / 1.5;
+end;
+
+procedure TRGBALoaderForm.SpeedButton3Click(Sender: TObject);
+begin
+ ImgAlpha.Scale := ImgAlpha.Scale * 1.5;
+end;
+
+procedure TRGBALoaderForm.SpeedButton4Click(Sender: TObject);
+begin
+ ImgAlpha.Scale := ImgAlpha.Scale / 1.5;
+end;
+
+procedure TRGBALoaderForm.Button5Click(Sender: TObject);
+begin
+ ImgRGB.Scale := 1;
+ ImgAlpha.Scale := 1;
+end;
+
+procedure TRGBALoaderForm.FormCreate(Sender: TObject);
+begin
+ OpenPictureDialog.Filter := GraphicFilter(TGraphic, True);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/RGBALoaderUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/ImgView_Layers_Ex/RGBALoaderUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/LineStippling_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/LineStippling_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/LineStippling_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program LineStippling_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/LineStippling_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/LineStippling_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,99 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
+ QStdCtrls, GR32, GR32_Image;
+
+type
+ TForm1 = class(TForm)
+ Image: TImage32;
+ ScrollBar1: TScrollBar;
+ procedure ScrollBarChange(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ procedure Spiral(X, Y: Integer);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.xfm}
+
+procedure TForm1.ScrollBarChange(Sender: TObject);
+var
+ Step: Single;
+begin
+ Step := ScrollBar1.Position / 100;
+
+ with Image.Bitmap do
+ begin
+ BeginUpdate;
+ Clear(clBlack32);
+ SetStipple([clWhite32, clWhite32, clWhite32, clWhite32, 0, 0, 0, 0]);
+ StippleStep := Step;
+ Spiral(50, 50);
+
+ SetStipple([clWhite32, $00FFFFFF]);
+ Spiral(150, 50);
+
+ SetStipple([clWhite32, clRed32, clGreen32, 0, 0, 0]);
+ Spiral(50, 150);
+
+ SetStipple([clGreen32, clGreen32, clGreen32, 0, 0, clWhite32, 0, 0]);
+ Spiral(150, 150);
+ EndUpdate;
+ end;
+ Image.Repaint;
+end;
+
+procedure TForm1.Spiral(X, Y: Integer);
+var
+ Theta: Single;
+begin
+ Theta := 0;
+ Image.Bitmap.MoveToF(X, Y);
+ while Theta < 15 * 3.1415926535 do
+ begin
+ Image.Bitmap.LineToFSP(X + Cos(Theta) * Theta, Y + Sin(Theta) * Theta);
+ Theta := Theta + 0.2;
+ end;
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ ScrollBarChange(Sender);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/LineStippling_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,133 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mattias Andersson <mattias at centaurix.com>
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
+ GR32, GR32_Image, GR32_Layers, GR32_Blend, QStdCtrls, QExtCtrls;
+
+type
+ TForm1 = class(TForm)
+ ImgView: TImgView32;
+ RadioGroup1: TRadioGroup;
+ procedure FormCreate(Sender: TObject);
+ procedure RadioGroup1Click(Sender: TObject);
+ protected
+ procedure PC_Add(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Sub(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Modulate(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Min(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Max(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Difference(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Exclusion(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Pattern(F: TColor32; var B: TColor32; M: TColor32);
+ public
+ PatCount: Integer;
+ L: TBitmapLayer;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.xfm}
+
+procedure TForm1.FormCreate(Sender: TObject);
+var
+ I, J: Integer;
+begin
+ L := TBitmapLayer.Create(ImgView.Layers);
+ L.Bitmap.SetSize(200, 200);
+ L.Bitmap.DrawMode := dmCustom;
+ L.Location := FloatRect(20, 20, 220, 220);
+ for J := 0 to 199 do
+ for I := 0 to 199 do
+ L.Bitmap[I, J] := Gray32(Round(((Sin(I / 10) + Sin(J / 10)) * 0.25 + 0.5) * 255));
+ L.Bitmap.OnPixelCombine := nil; // none by default
+end;
+
+procedure TForm1.PC_Add(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorAdd(F, B);
+end;
+
+procedure TForm1.PC_Max(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorMax(F, B);
+end;
+
+procedure TForm1.PC_Min(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorMin(F, B);
+end;
+
+procedure TForm1.PC_Modulate(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorModulate(F, B);
+end;
+
+procedure TForm1.PC_Pattern(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ PatCount := 1 - PatCount;
+ if PatCount = 0 then B := F;
+end;
+
+procedure TForm1.PC_Sub(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorSub(F, B);
+end;
+
+procedure TForm1.PC_Difference(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorDifference(F, B);
+end;
+
+procedure TForm1.PC_Exclusion(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorExclusion(F, B);
+end;
+
+procedure TForm1.RadioGroup1Click(Sender: TObject);
+begin
+ case RadioGroup1.ItemIndex of
+ 0: L.Bitmap.OnPixelCombine := nil;
+ 1: L.Bitmap.OnPixelCombine := PC_Add;
+ 2: L.Bitmap.OnPixelCombine := PC_Sub;
+ 3: L.Bitmap.OnPixelCombine := PC_Modulate;
+ 4: L.Bitmap.OnPixelCombine := PC_Min;
+ 5: L.Bitmap.OnPixelCombine := PC_Max;
+ 6: L.Bitmap.OnPixelCombine := PC_Difference;
+ 7: L.Bitmap.OnPixelCombine := PC_Exclusion;
+ 8: L.Bitmap.OnPixelCombine := PC_Pattern;
+ end;
+ L.Bitmap.Changed;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/MainUnit.xfm
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/MainUnit.xfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/MainUnit.xfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,7557 @@
+object Form1: TForm1
+ Left = 299
+ Top = 133
+ Width = 524
+ Height = 373
+ VertScrollBar.Range = 205
+ ActiveControl = RadioGroup1
+ Caption = 'Form1'
+ Color = clButton
+ Font.Color = clText
+ Font.Height = 11
+ Font.Name = 'MS Sans Serif'
+ Font.Pitch = fpVariable
+ Font.Style = []
+ Font.Weight = 40
+ ParentFont = False
+ Scaled = False
+ OnCreate = FormCreate
+ PixelsPerInch = 133
+ object ImgView: TImgView32
+ Left = 16
+ Top = 20
+ Width = 367
+ Height = 309
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Bitmap.Data = {
+ 1B010000D40000003A1EC5FF3820C2FF3922C0FF3924C0FF3823C5FF3925C4FF
+ 3C28C1FF3D2ABFFF3F29BEFF3526A6FF33318AFF3A4382FF3C4B83FF354980FF
+ 37488BFF3A5097FF3B589DFF3D5EA3FF4265A7FF446AABFF456BABFF4770AFFF
+ 4D78B7FF537EBDFF527DBCFF4F7AB9FF4C73B7FF486FB3FF496AB3FF4768B1FF
+ 4867B2FF4866B3FF3F5EADFF3E5FAFFF3C5EB1FF395DABFF36569FFF344F8FFF
+ 36487DFF3A4571FF35365CFF313052FF302F51FF383759FF3C3E5DFF3A3C5AFF
+ 383953FF3B3A4EFF3D3945FF41394AFF32264AFF241842FF241C41FF281D4BFF
+ 27135BFF29145FFF2B1758FF321D54FF3F2053FF451F3DFF6D3A38FFA1683BFF
+ B67C1CFFC08409FFC27F04FFC27D04FFC57F0DFFBC7A03FFBE8603FFAB8116FF
+ 64491DFF2E1C15FF241316FF1C1316FF161917FF1B201EFF2A1F27FF271D2AFF
+ 231F32FF242436FF242235FF242131FF221F2EFF25232FFF2A2834FF2E2D36FF
+ 302F38FF2F2F35FF2B2B31FF28282EFF24232DFF23222CFF252231FF252231FF
+ 242131FF241E2FFF292034FF271F30FF26222DFF27242DFF282128FF291F25FF
+ 34262CFF503521FF986723FFBA7D1BFFB77C0EFFBC7F09FFC6850BFFC48408FF
+ C5860EFFC1830DFFC28310FFC28311FFC28311FFC28311FFC28311FFC28311FF
+ C28311FFC28311FFC38412FFC38412FFC38412FFC38412FFC28311FFC28311FF
+ C18210FFBF810FFFBE8211FFBF8514FFC1881BFFC58B21FFC88E27FFC9902DFF
+ CA9031FFC99035FFC68D38FFC08837FFBF8539FFC88E46FFD49C55FFDFA661FF
+ DEA665FFDCA463FFDFA96AFFDFAA6BFFDFA96CFFDCAB6DFFDEAC70FFDCAE74FF
+ DBB077FFD8B07BFFD5AE7AFFC9A575FFCDAB80FFE4C59EFFF9D9B6FFF9DDBBFF
+ FCDEC1FFFDE4CAFFFCE7D8FFF1DFD4FFECDBD2FFF1E0D7FFFAEAE3FFFFF3EBFF
+ FFF3EDFFFAF0E9FFF6EAE8FFF6EDEAFFF8F0F1FFF9F1F2FFF0E9ECFFEAE3E6FF
+ EEE9EBFFFAF5F7FFFDF3F9FFFBF1F7FFF7EFF6FFF9F1F8FFFAF3FAFFFBF4FBFF
+ FAF2FCFFF6F1FAFFFBF5FFFFF7F3FEFFF6F2FEFFF6F2FEFFF6F3FFFFF6F3FFFF
+ F2F2FFFFF0F0FCFFF9F6FFFFF7F5FBFFF5F3F9FFF4F2F8FFF2F2F8FFF4F4FAFF
+ F7F8FCFFF8F9FDFFF2F5F9FFF0F3F7FFEEF3F4FFF0F5F6FFF3F8F9FFF5FAFBFF
+ F4F9FAFFF2F7F8FFF1F4F8FFF1F3F4FFF5EFF0FFF5EDEDFFF5EAEDFFF1EAEFFF
+ ECE8F3FFE7E9F4FFE2E4EEFFE6EAEFFFF3F3F3FFF2EFEBFFE5E1DCFFE9E2DFFF
+ EDE7E8FFE3E2E4FFE1E9E8FFE3F0EEFFF0F5F3FFF5F6F4FFF6F1F0FFF6EEEEFF
+ F7EFEFFFF8F3F2FFF5F1F0FFF2F0EFFFF5F6F4FFF5F4F0FFEAE5E2FFE4DCD5FF
+ D6CAC4FFC2B4A8FFC3AF9EFFC9B49FFFCBB49EFFC3AD94FFB99F87FFB3987DFF
+ B5997BFFBC9D7CFFCBAB88FFBF9B75FFB08C64FFAE895DFFB98F64FFBD9467FF
+ BB8F60FFB48754FFB6894CFFBE9050FFC0904EFFB88945FFB3823EFFB08038FF
+ AE7A33FFA77529FFB27C2FFFB98433FFC08837FFBE8732FFC08430FFC0852FFF
+ BC8027FFB4781EFFC1852BFFBF8526FFBE8121FFBB7F1BFFBD7F15FFBB7E10FF
+ BB7C0CFFBA7C0AFFBE800EFFBA7B0BFFB87B0DFF381DC1FF371FC1FF3721BDFF
+ 3722BEFF3622C1FF3723C2FF3A26BFFF3B28BDFF402ABFFF3627A7FF33318AFF
+ 394281FF3A4A7FFF34487FFF354788FF374E92FF39569BFF3A5BA0FF3F62A6FF
+ 4167A8FF446AABFF456EADFF4974B3FF4E79B8FF517CBBFF507ABBFF4F76BAFF
+ 4B72B7FF496AB3FF4465AEFF4160ABFF3E5CA9FF3E5DACFF3C5DADFF395BAEFF
+ 375BA9FF36569FFF344F8FFF35477CFF39426EFF303359FF302F51FF302F51FF
+ 383759FF3B3D5CFF3A3C5AFF383953FF3C3B4FFF3D3945FF403849FF312549FF
+ 241743FF251C44FF281C4CFF271459FF29145FFF281554FF2F1953FF3A1D54FF
+ 441E42FF6B3A3CFF9B663BFFB27818FFB87C00FFC27F04FFC27D04FFC57F0DFF
+ BC7A03FFBE8603FFAD8116FF64491DFF2F1C14FF251417FF1C1218FF161917FF
+ 1D201EFF291E26FF291C2AFF221E31FF242436FF282737FF272434FF252231FF
+ 262430FF292733FF2C2B35FF2C2B34FF2B2B31FF2A2A30FF27262FFF24232DFF
+ 23222CFF252231FF262332FF252232FF251F30FF292034FF271F30FF26222DFF
+ 27242DFF282128FF291F25FF33252BFF503521FF966521FFB97C1AFFB67B0DFF
+ BC7F09FFC5840AFFC28206FFC4850DFFC0820CFFC1820FFFC18210FFC18210FF
+ C18210FFC18210FFC18210FFC18210FFC18210FFC38412FFC38412FFC28311FF
+ C18210FFC18210FFC18210FFC18210FFC18311FFBE8211FFBD8312FFBD8516FF
+ BF8619FFC0861DFFC18720FFBF8623FFBF8526FFC0872CFFBB8128FFB67D28FF
+ B67E2CFFBC8433FFBF8738FFBD8538FFB98035FFBA8038FFBA8038FFB88138FF
+ B78239FFB6823BFFB7843EFFB58642FFB48744FFB68C4BFFAE8547FFAF894FFF
+ BF9963FFCBA674FFCDA979FFCCA97DFFCCAC83FFD2B392FFCCB092FFCBAE93FF
+ D0B59AFFDCC1A7FFE4CBB1FFE5CDB5FFE4CEB5FFDFC8B2FFDDC8B3FFDECAB8FF
+ E0CCBBFFDBC8B9FFDAC7B8FFE0D0C0FFECDCCCFFF8E6DBFFF6E5DCFFF5E3DCFF
+ F5E5DEFFF9E9E2FFFBEBE4FFFAEAE4FFF7E9E3FFF2E6E2FFF6EAE6FFF9ECEAFF
+ F8ECEAFFF7EBEBFFF5EBEBFFFAF0F0FFFDF5F5FFFFFAF9FFFDF7F8FFFBF5F6FF
+ F9F3F4FFF7F2F3FFF7F2F3FFF8F4F3FFF7F5F4FFF9F7F6FFF8F6F5FFF6F7F5FF
+ F7F8F6FFF8F9F7FFF9FAF8FFF8F9F7FFF8F9F7FFF7F8F6FFF8F6F5FFFCF5F2FF
+ FCF3F0FFFBF1F1FFF9F0F3FFF4F0F6FFF0EFF8FFF0F3F8FFEDF1F2FFF5F6F4FF
+ FAF7F3FFF4F1EDFFF6F1F2FFF9F5FAFFF1F1F7FFE7EFEFFFEAF5F3FFF3F8F7FF
+ F9F7F6FFF8F3F2FFF7EFF0FFF6F0F1FFF9F3F4FFF8F6F6FFF2F2F2FFF2F2F2FF
+ F1EFEFFFEDE9E8FFF2EBE8FFF2E9E6FFE8DCD6FFE8DACEFFECDCCFFFEDDDCDFF
+ E9D6C7FFDECCBBFFDAC6B4FFDDC5B1FFE1C9B1FFECD3B9FFE2C7ACFFD8BA9DFF
+ D7B899FFDDBC9BFFDEBE9BFFD8B593FFD1AD87FFCEA97DFFD1AB7BFFD0A877FF
+ CBA470FFC8A06CFFC69D66FFBE935AFFB5894EFFB48849FFB98B4BFFBC8C4AFF
+ BD8C48FFBE8B45FFBC8841FFB9833CFFB27E32FFB37E2EFFB27D2CFFB37D28FF
+ B27C25FFB37D1FFFB67E1FFFB7801DFFB9831EFFBA811EFFB47D1AFFB47C1DFF
+ 3A1FC2FF3821BFFF3924BDFF3824BDFF3723C2FF3824C3FF3B27C0FF3B28BDFF
+ 3F28C0FF3626A9FF333288FF37417DFF38497CFF32477BFF344784FF354D8FFF
+ 375499FF37589DFF3C5FA3FF3F65A6FF4369AAFF456DAEFF4670B1FF4771B2FF
+ 4C76B7FF4C76B9FF4E75B9FF4B72B7FF4A6BB4FF4363AEFF3D5BA8FF3856A3FF
+ 3E5CABFF3B59AAFF3758A8FF3557A3FF37559CFF354E8CFF344578FF343D69FF
+ 2D3056FF2D2D51FF302E52FF373658FF3B3D5CFF3A3C5AFF393A54FF3C3B4FFF
+ 3E3A46FF3F364AFF302349FF231644FF251B45FF281C4EFF251457FF27155CFF
+ 2C1B5AFF2F1B56FF341B59FF3E1C4BFF633843FF95643EFFB37C1BFFBA7F01FF
+ C27F04FFC27D04FFC57F0DFFBA7A04FFBF8504FFAF8017FF66491CFF311C14FF
+ 291619FF1D1319FF161818FF1C1E1EFF291E26FF281B29FF221F2FFF232335FF
+ 2B2A3AFF2B2838FF292635FF282632FF282632FF282731FF27262FFF26252EFF
+ 282730FF26252EFF24232DFF24232DFF252231FF262332FF252232FF272132FF
+ 292034FF271F30FF26222DFF27242DFF272027FF281E24FF33252BFF4F3420FF
+ 94631FFFB87B19FFB57A0CFFBB7E08FFC48309FFC08004FFC2830BFFBE800AFF
+ BF800DFFBF800DFFBF800DFFBF800DFFBF800DFFBF800DFFBF800DFFBF800DFF
+ C28310FFC1820FFFC0810EFFBF800DFFBF800DFFC1820FFFC28310FFC38612FF
+ C28614FFBF8613FFBE8413FFBC8211FFBC8113FFB98013FFB97F15FFB87F16FF
+ BB8219FFB87E17FFB57A16FFB37B16FFB57C19FFB57E1BFFB47D1CFFB47A1AFF
+ BB7D1FFFBB7D1FFFBA7C1EFFB97C1EFFBA7D1FFFB97F20FFB68022FFB58025FF
+ B07B21FFAE7922FFAB7926FFAD7D2BFFB28131FFB58537FFB5843AFFB2823AFF
+ B37F3CFFB17D3BFFB07C3AFFB17F3DFFB78445FFBA894BFFBA8B4EFFB98C4FFF
+ BC8E54FFB88B52FFB58953FFB68A54FFB58B56FFB88E59FFBE9661FFC79F6EFF
+ D6B388FFD3B38AFFD4B38CFFD6B58EFFDAB992FFDBBC95FFDCBC98FFD9BC97FF
+ E4C6A3FFEACEABFFF1D5B3FFEED3B1FFE8CCADFFE8CCADFFF1D5B6FFF5DEC4FF
+ F2E2D1FFEEE2D6FFEFE3D7FFF2E6DAFFF5E9DDFFF8ECE0FFF9EFE5FFFBF1E7FF
+ EFE5DBFFF0E7DEFFF2E9E0FFF3EAE1FFF2EBE2FFF3ECE3FFF5EDE6FFF7F0E7FF
+ FAF5ECFFFCF5ECFFFFF6EDFFFFF5EEFFFEF5F1FFFBF4F1FFF9F3F4FFF5F3F3FF
+ F8F6F5FFF7F6F2FFFBFBF5FFFDFCF8FFF6F4F4FFF1F1F7FFF0F1FFFFEDF0FEFF
+ EEF4F9FFF3F8F9FFF8FAFAFFFAF8F8FFF9F3F4FFF6EFF2FFF6F0F5FFF7F3F9FF
+ F8F6FCFFF3F3F9FFF1F2F6FFF0EFF3FFF0ECF1FFF7F3F8FFF9F5FAFFF4EFF1FF
+ F3EEEFFFF5EFF0FFF8F0F1FFF7EFEFFFF3EBEBFFF4EBE8FFF5ECE8FFF8EDE9FF
+ FDF1EBFFFAEDE5FFF5E9DFFFF8E9E0FFFFEFE3FFFFEFE3FFF9E9DDFFF3E2D5FF
+ F1DECFFFF0DBCCFFEFD8C8FFEDD7C5FFF0D8C6FFEFD7C1FFE6CAB2FFDBBEA3FF
+ D3B697FFD1B291FFD1AF8BFFD1AD87FFCEAA82FFC8A57AFFC29C72FFBF986BFF
+ BE9661FFBF975DFFBD955AFFB99051FFB48A49FFB28843FFB48A43FFB78E45FF
+ AD813AFFA87E37FFA87E39FF3D24C2FF3B25C1FF3B26BEFF3B28BFFF3A26C5FF
+ 3A26C5FF3D29C2FF3D2AC1FF3D26BEFF3525A8FF323089FF343E7AFF354679FF
+ 32477AFF354983FF354D8FFF375499FF36569DFF3B5DA3FF3F64A8FF456AAEFF
+ 466EAFFF456FB2FF446EB1FF456FB2FF466FB4FF4970B5FF486EB6FF4868B3FF
+ 4262AEFF3D5BA8FF3957A6FF3B59A8FF3855A6FF3253A3FF3454A0FF345398FF
+ 334C8AFF314275FF2F3863FF2A2D53FF2C2C50FF312F53FF353559FF3A3B5DFF
+ 3B3D5BFF3A3B55FF3C3B4FFF3F3B47FF403549FF302049FF251545FF261B49FF
+ 261A4EFF241356FF27155AFF2E1F5DFF2A1958FF2A135DFF341552FF542D46FF
+ 895A3EFFB37D1EFFBE8403FFC28003FFC17E04FFC3800DFFBA7A04FFBF8406FF
+ AF7F19FF6A491BFF331D12FF2A161BFF20131BFF19181AFF1C1E1FFF281D27FF
+ 271A28FF211E2EFF232333FF2E2B3BFF2D2A3AFF2B2837FF292635FF282632FF
+ 272630FF26252FFF25242DFF26252EFF25242DFF24232DFF24222EFF242130FF
+ 252231FF262333FF282233FF292034FF271F30FF26222DFF26232CFF272027FF
+ 271D23FF32242AFF4E331FFF91601CFFB67917FFB57A0CFFBA7D07FFC28107FF
+ BE7E02FFC08109FFBD8008FFBE800AFFBE800AFFBE7F0CFFBE800AFFBE7F0CFF
+ BE800AFFBE7F0CFFBE800AFFC1820FFFC0820CFFBE7F0CFFBD7F09FFBE7F0CFF
+ C0820CFFC38411FFC48713FFC78C18FFC38A16FFC28713FFBD8410FFBD810FFF
+ BA810EFFBA810EFFBA810EFFBA810EFFBA810EFFBA810EFFBB820FFFBC8310FF
+ BF8613FFC18716FFC48817FFC48418FFC48317FFC28216FFC18214FFC18214FF
+ C08315FFC18416FFBF8417FFBD8215FFBE841AFFBC831AFFB77D16FFB67B17FF
+ B9801DFFBA8020FFB67C1CFFC08323FFBF8123FFBD7F21FFBB7E20FFBA7D1FFF
+ B87D20FFB97D23FFB77D24FFBE862DFFBB822CFFB67F2AFFB47D28FFB47E2BFF
+ B7812EFFB98532FFBB8838FFB18139FFAF803CFFB0803EFFB38341FFB58543FF
+ B68946FFB78949FFB58949FFB58949FFBA8F50FFBD9253FFB88F51FFB28649FF
+ AF8648FFB68D4FFFB9935DFFBEA175FFBCA27DFFC1A582FFC6AC88FFCDB18EFF
+ D1B793FFD4B997FFD4BB99FFD3BA9AFFD5BD9FFFDCC2A4FFDDC5A9FFDFC7ABFF
+ E0CAAEFFE7CEB4FFE8D3B8FFF3E0C5FFF1E3C7FFF3E3CCFFF5E4CFFFF4E4D3FF
+ F3E4D4FFF3E4D4FFF0E4D2FFF8EEDCFFFFF9E6FFFFFFEFFFFFFDF2FFF6F2F1FF
+ EFEFF5FFEFEFFFFFEDF0FFFFF1F4FCFFF6F7FBFFFAF7F9FFFAF5F6FFF7F2F4FF
+ F6F0F5FFF5F0F9FFF5F1FCFFF4F0FBFFF5F2FBFFF8F4F9FFF9F4F6FFFAF5F7FF
+ FFFAFCFFFBF7FCFFF2F1F5FFF3F1F7FFF3F1F7FFF4F2F8FFF5F3F9FFF6F4FAFF
+ F7F6FAFFFAF6FBFFFAF6FBFFF9F5FAFFF8F5F7FFFAF5F7FFFCF7F9FFFFFAFCFF
+ FFFAFBFFFCF7F9FFFAF3F6FFF4EDF0FFF4EBEEFFF2E9ECFFF5EAECFFF9EDEDFF
+ F9ECEAFFF4E5E2FFEFDFD8FFFBEAE1FFF5E4D7FFF2DFD0FFF3DFCEFFF2DCCAFF
+ EBD6C1FFE6CEBAFFE4CCB4FFEAD2B4FFECD3B3FFEACFADFFE0C6A2FFD5BA95FF
+ D1B48DFFD4B68DFFD7BA8EFFCBAD84FFC6AA81FFC6A982FF3B23BFFF3924BDFF
+ 3925BAFF3926BDFF3723C2FF3722C4FF3A25C1FF3A26BFFF3A22BCFF3423A8FF
+ 312F88FF323C78FF344578FF334979FF374B84FF364F8FFF38549BFF3757A0FF
+ 3C5DA6FF4165ABFF466AB0FF486FB3FF4770B5FF4770B5FF466FB4FF456EB3FF
+ 466CB4FF4368B2FF4363AFFF3E5DACFF3B59A8FF3856A5FF3853A3FF3452A1FF
+ 31509FFF31509BFF335093FF314985FF2E3D6EFF2D345FFF282B51FF2D2D51FF
+ 313057FF36365AFF3A3A5EFF3B3D5CFF3B3C58FF3C3A50FF403B4AFF3E3248FF
+ 301D48FF251348FF271B4DFF26194FFF231353FF25165AFF241755FF24145BFF
+ 27116AFF311765FF4A2850FF7B513EFFAF7B1DFFBE8200FFC08003FFC17E04FF
+ C3800DFFBA7A04FFBF8308FFB07E1AFF6D4919FF381D0FFF2E181DFF22141FFF
+ 19181CFF1E1D21FF251C26FF241A27FF201D2CFF222232FF2B2838FF2B2838FF
+ 2B2837FF2A2736FF292733FF272630FF272630FF272630FF26252FFF25242EFF
+ 25232FFF24222EFF242130FF252231FF262333FF292334FF292034FF271F30FF
+ 26222DFF26232CFF261F26FF271D23FF302228FF4D321EFF8F5E1AFFB57816FF
+ B57A0CFFBA7D07FFC28107FFBD7D01FFBF8008FFBC7F07FFBD8008FFBD8008FF
+ BD7F09FFBD8008FFBD7F09FFBD8008FFBD7F09FFBD8008FFC1830DFFBF820AFF
+ BD7F09FFBC7F07FFBD7F09FFBF820AFFC2840EFFC48610FFC88B15FFC48A13FF
+ C38610FFBF850EFFBF830BFFBF830BFFBF830BFFBF830BFFBD8207FFBE8308FF
+ BF8307FFBE8206FFBD8204FFBE8305FFC08507FFC2860BFFC1820FFFC0810FFF
+ BF800EFFBE7F0CFFBE800AFFBE800AFFBF810BFFBF820AFFC2850DFFC68A12FF
+ C58812FFBD800CFFBB7E0AFFC18311FFC48515FFC08210FFBD800CFFBD800CFF
+ BE810DFFBD800CFFBD800CFFBB7F0DFFBD8110FFBD8214FFBE8617FFBD8417FF
+ BA8215FFB98116FFB78017FFB98219FFB68218FFB58018FFB57B1BFFB77A1CFF
+ B87B1DFFB77D1EFFB87E1FFFB87E1FFFB97E21FFB87F22FFB98023FFB78025FF
+ B67F24FFB27D23FFB27A21FFAF7A20FFB07B21FFB17B26FFAE7D2FFFAC7E31FF
+ B07F35FFAF8036FFB28038FFB18139FFB2813BFFB0813DFFAE7E3CFFB08340FF
+ B68646FFB7884AFFB98A4DFFB98C4FFFC09154FFBF955AFFCCA76FFFC7A772FF
+ C7A97AFFC8AB7FFFC8AC83FFC9AD84FFCBAD84FFC9AE82FFD9C094FFE4CEA5FF
+ E8D3B3FFE3D3BCFFE4DAD0FFEEE8E9FFF0EFF9FFEEEEFCFFF1F0FAFFF4F2F8FF
+ F8F3F5FFF7F2F3FFF6F1F3FFF5EFF4FFF3F0F9FFF5F1FCFFF4EEF9FFF5EDF4FF
+ F3E7E7FFF0E4E0FFF7EBE7FFFFF5F1FFFFF8F5FFFBF6F5FFFBF6F7FFF8F5F7FF
+ F8F5F7FFF9F6F8FFFBF8FAFFFCF8FDFFFAF9FDFFF9F8FCFFF8F7FBFFF7F5FBFF
+ F3F3F9FFF2F2F8FFF1F1F7FFF0F0F6FFEFEEF7FFEEEDF6FFF4F3FCFFF3F3F9FF
+ F3F3F9FFF5F4F8FFF4F3F7FFF4F1F3FFF3F1F1FFF6F1F2FFF5F1F0FFF3EEEBFF
+ F3EDE8FFF3EDE6FFF6EFE6FFF4EDE4FFF4EBE2FFF2E9E0FFF6ECE5FFF8EEE7FF
+ F7EBE5FFF1E6DEFFEADDD5FFE7DBD1FFECDDD4FFF0E2D6FFEEDFD6FFEADBD2FF
+ EADBD2FF371FB9FF3520B9FF3521B6FF3420B9FF321DBFFF321DC0FF341EBDFF
+ 341FBCFF3B22C0FF3625ACFF32308AFF313A79FF334477FF344A7AFF384C85FF
+ 354E8EFF37539AFF3756A1FF3D5DA8FF4164ADFF4669B2FF486FB4FF4972B7FF
+ 4B74B9FF4B74B9FF4971B9FF466BB5FF4064B0FF3E5DACFF3957A8FF3653A4FF
+ 3451A2FF334E9EFF324E9BFF304E9BFF314E98FF324C8EFF2F457FFF2B3969FF
+ 29305BFF282A52FF302F56FF35345BFF36375DFF393A60FF3B3D5FFF3A3C5AFF
+ 3B394FFF413C4BFF3D3147FF2E1A47FF271249FF281A50FF231751FF201252FF
+ 241658FF231557FF2A1C6AFF38238AFF462E8DFF55356BFF795249FFB27E24FF
+ BF8202FFC08003FFC17E03FFC3800BFFBA7906FFBF820AFFB27E1AFF724A16FF
+ 3C1E0DFF311A1EFF231521FF1C181EFF1D1C20FF241B25FF231925FF1F1D29FF
+ 222230FF272434FF292636FF2B2837FF2B2837FF292733FF282632FF282632FF
+ 292832FF262430FF262430FF262430FF25232FFF23202FFF23202FFF252232FF
+ 292334FF292034FF271F30FF25212CFF26232CFF261F26FF261C22FF302228FF
+ 4C311DFF8D5C18FFB57816FFB67B0DFFBB7E08FFC18006FFBC7C00FFBE7F07FF
+ BC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFC0830BFFBF820AFFBD8008FFBC7F07FFBD8008FFBE8109FFC0830BFF
+ C1840CFFC1840CFFBF830BFFBF820AFFBD8109FFBD8106FFBD8106FFBD8106FF
+ BD8105FFBC8004FFBC8103FFBE8103FFBD8000FFBD8000FFBE8200FFC28303FF
+ C18406FFC48610FFC28412FFC18311FFC0830FFFC0830DFFC0840CFFC2860BFF
+ C3870CFFBE8206FFC3870BFFC2860BFFBF8006FFBF8008FFC4850DFFC88510FF
+ C4850DFFC18307FFC28507FFC28408FFC38509FFC38509FFC2860BFFC4880DFF
+ C48810FFBE810BFFBF850EFFC18612FFBF8612FFC08714FFBF8815FFBE8714FF
+ BC8310FFC18212FFC38215FFC48316FFC38215FFC18214FFC08113FFC18214FF
+ C38416FFC38519FFC08216FFBF8115FFBE8316FFC3851BFFC2861CFFC2841AFF
+ BD8018FFBE831CFFBC811DFFBC801CFFBA7F1CFFB97E1BFFB97D1DFFB97C1EFF
+ B77C1FFFB87D20FFB87F24FFBB7F26FFBA7F29FFBA7E2AFFB87F2AFFBC802CFF
+ B9812FFFB07D2DFFAD7E34FFAB7F38FFAC813EFFAD8342FFAF8544FFB18643FF
+ B18643FFB2894AFFB08D55FFAC8F62FFB7A080FFD5C6B6FFF1E5E3FFF7EFF6FF
+ F4EEF9FFF3EEF7FFF4F0F6FFF6F1F3FFF7F1F2FFF6F1F3FFF3EFF4FFF1EEF7FF
+ F4EFF8FFFCF2F8FFF3E3E4FFDBC6BEFFCEB5A5FFD7BEAAFFE6CEBAFFE9D8C5FF
+ ECDECCFFEADACDFFEADDCFFFEDE0D2FFEFE4D6FFF4E8DCFFF6ECE2FFF9EFE5FF
+ FAF1E8FFFEF5ECFFFBF3ECFFFAF2EBFFF7F1ECFFF8F2EDFFFAF3F0FFFCF5F2FF
+ FBF6F3FFF9F4F3FFF8F2F3FFF9F4F3FFF9F4F3FFF5F0EFFFEFEAE9FFEFEAE9FF
+ F3EEEBFFF2EDEAFFF7F2EFFFF8F3F0FFF4F0EBFFF4F0EBFFF7F3EEFFF7F3EEFF
+ F3EEEBFFF3EEEFFFF5F0F2FFF6F1F3FFF3EEF0FFF0E9ECFFEFE8EBFFF4EBEEFF
+ F7EEF1FFF9F0F3FFF5ECEFFFF3ECEFFF3820BCFF3621BAFF3621B9FF3520BCFF
+ 331DC3FF331CC4FF351DC1FF351EC0FF3F24C7FF3A27B2FF353190FF31397CFF
+ 314176FF33487BFF364A84FF324A8CFF344F99FF3654A1FF3C5CA8FF3F62ACFF
+ 4366B0FF466CB4FF4A72BAFF4F77BFFF4A72BAFF486FB9FF466AB6FF4064B2FF
+ 3E5DACFF3856A7FF3551A5FF344EA2FF304999FF324C99FF334D99FF324E95FF
+ 314A8AFF2D4079FF2A3666FF292F5AFF2B2B53FF33325AFF373660FF363861FF
+ 383A62FF3C3E61FF3A3C5AFF3B394FFF423D4CFF3C3046FF2C1847FF27114CFF
+ 281953FF231753FF1F1151FF221559FF25175EFF35257CFF4733AAFF5840B0FF
+ 5A3B7EFF765050FFB17D2AFFC18307FFC08003FFC17E03FFC3800BFFBA7906FF
+ BF820AFFB67D1AFF784B12FF411F08FF351D1FFF241622FF1C181EFF1F1B21FF
+ 231A24FF231925FF1F1E28FF22222EFF262332FF292636FF2B2837FF2B2837FF
+ 292635FF282534FF282534FF292733FF272433FF282534FF282534FF262332FF
+ 23202FFF221F2EFF242131FF282233FF292034FF282031FF25212CFF25222BFF
+ 251E25FF251B21FF2F2127FF4B301CFF8C5B17FFB57816FFB77C0EFFBC7F09FF
+ C28107FFBC7C00FFBE7F07FFBC7F07FFBD8106FFBD8106FFBD8106FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBF8308FFBE8207FFBE8207FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBC8005FFBC8005FFBF8006FFBD8106FF
+ BF8006FFBE7F05FFBE7F05FFBD7E04FFC08107FFBF8006FFBE7F05FFBF8006FF
+ C18208FFC38509FFC4850BFFC3860EFFBE8211FFBB8012FFBA7F11FFBA800FFF
+ BC800EFFBD820EFFBE840DFFBE840DFFBD8109FFBE820AFFBD8109FFBD8008FF
+ BF810BFFC2840EFFC48310FFC3820FFFC4850DFFC5830CFFC4820BFFC2830BFF
+ C3830DFFC0820CFFBF810BFFBD800AFFB77A06FFBD800CFFC18311FFBD810FFF
+ BE8211FFBE8413FFBD8312FFBB7F0EFFBE800EFFC0810EFFC28310FFC1820FFF
+ BF800DFFBE7F0CFFBF820EFFC0830FFFC18311FFC18311FFC18311FFC28614FF
+ C78818FFC58918FFC48515FFBF8312FFC18311FFBE8210FFC08210FFBE8211FF
+ BF8312FFC18416FFC38618FFC3881BFFC4881EFFC1871EFFC1841CFFBF841DFF
+ BF831FFFBE831FFFBE821EFFBD811DFFBF8220FFC08323FFBE8326FFBE852AFF
+ BE872CFFC38A2FFFC58C2FFFC48C33FFB98433FFAA7E37FFA6824CFFC2A782FF
+ EFDCC7FFFFF5EEFFFFF6F8FFFFF7FDFFF8F0F7FFF7F1F6FFF9F2F5FFF8F3F4FF
+ F6F3F5FFF2F1F5FFF0EEF4FFF2ECF1FFFCEFEDFFEDD7CBFFCCAA92FFB38D6AFF
+ B99167FFC49D70FFC3A274FFC5A679FFC1A176FFC5A57CFFC8AA81FFCEB087FF
+ D4B58EFFD8BB94FFDDC09BFFDFC3A0FFE3C9A5FFE1C8A6FFE3CAA8FFE4CDADFF
+ E9D2B2FFECD7B8FFEFDABBFFF1DAC0FFF1D8C4FFEED4C3FFEFD5C5FFF3DACAFF
+ F2D9C9FFE9D2C3FFE2CDBEFFE0CDC0FFEEDDD0FFFBEBDFFFFEEFE6FFF8E9E0FF
+ F5E8E0FFFDF2EAFFFFF5EDFFF9F0E7FFF7EFE8FFF8F0E9FFFAF1EDFFFAF1EDFF
+ FCF0EEFFFBEFEFFFFBEFEFFFFBEEF0FFFCEFF1FFF9EDEDFFF9EDEDFF3E25C3FF
+ 3C26C2FF3C27C0FF3A25C2FF3821C9FF3820CCFF3A21C9FF3A22C8FF4327CEFF
+ 3E2AB9FF373295FF32397EFF313F79FF32477BFF344784FF2F468AFF324D97FF
+ 34529FFF3B5BA7FF3E60ACFF4063ADFF4368B2FF4A72BAFF5179C1FF456CB6FF
+ 446BB6FF4468B6FF4064B2FF405EAFFF3A58ABFF3752A8FF3650A4FF2D4696FF
+ 324A96FF354E98FF344D93FF314886FF2D3E76FF2A3463FF2A2E57FF2C2B55FF
+ 34335DFF373864FF353864FF383A63FF3A3D63FF3A3C5BFF3A3750FF423D4CFF
+ 3B2F45FF2B1746FF25104EFF281956FF231654FF1C1052FF22145BFF22155FFF
+ 342482FF4832B3FF553CB6FF50327BFF6A4148FFA97326FFBC7D05FFC08004FF
+ C17E03FFC3800BFFBA7A04FFC1810BFFB87D19FF7D4D0DFF472103FF371E1CFF
+ 251722FF1E1620FF1F1B21FF231A24FF221824FF201C27FF22222EFF262332FF
+ 292636FF2C2938FF2C2938FF292635FF272433FF282534FF292635FF272433FF
+ 292635FF292635FF262332FF221F2EFF211E2DFF232030FF272132FF292034FF
+ 282031FF25212CFF25222BFF251E25FF251B21FF2E2026FF4A2F1BFF8C5B17FF
+ B57816FFB87D0FFFBD800AFFC28107FFBC7C00FFBE7F07FFBD8008FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBE8207FF
+ BE8207FFBE8207FFBE8207FFBE8207FFBD8106FFBC8005FFBB7F04FFBE7F05FF
+ BF8006FFC38208FFC18208FFC1820AFFC08109FFBF8008FFBD7D07FFC68610FF
+ C1830DFFBE800AFFBE800AFFBF810BFFC0820CFFBF810BFFBC7E0CFFBD8012FF
+ BA7F11FFBA7F11FFBA800FFFBC800EFFBD810FFFBE830FFFBF850EFFBD800AFF
+ BA7D07FFB97C06FFBC7E08FFBE7F0CFFBF800DFFBD7E0CFFBE7D0AFFBE7D0AFF
+ BF7C07FFBE7B06FFBF7C07FFC07F0CFFC1800DFFBD7E0BFFBB7C09FFB97A08FF
+ BF810FFFC38414FFBF8010FFBD7E0EFFBD8110FFBE8113FFBA7E0DFFBF810FFF
+ C18410FFC38612FFC38612FFC18410FFC0830FFFC08511FFC28713FFBC810DFF
+ BE830FFFC18612FFC38814FFC28614FFBF8410FFBD810FFFBD800CFFC18410FF
+ BF820CFFBE810BFFBC820BFFBE830FFFC18612FFC58917FFC58C19FFC18716FF
+ BF8514FFBD8214FFBC8415FFBE8518FFBF8619FFBD8417FFBC8114FFC18013FF
+ C37F14FFC07F16FFC18017FFC4831AFFC7871BFFCA8920FFC68A26FFC48E37FF
+ B2853CFFB2905BFFD9C09EFFFFF1E0FFFFF7F1FFF8ECECFFFBF0F3FFFDF3F9FF
+ FBF4F9FFFCF6F7FFFBF6F7FFF5F4F6FFF2F1F3FFEEEDEFFFF2EAEAFFF7E5DAFF
+ EACFB5FFCAA278FFB2834DFFB88546FFBC8943FFB1833CFFAC8039FFAA7B37FF
+ AD7E3AFFAF823EFFB18440FFB18441FFB18545FFB58949FFB78C4DFFB48B4DFF
+ B58C4EFFB48D4FFFB99156FFBC975BFFBF9A5EFFC09A60FFBF9861FFC09766FF
+ BA9061FFBC9265FFC69D70FFC9A276FFC19C70FFB49267FFAD8D64FFC2A580FF
+ D6BA97FFE2C7A5FFDBC2A2FFDEC6A8FFEED9BAFFF6E2C3FFF0DBBFFFF0DEC1FF
+ EFDEC3FFF5E2C7FFF8E4CBFFFCE7D1FFFDE8D3FFFDE6D6FFFCE5D5FFFEE7D7FF
+ FBE5D3FFFBE5D3FF492FCFFF462ECEFF442DCBFF412ACCFF3F27D3FF4027D5FF
+ 442AD4FF452CD4FF492CD5FF442EC2FF3C359DFF343A83FF2F3D78FF2E417AFF
+ 324485FF30468DFF2E4894FF3351A0FF3A5AA6FF3B5DA9FF4063ADFF476CB6FF
+ 4B72BCFF4C73BDFF436AB5FF4067B2FF3D61AFFF395DABFF3B59AAFF3755A8FF
+ 334EA4FF314B9FFF2F4694FF324995FF344C94FF354C90FF354885FF313F74FF
+ 2D3564FF2A2E57FF2C2B55FF34335DFF393C69FF3A3F6CFF393C68FF343960FF
+ 363958FF3C3C54FF433C4BFF382B43FF2C194AFF261451FF241454FF1F1355FF
+ 201357FF20145CFF1D1060FF3D2D92FF4833B8FF4C30ACFF4D2D74FF6F464BFF
+ B0762EFFBA7906FFC28107FFC18006FFBF7D06FFC1810BFFBE7E08FFB87D16FF
+ 9E6821FF5A2F08FF3C221BFF24171FFF1E171EFF201920FF201721FF261D27FF
+ 25212CFF1D1B27FF262332FF282534FF2A2737FF2A2737FF282535FF262333FF
+ 262333FF282535FF262333FF262333FF262333FF252232FF252232FF252232FF
+ 252231FF272132FF271E32FF292132FF24202BFF232029FF282128FF261C22FF
+ 2D1F25FF4D321EFF8F5E1AFFB77A18FFB67B0DFFB97C06FFC38208FFC28206FF
+ C1820AFFB67901FFBD8106FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBF8006FFC18006FFC17F08FFC37F08FFC17F08FFC17E09FFC17E09FF
+ BF7F09FFBF7E0BFFBD7E0BFFBC7F0BFFBD7F0DFFBD7F0DFFBC800FFFBC800FFF
+ BC800FFFBD8110FFC08111FFC0810FFFBF800EFFBE7F0CFFBE800AFFBF810BFF
+ C1840CFFC2850DFFBD8008FFBD8008FFBE8109FFC0800AFFC1800DFFC1800DFF
+ C2800FFFC2810EFFC1800DFFC1810BFFC1810BFFC1810BFFC1800DFFC1800DFF
+ C1800DFFBF800DFFC0810EFFBF800DFFBE7F0DFFBD7E0CFFBD7E0CFFBD7F0DFF
+ BE7F0FFFBD8110FFBB8110FFB98110FFBB8110FFBB8110FFBB820FFFBB820FFF
+ BB820FFFBB820FFFB9800DFFB9800DFFBA810EFFBA810EFFBB8110FFBC8310FF
+ BC8211FFBC8211FFBC8211FFB98110FFB98110FFB8800FFFB98110FFB98311FF
+ BA8412FFBB8513FFB88112FFB68112FFB68112FFB68112FFB68112FFB48212FF
+ B48212FFB88112FFC08315FFC78619FFC18013FFBC7B0EFFC2800FFFC38313FF
+ C38317FFC38727FFBD8C3CFFAC8749FFCCB28DFFF9EAD7FFFFF5EEFFF6F0F1FF
+ F9F2F5FFF5EEF1FFFCF3F6FFF3EDEEFFF6F1F2FFF9F7F6FFF0F2F2FFEEF0F0FF
+ F2F0EFFFF6EDE4FFE9D4BFFFC4A27EFFB78A51FFC28C45FFC18735FFC1852BFF
+ C08A2CFFB98324FFBA8124FFBD8225FFBE8326FFBD8427FFBD8429FFBC8328FF
+ BB8227FFB88126FFB88027FFB68127FFB58026FFB57F28FFB57F28FFB37E27FF
+ B37D28FFB37E27FFB27D23FFB27D22FFB27D23FFB27E24FFAF7F27FFAD7E28FF
+ AD7F2BFFAB7F2CFFA87F30FFA88234FFAA863AFFAE8B41FFB29148FFB7974EFF
+ B99B54FFBB9C57FFBF9C5CFFC3A061FFCAA569FFD1AB71FFD5AE77FFD6AE79FF
+ D4AC7BFFD3AB7AFFCDA574FFCDA672FFCEA672FF3E23C7FF3C24C6FF3D25C5FF
+ 3C24C8FF3A21CFFF3A20D1FF3C22CEFF3C22CCFF482BD5FF402ABEFF362F97FF
+ 2E337EFF2C3977FF2E407BFF354689FF344A92FF2F4996FF3351A0FF3959A5FF
+ 3A5CA8FF3F62ACFF456AB4FF486FB9FF486FB9FF3F66B1FF3C63AEFF395DABFF
+ 365AA8FF3755A8FF3452A5FF304BA1FF2F499DFF2F4694FF344994FF354B93FF
+ 364C8EFF344681FF303D71FF2D3360FF2B2D56FF2D2C56FF333460FF373B6BFF
+ 3A3E6EFF373C69FF343861FF36385AFF3C3B55FF433B4CFF382B43FF2A1A4AFF
+ 241352FF221454FF1F1355FF201357FF21145EFF1E0F63FF3A2990FF4931B7FF
+ 492BA2FF4F2D6AFF7A4D4AFFB2742DFFBD7908FFC3810AFFC18006FFBE7C05FF
+ C0800AFFBD7C09FFBC7F17FFAD7524FF714411FF3D2315FF22171AFF1E171CFF
+ 1F181FFF211822FF261D27FF24202BFF1C1B25FF252231FF282534FF2A2737FF
+ 2A2737FF282535FF262333FF272434FF282535FF262235FF262333FF262333FF
+ 262333FF252232FF252232FF252231FF262130FF261D31FF292132FF24202BFF
+ 221F28FF282128FF261C22FF2D1F25FF4D321EFF905F1BFFB97C1AFFB87D0FFF
+ BB7E08FFC38208FFC18105FFC08109FFB87C01FFBD8106FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBF8006FFC17F08FFC37F08FFC37E09FF
+ C37E09FFC17E09FFC17E09FFBF7E0BFFBD7E0BFFBC7F0BFFBA7E0CFFBB7F0DFF
+ B9800DFFBA800FFFB8800FFFBA7F11FFBC800FFFC38411FFC3830DFFC2830BFF
+ C1820AFFC08109FFC08107FFC18208FFC18208FFBF8006FFBF8006FFC08109FF
+ BE8109FFBF810BFFBF800DFFC0810FFFC0810EFFBF810BFFBF820AFFBF810BFF
+ BF810BFFBF810BFFBF810BFFBF810BFFBF810BFFBF820CFFBE810BFFBD800CFF
+ BC7F0BFFBC7F0BFFBD800CFFBC810DFFBD810FFFB98110FFB98110FFB98112FF
+ BB8110FFBB8110FFBB820FFFBB8110FFBB820FFFBA810EFFBA810EFFBA810EFF
+ BA810EFFBB820FFFBB820FFFBD810FFFBD810FFFBB8110FFBA800FFFBA800FFF
+ BA800FFFBA800FFFB98110FFBB8312FFBB8411FFB98110FFB8820FFFB8820FFF
+ B8820FFFB8820FFFB6830FFFB6830FFFB88210FFBD8214FFC58618FFC18111FF
+ BE7F0DFFC58411FFC38313FFBE8119FFB98429FFB28843FFB99B6AFFDBCAB0FF
+ F6EFE6FFF6F3F5FFF3F1F7FFF6F2F7FFF1ECEEFFF7F1F2FFF5F0EFFFF6F4F3FF
+ F6F7F5FFF2F4F4FFF7F8F4FFF7F5EDFFF2E8D6FFD8C1A1FFBD9969FFB98844FF
+ C28A38FFC48727FFC58820FFC78C1FFFBF8417FFC08216FFC38317FFC48418FF
+ C58519FFC38519FFC28418FFC18319FFC08218FFC08218FFC08218FFC08218FF
+ BF8117FFBF8117FFBE8016FFBC7F17FFBC8016FFC08113FFC08111FFBE8211FF
+ BD8214FFBC8415FFBB8316FFBB8318FFB8841AFFB48218FFB18118FFB0801AFF
+ AE801BFFAB7E1CFFA97F1CFFA87E1BFFA87D1CFFA5761AFFA9771DFFAD7B23FF
+ AF7C26FFB07B2AFFAD7A2AFFAB772AFFA87729FFAC782BFFAC782BFFAC7929FF
+ 3F23CAFF3F25CCFF4028CAFF4028CEFF3E25D3FF3C22D3FF3B21CBFF3920C8FF
+ 4427D0FF3C26BAFF332C94FF2D327DFF2D3979FF30427FFF36468BFF334893FF
+ 304A97FF3351A0FF3858A4FF385AA6FF3D60AAFF4267B1FF446BB5FF446BB5FF
+ 3C63ADFF385FAAFF365AA8FF3357A5FF3452A5FF314FA2FF2E499FFF2D479BFF
+ 304694FF354891FF364A91FF37498AFF35437DFF2F3A6CFF2D335EFF2B2D56FF
+ 302F59FF343462FF373B6CFF383D6EFF353B6AFF323863FF36385BFF3C3B55FF
+ 423A4BFF382B45FF271949FF211452FF221454FF1F1355FF221357FF231360FF
+ 1E1167FF36268BFF4A32AEFF45268FFF552F59FF875745FFB47426FFBF7A0BFF
+ C27F0AFFC28107FFBC7D05FFBF8008FFBD7D07FFC18115FFBC8026FF8C5D1FFF
+ 3E2711FF211717FF1C1518FF20181FFF211822FF251D27FF251F2AFF1E1A25FF
+ 242130FF272433FF292636FF292636FF272336FF262235FF272336FF282437FF
+ 272237FF272336FF272336FF262235FF262333FF252232FF252231FF262130FF
+ 261D31FF292132FF24202BFF221F28FF282128FF261C22FF2D1F25FF4E331FFF
+ 92611DFFBC7F1DFFBC8113FFBD800AFFC28107FFBF7F03FFC08109FFBA7E03FF
+ BD8106FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBF8006FF
+ C37F08FFC47E09FFC37E09FFC37E09FFC17E09FFC17E09FFBF7F09FFBD7F09FF
+ BC7F09FFBA7F0BFFBA7F0BFFB9800CFFB7810CFFB7820DFFB8820DFFBA820BFF
+ C3860EFFC6850BFFC5840AFFC38307FFC08206FFBF8105FFBF8105FFBF8105FF
+ BD8105FFBD8105FFBE8207FFBD8109FFBE810BFFBE810DFFBF810FFFBD820EFF
+ BC830AFFBA8408FFBA830AFFBA830AFFBA830AFFBA830AFFBA830AFFBA830AFF
+ BA830AFFBA830AFFB98209FFB98209FFB98209FFB98209FFBA830AFFBA820BFF
+ BB820FFFBB820FFFBB8110FFBD810FFFBD810FFFBD820EFFBD810FFFBD820EFF
+ BF820EFFBF820EFFC0810EFFBF800DFFBF810BFFBF810BFFBF810BFFBF810BFF
+ C1810BFFC27F0AFFC27F0AFFBF7F09FFC0800AFFC1810BFFC2820CFFC1840CFF
+ C0820CFFC0830BFFC0830BFFBF830BFFBF830BFFBF830BFFBF8409FFBD830CFF
+ BE8211FFC18416FFC08210FFC28310FFC68715FFBF8115FFB67C1CFFB08032FF
+ B18E56FFD1BB98FFF0E7DAFFF5F5F5FFF0F2FAFFF0F2FCFFF1F1F7FFEEEBEDFF
+ F6F2F1FFF7F4F0FFF5F6F4FFF1F3F3FFF2F5F3FFFBFBF5FFF2EDDEFFDED0B4FF
+ BFA478FFB28D51FFB58438FFBE862DFFBF8420FFC3881BFFC68A19FFBD810FFF
+ BF810FFFBF810FFFC08210FFC18311FFC18311FFC08210FFBF8010FFBF8010FF
+ BF8010FFBF8010FFBF810FFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBD7F0DFF
+ C2800FFFC2800FFFC0810FFFC08010FFC08111FFC08111FFC08111FFBF8312FF
+ BF8514FFBE8413FFBD8214FFBA8213FFB88011FFB67F10FFB57E0FFFB47D0EFF
+ B88011FFBA7F12FFB97F15FFB97F16FFB87D16FFB67B17FFB47915FFB17815FF
+ B97E1BFFB97E1AFFB97E1AFF4528D1FF442AD1FF452DCFFF442CD0FF4129D5FF
+ 3E25D3FF3E25CDFF3C24CAFF4327CEFF3D28BAFF363095FF323881FF323F7DFF
+ 324481FF334388FF2D428DFF314B98FF34529FFF3757A3FF375AA4FF3B5EA8FF
+ 4166B0FF4168B2FF4067B1FF3C63ADFF3960AAFF365AA6FF3357A5FF3553A4FF
+ 3250A3FF2F4AA0FF30489AFF314592FF364790FF36498DFF354685FF334078FF
+ 2F3969FF2E315DFF2D2F57FF34335DFF343764FF363B6CFF353C6EFF353A6BFF
+ 323863FF36385BFF3B3956FF43384CFF372A44FF241A49FF1F1551FF201553FF
+ 201554FF231458FF24155FFF201369FF332283FF4A319FFF472579FF5F3848FF
+ 97643CFFB5741FFFC27C0BFFC07D08FFC17F08FFBC7D05FFBF8008FFBD7D07FF
+ C08010FFC48622FF9E6E26FF422C10FF211814FF1D1516FF20191EFF211920FF
+ 241C26FF241E29FF1D1924FF23202FFF262332FF282535FF292636FF272336FF
+ 262235FF272237FF282338FF282338FF282338FF272237FF272336FF262333FF
+ 252232FF242130FF262130FF251C30FF282031FF231F2AFF221F28FF282128FF
+ 271D23FF2E2026FF4F3420FF93621EFFBE811FFFBF8416FFBE810BFFC28107FF
+ BE7E02FFC1820AFFBC7F07FFBD8106FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBF8006FFC37F08FFC37E09FFC37E09FFC37E09FFC17E09FF
+ C17E09FFBF7F09FFBD8008FFBB7F07FFB98007FFBA8108FFB88108FFB78209FF
+ B78209FFB8830AFFBA830AFFC2860BFFC3840AFFC28309FFC18307FFBE8206FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBC8106FFBD8207FFBB8209FFBC820BFF
+ BC810DFFBD810FFFBB820EFFBA820BFFBA830AFFBA830AFFBA830AFFBA830AFF
+ BA830AFFBA830AFFBA8408FFBC830AFFBA8408FFBB8209FFB98307FFBB8209FF
+ B98307FFBC8308FFBC830AFFBD820EFFBD820EFFBF810FFFBF820EFFBF820EFF
+ C0820CFFC0820CFFC0820CFFC2820CFFC2830BFFC4820BFFC3810AFFC28009FF
+ C28107FFC18006FFC18006FFC48009FFC37F08FFC27E07FFC27E07FFC37F08FF
+ C28009FFC3810AFFC4820BFFC4820BFFC2830BFFC28309FFC28309FFC28309FF
+ C08409FFC08409FFC0830BFFBF810FFFC18212FFC1820FFFC38411FFC68616FF
+ B87E15FFAE7922FFAC823FFFC4A77BFFE9D8C3FFFFFAF5FFF3F6FBFFEFF1FBFF
+ F1F4FCFFEFF2F6FFEFEFEFFFF9F6F2FFF7F6F2FFF3F3F3FFEDEFEFFFF2F3EFFF
+ FBF7ECFFE4D8C0FFBFA882FFAD8C54FFAD833CFFB4822FFFBA8425FFBC831AFF
+ C18618FFC38814FFBA7D07FFBE810DFFBE810DFFBF820EFFBF820EFFBF820EFF
+ BF820EFFBE810DFFBE810DFFBF800DFFBE810DFFBE810DFFBD800AFFBD800CFF
+ BC7F0BFFBC7F0BFFBD7E0BFFC1800DFFC1800DFFBF800DFFBF800DFFBF800DFF
+ BF810BFFC1810BFFBF820AFFBC7F07FFBD8008FFBD8008FFBD8008FFBE8109FF
+ BF8308FFBF820AFFBF820AFFC1820AFFC1820AFFBF810BFFBE810DFFBF810FFF
+ BE8210FFBE8211FFBC8211FFBE8211FFBE8211FFBE8211FF4326CFFF4127CEFF
+ 4129CBFF412ACCFF3F28D0FF3F28D1FF4129CDFF412BCAFF472DCDFF412EB9FF
+ 393595FF333980FF303E79FF30427DFF324287FF2D428DFF334D99FF3553A0FF
+ 3757A3FF375AA4FF3C5FA9FF4167AFFF4068B0FF3E66AEFF3F67AFFF3C63ADFF
+ 395DA9FF365AA8FF3856A7FF3452A3FF314DA1FF324A9CFF304491FF35478EFF
+ 37488BFF344381FF313D73FF2F3766FF2F335CFF313159FF353760FF363966FF
+ 363A6DFF323A6FFF32396AFF313764FF34375DFF3B3957FF43374DFF372945FF
+ 22194BFF1C1651FF201652FF221553FF251457FF24155FFF201466FF2F2179FF
+ 482F89FF4E2B63FF724738FFA4702EFFBB7815FFC47E09FFBF7A05FFC07E07FF
+ BC7D05FFC18208FFBE7F07FFBB7C09FFC38416FFA67422FF4A3410FF231D12FF
+ 1C1512FF1F181BFF211A1FFF221A24FF231D28FF1E1A25FF221F2EFF252231FF
+ 282535FF282535FF272336FF262136FF272138FF282239FF2A243BFF292439FF
+ 282338FF272336FF262333FF252232FF242130FF262130FF251C30FF282031FF
+ 231F2AFF221F28FF282128FF271D23FF2E2026FF4F3420FF94631FFFBF8220FF
+ BF8416FFBE810BFFC28107FFBE7E02FFC1820AFFBD8008FFBD8106FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBF8006FFC17F08FFC37F08FF
+ C37F08FFC17F08FFC17F08FFC17F08FFBF8008FFBD8106FFBC8005FFBB8005FF
+ BB8005FFBA8106FFBA8106FFBB8207FFB98306FFBB8207FFBD8109FFBD800AFF
+ BD8109FFBE820AFFBE820AFFBD8207FFBD8207FFBB8207FFBA8106FFBA8108FF
+ BB8209FFB9810AFFBA810DFFBA810EFFBB820FFFBB820FFFBE810DFFBF810BFF
+ BF810BFFBF810BFFBF810BFFBF810BFFBF810BFFBF820AFFC0800AFFBE8109FF
+ C1810BFFBF820AFFC1810BFFBF820AFFC08109FFBE8109FFBF810BFFBE810BFF
+ BF800DFFBF810BFFBF810BFFC1820AFFC1820AFFC18208FFC48309FFC48309FF
+ C58208FFC58207FFC48106FFC38005FFC48005FFC48005FFC37F08FFC17E09FF
+ C07D08FFC07D08FFC07D08FFBF7F09FFC1810BFFC1810BFFC2820CFFC0820CFF
+ C0810EFFC0810EFFC0810EFFBF820EFFBF820EFFBF820EFFC1820FFFC3820FFF
+ C4820BFFC5850FFFC38416FFB37919FFAE7D31FFB69159FFE4CBABFFFAEDDFFF
+ FFFBFAFFF2F2F8FFF0F3F8FFF1F5F6FFF1F4F2FFF5F6F2FFF9F8F4FFF4F5F3FF
+ F0F2F3FFEFF1F1FFF6F3EEFFF8EEDCFFD9C3A0FFAD8B56FFAD813AFFB3812EFF
+ B88426FFBA841FFFBA8217FFBD8516FFC08511FFB97C06FFBD820EFFBD820EFF
+ BD820EFFBD820EFFBD810FFFBD810FFFBD810FFFBD810FFFBF810FFFBD810FFF
+ BD810FFFBC810DFFBC800EFFBB7F0DFFBB7F0DFFBB800CFFBD800AFFBD8109FF
+ BD8109FFBD8109FFBD8207FFBD8207FFBE8206FFBE8305FFBD8204FFBD8302FF
+ BF8202FFBE8200FFBE8200FFBD8200FFBD8100FFBD8000FFBF8006FFBF8008FF
+ BC7E08FFBC7F09FFBD800CFFBC810DFFBB820FFFBA8310FFB87F0CFFB87F0BFF
+ BA7F0BFF4326CFFF4128CCFF422ACAFF422CCBFF422CD2FF432ED1FF4631CEFF
+ 4732CEFF472FCBFF4130B7FF383591FF2F377AFF2B3973FF2C3E79FF344588FF
+ 344A92FF354F9BFF3655A0FF3858A3FF385BA4FF3D60A9FF4369B1FF426AB2FF
+ 3E66AEFF4068B0FF3D65ADFF3A5FA9FF365AA6FF3756A5FF3351A2FF2F4B9FFF
+ 2F4898FF2E438EFF36458DFF364689FF34417FFF313B71FF303665FF33355EFF
+ 36365EFF393B64FF383A6AFF343A6FFF31396EFF32396BFF313764FF35385EFF
+ 3B3957FF42354DFF362746FF1F194AFF191550FF1E1750FF221652FF261558FF
+ 27165FFF1E1565FF2E2171FF432A74FF583655FF84582FFFAD781EFFBE7C0BFF
+ C37F04FFBD7902FFC07D08FFBB7C04FFC28309FFC08109FFBA7B03FFC1800DFF
+ A8771BFF523F14FF292213FF1E1511FF201819FF20191EFF211923FF221C27FF
+ 1F1B27FF231E2DFF242130FF272434FF282535FF262136FF262136FF272138FF
+ 282239FF2B253CFF2A243BFF292439FF282437FF272336FF252232FF242130FF
+ 262130FF241B2FFF271F30FF231F2AFF221F28FF282128FF281E24FF2F2127FF
+ 503521FF956420FFBE811FFFBC8113FFBC7F09FFC28107FFC08004FFC3840CFF
+ BD8008FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FF
+ BF8006FFC18006FFC18006FFC17F08FFC17F08FFC17F08FFC17F08FFBF8006FF
+ BF8006FFBD7F03FFBE8004FFBC8004FFBC8004FFBD8106FFBD8105FFBD8306FF
+ BD8207FFBB7E08FFBC7F0BFFBD800CFFBE810BFFBE820AFFBE820AFFBD8207FF
+ BD8207FFBA8106FFBA8108FFBB8209FFBB810AFFBC810DFFBC810DFFBD810FFF
+ BD810FFFBF800DFFBF800DFFBF800DFFBF800DFFC1800DFFC1800DFFC1810BFF
+ C1810BFFC0800AFFC0800AFFC3800BFFC1810BFFC3800BFFC3800BFFC28009FF
+ C0800AFFBE800AFFBD800AFFBD800CFFBD800AFFBE800AFFBE8109FFC08109FF
+ C08107FFC28107FFC28206FFC48106FFC48106FFC48106FFC48104FFC48104FF
+ C48005FFC18006FFBF8008FFBE7F07FFBE7F07FFBE7F07FFBE8109FFBF810BFF
+ C0820CFFC0810EFFBF820EFFBF810FFFBF810FFFBF810FFFBD810FFFBD810FFF
+ BF810FFFC4840EFFC4820BFFC3810AFFC58411FFBE8119FFB07B24FFB78D4CFF
+ CCAF83FFFCE7D2FFFFF4EEFFFBF6F8FFEFEFF5FFF1F3F4FFF0F5F4FFEFF5F0FF
+ F6FAF5FFF6F7F3FFEFF1F1FFF0F3F7FFF3F5F5FFF5EEE5FFECDAC3FFD1B083FF
+ AE8340FFB57F2AFFBB8121FFBD831CFFBC8419FFBB8215FFBD8312FFBF820CFF
+ BD8008FFC1840CFFC0830DFFC0820CFFBE810BFFBE810DFFBF820EFFC0830FFF
+ C0830FFFC0830FFFBE830FFFBD820EFFBD810FFFBC800EFFBA810EFFBC800FFF
+ BB7F0DFFBC820BFFBC830AFFBB8209FFBB8209FFBD8109FFBC8106FFBC8205FF
+ BC8204FFC18608FFC18706FFC18706FFC38705FFC38705FFC38803FFC38803FF
+ C28505FFC08004FFBD7E06FFBC7D05FFBA7D05FFB87C04FFB67D04FFB47C05FF
+ B47C05FFB37B04FFB37B04FFB57C03FF472BD2FF462ED0FF4731CDFF4631CDFF
+ 422DCFFF402CCBFF3F2BC4FF3D2ABFFF3620B5FF3627A7FF35338CFF303978FF
+ 2C3B73FF2D4178FF354689FF364C94FF37519DFF3756A1FF3959A4FF395CA5FF
+ 4063ACFF456CB1FF446DB2FF4069AEFF3D65ADFF3961A9FF365BA5FF3155A1FF
+ 3251A0FF2D4C9BFF294697FF294292FF2F428DFF35448CFF354587FF33417CFF
+ 303B6FFF313766FF363861FF3A3A62FF3C3D69FF393B6BFF343A6FFF2F396FFF
+ 2F376CFF313766FF35385EFF3A3856FF43344FFF362747FF1D194AFF17164EFF
+ 1E184FFF231751FF261656FF28185FFF1D1562FF2D226AFF3E2660FF63414CFF
+ 996B2BFFB57E0FFFC18105FFC47F00FFBD7B04FFBE7E08FFBA7B03FFC28309FF
+ C28309FFB97A00FFC18006FFAC7B19FF5C4818FF2D2615FF1E160FFF201818FF
+ 1E171CFF1F1721FF221C27FF201C28FF221D2CFF23202FFF262333FF272434FF
+ 262136FF262136FF272138FF28223BFF2B253EFF2B253CFF2A253AFF282437FF
+ 272336FF252232FF242130FF262130FF241B2FFF271F30FF221E29FF221F28FF
+ 282128FF281E24FF2F2127FF503521FF956420FFBC7F1DFFB97E10FFBA7D07FF
+ C28107FFC28206FFC4850DFFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8106FFBF8006FFBF8105FFBF8006FFBF8006FF
+ C18006FFC18006FFC18006FFC18006FFBF7E04FFBF7E04FFC07F05FFC07F05FF
+ C07E07FFC18006FFC18006FFBF8008FFBD7E0BFFBE7F0CFFBE7F0CFFBF810BFF
+ BF820AFFBE8109FFBC8005FFBB7F03FFBF8105FFBF8006FFC08107FFC08107FF
+ C1820AFFC1820AFFC2820CFFC2820CFFBE810DFFBE800EFFBE800EFFBE800EFF
+ BF800DFFBF800DFFBF800DFFBF800DFFBD7E0BFFBE7F0CFFC1810BFFC0820CFF
+ C2820CFFC1810BFFC0800AFFBD7F09FFBB7E0AFFB97E0AFFB97D0BFFB97E0AFF
+ BB7E0AFFBB7E08FFBC7E08FFBC7F07FFBF8008FFBF8006FFC18006FFC18006FF
+ C28107FFC48106FFC48106FFC28206FFC08305FFBD8204FFBD8105FFBD8105FF
+ BD8106FFBD8207FFBE820AFFBF830BFFBF820CFFBD830CFFBD820EFFBD810FFF
+ BD810FFFBB8110FFBB8110FFBF810FFFC4840EFFC4820BFFC3800BFFC28315FF
+ B98221FFAF8133FFC4A26DFFEAD2B4FFFFF1E5FFFCF4F5FFF7F3F8FFEFEFF5FF
+ F0F2F3FFEEF4F3FFEEF5F0FFF1F8F3FFEDF2F1FFEAEEEFFFF0F4F9FFF5F5F5FF
+ E7DBD1FFD0B59AFFC1955FFFB88031FFC2811FFFC48114FFC0810FFFC08210FF
+ BE8210FFBE810DFFC18208FFC78409FFC68308FFC38307FFC48106FFC18105FF
+ C18006FFC28107FFC1820AFFC2830BFFC0820CFFC0820CFFBF810BFFBE810DFF
+ BD800CFFBB800CFFBC7E0CFFBC7E0CFFBF810FFFBE800EFFBE800EFFBD800CFF
+ BD800CFFBC7F0BFFBC7F09FFBC7F09FFB97C06FFB97D05FFBA7E06FFBB7F04FF
+ BC8005FFBD8106FFBD8106FFC08107FFC7840AFFC7840AFFC7840AFFC48309FF
+ C18208FFBE8207FFBC8106FFBB8005FFBD8207FFBD8207FFBE8207FF4730C8FF
+ 4832C7FF4533C2FF4331C0FF3C2BBCFF3423B4FF2C1CA9FF2718A2FF200E9DFF
+ 2A1C99FF333485FF373F7BFF344277FF32437CFF344687FF334990FF39549EFF
+ 3858A1FF3B5BA4FF3C5EA4FF4165ABFF476EB3FF486FB4FF4169B1FF3C61ABFF
+ 375CA6FF3256A2FF2F519DFF2D4C9BFF294796FF234190FF253C8AFF31428BFF
+ 354489FF374587FF33417CFF2D3A6EFF2F3667FF343A65FF393C68FF393D6DFF
+ 373B6EFF323970FF30376EFF2F386AFF313764FF35385EFF3A3757FF41334FFF
+ 362648FF1F174CFF191451FF1E1652FF211654FF251759FF28195DFF23155DFF
+ 36245FFF472849FF764E3CFFA97822FFB98104FFC48303FFC17E00FFC17E04FF
+ C17F08FFB97A00FFC28309FFC3840AFFB97A00FFC18006FFB27E1AFF684F17FF
+ 362B10FF21180EFF1D1718FF1B171DFF1A1621FF221C27FF211D28FF201E2AFF
+ 23202FFF262333FF272434FF262235FF262136FF272138FF29233CFF2C263FFF
+ 2B253CFF2A253AFF292439FF272336FF252232FF242131FF262031FF231A2EFF
+ 281E2FFF241E29FF241F28FF292128FF2A1F22FF322321FF53381EFF956420FF
+ BA7E1EFFB97B0FFFB97A07FFC0800AFFC1810BFFC4840EFFBC7D0AFFBD7E0BFF
+ BD7E0BFFBD7E0BFFBD7F09FFBD7E0BFFBD7F09FFBD7F09FFBD7F09FFBD7F09FF
+ BD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBD8008FFBF8006FF
+ C18105FFC18006FFC18006FFC18006FFC18006FFC38006FFC38006FFC17E04FF
+ C17E04FFC17D06FFC27E07FFC27E07FFC37F08FFC37F08FFC17F08FFBF810BFF
+ BE810DFFC0810EFFBF800DFFC07F0CFFBE7E08FFBC7D05FFBB7C02FFBF8105FF
+ BF8105FFC08107FFC08107FFC3810AFFC3810AFFC4820BFFC2820CFFBE810DFF
+ BC800EFFBE800EFFBE800EFFBE810DFFBE810DFFBE810DFFBE810BFFBD7F09FF
+ BE800AFFBF810BFFC0830BFFC0820CFFBF810BFFBE800AFFBD7E0BFFB87C0AFF
+ B67C0BFFB87C0BFFB87C0BFFB87C0AFFBA7C0AFFBA7D09FFBA7D09FFBC7D0AFF
+ BC7E08FFBE7E08FFBF8008FFC28009FFC28009FFC3810AFFC18208FFC08305FF
+ BE8305FFBD8204FFBD8204FFBE8305FFBE8407FFC08408FFC0850AFFBF830BFF
+ BF820CFFBF820EFFBF810FFFBD8110FFBD8012FFBD8012FFC08010FFC8830EFF
+ C6810CFFC17F0FFFBD821BFFB4812BFFAE8645FFCAB187FFF9EBD5FFF7F1ECFF
+ F4F3F7FFF6F4FAFFF1F1F7FFF0F2F3FFEFF4F3FFECF4F3FFEBF3F2FFE6EEEEFF
+ E8ECEDFFF4F6F7FFFAF1EDFFDBC7B5FFBA9670FFB2803EFFB97D24FFC58418FF
+ C3800BFFBD7D07FFBE800AFFBF820EFFBC7F09FFC28206FFCA880BFFC58207FF
+ C48106FFC27F04FFC17E03FFBF7F03FFC07F05FFC28107FFC18208FFC08109FF
+ C08109FFBE800AFFBD7F09FFBC7F09FFBB7E0AFFBB7E0AFFBB7E0AFFBF810FFF
+ BF810FFFBE800EFFBE800EFFBD800CFFBD800CFFBC7F0BFFBC7F0BFFBD800CFF
+ BD800AFFBC7F0BFFBB7E08FFBA7D07FFB97C06FFB87B05FFB97C04FFC17D06FF
+ C17E04FFC27F05FFC18006FFBF8006FFBE8004FFBB7F04FFBA7E02FFBC8005FF
+ BC8004FFBE7F05FF3E30AEFF382AA7FF30219AFF27198FFF1E1288FF180F84FF
+ 170D85FF170D89FF26189CFF31269AFF343482FF333A73FF333E78FF313F7AFF
+ 304386FF375096FF334F96FF38589FFF3B5BA2FF395BA1FF4163A9FF4B6FB5FF
+ 4C6FB8FF4267B1FF3455A4FF3354A4FF3250A3FF304D9EFF2C4A99FF2A4595FF
+ 274390FF2A418CFF37468BFF374385FF323F7DFF2F3D77FF2E3E73FF303E72FF
+ 303E6FFF2F3D6EFF364175FF333D73FF323970FF30386DFF343A69FF343A63FF
+ 36395FFF393858FF3F334FFF37244BFF271552FF22115AFF21165CFF21165CFF
+ 22175DFF2B195EFF321759FF431F49FF683E39FF96642FFFB27E13FFB77D00FF
+ B87800FFC07D03FFC27F05FFC27F04FFC07F05FFBE7F05FFC08004FFBE7F05FF
+ BE7D0AFFB37A17FF8E6625FF4D330EFF221507FF191618FF161822FF161A25FF
+ 1F1E27FF222026FF1F1E28FF211F2BFF23202FFF252232FF272336FF282338FF
+ 292439FF29233AFF282239FF282239FF282338FF282338FF272336FF262235FF
+ 242033FF251F32FF241B2FFF241A2BFF261C28FF291E26FF271D23FF2A1E1CFF
+ 3A2A1AFF573A15FF9A6923FFAE7316FFBB7912FFC07E0EFFBC7B0EFFBA790CFF
+ BA790CFFBB7A0DFFBA7B0DFFBA7B0DFFBA7B0DFFBA7B0BFFBA7B0DFFBA7B0BFF
+ BA7B0BFFBA7B0BFFB97A0AFFB97A0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBE7F0CFFC07E07FFC27F05FFC27E07FFC17D06FFC17D06FFC17D06FF
+ C27D04FFC17E04FFC38006FFC27F05FFC27F05FFC27F05FFC27F05FFC27F05FF
+ C17E04FFBD7E04FFBA8205FFB88206FFBB800CFFBE7F0FFFBF7E11FFBE7E0EFF
+ C07F0CFFC08109FFBF8006FFBD8106FFBD8008FFBD8008FFBD7F09FFBD7F09FF
+ BD8008FFBD8008FFBA7C0AFFBB7C0CFFBC7E0CFFBC7E0CFFBC7F0BFFBB7E08FF
+ BB7D07FFBA7D05FFC1840CFFBF820AFFBD8008FFBB7F04FFB97D05FFBA7E06FF
+ BB7F07FFBC7F0BFFC18214FFBD7F13FFBC7C10FFB9790DFFB8790BFFBA790CFF
+ BB7A0DFFBC7C0CFFBC7A0AFFBD7B0BFFBD7B0BFFBE7C0BFFC17D0CFFC27E0DFF
+ C27E0DFFC0800AFFBE7F05FFBD8204FFC18406FFC28507FFC38608FFC18608FF
+ C38608FFC18509FFBF8308FFBD8008FFBC7E08FFBD7E0CFFC38013FFC48015FF
+ C37F16FFC37D12FFCD8412FFC77D0DFFC6811AFFC1852CFFB78640FFC4A371FF
+ E7D8B8FFFFFAEBFFF5F9F4FFF1F6F9FFF4F4FAFFF3F3F9FFF4F3F7FFF0F1F5FF
+ EDF2F5FFEAF1F4FFE2ECECFFE7EDECFFFEF8F3FFFFEFE0FFDFBE9DFFBC8D59FF
+ B47F2FFFBA7F1CFFBE8211FFC0830DFFBF820CFFBE810DFFBD800CFFBC7F09FF
+ BE8004FFC08004FFBF8006FFBF8006FFBF8006FFBF8006FFBF8006FFBF8008FF
+ BF8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD7F09FF
+ BD7F09FFBD7F09FFBB7D07FFBC7E08FFBC7E08FFBD7F09FFBE800AFFBE800AFF
+ BF810BFFBF810BFFBD7F09FFBD8008FFBD7F09FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBC7D05FFBE7F07FFC1820AFFC08109FFBC7F07FFBC8005FF
+ BE8109FFC1850AFFBC7F07FFBC8005FFBC7F07FF180B85FF160983FF17077DFF
+ 17077CFF180B7EFF1D1385FF22198EFF261D96FF3C2EB1FF3E33A7FF363682FF
+ 323972FF373F7AFF364381FF334689FF365093FF334F96FF37579EFF3B5BA2FF
+ 3B5EA2FF4365ABFF4E70B6FF4B6EB8FF4163AFFF3B5CACFF3A58ABFF3651A7FF
+ 334DA1FF2E499AFF2C4693FF2A4490FF2F458DFF39498CFF384484FF323F7DFF
+ 2E3E79FF2F4078FF304179FF304179FF2E3F77FF324179FF323D76FF303A70FF
+ 32396BFF343A67FF373B64FF373B5EFF3A3A58FF40334DFF382447FF2B1550FF
+ 25115AFF23145EFF21165EFF23185EFF2D1C5BFF3B1B51FF572D44FF825236FF
+ A77229FFB7810FFFB57E00FFB67903FFBE7F0DFFC1800DFFC1800DFFBE800EFF
+ BE800EFFBD7F0DFFBD7E0EFFBD7C13FFB2791EFF926521FF57370CFF28180BFF
+ 1A161BFF141725FF131926FF1B1E23FF1F1D23FF1F1E28FF201E2AFF23202FFF
+ 252231FF272336FF282437FF292439FF292439FF282239FF282239FF282338FF
+ 282338FF272336FF262235FF242033FF251F32FF241C2DFF251A2AFF281C28FF
+ 291E26FF271D23FF2A1E1CFF3C2A19FF573A15FF885B1EFF9C6314FFA8690FFF
+ AB6B0DFFA5670DFFA3640CFFA2640AFFA3650BFFA5670DFFA3670DFFA5680BFF
+ A3680BFFA5680BFFA3680BFFA5680AFFA3690AFFA76A0CFFA66C0DFFA96D0DFF
+ A96F0FFFAD7111FFAC7212FFAF7313FFB17511FFBC7C10FFBD7D0DFFBD7D0DFF
+ BF7D0DFFBF7D0CFFBF7D0CFFBF7E0BFFBF7F09FFC17E09FFC07D08FFC07E07FF
+ C07E07FFC07E07FFC17E04FFC17E04FFBD7E04FFB78001FFB38002FFB57C08FF
+ B87C0BFFBC7B0EFFC07E0EFFC1800DFFC4820BFFBF8105FFBF8105FFBD8008FF
+ BD7F09FFBD7F09FFBD7F09FFBD8106FFBC8106FFBE810DFFBE810DFFBE810DFF
+ BE810BFFBF820CFFBF830BFFC0830BFFC0830BFFBC7E08FFBD800AFFBF820EFF
+ BE8210FFBB8110FFB87D0FFFB1780BFFAF750CFFAC7010FFA86D10FFA76A0DFF
+ A5680AFFA46709FFA46709FFA6680AFFA76A0AFFA56808FFA56808FFA9690AFF
+ AB6C0AFFAE6F0DFFB0710FFFB47311FFB4740EFFB97C0EFFBA7F0BFFBD800CFF
+ BE810BFFBF830BFFBE820AFFBF820AFFBE8109FFBF820AFFBD7F09FFBC7E08FF
+ BF7E0BFFC28010FFC68114FFC57F14FFC67E12FFCC8010FFCA8115FFC27F22FF
+ B88033FFBA915AFFD4BA95FFEDE5CEFFF5F6ECFFF3FAF7FFF0F8F8FFF4F5F9FF
+ F5F4F8FFF6F2F7FFF4F3F7FFF0F3F7FFEDF4F7FFEAF1F4FFF2F5F3FFFFF6EAFF
+ F9E1C5FFDAB282FFBB8A46FFB57D24FFBB8118FFBE8210FFBE840DFFBD820EFF
+ BC810DFFBD800CFFBC7F09FFBE7F05FFBE8004FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBB7E06FFBD8008FFBF820AFF
+ BE8109FFBC7F07FFBC7F07FFBD8008FFBF820AFFBC7F07FFBC7F07FFBC7F07FF
+ 2A17A4FF2916A1FF2B149EFF2D179FFF2F1DA0FF3525A8FF3B2DB1FF4032B9FF
+ 4131BBFF4236AEFF3B3887FF353973FF38407BFF374482FF334788FF354F92FF
+ 314F96FF36569DFF3B5BA2FF3D5FA5FF4668AEFF4C70B6FF486BB5FF3C5EAAFF
+ 4463B2FF3F5DAEFF3A56AAFF3550A1FF314A9AFF2F4694FF2E4791FF30468DFF
+ 39498CFF364282FF303D7BFF2D3D78FF32427DFF344780FF33467FFF33447CFF
+ 324179FF313F74FF303B6FFF32396AFF353B68FF373C63FF383B61FF3D3B59FF
+ 403448FF3A2742FF2B184BFF251555FF22175BFF22195CFF261B59FF342154FF
+ 432445FF683F44FF90613BFFA8762AFFAD7B11FFAB7903FFAB780AFFB27B13FF
+ B27713FFB17613FFAF7515FFAE7414FFAF7411FFAF7313FFAE7114FFA56E1DFF
+ 8A5E23FF573713FF2A1C10FF1C181DFF171826FF151827FF1A1922FF1C1A20FF
+ 1F1E28FF201E2AFF221F2EFF252231FF272336FF282437FF282338FF282338FF
+ 282239FF282239FF282338FF282338FF272336FF262235FF242033FF251F30FF
+ 261C2CFF251B28FF281D27FF291E26FF241C26FF261D20FF372721FF503520FF
+ 72481EFF824C15FF8B5012FF8B5110FF854C14FF814912FF804713FF804811FF
+ 844D14FF824E12FF844E12FF824E12FF844E11FF824F11FF844E11FF824F11FF
+ 824D0EFF814E0FFF855011FF855213FF895513FF895715FF8D5917FF8F5C13FF
+ A16C12FFA66F0EFFA7700DFFAB720FFFAF7410FFB17710FFB47A11FFB77C0FFF
+ B97C0EFFBB7C0CFFBD7E0CFFBD7E0BFFBF7F09FFC17F08FFC17F08FFC08107FF
+ BB8005FFB98005FFB97C06FFBA7B08FFBC7B08FFC07E07FFC48106FFC58306FF
+ C38104FFC38005FFC17F08FFC17E09FFBF7F09FFBF8006FFBF8204FFBD8204FF
+ BE8308FFBC830AFFBE820AFFBE8308FFC08409FFC1840CFFC4850DFFC28310FF
+ BA7C0AFFB97B0FFFB57B12FFB37815FFAB7314FFA36B12FF9B640FFF956010FF
+ 8B5710FF865511FF86520FFF84500DFF834F0CFF83500AFF85510BFF86520CFF
+ 87530DFF88540DFF8B550EFF8D5710FF8F5912FF915C13FF955E15FF986011FF
+ A76E13FFAA710EFFAD7510FFB17710FFB37A11FFB57B11FFB77C0EFFB97D0CFF
+ BD810FFFBE810DFFBD800CFFBF810BFFC2820CFFC2820CFFC1800DFFC27F0CFF
+ C67F0DFFC8841BFFB97E28FFB28240FFCAA97CFFEEDBC0FFF9F3E6FFF1F3EDFF
+ F6F9F7FFF5F7F7FFF8F5F7FFF9F4F6FFF8F3F5FFF5F4F6FFF2F6F7FFF2F7FAFF
+ F2F2F8FFFCF5F2FFF3E5CFFFD9C096FFC19B5BFFB2832FFFB37C1BFFBC8114FF
+ BF8010FFBF820EFFBE810DFFBD800AFFBD800AFFBC8008FFBE7F07FFBE7F07FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BF820AFFBF820AFFBE8109FFBE8109FFBD8008FFBC7F07FFBB7E06FFBB7E06FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBE8109FFBF820AFFBE8109FFBC7F07FFBC7F07FFBC7F07FFBE8109FF
+ BC7F07FFBC7F07FFBC7F07FF452DC7FF432BC5FF4229C1FF4027BDFF3F27BBFF
+ 3D28BAFF3D2BBAFF3D2CBDFF321FB2FF3A2CA9FF3B3888FF373B75FF373F7BFF
+ 33407EFF304485FF344E91FF314E98FF34559EFF3A5BA4FF4062A8FF476BB1FF
+ 4C70B6FF4467B1FF3759A5FF4160AFFF3F5CADFF3C57A8FF3850A2FF344B99FF
+ 314893FF2E468EFF31468AFF364688FF31407EFF2A3977FF2A3C79FF324481FF
+ 384A87FF374984FF344780FF32437CFF324075FF303B6DFF323A69FF343B66FF
+ 373C63FF3A3C5FFF403B5AFF433345FF3B263FFF2B1948FF261754FF23185CFF
+ 241A5CFF2C1D56FF3A254CFF502E3FFF73483FFF916236FF9C6923FF9A680EFF
+ 996A08FF98690DFF996911FF96620FFF956010FF955F12FF935D10FF945C0DFF
+ 935B0CFF945A0EFF8C5714FF7D521FFF543718FF2E1F16FF1E1A1FFF191A28FF
+ 181828FF1A1923FF1C1922FF1E1C28FF201E2AFF221F2EFF242130FF262235FF
+ 272336FF282338FF282338FF282239FF282239FF282338FF282338FF272336FF
+ 262235FF242033FF251F30FF261D2AFF251B27FF281D25FF271F26FF241C26FF
+ 241C23FF332526FF4B3425FF623C1CFF6F3F15FF754112FF754113FF6F3E18FF
+ 6A3C1AFF6B3A1AFF6A3A18FF6E4017FF704016FF704016FF704016FF704115FF
+ 704115FF704115FF704115FF6C3E0FFF6D3F10FF6E4011FF6F4112FF714313FF
+ 724414FF734515FF764910FF80520BFF865608FF8A5909FF8E5E0CFF96620FFF
+ 9C6611FFA06A13FFA46D12FFAC7213FFAE7310FFB0750EFFB4770FFFB87A10FF
+ BB7B0FFFBD7C0FFFBD7E0EFFBF810FFFBC810DFFBD7F0DFFBC7F0BFFBE7E08FF
+ C07F05FFC17F02FFC18000FFC48102FFC48005FFC37F08FFC37E09FFC37F08FF
+ C18006FFC18202FFBF8202FFBA8003FFBB8104FFBC8106FFBE8308FFBE820AFF
+ BD800CFFBC7E0CFFB97C0EFFB67812FFAE7212FFA2680FFF955F0CFF8D560BFF
+ 85510BFF814F0DFF7D4E11FF764713FF734515FF714313FF704310FF6F420FFF
+ 71420FFF724310FF734410FF784915FF794915FF7A4A16FF7A4B15FF7C4A15FF
+ 7C4A15FF7C4A15FF7F4D11FF8C570EFF905B0AFF945F0EFF9B6510FFA16B14FF
+ A77015FFAB7314FFB07511FFB67B14FFB97E11FFBA7F11FFBE8210FFC0830FFF
+ C0820CFFBD8008FFBB7D07FFC28010FFBE811FFFB07E32FFB9935DFFDFC7A9FF
+ FCF1E3FFFBF8F3FFF1F3F3FFF6F6F6FFF7F5F5FFF8F2F3FFF7F1F2FFF7F2F3FF
+ F4F4F4FFF1F7F6FFF3F7F8FFF9F2F7FFF9E9E3FFD9C4A4FFB5985FFFAA8432FF
+ B07F1DFFB47C11FFBE7F0FFFBF7F0FFFBF800EFFBD800CFFBD8109FFBC8008FF
+ BC8008FFBC7E08FFBE7E08FFBD7F09FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BD8008FFBC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBF820AFFBF820AFFBE8109FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF3E25C9FF4126CAFF
+ 4325CAFF4326C9FF4327C7FF3F27C3FF3C27C0FF3925BEFF311CB4FF3927A8FF
+ 383585FF343872FF353D79FF323F7DFF324386FF344D93FF304D98FF34549FFF
+ 3C5DA6FF4265AEFF496DB3FF496DB3FF4262ADFF3656A2FF3A58A7FF3957A6FF
+ 3B54A4FF3A51A1FF364D99FF324890FF2F438AFF2F4285FF314281FF2C3B79FF
+ 283775FF2A3B7AFF334385FF384A8BFF374988FF354784FF33447DFF314176FF
+ 303B6DFF313A66FF343A63FF363C61FF393B5EFF3E3958FF423047FF3A2440FF
+ 2B1849FF271856FF271960FF2A1C5EFF331F54FF422748FF5C363CFF744634FF
+ 845228FF845216FF82510DFF83560DFF7F5510FF7B500DFF7B4D0DFF7A4B0EFF
+ 7A4911FF78470FFF79470DFF7A460AFF7C460AFF75430EFF71471DFF53361BFF
+ 312219FF1F191EFF1A1A28FF1A1A2AFF1C1928FF1E1A26FF1E1C28FF1F1D29FF
+ 211E2DFF242130FF262235FF272336FF272237FF272237FF282239FF282239FF
+ 282338FF282338FF272336FF262235FF242033FF251F30FF241D2AFF251C26FF
+ 281E24FF272025FF221D26FF231C23FF302626FF473328FF5C3A1DFF683C17FF
+ 6B3D14FF6C3D17FF663C1FFF633B22FF643A23FF633B1FFF683E1BFF6A3F18FF
+ 6A4016FF6A4016FF6A4016FF6A4016FF6A4015FF6A4015FF6C4217FF6C4217FF
+ 6C4316FF6C4316FF6D4417FF6D4417FF6D4515FF6E4514FF6D420FFF70440EFF
+ 74470EFF774B10FF7D4E11FF825212FF885412FF8A5610FF935C13FF965E11FF
+ 9B6010FF9F6311FFA46711FFA96A12FFAC6D13FFAD6F11FFB37713FFB47A11FF
+ B77B11FFB97E10FFBD800CFFBD8106FFBE8103FFC08101FFC38104FFC38006FF
+ C47E09FFC37E09FFC37F08FFC38006FFC18202FFBF8301FFBA7F01FFBB8104FF
+ BE8308FFBF820CFFBC800EFFB67B0EFFB0750EFFAC7010FFA26A11FF996211FF
+ 8C570EFF7E4C0AFF77450BFF72420EFF734313FF714418FF6E4219FF6D421BFF
+ 6C411AFF6B4019FF6B4019FF6C4017FF6C4017FF6C4017FF70441BFF72451AFF
+ 72451AFF72451AFF74441AFF744519FF744519FF764616FF76450DFF7A490BFF
+ 7E4D0FFF855311FF8C5815FF915D16FF976114FF9B6311FFA0680FFFA66E0FFF
+ B17612FFB77D13FFBB8013FFBD8110FFBE810DFFBB7F0DFFBD8117FFB37E24FF
+ AF8647FFCBB189FFEFE2D2FFF9F5F4FFF2F3F7FFF5F6FAFFF7F2F3FFF7F2F1FF
+ FAF0F0FFF7EFEFFFF4EFF0FFF1F1F1FFEDF4F1FFF3F4F2FFFFF3F4FFF4D9CBFF
+ C5A679FFA17E34FFA47C16FFB3820EFFBA7F0BFFBD7E0BFFC07E0EFFC07E0EFF
+ BD7E0BFFBC8008FFBC8008FFBC8008FFBC7D0BFFBC7D0BFFBD7F09FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBF820AFFBF820AFF
+ BE8109FFBD8008FFBD8008FFBD8008FFBC7F07FFBB7E06FFBC7F07FFBC7F07FF
+ BC7F07FF3A21C5FF3C22C9FF4225CEFF482AD1FF482CD3FF472FD1FF4630CFFF
+ 4530CCFF432EC7FF412FB0FF353282FF30346EFF353D78FF374383FF344489FF
+ 334B93FF304D98FF34549FFF3C5FA9FF4467B0FF486CB2FF4569AFFF3E5FA8FF
+ 3756A1FF3654A1FF3853A3FF3B52A2FF39509CFF364B96FF32468DFF2E4184FF
+ 2C3E7DFF2B3D7AFF283A75FF273877FF2B3D7EFF344588FF374A8EFF38498CFF
+ 354788FF334580FF324277FF303C6CFF303964FF323960FF35395CFF37385AFF
+ 3D3756FF3E2E46FF372242FF29184BFF271757FF2A1A61FF301D5CFF3E234FFF
+ 4C2B40FF633934FF714227FF76431BFF73400EFF70400CFF714510FF6D4511FF
+ 683F0EFF6D4211FF6D4014FF6B3F16FF6A3E15FF6D3C14FF6E3C12FF6F3D0FFF
+ 6C3C12FF663E1BFF55371EFF36251CFF201A1BFF1C1A26FF1C1B2BFF1D1A29FF
+ 201B2AFF1D1B27FF1F1D29FF211E2DFF23202FFF252134FF272336FF272237FF
+ 272237FF282239FF282239FF282338FF282338FF272336FF262235FF242033FF
+ 251F30FF241E29FF241D24FF261F24FF272025FF221E24FF231D22FF302724FF
+ 453427FF5D3D20FF653E18FF6A3E15FF6B3F1AFF673F22FF654026FF663E25FF
+ 663E22FF6B401FFF6D411CFF6D421BFF6D421BFF6D421BFF6D421BFF6D421BFF
+ 6D4319FF6C4218FF6C4218FF6C4218FF6C4217FF6B4116FF6B4116FF6B4116FF
+ 6B4116FF6E431CFF6E431CFF6F431AFF6E4318FF704317FF724415FF754414FF
+ 774511FF794510FF7E470EFF814A0DFF854C0EFF8A500FFF8F5311FF915611FF
+ 93590EFF9B610FFF9E660DFFA36A0DFFAA710EFFB0780DFFB57D0CFFBB810AFF
+ BE8308FFBF8006FFC17F08FFC37E09FFC37E09FFC37F08FFC18006FFC18202FF
+ BF8202FFC08206FFBF820AFFBF820EFFBC7F11FFB47912FFAB7111FFA16910FF
+ 986312FF88550CFF83510FFF7C4C12FF764713FF734516FF714419FF70441BFF
+ 71441EFF6F431EFF6E411FFF6E411FFF6E411FFF6E421DFF6E421DFF6F421DFF
+ 6F421DFF6C3F19FF6D401AFF70411BFF71421CFF75441CFF76451DFF77461EFF
+ 78481EFF6F4014FF704213FF734515FF774815FF7A4A16FF7D4C14FF814E10FF
+ 844F0CFF895209FF91590AFF9C630DFFA66D10FFAE7414FFB47915FFB97F16FF
+ BA8019FFB47D1CFFB38335FFC2A16FFFE6D3B8FFF9F3EEFFF0F2FAFFEBEDF5FF
+ F5F5FBFFF4EFF0FFF7EFEFFFF9EFEFFFF7EFEFFFF2F0F0FFEEF0F0FFEBF1ECFF
+ F4F1E9FFFFECE5FFEBC3AAFFB89357FFA27A21FFAD800DFFB98608FFBD8106FF
+ C07D08FFC17C0DFFBF7D0DFFBD7F09FFBC8008FFBC8106FFBB7F07FFBC7D0BFF
+ BC7C0CFFBD7F09FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBB7E06FFBB7E06FFBC7F07FFBD8008FFBE8109FFBE8109FFBF820AFF
+ BF820AFFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBF820AFFBE8109FFBC7F07FFBD8008FFBE8109FFBE8109FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FF331EBBFF351DBDFF391EC1FF3C21C5FF
+ 3F24C8FF4028CAFF412BCAFF422DC9FF4833CCFF4533B4FF3A3485FF33356FFF
+ 383E79FF3A4484FF35438BFF344994FF2E4D98FF3356A0FF3E61ABFF4669B2FF
+ 496BB1FF4365ABFF3D5DA6FF3857A2FF3A56A3FF3B55A2FF3B519FFF394E99FF
+ 374891FF334388FF2E3E80FF2B3D7AFF293B76FF283C76FF2A3C7BFF2F4285FF
+ 35478EFF374A93FF384A91FF35488BFF344683FF334378FF303D6BFF2F3961FF
+ 31375CFF343658FF363557FF3A3453FF3A2C48FF332146FF29164DFF291858FF
+ 301B5FFF382056FF472746FF563036FF653928FF6E3D1DFF6E3D17FF6C3B13FF
+ 693A14FF683C17FF673D1AFF663C19FF6A3E19FF6A3D1BFF683C1DFF673B1EFF
+ 693A1EFF6A3B1CFF6E3B1AFF6A3C1AFF623B1BFF583A21FF3B2A1DFF231A17FF
+ 1E1922FF1D1B27FF1B1827FF1E1B2AFF1D1B27FF1E1C28FF211E2DFF23202FFF
+ 252134FF262235FF272237FF272237FF282239FF282239FF282338FF282338FF
+ 272336FF262235FF242033FF232030FF221E2AFF221D26FF251F24FF272023FF
+ 221E23FF231E1FFF322821FF473524FF604120FF694216FF6C4011FF6D4014FF
+ 6A401BFF69411EFF6A401DFF6B3E1CFF6E411CFF6E411CFF6E411CFF6E411CFF
+ 6E411CFF6E411BFF6E411BFF6E411BFF693C16FF693D14FF693D14FF6A3E15FF
+ 6A3E15FF6A3F14FF6A3F14FF6A3E15FF704321FF6F4221FF6E4120FF6E3F1FFF
+ 6D3F1DFF6D3D19FF6C3D17FF6E3D17FF6F3C14FF703E14FF723F14FF734113FF
+ 764213FF774314FF784513FF7A4611FF834E0FFF85510BFF895509FF8E5C0AFF
+ 97650BFFA26F0EFFAD790FFFB57E0FFFBA7E0CFFBD7E0BFFBF7F09FFC17E09FF
+ C17F08FFBF8006FFBD8105FFBD8106FFC1800DFFBD7C0FFFB97710FFAD7010FF
+ A16610FF945F0FFF895610FF805113FF754711FF724716FF704619FF6F451AFF
+ 6F451BFF6F451BFF70441BFF70441BFF6E411BFF6F421CFF6F431AFF6F431AFF
+ 6F431AFF6F431AFF714419FF714419FF704016FF704016FF714216FF724317FF
+ 764519FF77461AFF78471BFF76461CFF6D4118FF6D421BFF6E431CFF70441BFF
+ 72451AFF744519FF764515FF784612FF7C460FFF814B0EFF89520FFF8F580FFF
+ 965E0FFF9E6614FFA9701AFFAD7720FFA57321FFBB914EFFE0C69EFFFCF0DEFF
+ F8F7F9FFEBEFFAFFEBEEF6FFF1F2F6FFF4F0EFFFF8F1EEFFF7F1F2FFF5F2F4FF
+ F2F1F3FFEEF0F0FFEEF0EAFFF9F0E2FFF5D0BCFFD2A278FFAE8137FFAD8019FF
+ B9860AFFBD8500FFC18104FFC48009FFC27C0BFFC07B0CFFBE7E08FFBC7F07FF
+ BB8005FFBB7F07FFBC7D0BFFBC7D0BFFBD7F09FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBE8109FFBE8109FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBE8109FFBC7F07FFBB7E06FFBC7F07FF
+ BE8109FFBF820AFFBE8109FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF2E1BB2FF
+ 2D19B2FF2E17B5FF3116B9FF3419BCFF361EC0FF3923C2FF3C27C3FF3C27C0FF
+ 4230B1FF3E3889FF393B75FF393F7AFF364080FF324088FF334893FF2F4C97FF
+ 3356A0FF4263ACFF496BB1FF4769AFFF4062A8FF3B5BA4FF3B58A2FF415BA7FF
+ 4058A4FF3E529FFF3A4D98FF37468EFF324285FF2F3E7DFF2D3D78FF273B75FF
+ 273C79FF2C4081FF31458CFF364994FF374C97FF364B96FF364A91FF344685FF
+ 314378FF2E3D6BFF303860FF323659FF343655FF363452FF383251FF362C4AFF
+ 2F2046FF27174DFF2D1856FF372057FF40254CFF4F2D38FF5D3529FF65381DFF
+ 6C3C18FF6E3F19FF6C3F1AFF673D1AFF643B1BFF663B20FF6A3F24FF683C1DFF
+ 683C1DFF663A22FF663A23FF683923FF6A3A22FF6B3C1DFF6A3D1CFF633C1CFF
+ 5D3F24FF412D1CFF251913FF1F1A1CFF1B1A24FF1A1726FF1D1A29FF1D1B27FF
+ 1E1C28FF211E2DFF23202FFF252134FF262235FF262136FF262136FF282239FF
+ 282239FF282338FF282338FF272336FF262235FF242033FF232030FF201D2CFF
+ 201C27FF251F24FF262123FF241F21FF241F1EFF332820FF493523FF634320FF
+ 6B4116FF6D3F10FF6D3F10FF6B3E18FF6B3F1AFF6C3D17FF693A14FF6E3E1AFF
+ 6C3E1CFF6C3E1CFF6C3E1CFF6C3E1CFF6C3F1AFF6C3F1AFF6C3F1AFF6B3E19FF
+ 6C3F19FF6C3F19FF6D401AFF6E411BFF6F431AFF70441BFF70431DFF6C3E1CFF
+ 6C3D1DFF6C3D1DFF6C3D1DFF6C3D1DFF6C3E1CFF6C3E1CFF6C3E1CFF6E411CFF
+ 6D401BFF6D401BFF6D401BFF6C3F19FF6C3F19FF6C3F19FF6E4116FF744414FF
+ 74450FFF75450BFF784A0AFF81540BFF8F600EFF9E6D11FFA97510FFB67D10FF
+ BA7E0CFFBD7F09FFBF8008FFBF8008FFBD8106FFBC8106FFBC7F0BFFBD7B12FF
+ B57314FFA96A10FF9B5F0DFF8C550CFF7F4C0DFF75460EFF6E4312FF6E471BFF
+ 6A431CFF69421CFF67401AFF683F18FF683F18FF6C4017FF6D4118FF6C4017FF
+ 6D4118FF6D4118FF6D4118FF6E4219FF6E4318FF6F4217FF6F4217FF734319FF
+ 734418FF724317FF724317FF734216FF734214FF724115FF704016FF6C411AFF
+ 69421CFF6D431EFF6E441FFF714520FF72451FFF76451FFF77451BFF784618FF
+ 7A4715FF7E4813FF7F490DFF824C0BFF89550FFF966019FF9B6921FF976A26FF
+ C19E66FFF5E0C1FFFFFFF5FFF5F5FBFFEBEFFAFFF0F3F8FFEFEFEFFFF6F3EFFF
+ F7F3F2FFF5F4F8FFF4F4FAFFF3F3F9FFF2F2F2FFF2F1E7FFFFF1DAFFDFB48DFF
+ BC864AFFA7751DFFB58313FFBF8809FFBD8300FFC28101FFC8830AFFC27C0BFF
+ C07C0BFFBE7E08FFBC7F07FFBC8005FFBB8005FFBC7D0AFFBD7E0BFFBD7F09FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBF820AFF
+ BF820AFFBE8109FFBE8109FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BB7E06FFBA7D05FFBC7F07FFBF820AFFC0830BFFBF820AFFBD8008FFBC7F07FF
+ BC7F07FFBC7F07FF4232C6FF412EC5FF3C26C2FF371FBFFF341CBEFF341CBEFF
+ 331DBCFF341FBBFF3722BBFF3927A8FF373182FF363872FF3A3E79FF343D7DFF
+ 323E86FF384B96FF324C98FF3858A3FF4666AFFF4C6CB3FF4969B0FF4162A7FF
+ 3D5BA2FF3956A0FF3A559FFF37509AFF374C97FF374A93FF334388FF29397BFF
+ 283775FF2A3A75FF2D417BFF2E4682FF344A8CFF354B93FF344B97FF354B99FF
+ 374D9BFF3B5199FF3A4E8FFF32437BFF303F6DFF333C62FF2E3354FF363654FF
+ 3E3A57FF3A3550FF2D2843FF2D2649FF2F2053FF351F53FF3E2649FF4A2D3CFF
+ 5A382BFF653E1EFF6A3E19FF6B3F16FF6A3F18FF683F18FF674019FF673F1CFF
+ 6A3E1FFF6C3D21FF6B3E1DFF6B3E1DFF663B20FF663A22FF673822FF693921FF
+ 693A1BFF683B1AFF653C1BFF5D3D20FF4B341EFF302216FF1D1613FF17151BFF
+ 1A1824FF191927FF1E1C28FF1F1D29FF201D2CFF221F2EFF242033FF252134FF
+ 272237FF282338FF272138FF272138FF272237FF272237FF262235FF242033FF
+ 221E31FF211D30FF1D1C2CFF211F2BFF252127FF241E23FF221C21FF251F20FF
+ 342822FF463221FF623E20FF6C3F19FF704016FF724016FF6E3E1CFF6E3D1DFF
+ 723D1CFF703D1CFF693A1AFF683B1AFF693C1BFF693C1BFF6A3D1CFF6B3E1CFF
+ 6B3E1CFF6B3E1CFF6D401EFF6D411CFF6D411CFF6D411CFF6D411CFF6D421BFF
+ 6D421BFF6D421BFF72441BFF72441BFF72431DFF70431DFF70431DFF70431DFF
+ 6F441DFF6F441DFF6C411AFF6C411AFF694019FF683F18FF694019FF68411AFF
+ 6A431CFF6D441DFF6E431CFF6F431AFF6D4217FF6B400FFF6C4108FF784B08FF
+ 8B5A0EFF9D690FFFAC750DFFB67C0BFFBC8008FFBB7F03FFBD8105FFC08409FF
+ BE810BFFB57A0DFFB27317FFA46515FF91540AFF834907FF7A460AFF754511FF
+ 704317FF6A411AFF6C4421FF694321FF684220FF66401DFF68411BFF6A4218FF
+ 6D4217FF6D4318FF6B4019FF6A411AFF6D421BFF6E431CFF6F441DFF70451EFF
+ 72451FFF73471EFF6F431AFF6E4318FF6E4116FF6D4015FF6D4015FF6E4115FF
+ 724218FF714419FF6B4319FF694319FF6A431CFF6C421DFF6D431EFF6F431EFF
+ 71441FFF73441EFF77461EFF76441AFF7A491BFF7B4A18FF75430EFF78480EFF
+ 7F5013FF794B11FF8B622BFFCFB083FFFFEAD4FFFEF4EDFFF3F1F7FFF0F2FAFF
+ F1F3F3FFF6F5F1FFFDFDF7FFEFF0EEFFEDEFF7FFF1F3FDFFEEF0F8FFF6F4F3FF
+ F6EFE0FFEED8B5FFAD7F45FFB77F2EFFB67D1AFFB77E0BFFBC8103FFC28402FF
+ C48205FFC58007FFC27C0AFFC07D0AFFBE7E08FFBC7F07FFBC8005FFBC8005FF
+ BC7E08FFBC7E08FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBC7F07FFBD8008FFBE8109FFBE8109FFBE8109FFBE8109FF
+ BD8008FFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBB7E06FFBC7F07FFBC7F07FFBD8008FFBD8008FFBE8109FF
+ BF820AFFBF820AFFBE8109FFBE8109FFBE8109FF4130C7FF402EC7FF402BC8FF
+ 3F27C9FF3D25C7FF3A23C5FF3923C2FF3823C0FF3821BFFF3927AAFF352F81FF
+ 353771FF3B3F7AFF363F7FFF344086FF384B94FF324D97FF3959A2FF4866ADFF
+ 4B6CB1FF4867ACFF3F5EA3FF3A599EFF3A569DFF3A539BFF39509BFF394F97FF
+ 3B4D94FF344489FF29397BFF2A3775FF2A3A75FF304680FF314A88FF384F93FF
+ 3A529AFF384F9DFF354C9CFF324999FF344994FF384B8EFF31427BFF303E6EFF
+ 323A62FF313355FF383653FF3F3B54FF3C364FFF2C2943FF2D2647FF312150FF
+ 39234DFF452A3EFF523330FF613D1FFF694117FF693F15FF6A3F18FF663F19FF
+ 644018FF654217FF674019FF6C3F1EFF6D3E1FFF6E3E1CFF6C3E1CFF683C1FFF
+ 683B20FF673921FF673A1FFF683A1BFF683B19FF653D1AFF613E1DFF4F361CFF
+ 352514FF231912FF1C1719FF1A1923FF191927FF1E1C28FF1E1C28FF201D2CFF
+ 221F2EFF231F32FF252134FF272237FF272237FF272138FF272138FF272237FF
+ 272237FF262235FF242033FF231F32FF201E31FF1B1B2BFF1F1F2DFF252029FF
+ 241E23FF201A1FFF261E1FFF342824FF483324FF603E21FF6B3F1AFF703F17FF
+ 703F17FF6E3E1CFF6E3D1DFF723D1CFF723D1CFF6B3C1CFF683D1CFF683D1CFF
+ 683D1CFF683D1CFF693F1CFF693F1CFF693F1CFF6B411EFF6B411CFF6B411CFF
+ 6B411CFF6B421BFF6B421BFF6B421BFF6D421BFF704318FF704318FF704318FF
+ 704318FF6E4219FF6E4219FF6D4319FF6D4319FF6D4319FF6A4218FF694019FF
+ 674019FF674019FF69421BFF68441CFF6B441EFF693E1DFF6B401FFF6B411EFF
+ 6B4019FF6B4114FF734712FF835311FF925F0FFFA97112FFB47B0EFFBD8109FF
+ BD8105FFBD8106FFBE820AFFB97D0CFFAF7410FFA06515FF925816FF834D0EFF
+ 79440BFF734210FF724317FF6E411BFF6A401DFF6B4222FF684121FF674020FF
+ 66401EFF67401AFF694019FF6C4218FF6C4218FF6A401BFF68411BFF6B411EFF
+ 6B411CFF6C421FFF6D431EFF6F431EFF70451EFF6D421BFF6D4319FF6D401AFF
+ 6D4118FF6D4118FF6D4217FF704219FF6E4318FF6D4318FF6B4418FF6C441AFF
+ 6C441AFF6D441DFF6F441DFF70441FFF71441EFF72461DFF71431AFF73461BFF
+ 774B1CFF774919FF784B18FF7A4E19FF754D19FF8B6739FFC7AB88FFF5E2D3FF
+ FCF0EEFFF5F1F6FFF2F1F5FFF2F1EDFFF4F5ECFFF5F5EFFFEAECECFFEEF3FCFF
+ F0F4FFFFEFEFF5FFFDF7F2FFF1E3CDFFCEB184FFB28034FFBD821FFFBA7F12FF
+ BC7F0BFFBF8105FFC28205FFC48106FFC38006FFC27D08FFC07D08FFC07E07FF
+ BE7F07FFBE7F05FFBC8005FFBE7F07FFBC7F07FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FF
+ BC7F07FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FFBE8109FFBE8109FF
+ 3D2BCAFF412CCEFF452DD1FF472DD4FF462CD3FF432BD1FF4028CCFF3E27C9FF
+ 3C24C6FF3A26AEFF352C82FF353571FF3E3F7CFF3A4180FF374286FF3A4D91FF
+ 354F95FF3C5BA0FF4966A9FF4969ABFF4461A4FF3B589BFF375497FF375499FF
+ 375098FF395199FF3B5199FF3A4C93FF314186FF28387AFF2A3775FF2C3C77FF
+ 344986FF364F8FFF3C5699FF4059A3FF3C55A5FF3750A0FF314A9AFF304793FF
+ 34498DFF2F417EFF303E6FFF323A62FF333557FF3B3852FF413A4FFF3E374CFF
+ 2E2946FF30264AFF37234DFF412647FF4D2E37FF593628FF643F19FF694215FF
+ 693E17FF673D1AFF633D1BFF633F1BFF644116FF694019FF6C3D1DFF6E3C1EFF
+ 6F3D19FF6D3D19FF6A3D1CFF683C1DFF673B1EFF673B1EFF693C1BFF693D18FF
+ 673D18FF633E1CFF54371CFF3F2917FF2B1B14FF201819FF1C1922FF191925FF
+ 1D1B27FF1E1C28FF1F1C2BFF211E2DFF231F32FF252134FF262136FF272237FF
+ 272138FF272138FF282338FF272237FF272336FF252134FF242033FF211F32FF
+ 1B1B2DFF1E1E2CFF252029FF241D22FF1F1A1CFF261E1EFF362A24FF483625FF
+ 5E3E21FF67401AFF6B4117FF6B4117FF693F1CFF693E1DFF6E3E1AFF6E3E1AFF
+ 6D401BFF6C3F1DFF6C3F1DFF6B3F1AFF6B3F1AFF6B3F1AFF6B3F1AFF6B4019FF
+ 6D421BFF6D421BFF6D4319FF6D4319FF6D4319FF6D4319FF6D4319FF6D4319FF
+ 6C4017FF6C4017FF6C4017FF6C4017FF6C3F19FF6C3F19FF6C3F19FF6B4019FF
+ 6D4319FF6C4218FF6C4218FF6A4218FF6A4218FF6B4319FF6D451BFF6D441DFF
+ 6A3D1CFF6D3F20FF6D4221FF6C421FFF6C401BFF6F4216FF7B4A12FF86520BFF
+ A36B12FFB2780FFFBE810DFFC0830BFFBE810BFFBC7E0CFFB2760CFFA46B10FF
+ 895512FF7A4B13FF73440EFF70410EFF6F4112FF704318FF70411BFF6D3F1DFF
+ 6F411FFF6D401FFF6A3F1EFF693E1DFF663E1BFF67401AFF67401AFF68411BFF
+ 6A401DFF6B411EFF6B401FFF6B411EFF6D401FFF6D401EFF6D401EFF6D411CFF
+ 6D401BFF6D401AFF70401CFF70411BFF70411BFF704219FF6F401AFF6F4118FF
+ 6E4417FF6D4515FF6E4518FF6E4518FF6F451AFF6F451AFF70461BFF70461BFF
+ 70471AFF6E4417FF6E4415FF744B1AFF79511DFF754D19FF754D18FF7A5523FF
+ 997851FFC1A68BFFE3D1C6FFF0E4E2FFF1EBECFFF2EDEEFFF5F2EAFFF9F8EEFF
+ F1F3EDFFE8EDECFFEEF3FCFFF1F3FDFFF5F0F2FFFFF6EAFFE8D0B2FFAE894FFF
+ B47F24FFBE8113FFBD7F0DFFBD7E0BFFC08109FFC28107FFC18006FFC07F05FF
+ C07E07FFC07E07FFC07F05FFC07F05FFC07F05FFBE7F05FFC07F05FFBE7F07FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BB7E06FFBB7E06FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FF3D29CFFF3F2BD1FF462DD5FF492FD7FF4A30D8FF
+ 482FD7FF442ED4FF442CD2FF4229CDFF3E29B4FF362C86FF353472FF3E3F7CFF
+ 3A4180FF364282FF3A4B8EFF375194FF405B9EFF4A66A7FF4A66A6FF415D9EFF
+ 365495FF365293FF385396FF364F95FF385098FF3A4D96FF34468DFF2B3B80FF
+ 263678FF2B3A78FF2F417EFF364D8BFF375193FF3E589EFF405BA5FF3E59A9FF
+ 3A55A6FF364F9FFF344B99FF34488FFF324382FF313D73FF323964FF353658FF
+ 3A364FFF3F3748FF3E3347FF322846FF372749FF3E2648FF492A3FFF55322FFF
+ 5F3822FF653E18FF684115FF673D1AFF653C1CFF623C1CFF633E1CFF663F19FF
+ 683E19FF6C3D1EFF6E3C1EFF6D3D19FF6B3E18FF6A3D1BFF683D1CFF653C1CFF
+ 653C1CFF673D1AFF673D18FF673D18FF633D1AFF59391CFF462D19FF332018FF
+ 241A1AFF1D1821FF191925FF1D1B27FF1E1C28FF1F1C2BFF211E2DFF231F32FF
+ 252134FF262136FF272237FF272138FF272138FF282338FF282338FF272336FF
+ 262235FF242033FF222033FF1B1B2DFF1E1E2CFF261E28FF241D22FF211A1DFF
+ 271F1FFF382D25FF4A3827FF5C3F20FF654119FF694117FF694117FF67401AFF
+ 67401AFF6C3F19FF6C3F19FF6F421DFF6D401EFF6E401EFF6C3F1DFF6D3F1DFF
+ 6B3F1AFF6C3F1AFF6A3E19FF6D401BFF6C411AFF6D401AFF6C4218FF6D4118FF
+ 6C4218FF6D4118FF6D401AFF6C3F1AFF6C3F1AFF6C3F1AFF6C3F1AFF6C3F1AFF
+ 6C3F1AFF6C3F1AFF6C3F1AFF6C411AFF6C411AFF6D421BFF6D4319FF6E411BFF
+ 6E441AFF70441BFF6F441DFF6C3E1CFF6D401FFF6D4221FF6C4120FF693F1CFF
+ 6B3F16FF744311FF7E480BFF985F10FFA96E11FFB97C14FFBD8012FFB97E11FF
+ B2780FFFA56B0CFF925D0DFF774B10FF6E4514FF6A4011FF6A4013FF6F4217FF
+ 704219FF70411BFF6E3E1AFF713F1BFF6F3F1DFF6C3E1CFF6A3D1BFF683E1BFF
+ 663E1BFF653F1CFF68401DFF6B411EFF6D401EFF6D401FFF6C3F1DFF6D3F1DFF
+ 6C3E1CFF6C3E1CFF6C3F1AFF6E3E1AFF6F401AFF71421CFF74431DFF74431DFF
+ 73421AFF71401AFF6E4017FF704317FF6E4415FF6F4516FF6E4616FF6F4619FF
+ 6F4619FF70471AFF704818FF6F4717FF6F4716FF6D4514FF714918FF764F1BFF
+ 6F4814FF754E1AFF856335FFAD8F6CFFB8A18BFFCCB9B1FFDDD0CEFFEAE2E3FF
+ F2EDECFFFAF4EDFFFDFAF2FFF4F5F1FFECF1F0FFECEFF7FFF3F4F8FFFFF8F4FF
+ FFEDD8FFD8B88DFFA77A36FFB57D18FFBD800CFFBE7F0CFFBE800AFFBE800AFF
+ BD8008FFBF8006FFBE7F05FFBE7F05FFC07F05FFC07F05FFC07F05FFC07F05FF
+ C07F05FFC07F05FFC07F05FFBF8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FF
+ BC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBA7D05FFBB7E06FFBB7E06FFBB7E06FFBB7E06FF
+ BB7E06FFBB7E06FFBB7E06FFBB7E06FFBB7E06FFBB7E06FF3D2AD3FF3F2AD3FF
+ 442AD4FF462DD5FF472ED6FF472FD5FF4630D6FF4830D6FF482ED5FF432DBBFF
+ 382D89FF353474FF3D3E7BFF3A3F7CFF36417FFF384A89FF3E5495FF415C9CFF
+ 4863A3FF4763A0FF3F5A9AFF375393FF385294FF3A5497FF364F95FF374F97FF
+ 364992FF2C3E85FF25357AFF263678FF304180FF374988FF405697FF3E589BFF
+ 405AA0FF405BA5FF3E5AA7FF3957A6FF3651A2FF344E9BFF334893FF344687FF
+ 323D76FF323865FF37385AFF39364CFF3A3340FF3B3040FF3A2847FF3F2747FF
+ 472A41FF512F36FF5B342BFF623A21FF653C1BFF653D1AFF623A1DFF623A1EFF
+ 633B1EFF633C1CFF653C1BFF683D1CFF6A3B1FFF6B3B1FFF6A3D18FF693E17FF
+ 673D1AFF633D1BFF633E1CFF633E1CFF663E1BFF683E1BFF663C19FF653C1BFF
+ 5E391DFF51311EFF3A251DFF281A1BFF1D1821FF1B1827FF1C1A26FF1D1B27FF
+ 1E1B2AFF201D2CFF221E31FF242033FF252035FF262136FF262037FF272138FF
+ 282338FF282338FF282437FF272336FF262235FF232134FF1C1B2FFF1E1D2DFF
+ 261E28FF271D23FF261D20FF2D2421FF3A3026FF4B3A27FF5C401EFF644217FF
+ 674216FF674315FF654217FF654217FF6B4215FF6C4116FF6F4020FF6E3E22FF
+ 703E22FF6D3E1FFF6F3D1FFF6C3D1EFF6E3C1EFF6B3C1CFF6F3E1EFF6D3F1DFF
+ 6F3F1DFF6D3F1DFF6F3F1DFF6D3F1DFF6F3F1DFF6D3F1DFF6E3F20FF6D3F20FF
+ 6D3F20FF6D3F20FF6D401FFF6D401FFF6E3F1FFF6E3F1FFF6C3E1CFF6D401BFF
+ 6D401BFF6E411BFF70401CFF6F421CFF71421CFF6F421CFF70401CFF6F411FFF
+ 6D401EFF693F1CFF673D18FF693E17FF704115FF794411FF88500FFF9B6115FF
+ AE7219FFB17619FFAC7316FFA06A13FF925C0FFF7E4E0CFF6F4713FF684317FF
+ 6A4317FF6C4217FF6F431AFF71431AFF71401AFF703F19FF733F1AFF703E1AFF
+ 6D3D19FF6B3E19FF683E19FF67401AFF66411BFF68411BFF6E421DFF6F421DFF
+ 6E401EFF6D401BFF6F3F1BFF6E3E1AFF6D3D19FF6D3E18FF71401AFF724119FF
+ 73421AFF76431BFF76431BFF754319FF744119FF734117FF704318FF704317FF
+ 714418FF6F4518FF704617FF704617FF714718FF714817FF6F4615FF724A16FF
+ 704814FF6F4713FF6E4615FF6B4312FF7D5524FF99764AFFB89C7DFFB39E89FF
+ BFAEA5FFD6C9C7FFEAE2E3FFF5EFF0FFF9F4F1FFF8F5F1FFF6F4F3FFF2F2F2FF
+ EBECF0FFFCF7F4FFFFFFF0FFF6DAB7FFC69E64FFB17E2EFFB57B12FFBD7E0BFF
+ BD800AFFBD800AFFBD800AFFBC8008FFBB8005FFBB8005FFBC8004FFBE8004FF
+ C08004FFC08004FFC27F05FFC27F05FFC27E07FFC27E07FFBF8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBB7E06FFBB7E06FF
+ BB7E06FFBB7E06FFBB7E06FFBB7E06FFBB7E06FFBA7D05FFBB7E06FFBB7E06FF
+ BB7E06FF3E2BD4FF402BD4FF412AD2FF432BD1FF442CD0FF452DD1FF4530D3FF
+ 4830D4FF4A30D7FF452FBDFF3B308DFF363476FF3C3B79FF383E79FF36427CFF
+ 3B4D88FF425795FF435C9AFF465F9DFF455F9BFF415A98FF3B5794FF3B5696FF
+ 3D579AFF375096FF384E96FF33468FFF263A81FF23367AFF2C3E7FFF3A4B8AFF
+ 405593FF4A62A4FF4660A6FF425EA5FF3E5BA5FF3A58A5FF3654A3FF324D9EFF
+ 304999FF314592FF35458AFF323D77FF333767FF3A3959FF3B364BFF39313CFF
+ 3E303CFF412842FF492942FF512F36FF58342CFF603923FF633B1EFF633C1CFF
+ 623B1BFF613B1DFF613B1BFF623C1AFF653D1AFF673C1BFF683D1CFF683C1FFF
+ 683C1DFF673D1AFF653D1AFF633D1AFF623D1BFF613E1CFF613E1CFF643E1CFF
+ 663D1CFF663B1AFF663A1BFF633A21FF563522FF422821FF2C1B1EFF1E1621FF
+ 1A1726FF1C1A26FF1D1B27FF1E1B2AFF201D2CFF221E31FF242033FF252035FF
+ 262136FF262037FF272138FF282338FF282338FF282437FF282437FF262235FF
+ 242235FF1F1D31FF201D2DFF251D27FF291F25FF2C2326FF362A28FF3F322AFF
+ 4C3826FF5C3F20FF65401AFF694117FF694117FF67401AFF694019FF6C4017FF
+ 6E4017FF6D3E1EFF6D3D21FF6D3D21FF6C3C20FF6C3D1EFF6C3D1EFF6C3D1EFF
+ 6C3D1EFF6C3D1DFF6C3D1DFF6C3E1CFF6C3E1CFF6C3E1CFF6C3E1CFF6C3E1CFF
+ 6C3D1DFF6E3F20FF6D3F20FF6D3F20FF6D401FFF6D401FFF6D401FFF6E3F1FFF
+ 6E401EFF6B3E19FF6B3E19FF6C3F19FF6D401AFF70411BFF6E411BFF6F401AFF
+ 6F401AFF71421CFF6E411CFF6A411AFF663F18FF653E18FF683F18FF6C3F19FF
+ 744317FF7B4411FF8D5417FF9C611BFF9D6419FF956017FF8C5913FF7E4F11FF
+ 71450FFF6B4417FF694319FF6C441AFF6E441AFF6F421CFF71421CFF713F1BFF
+ 703E1AFF713F1BFF703E1AFF6E3E1AFF6B3E18FF6B4019FF6A411AFF694319FF
+ 6C431CFF6E421DFF6F421DFF6F421DFF6E411CFF6F3F1BFF6F401AFF6E3F19FF
+ 6E3F19FF72411BFF73421AFF73421AFF74441AFF76441AFF754319FF754319FF
+ 724218FF724119FF704219FF714419FF714419FF704619FF704617FF714718FF
+ 714817FF704716FF724918FF714817FF6D4314FF6A4011FF72481BFF906639FF
+ AC8860FFB99F81FFB4A08EFFC5B6ADFFE0D4D2FFF1E8EBFFF9F2F7FFF7F2F3FF
+ F1ECEDFFF1EFEFFFF3F1F1FFF3EEEFFFFFF4ECFFFFEDD3FFDBB98BFFB68841FF
+ B98128FFB87B13FFBD7F0DFFBE810BFFBC830AFFBA8106FFB78105FFB98005FF
+ BA8106FFBB8104FFBC8004FFBE8004FFC08004FFC27F05FFC27F05FFC37D07FF
+ C27E07FFBF8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBC7F07FFBD8008FFBE8109FFBF820AFFBF820AFFBE8109FFBD8008FF
+ BC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBB7E06FF
+ BB7E06FFBB7E06FFBB7E06FFBB7E06FF3F2ED3FF412DD3FF422DD0FF432CCEFF
+ 442FCCFF442FCCFF432FCEFF462FD1FF482FD3FF452FBDFF3C318EFF363476FF
+ 3B3B77FF383F78FF38457DFF40538CFF455A97FF445C98FF455D99FF435E97FF
+ 425C98FF415B97FF405B9BFF405A9CFF394F96FF394F97FF334691FF283B84FF
+ 293B82FF35488BFF445697FF4A5E9FFF4D64A8FF4861A9FF435FA6FF3E5BA5FF
+ 3A58A5FF3453A2FF2F4C9DFF2E4797FF2D418EFF33428AFF313B77FF323666FF
+ 3C3B5BFF3D394CFF3A323CFF42333BFF492B3EFF512D39FF59352BFF5E3C1FFF
+ 633F1BFF633E18FF613C1AFF5F3C1BFF5E3C18FF603D15FF643F13FF663F13FF
+ 673D18FF653D1AFF623E1AFF633E1CFF623C1AFF613B1BFF603D1CFF5E3D1CFF
+ 5D3E1DFF5D3E1DFF623F1EFF653E1EFF663A1BFF66391EFF643A23FF5C3828FF
+ 472A25FF2F1C1FFF1F1521FF1C1726FF1C1A26FF1C1A26FF1E1B2AFF201D2CFF
+ 211D30FF231F32FF252035FF252035FF262037FF272138FF282338FF292439FF
+ 292538FF282437FF272336FF252336FF201E32FF1F1C2CFF251C26FF2C2026FF
+ 34292CFF3D2F30FF46332EFF4F3529FF603C24FF693D1EFF6C3D1DFF6C3D1EFF
+ 6B3C21FF6C3C20FF723C1EFF723C1DFF6B3C1CFF683D1CFF683D1CFF683D1CFF
+ 683E1BFF693F1CFF693F1CFF693F1CFF693F1AFF693F1AFF693F1AFF693F1AFF
+ 694019FF694019FF694019FF6B4019FF6C3F1AFF6C3F1AFF6C3F1AFF6C3F19FF
+ 6C3F19FF6C3F19FF6C3F19FF6C3F19FF693D14FF6A3E15FF6B3F16FF6C4218FF
+ 6D4118FF6C4218FF6C4017FF6B3F16FF6F401AFF6C3F19FF694117FF654217FF
+ 644119FF66411BFF6B401FFF6E401EFF713C17FF7F481BFF89501CFF844F16FF
+ 794A12FF744813FF6E4616FF674216FF694216FF6A4218FF6D4319FF6E431CFF
+ 6F421DFF6E411CFF70401EFF6F3F1DFF6F3F1DFF6F3F1BFF6C3F1AFF6C4017FF
+ 6D4217FF6D4417FF6E4616FF6D4619FF6C431CFF6C421FFF6C421FFF6C421FFF
+ 6C421FFF6B411CFF6D411CFF6D421BFF70431DFF70431DFF6F421CFF6F431AFF
+ 71431AFF71431AFF72441BFF72441BFF70401CFF70401CFF71421CFF71421CFF
+ 72441BFF72451AFF73461AFF734718FF744819FF714418FF714418FF6F4217FF
+ 704219FF855630FFA97955FFBC9372FFBCA284FFBEAD98FFDACBC2FFF1E5E5FF
+ F5EBF1FFF5EDF7FFF5F1F7FFF0ECF1FFF1EDF2FFF6F1F2FFFBF2EFFFF4E1D2FF
+ D8BA97FFB99157FFB17F2DFFBB7F1FFFBC7D15FFBF8012FFBD820EFFBA8408FF
+ B78203FFB48102FFB78104FFB98306FFB98005FFBB8104FFBE8004FFC08003FF
+ C27F04FFC37E05FFC57C08FFC37D08FFBF8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBD8008FFC0830BFFC2850DFF
+ C2850DFFC0830BFFBD8008FFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BC7F07FFBC7F07FFBB7E06FFBB7E06FFBB7E06FFBB7E06FFBB7E06FF442FD1FF
+ 4430CFFF4631CEFF4732CBFF4631CAFF4631CAFF442FCBFF452ECCFF472ECCFF
+ 4430B8FF3B328CFF373676FF3A3B77FF383F78FF3C4780FF475890FF485C96FF
+ 435B95FF435B95FF435B95FF435D99FF455F9BFF455E9EFF455D9FFF3A5097FF
+ 3B4E97FF354891FF2C3F88FF2E4289FF3B5193FF4A5E9FFF4D63A5FF4660A6FF
+ 425EA5FF3F5CA6FF3C5CA5FF3B5AA5FF3755A2FF304E9BFF2F4996FF293D8AFF
+ 314088FF2E3977FF313667FF3E3D5FFF403A4DFF3E343AFF4B3638FF502E34FF
+ 58322EFF5D3921FF633F1BFF644018FF633F17FF613C1AFF5E3B1AFF5E3D16FF
+ 603E13FF643F13FF643F13FF673D18FF653D1AFF623E1AFF603E1AFF613C1AFF
+ 613B1BFF603D1CFF5E3C1EFF5F3D1FFF5F3D1FFF603F1EFF643E1EFF643B1BFF
+ 663A1DFF673B23FF623A28FF4C2D24FF331E1DFF23161EFF1E1823FF1D1924FF
+ 1C1A26FF1E1B2AFF1F1C2CFF211E2EFF231F32FF262033FF272134FF262136FF
+ 272237FF262438FF272539FF272539FF262437FF262437FF252434FF211F32FF
+ 1F1C2BFF231B25FF2C2228FF372C2FFF413334FF48342FFF513426FF643B24FF
+ 6B3C20FF6E3C20FF6E3C20FF6C3A23FF6E3A23FF723B20FF703C1EFF683B1AFF
+ 643C19FF653D1AFF653D1AFF663E1BFF67401AFF673F1CFF67401AFF67401AFF
+ 67401AFF67401AFF67401AFF674019FF674019FF674019FF694019FF693E17FF
+ 6A3D17FF693E17FF693E17FF693E17FF693E17FF693E17FF693E17FF673D13FF
+ 683E14FF6A4016FF694117FF6B4117FF694117FF6A4016FF693E17FF6A3D17FF
+ 6B3E18FF694019FF66421AFF68441CFF68421FFF694020FF6D3F20FF6C3B1BFF
+ 76421EFF78441BFF703F13FF673A0FFF673D13FF65401AFF67421CFF673E17FF
+ 683F18FF6B4019FF6C401BFF6D401EFF6D401EFF6E3F1FFF6E401EFF6E401EFF
+ 6D401BFF6D401BFF6D4118FF6D4217FF6F4518FF6F4717FF70471AFF6C431CFF
+ 6C421FFF6C421FFF6C421FFF6C421FFF6C421DFF6E421DFF6E431CFF70451EFF
+ 6F441DFF6F421CFF6E4219FF6E4219FF6F431AFF70441BFF73451CFF72411BFF
+ 72411BFF73421CFF73421CFF72441BFF72441BFF73461BFF73461AFF76491DFF
+ 6F4216FF714117FF704219FF754521FF926442FFB88969FFC1997CFFC0A78DFF
+ CBB9A8FFE8DAD4FFF8EDF0FFF0E8EFFFEEE9F2FFF7F3F9FFF5F4F8FFF5F1F6FF
+ F9F4F3FFFFF6EAFFE8D0B4FFB38E5CFFA4742CFFB77E23FFBA7C16FFBD7E16FF
+ C08113FFBE830FFFBA830AFFB68003FFB57F02FFB88206FFBA8408FFB98007FF
+ BB7F07FFBE7F05FFC07F05FFC07F05FFC27E07FFC27C0AFFC27C0AFFBF7F09FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBB7E06FF
+ BE8109FFC1840CFFC4870FFFC4870FFFC1840CFFBE8109FFBB7E06FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBF820AFF
+ BF820AFFBE8109FFBD8008FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBC7F07FF
+ BC7F07FFBC7F07FF4028C4FF422AC4FF432DC2FF452FC3FF4630C4FF452FC4FF
+ 452EC6FF442DC5FF4229BFFF3A29A8FF373484FF393D78FF3B3E7BFF3B407DFF
+ 3F4782FF414F89FF4B629AFF405B93FF38538CFF354F8BFF374E8CFF384E8FFF
+ 374D8FFF34498DFF40549BFF3B4E97FF33468FFF31458CFF384F93FF475EA2FF
+ 4C66A8FF4A65A8FF415DA4FF3D5DA6FF3C5DA6FF3B5CA5FF3858A1FF33539CFF
+ 304B95FF2D468EFF334893FF34468DFF2F3E7DFF333B70FF3D3E60FF3F3748FF
+ 453536FF573E34FF5B3929FF613A24FF623C1EFF633D1BFF623C1AFF623C1AFF
+ 613A1AFF603A1AFF5F3A18FF613B18FF623C19FF623C19FF643B1AFF623C1AFF
+ 613B19FF603A18FF633C16FF633C16FF643B1AFF643B1BFF613B1DFF603C1EFF
+ 603D1CFF603D1BFF623C19FF643A17FF673B1CFF663D24FF563525FF3D271CFF
+ 291C1AFF20191CFF19151BFF191520FF1A1726FF1C1B2BFF211E2EFF241E2FFF
+ 27202FFF27202FFF272132FF262235FF222338FF22253AFF22253AFF222639FF
+ 252535FF262634FF2B2733FF221E29FF1E1A25FF28242AFF342F31FF3E3230FF
+ 473328FF523421FF643B22FF693B1CFF6B391BFF6C3A1CFF6D3E1FFF6E3F20FF
+ 6D3E1EFF6C3E1CFF693E1DFF673E1DFF673E1DFF683F1EFF683F1EFF69411EFF
+ 69401FFF69411EFF673F1CFF663E1BFF653D1AFF633B18FF633B18FF633B18FF
+ 643C19FF643C19FF683E1BFF673D1AFF663C19FF663C19FF663C19FF673D1AFF
+ 693F1CFF6A401DFF683E1BFF683E1BFF683E1BFF663E1BFF683E1BFF663E1BFF
+ 683E1BFF683E1BFF6A3D1BFF6A3D1BFF6A3D1BFF683E1BFF683E1BFF683D1CFF
+ 683D1CFF6A3D1CFF6F4020FF6E401EFF6E3E1AFF6A3D18FF6A3D18FF693C1AFF
+ 683E1BFF693F1CFF6A401DFF68401DFF6A401DFF6A401DFF6A3F1EFF6A3F1EFF
+ 6C3F1DFF6C3F1DFF683B19FF693D18FF6B3F1AFF6D421BFF6F431AFF6F431AFF
+ 6F431AFF6F431AFF70431EFF6F421DFF6E411CFF6D401BFF6D401BFF6D401AFF
+ 6F421CFF6F421CFF71441EFF6E4219FF6E4017FF6E4116FF714419FF74471CFF
+ 74471CFF75451BFF7B491BFF7C481AFF7A471CFF78461CFF76451DFF73451CFF
+ 73451CFF72451AFF6C3D11FF744519FF72451AFF6F431AFF825833FFA87F5EFF
+ C19B7DFFC2A088FFB99E8AFFCFBBB0FFE8DADEFFF4EAF6FFF4EFF8FFF4F0F5FF
+ F5F3F3FFF6F4F3FFEDEDEDFFFEF8F1FFEFE0C6FFBDA172FFA2772EFFB27B20FF
+ C0811FFFBA7811FFBC7D0FFFBE7F0FFFC08210FFBD820EFFBA8009FFB97F08FF
+ BB800CFFBD820EFFBE810DFFBD800CFFBD7E0BFFBC7D0AFFBC7D0AFFBD7E0BFF
+ BE7F0DFFBF800DFFBC7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBC7F09FFBB7E08FFBB7E08FFBA7D07FFBB7E08FFBD800AFF
+ BE810BFFC0830DFFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF3C22BCFF3C23BBFF3D26B8FF
+ 3D26B6FF3D25B9FF3C23B9FF3A21B9FF3920B6FF341DAFFF32239CFF33337FFF
+ 353C75FF343976FF343976FF3B417CFF3F4B85FF41598FFF3C5B90FF3F5A92FF
+ 3E5992FF3E5593FF3A5091FF394C8FFF384B8FFF3A4C93FF3A4C93FF374C90FF
+ 374D8FFF3E5698FF4964A4FF4F6AAAFF4A68A9FF5372B7FF4868B1FF3D5EA7FF
+ 3859A2FF38589FFF37559CFF365096FF314A90FF324890FF32468DFF2E3E80FF
+ 323D71FF3D3D61FF3F3748FF483433FF593C2DFF5D3A20FF623B1BFF623B1BFF
+ 623B1BFF613A1AFF613A1AFF613A1AFF613A1AFF613A1AFF613A1AFF623B1BFF
+ 633C1CFF633C1CFF623B1BFF613A1AFF613B19FF633C15FF653C15FF663C19FF
+ 663A1BFF623A1DFF623C1EFF603D1CFF603E1AFF633E18FF633C16FF693C1AFF
+ 683E21FF5B3922FF442A1CFF2C1F17FF211919FF1E181DFF1B1722FF1B1827FF
+ 1C1B2BFF201D2DFF231E2DFF251E2DFF251E2BFF292132FF262235FF222338FF
+ 1F233BFF20243CFF1F2439FF252535FF272531FF2A242FFF221D26FF1C1B25FF
+ 26252EFF343133FF403531FF4C3728FF573821FF653D21FF693B1CFF6B391BFF
+ 6A3B1CFF6D3E1EFF6D401FFF6C3F1DFF683E19FF693E1DFF673E1DFF673E1DFF
+ 683F1EFF683F1EFF683F1EFF69401FFF69401FFF673E1DFF663D1CFF653C1BFF
+ 643B1AFF633A19FF643B1AFF643B1AFF653C1BFF653C1BFF653C1BFF643B1AFF
+ 643B1AFF643B1AFF653C1BFF673E1DFF683F1EFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF6A3D1CFF6A3D1CFF6A3D1CFF
+ 6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6D401FFF6C3F1EFF6B3E1DFF
+ 6A3D1CFF693C1BFF6A3D1CFF6B3E1DFF693E1DFF693E1DFF673E1DFF673E1DFF
+ 673E1DFF693E1DFF693E1DFF693F1CFF693F1CFF683C17FF693D18FF6B3F1AFF
+ 6D411CFF6F421CFF6F421CFF6F421CFF6F421CFF72421EFF71411DFF70401CFF
+ 6F3F1BFF6F401AFF70411BFF71421CFF71421CFF73451CFF71431AFF6F4217FF
+ 704318FF73461BFF75481DFF74471CFF75461AFF7C4819FF7E4819FF7A471CFF
+ 78461CFF73451CFF73451CFF73451CFF72441BFF72451AFF72451AFF704318FF
+ 774C25FF906A47FFB28F6EFFBD9F84FFB89B86FFBBA292FFD4C0BBFFEADDE5FF
+ F3EAF7FFF4EFF8FFF0EFF1FFEFF0EEFFF4F3EFFFF5F2EEFFFFF7E9FFE4CEAAFF
+ B49054FFA97921FFB87E17FFBE7C16FFBC7A11FFBD7E0EFFBE800EFFBF810FFF
+ BF810FFFBE800EFFBD7F0DFFBE800EFFBF810FFFBE800EFFBD7F0DFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE810DFFBC7F0BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBE810BFFBD800AFFBC7F09FF
+ BB7E08FFBB7E08FFBB7E08FFBC7F09FFBD800AFFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ 371FBBFF3720B8FF3721B5FF3621B3FF351FB3FF331DB2FF311AB2FF301AAFFF
+ 2A15A7FF2C2098FF31347FFF353F75FF323A75FF2F3772FF353D78FF3C4981FF
+ 374F85FF3B578DFF465F97FF48609AFF455A97FF3E5391FF3C4E8DFF3B4D8EFF
+ 2D3E81FF2F4285FF324889FF3B5290FF4962A0FF5A76B2FF6480BCFF6380BDFF
+ 5C7CBEFF4D6DB4FF3E60A6FF37599FFF3959A0FF3A589FFF375098FF314991FF
+ 324792FF34468DFF313F81FF343F73FF3F4062FF413747FF463330FF563A29FF
+ 5B381EFF603919FF613A1AFF613A1AFF613A1AFF613A1AFF623B1BFF623B1BFF
+ 623B1BFF623B1BFF633C1CFF643D1DFF643D1DFF633C1CFF623B1BFF623C1AFF
+ 633C16FF633C16FF643B1AFF643B1BFF623A1DFF623C1EFF603D1CFF603D1BFF
+ 643F19FF643D17FF693C1AFF683F1FFF5F3B23FF492F1FFF332219FF241915FF
+ 211A1DFF1F1A23FF1C1A26FF1C1C2AFF1D1C2CFF1F1C2BFF231C2BFF231C29FF
+ 282031FF252134FF212237FF21233BFF212439FF212538FF252434FF292531FF
+ 28202AFF221A24FF1F1B26FF2A2730FF383335FF433932FF4E392AFF5A3A23FF
+ 653D20FF693C1BFF6B3A1AFF6A3B1BFF6C3D1EFF6C3F1EFF6B3E1CFF683E19FF
+ 683D1CFF663D1CFF673E1DFF673E1DFF683F1EFF683F1EFF683F1EFF69401FFF
+ 683F1EFF673E1DFF663D1CFF653C1BFF643B1AFF643B1AFF653C1BFF653C1BFF
+ 653C1BFF643B1AFF643B1AFF643B1AFF643B1AFF653C1BFF663D1CFF673E1DFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF
+ 6B3E1DFF6B3E1DFF6A3D1CFF6A3D1CFF6A3D1CFF6B3E1DFF6C3F1EFF6A3F1EFF
+ 683D1CFF663D1CFF663D1CFF663D1CFF683D1CFF683D1CFF683E1BFF683E1BFF
+ 693D18FF6A3E19FF6B3F1AFF6D411CFF6F421CFF6F421CFF6E411BFF6E411BFF
+ 71411DFF70401CFF70401CFF6F3F1BFF6F401AFF70411BFF71421CFF71421CFF
+ 73451CFF72441BFF72451AFF73461BFF75481DFF75481DFF74471CFF744519FF
+ 79461BFF79461BFF78461CFF76451DFF73451CFF71441EFF71451CFF70441BFF
+ 764B20FF6E4318FF70461CFF87603AFFA88564FFBD9D80FFBCA088FFB19987FF
+ C0ACA1FFDDCECBFFF2E6ECFFF5ECF6FFF4F0F6FFEEEDEFFFECECECFFF4F3EFFF
+ F8F2EBFFF6E7D4FFCFB083FFA77D38FFB17D1FFFBE841BFFBF8018FFC3851BFF
+ BF8010FFBE800EFFBE800EFFBE800EFFBF810FFFC08210FFBF810FFFBE800EFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD800CFF
+ BD800CFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFF
+ BF820CFFBE810BFFBD800AFFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FF3D24C2FF3D25BFFF3C26BBFF3B25B9FF3A24B9FF
+ 3922BAFF3820BAFF3720B8FF3420AFFF32269CFF333680FF374276FF374079FF
+ 353E77FF39427BFF3C4981FF374C83FF3A548AFF425B93FF475E96FF455B95FF
+ 425592FF3D508DFF3B4E8BFF354786FF354885FF364B88FF405892FF5570A8FF
+ 6C87BFFF7493C8FF7290C9FF5576B5FF4A6BB0FF4162A7FF3B5BA2FF3B59A0FF
+ 3A569DFF364F97FF334991FF324590FF34468DFF324082FF373F74FF424163FF
+ 413845FF44312CFF533824FF5C3A1DFF613A1AFF613A1AFF623B1BFF633C1CFF
+ 633C1CFF643D1DFF643D1DFF623B1BFF633C1CFF643D1DFF653E1EFF653E1EFF
+ 643D1DFF633C1CFF623C1AFF613B18FF613B18FF643B1AFF623A1DFF613A1EFF
+ 603B1FFF603C1EFF603D1BFF65401AFF653E17FF693D18FF683F1FFF613E24FF
+ 523421FF3A271AFF271B15FF231B1BFF1E1A20FF1B1A24FF1B1B29FF1C1B2BFF
+ 1E1B2AFF231C2BFF231C29FF27202FFF242033FF232137FF22223AFF222338FF
+ 222337FF262333FF2A2330FF29202AFF241C23FF231E27FF2C2A30FF3A3537FF
+ 443832FF50392AFF5A3A23FF653D20FF693C1BFF6B3A1AFF6A3B1BFF6B3D1EFF
+ 6C3F1EFF6A3D1BFF673D1AFF663D1CFF663D1CFF663D1CFF673E1DFF673E1DFF
+ 683F1EFF683F1EFF683F1EFF683F1EFF673E1DFF663D1CFF653C1BFF643B1AFF
+ 643B1AFF653C1BFF663D1CFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 653C1BFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF683D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF
+ 6A3D1CFF6A3D1CFF6A3D1CFF693C1BFF6A3D1CFF6A3D1CFF6A3D1CFF6B3E1DFF
+ 6C3F1EFF6C3F1EFF6B401FFF663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF
+ 683D1CFF683E1BFF683E1BFF693D18FF6A3E19FF6C401BFF6D411CFF6E411BFF
+ 6E411BFF6E411BFF6D401AFF70401CFF70401CFF70401CFF70401CFF70411BFF
+ 71421CFF71421CFF71421CFF72441BFF73451CFF74471CFF75481DFF76491EFF
+ 75481DFF74471CFF72451AFF77451BFF77451BFF75441CFF73451CFF71441EFF
+ 71441EFF71451CFF71451CFF73471EFF6C4218FF7B522BFF9F7B57FFB9997CFF
+ BA9F85FFB69D89FFB5A293FFCABDB5FFE9DDDDFFF8ECF2FFF6EBF3FFF5EFF4FF
+ F2EFF1FFEEEEEEFFF9F6F1FFFFF3E7FFE5CDAFFFBC965CFFAB7A2AFFBA821DFF
+ C08518FFBD8018FFC3871DFFBF8312FFBE800EFFBD7F0DFFBE800EFFC08210FF
+ C18311FFBF810FFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBD800CFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFF
+ BD800AFFBD800AFFBD800AFFBE810BFFBD800AFFBD800AFFBC7F09FFBC7F09FF
+ BB7E08FFBB7E08FFBB7E08FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF4329C9FF432BC7FF
+ 432CC4FF422CC1FF422AC4FF432BC5FF432BC7FF432CC4FF4430BFFF392EA2FF
+ 31357CFF343F71FF3A447AFF3B457BFF3B457BFF3A487DFF3B5087FF395187FF
+ 3A5288FF3F538CFF42568FFF42548FFF3E508BFF3B4D88FF3A4C87FF394D86FF
+ 3B528AFF4A649AFF6481B4FF7D9ACDFF81A1D2FF7999CEFF5978B5FF5174B4FF
+ 496AAFFF3F60A5FF38569DFF345097FF354C97FF374C97FF314390FF35448DFF
+ 344082FF373F74FF424161FF413743FF443129FF523722FF5E3C1FFF633C1CFF
+ 633C1CFF643D1DFF653E1EFF653E1EFF663F1FFF663F1FFF623B1BFF633C1CFF
+ 643D1DFF653E1EFF653E1EFF643D1DFF633C1CFF623B1BFF613B19FF603B19FF
+ 623B1BFF613B1DFF613A1EFF603B1FFF603C1EFF623D1BFF643F19FF663F18FF
+ 6A3E19FF673E1DFF633E22FF583924FF432C1CFF302118FF231A17FF1F1A1CFF
+ 1A1922FF191925FF1A1B29FF1D1D2BFF221D2CFF251E2BFF261F2EFF251F30FF
+ 232135FF232137FF232137FF232236FF272132FF2B222FFF2D222AFF291F25FF
+ 28202AFF2F2B31FF3A3336FF413531FF4D3627FF583821FF653D20FF693C1BFF
+ 6B3A1AFF693A1AFF6A3C1DFF693D1EFF673C1BFF653A19FF653C1BFF653C1BFF
+ 663D1CFF663D1CFF673E1DFF673E1DFF683F1EFF683F1EFF683F1EFF673E1DFF
+ 653C1BFF643B1AFF643B1AFF643B1AFF653C1BFF653C1BFF623918FF633A19FF
+ 633A19FF643B1AFF653C1BFF653C1BFF653C1BFF653C1BFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF683D1CFF
+ 683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF673C1BFF673C1BFF
+ 683D1CFF693E1DFF693E1DFF6A3F1EFF6A3F1EFF6A3F1EFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF683D1CFF683D1CFF683E1BFF683E1BFF6A3E19FF6B3F1AFF
+ 6C401BFF6D411CFF6E411BFF6E411BFF6D401AFF6D401AFF6E3E1AFF6F3F1BFF
+ 70401CFF70401CFF71421CFF71421CFF71421CFF71421CFF72441BFF74461DFF
+ 75481DFF76491EFF75481DFF74471CFF73461BFF72451AFF72441BFF72441BFF
+ 72431DFF70431DFF71441EFF71441EFF71451CFF71451CFF6B4117FF704720FF
+ 8E6845FFB69574FFC0A289FFB19983FFB4A08FFFC4B5ACFFD8D1CEFFEEE8E9FF
+ FBF0F3FFF5EBF1FFF4EFF1FFF6F3F5FFF4F2F1FFFCF5ECFFFAE5CFFFCCAA7FFF
+ B3823CFFBA8124FFBC8114FFB87C0BFFB57B11FFB77D13FFBE8211FFBE810DFF
+ BC7F0BFFBD800CFFC0830FFFC18410FFBF820EFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBD800CFFBD800CFFBC7F0BFFBC7F0BFFBC7F0BFFBD800AFFBD800AFF
+ BD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBB7E08FFBB7E08FF
+ BC7F09FFBC7F09FFBD800AFFBD800AFFBD800AFFBD800AFFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FF4429CCFF442BC9FF442CC6FF442DC5FF452DC9FF472FCBFF4830CCFF
+ 4932CAFF4B37C6FF3B30A4FF2E3378FF303D6BFF394476FF3C477BFF3B467AFF
+ 374579FF3E5387FF3A4F86FF374C83FF3A4E85FF3E518AFF3F528BFF3E4F88FF
+ 384B84FF354881FF394C85FF42578EFF546CA0FF6D88BBFF829FD2FF84A4D5FF
+ 7C9CD1FF6888C3FF6081C0FF5274B6FF4263A8FF35539AFF304C93FF354C97FF
+ 3B509BFF32428FFF34438CFF333F81FF383F71FF41415FFF413842FF443227FF
+ 553921FF613C20FF643D1DFF643D1DFF643D1DFF653E1EFF653E1EFF653E1EFF
+ 653E1EFF623B1BFF623B1BFF633C1CFF643D1DFF643D1DFF633C1CFF623B1BFF
+ 623B1BFF603A1AFF603A1AFF613B1DFF5F3A1EFF5F3A20FF603B1FFF603C1EFF
+ 623D1BFF633E18FF694019FF6B3F1AFF683E1BFF643E20FF5B3C23FF4F3420FF
+ 3D2A1DFF251B14FF1E191AFF1B191FFF181923FF191A28FF1C1B2BFF221D2CFF
+ 261F2CFF261F2EFF261E2FFF241F34FF232036FF232036FF232135FF262031FF
+ 2A222DFF2F242CFF2B2127FF29212BFF302930FF373035FF3E322EFF4A3226FF
+ 56361FFF653D20FF693C1BFF693A1AFF693A1AFF6A3C1DFF683C1DFF663B1AFF
+ 643918FF653C1BFF653C1BFF653C1BFF663D1CFF663D1CFF673E1DFF673E1DFF
+ 673E1DFF663D1CFF663D1CFF643B1AFF633A19FF633A19FF633A19FF633A19FF
+ 643B1AFF613817FF623918FF633A19FF643B1AFF653C1BFF653C1BFF643B1AFF
+ 643B1AFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF
+ 683D1CFF673C1BFF683D1CFF693E1DFF6A3F1EFF6A3F1EFF693E1DFF693E1DFF
+ 693E1DFF663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF683D1CFF683E1BFF
+ 683E1BFF6B3F1AFF6B3F1AFF6C401BFF6D411CFF6E411BFF6E411BFF6D401AFF
+ 6C3F19FF6D3D19FF6E3E1AFF6F3F1BFF71411DFF72431DFF72431DFF72431DFF
+ 72431DFF72441BFF74461DFF75481DFF75481DFF73461BFF72451AFF72451AFF
+ 73461BFF6F421CFF6F421CFF70431DFF70431DFF70431DFF71451CFF71451CFF
+ 71451CFF6D421BFF815A34FFA78260FFC0A285FFBDA38BFFB39D8BFFC1B0A3FF
+ D9CEC6FFE7E3E2FFF0EDEFFFFAF1F4FFF5ECEFFFF3EEF0FFFAF6F5FFF7F3EEFF
+ F4E8D6FFD6B895FFB0834AFFAC7220FFC2821CFFBE800EFFB57A06FFB77E11FF
+ B67E13FFBC800FFFBD800CFFBC7F0BFFBD800CFFBE810DFFBE810DFFBD800CFF
+ BC7F0BFFBB7E0AFFBC7F0BFFBD800CFFBD800CFFBD800CFFBD800CFFBC7F0BFF
+ BB7E0AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFF
+ BD800AFFB97C06FFBA7D07FFBB7E08FFBD800AFFBE810BFFBE810BFFBE810BFF
+ BE810BFFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FF432ACEFF432BCBFF422CC8FF422CC8FF
+ 432CCAFF452ECCFF4730CEFF4833CBFF4836C5FF3A32A4FF2F377AFF31416CFF
+ 374575FF3A4879FF3B497AFF3B4A7BFF3D4F84FF3B5084FF3D5286FF405287FF
+ 405189FF3E4F87FF3C4A84FF374881FF3B4E87FF43568FFF4B5F98FF526AA0FF
+ 5F79AFFF6E8AC0FF7695CAFF7695CCFF6C8CC7FF6283C2FF5274B6FF4263A8FF
+ 37559CFF344D95FF344B96FF374C97FF32428FFF33428BFF313D7FFF363D6FFF
+ 40405EFF413842FF483429FF573B23FF603B1FFF633C1CFF623B1BFF623B1BFF
+ 623B1BFF623B1BFF623B1BFF613A1AFF613A1AFF613A1AFF623B1BFF633C1CFF
+ 633C1CFF623B1BFF613A1AFF613A1AFF603A1AFF5E3A1CFF5F3B1DFF5D3B1EFF
+ 5D3A20FF5E3C1FFF603C1EFF623D1BFF633B18FF693F1AFF6C401BFF673D1AFF
+ 633C1CFF603D23FF583922FF493321FF2A1E14FF211C19FF1B1A1EFF181923FF
+ 181927FF1A1929FF201B2AFF231C2BFF271E2BFF261F2EFF251F32FF241F34FF
+ 252035FF242033FF282130FF2A202CFF31242CFF2D2028FF28202BFF2E2630FF
+ 342C33FF3B2E2CFF4A3127FF573622FF653D20FF693C1BFF693B19FF693A1AFF
+ 693B1CFF673B1CFF643B1BFF623919FF653C1BFF653C1BFF653C1BFF653C1BFF
+ 663D1CFF663D1CFF673E1DFF673E1DFF653C1BFF643B1AFF633A19FF623918FF
+ 613817FF623918FF623918FF633A19FF613817FF623918FF633A19FF643B1AFF
+ 653C1BFF643B1AFF643B1AFF633A19FF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF683D1CFF683D1CFF683D1CFF
+ 683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF693E1DFF6A3F1EFF6A3F1EFF
+ 6A3F1EFF693E1DFF683D1CFF673C1BFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 693E1DFF693E1DFF693F1CFF693F1CFF6B3F1AFF6C401BFF6D411CFF6D411CFF
+ 6E411BFF6D401AFF6C3F19FF6C3F19FF6C3C18FF6D3D19FF6F3F1BFF71411DFF
+ 72431DFF72431DFF72431DFF72431DFF73451CFF74461DFF75481DFF73461BFF
+ 704318FF6F4217FF714419FF73461BFF6E411BFF6E431CFF6F431AFF6F431AFF
+ 72441BFF73461BFF73461BFF71461BFF7C5228FF9D7650FFB99877FFBEA186FF
+ B9A08CFFC2AFA0FFDCCCC0FFECE2DBFFEFF0EEFFECEEEFFFF7F0F3FFF7EEF1FF
+ F1ECEDFFFBF6F3FFF8F0E3FFE6D4B7FFB58D5CFFAB762DFFB47415FFC58313FF
+ C1830DFFBA8009FFBB8314FFBD8417FFB97D0BFFBC7F0BFFBD800CFFBD800CFF
+ BB7E0AFFBB7E0AFFBC7F0BFFBD800CFFBB7E0AFFBC7F0BFFBD800CFFBE810DFF
+ BE810DFFBD800CFFBC7F0BFFBB7E0AFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBA7D07FFBB7E08FFBD800AFFBE810BFF
+ BE810BFFBD800AFFBC7F09FFBB7E08FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF452CD0FF
+ 452DCFFF442DCBFF432CCAFF442CCCFF452DCDFF472FCFFF4833CCFF4635C2FF
+ 3C35A4FF353E7EFF374771FF3B4A78FF3C4A7AFF3F4D7DFF425182FF374A7DFF
+ 3C5185FF46588DFF47598EFF44538BFF3D4C84FF394781FF35467FFF3C4C87FF
+ 435590FF4A5E98FF485E98FF4D65A1FF5E78B4FF738FCBFF809ED9FF6483C0FF
+ 597AB9FF4B6DAFFF4162A7FF3C5AA1FF385199FF314893FF2E438EFF31418EFF
+ 32418AFF303C7EFF353C6EFF3F3F5DFF413842FF49352AFF583C24FF5E391DFF
+ 613A1AFF613A1AFF603919FF5F3818FF5F3818FF5E3717FF5E3717FF603919FF
+ 613A1AFF623B1BFF623B1BFF623B1BFF623B1BFF613A1AFF5F3919FF603A1CFF
+ 5E3A1CFF5D3B1EFF5D3B1EFF5D3A20FF5E3C1FFF603C1EFF623D1BFF623A17FF
+ 693F1AFF6C401BFF663C19FF623B1BFF623E20FF5E3D23FF533823FF312114FF
+ 271F18FF1F1D1DFF1A1922FF181826FF191828FF1E1928FF211A29FF261D2AFF
+ 271D2DFF271F30FF262033FF261F34FF262033FF27202FFF2A202CFF2E232BFF
+ 2A1F29FF271E2BFF2B2431FF332A34FF3B2D2FFF483129FF583825FF653D21FF
+ 693C1BFF693B19FF683B19FF673C1BFF673B1CFF633A1AFF613818FF643B1AFF
+ 653C1BFF653C1BFF653C1BFF663D1CFF663D1CFF673E1DFF673E1DFF643B1AFF
+ 633A19FF623918FF613817FF613817FF613817FF613817FF623918FF603716FF
+ 613817FF633A19FF643B1AFF653C1BFF643B1AFF633A19FF633A19FF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF
+ 683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF693E1DFF
+ 693E1DFF6A3F1EFF6B401FFF6A3F1EFF693E1DFF673C1BFF663B1AFF683F1EFF
+ 683F1EFF683F1EFF683F1EFF6A3F1EFF6A3F1EFF6A401DFF6A401DFF6B3F1AFF
+ 6C401BFF6D411CFF6D411CFF6E411BFF6D401AFF6C3F19FF6B3E18FF6C3C18FF
+ 6D3D19FF6F3F1BFF71411DFF72431DFF73441EFF72431DFF72431DFF73451CFF
+ 74461DFF74471CFF714419FF6E4116FF6E4116FF704318FF73461BFF6E4219FF
+ 6E4219FF6F431AFF714419FF72451AFF724519FF73461AFF71461BFF896039FF
+ AF8B67FFC3A485FFB69B81FFB49E8CFFD2C2B2FFF1E2D9FFF5EDE6FFF5F6F4FF
+ EBEDEEFFF5F0F2FFF6EFF2FFF0ECEBFFFEF7EEFFFAECD5FFE0C49BFFB48444FF
+ C4842FFFC8841BFFCA8412FFC3860EFFBC820BFFB9800DFFBD8312FFB77B09FF
+ BC7F0BFFBD800CFFBC7F0BFFBA7D09FFB97C08FFBB7E0AFFBD800CFFBB7E0AFF
+ BC7F0BFFBD800CFFBE810DFFBE810DFFBD800CFFBC7F0BFFBB7E0AFFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBC7F09FF
+ BD800AFFBE810BFFBE810BFFBD800AFFBC7F09FFBA7D07FFB97C06FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FF4229CDFF422ACCFF422ACAFF412AC8FF4028CAFF4028CAFF
+ 3F27C7FF3F2AC3FF4534C1FF3D36A5FF394281FF3B4C73FF3D4D78FF3D4C7AFF
+ 3F4D7DFF425182FF405184FF3F5186FF425287FF445489FF495890FF4C5B93FF
+ 43518BFF32427DFF31407EFF324382FF384A89FF3F5394FF485EA0FF4F67A9FF
+ 536DB0FF5571B2FF5776B5FF5273B2FF4C6EB0FF4869AEFF4462A9FF3D59A0FF
+ 344B96FF2E438EFF384895FF2B3A83FF2F3B7DFF3A4173FF3A3A58FF3B323CFF
+ 48352DFF563924FF5F3A1EFF603919FF5F3818FF613A1AFF643D1DFF653E1EFF
+ 643D1DFF623B1BFF653E1EFF653E1EFF643D1DFF633C1CFF623B1BFF603919FF
+ 5F3818FF5E3818FF603A1CFF5D391BFF5A381BFF5A381BFF5B391CFF5C3A1DFF
+ 603C1EFF643E1CFF643C19FF663C19FF663C17FF663C19FF623C1AFF613B1BFF
+ 603C1EFF593B22FF3C2A19FF291F15FF1C1716FF1A181EFF1A1A26FF191828FF
+ 1B1827FF211A29FF241B28FF241A2AFF231B2CFF211B2CFF211B2EFF211B2CFF
+ 241D2CFF261E29FF2C232DFF291F2BFF271F30FF2B2536FF332A37FF3A2C32FF
+ 4A322CFF5A3929FF633A21FF683D1CFF6B3E1CFF6C3F1DFF693E1DFF663D1DFF
+ 643A1DFF633A1AFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF673E1DFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF673E1DFF673E1DFF673E1DFF673E1DFF693E1DFF693E1DFF
+ 693F1CFF693F1CFF6A3E19FF6A3E19FF6B3F1AFF6C401BFF6D401AFF6C3F19FF
+ 6B3E18FF6B3E18FF6D3D19FF6E3E1AFF70401CFF72421EFF73441EFF74451FFF
+ 74451FFF73441EFF704219FF704219FF704318FF714419FF72451AFF72451AFF
+ 73461BFF73461BFF704318FF784B20FF72451AFF724317FF7A4B1FFF744519FF
+ 714418FF82582DFFA78059FFB4916FFFB89A7FFFAC947EFFAD9987FFC7B7AAFF
+ E8DCD2FFF8F0E9FFFBFAF6FFF7F9F9FFF5F2F4FFF1ECEDFFFAF6F1FFFFF8E6FF
+ E8D0ACFFC49E64FFB97E2EFFC47F1EFFC88112FFC8830EFFC2850FFFBE860FFF
+ BD820EFFBA7F0BFFBF820EFFBF820CFFBF820CFFBF820CFFBF820CFFBF820CFF
+ BF820CFFBF820CFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBD800AFFBD800AFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBB7E06FFBB7E06FFBB7E06FF4229CDFF422ACCFF4129C9FF
+ 4129C9FF4129CBFF4128CCFF4028CAFF402BC4FF4433C0FF3E38A5FF3A4480FF
+ 3D4E75FF3F4F7AFF3F4D7DFF404E7EFF435283FF425287FF425489FF45558AFF
+ 47578CFF4C5B93FF4D5B95FF42508BFF32417FFF354685FF364889FF394C8FFF
+ 3D5198FF41579FFF465DA8FF4B64AEFF4E6AB1FF5272B4FF4F71B3FF4F70B5FF
+ 4C6CB3FF4565ACFF3F5BA2FF374E99FF314691FF354794FF2B3A83FF2C3A7CFF
+ 384075FF3B3A5AFF3D3441FF49362FFF533824FF5D3B1EFF613A1AFF603919FF
+ 613A1AFF643D1DFF653E1EFF643D1DFF623B1BFF643D1DFF643D1DFF633C1CFF
+ 623B1BFF623B1BFF613A1AFF603919FF603919FF5F391BFF5D391BFF5B391BFF
+ 5B391BFF5C3A1DFF5F3B1DFF623C1CFF633C1CFF633A19FF663C19FF643C19FF
+ 643C19FF623C1AFF613C1AFF613B1BFF5B3A20FF46311CFF312317FF1F1815FF
+ 1B171CFF181824FF181727FF191625FF1E1726FF241B28FF251B28FF241A2AFF
+ 231B2CFF211B2EFF221C2DFF241D2CFF261D2AFF2A212EFF231C2BFF221D32FF
+ 2B263BFF322C3DFF3B2D38FF493230FF59392CFF643C23FF693E1DFF6B3E1CFF
+ 693F1CFF693E1DFF663D1DFF653B1EFF643B1BFF663D1DFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF693E1DFF693E1DFF693F1CFF693F1CFF6A3E19FF6A3E19FF6B3F1AFF
+ 6C401BFF6D401AFF6C3F19FF6B3E18FF6B3E18FF6F3F1BFF70401CFF71411DFF
+ 72421EFF72431DFF72431DFF71421CFF70411BFF704219FF704219FF704318FF
+ 714419FF714419FF72451AFF72451AFF72451AFF74471CFF774A1EFF75461AFF
+ 77481CFF7B4D1EFF75461AFF794E23FF90683EFFB08C68FFB79879FFB89E86FF
+ B09B86FFA99989FFB6A89CFFD2C6BCFFE4DCD5FFF3F2EEFFF4F5F3FFF1EEF0FF
+ F6F1F0FFFFF7EAFFE9D9BCFFC2A36EFFB18238FFBD7D1FFFC67E13FFC57E0CFF
+ C3810AFFBE840DFFBC840DFFBE810BFFBC7F09FFBE810BFFBE810BFFBE810BFF
+ BE810BFFBE810BFFBE810BFFBE810BFFBE810BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ 4029CBFF402AC9FF402BC8FF402AC9FF4028CCFF4129CDFF412ACCFF412DC6FF
+ 4333C0FF3D38A5FF3B4682FF3E5177FF41527DFF40507FFF404F80FF435185FF
+ 445489FF45568EFF48578FFF4B5A92FF505E98FF4D5B95FF3D4D88FF32417FFF
+ 3B4B8DFF3C4D90FF3A4E95FF394E99FF384F9BFF3C53A1FF425BABFF4763B0FF
+ 4D6DB6FF4F71B7FF5172BBFF4F70B9FF4868B1FF3F5CA6FF385199FF334B93FF
+ 334893FF293A83FF29397BFF364076FF3C3D5FFF3F3847FF4A3734FF4F3524FF
+ 5D3A20FF613A1AFF603919FF613A1AFF633C1CFF643D1DFF633C1CFF623B1BFF
+ 623B1BFF623B1BFF623B1BFF623B1BFF623B1BFF623B1BFF613A1AFF613A1AFF
+ 5F3818FF5F3919FF5E3B1AFF5D3C1BFF5D3B1DFF5F3C1BFF623B1BFF633A1AFF
+ 653A19FF633B18FF613B18FF613B18FF603B19FF603B19FF613B19FF5C3A1CFF
+ 51371FFF392919FF251A16FF1C161BFF191723FF181727FF191625FF1C1524FF
+ 251B28FF251B28FF241A2AFF231C2BFF211B2CFF221C2DFF241D2CFF241D2CFF
+ 262031FF1E192EFF1F1C35FF2C2943FF352F46FF392E3EFF463134FF57392EFF
+ 643E26FF683F1FFF693F1CFF683E1BFF683D1CFF663D1DFF663C1FFF663D1DFF
+ 663D1DFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 673E1DFF673E1DFF673E1DFF673E1DFF693E1DFF693E1DFF693F1CFF693F1CFF
+ 6A3E19FF6B3F1AFF6C401BFF6C401BFF6D401AFF6D401AFF6C3F19FF6B3E18FF
+ 70401CFF70401CFF71411DFF71411DFF71421CFF70411BFF6E3F19FF6E3F19FF
+ 6F4118FF704219FF704318FF704318FF714419FF714419FF714419FF714419FF
+ 7A4B1FFF744519FF714216FF734516FF724317FF72471CFF896137FFA88460FF
+ BA9B7CFFB69D83FFB39E89FFAC9C8CFFAB9D91FFB6AAA0FFCFC4BCFFE3DBD4FF
+ F0EDE8FFF2F1EDFFF2EDEEFFFCF4EDFFF9ECD6FFC8B086FF9F7833FFA67117FF
+ BF7B12FFC57C0AFFC27C07FFBE7E08FFB9810AFFBA820BFFBD8109FFBD8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FF3F29C8FF3F2AC7FF402BC8FF402AC9FF4129CDFF
+ 422ACEFF422BCDFF422EC7FF4232BFFF3D38A5FF3C4783FF405378FF435381FF
+ 425182FF414F83FF425287FF44538BFF475890FF4A5892FF4D5B95FF52609AFF
+ 4A5A95FF3A4987FF304180FF3B4D8EFF3C4F93FF3B4E97FF354C97FF334A98FF
+ 354E9EFF3D58A9FF4461B2FF4D6DB9FF4F72BCFF5173BFFF4D70BAFF4667B0FF
+ 3C5CA5FF38549BFF364F97FF324A92FF283C83FF293B7CFF344076FF3C3D63FF
+ 42394DFF4A3839FF4E3325FF5D3A20FF623B1BFF623B1BFF623B1BFF633C1CFF
+ 633C1CFF633C1CFF623B1BFF603919FF603919FF613A1AFF613A1AFF623B1BFF
+ 623B1BFF623B1BFF633C1CFF613818FF603A18FF5F3C1BFF5E3D1CFF5E3D1CFF
+ 5F3C1BFF613A1AFF623919FF663B1AFF643B1AFF603B19FF603B19FF603B19FF
+ 5F3A18FF623918FF5F3919FF593B22FF432D1BFF2B1E16FF1F1619FF191521FF
+ 1A1727FF1C1726FF1D1623FF241A26FF241A26FF251B28FF231C2BFF211B2CFF
+ 221D2CFF231F2BFF231E2DFF252337FF201D37FF21213FFF2D2C4CFF36324FFF
+ 392D43FF432E36FF52362FFF633E28FF674020FF693F1CFF673D18FF673C1BFF
+ 653C1BFF673D20FF673E1EFF663D1DFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF
+ 653C1BFF653C1BFF653C1BFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF
+ 643E1CFF643E1CFF643E1CFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF673E1DFF673E1DFF673E1DFF673E1DFF693E1DFF
+ 693E1DFF693F1CFF693F1CFF6B3F1AFF6B3F1AFF6C401BFF6D411CFF6E411BFF
+ 6D401AFF6C3F19FF6C3F19FF6E3E1AFF6F3F1BFF70401CFF70401CFF70411BFF
+ 70411BFF6F401AFF6E3F19FF704219FF704219FF704318FF704318FF704318FF
+ 704318FF704318FF704318FF75481CFF73461AFF75461AFF74471BFF71461BFF
+ 7E562CFF9E7A56FFB79879FFB69D83FFB5A18FFFB7A79AFFBCB0A6FFC5BAB2FF
+ D5CBC4FFE6DED7FFF0EAE3FFF4F1ECFFF5F2EEFFFAF3F0FFFDF1E5FFE4D1B0FF
+ AF9158FF9E701CFFB77D14FFC37D0CFFC67E08FFC07D08FFBC7E08FFB88009FF
+ B88108FFBD8008FFBC7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBA7D07FFBA7D07FFBA7D07FFBB7E08FFBB7E08FF
+ BB7E08FFBC7F09FFBC7F09FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FF402BC8FF402BC7FF
+ 402BC7FF412CC9FF422ACEFF422ACEFF432CCEFF432FC8FF4232BFFF3D38A5FF
+ 3C4783FF415479FF445482FF425182FF425085FF43528AFF44528CFF485992FF
+ 485893FF4C5C97FF53639EFF4A5A95FF394886FF344584FF3B4D8EFF394F91FF
+ 374D94FF334B93FF304A96FF344F9FFF3D5AABFF4664B5FF506EBFFF5071C1FF
+ 4D71BFFF476BB7FF4063ADFF385AA0FF36559AFF365398FF324C92FF283F83FF
+ 293D7EFF323F77FF393B63FF413950FF49383CFF4D3228FF5D3921FF633C1CFF
+ 633C1CFF633C1CFF623B1BFF623B1BFF623B1BFF623B1BFF5F3818FF5F3818FF
+ 603919FF603919FF613A1AFF623B1BFF623B1BFF653C1CFF643918FF633B18FF
+ 613C1AFF603D1BFF603D1BFF613C1AFF623918FF633817FF653C1CFF633C1CFF
+ 5F3C1BFF5F3C1AFF5E3B19FF5F3A18FF623A17FF603919FF5C3C1FFF4A311DFF
+ 332219FF221719FF1A141FFF1A1727FF1E1928FF221926FF231925FF241A26FF
+ 241A27FF221B28FF221D2CFF211E2DFF211F2BFF201F2FFF27273FFF232543FF
+ 262A4DFF2D3056FF333254FF362D47FF3E2D38FF4C322CFF603D29FF663E21FF
+ 683E1BFF673D18FF663B1AFF673C1BFF683C1FFF693D1EFF663D1DFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF633D1BFF633D1BFF
+ 633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF673E1DFF673E1DFF
+ 673E1DFF673E1DFF693E1DFF693E1DFF693F1CFF693F1CFF6B3F1AFF6C401BFF
+ 6D411CFF6D411CFF6E411BFF6E411BFF6D401AFF6C3F19FF6C3C18FF6D3D19FF
+ 6E3E1AFF70401CFF71421CFF71421CFF71421CFF70411BFF71431AFF71431AFF
+ 714419FF714419FF714419FF704318FF704318FF704318FF704318FF74491EFF
+ 7A4D22FF764B20FF7B5329FF916D49FFAB8C6DFFB69D83FFB2A08FFFC6B8ACFF
+ D9CFC8FFE1DBD6FFE8E1DEFFF0EBE8FFF6EFECFFF2EEE9FFF6F3EFFFF6F2EDFF
+ FFF9F2FFF8E7D2FFC8AE80FFA57E34FFAF7B17FFC58715FFC4810CFFC6820BFF
+ C0820CFFBE810BFFBA8108FFB98007FFBC7E08FFBC7E08FFBB7E08FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBA7D07FFBA7D07FF
+ BA7D07FFBB7E08FFBC7F09FFBC7F09FFBD800AFFBD800AFFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBD8008FFBD8008FF
+ BD8008FF412CC8FF412CC8FF412CC8FF422DCAFF422ACEFF422ACEFF422BCDFF
+ 422EC7FF4232BFFF3D38A5FF3B4682FF3F5278FF435381FF425182FF435186FF
+ 44528CFF43538EFF4A5A95FF495994FF4E5E99FF5767A2FF4A5C97FF3B4D8AFF
+ 3C4F8CFF3C518FFF3A5091FF374E92FF334D93FF314C96FF34539EFF3E5DACFF
+ 4465B5FF4C6CBFFF496BBEFF456ABCFF4066B4FF3A5FA9FF35599FFF335499FF
+ 335395FF324F94FF2A4487FF2C4081FF323F77FF373962FF3E3851FF4A3740FF
+ 4F332CFF5D3921FF633C1CFF643D1DFF633C1CFF613A1AFF603919FF613A1AFF
+ 623B1BFF5F3818FF5F3818FF5F3818FF603919FF613A1AFF613A1AFF623B1BFF
+ 643B1AFF653B18FF663C19FF623C19FF613D19FF613D19FF603B19FF623918FF
+ 633817FF673E1EFF643D1DFF613E1DFF5E3D1CFF5F3C1BFF603B19FF653B18FF
+ 623918FF5F3B1DFF51341FFF3C281DFF271B1BFF1B131EFF1B1526FF201928FF
+ 231A27FF231925FF231A24FF231B26FF221B28FF221D2CFF211E2DFF22202CFF
+ 1F1F2FFF262945FF2C3152FF2F355EFF2D335CFF2E2E56FF332E4BFF3F2E3BFF
+ 482F2BFF5C3B28FF653D20FF663E1BFF673D18FF663C19FF663B1AFF673B1CFF
+ 673B1CFF663D1DFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF
+ 633D1BFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF673E1DFF673E1DFF673E1DFF673E1DFF693E1DFF693E1DFF693F1CFF
+ 693F1CFF6C401BFF6C401BFF6D411CFF6E421DFF6F421CFF6E411BFF6D401AFF
+ 6D401AFF6B3B17FF6C3C18FF6E3E1AFF70401CFF72431DFF72431DFF72431DFF
+ 72431DFF73451CFF73451CFF72451AFF72451AFF72451AFF714419FF714419FF
+ 714419FF6D4217FF73491EFF6E441AFF683F18FF7B5630FFA07F5EFFB89D83FF
+ BCA896FFCDBFB3FFE5DCD8FFF9F5F4FFF7F4F6FFF1EEF0FFF2F0F0FFF5F1F0FF
+ F1EDECFFF4F0EFFFF8F2EDFFFFF5EBFFE7D2B7FFB39156FFA4751FFFB98112FF
+ C18208FFC3840CFFC4840EFFC18410FFBD830CFFBD8306FFBB8005FFBB7E0AFF
+ BC7E0CFFBB7E08FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBA7D07FFBB7E08FFBB7E08FFBC7F09FFBD800AFFBE810BFFBE810BFF
+ BF820CFFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FF412FC8FF412FC8FF402EC7FF402DCAFF
+ 402BCEFF402BCEFF3F2ACCFF3F2DC6FF4134BEFF3A37A4FF374580FF3B5076FF
+ 3F527FFF3F5083FF415088FF45538DFF465593FF4C5E9BFF4A5C99FF4F619EFF
+ 5B6DA8FF50629DFF42548FFF475A97FF445996FF3D5694FF385294FF335093FF
+ 325196FF35559CFF3C5CA7FF3F60AFFF4264B8FF3F62B8FF3E62B6FF3C61B1FF
+ 3A5FA9FF375BA1FF345698FF315192FF345194FF2D498AFF2D4384FF303F77FF
+ 32365FFF3A3550FF483643FF4E342EFF5B3922FF643D1DFF653E1EFF643D1DFF
+ 613A1AFF603919FF613A1AFF623B1BFF5F3818FF5F3818FF603919FF603919FF
+ 603919FF603919FF613A1AFF633A19FF693C1AFF693D18FF643D17FF603C16FF
+ 5F3B15FF603A17FF643918FF643918FF683F1FFF663F1FFF603E20FF5D3E1DFF
+ 5E3D1CFF613C1AFF663C19FF653A19FF613B1DFF583922FF452F24FF2B1D1EFF
+ 1A121DFF171221FF1E1726FF211825FF221824FF231A24FF231B26FF201C28FF
+ 201D2CFF1F1F2DFF20202CFF1E2032FF252946FF31395EFF383E6BFF2E3461FF
+ 2A2C55FF342F4FFF423243FF492F2FFF5A3926FF623C1EFF653D1AFF673D18FF
+ 663C19FF663B1AFF65391AFF643819FF663D1DFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF673E1DFF673E1DFF673E1DFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 693E1DFF693E1DFF693F1CFF693F1CFF6C401BFF6D411CFF6E421DFF6E421DFF
+ 6F421CFF6F421CFF6E411BFF6D401AFF6E3E1AFF6F3F1BFF70401CFF72421EFF
+ 72431DFF72431DFF72431DFF71421CFF74461DFF74461DFF74471CFF73461BFF
+ 73461BFF72451AFF72451AFF70451AFF6E441AFF70481EFF673E17FF6C451FFF
+ 967351FFC1A386FFD5BEA8FFDACABDFFE8DFDBFFF0EEEEFFF5F6FAFFEFF2F7FF
+ E8EBF0FFEAEBEFFFEFEFEFFFF1EFEFFFF2F0F0FFF8F1EEFFF1E3D7FFCDB492FF
+ AC823FFFAB7818FFBF820CFFBE7E01FFBE8109FFBD820EFFBE830FFFBD840BFF
+ BD8204FFBC8004FFBC7E0CFFBB7F0EFFBC7F0BFFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FFBC7F09FFBC7F09FFBD800AFF
+ BE810BFFBF820CFFC0830DFFC0830DFFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF4430C9FF
+ 4430C9FF432FC8FF432ECBFF422BCDFF3F2ACDFF3F2ACCFF3F2DC8FF4134C0FF
+ 3A37A5FF364284FF3A4D78FF3D507BFF3E507FFF425287FF46548EFF475996FF
+ 4E619EFF4C5F9CFF5164A1FF5E71AEFF5366A3FF465996FF4E63A0FF48609CFF
+ 425B99FF3A5697FF355295FF345398FF36569FFF3959A4FF385CAAFF395EB0FF
+ 375CB0FF385EB0FF3960AFFF3960AAFF375EA3FF33569AFF2E5092FF345496FF
+ 2F4B8CFF2F4684FF2F3F74FF2E345FFF373350FF433646FF4A3534FF583825FF
+ 613D1FFF643E1EFF643D1DFF613B19FF5F3818FF5F3919FF613B1DFF5F391BFF
+ 5F391BFF5F3919FF603919FF603A18FF603A18FF603A18FF623918FF683E1BFF
+ 673D18FF633B18FF603B15FF5E3A16FF5F3916FF643918FF653A19FF694020FF
+ 674020FF63401FFF603F1EFF613E1DFF623D1BFF643B1AFF643B1AFF633B1EFF
+ 5F3D25FF4F3525FF34211CFF1C1218FF17101DFF1B1423FF1D1623FF221824FF
+ 231A24FF231B25FF201C27FF1E1E2CFF1E1E2EFF1F1F2FFF1A1E36FF1D254AFF
+ 303B67FF384474FF2A3464FF242A55FF343053FF433547FF473133FF553726FF
+ 5E391DFF633D1AFF673D18FF673D18FF653B18FF633817FF623617FF683D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF673E1DFF
+ 673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF683D1CFF663D1DFF663D1DFF663D1DFF643D1DFF
+ 643E1CFF643E1CFF643E1CFF663D1CFF663D1CFF683D1CFF663D1CFF623C1AFF
+ 613D19FF613C1AFF623C19FF623C1AFF623C19FF623C19FF623C19FF623C19FF
+ 643C19FF643C19FF643C19FF643C19FF643C19FF643C19FF663C17FF6B3F1AFF
+ 6B4019FF6B4019FF6C4017FF6C4017FF6E4116FF6E4115FF6E4115FF714314FF
+ 724415FF734418FF734418FF734418FF734418FF724317FF714117FF73421CFF
+ 73421CFF74431DFF73441EFF72431DFF72431DFF70411BFF70411BFF764721FF
+ 734620FF734620FF72461DFF72471CFF73461AFF744519FF744617FF704317FF
+ 764C22FF714B28FF886649FFC2A78DFFE8D3BEFFF1E1D4FFF6EBE3FFEDE8E7FF
+ E8E4E9FFE4E4EAFFE7EAEFFFECEFF4FFEEF1F5FFEFEEF2FFECEBEDFFF5F3F3FF
+ FDF4EBFFE9D4BEFFBF9E70FFAF7F31FFB97F18FFC2850DFFBF8204FFBA7D07FF
+ B87F0CFFBC810DFFBD8109FFBE8103FFBD7F03FFBC7E0CFFBC800FFFBC7F09FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBD800AFFBE810BFFBF820CFFC0830DFFC1840EFFC1840EFFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FF
+ BC7E08FFBC7E08FFBC7E08FFBC7E08FFBC7E08FFBC7E08FFBC7E08FFBB7D07FF
+ BB7D07FFBB7D07FF4B30CDFF492ECBFF452DC9FF452CCAFF452DCDFF452ED0FF
+ 442CD0FF422CCBFF4636C9FF3E38AFFF393E8DFF3B497EFF3F517AFF42557BFF
+ 485788FF4D5C94FF4D619AFF4D659FFF4F67A3FF5169A5FF596DAEFF5C70B1FF
+ 5569AAFF485E9FFF526BABFF5570B0FF526DB0FF4360A5FF314E98FF2A4895FF
+ 314FA0FF3759ACFF446DBCFF3B67B4FF3561AEFF3862ADFF3D66AFFF3C64ACFF
+ 365CA4FF33559BFF3A5BA0FF314D8EFF2F4481FF2E3F72FF2D335CFF353553FF
+ 3F384DFF44343BFF4C3224FF56381DFF5E3B1AFF5F3A18FF5D3714FF5B3614FF
+ 5B3719FF5B391CFF5D3C22FF5C3C1FFF5F3C1BFF613C1AFF613B18FF633C16FF
+ 623C19FF623C19FF613916FF613916FF5E3816FF5E3815FF5F3917FF603A18FF
+ 633A19FF643B1AFF633D1BFF633D1BFF633E1CFF633E1CFF643F1DFF66401EFF
+ 66401EFF683F1FFF693E23FF633A23FF5A3A23FF472E1EFF231614FF191219FF
+ 1C1726FF1C1726FF231A24FF251B21FF1F191EFF1C1B24FF1C2130FF1A1F34FF
+ 20243CFF2B3253FF324070FF2F4078FF324179FF2B386CFF2A305DFF373658FF
+ 3F3748FF3B2B2CFF50392AFF593B20FF603C18FF623C12FF633B11FF643912FF
+ 643813FF623815FF653A19FF653A19FF653A19FF653A19FF653A19FF653A19FF
+ 653A19FF653A19FF673C1BFF673C1BFF673C1BFF673C1BFF673C1BFF673C1BFF
+ 673C1BFF673C1BFF643C19FF643B1AFF663B1AFF663A1BFF683A1BFF663A1DFF
+ 643A1DFF623A1DFF613B1DFF5F3C1BFF5D3C1BFF603D1CFF653F1DFF663D1CFF
+ 693C1BFF653A19FF66421EFF63421BFF613F1BFF623E18FF613D19FF613D17FF
+ 623D17FF623D17FF6A431DFF693F1AFF653C15FF673C15FF6A3F18FF6D401AFF
+ 6D401AFF6E4116FF703F11FF71400EFF71410DFF74420DFF79470DFF7E4A0EFF
+ 814E10FF855011FF895415FF865112FF814E10FF7D4B0FFF7C4A10FF78470FFF
+ 74430BFF713E0CFF774118FF774019FF744119FF72441BFF73471EFF74481FFF
+ 74451FFF71411DFF774626FF6C3F1EFF6A3F1EFF704623FF724A20FF724819FF
+ 774815FF7B4914FF82501CFF73461AFF987357FFD7BAABFFEFDED5FFF6EBE7FF
+ F7F1ECFFEDE8E7FFF4EDF0FFF6F0F5FFF3EDF2FFEEEBEDFFEFEFEFFFF1F0F2FF
+ F0EEF4FFF1EDF2FFF3F0EBFFF3E8D4FFCCB185FFA67C3BFFB57E23FFC7891DFF
+ BF800EFFB77903FFBB7F0DFFB77B09FFB97D05FFC18307FFC38306FFC08003FF
+ BC7F07FFBF820CFFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBD800AFFBD800AFFBD800AFFBD800AFFBC7F09FFBB7E08FF
+ BB7E08FFBA7D07FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FF
+ BC7F07FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7E08FFBC7D0AFFBB7C09FFBB7C09FFBA7B08FFBA7B08FFBB7C09FF
+ BB7C09FFBC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFF4A30CAFF472FCBFF472FCBFF
+ 4930CEFF4931D1FF4932D4FF472FD5FF452ED0FF4333C7FF3B33AFFF393B93FF
+ 3C4783FF40527BFF42557BFF485589FF4A5892FF475E96FF46619AFF4A64A0FF
+ 4F68A6FF596FB0FF5D73B5FF566CAEFF4961A3FF4F6AAAFF536FB0FF5570B3FF
+ 4A68AFFF3C59A4FF32509FFF3754A9FF3D5FB3FF3F6BB8FF3869B3FF3865AFFF
+ 3562ACFF3760A9FF345DA6FF355AA4FF3558A1FF36569DFF304C8DFF304680FF
+ 314071FF2E365EFF333554FF3C3851FF413640FF483226FF55371EFF5C3A1CFF
+ 5F3A18FF5E3815FF5C3814FF593719FF57391CFF57391EFF583A1FFF5E3D1CFF
+ 633F1BFF643F19FF653E17FF623D17FF613C16FF623C1AFF613B19FF613B19FF
+ 603A18FF603A18FF613B19FF623C1AFF633D1BFF633D1BFF633D1BFF643E1CFF
+ 643E1CFF653F1DFF653F1DFF66401EFF663F1FFF6C3F24FF643820FF5F3A1EFF
+ 4E311CFF2D1C13FF1B1215FF1A1622FF1B1625FF201721FF261C22FF211B20FF
+ 191822FF13192CFF101732FF1B203FFF293159FF34457DFF304380FF2D3F7AFF
+ 263469FF242A57FF323355FF403A4BFF413436FF4A3526FF54391EFF5E3C18FF
+ 643E14FF683E14FF693F15FF693D18FF693C1AFF653A19FF653A19FF653A19FF
+ 653A19FF653A19FF653A19FF653A19FF653A19FF673C1BFF673C1BFF673C1BFF
+ 673C1BFF673C1BFF673C1BFF673C1BFF673C1BFF643C19FF643B1AFF663B1AFF
+ 663A1BFF683A1BFF663A1BFF643A1DFF623A1DFF5B3719FF5C3B1AFF5E3E1BFF
+ 603E1AFF623D17FF653C15FF693C16FF6A3E15FF643D11FF623D11FF613C10FF
+ 633C0FFF643D10FF684010FF694110FF6B4211FF6B400DFF6D410CFF6E420CFF
+ 73450FFF784911FF7A4B13FF7B4C14FF7D4E11FF814F0DFF85520CFF89550FFF
+ 8F5A11FF976114FF9F6718FFA56D1CFFA8701EFFAA7220FFA76F1EFFA26A1BFF
+ 9E671CFF9A651CFF96621CFF925D1AFF8F591AFF905720FF89501DFF7D4815FF
+ 744410FF70440FFF724512FF754416FF754319FF78441FFF73431FFF724520FF
+ 72481EFF71471AFF744714FF7E4B13FF844F16FF905E2AFF9D7349FFCAAA93FF
+ F5E0D8FFF9EFEFFFF2F0F0FFF4F2F2FFF1EFEFFFF7F1F6FFF3EDF2FFF3EEF0FF
+ F3F1F1FFF3F1F0FFF3F3F3FFF4F0F5FFF1ECEDFFFAF2E5FFE2D1B0FFBA9A5FFF
+ A97A29FFBB7F1BFFC38313FFBE7F0DFFC38513FFBD810FFFB97E0AFFBC8005FF
+ C28408FFC48407FFBF8204FFBC8008FFBD830CFFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBD8008FFBC7F07FFBC7F07FF
+ BB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FFBC7D0AFFBC7D0BFFBC7D0BFF
+ BD7E0CFFBD7E0CFFBC7D0BFFBC7D0BFFBC7D0BFFBC7D0BFFBC7D0BFFBC7D0BFF
+ 4633CAFF4532C9FF4531CAFF4732CEFF4934D1FF4831D3FF452DD3FF422BCDFF
+ 4330C5FF3C31AFFF3A3A94FF3E4786FF425080FF435280FF46508CFF485496FF
+ 445996FF445F98FF48629EFF4F68A6FF5A70B1FF5F75B7FF556DAFFF4961A3FF
+ 4560A0FF4965A6FF506BAEFF4C6BB0FF405DA8FF32509FFF3452A5FF385DAFFF
+ 3C68B5FF396AB4FF3B68B1FF3562ABFF335CA5FF315AA3FF355AA4FF385BA4FF
+ 315198FF314C8FFF324784FF324074FF2F3661FF353658FF3C3953FF443844FF
+ 493328FF55371EFF5B391BFF5F3A18FF5E3815FF5D3816FF5A381AFF57391CFF
+ 54361BFF56381BFF5D3C1BFF64401CFF66411BFF674019FF633E18FF613C16FF
+ 653F1DFF643E1CFF633D1BFF623C1AFF613B19FF623C1AFF633D1BFF633D1BFF
+ 633D1BFF633D1BFF643E1CFF643E1CFF643E1CFF653F1DFF653F1DFF653F1DFF
+ 6C4021FF633A1AFF5F3919FF54361DFF372417FF201414FF18121DFF1A1622FF
+ 1B131DFF241C23FF221A24FF161525FF101430FF0E1739FF1C224BFF2C3666FF
+ 374881FF334683FF32427DFF29356BFF242A57FF303153FF433A4EFF47393BFF
+ 4D3627FF573A1FFF623E1AFF674117FF6C4218FF6D4118FF6B3F1AFF6A3D1BFF
+ 663B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF663B1AFF643B1AFF623B1BFF613B1BFF
+ 5F3919FF623D1BFF64401CFF663F18FF673E11FF693E0DFF70410DFF74450FFF
+ 71420CFF71420CFF72430BFF75450BFF78490CFF7C4C0CFF7F4F0DFF83520CFF
+ 86550BFF8A590BFF8F5E0EFF956310FF976610FF9A6810FF9B6911FF9E6A10FF
+ A37014FFA57113FFA87214FFAA7514FFAF7815FFB47C17FFB97E1AFFBB801CFF
+ BB801CFFB97E1BFFB67C1DFFB57C21FFB67D27FFB57E29FFB47C2BFFB2792AFF
+ AF7026FFA56720FF975D15FF88550CFF81500AFF7E4E0CFF804D0FFF804A13FF
+ 7A440FFF7C4714FF7A4813FF774510FF79470DFF814D11FF90581DFF97612AFF
+ 9D7142FFC1A17EFFF2DAC8FFFFF5EEFFFAF5F4FFF0EEEEFFF0EFEBFFF3F0ECFF
+ FBF6F7FFF2EFF1FFF2F1F5FFF0F1F5FFE9EBECFFF1F1F1FFF9F7F7FFF9F1EAFF
+ EDE0C6FFC1AA7CFFA47D39FFAD7B23FFC0841AFFBF7E0BFFBD7E0BFFC98C18FF
+ BC830FFFB9810AFFBD8207FFC08408FFC28507FFBE8206FFB9810AFFBB820EFF
+ BA8009FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BA7D07FFBA7D07FFBA7D07FFBA7D07FFBA7D07FFBB7E08FFBB7E08FFBB7E08FF
+ BD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FF
+ BC7D0AFFBD7E0CFFBF800EFFC0810FFFC0810FFFBF800EFFBD7E0CFFBC7D0BFF
+ BC7D0BFFBC7D0BFFBC7D0BFF4236CCFF4034CAFF4031C9FF3F2FCAFF412ECBFF
+ 402BCDFF3F27CBFF3E26C6FF4532C5FF3E33AFFF3B3C94FF3F4888FF425080FF
+ 435181FF454E8EFF475296FF435895FF445F98FF48619FFF4E67A5FF596FB1FF
+ 5D73B5FF536BADFF475FA1FF415C9CFF4460A0FF4C67AAFF4B6AAFFF3F5EA9FF
+ 304F9EFF2F4FA2FF355AACFF3965B2FF3B6AB4FF3D6AB3FF3A65AEFF3760A9FF
+ 385FA9FF395EA8FF395CA6FF2D4D96FF324D90FF354A87FF334175FF313863FF
+ 37385AFF3D3A54FF443A46FF483429FF543820FF59391CFF5D3A19FF5E3917FF
+ 5E3917FF5A381AFF59391CFF53351AFF55371AFF5C3B1AFF633F1BFF67401AFF
+ 674019FF643F19FF643E1BFF653F1DFF643E1CFF623C1AFF613B19FF613B19FF
+ 613B19FF613B19FF623C1AFF633D1BFF633D1BFF643E1CFF643E1CFF643E1CFF
+ 643E1CFF643E1CFF643E1CFF6A421FFF623A17FF613916FF5D3B1DFF432C1CFF
+ 261714FF181118FF191521FF1A121CFF231B26FF211A29FF1B182EFF1B1F42FF
+ 202955FF2A3365FF334078FF314380FF324582FF374782FF323E74FF2B3160FF
+ 313254FF41384CFF443539FF51392DFF5B3D24FF66411FFF6D441DFF6E431CFF
+ 6D401AFF693D18FF673A18FF673C1BFF653C1BFF653C1BFF653C1BFF653C1BFF
+ 653C1BFF653C1BFF653C1BFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643C19FF623C19FF623C19FF
+ 623C19FF613C1AFF613C1AFF66401DFF67401AFF684016FF6B4112FF71450FFF
+ 784C0DFF80510DFF86540CFF8C5812FF8E5811FF915A11FF925B10FF975F12FF
+ 996211FF9D6611FF9F6A10FFA87214FFAD7615FFB27A15FFB37C14FFB37B10FF
+ B27A0DFFB37C0DFFB57D10FFBA8217FFB98116FFB88013FFB88011FFBA800FFF
+ B9800DFFBB7F0EFFBB7F0EFFBB7F0EFFBA7D0FFFBA7C12FFBB7D17FFBD801EFF
+ BF8224FFBF8127FFBE8026FFBF7E22FFB97A1EFFB07518FFA87116FFA16C15FF
+ 996715FF946014FF905A13FF87500BFF905712FF8E560FFF8B530CFF925914FF
+ 9F6523FFB07335FFB37F4AFFB28F67FFDAC3A9FFFAEBDBFFF8F0E9FFF0EEEDFF
+ EEEFEDFFF2EFEBFFF4F1ECFFFAF6F5FFF2F2F2FFF2F5FAFFEAEEF3FFDEE1E5FF
+ EFEFEFFFFFFBF6FFFAEEDCFFCBB78EFFA8894CFFA07322FFB98221FFC78818FF
+ C28009FFBD7F09FFC1840EFFBA810DFFB9810AFFBD8207FFBF8307FFBD8306FF
+ BA8106FFB5800BFFB6800DFFBA8009FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFB97C06FFB97C06FFB97C06FFB97C06FFB97C06FF
+ BA7D07FFBC7F09FFBC7F09FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FF
+ BC7F07FFBC7F07FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7E08FFBD7E0BFFBE7F0DFFC18210FFC28311FFC28311FF
+ C18210FFBE7F0DFFBD7E0CFFBC7D0BFFBC7D0BFFBC7D0BFF4037CEFF3D34CBFF
+ 3B2FC9FF3B2DC9FF3D2BCAFF412BCAFF4129CBFF4229C7FF4733C2FF4034ACFF
+ 3C3B91FF3F4783FF404E7EFF425080FF444F8DFF455395FF3D5591FF3F5C95FF
+ 47609EFF4C65A3FF546CAEFF5870B2FF526AACFF4961A3FF4863A3FF4B67A7FF
+ 516CAFFF4F6EB3FF4363ACFF3656A2FF3556A6FF395EAEFF3965B2FF3C6BB5FF
+ 3E6BB4FF3E69B2FF4069B2FF4269B3FF3E62AEFF3858A3FF2D4D96FF365194FF
+ 374C8AFF324075FF323865FF37395CFF3D3956FF453B48FF47342CFF523722FF
+ 59391CFF5D3A19FF5F3A18FF5F3A18FF5B391BFF59391CFF55371CFF58381BFF
+ 5D3A19FF603C18FF653E18FF674019FF66411BFF67411EFF633D1BFF623C1AFF
+ 603A18FF5F3917FF5F3917FF5F3917FF5F3917FF603A18FF643E1CFF643E1CFF
+ 633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1AFF67401AFF643B14FF
+ 643C12FF643F1DFF503521FF301E17FF191215FF18141FFF1C141FFF231A27FF
+ 20172CFF201B3AFF2F325FFF3B457BFF3D4B86FF3A4B8AFF304283FF324382FF
+ 374684FF344076FF2E3262FF333155FF3F364BFF423337FF51392DFF5B3D24FF
+ 674220FF6D441DFF6F441DFF6E411BFF6B3E19FF693C1AFF683D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF653C1BFF653C1BFF
+ 653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF643B1BFF643B1AFF
+ 623C19FF613D19FF5F3D19FF5F3D19FF5F3D19FF613D19FF6A431DFF693F14FF
+ 6C3E0EFF74450DFF875612FF946416FF9C6A17FFA16D13FFAA7116FFAC7114FF
+ AC7114FFAC7213FFAF7313FFB17612FFB37811FFB77A12FFBA7C10FFBB7F0EFF
+ BE800EFFBC7F0BFFBA7C06FFB97C04FFBB7F04FFBE8109FFB87C0AFFB87C0AFF
+ B97E0AFFBC7F09FFBD800AFFBF820AFFC1810BFFC1810BFFC1810BFFBD7E0BFF
+ BC7C0CFFBB7B0FFFBC7A13FFBA7A14FFB87715FFB67512FFC38118FFC28115FF
+ BE8014FFBB8117FFB6801BFFB17B1CFFA9731CFFA56E19FFA66D18FFAF741EFF
+ AF731AFFAE7219FFB87C2AFFBC8237FFC28547FFC19060FFCFB696FFEEE2D0FF
+ FBF7ECFFEDEDE7FFEBECEAFFF1F2F0FFF5F2EDFFF8F4EFFFF5F2EDFFEEF0F0FF
+ EDF3F8FFE2E9F2FFE1E5EAFFF8F6F5FFFCF3E6FFE4D1B0FFAD8F56FFA47A2DFF
+ AD791BFFC1851BFFC58411FFC5840AFFC0830BFFB77E05FFB77F08FFB88108FF
+ BA8205FFBB8104FFB98104FFB68108FFB17F0DFFB07E0CFFB88009FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBA7D07FFB97C06FF
+ B87B05FFB87B05FFB97C06FFBA7D07FFBC7F09FFBD800AFFBD8008FFBC7F07FF
+ BC7F07FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FFBD7E0BFFBE7F0CFF
+ C1820FFFC28310FFC28310FFC1820FFFBE7F0CFFBD7E0BFFBC7D0AFFBC7D0AFF
+ BC7D0AFF3D32CFFF3B30CDFF3A2CCAFF3D2CC9FF402EC7FF442FC7FF472EC6FF
+ 452EC0FF412CB1FF3B2E9CFF3A3787FF3E457EFF414E7CFF41507EFF434E8AFF
+ 435291FF38508CFF3C5894FF465F9DFF4A63A3FF4E66A8FF536BADFF5169ABFF
+ 4A64A6FF4964A4FF4F6BABFF5371B2FF4D6CB1FF4262ABFF3B5BA7FF3859A9FF
+ 375CACFF3D67B4FF416EB8FF446FB8FF416CB5FF446BB5FF466DB7FF4163AFFF
+ 3555A0FF31519AFF3B5699FF384D8BFF2D3D72FF313A66FF393B5EFF3B3754FF
+ 433848FF48352EFF503723FF56381DFF5D391BFF603B19FF613C1AFF5C3A1CFF
+ 58381BFF58371DFF58381BFF5D3A19FF603A17FF643D17FF663F19FF68401DFF
+ 67411EFF613B19FF603A18FF5F3917FF5E3816FF5E3816FF5E3816FF5F3917FF
+ 603A18FF643E1CFF643E1CFF633D1BFF633D1BFF633D1BFF623C1AFF623C1AFF
+ 623C19FF613D15FF663E14FF693E13FF6B411CFF5C3D24FF3C281DFF1E1617FF
+ 19141DFF1C1621FF211A29FF1C132DFF201C40FF393D72FF4E5898FF48589DFF
+ 3C5097FF35488BFF334385FF32417FFF2D3871FF282C5DFF2F2D51FF3F364BFF
+ 46363DFF4C3329FF573821FF623C1CFF6A401BFF6E421DFF6F421DFF6F411FFF
+ 6E4120FF693E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF643B1BFF623C1AFF613C1AFF5F3C1AFF5D3D1AFF5D3D1AFF5F3D19FF
+ 623D17FF693F14FF6D3F0FFF75440CFF875310FF9D6818FFAC781EFFB3801FFF
+ B7821AFFB87E15FFB97D13FFBA7C10FFB97B0FFFB97C0EFFBB7C0EFFBC7D0DFF
+ BE7F0DFFBD7C09FFBD7D07FFBF7C07FFBD7B04FFBF7C02FFC07D03FFC38005FF
+ C4820BFFB97A07FFB97B09FFBB7E0AFFBD7F09FFBF810BFFC1820AFFC1820AFF
+ C1820AFFC2830BFFC0800AFFBE7D0AFFBD7D0DFFBE7D11FFBE7D14FFBC7A13FF
+ BA7811FFC07F12FFBE7F0DFFBD7E0CFFBB7F0EFFBA8114FFB88119FFB67F1EFF
+ B47C1DFFB67C1CFFBF8420FFC0821CFFC08420FFC58930FFBD8337FFBB8348FF
+ BD9369FFE4D2BBFFF4F2E7FFFBFEF5FFEAF0EBFFE9EBEBFFEEEFEDFFF2EEE9FF
+ F2EEE9FFF1F1EBFFEBEEECFFE5EDF4FFE4EBF4FFF0F3F8FFFFFBF6FFECDCC5FF
+ C1A477FFA77D36FFB07D21FFBA7F18FFBF8010FFBF7D06FFC3840AFFC3870FFF
+ B57D06FFB37E06FFB88108FFBA8205FFB88003FFB98005FFB7830BFFB18111FF
+ AF7F0FFFB87F0BFFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBC7F09FFBB7E08FFB97C06FFB87B05FFB97C06FFBA7D07FFBC7F09FF
+ BD800AFFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FFBC7F07FF
+ BD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7D0AFFBD7E0BFFBF800DFFC0810EFFC0810EFFBF800DFFBD7E0BFF
+ BC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFF3A29D1FF3A28CFFF3B28CBFF3F2AC6FF
+ 422DBFFF412DB6FF4028AEFF3C26A4FF311E92FF302484FF333177FF3D4378FF
+ 414F79FF40517CFF3F4E86FF3E508DFF3B538FFF405C98FF4763A0FF4661A1FF
+ 475FA1FF4960A4FF4862A4FF4660A2FF4661A1FF536FAFFF5775B6FF4F6FB1FF
+ 4565AEFF4262AEFF3E5FAEFF365CAAFF3E68B3FF4673BCFF4A75BEFF426DB6FF
+ 4067B1FF3F66B0FF3C5EAAFF34549FFF36569FFF405AA0FF364C8DFF2B3A72FF
+ 313968FF383B61FF383654FF3F3546FF483530FF4F3725FF55371EFF5B391CFF
+ 613B1BFF623C1CFF5E3A1CFF58381BFF57371AFF5A381AFF603A1AFF623C19FF
+ 663F19FF663F19FF673F1CFF653F1CFF613B19FF613B19FF603A18FF5F3917FF
+ 603A18FF613B19FF623C1AFF623C1AFF643E1CFF643E1CFF633D1BFF633D1BFF
+ 623C1AFF623C1AFF613B19FF613B18FF5D3812FF664016FF6E4115FF6F421CFF
+ 654228FF483122FF261A1AFF18141AFF1C1621FF21192AFF18112CFF19153FFF
+ 353974FF4A599EFF435AA6FF364E9AFF384C93FF314384FF2C3B7AFF27326CFF
+ 222758FF2B2A51FF3E344BFF47373EFF4B3228FF55361FFF603A1AFF673D18FF
+ 6B3F1AFF6D401BFF6E3F1FFF6E4120FF683F1EFF66401EFF66401EFF66401EFF
+ 66401EFF66401EFF66401EFF66401EFF653F1DFF653F1DFF653F1DFF653F1DFF
+ 653F1DFF653F1DFF653F1DFF653F1DFF643B1AFF623C1AFF613B1BFF5F3C1BFF
+ 5D3B1DFF5D3C1BFF613C1AFF643D16FF6C3E0FFF794810FF8C5615FF9F671AFF
+ AE741BFFB67D1AFFBB8318FFBD8516FFBC800FFFBB7F0DFFBC7E0CFFBA7C0AFF
+ BA7C0AFFBB7C0AFFBB7C0AFFBB7C09FFBE7C0BFFBD7B0AFFBF7B0AFFC07C0BFF
+ C47E0CFFC6800EFFC6800FFFC47F10FFBD7D11FFBC7E12FFBD8012FFBF8010FF
+ BE800EFFBE7F0DFFBC7D0AFFBB7C09FFBD7E0BFFBC7D0AFFBB7C0AFFBC7D0DFF
+ C08113FFC08216FFBF8117FFBE8016FFC08014FFBD7E10FFBB7C0CFFB97D0CFF
+ B77E11FFB98017FFB77F1AFFB77F1AFFB87E15FFC08517FFBD8110FFB97F15FF
+ B88126FFAF7C33FFB98A56FFD0AF8EFFF0E5D7FFF2F3EFFFF1F8F3FFE9F0EBFF
+ E8EDECFFEDEDEDFFF0EBE8FFEEE9E6FFF3F2EEFFEAEFEEFFE1EAF3FFE7EEF7FF
+ FAF7F9FFFBEDE1FFD9BE99FFB18A4CFFB4802DFFBB801CFFC08014FFBF7E0BFF
+ BF7D06FFC2830BFFC18410FFB87F0BFFB47E09FFBA820BFFBD8409FFBA8205FF
+ BC8308FFBB870FFFB68616FFB58313FFB87F0BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBF820CFFBD800AFFBB7E08FFB97C06FF
+ B97C06FFBA7D07FFBC7F09FFBD800AFFBD8008FFBC7F07FFBC7F07FFBB7E06FF
+ BB7E06FFBC7F07FFBC7F07FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7D0AFFBC7D0AFFBC7D0AFFBD7E0BFF
+ BD7E0BFFBC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFF3C24D0FF
+ 3D24CCFF3E26C6FF4129BDFF422BAFFF3B279EFF321E8FFF2C1883FF261479FF
+ 261A72FF2E2B70FF3B4176FF414E7AFF40507EFF3E4C86FF3A4C8BFF415A98FF
+ 4864A1FF4D68A8FF4761A3FF42599DFF40579BFF3F599BFF3E589AFF4965A5FF
+ 5978B7FF6080C1FF5577B9FF4E6FB8FF4D70BAFF486CBAFF3D63B1FF3F69B4FF
+ 4A77C0FF4F7AC3FF446DB6FF3960AAFF385DA7FF385AA6FF33539FFF3A59A4FF
+ 445EA4FF364C8DFF273871FF2F3968FF383A62FF373454FF3C3347FF473633FF
+ 503727FF55361FFF5B391CFF613B1BFF623C1CFF5E3A1CFF5A381BFF583619FF
+ 5A381AFF613B1BFF673F1CFF6A401BFF693F1AFF653D1AFF623C19FF623C1AFF
+ 623C1AFF613B19FF613B19FF623C1AFF633D1BFF643E1CFF653F1DFF643E1CFF
+ 643E1CFF633D1BFF633D1BFF623C1AFF613B19FF613B19FF613B19FF593511FF
+ 674019FF724218FF71421CFF6C4529FF503626FF2D1E1BFF1B1419FF1D151FFF
+ 1F192AFF140F2CFF120F3CFF29316DFF41529BFF3954A4FF2C4A99FF364C94FF
+ 2F4083FF293779FF26306CFF23275AFF2A2950FF3C3249FF44333CFF4F352EFF
+ 583924FF613B1DFF643C19FF683B19FF6A3C1AFF6A3B1CFF6A3C1DFF683F1EFF
+ 66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF
+ 66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF643B1AFF
+ 623C1AFF613B1DFF5F3A1EFF5D3B1EFF5F3B1DFF623C1AFF693E13FF72420EFF
+ 895415FFA3691DFFB37620FFB77A18FFB67A10FFB77A0CFFB97D0BFFBD7F0DFF
+ BD7F0DFFBB7D0BFFBA7C0AFFB97B09FFBA7B09FFBA7B09FFBB7C0AFFBB7C0AFF
+ BC7A0AFFBC7A0AFFBE7C0CFFC37E0FFFC37E0FFFC07B0CFFBA770AFFBB7B0FFF
+ BA7C10FFBC7E12FFBD8012FFBD8110FFBC800EFFBD7F0DFFBA7F0BFFBE810DFF
+ BA7F0BFFBB7E0AFFB97D0BFFBA7E0DFFBB7F0EFFB97C0EFFB7790DFFBE8218FF
+ BC8016FFBD8012FFBD8110FFBD8214FFBA8114FFB67D14FFB37A11FFBB8012FF
+ BE8413FFB87C0AFFB1790EFFAB7B23FFA77D3CFFC4A078FFF3DBC7FFFFF7F0FF
+ EFF4F3FFE8F1EEFFE7F0EDFFEEF2F3FFF8F5F7FFF9F3F4FFF4EFEEFFF5F6F4FF
+ EEF3F2FFE6EEF5FFEEF1F6FFFDF1EFFFF0D9C3FFD0AB79FFB8873DFFC2872AFF
+ C38219FFC07E0EFFC3800DFFC3830DFFBF800DFFBA7E0CFFB87F0CFFB57E0BFF
+ BC840DFFC1860BFFBE8308FFBE850CFFC08A15FFBC8A1AFFBB8617FFB87F0CFF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFC0830DFF
+ BF820CFFBC7F09FFBA7D07FFB97C06FFBA7D07FFBC7F09FFBD800AFFBD8008FF
+ BC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FF
+ BB7C09FFBB7C09FFBA7B08FFBA7B08FFBB7C09FFBB7C09FFBC7D0AFFBC7D0AFF
+ BC7D0AFFBC7D0AFF3F21C8FF4324C5FF4528BDFF4028ACFF3A2395FF311D80FF
+ 2A1774FF271570FF2D1C77FF211468FF2B286DFF41457FFF414E82FF3D4D82FF
+ 3F4E8DFF3D4E91FF405999FF4865A2FF526EAEFF526EAFFF4C66A9FF4862A5FF
+ 4C66A8FF526CAEFF5773B3FF6685C4FF7B9BDCFF6284C6FF6385CBFF4C6FB9FF
+ 4D71BFFF3A60AEFF4169B4FF3E69B2FF3F68B1FF3C65AEFF3960AAFF385DA7FF
+ 385AA6FF3959A5FF4261ACFF415AA2FF304688FF273871FF2F3969FF333760FF
+ 343355FF433A4EFF463637FF4F3829FF543722FF5A391FFF633D1FFF653F1FFF
+ 633F21FF603E20FF5C3A1DFF5F3B1DFF633D1BFF673F1CFF693F1AFF693F1AFF
+ 663E1BFF643E1CFF653F1DFF633D1BFF613B19FF603A18FF603A18FF613B19FF
+ 633D1BFF653F1DFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF5E3818FF663E1BFF73421AFF74431DFF693E23FF543625FF
+ 36231EFF1A1114FF1D151CFF1E1829FF17122FFF171844FF2F3A78FF3E55A0FF
+ 3354A4FF264797FF2E4590FF304387FF304082FF2C3773FF282E63FF33335BFF
+ 423953FF44353DFF4A322CFF543623FF5F3B1DFF653D1AFF693C1AFF683B19FF
+ 663819FF633718FF653C1BFF643E1CFF633D1BFF603A18FF5E3816FF5F3917FF
+ 633D1BFF66401EFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF
+ 633D1BFF633D1BFF68401DFF633D1BFF603A1CFF613920FF623D23FF663E22FF
+ 683E1BFF6D3F10FF7E4A0EFF955E15FFAD701AFFB57818FFBA7B13FFBF7F13FF
+ C08010FFBE7D10FFBB7B0FFFBA7C12FFBB7D11FFBB7D11FFBB7D11FFBD7D11FF
+ BC7D0FFFBB7C0EFFBE7F11FFBE7E0EFFBC7C0CFFBB7B0BFFBC7A09FFBC7A09FF
+ BD7B0AFFBC7D0BFFBA7B0BFFB97D0CFFB77D0CFFB87F0CFFB9800CFFB9810AFF
+ BC820BFFBA820BFFBA8009FFB9810AFFBC820BFFBC840DFFBC830FFFBC830FFF
+ BE8210FFBB8012FFBE841DFFBA8019FFB77B11FFB67B0DFFBA7D0FFFBB8012FF
+ BC8016FFBC8016FFBA7F11FFB67C0BFFBF8718FFB4821EFF9D7124FFB2905BFF
+ E6CDB3FFFDEDE6FFF4EFEEFFEBEFF0FFE9F0EDFFE9F0EDFFEEF0F1FFF4F0F5FF
+ FAF3F8FFFBF4F7FFEDEDEDFFEDEFEFFFE8EBEFFFF9F5F4FFFFECDFFFD1AE8CFF
+ AF7F3FFFC0852FFFC18220FFC28115FFBF7C0FFFBE7C0BFFBE7F0DFFBF8010FF
+ BB8012FFB88011FFBC8310FFBD820EFFBF820AFFBF820AFFBF820AFFBC810DFF
+ B88112FFB98213FFB87C0AFFBD800CFFC0830FFFC0830FFFBE810DFFBD800CFF
+ BD800CFFBE810DFFBA7D09FFBA7D09FFBA7D09FFBA7D09FFBA7D09FFBA7D09FF
+ BA7D09FFBA7D09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBD800AFFBD800AFFBC7F09FFBB7E08FFBB7E08FFBC7F09FF
+ BD800AFFBD800AFFBA7D05FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FF
+ BE8109FFBE8109FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FF
+ BD7F09FFBD7F09FFBE800AFFBE800AFFBE800AFF492CBDFF4228B2FF3920A0FF
+ 2F188CFF2A1578FF26146FFF2A166FFF2A1873FF1B0967FF1D0E6AFF2C2675FF
+ 3C3C82FF3B4581FF374580FF3B498BFF3D5093FF445F9FFF4C68A8FF5571B2FF
+ 5672B3FF536DB0FF516BAEFF556FB2FF5A76B7FF5170AFFF5B7CBBFF6F8FD0FF
+ 5B7EC0FF6082C8FF4D70B9FF5074C0FF436AB5FF4069B2FF3E69B2FF4069B2FF
+ 4067B1FF4065AFFF3B60AAFF3658A4FF3454A0FF3D5BA8FF3C559DFF2E4486FF
+ 283873FF323B6DFF353962FF343355FF3E374CFF443638FF4D372CFF523723FF
+ 59371FFF623C1EFF643D1DFF633D1FFF603C1EFF5E391DFF5F3B1DFF633D1BFF
+ 683E1BFF6A3E19FF693F1AFF673E1DFF653F1DFF653F1DFF633D1BFF613B19FF
+ 603A18FF603A18FF613B19FF633D1BFF653F1DFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF613B1BFF5F3B1DFF653E1EFF71401AFF
+ 703E1AFF693D20FF583724FF39261FFF221616FF1F151BFF1C1524FF1A1731FF
+ 282B57FF3E4D8BFF415CA6FF2E53A5FF24499BFF2C4791FF2F4488FF314184FF
+ 2E3B79FF2D3269FF36355FFF3F3853FF42323DFF4B3530FF553724FF5C3A1DFF
+ 613B19FF653A19FF653A19FF65391CFF643A1DFF623B1BFF633D1BFF623C1AFF
+ 603A18FF5E3816FF5F3917FF623C1AFF653F1DFF633D1BFF633D1BFF633D1BFF
+ 633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF673F1CFF643E1CFF643C1FFF
+ 633B1FFF653A1FFF683C1DFF6E4017FF75430EFF8E5712FFA26816FFB47618FF
+ BB7C14FFBE7D11FFC07F12FFC27F12FFBD7C10FFBD7C13FFBB7C14FFBE7C15FF
+ BD7F15FFBF7E15FFBE7E12FFBD7D11FFBD7E10FFBD7E0EFFBD7E0EFFBC7E0CFF
+ BB7E0AFFBB7C09FFBB7D07FFBB7D07FFBB7D07FFBD800CFFBB800CFFBA7F0BFF
+ BA7F0BFFBA8009FFB88009FFB88009FFB88009FFB9810AFFBA820BFFBB830CFF
+ BE830FFFBE830FFFBE8210FFBF810FFFBA7F11FFBE841DFFB88119FFB77D13FF
+ B97D0CFFBB7F0EFFBF8010FFBD7F13FFBD7F13FFBD7F13FFC0841AFFBF8722FF
+ B08028FFAD8747FFCEB18AFFF2DED3FFFBF0F2FFF0EDEFFFECEEEFFFEBF0EFFF
+ EBF0EFFFF0EFF3FFF2EEF4FFF5EDF4FFF5EDF4FFF0EDEFFFEDEDEDFFF5F3F2FF
+ FAF0E6FFE6CBB1FFBC9362FFB0762AFFBC7A1BFFC17F19FFC07E15FFBD7C0FFF
+ BD7C0FFFBD7E10FFBD8012FFBD8215FFBB8314FFBB8110FFBC810DFFBE800AFF
+ C08109FFBE800AFFBD800CFFBA800FFFBB8012FFB67A08FFBB7E0AFFBE810DFF
+ BE810DFFBD800CFFBC7F0BFFBC7F0BFFBE810DFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBE810BFFBD800AFFBC7F09FF
+ BB7E08FFBB7E08FFBB7E08FFBC7F09FFBD800AFFBB7E06FFBC7F07FFBC7F07FF
+ BC7F07FFBD8008FFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD7F09FFBD7F09FFBD7F09FF
+ BD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBE800AFFBE800AFFBE800AFF
+ 3B2792FF36228CFF2F1A81FF291477FF261370FF27126FFF251073FF250D79FF
+ 2E1489FF382495FF3F3397FF3D3A90FF373D84FF333F7FFF384688FF405495FF
+ 435E9EFF4766A5FF506CADFF536EB1FF516BB1FF516CAFFF5671B4FF5A76B7FF
+ 5978B7FF597AB9FF6687C6FF567ABAFF5A7DC1FF486BB4FF4C70BCFF466DB8FF
+ 426BB4FF416BB2FF426AB2FF436BB3FF4469B3FF3D62ACFF3557A3FF2F4F9BFF
+ 3A58A5FF364F99FF2B4084FF283A75FF333E70FF353B66FF323256FF3A3249FF
+ 44363AFF4B362EFF503625FF56371EFF5E3A1CFF623B1BFF603A1CFF5F391BFF
+ 603A1CFF603A1AFF643B1AFF663C19FF6A3E19FF693F1AFF683F1EFF69401FFF
+ 653F1DFF633D1BFF613B19FF603A18FF603A18FF613B19FF633D1BFF653F1DFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF613B1BFF
+ 603D23FF643D21FF6C3C1AFF6D3B17FF683C1FFF5C3925FF412B20FF2A1B18FF
+ 251A1CFF1C141FFF1A1933FF343C64FF4B5E9BFF4262ABFF2E54A6FF2C52A4FF
+ 2D4A95FF2E448BFF324287FF303F7DFF31386FFF383A63FF3E3954FF3E303BFF
+ 4B3732FF543827FF5A391FFF5E3917FF5F3917FF633A19FF643A1DFF643C1FFF
+ 613A1AFF613C1AFF603B19FF5E3917FF5D3816FF5D3816FF603B19FF633E1CFF
+ 623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF
+ 643E1CFF653F1DFF683F1FFF683C1DFF683919FF6E3D15FF794614FF854F10FF
+ A06718FFB17319FFBB7D17FFBF7F13FFBE7D10FFC07D10FFC07C11FFBF7B10FF
+ BF7D14FFBF7E15FFC17F16FFC08014FFC18013FFC18111FFC08010FFBF800EFF
+ BC7D0AFFBD7E0BFFBD7F09FFBD8008FFBD8008FFBC8005FFBB7F04FFBA7E03FF
+ BF820AFFBF820AFFBE800AFFBD800AFFBC7F09FFB97F08FFB87E07FFB87D09FF
+ BC800EFFBD810FFFBE8211FFC08111FFC08113FFBF7F13FFBF7E12FFBD7C13FF
+ BD831AFFBA8217FFBB8012FFBC810DFFC0810EFFC1820FFFC18111FFBF7F13FF
+ C07E17FFC58828FFB68029FFAD8037FFC7A675FFEFD7BFFFFDEDEEFFF9EFFBFF
+ EFEBF0FFEEEEEEFFF0F0F0FFF1F1F1FFF0EFF3FFF0ECF2FFF0E8F2FFEFE8EFFF
+ F9F4F6FFF5F0EDFFFEF5ECFFEBD8C3FFBA976FFFA47434FFB77820FFC27D16FF
+ BF7C15FFBE7D14FFBE7D14FFBD7D11FFBD7D11FFBC7E12FFBD8215FFC08517FF
+ BC800FFFBE800EFFBE7F0CFFBF7F09FFBF7E0BFFBE7F0CFFBE7F0FFFBE7F0FFF
+ B77907FFBA7D09FFBC7F0BFFBD800CFFBB7E0AFFBA7D09FFBB7E0AFFBD800CFF
+ BE810DFFBE810DFFBE810DFFBE810DFFBE810DFFBE810DFFBE810DFFBE810DFF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BF820CFFBE810BFFBD800AFFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBC7F09FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FFBF820AFFBF820AFF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BE8109FFBE8109FFBE8109FF2D1E72FF27176EFF21106BFF200E6CFF261273FF
+ 2C177EFF30168BFF311695FF4A2FB5FF553DBFFF4D3EB1FF3A3696FF343984FF
+ 333F7FFF394886FF445794FF435E9EFF4563A4FF4D68ABFF4F6AADFF4F69AFFF
+ 506AB0FF546FB2FF5773B4FF5E7CBDFF5879B8FF5C7FBEFF5579B9FF557ABEFF
+ 456BB3FF4970BAFF4C73BDFF4972BBFF456FB6FF426AB2FF4169B1FF4368B2FF
+ 3E63ADFF3758A7FF31509FFF3D5BA8FF324D97FF283F83FF2B3D7AFF364175FF
+ 373D68FF34335AFF37314AFF44363CFF49362FFF4F3525FF55351EFF5C371BFF
+ 603919FF5E381AFF5C3618FF603A1CFF613A1AFF633A19FF663C19FF693D18FF
+ 693F1CFF6B401FFF6A4120FF653F1DFF633D1BFF613B19FF603A18FF603A18FF
+ 613B19FF633D1BFF653F1DFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF613B1DFF603C24FF613B23FF683A18FF6A3A16FF673E1EFF
+ 5E3C24FF473021FF321F1AFF2C1E1FFF1C141EFF181830FF2E3A62FF465E9AFF
+ 3F62ABFF3058AAFF325AACFF31509BFF2F488EFF2F4488FF304180FF303B74FF
+ 383B67FF3E3A57FF3D313DFF493633FF533928FF583A1FFF5E3B1AFF603A1AFF
+ 603A1AFF633B1FFF623C1EFF5F3919FF603B19FF603B19FF5E3917FF5C3715FF
+ 5D3816FF5F3A18FF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF
+ 623D1BFF623D1BFF623D1BFF633D1BFF673E1DFF6A401DFF6A3D17FF6E3D11FF
+ 784310FF8C5315FF9B6115FFAF731AFFB87917FFBD7F15FFC07F12FFBD7C0FFF
+ BD7C0FFFBF7B12FFBE7C13FFBE7D10FFBF7E11FFC07F12FFC18111FFC18111FF
+ C0810FFFBF800EFFBE7F0CFFBB7D07FFBC7E08FFBD8008FFBE8207FFBE8207FF
+ BD8106FFBB7F03FFBA7E02FFC08109FFC08109FFBE800AFFBD7F09FFBC7F0BFF
+ BA7F0BFFB97D0BFFB97D0CFFBD8012FFBE8113FFC08014FFC07F16FFC17F16FF
+ BF7C15FFC07B14FFBD7A13FFBC7F17FFB98013FFBD8110FFC0830FFFC2840EFF
+ C38411FFC68316FFC3811AFFBE7E1FFFBD812DFFAA772EFFB1894FFFE1C5A3FF
+ FFEEE1FFFAEDF5FFF3ECF9FFF1EDF2FFF2F0F0FFF2F0F0FFF3F0F2FFF2EEF3FF
+ F1EDF3FFF0EBF4FFF1EAF1FFF8F2F3FFFFF7F0FFFFF2DFFFDAC09CFFA67D46FF
+ A67023FFC48321FFC88419FFBE7D14FFBE7F17FFBE8016FFBC7E12FFBA7C10FF
+ BA7D0FFFBD8012FFC08413FFBB7F0EFFBD7F0DFFBD7E0BFFBC7E08FFBC7D0AFF
+ BD7E0CFFBE7F0DFFBE7F0DFFBC7E0CFFBE810DFFBF820EFFBE810DFFBB7E0AFF
+ BA7D09FFBB7E0AFFBC7F0BFFBE810DFFBE810DFFBE810DFFBE810DFFBE810DFF
+ BE810DFFBE810DFFBE810DFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBF820CFFBE810BFFBD800AFFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBE8109FFBE8109FFBE8109FFBE8109FFBE8109FF
+ BF820AFFBF820AFFBF820AFFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FF292069FF211666FF
+ 1A0B67FF1A076EFF241081FF351D99FF462AB3FF4D30C3FF492BC4FF5037C7FF
+ 4235AFFF302C91FF303683FF354280FF3B4983FF3F538DFF46629FFF4866A7FF
+ 4E6BAEFF506DB2FF526CB2FF526CB2FF546FB2FF5773B4FF5977B8FF5273B2FF
+ 5679B8FF567ABAFF567CBDFF4B72B7FF5178C2FF5980CAFF5079C2FF4973BAFF
+ 4169B1FF3F65ADFF4164AEFF3F62ACFF3A5BAAFF3756A5FF415FACFF324D97FF
+ 294084FF2E407DFF364175FF373C69FF35355DFF37324DFF42353DFF49362FFF
+ 4F3426FF553420FF5C371BFF5E381AFF5D3719FF5B3517FF603A1CFF623B1BFF
+ 663B1AFF693C1AFF6A3E19FF693F1CFF6A3F1EFF683F1FFF653F1DFF633D1BFF
+ 613B19FF603A18FF603A18FF613B19FF633D1BFF653F1DFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF613B1DFF5B3922FF5F3921FF
+ 663C19FF683D16FF69401FFF603F25FF4D3323FF38231BFF2D1B1AFF1D141EFF
+ 14162EFF25345BFF3C5894FF3D62ACFF305AADFF325AADFF3755A2FF314A92FF
+ 2E448BFF304281FF303D75FF363C67FF3D3B58FF3E3641FF453431FF513828FF
+ 593B22FF5D3E1DFF613E1DFF603D1CFF613A1EFF60391DFF5E3818FF603B19FF
+ 603B19FF5F3A18FF5D3816FF5D3816FF5F3A18FF613C1AFF613C1AFF613C1AFF
+ 613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF623B1BFF663D1CFF
+ 6B3E18FF704010FF79440BFF88510CFFA06515FFB3751BFFB77816FFBA7C12FF
+ BC7D0FFFBE7D10FFBC7B0EFFBA7A0EFFBD7B12FFBF7E12FFBC7C0CFFBF7E0BFF
+ C07F0CFFC1800DFFC1800DFFC07F0CFFBD7E0BFFBC7E08FFBA7C06FFBB7D07FF
+ BD7F09FFBE8109FFBE8109FFBD8008FFBC7F07FFBB7E06FFBE7D0AFFBE7D0AFF
+ BD7E0CFFBD7E0CFFBC7D0DFFBB7F0EFFBB7E10FFB97E11FFBB7F15FFBC7F17FF
+ BE7E18FFC07E18FFC17D18FFBF7B16FFC07917FFBD7914FFBC7A13FFBB7D11FF
+ BD8110FFBE8210FFC28511FFC48515FFC8851EFFC78526FFC0822EFFB37D36FF
+ A67B42FFC4A479FFF6E1CBFFFFF4ECFFEFE7F1FFF1EDF9FFF2F1F5FFF3F1F1FF
+ F3F0F2FFF2EEF3FFF3EFF4FFF4F0F5FFF5F1F7FFF8F3F5FFF1EAE7FFFFFBEDFF
+ FFE9CBFFD1B07FFFB0853CFFB78228FFC68620FFC18014FFBE8016FFBE8119FF
+ BE8218FFBE8014FFBA7E0DFFBB7D0BFFBC7E0CFFBF820EFFBD800CFFBD800CFF
+ BC7F0BFFBB7E0AFFBB7D0BFFBD7E0CFFBE7F0DFFBE7F0DFFC28412FFC38513FF
+ C38513FFC08210FFBD7F0DFFBA7C0AFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7F0BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBF820CFFBE810BFF
+ BC7F09FFBB7E08FFBB7E08FFBB7E08FFBC7F09FFBC7F09FFBF820AFFBF820AFF
+ BF820AFFBE8109FFBE8109FFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FF1D1568FF211771FF291984FF332097FF3F28ACFF462EBCFF4B30C6FF
+ 4A2FCCFF4028C4FF4530C2FF3E33ADFF353496FF363C87FF384583FF394781FF
+ 354782FF405B9BFF4563A4FF4D6AAFFF4F6CB1FF4F69AFFF4D67ADFF4F6AADFF
+ 506EAFFF5576B5FF5376B5FF597CBBFF587EBEFF567CBDFF4D74B9FF5077C1FF
+ 587FC9FF517BC2FF4C74BCFF466CB4FF4066AEFF4063ADFF3F62ACFF3B5CABFF
+ 3859A8FF3E5CA9FF2E4894FF293F86FF314281FF364076FF343A67FF36365EFF
+ 39344FFF42353DFF483530FF4E3428FF543520FF5A371DFF5F391BFF5D3719FF
+ 5C3618FF603A1CFF623B1BFF683D1CFF6B3E1CFF6B3F1AFF6B3E1CFF683D1CFF
+ 653C1CFF653F1DFF633D1BFF613B19FF603A18FF603A18FF613B19FF633D1BFF
+ 653F1DFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 613B1DFF58361FFF5D3921FF653D1AFF673E17FF66411BFF624022FF513622FF
+ 402A1FFF2A1714FF1F141CFF141830FF22325CFF3A5794FF3C63AEFF305AADFF
+ 2E56A9FF3959A5FF304C93FF2E478DFF314586FF2E3D75FF333966FF3A3B57FF
+ 3E3744FF433431FF4F3828FF583D23FF5C3F20FF603E20FF613D1FFF5F3A1EFF
+ 5E391DFF5E3818FF603B19FF613C1AFF603B19FF5E3917FF5E3917FF5F3A18FF
+ 613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF
+ 613B1BFF633B1EFF643B1AFF6C3F13FF77460EFF89530CFF9D6311FFB27416FF
+ BF8018FFBD7D11FFBC7B0EFFBB7A0DFFBC7D0FFFBC7C10FFBA7910FFBC7B12FF
+ BF7F13FFBC7C0CFFBC7D0AFFBF7E0BFFBE7F0CFFC07F0CFFBD7E0BFFBC7D0AFF
+ BC7D0AFFBA7B08FFBA7D09FFBC7D0AFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7D0AFFBB7C0AFFBB7C0AFFBC7C0CFFBC7D0DFFBB7E10FFB97E10FFBA7F12FF
+ B87E14FFB87E15FFB97F16FFBC7F17FFBE7F17FFC07E17FFC07D16FFBF7B16FF
+ BE7A15FFBD7A13FFBD7C13FFBD8012FFBE8113FFC08315FFC3851BFFC58624FF
+ C5862EFFC1873FFFB38447FFBA976BFFE1C9ABFFFFF3E3FFF7F2EFFFEBE9EFFF
+ F0F2FAFFF2F4F5FFF3F2F4FFF3EFF4FFF4EEF3FFF3EFF4FFF5F1F6FFF5F4F6FF
+ FAF5F6FFFAEFEBFFFFF3E0FFEACDA6FFC0995BFFB78834FFC28B28FFC3871DFF
+ BF7F13FFBF8319FFBD8319FFBE8316FFBE8211FFBD7F0DFFBB7E08FFBB7E08FF
+ BB7F07FFBE810BFFBC820BFFBB800CFFBA7F0BFFBA7E0CFFBD7F0DFFBE810DFF
+ BF800DFFC48614FFC58715FFC48614FFC18311FFBD7F0DFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7E0AFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBD800AFFBC7F09FFBC7F09FFBB7E08FFBB7E08FFBC7F09FFBD800AFF
+ BE810BFFBF820AFFBF820AFFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FF231684FF302096FF402EB1FF4E38C6FF
+ 533AD0FF4D35CFFF432CCAFF3C27C3FF422FC4FF4234BBFF433DACFF3F409AFF
+ 384086FF384381FF3A4484FF324284FF375193FF3F5D9EFF4B68ADFF4E6BB0FF
+ 4D66AEFF4A64AAFF4B68ABFF4F6DAEFF5172B1FF577BB7FF5E81C0FF5D83C3FF
+ 547ABBFF4C73B8FF4B73BBFF5079C2FF4C74BCFF4A72BAFF4A70B8FF476DB5FF
+ 4669B3FF4063ADFF3B5CABFF3758A7FF34529FFF253F8BFF263C83FF324483FF
+ 344076FF333968FF36355FFF383451FF40353FFF483530FF4E3428FF553522FF
+ 5B381EFF603A1CFF5F391BFF5D3719FF61391CFF653C1CFF693F1CFF6D411CFF
+ 6E411CFF6A3D1BFF653A19FF613818FF653F1DFF633D1BFF613B19FF603A18FF
+ 603A18FF613B19FF633D1BFF653F1DFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF613B1DFF58361EFF5E3B21FF663F19FF663E14FF
+ 633F17FF603F1EFF573A25FF4C3226FF2F1B16FF21161EFF151931FF23355EFF
+ 3A5996FF3D65B0FF325BB0FF3158ADFF3557A3FF2E4C93FF304A90FF33498AFF
+ 2E3F77FF303965FF363856FF3D3643FF433733FF4E3A29FF553C22FF5B3E1FFF
+ 5F3D1FFF5E3C1EFF5E3C1FFF5E3C1FFF5D3A19FF5F3C1AFF603D1BFF603D1BFF
+ 5E3B19FF5D3A18FF5E3B19FF603D1BFF5E3B19FF5E3B19FF5E3B19FF5E3B19FF
+ 5E3B19FF5E3B19FF5E3B19FF5E3B1AFF623B1FFF643B1AFF704212FF845112FF
+ 9B6512FFAF7515FFBC7E12FFC0810FFFC18210FFBD7E0CFFBC7B0EFFBE7E12FF
+ BE7E12FFB97B11FFBA7C12FFC08014FFBC7D0FFFBD7E10FFBF7E11FFBE7F11FF
+ BF7E11FFBE7F11FFBD7E10FFBC7D0FFFBA7B0DFFB87B0DFFBA7B0DFFB87B0DFF
+ B97C0EFFBA7D0FFFBB7E10FFBB7F0EFFBC7D0DFFBC7D0DFFBA7E0DFFB87E0DFF
+ B67E0FFFB57E0FFFB67F10FFB67E11FFB67E11FFB77F12FFB98013FFBA8213FF
+ BC8113FFBE8113FFBF8010FFBF7E12FFC17D18FFC17F19FFBD8018FFBA8017FF
+ BA8017FFBC811DFFBF8329FFBE8536FFB68344FFB9905FFFD6BB99FFF7E9D3FF
+ FAF6EBFFEFF3EEFFEEF2F3FFEFF4F5FFEFF4F3FFF1F3F4FFF2F0F6FFF4F0F6FF
+ F3EFF4FFF3F0F2FFF1F1F1FFF5F2EEFFFFF5EDFFEED8BFFFC7A776FFAD833CFF
+ B28223FFBA861CFFBC8419FFBE841AFFBC8218FFBB8215FFBC8113FFBD810FFF
+ BF820CFFBF8308FFBD8106FFBC8004FFBF8409FFBC830AFFB9800CFFB9800DFF
+ B9800DFFBB7F0DFFBE810DFFBF820EFFC18311FFC28412FFC18311FFBF810FFF
+ BC7E0CFFBB7D0BFFBD7F0DFFBF810FFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7E0AFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BC7F09FFBD800AFFBE810BFFBF820CFFBE8109FFBE8109FFBE8109FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBB7E06FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FF4131B4FF
+ 4533BCFF4933C7FF4833CCFF4630CCFF442FCCFF4330CDFF4533CCFF402FC0FF
+ 3C31B0FF403CA5FF3E4196FF303982FF313D7FFF3C4588FF3A488AFF3C5293FF
+ 4460A1FF536EB1FF5572B7FF516EB3FF4E6BB0FF4F6FB1FF5575B6FF4566A5FF
+ 5175B1FF5B80BEFF5D83C3FF527ABBFF4E77BCFF4D77BEFF527BC4FF456DB5FF
+ 4A71B6FF4E75BAFF5073BCFF4B6EB7FF4265AFFF395BA7FF3555A1FF2A4994FF
+ 1D3980FF263B7FFF344683FF344076FF323867FF33355EFF363451FF3E3440FF
+ 463532FF4E3426FF563521FF5E391DFF613A1AFF603A1CFF5E381AFF613A1AFF
+ 653C1CFF6A401DFF6E411FFF6E411FFF683E1BFF643918FF5F3615FF673E1DFF
+ 653D1AFF633A19FF623A17FF623918FF633B18FF653C1BFF673F1CFF643B1AFF
+ 643C19FF643B1AFF643C19FF643B1AFF643C19FF643B1AFF623B1BFF5B381EFF
+ 613C20FF663F19FF623C12FF5F3B13FF603D1BFF5C3E23FF553928FF3D261EFF
+ 271B21FF141932FF203562FF365999FF3C63B1FF375FB2FF3C61B5FF3254A0FF
+ 2E4B95FF324C92FF374D8EFF304179FF2F3863FF343753FF3C3542FF453935FF
+ 4F3B2AFF553C22FF593B1EFF5B3C1DFF5E3C1EFF5F3C22FF603E21FF5B3A19FF
+ 5F3C1AFF613E1CFF613F1BFF5F3C1AFF5E3B19FF5F3C1BFF603C1EFF5E3A1CFF
+ 5E3B1AFF5E3B1AFF5E3B19FF5E3B1AFF5E3B1AFF5E3B1AFF603A1CFF653B1EFF
+ 6A3D17FF784611FF8D5912FFA77217FFB98017FFBD8110FFBB7C09FFC58614FF
+ C08010FFBD7D11FFBE8016FFBE8016FFB87C12FFB87D10FFBC8114FFBC7E12FF
+ BC7E12FFBD7F13FFBE8014FFBE8113FFBD8012FFBC7F11FFBC7F11FFB97C0EFF
+ B67B0DFFB77A0CFFB57A0DFFB67B0EFFB77C0FFFB97E11FFBA7F11FFBC7F11FF
+ BC800FFFBB7F0EFFB97F0EFFB67E0DFFB47E0CFFB47D0EFFB37C0DFFB57D10FF
+ B67E11FFB77F12FFBA8213FFBA8213FFBC8211FFBE8210FFBD8012FFC1811BFF
+ C0821EFFBF811BFFBA7F18FFB97E17FFB87E1FFFBA812CFFB6823CFFA67A45FF
+ B59571FFE4D1BCFFFCF6EBFFEDEEEAFFEAEFEDFFF4F9F7FFEDF2F0FFEEF3F1FF
+ F0F2F2FFF7F0F7FFF7EFF9FFF3EFF5FFEFEEF2FFEAECEDFFF0ECE7FFFEEEE1FF
+ D7BB9CFFB38D53FFAC7F2EFFB2801CFFB58012FFB77F14FFBB8117FFBB8215FF
+ B98112FFB97F0EFFBC810DFFC0830DFFC2850DFFBF8308FFBC8005FFC0850AFF
+ BD840BFFBA810DFFBA810EFFBA810EFFBC810DFFBF820CFFC0830DFFBD800CFF
+ BE800EFFBE800EFFBD7F0DFFBB7D0BFFBB7D0BFFBE800EFFC18410FFBD7F0DFF
+ BD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBC7F09FF
+ BC7F09FFBD7F09FFBC7F09FFBD7F09FFBC7F09FFBD7F09FFBC7F09FFBB7C09FF
+ BA7D07FFBB7D07FFBA7D07FFBD7F09FFBE810BFFC0820CFFC2850DFFBE8109FF
+ BE8109FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBA7D05FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD7F09FFBD8008FFBD7F09FFBD8008FFBD7F09FFBD8008FFBC7E08FF
+ BC7F07FFBC7E08FF4A3AC8FF4533C6FF442CC6FF432DC9FF4535C9FF4436CAFF
+ 4031C9FF3D2DC1FF4534C1FF3A2CA9FF352F94FF414499FF394292FF323E86FF
+ 40498CFF384583FF3C4E8DFF445D9DFF536DAFFF5774B7FF5271B6FF4C6DB2FF
+ 4C6FB1FF4F73B3FF4B70AEFF4E73B1FF557AB8FF597FBFFF5981C2FF547DC2FF
+ 4F79C0FF4D77BEFF4C73B8FF4E73B7FF5378BCFF5375BBFF4465AEFF395AA3FF
+ 32529DFF2A4A93FF3B589DFF304A8CFF2C3F7CFF2D3E76FF333E70FF313A66FF
+ 30355CFF343452FF3F3643FF483734FF543827FF5D3A20FF643D1DFF663D1CFF
+ 633C1CFF613A1AFF643B1AFF683D1CFF693E1DFF683D1CFF633A1AFF613818FF
+ 653A19FF673D1AFF6A401DFF693F1AFF673D1AFF663C17FF663C19FF663C17FF
+ 663C19FF673D18FF663C19FF663C17FF663C19FF663C17FF663C19FF663C17FF
+ 663C19FF643C19FF643C1FFF623B1BFF633B18FF673D18FF69421CFF68421FFF
+ 633D1DFF57391EFF462C1CFF25181AFF0B112EFF283F71FF3C60A6FF335DAAFF
+ 395DA9FF3B5DA9FF3A5AA6FF2F4F98FF2D4A8FFF2E4583FF2A3C71FF313B63FF
+ 3A3B55FF3E3641FF4B3B35FF513A2AFF563B21FF59391CFF5B391BFF5D3B1DFF
+ 5E3D23FF614124FF5A3B1CFF5D3D1AFF5E3E1AFF5E3F18FF603E1AFF603D1CFF
+ 5F3A20FF5E3820FF633A23FF653D24FF633F21FF603D1CFF5A381AFF593719FF
+ 5C391FFF643C20FF643110FF774112FF8D5718FF9F6A1AFFAB7818FFB47D14FF
+ B87F12FFBA7F12FFBE8016FFBE7F17FFBE7F17FFBC7F17FFBC8016FFBA8016FF
+ BA8016FFBA8016FFB87D10FFB97E11FFBA7F11FFBA7F11FFBA800FFFB87E0DFF
+ B67D0AFFB57C09FFB57C09FFB67F0CFFB97F0EFFB77F10FFB67E0FFFB57D0EFF
+ B77E11FFBB8012FFBB7E10FFBE8211FFC08412FFBF8410FFB9800CFFB67D0AFF
+ B67C0BFFB57D0EFFB57B11FFB87E15FFBA8017FFBA8017FFB87E14FFB77E11FF
+ B98110FFBB8415FFB47D15FFBA831BFFBC8219FFBF8319FFCA8A24FFC48729FF
+ B37B2CFFA57639FFAC8862FFDEC6B2FFF6ECE5FFEFECEEFFEEF1F5FFF0F4F5FF
+ F0F1EDFFF6F6F0FFEFEFE9FFFEFAF9FFFCF0F6FFF6EBF5FFEDE9F5FFE9E9F5FF
+ F0F2FAFFF1ECE9FFE7D2BCFFBC9B6EFFB1853EFFB28026FFB17D13FFB88112FF
+ BB8013FFBD7F13FFBC7F11FFBC800FFFBB7F0EFFBC7E0CFFBC7F0BFFBD800CFF
+ BE810DFFBF820CFFBF820CFFBE810BFFBB800CFFBA7F0BFFBA7F0BFFBD800AFF
+ BE810BFFBF820CFFC28511FFBD800CFFBC7F0BFFBF820EFFBF820EFFBC7F0BFF
+ BD800CFFC2850FFFB97C08FFBA7D07FFBC7F09FFBE810BFFBF820CFFBE810BFF
+ BD8109FFBC8008FFBC7F07FFBB7E06FFBC7D05FFBB7D07FFBF7F09FFBE7F0CFF
+ C07F0CFFBC7D0AFFBC7A09FFBB7C09FFBF7E0BFFBE800AFFC0800AFFBD8008FF
+ BD7E06FFBA7D05FFBA7D05FFBA7D07FFBC7F09FFBD800AFFBE810BFFBE810BFF
+ BD800AFFBD800AFFBB7E08FFBA7D07FFB97C06FFBA7D07FFBC7F09FFBE810BFF
+ BC7F09FFBB7E08FFBC7F09FFBE810BFFBF820EFFBE810BFFBB7E0AFFB97C06FF
+ BB7E0AFFBD800AFFBB7E0AFFBB7E08FFBB7E0AFF4834CDFF4833CFFF4B31D1FF
+ 4930CEFF4131C4FF3D31BFFF3C2FC1FF4030BEFF4732B6FF3C2B9EFF342B86FF
+ 3E3F8FFF3C4392FF313C86FF394285FF364080FF3C4D8CFF43599AFF4E68AAFF
+ 5370B3FF5170B5FF4B6EB2FF496FB0FF4B71B2FF5175B5FF5378B6FF567BB9FF
+ 577DBDFF577FC0FF5680C5FF5781C8FF5781C8FF4C71B5FF4C6FB1FF4F72B6FF
+ 4C6EB4FF3F60A9FF3859A2FF36569FFF314F96FF3B5699FF314A8AFF2D3F7AFF
+ 2F3F74FF333F6FFF323B66FF2E355CFF323452FF3D3645FF463735FF533726FF
+ 5D381CFF623B1BFF653C1BFF633B1EFF623A1DFF673C1BFF683E1BFF683D1CFF
+ 653C1CFF60391DFF60381BFF643918FF673B16FF6D401EFF6A401BFF6B3E1CFF
+ 673D18FF693C1AFF673D18FF693C1AFF683E19FF693C1AFF673D18FF683B19FF
+ 663C17FF683B19FF663C17FF693C1AFF673D1AFF633D1BFF643E1CFF663E1BFF
+ 653E18FF633B18FF603A17FF5F3916FF5A381AFF4F3420FF281C1CFF0E1634FF
+ 2B4379FF375DA5FF2E57A6FF395CA6FF3E5EA7FF405FAAFF3956A0FF385298FF
+ 334A88FF2B3C6FFF2C375DFF373951FF3D3540FF493835FF503727FF563720FF
+ 5C3C1FFF5F3D1FFF5D3B1DFF5A3A1DFF5D3D20FF5C3A1CFF5F3C1AFF603F18FF
+ 603F18FF623E18FF623D1BFF613A1EFF60381FFF5E351EFF5E361DFF5E371BFF
+ 5F391BFF5F391BFF603A1CFF60381FFF683A1BFF794217FF8B5116FF9E641CFF
+ AB751EFFB27E1AFFB68217FFBC8417FFBE841AFFBB7E16FFBC7F17FFBC7F17FF
+ BC8016FFBA8114FFBA8114FFBA8114FFB98013FFB67D10FFB77E11FFB88011FF
+ B88011FFB77F0EFFB67F0CFFB47D0AFFB37C09FFB67F0CFFB8810EFFB98110FF
+ B88011FFB67E0FFFB57C0FFFB67C12FFBA7F12FFBA7D0FFFBB7F0EFFBD810FFF
+ BE830FFFBD820EFFBB800CFFB97F0EFFB97E10FFBD8018FFBD821BFFBF831FFF
+ BE821EFFBC821BFFBB8318FFBD8617FFBD881AFFB48119FFB68119FFB87E14FF
+ BD8018FFC88724FFC0842BFFB27E37FFAB834FFFC4AA8CFFEBDBCFFFF8F2F3FF
+ EDEDF3FFEDF0F5FFF1F2F6FFEEEFEDFFF3F3EDFFF9F6F1FFF9F4F1FFF5EAEDFF
+ F9EEF8FFF4EFFEFFEFEFFBFFF6F6FCFFF6EFE6FFDBC3A5FFBB9460FFB68638FF
+ B98324FFB57E15FFBB8314FFBF8117FFC18017FFBF8012FFBE7F0FFFBD7E0EFF
+ BD7E0EFFBD7F0DFFBD7F0DFFBE800EFFBF810FFFBD800CFFBD800CFFBE810DFF
+ BE810DFFBE810BFFBE810BFFBD800AFFBD800AFFC18410FFBD800CFFBC7F0BFF
+ BE810DFFBE810DFFBC7F0BFFBD800AFFC1840EFFBD800AFFBD800AFFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8106FFBC8106FFBC8005FFBD7E04FFBD7E06FF
+ BE7E08FFC1800DFFC1800DFFC07E0DFFBE7C0BFFBD7B0AFFBE7C0BFFBF7E0BFF
+ C07F0CFFC0800AFFBF8008FFBE7F07FFBB7E06FFBC7F09FFBC7F09FFBD800AFF
+ BE810BFFBE810BFFBD800AFFBC7F09FFBB7E08FFBD800AFFBB7E08FFBA7D07FF
+ BB7E08FFBD800AFFBE810BFFBD800AFFBB7E08FFBC7F0BFFBE810DFFBF820EFF
+ BE810DFFBB7E0AFFBA7D09FFBB7E0AFFBD800CFFBF820EFFBF820EFFBF820EFF
+ 4830D0FF4B30D3FF4F2ED6FF4B2ED1FF432FC4FF3F2FBCFF3D2DB7FF422DB1FF
+ 3B2498FF32207EFF2A1F68FF383777FF44498EFF3C4289FF3A4087FF3D468AFF
+ 3C4C8EFF3F5596FF4761A3FF4D6AADFF4E6FB4FF4E71B5FF4C71B5FF4C72B3FF
+ 5276B6FF5478B8FF547ABAFF567CBCFF567EBFFF5680C5FF5781C8FF5680C7FF
+ 4A6EB4FF476AAEFF466AB0FF4367ADFF385BA4FF3656A1FF3857A2FF35529CFF
+ 385298FF2F4888FF2C3E79FF2F3F74FF344070FF343A67FF2E355CFF323452FF
+ 3B3645FF463637FF503626FF59361CFF60381BFF623B1BFF613A1EFF613A1EFF
+ 683F1FFF663D1CFF653C1CFF623B1BFF5F3A1EFF613A1EFF623919FF633916FF
+ 6A3F1EFF673F1CFF683D1CFF653D1AFF673C1BFF653D1AFF683D1CFF663E1BFF
+ 683D1CFF653D1AFF663B1AFF633B18FF653A19FF643C19FF673C1BFF663D1CFF
+ 5F3917FF623C1AFF663E1BFF643D17FF5F3714FF5B3512FF5E3816FF5E3C1FFF
+ 573C28FF2B1D1EFF181E3BFF354A81FF3659A2FF274FA1FF385AA6FF3E5DA8FF
+ 425FAAFF3D58A2FF3C559BFF374C8AFF2B3C6FFF2C365EFF373852FF403744FF
+ 483635FF4C3428FF54351EFF5C3C1FFF603F1EFF5F3C1BFF5A3918FF5C381AFF
+ 61391CFF643B1BFF653D1AFF653E18FF633F17FF633F17FF623D17FF613B18FF
+ 5D3616FF5D3518FF60351AFF62381BFF653B1EFF693D1EFF6B3E1CFF6F3F15FF
+ 8D551AFF9D631BFFAC731EFFB27D1CFFB68217FFB88412FFBD8715FFC1891AFF
+ BA7F12FFBB8013FFBC8114FFBD8214FFBD8312FFBC8211FFBB8012FFBA7F12FF
+ B87D10FFB97E11FFB97E11FFB97E10FFB97E10FFB87E0DFFB77D0CFFB67C0BFF
+ BA800FFFBB8012FFBC8113FFBB8013FFB87C12FFB77B11FFB77A12FFB97C14FF
+ B97B11FFBB7B0FFFBC7D0FFFBE7F0FFFBE8211FFBF8312FFBE8113FFBB8013FF
+ BB7D17FFBC7E1AFFBC801CFFBC801CFFBB8019FFBB8118FFBC8316FFBC8419FF
+ B6831BFFB6801BFFB97F16FFC2841EFFC7892BFFBC8433FFB6894CFFBE9B73FF
+ E6D1BBFFFBF0E8FFFEF9F8FFEEEDEFFFF1F0F2FFF2F4F5FFF1F1F1FFF2F3F1FF
+ FBFAF6FFF2F0EFFFEEE9EBFFF8F1F8FFF4F0FBFFF5F1F7FFFAF5F4FFF1E2D2FF
+ C5AA85FFB38B51FFB58434FFBE8627FFBB811AFFBF8319FFC2831BFFC18319FF
+ BF8012FFBF8010FFBE7F0FFFBD7E0EFFBD7F0DFFBD7F0DFFBE800EFFBF810FFF
+ BB7E0AFFBD800CFFBE810DFFC0830FFFC0830DFFBE810BFFBD800AFFBB7E08FF
+ BF820EFFBC7E0CFFBB7D0BFFBD7F0DFFBD800CFFBB7E0AFFBC7F09FFBF820CFF
+ C1840EFFBF820CFFBD8109FFBA7E06FFBA7E06FFBA7E06FFBB7F07FFBC8008FF
+ BC7F07FFBC7F07FFBC7E08FFBE800AFFC1820FFFC1820FFFBE7F0DFFBC7D0BFF
+ BC7D0BFFBC7D0BFFBD7E0BFFBD7E0BFFBD7F09FFBD8008FFBC7F07FFBC7F07FF
+ BE810BFFBE810DFFBF820EFFBE810DFFBE810DFFBC7F0BFFBB7E0AFFBA7D09FF
+ BF820EFFBD800CFFBC7F0BFFBC7F0BFFBE810DFFBF820EFFBD800CFFBB7E0AFF
+ BC7E0CFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBB7D0BFFBC7E0CFF
+ C28412FFC28412FFC28412FF4C2FD2FF492BD0FF4A28CDFF4B2BCAFF4832C0FF
+ 4432B5FF3C2AA7FF382495FF31187AFF2D1765FF24174FFF352E61FF4B4C86FF
+ 444988FF3D3F85FF434C90FF3B4B8DFF3B5192FF3F599BFF4865A8FF4E6FB4FF
+ 5275B9FF5176BAFF5075B9FF4D73B4FF5278B8FF577DBDFF557EBDFF557CC0FF
+ 527CC1FF4E78BFFF4872B9FF486CB2FF4466ACFF4266ACFF3F62ABFF3659A3FF
+ 3457A1FF3756A1FF34519BFF365096FF2D4587FF2A3C79FF2E3D75FF353E70FF
+ 343A67FF2E355CFF323452FF3C3647FF433536FF4E3325FF55331BFF5D3719FF
+ 60381BFF613A1EFF5F3A1EFF674020FF643E1CFF623B1BFF613B1DFF603B1FFF
+ 603B1FFF623919FF5F3615FF643B1AFF613B19FF633A1AFF613B19FF643B1BFF
+ 633D1BFF663D1DFF653F1DFF673E1EFF643E1CFF643B1BFF613B19FF633A1AFF
+ 623C1AFF663D1DFF653F1DFF5B3614FF5D3915FF603B15FF5F3A14FF5E3815FF
+ 5E3A16FF633E1CFF604023FF583D29FF2C1E1FFF212542FF3F5488FF3859A2FF
+ 264C9EFF3659A9FF3E5EAAFF405AA6FF38519BFF364D91FF324785FF2D3D72FF
+ 323B66FF3C3E5CFF423A4BFF46373BFF4F3830FF543623FF57361CFF5B391BFF
+ 603D1BFF5F3C1BFF5E3717FF67391AFF693A1BFF693C1BFF673D1AFF653E17FF
+ 653F15FF623F14FF613D15FF623C19FF633C1CFF683C1FFF693A1EFF693A1AFF
+ 6D3D19FF744519FF7F4C14FF9D631BFFAA6F19FFB37919FFB67F16FFB6800EFF
+ B57F0CFFB9820FFFBD8514FFB97E10FFBA7F11FFBC8211FFBD8411FFBD8411FF
+ BC8211FFBA7F11FFB97E11FFB87D10FFB87D10FFB97E11FFB97E11FFB97E10FF
+ B87D0FFFB87E0DFFB87E0DFFB97E10FFBB8013FFBC8114FFBB7F15FFB97C14FF
+ B87A14FFBA7C16FFBD7D17FFBE7C15FFBC7B12FFBB7B0FFFBD7E10FFBE8113FF
+ C08315FFBE8014FFBC7E14FFBA7C16FFBB7D19FFBA7D1BFFBA7D1BFFBA7E1AFF
+ BA7F18FFBB8117FFBB8219FFB7811CFFB8811EFFBF831FFFC88B2BFFC78B37FF
+ BA8643FFBF9969FFD5BB9DFFF4E7D9FFFDF7F2FFF9F6F2FFEEECEBFFF3F1F0FF
+ F7F7F7FFF3F5F6FFF1F5F6FFF0F2F2FFEFF1F1FFEDEFF0FFF2F1F5FFEFEBF0FF
+ F8F0F0FFFBEDE1FFDBC4AAFFB59365FFB08444FFB98532FFC28829FFC0821CFF
+ C08119FFC2821CFFC08119FFC18214FFC08111FFBF8010FFBE7F0FFFBD7F0DFF
+ BE800EFFBE800EFFBF810FFFBC7F0BFFBD800CFFBE810DFFBF820EFFBF820CFF
+ BE810BFFBD800AFFBC7F09FFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBD800AFFBF820CFFBE810BFFBC8008FFBB7F07FFBB7F07FF
+ BB7F07FFBC8008FFBC8008FFBD8008FFBC7F07FFBD7F09FFBF810BFFC28310FF
+ C28310FFBF800EFFBC7D0BFFBD7E0CFFBD7E0CFFBD7E0BFFBD7E0BFFBD7F09FF
+ BD7F09FFBD8008FFBD7F09FFBD800CFFBE810DFFBE810DFFBF820EFFBE810DFF
+ BD800CFFBC7F0BFFBB7E0AFFC18410FFBF820EFFBD800CFFBE810DFFBF820EFF
+ C0830FFFBE810DFFBC7F0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBB7D0BFFC18311FFC18311FFC18311FF4E2FD0FF4C2CCBFF
+ 4928C6FF482BBEFF442FAEFF3C2A9BFF331F89FF2F1775FF371A69FF371D59FF
+ 2F1B46FF382B51FF4E4976FF474A7DFF393C79FF3E4888FF3C4D8CFF384E8FFF
+ 3B5597FF4360A3FF4D6EB3FF5577BDFF567AC0FF537ABEFF5179BAFF597FC0FF
+ 5B81C1FF557EBDFF5279BDFF4E78BDFF4973BAFF416AB3FF466CB4FF4265AEFF
+ 4366AFFF4164AEFF385AA6FF3557A3FF3654A1FF304D98FF354E96FF2C4486FF
+ 293B78FF2D3C74FF343D6FFF333966FF2F335CFF313352FF3C3647FF433536FF
+ 4E3325FF55331BFF5D3719FF5F391BFF5F3A1EFF5F3A1EFF673F22FF643D1DFF
+ 61391CFF5E3A1CFF5E3C1FFF5E3C1FFF613A1AFF603716FF5D3616FF5C3616FF
+ 5D3518FF5D3717FF60381BFF613B1BFF643C1FFF643E1EFF653D20FF633D1DFF
+ 633B1EFF613B1BFF623A1DFF623C1CFF643C1FFF643E1EFF5F3C1AFF5C3A16FF
+ 5D3812FF5E3913FF613D19FF62401CFF63401EFF5E3E21FF543925FF30211FFF
+ 282B47FF46598CFF3B5BA4FF264B9FFF3658ABFF3E5DACFF3F59A5FF324A92FF
+ 2B4188FF2B3F80FF2E3C76FF364070FF3E4063FF3C364DFF483A45FF543F3DFF
+ 563B2DFF50311CFF563417FF623F1EFF65401EFF613817FF68391AFF6B391BFF
+ 6A3B1CFF693C1BFF673D18FF633F17FF614013FF603E13FF633F19FF67411FFF
+ 6C3F24FF69391DFF683612FF6D3A0FFF7D4A12FF8D5912FFAB701AFFB47715FF
+ BA7E14FFBA800FFFB57F0AFFB47E09FFB7800DFFBB8312FFB77F10FFB8800FFF
+ BB820FFFBC8310FFBE8210FFBD8110FFBC7E12FFBB7D11FFBA7C10FFBA7C10FF
+ BA7C10FFBA7C10FFBA7D0FFFBA7D0FFFBB7E10FFBB7E10FFB97B0FFFBB7D11FF
+ BD7F15FFBE7F17FFBD7D17FFBD7C19FFBF7E1BFFC1801DFFC27F1CFFC07E18FF
+ BD7B14FFBE7D14FFC07F16FFC07F16FFBD7F15FFBA7B13FFC0821CFFC0821EFF
+ C0811FFFC0811FFFBF831FFFC0851EFFC0861DFFBF861DFFB57F1AFFBA8320FF
+ C18424FFC1852CFFBD863DFFBB8D57FFCBAE8FFFEADACAFFF3EDE6FFF3F4F2FF
+ F2F1EDFFEDEDE7FFF2F2ECFFF7F8F6FFF1F4F8FFEEF3F6FFE8ECEDFFEFF4F5FF
+ EEF3F6FFEAEDF1FFF0ECEBFFFFF8EEFFFBE4CEFFC4A37CFFAD854AFFB5843AFF
+ BC862FFFC48828FFC2811EFFC07E18FFC0801AFFBE7F17FFC28315FFC18212FF
+ BF8010FFBE7F0FFFBE800EFFBE800EFFBE800EFFBF810FFFBF820EFFBE810DFF
+ BD800CFFBC7F0BFFBC7F09FFBD800AFFBE810BFFBF820CFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBC7E0CFFBD800CFFBD800CFFBC7F0BFFBA7D07FFBB7E08FF
+ BC7F09FFBD800AFFBE820AFFBD8109FFBD8109FFBC8008FFBD8008FFBC7F07FF
+ BD7F09FFBF810BFFC1820FFFC1820FFFBF800EFFBD7E0CFFBE7F0DFFBE7F0DFF
+ BD7E0BFFBD7E0BFFBD7F09FFBD7F09FFBE8109FFBE800AFFBB7E0AFFBC7E0CFF
+ BE800EFFBF810FFFBF810FFFBF810FFFBE800EFFBE800EFFC08210FFBF810FFF
+ BD7F0DFFBE800EFFC08210FFC18311FFBF810FFFBD7F0DFFBE7F0FFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BC7D0DFF4E31C4FF4C2FC0FF4A2DB9FF4127A9FF372191FF2E1B7CFF28156AFF
+ 2C135DFF381A55FF41234EFF3E253FFF3D2B42FF4D4564FF4D4C76FF3C4178FF
+ 414C8AFF3D4E8DFF384E8FFF385294FF3F5CA1FF4969B0FF5074BAFF537ABFFF
+ 537ABFFF5B82C6FF5F87C8FF5E84C5FF527ABBFF4D77BAFF4F79BEFF4E78BFFF
+ 4770B9FF486DB7FF4467B1FF4568B2FF4466B2FF3C5DACFF3859A8FF3655A4FF
+ 304D98FF375098FF2F4488FF283978FF2C3971FF313A6CFF313764FF2E325BFF
+ 333252FF3B3546FF443637FF503626FF57361CFF5F391BFF613B1BFF5F3A1EFF
+ 5F3A1EFF643D1DFF633C1CFF623B1BFF613B1DFF5E3C1FFF603B1FFF623B1BFF
+ 633A19FF5D3616FF5C3618FF5C3618FF5D3719FF5E381AFF603A1CFF623C1EFF
+ 633D1FFF633D1FFF633D1FFF633D1FFF633D1FFF633D1FFF633D1FFF633D1FFF
+ 613E1DFF62421FFF5E3E1AFF5E3A14FF5E3A14FF603E1AFF623F1DFF5F3C1BFF
+ 57371AFF533621FF382724FF303048FF475687FF3D5BA2FF294EA0FF3658ACFF
+ 3C5DADFF435DAAFF324994FF273D84FF283B7EFF2D3C7AFF344076FF393C68FF
+ 333050FF483D51FF54444BFF58423DFF523729FF55351EFF603E21FF644120FF
+ 633A19FF6A3919FF6D3A1AFF6A3B1CFF693B1CFF653C1BFF633E18FF5F3F16FF
+ 5E3E15FF5F3D19FF653F1DFF693D1EFF693917FF6A370CFF764009FF87540EFF
+ 9C6613FFB77A1AFFBF7E15FFC08111FFBE8210FFBD810FFFBB820FFFBA8213FF
+ BC8316FFB87F12FFB88011FFBA810EFFBA810DFFBC800EFFBE7F0FFFBE7D14FF
+ BE7D14FFBA7C10FFBA7C10FFB97B0FFFB97C0EFFBA7D0FFFBA7D0FFFBB7E10FF
+ BC7F11FFB87A0EFFBB7D11FFBD7E16FFBE7F17FFBE7D1AFFBF7E1BFFC1801EFF
+ C48321FFC5821FFFC3801DFFC07E18FFBF7D16FFBE7C15FFBE7D14FFBB7C14FF
+ BA7B13FFBE801AFFBD7F1BFFBC7E1AFFBD7F1BFFBD811DFFBE831CFFBE831CFF
+ BB811AFFB87F1CFFBE8627FFBE8229FFB37B2EFFB7854BFFC69F79FFDEC8B6FF
+ F9EEEAFFF0F0F0FFEEF3F2FFEDF1EBFFEFF0E7FFF2F3EAFFF3F4F0FFEDF0F4FF
+ E9ECF4FFE7EBF0FFEEF5F8FFE7F0F4FFEAEFEEFFF7F1EAFFFFF5E2FFF3D3B0FF
+ B68C57FFAD7F38FFBA8633FFBF8629FFC48523FFC27F1CFFBF7B16FFC28019FF
+ BC7E14FFC38416FFC28313FFC08111FFBF8010FFBE800EFFBE800EFFBE800EFF
+ BE800EFFC0830FFFBE810DFFBD800CFFBB7E0AFFBB7E08FFBD800AFFBE810BFF
+ C0830FFFBB7D0BFFBE800EFFBF810FFFBD7F0DFFBD7F0DFFBF810FFFBE810DFF
+ BB7E0AFFB87B05FFB97C06FFBC7F09FFBE810BFFBF830BFFBE820AFFBD8109FF
+ BC8008FFBE8109FFBC7F07FFBB7D07FFBC7E08FFBF800DFFC0810EFFBF800EFF
+ BE7F0DFFBF800EFFBE7F0DFFBE7F0DFFBD7E0BFFBD7E0BFFBE800AFFBE800AFF
+ BF810BFFBB7D0BFFBC7E0CFFBD7F0DFFBF810FFFC08210FFC08210FFC08210FF
+ BF810FFFBF810FFFBD7F0DFFBC7E0CFFBD7F0DFFC08210FFC18311FFC08210FF
+ BF810FFFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFFBB7C0CFF
+ BA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFF4B35ACFF452FA5FF3E269CFF341D8AFF
+ 2B1776FF281566FF2B165BFF321A50FF3D1E45FF4A2A42FF50333CFF443035FF
+ 4B4151FF50506EFF44487BFF444F8DFF3F508FFF3B4F90FF375193FF3B589DFF
+ 4163A9FF486BB4FF4971B9FF4B74B9FF557FC2FF5A84C5FF5A82C3FF5078B9FF
+ 4D77BAFF527CC1FF537DC4FF4C75BEFF4970BAFF4468B4FF4468B4FF4468B6FF
+ 3C60AEFF3B5CABFF3A59A8FF34509DFF3A519CFF304589FF283978FF2A3670FF
+ 2E366BFF2F3363FF2F315AFF333252FF3B3645FF443735FF513726FF5B391CFF
+ 623B1BFF633D1BFF623C1EFF5F3B1DFF613B19FF643B1AFF653C1BFF633C1CFF
+ 5F3A1EFF613B1DFF653C1BFF663E1BFF633C1CFF623C1CFF603A1AFF5F3919FF
+ 5F3919FF5F3919FF603A1AFF613B1BFF613B1BFF633D1DFF643E1EFF664020FF
+ 664020FF643E1EFF633D1DFF5F3C1BFF5E3E1BFF5D3D19FF603C16FF603C16FF
+ 5E3C18FF5B3B18FF593817FF553518FF563722FF44302BFF373247FF444E7DFF
+ 3E589BFF2E4EA1FF3557ABFF3C5BB0FF425DADFF344C98FF29408BFF283C83FF
+ 293A7DFF303E79FF333C6EFF2F315AFF423E5BFF4D4354FF59484CFF5D4742FF
+ 5C4133FF5A3B26FF583920FF603A1CFF673A18FF6B3B19FF693C1BFF673B1CFF
+ 633B1EFF603D1CFF5D3D1AFF5C3C19FF5F3C1AFF613B19FF663917FF6D3D13FF
+ 7A470FFF8A5613FF9D6817FFAE7518FFBF7D17FFC17E11FFC17F0FFFC08010FF
+ BF8214FFBE8316FFBB8118FFBB8019FFBA8017FFB98013FFB97F0EFFB87F0CFF
+ BA7E0DFFBD7E10FFC07D16FFC17E17FFBC7C10FFBA7D0FFFB97C0EFFB97C0EFF
+ B97C0EFFBB7F0EFFBC800FFFBD8012FFBA7C10FFBD7F13FFBF8018FFBF8018FF
+ BE7D1AFFBF7E1BFFC1801EFFC38220FFC4811EFFC4811EFFC2801AFFC07E17FF
+ BB7C14FFBA7B13FFBB7D13FFBC7D15FFBA7D15FFB97B15FFB77913FFB97B15FF
+ B97E17FFBB8019FFB97E17FFB77C18FFBB8121FFC68D32FFBE8637FFB38041FF
+ C49A70FFE3C4ADFFF4E4DEFFF7F3F8FFEDF1F6FFEBF3F3FFEEF4EFFFF0F5ECFF
+ F2F4EEFFF1F2F0FFECEFF3FFEAEDF5FFE9EBF5FFEBF1F8FFE3EEF2FFEFF4F2FF
+ F7EEE1FFECD4B8FFD6AE7EFFB2803EFFB17D2AFFBF892BFFC08522FFC2811EFF
+ C17D18FFBE7B14FFC4831AFFBE8113FFC48517FFC28313FFC18212FFBF8010FF
+ BE800EFFBE800EFFBE800EFFBE800EFFBE810DFFBE810DFFBD800CFFBD800CFF
+ BD800AFFBD800AFFBE810BFFBE810DFFBB7D0BFFBF8010FFC08111FFBE7F0FFF
+ BE800EFFC08210FFBF820EFFBB7E0AFFBB7E0AFFBC7F0BFFBC7F09FFBD800AFF
+ BD800AFFBD800AFFBC7F09FFBC7F09FFBE810BFFBB7E08FFB97C08FFB97C08FF
+ BB7D0BFFBD7F0DFFBE7F0FFFBE7F0FFFBF8010FFBE800EFFBD7F0DFFBC7F0BFF
+ BC7F0BFFBD800AFFBE810BFFBF820CFFBD7F0DFFBE7F0FFFBF8010FFC08111FF
+ C08111FFBF8010FFBE7F0FFFBE7F0FFFBC7D0DFFBB7C0CFFBA7B0BFFBC7D0DFF
+ C08111FFC28313FFC18212FFC08111FFBF8012FFBD7E10FFBB7C0EFFBB7C0EFF
+ BD7E10FFBD7E10FFBC7D0FFFB97A0CFFBB7C0EFFBB7C0EFFBB7C0EFF483896FF
+ 3B2A8BFF2D1A7BFF27126FFF2A1367FF301A62FF372057FF3D244AFF492A3FFF
+ 5A3A3FFF604439FF4C392CFF493E40FF504E64FF41457AFF3C488AFF415291FF
+ 3C5091FF375193FF38559AFF3C5EA4FF4066AEFF436BB3FF436DB4FF456FB4FF
+ 507ABDFF537DC0FF5077BBFF4F78BDFF557EC3FF527CC3FF4972BBFF4B72BDFF
+ 4569B5FF4468B6FF4367B5FF3D60B0FF3E5FAFFF3F5DAEFF3955A2FF3C539EFF
+ 33468AFF293877FF2A356FFF2F356AFF2E3360FF2E3059FF353351FF3D3643FF
+ 463734FF543925FF5F3B1DFF643E1CFF663E1BFF623C1CFF603A1AFF603815FF
+ 633C16FF673D1AFF653C1BFF603A1CFF603A1AFF683E1BFF6A401BFF6A4422FF
+ 674220FF663F1FFF633E1CFF623B1BFF5F3A18FF603919FF5F3A18FF613A1AFF
+ 623D1BFF663F1FFF674220FF684121FF65401EFF633C1CFF603B19FF543410FF
+ 593A13FF5F3E17FF5F3E17FF593915FF573714FF583716FF593A1BFF5A3A23FF
+ 4F3830FF3E3444FF434972FF3E5495FF2F4E9DFF3455ABFF3A5BB1FF3C59AAFF
+ 304C99FF29438FFF273E89FF263A81FF2B3D7EFF2F3D77FF2E3769FF393B63FF
+ 423E5BFF53495AFF64545BFF604B49FF50372DFF4A3020FF57381FFF633A19FF
+ 683C17FF673C1BFF633C1CFF623C1EFF603B1FFF5D3B1DFF5E3B1AFF633F1BFF
+ 623B14FF683C0DFF75470DFF8D5A14FFA26D1CFFB17C21FFBD821FFFBE7C13FF
+ BF7A0DFFBC790CFFBD7C10FFC07F16FFBE801AFFBA7D1BFFB77A18FFBB8019FF
+ B97F15FFB87E0DFFB67D0AFFB87C0BFFBC7D0FFFC07D16FFC27E19FFBC7C10FF
+ B97C0EFFB97C0EFFB87C0BFFB97D0CFFBB7F0EFFBC800FFFBE8211FFBD8012FF
+ BF8115FFC08218FFC08119FFBE7E18FFBE7D1AFFC07F1CFFC2811EFFC27F1CFF
+ C3811BFFC3811BFFBE7F17FFBB7C14FFBA7C12FFBC7E14FFBD8117FFBE8218FF
+ BC7F17FFBB7E16FFBA7F18FFBD821BFFBF841DFFBD811DFFBA7F1CFFBC8223FF
+ C8913CFFC18D4AFFB98E5DFFD5B49AFFFAE5DDFFFFF6F9FFF1F0FAFFEBF1F8FF
+ E8F1F4FFEFF6F3FFF2F9F2FFF2F6F1FFF1F4F2FFF2F3F7FFF1F3FBFFEAECF7FF
+ E9EEF7FFE6EFF2FFF8FAF4FFF2E5CFFFCCAD86FFBA8B4EFFB37B2CFFB57C1FFF
+ C58A26FFC1831DFFBF8018FFBF7D14FFBE7D11FFC68719FFC08413FFC48515FF
+ C38414FFC18212FFBF8010FFBE800EFFBE800EFFBE800EFFBE800EFFBC7F0BFF
+ BD800CFFBE810DFFBF820EFFBF820CFFBE810BFFBD800AFFBC7F0BFFBB7D0BFF
+ C08111FFC18212FFBE7F0FFFBE800EFFC18311FFC08210FFBB7E0AFFC0830FFF
+ BF820EFFBC7F0BFFBB7E08FFBA7D07FFBA7D07FFBC7F09FFBC7F09FFBF820CFF
+ BB7E08FFB77A06FFB77A06FFB97B09FFBC7E0CFFBE7F0FFFBE7F0FFFBF8010FF
+ BE7F0FFFBD7F0DFFBC7E0CFFBC7F0BFFBD800CFFBE810BFFBF820EFFBF810FFF
+ C08111FFC08111FFC08111FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFF
+ B97A0AFFB97A0AFFBC7D0DFFBF8010FFC28313FFC28313FFC18212FFBF8012FF
+ BD7E10FFBB7C0EFFBB7C0EFFBD7E10FFBE7F11FFBC7D0FFFB97A0CFFBE7F11FF
+ BE7F11FFBE7F11FF302470FF261967FF271568FF2F186CFF2C1560FF290F4FFF
+ 3C204EFF563B55FF8B6D72FF8F7264FF957B5DFF8F7D60FF72695CFF535262FF
+ 434781FF444D96FF3A4A8CFF3C518FFF3C5698FF3B589DFF3859A2FF375EA8FF
+ 3F68B1FF446FB8FF406CB3FF456FB4FF4E78BBFF507ABDFF4E77BCFF537CC1FF
+ 547EC5FF4A73BCFF4970BBFF4268B6FF3C61B1FF3B60B0FF395BAEFF3657A7FF
+ 3856A7FF3F5AAAFF445BA6FF34478BFF2F3E7DFF333E77FF32396BFF323562FF
+ 33325CFF302E4CFF3E3641FF493933FF573A25FF633D1DFF6B4320FF6C421DFF
+ 623C1AFF5D3715FF6C421DFF6B421BFF6C401BFF693F1AFF643E1CFF653F1DFF
+ 6B3F1AFF6C411AFF68401DFF633D1AFF623918FF613B18FF663D1CFF66401DFF
+ 673E1DFF633D1AFF643B1AFF633D1AFF663D1CFF653F1CFF663D1CFF623C19FF
+ 613817FF5C3814FF5B3B17FF583912FF593811FF5A3912FF5A3A16FF593B18FF
+ 593817FF573517FF5A391FFF4C3123FF3B2D38FF3C3E61FF394C89FF2A4895FF
+ 2B4A9FFF3B5CB2FF2E4EA1FF274695FF2C4A99FF34509DFF324B95FF2F458CFF
+ 304184FF2E3C77FF2F386AFF393D66FF444260FF4F485DFF60525DFF645356FF
+ 56423DFF4A3020FF5E3A1CFF5F3812FF623C19FF623D1BFF593517FF5D391BFF
+ 653F21FF623C1AFF5C340AFF6C440FFF7A4E0EFF895B0DFFA37119FFB47E1FFF
+ B97F1FFFBF811DFFC47F18FFC68015FFC48015FFC18017FFBE7E18FFBB7C1AFF
+ B87B1BFFB77B1BFFC38824FFC1891EFFBB8312FFB47B07FFB67A08FFBF8012FF
+ C27F18FFBE7B14FFBD7D11FFBB7E10FFB97D0CFFB87C0BFFB87C0BFFBA7E0CFF
+ BC800EFFBD8110FFBC800FFFBE8113FFBF8115FFBE8016FFBB7C14FFBA7A14FF
+ BB7B15FFBD7D17FFBD7D17FFC08119FFBF8018FFB97A12FFB87911FFB97D13FF
+ BA7E14FFB67B0EFFBE8316FFBD8319FFBD8319FFBC831AFFBC821BFFBE831FFF
+ BD821FFFBC7F21FFBA8126FFAD792CFFB88B52FFD2AF8DFFE5CFC3FFF5E8EAFF
+ F7F1FCFFEBEBF7FFECF2F9FFEBF2F5FFEBF3F2FFEAF3F0FFEBF1F0FFEEF0F0FF
+ EFEEF0FFEFEDF3FFEEEEFAFFE6E8F2FFEAEEEFFFFEFCF1FFE1CCB0FFB69060FF
+ C28B46FFC3872EFFBD811DFFBD8117FFBD7F13FFBF7F13FFC07F13FFC07F12FF
+ BC7F0BFFB87D09FFBE800EFFBC7D0DFFBB7C0CFFBC7D0DFFBF810FFFC08210FF
+ BF810FFFBD7F0DFFBE810DFFBD800CFFBD800CFFBD800CFFBC7F09FFBC7F09FF
+ BB7E08FFBB7E0AFFBC7E0CFFBF8010FFBE7F0FFFB87909FFB87909FFBD7F0DFF
+ BE800EFFBB7D0BFFB97B09FFBA7D09FFBC7F0BFFBD800CFFBD800AFFBC7F09FF
+ BA7D07FFB97C06FFBD800AFFBD800AFFBD800CFFBD800CFFBD7F0DFFBD7F0DFF
+ BD7E0EFFBD7E0EFFC18212FFBF8010FFBD7F0DFFBE800EFFC0830FFFBF820EFF
+ BD800AFFB97C08FFBB7D0BFFBB7C0CFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFFBF8010FFC08111FF
+ C08111FFC08111FFC28315FFC28315FFC38416FFC28315FFC18214FFBF8012FF
+ BD7E10FFBB7C0EFFBB7C0EFFBF8012FFC08113FF291B62FF23155CFF2A165FFF
+ 341C62FF331857FF3A1D4EFF644866FF987D87FFA48780FFA48870FFAB916DFF
+ AF9B78FF9A8E7CFF6C6873FF45487FFF3C458EFF3E4E90FF3F5492FF3E589AFF
+ 3B5A9FFF3659A2FF365DA7FF3A64AFFF406AB5FF436EB7FF436FB6FF4B75BAFF
+ 4D77BAFF4A73B8FF5079BEFF527CC3FF4972BBFF446BB6FF3F65B3FF3C61B1FF
+ 3B60B0FF395BAEFF3355A8FF3856A7FF3F5BA8FF3E55A0FF324589FF2F3E7CFF
+ 353E77FF333869FF313460FF32325AFF322E4BFF443C47FF4D3D36FF593C27FF
+ 613B1BFF673D18FF693F1AFF673F1CFF68401DFF673E17FF683E14FF673C15FF
+ 653B16FF633B18FF633B18FF683D16FF693E17FF613712FF5F3714FF623A17FF
+ 663E1BFF6B4320FF6D4522FF6C4421FF6B4320FF68401DFF68401DFF673F1CFF
+ 663E1BFF653D1AFF663E1BFF673F1CFF653F1CFF5F3F1BFF5E3E1AFF613D17FF
+ 603F18FF5F3F1BFF5D3F1CFF5E3D1CFF5D3C1BFF633F21FF563827FF47363AFF
+ 44425FFF3D4C84FF2D4892FF2D4DA0FF3D60B6FF2D4FA2FF284B9BFF3051A0FF
+ 3958A7FF3854A1FF344F99FF354B93FF304386FF32427DFF364175FF3A406BFF
+ 424365FF504A61FF594F5FFF574954FF574441FF5B3C25FF5C3918FF5F3C1BFF
+ 613E1DFF5C3918FF603A1AFF663D1CFF653A13FF6B410CFF855A17FF996D1AFF
+ A67617FFB37F1AFFB78018FFB67814FFB87714FFC07C17FFC07D16FFC07E17FF
+ BF8018FFBD7F1BFFBB7E1EFFBB7E20FFBB7F1FFFBF8420FFBE861BFFB98110FF
+ B57C08FFB87C0AFFC08111FFC28118FFBE7C15FFBD7F15FFBA7F11FFBD8012FF
+ BC8211FFBE8211FFBA800FFFBA7E0DFFB97F0EFFBA7E0DFFBA7F11FFBE8113FF
+ BC8114FFBD7F15FFBB7E16FFBF7F19FFBF811BFFB97A12FFBB7E16FFBB7E16FF
+ B87B13FFBA7E14FFBD8319FFBF851BFFBD8417FFBC8316FFBA8215FFBA8217FF
+ B78017FFB97E1AFFB87E1EFFBA7D1FFFB67D22FFC08836FFAF7E3AFFB79266FF
+ D6BEA8FFEADBD9FFF0E8F3FFEFECFBFFEBEBF7FFEAEDF5FFE8EFF2FFE7F1F1FF
+ E7F1F1FFE9F0F3FFEBEFF0FFF0EDEFFFF1EBF0FFEEEAF5FFF0EDF6FFFEFBF7FF
+ EFE5D3FFCBB189FFB88E53FFBA8132FFC08022FFC2841AFFBF8214FFBC7F11FF
+ BD7E10FFC07F12FFC18210FFC0830DFFBD830CFFBF810FFFBD7E0EFFBC7D0DFF
+ BD7E0EFFC08210FFC18311FFC08210FFBE800EFFBE810DFFBE810DFFBE810DFF
+ BD800CFFBD800AFFBC7F09FFBC7F09FFBC7F0BFFBE800EFFC18212FFBF8010FF
+ BB7C0CFFBB7C0CFFBF8010FFC08210FFBD7F0DFFBB7D0BFFBB7D0BFFBC7F0BFF
+ BC7F0BFFBC7F09FFBC7F09FFBB7E08FFBB7E08FFBD800AFFBD800AFFBD800CFF
+ BD800CFFBD7F0DFFBD7F0DFFBD7E0EFFBD7E0EFFBD7E0EFFBA7B0BFFB87909FF
+ B87A08FFBB7D0BFFBF820EFFC28511FFC38612FFB97B09FFB97A0AFFBB7C0CFF
+ BC7D0DFFBE7F0FFFC08111FFC18212FFC18212FFBD7E0EFFBD7E0EFFBE7F0FFF
+ BE7F0FFFBF8010FFBF8010FFC08111FFC08111FFC18214FFC18214FFC18214FF
+ C18214FFC08113FFBF8012FFBE7F11FFBD7E10FFBB7C0EFFBF8012FFC08113FF
+ 240E5DFF2E1964FF30175BFF270E46FF3A1E49FF6A4D67FF967B84FFAF928DFF
+ AC8F81FFA98C77FFAD8F72FFB9A185FFB2A390FF807980FF4B4D7DFF40498CFF
+ 415291FF425795FF405A9CFF3D5CA1FF375AA4FF345CA7FF3561AEFF3A67B1FF
+ 426FB8FF426EB5FF4872B7FF4973B8FF466FB4FF4C75BAFF4F79C0FF4972BBFF
+ 4068B3FF3F66B4FF3D64B3FF3B62B1FF355AACFF3153A6FF3452A3FF3A56A3FF
+ 354C97FF304386FF30407BFF343E74FF323867FF31335CFF323158FF33304AFF
+ 413943FF4B3B34FF60432EFF684222FF683E19FF673D18FF643C19FF68401DFF
+ 673E17FF693F15FF673E17FF663F19FF653F1CFF68421FFF6E451EFF71461FFF
+ 693F1AFF663F19FF663F19FF67401AFF68411BFF69421CFF67401AFF663F19FF
+ 653E18FF643D17FF633C16FF633C16FF633C16FF643D17FF653E18FF643E1BFF
+ 664420FF644420FF67431DFF64401AFF5F3C1AFF5A3918FF5B3816FF5B3816FF
+ 603A1AFF573720FF4A3534FF484156FF3E4A7AFF2E4589FF2C4B9AFF3B5FB3FF
+ 3D64B3FF3A61AFFF3C62B0FF4266B4FF3F5FABFF3C59A4FF3B55A1FF334B93FF
+ 354A8EFF344683FF35427AFF3C4473FF44476DFF4A4B67FF524F65FF615660FF
+ 62493FFF5D3E29FF56371EFF59391CFF5D3A19FF633D1AFF693E17FF673A07FF
+ 7A4C0CFF996A19FFAE7F1DFFB68519FFBE8619FFBF8319FFC2811FFFCA8627FF
+ BC7B18FFBB7D17FFBB7D17FFBD7F19FFBC801CFFBD8121FFBE8123FFBD8323FF
+ BB801CFFBA8215FFB8810EFFB58008FFB9800CFFBF8312FFC08218FFBB7E16FF
+ BD8018FFB97F15FFBD8117FFC1881BFFC3881BFFB98112FFB87D0FFFB77F10FF
+ B67B0DFFB67E0FFFBA7F11FFBA8114FFBC8016FFBC8218FFC0831BFFC0861DFF
+ B97C14FFB97F16FFBA8017FFB97F16FFBB8118FFBF871CFFC1891EFFC1891EFF
+ BA8215FFB78116FFB78017FFB6801BFFB97F1FFFB87F22FFBD8128FFBA8230FF
+ C49148FFB58A51FFC1A583FFE5D3C8FFF3ECF1FFEDEAF9FFEAEAF8FFECEDF7FF
+ E8EBF0FFE8EDF0FFE5EEF1FFE7F0F3FFE9EFF4FFEBEEF2FFF2EDEEFFF2EBEEFF
+ F4ECF3FFFDF4F7FFFFFDF1FFDAC5A9FFB69563FFBC8E47FFB87D27FFC2811EFF
+ C48418FFC08111FFBB7E10FFBA7D0FFFBF8010FFC28511FFC3870FFFC3870FFF
+ BF810FFFBE7F0FFFBD7E0EFFBE7F0FFFC08210FFC28412FFC18311FFBF810FFF
+ BF820EFFBF820EFFBF820EFFBE810DFFBE810BFFBD800AFFBD800AFFBD800CFF
+ BF8010FFC18214FFC08113FFBE7F11FFBE7F0FFFC18212FFC28313FFC08111FF
+ BC7E0CFFBC7E0CFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBC7F0BFF
+ BA7F0BFFBA7F0BFFBA7E0CFFBA7E0CFFBA7E0DFFBA7E0DFFBA7D0FFFBA7D0FFF
+ B77A0CFFB87C0BFFB87C0BFFB97D0BFFB97D0BFFBC810DFFC08511FFC28713FF
+ C08210FFBF810FFFBF810FFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFFBF810FFFBF810FFFBF810FFF
+ C08111FFC08111FFBF8010FFBF8010FFBF8010FFBF8010FFBF8010FFC08111FF
+ BB7C0CFFBF8010FFC08111FF331666FF351861FF30154DFF3B1E45FF6A4B60FF
+ A48588FFB2968BFFA38874FFA98B78FFAB8C77FFA8866FFFAF9079FFAD9987FF
+ 807879FF4E4E76FF424D87FF44548FFF435896FF415B9DFF3E5DA2FF3A5DA7FF
+ 365DABFF3662AFFF3765B2FF3E6BB5FF3B68B1FF436FB6FF4872B7FF466FB4FF
+ 4A73B8FF4C76BDFF4770B9FF4068B3FF4067B5FF4067B6FF3B62B1FF3459ABFF
+ 2E51A1FF2D4E9DFF304F9AFF2D458DFF2E4184FF2F3F7AFF323D71FF313764FF
+ 30325AFF303054FF34314BFF3A343FFF4C3E38FF745944FF876443FF825A37FF
+ 7B542EFF704A28FF724C2AFF704923FF704720FF6D4620FF69441EFF674220FF
+ 674220FF6A431DFF6C431CFF6A431DFF65401AFF643C19FF613C16FF633B18FF
+ 623D17FF663E1BFF65401AFF68401DFF67421CFF69411EFF68431DFF6A421FFF
+ 66411BFF673F1CFF643E1BFF613E1CFF63411DFF67421CFF643F19FF5D3A18FF
+ 593817FF5C3917FF603C18FF653D1AFF5D381EFF4F352EFF4B4050FF434A75FF
+ 324785FF284792FF2F54A4FF416BB8FF406AB5FF4169B4FF486CB8FF4265AFFF
+ 3C5BA6FF405CA9FF36509CFF344B96FF31488CFF364889FF3B4983FF3E4878FF
+ 3E446DFF45496CFF58556BFF68595DFF5F4A42FF553B2DFF523723FF59381EFF
+ 613B19FF683D12FF6D3E06FF8E5E16FFAA7820FFBA8621FFBC8719FFBE8619FF
+ C0831BFFC38023FFC9882CFFBA7D1FFFB87F1CFFB9811CFFB9811CFFBA811EFF
+ BC8222FFBE8425FFBF8525FFBC811DFFBA8118FFB98110FFB8810EFFBA8211FF
+ BC8415FFBB8118FFB97D19FFBC801CFFB87D16FFBB8019FFC2881FFFC2881FFF
+ BA8016FFB77E11FFBB8215FFB47B0EFFB57C0FFFB77E11FFB87F12FFBA8016FF
+ BC8218FFBE841BFFBF851CFFBC831AFFBC831AFFBB811AFFB88119FFBA8019FF
+ BA831BFFBB841BFFB9851BFFBB851AFFB78319FFB7821AFFB98423FFBD8427FF
+ BD842EFFC48A38FFC68F46FFC19255FFC09D71FFD7BFA9FFF3E7E1FFF7F3FEFF
+ EBEBFBFFE9E9F5FFEFF0FAFFECEDF1FFEAEEEFFFE7EDF2FFE8EEF3FFE8EEF5FF
+ ECEFF4FFF5F0F2FFF8F0F1FFFBF0F2FFFAECE6FFEED9C4FFC0A47BFFAE8547FF
+ BA8737FFBB8122FFC1821AFFC38317FFC18214FFBC7F11FFBC7F11FFBF8312FF
+ C38612FFC3870FFFC2860EFFC08210FFBF8010FFBD7E0EFFBF8010FFC18311FF
+ C28412FFC18311FFC08210FFC0830FFFC0830FFFBF820EFFBF820EFFBE810BFF
+ BE810BFFBE810BFFBD800CFFBF8010FFBF8012FFBF8012FFBF8012FFBF8010FF
+ C08111FFC18212FFC08111FFBE800EFFBD7F0DFFBB7D0BFFBA7D09FFBA7D09FF
+ BB7E0AFFBD800CFFBE810DFFBA7F0BFFBA7F0BFFBA7E0CFFBA7E0CFFBA7E0DFF
+ BA7E0DFFBA7D0FFFBA7D0FFFB87B0DFFBD8012FFC18514FFC28615FFBF8311FF
+ BB7F0DFFB97E0AFFB97E0AFFC28412FFC18311FFC08210FFBF810FFFBE800EFF
+ BD7F0DFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBE7F0FFF
+ BF8010FFC18212FFC28313FFBB7C0CFFBF8010FFC08111FF422067FF33134EFF
+ 42234AFF785869FFA88784FFB3927EFFAB8C6DFFA78869FFA98972FFB59383FF
+ B79081FFB29080FFAA927EFF80746EFF514F6CFF414B7BFF45538DFF425795FF
+ 415B9DFF3E5FA4FF3B60AAFF3862AFFF3664B2FF3565B3FF3664B1FF3663ADFF
+ 406CB3FF4773BAFF4771B6FF4872B7FF4A74BBFF456EB7FF3A64AFFF3C66B1FF
+ 3C66B3FF3960AEFF3358A8FF3053A3FF2E4F9EFF2F4E99FF274086FF2E4283FF
+ 2F4079FF2F3A6CFF2F3661FF303359FF313052FF35324BFF383440FF4F4341FF
+ 8C7462FFAA8A6DFFA88262FFA17C5AFF947052FF957251FF9A7652FF98734DFF
+ 926E4AFF8A6745FF826042FF7F5C3BFF7F5936FF7D5734FF7A5431FF785430FF
+ 785230FF74502CFF714B29FF6D4925FF6C4624FF6A4622FF6D4725FF6A4622FF
+ 684220FF65411DFF643E1CFF633F1BFF643E1CFF643F1DFF5A3715FF5F3A18FF
+ 653E18FF653E18FF613C1AFF5F3C1BFF643F1DFF68431DFF6E431CFF643D1DFF
+ 553829FF50434BFF4B5176FF394D86FF28468DFF254C97FF2F5AA3FF325FA8FF
+ 3D67AEFF5177BFFF4F70B9FF4161AAFF4360ABFF38529EFF354F9BFF334C96FF
+ 344A91FF374B8CFF37457FFF313E72FF374170FF484C6FFF5B576AFF5F545EFF
+ 5B4D4FFF594540FF593C2DFF583619FF653B11FF774A11FF9A6820FFAF7C26FF
+ BB8526FFBD8722FFC18825FFC28626FFBD7E26FFBC7F29FFBB832AFFB88426FF
+ B78424FFB88322FFB88322FFBB8324FFBC8326FFBD8427FFBE8424FFBB831EFF
+ BB8219FFBB8316FFBC8419FFBC821BFFBA7F1CFFB97C1EFFBD8022FFB97C1EFF
+ B97C1EFFBE8222FFBE8320FFBB801CFFBB811AFFBF861DFFB57D12FFB57D12FF
+ B67E13FFB77F14FFB98017FFBA8118FFBA8019FFBA8019FFBD861EFFBB841CFF
+ BA821DFFB7811CFFB87F1CFFB57E1BFFB6801BFFB5811CFFBD8820FFB7831EFF
+ B78221FFB98527FFBC832EFFBC8334FFC58B40FFC89354FFBB9363FFD0B495FF
+ EEDBCCFFFAF1EEFFF3F2FCFFEBECFAFFECECF8FFF1F3FBFFF1F2F6FFF0F2F3FF
+ ECEFF4FFEAEDF2FFEBEDF5FFEFEFF5FFF8F3F5FFFFF5F5FFFFF6F0FFEEDAC9FF
+ C2A382FFB18B55FFB18238FFB27D23FFBD821FFFB87C12FFC28118FFC18115FF
+ BF8115FFBE8316FFC08615FFC18513FFC0830DFFBE800AFFC08210FFBF8010FF
+ BD7E0EFFBF8010FFC18311FFC28412FFC18311FFC08210FFC0830FFFC0830FFF
+ BF820EFFBF820EFFBE810BFFBE810BFFBE810BFFBD800CFFBD7E0EFFBC7D0FFF
+ BD7E10FFBE7F11FFBF8012FFBF8012FFBF8010FFC08111FFBE7F0FFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBB7E0AFFBC7F0BFFBD800CFFBE810DFFBB800CFFBB800CFF
+ BB7F0DFFBB7F0DFFBB7F0EFFBB7F0EFFBB7E10FFBB7E10FFBE8113FFC28517FF
+ C68A19FFC68A19FFC18513FFBC800EFFB97E0AFFB87D09FFB97C08FFBA7D09FF
+ BC7F0BFFBE810DFFC0830FFFC28511FFC38612FFC48713FFBE810DFFBE810DFF
+ BD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBE800EFFBE800EFF
+ BD7F0DFFBC7E0CFFBD7F0DFFBF810FFFC18311FFC28412FFBB7D0BFFBF810FFF
+ C08210FF3A1A49FF442348FF664657FF92716EFFA47E6CFF956F51FF8A673FFF
+ 8E6D46FF97765CFFAC8975FFB9917FFFB4917DFFA88F75FF837569FF59556EFF
+ 484E7BFF46538BFF415694FF415B9DFF3F60A5FF3E62AEFF3A64B1FF3764B5FF
+ 3666B4FF3664B2FF3261ABFF3D6AB3FF4874BBFF4771B6FF4670B5FF4771B8FF
+ 436DB4FF3762ABFF3963AEFF3862AFFF345EABFF3459A9FF3559A7FF3355A1FF
+ 31519AFF264083FF2F4482FF2D3E76FF2B3668FF2F3560FF303457FF313050FF
+ 35324BFF343140FF473F3FFF917A6AFFB5987DFFB69476FFB59473FFAD8D70FF
+ B39376FFBC9B7AFFBC9977FFB89574FFB29072FFAC8C6FFFA9896CFFAC8968FF
+ AD8866FFA07B59FFA17E5CFFA57F5FFFA27F5DFF9D7757FF916E4CFF8A6444FF
+ 83603EFF866040FF7F5C3AFF7A5434FF714E2CFF714B2BFF714E2CFF785232FF
+ 795635FF694625FF6B4624FF6E4721FF6C451FFF66411FFF623F1DFF643F1DFF
+ 67401AFF693D14FF633916FF563623FF524144FF4E5170FF3F5186FF2E4B8EFF
+ 2A4F99FF2D59A0FF3564A8FF4A75B8FF6E95D9FF6B8ED2FF4E6CB3FF4461ABFF
+ 36509CFF3A54A1FF354F9CFF324B95FF30468DFF2E4283FF2F3F7AFF354378FF
+ 3E4975FF44496AFF56566EFF635D70FF665961FF5F4944FF583825FF66401DFF
+ 855924FFAB7A36FFB98636FFBB8530FFB98128FFBD852CFFBE852FFFB8802EFF
+ B8822FFFBA8835FFB98832FFB8862CFFB88527FFB88426FFBB8429FFBE842BFF
+ BE842BFFC3872DFFBE8326FFBD821FFFBD8421FFBE8522FFBC8223FFB98025FF
+ BB7F26FFBE812BFFBD8128FFBD7E26FFBA7E24FFBC7F22FFBC8222FFC08522FF
+ C08823FFBA8019FFB78018FFB87E17FFB78018FFBA8019FFB9821AFFBB811AFF
+ B88119FFB9831EFFB6801BFFB67F1CFFB88120FFB88021FFB5801FFFB68120FF
+ B98423FFBF8B27FFB78423FFB58123FFB8822BFFB77F2EFFB67C34FFC08442FF
+ C4905BFFC19E7CFFE1CCB7FFFCF0E6FFF8F3F2FFEFEEF7FFECEEF8FFEFF0FAFF
+ F2F4FCFFF3F4F8FFF4F3F7FFF1F0F4FFF0EEF4FFF0EEF4FFF4F0F6FFF9F3F8FF
+ FFF6F6FFFFF8ECFFE0C7ADFFAD895BFFB58747FFBF8B38FFB7801FFFC28821FF
+ B77D13FFBE7F17FFBE7F17FFBD8018FFBF8319FFC08517FFBF8514FFBE810DFF
+ BC7D0AFFBF810FFFBE7F0FFFBD7E0EFFBE7F0FFFC08210FFC28412FFC18311FF
+ BF810FFFBF820EFFBF820EFFBF820EFFBE810DFFBE810BFFBD800AFFBD800AFF
+ BD800CFFBC7D0DFFBA7B0DFFBC7D0FFFBF8012FFC08113FFBE7F11FFBE7F0FFF
+ C08111FFBE7F0FFFBD7E0EFFBD7F0DFFBC7E0CFFBC7F0BFFBD800CFFBD800CFF
+ BE810DFFBC810DFFBC810DFFBC800EFFBC800EFFBC800FFFBC800FFFBC7F11FF
+ BC7F11FFC48719FFC38618FFC28517FFBF8312FFBD810FFFBC800EFFBD820EFF
+ BF8410FFBA7D09FFBB7E0AFFBC7F0BFFBD800CFFBF820EFFC0830FFFC18410FF
+ C28511FFBE810DFFBE810DFFBD800CFFBD800CFFBD800CFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBF810FFFC08210FF
+ C08210FFBB7D0BFFBF810FFFC08210FF3C232DFF52393DFF6D5047FF775643FF
+ 794F38FF77492AFF704720FF69451DFF735133FF7E5C3FFF8C6648FF8F6C4BFF
+ 856B47FF6D5D4CFF584F69FF505282FF47548CFF425794FF425C9EFF4061A6FF
+ 3D64AFFF3A66B3FF3564B5FF3364B2FF3969B7FF3564AEFF3D6AB3FF4773BAFF
+ 456FB4FF426CB1FF456EB3FF426CB3FF3C67B0FF3B65B0FF3761AEFF315BA8FF
+ 345AA8FF365AA8FF3355A1FF2E4E97FF284285FF324784FF2E3E73FF273363FF
+ 2F355EFF333558FF313050FF33334BFF302F3FFF3E393BFF897669FFAD937BFF
+ AE9075FFB29477FFAD8F76FFB6997EFFB69679FFB59677FFB49477FFB19378FF
+ B09279FFB09378FFB49576FFB79675FFAE8D6CFFB39271FFBA9678FFB99877FF
+ B89476FFB1906FFFAF8B6DFFAB8A69FFAD896BFFA78665FFA48062FF9E7D5CFF
+ 9E7A5CFF9D7C5BFFA27E60FFA48160FF926F4EFF926C4AFF926843FF8D633EFF
+ 86603EFF805B39FF7D5735FF7C552FFF7B4E23FF794D28FF6B4932FF5F4B4AFF
+ 51526EFF3E4F80FF314D8EFF2F559DFF3865A8FF416FAFFF5782C1FF86ACECFF
+ 7FA1E3FF5572B5FF4662A9FF36519BFF3953A0FF37519EFF324C99FF2F4892FF
+ 31488CFF374C8AFF394B86FF394A7DFF364671FF465276FF555877FF615B72FF
+ 685760FF654B44FF745235FF92693CFFC19359FFCE9A57FFC8914CFFBA853CFF
+ B8833AFFB48236FFB18231FFB28534FFB98B3DFFB78A39FFB68834FFB7872FFF
+ B8862CFFBB852EFFBF8631FFC28634FFC68834FFC0832DFFBD8128FFC0842AFF
+ C2862DFFBE822EFFBC8131FFBF8435FFC28535FFC58937FFC48632FFBA7F29FF
+ BB7F26FFBF8629FFC28829FFBC8524FFBC8320FFB8821DFFB9811CFFB9831EFF
+ BD8520FFBD8722FFBD8520FFBA841FFFBA8320FFB5811DFFB47E1FFFB88223FF
+ B98325FFB68224FFB78325FFBC8929FFBD8A2AFFB58224FFB48026FFB8822FFF
+ B87F34FFB77E39FFC3874BFFC89668FFD4B69DFFF0E0D4FFFFF8F1FFF7F2F1FF
+ F0EFF3FFF1F4F9FFF1F3FBFFF0F2FAFFF0F0F6FFF2F1F5FFF6F0F5FFF6F0F5FF
+ F6F0F5FFF6EFF6FFF5EEF5FFFAF0F0FFF1E1D0FFC6AC88FFAD844DFFB9863DFF
+ C28C2EFFC18A21FFC18B20FFBB8318FFBA7C16FFBA7C18FFBA7C16FFBC7F17FF
+ BD8417FFBF8416FFC08111FFBE7F0DFFBF8010FFBD7E0EFFBC7D0DFFBD7E0EFF
+ C08210FFC18311FFC08210FFBE800EFFBE810DFFBE810DFFBE810DFFBD800CFF
+ BD800AFFBC7F09FFBC7F09FFBC7F0BFFBD7E10FFBB7B0FFFBD7E10FFC28315FF
+ C38416FFC08113FFBF8010FFC28313FFBD7E0EFFBD7E0EFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBD820EFFBB820EFFBB820FFFBB820FFF
+ BB8110FFBB8012FFBB8013FFBB8013FFC2871AFFBF8416FFBB8012FFB87E0DFF
+ B9800DFFBA810EFFBB820EFFBE830FFFBF820CFFBF820CFFBE810BFFBD800AFF
+ BD800AFFBC7F09FFBB7E08FFBB7E08FFBE810BFFBE810BFFBD800AFFBD800AFF
+ BC7F09FFBC7F09FFBB7E08FFBB7E08FFBC7F0BFFBD800CFFBE810DFFBE810DFF
+ BF820EFFBE810DFFBE810DFFBE810DFFBB7E0AFFBF820EFFC0830FFF5E402FFF
+ 573724FF57351DFF623D21FF6C3F24FF693A1EFF643918FF633D1AFF583618FF
+ 4E2F10FF51310EFF543712FF4E3612FF473524FF4C3E50FF514D77FF4A578BFF
+ 435895FF435E9EFF4363A5FF4066AEFF3C66B1FF3863B2FF3462B0FF416FBCFF
+ 3B68B2FF406BB4FF4771B8FF426CB3FF3F69B0FF436BB3FF416AB3FF456FBAFF
+ 426CB9FF3B62B0FF335AA8FF3458A6FF3759A5FF31519AFF2A478CFF2E4485FF
+ 364883FF2F3D71FF293160FF30345DFF343659FF313050FF33334BFF373745FF
+ 423B3EFF8C796CFFAF957DFFAE9075FFAF9174FFA68B71FFAF947AFFB39376FF
+ B29374FFAF8F72FFAB8D70FFA98C71FFA88B70FFAC8A6CFFAC8B6AFFB49274FF
+ B59376FFB59376FFB29073FFAF8D70FFAE8C6FFFB18F72FFB49275FFB39174FF
+ B49275FFB69477FFB79578FFB79578FFB49275FFB08E71FFAE8C6FFFB39173FF
+ B28F6EFFB28C69FFB28A67FFB0886BFFAE876BFFA88466FFA78260FF9F794FFF
+ 9E7953FF906E56FF7B635DFF605A6DFF434C77FF324987FF32549AFF3863A6FF
+ 3B69A9FF4F7BBBFF81A9EAFF7DA0E2FF4D6FB1FF4462A9FF3A57A1FF304E9BFF
+ 32509DFF304E9DFF304C99FF36519BFF3E579DFF3A5294FF344986FF394E85FF
+ 394A7BFF3C4571FF4F5072FF676075FF6F5F66FF796056FF8F7057FFB18A64FF
+ C2986BFFC89966FFBF905AFFBB8C54FFB38A4CFFAB8747FFAD8A48FFB18948FF
+ B28843FFB3863DFFB38538FFB68535FFB98636FFBD873AFFC0883BFFC0873CFF
+ B98035FFB77D31FFBB8233FFBE8438FFBD8337FFBD8439FFC1873FFFC2883DFF
+ C98F44FFC68C40FFBC8132FFB97F2DFFC18833FFC08731FFB77F26FFBB8429FF
+ B98325FFBA8223FFBC8425FFBF8827FFC18A29FFC08928FFBF8728FFBD8728FF
+ B88224FFB88126FFBB8429FFBC852AFFB98227FFBA8328FFBF892BFFBB8729FF
+ B48022FFB58026FFBB8433FFBA843DFFB98445FFC7915CFFCDA17CFFDECAB9FF
+ F4EBE7FFFFF8F8FFF5F0F1FFF4F0F5FFF5F5FBFFF1F3FBFFEFF1F9FFECECF2FF
+ F0EFF3FFF5F2F4FFF8F3F5FFF9F2F5FFF6EFF2FFF2EBF0FFF7EBE5FFD8C0A2FF
+ B08C5CFFB28242FFB57E2DFFB77D1DFFC38B20FFB98416FFB88015FFB97B15FF
+ B87A16FFB97815FFB97B15FFBA8016FFBE8316FFC28315FFC18212FFBE7F11FF
+ BC7D0FFFBB7C0EFFBC7D0DFFBF8010FFC08111FFBF810FFFBD7F0DFFBE800EFF
+ BD800CFFBD800CFFBD800CFFBC7F0BFFBC7F0BFFBB7E0AFFBB7D0BFFBF8010FF
+ BC7D0FFFBE7F0FFFC58616FFC68717FFC28313FFC18212FFC58616FFBC7D0DFF
+ BD7E0EFFBE7F0FFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBA7E0DFFBC8310FF
+ BA8310FFBC8310FFBC8211FFBC8113FFBC8113FFBC8114FFBC8114FFBF8417FF
+ BD8215FFBA7F11FFBA7F11FFBA800FFFB97F0EFFB57C09FFB47806FFBB7E0AFF
+ BC7E08FFBD7E0BFFBD7E0BFFBE7F0CFFBE7F0CFFBE810DFFBE810DFFBE810DFF
+ BE810DFFBD800CFFBD800CFFBC7F0BFFB97E0AFFB97E0AFFBB7E0AFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFBC800FFFBB7F0EFFBA7E0DFFB97D0CFF
+ BD8110FFBE8211FF613212FF633615FF673A19FF683C1DFF663B20FF633A21FF
+ 5D371FFF59351DFF503118FF54371CFF4E3214FF4B3113FF4D371EFF433023FF
+ 47353CFF5A516BFF434D7CFF374E86FF435D99FF4B67A7FF4365A7FF4066AEFF
+ 3F66B1FF335DAAFF446EBBFF426CB9FF4169B4FF436AB4FF476EB8FF4A71BBFF
+ 4972BBFF476FBAFF426BBAFF3F65B7FF3A5FAFFF3B5FADFF3F5FABFF3F5AA4FF
+ 375096FF314789FF32417FFF344179FF343D6FFF323764FF2E3058FF2C2E51FF
+ 2D2E50FF33324CFF33313DFF574D4DFF866F5FFFA2856AFFA98A6BFFA8896AFF
+ A78A6FFFAB8E73FFB49274FFB69372FFB49170FFAF8E6DFFA98A6BFFAA8968FF
+ B28C69FFB58F6CFFB28D71FFAF8D75FFB29078FFB4927AFFB18F77FFAD8B73FF
+ AD8B73FFB08E76FFB18F77FFB18F77FFB18F77FFB29078FFB18F77FFAF8D75FF
+ B18F77FFB4927AFFAF9077FFB09275FFB39370FFB28F6EFFB88F79FFBC9482FF
+ B4947DFFAA8F74FFA78F6BFFAD936FFFAB8D72FFAE9183FF907B83FF524D6CFF
+ 32407BFF2D4A94FF325BA4FF426FB8FF4C78BFFF557FC4FF618ACFFF557CC1FF
+ 3E65AAFF3D63ABFF3C61ABFF395DA9FF3357A5FF3152A1FF3857A6FF3D5CABFF
+ 3856A3FF314C96FF30478BFF3B4D8AFF455187FF4A507DFF4D4F72FF55526BFF
+ 675D6DFF77696DFF86706AFFB09384FFC8A48CFFC4A180FFDEBC98FFC9AC85FF
+ AF9872FFA68D65FFB29062FFB8905CFFBB8D57FFBA8B4EFFB98949FFB98A46FF
+ BA8D49FFBC924DFFBD9151FFB48547FFBD8A4CFFD19C5DFFD59D5CFFC18A45FF
+ B7813AFFBC8841FFB67F3AFFBA8340FFC9924DFFCA924BFFBD853EFFC48D44FF
+ CB9247FFB88031FFB67E2DFFBC8432FFBD842FFFB77E28FFBB8128FFC38930FF
+ C1872EFFB77D24FFB87F2AFFC18833FFC0852FFFBD802AFFC1852CFFC1852BFF
+ BF8329FFC48B2EFFC1892AFFC58D2EFFB78025FFB98532FFC89751FFBB8E55FF
+ BD966AFFE1C6ABFFF6ECE5FFEDECF0FFF3EFF5FFF7F3F9FFF8F4FAFFF7F2FBFF
+ F3F0F9FFEFEEF7FFEDEDF3FFEDEEF2FFEAECECFFF3F4F2FFF5F1F0FFF6F1EEFF
+ FBF2EFFFF2DECCFFC29B6EFFBC8A48FFB37C31FFB37A24FFB77D1DFFBF861DFF
+ C0861CFFB87D10FFC6871FFFBD7E16FFC4821BFFC98A22FFC2841AFFBF8115FF
+ C28315FFBE7F11FFBF7E15FFC3851BFFC08218FFBE8014FFC18317FFBC7F11FF
+ B87C0BFFBE8210FFBA7E0CFFBC800EFFBD810FFFBB7F0DFFB97D0BFFB97D0BFF
+ BC800FFFC18212FFC48614FFC18210FFBE7F0DFFBE7F0DFFC18210FFC38313FF
+ C38313FFC28114FFC08113FFC18115FFC48418FFC58519FFC5841BFFC38219FF
+ C18017FFBD7F13FFBA8213FFB7810FFFB67E0DFFB47C0BFFB37B0CFFB27A0BFF
+ B37B0CFFB37B0CFFC28719FFC08517FFBF8115FFBC7E12FFBA7D0FFFBB7E10FF
+ BC7F11FFBF8010FFBC7A09FFC07D0AFFC07C0BFFC07C0BFFBD7B0AFFBE7C0BFF
+ BF800EFFC38412FFBA7C0AFFB97B09FFB97D0CFFBE8211FFBF8312FFB87E0DFF
+ B67C0BFFB97D0CFFBC7C0CFFBC7C0CFFBC7D0FFFBE7F11FFBE8014FFBF8319FF
+ C2851DFFC3861EFFB77A12FFBB7E16FFBB7F15FF8D5722FF86521DFF794816FF
+ 6E4011FF633811FF5D3413FF5B3418FF5A351BFF543117FF5A3C1FFF573B1CFF
+ 4F371BFF4D3521FF422C20FF4B3635FF5F5566FF49527EFF3A4E88FF425A96FF
+ 4965A5FF4666A8FF4266ACFF4166B0FF375FAAFF3C63B1FF3D65B0FF3F67B2FF
+ 426AB5FF456CB7FF446CB7FF436BB6FF3F69B6FF3F67B9FF3C62B4FF395EAEFF
+ 3C5DACFF415DAAFF4059A3FF384D91FF324485FF35407CFF364076FF373B6EFF
+ 333663FF2E3058FF2C2E51FF2E2F51FF34334DFF2F2B37FF433735FF624A38FF
+ 7D5F44FF91704FFF987756FF937558FF8F7154FF906F4EFF977452FFA07B59FF
+ A3805EFFA48362FFA78462FFAC855EFFAC855FFFAD896BFFB29177FFB6947CFF
+ B19076FFAF8D75FFB29177FFB18F77FFAC8B71FFAB8971FFAE8D73FFB08E76FF
+ AE8D73FFAD8B73FFAE8D73FFAF8D75FFAC8D74FFB3957CFFB4987AFFB39572FF
+ AF8D6FFFB28875FFB18A7BFFAB8B78FFA0896FFFA89572FFA99671FFAB8B6EFF
+ B2917EFF9C807FFF62556DFF3D467FFF324D97FF2B529DFF3866B3FF4572BCFF
+ 5782CBFF6B95DCFF5E88CFFF426CB3FF3A64ABFF3D66AFFF3A62ADFF345AA8FF
+ 3055A5FF3557AAFF3A5CAFFF3959ACFF3553A2FF3A519DFF3C4F93FF3C4B89FF
+ 3C487EFF424A79FF4A4F76FF545577FF5D5A74FF675D6EFF928289FFF8E2DDFF
+ DFC7BBFFC7B19FFFEAD7C2FFE7D9C6FFD6C8B2FFD6BDA3FFCBAC8DFFC09B79FF
+ BF9871FFC8A175FFC9A575FFBE9D6CFFB09261FFB99A6DFFB69469FFB79069FF
+ BE946AFFC09368FFBB8F60FFB48C57FFB58C55FFD5A973FFC69A64FFC0935AFF
+ B5884FFFAD7E46FFBD8F55FFCA9B5EFFBC8B4DFFCD9D5DFFCC9A58FFC28E4BFF
+ B37F39FFB17D36FFBE8841FFC28D44FFBE8940FFBD883FFFBF8A41FFC28A3DFF
+ BF8637FFBA7F30FFB77C2CFFBC8433FFC68E3CFFC48D38FFC7913CFFC08C39FF
+ B9883CFFB28748FFA78452FFC2A683FFF1E2CFFFF1EFEEFFEBEEF6FFEFF1F9FF
+ F2F1FAFFF7F2FBFFF4F1FAFFF3F0F9FFEEF0F8FFEFF2F7FFEEF3F6FFE9EEEDFF
+ EFF3EEFFF6F3EEFFF7F1EAFFEEE4DAFFD9C2A8FFC0925CFFC08940FFBB8433FF
+ B8822BFFB88021FFBE8621FFC38A21FFBE841AFFC0841AFFBD7E16FFC1821AFF
+ C5861EFFC1821AFFC18319FFC18317FFBA7C10FFB6770FFFBE8119FFC08218FF
+ B97D13FFBC7E12FFB87D0FFFB97D0CFFBE8413FFBD810FFFBC8310FFBF8311FF
+ BB820FFFBB7F0EFFB97F0EFFBE8113FFC08315FFBB7F0EFFBD7F0DFFBC7E0CFF
+ BD7F0DFFBE7F0FFFBE7F0FFFBD7E10FFBC7C10FFBA7C10FFBC7E14FFBE8016FF
+ C18319FFC2831BFFC2831BFFC2821CFFC18319FFBC8211FFBB820EFFBA810EFF
+ B87F0CFFB77E0BFFB77D0CFFB87E0DFFB87E0DFFBF8312FFBE8211FFBD8012FF
+ BD8012FFBE7F11FFBC7F11FFBD8012FFBF8010FFC48414FFC78514FFC68413FF
+ C38110FFC07E0DFFBC7D0BFFBE7E0EFFBF810FFFBF810FFFBA7E0CFFBB7F0EFF
+ BF8312FFBD8312FFB87E0DFFB67C0BFFBA7E0DFFBF7F0FFFBE7E0EFFBD7E0EFF
+ BC7F11FFBD7F13FFBC8016FFBC8219FFBD831AFFB47A11FFB87E15FFBA7E14FF
+ A36E1EFF9E6B1BFF946317FF875912FF794D0EFF6D410CFF62380BFF5D320BFF
+ 613916FF66421EFF5E3E1BFF543819FF4E361EFF422D1EFF493432FF574D5EFF
+ 4F5786FF3B4D8CFF3E5496FF4762A5FF4565ACFF4066AEFF3E65AFFF3964ADFF
+ 345EA9FF3963AEFF3F69B4FF436EB7FF456DB8FF416BB6FF3F69B6FF3E67B6FF
+ 3D65B7FF3A60B2FF375CACFF3B5CABFF3E5CA9FF3E57A1FF374C90FF304283FF
+ 343F7BFF353F75FF333A6CFF2F3461FF2E3058FF2D2F52FF2F3052FF36334DFF
+ 3E3A46FF423634FF4E3624FF5C3E23FF6B4A29FF71502FFF69492CFF624225FF
+ 5F3D1FFF664322FF714E2CFF7D5A38FF866544FF8D6A48FF936C45FF936C45FF
+ 9C7957FFA58665FFA48566FF977857FF9A7B5CFFAD8E6DFFB59677FFAE8F6EFF
+ A48566FFA88968FFA98A6BFFA88968FFB09172FFB99A79FFB69778FFAC8D6EFF
+ A98B6EFFB09172FFB49470FFB49170FFB48B75FFB28A77FFAC8C75FFA78D6FFF
+ A58F6CFFA88E6AFFA88564FFB5907AFFA68A83FF716579FF48518AFF36509CFF
+ 284E9CFF315FADFF3E6AB7FF517EC8FF6A94DFFF638ED7FF4B74BDFF416AB3FF
+ 4169B4FF3D65B0FF385EACFF3359A7FF3659A9FF3B5EAEFF3E5FAFFF3F5CADFF
+ 455CACFF40529FFF38478CFF364282FF3B4680FF424A7FFF484C7CFF4C4C74FF
+ 524E71FF625973FFDED1DFFFFFF2F8FFE9DDDDFFF8EFEBFFFFFAF3FFFFFAF3FF
+ FFF5EDFFF7E8DFFFEAD6CBFFE1CABBFFDAC3B3FFD2BEACFFC9B8A5FFC0B29FFF
+ D4C5B5FFD8C7BAFFD5BFB4FFC8AFA5FFC9AFA3FFD2B8AAFFD1BAAAFFCAB49BFF
+ D3BA9AFFC3A883FFB89B76FFB0936CFFB1926BFFBEA077FFC1A178FFAC8C61FF
+ AE8D60FFBA976BFFC4A072FFC7A073FFC6A070FFC69E6EFFB99161FFAB834FFF
+ B1864DFFB18546FFBA894BFFC28F50FFBE8B4CFFB78446FFB98648FFBD8D4DFF
+ AB7B39FFB1823EFFC09350FFC59C5EFFB4915FFFB2956EFFD7C1A8FFFBF2E5FF
+ F0F2F2FFE9F2F6FFECF2F7FFEEF1F9FFF1F0F9FFEFF1F9FFF0F1FBFFEDF3FAFF
+ F1F7FEFFF0F6FBFFECF1F2FFF2F6F1FFFDFAF2FFFDF3E9FFE2D2C5FFBFA587FF
+ BD955BFFC19046FFC29141FFBC8B35FFB58224FFB78521FFBD8820FFBE871EFF
+ BA8118FFB77D16FFBA8019FFBD831CFFBC821BFFBE851CFFBD851AFFB87E14FF
+ B1770EFFBD831AFFC0841AFFB77D13FFB87D10FFB98112FFBD8312FFBF8716FF
+ BE8512FFBC8512FFBE8413FFBB8312FFBC8113FFBA8213FFBE8316FFBD8417FF
+ B57C0FFFB77E11FFBA8114FFBA8114FFB98013FFB77E11FFB87D10FFB87C12FF
+ B97D13FFB97C14FFBB7E16FFBC7F17FFBD8018FFBE8119FFBF821AFFC18317FF
+ C0830FFFC1850AFFC0830BFFBF820AFFBF820AFFC0820CFFC0820CFFC1830DFF
+ BC7F09FFBD800AFFBE810DFFBF820EFFC18210FFBF810FFFBF810FFFBC800EFF
+ C18815FFC28916FFC38814FFC08511FFBB800CFFB97E0AFFBA7E0CFFBB800CFF
+ C18612FFBE830FFFBD820EFFBF8410FFBE840DFFB97F08FFB87E07FFBD800AFF
+ C1830DFFC0820CFFBE810BFFBB800CFFBB7F0DFFB97F0EFFB8800FFFB98112FF
+ B57D0EFFB77F0EFFB97F0EFFA87110FFA87312FFA77515FFA47218FF996917FF
+ 8A5A12FF7C4A0EFF71420CFF704010FF693F12FF5C370BFF55340DFF533719FF
+ 4C351FFF4D392EFF4F4551FF565B88FF3D4D8FFF3B5094FF415DA4FF4465AEFF
+ 4065AFFF3D66AFFF3A67B0FF3562ACFF3B68B2FF426FB8FF4873BCFF4771BCFF
+ 456FBCFF416CBBFF416CBDFF3F67B9FF3B62B1FF395CACFF395AA9FF3C5AA7FF
+ 3B56A0FF364D91FF324485FF32407BFF343E74FF31386AFF2E3360FF2D2F57FF
+ 2E3053FF313052FF37344DFF3C3843FF413632FF4B3321FF513318FF583716FF
+ 5C3B1AFF5B3B1EFF5A3A1DFF5B391BFF5B3817FF5A3715FF5D3A19FF603E20FF
+ 664322FF6C451FFF69451DFF6F4D29FF765934FF755734FF6A4D28FF6E502DFF
+ 81643FFF8A6C49FF836641FF856744FF886B46FF886A47FF8B6E49FF9B7D5AFF
+ AC8F6AFFA78966FF967855FF8D6C4BFF987855FFA68460FFB08B69FFB38A71FF
+ B38A73FFB18E74FFAE9172FFA98D6AFFA98C67FFA98361FFB79278FFAD9284FF
+ 7C6F7DFF50578EFF37519EFF2F54A4FF315EAFFF3964B3FF4772C1FF5A86D3FF
+ 5B85D0FF4D77C2FF4A72BDFF4169B4FF3D65B0FF385FAAFF345AA8FF375BA9FF
+ 3B5EAEFF4162B2FF4462B3FF4860B4FF4156A8FF394A99FF35468FFF38488BFF
+ 3C4888FF3D4882FF3F457AFF474B7BFF43436BFF716E8EFFD1CEE4FFFDFAFFFF
+ EFEFF5FFF0F2F3FFFBFBFBFFF3F1F1FFF8F3F4FFFBF3F3FFFAEEEEFFF4E8E6FF
+ F2E9E6FFF5F0EDFFFBF7F6FFF5F1F0FFFDF7F8FFF9EEF0FFE9DCDEFFE8DBDDFF
+ F4E9EBFFF3EBECFFE9E0DCFFDDD3C2FFD7CAB4FFD6C8B2FFD9CBB5FFDFCFB8FF
+ E5D5BEFFDCCBB1FFC5B198FFBAA48BFFC2AD92FFCCB399FFCDB599FFD0B59BFF
+ D1B69BFFCDAF96FFC6A98AFFB5956AFFB29062FFB08A5AFFBB9363FFC59C6FFF
+ B98F64FFAE845AFFB38C60FFB48D60FFAB8555FFBB9767FFCAA97CFFBFA47FFF
+ C9B499FFE8DBCDFFF7F3EEFFEDF2F3FFE8F1F5FFE9EFF4FFEAEEF3FFECEFF4FF
+ EDF0F8FFEDF3FAFFEDF5FCFFECF6FDFFEAF3F7FFE8F0F0FFF1F2EEFFF9F3E8FF
+ EADDCDFFC2AF9AFFA08462FFBD9259FFBA8943FFBE8D41FFB58533FFAF7D23FF
+ B48123FFB68120FFBA8320FFBD8421FFBB801DFFBC811EFFC18623FFC28724FF
+ C18622FFC18720FFC18720FFBB8019FFC1861FFFBF851CFFB87E14FFBA8016FF
+ C0871AFFC1891AFFBE8617FFBE8615FFBE8615FFBD8516FFBC8415FFBB8215FF
+ BB8215FFBC8316FFBD8319FFB98116FFBC831AFFBE851CFFBE861BFFBB8318FF
+ B98116FFBA8016FFBC8218FFBC8218FFBB8117FFBA8016FFBB7F15FFBB7F15FF
+ BA7E14FFBA7E14FFBD8012FFC1810BFFC38208FFC38208FFC28309FFC28309FF
+ C3840CFFC3840CFFC2840EFFBE800AFFBD800AFFBD800CFFBE810DFFBE810DFF
+ BE800EFFBC800EFFBA810EFFB77F0EFFB88210FFB98310FFB9820FFFB67F0CFF
+ B67F0CFFB9800DFFBB820FFFBF8613FFBB820EFFBB7F0DFFBE830FFFBD820EFF
+ B97E0AFFBB7E0AFFBE810BFFC1840CFFC08409FFBF820AFFBD8109FFBA8009FF
+ BA7F0BFFB9800DFFB9800DFFBA810EFFBB820EFFBD820EFFB3770DFFB2780EFF
+ B1790EFFAF7810FFAB7413FFA36E14FF9F6718FF9B631CFF844E0DFF7A480CFF
+ 683D04FF5D3804FF59390EFF513816FF513B22FF4B3F3FFF595B84FF445092FF
+ 3A4E95FF3D58A2FF4062AEFF3E65B0FF3B66AFFF3C69B2FF3868B0FF3C6CB4FF
+ 4171B9FF4572BBFF4670BBFF456FBCFF436EBFFF4570C1FF436BBDFF3E65B4FF
+ 395CACFF3859A8FF3B59A6FF3C57A1FF384E95FF364889FF33417CFF313D73FF
+ 303769FF2C315EFF2D2F57FF2E3052FF313050FF36334CFF37313CFF3F332FFF
+ 4D3322FF553518FF5A3716FF5E3B1AFF5F3F22FF634326FF664426FF63401FFF
+ 5D3A19FF593615FF583618FF5C3918FF613A14FF5E3A12FF56350EFF5A3D16FF
+ 5E411CFF5D4019FF5D401BFF5F421BFF593C17FF51340DFF563914FF5E411AFF
+ 624520FF63461FFF6E512CFF7D6039FF7B5E39FF71512DFF6F4D29FF7B5733FF
+ 87633DFF926C49FF956D51FF987054FF9B7759FF9F7F5CFFA98966FFA78561FF
+ A17752FFA78161FF9C816DFF70656FFF4C538AFF3750A0FF3559ADFF3460B4FF
+ 3864B7FF3F6BBEFF4875C6FF4A75C4FF4571BEFF4771BCFF3F67B2FF3A63ACFF
+ 355CA6FF365AA6FF385CA8FF3B5FADFF3F63B1FF4465B5FF405BB2FF4058B0FF
+ 3C55ABFF3951A3FF374E9AFF364992FF36468BFF374587FF3D4884FF414B81FF
+ 303867FF646C91FFC1C6DFFFEEF3FFFFF3F7FCFFEAEFEEFFF7FAF8FFF5F6F4FF
+ F7F3F2FFF8F4F3FFFCF7F8FFFCF9FBFFF6F8F9FFF1F5F6FFF2F6F7FFFAF9FBFF
+ FAF5F6FFF3EEEDFFF4EFEEFFFAF5F6FFF5F4F6FFECECECFFF4F1ECFFF0EDE5FF
+ F2ECE5FFF5EFE8FFF9F2E9FFFEF7EEFFFDF4EBFFF0E7DEFFF0E5DDFFEBE1D7FF
+ E4D5CCFFD8CABEFFD8C7BEFFE1D1C5FFECDBD2FFF2E2D2FFE7D3BAFFE5D0B1FF
+ D1B799FFCFB297FFE0C2A9FFD1B29DFFC0A28FFFD3B5A2FFECCFBAFFCDB298FF
+ C7AC91FFC9B397FFC2AF9AFFD5C8BAFFF1EAE7FFF4F3F5FFE8EFF2FFE5EEF1FF
+ E5ECEFFFE6EBEEFFE9ECF0FFEBF0F3FFEDF3F8FFEEF7FBFFE7F2F6FFE3ECEFFF
+ E9EFEEFFF6F7EEFFF8F1E2FFDED0BAFFB8A286FFA98861FFCC9E68FFC28E4CFF
+ C28E47FFBA8639FFB7812EFFBE8831FFBB8227FFBB8023FFC5882BFFBF8024FF
+ BE7F23FFC48628FFC78729FFC18122FFC28223FFCC8D2BFFC88B29FFC28724FF
+ BC811DFFB87E17FFBB811AFFC38A21FFC1891EFFB88015FFBF871AFFBE8619FF
+ BD8417FFBC8316FFBC8218FFBC8218FFBC8218FFBC8219FFBE841DFFBD861EFF
+ C0861FFFBD841BFFBA8118FFB98017FFBD8319FFC0861CFFC0841AFFBF8417FF
+ BE8315FFBF8214FFBE8211FFBD8110FFBD8110FFBF810FFFBF7F09FFC17F08FF
+ C08109FFC1820AFFC2830BFFC0820CFFC1830DFFC0830FFFC18410FFBD820EFF
+ BB7F0DFFB97D0BFFB77E0BFFB87E0DFFB8800FFFB98110FFB47D0EFFB47F10FF
+ B68112FFB98213FFB78011FFB78011FFBA8114FFBC8316FFBB8013FFB87D0FFF
+ B97B0FFFBC7F11FFBC7F11FFB97C0EFFBC7D0FFFC08010FFC1810BFFC38208FF
+ C28009FFBF8008FFBE800AFFBE800AFFBF820EFFBF820EFFC28511FFC18410FF
+ C28310FFBB7910FFBA790DFFB8790BFFB6790BFFB4790CFFB37811FFB37619FF
+ B2751FFFA86D1EFF9F681FFF8F5C16FF7B4F10FF68430BFF59380AFF503510FF
+ 453328FF5C5979FF4A5490FF3E5194FF38539DFF3C5EAAFF3E65B0FF3A65AEFF
+ 3B68B1FF3868B0FF386AB2FF3C6CB4FF3F6CB5FF416CB5FF416BB8FF3F6ABBFF
+ 406BBCFF466DBCFF3F65B3FF395DABFF385AA6FF3C5BA6FF3C57A1FF394F96FF
+ 35498AFF334280FF323E74FF2F3668FF2B315CFF2C2F55FF2E2F51FF31314FFF
+ 353349FF3C3740FF423632FF4E3521FF57371AFF5E3B1AFF603D1CFF5B3B1EFF
+ 59391CFF5D3B1DFF5E3B1AFF5D3A19FF5C3A1CFF5E3C1FFF623E20FF673F1CFF
+ 65401AFF5A3A16FF583B16FF5B3E19FF5F421DFF60431EFF5A3D18FF543712FF
+ 523510FF4A2D08FF563914FF5D401BFF593C17FF583B16FF5D401BFF61441FFF
+ 61411DFF623E1AFF653F1CFF68421FFF6B4523FF6A4225FF6C4427FF734D2DFF
+ 7B5836FF856240FF855F3CFF7B5029FF7B5532FF71573FFF53494FFF434A81FF
+ 3D56A6FF375AB0FF3661B8FF3A65BCFF3E6ABEFF416DC0FF3E6BBCFF3C67B6FF
+ 3D67B4FF3B63AEFF365DA7FF3459A3FF375CA6FF3B60AAFF3C60ACFF3D61ADFF
+ 3F62B2FF3758AEFF3B5BB4FF3D5EB4FF3C5BB0FF3754A5FF334D9AFF334893FF
+ 36488FFF39498CFF384786FF39467EFF2E3B69FF6B7593FFE1E9FAFFFBFEFFFF
+ F4F8F3FFF2F8F3FFF1F5F0FFF1F2F0FFF3F3F3FFF5F6FAFFF4F7FCFFECF2F9FF
+ E4ECF3FFE8F1F5FFEAEFF2FFEEF0F0FFF5F3F2FFF5F6F2FFF1F4F2FFEAEFF0FF
+ E8EDEEFFF4F7FBFFF3F5F6FFF1F2F6FFF0EFF1FFEFEEF0FFF3F3F3FFF9F6F8FF
+ F8F6F6FFFCF9FBFFFDF8F9FFF8F3F4FFF2EDECFFEFE9EAFFF1ECEBFFF8F0F1FF
+ FBF4F1FFFFF9EFFFFFFFF2FFFDEDE0FFF6E5D8FFFFEEE6FFF4E0DBFFE8D5D2FF
+ FDEAE7FFFFEFEAFFEDDCD3FFE7D6C9FFE6D6C9FFDFD3C9FFE5DFDAFFEFEEF2FF
+ EBEEF6FFE9EFF4FFE5EEF1FFE7ECEDFFE7EBECFFEBEDEDFFECF0F1FFEFF4F7FF
+ EFF6F9FFE9F2F5FFE3EBEBFFE8EFECFFF3F4EBFFF2EAD9FFD6C7ADFFB49F80FF
+ B69770FFC29869FFB48551FFBB8D53FFB8894BFFBB8A46FFC6944CFFBC873EFF
+ B98336FFBB8336FFBA8034FFB87C30FFB77C2DFFB67B2CFFB17627FFB77A2AFF
+ C48A38FFCA913CFFBD852CFFB67E25FFB57E23FFB68022FFBC8425FFBC8524FF
+ B47D1AFFBE8724FFBC8621FFBC841FFFBB831EFFBD821FFFBD821FFFBD821FFF
+ BA811EFFBE8424FFBD8421FFBB821FFFBB801CFFB97E1AFFB97F18FFBC8219FF
+ BE841BFFBD8117FFBE8316FFC08315FFC18514FFC48515FFC48614FFC48614FF
+ C58614FFBF7D0CFFC07F0CFFBF800EFFC0810FFFC18210FFC08210FFBF810FFF
+ BD8110FFC18514FFBF8312FFBA7F11FFB77C0EFFB57D0EFFB67E0FFFB98112FF
+ B98213FFBC8316FFBD8518FFC0871AFFBF8619FFBD8417FFBB8215FFBD8117FF
+ BF8319FFBA7E14FFB97B11FFBA7B13FFBE7F17FFBE7F17FFBB7C14FFBB7C14FF
+ C08014FFC1800DFFC27F0AFFC0800AFFC07F0CFFC07F0CFFC0810EFFC18210FF
+ C18311FFC58614FFC28311FFC28310FFBB7210FFBC740FFFBC780DFFBB7B0BFF
+ BA7C0AFFB77A0CFFB6770FFFB37412FFBE7F23FFB77A24FFAB7321FF9D691DFF
+ 8B5C18FF7C5013FF6E4713FF583D23FF5F566AFF555B8AFF445693FF365096FF
+ 3A5AA5FF3D64AFFF3D64AEFF3B66AFFF3B68B2FF3867B1FF3B68B1FF3C69B2FF
+ 416AB3FF4169B4FF3D65B7FF3C64B6FF4168B7FF3C62B0FF395DABFF3C5CA8FF
+ 3D5CA7FF3C589FFF334C92FF304485FF354482FF323E74FF2E3567FF2A305BFF
+ 2D2E54FF2E304FFF2F304CFF343246FF3A323CFF40312EFF4D321EFF59371AFF
+ 603D1CFF623F1EFF5B3A20FF56351BFF583619FF5B3719FF5B391BFF5B391BFF
+ 5A381BFF5A381AFF5F3917FF603A17FF5C3B1AFF533415FF503112FF533415FF
+ 563718FF573819FF58391AFF5B3C1DFF563718FF5B3C1DFF5E3F20FF5B3C1DFF
+ 593A1BFF593A1BFF5B3C1DFF5E3D1CFF5F3917FF5C3613FF5B3713FF5C3715FF
+ 583214FF552F11FF573412FF5E3B19FF603A1AFF643E1CFF5F330EFF5D3714FF
+ 513B1FFF3D3536FF3D457AFF425BABFF3D60B6FF355FB8FF3561BAFF3966BDFF
+ 3C69C0FF3C6BBDFF3966B7FF3761AEFF3860ABFF3259A3FF3457A0FF3C5FA8FF
+ 4265AEFF4265AFFF3D61ADFF3B61AFFF355AAEFF365DB2FF3960B5FF395EB2FF
+ 3557AAFF31509FFF324B95FF32488FFF36498DFF2A3C7BFF3D4E87FF374674FF
+ 46516DFFBBC1CCFFFDFAF6FFFFFDF3FFF4F6F0FFF3F9F4FFF7FAF8FFF4F8F9FF
+ EFF2FAFFE8EEF9FFE6EFFCFFE6F2FEFFEAF7FFFFE6F1F5FFECF2F1FFF3F9F4FF
+ F5FCF5FFF0F7F2FFEAF5F3FFECF6F6FFF1F4FCFFF3F5FDFFF3F4FEFFF3F2FBFF
+ F2F1FAFFF1F1F7FFF0F2FAFFF2F5FAFFF1F3FBFFF3F6FBFFF3F6FBFFF2F5F9FF
+ F0F3F8FFF0F3F7FFF5F5FBFFF7F8FCFFEEF0F0FFF7F5F4FFFAF5F4FFFCF4F4FF
+ FEF5F8FFF9EFF5FFF4ECF3FFFAF2F9FFF1EAEFFFF6EEEFFFFCF3EFFFFEF6EFFF
+ FCF5F2FFF6F1F2FFECEEF6FFE9EBF5FFEEF4FBFFEFF4F7FFEFF1F2FFEFEFEFFF
+ F1EFEEFFF0F1EFFFF1F3F3FFF1F5F6FFF2F7F8FFE9EEEFFFE9EEECFFE9EAE1FF
+ E7E0D1FFD0C4ACFFB3A184FFB89F7FFFB49576FFAB8A69FFC19E7CFFC6A27CFF
+ CBA67AFFD3AD7DFFC29968FFBC915EFFB98C59FFC49863FFBF905CFFAF814BFF
+ AC7E48FFAF814BFFB78852FFC4945AFFC69452FFB9853FFFB6823BFFB9863DFF
+ B38234FFB27F2FFFB98433FFBA8633FFBE8833FFBB862FFFB9832CFFB8822BFF
+ BB822CFFBC832DFFBB822CFFB9802AFFBC842BFFBD8429FFBB8227FFBC8124FF
+ BC8223FFBE8222FFBD801EFFBC801CFFBF811BFFC0831BFFC4861AFFC7881AFF
+ C8871AFFC88818FFC68616FFC58515FFBE7E12FFBF7E15FFC18017FFC28118FF
+ C28118FFBF8117FFBF8117FFBC8114FFBC8114FFBB8013FFBA7F12FFB97E11FF
+ BA7F12FFBB8013FFBD8215FFBE8316FFC28517FFC48719FFC8891BFFC7881AFF
+ C48418FFC18115FFBE8016FFBF8117FFC08119FFBD7E16FFBE7E18FFC3831DFF
+ C2821CFFBE7E18FFBC7B18FFBE7F17FFBF8012FFC08010FFBF7F0FFFBF7E11FF
+ BF7E11FFBF8012FFC08113FFBF8214FFC28315FFBF8012FFBF8012FFBC7010FF
+ BA720DFFBA7409FFB97706FFB77805FFB67905FFB67707FFB6750CFFBA7812FF
+ B57412FFB27317FFB4781FFFB27A29FFAC772EFFA06C2AFF805932FF655759FF
+ 5D607FFF4C5A8EFF375090FF3959A0FF4164AEFF3F64AEFF3D64AEFF3E68B3FF
+ 3B68B2FF3B68B2FF406BB4FF456DB5FF446BB5FF3F66B5FF3B61B3FF3C62B0FF
+ 3B5FABFF3A5CA8FF3D5DA8FF3E5EA7FF3B579EFF30498FFF283E80FF344683FF
+ 323F77FF2C3666FF2A305BFF2D2E54FF2F2E4EFF312F4CFF333145FF38303AFF
+ 40312EFF4F3420FF5A381BFF5F3C1BFF603D1CFF5A391FFF57361CFF553316FF
+ 593517FF583618FF573518FF55341AFF583619FF623B1BFF663F1FFF603E21FF
+ 59381EFF56351BFF56351BFF59381EFF59381EFF59381EFF58371DFF57361CFF
+ 502F15FF4B2A10FF4F2E14FF55341AFF56351BFF523117FF512F12FF5B3515FF
+ 5B3513FF5C3917FF5F3E1DFF5C3A1DFF543215FF51300FFF553413FF583317FF
+ 643E20FF633916FF603C18FF503B1CFF39322FFF3A4474FF455DA9FF4568BEFF
+ 3660B9FF305CB5FF335FB8FF3967BFFF3E6CC0FF3C69BAFF3862AFFF3960AAFF
+ 3359A1FF36589EFF4062A8FF496BB1FF4568B1FF4063ADFF3B5FABFF385FAEFF
+ 365EB0FF345FB0FF355DAFFF345AA8FF33539FFF324B93FF2F468AFF304386FF
+ 314382FF2B3C75FF3F4C7AFF3F4764FF9A9CA6FFFFF8F1FFF8EFE1FFF8F4E9FF
+ F5F4EAFFF6F3EBFFF6F3EEFFF4F4F4FFF2F5FAFFEFF6FFFFEEF7FFFFEFF9FFFF
+ EBF2F5FFEBF1ECFFF4F7EEFFF5F9EEFFF0F5ECFFEDF4EFFFF1F7F6FFF1F2F6FF
+ F4F2F8FFF4F1FAFFF5F3F9FFF6F4FAFFF2F2F8FFEEF1F6FFEFF1F9FFF0F2FAFF
+ F1F4FCFFF1F7FEFFF1F7FEFFEEF4FBFFEAF2F9FFEBF3FAFFEDF5FCFFF4FAFFFF
+ EBEFF4FFF4F3F7FFF9F5FAFFF3EEF7FFF8F4FFFFFCFAFFFFEEEEFAFFF0EFF8FF
+ FCFBFFFFFBF9F8FFF7F4F0FFFAF6F5FFF5F2F4FFEBECF6FFF0F2FDFFF6F9FFFF
+ F5F8FCFFF4F6F7FFF3F4F2FFF3F1F0FFF5F2EEFFF4F2F1FFF3F3F3FFF5F9FAFF
+ F0F4F5FFF0F5F4FFEFF0ECFFF5F3E9FFEEE5D7FFD9CBB8FFDECDB8FFE2D0BFFF
+ DCCAB9FFF7E3D1FFF8E3CEFFF0DAC1FFEBD4BAFFCEB496FFC3A788FFC4A788FF
+ DBBC9BFFD3B493FFB79877FFB29372FFBD9E7DFFC6A786FFD0AE8AFFBC9569FF
+ B08756FFB18857FFB68E59FFAC834CFFA57D42FFB38849FFBC9251FFB38845FF
+ B28541FFAE823BFFB0823BFFB3823CFFB5823CFFB4813BFFB28038FFB98539FF
+ B78336FFB88235FFB98434FFBD8635FFBC8633FFB8822BFFB77F26FFBD8429FF
+ BE8528FFC28828FFC48926FFC38624FFC08420FFBD811DFFBB7F1BFFBB7E1EFF
+ BC7E20FFBD7F21FFBE8121FFBE8121FFBD8020FFBC7F1DFFBB7F1BFFB67A16FF
+ B77C15FFB87D16FFBC7F17FFBD8018FFBE8119FFBF821AFFBF8319FFBF7F13FF
+ C18214FFC58418FFC38317FFC28115FFBF7F13FFBF7E15FFC07F16FFC6851CFF
+ C3811AFFC3841CFFC78721FFC68620FFBF7F19FFBA7C16FFBC7F17FFBE8218FF
+ BF8115FFBE8014FFBD7F13FFBD7F13FFBD7F13FFBC8114FFBC8114FFBD8215FF
+ B87D10FFBA7C10FFBD7412FFBC740EFFB87508FFB67704FFB37902FFB57B04FF
+ B77B09FFBA7B0DFFBB7A11FFB97710FFB7750FFFB47311FFB47416FFB6771FFF
+ B97A2AFFA8773FFF7F6B5AFF646472FF556288FF3D548CFF375497FF3F5FAAFF
+ 3D5DA8FF4062AEFF3960AEFF365FAEFF426CB7FF4D74BEFF476BB1FF4164ADFF
+ 4468B4FF456BB9FF4064B0FF3F64AEFF4063ADFF4060ABFF3D5DA6FF37559CFF
+ 314B91FF2F4587FF344683FF334078FF2E3868FF2B315AFF2D2F52FF2E2E4CFF
+ 2F2E48FF332F42FF3F3640FF402F2CFF4F3420FF5D3B1EFF5E3818FF5C3616FF
+ 58371DFF56351BFF563417FF583619FF5B391CFF5E3C1FFF5C3A22FF5B3A20FF
+ 5F391BFF5D3719FF603D23FF5B3921FF57351DFF56341CFF58361EFF59371FFF
+ 59371FFF57351DFF59371FFF58361EFF57351DFF56341CFF56341CFF57351DFF
+ 58361EFF5B381EFF5F391BFF5B3817FF543516FF523417FF56341CFF58371DFF
+ 58391AFF573819FF59371FFF623F25FF603919FF573714FF533F20FF433D38FF
+ 3D446FFF4E64ABFF4466BAFF3C66BFFF325EB9FF3965BEFF3E6CC4FF3F6CC3FF
+ 416DC0FF345EABFF3057A1FF30549AFF35569BFF4160A5FF4766ABFF4262A9FF
+ 3C5CA7FF385BA5FF375CA6FF355CA6FF3860ABFF3D65B0FF4166B0FF3E5EA5FF
+ 395396FF354B8DFF324485FF31407EFF2C3872FF374170FF414562FF64626EFF
+ B8ACA8FFE5D6C6FFEADBC8FFE3D5BFFFE4D3BEFFECDDCAFFF4E7D9FFF7ECE4FF
+ F5F0EFFFF7F4F6FFF8F5F7FFF0ECEBFFEEE8E1FFF4EEE3FFFBF3E6FFFBF5E8FF
+ F7F5EBFFFAF6F1FFF6EFECFFFEF5F2FFFFF9F9FFFFF8F8FFFBF6F5FFF8F4F3FF
+ F8F6F6FFF9F8FAFFEDEEF2FFEDF0F4FFEFF4F7FFEEF4F9FFEAF2F9FFE6F0F7FF
+ E8F2F9FFEBF5FCFFE7EDF4FFECEFF4FFF3F2F6FFF7F3F8FFF6F5F9FFF4F4FAFF
+ EFF1FBFFEAEFF8FFF1F7FCFFF3F8F9FFF9FAF8FFFBFAF6FFFCF8F7FFF6F3F5FF
+ EEEDF6FFE9EAF4FFEDF0F8FFF3F6FAFFF7F9FAFFF5F6F4FFF3F1F0FFF2EFEBFF
+ F2F0EFFFF5F5F5FFF2F3F7FFF0F3F8FFF0F3F8FFF2F2F8FFF7F6F8FFFBF6F7FF
+ FAF3F0FFF4EEE9FFF1EDE8FFF8F5F0FFFDFAF2FFFBF5EEFFF9F2E9FFF8EFE5FF
+ F3EADDFFEDE2D4FFE8DBCBFFEDDFCDFFF7E9D7FFEEE0CEFFEADECCFFF1E5D3FF
+ ECDFCFFFF0E0CFFFF1DCC7FFE3CBB3FFD4BCA4FFE0C8ACFFD8BF9FFFBFA783FF
+ CBB189FFDDC198FFCEB184FFC7A97AFFC5A574FFBC9B6AFFAD8A58FFAD8A58FF
+ BB9664FFC09965FFD7AE77FFC79D62FFB68A4FFFB28649FFBB8F50FFBD9151FF
+ B18441FFA2732FFFA97931FFAF8036FFB9883CFFBC8B3DFFB58232FFAC7A28FF
+ B07E2CFFBD8837FFBB8433FFBA8231FFBB8332FFB8802EFFB27826FFB47B26FF
+ C18630FFC78D34FFC5892FFFC18629FFBF8224FFBE8121FFBF8222FFBF8220FF
+ BF8220FFC0821CFFBF8018FFC08216FFC38219FFC18317FFC28216FFBE8014FF
+ BD7F13FFBC7E12FFB87A0EFFC7891DFFC08216FFB97B0FFFC38519FFC08216FF
+ BA7F12FFC78E21FFBE861BFFC1891EFFC38B20FFC38B20FFC0881DFFBD851AFF
+ BA8217FFB98116FFBB8318FFB77F14FFB77F14FFBB730DFFBA760DFFB97909FF
+ B67B07FFB57D06FFB37D08FFB57C09FFB77B0AFFB57509FFB67509FFB87508FF
+ BB770CFFBC7A11FFBD7A17FFBC791CFFAA742DFF7E6543FF615D5CFF515D79FF
+ 3F5688FF3E5A9BFF4464ADFF3F5CA7FF3C5CA8FF375CACFF315AA9FF3D64B2FF
+ 4A6FB9FF4A6CB2FF4868AFFF4668B4FF4266B2FF4166B0FF3F64AEFF3E61ABFF
+ 3D5DA8FF3A5AA3FF345299FF2F498FFF2C4486FF304380FF2E3D75FF2A3666FF
+ 2A325AFF2E3053FF31314FFF32314BFF363245FF3D353CFF3D2C29FF4B301CFF
+ 59371AFF593313FF583212FF543319FF503118FF57341AFF583619FF5A381BFF
+ 5A391FFF583821FF59371FFF5D361AFF5C3618FF5D3A20FF58361EFF56341CFF
+ 56341CFF57351DFF58361EFF57351DFF55331BFF58361EFF57351DFF56341CFF
+ 55331BFF54321AFF55331BFF56341CFF59361CFF5B3719FF573517FF503215FF
+ 4F3217FF50311AFF52331CFF523419FF503318FF4F3019FF54341DFF542F13FF
+ 4F3011FF4D391AFF3C352CFF373C5DFF495B9AFF4362B1FF3C64BDFF345EB7FF
+ 3864BDFF3D6BC3FF3E6BC2FF3E6ABDFF345BA9FF30569EFF35569BFF385598FF
+ 3B589BFF3F5C9FFF3F5DA4FF3858A1FF31529BFF33559BFF37599FFF3C5FA8FF
+ 476AB3FF5272B9FF5471B6FF4B63A5FF405495FF38488AFF3C4B8AFF37427EFF
+ 384173FF3E4063FF4A455AFF71656BFF968479FFAA9276FFAF926BFFB8986FFF
+ C3A378FFCAAC83FFCAAE8BFFC6AF95FFC8B39EFFD3BFADFFCFBBA9FFD2BBA5FF
+ D7C2A7FFDEC7ADFFE4CFB4FFEDDBC4FFF8E7D2FFFBE8D3FFFBEAD5FFFEEDD8FF
+ FBECD9FFF6E8D6FFF1E4D4FFF0E7D9FFF4ECDFFFFAF3EAFFFAF7EFFFFCF9F4FF
+ F7F8F4FFF5F6F4FFF1F4F2FFECF1EFFFE9EEEDFFF7F7F7FFF8F4F3FFF5F0EDFF
+ F5EEEBFFF3EEEBFFF3F1F1FFF0F3F7FFF0F7FAFFF0F8F8FFF0F8F7FFF4F8F3FF
+ F4F5F1FFF5F4F0FFF4F2F2FFF3F1F7FFF2F1FAFFEAEEF3FFE9EEF1FFEBEFF0FF
+ EFF1F1FFF2F3F1FFF3F1F0FFF3F1F0FFF5F3F3FFEDECF0FFF0EEF4FFF3F0F9FF
+ F3F2FCFFF0EFF9FFEDECF6FFF0EDF6FFF2F2F8FFECF0F1FFEEF4F3FFEFF4F3FF
+ EEF3F2FFF3F5F5FFF8F9F7FFF6F4F3FFF0EDE9FFF4F0EBFFF6F3EBFFFFFCF7FF
+ F9F6F1FFFAF7F2FFFFFFF9FFF9F8F4FFFCF9F5FFFFF9F6FFFFF8F4FFFCF4EDFF
+ FFFFF7FFFFFBEEFFF5EBDAFFFAEFDBFFFFF2DCFFFEF1D7FFF4E6CAFFEFDFC2FF
+ E8D6B9FFDECAABFFE0CBACFFE7D2B3FFE7D0B0FFD8BC99FFCFB28DFFC8A982FF
+ C9AA83FFCFAF86FFCEAE83FFC7A679FFC19F71FFBB9767FFB79462FFB99460FF
+ BF9B65FFC49F67FFC19B61FFBD975DFFBE965BFFB6894CFFB8894CFFC39456FF
+ BC8D4FFFA77737FFAE7C3AFFBE8A47FFB8843DFFBE8B42FFC28E42FFC48F3FFF
+ C18A39FFBC8534FFBB8331FFBE8634FFC48B35FFC58C31FFBF8728FFBA8021FF
+ B97F20FFBC8222FFBF8623FFBE8522FFBE831FFFCB902CFFC98F28FFBE841DFF
+ B77D14FFBB8117FFBF851BFFBD8319FFBB8318FFB37C14FFB57F1AFFBA821DFF
+ BA831BFFB9821AFFB88118FFBA831AFFBC851CFFBE851CFFB88118FFB88118FF
+ B8740BFFB8770BFFB77B0AFFB77E0BFFB57E0BFFB37D0BFFB37B0CFFB3780BFF
+ B87A0EFFB9780BFFB97706FFBC7906FFBC7B08FFBD7B0AFFB9780CFFA6701BFF
+ 836738FF635B4EFF515C70FF405785FF405B9BFF4865AFFF435DA9FF3D5BA8FF
+ 3C5EB1FF3157A9FF365CAAFF4065AFFF4665AAFF4867ACFF4767B2FF4163AFFF
+ 4669B2FF4164ADFF3B5CA5FF35569FFF32529BFF304E95FF2E4B90FF30488AFF
+ 314481FF2F3E76FF2C3868FF2B335BFF2F3153FF30314DFF333049FF373142FF
+ 41363EFF402D28FF4D2F1CFF593418FF573111FF573111FF55341AFF52331AFF
+ 59361CFF59361CFF57361CFF57351DFF55351EFF54351CFF5A3519FF5A3618FF
+ 59371AFF56351BFF55341AFF56351BFF57361CFF57361CFF55341AFF533218FF
+ 55341AFF55341AFF543319FF543319FF543319FF543319FF55341AFF563619FF
+ 5B391CFF563619FF503416FF4E3319FF4F321DFF50331EFF51331AFF4D3218FF
+ 482D18FF4A2D18FF4A2810FF4C2E13FF4B361AFF3A2E22FF34354AFF445384FF
+ 3E5BA5FF3C63B8FF3560B7FF3965BEFF3E6CC4FF3C69C0FF3D68B9FF3259A7FF
+ 305298FF345496FF365292FF344F8FFF375194FF3A549AFF324F99FF294690FF
+ 324F94FF395399FF3D5A9FFF4966ABFF5B75BBFF617BBEFF5269ADFF3E5195FF
+ 334388FF364689FF344080FF303873FF3F4373FF4E4C70FF544E67FF766463FF
+ 95734FFFA4783BFFAE7D37FFB78539FFB78636FFB38236FFAE813EFFAD8348FF
+ B48A55FFB58C5BFFBE9360FFC09562FFBC915EFFB88F5EFFBF9669FFC8A476FF
+ CFAE7DFFCBAC79FFC9AB7AFFC8AC7DFFC1A779FFBAA177FFBBA47EFFC1AB88FF
+ EDD9BAFFF4E3C8FFFBECD2FFFDF0DAFFFFF7E4FFFFFFEEFFFFFFEDFFFFF8E7FF
+ F2E7D9FFF9ECDCFFFFF3E1FFFFF7E5FFFFF4E6FFF7F1E6FFF2EFEAFFEFF3EEFF
+ E9F0EDFFEDF4EFFFF1F8F1FFF5F7F1FFF5F5EFFFF6F2F1FFF6F3F5FFF7F5FBFF
+ EBF0F3FFE3EAEDFFE2EAEAFFE8F0EFFFECF2F1FFECF1F0FFEFEFEFFFF1EFEFFF
+ F7F2F4FFF3EDF2FFF5EDF7FFFBF3FEFFF5F1FDFFEAE7F6FFE4E3F3FFE6E8F3FF
+ EFF4F7FFECF2F1FFE9EEEDFFEAEEEFFFF4F6F7FFFCFBFDFFFAF9FBFFF6F4F4FF
+ F3F1F1FFF1EFEEFFF7F7F7FFF1F1F1FFF0F2F3FFF4F8F9FFEAEDF1FFE9EDF2FF
+ E8EAF4FFEEF3FCFFEBF1F8FFF1F6F9FFF0F5F6FFECF1EFFFF3F7F2FFEEF1E8FF
+ F9FAF0FFF7F7EBFFF8F6EBFFF8F5E7FFF2EFE1FFF5EFE2FFF6F0E3FFF4EDDEFF
+ F5E8DAFFF2E3D3FFF2E2D2FFF5E5D4FFF6E4D3FFEFDECBFFEEDBC6FFF0DEC7FF
+ E8D4BBFFDDC9B0FFD6C1A6FFD7C2A6FFD9C4A8FFD4BFA0FFC8B394FFC1AA8AFF
+ CBAF8DFFC9AB88FFD4B490FFC3A37FFFA2815AFFAD8B60FFC3A074FFB89466FF
+ AE8957FFB9925EFFC09962FFBC945AFFB0864BFFA57C3EFFA67A3DFFAA7E3EFF
+ C49551FFBE9049FFB7873FFFB18139FFB18036FFB38335FFB58434FFB88634FF
+ C28F39FFB9872FFFB78329FFB88328FFBA8426FFC18B2CFFC08B2AFFB88120FF
+ BB8324FFC1892AFFC78D2EFFC68C2CFFC38727FFBF8421FFC18623FFC48926FF
+ C18422FFBD821FFFBD821FFFB67509FFB6760AFFB57908FFB27A09FFB27B0CFF
+ AF7A0CFFB1790EFFB1770DFFBA7C10FFB8790BFFB67704FFB67802FFB97B05FF
+ BB7D0BFFB87A0EFFA8731CFF8A6B36FF685E4CFF596073FF455988FF3C5698FF
+ 4360ABFF4660ACFF4763B0FF4163B6FF365CAEFF355CAAFF375DA5FF3A599EFF
+ 405DA2FF4361AEFF3F61ADFF4669B2FF3E62A8FF3657A0FF2E4F98FF2C4C95FF
+ 2E4C93FF314D94FF344E90FF344987FF34437BFF2F3B6BFF2E345DFF2F3153FF
+ 2E2F4BFF2F2D43FF312C3BFF43393FFF422F2AFF4E301DFF5B361AFF5B3414FF
+ 5C3618FF5B3921FF593A21FF5A361EFF59361CFF56341CFF52321BFF51321DFF
+ 52321BFF59341AFF593517FF583618FF563718FF57371AFF58391AFF58381BFF
+ 573819FF563619FF543516FF523215FF533415FF533316FF543516FF563619FF
+ 573819FF58381BFF59391CFF5F3D20FF5A3A1DFF53391BFF52371DFF533522FF
+ 533522FF51361CFF4D341AFF4B331DFF492E19FF4A2B16FF51321BFF51381EFF
+ 3C2D1DFF36313AFF40496EFF3A5598FF3F64B8FF3B64B9FF3E69C0FF426FC6FF
+ 3E6CC0FF3C67B8FF335AA5FF315297FF334F90FF324B89FF334A88FF334B8DFF
+ 30498FFF28438DFF233D89FF2E4590FF334991FF364C94FF3E579DFF556EB4FF
+ 657EC4FF5972B8FF4359A0FF3D5099FF374990FF37468BFF303A7AFF424B84FF
+ 616697FF5A5E87FF675D6EFF8F7156FFA3773CFFAD7C30FFB78228FFBC841FFF
+ BC821BFFBC8425FFBF8932FFAE7929FFB17C33FFBA853CFFBD883FFFB8823BFF
+ AF7B35FFB17D3BFFB88743FFB0833AFFAA8035FFA87F36FFAB833BFFA87F3AFF
+ 9D7736FF9E793BFFA38146FFA98751FFB39461FFBB9D6EFFBCA175FFCAAE85FF
+ D8BE96FFD9BF9AFFCEB692FFC7AE8CFFCEB595FFDABF9DFFDAC1A1FFCFBA9EFF
+ C7B9A3FFCDC6B7FFD4D5CBFFDFE6DFFFE7EEE9FFF2F9F2FFF8FCF6FFF9F9F3FF
+ F5F3F2FFF5F2F4FFF4F3F7FFF2F5F9FFE6EDF0FFE4EDF0FFE8F2F2FFE8F0F0FF
+ E9EFEEFFEFF0EEFFF1EDECFFFEF5F2FFEDE0DEFFE5D6D4FFF3E3E4FFFFF1F5FF
+ FDF3F9FFF7EFF9FFF6F2F7FFF3F4F0FFF1F4EBFFF0EFEBFFEFEDECFFF5F0F1FF
+ F8F3F4FFF8F3F4FFF5F0F1FFF3EEEFFFEFEAEBFFF3F1F1FFEFEFEFFFF0F2F3FF
+ F4F7FCFFEAECF4FFEAECF6FFE9EDF8FFEFF5FFFFE8EFF8FFEAF2F9FFEBF4F8FF
+ ECF4F4FFF1F9F8FFEAF1EEFFEDF4F1FFF0F7F2FFF4FAF5FFF1F7F2FFEDF3EEFF
+ F0F5F3FFF5F8F6FFF3F6F4FFF4F2F1FFF2EFEBFFF4EFEEFFF9F4F1FFFAF3F0FF
+ F4EEE9FFF5EFEAFFFEF6EFFFFFF7F0FFFBF3ECFFFBF2E9FFFAF1E8FFF9F0E6FF
+ F5ECE2FFF1E7DDFFF0E4D8FFF6E9DBFFFAEBDBFFFFF6E6FFF9E9D8FFDCCBB8FF
+ D6C3AEFFD7C2ACFFC6B097FFD5BFA3FFE0C8AAFFE7CEAEFFE1C6A4FFCEB28FFF
+ BB9E79FFAF926DFFAC8E65FFBD9C6FFFC5A375FFCAA978FFC8A573FFBE9967FF
+ B48E58FFAE884EFFAE864BFFA87F40FFA97F3EFFB08641FFBC9049FFBF9248FF
+ B98B3EFFB28437FFB28234FFAE7A2DFFB78232FFC08839FFC08938FFBC8432FF
+ B9812FFFBE8530FFC48B36FFBF8631FFBB822DFFB9812FFFB5740BFFB57509FF
+ B27408FFAE7508FFAD750AFFAE750CFFB0760FFFB2780FFFB1750BFFB07507FF
+ B37705FFB47B08FFB47D0EFFB27B12FFAE7716FF9F701FFF7B5A28FF625442FF
+ 5A6175FF485E8EFF375295FF3C59A4FF455FABFF4A69B4FF3E63B3FF3962B1FF
+ 3A64B1FF3860A8FF34559AFF36559AFF3B5BA7FF395AA9FF3C5FA8FF3A5DA1FF
+ 36589EFF33559BFF32529BFF325097FF314D94FF314B8DFF344987FF32437BFF
+ 303C6CFF2F355EFF303254FF312F4CFF302D43FF332C3BFF42363CFF402C27FF
+ 4F301BFF5A3519FF5C3515FF5E381AFF5E3C24FF5C3D24FF5B371FFF59361CFF
+ 55331BFF51311AFF50311CFF50311AFF563319FF593517FF583618FF583918FF
+ 593A1BFF5A3B1AFF5A3B1CFF593A19FF58391AFF573817FF513213FF523312FF
+ 543516FF563716FF593A1BFF5B3C1BFF5C3D1EFF5C3D1EFF5E3C1FFF5A3A1DFF
+ 55391BFF53381DFF553621FF553522FF50341CFF4C3319FF4E381FFF4A321CFF
+ 4D2F1CFF563722FF53381EFF412C17FF392D29FF373C51FF354F8BFF4166B6FF
+ 426ABDFF426EC2FF4674C8FF426EC1FF3E67B6FF365BA5FF38589AFF304B8BFF
+ 304582FF374A87FF344889FF273D84FF1F3882FF213886FF293C8DFF2A3E8CFF
+ 293D8AFF2F4691FF4861ABFF607BC5FF5F7CC6FF516EB9FF4660ACFF374E99FF
+ 3C4F98FF304387FF3C4D8CFF6577B4FF6072ADFF525980FF726466FF856849FF
+ 946F35FFA47928FFB1801AFFB88112FFBC8316FFC1871EFFB97F1FFFB57C21FF
+ B67C23FFBA8027FFB77F26FFB47E27FFB7812EFFC08934FFB88224FFB88120FF
+ B98324FFBB8729FFBA852AFFB28028FFB1802AFFB48432FFAA7A2CFFAF8036FF
+ AE8138FFA67C37FFAC813EFFB68C49FFB38B4AFFA78042FFAC854EFFB8905BFF
+ C69E69FFC7A270FFB9996EFFB09777FFB9AB95FFC9C3B6FFE3E6DDFFE8EEE9FF
+ F2F8F3FFF7FBF6FFF7F8F4FFF3F4F2FFF2F1F3FFF1F2F6FFF6F8F9FFEDF0F4FF
+ EDF4F7FFECF5F8FFE4EDF0FFEAF0EFFFF4F3EFFFF4EDE4FFE6D6C9FFD0B9A9FF
+ C5AA96FFD5BAA6FFEFD5C4FFFDE6D6FFFEEDE0FFFFF4E4FFFAF0DEFFFAF3E0FF
+ FCF3E5FFFCF2E8FFF9EEE6FFF7EBE5FFF9EDE9FFFCF0ECFFF9EEEAFFF3E8E4FF
+ F7EEEAFFF5EEEBFFF6F2F1FFF9F6F8FFF2EEF4FFF4F0F6FFF3F0F2FFF6F4F4FF
+ EFF0EEFFF7F8F6FFFAFBF7FFF4F5F1FFF5F7F1FFEBEFE9FFF2F6F0FFF3FAF3FF
+ EEF4EFFFE6ECE7FFE6EBE9FFEAF0EFFFEDF2F1FFEBEFF0FFEEF2F3FFEBEDEEFF
+ EBECF0FFEFF1F2FFF2F4F5FFF2F4F5FFF5F7F8FFFDFCFEFFF1F0F2FFF5F4F6FF
+ FBF8FAFFFBF8FAFFFAF7F9FFFAF7F9FFFDFAFCFFFFFDFDFFEFEFEFFFF6F6F6FF
+ FDFBFBFFFFFDFCFFFFFDFCFFFBF6F3FFF4EEE9FFF2EAE3FFF9F0E7FFFEF4EAFF
+ FFF8EBFFFFF5E9FFFAEDDFFFEFDFD2FFE4D4C7FFDFCFBFFFC9B8A5FFD9C6B1FF
+ EBD6C0FFEEDAC1FFE5CFB6FFD2BCA0FFC3AB8DFFBDA484FFB59976FFB89B76FF
+ BA9C73FFC9A97EFFD3B285FFBB996BFFA78557FFB79260FFB58B56FFBB8E55FF
+ BB8C54FFB3854BFFAC7D40FFAA7B3EFFB38244FFBD8A4CFFB58244FFB07F41FF
+ AE7F42FFB6750CFFB57509FFB17307FFAF7407FFAD7309FFAE750CFFB1760FFF
+ B27710FFB0760CFFB37A0DFFB67E11FFB17D13FFA87514FF996911FF8C5A0EFF
+ 7C5013FF5D3C0FFF4D3D2DFF545972FF4B6094FF385298FF3654A1FF405DA8FF
+ 4565B0FF375EADFF3762B1FF3F6BB8FF3E68AFFF385A9CFF36579CFF3758A7FF
+ 3154A4FF32559EFF36599DFF3A5CA2FF3D5FA5FF3D5DA6FF38569DFF2F4B92FF
+ 2A4486FF2E4381FF2E3F77FF2E3A6AFF2F355EFF323456FF34334DFF343246FF
+ 383140FF3D3137FF3C2823FF4B2C17FF5A3416FF5A3215FF5B3517FF5C3820FF
+ 583821FF59351DFF58351BFF55331BFF52321BFF50301DFF51321DFF57331BFF
+ 583619FF593719FF583918FF5A3B1CFF5A3B1AFF593A1BFF593A19FF593A1BFF
+ 5B3C1BFF523314FF543514FF563718FF583918FF5A3B1CFF5B3C1BFF5C3D1EFF
+ 5C3D1EFF573517FF543516FF513415FF503416FF53321EFF52311EFF4E2F18FF
+ 482F15FF4B361BFF49331AFF4F311EFF553522FF54361BFF452C12FF3B2B1AFF
+ 302F38FF31497DFF4269B4FF466FBEFF4771C4FF4B77CAFF4370C1FF3F66B4FF
+ 385BA4FF3E5B9EFF324987FF2D407DFF344683FF344687FF273C80FF223985FF
+ 2B4292FF2D4097FF2C3F96FF273C8EFF273E8CFF33509BFF4766B1FF4D6EBDFF
+ 496DBBFF4868B4FF35549FFF38549BFF314A90FF324C8FFF5F7ABDFF7190D5FF
+ 6479B6FF5D5E84FF6A5D65FF786147FF8F7033FFA77B20FFB27E13FFB57D0EFF
+ B97C0EFFBF811BFFB97C1AFFB87B19FFBC811EFFBD821FFFB77E1BFFB37C1BFF
+ B77E1BFFBA7D15FFBE8016FFBF8319FFC1841CFFBF841DFFBE831FFFBB821FFF
+ BA8020FFBB8324FFBC8628FFB88328FFB07C22FFAF7D25FFB6842CFFB5842EFF
+ B07E2CFFA47226FFAF7B34FFBF8B45FFC49454FFBA905BFFB29269FFBBA58CFF
+ C9BEB0FFF1EEE9FFEFF2F0FFF0F5F3FFF0F5F3FFEFF1F1FFEEF0F0FFEFF2F6FF
+ F4F5F9FFF6F3F5FFF2F1F5FFF3F6FBFFEEF4F9FFE6EDF0FFEEF3F2FFF4F2EAFF
+ EAE0CFFFBBA48AFFB49574FFB38C65FFBC9569FFC7A276FFCAA97CFFC9AC80FF
+ C9B086FFD7C093FFDAC49AFFE0C9A3FFE3CAAAFFDFC4A9FFD8BFA5FFDCC1ACFF
+ E3C8B3FFEED6BEFFE5D0BAFFECDAC3FFEEDDC8FFF4E4D3FFF9ECDEFFF8E9E0FF
+ FFF2E9FFFFF6EAFFFFF1E4FFF4E7D7FFFFF2E2FFFFF9E8FFFCF4E3FFFFFAE9FF
+ FCF7E8FFEFECDEFFF9F7ECFFFAF9EFFFF5F6EDFFF8FAF4FFFCFDF9FFF6F7F5FF
+ EEF0F0FFF4F6F6FFF0F4F5FFEEF0F1FFE9EDEEFFEAEEEFFFECF0F1FFEEF2F3FF
+ EFF2F6FFEBEEF2FFEDF0F5FFEFEFF5FFECECF2FFEBEBF1FFECECF2FFECECF2FF
+ E7EAEFFFECF2F7FFEDF3F8FFE2E8EDFFE1E7ECFFEEF2F7FFEFF2F6FFEAEDF1FF
+ F5F7F8FFF7F6F8FFF7F5F5FFF5F3F3FFF9F4F5FFFEF9F8FFFFFBFAFFFFFAF9FF
+ FDF8F5FFF2ECE7FFF4EEE9FFF8F2EBFFFCF4EDFFFEF5ECFFF9EFE5FFEFE5DBFF
+ EADED2FFF7E7DAFFF4E4D3FFEAD9C6FFF5E4CFFFFFF4DFFFF2DDC7FFDDC8B2FF
+ EFD7BFFFEDD3B5FFEBCEAFFFE1C2A1FFD3B390FFC7A783FFC7A67FFFD2AE88FF
+ DCB892FFCAA57FFFC5A17BFFC3A17DFFB8770BFFB7770BFFB5770BFFB3780AFF
+ B3780BFFB2790CFFB5790FFFB37910FFB57B12FFB47D15FFB17A17FFA47016FF
+ 8E5D11FF78490CFF68390DFF5C320FFF502C0EFF412F24FF4D516EFF495D96FF
+ 36519BFF3655A4FF3F5CA7FF4161ACFF355FACFF3361AEFF3867B1FF3965ACFF
+ 3A5D9FFF3D5FA5FF3C5FAFFF3459A9FF3659A2FF395CA0FF3C5EA4FF3E60A6FF
+ 3E5EA7FF38569DFF2F4B92FF2A4486FF2D4280FF2D3E76FF2C3A6AFF2F375FFF
+ 333655FF36354FFF363448FF393241FF3E3238FF3D2924FF4D2E19FF5C3618FF
+ 5B3316FF5A3416FF5A361EFF54341DFF58341CFF57331BFF55331CFF53331CFF
+ 52321FFF53341FFF59351DFF59371AFF583619FF573819FF59391CFF58391AFF
+ 563619FF573819FF59391CFF5C3D1EFF553518FF563718FF57371AFF58391AFF
+ 58381BFF573819FF563619FF583618FF563214FF533113FF513310FF503314FF
+ 54311DFF54301EFF4F3017FF492E13FF473216FF493419FF513320FF573623FF
+ 57341AFF4E3112FF452E14FF2E2928FF2C4371FF4267B1FF4970BEFF4772C3FF
+ 4C78CBFF446FC0FF3D63B1FF385AA0FF365293FF2B407DFF243671FF2C3C77FF
+ 324284FF33468AFF3A4E9BFF445AACFF4156B2FF3D53B2FF374FA7FF2E4A9EFF
+ 2C4D9DFF3056A4FF3860B2FF3C67B6FF4B72C0FF4067B1FF3E60A6FF36579CFF
+ 2B4C91FF3F63A9FF618BD6FF6A8EDCFF566AB8FF575B95FF5E5766FF766348FF
+ 977533FFAC8023FFB8801BFFBC7F17FFBB7D19FFBB7C1AFFBF801EFFC68824FF
+ C68921FFBF851CFFBB8219FFBD831AFFB77A12FFBF8117FFC08218FFBB7D13FF
+ B97C14FFBE8119FFBC8219FFB67B14FFB57B14FFB77D16FFB67F17FFB47D15FF
+ B47E19FFB9831EFFBE8823FFC08926FFC08528FFBB7C24FFB87928FFBD8338FF
+ C18E50FFCAA174FFDDC2A7FFF0E0D3FFFAF5F2FFF3F5F6FFEFF4F7FFEDF2F5FF
+ ECF1F2FFEBF0F3FFEAF0F5FFEEF1F6FFF8F1F6FFF9EFF5FFF7F5FBFFF0F3F8FF
+ E8EDF0FFF1F4F2FFECE6DBFFCFC0A6FFA78A63FFB38B56FFBA8A4AFFBB8740FF
+ B38236FFAA7C2FFFA47A2FFFA27C2EFFAD8637FFAE8739FFB28940FFB78C49FF
+ B6894CFFB2864BFFB48650FFB98D57FFBB925BFFB38E56FFBD9963FFBF9F6AFF
+ C8A877FFD2B386FFD5B78EFFE4C4A0FFF3D2B1FFEBCAA9FFD9BA9BFFDDC0A1FF
+ E3C7A8FFE2C8AAFFE7D2B3FFE2CFB4FFDAC9AFFFF4E6D0FFFFF6E4FFFDF3E2FF
+ FAF1E4FFF9F0E6FFF7F0E7FFFAF4EDFFF4F2EAFFF8F9F0FFFAF8F0FFF0F1E8FF
+ EDEDE7FFF2F2ECFFF4F3EFFFF2F0EFFFF5F3F2FFF7F5F5FFF4F4F4FFF1F1F1FF
+ F2F1F3FFF6F5F7FFF6F5F9FFEFF0F4FFE3E8E9FFE9EEEFFFEBF0F1FFEDF2F3FF
+ F3F7F8FFF6FAFBFFF2F6F7FFF2F4F5FFF9FBFCFFF7F6F8FFF3F2F4FFF1F0F2FF
+ F5F2F4FFF7F4F6FFF7F4F6FFF5F4F6FFFBFFFFFFF4FAF9FFEFF5F4FFF0F5F4FF
+ F4F9F8FFFAFCFCFFFAFCFCFFFBFBFBFFF8F9F7FFF7F5F4FFF3F0ECFFF8F5F1FF
+ FFFFFBFFFCF7F4FFF4EFECFFFCF7F4FFFFFAF5FFFFF7F0FFFAF1E8FFF2E8DEFF
+ EFE3D7FFF3E6D8FFFBEEE0FFFFF5E5FFF3E4D4FFEEE1D1FFEEE1D3FFB8760DFF
+ B8770EFFB87A10FFB87B13FFB67B14FFB47915FFB17717FFAE7518FFAB7419FF
+ A5731BFF9B6A1AFF875B14FF72470EFF5F370DFF583014FF57301AFF563319FF
+ 473126FF4B4E6AFF4A5C91FF385298FF3A57A2FF435EA8FF4262ABFF3C64AFFF
+ 3460ADFF305FA9FF305CA3FF345B9FFF4164ADFF456ABCFF3F64B6FF3F64AEFF
+ 3E62A8FF3A5EA4FF395AA3FF3657A0FF33539AFF2F4E93FF2F4A8DFF304583FF
+ 30417AFF2E3C6DFF303762FF333557FF34324FFF333046FF362F3EFF45373BFF
+ 433028FF51341FFF5F3A1EFF5D351CFF5C341BFF58361EFF54341DFF54321AFF
+ 55331BFF55331BFF54341DFF54351EFF54351EFF55361DFF58361EFF543319FF
+ 563619FF57371AFF553518FF533316FF543417FF58381BFF5B3B1EFF57371AFF
+ 57371AFF58381BFF57371AFF563619FF533316FF513114FF4F2F12FF543417FF
+ 533316FF513316FF53351AFF573420FF573420FF54321AFF4F3217FF493115FF
+ 4E351BFF573823FF5B3922FF5C381AFF593817FF503416FF362822FF343F65FF
+ 4C67A7FF5070BBFF4A70C2FF4D76CBFF446CBEFF3F62ACFF3D599AFF31457FFF
+ 273871FF1F2D68FF223072FF2C3E85FF3C509DFF4C66B3FF5773C7FF4C6BC6FF
+ 4A6BC8FF4B69C0FF4464B7FF3A5DADFF375EADFF3B68B9FF4574C5FF416FBDFF
+ 4873BCFF446BAFFF4268A9FF2C5195FF21478FFF436CBBFF5C83D8FF6B8AE7FF
+ 576CBDFF485583FF53525BFF736144FF8D6E31FFA27322FFAD7516FFB97B17FF
+ BB7912FFBC7A13FFBE7D14FFB97B0FFFB3780BFFB77C0FFFBE8316FFBC7E12FF
+ C4861CFFC1821AFFB4770FFFB4770FFFBC8218FFBF8417FFB67B0EFFC0841AFF
+ BE841AFFBE861BFFBC861BFFB88419FFB98318FFBE861BFFC68A20FFCB8922FF
+ BD7918FFB4761CFFBE8639FFCF9F65FFE0BA90FFF4D9C4FFFFF3EAFFFAF4F5FF
+ F4F4FAFFF1F4FCFFF0F6FDFFF0F4F9FFEBF1F6FFE7EDF2FFE7EAEFFFFBF4F9FF
+ F9F1F8FFF7F4FDFFEEF0F8FFE9ECF0FFF6F3EEFFE7D9C6FFBCA27DFFB28D55FF
+ C08F49FFC48E3BFFBF862BFFB87F22FFB78122FFBC882AFFC28E30FFB88524FF
+ B3801FFFB47E20FFB88329FFBA8230FFB77F2EFFB77F30FFB98434FFB17E2EFF
+ A77628FFAC7C2EFFA87A2DFFA67930FFA87C35FFA87D3AFFB68A4BFFBA8D50FF
+ B68A4FFFA97C43FFAC8148FFB18851FFAE8750FFAE8A54FFA27F4DFFAF8F5EFF
+ D5B689FFE3C89CFFD0B68EFFBEA480FFBCA381FFD0B797FFE5D0B1FFD6C6A9FF
+ E5D7BBFFEEE0C4FFE6DABEFFE4D7BDFFEEE2CAFFF5E8D2FFF1E6D2FFF9EDDBFF
+ FDF3E2FFFDF4E6FFF9F0E2FFF8F0E3FFFDF4EAFFFFF6ECFFFBF4EBFFF2EFE7FF
+ F6F4ECFFFDFBF3FFF8F6EEFFF1EDE8FFFAF6F1FFFFFDF8FFF6F2EDFFEFEAE7FF
+ F1ECE9FFF3EFEEFFF5F0F1FFF3F0F2FFF3F0F2FFF1F0F4FFF0F1F5FFE3E8EBFF
+ E2EBEEFFE7F0F3FFEAF3F6FFECF3F6FFEAF1F4FFE7EEF1FFE5EBF0FFEAF0F5FF
+ EDF3F8FFF5F9FEFFF5F9FEFFEFF2FAFFF1F4FCFFF6F9FFFFF5F8FFFFEFF3F8FF
+ F1F4F8FFF5F7F8FFF6F8F8FFF7F7F7FFF6F7F5FFF8F6F5FFF9F8F4FFFCFAF9FF
+ F9F7F6FFF7F8F6FFB7740DFFB7750FFFB87715FFB47618FFB0741BFFA76C1CFF
+ 9D661BFF96611EFF875618FF7D5017FF6E4713FF613F11FF573811FF513415FF
+ 4E3319FF503219FF59371AFF4A3022FF3E3D4DFF4F5D87FF445A94FF334D8FFF
+ 465DA1FF4B65ABFF4565B0FF3E65B0FF3966B0FF3865AEFF3A64ABFF3960ABFF
+ 375CB0FF365BAFFF365CAAFF365BA5FF3C61ABFF3F62ABFF3457A0FF305298FF
+ 2F4E93FF2B4689FF304485FF334280FF353F75FF333968FF313258FF2F2F4DFF
+ 332F48FF3C3242FF463839FF422F22FF4F351DFF5D3E25FF5A3422FF512B19FF
+ 512E1AFF52331AFF593B20FF583A1FFF59381EFF58381BFF553917FF533816FF
+ 50341CFF4F321DFF53361BFF543619FF543619FF55371AFF56381BFF57391CFF
+ 583A1DFF583A1DFF523417FF543619FF56381BFF57391CFF56381BFF543619FF
+ 513316FF4E3116FF4B3218FF4C311CFF4E3122FF523324FF563424FF593622FF
+ 58371DFF58381BFF52331AFF57381FFF5B3921FF59371AFF593817FF5C3A1CFF
+ 55351EFF432A26FF3B3148FF474D7CFF566BAFFF5171C4FF456DC6FF486DC1FF
+ 4360A3FF2F437AFF2F3667FF23275AFF202667FF2A3783FF374CA1FF4B67BEFF
+ 5D7FD3FF6088DBFF5485D5FF6091DFFF618BD8FF5C83CEFF5F86D1FF5077C5FF
+ 3A67B8FF3E6DBEFF4272C0FF4B7BC3FF527CBFFF5076B7FF4465AAFF2F4F98FF
+ 3351A2FF4D6DC0FF658ADAFF678CD6FF5171B2FF435A88FF545B6FFF635A4DFF
+ 80612EFFAB7C2BFFAD730CFFC58312FFC38110FFBC7A09FFBD7E10FFBB7B0FFF
+ B97A0CFFC08111FFBD7F0DFFB87C0BFFB5750FFFB47715FFB9811CFFBC851CFF
+ B88210FFB47C0BFFBD7F13FFBE8119FFBA831BFFB4841BFFB7891EFFBD8D23FF
+ C48B22FFC5841BFFCF8A1BFFC18017FFB57F28FFAF823EFFAF8E60FFCEB89CFF
+ F7E7DBFFFFFAF7FFF5EFF4FFF3F0F9FFF2F3FDFFF3F5FFFFF3F4FEFFF0F2FAFF
+ EBEEF2FFEAEBEFFFEAE8EEFFEEEDF7FFE9EDF8FFEDF3FAFFFAFAFAFFEEE5D8FF
+ D4BB99FFC9A36DFFBF8E44FFC28C35FFBF8728FFBD8421FFBD8421FFBE8320FF
+ BF7F20FFBD7D1EFFBA7F1CFFB9801DFFBC811EFFBB8121FFBC8223FFBE8425FF
+ BF8427FFBF8427FFBA8124FFBA8124FFB98023FFB57F21FFB27B20FFB37C21FF
+ B58026FFBA852BFFB37E23FFB17E22FFB07D21FFB38024FFB78329FFB8862CFF
+ B7852DFFB4832DFFAD7B28FFAC7D29FFAD7D2BFFAD7E2DFFAE7E30FFB07F33FF
+ B18034FFAD8037FFAF8544FFB79052FFBF9A5CFFC19C60FFC2A065FFCBA973FF
+ D6B681FFDBBB8AFFD3B788FFD4B98DFFE1C89EFFF2DCB3FFF3DEB8FFE7D1ADFF
+ E1CDAAFFE6D2B3FFF2DFCAFFF7E6D3FFFFF2E0FFFFF7E5FFFEE9D4FFE9D4BFFF
+ E7D1BFFFF0DCCBFFFFECDDFFFBEBDEFFFBEFE5FFFFF6EFFFFEF6F6FFF7F2F3FF
+ F4F0F5FFF4F2F8FFF1F1F7FFEDF0F5FFECEFF3FFEDF0F4FFEFF4F5FFF0F5F6FF
+ EEF3F4FFEBF0F3FFE8EDF0FFEEF3F6FFF3F9FEFFEEF4F9FFE5EBF2FFEAEFF8FF
+ EFF4FDFFEAEDF5FFECF0F1FFEBEDEDFFECEEEEFFF1F3F3FFF2F4F4FFEFF1F1FF
+ EEF0F0FFF1F4F2FFF0F2F2FFEEF0F0FFF4F6F6FFB97924FFB27420FFA76A1AFF
+ 995F13FF8E5510FF834D0EFF7A470FFF734313FF673C11FF603913FF5A3715FF
+ 523516FF4F3419FF4E351BFF4C361DFF50371DFF573518FF492F1EFF3D3742FF
+ 4F5879FF4B5F8FFF3A4F8CFF42589AFF4760A6FF4663AEFF3F63AFFF3A64AFFF
+ 3A67B1FF3E69B2FF4067B5FF3F64B8FF3E63B7FF4368B8FF3D64AFFF4065AFFF
+ 4167AFFF3B5EA7FF395BA1FF355499FF2D488BFF304386FF334281FF353D78FF
+ 333869FF30325BFF302F4FFF342F4AFF3C3242FF463937FF433021FF4B341AFF
+ 573A1FFF56301EFF532C1DFF57321CFF58371DFF57391EFF56381BFF58371DFF
+ 573819FF543A12FF533914FF4E341CFF4E331FFF54361DFF56381BFF57391CFF
+ 583A1DFF57391CFF56381BFF543619FF533518FF503215FF503215FF513316FF
+ 513316FF513316FF503215FF4F3114FF4E3116FF4A3117FF49311BFF4B3121FF
+ 4F3223FF523421FF54351EFF553518FF553518FF502F15FF523018FF53351AFF
+ 533719FF523614FF553413FF5A3618FF573626FF55444FFF4D496DFF4B5692FF
+ 475EAAFF3D5BACFF3C59A4FF3C4E89FF313B6AFF272951FF1F1F4DFF252A67FF
+ 404C94FF5B6FBDFF738AD8FF7E98DEFF7698D4FF779ED5FF6A92C6FF5375ABFF
+ 506DA6FF6884C1FF6C8ACBFF5C7EC4FF557CC6FF4F79C4FF527DC6FF557EC3FF
+ 567DC1FF4E71B5FF36569FFF2E4A97FF3958A3FF567DC1FF6590D3FF5D88D1FF
+ 4D71B7FF4B659BFF505B77FF655B51FF856A3EFF9C722BFFAB761FFFAA7116FF
+ AC7213FFB57B1CFFBB801DFFBB8118FFBD8417FFBE8518FFC1871DFFC1801EFF
+ B67617FFB37713FFB87F16FFBC8516FFBD8516FFBF8117FFBD7F19FFB57D18FF
+ AC7C13FFAE8015FFB5851CFFBF8420FFC2801AFFC68316FFC5851FFFAA7826FF
+ 997539FFB39B77FFE3D3C2FFFAF0E9FFF4EEEFFFF1EAF1FFEFECF5FFEFEDF9FF
+ EFEFFBFFF1F2FCFFF2F5FAFFF4F6F7FFF4F6F7FFEBEDF5FFECEEF8FFE9F0F9FF
+ F2F6FBFFF8F5F0FFE1D3BDFFC5A378FFB98B4BFFC28A38FFC58929FFC0861FFF
+ BD841BFFBC821BFFBE801CFFC27D1CFFC17C1BFFBF811DFFBD821BFFBD821BFF
+ BD821BFFBE831CFFBE831CFFBE831CFFBF841DFFBF841DFFBE831CFFBD821BFF
+ BB8019FFBA7F18FFBA7F18FFBD821BFFBF841DFFB98116FFB88013FFB88015FF
+ BA8217FFBE861BFFC0881DFFC0871EFFBE851CFFBC831AFFBC821BFFBC821BFF
+ BD831CFFBD821EFFBD821EFFBD821EFFBB821FFFB17A1FFFB47E27FFB57F28FF
+ B07A25FFAD7B28FFB07F2FFFB28234FFAE8137FFAA7F36FFA67D38FFAA8241FF
+ AF8B4BFFAF8C4DFFA9874BFFAB894DFFB08E58FFB69568FFBC9971FFC8A57DFF
+ D2AF84FFCBA87DFFC09D71FFC59F75FFD1AD85FFD9B891FFDCBE9BFFE8CEB0FF
+ F9E2C8FFFFEED9FFFEF0DEFFFCEFE1FFFCF0E6FFFDF1EBFFFCF1EDFFFDF3ECFF
+ FFF5EEFFFFF9F0FFFFF8EFFFF9F4EBFFF6F0E9FFF5F1ECFFF1EEE9FFF9F6F2FF
+ FCFAF9FFF4F2F2FFEFECEEFFF0ECF1FFEEEBEDFFF7F4F0FFF4F1ECFFF5F2EDFF
+ F7F6F2FFF4F4F4FFEEF0F1FFECF0F1FFF1F5F6FFE9ECF0FFE6EAEBFFEEF0F1FF
+ 935E25FF8E5920FF824E19FF774511FF6D3D0DFF67370DFF62350FFF5F3413FF
+ 5C3515FF593418FF57341AFF52331AFF4E3319FF4C321AFF4B3119FF4D3218FF
+ 563417FF492D1CFF373035FF484F6AFF51618FFF3F558FFF3C5294FF415AA2FF
+ 4463AEFF3E62AEFF3B64ADFF3B66AFFF416AB3FF426AB5FF4066B8FF3E63B5FF
+ 4C72C0FF4367B3FF4065AFFF4066AEFF3D60A9FF3C5EA4FF38579CFF2E498CFF
+ 314487FF334281FF333E78FF34396AFF31335CFF313050FF34314BFF3B3443FF
+ 453939FF423225FF4A3418FF523516FF542E16FF593019FF60381FFF5C3A1DFF
+ 563619FF543619FF56351BFF563718FF563914FF543815FF53341DFF50321FFF
+ 57381FFF583A1FFF5A3C21FF5A3C21FF583A1FFF55371CFF513318FF4F3116FF
+ 503217FF503217FF4F3116FF4F3116FF4F3116FF503217FF513318FF523417FF
+ 4E3013FF4F3315FF4B3617FF4C3819FF4D371BFF50351AFF513316FF513213FF
+ 4E3112FF4B3113FF483219FF49341EFF4A3216FF50330CFF6A450DFF725227FF
+ 655354FF433E5DFF363A6BFF36417BFF303D7BFF29356FFF2A2F5CFF25264CFF
+ 18183CFF2C2B55FF4E5489FF6E76B1FF717BB1FF69729EFF626885FF595F72FF
+ 3B404FFF323845FF1D1E32FF151630FF2D2F51FF454B76FF576498FF6A7DBAFF
+ 5E7BBEFF5A7DC6FF5B82CCFF6089D2FF5E86CEFF456CB1FF2B4E90FF204382FF
+ 395E98FF547BB9FF638DD4FF5781CCFF466BB5FF3E5B98FF435279FF4E4E5EFF
+ 6D5D57FF80644CFF936D4AFF9D7241FF9B6C2EFF9F6E22FFA6771CFFA77717FF
+ A27115FFB27B20FFC38024FFC27A1CFFBE7715FFC17F18FFC2841EFFBD831CFF
+ BD801EFFBE811FFFB97F18FFB37C13FFB37F14FFB9841CFFBD8023FFBC7B1FFF
+ BC7A1BFFC0842BFFAA7C35FFA88553FFD3BDA1FFFFEFE2FFFEF5F1FFF1EAEDFF
+ F7F1F6FFF2EFF8FFEFEEF7FFECEEF6FFECF0F5FFEEF1F5FFF2F4F4FFF3F5F5FF
+ F0F3F8FFEBEDF5FFEBEFF4FFF9FAF8FFF9F1E4FFD7C2A6FFB28F5DFFA77932FF
+ BD842EFFC08522FFBC821BFFBB8118FFBA7F18FFBC7E18FFC07C17FFBF7B16FF
+ BF821AFFBD831AFFBC8219FFBC8219FFBB8118FFBB8118FFBB8118FFBA8017FF
+ BE841BFFBC8219FFBB8118FFBA8017FFBB8118FFBB8118FFBA8017FFB97F16FF
+ B87E15FFB77D13FFB77D14FFB97F15FFBC8218FFBD8319FFBD8319FFBC8218FF
+ BE841AFFBE841BFFBD831AFFBC8219FFBB8118FFBA8017FFB97F15FFB97F15FF
+ BE8218FFBC7F17FFB97C14FFB47912FFB67A16FFB87D19FFB47B18FFAD7615FF
+ B27C1DFFAE791EFFAD791FFFAB7921FFA97921FFA87923FFAC7D27FFB1812FFF
+ A6752BFFA7752DFFAE7D33FFB68438FFB38135FFAC7A2EFFB37F33FFBD8A41FF
+ A87830FFA87B37FFB08645FFBE965BFFC8A56DFFCDAD78FFD5B584FFD9BC90FF
+ EECFB0FFEACCB1FFE8CAAFFFEACCB1FFEFD2B7FFF4D9BEFFF8E0C4FFFAE3C9FF
+ E5CFB6FFDBC6B1FFEAD6C4FFFFF5E4FFFFFDF0FFFFF4E9FFFEEDE4FFF9E9DDFF
+ FAEADDFFFBEEE0FFFEF4EAFFFFF8F4FFFBF7F6FFF1F0F4FFEDEFF7FFF0F3FBFF
+ ECEEF8FFEAECF4FFF6F5F9FF623710FF613712FF623813FF613916FF613817FF
+ 5E3619FF5C3519FF5A351BFF5E3A22FF5B3921FF5A3820FF56371EFF53361BFF
+ 4F3419FF4E3318FF4F3217FF55341AFF4B2F1EFF372B2BFF434458FF56628AFF
+ 485C93FF374E92FF3D58A2FF4464B0FF3E62AEFF3A63ACFF3B64ADFF3D66AFFF
+ 3C64AFFF395EAEFF3659A9FF476BB9FF3E62AEFF3B60AAFF395FA7FF3457A0FF
+ 34569CFF345398FF2F498FFF2F4488FF314281FF333E78FF333A6CFF33355EFF
+ 343353FF35324CFF393344FF41383BFF423428FF49371AFF4F3412FF522D11FF
+ 5C3418FF613A1EFF59371AFF523419FF513419FF523419FF553617FF553813FF
+ 563815FF56341DFF543320FF583920FF593B20FF593B20FF583A1FFF57391EFF
+ 54361BFF523419FF503217FF523419FF523419FF53351AFF53351AFF54361BFF
+ 54361BFF55371CFF57361CFF543215FF513415FF4E3815FF4C3916FF4C3819FF
+ 4E361AFF513318FF513114FF523614FF4D3517FF47351EFF45331CFF4A3214FF
+ 5E3E0DFF835C0EFF916E2EFF6A5851FF413C57FF31335CFF2C3365FF20285DFF
+ 171E4FFF1C1D43FF1D1B39FF292640FF3A3653FF515274FF57577BFF3E3E5CFF
+ 28263AFF292227FF2F231FFF26150CFF36231BFF33221FFF241519FF1C0E1AFF
+ 180F24FF232040FF353A67FF5C6BA3FF5E76B8FF6182CBFF638AD4FF648ED5FF
+ 547EBFFF3B619BFF24487EFF28477AFF3B5992FF5073B5FF547BC5FF466FBEFF
+ 3F65B3FF3F5FA1FF3D5289FF474F77FF5B5872FF7A6C78FF8A746FFF896E59FF
+ 977C57FFA68B58FFA08447FF9A7737FFA4762FFFB97B27FFC88022FFCA801AFF
+ CB841CFFC28622FFB7801FFFB47B1EFFB77E21FFBC811DFFBA8118FFBD841BFF
+ BD8520FFBA7F22FFB37620FFB97D29FFB78239FFBC9158FFD6B790FFFAE5D0FF
+ FFF6EEFFF9F1F1FFF5F0F2FFF6F2F7FFF3F1F7FFEFEFF5FFEBEFF4FFEBF0F3FF
+ ECF2F1FFEFF4F2FFF0F5F3FFF1F4F8FFEBECF0FFEFEFEFFFFCF7EEFFF4E6CFFF
+ CFB68EFFB08B4FFFAC7B2FFFB98227FFBD821FFFBC811AFFBA8017FFB97E17FF
+ BB7E16FFC07E15FFBF7E15FFBD8215FFBA8114FFBA8114FFBA8114FFB98013FF
+ B98013FFB98013FFB98013FFBC8316FFBA8114FFB98013FFBA8114FFBC8316FF
+ BB8215FFB87F12FFB47B0EFFB87E15FFB87E15FFBA7D15FFB97F16FFBC8016FF
+ BB8117FFBD8117FFBB8215FFBE8316FFBC8316FFBD8215FFBA8114FFBB8013FF
+ B87F12FFB97E10FFBB7F0EFFC18210FFC2800FFFBE7F0DFFBF800EFFC18111FF
+ C38414FFC28313FFBE8113FFBD7F13FFBC8114FFBA8016FFB97F16FFB87E15FF
+ B98017FFBB8118FFB97F18FFBE8222FFBA8021FFBD8121FFC08522FFBE811FFF
+ B97D19FFBA7E1AFFC08321FFB97F1FFFB1781BFFAB761CFFAB7822FFAC7C2AFF
+ AD7F31FFB2883BFFB98F4AFFAF8147FFAD7E48FFAB7B47FFAC7E48FFB18550FF
+ B98F5AFFC19964FFC49F6BFFAE8A5AFF9F7D4FFFB08E63FFD7B78EFFECCCA8FF
+ EDCDAAFFE4C5A4FFDDBE9DFFCFB091FFD7BB9DFFE7CDB5FFF5DFCDFFF6E6D9FF
+ F1E5DFFFEFE8E5FFF4EFEEFFF2ECEDFFF7F0EDFFFFF9F3FF4D2C12FF4E3015FF
+ 523419FF56381DFF583920FF583920FF56371EFF54351CFF57381FFF56381DFF
+ 55371AFF543718FF553917FF573D19FF593F1BFF5C401EFF563619FF4E331FFF
+ 3C2A23FF3E3A45FF565D7EFF4F6295FF385295FF3957A4FF4565B1FF4064B0FF
+ 3D65ADFF3D67AEFF3D66AFFF3B63AEFF395DABFF3559A7FF3B5FABFF375BA7FF
+ 395EA8FF355BA3FF2C4F98FF2C4E94FF335198FF354F95FF2F4488FF314281FF
+ 333E78FF343B6DFF363861FF343557FF34324FFF373346FF3E383DFF3F352BFF
+ 48371CFF503715FF533113FF593517FF5A371DFF4F3017FF4E321AFF4C321AFF
+ 4F341AFF533518FF573714FF5A3715FF5B341EFF593420FF5A3820FF57391EFF
+ 55371CFF54361BFF53351AFF53351AFF54361BFF55371CFF4F3116FF513318FF
+ 54361BFF56381DFF56381DFF55371CFF54361BFF55341AFF57331BFF56341CFF
+ 52381AFF4E381CFF4E361EFF51341FFF55321EFF55331BFF513517FF50381AFF
+ 4B351CFF463014FF54360DFF724D0FFF9C6E0FFFA17A2CFF6A574AFF49445FFF
+ 3D416AFF303B6DFF1C2B63FF162455FF1F284AFF28293EFF433D48FF3C3336FF
+ 392E31FF382A2EFF2A1F22FF281B1DFF2E211FFF35241BFF371E0EFF432716FF
+ 42281AFF39221AFF301B19FF281419FF23121FFF201731FF3E4068FF505D91FF
+ 627BBBFF6485CAFF5C83C7FF5980BEFF4D72A6FF3E5C8BFF374B7BFF344578FF
+ 3F558FFF506CADFF5273BCFF5279C4FF557CC7FF5073BCFF4966A9FF485D9AFF
+ 536094FF5E648FFF717592FFA1A5B8FFC0C5CEFFBBBAB6FFB6A892FFAA895CFF
+ AF7A31FFC17F20FFC88314FFC78514FFBE8621FFB48123FFAB7A24FFB07D27FF
+ B77E21FFBA7F1CFFBC821BFFBF8722FFB78423FFAE7C24FFBC8A42FFB78A51FF
+ D0AD82FFF6DEC2FFFFF2E5FFFBF2EFFFF6F0F1FFF3EEF0FFEDE9EEFFECEBEFFF
+ EAEDF1FFECF1F4FFECF4F4FFEEF7F4FFF1F8F3FFF3F9F4FFF0F3F7FFF2F1F3FF
+ F9F3ECFFF6EBD7FFDCC6A2FFBA9B64FFAE843DFFB6832DFFB88021FFBC811DFF
+ BD821BFFBD7F19FFBC7F17FFBE8016FFC18115FFC18214FFB97F0EFFB97F0EFF
+ BA800FFFBA800FFFBA800FFFBB8110FFBB8110FFBB8110FFBC8211FFBA800FFF
+ BA800FFFBB8110FFBD8312FFBD8312FFB97F0EFFB57A0CFFBB7F15FFBC7F17FF
+ BE8016FFBC8016FFBE8016FFBC8016FFBF8115FFBD8214FFBC7F11FFBA7F11FF
+ BC800FFFBA800FFFBC800EFFBA810EFFBC800EFFBC800EFFBA7B08FFBE7D0AFF
+ BF7E0BFFC07F0CFFBE7D0AFFBA7B08FFBB7C09FFBE7F0CFFBC7D0AFFBD7E0BFF
+ BE7F0CFFBD7E0BFFBE7F0CFFBF800DFFC1800DFFBC7D0BFFBF8010FFBE7F11FF
+ C08010FFC38412FFC58312FFC2800FFFC1800DFFC38110FFC78717FFC08315FF
+ BC8016FFBB8219FFB57F1AFFAD7817FFA87616FFAA771BFFAC731DFFB17620FF
+ B47824FFB57C26FFB77E29FFB7802BFFB7812CFFB3812EFFC0903EFFAD7E2DFF
+ A87A2DFFAF8238FFAF833CFFAE813DFFAB803DFFA5793AFFAD7E41FFB58650FF
+ C29766FFCEA97DFFD0B08CFFCEB293FFD0B99FFFD6C2A9FFDDC8B2FFE9D2B8FF
+ F8DCBDFF4F331BFF50351BFF50341CFF51361CFF52361EFF55371EFF56381FFF
+ 573A1FFF533719FF533617FF523614FF523613FF533813FF563C14FF593F17FF
+ 5B401BFF543619FF523421FF432D21FF3B3032FF4E526BFF556492FF3D5799FF
+ 3858A4FF4160AFFF4163AFFF4268B0FF426BB0FF416BB2FF3F68B1FF4064B0FF
+ 4062AEFF375BA7FF365AA6FF3B60AAFF385EA6FF2D5197FF2D4F95FF37559CFF
+ 3C569CFF304589FF304283FF323D79FF333B70FF363965FF35375AFF363451FF
+ 353347FF3D3841FF3C322BFF43351EFF4F3A1AFF523617FF553518FF52341BFF
+ 4A2D18FF4B321EFF4B331DFF50351BFF523617FF583815FF5B3816FF5D341DFF
+ 5B3320FF58361EFF54361BFF523419FF503217FF503217FF523419FF55371CFF
+ 57391EFF4C2E13FF4E3015FF513318FF53351AFF54361BFF523419FF4F3116FF
+ 4D2F14FF57361CFF57361CFF53361BFF53351CFF53341FFF543520FF583521FF
+ 583521FF503219FF4F3419FF4B3015FF4E300DFF633F0FFF855B1AFFA4721AFF
+ 9B712EFF5B4E46FF454966FF434C77FF384677FF223267FF1D2D5CFF2A3355FF
+ 343549FF413A3DFF372A22FF322114FF382413FF3B2414FF3F2818FF422C1AFF
+ 422A14FF533316FF512D0FFF432208FF3C1E05FF3E1F08FF3E200DFF3A1F11FF
+ 311C1AFF1E1421FF373957FF5B6B9AFF6882BEFF5E80C2FF5379BAFF496EACFF
+ 3F5D96FF475589FF354072FF324179FF405592FF4865A8FF4F75BDFF5983CEFF
+ 5A88D5FF5F8BD8FF537BC6FF4C6DB6FF415EA3FF4B62A0FF8094CDFFAFC4F7FF
+ C1CDF1FFB5B0B9FF9D856FFF9E7235FFB57B22FFBD7D11FFBC7D0DFFB6801BFF
+ AF7E22FFB88935FFB98734FFBA8229FFB97E21FFBC8222FFC38C29FFC0912FFF
+ B78B37FFBE9459FFC19E73FFE0C3A8FFF6E4D3FFF6EAE4FFF6F0F1FFF8F3F5FF
+ EDE7ECFFEEEBEDFFEEEDEFFFEDF0F4FFECF3F6FFEDF5F5FFEBF6F3FFEBF6EEFF
+ ECF3EEFFEFF4F3FFFBF8F4FFFEF3E5FFE5D1B2FFBA9C6BFFA37E3AFFAA7B29FF
+ B68224FFB9801DFFBD821BFFBF811BFFC0801AFFBF8018FFC08014FFC18212FF
+ C08412FFB87F0CFFB87F0CFFB9800DFFB9800DFFBA810EFFBA810EFFBA810EFF
+ BB820FFFB9800DFFB9800DFFBA810EFFBB820FFFBC8310FFBC8310FFBA810EFF
+ B87E0DFFBD7F13FFBE8016FFBF8117FFBE8014FFBD7F13FFBC7E12FFBD8012FF
+ BE8211FFBA7E0DFFBA7E0CFFBB7F0DFFBB800CFFBC810DFFBC810DFFBD820EFF
+ BF820EFFBA7C0AFFBC7D0BFFBF800EFFC28310FFBF800EFFBC7D0AFFBE7F0CFF
+ C2840EFFC98913FFC5850FFFC3830DFFC4840EFFC8860FFFC98710FFCB8912FF
+ CC8914FFBD7E0BFFBD7E0BFFBF800DFFC3830DFFC2820CFFC17F08FFC07E07FF
+ BF7D06FFC2820CFFBF800DFFC28412FFC78A1CFFC38A1DFFBD851AFFB68119FF
+ BA831BFFBC7C16FFC07E18FFC3811BFFC3831DFFC3831DFFC1831DFFC2841EFF
+ C1861FFFC28723FFBB821FFFB98221FFB47E20FFAC751AFFAE761DFFB68029FF
+ B9802BFFB67A28FFB4792AFFB57C31FFB3803AFFAE8040FFA97F44FFAB854FFF
+ B28D59FFA8834FFFB18B55FFBE9459FF533719FF533718FF513517FF513516FF
+ 513517FF543718FF56391AFF583B1CFF573B19FF593A19FF583A17FF573A15FF
+ 563914FF553811FF553811FF523613FF523419FF533621FF492F1EFF36261FFF
+ 444353FF56628AFF445D9DFF3858A3FF3B5BA7FF3F62ACFF4569AFFF456CB1FF
+ 416BB2FF4067B1FF4467B1FF4568B2FF3A5EAAFF375BA7FF3A5FA9FF395FA7FF
+ 31559BFF33559BFF3959A0FF3B589DFF2E4589FF304283FF323D79FF333B70FF
+ 353A67FF35385EFF353553FF353349FF3F3845FF372D2DFF3F311FFF4B3A1FFF
+ 4E391AFF4D3519FF4C341EFF49311DFF4C3422FF4D351FFF51361BFF553917FF
+ 5B3915FF5D3816FF5D341DFF5B3320FF56341CFF53341BFF513219FF503118FF
+ 503118FF513219FF52331AFF53341BFF4F3017FF503118FF513219FF52331AFF
+ 513219FF503118FF4F3017FF4E3013FF543917FF533715FF533316FF543117FF
+ 543117FF57331BFF56371EFF593922FF53321FFF4F2D16FF512D0FFF633B11FF
+ 7D521FFF93642CFF9C6931FF86613FFF51515DFF3C4D74FF425280FF3C4B7CFF
+ 293768FF242F5BFF2C3255FF34354AFF352E35FF2D211BFF2F1D0CFF382107FF
+ 3F2203FF492905FF58350DFF5E390DFF61370AFF623809FF633B0BFF623C0CFF
+ 623A0AFF5E3606FF563204FF4B2B07FF371F0BFF302626FF444860FF5E719EFF
+ 5E7CBDFF4F75C3FF3E67BCFF385CAAFF495896FF434A81FF35417BFF314382FF
+ 304A8CFF36599DFF456FB6FF4E7EC6FF5D91D8FF5A8DD6FF598AD4FF4A74BFFF
+ 385BA5FF4562ACFF6880C8FF8794CCFF88859FFF7E6B63FF916D3DFFAD7D2FFF
+ B37919FFB1770EFFB27B1AFFAE791EFFC39139FFC28D36FFBF852CFFBA7E24FF
+ BC8026FFC18B2DFFBF9231FFB48E3CFFB89766FFCEB398FFEBD7C6FFF4E7DFFF
+ F0EAEBFFF3EFF4FFF5F1F6FFF0ECF1FFF3F0F2FFF2F1F3FFEFF2F6FFEDF4F7FF
+ EBF3F3FFE7F2F0FFE6F0EAFFE6EEE7FFF2F5F3FFF8F3EAFFF1E1CAFFCDB188FF
+ A98446FFAA7C2EFFB68325FFB47E19FFB97F18FFBC811AFFC1811BFFC2801AFF
+ BF7E15FFBE7F11FFBF820EFFBE840DFFBA810DFFBA810DFFBA810DFFBA810DFF
+ B9800CFFB9800CFFB9800CFFB87F0BFFB77E0AFFB9800CFFBA810DFFBB820EFF
+ BB820EFFBB820EFFBC830FFFBD8411FFBB7E10FFBF8012FFC08113FFBF8012FF
+ BC7D0FFFBA7B0BFFBB7C0CFFBD7F0DFFBC7E0CFFBC7F0BFFBD800CFFBD800CFF
+ BE810DFFBE810BFFBE810BFFBC810DFFB87B0DFFB3780BFFB4790CFFBA7F11FF
+ BE8014FFBB7E10FFBC7D0FFFBE7F0FFFC28212FFB97909FFB67705FFBC7D0BFF
+ C07E0DFFBD7B0AFFBE7D0AFFC18210FFC18416FFC08518FFC08518FFC18416FF
+ BF8214FFBF8010FFBE7F0FFFBE800EFFBA7B0BFFB57908FFB4790BFFB77D13FF
+ B98017FFB78018FFB8831BFFC08823FFBC7B18FFC07C19FFBF7B16FFBD7B15FF
+ BD7B14FFBF7E15FFC5841BFFC9881FFFB87A10FFB87911FFBF7F19FFC0821CFF
+ B97B17FFBA7B19FFC48321FFC48321FFC17F19FFBD7B15FFB97815FFB87B1BFF
+ B67B1EFFB17920FFB47E27FFBA842FFFB27C27FFB27C25FFBA8229FF563718FF
+ 563716FF563718FF553615FF543516FF523314FF513213FF503112FF593A19FF
+ 5A3B1AFF5B3C1BFF5C3D1CFF5B3C1BFF593A19FF563716FF523516FF4F2F18FF
+ 543520FF4E321AFF362112FF403842FF586182FF4A609AFF3A57A1FF3757A2FF
+ 3C5FA9FF4468AEFF436AAFFF3D65ADFF3A62AAFF3F62ABFF4465AEFF3F62ACFF
+ 365BA5FF375DA5FF375DA5FF34589EFF37599FFF3959A0FF37539AFF2E448BFF
+ 304184FF303D7BFF323C72FF353B6AFF363860FF333554FF33334BFF3D3748FF
+ 32292CFF392A21FF483722FF4F391DFF4D3517FF4F361CFF50371DFF50371DFF
+ 54381AFF573A15FF5B3B12FF5D3A12FF5D3816FF5B351DFF59341EFF54321BFF
+ 52331AFF52331AFF513219FF513219FF503118FF4F3017FF4F3017FF56371EFF
+ 55361DFF54351CFF53341BFF52331AFF52331AFF52331AFF533518FF533914FF
+ 503611FF523013FF522D13FF532E12FF553316FF55381DFF583A21FF573724FF
+ 4E2C15FF542E0EFF6E4720FF8A6336FF936C45FF8A614AFF6C5756FF596480FF
+ 405A88FF445A8AFF415487FF303E6FFF28315DFF2D3056FF37334CFF32272FFF
+ 302014FF3E260AFF58380DFF6F4712FF835718FF92631FFF96631DFF9B6724FF
+ 9B6724FF9B6A26FF9C6B25FF9B6A20FF99681EFF95661CFF8B611CFF79551FFF
+ 432B07FF32281EFF505466FF6273A4FF5A78BFFF496ECAFF4467C1FF475CA0FF
+ 4B5A98FF3E5091FF294084FF1E377FFF214188FF365B9FFF4670B3FF4C79BCFF
+ 5081C5FF5F91D9FF6291DBFF4A71BFFF3354A3FF324D9DFF415196FF5F6594FF
+ 615D70FF7E6E5EFF987C53FF987133FF9E6E26FFAA782CFFAF7A2AFFBA852EFF
+ BA852BFFBA7E24FFB4781FFFB57723FFB77E29FFB4822AFFA37C32FFAE946CFF
+ D0BEADFFF2E5DDFFFAF2F2FFF9F5FAFFEFEDF3FFEEEDF1FFFEFBFDFFF0EEEEFF
+ EFEEF0FFECEFF3FFECF1F4FFEBF2F5FFEBF3F3FFEBF4F1FFEDF4EDFFF7F8EFFF
+ F5EBDAFFE1CAAAFFBC9967FFAF8239FFC48F38FFCB9530FFB57F14FFB87E15FF
+ BC7F17FFC0801AFFC17F19FFBE7C13FFBB7C0CFFBC7F09FFBC820BFFBD8410FF
+ BC830FFFBB820FFFBA810DFFB9800DFFB87F0BFFB77E0BFFB67D09FFB67D0AFF
+ B87F0BFFBB820FFFBB820EFFBA810EFFBA810DFFBD8411FFC28614FFBB7D0BFF
+ BD7E0EFFBE800EFFBD7F0DFFB97B09FFB77907FFB97B09FFBB7E0AFFBE810DFF
+ BE810DFFBE810DFFBE810DFFBD800CFFBD800AFFBD800CFFBD7F0DFFC48719FF
+ B87D10FFB4790CFFBA7F12FFC18317FFBD7F13FFB8790BFFB57608FFC18212FF
+ B77808FFB87808FFC38412FFC58515FFBD7E0CFFB97A08FFBD7E0EFFBB8013FF
+ BB8117FFBC8218FFBD8215FFBC8114FFBF8214FFC28517FFC48817FFC08315FF
+ BB7E10FFB77C0FFFB77D13FFB67D14FFB47B12FFB47D15FFBB811AFFBF7E1BFF
+ C3801DFFC4821CFFC3811BFFBF7D16FFBC7B12FFBC7C10FFBE7E12FFC38317FF
+ B8780CFFB9770EFFBF7D14FFBE7B14FFBF7C15FFC07C17FFBF7B12FFC48212FF
+ C17F0EFFC2800FFFC58515FFC68719FFC28216FFBE8014FFC18319FFC7891FFF
+ BD7F13FFC58519FF5A381BFF573517FF533114FF533113FF553316FF563417FF
+ 553316FF543215FF58351BFF59361CFF56341CFF56341CFF54321AFF523019FF
+ 4F2D16FF4C2B17FF4C2B17FF4B2C15FF4B2D12FF4E3521FF403636FF3F435BFF
+ 4C5F92FF4560A3FF3956A0FF3A5BA4FF3E62A8FF3E65AAFF3A62AAFF375FA7FF
+ 3A5DA6FF3E5FA8FF3C5FA9FF4669B3FF395CA5FF30539CFF3E62A8FF4062A8FF
+ 3858A1FF425EA5FF344A91FF344588FF323F7DFF343E74FF383E6DFF373C63FF
+ 343658FF32304DFF373045FF3A2F39FF3B2A27FF463220FF563E20FF563B16FF
+ 523510FF593A13FF533008FF522F03FF5E3905FF633E0AFF5D390BFF5B3713FF
+ 5B381EFF53331CFF503019FF54351CFF513219FF52331AFF593A21FF56371EFF
+ 4F3017FF503118FF53341BFF56371EFF57381FFF54351CFF4F3017FF4D2E15FF
+ 52331AFF57391CFF503612FF4E320FFF502F15FF57331BFF5B3A20FF5A3C1FFF
+ 52381AFF493115FF51361CFF513419FF5A3B1AFF6E5230FF846E52FF8A7A6AFF
+ 746874FF535371FF3C5079FF385685FF4A6296FF3F548BFF23326AFF262E63FF
+ 3C3B65FF433A55FF2E1A1FFF4F311EFF775023FF966624FFA8721FFFAF7516FF
+ B17511FFB17511FFB2771AFFB2761CFFB37619FFB27517FFB37614FFB27612FF
+ B17612FFAA7514FFA4751AFF997227FF745724FF4C3E28FF505062FF6E7CADFF
+ 6981D3FF4D6BC4FF5370BBFF5573BAFF4A69B8FF3B5CACFF2D4E9EFF20408CFF
+ 2A4588FF3F5B98FF6481BAFF6989C4FF6287C5FF5B82C6FF5981C9FF4E73BDFF
+ 4A69B4FF5773BAFF4D67AAFF53689FFF7E8CB0FFB3B5C7FFB9ABADFFBFA293FF
+ A67D5CFFA06F37FFB38030FFB67F24FFBD8427FFBC8026FFBB7B2DFFB5762CFF
+ B4772DFFBF8F55FFCEB698FFEBE2D5FFFEF7F4FFF0EDEFFFECECF2FFF2F5FAFF
+ F5F4F8FFF1F0F2FFF2F0F0FFF4F3F5FFF0F3F7FFEFF3F8FFF1F7FCFFF4FBFEFF
+ F0F6F5FFEDEFE9FFFAF4E7FFCCBDA3FFAD8F66FFA98042FFBB8838FFC68C2DFF
+ B77E15FFB98013FFB97F15FFBD8018FFBF7F19FFBF7D16FFBD7C10FFBA7B0BFF
+ BB7E08FFBA8009FFBC800EFFBA7E0CFFB87C0BFFB87C0AFFB97D0CFFBA7E0CFF
+ B87C0BFFB67A08FFB97D0CFFBE8210FFC38716FFC18513FFBC800FFFB87C0AFF
+ BA7E0DFFBD810FFFBB7E0AFFBE800AFFBF810BFFBE800AFFBD7F09FFBC7E08FF
+ BD7F09FFBF800DFFBB7C09FFBE7F0CFFC18210FFC18210FFBE7F0DFFBD7E0BFF
+ BE7F0DFFBF800EFFBF800EFFBF800EFFBF800EFFBF800EFFBF800EFFBF800EFF
+ BF800EFFBF800EFFBC7D0BFFBD7E0CFFBF7D0CFFBE7F0CFFBF800EFFC0810EFF
+ C0810EFFBF810FFFB87D0FFFB87D10FFB87D10FFBA7D0FFFBA7D0FFFBC7D0DFF
+ BC7D0DFFBC7E0CFFBC7D0DFFBC7D0DFFBB7F0EFFBB7E10FFBA7F12FFBA7F12FF
+ B97F15FFB97F16FFC0821CFFC48622FFC78923FFC48620FFBF8018FFBA7C12FF
+ BA7C10FFBC7E12FFBB7D11FFBA7C10FFBB7B0FFFBE7E12FFC18017FFC4831AFF
+ C5831CFFC4831AFFBC7D0DFFBC7E0CFFBD7F0DFFBD800CFFBE800EFFBE810DFF
+ BF820EFFBF820EFFC28511FFC28511FFC28511FF5B381EFF59371AFF563319FF
+ 563417FF59371AFF5A381BFF58371DFF57361CFF59371FFF59371FFF593720FF
+ 593622FF583422FF573321FF563222FF553121FF52311EFF503019FF4F2F12FF
+ 4E351BFF41342CFF40404EFF4E5B87FF4A629EFF3F5CA1FF3E5EA7FF3D61A7FF
+ 3C63A8FF3962A7FF365EA6FF365DA2FF385BA4FF395CA6FF4568B2FF4063ACFF
+ 3659A2FF3A5EA4FF3A5CA2FF3858A1FF425DA7FF374D95FF35488CFF324180FF
+ 323D76FF363D6EFF373B64FF343659FF31314FFF3B3651FF403545FF412F30FF
+ 48301EFF553813FF573605FF5C3501FF683F08FF6E4207FF76490CFF865818FF
+ 84581BFF714817FF633E18FF583A1FFF4E321AFF54341DFF583920FF55361DFF
+ 55361DFF5C3D24FF593A21FF52331AFF53341BFF52331AFF55361DFF583920FF
+ 56371EFF513219FF4E2F16FF503118FF53351AFF5B3B1EFF58381BFF56341CFF
+ 54341DFF52361EFF4D341AFF463014FF412B0FFF50381CFF482F15FF574026FF
+ 7F6D5CFF9D9491FF9C9FAEFF8E9AC2FF869BCFFF4D669EFF37548DFF344E8AFF
+ 324A86FF2C3E79FF384173FF424064FF3F303EFF56392BFF774D23FF98641DFF
+ AF7417FFB87A10FFB77806FFB57604FFB37404FFB4780EFFB3760EFFB7760DFF
+ B8760DFFB7760AFFB67508FFB57606FFB37706FFAB7304FFAB7712FF9F711DFF
+ 7F5D22FF5C4836FF534D5EFF5E6597FF687BBFFF5C79BEFF5B7EC8FF5078CAFF
+ 4B74C9FF4972C7FF3C5FAFFF263F85FF182A69FF34457EFF5469A0FF6884C0FF
+ 6283C2FF577ABCFF5C81C5FF6385C7FF5B7CC1FF6487D1FF6A8BD4FF81A0DFFF
+ A9BEF1FFBEC1E7FFC7B7C8FFAA887BFFA77A4EFFAC7A2EFFB37D1FFFB67E1FFF
+ B77D24FFBF8036FFBB7B3AFFC08144FFD9A979FFE0CBB5FFEEEBE3FFFAF8F7FF
+ EDEEF2FFEAEEF3FFF0F3F8FFF1F2F6FFF1F0F2FFF5F3F3FFF5F4F6FFF1F4F8FF
+ EFF3F8FFF1F5FAFFF2F7FAFFF0F4F5FFF3F0EBFFFFFEECFFDAC4A1FFB99664FF
+ B48541FFC28933FFC48824FFB3770DFFB57A0CFFB67C12FFB87E15FFBE7F17FF
+ C07E17FFBE7D11FFBC7D0DFFBA7F0BFFBC810DFFBD8110FFBC800FFFBB7E10FF
+ BB7F0EFFBD8012FFBD8110FFBA7D0FFFB87C0BFFB97C0EFFBC800FFFBF8214FF
+ BF8312FFBC7F11FFBA7E0DFFBC7F11FFC18311FFB97C06FFBC7F07FFBE8109FF
+ BD8008FFBB7E06FFBA7D05FFBC7E08FFBD7F09FFBB7C09FFBE7F0CFFC0810FFF
+ C0810FFFBE7F0DFFBC7D0BFFBD7E0CFFBE7F0CFFBF7F09FFBF8008FFBF7F09FF
+ BF7F09FFBF7F09FFBF7F09FFBF7F09FFBF7F09FFC2820CFFBF810BFFBF810BFF
+ BE7F0CFFBD7E0BFFBC7F0BFFBB7E0AFFBB7E0AFFBA7E0DFFBA7E0DFFBC7D0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7E0BFFBC7F0BFFBC7F0BFFBC7F0BFFBD7F0DFF
+ BD7F0DFFBE7F0FFFBC800FFFBD8110FFBB8012FFBA7E14FFBE8218FFC1851BFF
+ C08518FFBA7F12FFB77C0EFFB87D0FFFBA800FFFBB8110FFBA7F11FFB97E10FF
+ BA7F11FFBF8115FFC18317FFC08218FFBF8115FFB87E0DFFB87F0CFFB9800DFF
+ BB7F0DFFBC810DFFBC810DFFBD820EFFBD820EFFBC7F0BFFBA7F0BFFBA7F0BFF
+ 573920FF55381DFF54351CFF53351AFF54361BFF55371CFF54361BFF53351AFF
+ 53341BFF53341BFF52321BFF52311DFF54301EFF54301EFF543020FF553121FF
+ 563522FF54351CFF533415FF4F3419FF413023FF413A41FF4D5677FF506297FF
+ 4A64A6FF4363AAFF4064AAFF3D64A9FF3B64A9FF3963A8FF365EA6FF355BA3FF
+ 3659A3FF3E61ABFF4063ACFF3B5EA7FF395DA3FF3C5EA4FF3E5EA7FF3F5CA6FF
+ 3A529AFF394C90FF354483FF333E78FF363D6FFF343A65FF33375AFF313352FF
+ 363452FF3D3448FF433033FF4F311EFF633F11FF714506FF804E06FF935D10FF
+ 996112FFA1691AFFA56F22FF93621EFF734613FF613C16FF593C21FF50361EFF
+ 4D2E17FF52321BFF4F2F18FF503019FF573720FF55351EFF4F2F18FF51311AFF
+ 503019FF54341DFF583821FF573720FF53331CFF4F2F18FF4F2F18FF523019FF
+ 5E3421FF5B3321FF52331EFF4B331DFF47311FFF432F1DFF462E1AFF462E16FF
+ 523A1EFF483219FF5E4D44FF908892FFA5AACBFF8EA1D4FF7697D6FF7B9DE3FF
+ 6B86D0FF4A62AAFF354E96FF365092FF3E528BFF4B557DFF4D495CFF483226FF
+ 855D2DFFA16B1EFFBB7912FFC6800AFFC37E05FFB97903FFAD7407FFAA730BFF
+ B1780FFFB2780EFFB6780EFFB7760DFFB7750EFFB7760DFFB6760AFFB67707FF
+ B57701FFB57802FFB4790BFFA57214FF835A1CFF614425FF554344FF504E6BFF
+ 7889BCFF708FD4FF5E87D6FF4D7CD0FF4F7ED4FF4D77CAFF3F5CA7FF314488FF
+ 172462FF222D69FF394C89FF48619FFF4564A1FF5678B4FF7A9CD2FF89AAE2FF
+ 81A3E5FF84A4EBFF7EA1E3FF88A5DEFFA0ABD7FFA6A0B3FF8F7264FF996F40FF
+ AC7B2DFFB47E20FFB17B1DFFBA812CFFC58A45FFB3793EFFB77E4AFFDFB78DFF
+ F5E6D3FFF4F4EEFFF5F7F7FFEBF0F3FFEBEFF4FFEDF2F5FFEFF1F2FFF0F0F0FF
+ F6F6F6FFF3F5F6FFF1F4F9FFF0F3FBFFEEF1F9FFEFF2F7FFF3F2F4FFFAF3EAFF
+ E7D3BAFFBFA276FFAF874DFFBB883FFFCB9138FFCC8E2AFFBA7E14FFBC8114FF
+ B47A10FFB77D14FFBD7E16FFBE8016FFBF7F13FFBE7F0FFFBC800EFFBC800EFF
+ C18214FFC08113FFBF7F13FFC18214FFC28216FFC18214FFBE7E12FFBB7C0EFF
+ BC7C10FFBD7E10FFBD7D11FFBD7E10FFBE7E12FFBF8012FFC08014FFC18212FF
+ B87C04FFBA7F04FFBC8106FFBB8005FFB97D05FFB87C04FFB97C06FFBB7E08FF
+ BA7D09FFBC7F0BFFBD7F0DFFBE800EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0BFF
+ BE7F05FFC08004FFBE8004FFBE8004FFBE7F05FFBE7F05FFBC7F07FFBC7F07FF
+ BF820AFFBE820AFFBD8109FFBC7F09FFBB7E08FFB97F08FFB87E07FFB87E07FF
+ BC7F09FFBD7F09FFBD7F09FFBD8008FFBD8008FFBD8008FFBF8008FFBD8008FF
+ BD8008FFBD8008FFBE8109FFBE8109FFBF810BFFBE810BFFBF820CFFBD820EFF
+ B77C08FFBA7F0BFFBE830FFFBD830CFFBA8009FFB87E07FFB88009FFBB830CFF
+ BD850EFFB9830EFFB8810EFFB9820FFFBB8312FFBB8314FFB98114FFB88011FF
+ B87D0FFFB87E0DFFB97F0EFFB77F0EFFB88011FFB88011FFB98112FFB88112FF
+ BB8314FFBB8314FFBB8314FF53381EFF52371DFF52341BFF513419FF4F3217FF
+ 4E3214FF4D3113FF4C3012FF53351AFF523419FF513219FF503118FF523019FF
+ 522F1BFF522F1BFF522E1CFF54331FFF54351CFF553617FF513517FF44301EFF
+ 413835FF4C4E66FF53608CFF5469A6FF4968ADFF4367ADFF3D66ABFF3E67ACFF
+ 3F69AEFF3B65ACFF355DA5FF355AA4FF3558A2FF395CA5FF3C5FA8FF3B5FA5FF
+ 4266ACFF4565AEFF3B58A2FF3D559DFF3A4E95FF364688FF34407AFF333C6EFF
+ 333A65FF31375CFF2F3455FF2E304FFF383249FF473136FF5C3B27FF80541EFF
+ 986417FFA86D17FFB6791CFFB6771BFFB2761DFFA66E1DFF895512FF67390AFF
+ 5A3412FF55381DFF4C3319FF492A13FF4E2E17FF4B2B14FF4C2C15FF54341DFF
+ 53331CFF4E2E17FF503019FF4F2F18FF52321BFF55351EFF54341DFF52321BFF
+ 503019FF51311AFF57321EFF5B2F1EFF5B301FFF52331CFF483219FF402F1CFF
+ 3F2D1CFF48301EFF4B331DFF50351AFF523B25FF715E5BFF9D94A8FFA7ABDBFF
+ 8B9DDCFF708ED5FF6C8CD7FF7D93E1FF6777C3FF576AADFF5B6BA0FF5C6688FF
+ 5E5E6AFF655548FF6A4A1FFFA17026FFB57915FFC48009FFC78203FFC17E03FF
+ B97A07FFB17710FFAE7714FFB57C13FFB87D10FFBA7C12FFB97A12FFB97913FF
+ B97913FFB97A12FFBB7C0EFFBF7F09FFBA7B01FFB67700FFB17608FFA9741DFF
+ 956727FF6E4A22FF412D22FF434157FF5C6D98FF708FC6FF6991D2FF5986D0FF
+ 4D79C6FF4B6DB9FF516AB4FF5868ADFF374789FF203271FF1F356FFF254073FF
+ 3F5987FF687FA5FF8397BAFF8C98C0FF8894BCFF7C8EB3FF7987A4FF868795FF
+ 8A7D75FF876541FF9F7032FFB57F2AFFB98122FFB87F24FFCA9241FFD49E5DFF
+ B17F4BFFAE8457FFE2C5A6FFFEF5E7FFF3F4F0FFEEF2F3FFEDF2F5FFECF2F7FF
+ EDF2F5FFEEF0F1FFF0F0F0FFF5F5F5FFF0F2F3FFF0F3F8FFF1F3FBFFEDF0F5FF
+ F1F0F4FFF6F1F2FFFAEEE2FFCEB391FFAB8654FFA57737FFB68033FFC5892FFF
+ C58723FFB97A12FFBC7F17FFB67C13FFB87E15FFBC7F17FFBF8117FFBE8014FF
+ BF8012FFBC800FFFBB7E10FFC08113FFBF7F13FFBF7F13FFC18115FFC28216FF
+ C28216FFBE7E12FFBB7B0FFFC08014FFBD7D11FFBB7B0FFFBB7B0FFFBD7D11FF
+ C08014FFC08014FFBF8010FFBA7D07FFBB8005FFBD8207FFBC8008FFBA7E06FF
+ B97D05FFBB7E08FFBD800AFFBA7D09FFBB7E0AFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BB7D0BFFBB7C0CFFBA7D09FFBC7F07FFBE8004FFBC8004FFBC8004FFBC8005FF
+ BC8005FFBB7F07FFBB7F07FFB77E05FFB77E05FFB87E07FFB77F08FFB87F0BFF
+ B87F0BFFB9800CFFBB810AFFBD8008FFBF8006FFBF8006FFBF8006FFBF8006FF
+ BD8106FFBD8106FFBD8008FFBD8008FFBC8008FFBD8109FFBD8109FFBE820AFF
+ BE820AFFBD830CFFBD830CFFB87B05FFBB7E08FFBD800AFFBD8109FFBB7F07FF
+ B98007FFBA8108FFBB840BFFBB830CFFB8820DFFB7800DFFB8820FFFBB8314FF
+ BA8314FFB88013FFB77F10FFB87E0DFFBA7E0DFFB97F0EFFB97E10FFB88011FF
+ B77F12FFB88013FFB68015FFBE861BFFBE8619FFBE8619FF52341BFF52341BFF
+ 52351AFF513517FF503415FF4F3314FF4E3311FF4E3311FF593D1BFF593D1BFF
+ 573A1BFF56381BFF563619FF55341AFF54321AFF54321BFF512E1AFF51311AFF
+ 55371AFF503618FF49321CFF44342DFF494453FF525B7DFF50649BFF4764A7FF
+ 4064AAFF3961A9FF3C65AAFF3F69AEFF3C66ADFF345DA6FF375DA5FF3558A1FF
+ 3B5EA7FF3E61AAFF3A5EA4FF4064AAFF4464ADFF37549EFF3D569EFF3C5097FF
+ 38488AFF35407CFF323D71FF313A66FF2F365DFF2F3657FF2E3556FF38364CFF
+ 4B353AFF68442CFF956628FFB27923FFB97B17FFBB7B15FFB87B1BFFA76C16FF
+ 935C11FF78460CFF5F320DFF583017FF523419FF472C11FF53351CFF56361FFF
+ 52321BFF51311AFF56361FFF54341DFF4E2E17FF503019FF4E2E17FF503019FF
+ 503019FF503019FF503019FF51311AFF54341DFF59371FFF5D351CFF5C371BFF
+ 543917FF4A3515FF402F15FF3F2C17FF462D19FF4E311CFF4E3015FF5F402BFF
+ 785956FF8C7486FF9284AEFF8B88C0FF7A84C0FF707EC0FF6D79C1FF6B74B4FF
+ 7578A4FF7D7B8EFF7D7167FF7D6541FF8A662AFF976A19FFAD7718FFB47A10FF
+ B67D0AFFB47B08FFB27709FFB1770DFFB27714FFB57816FFB97B11FFBB7C0EFF
+ BB7B0FFFB97A12FFB97815FFB87A16FFB87A14FFBA7B13FFB77A0CFFB97D0BFF
+ B77B09FFB0770AFFAF7817FFAD7926FF9C6D29FF7F5929FF4D351FFF534949FF
+ 5F6675FF7186A5FF7CA0D0FF729BD9FF5A82CAFF4B71BFFF4E6FBEFF5372BDFF
+ 4C68A9FF4F679DFF7285ABFF8E99B4FF858B98FF777073FF8C746EFF896C5DFF
+ 8D7660FF8F7956FF9A7C4BFF9E7837FFA67323FFB87F22FFBF8220FFBC801CFF
+ BC7F22FFD49C4BFFDBAB6BFFB89361FFBCA480FFF1E4CEFFF9F5EAFFEDEEECFF
+ EAEEEFFFEFF4F7FFEEF4F9FFEEF3F6FFEFF1F2FFF0F0F0FFF2F2F2FFECEEEFFF
+ EEF1F5FFEFF2F7FFF0EFF3FFF5F2F4FFF6EFECFFF1E1D0FFD7B78EFFB68A4FFF
+ AD7A34FFB27A2BFFB67A20FFB77A1AFFB77915FFC0821EFFBA7E1AFFB97F18FF
+ BB8117FFBD8215FFBE8113FFBD8012FFBC7C10FFBB7B0FFFBF7F13FFBE7F11FF
+ BD7E10FFBE7F11FFC08113FFBF8012FFBC7D0FFFBA7B0DFFC28315FFBE7F11FF
+ BB7C0EFFBA7B0DFFBD7E10FFBF8012FFBD7E10FFBB7C0CFFBA7F0BFFBC830AFF
+ BD840BFFBC820BFFBA8009FFBA8009FFBB800CFFBD820EFFB87D09FFB97E0AFF
+ B97E0AFFBA7F0BFFBA7F0BFFBA7F0BFFB97D0BFFB87D09FFBB810AFFBB810AFF
+ BB810AFFBB810AFFBB810AFFBB810AFFB9800CFFB9800CFFB57C08FFB57C08FF
+ B67D09FFB57F0AFFB67F0CFFB67F0CFFB7800DFFB9800CFFBC8008FFBD8105FF
+ BD8106FFBD8106FFBD8008FFBC8008FFBC8008FFBA8009FFBA8009FFBA8009FF
+ BB810AFFBB810AFFBA820BFFBA820BFFBB820EFFBB820EFFBD7E0EFFBF7F0FFF
+ BF7F0FFFBD7F0DFFBC7E0CFFBB7D0BFFBC7E0CFFBC800EFFBA7E0DFFB87E0DFF
+ B87D0FFFB98112FFBD8117FFBC8218FFBA8017FFBA7F12FFBD7E0CFFBD7E0BFF
+ BD800CFFBD7F0DFFBC800FFFBA7F11FFB98013FFB88013FFB87F12FFB87F12FF
+ BA7F11FF523019FF52331AFF57361CFF56381BFF56391AFF563A18FF573B19FF
+ 583C19FF573B19FF573B19FF573B19FF56391AFF563619FF543417FF513016FF
+ 502E16FF4F2D16FF502E17FF53361BFF50351AFF4B341AFF463324FF443941FF
+ 4F526EFF48598CFF415D9EFF3B5EA7FF345CA4FF3760A5FF3B65AAFF3561A8FF
+ 2F58A1FF395FA7FF3C5FA8FF4467B0FF4164ADFF365AA0FF385CA2FF3D5DA6FF
+ 37549EFF3B549CFF3A5097FF38498CFF35437EFF333E72FF313A66FF2F365DFF
+ 2D3658FF2A3555FF35364BFF463237FF69442AFF9C6B27FFBB8122FFBC7E14FF
+ B4780EFFB57B1CFF95600FFF774705FF653708FF592C11FF58301DFF59381EFF
+ 503416FF583920FF593922FF53331CFF4F2F18FF53331CFF503019FF492912FF
+ 4A2A13FF4F2F18FF4F2F18FF4F2F18FF4E2E17FF4F2F18FF52321BFF55351EFF
+ 5A3820FF553316FF563514FF523613FF4E3513FF4A3216FF4A3117FF4F341AFF
+ 57361CFF583212FF714828FF845840FF825B4DFF7E5D61FF7F6575FF73657DFF
+ 645979FF655A7BFF6E617BFF806F72FF8D7561FF927241FF966D28FFA3731BFF
+ B27916FFB57B11FFB67B0DFFB27A0BFFAE7609FFAB750AFFAE750CFFB17511FF
+ B67610FFB6760AFFB77609FFB7760DFFB5760EFFB5750FFFB67610FFB6770FFF
+ B6780EFFB27408FFB3780BFFB5790FFFB2780FFFAD720EFFAA7010FFB07518FF
+ B07B2AFF9F7435FF7C5E2FFF5D4C2BFF5F5C4DFF758088FF7C92AEFF7694C5FF
+ 7696D7FF6F92DBFF789BE4FF7194D3FF7C9BCEFFAEC4E8FFCFDDF3FFCBCEDCFF
+ CBBFBBFF9E775BFF9F6E40FFA67842FF9F722EFFA97927FFAF7B1DFFB67B17FF
+ BC8219FFC1831DFFB97C1AFFB8791DFFC48C3BFFC69656FFBC9B6EFFCFC3ABFF
+ F2F0E5FFF2EFEAFFE9EAE8FFEAEEEFFFF0F5F8FFEFF3F8FFEDF2F5FFF1F3F4FF
+ F1F1F1FFF0F0F0FFEBEDEDFFEFF0F4FFEFF0F4FFF0EFF1FFFBF6F5FFF1E9E2FF
+ DBC8B3FFD7B083FFC09050FFBF8A41FFC08837FFBA7E25FFBC7E20FFBF7F21FF
+ C48727FFBD821FFFBB811AFFBA8016FFB98112FFBB8012FFBD7F13FFBD7B14FF
+ BB7912FFBF7F13FFBD7E0EFFBB7C0EFFBB7C0CFFBD7E10FFBD7E0EFFBC7D0FFF
+ BA7B0BFFC28315FFBF8010FFBC7D0FFFBB7C0CFFBD7E10FFBD7E0EFFBC7D0FFF
+ BA7B0BFFBB7F0DFFBD820EFFBE830FFFBE830FFFBC810DFFBB800CFFBC810DFF
+ BE830FFFBA7F0BFFB97E0AFFB97E0AFFBA7F0BFFBC810DFFBB810AFFBA7F0BFF
+ B87D09FFBC810DFFBA810DFFBC800EFFBA810DFFBC800EFFBA810EFFBA810EFF
+ BA810EFFBA810EFFBA810EFFB9800DFFB87F0CFFB77E0BFFB57E0BFFB67C0BFF
+ B87D09FFBD8106FFBF8105FFBF8006FFBD8106FFBD8008FFBC8008FFBC7F09FF
+ BA8009FFBA7F0BFFB87F0BFFB9800CFFB9800CFFB8810EFFB8820DFFB9820FFF
+ BB820FFFBE8113FFBF8012FFBF8012FFBD7E0EFFBC7D0DFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBB7D0BFFB97D0BFFBA7E0DFFBD8110FFC08315FFC08315FFBE8014FF
+ BD7E10FFBF7E0BFFBF7F09FFBE7F0CFFBD800CFFBC800EFFBC800FFFBB8012FF
+ B98112FFB47C0DFFB67B0DFFB87C0BFF592F1CFF59321CFF5E351FFF5D371FFF
+ 5B361CFF5A3519FF593719FF5A3918FF543214FF533415FF553617FF563619FF
+ 55341AFF523018FF4C2C15FF4C2A13FF512F18FF512F18FF52341BFF4B3317FF
+ 4B3317FF44301EFF3F3132FF4C495FFF465485FF415B9DFF3D60A9FF355EA7FF
+ 365FA4FF3963A8FF325FA8FF2B569FFF385EA6FF4061AAFF4366AFFF3E61AAFF
+ 375AA3FF385BA4FF3C5CA5FF3956A0FF38519BFF384E95FF38498CFF364381FF
+ 343F73FF313A66FF2E375DFF2B3557FF263353FF30354AFF443035FF643F25FF
+ 97641EFFB77D1DFFBA8017FFB27C17FFA2711BFF7B510CFF603905FF57310FFF
+ 532A1BFF562F21FF5D3A20FF5C3D1EFF513219FF53321EFF4D2C18FF4B2A16FF
+ 51301CFF4F2E1AFF4A2915FF4C2B17FF502F1BFF502F1BFF502F1BFF502F1BFF
+ 51301CFF51301CFF52311DFF52321BFF4C2F14FF4E3214FF523117FF553218FF
+ 563417FF583618FF583A17FF613D17FF663B10FF865420FFA36928FFA66B25FF
+ 9F6A27FF9C6B33FF8F6540FF855D40FF8D603EFF96693EFF997039FF9D722FFF
+ A27524FFA9771DFFB17717FFB67610FFBD7B12FFBC7B0FFFB6780CFFB3780BFF
+ B07809FFB3780AFFB6790BFFB9790DFFB67509FFB6740BFFB5740BFFB4760CFF
+ B7760DFFB8770BFFBA7808FFBB7909FFB67508FFB3750BFFB17511FFB37713FF
+ B47310FFB27007FFB87004FFB77407FFAD760EFFA77717FF99701BFF84621CFF
+ 6F5729FF655744FF76757EFF939EBEFF96ADDDFF8DAEE6FF88AFE6FF8DB6E7FF
+ A2C8F2FFB0D0F4FFAAC3E3FFB2B5C3FF9D7F66FFBC8C5CFFC59155FFAB762DFF
+ B87F29FFBA8021FFB67C1CFFBA8322FFBC8628FFBC8326FFBC7F22FFB67D28FF
+ AE7C3AFFC5A57AFFE8DED4FFEAECEDFFF0EEEEFFEDEBEBFFF0F1F5FFF2F6FBFF
+ ECF0F5FFECEFF3FFF2F4F4FFF1F2F0FFF1F2F0FFECEEEEFFF0F2F3FFEEF0F1FF
+ F2F0EFFFFEFAF5FFEAE0D6FFC2AD92FFC39B67FFBF8B45FFCB9449FFCD9341FF
+ BE812BFFBD7F25FFBD7E24FFBD7E22FFBE8222FFBB811AFFB77F12FFB77F10FF
+ BA7F11FFBE8014FFC07E18FFBF7D17FFC18214FFBE800EFFBB7C0CFFBA7C0AFF
+ BB7C0CFFBD7F0DFFBD7E0EFFBC7E0CFFBD7E0EFFBC7E0CFFBC7D0DFFBD7F0DFF
+ BE7F0FFFBD7F0DFFBC7D0DFFBB7C0CFFBA7E0DFFBC800FFFBD810FFFBD810FFF
+ BB7F0DFFBA7E0CFFBB7F0DFFBD810FFFBB800CFFBA7F0BFFB97F08FFBB810AFF
+ BD830CFFBD840BFFBB810AFFB87E07FFBB7F0DFFBB7F0DFFBD7E0EFFBB7F0DFF
+ BD7E0EFFBD7F0DFFBD7F0DFFBD7F0DFFBF810FFFBE800EFFBF800DFFBE7F0CFF
+ BD7E0BFFBC7F0BFFBC7D0BFFBC7E08FFC18006FFC18105FFC18006FFBF8006FF
+ BF8008FFBD7F09FFBC7F0BFFBA7F0BFFBA7E0CFFBA7E0CFFB9800DFFB9800DFF
+ BA800FFFBA810EFFBB8110FFBB8110FFBB8012FFBA7F11FFB87E0DFFB77E0BFF
+ B77E0AFFB97F08FFBA8009FFBD8109FFBC8106FFBD8106FFBE8207FFC08409FF
+ C4850DFFC4850DFFC0800AFFBD7D07FFBD7F09FFBD7F09FFBD800CFFBD800CFF
+ BC810DFFBC800EFFBB820FFFBB8110FFB97F0EFFB9800DFFBB7F0DFF5B301FFF
+ 5D3320FF5F3522FF5D341EFF573119FF532E14FF502E11FF502E11FF553316FF
+ 573518FF59391CFF5B3A20FF5B3921FF58361FFF52321BFF523019FF57341AFF
+ 503118FF4B331DFF462F19FF4B3015FF452D17FF3F2B26FF4D4556FF4A5785FF
+ 4861A1FF4668AEFF3C64ACFF3A63A8FF3C66ABFF3762ABFF2F58A1FF395CA5FF
+ 3D5EA7FF3A5DA7FF385BA5FF3C5FA9FF4263ACFF4161AAFF3C5AA1FF364F99FF
+ 354D95FF354A8EFF334483FF313E76FF2F3969FF2E365EFF2C3459FF30395EFF
+ 3A3B55FF46353EFF5D3D26FF8A5D1AFFAA751AFFB37C1BFFAF7C20FF865A13FF
+ 653F09FF57340CFF5C391FFF5B3426FF573022FF56351BFF573819FF4C2D14FF
+ 503019FF4D2C18FF4E2E17FF583723FF593922FF573622FF5B3B24FF51301CFF
+ 51311AFF52311DFF53331CFF52311DFF51311AFF4E2D19FF4C2D16FF52371DFF
+ 53351CFF58341CFF59331BFF593418FF563514FF553511FF59380BFF6C420DFF
+ 8B5613FFAD6E16FFBC7916FFBA7811FFB27515FFAA7225FFAB732CFFB4782CFF
+ BC7D2CFFB67B25FFAE771CFFB17A19FFB87D1AFFB67812FFB27009FFBC7912FF
+ BB7910FFB9780FFFB7790DFFB87A0EFFB97C0EFFBC7D0FFFBD7C0FFFB8760DFF
+ B9770EFFB8760FFFB7790FFFB9790DFFBB7A0DFFBE7C0BFFBE7C0BFFBA790DFF
+ BE7C15FFBA7B19FFB57614FFBA7714FFC27E15FFC67C0CFFBD7400FFB37500FF
+ B67D0AFFB57D10FFAF791AFFA17024FF89622BFF7D6143FF7E6F66FF818089FF
+ 8B95A7FF91A1B8FF8398AEFF879AAFFFA5B7C8FFA1AFC1FF8A8685FF795733FF
+ B8864AFFCE974EFFAB721DFFBE8123FFBB801DFFAD7516FFB47E20FFBC872DFF
+ C38D36FFC58C36FFAF7B2EFFA0763BFFD3B896FFFFFDF8FFEEF1F6FFF2F0F0FF
+ F1EFEEFFF7F6F8FFF7F7FDFFE9EDF2FFE9EEF1FFF0F5F4FFEFF2F0FFF2F3F1FF
+ F0F0F0FFF1F2F6FFEFEEF2FFF5F0EFFFFFFBF3FFEDDCC7FFBA9B74FFB38545FF
+ B47C2DFFC78D3BFFC58B32FFB7791FFFBC7D21FFC08125FFC18424FFBF831FFF
+ BA8017FFB67E0FFFB57D0CFFBA800FFFBF8214FFC08218FFC28118FFC48515FF
+ C08210FFBB7D0BFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFB97B09FF
+ BA7C0AFFBC7E0CFFBE800EFFBE800EFFBE800EFFBD7F0DFFBC7E0CFFB97D0CFF
+ BA7E0DFFBC800EFFBB7F0DFFB97D0BFFB87C0AFFBA7F0BFFBB800CFFBC810DFF
+ BB810AFFBA8009FFBB810AFFBE850CFFBE850CFFBB8209FFB87E07FFBB7E0AFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7D0BFFBC7D0AFFBC7D0BFF
+ BD7E0BFFBD7E0BFFBE7F0CFFC1800DFFC0810EFFC2810EFFC2820CFFC18006FF
+ C18006FFBF8006FFBF8008FFBF8008FFBD7F09FFBC7F09FFBC7F0BFFBA7F0BFF
+ BA7F0BFFBB7F0DFFB9800DFFBC800EFFBA810EFFBD810FFFBB820FFFB87F0CFF
+ B77E0BFFB57C08FFB57C08FFB67E07FFB98007FFBA8106FFBD8207FFBF8508FF
+ BF8406FFBF8307FFC38608FFC4860AFFC28408FFC08004FFBA7B01FFBD7F09FF
+ BC7F0BFFBD7F0DFFBD7F0DFFBC800EFFBC800EFFBB820FFFBB820FFFB97F0EFF
+ B9800DFFBB7F0DFF553121FF55311FFF54301EFF522F1BFF512E1AFF502E17FF
+ 4F2D15FF4F2D15FF512F17FF523018FF54321AFF56341CFF57351DFF56341CFF
+ 55331BFF563319FF613E1CFF55371AFF3F2C1DFF372619FF482910FF502E16FF
+ 4E3329FF403440FF515A85FF465E9AFF4865A8FF4367ADFF3E66AEFF4068B0FF
+ 4167AFFF3E62A8FF4465AEFF3D60AAFF365AA6FF375BA7FF3D5FABFF4060ABFF
+ 3E5CA3FF3A579CFF334F96FF375197FF365096FF324A8CFF2F417CFF2C3A6EFF
+ 2E3763FF32365FFF32315BFF3A3457FF423648FF533D31FF765419FFA77B28FF
+ A8721FFF9E6821FF6F4413FF623C19FF583716FF523215FF552F17FF522E16FF
+ 4B2F11FF482E10FF503219FF4F3118FF50311AFF53351CFF573821FF583A21FF
+ 563720FF53351CFF53341DFF503219FF4C2D16FF4A2C13FF492A13FF4C2E15FF
+ 4F3019FF53341BFF58361EFF54321AFF56321AFF58361EFF57391EFF533719FF
+ 513713FF583B0EFF6D470DFF946319FFB4791CFFBD7B14FFBA790DFFBA7C12FF
+ B57B1CFFB0771CFFB5761CFFB7751CFFB5761AFFB57719FFB57818FFB77816FF
+ B97816FFB97815FFBB7815FFBB7913FFB87812FFB87911FFB87911FFB7790FFF
+ B7790FFFB9780FFFB8760FFFBB7912FFBB7D13FFBB7D13FFB87A10FFB8780CFF
+ B7770BFFB8780CFFB9780FFFB97A12FFBB7A17FFBB7A18FFB87715FFB97613FF
+ BB7714FFBD7A13FFBA7C12FFB5790FFFB57915FFB87D20FFB67D28FFAC782CFF
+ A57632FFA2783DFF946F3DFF937348FF927451FF8E7250FF8F7354FF947859FF
+ 967A58FF9A774BFFAC7E3EFFB57E2DFFB67C1DFFB47A13FFB47B12FFB78018FF
+ BC8425FFC1882DFFBA7E25FFB67C2AFFCB984FFFB68F51FFBCA27AFFF7EAD4FF
+ FFFCF7FFF1F1F1FFF2F2ECFFF3F3EDFFF7F2F3FFF4F3F7FFEEF1F9FFE7F0F4FF
+ E4EFEDFFE4EDEAFFE9EDE8FFF8F6F6FFF0ECF7FFEEE6F1FFFEF1F3FFFBE6D7FF
+ D6B58EFFB4884BFFC38B3AFFC08326FFB97C1CFFBB7E1CFFBE801CFFBA7C18FF
+ B77913FFB77A12FFB67B0EFFB87D0FFFBA800FFFBC8310FFBE8210FFBD810FFF
+ BB7F0DFFBA7E0CFFBF810FFFBE800EFFBD7F0DFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BE800EFFBF810FFFBF810FFFBF810FFFBF810FFFBE800EFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC7F09FFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F09FFBA7D09FFBC7F09FFBD800AFFBC7F09FFBB7D07FFBA7D07FF
+ BF810BFFC2840EFFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC8008FF
+ BC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBA8009FFBC7F09FFBA8009FF
+ BC7F09FFBA8009FFB87E07FFB87F06FFB87F06FFB87F06FFB87F06FFBA7F04FF
+ BA7F04FFBA7F04FFC0850AFFC08609FFC0850AFFC08408FFC08409FFBF8308FF
+ BE8207FFBE8109FFBD7F0DFFBD8110FFBC800FFFBB7F0EFFBE8211FFC28615FF
+ C08413FFBA7E0DFFBA7D0FFFBA7E0DFFBA7E0DFF563522FF543320FF53321EFF
+ 52321BFF52321BFF51331AFF513219FF503118FF4C2D14FF4F3017FF52331AFF
+ 55361DFF56361FFF54341DFF52321BFF523018FF5C3918FF543619FF423124FF
+ 422F22FF513016FF563214FF51301CFF412D2CFF454864FF4B5C8DFF4864A0FF
+ 3E61A5FF4168B2FF436CB5FF3D65ADFF3C62AAFF3F62ACFF3D60AAFF395DABFF
+ 355BA9FF385AA6FF3959A4FF3B59A0FF3C599EFF38559AFF375499FF345196FF
+ 314B8EFF2E4381FF2C3B73FF2F3766FF33355EFF36315EFF3A3257FF3B3148FF
+ 4B3833FF6F521FFFA0772EFF99651EFF885216FF683B19FF5C371DFF563619FF
+ 553518FF5B3418FF573216FF4B3015FF442E12FF51361CFF52341BFF52341BFF
+ 53351CFF54361DFF53351CFF51331AFF4F3118FF53351CFF51331AFF4F3118FF
+ 4D2F16FF4D2F16FF4E3017FF51331AFF54351CFF553119FF512D15FF4F2D15FF
+ 52331AFF51351DFF51361BFF553B17FF614314FF744E0EFF966716FFB47A1BFF
+ BC7B12FFB9780BFFBB7B0FFFBA7D15FFB57915FFB77718FFB97718FFB97718FF
+ B97718FFB97718FFB97816FFB97816FFB97815FFB97815FFB97815FFB87812FF
+ B87812FFB87812FFB77711FFB77810FFB77810FFB6770FFFB97A12FFBB7D13FF
+ BA7C12FFB87A10FFB6780EFFB6780EFFB6780EFFB77810FFB97A12FFBA7A14FF
+ BA7916FFB87715FFB87617FFB97619FFBB791AFFB77915FFB57713FFB8781AFF
+ BB7C22FFBB7C24FFB67923FFB47A21FFB57F28FFB47C2AFFB47E31FFB27B36FF
+ AC7635FFAB7637FFAC793AFFAD7B39FFAC7A32FFB98231FFBA8126FFBA8017FF
+ B57D0EFFB47C0FFFB47D14FFB87E1EFFBB7F25FFC4842FFFBB8135FFAC8040FF
+ AE8D5FFFDDCCB1FFFEF8EBFFEDEAE5FFEBE9E8FFEDEDE7FFEFEFE9FFF4F0EFFF
+ F2F1F3FFEFF3F8FFECF2F7FFE9F3F3FFEAF3F0FFEBEFEAFFECECECFFF3EBF5FF
+ FBEDF8FFF5E1E0FFDABBA6FFBD9561FFB78539FFC08528FFC4841EFFC2821CFF
+ C3841CFFC08119FFBC7E14FFBF8115FFC5881AFFBF8214FFBE8211FFBD810FFF
+ BB7F0DFFBB800CFFBB800CFFBB810AFFBB810AFFBE800EFFBD7F0DFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BC7E0CFFBE800EFFBF810FFFC18311FFC28511FFBC7F09FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBB7E08FFBB7E08FFBD800AFFBF820CFFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBF830BFFBF830BFFBF830BFF
+ BE820AFFBE820AFFBD8109FFBD8109FFBC7F09FFB67A09FFB97C0EFFB97C0EFF
+ B87B0DFFBB7E10FFBF8214FFBC7F11FFB6790BFFBA7D0FFFBA7D0FFFBA7D0FFF
+ 52331CFF50311AFF4E3017FF4F3217FF523618FF503717FF503415FF4C3313FF
+ 4B3113FF4B3113FF4B3016FF4B2F17FF492E19FF4A2F1BFF4B2F1EFF4D2F1EFF
+ 573420FF54331FFF4C3222FF4B331DFF543312FF56330BFF55300AFF482D13FF
+ 453C3FFF535B78FF496195FF385B9DFF426AB2FF436DB8FF3663ADFF3761ACFF
+ 385DA7FF3B5EA8FF395DABFF345AA8FF3557A3FF3656A1FF3C59A3FF415DA4FF
+ 3B589DFF38559AFF334F96FF314B8EFF314684FF303F77FF303867FF31325EFF
+ 37325FFF393058FF392E48FF453332FF6A4D21FF997031FF8A5718FF6F3A07FF
+ 613516FF57321CFF53341BFF57361CFF5E361DFF5B361CFF4E3319FF482F15FF
+ 4A2F15FF4E3017FF51331AFF52341BFF52341BFF52341BFF53351CFF54361DFF
+ 52341BFF52341BFF51331AFF503219FF503219FF51331AFF52341BFF54351CFF
+ 57361CFF553119FF4F2F18FF4F3019FF4C2F1AFF4C2F14FF533611FF63400EFF
+ 815813FF9E6C19FFB67B18FFBB7B0FFFB8770AFFBA7A0EFFB97B17FFB77816FF
+ B87715FFB87715FFB87715FFB87715FFB87715FFB87714FFB87714FFB87714FF
+ B97815FFB97913FFB87812FFB87812FFB87812FFB77711FFB77810FFB77810FF
+ B6770FFFB97A12FFBA7B13FFBA7B13FFB7790FFFB6780EFFB6780EFFB7790FFF
+ B6770FFFB87911FFBA7A14FFB97815FFB87715FFB87617FFBA771AFFBD7B1CFF
+ B77516FFB87617FFBC781FFFBD7A23FFBA7924FFB6771FFFB67A20FFB87F24FF
+ B87E25FFB57E29FFB27A2BFFAC7629FFAC752AFFAD792CFFAE7B2BFFAE7A27FF
+ B77F26FFB97F20FFB87E17FFB67E13FFB57D12FFB67D14FFB97C1AFFBA7D20FF
+ BE8230FFB17D36FFA27B44FFC3A984FFFDF0DAFFFFFCF1FFEEEBE6FFF7F5F4FF
+ F1EFEEFFF2F0EFFFF2F3F1FFF1F3F3FFEEF1F5FFEDF0F4FFEBEFF0FFEAEFEEFF
+ EBF1ECFFE9ECEAFFF7F0F3FFFEEEEFFFE7CBC0FFC49E7EFFB28748FFB58330FF
+ B6791BFFBF7F19FFC3831DFFC2831BFFBC7D15FFB97B11FFC18317FFCC8F21FF
+ C48719FFC18514FFBD810FFFB97D0BFFB87D09FFB97E0AFFBB810AFFBD830CFF
+ BC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFF
+ C08210FFBF810FFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE810DFF
+ BC7F09FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BF820CFFBD800AFFBB7E08FFBB7E08FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BE810BFFBE810BFFBD800AFFBD800AFFBD800AFFBC7F09FFBC7F09FFBC7F0BFF
+ B97D0CFFBD8012FFBF8214FFBE8113FFC08315FFC28517FFBF8214FFB97C0EFF
+ BA7D0FFFBA7D0FFFBA7D0FFF4A2E16FF482D13FF472C12FF492E13FF4C3116FF
+ 4D3217FF4B3015FF482D12FF4D3217FF4D3218FF4D3218FF4C3018FF4A2F1AFF
+ 4B301CFF4B301CFF50301DFF532D1BFF542D17FF522D11FF53310DFF573609FF
+ 613C08FF6C4409FF6A4513FF5E472DFF615B60FF4E6089FF3B5C9BFF3E65AAFF
+ 3D67B2FF3363B1FF3563B1FF385CA8FF3A5DA7FF375BA7FF345AA8FF365AA6FF
+ 3C5CA7FF415EA8FF4561A8FF3B589DFF365398FF304C93FF2E498CFF324785FF
+ 324179FF32396AFF31325EFF36315EFF3A3257FF3A2E4AFF423134FF614522FF
+ 8D6530FF7D4B16FF623105FF5B3219FF51301DFF50311AFF53341BFF5C361EFF
+ 5C361EFF53341DFF4D331BFF492E14FF4E3017FF51331AFF51331AFF4F3118FF
+ 4F3118FF52341BFF54361DFF4F3118FF503219FF503219FF51331AFF51331AFF
+ 51331AFF51331AFF52331AFF57361CFF54321AFF50311CFF4F2F1CFF4C2D18FF
+ 4D2C12FF58340EFF68410AFF926319FFA67218FFB67C15FFB87B0DFFB7770BFF
+ B9780FFFBA7917FFB97718FFB87715FFB87714FFB87812FFB87812FFB87812FF
+ B87812FFB87812FFB87812FFB97913FFB97913FFB87812FFB87812FFB87812FF
+ B77711FFB77810FFB77810FFB6770FFFB87911FFBA7B13FFB97A12FFB7790FFF
+ B6780EFFB7790FFFB97B11FFB6770FFFB77810FFB97913FFB97913FFB87714FF
+ B97816FFBB791AFFBE7C1DFFB67415FFB97619FFBD7920FFBE7922FFBA7720FF
+ B7781EFFB97A1EFFBB7E20FFB47A1BFFB57A1DFFB37920FFB07721FFB17822FF
+ B17C22FFB17D1FFFB37D1EFFB77A1CFFB87B1BFFB77C18FFB87F16FFBA8217FF
+ BC8219FFBF811DFFBD8023FFC38A3BFFAB7C3EFFB09065FFE8D6B9FFFFF8E9FF
+ F6F3EBFFFCF9F4FFF6F2F1FFF3F1F1FFF2F1F3FFEEF3F1FFEEF3F1FFF0F2F3FF
+ F0EFF3FFEEEDF1FFEBEDEEFFE7ECEAFFF1F3EDFFF8F0E9FFE8D2C6FFCDA991FF
+ C4976BFFBF9046FFB38024FFB07512FFBA7B13FFBE7F17FFBD7F15FFB7790FFF
+ B5770BFFBC7E12FFC48719FFC38716FFC18514FFBD810FFFB97D0BFFB87D09FF
+ BA7F0BFFBD830CFFBF8410FFBA7C0AFFBA7C0AFFBA7C0AFFB97B09FFB97B09FF
+ BA7C0AFFBA7C0AFFBA7C0AFFC38513FFC18311FFBE800EFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBC7F0BFFBC7F09FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFC1840EFFBE810BFFBA7D07FFBA7D07FFBC7F09FF
+ BD800AFFBC7F09FFBA7D07FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC7F09FFBD800CFFBD800CFFBD7F0DFFBD800CFFBD7F0DFF
+ BD800CFFBD7F0DFFBD800CFFBE800EFFBD800CFFBC7E0CFFBC7F0BFFBB7D0BFF
+ BC7F0BFFBC7E0CFFBD7F0DFFBB7F0EFFC08315FFC38618FFC18416FFC28517FF
+ C48719FFC18416FFBB7E10FFBA7D0FFFBA7D0FFFBA7D0FFF432B15FF432B15FF
+ 452A15FF472C18FF4A2F1BFF4B2F1EFF482C1BFF482A19FF4B2D1CFF4F2F1CFF
+ 51311EFF53341FFF54351EFF53351CFF53351AFF563319FF542B12FF5C2D0DFF
+ 643404FF6A3E03FF6E490BFF7D5913FF956614FF9C6C1EFF8A642AFF725D47FF
+ 566078FF466199FF375A9EFF355DA8FF3967B5FF3866B4FF4067B2FF3F62ACFF
+ 385CA8FF375DABFF3D61ADFF4164AEFF4161AAFF405EA5FF38549BFF324E95FF
+ 2A4791FF2C468CFF324687FF34437BFF333A6BFF32335FFF37305BFF3D3258FF
+ 3E324EFF423239FF583D23FF7C562CFF704318FF61340FFF57321EFF502F20FF
+ 4C2E1BFF4F3019FF59331BFF5B341EFF553621FF523520FF54351EFF55371EFF
+ 55371EFF52341BFF4D2F16FF492B12FF4A2C13FF4B2D14FF4C2E15FF4D2F16FF
+ 4E3017FF4F3118FF503219FF503219FF4F3118FF4F3118FF4C2E13FF4B2D14FF
+ 4C2E1BFF4E301FFF502F1CFF563115FF693F14FF7C4F12FF9F6C1CFFAE7617FF
+ B67C12FFB87B0DFFB8780CFFB97710FFBB7716FFB97718FFB87812FFB87911FF
+ B87911FFB87911FFB87911FFB87911FFB87911FFB87911FFB97A12FFB97A12FF
+ B87911FFB87911FFB87812FFB77711FFB77711FFB77711FFB6770FFFB87911FF
+ B97A12FFB87911FFB7790FFFB6780EFFB87A0EFFBA7C10FFB6780EFFB87911FF
+ B97913FFB87812FFB77613FFB87715FFBC7A1BFFBF7D1EFFB87415FFBC7819FF
+ BF791EFFBF7820FFBB771EFFBB781CFFBD7C1AFFBB7D19FFB37811FFB47814FF
+ B77A18FFB97D1DFFB97D1DFFB67D1AFFB47D14FFB57C13FFB97B15FFBB7D19FF
+ B8801BFFBA831BFFBE841BFFC1841CFFC3831DFFBD7F25FFC8944DFFB9925EFF
+ C8B394FFFAF0DFFFFBF9EFFFECEBE7FFF2EFEAFFDAD6D5FFEDE9EEFFEAEBEFFF
+ E9F0EDFFEBF2EDFFF2F2F2FFF7F1F6FFF8F1F8FFF6F2F7FFECF0EBFFF6F6EAFF
+ EFE3D1FFCBAE93FFB2855AFFBD874AFFC18F37FFAE7A15FFB67B14FFBC7D15FF
+ BC7D15FFB97B11FFB7790FFFB6780CFFB87A0EFFB97C0EFFBE8211FFBD8110FF
+ BC800EFFBB7F0DFFBB800CFFBC810DFFBD820EFFBE830FFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBD7F0DFFBF810FFFC18311FFC28511FFBC7F09FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFC1840EFFBE810BFF
+ BA7D07FFBA7D07FFBC7F09FFBD800AFFBC7F09FFBA7D07FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBE800EFFBE800EFF
+ BE7F0FFFBE800EFFBE7F0FFFBE800EFFBE7F0FFFBE800EFFBD7E0EFFBD7F0DFF
+ BC7D0DFFBB7D0BFFBB7C0CFFBC7E0CFFBD7E0EFFBE7F0FFFB77A0CFFBD8012FF
+ BF8214FFBD8012FFBC7F11FFBE8113FFBC7F11FFB77A0CFFBA7D0FFFBA7D0FFF
+ BA7D0FFF442C18FF462E1AFF492F1EFF4B3121FF4D3021FF4C2F21FF4D2D20FF
+ 4F2E1FFF4E2A1AFF4E2915FF4E2810FF4E2A0CFF532E0CFF59360EFF613E12FF
+ 6A4316FF734319FF7F4815FF8D520CFF945D0CFF8F6617FF986F1AFFAC7814FF
+ B17A17FFAD7827FF846234FF636167FF50638EFF375695FF335AA5FF3F68B7FF
+ 3D66B5FF4C71BBFF456AB4FF3C63AEFF3C62B0FF4165B1FF4265AFFF3E5EA7FF
+ 39579EFF38549BFF334F96FF2C4993FF2D468EFF304687FF32437CFF323B6DFF
+ 333460FF38325BFF3C3256FF3E324EFF45363EFF523827FF6D4A29FF663C19FF
+ 62381BFF533121FF4B2E20FF492E1AFF4B2F17FF553119FF57331BFF543320FF
+ 513320FF54351EFF54361DFF53351CFF503219FF4D2F16FF4C2E15FF4C2E15FF
+ 4D2F16FF4B2D14FF4C2E15FF4D2F16FF4E3017FF4F3118FF4F3118FF4F3118FF
+ 4F3118FF4D2F16FF4C3018FF4F311EFF50321FFF53311AFF5C3515FF744616FF
+ 8E5A17FFAC731EFFB47916FFB87C12FFB97B0FFFB87A10FFBA7812FFBB7716FF
+ BB7716FFB77810FFB7790DFFB7790DFFB7790DFFB7790DFFB7790FFFB7790FFF
+ B77810FFB97A12FFB97A12FFB87911FFB87911FFB87812FFB77711FFB77711FF
+ B77711FFB6770FFFB87911FFB97A12FFB87911FFB6780EFFB6780EFFB97B0FFF
+ BB7D11FFB87A10FFB97B11FFB97A12FFB87812FFB67610FFB77613FFBB7A18FF
+ BE7D1BFFB97613FFBC7916FFBD791AFFBC771AFFBD781BFFC07C1DFFBD7D17FF
+ BA7B13FFB97B11FFB77B11FFBC7C16FFBF811DFFBE801AFFB97C14FFB57A0CFF
+ B4790BFFBF8117FFBE801AFFBB831EFFBC841FFFBF851CFFC0831BFFC07F1DFF
+ B47B26FFB28649FFD3B68FFFE7D9C6FFF6F3EBFFF6F7F3FFE0E3E1FFDDDCD8FF
+ D8D6D5FFEDEBF1FFECECF2FFEAF1EEFFEBF2EDFFF1F1F1FFF6F0F5FFF8EFF9FF
+ F8F1F6FFFFFEF6FFF8F2DFFFE3CEAEFFBF9B6DFFAD773BFFB37829FFB9821FFF
+ B57F14FFBE8218FFC08218FFBE8016FFBB7D11FFBA7C10FFBC7F11FFBA7D0FFF
+ B6790BFFBA7E0DFFBA7E0DFFBB7F0DFFBB7F0DFFBC810DFFBC810DFFBC810DFF
+ BC810DFFBB7D0BFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFF
+ BB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFFBE800EFF
+ BE810DFFBC7F09FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBF820CFFBD800AFFBB7E08FFBB7E08FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC7F09FFBD7F0DFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFFBF8010FF
+ C08111FFBA7D0FFFBF8214FFC18416FFBD8012FFBB7E10FFBD8012FFBD8012FF
+ BA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFF432B19FF472F1DFF4D3322FF4F3223FF
+ 4F3021FF4F2C1EFF522E1CFF57301AFF572E15FF592D0EFF5B3009FF603405FF
+ 693D07FF744B0CFF815714FF8D5F18FF9C661FFFA76A1AFFB37112FFB47610FF
+ A97816FFA97814FFB1790AFFB47807FFB87A14FF996A26FF736454FF58617CFF
+ 415A92FF3E5EA9FF4667B6FF4364B3FF4B6EB8FF466BB5FF4168B3FF4066B4FF
+ 4266B2FF4164AEFF3E5EA7FF3B59A0FF3B58A2FF37549EFF324F9AFF314A92FF
+ 32488AFF32427DFF323A6FFF323562FF3B365DFF382F50FF39304AFF463843FF
+ 51392DFF614229FF593216FF5B351DFF4F3021FF492E20FF472E1AFF4A3117FF
+ 533218FF563319FF51301CFF4F2F1CFF50311AFF4E3017FF4D2F16FF4E3017FF
+ 503219FF52341BFF53351CFF53351CFF4D2F16FF4D2F16FF4D2F16FF4E3017FF
+ 4F3118FF503219FF52341BFF52341BFF53381EFF52361EFF523421FF52331EFF
+ 563115FF63390FFF825016FFA0671CFFB5781BFFB87A14FFB87B13FFB87B13FF
+ B87A14FFBA7916FFBB7815FFBB7913FFB7790DFFB77A0CFFB77A0CFFB77A0CFF
+ B77A0CFFB7790DFFB7790DFFB7790FFFB97B11FFB97B11FFB87911FFB87911FF
+ B87911FFB77810FFB77711FFB77711FFB67610FFB77711FFB87911FFB77810FF
+ B6780EFFB6780EFFB97B0FFFBC7E12FFB97B0FFFBA7C12FFB97B11FFB77810FF
+ B67610FFB77613FFBA7916FFBE7E18FFB97B11FFBA7C12FFB97913FFB87714FF
+ BE7B18FFC2801AFFBF7E15FFB8780CFFBD7D11FFB97B0FFFBD7B14FFC1811BFF
+ C1811BFFBB7C14FFB97B0FFFBA7D0FFFBD7F15FFBC7F17FFB9811CFFBB831EFF
+ C0821CFFBF811DFFBB7C20FFAC782CFFB18D5DFFECD9BEFFFBF6EDFFEAECECFF
+ ECEEEEFFE3E5E5FFDCDEDEFFEDEDEDFFF2F0F6FFEFF0F4FFEDF2F0FFECF2EDFF
+ F0EFF1FFF2EEF4FFF5EBF7FFF7EEF1FFFFFEF1FFEDDEBEFFCBAB7AFFB48848FF
+ B87D2EFFB97B1DFFB77F12FFBC8413FFB97E11FFBF8115FFBE8014FFBB7D11FF
+ BA7C10FFBD8012FFBC7F11FFB97D0CFFBB7F0EFFBB7F0EFFBA7E0CFFBA7E0CFF
+ BA7F0BFFBA7F0BFFB97E0AFFB97E0AFFBD7F0DFFBE800EFFBF810FFFC08210FF
+ C08210FFBF810FFFBE800EFFBD7F0DFFBF810FFFC08210FFC08210FFC08210FF
+ BF810FFFBC7E0CFFBA7C0AFFB87B07FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BB7E08FFBB7E08FFBD800AFFBF820CFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBF810FFFBE800EFFBC7E0CFFBB7D0BFF
+ BC7E0CFFBE800EFFC08210FFC28313FFBE8113FFC38618FFC38618FFBE8113FF
+ BB7E10FFBE8113FFC08315FFBE8113FFBA7D0FFFBA7D0FFFBA7D0FFF442810FF
+ 4C2E15FF53341BFF55341AFF523013FF522C0CFF562E0BFF5E340AFF613506FF
+ 6D3F09FF7D4E10FF8E5D17FF9A691DFFA1711FFFA4731DFFA9761AFFB17619FF
+ B87714FFBD7B0BFFBB7C09FFB47B0EFFB37C0DFFBA7D09FFBC7C06FFB67201FF
+ A7711AFF826742FF626066FF4D6190FF4666ADFF4766B1FF4462AFFF4063ADFF
+ 4166B0FF4269B4FF4269B7FF4067B2FF4063ADFF4161AAFF4260A7FF415EA8FF
+ 3D5AA4FF37549FFF334E98FF34498DFF32417FFF323970FF323562FF3C3960FF
+ 332E4BFF352E43FF473A42FF4F3A32FF5C3E2BFF4D2B14FF523019FF4B2E1FFF
+ 472E1EFF47301AFF4C3418FF523516FF533316FF4E2D19FF4A2A17FF54351EFF
+ 51331AFF4E3017FF4E3017FF503219FF52341BFF52341BFF503219FF4F3118FF
+ 4F3118FF4F3118FF4F3118FF503219FF52341BFF54361DFF55371EFF51351DFF
+ 4F331BFF50311AFF523215FF5B340EFF6E420DFF955E19FFB67A26FFB9791AFF
+ BA7A14FFB77913FFB87A14FFB97B17FFBB7A17FFBC7A14FFBC7A11FFB97A0CFF
+ B77B0AFFB77B0AFFB77B0AFFB77A0CFFB77A0CFFB7790DFFB7790DFFB97B11FF
+ B97B11FFB87911FFB87911FFB87911FFB77810FFB77711FFB77711FFB67610FF
+ B77711FFB87911FFB77810FFB6780EFFB6780EFFB97B0FFFBD7F13FFBB7D11FF
+ BB7D11FFBA7C12FFB7790FFFB5760EFFB67610FFB97913FFBD7E16FFBA7D0FFF
+ B87E0DFFB87A10FFB77810FFBC7D15FFC2831BFFBF7F13FFB67709FFBB7C0EFF
+ B8780CFFBA7811FFC17F19FFC3811BFFC07E18FFC07F16FFC58519FFB7790FFF
+ B57B12FFB77C18FFBA7F1CFFBF811DFFBD8020FFB67C2AFFA47838FFD2B894FF
+ F9EFDEFFFCFDFBFFDEE3E6FFE4E8E9FFF1F3F4FFE9EDEEFFF0F2F3FFECEAF0FF
+ ECEBEFFFEEEFEDFFEDF0EEFFEFF0F4FFF3F0F9FFF9F1FCFFFFF5F5FFFEEBD6FF
+ DCC195FFB28845FFA6721FFFBE8022FFC7861DFFBA810EFFB87F0BFFB17504FF
+ B97C0EFFBC7E12FFB87B0DFFB6790BFFB97C0EFFBC800FFFBB7F0EFFBE8211FF
+ BC800FFFBA7E0CFFB87C0AFFB77C08FFB77C08FFB77C08FFB77C08FFBE800EFF
+ BF810FFFC08210FFC18311FFC18311FFC08210FFBF810FFFBE800EFFB87A08FF
+ BA7C0AFFBE800EFFC08210FFC18311FFC08210FFBE800EFFBC7E0CFFBC7F0BFF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBA7D07FF
+ BC7F09FFBD800AFFBC7F09FFBA7D07FFBA7D07FFBE810BFFC1840EFFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F0BFFBC7F0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFC08210FF
+ BE800EFFBD7F0DFFBC7E0CFFBC7E0CFFBE800EFFC18311FFC38513FFBA7E0DFF
+ BF8214FFBE8113FFB87B0DFFB5780AFFB87B0DFFBB7E10FFBB7E10FFBA7D0FFF
+ BA7D0FFFBA7D0FFF542E0BFF542F09FF573107FF5C3606FF654008FF714A0CFF
+ 7D540FFF855B0EFF996A18FF9E6E16FFA47415FFAA7717FFAD7817FFAE7714FF
+ AE7611FFAF750CFFB27507FFB67806FFB97A07FFB87A04FFB67705FFB57705FF
+ B77805FFBD7A05FFBD7702FFB47612FF8F682AFF6A5D4DFF4A5D80FF3A5A9BFF
+ 415EA8FF4E6DB8FF4164ADFF3E63ADFF3B62ADFF3960AEFF3960ABFF3D62ACFF
+ 4465AEFF4767B0FF4766B1FF4160ABFF3553A0FF304B95FF34498DFF364885FF
+ 333D73FF2C315EFF343458FF34314BFF343141FF3F353BFF4B3831FF4E3424FF
+ 4F2F1CFF4E2F1AFF4C301FFF48301CFF493119FF4D3517FF543815FF563716FF
+ 503118FF4C2B17FF4E2F18FF4F3118FF4F3118FF4F3118FF4F3118FF4E3017FF
+ 4D2F16FF4D2F16FF4F3118FF4F3118FF503219FF503219FF51331AFF52341BFF
+ 52341BFF52331CFF4B2C17FF55361FFF583A1FFF57330FFF623908FF835311FF
+ A56D1CFFB8791DFFBB7716FFBB7815FFB97816FFB77816FFB57816FFB77913FF
+ BC7A11FFBC7B0EFFB87909FFB67A08FFB67A08FFB67A08FFB77B0AFFB77B0AFF
+ B77A0CFFB77A0CFFB7790DFFB97B0FFFBB7D13FFBD7F15FFBD7E16FFBB7C14FF
+ B97A12FFB77810FFBC7C16FFBC7C16FFBB7C14FFBB7C14FFBA7C12FFB97B11FF
+ B97B0FFFB97B0FFFBA7D0FFFB97C0EFFB97B0FFFB87A10FFB7790FFFB77810FF
+ B6770FFFB6780EFFBA800FFFB67F0CFFB4790CFFB1750BFFB0740AFFB2760CFF
+ B77A0CFFB97D0CFFB97C0EFFB97B0FFFBA7A14FFBA7916FFBC7916FFBD7A17FF
+ BD7B14FFBB7D13FFC58820FFB67B14FFB97E1AFFB57816FFBA7A1BFFCB8F36FF
+ A7752DFFBF9C6AFFFDEED4FFEFEDE5FFE9ECF0FFE7EBF0FFE7E9EAFFE7E9E9FF
+ E9ECF0FFEDF0F4FFF2F1F5FFFAF8F8FFEEEAE9FFEEECECFFF0EFF8FFEAE9F3FF
+ F5F0F9FFFFFBF5FFDCC09EFFB28A4FFFAB7522FFBF8220FFBE7D14FFB57606FF
+ B87D09FFBD820EFFB67A09FFB77B0AFFB87B0DFFB97D0CFFBB7F0EFFBD8110FF
+ BE8211FFBF8312FFBF8311FFBF8311FFBF8311FFBE8210FFBE8210FFBD810FFF
+ BC810DFFBC810DFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBA7D09FFBA7D09FFBC7F0BFFBD800CFFBD800CFFBC7F0BFF
+ BA7D09FFBA7D09FFBE810DFFBC7F0BFFBA7D09FFBB7E0AFFBE810DFFBF820EFF
+ BD800CFFBB7E0AFFBA7D07FFBB7E08FFBD800AFFBF820CFFBF820CFFBD800AFF
+ BB7E08FFBA7D07FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFB97C08FFBA7D09FFBB7E0AFFBC7F0BFFBC7F0BFFBB7E0AFF
+ BA7D09FFB97C08FFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFF
+ BD800CFFBD800CFFBC7F0BFFBD800CFFBE810DFFBF820EFFBF820EFFBE810DFF
+ BD800CFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBD800CFF
+ BE810DFFBF810FFFBD8110FFBA7D0FFFB77A0CFFB77A0CFFBA7D0FFFBC7F11FF
+ BC7F11FFBA7D0FFFBC7F11FFBC7F11FFB47709FF70430AFF75490EFF7E5213FF
+ 895C18FF94691AFF9D7019FFA27619FFA77914FFA5750BFFAA760BFFAD780AFF
+ B0790AFFB2790CFFB4790CFFB6780CFFB6790BFFB47905FFB67C05FFB57C09FF
+ B87A08FFB97805FFBA7704FFB77707FFBB7908FFBF7903FFBA790DFF9C6B1BFF
+ 79623CFF566477FF45649BFF4061A6FF4265AFFF3B61A9FF3961A9FF3A62ADFF
+ 3B62B0FF3E65B0FF4166B0FF4666B1FF4767B0FF4160ABFF3D5CA7FF33519EFF
+ 2E4894FF2F458CFF334483FF323B74FF2D325FFF363759FF37344DFF373443FF
+ 3F383DFF493631FF4A3024FF4B2D1CFF4D2E19FF4A2F1BFF48301AFF483117FF
+ 4E3515FF533813FF533714FF4F3116FF4C2C15FF503219FF4F3118FF4F3118FF
+ 4E3017FF4E3017FF4E3017FF4E3017FF4E3017FF4E3017FF4F3118FF4F3118FF
+ 4F3118FF503219FF51331AFF51331AFF51321BFF482914FF533119FF573413FF
+ 5B3407FF734809FF986719FFB4781EFFB97816FFBC7815FFBC7815FFB97718FF
+ B77719FFB57816FFB77913FFBC7B0EFFBC7D0BFFB97B09FFB77B09FFB77B0AFF
+ B77B0AFFB77B0AFFB67A09FFB6790BFFB6790BFFB7790DFFB87A0EFFBA7C12FF
+ BC7E14FFBC7D15FFBA7B13FFB87911FFB77810FFB97913FFB97913FFB97913FF
+ B87911FFB87A10FFB7790FFFB7790DFFB6780CFFB87B0DFFB87B0DFFB87A0EFF
+ B87A0EFFB87A10FFB87A10FFB87911FFB67A10FFB87E0DFFB67E0DFFB67D10FF
+ B67C12FFB87B13FFB77B11FFB77C0EFFB77D0CFFBA7D0FFFBA7C10FFBA7A14FF
+ BA7916FFBA7916FFBC7916FFBD7B14FFBB7D13FFB98017FFB37912FFBB801DFF
+ BD8022FFB87A20FFB47C2DFFA57B40FFD8BE99FFFCF5E6FFEBF0EFFFE8ECF1FF
+ E7EBF0FFECECECFFECECECFFE7EBF0FFE6EAEFFFF3F3F3FFFBF7F6FFF3EEEDFF
+ F2EDEEFFEFEEF8FFEEEDF7FFF2EDEFFFF1E1D0FFAF8B5DFFA37027FFAD7010FF
+ C18013FFBE7F0DFFBB7E0AFFBF8410FFBD820EFFB87C0AFFB87C0BFFB97D0CFF
+ BA7E0DFFBB7F0EFFBD8110FFBE8211FFBE8211FFBE8210FFBE8210FFBD810FFF
+ BD810FFFBD810FFFBD810FFFBC810DFFBC810DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7D09FFBB7E0AFFBC7F0BFF
+ BD800CFFBD800CFFBC7F0BFFBB7E0AFFBA7D09FFBF820EFFBD800CFFBB7E0AFF
+ BC7F0BFFBE810DFFBF820EFFBD800CFFBB7E0AFFBA7D07FFBB7E08FFBD800AFF
+ BF820CFFBF820CFFBD800AFFBB7E08FFBA7D07FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBD800CFFBD800CFFBF820EFF
+ BF820EFFBF820EFFBF820EFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFF
+ BD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBC7F0BFFBC7F0BFFBD800CFF
+ BE810DFFBE810DFFBD800CFFBC7F0BFFBC7F0BFFBD800CFFBC7F0BFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBC7F0BFFBD800CFFBE800EFFBD8110FFBB7E10FFB97C0EFF
+ BA7D0FFFBC7F11FFBD8012FFBC7F11FFBB7E10FFBE8113FFBD8012FFB77A0CFF
+ 9F6817FFA26C19FFA8721BFFAB761BFFAE7918FFAE7813FFAC760BFFAA7506FF
+ B37B0AFFB27B08FFB37908FFB47807FFB67709FFB7770BFFB9790DFFB87A0EFF
+ B17B09FFAF7D0DFFAE7C12FFB27910FFB97609FFBA7506FFB6750CFFB7770BFF
+ BE7B08FFBB7B0BFFA7700FFF84672AFF64696AFF506E97FF4167A7FF365FA8FF
+ 365EA6FF3860A8FF3A62ADFF3C66B1FF4169B4FF436AB4FF4669B3FF4768B1FF
+ 3E5DA8FF3D5CA7FF3755A2FF324C98FF31478FFF334385FF343C77FF313565FF
+ 36385BFF37374FFF3B3945FF413A3DFF463532FF462D23FF4A2C1BFF4E2F1AFF
+ 492E19FF492F17FF4A3117FF4E3515FF533911FF523712FF4F3116FF4C2D16FF
+ 52341BFF51331AFF4F3118FF4D2F16FF4D2F16FF4D2F16FF4E3017FF4F3118FF
+ 4E3017FF4E3017FF4E3017FF4E3017FF4F3118FF4F3118FF4F3118FF4F3118FF
+ 4B2B14FF523013FF593309FF663E04FF895B0EFFAE791FFFBB7F1BFFB5730CFF
+ BC7813FFBB7716FFB97619FFB77719FFB77816FFB97A12FFBB7C0CFFBC7D0AFF
+ BB7C0CFFB97D0CFFB87B0DFFB77A0CFFB77A0CFFB6790BFFB5770BFFB5770BFF
+ B6780CFFB7790DFFB97B11FFBA7C12FFBA7C12FFB97B11FFB7790FFFB6770FFF
+ B67610FFB67610FFB67610FFB6770FFFB5770DFFB5770DFFB5770BFFB5780AFF
+ B6790BFFB6790BFFB77A0CFFB87B0DFFB97B0FFFBA7C10FFBA7C12FFB87C12FF
+ B57A0DFFB67D10FFBB8118FFBE831CFFBE831CFFBB8118FFB77E11FFB57D0EFF
+ B97E10FFB97E11FFB87B13FFB87A14FFB87A14FFBA7A14FFBA7C12FFB87D10FF
+ B27B12FFAF7914FFBA7E1EFFC1852BFFB17928FFA47432FFB59467FFF6E5CBFF
+ F9F6F1FFE9EFF4FFE6EAEFFFE8EBEFFFEFEFEFFFF1F1F1FFE9EDF2FFE5EAEDFF
+ EEEFEDFFF4F1EDFFF7EFEFFFF7F0F3FFF5F2FBFFFFFDFFFFFEF4EDFFE1CCADFF
+ AB7F42FFB67B25FFC8841BFFD08B16FFC1820FFFBE830FFFC08511FFB57C09FF
+ BA7E0CFFBA7E0CFFBB7F0DFFBB7F0DFFBC800EFFBC800EFFBD810FFFBD810FFF
+ BB7F0DFFBB7F0DFFBB7F0DFFBC800EFFBC800EFFBC800EFFBC800EFFBC800EFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7F0BFFBC7F0BFFBD800CFFBE810DFFBE810DFFBD800CFFBC7F0BFFBC7F0BFF
+ BF820EFFBE810DFFBD800CFFBD800CFFBF820EFFBF820EFFBE810DFFBD800CFF
+ BA7D07FFBB7E08FFBD800AFFBE810BFFBE810BFFBD800AFFBB7E08FFBA7D07FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BD800CFFBE810DFFBE810DFFBF820EFFBF820EFFBE810DFFBE810DFFBD800CFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BB7E08FFBC7F09FFBD800AFFBD800AFFBD800AFFBD800AFFBC7F09FFBB7E08FF
+ BE810BFFBD800AFFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBC7F09FFBD800CFF
+ BD8110FFBC7F11FFBB7E10FFBC7F11FFBD8012FFBD8012FFBC7F11FFBA7D0FFF
+ BF8214FFBE8113FFBA7D0FFFB17511FFB0750EFFAF750CFFAF7309FFAF7309FF
+ AF7407FFB27507FFB27605FFB87C0BFFB97A0AFFB87909FFB8790BFFB8770BFF
+ B9780CFFB9770EFFB5790FFFAF7B10FFAB7D12FFAC7B17FFAF7914FFB8770BFF
+ B87409FFB4750DFFB5760EFFB97706FFBB7C0AFFB07508FF916A1CFF6F6A55FF
+ 5C7389FF476EA5FF3562ABFF3963AAFF3A64ABFF3C65AEFF3D67B2FF426AB5FF
+ 436AB4FF4669B3FF4667B0FF4160ABFF4361AEFF3F5DACFF3753A0FF344B96FF
+ 354689FF353F7BFF353A6BFF35365CFF383751FF3C3A46FF423C3DFF463532FF
+ 462D23FF492D1CFF51321DFF4C3018FF4D3218FF51331AFF533719FF543A12FF
+ 543914FF513419FF4F3019FF54361DFF52341BFF4F3118FF4D2F16FF4C2E15FF
+ 4D2F16FF4F3118FF503219FF4D2F16FF4D2F16FF4D2F16FF4D2F16FF4D2F16FF
+ 4E3017FF4E3017FF4F3017FF523117FF583311FF643B0AFF7C4F0CFF9F6C16FF
+ B77E1BFFB97C14FFB27108FFBB7913FFBB7716FFB77719FFB77719FFB77915FF
+ B97B11FFBB7D0BFFBB7D0BFFBA7D0FFFBA7C10FFB97B0FFFB87A0EFFB7790DFF
+ B6780CFFB5770BFFB5770BFFB5770BFFB6780CFFB7790FFFB87A10FFB87A10FF
+ B7790FFFB6780EFFB5760EFFB67610FFB67512FFB67610FFB6770FFFB6770FFF
+ B5770BFFB5770BFFB5780AFFB87B0DFFB87B0DFFB87B0DFFB97C0EFFB97B0FFF
+ B97B0FFFBA7C12FFBA7C12FFB4790CFFB67C12FFBD7F19FFBF831FFFC28420FF
+ BD821BFFBA7F12FFB77C0EFFB97E10FFB97E11FFB97C14FFB87A14FFB87A14FF
+ B87C12FFBA7C10FFB67E0FFFB57F14FFB07C17FFB57D1EFFB7802BFFA97630FF
+ AF8752FFD6BF9FFFFCF3E5FFEDEFEFFFE5EBF0FFE5E9EEFFE7EAEEFFEEEDEFFF
+ F1F0F2FFEBF0F3FFEAEFF2FFE9EAE8FFECE9E5FFF3EDEEFFF5EEF1FFF8F1F8FF
+ FFFEFEFFFFF0DDFFD0B387FFAF7E34FFBE7F1DFFC98415FFC9840FFFBB7C0AFF
+ BC800FFFBE8512FFB67D0AFFBC800EFFBC800EFFBC800EFFBC800EFFBC800EFF
+ BC800EFFBC800EFFBC800EFFB97D0BFFB97D0BFFBA7E0CFFBA7E0CFFBB7F0DFF
+ BC800EFFBC800EFFBC800EFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBE800EFFBE800EFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD800CFFBD800CFFBE810DFFBE810DFFBE810DFF
+ BE810DFFBD800CFFBD800CFFBF820EFFBF820EFFBE810DFFBE810DFFBF820EFF
+ BF820EFFBF820EFFBE810DFFBB7E08FFBC7F09FFBD800AFFBE810BFFBE810BFF
+ BD800AFFBC7F09FFBB7E08FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBA7D09FFBA7D09FFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBA7D09FFBA7D09FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFF
+ BC7F09FFBC7F0BFFBC7F09FFBF820EFFBE810BFFBD800CFFBB7E08FFBB7E0AFF
+ BB7E08FFBB7E0AFFBC7F0BFFBB7F0EFFBB7E10FFBC7F11FFBD8012FFBD8012FF
+ BC7F11FFBA7D0FFFB87B0DFFBD8012FFBD8012FFBB7E10FFB77806FFB57604FF
+ B37303FFB37303FFB47307FFB8770BFFBB7A11FFBE7C15FFB8760FFFB8760FFF
+ B97710FFB97710FFB97710FFB9780FFFB8770EFFB3770DFFAB7B12FFA97C15FF
+ AD7B17FFB17914FFB7770BFFB67509FFB2750DFFB3760EFFB27305FFB87909FF
+ B87808FF9F6D13FF7E673AFF6B7071FF5074A2FF3D6EB4FF426CB1FF406AB1FF
+ 3E67B0FF3C66B1FF4068B3FF4168B2FF4265AFFF4162ABFF4060ABFF4363AFFF
+ 4160AFFF3A56A3FF354C97FF354689FF343E7AFF34386BFF31335CFF343452FF
+ 3A3A46FF433C3FFF463735FF473028FF4C301FFF543520FF503019FF52331AFF
+ 55351EFF56381DFF563B16FF563B16FF53361BFF53341DFF55371EFF53351CFF
+ 503219FF4D2F16FF4C2E15FF4D2F16FF4F3118FF503219FF4D2F16FF4D2F16FF
+ 4D2F16FF4D2F16FF4D2F16FF4D2F16FF4D2F16FF4E3015FF553413FF5D370DFF
+ 75490EFF946317FFAE781AFFB67B14FFBA7A0EFFBA7A0EFFB97A12FFB77915FF
+ B77816FFB77816FFB77913FFB97B0FFFBB7C0CFFBB7C0CFFBB7D11FFBA7C12FF
+ BA7C12FFB97B11FFB7790FFFB6780EFFB6780EFFB5770DFFB6780EFFB6780EFF
+ B7790DFFB7790DFFB7790DFFB7790DFFB6780CFFB6780EFFB77711FFB77613FF
+ B77711FFB87911FFB87911FFB87A0EFFB87A0EFFB87B0DFFBA7E0DFFBA7E0DFF
+ BA7E0DFFB97D0CFFB97C0EFFB97C0EFFB87A0EFFB87A0EFFB7790DFFB77B11FF
+ BC7C16FFBD7F1BFFBF7F19FFBC7F17FFBC7E12FFBA7D0FFFBA7E0DFFBA7D0FFF
+ BA7C12FFBA7B13FFBA7B13FFBA7C10FFBA7D0FFFB67E0DFFB68113FFB6831BFF
+ B88426FFAE7A2DFFA57A41FFCAAB84FFF8E9D6FFF5F2EAFFE7E9E9FFE6EBEEFF
+ E8EBEFFFE9EAEEFFE8E9EDFFE8EAEBFFEAEEEFFFEFF1F1FFECEDEBFFE9E7E6FF
+ F1ECEEFFF2EBEEFFF4EBEEFFFFF3EAFFECD3B3FFBC975DFFB6842CFFBC8114FF
+ C27E0DFFC27E0DFFBD7D11FFBD8215FFBF8716FFBB8411FFBA810DFFBC810DFF
+ BC810DFFBB800CFFBB800CFFBB800CFFBB800CFFBA7F0BFFB97D0BFFB97D0BFF
+ B97D0BFFBA7E0CFFBA7E0CFFBB7F0DFFBB7F0DFFBC800EFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE800EFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFFBF810FFF
+ BF810FFFBF810FFFBE800EFFBE800EFFBF810FFFBF820EFFBB7E08FFBC7F09FF
+ BD800AFFBD800AFFBD800AFFBD800AFFBC7F09FFBB7E08FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E0AFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBD800CFF
+ BC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBD7F0DFFBD800CFFBF810FFFBE810DFF
+ BD7F0DFFBB7E0AFFBB7D0BFFBB7E0AFFBB7D0BFFBC7E0CFFB97D0CFFBA7D0FFF
+ BC7F11FFBC7F11FFBB7E10FFB97C0EFFB87B0DFFB77A0CFFBA7D0FFFBA7D0FFF
+ BC7F11FFBC7C06FFBC7C06FFBB7A07FFB87907FFBA770AFFB7760AFFB6740BFF
+ B5720BFFB7740DFFB8750EFFB8760FFFB97710FFB9780FFFB9790DFFB8790BFF
+ B3780BFFAB790FFFAB7B12FFB27B12FFB37A0DFFB47709FFB37608FFB2760CFF
+ B1770DFFAD7107FFB67709FFBE7A09FFAC710EFF8E6625FF786D59FF577499FF
+ 4474B6FF4973B8FF456FB6FF3E69B2FF3C66B1FF3E66B1FF3E65AFFF3D60AAFF
+ 3B5CA5FF3B5BA7FF3F5EADFF3D5BACFF3853A3FF344B96FF344489FF323C78FF
+ 2E3469FF303360FF343353FF393947FF433C3FFF483839FF49312BFF4E3122FF
+ 563521FF512F18FF56311BFF5A3521FF59371FFF573B18FF563A17FF54371CFF
+ 55361FFF55371EFF54361DFF51331AFF4F3118FF4E3017FF4E3017FF4E3017FF
+ 4F3118FF4E3017FF4E3017FF4E3017FF4D2F16FF4D2F16FF4D2F16FF4C2E15FF
+ 4D2F12FF54330CFF663E0DFF855815FFA6721FFFB87C1CFFB87A10FFBB7B0FFF
+ C28216FFB77A12FFB57A13FFB57915FFB57A13FFB97B11FFB97B0FFFBB7C0CFF
+ BB7C0EFFBA7C12FFBA7B13FFB97913FFB97A12FFB87911FFB7790FFFB7790FFF
+ B7790FFFB6780EFFB6780EFFB7790DFFB7790DFFB7790DFFB7790DFFB6780CFF
+ B6780EFFB87812FFB87714FFB87812FFB97A12FFB97A12FFBA7C10FFBA7C10FF
+ BA7D0FFFBC800FFFBC800FFFBB7F0EFFBA7E0DFFB97C0EFFB87B0DFFB87A0EFF
+ B87A0EFFBB7C0EFFBB7B0FFFBB7912FFBC7A14FFBC7A13FFBC7B12FFBC7D0FFF
+ BA7E0DFFBB7C0CFFB97C0EFFB97B11FFBA7B13FFBB7D13FFBB7D11FFBC800FFF
+ BA800FFFB37E0FFFB7841CFFBE8A30FFAD7F38FFB99567FFE4CDB3FFFFFBF1FF
+ F1EFEEFFE9EBEBFFEAEEEFFFEEEFF3FFEAEBEFFFE5E5EBFFE4E5E9FFE9E9E9FF
+ EDEEECFFF2F0EFFFECEDEBFFF1F0F2FFF6F1F3FFFDF0EEFFF8E1D1FFD7B58AFF
+ BB914AFFBD8B27FFC08714FFC18210FFC58215FFC3811BFFBE801AFFB88011FF
+ B47F0AFFB87F0BFFBA7F0BFFBA7F0BFFBA7F0BFFBA7F0BFFBA7F0BFFBA7F0BFF
+ BA7F0BFFBA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBB7F0DFFBB7F0DFF
+ BB7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBE800EFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BE800EFFBD7F0DFFBE800EFFBF810FFFBF810FFFBD7F0DFFBD7F0DFFBE800EFF
+ BF820EFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBF810FFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBE800EFFBE800EFF
+ BF810FFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBF8010FFBE7F0FFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBE7F0FFF
+ BF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFF
+ BD7E0EFFBA7D0FFFBC7F11FFBD8012FFBC7F11FFBA7D0FFFB87B0DFFB87B0DFF
+ B87B0DFFB87B0DFFB97C0EFFBD8012FFB37402FFB47503FFB67705FFB67707FF
+ B77707FFB57608FFB37406FFB27305FFB67709FFB67709FFB67606FFB77707FF
+ B77806FFB87906FFBA7B08FFB87C0AFFAD780AFFB17A0BFFB97C06FFB97C04FF
+ B47905FFB17805FFB27709FFB2790CFFAE740BFFB17309FFBF7809FFBA750EFF
+ A46919FF896C47FF5E708DFF446FAEFF4B75B8FF4670B7FF406BB4FF3E68B3FF
+ 4068B3FF3D64AEFF395CA6FF34559EFF3757A3FF3A59A8FF3A58A9FF3752A2FF
+ 364D98FF38488DFF353E7DFF30356CFF343567FF343458FF393848FF433C41FF
+ 4B383BFF4D322EFF503122FF55321EFF502B15FF562F19FF5A3220FF59341EFF
+ 563716FF533715FF53351CFF523520FF55361FFF54361DFF53351CFF51331AFF
+ 4F3118FF4E3017FF4D2F16FF4D2F16FF4F3118FF4F3118FF4E3017FF4E3017FF
+ 4D2F16FF4D2F16FF4C2E15FF4F3011FF58360BFF734D13FF97671FFFAF7620FF
+ B97B17FFBC7B0FFFBD7D11FFBD7F13FFB57B12FFB57B12FFB57B12FFB57B11FF
+ B97B0FFFB97C0EFFB97C0EFFB97B0FFFB97A12FFB97913FFB97815FFB97913FF
+ B97913FFB87911FFB87911FFB87911FFB7790FFFB7790FFFB7790DFFB7790DFF
+ B77A0CFFB77A0CFFB77A0CFFB7790DFFB77711FFB77613FFB87812FFB87911FF
+ B97A12FFB97B0FFFBA7C10FFBA7D0FFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFF
+ BA7E0DFFBA7E0DFFBA7D0FFFBC7D0FFFBD7D0DFFBD7D0DFFBC7B0FFFBB7910FF
+ BB7910FFBB7A0EFFBC7C0CFFBB7D0BFFBA7B09FFB97A0AFFBA7910FFBC7A13FF
+ BD7B14FFBE7D14FFBF8012FFBC8211FFB47E0CFFB17E16FFB6842CFFB58B4AFF
+ E3C6A1FFFDEBDAFFF8F3F0FFF1F3F4FFEFEFEFFFEFEFEFFFEEEDEFFFEAEAF0FF
+ E6E8F0FFE6E9EEFFEDECE8FFF0EDE8FFF1EFEEFFECEEEEFFEDF1F2FFF8F6F6FF
+ FFF4EEFFE7C8B1FFBB915CFFBB8A3AFFAD7C10FFB47F0AFFB77D0CFFB97A12FF
+ BD791AFFBA7917FFB17A0BFFAE7904FFB67D09FFB87E07FFB97F08FFB97F08FF
+ B97E0AFFB97E0AFFB97E0AFFB97E0AFFBC810DFFBB800CFFBB7F0DFFBB7F0DFF
+ BB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBB7D0BFFBD7F0DFFBF810FFFBE800EFF
+ BC7E0CFFBB7D0BFFBD7F0DFFBF820EFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBF810FFFBF810FFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBF810FFFBF810FFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7E0EFFC08113FFC08113FFBE7F11FFBE7F11FF
+ BE7F11FFBE7F11FFC08113FFC08113FFBD7E10FFBC7D0FFFBB7C0EFFBB7C0EFF
+ BB7C0EFFBC7D0FFFBD7E10FFBE7F11FFBE8113FFC08315FFC08315FFBE8113FF
+ BA7D0FFFB97C0EFFBA7D0FFFBC7F11FFB97C0EFFBA7D0FFFC08315FFB57608FF
+ B47507FFB47507FFB47507FFB47507FFB47507FFB57608FFB57606FFB77808FF
+ B57705FFB37503FFB27402FFB47502FFB67905FFBB7D07FFBA7F0BFFAE7605FF
+ B27906FFB97D02FFBA7C00FFB17902FFAF7805FFB07807FFB2790CFFB2780FFF
+ B07208FFBC7708FFBE770FFFAE6E16FF956D39FF6D7078FF506D9AFF4F73B3FF
+ 456EB7FF3E6BB4FF406CB3FF436BB3FF3F66ABFF375AA3FF2E519BFF3757A3FF
+ 3A5AA6FF3B59A8FF3954A4FF3A519FFF3A4D98FF364486FF323A75FF35386FFF
+ 333460FF38364CFF423A44FF4A393CFF4D332DFF4E301FFF523019FF4F2812FF
+ 532C16FF56301EFF55321EFF523417FF4E3515FF4C3319FF50341CFF55351EFF
+ 55361DFF53351CFF52341BFF50311AFF4F3019FF4D2F16FF4D2E15FF513318FF
+ 513318FF4F3118FF4F3019FF4E2F18FF4E2F16FF4E3013FF53320BFF653E07FF
+ 8B5D16FFA97522FFB3781BFFB77711FFBD7C10FFBC7C10FFB4760CFFB77B11FF
+ B57B11FFB57B11FFB77C0FFFB97C0EFFB97C0EFFB97B0FFFB97B11FFB97A12FF
+ B97913FFB97913FFB97913FFB97A12FFB97B11FFB97B11FFB97B11FFB87A0EFF
+ B87A0EFFB87A0EFFB77A0CFFB77A0CFFB87B0DFFB87B0DFFB87A0EFFB6770FFF
+ B67610FFB6770FFFB77810FFB87A10FFB87A0EFFB97C0EFFB97C0EFFB87C0BFF
+ B97D0CFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBC7F11FFBE7F0FFFBE7F0CFF
+ BE7F0CFFBC7D0FFFBB7B0FFFBB7B0FFFBA7A0EFFBB7A0DFFBB7B0BFFB97909FF
+ B9780BFFBA7A0EFFB97B11FFBB7C14FFBD7F15FFBE8014FFBD8215FFB77D13FF
+ A97314FFA1742AFFB3905EFFFFEDD4FFFFFDF5FFE8E6E6FFF4F6F7FFF0F0F0FF
+ EEECECFFE9E8EAFFE9E9EFFFEBEDF5FFF0F1F5FFF3F2EEFFF1F1EBFFEAEDEBFF
+ E8EDECFFEAECECFFFAF1EDFFFFECDCFFD1AC86FF996A26FFA97618FFB08010FF
+ BC8A14FFBF8819FFBC7E18FFBC7A1BFFBC7D1BFFB68015FFB5810FFFB57C09FF
+ B77C08FFB77C08FFB87D09FFB87D09FFB97E0AFFB97D0BFFB97E0AFFBD810FFF
+ BD810FFFBC800EFFBC800EFFBB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFFBE800EFF
+ BE810DFFBD7F0DFFBD800CFFBC7E0CFFBB7E0AFFBB7D0BFFBB7E0AFFBC7E0CFF
+ BC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBD7F0DFF
+ BC7F0BFFBA7C0AFFBA7D09FFBA7C0AFFBA7D09FFBC7E0CFFBD800CFFBB7D0BFF
+ BD800CFFBF810FFFBE810DFFBB7D0BFFBA7D09FFBC7E0CFFBE810DFFBD800CFF
+ BC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBD800AFFBC7F0BFF
+ BC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F0BFFBC7E0CFF
+ BB7D0BFFBA7C0AFFB97B09FFB97B09FFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7E0EFFC18214FF
+ C18214FFBF8012FFBE7F11FFBE7F11FFBF8012FFC18214FFC18214FFBC7D0FFF
+ BB7C0EFFBB7C0EFFBB7C0EFFBB7C0EFFBD7E10FFBE7F11FFBF8012FFC28517FF
+ C38716FFC28517FFBF8312FFBC7F11FFBB7F0EFFBD8012FFC08413FFBB7E10FF
+ BB7F0EFFC38618FFB4760CFFB4760CFFB4760CFFB4760CFFB4760AFFB4760AFF
+ B4760AFFB4760AFFB6780CFFB47709FFB27507FFB37706FFB77808FFB67A09FF
+ B67707FFB27605FFB67C0BFFB47B08FFB47B02FFB27900FFAE7803FFAD7907FF
+ AF7A0CFFB37B10FFB67B0EFFB97A0CFFB87605FFB7790FFFB07A23FF956E30FF
+ 7A694EFF6D7380FF506DA6FF3D67B4FF3A6BB1FF4472B2FF4E75B3FF486DABFF
+ 395CA5FF2D519DFF30529EFF3B5AA5FF3E57A1FF4259A7FF3851A7FF2A4498FF
+ 2E448BFF2A3B7AFF313B77FF313568FF343557FF3F394AFF483A3BFF4B3529FF
+ 4F331BFF55341AFF583319FF543018FF502D19FF4E2F1AFF4D331BFF4C351BFF
+ 493418FF4A3117FF56341CFF58341CFF54351CFF52341BFF4F321DFF4E311CFF
+ 4F2F18FF502E16FF583619FF4D2D10FF4B2C13FF553420FF563521FF512F17FF
+ 54320EFF653F09FF966517FFAC7316FFB67A1AFFB57713FFB4750DFFBA7910FF
+ BC7E14FFBB7D13FFB7790FFFB67B0EFFB67B0EFFB97C0EFFB97C0EFFBA7D0FFF
+ BA7D0FFFBB7D11FFB7790FFFB77810FFB7790FFFB7790FFFB6780CFFB6790BFF
+ B6790BFFB67A09FFB47807FFB67A09FFB77B0AFFB6790BFFB47709FFB37509FF
+ B4760AFFB6780CFFB7790DFFB87A0EFFB87A0EFFB97B0FFFB97B0FFFBA7D0FFF
+ BA7D0FFFBB7E10FFB87B0DFFB87B0DFFB87B0DFFB77A0CFFB77A0CFFB87B0DFF
+ B87B0DFFB87C0BFFBB7E0AFFB77D06FFB27A09FFB37C0DFFB57F14FFB98116FF
+ BD7F15FFBE7D11FFBC780DFFC18013FFBC7C10FFB4790CFFB87E14FFB98116FF
+ B47A11FFB1760FFFC08021FFA97021FFA9824EFFECD4B8FFFFFBF3FFF4EFF0FF
+ F8F5F7FFF4F3F5FFEBEAECFFE9E8EAFFE8E7EBFFEAE9EDFFF0EDEFFFF3F1F1FF
+ F3F1F0FFEEF1EFFFEAF5F2FFE7EEEBFFF8F1EEFFFFF8ECFFEEC9A7FFB5894CFF
+ B08028FFB8871BFFAE7D09FFB4810DFFBA8215FFBA8017FFB77C15FFB57D18FF
+ B9821FFFC08B23FFC18618FFC18311FFBD7F0DFFBD7F0DFFBF810FFFC08210FF
+ BD7E0EFFBA7C0AFFC38414FFC08111FFBD7E0EFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BC7D0DFFBA7C0AFFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FF
+ BC7F0BFFBC7F09FFBA7D09FFBA7D07FFB97C08FFB97C06FFBA7D09FFBB7E08FF
+ BD800CFFBE810BFFBE810DFFBE810BFFBD800CFFBC7F09FFBA7D09FFB97C06FF
+ B87B07FFB87B05FFBC7F0BFFBB7E08FFBB7E0AFFBB7E08FFBB7E0AFFBD800AFF
+ BE810DFFBF820EFFBA7D09FFBC7F0BFFBE800EFFBE810DFFBC7E0CFFBC7F0BFF
+ BF810FFFC18410FFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFF
+ BC7E0CFFBC7E0CFFBF810FFFBF810FFFBE800EFFBE800EFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBA7C0AFFBC7E0CFFBD7F0DFFBC7E0CFFB97B09FFB97B09FF
+ BB7D0BFFBE800EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFC08111FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBC7D0DFFB87A08FFB97A0AFFBE800EFFBD7E0EFFB77907FF
+ B67707FFB97B09FFBD7E0EFFBD7F0DFFBD7E0EFFB4750DFFB4750DFFB4750DFF
+ B4750DFFB4760CFFB4760CFFB4760CFFB4760CFFB5770BFFB4760AFFB37608FF
+ B37608FFB5780AFFB5780AFFB47709FFB37608FFB77A0CFFB67A09FFB27905FF
+ AF7A02FFAE7805FFAD7809FFAF790EFFB27A0FFFB97C0EFFBA7B09FFB57603FF
+ B3780AFFAB781AFF966E23FF896A35FF7A7164FF5E72A1FF476EB8FF4371B8FF
+ 4575B5FF4F77B2FF4E73B1FF4167AFFF365CAAFF3054A0FF3959A4FF3B549CFF
+ 3E55A3FF3250A9FF2A489FFF314E98FF324A8CFF334385FF323B74FF333760FF
+ 3B394FFF453A3CFF4A3728FF4D331BFF543417FF563417FF553119FF502F1BFF
+ 4D2F1CFF4C311CFF49331AFF483317FF4A3216FF57331BFF5A341CFF56341CFF
+ 52341BFF4F321DFF50311CFF512F18FF522E16FF593418FF523013FF512F17FF
+ 54331FFF55331CFF553014FF5E3B10FF774C0DFFA77015FFB77810FFBA7B13FF
+ B87911FFB6780EFFB7790FFFB97B11FFBA7C12FFB87A0EFFB87A0EFFB87B0DFF
+ B97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB6780EFFB6780EFFB6780CFF
+ B6790BFFB77A0CFFB77B0AFFB77B09FFB77B09FFB67A08FFB87C0AFFB97D0CFF
+ B87C0BFFB6780CFFB5770BFFB7790FFFB87A0EFFB87A0EFFB87B0DFFB97C0EFF
+ B97C0EFFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFFB87B0DFFB87B0DFFB97C0EFF
+ B97C0EFFB97C0EFFB97C0EFFB87B0DFFB87C0BFFBB7E0AFFB87E07FFB37D0AFF
+ B27E0CFFB27F11FFB57F14FFBA7D15FFBD7B14FFBF7D14FFC28115FFBF8115FF
+ B98013FFBA8217FFBA8217FFB87F16FFBB7F1FFFBD7D29FFAD7736FFCAAA87FF
+ F6E7D7FFFAF5F4FFF0F0F6FFF1F0F2FFF2EFF1FFECEBEDFFEBEAEEFFEBEAEEFF
+ EFECEEFFF6F1F0FFF7F2F1FFF4F2F2FFEEF0F0FFE3EEECFFF5F9F3FFFFF3EAFF
+ FFE2C9FFDFB481FFB78638FFAF7E18FFB4810DFFB47E0BFFB6800DFFB98112FF
+ B87F12FFB47C11FFB27B12FFB47D1AFFBA811EFFBB8013FFC08111FFC18212FF
+ C08111FFBE7F0FFFBD7E0EFFBD7E0EFFBD7E0EFFC38414FFC08111FFBD7E0EFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBD7E0EFFBB7D0BFFBC7F0BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBD800AFFBD800AFFBC7F09FF
+ BB7E08FFBC7F09FFBC7F09FFBE810BFFBE810BFFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBE810BFFBD800AFFBC7F09FF
+ BB7E08FFBB7E08FFBC7F09FFBC7F09FFBD800AFFBE800EFFC08210FFC18311FF
+ BF810FFFBC7E0CFFB97B09FFB97B09FFBA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE800EFFBE800EFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBF810FFFBD7F0DFFBA7C0AFFBB7D0BFF
+ BF810FFFBF810FFFBB7D0BFFB97B09FFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFF
+ B4750DFFB4750DFFB4750DFFB4750DFFB4760CFFB4760CFFB4760CFFB4760CFF
+ B37509FFB4760AFFB5780AFFB5780AFFB37608FFB37608FFB47709FFB5780AFF
+ B4790CFFB3780AFFB37A07FFB17A07FFB0790AFFB0780BFFB0770EFFB2780FFF
+ BB7B0FFFBB7908FFB97700FFB67905FFAF780FFF9C6F14FF8E6B22FF7C6D4DFF
+ 677292FF5272B3FF4975BCFF4273B9FF4772B5FF4A74B7FF456EB7FF3D64B2FF
+ 3057A5FF365AA6FF3B58A3FF3E5CABFF3A5BB1FF3559ADFF3D5DA8FF3F5CA1FF
+ 3C5299FF374685FF343C6BFF363955FF403A3FFF45362DFF4B341EFF4F3217FF
+ 543319FF56321AFF53321EFF50301DFF4D301BFF492F17FF483117FF4C3116FF
+ 57331BFF59331BFF55331BFF52341BFF51321BFF50311CFF512F18FF522E16FF
+ 563417FF563417FF55331BFF56341CFF563117FF5A3411FF704716FF8E5F1BFF
+ B37A1DFFB97A12FFB87911FFB97A12FFB87A10FFB6780EFFB6780EFFB87A10FF
+ B97B0FFFB97B0FFFB97C0EFFB97C0EFFB87B0DFFB87B0DFFB87B0DFFB87B0DFF
+ B5770DFFB5770DFFB5770BFFB6790BFFB77A0CFFB87C0BFFB87C0AFFB87C0AFF
+ B77B09FFB97D0BFFBA7E0DFFB97D0CFFB87A0EFFB87A0EFFB97B11FFBA7C10FF
+ BA7C10FFBA7D0FFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB87B0DFFB87B0DFF
+ B87B0DFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBA7D0FFFB97C0EFFB87C0BFF
+ BA7D09FFB97E0AFFB87F0BFFB67F0CFFB47E0CFFB57C0FFFB87C12FFBB7C14FF
+ BA7B13FFB77810FFB87E14FFB77F14FFB47C11FFB57D12FFB77D14FFB97F20FF
+ AD7429FFB58751FFF3D8BDFFFFF9EFFFEFEDEDFFF0F3F8FFEFEEF2FFEEEDEFFF
+ EEEDEFFFEEEDEFFFF1EEF0FFF3F1F1FFF8F3F2FFF8F3F2FFF3F1F1FFEFEFEFFF
+ F1F3F3FFFFFFF9FFF6E4CDFFD1B186FFBA904BFFAF7B21FFB17A11FFB8810EFF
+ BA810EFFB97F0EFFBA7E0DFFB97C0EFFB67B0DFFB37B0EFFB17A12FFB47A13FF
+ B87A0EFFBF8010FFC38414FFC28313FFBE7F0FFFBB7C0CFFBC7D0DFFBF8010FF
+ C38414FFC18212FFBE7F0FFFBD7E0EFFBE7F0FFFBF8010FFBE7F0FFFBC7E0CFF
+ BC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ C0830DFFBF820CFFBE810BFFBD800AFFBD800AFFBD800AFFBE810BFFBE810BFF
+ B87B05FFB97C06FFB97C06FFBA7D07FFBC7F09FFBD800AFFBD800AFFBE810BFF
+ C0830DFFBF820CFFBD800AFFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ B87A08FFBB7D0BFFBD7F0DFFBE800EFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBF810FFFBE800EFFBC7E0CFFBA7C0AFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBE800EFFBF810FFFC08210FF
+ BE800EFFBC7E0CFFBD7F0DFFC08210FFC18311FFBE800EFFBD7F0DFFBF810FFF
+ BD7F0DFFBD7F0DFFBD7F0DFFB4750DFFB4750DFFB4750DFFB4750DFFB4760CFF
+ B4760CFFB4760CFFB4760CFFB27408FFB4760AFFB6790BFFB5780AFFB37608FF
+ B27507FFB47709FFB6790BFFB3780BFFB3780BFFB37908FFB47A09FFB27A0BFF
+ B0780DFFB1760FFFB3750FFFBC7A11FFBC7708FFBC7801FFBA7B03FFB37908FF
+ A6730BFF9A7017FF866D3BFF686874FF596EA2FF4E73B7FF3E6CB9FF3E6BB5FF
+ 4370BAFF426FB9FF3C66B3FF335DAAFF395FADFF4163AFFF4869B8FF466BBFFF
+ 436BBEFF436AB4FF4566AFFF4360ABFF3D5296FF354377FF333B59FF3B3742FF
+ 423630FF473321FF4D3119FF513219FF55331CFF56331FFF52311DFF4E2F1AFF
+ 4A2E16FF493016FF4D3218FF56311BFF59331BFF55341AFF53351AFF53331CFF
+ 51311AFF523019FF532E18FF563319FF57361CFF59371FFF57341AFF583210FF
+ 673C11FF85571DFFA37125FFBA8021FFB97A12FFB5760EFFB97A12FFBA7C12FF
+ B6780EFFB5770DFFB97B11FFBA7C10FFB97B0FFFB97C0EFFB87B0DFFB87B0DFF
+ B77A0CFFB77A0CFFB6790BFFB4760AFFB4760CFFB5770BFFB6790BFFB77A0CFF
+ B87C0BFFB97D0BFFB97D0BFFB77B09FFB87C0AFFB87C0BFFB97D0CFFB87A0EFF
+ B97B0FFFB97B11FFBA7C10FFBB7E10FFBA7D0FFFBA7D0FFFB97C0EFFB97C0EFF
+ B87B0DFFB87B0DFFB77A0CFFB77A0CFFB97C0EFFBB7E10FFBD8012FFBD8012FF
+ BB7E10FFB97C0EFFB77B0AFFBA7C0AFFBC7F0BFFBC820BFFB9810AFFB67D09FF
+ B57B0AFFB67A10FFB97C14FFB47912FFAE730CFFB67C13FFB37B10FFB1790EFF
+ B87E15FFB57A13FFB0781FFFA27434FFC8A57DFFFFEED9FFFFFAF3FFEAE9EDFF
+ EBEEF6FFEFEFF5FFEFEEF2FFEEEDEFFFEFEEF0FFF3F1F1FFF7F3F2FFF8F3F0FF
+ F7F2F1FFF1EEF0FFEFECEEFFFFFBFAFFFFF5E7FFD6BE9AFFA8864AFFA87B24FF
+ AF7914FFB27A0BFFC08412FFC08111FFBD7E0EFFBC7C0CFFBB7D0BFFBA7E0CFF
+ B87E0DFFB37B10FFB2780EFFB77A0CFFBD7E0EFFC18212FFC28313FFBF8010FF
+ BD7E0EFFBC7D0DFFBD7E0EFFC38414FFC08111FFBE7F0FFFBD7E0EFFBE7F0FFF
+ BF8010FFBE7F0FFFBD7F0DFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFC0830DFFBF820CFFBE810BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBD800AFFB87B05FFB97C06FFB97C06FFBA7D07FFBC7F09FF
+ BD800AFFBD800AFFBE810BFFBF820CFFBE810BFFBC7F09FFBB7E08FFBB7E08FF
+ BB7E08FFBC7F09FFBC7F0BFFB67806FFB87A08FFBB7D0BFFBD7F0DFFBE800EFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBE800EFFBE800EFFBC7E0CFFBC7E0CFFBC7E0CFFBF810FFFC28412FF
+ C18311FFBD7F0DFFB97B09FFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBD7F0DFFBC7E0CFFBD7F0DFFBF810FFFBF810FFF
+ BF810FFFBF810FFFC08210FFBD7F0DFFBD7F0DFFBD7F0DFFB4750DFFB4750DFF
+ B4750DFFB4750DFFB4760CFFB4760CFFB4760CFFB4760CFFB27408FFB4760AFF
+ B6790BFFB5780AFFB37608FFB27507FFB47709FFB6790BFFB3780BFFB3780AFF
+ B57908FFB47A09FFB4790BFFB1770DFFB3750FFFB57411FFBB7811FFBB7607FF
+ BD7902FFC07D03FFBA7D05FFB37A07FFAB7810FF96722CFF706256FF646B8CFF
+ 5372B1FF406BBAFF396ABAFF3E6FBFFF406EBBFF3C68B5FF3B64B3FF3D64B3FF
+ 4267B7FF456CBBFF4671C2FF4572C3FF446EBBFF4269B7FF4568B8FF3F5AA4FF
+ 344881FF2F3B5FFF353545FF3E3532FF463324FF4A321CFF50311AFF55331CFF
+ 56331FFF54311DFF4F2E1AFF4C2D16FF4B3016FF4F3118FF53311AFF56321AFF
+ 55341AFF53351AFF53341BFF52321BFF53311AFF523019FF533119FF59381EFF
+ 5A391FFF5B3515FF62380EFF794A14FF9A6620FFB37C27FFBC7F1DFFB77810FF
+ B3740CFFB87911FFBB7D13FFB87A10FFB7790FFFBA7C12FFB97B0FFFB97B0FFF
+ B87B0DFFB87B0DFFB77A0CFFB77A0CFFB6790BFFB6790BFFB4760AFFB4760AFF
+ B5770BFFB6790BFFB77A0CFFB87C0BFFB97D0CFFB97D0CFFB67A09FFB67A09FF
+ B67A09FFB67A09FFB87A0EFFB87A0EFFB87A0EFFB87A0EFFBB7E10FFBA7D0FFF
+ BA7D0FFFB97C0EFFB97C0EFFB87B0DFFB87B0DFFB77A0CFFB77A0CFFB97C0EFF
+ BB7E10FFBD8012FFBD8012FFBB7E10FFB97C0EFFB77A0CFFB97A0AFFBC7F0BFF
+ BD800AFFBC8008FFB97C06FFB67A08FFB67B0EFFB67C13FFB67C15FFB27811FF
+ BA8017FFB47A11FFB87E15FFC28720FFBA7D1DFFAF7A2AFFBC9666FFEED7BDFF
+ FFF4E8FFF7F3F2FFEAEDF2FFE4E7EFFFECEFF4FFEAEBEFFFEAECEDFFEEEDEFFF
+ F3F1F1FFF6F2F1FFF6F1EEFFF3EFEEFFEDECEEFFEFEAECFFFFF5F3FFE8CFBBFF
+ B49560FF9C7725FFB18219FFB9820FFFB57705FFBF7F0FFFC38013FFC07D10FF
+ BE7C0BFFBF7E0BFFC0810EFFBE8210FFB77F0EFFB47C0DFFBA7E0DFFBB7C0CFF
+ BC7D0DFFBF8010FFC18212FFC18212FFBD7E0EFFB97A0AFFC28313FFBF8010FF
+ BD7E0EFFBC7D0DFFBE7F0FFFBF8010FFBE7F0FFFBD7F0DFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBE810DFFBD800CFF
+ BC7F0BFFBA7D09FFBA7D09FFBA7D09FFBA7D09FFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBC7F0BFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBE810DFFBF820EFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFB87A08FFB67806FFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBF810FFFC28412FFC18311FFBD7F0DFFB97B09FFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE800EFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBC7E0CFFBE800EFFBE800EFFBE800EFFBC7E0CFFBC7E0CFF
+ BC7E0CFFB4750DFFB4750DFFB4750DFFB4750DFFB4760CFFB4760CFFB4760CFF
+ B4760CFFB37509FFB4760AFFB5780AFFB5780AFFB37608FFB37608FFB47709FF
+ B5780AFFB4790BFFB37908FFB57907FFB57907FFB37908FFB3780BFFB3750FFF
+ B67512FFBA7710FFB77407FFBC7904FFC27F05FFBF7E04FFBC7E08FFB87E0DFF
+ A37420FF806441FF716B76FF5D72A6FF476FBAFF3E6EC0FF3D71C4FF4273BFFF
+ 4370BAFF466FBEFF3F67B9FF3F67B9FF3B66B5FF3D6BB9FF4070BEFF3E6CBAFF
+ 416CBDFF4469BDFF3F5FABFF354D87FF2E3B61FF313345FF3B3334FF453529FF
+ 4B3321FF4F311EFF52311DFF57321EFF55301CFF523019FF4E2E17FF4E2F18FF
+ 4E2F18FF53311AFF533119FF543319FF553518FF55341AFF52331AFF53311AFF
+ 502F1BFF52321BFF56371EFF5A381BFF5C3613FF704212FF8F5A1BFFAD7222FF
+ BB7E20FFB97B17FFB77810FFB4750DFFB77810FFBA7C12FFB97B11FFB87A10FF
+ B97B11FFB87A0EFFB87A0EFFB77A0CFFB77A0CFFB77A0CFFB77A0CFFB77A0CFF
+ B6790BFFB5770BFFB5770BFFB5770BFFB6790BFFB77A0CFFB87C0BFFB87C0BFF
+ B87C0BFFB67A09FFB57908FFB47807FFB6790BFFB87B0DFFB97B0FFFB97B0FFF
+ B87A0EFFBA7D0FFFBA7D0FFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB87B0DFF
+ B87B0DFFB87B0DFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBA7D0FFFB97C0EFF
+ B87B0DFFB97A0CFFBA7C0AFFBC7E08FFBC7F07FFBA7E06FFB87D09FFB77C0EFF
+ B67C12FFB57C13FFB37912FFBA8017FFB2780FFFB87D19FFBE8425FFB27A21FF
+ B68743FFE9CFABFFFFFFF3FFFEF8F3FFF0EFF1FFEFF3F8FFE3E6EEFFE6EAEFFF
+ E5E8EDFFEAEBEFFFECEEEFFFF2F0F0FFF5F1F0FFF3F0ECFFF0EEEDFFEBECF0FF
+ F2ECEDFFFFEAE4FFCDAB8DFF9F7C38FF9F7514FFB68511FFBF860BFFBA7B08FF
+ C48212FFC47F12FFC27D10FFC27E0DFFC3800DFFC48310FFC28511FFBB820FFF
+ B97F0EFFBD8110FFBC7D0DFFBA7B0BFFBD7E0EFFC18212FFC18212FFBC7D0DFF
+ B77808FFC08111FFBE7F0FFFBB7C0CFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BD7F0DFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBA7D09FFBA7D09FFB97C08FFBA7D09FFBA7D09FF
+ BB7E0AFFBD800CFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFFBA7D09FFBA7D09FF
+ B97C08FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBD800CFFBF820EFF
+ C0830FFFBE800EFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBB7D0BFF
+ BA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBF810FFFBE800EFFBC7E0CFF
+ BA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBF810FFFBE800EFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBA7C0AFFBC7E0CFFBB7D0BFFB97B09FFB97B09FFBC7E0CFFBD7F0DFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFB4750DFFB4750DFFB4750DFFB4750DFF
+ B4760CFFB4760CFFB4760CFFB4760CFFB5770BFFB4760AFFB37608FFB37608FF
+ B5780AFFB5780AFFB47709FFB37608FFB57B0AFFB47B08FFB47A03FFB37902FF
+ B37804FFB47807FFB6780EFFB77711FFB97711FFB37209FFB87907FFBE7E08FF
+ BD7A05FFBE7E08FFBD7D0DFFA97013FF956B30FF826D5EFF666F94FF4F70B5FF
+ 406FC1FF3D71C4FF4576C0FF4A77C0FF4D77C4FF426DBEFF426DBEFF3B68B9FF
+ 3D6EBAFF4373C1FF3D6CBDFF406CBFFF4068BBFF4060ABFF385189FF2F3C62FF
+ 2F3143FF383134FF44342DFF4A3526FF4D3120FF51301DFF542F1BFF542F19FF
+ 55301AFF53311AFF4F3019FF4E2F18FF503019FF533119FF543319FF573518FF
+ 573518FF543319FF51311AFF50311CFF52331EFF54341DFF563416FF60380EFF
+ 7E4E14FFA46B20FFBA7B1FFFBD7B15FFB77810FFB87911FFB87911FFB77810FF
+ B7790FFFB97B11FFB87A10FFB4760CFFB6780CFFB6780CFFB6790BFFB77A0CFF
+ B77A0CFFB77A0CFFB77A0CFFB77A0CFFB6790BFFB6790BFFB6790BFFB6790BFF
+ B77A0CFFB77A0CFFB77A0CFFB77A0CFFB77A0CFFB6790BFFB5780AFFB77A0CFF
+ BA7D0FFFBC7F11FFBB7E10FFBA7D0FFFB87B0DFFB87B0DFFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFBA7D0FFFBA7D0FFFB87B0DFFB87B0DFFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFB87B0DFFB87B0DFFB77A0CFFB87909FFB97A07FFBA7C06FF
+ BB7E08FFBA7F0BFFB87D0FFFB57C0FFFB47A10FFB4780EFFBD7F15FFB57711FF
+ B67C1DFFAF7823FFA7742BFFC8A26CFFFFF2DDFFFFFFFCFFF6F6F6FFE9ECF0FF
+ F0F4F9FFEBEFF4FFE4E8EDFFEAEEF3FFEAEDF1FFEEF0F1FFF4F2F2FFF3F1F0FF
+ F1EFEEFFF1EFEFFFEEEFF3FFF8F0F0FFF7D8C9FFBE966CFFA57C2DFFAD7F14FF
+ B58007FFC08507FFC3820FFFC78213FFC37E11FFC37E0FFFC57F0DFFC4810EFF
+ C3820FFFC0830FFFBA810EFFB87F0CFFBD8110FFBE7F0FFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFB97A0AFFBE7F0FFFBC7D0DFFBA7B0BFFBA7B0BFF
+ BC7D0DFFBD7E0EFFBD7E0EFFBC7E0CFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBC7F0BFFBD800CFFBE810DFFBC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFF
+ BB7E0AFFBA7D09FFBA7D09FFBA7D09FFBD800CFFBC7F0BFFBC7F0BFFBB7E0AFF
+ BB7E0AFFBC7F0BFFBD800CFFBE810DFFBD7F0DFFBA7C0AFFB87A08FFB97B09FF
+ BC7E0CFFC08210FFC18311FFC18311FFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBC7E0CFFBE800EFFBD7F0DFFB87A08FF
+ B87A08FFBC7E0CFFBD7F0DFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFB4750DFF
+ B4750DFFB4750DFFB4750DFFB4760CFFB4760CFFB4760CFFB4760CFFB6780CFF
+ B4760AFFB27507FFB37608FFB5780AFFB6790BFFB47709FFB27507FFB67C0BFF
+ B47B08FFB47A03FFB27900FFB27801FFB47806FFB6780CFFB87911FFB57810FF
+ B1720AFFB5780AFFBB7C0CFFB87907FFBC7A09FFBD7B0BFFAC6E0AFFA46F1FFF
+ 8F6F46FF6E6D7DFF576EA6FF446EBBFF3C6EC0FF4575BDFF4D7BC2FF507AC5FF
+ 4671C0FF4875C6FF4372C3FF4778C4FF4B7CC8FF3F6FC1FF3F6DC1FF3D65B8FF
+ 4161AAFF3C548AFF303E62FF2E3042FF373035FF433431FF4A362BFF4A3022FF
+ 4D2F1EFF502D19FF532E18FF56311BFF55331CFF51301CFF4E2F1AFF4F3019FF
+ 513219FF543319FF573518FF573518FF543319FF52321BFF50311CFF50321FFF
+ 53331CFF553211FF63390AFF8A5614FFB17521FFC4801BFFBE790CFFB6750CFF
+ BA7B13FFBB7C14FFB6770FFFB5770DFFB97B11FFB7790FFFB17309FFB5770BFF
+ B5770BFFB6790BFFB6790BFFB77A0CFFB77A0CFFB87B0DFFB87B0DFFB77A0CFF
+ B77A0CFFB77A0CFFB77A0CFFB6790BFFB6790BFFB6790BFFB6790BFFB97C0EFF
+ B87B0DFFB77A0CFFB97C0EFFBC7F11FFBE8113FFBD8012FFBC7F11FFB77A0CFF
+ B87B0DFFB87B0DFFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFFBB7E10FFB87B0DFF
+ B87B0DFFB87B0DFFB77A0CFFB77A0CFFB87B0DFFB87B0DFFB87B0DFFB7790DFF
+ B5780AFFB77806FFB97A07FFBC7F0BFFBC800EFFB97E10FFB77C0FFFBD8012FF
+ BC7F11FFC6861AFFBE801CFFB9802AFFA5742AFFA2783DFFDABF9AFFFFFAF0FF
+ EBEDEEFFECEFF3FFE5E8ECFFEEF1F5FFF5FAFDFFE7EBF0FFF4F8FDFFECEFF3FF
+ F0F2F3FFF3F3F3FFF4F2F1FFF2F0EFFFF0F0F0FFF3F2F4FFFFF6EEFFE5C3A6FF
+ BB8D57FFB98B33FFC19121FFBB8207FFC18509FFC48310FFBC7A0AFFC07E0EFF
+ C17F0FFFC4810EFFC4810EFFBF7F0FFFBB7F0EFFB77E0BFFB47D0AFFBB7F0EFF
+ C08111FFC18212FFBE7F0FFFB97A0AFFB77808FFB97A0AFFBD7E0EFFBD7E0EFF
+ BB7C0CFFB97A0AFFB97A0AFFBB7C0CFFBD7E0EFFBC7D0DFFBB7C0CFFBC7E0CFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBD800CFF
+ BD800CFFBC7F0BFFBC7F0BFFBD800CFFBE810DFFC0830FFFC0830FFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBF820EFF
+ BE810DFFBD800CFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFC58715FF
+ C08210FFBB7D0BFFB97B09FFBB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFB97B09FFBA7C0AFF
+ BC7E0CFFBD7F0DFFBC7E0CFFB97B09FFB97B09FFBB7D0BFFBE800EFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ C18311FFBF810FFFB97B09FFB97B09FFBD7F0DFFBE800EFFBA7C0AFFBB7D0BFF
+ BB7D0BFFBB7D0BFFB1720AFFB2730BFFB4750DFFB5760EFFB4760CFFB3750BFF
+ B2740AFFB17309FFB4760AFFB4760AFFB47709FFB47709FFB47709FFB47709FF
+ B47709FFB47709FFB6790BFFB27605FFB27703FFB77D06FFB87E07FFB47806FF
+ B3780AFFB77B11FFB1770EFFB1770EFFB2780EFFB2790CFFB77A0CFFBA7B0DFF
+ BB7A0EFFBA7811FFB47814FF986D2AFF776963FF667399FF5376B8FF406EBBFF
+ 4270B7FF4978BCFF4974BDFF4F7BC8FF4F7ECFFF4B7ACBFF4576C2FF4171BFFF
+ 3B6ABEFF3664B8FF3358A8FF39569BFF3C4F82FF2E385AFF212133FF2F272EFF
+ 483B39FF524039FF432D22FF472A1CFF4E2D1AFF57321EFF57321CFF512E1AFF
+ 50301DFF533522FF4D301BFF4F3118FF523117FF523215FF543215FF533316FF
+ 51321BFF4F321DFF4F311EFF56361FFF5D3714FF714510FF956017FFAF7014FF
+ BA7508FFC27A0AFFBB7A0EFFB87911FFB77810FFB77810FFB7790FFFB7790FFF
+ B5770DFFB4760CFFB7790DFFB7790DFFB87B0DFFB87B0DFFB97C0EFFB87B0DFF
+ B87B0DFFB77A0CFFB77A0CFFB87B0DFFBA7D0FFFBB7E10FFBB7E10FFB97C0EFF
+ B77A0CFFB6790BFFB5780AFFB6790BFFB77A0CFFB87B0DFFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFB47709FFB77A0CFFB97C0EFFB97C0EFFB77A0CFFB77A0CFF
+ B97C0EFFBB7E10FFC28517FFBF8214FFBC7F11FFBC7F11FFBD8012FFBD8012FF
+ BB7E10FFB97C0EFFB57A0DFFB77A0CFFB77A0CFFB87C0BFFBA7E0DFFB97F0EFF
+ BA7F11FFBB7E10FFB57606FFC38313FFBE7D11FFCA8D2DFFBD893CFF996F34FF
+ C0A279FFFFF6DFFFF6F3EFFFEFF3F8FFF0F3F7FFF0F2F3FFEDEFF0FFE9EDEEFF
+ E9ECF0FFEAEDF1FFE6E9EDFFEAEDF1FFF3F5F6FFFAFAFAFFEAEBE9FFEAE8E7FF
+ F4F3EFFFF0E2D0FFBE9B70FFA97A36FFB98628FFBD881AFFBB800CFFC58711FF
+ BE7E0EFFC07F12FFC0810FFFC0810FFFC2800FFFBF7F0FFFBE7E12FFB97E11FF
+ B67E0DFFB57D0CFFBA7E0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFB87909FFC28313FFC38414FFBA7B0BFFBA7B0BFFC38414FF
+ C28313FFB87909FFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBA7C0AFFBC7E0CFFBF810FFFBE800EFFBB7D0BFFB87A08FF
+ B97B09FFBA7C0AFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFB97B09FFB97B09FFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFBE800EFFBE800EFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFB97B09FFBB7D0BFFBE800EFFBD7F0DFFBB7D0BFFBB7D0BFF
+ BD7F0DFFC08210FFBD7F0DFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFF
+ BA7C0AFFB97B09FFBB7D0BFFBB7D0BFFBB7D0BFFB1720AFFB2730BFFB3740CFF
+ B3740CFFB4760CFFB3750BFFB3750BFFB3750BFFB4760AFFB4760AFFB47709FF
+ B47709FFB47709FFB47709FFB47709FFB4760AFFB6780EFFB3750BFFB37608FF
+ B77B09FFB77B09FFB27906FFB27709FFB47B0EFFB3790FFFB27A0FFFB07A0FFF
+ B07B0DFFB27A0DFFB57A0DFFB7790FFFB9790DFFBB7C0AFFA4721AFF80684CFF
+ 6D6E82FF5873ACFF4C75BEFF4B7ABEFF4F7EC2FF4775BCFF4E7BC5FF4E7ECCFF
+ 4B7CCCFF497AC6FF4777C5FF406FC5FF3D69BDFF4165B3FF385294FF2F3E6FFF
+ 242A4DFF201F33FF352D37FF4E4346FF594A48FF45312CFF462D23FF4B2C1DFF
+ 52311DFF55331CFF522F1BFF4D2D1AFF4C2E1BFF4A2D18FF4E2F18FF513219FF
+ 543319FF553518FF543417FF50311AFF4D301BFF492B18FF523018FF5C350FFF
+ 76470FFFA06819FFB87917FFC27A0AFFC37D08FFBA790DFFB87911FFB87911FF
+ B77810FFB7790FFFB7790FFFB87A10FFB97B11FFBA7C10FFB97B0FFFB77A0CFF
+ B6790BFFB6790BFFB77A0CFFB87B0DFFB97C0EFFB97C0EFFB97C0EFFB97C0EFF
+ BA7D0FFFBA7D0FFFBB7E10FFBC7F11FFBC7F11FFB77A0CFFB87B0DFFB87B0DFF
+ B87B0DFFB87B0DFFB87B0DFFB87B0DFFB87B0DFFB77A0CFFB97C0EFFBA7D0FFF
+ B97C0EFFB77A0CFFB6790BFFB77A0CFFB97C0EFFBF8214FFBC7F11FFBA7D0FFF
+ BA7D0FFFBB7E10FFBB7E10FFB97C0EFFB6790BFFB57A0DFFB67B0EFFB67B0EFF
+ B77C0FFFB87D10FFB87D10FFB97E10FFBB7F0EFFB77806FFBD7C0FFFC2801AFF
+ BD822CFFAC7F3CFFB89769FFE9D4B9FFFFFEF4FFEDEFF0FFEAF0F7FFEDF0F4FF
+ EEF0F0FFECEEEEFFECEEEEFFEDEFF0FFEEF1F5FFF5F8FCFFEAEDF1FFE5E9EAFF
+ EDEFEFFFEDEEECFFFBF8F3FFF6F0E5FFCDBB9EFFBB955BFFAB7828FFBA8524FF
+ BD8518FFB97C0EFFC28313FFBB7B0FFFBC7F11FFBC800EFFBE800EFFBE800EFF
+ BE7F11FFBC7E14FFB97D13FFB67E11FFB67F10FFBA7E0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBA7B0BFFC08111FFC18212FF
+ BC7D0DFFBC7D0DFFC18212FFC08111FFBA7B0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBD7F0DFFBF810FFF
+ BE800EFFBC7E0CFFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE800EFFBE800EFF
+ BD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBE800EFFBE800EFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFFBC7E0CFFBE800EFF
+ BE800EFFBC7E0CFFBC7E0CFFBE800EFFC08210FFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFB97B09FFBB7D0BFFBB7D0BFFBB7D0BFF
+ B2730BFFB1720AFFB1720AFFB2730BFFB2740AFFB4760CFFB5770DFFB5770DFF
+ B4760AFFB4760AFFB47709FFB47709FFB47709FFB47709FFB47709FFB4760AFF
+ B97711FFB77411FFB4750DFFB5790FFFB4790BFFB27709FFB27709FFB2790CFF
+ B67D10FFB27D0FFFB07D0FFFAF7C0EFFB07B0DFFB1790CFFB4780EFFB7780AFF
+ BE7D03FFAA740FFF886736FF6E6464FF566996FF4D72B6FF4D7ABEFF4B7CC2FF
+ 4576BAFF4B7CC2FF4B7CCAFF4B7CCCFF4C7CCAFF4C7BCCFF4273C9FF3F6BBFFF
+ 4868B4FF324889FF1F2D5EFF1E2447FF2A2740FF3D3847FF4F4752FF574C54FF
+ 483A3CFF44312EFF472B20FF4E2E1BFF52311DFF502F1BFF4B2A1AFF472918FF
+ 472C17FF4B2F17FF513219FF55341AFF563619FF523419FF4D3119FF4C2F1AFF
+ 492B18FF502D13FF60360CFF7F4E10FFA9701BFFBF8018FFC47E0CFFC17B06FF
+ B9780CFFB87911FFB97A12FFB87911FFB6780EFFB7790FFFBB7D13FFBF8117FF
+ BD7F13FFBB7D11FFB77A0CFFB5780AFFB47709FFB5780AFFB87B0DFFB97C0EFF
+ BA7E0DFFB97D0CFFB97D0CFFB87B0DFFBA7D0FFFBC7E12FFBF8115FFC18317FF
+ B97B0FFFB97B0FFFB97B0FFFB87B0DFFB87B0DFFB87C0BFFB87C0BFFB87C0BFF
+ B97C0EFFBA7D0FFFBB7E10FFB97C0EFFB77A0CFFB6790BFFB6790BFFB77A0CFF
+ BB7E10FFBA7D0FFFB87B0DFFB87B0DFFB97C0EFFB87B0DFFB6790BFFB3780AFF
+ B57D0EFFB57C0FFFB67C12FFB67C13FFB57B12FFB57B11FFB87D10FFBB7E10FF
+ BE7E0EFFBA7C12FFC18427FFA87428FF9D7642FFD6BF9FFFFFF7E9FFF2F0EFFF
+ E7EBF0FFE6ECF1FFECEEEFFFEEEFEDFFEDEEECFFEEEEEEFFEFF1F1FFF3F5F6FF
+ EBEDEEFFEEF2F3FFF1F4F8FFF4F6F6FFF2EFEAFFFFF7EAFFFDEFD9FFD7BB92FF
+ B58C43FFAA771BFFBB821FFFBC8219FFB87A10FFBD7F15FFB67A10FFBA7F12FF
+ B97F0EFFB9800DFFBB7F0EFFBB7D11FFBB7C14FFB87E15FFB57F14FFB58012FF
+ B87D0FFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBD7F0DFFBF810FFFBF810FFFBD7F0DFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFB97B09FFB97B09FF
+ BA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BF810FFFBF810FFFBE800EFFBD7F0DFFBC7E0CFFBA7C0AFFBA7C0AFFB97B09FF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBE800EFFBF810FFF
+ BA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFB87A08FF
+ BB7D0BFFBB7D0BFFBB7D0BFFB2730BFFB1720AFFB07109FFB07109FFB2740AFF
+ B4760CFFB6780EFFB7790FFFB4760AFFB4760AFFB47709FFB47709FFB47709FF
+ B47709FFB47709FFB4760CFFBA7613FFB87413FFB47612FFB27710FFB1770DFF
+ B0770AFFB17609FFB27709FFB77C0EFFB47D0EFFB27D0EFFAF7D0DFFAF7D0DFF
+ B07B0CFFB37A0DFFB77B09FFB97B00FFB1770DFF956A2BFF735F4EFF525B80FF
+ 4765A6FF446FB8FF3E71BAFF477BBEFF4A7FC2FF497DC9FF487BCBFF4C7BCCFF
+ 4A7BCBFF4072C5FF3968BAFF3858A4FF253B7DFF1B285CFF272E55FF3A3A58FF
+ 424056FF454357FF4A4455FF4A424DFF443739FF432C24FF46291AFF4E2F1AFF
+ 51301CFF4D2C1CFF472918FF492E19FF4C3018FF503019FF52331AFF523419FF
+ 513419FF4E321AFF4B301BFF52331EFF553014FF663A0BFF875513FFAF761BFF
+ C08218FFC17E09FFBA7702FFB8780CFFB97A12FFBB7C14FFB97A12FFB5770DFF
+ B7790FFFBD7F15FFC4861CFFBD7F13FFBB7D11FFB87B0DFFB6790BFFB5780AFF
+ B5780AFFB6790BFFB77A0CFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97B0FFF
+ BB7D11FFBD7F13FFBE8014FFB97B0FFFB97B0FFFB87A0EFFB87B0DFFB87B0DFF
+ B97D0CFFBA7E0DFFBA7E0DFFBA7D0FFFBA7D0FFFBA7D0FFFB97C0EFFB87B0DFF
+ B87B0DFFB87B0DFFB87B0DFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFF
+ B87B0DFFB77A0CFFB3780AFFB47D0EFFB67E11FFB77E15FFB67C15FFB47A13FF
+ B47A11FFB97B0FFFBB7D11FFBF8117FFBD8121FFBF8738FFA07437FFAC8F68FF
+ F0E1CEFFFEFBF6FFE0E5E8FFE5EBF0FFE8EDF0FFEBEDEDFFECEDEBFFECEDEBFF
+ EDEEECFFEFF1F1FFF2F4F4FFF1F3F3FFF0F2F3FFE4E8E9FFF0F1EFFFFBF6EDFF
+ F6E8D5FFE3C9A5FFC39E64FFB1832FFFAD7613FFBB811AFFBE8119FFB97A12FF
+ BA7E14FFB57B11FFB98013FFB77F10FFB67E0DFFBA7D0FFFBA7C10FFBB7D13FF
+ B87E15FFB68015FFB78214FFB87D0FFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBE7F0FFFBB7C0CFFBC7D0DFFC18212FFC18212FF
+ BC7D0DFFBB7C0CFFBE7F0FFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBD7F0DFFBF810FFFBF810FFFBE800EFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBD7F0DFF
+ BD7F0DFFBE800EFFBE800EFFB97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBA7C0AFFB97B09FFBB7D0BFFBB7D0BFFBB7D0BFFB2730BFFB1720AFF
+ B07109FFB07109FFB2740AFFB4760CFFB6780EFFB7790FFFB4760AFFB4760AFF
+ B47709FFB47709FFB47709FFB47709FFB47709FFB4760AFFB97510FFB97613FF
+ B57713FFB0760FFFB0760FFFB1770EFFB4760AFFB57608FFB87909FFB67A09FF
+ B27C0AFFB07C0AFFB17D0BFFB17D0BFFB47C0DFFB77E0BFFB37700FFB47B0EFF
+ A6732AFF816346FF595A76FF4760A0FF3F6BB8FF396EBEFF4980C5FF4A84C6FF
+ 4780CBFF467BCBFF4879C9FF4375C7FF376CBDFF3060B2FF264A98FF1E377DFF
+ 212F69FF333B6AFF43466CFF3F4261FF383C59FF3B3F58FF49485CFF453D47FF
+ 402F2CFF412A1BFF4A2C19FF51301CFF51311EFF4C2E1BFF4C321AFF4B3119FF
+ 4E2F18FF4E2F18FF4E3116FF4E3319FF4D331BFF4E331EFF573622FF593212FF
+ 6E3F0CFF905C15FFAF7619FFBD8215FFBF800DFFB97A07FFB9790DFFBA7B13FF
+ BC7D15FFB97A12FFB6780EFFB7790FFFBD7F15FFC3851BFFBA7C10FFBA7C10FF
+ B97C0EFFB87B0DFFB77A0CFFB6790BFFB5780AFFB5780AFFB77B0AFFB77B09FF
+ B87C0BFFB97D0CFFB97B0FFFB87A0EFFB7790FFFB7790FFFB87A10FFB87A10FF
+ B7790DFFB77A0CFFB87B0DFFBA7E0DFFBC800EFFBD8110FFB87B0DFFB87B0DFF
+ B87B0DFFB97C0EFFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFB97C0EFFBA7D0FFF
+ BC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFFB67B0DFFB47D0EFFB47F11FF
+ B67F17FFB77C18FFB57915FFB67812FFBA7C12FFBC7D15FFB47818FFBB8532FF
+ B68A4BFFB08F62FFDBC7AEFFFFFEF4FFF4F6F6FFE9F0F3FFE7EEF1FFEBEFF0FF
+ EFF0EEFFEEEFEBFFECEDEBFFEAEDEBFFEDF0EEFFEFF2F0FFF4F5F3FFF3F6F4FF
+ E2E4E4FFF3F2EEFFFFF6E8FFD2BD9EFFA98450FFA3732BFFB38020FFB37A11FF
+ BE8119FFC08119FFBB7C14FFBA7E14FFB57D12FFB98114FFB67E13FFB77E11FF
+ BA7C10FFBA7C10FFBA7D0FFFBA7F12FFB88015FFBA8215FFBA7D0FFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBF8010FFBA7B0BFF
+ BB7C0CFFC28313FFC28313FFBB7C0CFFBA7B0BFFBF8010FFBD7E0EFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBD7E0EFF
+ BD7E0EFFBE7F0FFFBF8010FFBF8010FFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFF
+ BB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFFBA7B0BFFBA7B0BFF
+ BA7B0BFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBE800EFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFB97B09FFBA7C0AFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBA7C0AFFBB7D0BFFBB7D0BFF
+ BB7D0BFFB2730BFFB1720AFFB1720AFFB2730BFFB2740AFFB4760CFFB5770DFF
+ B5770DFFB4760AFFB4760AFFB47709FFB47709FFB47709FFB47709FFB47709FF
+ B4760AFFB7760DFFB77810FFB37811FFAF750EFFAF750EFFB2780FFFB6780EFF
+ B67508FFB97707FFB77806FFB37A07FFB27B08FFB27C09FFB37D0AFFB47C0BFF
+ B67D0AFFB07703FFB57C13FFB07928FF946D47FF69637AFF5469A7FF4572C3FF
+ 3E78CAFF4683C7FF4A86C8FF4984CCFF447ECAFF4277C8FF3D72C3FF3169BAFF
+ 2C5FAFFF274C9EFF27418DFF2A3B7AFF384377FF424875FF393F68FF313A60FF
+ 384163FF464A66FF464654FF463A3AFF452F24FF492E1AFF50311CFF50321FFF
+ 4D321EFF4D331BFF4C321AFF4C2F1AFF4C2D16FF4D2F16FF4D3218FF4C341CFF
+ 503520FF56341DFF5B3211FF754511FF99641BFFB07918FFBB8012FFBE8210FF
+ BD7F0DFFB97B0FFFBB7C14FFBC7D15FFBA7B13FFB7790FFFB7790FFFBB7D13FF
+ BF8117FFB97B0FFFB97B0FFFB97C0EFFB97C0EFFB87B0DFFB77A0CFFB6790BFF
+ B57908FFB57908FFB67A08FFB87C0BFFB97D0CFFB97B0FFFB7790DFFB5770DFF
+ B3750BFFBA7C12FFB97B11FFB87A0EFFB77A0CFFB87B0DFFBA7E0DFFBC800EFF
+ BE8210FFB97C0EFFB87B0DFFB77A0CFFB97C0EFFBB7E10FFBC7F11FFBC7F11FF
+ BB7E10FFB97C0EFFBB7E10FFBE8113FFBE8113FFBD8012FFBB7E10FFBA7D0FFF
+ B87D0FFFB17C0DFFB27F11FFB78018FFB77C18FFB77915FFB87812FFBD7B14FF
+ BC7E1AFFAD751CFFB4833DFFB38F5FFFCAB296FFFBEFE3FFFFFFFBFFE5E9EAFF
+ EBF2F5FFEAEFF0FFECF1F0FFF1F2F0FFF0F1EDFFECEFEDFFEAEDEBFFEBEEECFF
+ EDF0EEFFEBECE8FFF7F8F4FFF1F2F0FFFFFFF9FFFFF9E6FFC5A881FFA57535FF
+ B77E28FFB97E1AFFB67D10FFBE8016FFBE8016FFBC7E12FFBA7F11FFB67E11FF
+ B68113FFB87F16FFB87E15FFBA7C12FFBB7C0EFFBC7E0CFFB97F0EFFB98013FF
+ BA8114FFBA7D0FFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBF8010FFBB7C0CFFBC7D0DFFC18212FFC18212FFBC7D0DFFBB7C0CFF
+ BF8010FFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFFBF8010FFBF8010FFBD7E0EFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFB97A0AFFB97A0AFFBA7B0BFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFF
+ BD7E0EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFF
+ BE800EFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BD7F0DFFB97B09FFBA7C0AFFBA7C0AFFBC7E0CFFBD7F0DFFBE800EFFBF810FFF
+ BF810FFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBE800EFFBD7F0DFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFB1720AFFB2730BFFB3740CFFB3740CFF
+ B4760CFFB3750BFFB3750BFFB3750BFFB4760AFFB4760AFFB47709FFB47709FF
+ B47709FFB47709FFB47709FFB47709FFB57608FFB6790BFFB37A0DFFAC760BFF
+ AD760DFFB37910FFBA7910FFB97609FFBC7708FFBC7807FFB87906FFB57A06FF
+ B37A07FFB37A07FFB37908FFB3780AFFB47C0FFFB07A15FFAF7621FF9B7144FF
+ 786D81FF5F71B0FF4A77CEFF3F7BD4FF3F80C5FF4787C8FF4987CEFF4480CCFF
+ 4178C9FF3D73C6FF326DBCFF2E66B3FF335BAEFF3553A2FF35488CFF37457FFF
+ 3D487AFF36406FFF2C3A6AFF37456FFF404A6CFF494D60FF50474AFF4C3931FF
+ 4D3120FF4F3019FF4E311CFF4C311CFF4C321AFF4B3119FF4C2F1AFF4D2E19FF
+ 4C3018FF4B3218FF4B331BFF4F341FFF55331CFF5E3514FF814F1AFFA66F24FF
+ B47A1AFFB57D0EFFB87E0DFFB87E0DFFBC7E14FFBC7D15FFBC7D15FFBA7B13FF
+ B87A10FFB7790FFFB7790FFFB87A10FFB97B0FFFB97B0FFFB87B0DFFB77A0CFF
+ B77A0CFFB77A0CFFB87B0DFFB87C0BFFB67A09FFB77B09FFB77B0AFFB87C0BFF
+ B87A0EFFB87A0EFFB87A10FFB87A10FFBE8016FFBC7E14FFBA7C10FFB87B0DFF
+ B77A0CFFB87C0BFFBA7E0CFFBB7F0DFFBB7E10FFB97C0EFFB87B0DFFB97C0EFF
+ BB7E10FFBC7F11FFBB7E10FFB97C0EFFB77A0CFFBA7D0FFFBE8113FFBF8214FF
+ BD8012FFBA7D0FFFBA7D0FFFB87D0FFFAF7B09FFB17F0FFFB78017FFB87E17FF
+ B87A14FFBB7913FFBE7C15FFBC7F1FFFB47F2EFFAE8547FFB89C79FFE5D5C5FF
+ FFF9F6FFF0F2F3FFE4EAE9FFE7EDECFFE8EEEDFFECF1F0FFF3F4F2FFF3F4F2FF
+ EFF1F1FFEAEFEEFFECEFEDFFEEEFEDFFF4F3EFFFF4F3EFFFE9EAE6FFFBF7ECFF
+ F8E7CDFFC8A776FFBC8437FFC98728FFBE8016FFBC7E12FFBD7D11FFBC7D0FFF
+ BD7E0EFFBB7F0DFFB47E0CFFB27D0FFFBA7F1BFFB97D19FFBD7C13FFBC7C0CFF
+ BC7E08FFBA8009FFBA7F11FFB98013FFBA7D0FFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBC7D0DFFBD7E0EFFBF8010FF
+ BF8010FFBD7E0EFFBC7D0DFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFFBC7D0DFF
+ BE7F0FFFBF8010FFBD7E0EFFBB7C0CFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFF
+ BB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BD7F0DFFBE800EFFBE800EFFBE800EFFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBE800EFFBE800EFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBC7E0CFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBC7E0CFFBA7C0AFFB87A08FFBC7E0CFFBB7D0BFFB97B09FFB97B09FF
+ B97B09FFBB7D0BFFBD7F0DFFBE800EFFBB7D0BFFBB7D0BFFBB7D0BFFB1720AFF
+ B2730BFFB4750DFFB5760EFFB4760CFFB3750BFFB2740AFFB17309FFB4760AFF
+ B4760AFFB47709FFB47709FFB47709FFB47709FFB47709FFB47709FFB47505FF
+ B67A09FFB27A0BFFAE7609FFAE760BFFB47A10FFBB7B0FFFBA770AFFBD7809FF
+ BD7809FFB87907FFB77907FFB47807FFB17706FFB37706FFB07507FFBC831AFF
+ B17815FFAA6F19FF9A6F3EFF7A6F83FF6274B3FF4877CDFF3A78D2FF3A7BC5FF
+ 4485C9FF4886D2FF4481D1FF407BCBFF3D78C8FF3573C1FF346DBCFF3A66BAFF
+ 3D5FB2FF37509AFF344889FF394984FF31427AFF2A3B73FF334477FF3A4773FF
+ 474F6DFF524D5CFF4E4041FF493328FF4B301CFF4C2F1AFF4B2F17FF4A3018FF
+ 4A3018FF4D3119FF4E321AFF4C3319FF4A321AFF49311DFF4C311CFF59371AFF
+ 663C12FF8E5B1DFFB17927FFB77C18FFAF7708FFB07809FFB07809FFBC8016FF
+ BD7E16FFBC7D15FFBA7B13FFB97B11FFB7790FFFB5770DFFB3750BFFBA7C10FF
+ B97B0FFFB6790BFFB5780AFFB5780AFFB77A0CFFB97C0EFFBB7E10FFB87C0BFF
+ B77B0AFFB77B0AFFB77A0CFFB87A0EFFBA7C10FFBD7F15FFBE8016FFC2841AFF
+ C08218FFBC7E12FFB97B0FFFB6790BFFB67A09FFB77B0AFFB87C0BFFBE8113FF
+ BB7E10FFB97B0FFFB97B0FFFBB7D11FFBB7D11FFB97B0FFFB7790DFFB5780AFF
+ B97C0EFFBD8012FFBE8211FFBC7F11FFB97C0EFFB97C0EFFB87D0FFFB07A08FF
+ B57E0FFFB98116FFB97F16FFB87C12FFB97B11FFBB7E16FFB98023FFBD8A44FF
+ A98353FFC0A993FFFBF1EAFFFDFCFEFFEBF0F3FFF8FEFDFFEEF5F2FFE7ECEAFF
+ EBF0EEFFF1F4F2FFF5F6F4FFF1F3F3FFECF1F0FFEBF0EFFFEDF0EEFFECE9E5FF
+ F9F3EEFFFAF4E9FFF2E4CEFFC4AA82FF9A7133FFAE711BFFC4811AFFBF7F13FF
+ BD8012FFBA7B0DFFB97A0CFFBB7D0BFFB97E0AFFB37C09FFB0780BFFBC811AFF
+ BC7E18FFBD7C13FFBB7C0CFFBB7D07FFBB7E08FFB97F0EFFBB8012FFBA7E0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBE7F11FFBE7F11FFBD7E10FFBC7D0DFFBB7C0CFF
+ BB7D0BFFBB7C0CFFBB7D0BFFBB7C0CFFBB7D0BFFBB7C0CFFBB7D0BFFBA7B0BFF
+ B97B09FFB87909FFBB7D0BFFBE7F0FFFBF810FFFBC7D0DFFBA7B0BFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBA7B0BFFB97A0AFFB97A0AFFBA7C0AFF
+ BB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBE800EFFBF810FFFBF810FFFBC7E0CFF
+ BC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBB7D0BFF
+ BB7E0AFFBB7D0BFFBB7E0AFFBB7D0BFFBB7E0AFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFF
+ BB7D0BFFB97B09FFB97B09FFBB7D0BFFBB7D0BFFB97B09FFB67806FFBD7F0DFF
+ BB7D0BFFB97B09FFB77907FFB87A08FFBB7D0BFFBE800EFFC08210FFBB7D0BFF
+ BB7D0BFFBB7D0BFFB07109FFB2730BFFB4750DFFB3740CFFB2740AFFB2740AFF
+ B3750BFFB5770DFFB17307FFB27408FFB47709FFB6790BFFB77A0CFFB77A0CFF
+ B77A0CFFB77A0CFFB37608FFB37608FFB17609FFB2770AFFB2770AFFB3780BFF
+ B5770BFFB7770BFFB7780AFFB8790BFFB8790BFFB6790BFFB77A0CFFB77A0CFF
+ B77A0CFFB87A0EFFB5770DFFB87C18FFAF751CFF936B3AFF736D80FF5972B0FF
+ 4476C8FF3E7ED6FF4886D2FF4886D2FF4482D6FF3F7FD3FF3D7EC9FF3E7CC8FF
+ 3C76C8FF376DC2FF4071C7FF406ABDFF3054A2FF26438DFF304A8DFF395193FF
+ 3B4E91FF3D4F8EFF3A4882FF3A4474FF47486AFF544E61FF503F42FF42291FFF
+ 4A2B16FF5B3C23FF4E2F18FF4C3018FF492F11FF4D3414FF513A20FF4C351FFF
+ 482F1FFF533621FF4F2D09FF795019FFA17022FFB07819FFB4770FFFB77C0EFF
+ B77F10FFB47B0EFFB2760CFFB4750DFFB5760EFFB77810FFB97B11FFBA7C12FF
+ BB7D13FFBC7E14FFB97B0FFFBA7C10FFBA7D0FFFBA7D0FFFB97C0EFFB77A0CFF
+ B47709FFB37608FFC18416FFBD8012FFB77A0CFFB5770BFFB6780CFFB87A0EFF
+ B87A0EFFB87A0EFFB6780CFFBC7E12FFBD7F13FFB97B0FFFB97B0FFFBD8012FF
+ BC7F11FFB6790BFFB67B0DFFB67B0EFFB67A10FFB97C14FFBC7F17FFBC7E18FF
+ BA7B13FFB7790FFFB7790DFFB87B0DFFBB7C0CFFBC7E0CFFBC7D0DFFBB7C0CFF
+ B97A0CFFB8790BFFBA7B0BFFBE7F11FFB6780EFFB2770AFFBA8211FFB88210FF
+ B07C11FFAF7F27FFAE8148FFCDA98BFFF0DBD3FFF8F0F1FFE9EDEEFFE6EEEDFF
+ E8F2ECFFE4EFE7FFE5ECE7FFE3E8E6FFEBEDEDFFF2F2F2FFECEFEDFFEBF0EEFF
+ ECF2F1FFEAECECFFEDE8E9FFFFFBF5FFFFF2DCFFD6B88FFFA77F3EFFA2701DFF
+ B3791AFFBE7F17FFBC7E12FFBB7F0EFFB97D0CFFB77B0AFFB77B0AFFB77B09FF
+ B77D0CFFB87D0FFFB87D10FFB97B0FFFB97C0EFFB97D0CFFBB7D0BFFBB7F0DFF
+ BC800FFFBD8110FFBB7F0EFFBB7F0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7E10FFBB7E10FFB77A0CFFBD8012FFBD8012FFB77A0CFFB6780CFFBC7E12FF
+ C18317FFC18416FFB57907FFB97E0AFFBC800EFFBC810DFFBA7E0CFFB87D09FF
+ B87C0AFFB97E0AFFB97D0BFFBA7F0BFFBB7F0DFFBC810DFFBC800EFFBB800CFF
+ BA7E0CFFB97D0BFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBC7D0DFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFF
+ BD7E0EFFBA7B0BFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BE7F0FFFBE7F0FFFC08111FFC08111FFBF8010FFBD7E0EFFBB7C0CFFBC7D0DFF
+ C08111FFC38513FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FF
+ BC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FF
+ BC7F0BFFBC7F0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFB87A08FFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BA7C0AFFB87A08FFBF810FFFBD7F0DFFBC7E0CFFBC7E0CFFBE800EFFBF810FFF
+ BE800EFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FFB2730BFFB4750DFF
+ B3740CFFB2740AFFB2740AFFB3750BFFB5770DFFB17307FFB37509FFB47709FF
+ B6790BFFB77A0CFFB77A0CFFB77A0CFFB77A0CFFB37509FFB37509FFB4760AFF
+ B4760AFFB4760AFFB5770BFFB5770BFFB5770BFFB6780CFFB6780CFFB6780CFF
+ B6780CFFB7790DFFB7790DFFB7790DFFB7790DFFB6750CFFB87A14FFAE7518FF
+ 956F39FF777281FF5E76B2FF4677C7FF3D7AD0FF3E7CC8FF4683CDFF4783D5FF
+ 4885D5FF4A88CEFF4987CEFF467ED0FF3E73CAFF3D70C6FF3D6CC0FF305BACFF
+ 284E9CFF34539EFF3C57A1FF395199FF3B4F96FF3C4E8FFF3D4B85FF474D7CFF
+ 4F4E6EFF504653FF4B3835FF482E1EFF4C2D16FF502F1BFF56381FFF553A18FF
+ 4F3614FF4D371BFF4A321AFF492E1AFF523419FF5F3B0BFF855B16FFA9741DFF
+ B47A13FFB5770DFFB87B0DFFB87D0FFFB57C0FFFB77B11FFB97A12FFB87911FF
+ B87911FFB87A10FFB7790FFFB7790FFFB7790FFFB6780CFFB6780CFFB87B0DFF
+ B97C0EFFB97C0EFFB97C0EFFB87B0DFFB77A0CFFBC7E12FFBA7C10FFB7790DFF
+ B7790DFFB97B0FFFBA7C10FFB97B0FFFB87A0EFFB4760AFFB6780CFFB6780CFF
+ B4760AFFB4760AFFB6780CFFB6780CFFB4760AFFB57A0CFFB57A0CFFB67A10FF
+ B97C14FFBB7D17FFBB7D17FFBA7A14FFB77810FFBB7D11FFBC7F11FFBF8010FF
+ BF8010FFBF8010FFBE7F0FFFBD7D11FFBC7C10FFC18013FFBA790DFFB8780CFF
+ BE8113FFBA810EFFAC7708FFA97814FFAC8132FFAE875AFFDDBFACFFF9E7E6FF
+ F6F0F5FFF2F6F7FFEBF3F2FFE4EEE8FFEAF1ECFFEBF2EFFFEBF0EFFFEEEEEEFF
+ ECECECFFEDEEECFFF1F4F2FFF1F6F7FFEFF1F2FFF4ECEDFFFDEAE2FFE6C4A6FF
+ BC935CFFB07D2DFFB27A1BFFB47916FFB97F16FFB97E10FFBB7F0EFFBB7F0EFF
+ BA7E0DFFB97D0CFFB87C0BFFB77B0AFFB77B0AFFBA7E0DFFBA7E0DFFB97D0CFF
+ B97D0CFFB97D0CFFBB7F0EFFBC800FFFBD8110FFBB7F0DFFBB7F0DFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBB7E10FFBB7E10FFB97C0EFFBC7F11FFBC7E12FF
+ B7790DFFB7790DFFBD7F13FFC08218FFC08216FFB87C0AFFBA7F0BFFBB800CFF
+ BB800CFFBA7F0BFFB97E0AFFB97E0AFFBA7F0BFFB97E0AFFBA7F0BFFBB800CFF
+ BC810DFFBC810DFFBB800CFFBA7F0BFFB97E0AFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBE7F0FFFBC7D0DFFBA7B0BFF
+ BB7C0CFFBD7E0EFFBE7F0FFFBD7E0EFFBB7C0CFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBF8010FFC08111FFC08111FF
+ BE7F0FFFBC7D0DFFBC7D0DFFBE7F0FFFC18311FFBC7F0BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBE800EFFC08210FF
+ C28412FFC28412FFC08210FFBE800EFFBD7F0DFFBF810FFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBE800EFFBF810FFFBE800EFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ B07109FFB2730BFFB4750DFFB3740CFFB2740AFFB2740AFFB3750BFFB5770DFF
+ B27408FFB37509FFB47709FFB6790BFFB77A0CFFB77A0CFFB77A0CFFB6790BFF
+ B37509FFB4760AFFB4760AFFB4760AFFB5770BFFB5770BFFB6780CFFB6780CFF
+ B7790DFFB7790DFFB7790DFFB7790DFFB6780CFFB6780CFFB6780CFFB6780CFF
+ B5770DFFB47912FFAD7615FF9A7237FF81767EFF697AB2FF4F77C9FF3E77CDFF
+ 4680CBFF4A87C9FF4984C9FF4F86C9FF5086C7FF4A7EC4FF4179C8FF3D74C9FF
+ 3A70C5FF3E6FC5FF3763B6FF345DACFF4061B0FF4260ADFF3A57A2FF3A539DFF
+ 3A5097FF405291FF445185FF4B5077FF555065FF574B51FF4D3A33FF422818FF
+ 4E2E1BFF5B3C23FF593E1CFF4F3614FF4F3517FF4F3419FF503217FF5B3711FF
+ 774F14FF956719FFAF791BFFB57B12FFB6760AFFB97A0AFFBA7E0DFFB77D0CFF
+ BB7D13FFBA7B13FFB97A12FFB87911FFB7790FFFB6780EFFB5770DFFB5770DFF
+ B6780CFFB7790DFFB87B0DFFB87B0DFFB97C0EFFB97C0EFFB87B0DFFB87B0DFF
+ B87A0EFFB7790DFFB87A0EFFB97B0FFFBB7D11FFBB7D11FFB97B0FFFB87A0EFF
+ B5770BFFB37509FFB27408FFB4760AFFB4760AFFB27408FFB37509FFB5780AFF
+ B47A09FFB47B08FFB57A0CFFB87D10FFBA7D15FFB97C14FFB97A12FFB77810FF
+ BB7D11FFBB7E10FFBC7F11FFBD8012FFBD7F13FFBD7F13FFBE7C15FFBD7B14FF
+ C2831BFFB8770EFFBB7A0EFFC48316FFBC7F11FFB17914FFAE7F29FFAD8747FF
+ C5A784FFF7E2D3FFFFF5F6FFF3EDF2FFF7F9FAFFEFF3F4FFE1E6E7FFEDF2F3FF
+ EEF1F5FFF3F4F8FFF2EFF1FFEDE8E9FFEEECECFFF4F3F5FFF3F3F9FFF4F0F5FF
+ FFF6F7FFEDD3C5FFB8916AFF9D6C2EFFB37C27FFBF8323FFB67A1AFFBB8019FF
+ B87D10FFBB7F0EFFBC800FFFBC800FFFBB7F0EFFB97D0CFFB67A09FFB47807FF
+ BA7E0DFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFBA7E0DFFBC800FFFBC800FFF
+ BB7F0DFFBB7F0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBB7E10FFBB7E10FF
+ BB7E10FFBC7F11FFBA7C10FFB7790DFFB97B0FFFBE8014FFC08218FFBE8014FF
+ BC800EFFBB800CFFB97E0AFFB97E0AFFBB800CFFBB800CFFBB800CFFBB800CFF
+ B97E0AFFBA7F0BFFBB800CFFBB800CFFBB800CFFBB800CFFBA7F0BFFB97E0AFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BF8010FFC08111FFC18212FFBF8010FFBC7D0DFFBB7C0CFFBC7D0DFFBE800EFF
+ BC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFF
+ BE800EFFBD7F0DFFBB7D0BFFBC7E0CFFBE800EFFBF810FFFBD7F0DFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFB07109FFB2730BFFB4750DFFB3740CFFB2740AFF
+ B2740AFFB3750BFFB5770DFFB37509FFB37509FFB5780AFFB6790BFFB77A0CFF
+ B77A0CFFB6790BFFB6790BFFB4760AFFB4760AFFB4760AFFB5770BFFB5770BFF
+ B6780CFFB6780CFFB6780CFFB7790DFFB7790DFFB7790DFFB7790DFFB6780CFF
+ B6780CFFB6780CFFB4790CFFB77B11FFB27910FFAD7510FF9C722FFF877673FF
+ 747DA9FF5A79C8FF4474CCFF4D87CFFF4D8AC8FF518AC2FF6598D0FF6B97D2FF
+ 517FBFFF4074C0FF3E76C8FF3A70C7FF3E70C8FF3B6ABEFF3C66B9FF456BBDFF
+ 4366B6FF3C5BAAFF3957A4FF344F99FF384F93FF3C4E89FF444E7DFF525472FF
+ 5A5465FF56484CFF4C3932FF4B2E1FFF54351EFF503618FF4D3315FF52371CFF
+ 543619FF5A3814FF694110FF8F631CFFA6741CFFB57C19FFB77B11FFB7770BFF
+ B97A0CFFB97D0BFFB97D0BFFB87A10FFB87911FFB87911FFB87911FFB87A10FF
+ B87A10FFB7790FFFB7790FFFBB7D11FFBA7C10FFBA7D0FFFB97C0EFFB77A0CFF
+ B6790BFFB5780AFFB47709FFB87A0EFFB97B0FFFB97B0FFFBA7C10FFBA7C10FF
+ BA7C10FFB97B0FFFB87A0EFFB97B0FFFB5770BFFB6780CFFBC7E12FFBC7E12FF
+ B6780CFFB5770BFFB97C0EFFB47B08FFB47B07FFB57B0AFFB77C0EFFB87C12FF
+ B87B13FFB87911FFB7790FFFB7790DFFB87A0EFFB87A0EFFB97B0FFFB97B11FF
+ B97A12FFB97815FFB97815FFBC7E1AFFBD7D17FFBF7B10FFC07C11FFC2801AFF
+ BD832AFFB88B47FFB89769FFEAD5BFFFFFF8F0FFFFF8F8FFF0EBEDFFF7F4F6FF
+ EDEEF2FFE1E4E9FFEEF0F8FFEEEDF6FFF7F3F9FFF6F1F2FFEFEBEAFFF0EBECFF
+ F2EFF1FFF1EFF5FFFAF0F6FFFFFCF7FFDCBDA6FFA57845FF9F681FFFBA7E24FF
+ C38422FFBB7E1CFFBE821EFFBA7F12FFBC800FFFBC800FFFBC800FFFBB7F0EFF
+ B97D0CFFB77B0AFFB67A09FFBB7F0EFFBA7E0DFFBA7E0DFFB97D0CFFB97D0CFF
+ BA7E0DFFBB7F0EFFBC800FFFBB7F0DFFBB7F0DFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBB7E10FFBB7E10FFBD8012FFBB7E10FFB87A0EFFB87A0EFFBB7D11FF
+ BE8014FFBE8016FFBC7E12FFBF8311FFBC810DFFB87D09FFB87D09FFBB800CFF
+ BD820EFFBD820EFFBB800CFFBA7F0BFFBA7F0BFFBA7F0BFFBB800CFFBB800CFF
+ BA7F0BFFBA7F0BFFBA7E0CFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBC7D0DFFBC7D0DFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBF8010FFC08111FFC18212FFC08111FFBD7E0EFF
+ BB7C0CFFBB7C0CFFBC7E0CFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFB87A08FFB97B09FFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFB97B09FFB87A08FFBE800EFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BE800EFFBD7F0DFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FFB2730BFF
+ B4750DFFB3740CFFB2740AFFB2740AFFB3750BFFB5770DFFB37509FFB4760AFF
+ B5780AFFB6790BFFB77A0CFFB6790BFFB6790BFFB5780AFFB4760AFFB4760AFF
+ B5770BFFB5770BFFB6780CFFB6780CFFB7790DFFB7790DFFB7790DFFB7790DFF
+ B7790DFFB7790DFFB6780CFFB6780CFFB6780CFFB4790CFFB77F12FFB07A0FFF
+ AE750CFFA07225FF8A715DFF7B7997FF6379C1FF4D76CBFF4F84CDFF508CC7FF
+ 5E96C5FF8EBDE9FF9CC1F3FF6E93CFFF4A7DC3FF457ECDFF3D73CAFF3E72CCFF
+ 3B6CC2FF3C6ABEFF446EC1FF4267BBFF385CB0FF395BAEFF3051A0FF304D97FF
+ 344D8DFF3D4F84FF495179FF4D506CFF524F5FFF5B5053FF503A2FFF4F3322FF
+ 442C16FF483018FF533A20FF563716FF5F3A0EFF774B0EFFA27220FFB07B1AFF
+ B97E17FFB97B11FFB6770FFFB7790DFFB97D0CFFB77E0BFFB97B11FFB97A12FF
+ B87911FFB87911FFB87A10FFB7790FFFB7790FFFB7790FFFBB7D11FFBB7D11FF
+ B97C0EFFB87B0DFFB77A0CFFB6790BFFB5780AFFB5780AFFBC7E12FFBC7E12FF
+ BA7C10FFB97B0FFFB7790DFFB7790DFFB7790DFFB87A0EFFB97B0FFFB7790DFF
+ BA7C10FFC18317FFC18317FFBA7C10FFB7790DFFB97C0EFFB37A06FFB57D06FF
+ B67D0AFFB77D0CFFB77C0FFFB67A10FFB67A10FFB77B11FFB57A0DFFB57A0DFF
+ B57A0DFFB67A10FFB67812FFB77915FFB87819FFB8781AFFB5781AFFBB7E1CFF
+ BD7910FFC07812FFC47E23FFB77C34FFB78D5EFFCDB49AFFFDF3E9FFF9F5F4FF
+ F3F1F1FFF2EFF1FFF6F1F3FFF0ECF2FFE8E7F1FFEDEBF7FFF2EBF8FFF6EFF6FF
+ F6F1F0FFF2EFEBFFF1EDECFFF1EEF0FFF8F1F8FFFFF6F7FFFFEADAFFCBA680FF
+ AD7937FFB57925FFBF7E1CFFBE7C15FFBA7E1AFFBC811AFFBC8114FFBD8110FF
+ BB7F0EFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFB97D0CFFBC800FFFBB7F0EFF
+ BA7E0DFFB97D0CFFB97D0CFFBA7E0DFFBA7E0DFFBB7F0EFFBA7E0CFFBA7E0CFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7D0FFFBA7D0FFFBE8113FFBA7D0FFF
+ B87A0EFFBA7C10FFBD7F13FFBE8014FFBD7F15FFBC7E12FFBF8312FFBC800EFF
+ B87C0AFFB87C0AFFBB7F0DFFBD810FFFBD810FFFBB7F0DFFBB7F0DFFBA7E0CFF
+ BA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBB7F0DFFBB7C0CFFBC7D0DFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBF8010FFBF8010FF
+ BE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBE7F0FFFC08111FF
+ C18212FFBF8010FFBC7D0DFFBA7B0BFFBA7B0BFFBB7D0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBE800EFFBE800EFF
+ BF810FFFBF810FFFBF810FFFBF810FFFBE800EFFBE800EFFBD7F0DFFBC7E0CFF
+ BA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBC7E0CFFBB7D0BFFBC7E0CFFBC7E0CFF
+ BC7E0CFFB07109FFB2730BFFB4750DFFB3740CFFB2740AFFB2740AFFB3750BFF
+ B5770DFFB4760AFFB5770BFFB6790BFFB6790BFFB6790BFFB6790BFFB5780AFF
+ B47709FFB5770BFFB5770BFFB5770BFFB6780CFFB6780CFFB7790DFFB7790DFF
+ B7790DFFB5770BFFB5770BFFB6780CFFB6780CFFB7790DFFB7790DFFB87A0EFF
+ B67B0EFFB58012FFB07B0DFFB2770AFFA6701DFF8C6B44FF81737EFF6F7AB4FF
+ 5778C8FF5489D2FF528FCDFF6198C5FF99C8EEFFB1D0FDFF7B9AD1FF4F7FBFFF
+ 467FCAFF4077CCFF3E73CDFF3B6DC5FF3D6CC2FF436FC3FF3D66BBFF365DB2FF
+ 3A5FB4FF375CAEFF3253A2FF345097FF3A528EFF3F4E7FFF3F486DFF474B67FF
+ 5D5867FF5C4A4BFF533C34FF412E21FF453120FF4F3622FF513211FF633B07FF
+ 82550CFFAE7A1CFFB77E15FFB97D13FFB97A12FFB67814FFB57A13FFB57D0EFF
+ B47C0DFFBB7F15FFBC7D15FFBB7C14FFB97A12FFB7790FFFB5770DFFB4760CFF
+ B3750BFFB87A0EFFB7790DFFB77A0CFFB77A0CFFB77A0CFFB87B0DFFB97C0EFF
+ BA7D0FFFBD7F13FFBD7F13FFBC7E12FFB97B0FFFB6780CFFB5770BFFB6780CFF
+ B87A0EFFB5770BFFB6780CFFB97B0FFFBE8014FFBE8014FFB97B0FFFB6780CFF
+ B5780AFFB47B07FFB67E07FFB77E0BFFB77D0CFFB67B0DFFB67B0EFFB77B11FF
+ B97D13FFB97E11FFB97E11FFB87C12FFB97C14FFBA7C16FFBB7C1AFFBC7C1EFF
+ BB7C20FFB77C1FFFB57919FFBA7611FFC27D1CFFBD7A2BFFAB743BFFBB9779FF
+ E8D6CBFFFAF6F5FFE3E7E8FFE8EAEBFFF5F4F6FFF9F3F8FFF5EEF5FFF0ECF7FF
+ EDE9F5FFF6EEF9FFF2ECF1FFF3F0ECFFF0F0EAFFEEECEBFFF8F3F4FFFFF4F6FF
+ FCE9E1FFDDBDA0FFBA905BFFB77F30FFC58526FFBC7B12FFB8780CFFBB7E16FF
+ B67C12FFBC8113FFBD8110FFBB7F0EFFB97D0CFFB97D0CFFB97D0CFFBB7F0EFF
+ BC800FFFBC800FFFBC800FFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFBA7E0DFF
+ BA7E0DFFBA7E0CFFBA7E0CFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7D0FFF
+ BA7D0FFFBD8012FFBA7D0FFFB97B0FFFBC7E12FFBD7F13FFBB7D11FFBB7D13FF
+ BC7E12FFBC800FFFBB7F0DFFB97D0BFFB97D0BFFBB7F0DFFBB7F0DFFBB7F0DFF
+ BB7F0DFFBB7F0DFFBB7F0DFFBA7E0CFFB97D0BFFB97D0BFFBA7E0CFFBB7F0DFF
+ BB7F0DFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBB7C0CFF
+ BA7B0BFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBC7D0DFF
+ BD7E0EFFC08111FFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFF
+ BB7C0CFFBE7F0FFFBF8010FFBF8010FFBE7F0FFFBB7C0CFFBA7B0BFFBB7C0CFF
+ BD7F0DFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBB7D0BFFBA7C0AFFBB7D0BFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FFB2730BFFB4750DFFB3740CFF
+ B2740AFFB2740AFFB3750BFFB5770DFFB4760AFFB5770BFFB6790BFFB6790BFF
+ B6790BFFB6790BFFB5780AFFB47709FFB5770BFFB5770BFFB6780CFFB6780CFF
+ B7790DFFB7790DFFB7790DFFB7790DFFB37509FFB4760AFFB5770BFFB6780CFF
+ B7790DFFB87A0EFFB97B0FFFB87D10FFB17C0EFFB1790CFFB97A0CFFAD7215FF
+ 92682DFF877061FF777AA0FF5F79BFFF598AD8FF5391D8FF5790C3FF8BBCE4FF
+ ADCAF6FF7E9CCDFF5684BEFF467FC4FF4379CCFF4076CDFF3D70C6FF3F70C6FF
+ 4472C6FF3C68BCFF325DB4FF3760B5FF3C63B8FF375CAEFF3858A3FF3C579AFF
+ 3B4F88FF364674FF3D486EFF50536FFF5D5360FF58494DFF47393AFF41312BFF
+ 453021FF4C2F10FF6A410AFF916010FFB47D15FFB97D0CFFB87A0EFFB97913FF
+ B67A1AFFB47A1AFFB07C12FFB07A0FFFBA7D15FFBB7C14FFBA7B13FFB97A12FF
+ B7790FFFB5770DFFB4760CFFB4760CFFB87A0EFFB87A0EFFB77A0CFFB6790BFF
+ B77A0CFFB87B0DFFB97C0EFFBA7D0FFFB87A0EFFBA7C10FFBC7E12FFBB7D11FF
+ B97B0FFFB7790DFFB7790DFFB87A0EFFB5770BFFB87A0EFFB97B0FFFB7790DFF
+ B7790DFFB97B0FFFB87A0EFFB5780AFFB77B09FFB97E0AFFBB7F0DFFBA7E0DFF
+ B67B0DFFB67B0EFFB87D10FFBA7F12FFB97E11FFB87D10FFB67C12FFB67C13FF
+ B77B17FFB97C1CFFBB7C20FFBC7D23FFBF8427FFB37618FFBB7A18FFBE7E26FF
+ B37735FFB9895FFFDDC0B1FFFCF0F0FFEDF0F4FFDEE7EBFFE6EAEBFFF3F2F4FF
+ F6F0F5FFF4EDF4FFF3EDF8FFF0EAF5FFF3EBF2FFEDE8E9FFEEF0EAFFEBF0E7FF
+ E9EDE8FFFBF8F4FFF2E4DEFFCBB29EFFB38D5DFFB5853DFFBE8425FFC08216FF
+ BC7B0EFFC08111FFC18618FFB57D0EFFB97F0EFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBC800FFFBC800FFFBD8110FFBD8110FFBC800FFFBB7F0EFFB97D0CFF
+ B97D0CFFB97D0CFFBA7E0DFFBA7E0DFFB97D0BFFB97D0BFFB97D0CFFB97D0CFF
+ B97D0CFFB97D0CFFB97C0EFFB97C0EFFBC7F11FFBA7D0FFFBB7D11FFBE8014FF
+ BD7F13FFB97B0FFFB97B11FFBE8014FFB87C0BFFBA7E0CFFBB7F0DFFBB7F0DFF
+ BA7E0CFFB97D0BFFB97D0BFFBA7E0CFFBC800EFFBB7F0DFFBA7E0CFFB97D0BFF
+ B97D0BFFBA7E0CFFBB7F0DFFBC800EFFBA7B0BFFBB7C0CFFBD7E0EFFBF8010FF
+ BF8010FFBD7E0EFFBB7C0CFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFBD7E0EFF
+ BB7C0CFFBA7B0BFFBC7D0DFFBE7F0FFFC08111FFC08111FFBF8010FFBE7F0FFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFFBC7D0DFF
+ BA7B0BFFBA7B0BFFBC7D0DFFBF810FFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFB97B09FFB97B09FF
+ B97B09FFB97B09FFBA7C0AFFBA7C0AFFBD7F0DFFBB7D0BFFB97B09FFBA7C0AFF
+ BC7E0CFFBD7F0DFFBC7E0CFFBA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FF
+ B2730BFFB4750DFFB3740CFFB2740AFFB2740AFFB3750BFFB5770DFFB5770BFF
+ B5770BFFB6790BFFB6790BFFB6790BFFB5780AFFB47709FFB47709FFB5770BFF
+ B5770BFFB6780CFFB6780CFFB7790DFFB7790DFFB7790DFFB87A0EFFB27408FF
+ B37509FFB4760AFFB6780CFFB7790DFFB97B0FFFBA7C10FFB97E11FFAD780AFF
+ B0790AFFBF7C0FFFB57411FF9A691BFF8F7148FF817C8BFF677BB2FF5280CEFF
+ 518CDCFF518DC8FF87B9E7FFB0D0FBFF8EABD8FF6492C8FF4F85C6FF467BCBFF
+ 4379CEFF4074C7FF4375C8FF4675C9FF3B69BDFF325EB2FF3561B5FF3C65BAFF
+ 3B61B3FF395DABFF3C5AA1FF3A5391FF344980FF354776FF434C72FF55526CFF
+ 595162FF4B424FFF3D3235FF3D2A22FF4C2E11FF73480FFFA06C19FFB67D10FF
+ BA7B08FFB9780BFFB97913FFB87B1DFFB47B1EFFAC7B15FFAD790FFFB37910FF
+ B77810FFB77810FFB87911FFB87A10FFB87A10FFB87A10FFB97B11FFBD7F13FF
+ BB7D11FFB97C0EFFB77A0CFFB6790BFFB5780AFFB6790BFFB6790BFFB37509FF
+ B7790DFFBC7E12FFBE8014FFBB7D11FFB97B0FFFB87A0EFFB87A0EFFB97B0FFF
+ BD7F13FFBB7D11FFB4760AFFB4760AFFBB7D11FFBD7F13FFB97C0EFFB87C0BFF
+ BA7E0CFFBB7E10FFBB7E10FFB77C0FFFB67B0EFFB97E11FFBC8114FFB57A0DFF
+ B37A0DFFB2780EFFB2780FFFB37713FFB47818FFB8791DFFB87B1EFFC6892CFF
+ B3781BFFB87C22FFAF7A2AFFA4753FFFD2AE90FFFFF0E9FFFFFAFFFFEDF0F8FF
+ E8F1F5FFEAEFF0FFEBEDEEFFECE8EEFFEEE7EEFFF0ECF2FFF6EFF6FFEBE4E7FF
+ E8E3E4FFEDF1EBFFE9F1EAFFE7EDE8FFFAF8F0FFDECEBEFF977857FF9A6F30FF
+ B6832DFFBF851EFFB67A09FFBB7F0EFFCC901FFFC98F1EFFBB8110FFB87C0BFF
+ B97D0CFFBB7F0EFFBD8110FFBE8211FFBD8110FFBC800FFFBC800FFFBD8110FF
+ BC800FFFBB7F0EFFB97D0CFFB97D0CFFB97D0CFFB97D0CFFBA7E0DFFB97D0BFF
+ B97D0BFFB97D0CFFB97D0CFFB97D0CFFB97D0CFFB97C0EFFB97C0EFFBC7F11FF
+ BA7D0FFFBC7E12FFBF8115FFBD7F13FFB7790DFFB87A10FFBF8115FFB57908FF
+ B97D0BFFBC800EFFBC800EFFBA7E0CFFB87C0AFFB87C0AFFB97D0BFFBC800EFF
+ BB7F0DFFBA7E0CFFB97D0BFFB97D0BFFBA7E0CFFBB7F0DFFBC800EFFBA7B0BFF
+ BB7C0CFFBD7E0EFFBF8010FFBF8010FFBD7E0EFFBB7C0CFFBA7B0BFFBA7B0BFF
+ BD7E0EFFBE7F0FFFBD7E0EFFBB7C0CFFBA7B0BFFBC7D0DFFBE7F0FFFC08111FF
+ C08111FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBA7B0BFFB97A0AFFBA7B0BFFBD7E0EFFC18212FFBC7E0CFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBE800EFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFFBD7F0DFF
+ BB7D0BFFB97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBB7D0BFFBA7C0AFFBC7E0CFF
+ BC7E0CFFBC7E0CFFAF7008FFB07109FFB1720AFFB3740CFFB3750BFFB3750BFF
+ B2740AFFB2740AFFB4760AFFB4760AFFB5780AFFB5780AFFB6790BFFB6790BFF
+ B6790BFFB77A0CFFB87A0EFFB7790DFFB6780CFFB6780CFFB87A0EFFBA7C10FF
+ BC7E12FFBE8014FFB5770BFFB6780CFFB7790DFFB97B0FFFB97B0FFFB7790DFF
+ B6780CFFB3780BFFB07B0DFFB07809FFBF770BFFC37C14FFB17A19FF94712FFF
+ 807365FF6F7B9DFF5880CBFF4D85DEFF5492D9FF6097D0FF99BEEAFFB1D3FEFF
+ 77A6DAFF4C81C0FF477BC7FF4C7ED0FF4A7CCEFF4272C4FF3E6DBFFF3F6EC0FF
+ 3F6BBEFF3965B8FF3F69BCFF335BADFF3258A6FF3657A0FF375394FF3C5692FF
+ 41568DFF3E4E7DFF4D5076FF4A4866FF535167FF59535EFF483734FF482A11FF
+ 784D14FFAD7722FFB97C0EFFC17F08FFBC7A09FFB5740BFFB27416FFB2791CFF
+ AD7C16FFA8750DFFB37910FFB87911FFB87911FFB97A12FFBA7C12FFBA7C12FF
+ BB7D13FFBB7D13FFC08216FFBD7F13FFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFF
+ B87B0DFFB6790BFFB6780CFFBB7D11FFBB7D11FFB6780CFFB7790DFFBE8014FF
+ C08216FFBC7E12FFC98B1FFFC88A1EFFC4861AFFC08216FFBB7D11FFB7790DFF
+ B4760AFFB27408FFB47709FFBA7D0FFFBB7D13FFB7790FFFB67A10FFBA7E14FF
+ BA7E14FFB4790CFFBD8417FFB88011FFB2790CFFAF770CFFB27811FFB37A17FF
+ B5781AFFB4771AFFBB7C20FFB4781EFFAF7D2AFFA37936FFAD8D62FFF1D9C5FF
+ FFFEFEFFE2DFE8FFE9EDF2FFE8EFF2FFEBF0F1FFEFF1F2FFF3EFF5FFF1EDF3FF
+ F0EDEFFFF1ECEDFFF9F3F4FFEEE9EAFFEFF6F3FFE4EFECFFE8EFECFFF6F1E8FF
+ D3BDA4FFAC8558FFB18034FFB67E1FFFB67E13FFB88011FFB97F15FFB67D10FF
+ B57D0CFFB9800DFFB97D0CFFB97D0CFFBA7E0DFFBB7F0EFFBC800FFFBD8110FF
+ BE8211FFBE8211FFBA7E0DFFB97D0CFFB87C0BFFB87C0BFFB87C0BFFB97D0CFF
+ BA7E0DFFBA7E0DFFB97D0BFFB97D0BFFB87C0BFFB87C0BFFB77B0AFFB77B0AFF
+ B77A0CFFB6790BFFB87B0DFFBB7E10FFBD7F13FFBD7F13FFBB7D11FFBA7C10FF
+ BC7E14FFBE8014FFBB7E10FFB97D0CFFB87C0BFFBA7E0DFFBC800FFFBB7F0EFF
+ B87C0BFFB57908FFBC800FFFBC800FFFBD8110FFBD8110FFBD8110FFBB7F0EFF
+ B97D0CFFB87C0BFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBC7D0DFFBF8010FFC18212FFC08111FFBE7F0FFFBB7C0CFF
+ BB7C0CFFBC7D0DFFBD7E0EFFBC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFF
+ BD7E0EFFBE7F0FFFB97A0AFFBB7C0CFFBE7F0FFFBF8010FFBF8010FFBE7F0FFF
+ BB7C0CFFB97A0AFFBB7D0BFFBD7F0DFFBE800EFFBF810FFFBE800EFFBC7E0CFF
+ BA7C0AFFB87A08FFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFF
+ B97B09FFB97B09FFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BE800EFFBE800EFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBE800EFFBD7F0DFF
+ BC7E0CFFBB7D0BFFB97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BA7C0AFFB97B09FFBA7C0AFFBA7C0AFFBA7C0AFFB1720AFFB2730BFFB3740CFF
+ B4750DFFB4760CFFB3750BFFB2740AFFB2740AFFB5770BFFB5770BFFB5780AFF
+ B6790BFFB6790BFFB77A0CFFB77A0CFFB77A0CFFB5770BFFB6780CFFB7790DFF
+ B87A0EFFB97B0FFFBA7C10FFBA7C10FFBA7C10FFB87A0EFFB87A0EFFB7790DFF
+ B7790DFFB7790DFFB7790DFFB87A0EFFB67B0EFFB37B0EFFB3780AFFBF770BFF
+ C47D0EFFB57A0CFF9B731BFF86714BFF757782FF5D79BAFF4E7ED6FF508BDAFF
+ 5690D2FF7FABDAFFA2C9F5FF87B6EAFF5B8ECCFF4F82CBFF4D7ECCFF4778C8FF
+ 3F70C0FF3C6BBCFF3E6DBEFF416EBFFF416EBFFF3B65B8FF3058AAFF2E54A2FF
+ 31549EFF335297FF3B5798FF3F5896FF3E5289FF414B7BFF444970FF515473FF
+ 5D5B6EFF55474BFF503723FF744B1AFFA06C1FFFBE8119FFC3800DFFC07C0BFF
+ BD7C10FFB97A18FFB47A1AFFAF7C14FFB07C12FFB47A11FFB87911FFB87911FF
+ B87911FFB87A10FFB7790FFFB7790FFFB7790FFFBB7D11FFB87A0EFFB6790BFF
+ B77A0CFFBA7D0FFFBC7F11FFBD8012FFBD8012FFB4760AFFB6780CFFB7790DFF
+ B7790DFFB97B0FFFBE8014FFC18317FFC18317FFC08216FFBF8115FFBE8014FF
+ BD7F13FFBC7E12FFBB7D11FFBA7C10FFBA7C10FFB7790DFFBA7C12FFBB7C14FF
+ BA7B13FFB97C14FFBB7E16FFBA7E14FFB67D10FFB77F10FFB57E0FFFB57D10FF
+ B47E13FFB78018FFBA811EFFBD8324FFBF8427FFB37619FFAE7722FFB3883FFF
+ BD9F68FFD2BE9FFFF6ECE2FFFFFEFFFFEFEEF7FFEBEEF2FFEBF0F1FFECF0F1FF
+ EFF0F4FFF0EEF4FFEFEEF2FFF0EEEDFFF1EEEAFFF6F0F1FFEFEDEDFFE3EBEBFF
+ E4EFEDFFF9FCFAFFF6EDDFFFCEB290FFB3864DFFB8822DFFBB801CFFB98017FF
+ BC831AFFBB831EFFB67F17FFB97E10FFBB7F0DFFB97D0CFFBA7E0DFFBA7E0DFF
+ BB7F0EFFBC800FFFBC800FFFBD8110FFBD8110FFB97D0CFFB97D0CFFB87C0BFF
+ B87C0BFFB87C0BFFB97D0CFFBB7F0EFFBC800FFFBB7F0DFFBB7F0DFFBB7F0EFF
+ BA7E0DFFBA7E0DFFB97D0CFFB97C0EFFB97C0EFFB97C0EFFBA7D0FFFBC7E12FF
+ BB7D11FFB97B0FFFB97B0FFFBC7E14FFBE8014FFBD8012FFBB7F0EFFB87C0BFF
+ B87C0BFFBA7E0DFFBB7F0EFFB97D0CFFB87C0BFFBB7F0EFFBC800FFFBD8110FF
+ BD8110FFBC800FFFBB7F0EFFBA7E0DFFB97D0CFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBA7B0BFFBC7D0DFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBD7E0EFFC08111FFBF8010FFBD7E0EFF
+ BC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFFBB7C0CFFBC7D0DFFBC7D0DFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBF810FFFBE800EFFBC7E0CFF
+ BA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BE800EFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFF
+ B3740CFFB4750DFFB4750DFFB5760EFFB5770DFFB4760CFFB3750BFFB2740AFF
+ B6780CFFB6780CFFB6790BFFB77A0CFFB77A0CFFB87B0DFFB87B0DFFB87B0DFF
+ B37509FFB5770BFFB7790DFFB97B0FFFBA7C10FFB97B0FFFB87A0EFFB7790DFF
+ BB7D11FFBA7C10FFB87A0EFFB7790DFFB7790DFFB87A0EFFBA7C10FFB97E11FF
+ B77C0FFFB6790BFFC0780CFFC37D0CFFB67C05FFA1730EFF8E6F30FF7B7062FF
+ 6574A2FF587CC8FF4F86D7FF4E89D1FF6395C9FF86B4E3FF8EBDF5FF6999D9FF
+ 5486CEFF4C7DC9FF4575C3FF4373C1FF4171BFFF3E6EBCFF416FBDFF4573C1FF
+ 406BBCFF375EADFF2E54A2FF2E519BFF305097FF38559AFF3D599AFF3F5492FF
+ 3C4981FF434A7BFF4B5279FF5B5C76FF605662FF5E483DFF734E28FF9A6826FF
+ BC8124FFBF7E12FFC07B0EFFC27E13FFBF7D17FFB57711FFB27A0FFFB67E11FF
+ B77A12FFB87911FFB87911FFB77810FFB6780EFFB5770DFFB5770DFFB4760CFF
+ BF8115FFBC7E12FFB87B0DFFB77A0CFFB77A0CFFB97C0EFFB97C0EFFB97C0EFF
+ BD7F13FFBB7D11FFB97B0FFFBA7C10FFBA7C10FFB87A0EFFB97B0FFFBB7D11FF
+ B97B0FFFB97B0FFFBA7C10FFBB7D11FFBC7E12FFBD7F13FFBD7F13FFBE8014FF
+ BD7C13FFBB7912FFBB7C14FFBE7E18FFBC7E18FFBA7D15FFB87E14FFB98013FF
+ B27A0BFFB47D0EFFB77F12FFB88217FFB9821AFFBA8320FFBD8427FFC1882DFF
+ B57A24FFA9782AFFAE8C50FFD1BD94FFF1E7D5FFF6F5F1FFF2F3F7FFF1F4F9FF
+ EEF0F1FFEEF0F0FFECF0F1FFECEFF3FFEEEEF4FFEDEFF0FFF0EFEBFFF1EEE9FF
+ F0EEEEFFF7F9FAFFE9EFF4FFF3F8FBFFFFFEFAFFDFCEBBFFB89569FFB58440FF
+ BF8329FFC0821CFFBC811DFFBF8623FFBD8526FFBA811EFFBB7F15FFBD8012FF
+ BA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBC800FFF
+ B97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFBA7E0DFFBB7F0EFFBC800FFF
+ BE8210FFBD810FFFBD8110FFBD8110FFBC800FFFBC800FFFBB7E10FFBB7E10FF
+ B97C0EFFBA7D0FFFBA7C10FFB97B0FFFB87A0EFFB97B0FFFBB7D13FFBE8014FF
+ BF8214FFBC7F11FFB97C0EFFB87B0DFFB97C0EFFBA7D0FFFBB7E10FFBA7D0FFF
+ BB7E10FFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ B97A0AFFB97A0AFFBA7B0BFFBC7D0DFFBD7E0EFFBE7F0FFFBD7E0EFFBD7E0EFF
+ BF8010FFBE7F0FFFBD7E0EFFBB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBC7E0CFFBE800EFFBF810FFF
+ B97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBA7C0AFFBA7C0AFFB4750DFFB5760EFFB6770FFFB6770FFFB6780EFF
+ B5770DFFB4760CFFB3750BFFB6780CFFB7790DFFB77A0CFFB77A0CFFB87B0DFF
+ B87B0DFFB97C0EFFB97C0EFFB4760AFFB5770BFFB6780CFFB87A0EFFB87A0EFF
+ B87A0EFFB7790DFFB7790DFFBB7D11FFBA7C10FFB97B0FFFB97B0FFFB97B0FFF
+ B97B0FFFBA7C10FFBB7D11FFB97B0FFFB9790DFFBF7A0BFFBF7D0CFFB77D06FF
+ A7760AFF9B711EFF886E46FF737184FF687FB7FF5282CAFF4C87CFFF548DC1FF
+ 679CCEFF7EADEAFF6C9BDFFF5786D0FF4A7BC7FF4677C3FF4C7DC9FF4B7BC9FF
+ 4171BFFF3E6CBAFF406EBCFF4D78C7FF426BBAFF375DABFF3054A0FF30519AFF
+ 33539AFF36549BFF395396FF3C4C8EFF404C86FF3F4C7AFF4D5376FF5D5A70FF
+ 615256FF70523FFF91683BFFA8762AFFB27819FFBB7913FFBD7B12FFBB7811FF
+ B3750BFFB2770AFFB37B0CFFB77B11FFB97A12FFB87911FFB87911FFB87A10FF
+ B7790FFFB7790FFFB7790FFFC18317FFBE8014FFBA7D0FFFB77A0CFFB5780AFF
+ B6790BFFB77A0CFFB87B0DFFC4861AFFBD7F13FFBB7D11FFBD7F13FFBA7C10FF
+ B4760AFFB37509FFB87A0EFFB97B0FFFB97B0FFFB97B0FFFBA7C10FFBA7C10FF
+ BA7C10FFBA7C10FFBA7C10FFBD7C13FFB97710FFB97A12FFBF8018FFBD7F19FF
+ B87B13FFB57C0FFFBA8213FFB57E0FFFB37E0FFFB47F11FFB37F15FFB57F1AFF
+ B57E1DFFB57C21FFB07924FFC48F3FFFAC813EFFB19768FFDDD1B5FFF7F6ECFF
+ EFF3F4FFE8ECF1FFECEFF4FFEFF1F2FFEFF1F1FFEFF1F2FFECEFF3FFEBEEF2FF
+ ECEEEFFFEFEFE9FFEFEFE9FFE5E7E7FFEFF3F4FFE6E9EEFFF8F6F6FFF7EBE1FF
+ C2A88AFFA97D47FFAD772AFFC28525FFC1811BFFBC7F1DFFBD8324FFBC8326FF
+ BA8020FFBD7E16FFC08014FFBB7E10FFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBC800FFFBC800FFFBA7E0DFFB97D0CFFB97D0CFF
+ B97D0CFFB97D0CFFBA7E0DFFBE8210FFBD810FFFBD8110FFBD8110FFBC800FFF
+ BC800FFFBB7E10FFBB7E10FFBA7D0FFFB97C0EFFB87A0EFFB7790DFFB7790DFF
+ B97B0FFFBB7D13FFBD7F13FFBD7F13FFBD8012FFBB7E10FFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBA7D0FFFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FF
+ BA7D0FFFBA7D0FFFBA7D0FFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBB7C0CFFBC7D0DFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFFBC7D0DFF
+ BE7F0FFFC08111FFC18212FFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFB87A08FFBA7C0AFFBC7E0CFFBE800EFFBF810FFF
+ BE800EFFBD7F0DFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ BC7E0CFFBB7D0BFFB97B09FFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFB4750DFFB5760EFF
+ B6770FFFB77810FFB7790FFFB6780EFFB5770DFFB4760CFFB6780CFFB7790DFF
+ B77A0CFFB77A0CFFB87B0DFFB87B0DFFB97C0EFFB97C0EFFB7790DFFB6780CFF
+ B6780CFFB5770BFFB6780CFFB7790DFFB87A0EFFB97B0FFFB97B0FFFBA7C10FF
+ BB7D11FFBC7E12FFBC7E12FFBB7D11FFBA7C10FFB97B0FFFBC7A11FFBB7A0EFF
+ BB7B0BFFBA7E0CFFB57E0BFFAF7A0CFFAB7615FF9C722FFF816D5CFF797E97FF
+ 577CB4FF4F86C9FF5790C7FF548CC3FF6496D8FF6999E1FF5B8CD6FF4B7DC9FF
+ 4677C5FF4E7FCDFF4F80CEFF4273C1FF3B6BB9FF3F6DBBFF547FCEFF4E77C6FF
+ 4268B6FF375BA7FF3355A1FF33539EFF33539EFF38559FFF3E539EFF3E5194FF
+ 374B82FF40507BFF52587BFF565369FF5E4F53FF775C48FF8B6634FFA2722AFF
+ B37920FFB67814FFB7750FFFB8780CFFB6790BFFB3780AFFB97B11FFB97A12FF
+ BA7B13FFBA7B13FFBA7C12FFBB7D13FFBB7D13FFBB7D13FFB97B0FFFB87A0EFF
+ B77A0CFFB6790BFFB6790BFFB87B0DFFBB7E10FFBE8113FFBE8014FFB97B0FFF
+ B87A0EFFBC7E12FFBB7D11FFB7790DFFB87A0EFFBD7F13FFB97B0FFFB97B0FFF
+ B97B0FFFB97B0FFFB87A0EFFB87A0EFFB87A0EFFB87A0EFFBB7B0FFFB7760DFF
+ B7790FFFBD7F15FFBB7E16FFB67A10FFB37A0DFFB88011FFBC8516FFB68112FF
+ B27C11FFB17C14FFB57E1DFFB57F21FFB27923FFA97424FFBC9049FFB18F59FF
+ CBB794FFF2EAD9FFF5F8F6FFEDF3F8FFEFF3F8FFECEFF4FFF0F2F3FFF0F2F3FF
+ EFF0F4FFEBEEF2FFE9EEEFFFEAEFEEFFEFEEEAFFEDEEEAFFECF2F1FFEDF3F2FF
+ F0EEEEFFFFF8F2FFF4DDC7FFC6A377FFBE8D47FFBD852CFFC38521FFBF8018FF
+ B87B19FFBA7E1EFFBB7E20FFB97C1AFFBC7C16FFC07F16FFBA7D0FFFBA7E0DFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFC08413FFBF8312FF
+ BD8110FFBA7E0DFFB87C0BFFB87C0BFFB77B0AFFB77B0AFFBC800EFFBB7F0DFF
+ BB7F0EFFBB7F0EFFBA7E0DFFBA7E0DFFB97C0EFFB97C0EFFBA7D0FFFB97C0EFF
+ B7790DFFB7790DFFB87A0EFFBA7C10FFBB7D13FFBB7D11FFBA7C10FFBB7E10FF
+ BE8113FFBF8214FFBE8113FFBB7E10FFB97C0EFFB87B0DFFBA7D0FFFBA7D0FFF
+ BA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFBB7E10FFBB7C0CFFBC7D0DFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBB7C0CFFBB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFF
+ BA7B0BFFBA7B0BFFBC7D0DFFBE7F0FFFC08111FFC18212FFBA7B0BFFBB7C0CFF
+ BD7E0EFFBF8010FFBF8010FFBD7E0EFFBB7C0CFFBA7B0BFFB87909FFBA7B0BFF
+ BC7D0DFFBE7F0FFFBF8010FFBE7F0FFFBD7E0EFFBB7C0CFFBE7F0FFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBA7B0BFFB97A0AFFBB7D0BFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFB2730BFFB3740CFFB5760EFFB6770FFFB7790FFFB6780EFFB6780EFF
+ B6780EFFB6780CFFB6780CFFB6790BFFB77A0CFFB77A0CFFB87B0DFFB87B0DFF
+ B87B0DFFB97B0FFFB87A0EFFB6780CFFB5770BFFB5770BFFB6780CFFB87A0EFF
+ BA7C10FFB87A0EFFB97B0FFFBB7D11FFBC7E12FFBC7E12FFBB7D11FFB97B0FFF
+ BA7A0EFFBE7A11FFBB7A0EFFB77B09FFB57E0BFFB37E10FFB27C11FFB97B0FFF
+ AC761FFF8E6A3AFF7D7470FF5A749CFF5183BFFF5893CBFF4D89C5FF5486CEFF
+ 6694E1FF6092DEFF4D81CDFF4576C4FF487CC9FF4C7DCBFF4576C4FF3F70BEFF
+ 4272C0FF4E7CCAFF4F7AC9FF486FBDFF3C62B0FF375BA9FF3256A4FF3256A4FF
+ 3E5DACFF3E59AAFF3D55A1FF385191FF3D5289FF465586FF484E77FF4A4663FF
+ 56484EFF725840FF916C38FFAB7A2EFFB37A1FFFB67814FFBC7B12FFBB7E10FF
+ B87B0DFFB97B11FFBA7B13FFBA7B13FFBB7C14FFBC7E14FFBD7F15FFBD7F15FF
+ BE8016FFB97B0FFFB97B0FFFB97C0EFFB87B0DFFB77A0CFFB6790BFFB87B0DFF
+ BA7D0FFFBE8014FFBB7D11FFBA7C10FFBA7C10FFBA7C10FFB87A0EFFB87A0EFF
+ BB7D11FFB6780CFFB7790DFFB7790DFFB87A0EFFB97B0FFFB97B0FFFBA7C10FF
+ BA7C10FFB97A0CFFB8790BFFB7790DFFBA7C10FFB97E11FFB77C0FFFB47C0DFF
+ B57E0FFFBF8819FFB88315FFB27E14FFB37D18FFB78122FFBD852CFFBD8533FF
+ B58239FFA27D3FFFB89E70FFE8D8C1FFFFFBF4FFF1F4F8FFEAF1FAFFF0F6FDFF
+ EBEEF3FFF2F3F7FFF0F1F5FFEDF0F4FFEBEFF0FFE9EFEEFFE9EEECFFEFEDECFF
+ EDEEECFFDDE8E5FFE4EEE8FFFAF4EFFFF6E3D4FFC8A884FFAA7E43FFB5812EFF
+ BE8621FFC1851BFFBC7E14FFB67812FFB97B17FFBA7C18FFBA7A14FFBC7A13FF
+ BF7F13FFB97C0EFFB97D0CFFB97D0CFFB97D0CFFBA7E0DFFBA7E0DFFBA7E0DFF
+ BA7E0DFFC18514FFC08413FFBD8110FFBB7F0EFFB97D0CFFB87C0BFFB77B0AFF
+ B77B0AFFBA7E0CFFBA7E0CFFBA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87B0DFF
+ B87B0DFFB97C0EFFB87B0DFFB87A0EFFB97B0FFFBB7D11FFBC7E12FFBB7D13FF
+ BA7C10FFB7790DFFBA7D0FFFBE8113FFC08315FFBE8113FFBB7E10FFB87B0DFF
+ B6790BFFBA7D0FFFB97C0EFFB97C0EFFB87B0DFFB97C0EFFBA7D0FFFBB7E10FF
+ BB7E10FFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBB7C0CFF
+ BA7B0BFFBD7E0EFFBE7F0FFFBF8010FFBC7D0DFFB97A0AFFB87909FFBA7B0BFF
+ BC7D0DFFBF8010FFBE7F0FFFBD7E0EFFBB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFF
+ BC7D0DFFB97A0AFFBB7C0CFFBE7F0FFFC08111FFC08111FFBE7F0FFFBB7C0CFF
+ B97A0AFFBE7F0FFFBD7E0EFFBB7C0CFFBA7B0BFFBA7B0BFFBC7D0DFFBE7F0FFF
+ BF8010FFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFFBB7C0CFF
+ BB7C0CFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFF
+ BE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FFB1720AFFB3740CFFB5760EFF
+ B6780EFFB7790FFFB7790FFFB7790FFFB5770BFFB5770BFFB5780AFFB6790BFF
+ B6790BFFB77A0CFFB77A0CFFB77A0CFFB97B0FFFB97B0FFFB87A0EFFB87A0EFF
+ B87A0EFFB87A0EFFB87A0EFFB87A0EFFB97B0FFFB97B0FFFBA7C10FFBA7C10FF
+ BA7C10FFBA7C10FFB97B0FFFBB7B0FFFBF7B12FFBB7A0EFFB27C07FFAD7B09FF
+ AC7B15FFB37B16FFBF7B0AFFB9760FFFA27125FF806C49FF5F7287FF507DB0FF
+ 4F8AC2FF4F8CCCFF5182D0FF5B8ADCFF5B8FDCFF4A80CDFF4275C5FF457ACAFF
+ 4C7FCFFF497CCCFF4376C6FF4374C4FF4775C3FF507BCAFF4B74C3FF4067B6FF
+ 375EADFF3055A5FF3055A7FF3E60B4FF3C5CB5FF3655AAFF35559CFF375695FF
+ 37508EFF394C85FF3D4678FF414060FF584C4CFF796040FF9A7335FFAD7B29FF
+ B57B1CFFB77A12FFB77C0FFFB97E10FFBA7C12FFBA7B13FFBA7B13FFBA7B13FF
+ BA7C12FFBB7D13FFBB7D13FFBB7D13FFBA7C10FFBC7E12FFBD8012FFBB7E10FF
+ B77A0CFFB47709FFB37608FFB47709FFBE8014FFBF8115FFBD7F13FFB97B0FFF
+ B7790DFFB97B0FFFB97B0FFFB7790DFFB7790DFFB7790DFFB87A0EFFB87A0EFF
+ B97B0FFFBA7C10FFBA7C10FFBB7E10FFB97A0AFFBB7C0CFFBD7E10FFBA7D0FFF
+ B87D0FFFBA7F11FFB77F10FFB47D0EFFBC8516FFBA8517FFB78319FFB67F1CFF
+ B78025FFBD8631FFC99041FFC79652FFAC8D56FFD4C19CFFFDF0E2FFFDF7F8FF
+ EEEDF6FFEAEEF9FFEFF2FAFFEBEEF3FFF2F1FAFFF1F1F7FFEDF0F5FFEAEFF0FF
+ E9EEECFFEBEEECFFEFEDEDFFEBEDEDFFDDEEE5FFECF8ECFFFFFCEFFFE2C9AFFF
+ AB8251FF9D6C22FFAF7A19FFBF8718FFBD8312FFBA7D0FFFBA7910FFBD7C13FF
+ C07F13FFBD7C0FFFBB7B0FFFBC7D0FFFB77B0AFFB87C0BFFB87C0BFFB97D0CFF
+ BA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBF8312FFBE8211FFBC800FFFBB7F0EFF
+ BA7E0DFFB97D0CFFBA7E0DFFBA7E0DFFBB7F0DFFBA7E0CFFBA7E0DFFBA7E0DFF
+ B97D0CFFB97D0CFFB87B0DFFB87B0DFFB97C0EFFB87B0DFFB97B0FFFBB7D11FF
+ BE8014FFBE8014FFBB7D13FFB87A0EFFB7790DFFBA7D0FFFBE8113FFBE8113FF
+ BB7E10FFB87B0DFFB77A0CFFB77A0CFFB97C0EFFB97C0EFFB87B0DFFB87B0DFF
+ B87B0DFFB97C0EFFBB7E10FFBC7F11FFBA7B0BFFBB7C0CFFBD7E0EFFBF8010FF
+ BF8010FFBD7E0EFFBB7C0CFFBA7B0BFFBB7C0CFFBF8010FFC18212FFBE7F0FFF
+ B97A0AFFB77808FFBC7D0DFFC18212FFC08111FFBF8010FFBD7E0EFFBC7D0DFF
+ BB7C0CFFBA7B0BFFBA7B0BFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFF
+ BE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBF8010FFBE7F0FFFBC7D0DFFBA7B0BFF
+ BA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BC7D0DFFBD7E0EFFC08111FFC18212FFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBC7E0CFFBC7E0CFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFAE6E08FF
+ B07109FFB2720CFFB4750DFFB6770FFFB77810FFB77810FFB7790FFFB4760CFF
+ B4760AFFB5770BFFB5770BFFB6780CFFB6790BFFB6780CFFB7790DFFB7790DFF
+ B97B0FFFBA7C10FFBB7D11FFBB7D11FFB97B0FFFB87A0EFFB7790DFFBB7D11FF
+ BA7C10FFB87A0EFFB7790DFFB7790DFFB87A0EFFBA7C10FFBB7D13FFBD7A13FF
+ B87A10FFAD7907FFA97909FFA97812FFB37814FFBF7809FFBA7409FFB57C21FF
+ 8D6B30FF79786EFF627D97FF547FB0FF578CCFFF5183D5FF4C7FD5FF5086D3FF
+ 477EC9FF4278C5FF487DCDFF5285D5FF5283D1FF4B7AC4FF4572BCFF4671C0FF
+ 517CCDFF4D77CAFF3F69BCFF375DAFFF2D52A4FF2E50A4FF3A5CB5FF3B5DB7FF
+ 3155A9FF34549FFF345496FF304B8EFF364C8DFF3D4C8AFF3E4675FF414054FF
+ 5D5147FF83673EFFA17736FFAE7823FFAF730FFFB37706FFBB7F0DFFB97D13FF
+ B87B13FFB87B13FFB77B11FFB87A10FFB87A10FFB7790FFFB7790FFFB3740CFF
+ B57810FFB87B13FFB97D13FFB77B11FFB7790DFFB77A0CFFB87B0DFFB5780AFF
+ BA7C10FFBA7C10FFB6780CFFB7790DFFC08014FFC28216FFBE7E12FFBC7C10FF
+ BC7C10FFBC7C10FFBB7C0EFFBB7B0FFFB87B0DFFB87A0EFFB87B0DFFB97A0AFF
+ BF8010FFC08113FFBA7D0FFFB97E10FFBD8214FFBD8214FFB57D0EFFB88011FF
+ BC8419FFBC841FFFB77F20FFB07A23FFB68131FFC7914AFFCB9F64FFCCB68DFF
+ F4E9D3FFFFFEF7FFF4EFF1FFEDECF5FFF0F3FBFFEFF3F8FFF0F4F9FFF1F3FBFF
+ F1F0F9FFEFEFF5FFECEDF1FFEBEDEDFFECECECFFECEBEFFFEBEDEEFFEDF7F1FF
+ F1F5E9FFF9E8D3FFCCAB84FFAB7B3BFFB27B26FFB47D14FFB57F0DFFB98112FF
+ B67B0DFFBA7A0EFFC18013FFC48212FFBE7F0DFFBA7B0BFFB87C0BFFB67A09FF
+ B77B0AFFB77B0AFFB87C0BFFBA7E0DFFBB7F0EFFBB7F0EFFBC800FFFBC800FFF
+ BC800FFFBB7F0EFFBA7E0DFFBA7E0DFFBB7F0EFFBC800FFFBD8110FFBC800FFF
+ BC800FFFBB7F0EFFBB7F0EFFBA7E0DFFBA7E0DFFBA7D0FFFB97C0EFFB97C0EFF
+ B97C0EFFBA7C10FFBD7F13FFC08216FFC08216FFBB7D11FFB7790DFFB87B0DFF
+ BA7D0FFFBC7F11FFBB7E10FFB87B0DFFB77A0CFFB77A0CFFB97C0EFFB97C0EFF
+ B87B0DFFB77A0CFFB77A0CFFB87B0DFFB97C0EFFBB7E10FFBC7F11FFBA7B0BFF
+ BB7C0CFFBD7E0EFFBF8010FFBF8010FFBD7E0EFFBB7C0CFFBA7B0BFFB87909FF
+ BE7F0FFFC28313FFBF8010FFB97A0AFFB87909FFBE7F0FFFC68717FFBD7E0EFF
+ BC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBB7C0CFF
+ BD7E0EFFBE7F0FFFBF8010FFBE7F0FFFBC7D0DFFBA7B0BFFB87909FFBC7D0DFF
+ BB7C0CFFB97A0AFFB97A0AFFBB7C0CFFBF8010FFC38414FFC68717FFBE800EFF
+ BE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBE800EFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBD7F0DFF
+ BC7E0CFFBA7C0AFFB97B09FFB97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFB1730FFFB47610FFB77915FFB77913FFB57711FFB3750FFF
+ B3750FFFB4770FFFB77A12FFB5790FFFB5790FFFB67A10FFB77B11FFB77C0FFF
+ B3770DFFAF7407FFB3780BFFB4790CFFB57A0DFFB67B0EFFB67B0EFFB57A0DFF
+ B4790CFFB3780BFFB4790CFFB57A0DFFB57A0DFFB57A0DFFB67B0EFFB67B0EFF
+ B77C0FFFB77B11FFB87E15FFB57C13FFAF7B11FFAD790EFFAD780AFFAF750BFF
+ B5730DFFB57110FFAF7113FFA57424FF8C7139FF797562FF7180A0FF6083C5FF
+ 4B7DD5FF4982DDFF4B84CFFF4078BFFF4276C2FF4C80CDFF4B7EC7FF6491D5FF
+ 769BD9FF4B6EAEFF4468B4FF4A71C6FF3B66C3FF3B67C0FF3F62B2FF3655A4FF
+ 3A58B1FF3353ACFF385DAFFF3C5EAAFF334F96FF2B4286FF37488BFF3C4C8EFF
+ 3B4A88FF425084FF3A4466FF4D4D5BFF625144FF836038FFAA7933FFB77B1BFF
+ BA7702FFC38208FFB57B11FFB27B13FFB47B12FFB57B11FFB77C0FFFB97E11FF
+ BC8016FFBE801AFFBD7E1CFFB67919FFB07214FFAE7111FFB07410FFB67A10FF
+ B97C0EFFBA7E0DFFBB7C0EFFBC7D0FFFBD7D11FFBE7E12FFBE7D14FFBD7B12FF
+ BD790EFFBC780DFFBD780BFFC07B0EFFC07D10FFBF7D0DFFBB7A0DFFB87909FF
+ B87B0DFFBA7D0FFFB97B0FFFBA7C10FFBC7E14FFBC8016FFBC8016FFBA7F12FF
+ BA7D0FFFB97C0EFFB7790DFFB77A12FFCC8F2DFFBE842BFFB27D2DFFBB8842FF
+ B48548FFB39064FFDFD3C1FFE0DFDBFFEEECECFFF5F2F4FFF5F7F8FFF4F8F9FF
+ EFF4F5FFE8EDF0FFF1F4F9FFEDEBF1FFF0EBF4FFF3ECF3FFEFE8EFFFEEEAF0FF
+ EAEAF0FFE3E3E9FFEFEAECFFFFF7EEFFF2D3B4FFBC935CFFAE7929FFB67E1FFF
+ B88119FFB57E15FFB57E16FFB77D16FFBD7B14FFBE7D11FFBF7D0CFFBC7D0BFF
+ B77E0BFFB57D0CFFBC800FFFBA7D0FFFB87B0DFFB77A0CFFB87B0DFFBA7D0FFF
+ BC7F11FFBE8113FFB87B0DFFB77A0CFFB6790BFFB97C0EFFBD8012FFC08315FF
+ BF8214FFBE8113FFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBB7E10FFBB7E10FF
+ BA7D0FFFB97C0EFFB97C0EFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BA7E0DFFB97D0CFFBA7E0DFFB97D0CFFB97D0CFFBB7F0EFFBE8211FFBF8312FF
+ BD8110FFBB7F0EFFB97D0CFFBA7E0DFFBB7F0EFFBC800FFFBC800FFFBB7F0EFF
+ BA7E0DFFB97D0CFFBA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFF
+ B77B0AFFB67A09FFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BC7D0DFFBB7C0CFFBE7F0FFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BC7D0DFFBB7C0CFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBD7F0DFFBB7D0BFFB97B09FFBA7C0AFFBC7E0CFFBC7E0CFF
+ BB7D0BFFB97B09FFBA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFF
+ B97D0CFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFB1730FFFB47612FFB77915FF
+ B77915FFB57713FFB37511FFB3750FFFB47610FFB57810FFB4770FFFB3760EFF
+ B4770FFFB5790FFFB5790FFFB3770DFFB1750BFFB4790CFFB57A0DFFB67B0EFF
+ B77C0FFFB77C0FFFB67B0EFFB57A0DFFB4790CFFB67B0EFFB67B0EFFB77C0FFF
+ B77C0FFFB87D10FFB87D10FFB87D10FFB77D13FFB27910FFB07911FFAE7911FF
+ B07910FFB37D0BFFB67D10FFBC7B19FFBD7A1DFFB57614FFB1781BFFA17724FF
+ 907647FF7D7984FF6C7EB3FF547FCEFF4B82D7FF4C83CCFF548BD0FF4A7ECAFF
+ 3E6FBDFF4C7DC7FF89B5F5FFA3C5FBFF6D8AC3FF4665B0FF456ABFFF3963C3FF
+ 365FBBFF395AA9FF3855A0FF3854ABFF3553AAFF385CA8FF3D5FA5FF395298FF
+ 314487FF364486FF3C4B8AFF3E508DFF3E518AFF3B4D7CFF374061FF4D4752FF
+ 695445FF7E5A2CFF9C6B21FFBB821FFFC4861AFFB77C15FFB67B14FFB47A10FF
+ B57A0CFFB77C0EFFBB8013FFC0831BFFC38521FFC38324FFBF7F21FFBB7B1CFF
+ B67917FFB87A14FFB87C12FFB77B11FFB57A0DFFBB7E10FFBB7E10FFBB7E10FF
+ BA7C10FFBA7C12FFBC7B12FFBD7A13FFBE7C13FFC37F16FFC48017FFC48015FF
+ C18014FFBF7E12FFBE7F11FFBD8012FFBE8014FFBC8016FFBB7E16FFBA7E14FF
+ BB7D13FFBB7D13FFBC7E12FFBD7F13FFC08014FFC28216FFBD7E16FFC38626FF
+ B67B25FFB07B32FFAF8042FFAC8450FFC6AB89FFEDE7E0FFE9EDF2FFF0F1F5FF
+ F0EFF1FFEDEFEFFFEFF1F1FFECF2F1FFE9EEEFFFF2F5F9FFECEAF0FFEFE7F1FF
+ F4EBF5FFF3EAF4FFF2EDF6FFEEF1F6FFEDECF0FFF5E7E9FFE0C6B8FFC7A177FF
+ B98947FFB58026FFB47A13FFB07910FFB07B13FFB37D18FFB67B17FFBB7C14FF
+ BE7D11FFBF7D0CFFBB7D0BFFB77E0BFFB57D0CFFB97E10FFBA7D0FFFB97C0EFF
+ B87B0DFFB97C0EFFBA7D0FFFBC7F11FFBD8012FFBD8012FFBB7E10FFBB7E10FF
+ BD8012FFC08315FFC28517FFC28517FFC08315FFBB7E10FFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFB77A0CFFB87B0DFFBA7D0FFF
+ BB7E10FFBC7F11FFBC7F11FFBB7E10FFBB7E10FFB97D0CFFBA7E0DFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFBA7E0DFFB97D0CFFB97D0CFF
+ BB7F0EFFBE8211FFBF8312FFBD8110FFBA7E0DFFB87C0BFFB97D0CFFBA7E0DFF
+ BB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFB87C0BFFBA7E0DFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBB7F0EFFB97D0CFFB87C0BFFB77B0AFFBB7C0CFFBB7C0CFFBB7C0CFF
+ BA7B0BFFBA7B0BFFBB7C0CFFBB7C0CFFBB7C0CFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBB7C0CFF
+ BA7B0BFFBA7B0BFFBB7C0CFFBB7C0CFFBB7C0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFF
+ BB7D0BFFBD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFBA7E0DFFB97D0CFFB97D0CFF
+ B87C0BFFB87C0BFFB97D0CFFB97D0CFFBA7E0DFFB87C0BFFB87C0BFFB87C0BFF
+ B27410FFB47612FFB67814FFB67814FFB47612FFB37511FFB3750FFFB57711FF
+ B4770FFFB3760EFFB1740CFFB2750DFFB3770DFFB5790FFFB5790FFFB4780EFF
+ B57A0DFFB67B0EFFB77C0FFFB77C0FFFB77C0FFFB77C0FFFB67B0EFFB57A0DFF
+ B87D10FFB87D10FFB87D10FFB87D10FFB97E11FFB97E11FFBA7F12FFBA7E14FF
+ B2780FFFB27811FFB07911FFB27C11FFB67F10FFBA8114FFC1801EFFC28021FF
+ BA7C18FFB37919FFA8791EFF977435FF817063FF767A93FF6582BBFF5681CAFF
+ 4D7FC7FF4F84CDFF487BCBFF3F72C2FF4476C2FF6895D8FF95B6EEFF97B4EDFF
+ 5171BAFF4365B9FF3B62BEFF2E54ACFF305099FF3A569DFF3350A1FF3454A7FF
+ 395DA9FF3E60A6FF3C5699FF34478AFF2E3E80FF374887FF435798FF3F5694FF
+ 435993FF2E406FFF393E5FFF544D5AFF635043FF755936FF937038FFAA7B31FF
+ BA7A1CFFC17A12FFBA7A0AFFB97B09FFB77D0CFFB97F15FFBD801EFFBF8222FF
+ B77516FFB77411FFB7780AFFB77907FFB77B0AFFB57A0DFFB27612FFB17511FF
+ BA7F12FFB97F0EFFB57D0EFFB47B0EFFB47A11FFB67B14FFB87C18FFB97C1AFF
+ C18220FFBF801EFFBC7E1AFFBD7C19FFBD7D17FFBE7F17FFBD8018FFBC7F17FF
+ BA7F18FFBA8017FFBD7F15FFBE7F11FFBE7F11FFBF8012FFBE8014FFBE8016FF
+ BD7E16FFB77711FFB57818FFAC711BFFA8742DFF9E7439FFA68558FFDBC6ABFF
+ FAF7F2FFF3F8FBFFF3F6FAFFF0F2F3FFEEEDEFFFEDEFEFFFECF1F0FFECF0F1FF
+ F1F4F8FFE8E7F0FFEAE6F1FFF2ECF7FFF0EBF4FFF2EEF4FFF3F2F6FFF4F0EFFF
+ FEEFE6FFC4A98FFFA7804CFFB28339FFB78221FFB47C0FFFB67E11FFB68015FF
+ B47D15FFB67C15FFBB7D13FFBD7C0FFFBF7D0DFFBC7E0CFFB77D0CFFB57D0EFF
+ B77C0EFFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFFBB7E10FFBB7E10FFBC7F11FF
+ B97C0EFFB87B0DFFB87B0DFFB97C0EFFBB7E10FFBC7F11FFBB7E10FFBA7D0FFF
+ BC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FF
+ B6790BFFB77A0CFFB97C0EFFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBC7F11FF
+ B97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFF
+ BB7F0EFFBA7E0DFFBA7E0DFFBB7F0EFFBE8211FFBE8211FFBC800FFFBA7E0DFF
+ B87C0BFFB97D0CFFB97D0CFFBA7E0DFFBA7E0DFFB97D0CFFB97D0CFFB87C0BFF
+ BB7F0EFFBB7F0EFFBC800FFFBC800FFFBC800FFFBB7F0EFFB97D0CFFB97D0CFF
+ BC7D0DFFBB7C0CFFB97A0AFFB87909FFB87909FFB97A0AFFBB7C0CFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBF8010FFBE7F0FFFBD7E0EFFBB7C0CFFBA7B0BFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBB7C0CFFB97A0AFFB87909FFB87909FFB97A0AFFBB7C0CFFBC7D0DFF
+ BF810FFFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFF
+ BD7F0DFFBC7E0CFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBD7F0DFFBB7D0BFF
+ BA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFB97D0CFFBA7E0DFF
+ B87C0BFFB87C0BFFB87C0BFFB27410FFB47612FFB57713FFB57713FFB37511FF
+ B27410FFB3750FFFB57711FFB4770FFFB3760EFFB2750DFFB2750DFFB4780EFF
+ B67A10FFB87C12FFB87C12FFB77C0FFFB77C0FFFB77C0FFFB77C0FFFB77C0FFF
+ B77C0FFFB77C0FFFB77C0FFFB77C0FFFB77C0FFFB77C0FFFB87D10FFB87D10FF
+ B97E11FFB97E11FFB97D13FFB67B14FFB57B14FFB37C13FFB37D12FFB67D10FF
+ BA7E14FFBD7C19FFBE7D1AFFBC7E1AFFB47915FFB07A1BFFA17528FF8C6B44FF
+ 817573FF7483A4FF5E80BBFF5683C7FF4B7CCAFF4979CBFF487ACCFF3C70BDFF
+ 3867ABFF6587C2FF9BB9F2FF718FD6FF4C6DBDFF3E62BAFF25499DFF2A448AFF
+ 3B5597FF2F4C97FF3554A3FF3D62ACFF4365ABFF405B9EFF36498CFF273779FF
+ 304283FF485EA0FF455FA1FF4662A3FF354C8AFF2A3B6EFF424B71FF646377FF
+ 635B5CFF5D5244FF806540FFA66F2CFFB5731AFFB47612FFB37A0DFFB57D0EFF
+ B67D10FFB87A16FFB97816FFB97514FFBA7710FFBB7C0AFFBB7E08FFBB800CFF
+ BB8012FFB97D19FFBA7D1BFFB57B11FFB77C0EFFB47B0EFFB3790FFFB37912FF
+ B47915FFB57A17FFB67B18FFBC811EFFB97C1AFFB47814FFB37811FFB77A12FF
+ B97D13FFB97D13FFB67C12FFB37814FFB57B14FFBE8014FFC48414FFC48414FF
+ C18013FFBA7C12FFB67911FFBC7E18FFB77816FFBF8123FFBA812CFFAE7D39FF
+ A7804CFFBDA280FFF6E8D5FFF3F3EDFFF0F5F8FFF4F7FBFFF5F6FAFFF4F3F7FF
+ F2F1F3FFEFF1F1FFEDF2F1FFEDF0F4FFE6E8F0FFE8E8F4FFEEECF8FFEBE8F1FF
+ EDE9EEFFF4EFF0FFFCF3EAFFFBE7D5FFBFA27DFFA87F41FFB0812DFFAE7911FF
+ B47C0BFFBF8716FFB67F10FFB67E13FFB77D14FFBA7C10FFBD7C0FFFBF7D0DFF
+ BC7D0DFFB67E0FFFB67E0FFFB67B0DFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBB7E10FFB77A0CFFB77A0CFFB77A0CFFB77A0CFFB77A0CFF
+ B77A0CFFB77A0CFFB77A0CFFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBB7E10FFB87B0DFFB87B0DFFBA7D0FFFBB7E10FFBC7F11FF
+ BC7F11FFBB7E10FFBB7E10FFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBA7E0DFFB97D0CFFBB7F0EFFBA7E0DFFBA7E0DFFBC800FFFBE8211FF
+ BE8211FFBC800FFFB97D0CFFBA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBC800FFFBD8110FFBC800FFF
+ BC800FFFBB7F0EFFBA7E0DFFBC7D0DFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFF
+ BB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBF8010FFC08111FFBF8010FF
+ BD7E0EFFBB7C0CFFBA7B0BFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFF
+ BB7C0CFFBC7D0DFFBC7D0DFFBE800EFFBE800EFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBB7D0BFFBA7C0AFFB97B09FFBA7C0AFFBC7E0CFF
+ BD7F0DFFBC7E0CFFBA7C0AFFBA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87C0BFF
+ B97D0CFFB97D0CFFBA7E0DFFB87C0BFFB87C0BFFB87C0BFFB27410FFB37511FF
+ B57713FFB47612FFB27410FFB1730FFFB3750FFFB57711FFB57810FFB57810FF
+ B57810FFB57810FFB5790FFFB77B11FFBA7E14FFBC8016FFB77B11FFB77B11FF
+ B77B11FFB77B11FFB77B11FFB77B11FFB77B11FFB77B11FFB5790FFFB5790FFF
+ B5790FFFB67A10FFB67A10FFB77B11FFB77B11FFB77B11FFB97B15FFB67B14FF
+ B47C0FFFB17C0EFFB47A10FFB67911FFB97913FFBA7A14FFB97E17FFB37912FF
+ B77C15FFB0791EFF9D6E2AFF8E7351FF80808CFF6B82AFFF6189CAFF5A8AD8FF
+ 5080D2FF4476C8FF4376C6FF4474BCFF5B80BAFF7F9DD6FF95B2F7FF5B79C6FF
+ 4362B7FF264594FF283E7FFF39518DFF2E4B90FF3657A0FF4469B3FF496CB5FF
+ 425FA4FF384E90FF243677FF283A7BFF4A60A2FF506AB0FF4767B0FF3757A0FF
+ 243E84FF2C4381FF526396FF5D6991FF515976FF5F585FFF815D45FF956531FF
+ 9E6D23FFA97618FFB47E13FFB87F0CFFB9780BFFB7730AFFC47E19FFC17E17FF
+ BD7D11FFB97C0EFFB57B0AFFB37B0CFFB77A12FFB87A14FFB67610FFB77711FF
+ B87812FFB87812FFB87714FFB87714FFB57713FFB47610FFBD7F19FFB77D14FF
+ B2780EFFB1790AFFB37B0AFFB57E0BFFB77F08FFB47C0BFFB07911FFB27A15FF
+ BC7E12FFC28212FFC48212FFBF7E11FFB97A12FFB37713FFB77A18FFB27515FF
+ C4872AFFBE8736FFA97D3EFFB29267FFD8C6AFFFFFFAEFFFE9EDE8FFEAEFF0FF
+ F0F3F8FFF5F5FBFFF6F4FAFFF2F1F5FFF1F1F1FFF0F2F2FFEEF3F6FFE7EDF4FF
+ E9EDF8FFE8EAF5FFE6E3ECFFEEE9EBFFFCF3EFFFFFF8E6FFDAC3A3FFB1905EFF
+ A87D34FFB18024FFAE7609FFB47C05FFBC8611FFAF7906FFB57D10FFB67C12FF
+ BA7C10FFBC7D0FFFBD7D0DFFBC7D0DFFB77F10FFB77E11FFB67B0DFFB97C0EFF
+ BA7D0FFFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBC7F11FFBC7F11FF
+ BC7F11FFBC7F11FFBB7E10FFBA7D0FFFBB7E10FFBB7E10FFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFBB7E10FFBB7E10FF
+ BC7F11FFBC7F11FFBB7E10FFBA7D0FFFB87B0DFFB87B0DFFB97D0CFFBA7E0DFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFBC800FFFBB7F0EFF
+ BA7E0DFFBC800FFFBE8211FFBE8211FFBB7F0EFFB97D0CFFBD8110FFBD8110FF
+ BC800FFFBC800FFFBC800FFFBC800FFFBD8110FFBD8110FFBA7E0DFFBB7F0EFF
+ BC800FFFBC800FFFBD8110FFBC800FFFBB7F0EFFBB7F0EFFBC7D0DFFBD7E0EFF
+ BE7F0FFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBE7F0FFFBE7F0FFF
+ BF8010FFBF8010FFBF8010FFBE7F0FFFBC7D0DFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFF
+ BE7F0FFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBD7F0DFFBD7F0DFF
+ BE800EFFBE800EFFBD7F0DFFBC7E0CFFBA7C0AFFB97B09FFB97B09FFB77907FF
+ B67806FFB87A08FFBA7C0AFFBB7D0BFFBB7D0BFFB97B09FFBA7E0DFFB97D0CFF
+ B97D0CFFB87C0BFFB87C0BFFB97D0CFFB97D0CFFBA7E0DFFB87C0BFFB87C0BFF
+ B87C0BFFB27410FFB37511FFB47612FFB37511FFB1730FFFB0720EFFB3750FFF
+ B57711FFB4770FFFB57810FFB67911FFB67911FFB67A10FFB77B11FFB97D13FF
+ BB7F15FFB77B11FFB77B11FFB67A10FFB5790FFFB5790FFFB67A10FFB77B11FF
+ B77B11FFB4780EFFB4780EFFB5790FFFB5790FFFB67A10FFB67A10FFB67A10FF
+ B67911FFB57713FFB37811FFB17A0BFFB17A0BFFB37910FFB67812FFBC7A13FF
+ B97C14FFB77D16FFB27811FFBC7B12FFBB7A17FFAB731AFF967137FF837C79FF
+ 7A8AAFFF6487C7FF5A88D6FF5584D6FF4D7DCFFF4E83D3FF5284CCFF6186C2FF
+ 7E9FD7FF9EBBFEFF607AC6FF4461B2FF2F4995FF2A3C7BFF334781FF2E4A8BFF
+ 3C5EA4FF486FBAFF4F73BFFF4664ABFF3C5699FF263A7BFF1F3374FF445C9EFF
+ 5774B9FF4D6DB9FF3A5EACFF2C4D9DFF21418DFF2F4C91FF5770B0FF657CB4FF
+ 57638BFF655B6BFF746055FF816641FF906F30FFA47824FFB17D19FFB87A10FF
+ B9750AFFBE7A11FFBB7811FFB77810FFB2760CFFAE740AFFAF7609FFB4790CFF
+ B67A10FFB67814FFB77915FFBA7916FFBB7B15FFBC7A14FFBA7811FFB8760FFF
+ B4760CFFBE8016FFBA7F12FFB87D0FFFB77D0CFFB87F0CFFBA810DFFBB840BFF
+ B9820FFFB77F1AFFB57C19FFBA7C12FFBC7B0EFFBE7C0CFFBD7C0FFFBC7C16FF
+ BA7D1BFFB67919FFAE7114FFB97E28FFB27F36FFA57D48FFC1A886FFE8DFD1FF
+ F8F7F3FFECF2EDFFEBF1F0FFEDF0F5FFF0EFF8FFF0EDF6FFEDECF0FFEFEFEFFF
+ F2F4F4FFF1F6F7FFEAF3F7FFE8EEF9FFE3E7F2FFE6E4EAFFF5EDEDFFFFF3E7FF
+ FFEBD0FFBA9D71FFA37E40FFA77A29FFBA8726FFBE8615FFBE850CFFBC840DFF
+ B37C09FFB57D0EFFB57C0FFFBA7D0FFFBC7D0FFFBD7D0DFFBD7E0EFFB77F10FF
+ B77E11FFB77C0EFFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFFBB7E10FFBB7E10FF
+ BC7F11FFB97C0EFFBA7D0FFFBB7E10FFBA7D0FFFB97C0EFFB87B0DFFB97C0EFF
+ BA7D0FFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFF
+ B97C0EFFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBB7E10FFB97C0EFFB77A0CFF
+ B6790BFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFF
+ B97D0CFFBD8110FFBB7F0EFFBB7F0EFFBC800FFFBD8110FFBD8110FFBB7F0EFF
+ B87C0BFFBD8110FFBD8110FFBC800FFFBC800FFFBC800FFFBC800FFFBD8110FF
+ BD8110FFB97D0CFFB97D0CFFBB7F0EFFBC800FFFBC800FFFBC800FFFBB7F0EFF
+ BB7F0EFFBC7D0DFFBE7F0FFFC08111FFC18212FFC18212FFC08111FFBE7F0FFF
+ BC7D0DFFC08111FFBF8010FFBF8010FFBE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBE7F0FFFC08111FFC18212FFC18212FFC08111FFBE7F0FFF
+ BC7D0DFFBC7E0CFFBD7F0DFFBE800EFFBF810FFFBE800EFFBC7E0CFFB97B09FF
+ B87A08FFB87A08FFB77907FFB67806FFB77907FFBA7C0AFFBC7E0CFFBB7D0BFF
+ B97B09FFBA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFB97D0CFF
+ BA7E0DFFB97D0CFFB97D0CFFB97D0CFFB27410FFB37511FFB37511FFB27410FF
+ B0720EFFB0720EFFB2740EFFB57711FFB0730BFFB3760EFFB57810FFB67911FF
+ B4780EFFB4780EFFB5790FFFB77B11FFB77B11FFB67A10FFB5790FFFB4780EFF
+ B4780EFFB5790FFFB67A10FFB77B11FFB5790FFFB67A10FFB67A10FFB67A10FF
+ B77B11FFB77B11FFB87C12FFB87B13FFB57713FFB37811FFB17A0BFFB27B0CFF
+ B37811FFB77915FFBD7C13FFBA7E14FFB47F17FFB17A12FFB9780FFFBE7D11FF
+ B67911FF986F26FF83796FFF8695B6FF6486C2FF517DCAFF5582D3FF5788D8FF
+ 5186D6FF497DC4FF5D87C2FF93B6EEFF8AA8E9FF566FB7FF465DABFF3E539EFF
+ 2F3E7CFF293A73FF2E4A8AFF4367ADFF4A71BFFF5479C9FF4969B4FF4360A5FF
+ 2B4385FF162F6FFF3B5597FF5B78BDFF5373BFFF476ABAFF3F64B6FF2E53A5FF
+ 264796FF3E5EA7FF5B78BDFF5D79B6FF5871A3FF5A6B8CFF60646FFF6F6456FF
+ 856A3EFF9B722DFFAC771DFFB67812FFBB7A11FFBE7D11FFBF7D16FFBD7D17FF
+ B97B15FFB77D14FFB98112FFBC8316FFB88119FFB77F1AFFB98017FFBB7F15FF
+ BC7E12FFBC7D0FFFBC7B0EFFBB7A0DFFBD7C0FFFBE7F11FFBE7F11FFBD8012FF
+ BC7F11FFBD8110FFBF8312FFBE8315FFBB831EFFB9801DFFBA7D15FFB97B11FF
+ BB7B0FFFBE7D14FFC0801AFFBE811FFFC5882BFFB97E28FFB47E31FFB18546FF
+ BE9E73FFE4D3B9FFF7F4EFFFF0F5F6FFF0F5F3FFEDF2F0FFECEFF4FFF0EFF8FF
+ EFECF5FFEDE9EFFFF0EEEEFFF2F4F4FFECF1F2FFE8F1F5FFE4EEF8FFE3EAF3FF
+ EDECF0FFFBF1EAFFEEDAC8FFD1B592FFAC8A55FFB18742FFB6852FFFBD8623FF
+ C38918FFC18710FFBC830FFFBA8310FFB57D0EFFB77C0FFFB97C0EFFBC7D0FFF
+ BD7E0EFFBB7F0EFFB97E10FFB88011FFB97E10FFBA7D0FFFB97C0EFFB87B0DFF
+ B97C0EFFBA7D0FFFBC7F11FFBD8012FFB5780AFFB77A0CFFB87B0DFFB87B0DFF
+ B6790BFFB5780AFFB77A0CFFB97C0EFFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFF
+ BA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFBB7E10FFBB7E10FFBC7F11FFBC7F11FF
+ BB7E10FFBA7D0FFFB87B0DFFB77A0CFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFBD8110FFBC800FFFBB7F0EFFBC800FFF
+ BD8110FFBD8110FFBA7E0DFFB77B0AFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFF
+ B97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFB77B0AFFB87C0BFFB97D0CFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFC28313FFC08111FFBE7F0FFFBD7E0EFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBF8010FFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBE800EFFBE800EFFBE800EFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBA7C0AFFB97B09FFBA7C0AFFB97B09FFB87A08FFBA7C0AFF
+ BD7F0DFFBE800EFFBE800EFFBC7E0CFFBA7E0DFFB97D0CFFB97D0CFFB87C0BFF
+ B87C0BFFB97D0CFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFB27410FF
+ B37511FFB37511FFB1730FFFAF710DFFB0720EFFB2740EFFB57711FFAD7008FF
+ B0730BFFB4770FFFB57810FFB3770DFFB1750BFFB2760CFFB3770DFFB67A10FF
+ B5790FFFB4780EFFB3770DFFB3770DFFB4780EFFB5790FFFB67A10FFB77B11FF
+ B77B11FFB87C12FFB87C12FFB97D13FFB97D13FFB97D13FFBA7C16FFB97A18FF
+ B67A16FFB47C0FFFB37B0EFFB47814FFB67715FFB97B11FFB67C12FFB4801BFF
+ AE7A16FFB4750DFFBC7B0FFFBB7C0CFF996E1FFF80776DFF8A9DC0FF698BC6FF
+ 5883CCFF5785D2FF5182D0FF4B83D0FF4D83CAFF6490CDFF95BAF4FF718FD0FF
+ 4963A9FF445AA8FF4B5BA7FF35407EFF23316BFF2E4989FF496DB3FF4871C0FF
+ 557DCFFF486CB8FF4666AFFF2E4B8EFF102C6DFF324F92FF5A78BFFF5477C1FF
+ 557ACAFF4D75C7FF436BBDFF355AAAFF204490FF34559EFF6185CBFF5E8BCFFF
+ 527BB9FF4B6698FF4F5A78FF615A5DFF79634AFF916D37FFA27426FFAD7719FF
+ B77B17FFBE7E18FFBC7C16FFB87812FFB2750DFFB07508FFAD7508FFBD8820FF
+ B9861EFFBA831AFFB98114FFBA800FFFBE7F0FFFBE7F0FFFBF8010FFB7780AFF
+ B97B0FFFBC7E14FFBC7E14FFBD7C13FFBD7C13FFBF7F13FFC08218FFBC811DFF
+ BA821DFFBB801CFFBC811AFFBE801AFFC0801AFFBF811DFFBD8020FFC68A31FF
+ B98132FFA67634FFAA8551FFCEB797FFF2E9DBFFF2F4F5FFE1E7ECFFECF3F0FF
+ EBF0EEFFEDF0F5FFF3F2FCFFF3F0F9FFEFEBF1FFEFEDEDFFF1F4F2FFE4E9EAFF
+ E2EEF0FFE4EFF7FFE9EFF6FFF9F5F4FFFEF1E3FFD9BFA1FF9F7C50FFAD8446FF
+ CA9B51FFC8933CFFB37A17FFB27709FFBA7E0CFFBA7E0CFFBA800FFFB57D0EFF
+ B77C0FFFB97C0EFFBC7D0FFFBD7E0EFFBB7F0EFFBA7F11FFBA7F11FFBC7F11FF
+ BA7D0FFFB87B0DFFB77A0CFFB87B0DFFBA7D0FFFBC7F11FFBE8113FFB97C0EFF
+ BB7E10FFBD8012FFBD8012FFBB7E10FFBA7D0FFFBC7F11FFBF8214FFBC7F11FF
+ BC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFB97C0EFF
+ BA7D0FFFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBA7D0FFFB97C0EFFB97D0CFF
+ BA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFBE8211FF
+ BC800FFFBB7F0EFFBC800FFFBD8110FFBD8110FFBA7E0DFFB77B0AFFB97D0CFF
+ B87C0BFFB77B0AFFB67A09FFB67A09FFB77B0AFFB87C0BFFB97D0CFFB67A09FF
+ B77B0AFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBA7E0DFFBA7E0DFFBE7F0FFF
+ BD7E0EFFBB7C0CFFBA7B0BFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFC38414FF
+ C18212FFBE7F0FFFBC7D0DFFBB7C0CFFBD7E0EFFBF8010FFC18212FFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBE7F0FFF
+ BD7E0EFFBB7C0CFFBA7B0BFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFC18311FF
+ C08210FFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BB7D0BFFBA7C0AFFBC7E0CFFBF810FFFC18311FFC08210FFBF810FFFBA7E0DFF
+ B97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFB97D0CFFBA7E0DFFBB7F0EFF
+ BB7F0EFFBB7F0EFFAF710DFFB0720EFFB1730FFFB1730FFFAE700CFFAE700CFF
+ AF710BFFB1730DFFAE7109FFAF720AFFB1740CFFB3760EFFB4780EFFB4780EFF
+ B4780EFFB3770DFFB67911FFB1740CFFB0730BFFB57810FFB77A12FFB57810FF
+ B57810FFB77A12FFB87B13FFB3760EFFB4770FFFB97C14FFB97C14FFB57810FF
+ B57810FFBA7C16FFB47717FFB27714FFB1790EFFB27A0FFFB57816FFB77816FF
+ B5770DFFAE740AFFAB7A18FFA87616FFB67B18FFB57810FFB97E10FF9B7429FF
+ 71706CFF869EC8FF7B9DD8FF4D78BBFF5381C8FF6195DCFF528BD6FF4C82C9FF
+ 6693D0FF93B7F3FF6886C7FF465FA5FF4B5FADFF414E9AFF2E3777FF202B69FF
+ 334D8FFF5174BDFF4772C3FF517DD0FF537CCBFF4C71BBFF3B5DA3FF1D3E83FF
+ 1E3F84FF4365ABFF476CB6FF557CCAFF5A85D4FF5884D1FF5078C3FF365EA6FF
+ 274C90FF254F92FF5489CCFF5C93D8FF507DC6FF4E6FB4FF5F72ABFF555A7BFF
+ 534A47FF7C6341FF967232FFAC7B25FFB9801DFFBC7D15FFB7760DFFB4730AFF
+ B5760EFFB47A13FFAE7A15FFAC7B15FFAC770FFFB37D12FFBF8718FFBA7F11FF
+ B17609FFB77B11FFB77D14FFB47A13FFB37814FFB57915FFBB7B15FFBD7B14FF
+ BA780FFFB6750CFFB3760EFFBB811AFFBC8320FFB9801DFFB97E1BFFB47715FF
+ B57516FFBA7D20FFC48B36FFAB7931FFA7824AFFCFB590FFF7E9D6FFFBF8F3FF
+ EEF3F6FFE9F2F6FFE9EFEEFFE9EEECFFE9ECF1FFEDECF5FFF1EEF7FFF3EFF5FF
+ F0EEEEFFE8EBE9FFEAEFF0FFEFF8FBFFE3EDF4FFECF1F4FFFFF9F0FFD6C4ADFF
+ A07F58FF976D38FFAD7D3BFFB48033FFB27923FFB37717FFBF8018FFBF8214FF
+ BA7D0FFFBD8214FFB77C0FFFB77C0FFFBA7D0FFFBD7E10FFBE7F0FFFBD810FFF
+ BC8211FFBC8211FFB77A0CFFBF8214FFC18416FFBD8012FFBA7D0FFFBC7F11FF
+ BC7F11FFB97C0EFFBA7D0FFFBE8113FFBD8012FFB87B0DFFB87B0DFFBD8012FF
+ BE8113FFBA7D0FFFB87B0DFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBA7D0FFF
+ B97C0EFFB87B0DFFBB7E10FFBA7D0FFFB87B0DFFB6790BFFB6790BFFB87B0DFF
+ BA7D0FFFBB7E10FFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFF
+ B97D0CFFB87C0BFFB87C0BFFBA7E0DFFBB7F0EFFBC800FFFBC800FFFBB7F0EFF
+ B97D0CFFB87C0BFFBF8312FFBC800FFFB87C0BFFB57908FFB57908FFB67A09FF
+ B97D0CFFBB7F0EFFC48817FFBF8312FFB87C0BFFB67A09FFB77B0AFFBA7E0DFF
+ BD8110FFBE8211FFBC7D0DFFBB7C0CFFB97A0AFFB87909FFB87909FFB97A0AFF
+ BB7C0CFFBC7D0DFFC08111FFC08111FFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBD7E0EFFBB7C0CFFBC7D0DFFBF8010FFC18212FFC28313FFC38414FF
+ C28313FFC18212FFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BC7D0DFFBB7C0CFFBF810FFFBE800EFFBD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBB7D0BFFBD7F0DFFBE800EFFBD7F0DFFBA7C0AFFBA7C0AFF
+ BC7E0CFFBF810FFFBF8312FFBA7E0DFFBB7F0EFFC28615FFC38716FFBD8110FF
+ B87C0BFFB87C0BFFB77B0AFFBC800FFFBC800FFFAB6D09FFAF710DFFB37511FF
+ B47612FFB37511FFB0720EFFAF710BFFAF710BFFAF720AFFB0730BFFB1740CFF
+ B3760EFFB4780EFFB5790FFFB5790FFFB5790FFFB97C14FFB4770FFFB2750DFF
+ B67911FFB87B13FFB57810FFB4770FFFB57810FFB87B13FFB67911FFB77A12FF
+ B97C14FFB97C14FFB77A12FFB77A12FFB77C15FFB47719FFB37717FFB27910FF
+ B37A11FFB67919FFB57816FFB6780EFFAF750BFFA87819FFA7781CFFAE7617FF
+ B07511FFB1790EFF937027FF74777BFF8BA7D6FF779CD4FF5C87C6FF5C8ACAFF
+ 5D90D6FF548BD6FF4B80C9FF5985C4FF82A7E3FF7595D6FF4760A8FF3F53A1FF
+ 364290FF272C71FF192363FF2E488BFF4267B1FF4773C6FF5482D6FF5785D3FF
+ 507AC5FF4267B1FF244790FF193C85FF2E539DFF4D75C0FF527ECBFF5482CFFF
+ 5A89D3FF5F8CD5FF537DC2FF3B63A4FF2B5797FF205496FF447CC3FF5385D7FF
+ 4977CBFF4A6FC1FF4862A5FF455179FF54535CFF78694FFF8E6F3AFFA0762BFF
+ AE791FFFB67A1AFFBD7C19FFC07F1CFFC0821CFFB0760FFFB47D15FFB57B11FF
+ B77C0FFFBD8012FFBA7D0FFFB97E11FFC2881EFFB47D15FFB17A17FFB27B1AFF
+ B57C19FFB97D19FFBD7D17FFBE7C13FFBD7C10FFBC7E14FFBC821BFFBA811EFF
+ B47C1DFFB47B1EFFB87D20FFC08326FFC28731FFBF893CFFAB8041FFBEA175FF
+ EADBC1FFFDF8EFFFF9FBFBFFF0F6FBFFE9EFF4FFE7EDECFFE7ECEBFFE7EAEEFF
+ ECEBF4FFF1EEF7FFF5F1F7FFF2F2F2FFEEF0F0FFE7EFEFFFE1EBEBFFE1E8EBFF
+ F4F5F1FFFEF1E1FFD4BB9BFFAC8755FFAE7F41FFB8843DFFBE8635FFB87C23FF
+ B47717FFBA7C18FFBC7D15FFBA7E14FFC1851BFFBC8016FFBC8016FFBD7F13FF
+ BE7F0FFFBD7E0EFFBC7E0CFFB97D0BFFB77D0CFFBA7D0FFFBF8214FFC08315FF
+ BB7E10FFB87B0DFFB97C0EFFB87B0DFFB47709FFBA7D0FFFBD8012FFBC7F11FF
+ B87B0DFFB87B0DFFBC7F11FFBD8012FFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFF
+ BA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFB97C0EFFBA7D0FFFBC7F11FF
+ BE8113FFBE8113FFBC7F11FFBA7D0FFFB97C0EFFBC800FFFBB7F0EFFBB7F0EFF
+ BA7E0DFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFF
+ BB7F0EFFBA7E0DFFB97D0CFFB87C0BFFB77B0AFFBA7E0DFFB87C0BFFB87C0BFF
+ B97D0CFFBC800FFFBE8211FFBD8110FFBC800FFFBB7C0CFFBB7C0CFFBA7B0BFF
+ BA7B0BFFBA7B0BFFBA7B0BFFBB7C0CFFBB7C0CFFBE7F0FFFBD7E0EFFBC7D0DFF
+ BB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBF8010FFBF8010FFBF8010FF
+ BF8010FFBF8010FFBF8010FFBF8010FFC08111FFBB7C0CFFBC7D0DFFBD7E0EFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBF810FFFBE800EFFBD7F0DFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBA7C0AFFBC7E0CFFBE800EFF
+ BE800EFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFFBC800FFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBD8110FFBF8312FFBD8110FFB97D0CFFB97D0CFFBB7F0EFFBB7F0EFF
+ B1730FFFB1730FFFB1730FFFAF710DFFAE700CFFAF710DFFB47610FFB87A14FF
+ B0730BFFB1740CFFB1740CFFB2750DFFB4780EFFB67A10FFB77B11FFB87C12FF
+ BB7E16FFB67911FFB4770FFFB87B13FFB97C14FFB57810FFB3760EFFB4770FFF
+ B87B13FFBA7D15FFB97C14FFB77A12FFB77A12FFB97C14FFB97C14FFB57A13FF
+ B5781AFFB47818FFB57A13FFB57A13FFB57919FFB67917FFB87A10FFB2780FFF
+ A77418FFAA7A22FFA97419FFAC7716FFA97511FF8A6A29FF777D88FF8BAADDFF
+ 7DA4DBFF74A0DBFF6D99D8FF5C8BCFFF5488D4FF4E81CAFF527EBEFF739AD8FF
+ 7A9DDDFF4460A7FF324896FF323F8EFF272D74FF1F286CFF39529AFF4367B3FF
+ 4672C5FF5383D5FF5A89DAFF5C88D5FF527CC7FF325BA4FF19408BFF1C448FFF
+ 4F79C6FF507ECBFF4C7ECAFF5184CDFF6396DCFF689ADCFF5682C1FF3F6AA9FF
+ 234D8EFF2E589DFF416EB8FF4E7ECCFF4C7BCCFF416BB8FF36599DFF395082FF
+ 4B546FFF605B5AFF776246FF8F6A36FFA47329FFB1771EFFB97816FFBC7710FF
+ BE780DFFC58013FFC77F10FFC27A0AFFC57E0CFFC4800FFFC38215FFC4881EFF
+ B37C14FFB17D19FFB37E1DFFB67F1CFFBA8019FFBC8016FFC28114FFC38215FF
+ BA7C10FFB67C13FFB07918FFA97517FFAC771DFFBA812BFFC78C36FFC48C3DFF
+ A77735FFA68351FFD0BC9DFFFAF2E5FFF9F9F9FFF1F5FAFFF3F8FBFFEDF2F3FF
+ EFF4F3FFEDF2F1FFEDEEF2FFEDEDF3FFEFEDF3FFF0EFF3FFEDEFF0FFEAEFEEFF
+ EDF5F5FFDEE6E5FFEAEDEBFFFFFDF2FFF5E1C8FFC8A87FFFB08447FFB48138FF
+ BD8536FFC38733FFBD8127FFB87B1DFFB97C1AFFB97B17FFB87D16FFBE831CFF
+ BB8118FFBD8117FFBE8014FFBC800FFFBD7E0EFFBB7D0BFFB87C0AFFB87C0AFF
+ BA7E0DFFBC7F11FFBB7E10FFB97C0EFFB97C0EFFBA7D0FFFB87B0DFFB47709FF
+ BA7D0FFFBB7E10FFBA7D0FFFB77A0CFFB77A0CFFBA7D0FFFBB7E10FFBA7D0FFF
+ BC7F11FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBC7F11FF
+ BB7E10FFBD8012FFBF8214FFC08315FFC08315FFBF8214FFBD8012FFBB7E10FF
+ BD8110FFBC800FFFBA7E0DFFB97D0CFFB87C0BFFB97D0CFFBA7E0DFFBB7F0EFF
+ BE8211FFBD8110FFBA7E0DFFB87C0BFFB87C0BFFB87C0BFFBA7E0DFFBB7F0EFF
+ B97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB87C0BFFB77B0AFF
+ B97D0CFFB87C0BFFB77B0AFFB97D0CFFBC800FFFBD8110FFBC800FFFBA7E0DFF
+ BB7C0CFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBB7C0CFF
+ BB7C0CFFBA7B0BFFBA7B0BFFB97A0AFFBA7B0BFFBA7B0BFFBC7D0DFFBC7D0DFF
+ C38414FFC18212FFBE7F0FFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFF
+ BB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BE800EFFBE800EFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFF
+ B97B09FFBC7E0CFFBE800EFFBF810FFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFF
+ B97D0CFFBC800FFFBB7F0EFFB67A09FFB87C0BFFC08413FFC08413FFBB7F0EFF
+ BC800FFFBA7E0DFFBA7E0DFFB27410FFB27410FFB0720EFFAE700CFFAD6F0BFF
+ B0720EFFB67812FFBB7D17FFB2750DFFB1740CFFB1740CFFB2750DFFB4780EFF
+ B67A10FFB97D13FFBA7E14FFBB7E16FFB67911FFB4770FFFB97C14FFBA7D15FF
+ B77A12FFB4770FFFB57810FFB57810FFBA7D15FFBA7D15FFB57810FFB4770FFF
+ B97C14FFB97C14FFB27612FFB67A1AFFB67A1AFFB87A16FFB67A16FFB37919FF
+ B37A17FFB97B11FFB47912FFAE791EFFB8862EFFB47F24FFB98626FFB68021FF
+ 947236FF888E99FF96B4E5FF8CB2E8FF87B2EBFF7EAAE7FF608DD0FF5082CEFF
+ 5485D1FF5984C7FF6A93D2FF769CDDFF4464ABFF2F4694FF344392FF2D337CFF
+ 222C72FF465FA9FF466DB8FF4370C1FF497ACAFF5686D4FF6694E1FF6693DDFF
+ 4670BBFF254B99FF1A418FFF416AB9FF4D7BC9FF4D7FCBFF457AC3FF538ACFFF
+ 6B9FE1FF6A9BD9FF5A85C4FF4D70B2FF2A4D91FF234A8EFF3764A8FF3F6FB7FF
+ 4475C1FF4472C0FF3A61ABFF3F5C99FF4D5E89FF616171FF736559FF886942FF
+ 9C6F32FFAE7627FFBD7C20FFBB7714FFC47B13FFC0770BFFBD7204FFC27907FF
+ C67F0DFFC07E0EFFB5770BFFB47A13FFB27E1AFFB5801FFFB5801FFFB77F1AFF
+ B97F16FFC08014FFC38215FFB7790DFFB37910FFB07918FFAD781DFFB07A23FF
+ BB8532FFC48C3DFFBC8943FFA37C45FFB99F77FFE1D5C3FFF5F4F0FFEBEFF4FF
+ E5EBF2FFEFF3F4FFF2F4F4FFF1F5F6FFEFF3F4FFEFF0F4FFEFEDF3FFEEEDF1FF
+ EFEEF2FFEBEFF0FFEAF0EFFFEDF5F5FFE4EAE9FFF9F6F1FFFFF7E5FFE3C8A6FF
+ BF9864FFB4833DFFB07826FFB97E28FFBE8228FFBF8427FFBF8323FFBB7F1FFF
+ B77C19FFB67A16FFB87D16FFB67C13FFB67C12FFB97E11FFBB7F0EFFBE7F0FFF
+ BE800EFFBD820EFFBD810FFFB87C0BFFB77A0CFFB77A0CFFB87B0DFFBC7F11FF
+ BF8214FFBE8113FFBB7E10FFBA7D0FFFBA7D0FFFB97C0EFFB87B0DFFB87B0DFF
+ B97C0EFFBA7D0FFFBA7D0FFFBB7E10FFBC7F11FFBD8012FFBE8113FFBE8113FF
+ BD8012FFBC7F11FFBB7E10FFC08315FFBF8214FFBD8012FFBB7E10FFBB7E10FF
+ BD8012FFBF8214FFC08315FFBE8211FFBC800FFFBA7E0DFFB87C0BFFB77B0AFF
+ B87C0BFFBA7E0DFFBC800FFFBD8110FFBC800FFFBB7F0EFFB97D0CFFB97D0CFF
+ B97D0CFFB97D0CFFBA7E0DFFBD8110FFBB7F0EFFB97D0CFFB77B0AFFB77B0AFF
+ B97D0CFFBB7F0EFFBC800FFFC18514FFBD8110FFB77B0AFFB57908FFB67A09FF
+ B87C0BFFB97D0CFFB97D0CFFBB7C0CFFBC7D0DFFBE7F0FFFBF8010FFBF8010FF
+ BE7F0FFFBC7D0DFFBB7C0CFFBB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFF
+ BC7D0DFFBD7E0EFFBE7F0FFFC18212FFC08111FFBE7F0FFFBC7D0DFFBB7C0CFF
+ BA7B0BFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBD7F0DFFB97B09FFBB7D0BFFBE800EFFBF810FFFBF810FFF
+ BD7F0DFFBB7D0BFFBA7C0AFFB97D0CFFBB7F0EFFBA7E0DFFB77B0AFFB87C0BFF
+ BD8110FFBD8110FFBB7F0EFFBE8211FFB97D0CFFB97D0CFFA96B07FFAE700CFF
+ B47612FFB77915FFB67814FFB47612FFB2740EFFB2740EFFB2750DFFB2750DFF
+ B2750DFFB2750DFFB3770DFFB67A10FFB87C12FFBA7E14FFB77A12FFB3750FFF
+ B3750FFFB97B15FFBB7D17FFB87A14FFB67812FFB77913FFB2740EFFB77913FF
+ B77913FFB2740EFFB2740EFFB77913FFB77913FFB07410FFB77B1BFFB77B1BFF
+ B97A18FFB97A18FFB17A19FFB07916FFB77A12FFB87A14FFB0771CFFB7812AFF
+ B27C1DFFB88322FFB57C1FFF997438FF93929BFF9DB6E2FF8CB1E5FF83AEE7FF
+ 86AFEDFF6A94D9FF4E7ECCFF5585D3FF5E88CFFF5B85C8FF78A0E1FF5377BDFF
+ 34509DFF354695FF2B317CFF1E2A72FF4E69B3FF4E75C0FF4674C1FF4373C1FF
+ 4D7FCBFF6798E2FF74A1EBFF5982CBFF3559A5FF234793FF294F9DFF4973C0FF
+ 5687D3FF487DC6FF477EC3FF6399DAFF74A7E6FF709CDCFF6587CDFF4765ACFF
+ 2F508FFF20457FFF234983FF4972B0FF5F8BD2FF4E79C8FF4570C1FF496DB9FF
+ 5068A4FF525E82FF5E575EFF715C47FF8F693FFFAA7A3AFFB17928FFB87B1EFF
+ B97815FFB7750CFFBD780BFFC68211FFC58313FFBC7C10FFB67B14FFB67D1AFF
+ B47E1FFFB37D1FFFB47A1BFFB47818FFBA7916FFBB7C14FFB87C12FFB97F16FF
+ BB821FFFBC8326FFB9832CFFB68130FFB48138FFAC8043FFC2A277FFE7D4B9FF
+ F9F4EBFFF0F3F7FFE8EEF5FFE5EBF0FFEAECECFFF3F4F2FFE8ECEDFFE8EBEFFF
+ EDECF0FFEEEDF1FFF0EFF1FFF0F2F3FFF1F6F7FFF1F9F9FFEAF2F2FFEDF0EEFF
+ FEF5EBFFF0DCC3FFC8A67BFFBB9051FFC18C3BFFB57A1DFFB57B1BFFB87F1CFF
+ BC8320FFBC8320FFB77E1BFFB47B18FFB77C18FFB67C15FFB47A11FFB57B11FF
+ B87D10FFBB7F0EFFBE7F0FFFBF810FFFC0830FFFC18311FFBB7F0EFFB97C0EFF
+ B87B0DFFBB7E10FFBF8214FFC18416FFC08315FFC08315FFBB7E10FFB97C0EFF
+ B87B0DFFB87B0DFFB87B0DFFB87B0DFFB97C0EFFBB7E10FFB97C0EFFBB7E10FF
+ BF8214FFC18416FFC18416FFBF8214FFBB7E10FFB97C0EFFBE8113FFBD8012FF
+ BB7E10FFB97C0EFFB97C0EFFBB7E10FFBD8012FFBE8113FFBE8211FFBC800FFF
+ BA7E0DFFB87C0BFFB77B0AFFB87C0BFFBA7E0DFFBC800FFFBA7E0DFFBB7F0EFF
+ BB7F0EFFBC800FFFBB7F0EFFBA7E0DFFB97D0CFFB87C0BFFBC800FFFBB7F0EFF
+ B97D0CFFB87C0BFFB87C0BFFBA7E0DFFBC800FFFBD8110FFC18514FFBD8110FF
+ B87C0BFFB67A09FFB67A09FFB77B0AFFB87C0BFFB77B0AFFBC7D0DFFBD7E0EFF
+ BE7F0FFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBE7F0FFFBF8010FFC08111FFBB7C0CFFBC7D0DFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBA7C0AFFBB7D0BFF
+ BD7F0DFFBF810FFFBF810FFFBE800EFFBB7D0BFFB97B09FFBC800FFFBA7E0DFF
+ BA7E0DFFBD8110FFBC800FFFB87C0BFFB77B0AFFBA7E0DFFBE8211FFB97D0CFF
+ B97D0CFFAB6D09FFAF710DFFB37511FFB57713FFB47612FFB27410FFB1730DFF
+ B2740EFFB2750DFFB2750DFFB2750DFFB3760EFFB3770DFFB5790FFFB67A10FF
+ B77B11FFB57711FFB1730DFFB2740EFFB97B15FFBB7D17FFB87A14FFB67812FF
+ B77913FFB2740EFFB47610FFB57711FFB3750FFFB47610FFB77913FFB77913FF
+ B37713FFB67B18FFB87B1BFFBC7A1BFFB87819FFAD7817FFAD7915FFB77913FF
+ BB7A17FFB4761CFFB1781DFFAC7514FFB07714FFB17416FFA07439FF958F90FF
+ 9BAED4FF7DA0D2FF729DD6FF7FA8E7FF6B94D9FF4D7ACBFF527ED1FF557DC8FF
+ 4C75BAFF77A1E4FF678ED3FF3E5CA9FF364C9AFF2F3A84FF26347CFF617EC8FF
+ 638CD5FF507FC9FF4576C0FF487BC4FF6092DAFF749FE8FF658DD5FF4767B2FF
+ 2F4E99FF1D3D89FF3E62AEFF5B85D0FF5789D1FF5084C7FF5F93D5FF74A5E3FF
+ 79A5E5FF769AE0FF6484CBFF5270B1FF36528FFF1D3A73FF2B4B86FF4B71B2FF
+ 5681CAFF4E7DCFFF517FD3FF527ACCFF4E6BAEFF495886FF494B63FF5A4C50FF
+ 6E5644FF87643CFF926A30FF9C6F2BFFA47121FFA86E15FFB27513FFBE7E18FF
+ BC7F17FFB67B14FFB57C19FFB47D1CFFB37B1CFFB37919FFB47916FFB67814FF
+ B67911FFB47A11FFB97F18FFBB801CFFBC8223FFB88027FFA87323FFA0702EFF
+ A37E4AFFDBC4A4FFFBF1E0FFFCFCFCFFE9EFF6FFEAF2F9FFECF3F6FFEEECEBFF
+ F1F0ECFFE9ECF0FFEAEDF2FFEFEEF2FFF1EEF0FFEFEFEFFFEEF0F0FFEBF3F3FF
+ EBF5F5FFF2FAFAFFF8F9F5FFF4E9DBFFD3B99BFFB08857FFB5843EFFC48C33FF
+ BB7F1BFFBC831AFFB87F16FFB67F17FFB57E16FFB07813FFB37B16FFB9811CFF
+ B88119FFB88015FFB98013FFBA7F11FFBA800FFFBD7F0DFFBD7F0DFFBC7F0BFF
+ BC7E0CFFC18514FFBD8012FFBC7F11FFBE8113FFBF8214FFBD8012FFBD8012FF
+ BF8214FFBC7F11FFB97C0EFFB87B0DFFBA7D0FFFBA7D0FFFB87B0DFFB97C0EFF
+ BC7F11FFB97C0EFFBB7E10FFBE8113FFC18416FFC18416FFBE8113FFBB7E10FF
+ B97C0EFFB87B0DFFB97C0EFFBB7E10FFBD8012FFBD8012FFBB7E10FFB97C0EFF
+ B87B0DFFBD8110FFBC800FFFBA7E0DFFB97D0CFFB87C0BFFB97D0CFFBA7E0DFF
+ BB7F0EFFB87C0BFFB97D0CFFBB7F0EFFBC800FFFBD8110FFBB7F0EFFBA7E0DFF
+ B87C0BFFB77B0AFFB97D0CFFBC800FFFBE8211FFBE8211FFBD8110FFBA7E0DFF
+ B97D0CFFB97D0CFFB97D0CFFB97D0CFFBB7F0EFFBD8110FFBC800FFFB97D0CFF
+ B67A09FFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBD7E0EFFBE7F0FFFBF8010FF
+ C08111FFB97A0AFFBA7B0BFFBC7D0DFFBE7F0FFFBF8010FFBE7F0FFFBD7E0EFF
+ BC7D0DFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFF
+ BD7E0EFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBE800EFF
+ BE800EFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBF810FFFBE800EFFBC7E0CFF
+ B97B09FFBD8110FFBA7E0DFFBB7F0EFFC08413FFBE8211FFB77B0AFFB67A09FF
+ BB7F0EFFBC800FFFBA7E0DFFBA7E0DFFB1730FFFB1730FFFB0720EFFAE700CFF
+ AC6E0AFFAE700CFFB2740EFFB57711FFB2750DFFB2750DFFB3760EFFB3760EFF
+ B4780EFFB3770DFFB3770DFFB2760CFFB67812FFB2740EFFB3750FFFB87A14FF
+ BB7D17FFB77913FFB3750FFFB47610FFB57711FFB3750FFFB47610FFB77913FF
+ B97B15FFB87A14FFB97B15FFB97E17FFB67B17FFB87B19FFBE791CFFB77719FF
+ AC7716FFA97713FFB57A13FFBB7A17FFC17F26FFB7781CFFB97F18FFB87E15FF
+ BA7819FFAC793BFF93837DFF8C9AB7FF7595C6FF6993CEFF7399DAFF6088D0FF
+ 4C76C9FF4B74C9FF486FBDFF4B73BBFF6994D7FF6E97DCFF4062AEFF374F9BFF
+ 37458DFF2E3E83FF6686CDFF638DD4FF5586CCFF4A7DC3FF4679BFFF5283C7FF
+ 6B95DAFF7496DCFF5D79C0FF3E569EFF27408AFF2F4C96FF496FB7FF618BD0FF
+ 5F8FD1FF6291CFFF6F9CD9FF77A3E0FF7AA6E5FF6A94D5FF5F7FC8FF5269B4FF
+ 394C95FF253A7EFF2D4A87FF4266A2FF5985C4FF5A8BD1FF5C8CDAFF5782D3FF
+ 4B6CBBFF4058A0FF3B4D8AFF434C78FF4B4A5EFF5C5252FF786556FF907452FF
+ 99733DFF9F712AFFA9731EFFA87011FFB47B18FFB37B16FFB37C14FFB47D15FF
+ B57E15FFB77F12FFB87D0FFFB67B0DFFB1780FFFB77D16FFB57915FFB67B18FF
+ B77E23FFA46F1FFFA07536FFBB9B70FFF1E1CAFFF7F1EAFFECF0F5FFDEE7F0FF
+ E8F0F7FFF2F7F8FFF5F2EEFFF0EDE9FFF0F1F5FFEFF2F7FFF6F2F7FFF4F2F2FF
+ EDEDEDFFE6EBEAFFE1EBEBFFDFEBEDFFF4FCFCFFF6F6F0FFE6D6C6FFC2A382FF
+ AC804AFFB07C30FFBE8425FFC4881EFFC28A1BFFB98213FFB68113FFB37F15FF
+ AE7911FFB37E16FFB8831BFFB78017FFBB8318FFBC8316FFBC8113FFBA800FFF
+ BD7F0DFFBB7D0BFFBA7B08FFB97B09FFC08413FFBD8012FFBC7F11FFBE8113FF
+ BC7F11FFB97C0EFFBA7D0FFFBF8214FFBE8113FFB97C0EFFB87B0DFFBB7E10FF
+ BB7E10FFB87B0DFFB97C0EFFBE8113FFBB7E10FFBC7F11FFBC7F11FFBD8012FF
+ BD8012FFBC7F11FFBC7F11FFBB7E10FFB87B0DFFBA7D0FFFBC7F11FFBD8012FF
+ BD8012FFBC7F11FFBA7D0FFFB87B0DFFBC800FFFBB7F0EFFBB7F0EFFBA7E0DFF
+ BA7E0DFFB97D0CFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFBA7E0DFF
+ BB7F0EFFBC800FFFBC800FFFBC800FFFB67A09FFB87C0BFFBC800FFFBF8312FF
+ BF8312FFBE8211FFBB7F0EFFB97D0CFFBA7E0DFFBA7E0DFFBA7E0DFFBD8110FF
+ BE8211FFBD8110FFB97D0CFFB67A09FFBE7F0FFFBD7E0EFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFFBE7F0FFFBC7D0DFFBC7D0DFF
+ BB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBD7F0DFFBE800EFFBF810FFFBD7F0DFFBC7E0CFFBB7D0BFFBC7E0CFF
+ BE800EFFBE800EFFBC7E0CFFBA7C0AFFBC800FFFBD8110FFBD8110FFBD8110FF
+ BA7E0DFFB97D0CFFBB7F0EFFBF8312FFB97D0CFFBB7F0EFFBB7F0EFFAE700CFF
+ AE720EFFB27410FFAF730FFFAF710DFFAC700CFFAF710DFFAF740DFFB1730DFF
+ B0760DFFB3760EFFB2780FFFB4770FFFB0760CFFB1750BFFB0730BFFB77913FF
+ B3750FFFB3750FFFB87A14FFBA7C16FFB57711FFB1730DFFB0720CFFB87A14FF
+ B3750FFFB57711FFBB7D17FFBD7F19FFBA7C16FFBB7D17FFC1831DFFB67B14FF
+ B97B17FFBD791AFFB97718FFAD7613FFAB7712FFB47814FFBB7A18FFB77719FF
+ AC6C0DFFB57A13FFB4770FFFB36F10FFA76D25FF856647FF7C7474FF909BAFFF
+ 869BBBFF8294BDFF6C80B0FF647AAEFF5774B1FF456AB4FF527CC7FF5784C8FF
+ 6C95DAFF3E5EAAFF334B97FF36448CFF2B3777FF6275AEFF5772A5FF6688BDFF
+ 5C83BAFF4C76B9FF4975BCFF618BD2FF7A9EE4FF6B88CBFF475FA1FF384E90FF
+ 253C80FF375497FF6084C4FF6994D3FF628ECDFF6491D4FF6C9BDFFF6699D8FF
+ 6A97DAFF5D80CAFF4E68B5FF4C60ADFF4457A0FF2D4789FF1C3E7AFF4B74B3FF
+ 4978BCFF4978C9FF4775CDFF446DC9FF3F66C2FF3D61B9FF4361AEFF475B94FF
+ 556288FF787F93FFA09B9DFFAE9C8BFFAE916CFFAA8247FFA47327FFAE791EFF
+ B07A15FFB27C11FFB67E11FFBA8314FFBC8415FFBB8012FFB97E11FFB77C15FF
+ BE811FFFB57818FFB47B20FFBB8433FFA57835FFAB8A5CFFD9C4A8FFFFFFF4FF
+ F3F5F5FFE4EAEFFFDFE7EEFFE9EEF1FFF4F6F6FFF6F5F1FFECEAE9FFECEDF1FF
+ EEEEF4FFF5F2F4FFF4F2F2FFEEEEEEFFE7EBECFFE1EAEDFFE2EBEEFFEBF0EFFF
+ EDE6DDFFDAC3ADFFC29E76FFB8894BFFB67F2EFFBC8222FFCD9329FFC38B1CFF
+ BA8314FFB98416FFBB851AFFB47F17FFB68119FFB98219FFB17A11FFBB8318FF
+ BB8215FFBC8113FFBA800FFFBB7F0EFFBB7D0BFFBA7C0AFFB97B09FFBB7F0EFF
+ B87B0DFFBA7D0FFFBD8012FFBB7E10FFB77A0CFFBB7E10FFC38618FFBF8214FF
+ BA7D0FFFB97B0FFFBC7E12FFBC7E12FFB97B0FFFBA7C10FFBF8115FFBE8113FF
+ BD8012FFBB7E10FFB97C0EFFB97C0EFFBB7E10FFBD8012FFBE8113FFBE8113FF
+ BD8110FFBB7E10FFB97D0CFFB97D0CFFBB7F0EFFBD8110FFBE8211FFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFB87C0BFFB97D0CFF
+ B87C0BFFB87C0BFFB87C0BFFB97D0CFFBB7F0EFFBE8211FFBF8312FFBB7F0EFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBB7F0EFFBC800FFFBD8110FFBE8211FFC48817FF
+ C08413FFBC800FFFB97D0CFFB97D0CFFB97D0CFFB87C0BFFB77B0AFFBE7F0FFF
+ BD7F0DFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BD7E0EFFBB7C0CFFBA7B0BFFB97A0AFFB97A0AFFBA7B0BFFBA7B0BFFC08111FF
+ BE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBC7D0DFFBE7F0FFFBF8010FFBE7F0FFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBC7D0DFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBE800EFFBF810FFFBF810FFF
+ BC7E0CFFBA7C0AFFBA7C0AFFBD7F0DFFBE800EFFBD7F0DFFBB7C0CFFBA7E0DFF
+ BF8214FFBF8312FFB87C0BFFB67A09FFBC800FFFC18513FFC28614FFB77B09FF
+ BC800EFFBC800FFFAC6F0DFFAC710EFFAF7210FFAF7411FFB17412FFAF7410FF
+ AF730FFFAE740DFFAE730CFFAE740DFFB0750EFFAD740BFFAD730AFFAE750CFF
+ B47A11FFB87E15FFB2740EFFB3750FFFB0720CFFB67812FFBF811BFFB77913FF
+ AF710BFFB57711FFBB7D17FFBA7C16FFB97B15FFB77913FFB77913FFB77913FF
+ B77913FFB87A14FFB3760EFFB47610FFB77613FFB67814FFB47814FFB27713FF
+ B47612FFB37511FFB97A18FFB77816FFB57713FFB77915FFBD7C1AFFB87921FF
+ A67226FF91692FFF836A42FF827059FF7D6A63FF705D5AFF6B5F53FF676B76FF
+ 4E6EAFFF406EC2FF4772BBFF5C83C8FF425EABFF2A3E8BFF3A4890FF373C73FF
+ 251F3EFF262031FF181F30FF314362FF566FADFF597AC9FF537ECFFF6A94DFFF
+ 6E96D1FF5978AFFF465A94FF42528DFF364883FF3E5894FF5D82BCFF6C97DAFF
+ 5F8FE1FF5588DEFF5C8DDBFF5988D2FF5C83CDFF5778C1FF4D6BB2FF4E6BB5FF
+ 4A6AB5FF3B5DA9FF2C51A1FF3358ACFF4065BAFF4A6FC4FF486EC6FF436BC3FF
+ 4673CAFF5580D1FF6587CDFF5F7DB4FF738FB8FFABC0DCFFC5CCE0FFD1C8CBFF
+ B1977FFF8A632FFFAA7B29FFB27E19FFB67E11FFB8800FFFBA8211FFBD8214FF
+ BB7D17FFBA7916FFBB7815FFC58324FFBD802AFFB58135FFB88C51FFB5976EFF
+ CBBBA4FFF5F0E7FFF3F8F7FFEFF6F9FFEEF3F4FFEBF1F0FFEDF0EEFFEEEFEDFF
+ EEEEEEFFEEEDEFFFEEEDF1FFE8E7EBFFE7E6E8FFEAEAEAFFE8EBEFFFE9EDF2FF
+ E6ECF3FFE7EAEEFFF1ECE9FFDFCFBFFFBF9E7DFFAD824FFFB4813BFFB37C27FF
+ B47B1EFFC78E2BFFBA7F18FFC1861FFFC68B24FFC38821FFBB8019FFB57A13FF
+ B67C13FFB97F16FFBB8117FFB57A0DFFB2770AFFB77C0EFFBA7F11FFBA7D0FFF
+ BA7D0FFFBE8211FFBB8012FFB97E10FFB77C0EFFB87D0FFFBB8012FFBC8113FF
+ BA7F12FFB87D10FFBC8114FFB87D10FFB77B11FFB97D13FFB77B11FFB3770DFF
+ B67A10FFBE8218FFBC7E12FFBA7D0FFFB97C0EFFBA7D0FFFBD8012FFC08315FF
+ C18514FFC18514FFB97D0CFFBA7E0CFFBB7F0EFFBB7F0DFFBB7F0DFFBB7F0DFF
+ BA7E0CFFB97D0BFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBD7F0DFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BA7C0AFFB97B09FFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFC18311FFBF810FFFBE800EFFBD7F0DFFBD7F0DFFBE800EFF
+ BF810FFFC18311FFB77B09FFB97E0AFFBB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFF
+ BB7F0DFFBE8210FFBC800FFFBA7E0DFFBA7D0FFFBC7F11FFBE8113FFBE8113FF
+ BB7E10FFB87B0DFFB87B0DFFBA7D0FFFBC7F11FFBC7F11FFBA7D0FFFBA7D0FFF
+ BC7F11FFBE8113FFB97C0EFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBB7E10FF
+ BA7D0FFFBA7D0FFFBB7E10FFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0CFFBA7E0CFF
+ B97E0AFFB97E0AFFBB800CFFBA7F0BFFB87C0AFFB77B09FFB77B0AFFB87C0BFF
+ BA7E0DFFBB7E10FFBF8115FFBE8014FFBC7F11FFBA7E0DFFB97D0CFFBA7E0CFF
+ BB800CFFBC810DFFBF8410FFB77C08FFB77B09FFAD720FFFAE7310FFAF7411FF
+ B07512FFB07512FFAF7411FFAE730FFFAD720EFFAB710AFFAE740DFFB17710FF
+ B37912FFB37A11FFB27910FFB1780FFFB1780FFFB1730DFFB57711FFB2740EFF
+ B47610FFBB7D17FFB77913FFB1730DFFB67812FFBB7D17FFBA7C16FFB87A14FF
+ B77913FFB77913FFB77913FFB77913FFB87A14FFB57810FFB57810FFB67812FF
+ B67812FFB67812FFB67812FFB57713FFB57713FFB67814FFB77915FFB87917FF
+ B77816FFB77816FFB87917FFB9791AFFB37920FFA3742AFFA0753CFF9C6F49FF
+ 936944FF8E6B39FF7B6D5AFF536BA1FF456FC2FF517BC2FF6083C7FF4960ACFF
+ 33438FFF3E488EFF3D3C6EFF372433FF3B2422FF271B17FF2E2E3CFF465183FF
+ 5874BBFF5780CFFF5D8ED8FF6695D3FF5C83BAFF586EA8FF44528DFF2B3973FF
+ 2F427BFF435F95FF4C71ABFF5881C6FF6D9AE4FF5E8AD7FF5F8BD8FF648FD8FF
+ 658FD6FF618BD0FF638DD4FF5883CCFF456CBAFF476CBCFF3C5FAFFF395AAAFF
+ 3E5FAFFF4466B9FF4D73C5FF5781D4FF6089D8FF688BD4FF799BD7FF8CB1DDFF
+ ADCBEEFFC3D2F3FFD8D7E7FFB6A396FF836034FFA6782AFFB27C17FFB57B11FF
+ B97C0EFFB87D0FFFB97D13FFB77A1AFFB9791BFFD59132FFBB7A1EFFB17627FF
+ AC7C3CFFAA875BFFCCB79CFFEDE6DDFFEBEFF0FFE9F2F6FFE8F1F4FFEAF0EFFF
+ EBEFEAFFECEDE9FFECEDEBFFEBECF0FFEBEBF1FFF2F1F5FFF0EDEFFFE7E6E8FF
+ E8EAEBFFF0F3F7FFEFF3F8FFEDF0F5FFF8F6F6FFF4E8DEFFCDB59DFFBE976BFF
+ C6975AFFC38D40FFAF7620FFA86F12FFAE7414FFB87B19FFBC7E1AFFBF811DFF
+ BF811BFFBD7F19FFBB7E16FFB97C14FFB87C12FFBA7E14FFB67A10FFB57A0DFF
+ B97E11FFBA7F12FFB67B0EFFB57A0CFFB77C0EFFBB8012FFB97E10FFB87D0FFF
+ B87D0FFFBB8012FFBB8012FFBA7F12FFB87D10FFB5790FFFB4780EFFB87C12FF
+ BD8117FFBD8018FFBA7D15FFBC7F17FFC2861CFFC18317FFBE8113FFBB7E10FF
+ B97C0EFFBA7D0FFFBB7E10FFBA7E0DFFB87C0BFFB77B09FFB97D0BFFBB7F0DFF
+ BD810FFFBD820EFFBB800CFFB97E0AFFB77C08FFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFFBA7C0AFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBE800EFFBD7F0DFFB97E0AFFBB800CFFBC810DFF
+ BB800CFFB97D0BFFB87C0AFFBA7E0CFFBB7F0DFFBB7F0EFFBB7F0EFFBB7E10FF
+ BC7F11FFBD8012FFBD8012FFBB7E10FFB97C0EFFBD8012FFBF8214FFC08315FF
+ C08315FFBE8113FFBD8012FFBF8214FFC18416FFBC7F11FFBC7F11FFBC7F11FF
+ BC7F11FFBB7E10FFB97C0EFFB77A0CFFB6790BFFBB7E10FFBB7E10FFBB7F0EFF
+ BB7F0EFFBA7E0CFFBA7E0CFFB97E0AFFB97E0AFFB97E0AFFB97E0AFFB97D0BFF
+ BA7E0CFFBA7E0DFFB97D0CFFB97C0EFFB97C0EFFBC7E12FFBC7E12FFBC7F11FF
+ BB7F0EFFBB7F0DFFBA7E0CFFB97E0AFFB97F08FFC18612FFBA7F0BFFBA7E0CFF
+ AF7411FFAF7411FFB07512FFB07512FFB07512FFB07512FFAF7410FFAE730FFF
+ B07511FFB17612FFB27811FFB47A13FFB57B14FFB57B14FFB27910FFAF760DFF
+ B0720CFFB77913FFB57711FFB2740EFFB57711FFB67812FFB47610FFB67812FF
+ BA7C16FFB97B15FFB87A14FFB77913FFB67812FFB77913FFB77913FFB87A14FF
+ B77A12FFB77A12FFB67812FFB67812FFB67812FFB67812FFB77915FFB77915FF
+ B47612FFB77915FFBA7B19FFB87917FFB57614FFB67715FFBC7C1DFFBD8225FF
+ AE7825FFA97630FFA7733EFFA4723EFF9C7132FF806B4BFF576791FF4D70BAFF
+ 4D70B2FF516EB1FF41559CFF354489FF3D4686FF3C3B67FF3C2835FF442722FF
+ 422520FF322027FF333554FF576DA1FF5B85C8FF5086CDFF548AD1FF4A79BDFF
+ 4D6DAFFF394F90FF2B3A79FF303E78FF2F4071FF273B64FF405473FF637DA2FF
+ 5677B6FF5B84CDFF6796E0FF659AE3FF5D98DEFF609BE0FF669CDBFF6094D0FF
+ 507EB8FF4A73B1FF486EAFFF4062A8FF304F9AFF3856A3FF5973BFFF6F89CFFF
+ 748CCEFF7C97CAFF87A6C7FFA8C0D6FFB6C0D1FFBCB6B7FFA2896FFF8C642FFF
+ B17D2AFFBD811DFFC2801AFFC27F18FFBE7F17FFBB7F1BFFBC7F22FFBF8026FF
+ C68529FFB0701BFFAA732AFFAC7F46FFB79773FFE4D3BEFFFFFCF5FFEEF2F3FF
+ E9EFF4FFE7F0F3FFEAF0EFFFECEFEDFFEEEFEDFFEFEFEFFFEEEFF3FFEEEFF3FF
+ F4F1F3FFF5F2F4FFECEBEDFFE9EAEEFFF0F3F7FFF0F2F3FFF1EFEFFFFFF9F0FF
+ D9C5B3FFB49673FFB98F5AFFD39F5CFFC99140FFC0842AFFC08424FFB67B17FF
+ B77915FFB67812FFB67812FFB97B15FFBD7F19FFBD8018FFBA7D15FFB67A10FF
+ BB7F15FFBB8013FFBD8215FFBF8417FFBE8315FFB97E10FFB77C0EFFB97E10FF
+ BB8110FFB97F0EFFB87E0DFFB97F0EFFBA7F11FFBB8012FFBA7F11FFB87D0FFF
+ B87D10FFBA7F12FFBF8417FFC3881BFFC1851BFFBB7F15FFB97D13FFBB7F15FF
+ BC7E12FFBA7D0FFFB87B0DFFB87B0DFFBA7D0FFFBB7E10FFBB7F0EFFB97D0CFF
+ B67A08FFB87C0AFFBC800EFFBF8311FFBF8410FFBC810DFFB87D09FFB67B07FF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BA7C0AFFBC7E0CFFBD7F0DFFBF810FFFBF810FFFBD7F0DFFBC7E0CFFBA7C0AFF
+ BB800CFFBC810DFFBD820EFFBC810DFFB97D0BFFB77B09FFB87C0AFFBA7E0CFF
+ BA7E0DFFBB7F0EFFBD8012FFBD8012FFBC7F11FFBB7E10FFBB7E10FFBB7E10FF
+ BA7D0FFFBB7E10FFBD8012FFBC7F11FFB97C0EFFB87B0DFFBA7D0FFFBB7E10FF
+ BB7E10FFBB7E10FFBC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFFB87B0DFF
+ BC7F11FFBB7E10FFBB7F0EFFBA7E0DFFBA7E0CFFB97D0BFFB97E0AFFB97E0AFF
+ B77C08FFB97E0AFFBA7E0CFFBC800EFFBC800FFFBA7E0DFFB97C0EFFB77A0CFF
+ B87B0DFFBA7D0FFFBB7E10FFBC800FFFBC800EFFBA7E0CFFB87C0AFFB77C08FF
+ BF8311FFB97D0BFFB97D0BFFAE7310FFAF7411FFAF7411FFB07512FFB17613FF
+ B17613FFB17612FFB17612FFB97E1AFFB57A16FFB17710FFB0760FFFB27811FF
+ B47A13FFB47B12FFB37A11FFB0720CFFB87A14FFB87A14FFB1730DFFB0720CFF
+ B57711FFB77913FFB77913FFB97B15FFB87A14FFB77913FFB67812FFB67812FF
+ B77913FFB77913FFB87A14FFBA7D15FFB97C14FFB77913FFB67812FFB67812FF
+ B77913FFB97B17FFBA7C18FFB57713FFB87A16FFB97A18FFB97A18FFB87917FF
+ B97A18FFBC7C1DFFBE8022FFB1781BFFB17927FFB47934FFB07635FFA77229FF
+ 896C40FF616784FF526EAEFF4A68A9FF4662A3FF405397FF3F4A8EFF404884FF
+ 3C3A64FF3E2D38FF452821FF4E2A22FF391C18FF32272FFF5C6580FF6787B8FF
+ 5B89C9FF588CD8FF4475C3FF365EA6FF365698FF3C5293FF40538CFF313F6FFF
+ 1C2747FF272F3CFF414A58FF52638AFF486298FF476DA7FF4F80BEFF5791D3FF
+ 609CDEFF68A3E1FF6CA5DDFF74A8DDFF6392C8FF5480BDFF456AAEFF2E4E97FF
+ 2C458FFF36488FFF364584FF6773A9FF667197FF616E7CFF737B7AFF80766FFF
+ 8E7660FF956E41FFA87431FFBA7E24FFC68320FFC78322FFC48321FFBD801EFF
+ BA7E1EFFB97D23FFBB7F26FFBE7E29FFB77E2FFFA77435FFAF8959FFDCC1A6FF
+ F5E8DAFFF1EDECFFEEF1F5FFEFF3F8FFEDF4F7FFEEF4F3FFEFF4F2FFF1F3F3FF
+ F1F3F4FFF1F2F6FFF1F2F6FFEFECEEFFF3F1F1FFF3F2F6FFEDEEF2FFE9EAEEFF
+ EEECECFFF1E9E2FFF3E3D2FFBCA383FFB28E60FFBB8C4EFFBE883BFFB0751FFF
+ BA7D1FFFC48725FFB2740EFFB57711FFB57810FFB57711FFB87B13FFBB7E16FF
+ BC8016FFBA7E14FFB77C0FFFB77C0FFFBA7F12FFBC8114FFBD8214FFBA7F11FF
+ B87D0FFFB87D0FFFBB8110FFBA800FFFB97F0EFFB97F0EFFB97F0EFFBA7F11FF
+ BA7F11FFBA7F11FFB97E10FFB97E11FFBC8114FFC08518FFC2871AFFBF8319FF
+ BA7E14FFB77B11FFB77C0FFFBB7E10FFB97C0EFFB87B0DFFB97C0EFFBB7E10FF
+ BD8012FFBC800FFFBB7F0EFFB87C0AFFB97D0BFFBB7F0DFFBD810FFFBD820EFF
+ BB800CFFB97E0AFFB87D09FFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFF
+ BD7F0DFFBF810FFFC18311FFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBE800EFFBE800EFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBA7C0AFFBA7F0BFFBC810DFFBD820EFFBB800CFFB97D0BFF
+ B87C0AFFB97D0BFFBB7F0DFFB97D0CFFBC800FFFBE8113FFBD8012FFBB7E10FF
+ B97C0EFFBB7E10FFBD8012FFB87B0DFFBA7D0FFFBB7E10FFB97C0EFFB77A0CFF
+ B5780AFFB6790BFFB87B0DFFB5780AFFB77A0CFFB97C0EFFBB7E10FFBC7F11FF
+ BD8012FFBD8012FFBD8012FFBC7F11FFBC7F11FFBB7F0EFFBA7E0DFFB97D0BFF
+ B97D0BFFBA7F0BFFBA7F0BFFB97E0AFFB97E0AFFBB7F0DFFBB7F0DFFBB7F0EFF
+ BB7F0EFFB97C0EFFB97C0EFFB87B0DFFB97D0CFFBA7E0DFFBA7E0DFFBA7E0CFF
+ B97D0BFFB87C0AFFB77B09FFBA7E0DFFB57907FFB57907FFAC7010FFAD7111FF
+ AE7212FFAF7313FFB17613FFB27714FFB47916FFB57A17FFBA7F1BFFB67B17FF
+ B27811FFB0760FFFB27811FFB47A13FFB47A13FFB27811FFB1730DFFB67812FF
+ B87A14FFB2740EFFAE700AFFB47610FFB97B15FFB77913FFB87A14FFB77913FF
+ B67812FFB67812FFB67812FFB67812FFB87A14FFB87A14FFBA7D15FFB97C14FF
+ B87A14FFB77913FFB77913FFB87A14FFB97B17FFBA7C18FFB87A16FFB77915FF
+ B77816FFB97A18FFBC7D1BFFBD7E1CFFBB7B1CFFB87917FFB57915FFBB7F1FFF
+ BE7D2CFFB67628FFAE721EFF96703AFF6B697CFF556AA1FF536FAFFF506CADFF
+ 4F62A6FF4E5A9CFF474F8AFF3E3D65FF3C2D35FF41251EFF4D2A1DFF492717FF
+ 513925FF706861FF727E96FF6B87BDFF648EDBFF4678CBFF3968B2FF406CACFF
+ 496CABFF47649DFF3E5085FF354066FF363A45FF373638FF333039FF383B4AFF
+ 43546EFF56739AFF5C83BAFF5585C7FF598DD3FF689FE4FF84BDFAFF7AB1EEFF
+ 72A4E6FF628ED5FF4D6FBBFF435BA7FF404F97FF3E447FFF433E65FF675A6AFF
+ 786A5EFF8B7355FF966D46FFAC7641FFAE6E27FFAF6A13FFBD7916FFC07E18FF
+ BD7E22FFBA7E24FFB37C21FFAD791BFFAE771CFFAE761DFFCC9443FFC08C46FF
+ A67C47FFC1A17EFFFEEAD8FFFFF8F1FFE6E3E5FFEAEDF2FFF1F4F9FFF0F5F8FF
+ F1F6F5FFF0F5F4FFF1F3F4FFF0F1F5FFEFEFF5FFEFEFF5FFEEECECFFEDEBEBFF
+ F1F2F6FFEFEFF5FFE9E8ECFFF6F1EEFFF4E7D9FFD8C2A6FFBE9B6FFFC69A5DFF
+ C39047FFB57C27FFAF7214FFC0811FFFC88822FFB97A12FFB67911FFB87C12FF
+ BB7E16FFBB7F15FFB97D13FFB87D10FFB97E11FFBA7F12FFB2770AFFB57A0CFF
+ B67B0DFFB57A0CFFB3780AFFB57B0AFFB87E0DFFBB8110FFB97F0EFFBA810EFF
+ BA810EFFBA810EFFB97F0EFFB97F0EFFB97F0EFFBA800FFFB3780AFFB77C0EFF
+ BB8013FFBB8013FFBA7F12FFBA7F12FFBB8013FFBC8114FFC28517FFC08315FF
+ BD8012FFBD8012FFBD8012FFBC7F11FFB97D0CFFB67A09FFBB7F0DFFBA7E0CFF
+ BA7E0CFFBA7E0CFFBA7F0BFFBA7F0BFFBA7F0BFFBB800CFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBE800EFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFC08210FFC18311FFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBC7E0CFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFB87D09FFBA7F0BFF
+ BB800CFFBB800CFFBA7E0CFFB97D0BFFBB7F0DFFBD810FFFBA7E0DFFBC800FFF
+ BE8113FFBC7F11FFBA7D0FFFB97C0EFFBB7E10FFBE8113FFBD8012FFBE8113FF
+ BF8214FFBE8113FFBB7E10FFBA7D0FFFBB7E10FFBD8012FFB5780AFFB77A0CFF
+ B97C0EFFBB7E10FFBC7F11FFBD8012FFBD8012FFBD8012FFBD8012FFBC7F11FF
+ BA7E0DFFB97D0CFFB97D0BFFB97D0BFFBA7F0BFFBB800CFFBC810DFFBB800CFF
+ BA7E0CFFB97D0BFFB97D0CFFBA7E0DFFBB7E10FFBC7F11FFBA7E0DFFB97D0BFF
+ B87C0AFFB87C0AFFB87C0BFFB97D0CFFBA7E0DFFBB7F0EFFB87B0DFFB67A09FF
+ B67A09FFAC7010FFAC7010FFAD7111FFAE7212FFAF7411FFB17613FFB37815FF
+ B47916FFB27713FFB37814FFB37814FFB57B14FFB57B14FFB37912FFB0760FFF
+ AE740DFFB47610FFB3750FFFB67812FFB47610FFB0720CFFB47610FFB97B15FF
+ B67812FFB77913FFB67812FFB57711FFB57711FFB57711FFB67812FFB87A14FF
+ B87A14FFB97C14FFB87B13FFB87A14FFB77913FFB77913FFB87A14FFB87A16FF
+ B97B17FFB97B17FFB67814FFB57614FFB97A18FFBD7E1CFFBE7F1DFFBA7A1BFF
+ B47612FFB67C13FFBE801AFFC17E22FFB8751EFFB3741AFF9E7237FF746C73FF
+ 596998FF4F6AAAFF526FB4FF5269ADFF4C5C9EFF434D89FF3A3A62FF362B35FF
+ 39241CFF442719FF523018FF775629FF896F4AFF7B706CFF707A98FF6483C8FF
+ 517DD0FF497EC7FF4C81C4FF4D7EBCFF4970AEFF4764A1FF4D5E8FFF454C65FF
+ 343035FF5E4C41FF483526FF332A21FF43464AFF646F8AFF6B82AFFF6484BFFF
+ 5F8AC9FF5B8ECCFF6499D8FF679BDEFF5C89D3FF4E71C1FF4563B2FF4960ABFF
+ 5966A4FF5B5A86FF62596EFF6B5B54FF876C51FF91643FFFA36836FFB06D28FF
+ BD7A25FFB9791AFFBA7D1DFFB67E25FFB47E29FFB37F25FFB07D21FFB27B20FF
+ AF7922FFB78239FFAC7E44FFBA986DFFE7CFB7FFFFF7EFFFFAF5F7FFEBEBF1FF
+ EDEFF7FFEDF0F4FFEDF1F2FFEDF1F2FFEDF1F2FFEEEFF3FFECECF2FFEBEAF3FF
+ EAEAF0FFF0F0F0FFE8E7E9FFE9ECF1FFEFEFF5FFF4F0F5FFFFF7F0FFF0DBC6FF
+ C2A37CFFB0884EFFB6843CFFB17A25FFAF7417FFB77A18FFBE801AFFC07E17FF
+ BA7B13FFB97B11FFBA7F12FFBC8016FFBB8013FFB87D10FFB77C0FFFB87D10FF
+ BB8013FFB77C0EFFBA7F11FFBA7F11FFB87D0FFFB87E0DFFBD8312FFC18716FF
+ C28817FFB87F0CFFBA810EFFBB820FFFBA810EFFB97F0EFFB87E0DFFB97F0EFF
+ BB8110FFB67B0DFFB97E10FFBA7F12FFB77C0FFFB57A0DFFB77C0FFFB87D10FF
+ B87D10FFBF8214FFBE8113FFBD8012FFBD8012FFBF8214FFBF8214FFBC800FFF
+ B97D0CFFBC800EFFBB7F0DFFB97D0BFFB87C0AFFB87D09FFB97E0AFFBB800CFF
+ BC810DFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFF
+ BA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBF810FFF
+ BF810FFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFB97B09FFB97B09FFBA7C0AFFBC7E0CFF
+ BD7F0DFFB77C08FFB97E0AFFBB800CFFBB800CFFBA7E0CFFBA7E0CFFBC800EFF
+ BE8210FFBC800FFFBC800FFFBC7F11FFBB7E10FFBA7D0FFFBA7D0FFFBC7F11FF
+ BD8012FFBB7E10FFBC7F11FFBE8113FFBD8012FFBA7D0FFFB97C0EFFBB7E10FF
+ BC7F11FFBB7E10FFBB7E10FFBC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFF
+ B87B0DFFBE8113FFBC7F11FFBA7E0DFFB87C0BFFB87C0AFFB97D0BFFBA7F0BFF
+ BB800CFFBD820EFFBC810DFFBA7E0CFFB97D0BFFB97D0CFFBA7E0DFFBC7F11FF
+ BD8110FFBB7F0DFFBA7E0CFFB87C0AFFB77B09FFB87C0BFFB97C0EFFBC7F11FF
+ BD8012FFBB7D11FFBA7D0FFFBA7D0FFFAF7313FFAE7212FFAD7111FFAD7111FF
+ AD7111FFAF7313FFB07512FFB17613FFAE7310FFB07511FFB37814FFB47915FF
+ B27713FFB07511FFAF750EFFAE740DFFB77913FFAF710BFFB2740EFFB77913FF
+ B3750FFFB47610FFB87A14FFB57711FFB67812FFB57711FFB57711FFB57711FF
+ B57711FFB67812FFB87A14FFB97B15FFB77A12FFB77A12FFB87A14FFB87A14FF
+ B87A14FFB87A14FFB77915FFB77915FFB57713FFB57713FFB57614FFB77816FF
+ B97A18FFBB7C1AFFBB7B1CFFB87C18FFBA8118FFB77E15FFBA7819FFBA771BFF
+ B7761AFF9E7233FF786C6CFF5F6B95FF4763A4FF5070BBFF4E69B3FF405599FF
+ 374482FF2E345FFF2C2532FF31231DFF35221AFF45290BFF875C1DFF9E7330FF
+ 8C6B44FF7E7071FF6574A5FF5B83CBFF5187CEFF4C8AD0FF518ED2FF5087CCFF
+ 4C76C1FF4E6EB0FF475B8BFF424155FF755948FF8F643DFF845E2EFF6A4A1FFF
+ 563C24FF524445FF696D86FF889BC6FF6587BCFF638CCAFF5680C5FF4C76C3FF
+ 567BCFFF557ACEFF4A71BFFF4C72BAFF506AB0FF394D84FF4D5876FF8F8D99FF
+ A48B8FFF9E7769FF966741FFA06E32FFAC7B2BFFAD7D25FFAE7D27FFB07F29FF
+ B58329FFBA852AFFBF862BFFBB8331FF9C6C2AFFA78151FFD9BFA1FFFFF1E4FF
+ F9F3F4FFEBEAF4FFEEEFF9FFEEF0F8FFEBECF0FFECEEEFFFEDEFF0FFEEF0F1FF
+ ECEFF3FFEBEEF3FFECEBF4FFEBEBF1FFEFF1F2FFEBEDEEFFE5E7EFFFECEBF4FF
+ FBF6F8FFF7E8DFFFD4BA9CFFB38E5CFFB2833FFFB57F2CFFB67D20FFBE831FFF
+ C48620FFC0831BFFBF7D16FFBB7D13FFBB7D11FFB87D0FFFB77C0FFFB77C0EFF
+ B97E10FFB97E10FFB97E10FFB87D0FFFBB8012FFBE8315FFBE8413FFBC8211FF
+ BE8413FFC38918FFC48A19FFC08615FFB87F0CFFBA810EFFBB820FFFBB820FFF
+ B87F0CFFB87F0CFFB97F0EFFBB8110FFB97E10FFBE8315FFBE8315FFB87D0FFF
+ B4790CFFB57A0DFFB57A0DFFB2770AFFB87B0DFFB77A0CFFB87B0DFFBB7E10FF
+ BF8214FFC18416FFBF8312FFBD8110FFBB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFF
+ BA7F0BFFBA7F0BFFBB800CFFBB800CFFBA7C0AFFBB7D0BFFBD7F0DFFBF810FFF
+ BF810FFFBD7F0DFFBB7D0BFFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFB87D09FFBA7F0BFFBC810DFFBB800CFF
+ B97D0BFFB97D0BFFBA7E0CFFBC800EFFBE8211FFBC800FFFBA7D0FFFBA7D0FFF
+ BB7E10FFBC7F11FFBC7F11FFBC7F11FFB77A0CFFB97C0EFFBB7E10FFBA7D0FFF
+ B87B0DFFB87B0DFFB97C0EFFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBC7F11FF
+ BB7E10FFB97C0EFFB77A0CFFB6790BFFBE8113FFBC7F11FFBA7E0DFFB87C0BFF
+ B87C0AFFB97D0BFFBA7F0BFFBC810DFFBC810DFFBB800CFFBB7F0DFFBB7F0DFF
+ BB7F0EFFBB7F0EFFBB7E10FFBC800FFFBA7F0BFFBA7F0BFFBA7E0CFFBA7E0CFF
+ BB7F0EFFBB7E10FFBC7E12FFBD7F13FFBB7D13FFBB7D11FFBB7E10FFB27616FF
+ B07414FFAE7212FFAD7111FFAC7010FFAC7010FFAD720FFFAD720FFFB07512FF
+ B17613FFB17612FFAE730FFFAB700CFFAC710DFFB0760FFFB37912FFBA7C16FF
+ AD6F09FFB0720CFFB97B15FFB67812FFB47610FFB77913FFB47610FFB57711FF
+ B57711FFB47610FFB47610FFB57711FFB67812FFB87A14FFB97B15FFB57810FF
+ B67911FFB87A14FFB97B15FFB97B15FFB87A14FFB67814FFB57713FFB0720EFF
+ B47612FFB67715FFB67715FFB57614FFB67715FFBC7C1DFFC08321FFBA861CFF
+ B17A11FFB37412FFBB781BFFB8791DFFA07030FF7C6C60FF686F90FF536FB0FF
+ 5B7ECEFF5573C0FF3D559DFF314183FF292F5CFF25212DFF2B211AFF43342BFF
+ 432806FF8D5C10FFAB761CFF9B6B29FF86694AFF5E6176FF5B78ABFF5887C4FF
+ 518CD1FF5D9BE2FF5E99E8FF5084D7FF4D75C7FF5270B1FF61698EFF7B5E59FF
+ A0714BFFA37234FF9D6A24FF9A6A2AFF886232FF67523DFF4F4A4CFF7A8397FF
+ 8194B9FF738CBEFF617DBAFF6080C7FF587FC9FF4F80C4FF5B8FD2FF5079C2FF
+ 4668AAFF6884B3FFB4C4E8FFD0CDEDFFD2C1CFFFB89D8FFFA48058FFA07732FF
+ A57821FFA8761CFFAE791EFFB68022FFBF862BFFC38832FFBB863DFFAA814AFF
+ C3A37FFFEBD8C3FFFFF5F1FFF2F1FAFFE9ECFAFFEBECFAFFE9EAF4FFEBECF0FF
+ EEEDEFFFEEF0F1FFF0F1F5FFEFF2F7FFEFF2F7FFF0EFF8FFF0F0F6FFEDEEF2FF
+ F1F4F8FFE7E9F1FFEBE9EFFFFBF3F3FFE3D0C1FFB89874FFAE8449FFAC782BFF
+ B47B1EFFC08521FFC2881FFFB97F16FFBB7E16FFBF8018FFB87A10FFBA7F12FF
+ B4790BFFB07507FFB3780AFFBA7F11FFBD8214FFBA7F11FFB57A0CFFB4790BFF
+ B77C0EFFB77D0CFFB67C0BFFB97F0EFFBD8312FFBA800FFFB37908FFB87F0CFF
+ BA810EFFBC8310FFBB820FFFB87F0CFFB77E0BFFB97F0EFFBB8110FFB3780AFF
+ BA7F11FFBD8214FFB97E10FFB77C0FFFBA7F12FFBA7F12FFB77C0FFFBA7D0FFF
+ B97C0EFFB97C0EFFBB7E10FFBD8012FFBC7F11FFB97D0CFFB67A09FFB97D0BFF
+ BA7E0CFFBB7F0DFFBC800EFFBC810DFFBB800CFFBA7F0BFFB97E0AFFBA7C0AFF
+ BB7D0BFFBD7F0DFFBF810FFFBF810FFFBD7F0DFFBB7D0BFFBA7C0AFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFBE800EFFBC7E0CFFBB7D0BFFBE800EFF
+ BE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBA7C0AFF
+ BB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBB800CFF
+ BC810DFFBD820EFFBC810DFFB97D0BFFB77B09FFB87C0AFFBA7E0CFFBF8312FF
+ BC800FFFB97C0EFFB97C0EFFBB7E10FFBD8012FFBD8012FFBB7E10FFBB7E10FF
+ BD8012FFBF8214FFBF8214FFBE8113FFBD8012FFBF8214FFC18416FFB97C0EFF
+ B97C0EFFBA7D0FFFBB7E10FFBB7E10FFBB7E10FFBA7D0FFFBA7D0FFFBE8113FF
+ BC7F11FFBA7E0DFFB87C0BFFB77B09FFB87C0AFFBA7F0BFFBC810DFFBA7F0BFF
+ BB800CFFBC800EFFBD810FFFBD8110FFBC800FFFBB7E10FFBA7E0DFFB87D09FF
+ B97F08FFBB7F0DFFBD810FFFBE8113FFBD8012FFBC7E14FFBB7D13FFB87A10FF
+ B97B0FFFB97B0FFFAA6D0FFFA76A0CFFA96C0EFFAF7214FFAF7313FFAB6F0FFF
+ AA6E0EFFAD7111FFB17613FFAE7310FFAB700DFFAC710EFFAF7410FFB17612FF
+ B17612FFB07511FFB2740EFFB1730DFFB2740EFFB57711FFB97B15FFBB7D17FF
+ B97B15FFB67812FFBD7F19FFBB7D17FFB97B15FFB77913FFB57711FFB47610FF
+ B3750FFFB3750FFFB97C14FFBA7D15FFB87A14FFB57711FFB67812FFBA7C16FF
+ B87A16FFB27410FFB67814FFB27410FFB37412FFB87917FFBA7B19FFB87917FF
+ BA7A1BFFBD821FFFAE7B13FFAF7C14FFB27616FFB7791BFFBF8024FFAD7C38FF
+ 8A735DFF72758AFF546CAEFF6084D8FF6889D8FF3D58A2FF405093FF333968FF
+ 292531FF31261EFF3A2A1DFF5A3D16FF9C6A17FFB87E17FFA06B10FF8A6626FF
+ 6E6557FF475669FF53739EFF517DBAFF5287D0FF5D95E7FF669DF8FF598BE3FF
+ 4A71BCFF5768A0FF685772FF744F47FF8F622FFFA77424FFAB7411FFAE7918FF
+ A57827FF846227FF705A37FF766A5EFF807A85FF6C708DFF6676A1FF7595C6FF
+ 6CA0CFFF6A9FD2FF78A0DAFF799CD4FF88ACDCFF9DBCE9FFA9BAEBFFCED2F5FF
+ D7CDD3FF9E866AFF8F6A26FFB78428FFCE902CFFC27E19FFB2710FFFC2842AFF
+ C98F44FFB08144FFA28154FFE2CCB0FFFFF3E7FFEEE9EAFFE8EAF5FFEDF1FFFF
+ ECEFFDFFEAECF6FFEFF0F4FFF0EFF1FFEDEFF0FFEBEEF2FFECEFF4FFEEF0F8FF
+ F2F1FAFFF3F2FBFFF0F3F8FFE8EBF0FFDDE0E5FFF4F1F3FFF0E5DDFFCBB59CFF
+ C09C6EFFBE914EFFB07924FFB37A17FFBC811AFFC0861DFFBC8219FFBF851CFF
+ C1831DFFB77A12FFB97E10FFBD8312FFBB8110FFB47A09FFB37908FFB77D0CFF
+ B87D0FFFB3780AFFB4790BFFB87D0FFFBB8012FFBB8012FFB77C0EFFB57A0CFF
+ B77C0EFFBA800FFFBB820FFFBD8411FFBD8312FFBB8110FFB77D0CFFB67C0BFF
+ B77C0EFFB97E10FFC3881AFFBE8315FFB97E11FFB97E11FFBB8013FFBD8215FF
+ BC8114FFBC8114FFC28517FFC08315FFBC7F11FFB97C0EFFB87B0DFFBA7D0FFF
+ BD8110FFBF8312FFBD810FFFBC800EFFBB7F0DFFBA7E0CFFBA7F0BFFBB800CFF
+ BC810DFFBD820EFFBC7E0CFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFFBF810FFF
+ C18311FFC28412FFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBB7D0BFFBC7E0CFF
+ BE800EFFBF810FFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBF8410FFBC810DFFBA7F0BFFBB800CFFBC800EFFBD810FFF
+ BB7F0DFFB87C0AFFBC800FFFC38716FFC5881AFFBF8214FFBC7F11FFBD8012FF
+ BC7F11FFB97C0EFFBE8113FFBB7E10FFBA7D0FFFBD8012FFC28517FFC48719FF
+ BF8214FFBA7D0FFFB97C0EFFBA7D0FFFBD8012FFBE8113FFBE8113FFBD8012FF
+ BA7D0FFFB97C0EFFBB7E10FFBC7F11FFBD8110FFBE8211FFBF8311FFBE8210FF
+ BC810DFFBB800CFFBC810DFFBB800CFFBA7E0CFFB97D0BFFB97D0CFFBA7E0DFF
+ BB7E10FFBC800FFFBB800CFFBB810AFFBB7F0DFFBB7F0DFFBB7E10FFBB7E10FF
+ BB7D13FFBB7D13FFBD7F15FFC38519FFC38519FFAA6D0FFFA86B0DFFA96C0EFF
+ AE7113FFAF7313FFAB6F0FFFAA6E0EFFAD7111FFB17613FFAF7411FFAD720FFF
+ AD720FFFAF7410FFB17612FFB07511FFAE730FFFB2740EFFB1730DFFB2740EFF
+ B57711FFB97B15FFBA7C16FFB97B15FFB67812FFBC7E18FFBB7D17FFB97B15FF
+ B87A14FFB77913FFB77913FFB77913FFB77913FFB67911FFB77A12FFB67812FF
+ B3750FFFB57711FFB97B15FFB77915FFB27410FFB67814FFB47612FFB57614FF
+ BA7B19FFBB7C1AFFB77816FFB67617FFB67B18FFA97812FFAF7E18FFB97D1DFF
+ BD7F21FFBF8024FFA9752EFF8C6D4CFF756F7AFF677CB9FF5E82D6FF5E81D1FF
+ 405DA8FF435396FF2E3262FF27202DFF403325FF372207FF684813FFA77218FF
+ B4780EFFAC730AFFB0822EFF998252FF6D6655FF4C5461FF5E7498FF658AC2FF
+ 5C8CD4FF598FE4FF5A90E7FF5180D2FF4F6BB2FF55578DFF5B4960FF6A4F3AFF
+ 8E692DFFA97A1EFFB17D13FFAF7A12FFA9761AFFA67930FF8E6632FF815F42FF
+ 6A554DFF635F65FF758494FF8CADC0FFA4CCE8FF9EBCE5FF9DBAE7FF9FC3EBFF
+ A6C8F3FFA6C1F4FFBDCBF5FFB9B9C5FF82725BFF93702EFFA87318FFBE7A17FF
+ C97F19FFC17C1BFFBC7C27FFBE8742FFB8905CFFBEA583FFECDECBFFFFF7F0FF
+ ECEBEFFFE6E9F7FFEAEEFFFFE7EAF8FFE6E8F2FFF0F1F5FFF0F2F3FFEFF3F4FF
+ EEF2F3FFEEF1F6FFEDEFF7FFF1EEF7FFEEEDF6FFEEF0F8FFF1F4F9FFFBFAFCFF
+ F9F0ECFFD1BFAEFFAD916FFFAC834CFFAD7C32FFBC852AFFB87D19FFB87F16FF
+ BA8217FFB67D14FFB87F16FFBE831CFFBC7F17FFBB8012FFBC8211FFBA800FFF
+ B67C0BFFB57B0AFFB77D0CFFB77C0EFFB67B0DFFC3881AFFC08517FFBE8315FF
+ BC8113FFBC8113FFBC8113FFBC8114FFBC8113FFBA800FFFBA800FFFBA800FFF
+ B77D0CFFB47A09FFB4790BFFB67B0DFFB97E10FFB77C0EFFBB8013FFBC8114FF
+ B87D10FFB57A0DFFB77C0FFFBC8016FFC08518FFBA7D0FFFBB7E10FFBC7F11FF
+ BD8012FFBD8012FFBC7F11FFBC800FFFBB7F0EFFBB7F0DFFBB7F0DFFBA7E0CFF
+ BA7E0CFFBA7F0BFFBA7F0BFFBB800CFFBB800CFFBB7D0BFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBB7D0BFFBC7E0CFFBE800EFFBF810FFFBE800EFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBE830FFFBC810DFFBA7F0BFF
+ BB800CFFBC800EFFBD810FFFBB7F0DFFB97D0BFFBA7E0DFFC08413FFC28517FF
+ BE8113FFBC7F11FFBD8012FFBE8113FFBB7E10FFBF8214FFBC7F11FFBB7E10FF
+ BD8012FFC08315FFC18416FFBF8214FFBB7E10FFB97C0EFFBA7D0FFFBD8012FF
+ BE8113FFBE8113FFBD8012FFBA7D0FFFB97C0EFFBC7F11FFBC7F11FFBD8110FF
+ BD8110FFBD810FFFBD810FFFBC810DFFBC810DFFBC810DFFBB800CFFBA7E0CFF
+ B97D0BFFB97D0CFFBA7E0DFFBB7E10FFBC800FFFBB800CFFBB800CFFBB7F0DFF
+ BB7F0DFFBB7F0EFFBB7E10FFBB7D11FFBB7D11FFB97B11FFB7790DFFB77A0CFF
+ AB6E11FFA96C0FFFAA6D0FFFAE7113FFAE7113FFAC6F11FFAB6F0FFFAD7111FF
+ B07414FFAF7313FFAE7310FFAF7411FFB07512FFB07512FFAF7411FFAD720EFF
+ B2740EFFB2740EFFB2740EFFB57711FFB77913FFB97B15FFB87A14FFB77913FF
+ BB7D17FFBA7C16FFB97B15FFB87A14FFB87A14FFB97B15FFBA7C16FFBB7D17FF
+ B3760EFFB57810FFB47610FFB1730DFFB3750FFFB87A14FFB77915FFB1730FFF
+ B57713FFB57713FFB77816FFBB7C1AFFBA7B19FFB57614FFB27213FFAF7411FF
+ A5710CFFAE7A15FFB87B19FFB9791AFFB67519FFA36B1EFF906838FF7C6E68FF
+ 6D7DB2FF5F80D0FF5E81D1FF4966B1FF4A569CFF343464FF281C28FF432E18FF
+ 573805FF896116FFB2791CFFB47610FFB57B12FFC08B2AFFB28738FF8F6F34FF
+ 6E5737FF665E57FF667389FF6788B6FF608FD3FF568BDCFF4F7FD7FF4B71C9FF
+ 455CAAFF444F88FF4D4D65FF6F6359FF92784AFF9E762EFFA8761EFFBF8526FF
+ C4852BFFAF701FFFA66D28FF996A34FF84653EFF857459FF8D8D7BFF969E9DFF
+ ABB9D0FFAABDDEFFA6C1DCFF9DB9D7FF97ACD2FF9FADCAFF999A9EFF77694DFF
+ 967334FFB27E2BFFC27F23FFC47B1FFFBE7922FFB77C2DFFB38341FFAD8D5CFF
+ E3D2B8FFF7F1E6FFFBF7F6FFEAEAF0FFE8EBF9FFE9EEFDFFE6EAF5FFE6E9F1FF
+ EFF2F6FFF0F4F5FFF0F5F4FFF0F4F5FFEFF2F6FFECEFF4FFEDEBF1FFE9E8F1FF
+ F5F7FFFFF2F1F5FFFBF4F1FFE5D5C8FFBCA486FFB69466FFB58949FFAB7625FF
+ C38A2DFFBA7F1BFFB67D14FFB78017FFB47D14FFB47B12FFB97F16FFBC8218FF
+ BD8214FFBA800FFFB97F0EFFBA800FFFB97E10FFB77C0EFFB77C0EFFB97E10FF
+ C4891CFFBD8215FFB67B0EFFB4790CFFB67B0EFFB87D10FFB67A10FFB4790CFF
+ C18618FFBF8416FFBC8113FFB77C0EFFB3780AFFB2770AFFB4790CFFB67B0EFF
+ B67B0EFFBE8218FFC0841AFFB97D13FFB3770DFFB77B11FFBD8018FFBE8218FF
+ B7790DFFB87B0DFFBA7D0FFFBC7F11FFBC7F11FFBC7F11FFBC800FFFBB7F0EFF
+ B97D0BFFB97D0BFFBA7E0CFFBA7E0CFFBA7F0BFFBA7F0BFFB97E0AFFB97E0AFF
+ BB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BC810DFFBB800CFFBA7F0BFFBB800CFFBC800EFFBD810FFFBC800EFFBB7F0DFF
+ B97D0CFFBD8110FFBF8214FFBD8012FFBC7F11FFBE8113FFBE8113FFBD8012FF
+ BF8214FFBE8113FFBD8012FFBC7F11FFBD8012FFBE8113FFBD8012FFBD8012FF
+ B97C0EFFBB7E10FFBC7F11FFBE8113FFBE8113FFBC7F11FFBB7E10FFB97C0EFF
+ BD8012FFBD8012FFBC800FFFBC800FFFBB7F0DFFBC800EFFBC810DFFBD820EFF
+ BB800CFFBB800CFFBA7E0CFFB97D0BFFB97D0CFFBA7E0DFFBB7E10FFBB7F0EFF
+ BB7F0DFFBB7F0DFFBB7F0DFFBB7F0DFFBB7F0EFFBB7E10FFBB7E10FFBB7E10FF
+ C08216FFB5780AFFB5780AFFAC6F12FFAB6E11FFAC6F11FFAD7012FFAD7012FF
+ AC6F11FFAC7010FFAD7111FFAC7010FFAD7111FFAE7310FFB07512FFB17613FF
+ B17613FFB07512FFAE730FFFB27410FFB2740EFFB3750FFFB47610FFB67812FF
+ B77913FFB77913FFB77913FFBA7C16FFB97B15FFB87A14FFB77913FFB77913FF
+ B87A14FFB87A14FFB97B15FFB3760EFFB57810FFB47610FFB2740EFFB47610FF
+ B97B15FFB87A16FFB37511FFB57713FFB57713FFB77816FFB97A18FFB87917FF
+ B57614FFB37314FFB07311FFAC770FFFB17A12FFB47612FFB37210FFB37013FF
+ A86C1AFF9E6F31FF8D7765FF6B77A7FF6081D1FF5B80D0FF415FACFF404E96FF
+ 3C396BFF2E202CFF42270CFF835C17FFA27115FFB47719FFBB7A18FFC07F1CFF
+ BC7E1AFFB07616FFAA751EFFA1732CFF7B5B2AFF675D4BFF6D7985FF6888B1FF
+ 5F89CAFF537DD0FF446EC7FF365DB2FF3A5AA5FF435790FF515977FF625D5CFF
+ 776145FF926A35FFA7732CFFBF8030FFBD7A25FFC27F2AFFB97C2CFFA37129FF
+ 9B7338FF967547FF816C4DFF94877FFF958F90FF92928CFF868581FF7B777CFF
+ 7D7575FF83755FFF866D41FF9C742CFFB78330FFC88633FFC88333FFBE8034FF
+ AE7B35FFB18B51FFC0A87EFFF5EDDCFFF6F5F1FFF2F1F3FFE8EBF0FFEEF0FAFF
+ EEF2FDFFEBEDF7FFECEFF7FFEDF2F5FFEEF2F3FFEEF3F2FFEDF2F1FFECF0F1FF
+ EBECF0FFE9EAEEFFEAE8EEFFE7E6EFFFF3EEF0FFFBEFE5FFC8B299FFA07E53FF
+ AC8345FFB9873BFFBF8A30FFC28828FFB77C18FFB37C14FFBB841BFFBA831AFF
+ B47B12FFB57B11FFBA8114FFBF8416FFB97F0EFFB97F0EFFBD8312FFBC8113FF
+ B77C0EFFB77C0EFFBC8113FFC3881BFFBF8417FFBA7F12FFB97D13FFBA7E14FF
+ BB7F15FFBA7D15FFB97D13FFC08518FFBF8416FFBD8215FFBA7F12FFB87D10FF
+ B77C0FFFB87D10FFB87C12FFBD8117FFC2861CFFC0831BFFB97C14FFB77A12FF
+ BD8018FFBE801AFFB87B13FFBB7D11FFB97C0EFFB87B0DFFB6790BFFB77A0CFF
+ B97C0EFFBC800FFFBD8110FFB77B09FFB87C0AFFBA7E0CFFBB7F0DFFBB800CFF
+ BA7F0BFFB87D09FFB77C08FFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ BD7F0DFFBB7D0BFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBA7F0BFFBA7F0BFFBA7F0BFFBB800CFFBC800EFF
+ BD810FFFBD810FFFBD810FFFBA7E0DFFBC800FFFBC7F11FFBC7F11FFBC7F11FF
+ BD8012FFBD8012FFBD8012FFC08315FFBF8214FFBE8113FFBC7F11FFBB7E10FF
+ BB7E10FFBC7F11FFBE8113FFBA7D0FFFBB7E10FFBC7F11FFBD8012FFBD8012FF
+ BC7F11FFBB7E10FFBA7D0FFFBE8113FFBD8012FFBC800FFFBA7E0DFFBA7E0CFF
+ BB7F0DFFBC810DFFBD820EFFBB800CFFBA7F0BFFBA7E0CFFBA7E0CFFBA7E0DFF
+ BA7E0DFFBA7D0FFFBB7E10FFBB7F0EFFBB7F0DFFBB7F0DFFBB7F0DFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFC5881AFFB97D0CFFB97D0CFFAD7013FFAE7114FF
+ AD7013FFAC6F12FFAC6F11FFAD7012FFAD7012FFAC6F11FFA96D0DFFAB6F0FFF
+ AE7212FFB07414FFB17613FFB27714FFB27714FFB27713FFB27410FFB3750FFF
+ B3750FFFB47610FFB47610FFB57711FFB67812FFB77913FFB97B15FFB87A14FF
+ B77913FFB57711FFB47610FFB47610FFB47610FFB57711FFB57810FFB77A12FF
+ B67812FFB47610FFB67812FFBB7D17FFBA7C18FFB57713FFB57713FFB67814FF
+ B67715FFB67715FFB67715FFB77816FFB87819FFB57816FFB97F18FFB87F16FF
+ B67512FFB77312FFBC771AFFB4741FFFAB762DFF96795AFF757CA7FF607FCEFF
+ 5076C8FF3255A5FF323F8DFF3A376FFF372634FF4D3011FF9B6E1DFFAD760EFF
+ B07011FFBA7518FFC17C1FFFB87312FFB47007FFBF7D14FFBC7E18FFA4721AFF
+ 896829FF736646FF677074FF6D85A9FF6783C3FF466CBAFF4B7CC8FF4B7CC8FF
+ 5274C0FF455D9FFF454F7EFF6C6982FF8F7D7CFF907059FF9C6F44FFA56E31FF
+ B27426FFBE7E26FFBE8026FFBE822EFFB9813AFFAB7539FFA5733FFFA67642FF
+ A5793AFFA07435FF9D6D39FF996A34FFA17333FFB6883BFFBB8931FFB68127FF
+ BF8435FFD19651FFBF8E50FF9D763FFFB29869FFEBDEBEFFF9F8EEFFEFF3F4FF
+ EBEDEEFFEBECF0FFF3F3F9FFF1F4F9FFECEFF7FFEDF1F6FFEBF0F3FFEAEFF0FF
+ EAEFEEFFE8EDECFFEAECECFFEAECEDFFEAEBEFFFEDEBF1FFF3EFF5FFFFF7F7FF
+ F6E2D0FFBE9E7AFFAC8148FFBE8D43FFC38D36FFD09839FFBF8623FFB57D18FF
+ B17914FFB88119FFBC831AFFB57D12FFB57C0FFFBD8516FFBE8315FFB97E10FF
+ B97E10FFBE8315FFBD8215FFB87D10FFB87D10FFBC8114FFB87C12FFBA7E14FF
+ BC8016FFBB7E16FFB97C14FFB87B13FFBA7C16FFBC7F17FFB67A10FFB77C0FFF
+ B77B11FFB97D13FFBB7F15FFBC8016FFBC8016FFBC7F17FFBB7E16FFBD8018FF
+ BC7E18FFB77913FFB87A14FFBC7E18FFBC7E1AFFB87B13FFBC7E12FFBB7E10FF
+ B97C0EFFB77A0CFFB77A0CFFB77A0CFFB97D0CFFBA7E0DFFB77B09FFB87C0AFF
+ BA7E0CFFBB7F0DFFBB800CFFBA7F0BFFB87D09FFB77C08FFBD7F0DFFBD7F0DFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFB97B09FFBA7C0AFF
+ BC7E0CFFBE800EFFBE800EFFBE800EFFBD7F0DFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBA7F0BFFBA7F0BFF
+ BB800CFFBB800CFFBC800EFFBC800EFFBD810FFFBD810FFFBD8110FFBB7F0EFF
+ BB7E10FFBB7E10FFBB7E10FFBA7D0FFFBA7D0FFFBA7D0FFFBF8214FFBF8214FF
+ BD8012FFBB7E10FFBA7D0FFFBA7D0FFFBC7F11FFBD8012FFBB7E10FFBB7E10FF
+ BC7F11FFBC7F11FFBC7F11FFBC7F11FFBB7E10FFBB7E10FFBF8214FFBD8012FF
+ BB7F0EFFBA7E0DFFB97D0BFFBA7E0CFFBB800CFFBB800CFFBA7F0BFFBA7F0BFF
+ BA7E0CFFBB7F0DFFBB7F0EFFBA7E0DFFBA7D0FFFBA7D0FFFBA7D0FFFBA7E0DFF
+ BA7E0DFFBA7E0DFFBA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBC800FFFB67A08FF
+ B67A08FFAE7114FFB07316FFAF7215FFAB6E11FFAB6E10FFAD7012FFAE7113FF
+ AC6F11FFA96D0DFFAC7010FFAE7212FFB07414FFB07512FFB07512FFB27714FF
+ B37814FFB27410FFB3750FFFB47610FFB3750FFFB3750FFFB3750FFFB57711FF
+ B77913FFB87A14FFB77913FFB57711FFB47610FFB3750FFFB3750FFFB3750FFF
+ B3750FFFB77A12FFB87B13FFB77913FFB57711FFB77913FFBB7D17FFBA7C18FF
+ B57713FFB67814FFB87A16FFB87917FFB67715FFB77816FFBB7C1AFFBD7D1EFF
+ BB7C1AFFB67C13FFB67C13FFB67512FFB77614FFBE791CFFB3741AFFA86E1CFF
+ 8F6C44FF757CA3FF5977C8FF4670C3FF385DB1FF344699FF3D3C7AFF3A293EFF
+ 58371DFFA27121FFB77D14FFB57314FFB57013FFBA7419FFB87312FFB57108FF
+ BC7A0AFFC17F0EFFB5790FFFA87519FF916E2CFF786647FF6C6C6CFF6D7898FF
+ 607FB4FF497CBBFF487FC8FF567FCEFF4E6CB9FF5C72B3FF9DABDBFFC8CCE9FF
+ BAB2BDFFA28882FFA1795CFFA36F33FFB97F2DFFC88B2BFFC0811FFFBC7A27FF
+ BD7B2DFFBF7D2FFFBA7A26FFBD7D1FFFC27F22FFC68131FFC17E2FFFBE7E29FF
+ CC9336FFC38C2BFFBB862BFFBD863BFFC28F51FFB78C59FFAF8F64FFD1BE9DFF
+ FFFBE8FFF2F7F5FFE9F2F6FFEAEDF1FFEDEFF0FFF5F2F4FFF1F0F2FFEBEEF2FF
+ EAEEF3FFE9F0F3FFE7EEF1FFE8EEEDFFE8EDECFFEAECECFFEBEDEDFFEDEFF0FF
+ F0EFF3FFFAF4F9FFF8E9E6FFD8BDA3FFAF8959FFBA8741FFC68D37FFBB7F1FFF
+ BB7F1BFFC38824FFB9811CFFAF7712FFB07911FFB77F14FFB57D0EFFB67E0DFF
+ C38A17FFBB8012FFBA7F11FFBA7F11FFBD8214FFBD8215FFBA7F12FFB97E11FF
+ BA7F12FFAE7208FFB4780EFFB87B13FFB97C14FFB67812FFB57711FFB87A14FF
+ BC7E18FFB97C14FFB77B11FFB67A10FFB67A10FFB67A10FFB77A12FFB57810FF
+ B4770FFFB3750FFFB57711FFB77913FFB77913FFB67814FFB67814FFB97B17FF
+ BC7E18FFB87A0EFFBA7D0FFFBC7F11FFBD8012FFBC7F11FFB97C0EFFB67A09FF
+ B47807FFB97D0BFFB97D0BFFBA7E0CFFBA7E0CFFBA7F0BFFBA7F0BFFB97E0AFF
+ B97E0AFFBD7F0DFFBD7F0DFFBE800EFFBF810FFFBF810FFFBF810FFFBE800EFF
+ BE800EFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFF
+ BE800EFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBA7F0BFFBB800CFFBC810DFFBC810DFFBB7F0DFFBB7F0DFFBC800EFF
+ BD810FFFBE8211FFBA7E0DFFB87B0DFFBA7D0FFFBB7E10FFB97C0EFFB97C0EFF
+ BA7D0FFFBE8113FFBD8012FFBB7E10FFBB7E10FFBC7F11FFBC7F11FFBC7F11FF
+ BB7E10FFBB7E10FFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBB7E10FF
+ BB7E10FFBE8113FFBD8012FFBC800FFFBB7F0EFFBA7E0CFFB97D0BFFB97E0AFF
+ B97E0AFFB97E0AFFBA7F0BFFBB7F0DFFBB7F0DFFBB7F0EFFBB7F0EFFBA7D0FFF
+ B97C0EFFBA7D0FFFBA7D0FFFBA7D0FFFBA7E0DFFBA7E0CFFBA7E0CFFBA7E0CFF
+ BA7F0BFFB77B09FFB67A08FFB67A08FFAF7215FFB17417FFB07316FFAB6E11FF
+ AA6D10FFAE7114FFAF7214FFAC6F11FFAD7012FFAF7214FFB07414FFAF7313FF
+ AD720FFFAD720FFFB07512FFB27713FFB27410FFB47610FFB47610FFB3750FFF
+ B1730DFFB2740EFFB57711FFB77913FFB77913FFB67812FFB57711FFB57711FF
+ B47610FFB57711FFB67812FFB77913FFB67911FFB87B13FFB67812FFB3750FFF
+ B57711FFB97B15FFB87A16FFB27410FFB77915FFBB7D19FFBC7D1BFFBA7B19FF
+ BB7C1AFFBF801EFFBF7F20FFBB7C1AFFB3750FFFB77913FFB67715FFB77718FF
+ BB781CFFAF7016FFA86E15FF906E40FF70769BFF5878CBFF4977CFFF3F68C4FF
+ 3C51ACFF4C4E94FF43344FFF583825FFA3722EFFB97C1FFFBC791CFFBA7617FF
+ BA7518FFB47415FFAD7411FFAE7611FFB67C12FFB5770BFFB8760FFFB87A20FF
+ 9F6F2DFF7C5D36FF71685BFF738394FF5784B7FF588DD0FF688FD4FF6887C6FF
+ 7996C9FFACC5EFFFBCD6FBFFABBDDCFFB3B4CEFFAB9CA0FF967254FF9D6E30FF
+ B47F25FFB37919FFB07420FFB37828FFB27924FFAF781DFFB87F1CFFBC7F21FF
+ C38031FFC27F34FFB67726FFBB8227FFAD7915FFB38022FFB68236FFB08144FF
+ B99265FFDBBFA1FFF9E9D9FFFDF8F5FFEAF3F7FFE5F0F8FFECF1F4FFF1F1F1FF
+ F3EFEEFFF1EDECFFECEEEFFFEBF0F3FFE9F2F6FFE8F1F4FFECF2F1FFEDF2F0FF
+ EFF2F0FFF1F2F0FFEFF1F2FFF3F0F2FFF7EEF1FFF3E0D9FFD5B493FFBC8F56FF
+ B98130FFB37616FFB97A12FFC18319FFC18720FFBD8520FFB37B16FFB0760FFF
+ B77E11FFB87E0DFFB77E0AFFBE8511FFB77D0CFFBA7F11FFBB8013FFBA7F12FF
+ BA7F12FFBC8114FFBB7F15FFB87C12FFBB7E16FFBC7F17FFBD7F19FFBE801AFF
+ BF811DFFC0821EFFC28420FFC48622FFC2851DFFBD8018FFB77A12FFB57810FF
+ B57810FFB77913FFB87A14FFB87A14FFBD7F1BFFB77915FFB77915FFBC7E1AFF
+ BC7D1BFFB67715FFB67715FFBB7D17FFB6780CFFB87B0DFFBC7F11FFBE8113FF
+ BD8012FFBB7E10FFB87C0BFFB57908FFBB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFF
+ BA7F0BFFBA7F0BFFBB800CFFBB800CFFB97B09FFBA7C0AFFBC7E0CFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBD7F0DFFC08210FFBF810FFFBE800EFFBC7E0CFF
+ BB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBB800CFFBC810DFFBE830FFFBD820EFF
+ BA7E0CFFB97D0BFFBB7F0DFFBC800EFFBD8110FFB77B0AFFB5780AFFB97C0EFF
+ BB7E10FFBA7D0FFFB97C0EFFBC7F11FFBD8012FFBA7D0FFFB97C0EFFBB7E10FF
+ BE8113FFBF8214FFBD8012FFB97C0EFFBC7F11FFBC7F11FFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC800FFFBC800FFF
+ BB7F0DFFB97D0BFFB87D09FFB77C08FFB97E0AFFBA7F0BFFBB7F0DFFBC800EFF
+ BC800FFFBB7F0EFFBA7D0FFFB97C0EFFB97B0FFFB97B0FFFB97C0EFFB97D0CFF
+ B97D0BFFB97D0BFFB97E0AFFB97F08FFB97E0AFFB97E0AFFB97D0BFFAF7215FF
+ B27518FFB07316FFAA6D10FFAA6D10FFAE7114FFAF7214FFAC6F11FFB17416FF
+ B27517FFB27616FFAF7313FFAC7010FFAB700DFFAD720FFFB17412FFB07410FF
+ B27710FFB47612FFB1760FFFB1730FFFAF740DFFB47612FFB57A13FFB67814FF
+ B47912FFB57713FFB47912FFB77915FFB67B14FFBA7C18FFB97E17FFB67812FF
+ B57A13FFB57711FFB0750EFFB37511FFB57915FFB57713FFAD710DFFB77915FF
+ BB7F1BFFC0811FFFBC7F1DFFBE7F1DFFBF8220FFBF7F20FFB97A18FFB97B17FF
+ BF811DFFC0811FFFBC7F1FFFBD7D1FFFB6781AFFB97D23FFAD8550FF7A788BFF
+ 7189C5FF5C84CFFF3E69BAFF3751A5FF5661A5FF4D4868FF523C31FF9C6F36FF
+ AC731EFFB6781EFFC08022FFBF7F20FFB47818FFB07918FFB67F1CFFAE750CFF
+ C08014FFC57D11FFBC740FFFB2711CFFA06C29FF8A6938FF756C58FF798D9EFF
+ 81A1C5FF90A9D5FF8EA7D3FF98B6DFFFA7CAF2FFA3C9F3FF9DBCE3FF9EADCEFF
+ A9A5B1FF93775FFF926630FFB5812EFFC2892CFFBA812CFFB17823FFAD781DFF
+ B27F1FFFC08B2AFFBC8328FFC08131FFC68638FFBF7F2AFFBE8326FFB27D1CFF
+ A9751BFFA67531FFB08554FFC4A382FFE5CFBDFFF6EAE4FFE9E8EAFFE4ECF3FF
+ E4EEF5FFEEF2F3FFF1F2F0FFF1EEEAFFEEEDE9FFEFF1F1FFEEF5F8FFEBF4F7FF
+ ECF5F8FFEFF7F7FFF2F7F6FFF4F6F6FFF2F4F4FFF0F2F3FFF6F1F0FFF7E5DAFF
+ DEC1A6FFB58D5DFFB1803AFFB77E23FFB87911FFC7871BFFC4861AFFBD831AFF
+ C18720FFBA8019FFB57C13FFBD8215FFBB8110FFB37A06FFB47B07FFB57B0AFF
+ BB8012FFBC8114FFB97E11FFB97E11FFBD8215FFBC8016FFB67A10FFC0841AFF
+ BB7E16FFB77A12FFB87B13FFBD7F19FFC1831DFFC28420FFC1831DFFC1841CFF
+ BB7F15FFB57810FFB57810FFBA7C16FFC3851FFFC98B25FFCD8F29FFD2942EFF
+ C0821CFFB97B15FFC2841EFFC68822FFBD7F1BFFB57713FFB57711FFB97B0FFF
+ B97C0EFFB97C0EFFB97C0EFFBA7D0FFFBB7E10FFBC800FFFBD8110FFBD8110FF
+ BC800EFFBB7F0EFFBA7E0CFFBA7E0CFFBB7F0DFFBC800EFFBD810FFFB67905FF
+ B87B07FFBA7D09FFBC7F0BFFBD800CFFBD7F0DFFBD7F0DFFBC7E0CFFC48614FF
+ C28412FFBF810FFFBC7E0CFFB97B09FFB87A08FFB87909FFB87A08FFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBB7F0DFF
+ BD820EFFBF8311FFBD810FFFBA7E0CFFB87C0AFFBA7E0CFFBC800EFFBB7F0EFF
+ B47807FFB27507FFB87B0DFFBB7E10FFBA7D0FFFBB7E10FFBE8113FFBC7F11FF
+ B97D0CFFB77A0CFFBB7F0EFFC08315FFC18514FFBD8012FFB87C0BFFBC7F11FF
+ BC800FFFBB7E10FFBB7F0EFFBB7E10FFBB7F0EFFBC7F11FFBC800FFFBB7F0EFF
+ BC800FFFBD8110FFBD810FFFBB7F0DFFB97D0BFFB77C08FFB67B07FFB97E0AFF
+ BA7F0BFFBB7F0DFFBC800EFFBC800EFFBB7F0EFFBA7E0DFFB97D0CFFB97C0EFF
+ B97C0EFFB97D0CFFB97D0BFFB97D0BFFB97E0AFFB97F08FFB97F08FFBA8009FF
+ B77D06FFB77C08FFAD6E14FFAF7016FFB17218FFAF7016FFAC6D11FFAA6B0FFF
+ AC6D11FFAE6F13FFAD6F11FFAD6F11FFAD6F11FFAC6F0FFFAC6F0FFFAC6F0FFF
+ AB6E0EFFAB6E0CFFB07311FFAF7410FFB07311FFAF7410FFB27513FFB37814FF
+ B67917FFB77C18FFB47715FFB27713FFB17412FFB07511FFB27513FFB37814FF
+ B77A18FFB87D19FFB07410FFB37814FFB87C18FFB97E1AFFB87B19FFB57A17FF
+ B57816FFB57A17FFB97C1AFFBA7F1CFFBC7F1DFFB97E1BFFB77A18FFB37815FF
+ B57816FFB67919FFB9791BFFBA7A1CFFB87B1BFFB67B17FFB67B14FFB87C18FF
+ B97E21FFA97B3BFF836D5BFF8E90A2FF7C95C1FF5F83BFFF7699D9FF9AB5EEFF
+ 8D9AC0FF736C6FFF805D2BFF9B6A1CFFAD7724FFAE761DFFB57E1DFFBD821EFF
+ B57B14FFBE8119FFBA7910FFC9871EFFC9811BFFBB7412FFB97619FFB37620FF
+ AB7324FFA37839FF88714BFF887F71FFA0A1A5FFAAB9CCFF9DBBDEFF9CC2ECFF
+ A3CAF6FFABCBEEFFAFBDCFFF87817AFF7B5F3CFF9A6E31FFB77F30FFC2832BFF
+ C08028FFBB7D23FFAE7617FFBE8829FFC79238FFC18833FFC58937FFBF822CFF
+ B37314FFC18422FFC18629FFBB8538FFB48450FFBC9676FFDAC1B1FFF8EDE5FF
+ F7F7F1FFE5E9E4FFECEEEEFFF0F0F0FFF3F4F2FFF3F7F2FFF4F8F3FFF1F7F2FF
+ EEF4F3FFE9F3F3FFECF5F8FFE6EFF2FFEBF1F6FFF1F6F9FFF1F4F8FFE8EBEFFF
+ E8EBEFFFFFFCF2FFF4D4ABFFC09356FFA17228FFB07D27FFB7801FFFB77D14FF
+ BD8215FFBE8113FFBB8013FFB97D13FFBB7F15FFC2861CFFC18619FFBB8012FF
+ B97F0EFFBD8312FFBE8315FFC28418FFC38519FFBF8115FFB97B0FFFB7790DFF
+ BB7D11FFBF8115FFC18317FFBD7F15FFB97B11FFB97B11FFBB7D13FFBE8016FF
+ BE8016FFBE8016FFBB7D11FFBB7D11FFBB7D13FFBB7C14FFBC7C16FFBE7E18FF
+ C0801AFFC2831BFFBA7C12FFBD7F13FFBF8115FFBE8014FFBB7D13FFB87911FF
+ B67610FFB6770FFFC38317FFBA7B0DFFB97A0CFFBA7B0DFFB8790BFFBC7D0FFF
+ C08113FFBB7C0EFFBE7F11FFBE7F0FFFBD7E10FFBD7E0EFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBC7E0CFFBB7E0AFFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7D0BFFBD7F0DFFBE7F0FFFC08111FFC18212FFC08111FF
+ BF8012FFBF8010FFC08210FFBD7F0DFFB97B09FFB97B09FFBA7C0AFFBC7E0CFF
+ BB7D0BFFB97B09FFC08210FFBE800EFFBC7E0CFFBA7C0AFFB97B09FFBB7D0BFF
+ BD7F0DFFBE800EFFBB7D0BFFBB7D0BFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BE7F0FFFBE7F0FFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBB7C0CFFBB7D0BFFBB7C0CFFBB7D0BFFBB7C0CFFBB7D0BFF
+ BB7C0CFFBB7D0BFFBC7D0DFFBC7E0CFFBC7D0DFFBC7E0CFFBC7D0DFFBC7E0CFF
+ BC7D0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBF820EFFC0830FFFC38612FFC48713FFC48713FFC38513FF
+ C08210FFBF820EFFBC7F0BFFBC7F0BFFBC7F09FFBB7E08FFBB7E08FFBA7D07FF
+ BA7E06FFBA7E06FFBB7F07FFBB7F07FFBB7E08FFAD6E14FFAE6F15FFB07117FF
+ AF7016FFAC6D11FFAB6C10FFAD6E12FFAE6F13FFAC6E10FFAC6E10FFAD6F11FF
+ AE7012FFAF7212FFB17414FFB27515FFB27515FFB47916FFB37815FFB27714FF
+ B07512FFB07512FFB07512FFB17613FFB17613FFAF7411FFB07512FFB27714FF
+ B47916FFB57A17FFB67B18FFB67B18FFB67B18FFB77C19FFB97E1BFFBB801DFF
+ BA7F1CFFB87D1AFFB67B18FFB77C19FFB87D1AFFAE7310FFB27714FFB67B18FF
+ B77C19FFB57A17FFB27714FFB07512FFB07313FFB8771BFFB7781CFFB47A1AFF
+ B37B16FFB57B12FFB67B14FFB77C1FFFAE7B32FF8F6D42FF9D9185FFA0AEC1FF
+ 9DB9E2FFA8C9FAFFB5D5FFFFB1C8EEFFB5B7BFFF937348FF99671FFFA67225FF
+ B17B26FFB37D1EFFB78018FFB5790FFFB7770BFFB8770BFFBE7A11FFC37E17FF
+ C17D1AFFBE7A19FFBF7D1EFFC48223FFBD8128FFA4722AFF96703AFF907959FF
+ 8B8376FF7E868DFF7F8FA0FF8A9AABFF8F9AA2FF858077FF7B6748FF85602CFF
+ A2712BFFB67B2BFFBD7E24FFB9781CFFAD7010FFBE8424FFB47E20FFAD7621FF
+ AD7524FFC48A38FFCF933AFFC18220FFC08323FFC78C36FFB47F3CFFBA9066FF
+ DDBDAAFFF1E1DBFFF5F0EFFFEFF5F0FFF0F6F1FFF1EFEEFFF1EDECFFEBECEAFF
+ E7EBE6FFE5EBE6FFE5ECE7FFE6EFECFFE7EFEEFFE8F2F2FFEEF5F8FFEBEFF4FF
+ ECEFF4FFF1F2F6FFFFFEFFFFFFFFFFFFF2E3D0FFDCB47AFFC08B3BFFB17C25FF
+ BD892BFFBB8520FFB57D12FFB57C0FFFB4790BFFBA7D0FFFB97B0FFFBB7D13FF
+ BE8016FFBB8013FFB87D10FFB37B0CFFB47C0DFFBC7E12FFBF8115FFC18317FF
+ BE8014FFB97B0FFFB87A0EFFBC7E12FFC08216FFC18317FFBD7F13FFBA7C10FF
+ B97B0FFFBB7D11FFBD7F13FFBE8014FFBD8012FFB97D0CFFB87C0BFFB87A0EFF
+ B97B11FFBB7B15FFBD7D17FFBF8018FFC08218FFB7790DFFBA7E0DFFBC800FFF
+ BB7F0EFFB97C0EFFB87A0EFFB97A12FFBA7B13FFC48418FFBE7F11FFBE7F11FF
+ BF8012FFBC7D0FFFC08113FFC58618FFC18214FFBC7D0FFFBB7C0EFFBB7C0EFF
+ BA7B0DFFB97A0CFFB8790BFFB8790BFFB77808FFBB7E08FFBB7F07FFBB7F07FF
+ BB7F07FFBB7E08FFBB7E08FFBB7E0AFFBB7E0AFFBB7D0BFFBC7E0CFFBD7E0EFF
+ BF8010FFBF8012FFBF8012FFBE7F11FFBE7F0FFFBF8010FFBD7F0DFFBB7D0BFF
+ BA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBA7C0AFFB97B09FF
+ B97B09FFBA7C0AFFBD7F0DFFC08210FFC28412FFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBE800EFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBE800EFFBE800EFFBF820EFFBF820EFFBE810DFF
+ BD800CFFBC7F0BFFBA7D09FFBA7D09FFB97C08FFBB7E0AFFBC7F0BFFBD800CFF
+ BE810DFFBE810DFFBD800CFFBC7F0BFFBB7E0AFFBC7F09FFBC7F09FFBC7F09FF
+ BB7E08FFBB7E08FFBA7D07FFBA7D07FFBA7D07FFBB7E08FFBB7E08FFBB7E08FF
+ AB6D13FFAC6E14FFAD6F15FFAD6F15FFAC6E14FFAC6E14FFAD7013FFAE7114FF
+ AD7012FFAE7113FFAF7214FFB07315FFB17515FFB27616FFB37717FFB47818FF
+ B57A17FFB47916FFB37815FFB17613FFB07512FFB07512FFB07512FFB07512FF
+ B07512FFB27714FFB67B18FFB87D1AFFB97E1BFFB67B18FFB37815FFB17613FF
+ BA7F1CFFBB801DFFBA7F1CFFB87D1AFFB67B18FFB57A17FFB77C19FFB87D1AFF
+ B87D1AFFBB801DFFBE8320FFBE8320FFBB801DFFB87D1AFFB57A17FFB47818FF
+ B7791BFFB77A1DFFB37B1CFFAF7B17FFB17A12FFB37912FFB77B1BFFAF7A29FF
+ A27D45FF9E8B70FFABAEB2FFC0D1EBFFC2DCFFFFB9D6FDFFB4CAEDFFC4C6CEFF
+ B28E68FF9E6827FFA56E25FFB67E2CFFB57C1FFFBA8019FFB97E11FFB97A0AFF
+ BA7A0AFFB37205FFBE7D11FFC8851EFFC07D1AFFC1801EFFC68725FFBD8022FF
+ BD832AFFAF7A2AFFA27532FF99723BFF917043FF90734EFF947653FF94734CFF
+ 9B7343FFA2743AFFAF7B34FFB77F2DFFBB7F25FFBF8220FFC1831DFFB87D16FF
+ B9801DFFBA8426FFC38C37FFB98130FFB27727FFB37723FFB87A20FFC78D34FF
+ B68033FFAB7E41FFC8A583FFF6DFCFFFFEF2F0FFEFECEEFFE9EEEDFFECF3F0FF
+ F7F7F7FFF6F4F4FFF0F1EFFFEAEEE9FFE8EEE9FFE9EFEAFFEBF2EDFFEDF4F1FF
+ E6EEEEFFEEF5F8FFEAEEF3FFE8EBEFFFECEAEAFFFCF6F1FFF2E9DCFFBAA586FF
+ B78B4CFFB17B28FFB47F25FFC18B2CFFBD861EFFB57D12FFB57C0FFFB4790BFF
+ B87A0EFFBB7D11FFBB7D13FFBA7C12FFB87C12FFB97E11FFB47C0DFFB07809FF
+ B97B0FFFBC7E12FFBE8014FFBC7E12FFB97B0FFFB97B0FFFBD7F13FFC08216FF
+ BF8115FFBD7F13FFBA7C10FFB97B0FFFBB7D11FFBD7F13FFBD7F13FFBD8012FF
+ B77B0AFFB77B0AFFB7790DFFB87A10FFBA7B13FFBB7C14FFBD7E16FFBE8014FF
+ B6790BFFB77B0AFFB97D0CFFB87C0BFFB87B0DFFB87A0EFFBB7C14FFBE8016FF
+ BD7D11FFB97A0CFFBC7D0FFFBD7E10FFB8790BFFBB7C0EFFC18214FFC08113FF
+ BD7E10FFBC7D0FFFBB7C0EFFBA7B0DFFB97A0CFFB8790BFFB7780AFFB77808FF
+ BB7E08FFBB7F07FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E0AFFBB7E0AFF
+ BB7D0BFFBB7D0BFFBC7D0DFFBD7E0EFFBE7F0FFFBD7E0EFFBD7E10FFBD7E0EFF
+ BE7F0FFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFC08210FFC28412FF
+ BD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BF810FFFBF810FFFBF810FFFBF810FFFBF810FFFBF810FFFBF810FFFBF810FFF
+ B97C08FFBA7D09FFBB7E0AFFBC7F0BFFBD800CFFBE810DFFBF820EFFBF820EFF
+ BA7D09FFBA7D09FFBA7D09FFBB7E0AFFBB7E0AFFBA7D09FFBA7D09FFBA7D09FF
+ BC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFFBA7D09FFBA7D09FFBA7D09FF
+ BA7D09FFBA7D09FFBA7D09FFAB6D13FFAB6D13FFAC6E14FFAC6E14FFAD6F15FF
+ AD6F15FFAE7114FFAE7114FFB27517FFB27517FFB17416FFB17416FFB17515FF
+ B07414FFB07414FFB07414FFB17515FFB17613FFB17613FFB17613FFB17613FF
+ B27714FFB27714FFB27714FFB57A17FFB77C19FFB97E1BFFBA7F1CFFB97E1BFF
+ B57A17FFB07512FFAD720FFFB57A17FFB57A17FFB57A17FFB57A17FFB47916FF
+ B47916FFB47916FFB57A17FFB77C19FFB87D1AFFB87D1AFFB77C19FFB77C19FF
+ B77C19FFB87D1AFFB97E1BFFB97D1DFFB77D1EFFB27C1DFFB07B1AFFAF7914FF
+ B27B13FFB77B17FFB37C21FF9E722BFF876938FF918370FFB5B5B5FFC9D2DFFF
+ C9D7E9FFC5CFE0FFCCC6C1FFB68E64FFA26B28FFA36A1FFFAD7523FFB07819FF
+ B77D16FFB97E11FFBD8110FFBE7F0FFFB67508FFBC7A11FFC5831CFFC07F1CFF
+ BB7C1AFFBB7E1EFFB97C1EFFBA7D20FFBA7E25FFBC802CFFBC8131FFB77D31FF
+ B47A32FFB27731FFB0752FFFB0752DFFB97F33FFBF8533FFBB8128FFB47A1BFF
+ B77C19FFBD831CFFBF851EFFC28B28FFBC8628FFC58E39FFC08837FFB87D2DFF
+ B57A2AFFAF7523FFB37E2EFFA97C39FFC29D6BFFECD4B8FFFFF5E9FFFBF5F6FF
+ F4F5F9FFF2F7F8FFEAEFF0FFF6F8F9FFF8F7F9FFF5F7F7FFF5F8F6FFF2F8F3FF
+ F2F9F2FFF2F9F2FFF2F7F5FFE4E9EAFFE4EBEEFFF0F4F9FFF5F7F8FFFCF6F1FF
+ FAEDDFFFD3BFA6FFA7875CFFA77630FFA9731CFFB17A1FFFBA8322FFB98017FF
+ B87F12FFBE8315FFBC8113FFB97B0FFFBD7F13FFBE8016FFB87C12FFBA7E14FF
+ BD8319FFBA8114FFB37A0DFFB67B0EFFBA7C10FFBC7E12FFBB7D11FFB97B0FFF
+ B97B0FFFBB7D11FFBE8014FFBE8014FFBC7E12FFBB7D11FFBA7C10FFBB7D11FF
+ BC7E12FFBC7E12FFBD8012FFBB7F0EFFBA7E0DFFBA7D0FFFBA7C10FFBA7C12FF
+ BB7D13FFBB7D13FFBB7D11FFB97D0CFFB97D0CFFB97D0BFFB87C0AFFB77B0AFF
+ B97C0EFFBD7F15FFC18319FFB8780CFFB67709FFBB7C0EFFBC7D0FFFB67709FF
+ B8790BFFBF8012FFBF8012FFBF8012FFBE7F11FFBE7F11FFBE7F11FFBE7F11FF
+ BD7E10FFBD7E10FFBD7E0EFFBB7E08FFBB7F07FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E0AFFBB7E0AFFBB7D0BFFBB7D0BFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0FFFBB7C0CFFBC7E0CFFBE800EFFC08210FFBE800EFFBC7E0CFF
+ BB7D0BFFBD7F0DFFBF810FFFBF810FFFBE800EFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBC7D0DFF
+ BB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFB87B07FFB97C08FFBA7D09FFBB7E0AFFBD800CFF
+ BF820EFFC0830FFFC18410FFBD800CFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFF
+ BC7F0BFFBC7F0BFFBD7F0DFFBC7E0CFFBC7E0CFFBC7D0DFFBB7D0BFFBB7C0CFF
+ BA7C0AFFBA7B0BFFBA7C0AFFBA7B0BFFBA7C0AFFBA7B0BFFAB6C14FFAB6C14FF
+ AB6D13FFAC6E14FFAD6F15FFAE7016FFAE7114FFAE7114FFB07316FFB07316FF
+ B07315FFB07315FFAF7214FFAF7214FFAF7214FFAF7313FFB17515FFB17515FF
+ B17515FFB27616FFB27616FFB27616FFB27616FFB27616FFB57919FFB67A1AFF
+ B67A1AFFB77B1BFFB67A1AFFB57919FFB37717FFB27616FFB07512FFB17613FF
+ B47916FFB67B18FFB87D1AFFB87D1AFFB67B18FFB57A17FFB27714FFB37815FF
+ B67B18FFBA7F1CFFBD821FFFBF8421FFBF8421FFBF8421FFBC801CFFBB801DFF
+ B67F1EFFB37C19FFB37B16FFB57C13FFBA7E14FFBB8019FFB67F24FF9D6E24FF
+ 97723EFFA58B67FFAE9E87FFB3A696FFA99F8EFFA38E6FFFA5783FFFA76E23FF
+ A8701EFFA87017FFAF7515FFB47A11FFAE7208FFB87A0EFFBD7D11FFBD7B14FF
+ B97613FFBA7917FFBE7E1FFFB6781AFFB17417FFB87C22FFAF731FFFB27624FF
+ B97925FFBD7D25FFC37F26FFC17D24FFBB7821FFB87722FFAC6E1AFFB17823FF
+ B57F2AFFB7822BFFB58226FFB27E20FFB68120FFBC8726FFC18C2BFFB68022FF
+ BD842EFFC18735FFC48939FFC3893DFFB47F36FFAF7F3DFFA9854FFFD6BC97FF
+ FFF0DFFFFDF7F2FFE9E8ECFFEBEEF6FFF3F7FCFFE9EEF1FFF0F1F5FFF0F1F5FF
+ F0F2F3FFEEF3F2FFF0F4EFFFF1F5EFFFF2F6F0FFF2F6F1FFEBF0F1FFE4EBEEFF
+ F6FAFFFFF2F2F2FFFEF5E8FFF1DDC4FFAC8F68FF9C743AFFAE7A2DFFB1781DFF
+ B3791AFFB77C18FFB67D14FFBA8114FFBF8416FFBC8113FFB67B0EFFB97E11FF
+ B97D13FFB77A12FFB87E15FFBE851CFFBC8419FFB67C12FFB87D10FFBB7E10FF
+ BC7F11FFBB7E10FFBA7D0FFFB87B0DFFB97C0EFFBA7D0FFFBC7F11FFBC7F11FF
+ BB7E10FFBB7E10FFBA7D0FFFBA7D0FFFBC7F11FFBC7F11FFC08413FFBF8312FF
+ BF8214FFBD7F13FFBC7E12FFBB7D11FFB97B0FFFB97C0EFFBE8211FFBE8210FF
+ BD810FFFBA7E0CFFB87C0BFFBA7D0FFFBE8014FFC18317FFBC7D0FFFBA7B0DFF
+ BF8012FFC18214FFBA7B0DFFBD7E10FFC38416FFC28315FFBD7E10FFBD7E10FF
+ BD7E10FFBE7F11FFBF8012FFBF8012FFC08113FFC08111FFBB7E0AFFBB7E08FF
+ BB7E08FFBB7E08FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBA7B0BFFBB7C0CFFBB7C0CFFBB7C0CFFBB7D0BFFBD7F0DFF
+ C08210FFBF810FFFBD7F0DFFBB7D0BFFBD7F0DFFBF810FFFBE800EFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBE800EFFBE800EFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFC18311FFC08210FF
+ BF810FFFBD7F0DFFBB7D0BFFBA7C0AFFB97B09FFB87A08FFBC7E0CFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7D0DFFBC7D0DFF
+ BC7D0FFFBB7C0CFFBB7C0EFFBA7B0BFFBA7B0DFFBA7B0BFFBA7B0DFFBA7B0BFF
+ BA7B0DFFAD6E16FFAC6D15FFAB6D13FFAC6E14FFAD6F15FFAE7016FFAD6F15FF
+ AC6F12FFAB6E11FFAC6F12FFAD7012FFAE7113FFAF7214FFB07315FFB17416FF
+ B27517FFB37717FFB37717FFB37717FFB37717FFB27616FFB07414FFAF7313FF
+ AE7212FFB07414FFB17515FFB27616FFB37717FFB57919FFB77B1BFFB97D1DFF
+ BA7E1EFFB27714FFB37815FFB67B18FFBA7F1CFFBD821FFFBD821FFFBB801DFF
+ B87D1AFFB97E1BFFBB801DFFBF8421FFC38825FFC58A27FFC28724FFBC811EFF
+ B87D19FFBB8019FFBC811AFFBA7F1CFFB57C19FFB27A15FFB57B12FFBC7E12FF
+ BF8115FFBC7E18FFB57C1FFFAD792DFFA17536FF9A723EFF967446FF937447FF
+ 936F39FFA27127FFB17A25FFBC852AFFB67E1FFFBA7F1BFFBA7F18FFAF720AFF
+ B6770FFFB67610FFBD7C1AFFB87617FFB57517FFBC7D21FFB6791CFFAF7417FF
+ B87E25FFBD8331FFBA7D2DFFB47420FFB47219FFC07B1EFFC27E1FFFBD7B1CFF
+ BB7B1DFFB6791CFFB67C23FFB58026FFBB872DFFBE8B2FFFB88426FFB78122FF
+ BE8829FFB68021FFBA8124FFC78D34FFC38A35FFBC8132FFB77D35FFB48142FF
+ C39964FFBDA178FFE2D1B6FFFBF5EAFFF0F0F0FFDFE3E8FFDEE4EBFFE8ECF1FF
+ ECEFF4FFEFF2F7FFEDF0F5FFEAEDF1FFE8EDECFFEBEFEAFFEEF2ECFFF4F7EEFF
+ F5F9F4FFEFF4F5FFEEF4F9FFFAFEFFFFF1EFEEFFFFF7E7FFFFE6C4FFC39E6AFF
+ BE9049FFBA832EFFBC7F21FFB87D1AFFBA7F18FFBA8016FFBA8114FFB97E10FF
+ B4790BFFB67B0EFFB57A0DFFB4770FFFB2780FFFB67D14FFBA8118FFB87F16FF
+ B47A11FFB87D10FFBB7E10FFBC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFF
+ B97C0EFFBA7D0FFFBB7E10FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFFBB7E10FF
+ BC800FFFC18513FFC18513FFC08413FFBF8214FFBD8012FFBB7E10FFB97C0EFF
+ B87C0BFFBF8311FFBF8311FFBE8210FFBB7F0DFFB87C0BFFB97D0CFFBC7F11FF
+ BF8214FFBB7C0EFFB8790BFFBC7D0FFFBE7F11FFB97A0CFFBC7D0FFFC08113FF
+ BD7E10FFBA7B0DFFBA7B0DFFBA7B0DFFBB7C0EFFBC7D0FFFBC7D0FFFBD7E10FF
+ BD7E0EFFBB7E0AFFBB7E08FFBB7E08FFBB7E08FFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7B0BFFBA7B0BFFBB7C0CFF
+ BB7C0CFFBA7C0AFFBC7E0CFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BE800EFFB97B09FFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBF810FFF
+ C08210FFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBF810FFFBF810FFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFF
+ B97B09FFB87A08FFB97B09FFB97B09FFB97B09FFB97B09FFB97B09FFB97B09FF
+ B87A08FFBC7D0FFFBC7D0FFFBC7D0FFFBB7C0EFFBB7C0EFFBA7B0DFFBA7B0DFF
+ BA7B0DFFB97A0CFFB97A0CFFB97A0CFFAD7118FFAB6F16FFA96D14FFAA6E15FF
+ AB6F16FFAC7016FFAA6E14FFA86C12FFAA6F12FFAA6F12FFAB7013FFAD7215FF
+ AE7415FFAF7516FFB07617FFB17718FFB27616FFB27616FFB37717FFB37717FF
+ B37717FFB17515FFB07414FFAF7313FFAF7313FFB07414FFB17515FFB37717FF
+ B47818FFB67A1AFFB77B1BFFB87C1CFFB57A17FFB57A17FFB57A17FFB87D1AFF
+ BB801DFFBC811EFFBB801DFFB87D1AFFBA7F1CFFB87D1AFFB77C19FFB77C19FF
+ B77C19FFB57A17FFB07512FFAE720EFFBA7E14FFBC7E14FFBA7C18FFB57816FF
+ B37614FFB37811FFBA7C10FFBD8012FFBD7D11FFC3831DFFC3842AFFBB7E2EFF
+ B1772CFFA7712AFFA7752DFFB18032FFAE791FFFB57E1DFFC78E2BFFC28723FF
+ B97F18FFBD821BFFBA7C18FFBA7B19FFB37315FFBB7A1EFFBE7C23FFBA7B21FF
+ B97B21FFB67B1EFFB67C1DFFB67D20FFBE832DFFBD812FFFB57723FFB2751FFF
+ BC8026FFBF8427FFBD8225FFC2872AFFB67D20FFB87F22FFB47B1EFFB67E1FFF
+ BB8324FFB77D1EFFB27818FFB87E1EFFC08626FFBD8324FFBF8329FFBB7F2BFF
+ C08536FFB9823DFFAE7F47FFBB986CFFE0CAAEFFF3EBDAFFFAF9F5FFECF3F6FF
+ EAF3F7FFE8F0F7FFEDF0F5FFF6F9FEFFF2F4FCFFF0F3F8FFEEF1F5FFECF0F1FF
+ EFF3EEFFF2F4EEFFF5F7F1FFF5F9F4FFEEF5F8FFF4FCFFFFF1F7FEFFF2F0EFFF
+ F0E2CFFFD6BA91FFBE9354FFBA8535FFC0842AFFBE811FFFBA7F18FFBD8018FF
+ BE8218FFBB8013FFB87D0FFFB87D0FFFBB8215FFB57C0FFFB2780FFFB57B12FF
+ B87E17FFB87E17FFB57B14FFB47A11FFB77C0FFFBA7E0DFFBB7F0EFFBC800FFF
+ BD8110FFBC800FFFBB7F0EFFBB7F0EFFB97D0CFFBB7F0EFFBC800FFFBC800FFF
+ BA7E0DFFB97D0CFFBA7E0DFFBC800FFFBD810FFFBE8210FFBE8210FFBE8211FF
+ BD8110FFBB7F0EFFB97D0CFFB87C0BFFBC800EFFBC800EFFBC800EFFBA7E0CFF
+ B77B09FFB77B0AFFBA7E0DFFBC800FFFBA7B0BFFB57606FFB87909FFBA7B0BFF
+ B77808FFB97A0AFFBC7D0DFFB67707FFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFF
+ BB7C0CFFBB7C0CFFBA7B0BFFBA7B0BFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFF
+ BE800EFFBE800EFFBD7F0DFFBB7D0BFFB97B09FFB97B09FFBA7C0AFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFB97B09FFBA7C0AFFBA7C0AFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFB97B09FFBA7C0AFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBA7C0AFFB97B09FFBC7D0FFFBC7D0FFFBC7D0FFFBB7C0EFF
+ BB7C0EFFBA7B0DFFBA7B0DFFBA7B0DFFB97A0CFFB97A0CFFB97A0CFFAE7219FF
+ AB6F16FFA96D14FFAA6E15FFAB6F16FFAC7017FFAA6E14FFA76B11FFAF7319FF
+ AF7417FFAF7417FFAF7417FFAE7415FFAE7415FFAE7415FFAE7415FFAC6F11FF
+ AE7212FFB07414FFB27616FFB47818FFB47818FFB47818FFB47818FFB37717FF
+ B37717FFB47818FFB47818FFB47818FFB37717FFB17515FFB07414FFB67B18FF
+ B47916FFB27714FFB37815FFB57A17FFB77C19FFB67B18FFB57A17FFBB801DFF
+ B57A17FFAF7411FFAE7310FFB27714FFB87D1AFFBD821FFFC08420FFB97B11FF
+ B97B11FFB97815FFB47513FFB27311FFB37511FFB67911FFB97D13FFB7790FFF
+ BB7B15FFBD7A1DFFC27F28FFC2802DFFB17221FFAA6E1CFFB77E28FFB67C1CFF
+ AC710DFFBC821BFFB97F18FFAA6E0AFFB57915FFC08021FFBE7E20FFB7751CFF
+ B97921FFC5852DFFC3842CFFB4791CFFB77D1EFFBA8320FFAF7815FFB27819FF
+ BD8127FFBD8127FFB97F26FFB98128FFB27A21FFAE741BFFB47B20FFB17619FF
+ BC7F21FFBB7F1FFFBC8020FFC28626FFBD8121FFB27818FFB47A1AFFB77B1BFF
+ BB7E20FFBE8026FFBC7E2AFFC1873CFFB78243FFA87C4DFFB99A79FFE9DAC7FF
+ F7F5EBFFEFF4F3FFE2EBEFFFEDF6FAFFF1F7FCFFECEFF4FFF2F2F8FFEDEFF7FF
+ EEF1F6FFEFF3F8FFF1F5F6FFF3F6F4FFF2F3EFFFEFF0ECFFE9EEECFFE9EFF4FF
+ F3FBFFFFECF0F5FFFFFEF9FFE6D7BDFFAC8E5FFFB68743FFB47E27FFBE8222FF
+ BC7E18FFB97C14FFBA7E14FFBC8114FFBA7F12FFBD8214FFC4891BFFC48B1EFF
+ BA8114FFB67C12FFBB8118FFBD831CFFB97F18FFB57A16FFB77C15FFB57A0DFF
+ B87C0BFFBA7E0DFFBC800FFFBE8211FFBF8312FFBE8211FFBD8110FFB87C0BFF
+ BB7F0EFFBD8110FFBC800FFFBA7E0DFFB87C0BFFBA7E0DFFBC800FFFB87C0BFF
+ B97D0BFFBB7F0DFFBC800EFFBC800FFFBB7F0EFFB97D0CFFB87C0BFFB77B09FF
+ B87C0AFFB97D0BFFB87C0AFFB67A08FFB67A08FFB87C0BFFBA7E0DFFC08111FF
+ BA7B0BFFBB7C0CFFBE7F0FFFBC7D0DFFBE7F0FFFBF8010FFB87909FFC48515FF
+ C38414FFC28313FFC08111FFBE7F0FFFBD7E0EFFBB7C0CFFBB7D0BFFBB7D0BFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBF810FFF
+ BE800EFFBC7E0CFFBB7D0BFFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFFBA7C0AFF
+ B97B09FFB97B09FFBB7D0BFFBE800EFFBF810FFFBC7E0CFFB97B09FFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BE800EFFC08210FFC28412FFC28412FFC08210FFBE800EFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0FFFBB7C0CFFBB7C0EFFBA7B0BFFBA7B0DFFBA7B0BFFB97A0CFF
+ B97A0AFFB97A0CFFAC6F19FFA56812FFA46711FFA86B15FFAA6E15FFA66A11FF
+ A3670EFFA5690FFFAE7218FFAD7117FFAD7215FFB07518FFB3781BFFB3781BFF
+ B07518FFAD7314FFA6690BFFB27517FFB47719FFB27517FFB5781AFFB17416FF
+ B07315FFBA7D1FFFB17416FFB07315FFB17416FFB47719FFB87B1DFFB97C1EFF
+ B6791BFFB37717FFB67B18FFB77C19FFB87D1AFFB87D1AFFB77C19FFB57A17FF
+ B37815FFB27714FFBA7F1CFFBC811EFFB87D1AFFB47916FFB67B18FFBB801DFF
+ BA7F1CFFB47814FFB77913FFBA7A14FFBB7A18FFBA7819FFB77516FFB47415FF
+ B57915FFB77C18FFB57C19FFB47A1BFFB67621FFB77827FFB87A2CFFB97B2FFF
+ B67B2CFFB47A28FFB97E21FFB87B1BFFBF8220FFC38624FFBC7D1BFFB57516FF
+ B77719FFB7761AFFB4751BFFBC7C24FFBF7F27FFB6791CFFAF7515FFB47C17FF
+ BA861CFFC08A1FFFB37B10FFBA8017FFB77F1AFFAE7716FFAA7318FFB0761DFF
+ B57920FFB5761EFFC28125FFBB781BFFBA7819FFC48321FFC78A28FFC18727FF
+ B57F20FFB17B1CFFB97D1DFFBA7C1EFFBF8127FFB77B29FFB37A35FFB6854DFF
+ BB946DFFCDB49AFFFFF7EAFFF2F1EDFFE6EEEEFFE5EEF2FFE8F1F5FFF0F5F8FF
+ F4F6F7FFF6F5F9FFEDEDF3FFE7EAEFFFE5E8EDFFE8ECEDFFF0F3F1FFF3F6F4FF
+ F1F4F2FFEBEFF0FFE7EDF2FFE4EAF1FFEBEEF2FFF0EBE2FFE3D1B4FFD3B280FF
+ C2924AFFAD751CFFB77B17FFBE8016FFC18319FFC2841AFFC08518FFBF8417FF
+ BE8316FFBE8316FFCB9225FFBE8518FFB67C12FFB97F16FFBC811AFFB97E17FF
+ B77B17FFB87D16FFB77C0FFFBA7D0FFFBA7D0FFFB87B0DFFB6790BFFB77A0CFF
+ BC7F11FFC08315FFBD8012FFBD8012FFBC7F11FFB97C0EFFB6790BFFB5780AFF
+ B77A0CFFBA7E0DFFBA7E0DFFBB7F0EFFBC800EFFBC800EFFBC800EFFBB7F0DFF
+ B97D0BFFB87C0AFFBA7E0DFFBB7F0EFFBB7F0EFFB87C0BFFB67A08FFB67A08FF
+ B97D0BFFBC800EFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBA7C0AFFC08210FFBE800EFFBB7D0BFFB97B09FFB97B09FFBD7F0DFF
+ C18311FFC48614FFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7D09FFBB7E0AFFBD800CFFBC7F0BFFBA7D09FFB97C08FF
+ BB7E0AFFBC7F0BFFB77907FFB97B09FFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFF
+ B97B09FFB97B09FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBC7F0BFFBB7E0AFFBB7E0AFFBA7D09FFBA7D09FFBB7E0AFF
+ BB7E0AFFBC7F0BFFBA7C0AFFBB7D0BFFB97B09FFB77907FFBB7D0BFFC08210FF
+ BE800EFFB87A08FFBC7E0CFFBB7D0BFFBB7D0BFFBD7F0DFFBF810FFFBF810FFF
+ BC7E0CFFB97B09FFBA7B0BFFBC7D0DFFBF8010FFC08111FFC08111FFBD7E0EFF
+ B97A0AFFB77808FFC08111FFC08111FFC08111FFC08111FFBF8010FFBF8010FF
+ BE7F0FFFBE7F0FFFB97A0AFFBA7C0AFFBB7C0CFFBC7E0CFFBC7D0DFFBB7D0BFF
+ BA7B0BFFB97B09FFB77808FFB77907FFB77808FFAB6E18FFA66913FFA56812FF
+ A96C16FFAC7017FFAA6E15FFA86C13FFAA6E15FFA66A10FFA5690FFFA4680EFF
+ A56A0DFFA86D10FFAB7013FFAD7215FFAE7316FFAB6E10FFB37618FFB27517FF
+ AF7214FFB37618FFB27517FFB27517FFBB7E20FFB37618FFB37618FFB27517FF
+ B37618FFB47719FFB5781AFFB47719FFB37717FFB87C1CFFB87D1AFFB87D1AFF
+ B87D1AFFB87D1AFFB97E1BFFBA7F1CFFBA7F1CFFBD821FFFBA7F1CFFB77C19FF
+ B67B18FFB57A17FFB47916FFB37815FFB37815FFB27513FFB37614FFB87617FF
+ BA7617FFB97516FFB97718FFBB7C1AFFBC7F1DFFB57B1CFFB37A1FFFB57925FF
+ B87B2BFFBD7F31FFBD8135FFBD8135FFBD8030FFBC7D25FFBB7C20FFC18325FF
+ C38626FFB9791AFFB37314FFB9791AFFBB7D1FFFB6771BFFB97A20FFB87A20FF
+ B37619FFB17717FFB67E19FFB7821AFFB88217FFBC8516FFBE8619FFBB841BFF
+ B37C19FFAE781AFFB2781FFFB67A21FFB97A22FFC8862DFFC27F23FFBD7A1DFF
+ C08022FFC18426FFBE8425FFB68022FFB57F21FFC5882AFFC18226FFB97924FF
+ AB7125FFB07B3CFFB58A59FFC0A180FFE3D2BFFFF9F3ECFFEDEFEFFFE4EBEEFF
+ E2EBEEFFE8EDF0FFECF0F1FFF1F1F1FFF0EFF1FFEFEFF5FFEAEDF2FFE9ECF0FF
+ EDEFF0FFF2F4F4FFF2F7F6FFF0F5F4FFEDF2F3FFE7EBF0FFF1F4F8FFF6F2F1FF
+ E3D9C8FFC9B18DFFB39058FFB18034FFB87F22FFB97E17FFBB7D11FFB97B0FFF
+ B87A10FFB77B11FFB77C0FFFB77C0FFFB77C0FFFBA8114FFB77E11FFB67D10FF
+ B87E14FFBA8017FFBC7E18FFBC7E18FFBE801AFFBC7E12FFBC7F11FFBA7D0FFF
+ B97C0EFFB97C0EFFBC7F11FFC18416FFC48719FFB87B0DFFBA7D0FFFBC7F11FF
+ BB7E10FFB97C0EFFB87B0DFFB97C0EFFBB7E10FFBA7D0FFFBB7F0EFFBC800FFF
+ BD810FFFBC800EFFB97D0BFFB67A08FFB47806FFB67A09FFB87C0BFFBB7F0EFF
+ BB7F0EFFB97D0CFFB87C0AFFB97D0BFFBB7F0DFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBF810FFFBD7F0DFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBD7F0DFFC08210FFC28412FFC08210FFBF810FFFBE800EFF
+ BD7F0DFFBB7D0BFFBA7C0AFFB87A08FFB87A08FFBA7D09FFBB7E0AFFBD800CFF
+ BC7F0BFFBA7D09FFB97C08FFBB7E0AFFBC7F0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBA7C0AFFB97B09FFB87A08FFBB7D0BFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFB97B09FFB97B09FFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFFB87A08FFBF810FFFC28412FF
+ BD7F0DFFB97B09FFBB7D0BFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBC7E0CFFBD7F0DFFBC7E0CFFBA7C0AFFBD7E0EFFBD7E0EFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFFBC7E0CFFBD7F0DFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBD7F0DFFBC7E0CFFB87A08FFB87A08FFB87A08FF
+ A86D17FFA46913FFA46913FFA86D17FFAB701AFFAB701AFFAB7118FFAD731AFF
+ A76D14FFA86F14FFA97015FFAA7116FFAB7217FFAC7318FFAE7518FFB2771AFF
+ AD7012FFB17416FFB17416FFB17416FFB6791BFFB5781AFFB37618FFB6791BFF
+ B47719FFB47719FFB47719FFB37618FFB17416FFB17416FFB27517FFB37717FF
+ B67A1AFFB57A17FFB57A17FFB57A17FFB67B18FFB97E1BFFBC811EFFBE8320FF
+ BA7F1CFFB57A17FFB47916FFB77C19FFB57A17FFB07512FFB17613FFB77B1BFF
+ B87E1FFFB87D20FFB97A1EFFB87518FFB87312FFBB7412FFBC7813FFBC7A14FF
+ B17210FFAE7113FFAD7118FFAE721EFFB27525FFB47628FFB37527FFB37423FF
+ BD7D28FFBB7C22FFC18226FFC28525FFB67917FFB17511FFB97D19FFBE821EFF
+ B67919FFB5781AFFB37619FFB27518FFB3791AFFB77D1EFFB57B1BFFAE7714FF
+ BA851DFFB6841AFFB4801BFFB4801CFFB27C1EFFB17A1FFFB57B22FFBA8027FF
+ BE812BFFBB7B26FFB97A22FFB97D24FFBA7E25FFB57C21FFB2781FFFB2791EFF
+ C18427FFBD7E26FFB37626FFAF7833FFBF905AFFC8A47CFFD9C1A9FFFFF5E9FF
+ F7F4F0FFECF0F1FFE8EDF0FFE7ECEFFFEBEDEEFFEDEFEFFFEFF0EEFFEFEFEFFF
+ F0F1F5FFF0F0F6FFF0F1F5FFF1F3F4FFF2F4F4FFF1F6F5FFF1F4F8FFF1F4F8FF
+ EFF0F4FFFDFAF6FFF0E7DAFFD5C2A7FFC4A677FFB38B4AFFAC7B2BFFB88223FF
+ C2881FFFC08315FFB97B0FFFB7790FFFB77B11FFB77D13FFB77D13FFB57B11FF
+ B47B0EFFB98013FFBD8215FFBB8013FFB87C12FFBA7B13FFBA7A14FFBA7B13FF
+ BC7E14FFBA7C10FFB7790DFFB7790DFFBA7C10FFBE8014FFC18317FFC38519FF
+ B5770BFFB97B0FFFBC7E12FFBE8014FFBD7F13FFBC7E12FFBC7E12FFBD7F13FF
+ B87A0EFFBA7D0FFFBB7F0EFFBC800FFFBC800EFFBA7E0CFFB87C0AFFB67A08FF
+ B37706FFB77A0CFFBB7E10FFBE8113FFBD8012FFBB7F0EFFB97D0BFFB87C0AFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBF810FFF
+ BF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFF
+ BA7D09FFBB7E0AFFBD800CFFBC7F0BFFBA7D07FFB97C06FFBB7E08FFBC7F0BFF
+ BE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFB97B09FFB97B09FF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BA7D09FFBB7E0AFFBD800CFFBE810DFFBE810DFFBD800CFFBB7E0AFFBA7D09FF
+ BA7C0AFFC38513FFC68816FFBF810FFFB97B09FFBA7C0AFFBD7F0DFFBE800EFF
+ BE800EFFBB7D0BFFB87A08FFB77907FFB97B09FFBB7D0BFFBC7E0CFFBB7D0BFF
+ BE7F0FFFBD7E10FFBC7D0FFFBC7D0FFFBC7D0FFFBD7E10FFBF8012FFBF8012FF
+ BD7E10FFBC7D0FFFBA7B0DFFB97A0CFFB8790BFFB97A0CFFBA7B0DFFBA7B0BFF
+ BB7D0BFFBC7F0BFFBD800CFFBD800CFFBD800CFFBD800CFFBC7F0BFFBB7E0AFF
+ B97C08FFB97C08FFB97C08FFA76C16FFA66B15FFA66B15FFA86D17FFA96E18FF
+ AA6F19FFAC7219FFAD731AFFAA7017FFB0761DFFB67D22FFB87F24FFB57C21FF
+ B1781DFFAE7518FFAE7518FFAD7013FFB07315FFB27517FFB6791BFFBB7E20FF
+ B97C1EFFB37618FFB07315FFB07315FFB37618FFB5781AFFB5781AFFB27517FF
+ B17416FFB27517FFB47719FFB17515FFB17613FFB17613FFB27714FFB37815FF
+ B57A17FFB87D1AFFB97E1BFFB27714FFB17613FFB37815FFB67B18FFB57A17FF
+ B47916FFB87D1AFFBC8222FFB37A1DFFB67A20FFB7781CFFB77516FFB97413FF
+ C07A15FFC37E17FFC17E17FFBE7C16FFB97B17FFB6781AFFB77A1DFFB97A22FF
+ B97924FFB77522FFB57320FFBD7C27FFB7771FFFBC7D21FFBF8220FFB87D16FF
+ B47A11FFB97F16FFBA8017FFB37814FFB37717FFB47719FFB5781BFFB87A20FF
+ B77B21FFB7791FFFB2771AFFB47D1AFFAE7A15FFAF7B17FFB7801DFFB7801FFF
+ B37B1CFFB37A1DFFB98025FFB57920FFB77B22FFBB7F26FFBD8128FFBE7F27FF
+ BA7C22FFB6771DFFB4751BFFB97B21FFB67A26FFB97F37FFC18F53FFD1AA7EFF
+ E0C4A6FFEFDFCEFFFFFBF4FFF4F4F4FFEFF2F6FFEFF0F4FFEFF0F4FFF1F0F2FF
+ F2F2F2FFF1F4F2FFF1F4F2FFEFF0F4FFF1F2F6FFF4F3F5FFF4F3F5FFF0F2F3FF
+ EDF1F2FFEEF3F6FFF3F4F8FFF8F4F3FFFBF1E7FFDDC9B0FFC1A37AFFC39B60FF
+ BC8D43FFB27F29FFBE8928FFC58B21FFC18416FFB97B0FFFB67A10FFB97F16FF
+ BC8219FFBA8017FFB67C12FFB57C0FFFBB8314FFBD8214FFBA7D0FFFB97B0FFF
+ BE7D14FFBE7B14FFB8760FFFBB7A11FFB7790DFFB5770DFFB6780CFFB97B11FF
+ BB7D11FFBB7D13FFB97B0FFFB87A10FFBB7D11FFBE8016FFBE8014FFBD7F15FF
+ BC7E12FFBD7F15FFBF8115FFB97B11FFBA7C10FFBA7D0FFFBB7F0EFFBC800EFF
+ BD810FFFBD810FFFBE8211FFB77A0CFFB97B0FFFBC7E12FFBE8014FFBD7F13FF
+ BB7E10FFB87C0BFFB77B09FFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE800EFF
+ BF810FFFC08210FFC08210FFBA7D09FFBB7E0AFFBD800CFFBC7F0BFFBA7D07FF
+ B97C06FFBB7E08FFBC7F09FFBB7E0AFFBA7C0AFFB97B09FFB97B09FFBA7C0AFF
+ BB7D0BFFBD7F0DFFBF810FFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BB7D0BFFB97B09FFB97B09FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBA7D09FFBB7E0AFFBE810DFFBF820EFFBF820EFF
+ BE810DFFBB7E0AFFBA7D09FFBF810FFFC28412FFC18311FFBC7E0CFFBB7D0BFF
+ BD7F0DFFBC7E0CFFB87A08FFBD7F0DFFBA7C0AFFB87A08FFB87A08FFBA7C0AFF
+ BB7D0BFFBB7D0BFFBA7C0AFFBD7E10FFBD7E10FFBC7D0FFFBC7D0FFFBD7E10FF
+ BE7F11FFBF8012FFC08113FFC08113FFBF8012FFBD7E10FFBB7C0EFFBB7C0EFF
+ BB7C0EFFBD7E10FFBE7F0FFFB77907FFB87A08FFB97B09FFB97B09FFB97B09FF
+ B97B09FFB87A08FFB77907FFB87A08FFB87A08FFB87A08FFA96D19FFA96D19FF
+ A86C18FFA66A16FFA66B15FFA76C16FFA96E18FFA96E18FFA66C13FFAB7118FF
+ B1781DFFB47B20FFB1781DFFAD7419FFAB7217FFAA7114FFB37619FFB07316FF
+ B27518FFB5781BFFB87B1EFFB97C1FFFB77A1DFFB27518FFAC6F12FFB07316FF
+ B5781BFFB77A1DFFB5781BFFB37619FFB4771AFFB5781AFFB17515FFB27714FF
+ B37815FFB57A17FFB57A17FFB57A17FFB47916FFB47916FFB07512FFB57A17FF
+ B87D1AFFB57A17FFB57A17FFB97E1BFFBE8320FFBF8421FFB47A1BFFB97C1EFF
+ B87B1BFFB57614FFBA7714FFC17D18FFC58019FFC27E15FFBF7D14FFBD7C13FF
+ BA7B13FFBA7C16FFBC7D1BFFBE7C1DFFBD781BFFBB741CFFBC7C24FFB17319FF
+ B47719FFBC811DFFBA8118FFB88015FFB77F14FFB1790EFFB17710FFB47916FF
+ B87B1EFFBB7D23FFBA7B23FFB97924FFBA7825FFBB7C24FFB87B1DFFB57A17FF
+ B77C19FFBF831FFFC08420FFB97D19FFB57A17FFB77C19FFB67A1AFFBB7D1FFF
+ BF8123FFC38324FFC68223FFC68120FFC67F1EFFC37D20FFC0802BFFB88033FF
+ BE894AFFC69A6BFFCFB091FFE7D3C1FFF4EDE4FFEAEBE9FFECF0F1FFEDF0F5FF
+ F1EFF5FFF3EFF4FFF4F1F3FFF3F3F3FFF0F7F4FFF1F8F5FFEDEEF2FFF1F0F4FF
+ F5F2F4FFF2F1F3FFEDEFF0FFE9ECF0FFEAEEF3FFF2F1F3FFFCF4EDFFF2DFCAFF
+ CBAC85FFB0854CFFB48339FFB47E29FFB37C21FFC38C29FFBD8417FFB87D0FFF
+ B3780BFFB47A10FFBB8118FFBC831AFFB87F16FFB1790EFFB57C0FFFB67E0FFF
+ B57A0CFFB5780AFFBF7E11FFCA861BFFCB831DFFC17C15FFBC7A13FFB97B11FF
+ B97A12FFBA7C12FFBC7D15FFBB7D13FFB77810FFB3750BFFBE7F17FFBF8117FF
+ BF8018FFBD7F15FFBA7B13FFBA7C12FFBC7D15FFBE8016FFC2831BFFC08218FF
+ BD8012FFBB7F0EFFBA7E0CFFBC800EFFBF8312FFC18514FFBF8115FFBE8016FF
+ BD7F15FFBB7D13FFBA7C10FFB97C0EFFB77B0AFFB67A08FFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBC7F0BFF
+ BD800CFFBD800CFFBD800CFFBC7F0BFFBB7E0AFFBB7D0BFFBB7C0CFFBB7C0EFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBF8010FFC08210FFC08210FFBA7D09FFBB7E0AFF
+ BD800AFFBC7F09FFBA7D07FFB97C06FFBB7F07FFBC7F09FFBB7E0AFFBA7C0AFF
+ B97B09FFB97B09FFBA7C0AFFBB7D0BFFBD7F0DFFBF810FFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFB97B09FFB97B09FFBB7E0AFFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFB97C06FFBB7E08FF
+ BD800AFFBF820CFFBF820CFFBD800AFFBB7E08FFB97C08FFBD7F0DFFBF810FFF
+ BE800EFFBA7C0AFFB97B09FFBC7E0CFFBB7D0BFFB67806FFBA7C0AFFB97B09FF
+ B97B09FFBA7C0AFFBC7E0CFFBC7E0CFFBA7C0AFFB77907FFBB7C0EFFBB7C0EFF
+ BD7E10FFBE7F11FFBE7F11FFBE7F11FFBE7F11FFBE7F11FFBF8012FFBE7F11FF
+ BD7E10FFBC7D0FFFBB7C0EFFBC7D0FFFBC7D0FFFBD7E10FFB77808FFB87909FF
+ B97A0AFFB97A0AFFB97A0AFFB97A0AFFB87909FFB77808FFB77808FFB77808FF
+ B77808FFAA6E1AFFAD711DFFAB6F1BFFA66A16FFA46913FFA66B15FFA86D17FF
+ A86D17FFA56B12FFA66C13FFA86F14FFAA7116FFAB7217FFAD7419FFB0771CFF
+ B37A1FFFB87D20FFB37619FFB17417FFB27518FFB27518FFB77A1DFFBB7E21FF
+ B77A1DFFAE7114FFB17417FFB4771AFFB6791CFFB6791CFFB6791CFFB6791CFF
+ B6791BFFB67A1AFFB77C19FFB97E1BFFBA7F1CFFBA7F1CFFB97E1BFFB77C19FF
+ B57A17FFB47916FFBA7F1CFFBA7F1CFFB57A17FFB47916FFBA7F1CFFBD821FFF
+ BA7D1BFFBC7E1AFFBF811DFFBB7F1BFFB57915FFB77915FFC07F1CFFC17E1BFF
+ BA7812FFBE7C15FFBB7D13FFB87E14FFBC8219FFC2841EFFC68523FFC78324FF
+ C57F24FFBB7B23FFAF7018FFB27517FFBC811EFFBC821BFFBB8318FFB88015FF
+ B1780FFFB47915FFB67B18FFBA7D1FFFBD7F25FFBD7D25FFB97921FFBB7B23FF
+ C08127FFC18325FFBF8220FFBF8220FFC48622FFC38422FFBE801CFFB87917FF
+ B67715FFB87917FFB9791AFFBA7819FFB77614FFBB7716FFC27D1CFFC68120FF
+ C48125FFC48836FFB8843DFFB3844EFFB9946EFFC8B09CFFE7DCD4FFF5F6F4FF
+ E0E7EAFFE4EAEFFFE7EBF0FFF0ECF2FFF3ECF3FFF0ECF1FFEDEFF0FFEAF3F0FF
+ EAF5F3FFEBEEF2FFF1F0F4FFF4F1F3FFF0F0F0FFEBEDEEFFE7EAEEFFE8ECF1FF
+ F0EEEEFFFCF0E4FFDFC5A7FFC09562FFB5813AFFBE832DFFBD8121FFB47A1AFF
+ B47A13FFBA8114FFB87D0FFFB47B0EFFB97F16FFBF851EFFC18720FFBB811AFF
+ B47C11FFBB8215FFB87D0FFFB57908FFB87909FFC28010FFCA8518FFC98018FF
+ C17913FFC28019FFC08119FFC08119FFC08119FFC08119FFBD7E16FFB97A12FF
+ B6770FFFC1821AFFC1821AFFC08119FFBC7D15FFB97A12FFB87911FFBA7B13FF
+ BD7E16FFC88921FFC5871DFFC08216FFBC7F11FFB97D0CFFBA7E0CFFBB7F0EFF
+ BD8012FFC5871DFFC1821AFFBC7D15FFB97A12FFB87A10FFB77A0CFFB77B0AFF
+ B67A08FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFF
+ BA7C0AFFBF8010FFBF8012FFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBA7C0AFF
+ BA7C0AFFBA7D09FFBB7E0AFFBD800AFFBC7F09FFBA7D07FFB97C06FFBB7F07FF
+ BC7F09FFBE810DFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFB97B09FF
+ B97C08FFBB7E0AFFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFB97C06FFBA7D07FFBC7F09FFBD800AFFBD800AFFBC7F09FFBA7D07FF
+ B97C06FFB77907FFBD7F0DFFBF810FFFBA7C0AFFB77907FFBA7C0AFFBC7E0CFF
+ BA7C0AFFBA7C0AFFB97B09FFBA7C0AFFBC7E0CFFBE800EFFBD7F0DFFBA7C0AFF
+ B77907FFBA7B0DFFBB7C0EFFBC7D0FFFBD7E10FFBE7F11FFBD7E10FFBC7D0FFF
+ BB7C0EFFBB7C0EFFBB7C0EFFBB7C0EFFBA7B0DFFBA7B0DFFB97A0CFFB97A0CFF
+ B97A0CFFBB7C0EFFBC7D0FFFBD7D11FFBD7E10FFBD7D11FFBD7E10FFBC7C10FF
+ BB7C0EFFB7770BFFB7780AFFB7770BFFAA711CFFAD741FFFAC731EFFA66D18FF
+ A26913FFA66D17FFA9701AFFA86F19FFA76F16FFA66E15FFA66E15FFA87017FF
+ AC751AFFB0791EFFB37C21FFB77E23FFB77C1FFFB37619FFB4771AFFB6791CFF
+ B27518FFB6791CFFBB7E21FFB6791CFFB6791CFFB5781BFFB37619FFB37619FF
+ B5781BFFB77A1DFFB87B1EFFB87B1DFFB87C1CFFB87D1AFFB97E1BFFB97E1BFF
+ B97E1BFFB97E1BFFB97E1BFFB87D1AFFB77C19FFB77C19FFB57A17FFB47916FF
+ B67B18FFB97E1BFFB97E1BFFBB7D17FFB7760AFFBE7D11FFBA7D15FFB47915FF
+ B67C1CFFBE8528FFC08528FFB77C1FFFAB7111FFA9730EFFA8740FFFAC7813FF
+ B27B18FFB77D1EFFB97A20FFB87820FFB97925FFB3731EFFB67A21FFBD8225FF
+ B87E1EFFB67E19FFB9811CFFB77F1AFFBC811EFFB87C1CFFB87B1BFFBC7E20FF
+ C08022FFBC7C1DFFBA7B19FFBC7D1BFFBF8220FFC08321FFBE811FFFBC7F1FFF
+ BD7F21FFBF7F21FFBC7B1FFFB97619FFBC791CFFBC791CFFB87518FFB27214FF
+ B17416FFB97E21FFBC8328FFB8822BFFBE883BFFBE8C4AFFAA8051FFB59578FF
+ D8C6BBFFF0ECEBFFEFF8FCFFE1EDF3FFE0EAF1FFE9ECF4FFF2EDF6FFF5EDF4FF
+ F2ECF1FFECEEEFFFE5F2F0FFE7F4F2FFECF1F4FFF1F0F4FFF3F1F1FFF2F0F0FF
+ ECEEEFFFE8EBEFFFE8EBF0FFF1EDECFFE3D3C2FFC09F78FFB98647FFCB8D39FF
+ D08C2BFFCA881FFFBD7F19FFAB7108FFBD8214FFBA7F11FFB77E11FFBB8118FF
+ C0861FFFC28821FFBD831CFFB77E15FFBB8215FFB87E0DFFB87C0AFFBE7F0DFF
+ C47F10FFC37B0FFFC1770DFFBE750DFFC4811AFFC2821CFFC2821CFFC0801AFF
+ BE7E18FFBC7C16FFBC7C16FFBC7C16FFBF7F19FFC0801AFFC0801AFFBD7D17FF
+ BA7A14FFB87812FFB97913FFBA7A14FFC1811BFFC08119FFBE8016FFBC7F11FF
+ BB7F0EFFBA7E0DFFBA7D0FFFBA7D0FFFC5871DFFC1821AFFBC7C16FFB97913FF
+ B97B11FFB97B0FFFB87B0DFFB77B09FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBD800CFFBD800CFFBC7F0BFFBB7E0AFF
+ BA7D09FFBA7D09FFBA7D09FFBA7C0AFFC08111FFBF8012FFBE7F11FFBD7E10FF
+ BB7C0CFFBA7B0BFFB87A08FFB87A08FFBA7D09FFBB7E0AFFBD800AFFBC7F09FF
+ BA7E06FFB97D05FFBB7F07FFBC7F09FFBC7F0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BB7D0BFFBA7C0AFFB97B09FFB87A08FFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFB97B09FFB97C08FFBB7E0AFFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFB97C06FFB97C06FFBA7D07FFBA7D07FF
+ BA7D07FFBA7D07FFB97C06FFB97C06FFB87A08FFBB7D0BFFBC7E0CFFBA7C0AFF
+ BB7D0BFFBF810FFFC08210FFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBB7D0BFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFBC7D0FFFBC7D0FFFBB7C0EFFBA7B0DFF
+ BA7B0DFFBA7B0DFFBB7C0EFFBB7C0EFFBA7B0DFFBB7C0EFFBD7E10FFBD7E10FF
+ BD7E10FFBB7C0EFFB97A0CFFB8790BFFBC7C10FFBD7D11FFBE7D14FFBE7E12FF
+ BE7D14FFBE7E12FFBD7C13FFBC7C10FFBA7910FFBA7A0EFFBA7910FFAB711FFF
+ AF7523FFAE7422FFA76D1BFFA46B16FFA86F1AFFAC731EFFAB721CFFA66D17FF
+ A56D14FFA66E15FFAA7219FFAF771EFFB0791EFFAE771CFFAE751AFFB0741AFF
+ AE7218FFB77B21FFBD8127FFB77B21FFB67A20FFB67A20FFAE7316FFBC8026FF
+ B77B21FFB0741AFFAE7218FFB0741AFFB4781EFFB67A20FFB97C1FFFB67A1AFF
+ B57A17FFB47916FFB47916FFB47818FFB67A1AFFB87B1DFFB77D1EFFB3791AFF
+ AD7314FFAB7112FFB27819FFB67C1DFFB77A1CFFB87C1CFFBF811DFFBA790DFF
+ C38013FFBF8018FFB57A16FFB57C1FFFBC852AFFB9802AFFAE761DFFB0791EFF
+ AF791AFFAD7A19FFB07E1AFFB3801FFFB68021FFB97E21FFB97B21FFB97924FF
+ B77722FFBC8026FFBF8427FFB67C1CFFB57A17FFBE8320FFC38825FFC38727FF
+ BA7D1DFFB47717FFB97C1CFFBE8121FFBB7E1EFFB57816FFB37713FFB77B17FF
+ B97D19FFB57A17FFB17515FFB6771BFFBE7F25FFC07D26FFBB7821FFC58128FF
+ C58428FFC08224FFBC7F21FFBC8326FFC08B30FFC18D33FFBB8734FFBF8B3FFF
+ C7985BFFAC8860FFBBA38DFFF0E4DEFFF8FAFBFFE7F0F4FFDDE9EFFFE8F0F7FF
+ EEF1F9FFF7F2FBFFF8F1F8FFF3EFF4FFEEF0F1FFE8F3F1FFEAF5F3FFF1F2F6FF
+ F2F1F5FFF1F1F1FFF0F0F0FFEBEFF0FFECEDF1FFEFECEEFFF8EDE5FFC4A98EFF
+ A8804CFFB78134FFD29234FFC27F18FFB9770EFFC0821CFFBC811AFFB87D10FF
+ B57A0CFFB4790CFFB57B11FFB97F16FFBA7F18FFB77D14FFB3790FFFAF7609FF
+ B07605FFB77B09FFC08210FFC28010FFBD780BFFBE760AFFC17B10FFC28017FF
+ BF8117FFBE7F17FFBA7B13FFB77810FFB87911FFBC7D15FFC08119FFBB7D13FF
+ BD7F15FFC08218FFBF8117FFBC7E14FFB97A12FFB87911FFB87911FFB5760EFF
+ B7790FFFB97B0FFFBC7F11FFBD8110FFBC800FFFBC7F11FFBB7D11FFC3851BFF
+ BF8018FFBB7C14FFBA7B13FFBB7D13FFBB7E10FFB97D0CFFB77B09FFB87C0AFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7D09FFBA7D09FFBA7D09FFBA7D07FFBE810DFF
+ BD800CFFBB7E0AFFBA7D09FFB97C08FFBA7D09FFBA7D09FFBB7D0BFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7D09FF
+ BB7E0AFFBD800CFFBC7F09FFBA7D07FFB97C06FFBB7E08FFBC7F09FFB77907FF
+ B97A0AFFBB7C0CFFBC7E0CFFBD800CFFBD800CFFBC7F0BFFBB7E0AFFBB7C0CFF
+ BC7D0FFFBC7D0FFFBC7D0DFFBC7E0CFFBB7E0AFFB97B09FFB97B09FFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7E0AFFBB7E08FFBB7E08FFBB7F07FFBB7F07FFB97D05FF
+ B97C06FFB87B05FFB87B05FFB87B05FFB87B05FFB97C06FFB97C06FFBD800CFF
+ BA7C0AFFB67806FFB77907FFC18311FFC98B19FFC58715FFBB7E0AFFC0830FFF
+ BD7F0DFFBA7C0AFFB97A0AFFBB7C0CFFBD7E0EFFBD7E0EFFBD7E0EFFC08010FF
+ BE7E0EFFBA7A0AFFB77907FFB67707FFB87909FFBA7B0DFFBC7D0FFFBD7D11FF
+ BD7F13FFC18214FFC38416FFC28315FFC08113FFBD7E10FFBB7C0EFFB97A0CFF
+ BA7A0EFFBB7B0FFFBC7C10FFBC7C10FFBB7B0FFFBA7A0EFFB9790DFFBC7B12FF
+ BC7C10FFBC7C10FFA66D1EFFAD7425FFB2792AFFAF7627FFA97120FFA66E1DFF
+ AC7220FFB27826FFAD741FFFAE751FFFB27721FFB1771EFFAF751CFFAE741BFF
+ AF751CFFB1771EFFB17620FFAF731FFFAC711BFFAD721CFFB0761DFFB37920FF
+ B2781FFFB1781DFFB2781FFFAF751CFFAE741BFFB37920FFBC812BFFBE832DFF
+ B87C28FFB3771EFFB87B1BFFB87B19FFBF8220FFBE8222FFB5781BFFB2761CFF
+ B77B22FFB37822FFB27622FFB37723FFB47923FFB47923FFB47A21FFB57920FF
+ B4781EFFB6791BFFBE7E18FFBC7D15FFB87A16FFB67919FFB6791CFFB7791FFF
+ B77722FFB67621FFBE8229FFB77B21FFB57C1FFFBC8524FFBF8825FFB8811EFF
+ B37B16FFB27916FFB17718FFB67C1DFFB47719FFB57919FFBE8320FFBC801CFF
+ B47814FFB67A16FFB77A18FFBB7E1EFFBD8020FFBD7F21FFC08125FFC08326FF
+ BA7C22FFB17417FFB37614FFB17511FFB07511FFB47916FFB87B1DFFB97B21FF
+ B87823FFB87824FFC2822DFFBF8127FFB77D1EFFB77D1DFFBF8827FFC48E30FF
+ BA852BFFAA7421FFB67F34FFB4864CFFC1A380FFEEE0CEFFF9F4F1FFEAECEDFF
+ F3F5F6FFEFF3F4FFEAEDF1FFEDF0F5FFF0F3F8FFF4F5F9FFF6F5F7FFF3F3F3FF
+ EDF0EEFFEDEDEDFFF1ECEEFFF3F0F2FFEBF0EEFFEDF4F1FFE8EDF0FFF4F3F5FF
+ FEF1EFFFDBC1B1FFBA9367FFB58440FFAD761BFFB87D16FFB97B15FFB77B17FF
+ C18426FFBA7E1EFFBD8117FFB97C0EFFBE8113FFBD8215FFB57A0DFFB57A0DFF
+ B97E11FFB3780BFFB67B0DFFBE8113FFBD8110FFB67A09FFB67709FFBE7F11FF
+ C58417FFC48517FFB97A0AFFB97A0AFFB97A0CFFB9790DFFBB7B0FFFBC7B12FF
+ BE7E12FFBF8012FFBF8010FFBC7D0DFFBA7C0AFFBB7D0BFFBE7F0FFFC08113FF
+ BF7F13FFBF7F13FFBF8012FFBE7F0FFFBF8010FFC18212FFC38414FFC38414FF
+ C18214FFBE7F11FFB7770BFFBC7C10FFBE7E12FFB97A0CFFB97A0AFFBE7F0FFF
+ BE800EFFB87C0AFFB97C0EFFB97C0EFFBA7D0FFFBA7E0DFFB97D0BFFB87D09FF
+ B97C06FFB87C04FFB77A04FFB97C06FFBC7E08FFBE800AFFBF800DFFC0810EFF
+ C0810FFFC0810FFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBE800EFFBC7E0CFFBA7C0AFFB87B07FFB87B07FFBA7D09FF
+ BC7F0BFFBE800EFFC08113FFB7780AFFB97A0CFFBE7F0FFFBA7D07FFB87D02FF
+ BB8005FFB97C06FFB27206FFBD7B14FFC5831CFFC6851CFFC48614FFC2850FFF
+ BC7F0BFFB57705FFCE8D24FFC5831CFFBB7B0FFFB77808FFB87B07FFBB7F07FF
+ BA7F04FFB87D02FFBB8005FFBA7E06FFBA7D07FFB97C06FFB97C06FFBA7D07FF
+ BA7D07FFBB7E08FFBA7D09FFBB7D0BFFBB7C0CFFBC7D0DFFBC7D0DFFBB7D0BFF
+ BB7E0AFFBA7D07FFBB7E08FFB87B07FFB87909FFBC7C10FFBD7D11FFBB7B0FFF
+ BD7E10FFC28212FFBC7A0AFFBD7B0AFFBE7E08FFBD8008FFBD800AFFBE810DFF
+ BD8110FFBD7F13FFC08218FFB97D13FFBA7C10FFBE8113FFC08413FFBB7F0EFF
+ BA7B0BFFBB7C0CFFB77907FFB77907FFB87A08FFB87909FFB97A0AFFBA7B0DFF
+ BA7B0DFFBB7C0EFFBA7A0EFFBA7B0DFFBA7B0DFFA66E1DFFAD7524FFB67B2BFF
+ B77C2CFFB27826FFAD7321FFAF731FFFB17620FFB0751FFFB2781FFFB5791FFF
+ B5791FFFB3781BFFB3781BFFB6791CFFB67A20FFB3771EFFB0751FFFAE741BFF
+ AE741BFFB0771CFFB1781DFFB1781BFFB1781BFFB77E21FFB47B1EFFB37A1FFF
+ B77E23FFBD832AFFBE842BFFBA7F29FFB77B21FFB47717FFB57713FFBB7E1EFF
+ BD8022FFBB7D23FFC1842EFFCC903CFFCF9341FFB67B2BFFB67B2BFFB87E2CFF
+ BD8331FFC38733FFC18630FFBC7F29FFB6791CFFB77A18FFB47612FFB0710FFF
+ B57516FFBC7E20FFC18226FFC08127FFBC7D23FFB7791FFFB2741AFFAE7316FF
+ B3791AFFB77D1DFFB67D1AFFB37A17FFB17815FFBF8526FFBD8324FFB87C1CFF
+ B37717FFB77A18FFB77A18FFBA7C18FFBD7F1BFFB97A18FFBD7E1CFFBC7F1FFF
+ BA7C1EFFBA7D20FFBD8023FFB97D23FFB3771DFFB37616FFB77A18FFBB801DFF
+ BF8421FFC28527FFC18329FFB97C26FFB2751FFFBB7F26FFB87D20FFB27B1AFF
+ B27B18FFB88120FFBD8427FFB9802AFFB1792AFFA9752FFFB8905BFFD4BDA3FF
+ F3EAE0FFF1F1F1FFE6E9EDFFF1F1F1FFF1F1F1FFECEEEFFFECEFF3FFEEF1F5FF
+ F1F4F8FFF5F5F5FFF4F4F4FFF1F1F1FFF2F0F0FFF7F2F4FFEFEDEDFFE5ECE9FF
+ F0F7F4FFF9FDFEFFFDF5F5FFF0DACFFFD2AE90FFB18349FFBB8635FFBC8222FF
+ C2881FFFBC811DFFB87C1CFFC18629FFC18525FFBA7E14FFB97C0EFFBA7D0FFF
+ BB7E10FFBA7D0FFFBC7F11FFBE8113FFBB7E10FFBC7F11FFBD8012FFBC7F11FF
+ B87B0DFFB87B0DFFBC7F11FFC08315FFC18514FFBB7D0BFFBB7E0AFFBA7B0BFF
+ BA7B0BFFBB7B0FFFBC7C10FFBE7F11FFBF8010FFBA7C0AFFB97C08FFB87B05FF
+ BA7D07FFBE800EFFC18212FFC28315FFC18214FFBB7D0BFFBA7D09FFB97B09FF
+ BB7D0BFFBD7E0EFFBE7F0FFFBD7E10FFBA7B0DFFB97A0CFFBA7B0DFFBA7B0BFF
+ B97A0AFFBB7D0BFFBF810FFFC0830FFFBC800EFFC5881AFFC08517FFBE8113FF
+ BA7E0DFFB77B09FFB77C08FFBB7E0AFFBC7F09FFBD800AFFBD800AFFBF810BFF
+ BF810BFFBE7F0CFFBD7E0BFFBE7D0AFFBB7C09FFBD7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7E0AFFBB7E0AFFBD7F0DFFBC7E0CFFBA7D09FF
+ B97C08FFB97C08FFBA7D09FFBC7F0BFFBD7F0DFFBA7B0BFFB97A0CFFC48418FF
+ CA8B1DFFBF820CFFB97E03FFBB8005FFBC7F09FFC48418FFC98721FFC98721FF
+ C28118FFBE800EFFBD800AFFBC7F0BFFB97A0AFFC6841DFFC17F19FFBA7910FF
+ B87909FFB97C08FFBB7F07FFBA7F04FFB97E03FFBB7F07FFBB7E08FFBB7E0AFF
+ BC7F0BFFBC7F0BFFBB7E08FFBB7E08FFBB7E08FFBA7D09FFBB7D0BFFBB7C0CFF
+ BC7D0FFFBC7D0DFFBB7D0BFFBB7E08FFBA7E06FFBF830BFFBC7F09FFBC7D0FFF
+ C18115FFC17F18FFBF7E15FFBF7F13FFC48316FFBD7B0BFFBF7B0AFFBD7E06FF
+ BC8005FFBD8106FFBD800AFFBB7F0EFFBB7D13FFBE8119FFB87B13FFB5790FFF
+ B87D0FFFBB7F0EFFB77B09FFB87909FFB97A0AFFBC7E0CFFBC7E0CFFBB7D0BFF
+ BA7B0BFFBA7B0BFFB97A0CFFB8790BFFB8790BFFB8790BFFB8790BFFB8790BFF
+ A46A11FFA86E15FFAF731AFFAF731AFFAC7016FFAA6E14FFAB6E11FFAC6F11FF
+ AA6D0FFFAC7010FFAF7210FFAF7210FFAD710DFFAD710DFFB1730FFFB17412FF
+ B67919FFB5781AFFB57919FFB47818FFB27714FFB27714FFB47915FFB57A16FF
+ B57A16FFB37814FFB17613FFB37815FFB67A1AFFB67A1AFFB47719FFB17515FF
+ B67715FFB57713FFB87B1BFFB87B1DFFB2741AFFB57822FFBE822EFFC18533FF
+ B77C2CFFB87D2DFFBC8230FFC08634FFC48834FFC18630FFBD802AFFBA7D20FF
+ B77A18FFB67812FFB47612FFB77915FFBB7E1CFFBF8222FFBF8222FFBD7F21FF
+ BA7D1FFFB77A1CFFB07518FFAE7316FFB2771AFFB87C22FFB87C22FFB4781EFF
+ C4882FFFBE8228FFBC7F22FFB77A1DFFB37517FFB77A1AFFC0811FFFC38422FF
+ B97B17FFBD7F1BFFBA7D1BFFB67917FFB47818FFBA7E1EFFBB8122FFBA8021FF
+ BF8024FFC28426FFBE8222FFB77B1BFFB97D1DFFC18426FFBF8329FFB97D23FF
+ C08528FFBC8222FFB6801BFFB37D18FFB27A1BFFB2791EFFB57B29FFB67F36FF
+ AB7D43FFC8A87FFFF1E3D1FFF6F4F3FFE8ECF1FFE6ECF3FFEDEFF0FFF1EFEEFF
+ ECECECFFECEEEFFFECEFF3FFEFF2F6FFF2F4F5FFF3F5F6FFF0F3F7FFF0F3F7FF
+ EAECEDFFECEEEFFFF2F7F6FFF6F8F8FFF3EEEDFFDBCAC1FFBD9F86FFC0976AFF
+ B27F39FFC58F38FFC3892AFFC18422FFBB7D1FFFB47618FFBB7E1CFFBB8118FF
+ BE8014FFBD8012FFB87B0DFFB77A0CFFBD8012FFBF8214FFBC7F11FFBD8012FF
+ C08315FFBC7F11FFBA7D0FFFBC7F11FFBD8012FFBD8012FFBE8113FFC08413FF
+ BD7F0DFFBD800CFFBC7D0DFFBB7C0CFFBC7C10FFBD7D11FFBE7F11FFBE7F0FFF
+ C18311FFBE810DFFBB7E08FFBA7D07FFBB7D0BFFBC7D0DFFBA7B0DFFB97A0CFF
+ BB7D0BFFB87B07FFB77907FFB87A08FFBA7B0BFFBC7D0DFFBB7C0EFFBA7B0DFF
+ C18214FFBB7C0EFFB87909FFBA7B0BFFBE800EFFBE800EFFBE810DFFBC810DFF
+ C58917FFC08714FFBE8210FFBA7E0CFFB77B0AFFB77B0AFFBB7C0CFFBC7D0DFF
+ BE7F0FFFBE800EFFBF800EFFBF800DFFBE800AFFBC7F07FFBC7D05FFB97B05FF
+ C08010FFBE7F11FFBE7F11FFBD7E10FFBC7D0DFFBC7D0DFFBB7D0BFFBB7D0BFF
+ BB7E0AFFBB7E0AFFBB7E08FFBB7E08FFBB7F07FFBB7F07FFBB7F07FFBB7E08FF
+ BA7D09FFB97B09FFC48418FFCA8A1EFFBF8010FFB97C08FFBB7E08FFBC7F0BFF
+ C68719FFC9881FFFC58519FFBD7E0EFFB97C08FFBB7E08FFBE7F0FFFBD7E10FF
+ BC7D0FFFBB7C0EFFB97B09FFB97C08FFBA7D07FFBA7E06FFBA7D07FFBA7D09FF
+ BB7D0BFFBC7D0DFFBE7F0FFFBF8010FFBF810FFFBE810DFFBC7F09FFBB7E08FF
+ BA7D09FFBB7D0BFFBB7C0CFFBC7D0FFFBC7D0DFFBB7D0BFFBB7E08FFBA7E06FF
+ B57901FFB87B05FFC28315FFCD8D21FFCD8B24FFC38219FFB9790DFFB77609FF
+ BD7B0BFFBF7B0AFFBD7E06FFBB7F04FFBC8005FFBB7E08FFB97D0CFFB97B11FF
+ C3861EFFBB7E16FFB67A10FFB67B0DFFB87C0BFFB67A08FFB97A0AFFBC7D0FFF
+ BE7E12FFBE7D14FFBD7C13FFBC7C10FFBC7C10FFBB7C0EFFBA7B0DFFBA7B0DFF
+ B8790BFFB8790BFFB8790BFFAF7417FFAF7417FFAF7215FFAD7013FFAC6F11FF
+ AD7012FFB17414FFB47715FFAC6F0DFFAE720EFFB2740EFFB3750FFFB2750DFF
+ B2750DFFB6770FFFB77913FFB87A16FFB77A18FFB87C18FFB57915FFB27710FF
+ B1760FFFB47A11FFB67C13FFBB8118FFB97F16FFB77C15FFB77C15FFB77B17FF
+ B87C18FFB77A18FFB57816FFBB7D19FFBA7C18FFBF8222FFBF8224FFB5771DFF
+ B2751FFFB57925FFB37725FFB07525FFB67B2BFFBB812FFFB97F2DFFB67A26FF
+ B37822FFB87B25FFBF8225FFBC7F1DFFC0821CFFC0821CFFBD7F19FFB67A16FF
+ B47814FFB77A18FFBA7D1BFFC88C2CFFC58929FFBA7F22FFB2771AFFB4781FFF
+ BD8128FFBF822CFFB97C26FFBF822CFFBA7E25FFBE7F27FFBD8023FFB6771BFF
+ BA7D1DFFC68627FFC68725FFB97B17FFBD7F1BFFB97D19FFB37713FFB07512FF
+ B77C19FFBC8222FFBE8425FFB8791DFFC18226FFC18426FFBB7F1FFFBC8020FF
+ C28626FFBB8023FFAE7415FFBA8021FFB77E1BFFB57F1AFFB57F1AFFB37B1CFF
+ B57B22FFC08535FFCA934EFFBF9560FFDDC19EFFFFFBEEFFF8FAFBFFE2E9F2FF
+ EBF2FBFFEFF1F2FFF0EEEDFFECECECFFEBEDEDFFEDEEF2FFEDF0F4FFF1F3F4FF
+ F1F5F6FFF2F5FAFFF2F7FAFFF7FAFEFFEAEEEFFFE9EDEEFFF1F1F1FFFFF3F1FF
+ DEC8BCFFAD8C6BFFB98D58FFAB7A2CFFC28B30FFBA7D1FFFB47618FFB6771BFF
+ B57719FFBE801AFFBF8417FFC4861AFFC38618FFB97C0EFFB5780AFFBE8113FF
+ BE8113FFB87B0DFFBB7E10FFC38618FFBC7F11FFB97C0EFFBF8214FFC18416FF
+ BD8012FFBC7F11FFBF8312FFBF810FFFBE810DFFBD7E0EFFBC7D0DFFBC7C10FF
+ BD7D11FFBE7F11FFBE7F0FFFBD7F0DFFBA7D09FFB87B05FFB97C06FFBB7D0BFF
+ BD7E0EFFBD7E10FFBC7D0FFFBE800EFFBB7E0AFFB97B09FFB97B09FFBB7C0CFF
+ BD7E0EFFBE7F11FFBD7E10FFCB8C1EFFC08113FFB97A0AFFBC7D0DFFBE800EFF
+ BB7D0BFFB87B07FFB87D09FFB97E0AFFB77E0AFFBA7E0CFFBA7E0CFFB97D0CFF
+ B87C0BFFB97A0CFFB8790BFFBB7C0EFFBB7C0CFFBD7D0DFFBE7F0CFFBE800AFF
+ BE8207FFBF8006FFBD8008FFC18111FFC08014FFBF7F13FFBE7E12FFBD7E10FF
+ BC7D0DFFBB7C0CFFBB7D0BFFBA7D09FFBB7E08FFBB7E08FFBC8008FFBC8106FF
+ BB8005FFBB8005FFBA7F04FFC0830DFFB77A06FFB9790DFFBE7E12FFBA7B0DFF
+ B87A08FFBB7E0AFFB97C08FFB7780AFFBC7D0FFFBD7E10FFB97B09FFB87B05FF
+ BD800AFFC18214FFC08113FFB57606FFB67905FFB87B07FFBA7D07FFBA7E06FF
+ BA7E06FFBA7D09FFBA7C0AFFBC7D0DFFBD7E10FFC08014FFC18214FFC18212FF
+ C0830FFFBD800CFFBC7F09FFBA7D09FFBB7D0BFFBB7C0CFFBC7D0FFFBC7D0DFF
+ BB7D0BFFBB7E08FFBA7E06FFBB7F07FFB97C06FFBB7C0EFFC08014FFC07E17FF
+ BB7A11FFB9790DFFBC7B0EFFBD7B0BFFBF7B0AFFBD7E06FFBB7F04FFBB7F04FF
+ BA7D07FFB87C0BFFB7790FFFCB8E26FFC1841CFFBA7E14FFB97E10FFBA7E0DFF
+ B97D0BFFBD7E0EFFC18214FFBB7912FFBC7A14FFBC7A13FFBD7C13FFBE7D14FF
+ BE7E12FFBF8012FFBF8012FFBD7E10FFBD7E10FFBD7D11FF}
+ Color = clDark
+ ParentColor = False
+ Scale = 1.000000000000000000
+ ScrollBars.Color = clDark
+ ScrollBars.ShowHandleGrip = True
+ ScrollBars.Style = rbsDefault
+ SizeGrip = sgAuto
+ TabOrder = 0
+ end
+ object RadioGroup1: TRadioGroup
+ Left = 394
+ Top = 20
+ Width = 109
+ Height = 185
+ Items.Strings = (
+ 'Opaque'
+ 'Add'
+ 'Sub'
+ 'Modulate'
+ 'Min'
+ 'Max'
+ 'Difference'
+ 'Exclusion'
+ 'Pattern')
+ Anchors = [akTop, akRight]
+ Caption = 'Operation'
+ ItemIndex = 0
+ TabOrder = 1
+ OnClick = RadioGroup1Click
+ end
+end
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/PixelCombine_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/PixelCombine_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/PixelCombine_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program PixelCombine_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/PixelCombine_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelCombine_Ex/PixelCombine_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,168 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is PixelF_Ex
+ *
+ * The Initial Developer of the Original Code is
+ * Michael Hansen
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Classes, QGraphics, QControls, QForms, QDialogs, QStdCtrls, QExtCtrls,
+ GR32, GR32_Lowlevel, GR32_Image, GR32_RangeBars;
+
+type
+ TMainForm = class(TForm)
+ Image32: TImage32;
+ PnlSettings: TPanel;
+ Label3: TLabel;
+ Panel4: TPanel;
+ gbTwist: TGaugeBar;
+ rbGetPixelFS: TRadioButton;
+ rbPixelS: TRadioButton;
+ procedure Image32PaintStage(Sender: TObject; Buffer: TBitmap32;
+ StageNum: Cardinal);
+ procedure FormCreate(Sender: TObject);
+ procedure gbTwistChange(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ Src: TBitmap32;
+ procedure TwirlDistortion(Dst, Src: TBitmap32; const Value: Integer);
+ end;
+
+var
+ MainForm: TMainForm;
+
+implementation
+
+{$R *.xfm}
+
+uses Math;
+
+procedure TMainForm.TwirlDistortion(Dst, Src: TBitmap32; const Value: Integer);
+{twirl algoritm inspired by Patrick Quinn´s remap demo}
+var
+ X, Y, DstR, DstB: Integer;
+ r, rx, ry, t, tt, v: Single;
+begin
+ rx := Src.Width / 2;
+ ry := Src.Height / 2;
+ v := -Value / 5 / Src.Height;
+ DstR := Dst.Width - 1;
+ DstB := Dst.Height - 1;
+
+ if rbGetPixelFS.Checked then
+ for Y := 0 to DstB do
+ for X := 0 to DstR do begin
+ r := Hypot(X - rx, Y - ry);
+ t := ArcTan2(Y - ry, X - rx);
+ tt := t + r * v;
+ Dst.Pixel[X, Y] := Src.PixelFS[ rx + r * Cos(tt),
+ ry + r * Sin(tt) ];
+ end
+ else if rbPixelS.Checked then
+ for Y := 0 to DstB do
+ for X := 0 to DstR do begin
+ r := Hypot(X - rx, Y - ry);
+ t := ArcTan2(Y - ry, X - rx);
+ tt := t + r * v;
+ Dst.Pixel[X, Y] := Src.PixelS[ Round(rx + r * Cos(tt)),
+ Round(ry + r * Sin(tt)) ];
+ end;
+end;
+
+procedure TMainForm.Image32PaintStage(Sender: TObject; Buffer: TBitmap32;
+ StageNum: Cardinal);
+const
+ Colors: array [0..1] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
+var
+ W, I, J, Parity: Integer;
+ Line1, Line2: TArrayOfColor32; // a buffer for a couple of scanlines
+begin
+ with Image32.Buffer do
+ if StageNum = 0 then
+ begin
+ W := Width;
+ SetLength(Line1, W);
+ SetLength(Line2, W);
+ for I := 0 to W - 1 do
+ begin
+ Parity := I shr 3 and $1;
+ Line1[I] := Colors[Parity];
+ Line2[I] := Colors[1 - Parity];
+ end;
+ for J := 0 to Height - 1 do
+ begin
+ Parity := J shr 3 and $1;
+ if Boolean(Parity) then MoveLongword(Line1[0], ScanLine[J]^, W)
+ else MoveLongword(Line2[0], ScanLine[J]^, W);
+ end;
+ end
+ else
+ FrameRectS(BoundsRect , $FF000000);
+end;
+
+procedure TMainForm.FormCreate(Sender: TObject);
+var
+ i: integer;
+begin
+ with Image32 do
+ begin
+ if PaintStages[0].Stage = PST_CLEAR_BACKGND then PaintStages[0].Stage := PST_CUSTOM;
+ PaintStages.Add.Stage := PST_CUSTOM;
+ end;
+
+ Src := TBitmap32.Create;
+ with Src do begin //Making distorted borders look better
+ Assign(Image32.Bitmap);
+ for i:= 0 to Width - 1 do begin
+ Pixel[i, 0] := Pixel[i, 0] and $00FFFFFF;
+ Pixel[i, Height - 1] := Pixel[i, 0] and $00FFFFFF;
+ end;
+ for i:= 0 to Height - 1 do begin
+ Pixel[0, i] := Pixel[i, 0] and $00FFFFFF or $7F000000;
+ Pixel[Width - 1, i] := Pixel[i, 0] and $00FFFFFF;
+ end;
+ OuterColor := $00000000;
+ end;
+end;
+
+procedure TMainForm.gbTwistChange(Sender: TObject);
+begin
+ with Image32 do
+ begin
+ TwirlDistortion(Bitmap, Src, gbTwist.Position);
+ gbTwist.Repaint;
+ Repaint;
+ end;
+end;
+
+procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ Src.Free;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/MainUnit.xfm
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/MainUnit.xfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/MainUnit.xfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,9259 @@
+object MainForm: TMainForm
+ Left = 272
+ Top = 282
+ Width = 467
+ Height = 285
+ HorzScrollBar.Range = 143
+ ActiveControl = rbPixelS
+ Caption = 'PixelF Example'
+ Color = clButton
+ Constraints.MaxHeight = 285
+ Constraints.MaxWidth = 467
+ Constraints.MinHeight = 285
+ Constraints.MinWidth = 467
+ Font.Color = clText
+ Font.Height = 11
+ Font.Name = 'MS Sans Serif'
+ Font.Pitch = fpVariable
+ Font.Style = []
+ Font.Weight = 40
+ ParentFont = False
+ Position = poScreenCenter
+ Scaled = False
+ OnClose = FormClose
+ OnCreate = FormCreate
+ PixelsPerInch = 75
+ object Image32: TImage32
+ Left = 8
+ Top = 8
+ Width = 300
+ Height = 244
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Bitmap.DrawMode = dmBlend
+ Bitmap.Data = {
+ 2C010000F4000000C2D7D4FFACC1BEFFA7BCB9FFBACFCCFFBDD2CFFFAABFBCFF
+ A2B7B4FFAABFBCFFB6CBC8FF97ACA9FF9EB3B0FFB9CECBFFBACFCCFFB5CAC7FF
+ B0C5C2FFA1B6B3FFAEC3C0FFACC1BEFFB1C6C3FFB6CBC8FFB1C6C3FFA3B8B5FF
+ 9DB2AFFF9FB4B1FF9BB0ADFF9CB1AEFF90A5A2FF8BA09DFF738885FF687D7AFF
+ 7E9390FF79908CFF778E8AFF748D89FF768F8BFF7B9490FF819894FF7F9692FF
+ 7D9490FF7D9490FF859A97FF7E9390FF7C918EFF819693FF8A9D9AFF8DA09DFF
+ 92A5A2FF97AAA7FF889B98FF94A7A4FF94A7A4FF869996FF849794FF9BAEABFF
+ B8CBC8FFC6D9D6FFB7CAC7FFA7BAB7FFA6B9B6FFADC0BDFFAABDBAFFAEC1BEFF
+ B9CCC9FFBACFCCFFA4B9B6FFB4CBC7FFB9CECBFFBACFCCFFC3D8D5FFC1D6D3FF
+ B8CBC8FFB7CAC7FFB8C9C6FFAFC0BDFF9EAFACFFA4B5B2FFAAB8B6FF7F8D8BFF
+ 374543FF818F8DFF7D8C88FF94A39FFF97A6A2FF8E9D99FF91A09CFF95A4A0FF
+ 94A39FFF97A6A2FF8B9A96FF8B9A96FF8A9995FF8A9995FF8A9995FF899894FF
+ 879692FF869591FF80928BFF8A9F97FF99ADA8FFA0B6B1FFD1E7E5FFC3DBD9FF
+ B7CFCFFFB1CBCBFFB7D1D1FFB0CACAFFBCD2D0FFB9D0CCFFADC2BFFFBFD5D0FF
+ D4E6DFFFC1D6CEFFC5DCD8FFC7E0DCFFD3ECE8FFD9F2EEFFC9E4E0FFB4CFCBFF
+ B2CDC9FFBFDAD6FFC3E1DCFFC7E5E0FFC2E2DDFFB8D8D3FFB2D2CDFFB2D2CDFF
+ ABCDC7FFA2C4BEFF82A09BFFACCAC5FFB5D3CEFFA8C6C1FFADCBC6FFAAC8C3FF
+ A2BDB9FFA9C4C0FFC9E2DEFFD5EEEAFFDCF3EFFFD5ECE8FFD0E7E3FFD0E7E3FF
+ CAE1DDFFBFD8D4FFB1D1CCFFABCBC6FFA5C3BEFF99B2AEFF7A8F8CFF556663FF
+ 3E4B49FF384341FF676D6CFF6A706FFFA5ABAAFFB1B9B8FF9AA2A1FF879290FF
+ 7B8886FF9BA9A7FF83928EFF7D8E8AFF7F908CFF8A9B97FF94A5A1FF93A4A0FF
+ 8A9B97FF82938FFF99AAA6FFA5B6B2FFA9BAB6FF9EAFABFF94A5A1FF93A4A0FF
+ 97A8A4FF97A8A4FF93A1A0FF879594FF99A9A8FFA0B0AFFF8E9E9DFFA5B5B4FF
+ C4D6D5FFBACCCBFFBED3D1FFB1C6C4FFA6BBB9FFA2B7B5FF98AEACFF879D9BFF
+ 768C8AFF6F8481FF4C5957FF4C5754FF5D6B67FF677571FF5C6A66FF677571FF
+ 7C8B87FF7B8A86FF768783FF7D8E8AFF81928EFF7F908CFF7D918CFF80948FFF
+ 839792FF829691FF859391FF8B9997FF8B9997FF849290FF82908EFF889694FF
+ 8B9997FF899795FF889694FF889694FF889694FF889694FF879593FF869492FF
+ 849290FF83918FFF84938FFF83928EFF84928EFF85938FFF869490FF85938FFF
+ 848F8CFF808B88FF767F7CFF4E5754FF818A87FF7C8582FF7C8380FF828986FF
+ 828986FF77807DFF8B9491FF8C9794FF8E9C98FF95A39FFF9CAAA6FFA4B2AEFF
+ A8B7B3FFACBBB7FFA1B2AEFFA1B2AEFFA2B3AFFFA3B4B0FFA3B7B2FFA4B8B3FF
+ A5B9B4FFA5B9B4FFAEC2BDFFA8BCB7FFA7BBB6FFADC1BCFFB0C4BFFFAABEB9FF
+ A1B5B0FF9DB1ACFF9CB0ABFFA2B6B1FFA5B9B4FFA3B7B2FFA2B6B1FFA2B6B1FF
+ 9DB1ACFF97ACA4FF93AAA2FF96AEA4FFA6BEB4FFBED6CCFFC7DED6FFBBD2CAFF
+ ADC4BCFFA8BFB7FF9DB3AEFF9EB4AFFF9EB3B0FF9DB2AFFF99AEABFF93A8A5FF
+ 8DA2A0FF8C9F9CFF80918EFF7B8A86FF798884FF6A7975FF4F5E5AFF4A5955FF
+ 566561FF5B6A66FF5D6C68FF5F6E6AFF5F6E6AFF5E6D69FFB5CAC7FF9DB2AFFF
+ 93A8A5FFA2B7B4FFAFC4C1FFAABFBCFFA4B9B6FFA5BAB7FFBCD1CEFFA1B6B3FF
+ 96ABA8FFA0B5B2FFACC1BEFFB5CAC7FFB8CDCAFFB2C7C4FFAEC3C0FFADC2BFFF
+ B0C5C2FFB3C8C5FFADC2BFFFA2B7B4FF9DB2AFFFA0B5B2FF9CB1AEFF9DB2AFFF
+ 91A6A3FF8A9F9CFF6F8481FF627774FF768B88FF728784FF6B827EFF67807CFF
+ 68817DFF6F8884FF7B928EFF849B97FF8AA19DFF8EA5A1FF8BA09DFF879C99FF
+ 859A97FF849996FF839693FF829592FF8B9E9BFF96A9A6FF95A8A5FF889B98FF
+ 869996FF8EA19EFF8C9F9CFF8B9E9BFFA7BAB7FFCEE1DEFFB9CCC9FFA7BAB7FF
+ A5B8B5FFABBEBBFFA9BCB9FFAEC1BEFFB7CAC7FFB5CAC7FFAABFBCFFB8CFCBFF
+ BACFCCFFB8CDCAFFC0D5D2FFC0D5D2FFBBCECBFFBDD0CDFFC1D2CFFFB8C9C6FF
+ A6B7B4FFA7B8B5FFABB9B7FF82908EFF2E3C3AFF667472FF758480FF879692FF
+ 8A9995FF859490FF889793FF879692FF869591FF8E9D99FF8F9E9AFF92A19DFF
+ 94A39FFF93A29EFF8F9E9AFF8A9995FF899894FF899894FF82948DFF8A9C95FF
+ 92A6A1FF95ABA6FFCBE1DFFFC8E0DEFFBFD7D7FFB0CACAFF8EA8A8FF7D9797FF
+ 8FA5A3FFA4BBB7FFA5BAB7FFAFC3BEFFBFD1CAFFBCD1C9FFB4CBC7FFB9D2CEFF
+ C8E1DDFFD3ECE8FFCCE5E1FFBCD7D3FFC0DBD7FFCFEAE6FFBEDCD7FFC7E5E0FF
+ CAE8E3FFC4E4DFFFBEDED9FFB7D7D2FFA9CBC5FF9DBDB8FF7E9C97FFAFCDC8FF
+ BCDAD5FFAFCDC8FFB9D7D2FFC0DED9FFB5D0CCFFACC7C3FFC9E2DEFFD6EFEBFF
+ DCF3EFFFD2E9E5FFCCE3DFFFCFE6E2FFD2E9E5FFCDE6E2FFC1DFDAFFB4D4CFFF
+ A9C7C2FF9FB8B4FF879C99FF657673FF475452FF384341FF696F6EFF6A706FFF
+ 858B8AFF959D9CFF98A3A1FF929D9BFF83908EFF8A9896FF97A6A2FF91A29EFF
+ 8C9D99FF8A9B97FF8D9E9AFF92A39FFF93A4A0FF91A29EFF8A9B97FF9EAFABFF
+ ACBDB9FFA5B6B2FF98A9A5FF93A4A0FF95A6A2FF96A7A3FF8D9B99FF82908FFF
+ 93A3A2FF9CACABFF90A09FFFA6B6B5FFBFD1D0FFB3C5C4FFBCD1CFFFB8CDCBFF
+ B1C6C4FFA9BEBCFF9CB2B0FF8AA09EFF758B89FF687D7AFF3E4C48FF485350FF
+ 596763FF62706CFF5E6C68FF65736FFF73827EFF788783FF778884FF7C8D89FF
+ 7F908CFF7D8E8AFF7C908BFF7F938EFF80948FFF7E928DFF82908EFF889694FF
+ 899795FF849290FF83918FFF899795FF8D9B99FF8B9997FF899795FF899795FF
+ 8A9896FF8A9896FF8B9997FF8A9896FF8A9896FF8A9896FF859490FF84938FFF
+ 83918DFF84928EFF85938FFF84928EFF848F8CFF818C89FF79827FFF505956FF
+ 838C89FF7F8885FF7F8683FF858C89FF868D8AFF7C8582FF87908DFF8A9592FF
+ 909E9AFF98A6A2FF9FADA9FFA4B2AEFFA5B4B0FFA5B4B0FFA2B3AFFFA4B5B1FF
+ A7B8B4FFA8B9B5FFA5B9B4FFA2B6B1FF9EB2ADFF9BAFAAFFA6BAB5FFA6BAB5FF
+ A9BDB8FFAFC3BEFFAEC2BDFFA7BBB6FFA3B7B2FFA4B8B3FFA1B5B0FFA4B8B3FF
+ A4B8B3FFA0B4AFFF9FB3AEFFA2B6B1FFA2B6B1FF9EB3ABFF97AEA6FF98B0A6FF
+ A6BEB4FFBED6CCFFC6DDD5FFBAD1C9FFAAC1B9FFA4BBB3FF9EB4AFFF9EB4AFFF
+ 9FB4B1FF9EB3B0FF9AAFACFF94A9A6FF8EA3A1FF8C9F9CFF81928FFF7C8B87FF
+ 778682FF657470FF485753FF43524EFF53625EFF5A6965FF5E6D69FF606F6BFF
+ 62716DFF61706CFFB9CECBFFA3B8B5FF94A9A6FF9AAFACFFA7BCB9FFA7BCB9FF
+ 98ADAAFF8BA09DFFA3B8B5FFA0B5B2FF94A9A6FF95AAA7FFADC2BFFFBDD2CFFF
+ B9CECBFFB4C9C6FFB4C9C6FFB2C7C4FFB1C6C3FFB0C5C2FFA8BDBAFF9EB3B0FF
+ 9AAFACFF9BB0ADFF9AAFACFF9BB0ADFF8EA3A0FF859A97FF697E7BFF5C716EFF
+ 718683FF6E8380FF728985FF6D8480FF69807CFF6A817DFF738A86FF7E9591FF
+ 879C99FF8BA09DFF869B98FF889D9AFF899E9BFF859A97FF7D928FFF7B908DFF
+ 8B9E9BFF9DB0ADFFA0B3B0FF8C9F9CFF879A97FF90A3A0FF8A9D9AFF809390FF
+ 98ABA8FFC1D4D1FFBBCECBFFA9BCB9FFA6B9B6FFAEC1BEFFB0C3C0FFB6C9C6FF
+ BACDCAFFB1C6C3FFABC0BDFFB6CDC9FFB4C9C6FFADC2BFFFB4C9C6FFB6CBC8FF
+ B7CAC7FFBED1CEFFB4C5C2FFB1C2BFFFA4B5B2FFA5B6B3FFAFBDBBFF96A4A2FF
+ 414F4DFF677573FF788783FF83928EFF869591FF879692FF8B9A96FF84938FFF
+ 83928EFF92A19DFF909F9BFF94A39FFF97A6A2FF96A5A1FF91A09CFF8D9C98FF
+ 8B9A96FF8C9B97FF80928BFF869891FF8EA29DFF90A6A1FFC8DEDCFFD0E8E6FF
+ C5DDDDFFA6C0C0FF758F8FFF5A7474FF6B817FFF93AAA6FFA1B6B3FFA2B6B1FF
+ B0C2BBFFBCD1C9FFB1C6C3FFB6CDC9FFC3DAD6FFCAE3DFFFC4DDD9FFBAD3CFFF
+ BDD8D4FFCBE6E2FFC0DBD7FFC6E4DFFFCBE9E4FFC9E7E2FFC3E3DEFFBDDDD8FF
+ B2D2CDFFA8C8C3FF7D9B96FFADCBC6FFBFDAD6FFB3CECAFFBDD8D4FFCAE5E1FF
+ BED7D3FFA8C1BDFFC7DEDAFFD6EDE9FFDDF4F0FFD5ECE8FFD0E5E2FFD4E9E6FF
+ D9EEEBFFD5EEEAFFCCEAE5FFBBDBD6FFAECCC7FFA9C2BEFF9BB0ADFF7F908DFF
+ 5C6967FF46514FFF515756FF717776FF798180FF848C8BFF879290FF7E8987FF
+ 828F8DFF849290FF8D9C98FF96A7A3FF9BACA8FF94A5A1FF8D9E9AFF8C9D99FF
+ 869793FF7D8E8AFF7F908CFF96A7A3FFAABBB7FFA9BAB6FF9BACA8FF91A29EFF
+ 90A19DFF92A39FFF99A7A5FF8C9A98FF93A19FFF95A3A1FF899A97FF9DAEABFF
+ B1C4C1FFA7BAB7FFAABDBAFFB0C3C0FFABC0BDFF9DB2AFFF8FA6A2FF839A96FF
+ 718884FF617673FF4C5A56FF5E6966FF63716DFF63716DFF667470FF667470FF
+ 6B7A76FF798884FF7B8C88FF7E8F8BFF7F908CFF7E8F8BFF7E928DFF839792FF
+ 829691FF7D918CFF818F8DFF869492FF879593FF849290FF83918FFF879593FF
+ 8B9997FF8A9896FF889694FF899795FF899795FF8A9896FF8B9997FF8C9A98FF
+ 8D9B99FF8D9B99FF8B9A96FF889793FF879591FF869490FF879591FF879591FF
+ 889390FF86918EFF828B88FF565F5CFF87908DFF838C89FF828986FF868D8AFF
+ 868D8AFF7E8784FF828B88FF87928FFF909E9AFF9BA9A5FFA1AFABFFA3B1ADFF
+ A0AFABFF9EADA9FF9EAFABFFA2B3AFFFA8B9B5FFACBDB9FFA9BDB8FFA3B7B2FF
+ 9CB0ABFF97ABA6FF9EB2ADFFA2B6B1FFA9BDB8FFAEC2BDFFAABEB9FFA3B7B2FF
+ A4B8B3FFAABEB9FFA5B9B4FFA9BDB8FFAABEB9FFA7BBB6FFA7BBB6FFAABEB9FF
+ A8BCB7FFA4B9B1FF9DB4ACFF9AB2A8FFA6BEB4FFBCD4CAFFC6DDD5FFBAD1C9FF
+ A8BFB7FF9FB6AEFF9EB4AFFF9FB5B0FFA0B5B2FF9EB3B0FF9AAFACFF95AAA7FF
+ 8FA4A2FF8DA09DFF81928FFF7C8B87FF768581FF61706CFF42514DFF3D4C48FF
+ 4E5D59FF576662FF556460FF596864FF5F6E6AFF63726EFFC6DBD8FFBACFCCFF
+ ADC2BFFFAABFBCFFB0C5C2FFAFC4C1FF9AAFACFF839895FF8A9F9CFF9FB4B1FF
+ 95AAA7FF8BA09DFFA5BAB7FFB8CDCAFFB4C9C6FFB5CAC7FFB9CECBFFB7CCC9FF
+ B4C9C6FFAEC3C0FFA4B9B6FF9BB0ADFF96ABA8FF95AAA7FF97ACA9FF97ACA9FF
+ 889D9AFF7E9390FF627774FF576C69FF718683FF718683FF79908CFF778E8AFF
+ 728985FF6D8480FF708783FF788F8BFF7E9390FF7E9390FF879C99FF889D9AFF
+ 8A9F9CFF889D9AFF7F9491FF7C918EFF889B98FF97AAA7FF9AADAAFF99ACA9FF
+ 96A9A6FF91A4A1FF8DA09DFF94A7A4FFA8BBB8FFBCCFCCFFC8DBD8FFB6C9C6FF
+ B2C5C2FFB8CBC8FFB8CBC8FFBACDCAFFB3C6C3FFA0B5B2FFA7BCB9FFB1C8C4FF
+ ACC1BEFFA1B6B3FFA5BAB7FFA9BEBBFFAFC2BFFFBBCECBFFA7B8B5FFA7B8B5FF
+ A0B1AEFF9FB0ADFFACBAB8FFA6B4B2FF5D6B69FF7A8886FF7F8E8AFF859490FF
+ 889793FF8F9E9AFF93A29EFF899894FF899894FF9EADA9FF92A19DFF91A09CFF
+ 909F9BFF909F9BFF909F9BFF8F9E9AFF8D9C98FF8B9A96FF7D8F88FF82948DFF
+ 8DA19CFF8FA5A0FFC7DCDAFFD7EDEBFFCBE3E3FF9FB9B9FF7B9595FF617979FF
+ 637977FF829995FF99ACA9FF9BAFAAFFA8BAB3FFB7CCC4FFAABFBCFFB0C7C3FF
+ BBD2CEFFC2D9D5FFBCD3CFFFB3CCC8FFB8D1CDFFC2DDD9FFC7E2DEFFC7E2DEFF
+ C6E1DDFFC2E0DBFFC1DFDAFFC1E1DCFFC2E2DDFFC2E2DDFF91AFAAFFAECCC7FF
+ BFDAD6FFB9D4D0FFBAD5D1FFBED9D5FFB8D1CDFFABC4C0FFBED5D1FFCDE4E0FF
+ D7EEEAFFD4EBE7FFD3E8E5FFD6EBE8FFD6EBE8FFCFE6E2FFCEE9E5FFC1DFDAFF
+ B7D2CEFFB3CCC8FFADC2BFFF98A9A6FF788583FF606B69FF394140FF6E7675FF
+ 727A79FF7D8584FF7D8886FF6E7977FF7C8987FF798684FF6F7E7AFF839490FF
+ 92A39FFF8D9E9AFF859692FF849591FF7F908CFF758682FF82938FFF93A4A0FF
+ A3B4B0FFA5B6B2FF9CADA9FF95A6A2FF94A5A1FF97A8A4FFA1AFADFF96A4A2FF
+ 95A3A1FF909E9CFF879895FF9CADAAFFB6C7C4FFB5C8C5FFB7CAC7FFC2D5D2FF
+ BCD1CEFFA4B9B6FF8EA5A1FF829995FF6D8480FF5A6D6AFF3D4B47FF535E5BFF
+ 515F5BFF4F5D59FF5E6C68FF62706CFF677672FF808F8BFF778884FF7A8B87FF
+ 7B8C88FF7A8B87FF7D918CFF839792FF829691FF7C908BFF83918FFF859391FF
+ 879593FF859391FF83918FFF849290FF869492FF879593FF879593FF879593FF
+ 879593FF879593FF879593FF889694FF899795FF8A9896FF8C9B97FF889793FF
+ 85938FFF83918DFF84928EFF85938FFF86918EFF85908DFF87908DFF58615EFF
+ 88918EFF848D8AFF818885FF838A87FF838A87FF7D8683FF828B88FF87928FFF
+ 8F9D99FF99A7A3FF9FADA9FFA0AEAAFF9DACA8FF9BAAA6FF97A8A4FF9CADA9FF
+ A3B4B0FFA9BAB6FFA9BDB8FFA7BBB6FFA2B6B1FF9FB3AEFF9DB1ACFF9FB3AEFF
+ A5B9B4FFAABEB9FFA7BBB6FFA0B4AFFFA1B5B0FFA7BBB6FF9EB2ADFFA5B9B4FF
+ AABEB9FFAABEB9FFAABEB9FFA9BDB8FFA4B8B3FF9DB2AAFF9EB5ADFF9BB3A9FF
+ A5BDB3FFBBD3C9FFC5DCD4FFB9D0C8FFA7BEB6FF9EB5ADFF9FB5B0FF9FB5B0FF
+ A0B5B2FF9FB4B1FF9BB0ADFF95AAA7FF8FA4A2FF8DA09DFF80918EFF7C8B87FF
+ 778682FF63726EFF43524EFF3D4C48FF4C5B57FF53625EFF54635FFF596864FF
+ 606F6BFF64736FFFC5DAD7FFC1D6D3FFB6CBC8FFAEC3C0FFB0C5C2FFB3C8C5FF
+ AABFBCFF9CB1AEFF8FA4A1FFA8BDBAFF98ADAAFF7B908DFF899E9BFFA2B7B4FF
+ ADC2BFFFB8CDCAFFB4C9C6FFB5CAC7FFB4C9C6FFAEC3C0FFA5BAB7FF9EB3B0FF
+ 99AEABFF95AAA7FF9AAFACFF99AEABFF889D9AFF7A8F8CFF5C716EFF526764FF
+ 6F8481FF728784FF6F8481FF758A87FF778C89FF738885FF738885FF7A8F8CFF
+ 7E9390FF7D928FFF8DA29FFF8A9F9CFF8A9F9CFF8A9F9CFF869B98FF809592FF
+ 819693FF869B98FF91A4A1FF95A8A5FF99ACA9FF9AADAAFF9BAEABFFA6B9B6FF
+ BACDCAFFC9DCD9FFCFE2DFFFBFD2CFFFBCCFCCFFBFD2CFFFBBCECBFFB8CBC8FF
+ A9BCB9FF8DA29FFFA7BCB9FFB2C9C5FFADC2BFFFA0B5B2FFA1B6B3FFA4B9B6FF
+ AEC1BEFFBCCFCCFFB0C1BEFFADBEBBFFA4B5B2FF99AAA7FF9BA9A7FF9EACAAFF
+ 616F6DFF7A8886FF7E8D89FF84938FFF879692FF8E9D99FF93A29EFF8A9995FF
+ 8C9B97FFA1B0ACFF9EADA9FF96A5A1FF8D9C98FF8B9A96FF8E9D99FF909F9BFF
+ 8C9B97FF869591FF82928BFF7D8F88FF879B96FF879D98FFB8CDCBFFD2E8E6FF
+ D7EFEFFFB2CACAFF89A1A1FF768E8EFF657B79FF687F7BFF7F928FFF8FA39EFF
+ 9DAFA8FFA8BAB3FF9AADAAFFA1B6B3FFB0C5C2FFB9D0CCFFBAD1CDFFB8D1CDFF
+ C1DAD6FFCBE4E0FFCEE7E3FFC8E3DFFFC4DFDBFFC0DED9FFC1DFDAFFC5E3DEFF
+ CBE9E4FFD0EEE9FFB7D2CEFFB7D2CEFFC2DBD7FFC9E2DEFFBFD8D4FFB5CECAFF
+ BAD1CDFFC0D7D3FFC2D7D4FFCCE1DEFFD0E5E2FFCCE1DEFFD0E3E0FFD7EAE7FF
+ D7EAE7FFCDE2DFFFCEE7E3FFC8E3DFFFC4DDD9FFC0D7D3FFB7CCC9FFA8B9B6FF
+ 8D9B99FF7A8583FF3B4644FF5B6362FF5C6463FF7A8281FF899492FF7D8886FF
+ 7F8C8AFF687573FF667571FF74837FFF7B8A86FF758480FF72817DFF7B8A86FF
+ 859490FF879692FF869591FF899894FF909F9BFF95A4A0FF97A6A2FF98A7A3FF
+ 9BAAA6FF9FAEAAFFA3B1AFFF9EACAAFF96A4A2FF859391FF768482FF798A87FF
+ 869794FF899A97FF91A4A1FFA5B8B5FFABC0BDFF9FB4B1FF92A7A4FF869B98FF
+ 6F8481FF576A67FF495753FF5A6562FF53615DFF4F5D59FF5E6C68FF5E6C68FF
+ 5D6C68FF707F7BFF6E7F7BFF72837FFF758682FF758682FF778B86FF7D918CFF
+ 7E928DFF7A8E89FF7F8D8BFF808E8CFF83918FFF859391FF849290FF83918FFF
+ 859391FF899795FF889694FF879593FF869492FF859391FF849290FF849290FF
+ 859391FF869492FF869591FF83928EFF7F8D89FF7D8B87FF7E8C88FF7E8C88FF
+ 808B88FF7E8986FF828B88FF505956FF808986FF7F8885FF7F8683FF818885FF
+ 848B88FF828B88FF848D8AFF87928FFF8D9B97FF95A39FFF9BA9A5FF9EACA8FF
+ 9EADA9FF9EADA9FF97A8A4FF9AABA7FF9FB0ACFFA4B5B1FFA5B9B4FFA6BAB5FF
+ A6BAB5FFA6BAB5FFA1B5B0FF9EB2ADFFA0B4AFFFA5B9B4FFA5B9B4FFA0B4AFFF
+ 9DB1ACFF9FB3AEFF98ACA7FF9CB0ABFF9CB0ABFF99ADA8FF99ADA8FF9BAFAAFF
+ 9AAEA9FF96ABA3FF9DB4ACFF9AB2A8FFA5BDB3FFBAD2C8FFC4DBD3FFB8CFC7FF
+ A7BEB6FF9FB6AEFF9EB4AFFF9FB5B0FF9FB4B1FF9EB3B0FF9AAFACFF94A9A6FF
+ 8EA3A1FF8DA09DFF7F908DFF7B8A86FF798884FF687773FF4B5A56FF43524EFF
+ 4D5C58FF505F5BFF5B6A66FF5F6E6AFF63726EFF63726EFFBCD1CEFFB5CAC7FF
+ A8BDBAFF9CB1AEFF98ADAAFF9DB2AFFFA2B7B4FFA2B7B4FF91A6A3FFA9BEBBFF
+ A4B9B6FF8A9F9CFF889D9AFF99AEABFFA1B6B3FFA1B6B3FFA8BDBAFFAFC4C1FF
+ B3C8C5FFB0C5C2FFAABFBCFFA6BBB8FF9FB4B1FF99AEABFF9FB4B1FF9FB4B1FF
+ 8EA3A0FF7E9390FF5C716EFF4F6461FF6A7F7CFF6D827FFF6B807DFF778C89FF
+ 7D908DFF718683FF6C7F7CFF708582FF788D8AFF798E8BFF839895FF7F9491FF
+ 809592FF889D9AFF8DA29FFF8CA19EFF8A9F9CFF8A9F9CFF98ABA8FF8DA09DFF
+ 8FA29FFF9CAFACFF9CAFACFF96A9A6FFA5B8B5FFBFD2CFFFB9CCC9FFAFC2BFFF
+ B1C4C1FFB8CBC8FFBACDCAFFBED1CEFFB3C6C3FF98ADAAFFAABFBCFFB8CFCBFF
+ B6CBC8FFA9BEBBFFA7BCB9FFA8BDBAFFB1C4C1FFC0D3D0FFB7C8C5FFABBCB9FF
+ A1B2AFFF95A6A3FF909E9CFF95A3A1FF5E6C6AFF758381FF7F8E8AFF899894FF
+ 8A9995FF8C9B97FF91A09CFF8C9B97FF8E9D99FF9EADA9FFAAB9B5FFA0AFABFF
+ 95A4A0FF91A09CFF91A09CFF8F9E9AFF899894FF83928EFF899992FF7C8C85FF
+ 849591FF7E928DFFA0B5B3FFC0D6D4FFE1F6F7FFCEE6E6FF91A9A9FF89A1A1FF
+ 6A807EFF576C69FF6B7E7BFF859692FF91A19AFF97A9A2FF92A5A2FF9CB1AEFF
+ ACC1BEFFB6CBC8FFBACFCCFFBDD4D0FFC4DBD7FFC9E2DEFFCEE7E3FFCBE4E0FF
+ CAE3DFFFCBE6E2FFCBE6E2FFC5E3DEFFC5E3DEFFCBE6E2FFCBE6E2FFB6CFCBFF
+ BCD5D1FFCDE6E2FFC0D9D5FFB2C9C5FFBAD1CDFFC6DDD9FFCADFDCFFD1E6E3FF
+ D0E5E2FFCADDDAFFCADDDAFFD6E9E6FFDCEFECFFD8EDEAFFD2E9E5FFD0E9E5FF
+ CFE6E2FFC8DDDAFFC0D3D0FFB3C4C1FF9FADABFF8C9997FF45504EFF45504EFF
+ 5C6765FF879290FF8D9896FF838E8CFF869391FF798684FF6D7C78FF707F7BFF
+ 73827EFF72817DFF6F7E7AFF6D7C78FF6E7D79FF6F7E7AFF73827EFF6E7D79FF
+ 6F7E7AFF778682FF808F8BFF859490FF8B9A96FF91A09CFF909E9CFF94A2A0FF
+ 8F9D9BFF849290FF7E8C8AFF7E8C8AFF7D8E8BFF7D8E8BFF7A8B88FF8C9F9CFF
+ 9DB0ADFF9DB2AFFF94A9A6FF819693FF627774FF485B58FF4A5854FF505B58FF
+ 4A5854FF4C5A56FF5A6864FF616F6BFF63726EFF6B7A76FF6F807CFF768783FF
+ 7A8B87FF7A8B87FF798D88FF7E928DFF819590FF80948FFF798785FF7A8886FF
+ 7E8C8AFF849290FF859391FF849290FF869492FF8C9A98FF8A9896FF889694FF
+ 869492FF849290FF83918FFF83918FFF849290FF859391FF879692FF84938FFF
+ 818F8BFF808E8AFF808E8AFF7F8D89FF808B88FF7E8986FF767F7CFF434C49FF
+ 747D7AFF79827FFF7C8380FF818885FF888F8CFF8B9491FF858E8BFF87928FFF
+ 8B9995FF92A09CFF99A7A3FF9EACA8FFA0AFABFFA1B0ACFF9EAFABFF9EAFABFF
+ A0B1ADFFA1B2AEFFA1B5B0FFA2B6B1FFA4B8B3FFA4B8B3FFA4B8B3FFA0B4AFFF
+ A0B4AFFFA4B8B3FFA4B8B3FF9FB3AEFF9CB0ABFF9DB1ACFFA1B5B0FF9FB3AEFF
+ 97ABA6FF8EA29DFF8DA19CFF94A8A3FF9AAEA9FF9CB1A9FF9CB3ABFF9BB3A9FF
+ A7BFB5FFBBD3C9FFC1D8D0FFB4CBC3FFA6BDB5FFA1B8B0FF9DB3AEFF9EB4AFFF
+ 9EB3B0FF9DB2AFFF99AEABFF93A8A5FF8DA2A0FF8B9E9BFF80918EFF7A8985FF
+ 778682FF6A7975FF52615DFF4C5B57FF52615DFF505F5BFF53625EFF576662FF
+ 5B6A66FF5D6C68FFB7CCC9FFADC2BFFFA1B6B3FF98ADAAFF93A8A5FF91A6A3FF
+ 95AAA7FF99AEABFF92A7A4FFA0B5B2FFABC0BDFFA1B6B3FF97ACA9FFA0B5B2FF
+ A0B5B2FF8DA29FFFA3B8B5FFAEC3C0FFB6CBC8FFB4C9C6FFAFC4C1FFAABFBCFF
+ A0B5B2FF96ABA8FF9CB1AEFFA0B5B2FF94A9A6FF879C99FF647976FF526764FF
+ 697E7BFF687D7AFF718481FF7E918EFF7F908DFF687B78FF5B6C69FF5F726FFF
+ 6F827FFF788B88FF7F928FFF7B8E8BFF7C918EFF859A97FF8EA3A0FF90A5A2FF
+ 90A5A2FF93A8A5FF9CAFACFF95A8A5FF91A4A1FF90A3A0FF8C9F9CFF8C9F9CFF
+ 9AADAAFFACBFBCFFAABDBAFFA3B6B3FFA8BBB8FFAFC2BFFFB5C8C5FFC1D4D1FF
+ C0D3D0FFAABFBCFFA5BAB7FFB7CECAFFB9CECBFFAEC3C0FFAABFBCFFA7BCB9FF
+ ADC0BDFFBBCECBFFB4C5C2FFA0B1AEFF99AAA7FF99AAA7FF98A6A4FF9DABA9FF
+ 63716FFF748280FF81908CFF909F9BFF909F9BFF899894FF8C9B97FF8B9A96FF
+ 8C9B97FF96A5A1FFA3B2AEFFA2B1ADFF9FAEAAFF9AA9A5FF94A39FFF8E9D99FF
+ 899894FF879692FF8F9F98FF7D8D86FF899A96FF80948FFF90A5A3FFA7BDBBFF
+ D6EBECFFD5EAEBFF99AEAFFF95AAABFF718684FF576C69FF687B78FF7A8B87FF
+ 809089FF899B94FF8FA29FFF9DB0ADFFACBFBCFFB2C7C4FFB5CAC7FFB8CDCAFF
+ BBD0CDFFBDD4D0FFCEE5E1FFC9E2DEFFCBE4E0FFD1EAE6FFD0E9E5FFC7E2DEFF
+ C5E0DCFFC7E2DEFFD0E9E5FFB4CBC7FFB7CECAFFC8DFDBFFBFD6D2FFB6CBC8FF
+ B7CCC9FFB0C5C2FFB3C6C3FFC3D6D3FFCCDFDCFFC6D7D4FFC0D1CEFFC7D8D5FF
+ D0E1DEFFD1E4E1FFD4E9E6FFD3EAE6FFCFE6E2FFCADFDCFFC8DBD8FFC2D3D0FF
+ B1BFBDFF9DABA9FF667371FF3A4745FF657270FF96A3A1FF8A9795FF83908EFF
+ 8B9896FF919E9CFF7D8C88FF758480FF758480FF7E8D89FF7C8B87FF6C7B77FF
+ 5F6E6AFF5E6D69FF62716DFF5E6D69FF606F6BFF687773FF6C7B77FF6C7B77FF
+ 6F7E7AFF768581FF717F7BFF788682FF788682FF818F8BFF9AA9A5FFAFBEBAFF
+ B5C4C0FFB7C8C4FFACBDB9FFAFC3BEFFB6CAC5FFB7CBC6FFACC0BBFF93A7A2FF
+ 728883FF5D716CFF465450FF35403DFF2A3834FF2E3C38FF3B4945FF566460FF
+ 6C7B77FF71807CFF71827EFF7B8C88FF82938FFF7E8F8BFF788C87FF7A8E89FF
+ 7F938EFF819590FF7C8A88FF7B8987FF7F8D8BFF859391FF859391FF808E8CFF
+ 82908EFF889694FF859391FF83918FFF818F8DFF7F8D8BFF7F8D8BFF808E8CFF
+ 82908EFF849290FF859490FF83928EFF82908CFF818F8BFF818F8BFF7F8D89FF
+ 7E8986FF7B8683FF717A77FF3D4643FF6E7774FF757E7BFF7A817EFF7E8582FF
+ 878E8BFF8C9592FF848D8AFF86918EFF8B9995FF93A19DFF9AA8A4FF9FADA9FF
+ A1B0ACFFA2B1ADFFA0B1ADFFA1B2AEFFA1B2AEFFA1B2AEFFA0B4AFFFA0B4AFFF
+ A1B5B0FFA1B5B0FFA3B7B2FFA4B8B3FFA7BBB6FFA9BDB8FFA4B8B3FF9EB2ADFF
+ 9EB2ADFFA4B8B3FFA8BCB7FFA6BAB5FF9FB3AEFF96AAA5FF94A8A3FF9AAEA9FF
+ 9FB3AEFF9FB4ACFF9CB3ABFF9FB7ADFFACC4BAFFBCD4CAFFBDD4CCFFAEC5BDFF
+ A2B9B1FFA1B8B0FF9BB1ACFF9CB2ADFF9DB2AFFF9CB1AEFF98ADAAFF92A7A4FF
+ 8CA19FFF8A9D9AFF849592FF788783FF71807CFF667571FF54635FFF52615DFF
+ 586763FF54635FFF4B5A56FF4F5E5AFF54635FFF586763FFB3C8C5FFABC0BDFF
+ A7BCB9FFABC0BDFFAABFBCFFA2B7B4FF9DB2AFFFA0B5B2FFA2B7B4FF9DB2AFFF
+ A3B8B5FF9EB3B0FF94A9A6FFA6BBB8FFAFC4C1FF98ADAAFFA5BAB7FFB2C7C4FF
+ BCD1CEFFB9CECBFFB2C7C4FFAABFBCFF9CB1AEFF8EA3A0FF94A9A6FF9CB1AEFF
+ 96ABA8FF8DA29FFF6B807DFF586D6AFF6B807DFF6A7D7AFF6F807DFF7C8D8AFF
+ 7A8886FF5D6E6BFF4B5C59FF586966FF728380FF809390FF8DA09DFF889B98FF
+ 849996FF879C99FF879C99FF859A97FF869B98FF8A9F9CFF91A4A1FFA3B6B3FF
+ 9DB0ADFF829592FF829592FFA1B4B1FFB3C6C3FFAEC1BEFFB8CBC8FFAFC2BFFF
+ AEC1BEFFAEC1BEFFAEC1BEFFBBCECBFFBCCFCCFFA8BDBAFF9BB0ADFFB0C7C3FF
+ B6CBC8FFACC1BEFFA6BBB8FFA1B6B3FFA5B8B5FFB2C5C2FFB8C9C6FF9DAEABFF
+ 99AAA7FFA2B3B0FFA5B3B1FFA7B5B3FF667472FF6E7C7AFF7E8D89FF92A19DFF
+ 909F9BFF82918DFF83928EFF859490FF859490FF899894FF92A19DFF9BAAA6FF
+ A3B2AEFFA0AFABFF96A5A1FF8D9C98FF8B9A96FF8D9C98FF90A099FF809089FF
+ 95A4A0FF8D9E9AFF8FA1A0FF97ACAAFFC4D9DAFFC8DDDEFF9BB0B1FF95AAABFF
+ 728785FF5D706DFF6B7C79FF6E7F7BFF6E7E77FF7E8E87FF869794FF93A6A3FF
+ A6B7B4FFADC0BDFFB2C5C2FFB4C9C6FFB8CDCAFFB9CECBFFCFE4E1FFC9E0DCFF
+ C9E0DCFFCDE6E2FFCEE7E3FFC9E2DEFFCAE3DFFFD1EAE6FFD4EBE7FFB7CECAFF
+ B8CFCBFFC6DBD8FFC1D6D3FFBFD4D1FFB5CAC7FF9BAEABFF869996FFA7B8B5FF
+ BECFCCFFBCCDCAFFAFC0BDFFAFBDBBFFB5C3C1FFB6C7C4FFD4E7E4FFD1E6E3FF
+ CCE1DEFFCBDEDBFFCEE1DEFFCFE0DDFFBDCECBFFAAB8B6FF9AA8A6FF374442FF
+ 586563FF93A09EFF95A2A0FF99A6A4FF919E9CFF8C9997FF92A09CFF7A8985FF
+ 707F7BFF7B8A86FF81908CFF798884FF778682FF808F8BFF64736FFF64736FFF
+ 697874FF6E7D79FF6A7975FF606F6BFF606F6BFF677672FF75837FFF6F7D79FF
+ 5D6B67FF5E6C68FF7D8B87FF93A29EFF96A5A1FF98A7A3FF9EAFABFF9CADA9FF
+ A3B4B0FFB1C5C0FFBDD1CCFFBBCFCAFFB3C9C4FFB1C5C0FFA6B4B0FF76817EFF
+ 4C5A56FF33413DFF25332FFF3B4945FF566561FF53625EFF6C7D79FF788985FF
+ 7F908CFF798A86FF6F837EFF6F837EFF748883FF788C87FF849290FF818F8DFF
+ 82908EFF879593FF83918FFF7B8987FF7A8886FF7F8D8BFF7D8B89FF7C8A88FF
+ 7A8886FF798785FF7A8886FF7D8B89FF808E8CFF818F8DFF7B8A86FF7A8985FF
+ 798783FF798783FF798783FF778581FF747F7CFF707B78FF757E7BFF3F4845FF
+ 6E7774FF747D7AFF777E7BFF7A817EFF828986FF88918EFF818A87FF85908DFF
+ 8C9A96FF95A39FFF9CAAA6FFA1AFABFFA2B1ADFFA2B1ADFF9EAFABFF9FB0ACFF
+ A1B2AEFFA3B4B0FFA2B6B1FFA2B6B1FFA1B5B0FFA1B5B0FFA1B5B0FFA6BAB5FF
+ ADC1BCFFADC1BCFFA4B8B3FF9CB0ABFFA1B5B0FFACC0BBFFA1B5B0FFA5B9B4FF
+ A5B9B4FFA1B5B0FF9FB3AEFF9FB3AEFF9BAFAAFF95AAA2FF9EB5ADFFA2BAB0FF
+ B0C8BEFFBED6CCFFBBD2CAFFAAC1B9FF9FB6AEFFA0B7AFFF9BB1ACFF9BB1ACFF
+ 9CB1AEFF9BB0ADFF97ACA9FF91A6A3FF8BA09EFF899C99FF879895FF778682FF
+ 6C7B77FF62716DFF54635FFF566561FF5C6B67FF576662FF576662FF586763FF
+ 596864FF586763FFB9CECBFFB7CCC9FFBED3D0FFAFC4C1FFB2C7C4FFC0D5D2FF
+ B1C6C3FFABC0BDFFA1B6B3FFA3B8B5FFAABFBCFFA7BCB9FF9DB2AFFFA4B9B6FF
+ AABFBCFFA0B5B2FFAFC4C1FFBACFCCFFBACFCCFFADC2BFFFA6BBB8FFA7BCB9FF
+ A0B5B2FF94A9A6FF98ADAAFF95AAA7FF99AEABFF96ABA8FF879C99FF516663FF
+ 6A7F7CFF607370FF6A7876FF5A6866FF5B6866FF5A6866FF4F5D5BFF546562FF
+ 71827FFF879895FF829592FF899C99FF829794FF819693FF8BA09DFF889D9AFF
+ 809793FF859A97FF809390FF92A5A2FF98ABA8FF92A5A2FF90A3A0FF92A5A2FF
+ A5B8B5FFC5D8D5FFB6C9C6FFB6C9C6FFB0C3C0FFA8BBB8FFA8BBB8FFB2C5C2FF
+ BCCFCCFFBDD2CFFFA3B8B5FFB2C9C5FFB4C9C6FFADC2BFFFAEC3C0FFAABFBCFF
+ A8BBB8FFAEC1BEFFB1C2BFFF9CADAAFF9AABA8FF93A4A1FF9BA9A7FF9DABA9FF
+ 808E8CFF748280FF869591FF8B9A96FF8C9B97FF899894FF889793FF8A9995FF
+ 8A9995FF879692FF95A4A0FF8C9B97FF8E9D99FF9DACA8FFA5B4B0FFA0AFABFF
+ 9CABA7FF9EADA9FF9CAAA4FFA5B5AEFFA7B6B2FF9DAEAAFF9EB0AFFFB1C6C4FF
+ C2D7D8FFC7DCDDFF9CB1B2FF8FA4A5FF6D8280FF607370FF6F807DFF6A7975FF
+ 62706AFF73837CFF778583FF71827FFF808E8CFF9CADAAFFB4C5C2FFB7CAC7FF
+ B6C9C6FFB8CBC8FFCCDFDCFFBED3D0FFBFD4D1FFCEE5E1FFD5ECE8FFCEE5E1FF
+ CAE1DDFFCFE6E2FFD8EFEBFFC3D8D5FFBCD1CEFFC5D8D5FFC3D6D3FFC0D3D0FF
+ B7CAC7FFA8B9B6FF97A8A5FF8A9896FF899795FF9BA9A7FFA4B2B0FF9BA8A6FF
+ 93A09EFF94A2A0FF9DAEABFFA9BCB9FFB1C4C1FFB4C5C2FFBECFCCFFCADBD8FF
+ C2D3D0FFAEBFBCFFA1B2AFFF6F7D7BFF263432FF657371FF8A9795FF8D9A98FF
+ 889391FF94A19FFFA5B3AFFF82908CFF717F7BFF6E7C78FF63716DFF62706CFF
+ 72807CFF7E8C88FF7E8C88FF778581FF677571FF62706CFF667470FF5E6C68FF
+ 5A6864FF667470FF6A7670FF68746EFF5F6B65FF596761FF707E78FF919F99FF
+ 9AAAA3FF91A19AFF96A69FFFA3B5AEFFB4C6BFFFBBCDC6FFB5CAC2FFB0C5BDFF
+ B0C5BDFFB5C7C0FFCAD8D4FFC6D1CEFFB6C4C0FF93A19DFF5D6B67FF33413DFF
+ 31403CFF475652FF4C5D59FF62736FFF758682FF758682FF718580FF758984FF
+ 798D88FF788C87FF7C8A88FF7B8987FF778583FF758381FF7A8886FF808E8CFF
+ 7D8B89FF768482FF6D7B79FF72807EFF798785FF7A8886FF707E7CFF677573FF
+ 6A7876FF748280FF74837FFF7A8985FF808E8AFF7D8B87FF73817DFF6D7B77FF
+ 6F7A77FF737E7BFF707976FF29322FFF646D6AFF6A7370FF707774FF7A817EFF
+ 848B88FF868F8CFF8F9895FF818C89FF889692FF9AA8A4FF9EACA8FFA3B1ADFF
+ A7B6B2FFA5B4B0FFA5B6B2FFA4B5B1FFA3B4B0FFA4B5B1FFA4B8B3FFA5B9B4FF
+ A5B9B4FFA4B8B3FFA5B9B4FF91A5A0FFA1B5B0FFBACEC9FFADC1BCFFA0B4AFFF
+ A1B5B0FF9CB0ABFF9CB0ABFF9FB3AEFFA3B7B2FFA3B7B2FF9FB3AEFF99ADA8FF
+ 93A7A2FF90A59DFF91A8A0FF9CB4AAFFB8D0C6FFB8D0C6FFB6CDC5FFB7CEC6FF
+ A3BAB2FFA1B8B0FFA0B6B1FF9EB4AFFF99AEABFF93A8A5FF8DA29FFF869B98FF
+ 819694FF819491FF768784FF7B8A86FF6C7B77FF687773FF5E6D69FF303F3BFF
+ 5E6D69FF4B5A56FF586763FF5A6965FF5C6B67FF5C6B67FFB5CAC7FFACC1BEFF
+ B1C6C3FFA4B9B6FFA5BAB7FFAEC3C0FF9EB3B0FF9DB2AFFFA1B6B3FFA2B7B4FF
+ AABFBCFFABC0BDFFA6BBB8FFADC2BFFFB1C6C3FFA5BAB7FFAEC3C0FFBACFCCFF
+ BCD1CEFFB0C5C2FFA7BCB9FFA7BCB9FFA2B7B4FF98ADAAFF98ADAAFF96ABA8FF
+ 9AAFACFF9BB0ADFF8FA4A1FF5F7471FF748986FF6D807DFF6A7876FF5B6866FF
+ 586361FF566361FF525F5DFF5D6B69FF73817FFF798A87FF90A19EFF93A6A3FF
+ 8BA09DFF869B98FF8BA09DFF879C99FF819894FF889F9BFF8EA19EFF99ACA9FF
+ 99ACA9FF94A7A4FF95A8A5FF96A9A6FFA4B7B4FFBFD2CFFFC9DCD9FFC9DCD9FF
+ C4D7D4FFBDD0CDFFB9CCC9FFB9CCC9FFB3C6C3FFAABFBCFFADC2BFFFB9D0CCFF
+ B8CDCAFFB0C5C2FFB2C7C4FFAFC4C1FFACBFBCFFB1C4C1FFB5C6C3FF9CADAAFF
+ 95A6A3FF8D9E9BFF98A6A4FF9DABA9FF7E8C8AFF707E7CFF899894FF8E9D99FF
+ 909F9BFF8D9C98FF8C9B97FF8E9D99FF8C9B97FF889793FF96A5A1FF91A09CFF
+ 909F9BFF96A5A1FF9CABA7FF9DACA8FFA0AFABFFA4B3AFFF9EACA6FFA6B4AEFF
+ A4B3AFFF9DACA8FFA4B4B3FFB8CAC9FFC4D8D9FFC2D7D8FF95AAABFF8CA0A1FF
+ 708281FF647572FF6F7D7BFF687773FF62706AFF717F79FF74817FFF6E7C7AFF
+ 717F7DFF849290FF9CAAA8FFABBCB9FFB4C5C2FFB8CBC8FFD0E3E0FFC4D7D4FF
+ BDD0CDFFBFD4D1FFC3D8D5FFC2D9D5FFC3DAD6FFC7DCD9FFCBE0DDFFBFD2CFFF
+ C3D6D3FFCFE2DFFFCCDFDCFFC1D4D1FFB0C1BEFF98A9A6FF9DABA9FF95A3A1FF
+ 94A2A0FF9BA8A6FF9BA8A6FF94A19FFF929F9DFF98A5A3FF9DABA9FF9BA9A7FF
+ 90A19EFF8D9E9BFF9CADAAFFB6C7C4FFC4D5D2FFC4D5D2FFBCCDCAFF99AAA7FF
+ 344240FF697775FF83908EFF818E8CFF7B8684FF86918FFFA4B2AEFF8A9894FF
+ 879591FF8D9B97FF798783FF64726EFF6C7A76FF7B8985FF899793FF84928EFF
+ 74827EFF6C7A76FF6C7A76FF5F6D69FF55635FFF5C6A66FF6B7771FF616D67FF
+ 505C56FF4E5A54FF687670FF8E9C96FF9BA9A3FF91A19AFF94A49DFFA2B2ABFF
+ AFC1BAFFB6C8C1FFB3C5BEFFADC2BAFFACC1B9FFB1C3BCFF9DABA7FFAAB5B2FF
+ BECCC8FFD9E7E3FFE3F1EDFFC5D3CFFF859490FF4F5E5AFF4E5F5BFF536460FF
+ 5E6F6BFF6B7C78FF728681FF748883FF718580FF6F837EFF677573FF6D7B79FF
+ 72807EFF768482FF7A8886FF798785FF6D7B79FF5F6D6BFF73817FFF73817FFF
+ 748280FF73817FFF6C7A78FF63716FFF63716FFF677573FF73827EFF768581FF
+ 798783FF768480FF6F7D79FF6B7975FF6E7976FF707B78FF4C5552FF212A27FF
+ 6D7673FF79827FFF727976FF6E7572FF737A77FF78817EFF8A9390FF86918EFF
+ 92A09CFF9FADA9FF9EACA8FFA2B0ACFFA8B7B3FFA5B4B0FFA2B3AFFFA2B3AFFF
+ A1B2AEFFA1B2AEFF9EB2ADFF9EB2ADFF9FB3AEFFA0B4AFFFA9BDB8FF9CB0ABFF
+ 9EB2ADFFA6BAB5FFA0B4AFFF9BAFAAFFA2B6B1FFA8BCB7FF9FB3AEFFA2B6B1FF
+ A5B9B4FFA7BBB6FFA6BAB5FFA2B6B1FF9EB2ADFF9BB0A8FF95ACA4FFA0B8AEFF
+ BBD3C9FFB9D1C7FFB5CCC4FFB5CCC4FFA2B9B1FFA1B8B0FF99AFAAFF9BB1ACFF
+ 9DB2AFFF9BB0ADFF95AAA7FF8BA09DFF809593FF7B8E8BFF829390FF7F8E8AFF
+ 6D7C78FF697874FF5A6965FF2F3E3AFF5B6A66FF51605CFF53625EFF576662FF
+ 5B6A66FF5C6B67FFAEC3C0FF9FB4B1FFA4B9B6FFA0B5B2FFA3B8B5FFA9BEBBFF
+ 9DB2AFFFA5BAB7FFACC1BEFFA8BDBAFFAEC3C0FFB1C6C3FFADC2BFFFB0C5C2FF
+ ADC2BFFF9CB1AEFFAEC3C0FFBACFCCFFBFD4D1FFB4C9C6FFA9BEBBFFA4B9B6FF
+ 9DB2AFFF95AAA7FF98ADAAFF98ADAAFF9BB0ADFF9EB3B0FF96ABA8FF6B807DFF
+ 728784FF718481FF667371FF5A6563FF575F5EFF55605EFF5A6563FF6D7A78FF
+ 7B8987FF728380FF879895FF8DA09DFF879C99FF829794FF859C98FF839A96FF
+ 849B97FF8FA6A2FF96A9A6FF9BAEABFF96A9A6FF92A5A2FF97AAA7FF98ABA8FF
+ A3B6B3FFBBCECBFFBDD0CDFFBED1CEFFBBCECBFFB7CAC7FFB7CAC7FFB9CCC9FF
+ B3C6C3FFA8BDBAFFABC0BDFFB4CBC7FFB0C5C2FFA9BEBBFFAEC3C0FFAEC3C0FF
+ ABBEBBFFAEC1BEFFB5C6C3FF98A9A6FF8D9E9BFF869794FF93A19FFF9BA9A7FF
+ 7E8C8AFF707E7CFF84938FFF8A9995FF8C9B97FF8A9995FF8A9995FF8B9A96FF
+ 879692FF81908CFF889793FF8E9D99FF91A09CFF909F9BFF91A09CFF96A5A1FF
+ 99A8A4FF98A7A3FF93A19BFF97A59FFF93A29EFF92A19DFFA3B3B2FFBED0CFFF
+ C5D9DAFFBCD0D1FF90A4A5FF899D9EFF768887FF6C7D7AFF717F7DFF6A7975FF
+ 67756FFF72807AFF7A8785FF778482FF727F7DFF73817FFF818F8DFF93A19FFF
+ 9CAAA8FF9AABA8FFBFD0CDFFBBCECBFFB5C8C5FFB2C5C2FFB7CAC7FFBED3D0FF
+ C0D5D2FFBCD1CEFFAFC2BFFFA8B9B6FFB4C5C2FFC7D8D5FFC8D9D6FFBFD0CDFF
+ B0BEBCFF9AA8A6FF98A5A3FF9CA9A7FF9EABA9FF9CA7A5FF95A09EFF949F9DFF
+ 9BA6A4FFA3AEACFF94A19FFF8F9C9AFF8A9896FF8F9D9BFF9CADAAFFAEBFBCFF
+ BACDCAFFC0D3D0FFC2D5D2FFB9CCC9FF4A5B58FF5B6967FF768381FF7B8886FF
+ 6D7876FF737E7CFF939E9BFF798481FF7C8784FF8D9895FF838E8BFF6F7A77FF
+ 6E7976FF75807DFF8A9592FF87928FFF798481FF707B78FF6E7976FF5F6A67FF
+ 515C59FF545F5CFF626C66FF545E58FF44504AFF4A5650FF6C7872FF8F9D97FF
+ 9AA8A2FF92A09AFF8B9B94FF96A69FFFA3B3ACFFA7B9B2FFA6B8B1FFA2B4ADFF
+ A2B4ADFFA6B6AFFFB9C7C3FFB4BFBCFFA5B3AFFFA5B3AFFFC0CECAFFE1EFEBFF
+ E2F1EDFFD1E0DCFF96A7A3FF71827EFF4B5C58FF445551FF526661FF637772FF
+ 6D817CFF718580FF717F7DFF6C7A78FF63716FFF5D6B69FF616F6DFF6A7876FF
+ 6E7C7AFF6B7977FF616F6DFF5E6C6AFF606E6CFF667472FF687674FF657371FF
+ 647270FF667472FF697874FF6B7A76FF6F7D79FF6F7D79FF6B7975FF64726EFF
+ 5E6966FF5A6562FF444D4AFF1D2623FF5A6360FF6D7673FF707774FF787F7CFF
+ 7C8380FF7D8683FF87908DFF8B9693FF9BA9A5FFA2B0ACFF9CAAA6FFA2B0ACFF
+ A9B8B4FFA3B2AEFFA0B1ADFFA3B4B0FFA4B5B1FFA2B3AFFF9CB0ABFF9BAFAAFF
+ 9EB2ADFFA2B6B1FFA8BCB7FFACC0BBFFA3B7B2FF9AAEA9FF99ADA8FF97ABA6FF
+ 98ACA7FFA2B6B1FF9BAFAAFF9DB1ACFFA0B4AFFFA3B7B2FFA5B9B4FFA4B8B3FF
+ A2B6B1FFA0B5ADFF9BB2AAFFA5BDB3FFC0D8CEFFBAD2C8FFB3CAC2FFB2C9C1FF
+ 9FB6AEFFA0B7AFFF9AB0ABFF9CB2ADFF9DB2AFFF9CB1AEFF95AAA7FF8A9F9CFF
+ 7F9492FF7A8D8AFF81928FFF798884FF697874FF6A7975FF556460FF293834FF
+ 4C5B57FF4B5A56FF505F5BFF53625EFF586763FF5A6965FFB4C9C6FF9FB4B1FF
+ A3B8B5FFA2B7B4FFA5BAB7FFA6BBB8FF9BB0ADFFA8BDBAFF96ABA8FF92A7A4FF
+ 9DB2AFFFACC1BEFFB3C8C5FFBCD1CEFFBBD0CDFFABC0BDFFA8BDBAFFB6CBC8FF
+ BED3D0FFB7CCC9FFA9BEBBFF9EB3B0FF94A9A6FF8CA19EFF95AAA7FF97ACA9FF
+ 9AAFACFF9FB4B1FF97ACA9FF708582FF607572FF657673FF5F6A68FF5A6261FF
+ 596160FF5A6261FF636B6AFF7C8785FF869391FF788684FF7F908DFF889B98FF
+ 879A97FF819693FF839A96FF809793FF819894FF8EA5A1FF8FA4A1FF95A8A5FF
+ 91A4A1FF91A4A1FF95A8A5FF94A7A4FFA0B3B0FFBCCFCCFFADC0BDFFADC0BDFF
+ A8BBB8FFA3B6B3FFA5B8B5FFAFC2BFFFB6C9C6FFB5CAC7FFA7BCB9FFAEC5C1FF
+ A8BDBAFFA2B7B4FFABC0BDFFADC2BFFFAABDBAFFACBFBCFFAEBFBCFF95A6A3FF
+ 8C9D9AFF839491FF8E9C9AFF96A4A2FF7E8C8AFF758381FF81908CFF869591FF
+ 899894FF899894FF8A9995FF8A9995FF859490FF7D8C88FF7A8985FF8C9B97FF
+ 98A7A3FF95A4A0FF91A09CFF93A29EFF8F9E9AFF879692FF89958FFF8C9892FF
+ 879591FF8A9995FFA6B6B5FFCBDBDAFFCFE1E2FFBDD1D2FF8FA3A4FF8C9E9FFF
+ 829291FF788986FF778583FF74827EFF74807AFF79857FFF798684FF7D8A88FF
+ 7B8886FF758280FF7A8785FF859391FF869492FF7D8B89FF95A3A1FF9FB0ADFF
+ A3B4B1FF9FB2AFFFA8BBB8FFB7CAC7FFB7CAC7FFABBEBBFFA0B1AEFF93A4A1FF
+ 99AAA7FFA7B8B5FFA9BAB7FFACBAB8FFA8B6B4FF9CAAA8FF869391FF929F9DFF
+ 9DA8A6FF9AA5A3FF99A4A2FF9EA9A7FFA5B0AEFFA8B3B1FFADB8B6FFABB6B4FF
+ ADBAB8FFB3C1BFFFB3C4C1FFB4C5C2FFB9CCC9FFC3D6D3FFC6D9D6FFCBDEDBFF
+ 809390FF445552FF73817FFF84918FFF646F6DFF5D6866FF86918EFF6C7774FF
+ 67726FFF747F7CFF798481FF7A8582FF75807DFF697471FF77827FFF788380FF
+ 6C7774FF646F6CFF65706DFF5B6663FF4F5A57FF525D5AFF545E58FF4B554FFF
+ 46524CFF56625CFF77837DFF939F99FF98A6A0FF92A09AFF8A9892FF90A099FF
+ 9AAAA3FF9FAFA8FF9DAFA8FF9BADA6FF9BADA6FF9DADA6FF95A39FFFA4AFACFF
+ ABB9B5FFACBAB6FFB2C0BCFFC3D1CDFFD0DFDBFFD4E3DFFFDFF0ECFFD6E7E3FF
+ B5C6C2FF7D8E8AFF495D58FF3B4F4AFF4F635EFF667A75FF4F5D5BFF576563FF
+ 5F6D6BFF657371FF6C7A78FF707E7CFF697775FF606E6CFF515F5DFF515F5DFF
+ 586664FF62706EFF667472FF647270FF62706EFF647270FF5C6B67FF5F6E6AFF
+ 667470FF6A7874FF677571FF5B6965FF4C5754FF3F4A47FF323B38FF151E1BFF
+ 3F4845FF58615EFF616865FF747B78FF7A817EFF7A8380FF808986FF86918EFF
+ 94A29EFF9AA8A4FF98A6A2FFA4B2AEFFABBAB6FFA2B1ADFF9FB0ACFFA3B4B0FF
+ A6B7B3FFA2B3AFFF99ADA8FF95A9A4FF98ACA7FF9DB1ACFFA0B4AFFFB8CCC7FF
+ B2C6C1FFA3B7B2FFA7BBB6FF9FB3AEFF91A5A0FF95A9A4FF9CB0ABFF9CB0ABFF
+ 9DB1ACFF9FB3AEFFA2B6B1FFA3B7B2FFA3B7B2FFA1B6AEFF9FB6AEFFAAC2B8FF
+ C4DCD2FFBCD4CAFFB1C8C0FFAEC5BDFF9DB4ACFF9FB6AEFFA0B6B1FF9DB3AEFF
+ 99AEABFF93A8A5FF8CA19EFF859A97FF809593FF7F928FFF7B8C89FF73827EFF
+ 6A7975FF71807CFF54635FFF2B3A36FF404F4BFF455450FF4E5D59FF52615DFF
+ 556460FF566561FFC2D7D4FFABC0BDFFAABFBCFFA3B8B5FF9FB4B1FF9BB0ADFF
+ 8BA09DFF95AAA7FFA0B5B2FF96ABA8FF9CB1AEFFA9BEBBFFADC2BFFFB0C5C2FF
+ ABC0BDFF9BB0ADFF9CB1AEFFA9BEBBFFB5CAC7FFB4C9C6FFAABFBCFF9EB3B0FF
+ 92A7A4FF8BA09DFF8FA4A1FF94A9A6FF96ABA8FF9DB2AFFF97ACA9FF768B88FF
+ 4F6461FF596A67FF5C6463FF5C6261FF616766FF606867FF666E6DFF7B8684FF
+ 869391FF7A8886FF80918EFF8C9F9CFF8DA09DFF889D9AFF889F9BFF819894FF
+ 7B9490FF879E9AFF8CA19EFF94A7A4FF94A7A4FF95A8A5FF94A7A4FF8EA19EFF
+ 9CAFACFFBCCFCCFFB9CCC9FFBBCECBFFB5C8C5FFAABDBAFFA5B8B5FFABBEBBFF
+ B4C7C4FFB6CBC8FFB1C6C3FFB7CECAFFB0C5C2FFA9BEBBFFB0C5C2FFB1C6C3FF
+ ADC0BDFFAFC2BFFFADBEBBFF9AABA8FF96A7A4FF899A97FF8A9896FF8D9B99FF
+ 788684FF768482FF859490FF899894FF8C9B97FF8C9B97FF8F9E9AFF909F9BFF
+ 8A9995FF81908CFF7F8E8AFF93A29EFF9FAEAAFF9BAAA6FF94A39FFF94A39FFF
+ 909F9BFF879692FF8C9892FF8F9B95FF8A9894FF8D9C98FFADBDBCFFD6E6E5FF
+ DAECEDFFC6D8D9FF90A2A3FF8A9C9DFF879796FF81928FFF7B8987FF7C8A86FF
+ 7F8B85FF7B8781FF707B79FF7A8583FF7D8886FF788583FF7D8A88FF899694FF
+ 8B9896FF82908EFF7B8987FF889996FF8D9E9BFF899A97FF91A29FFFA0B3B0FF
+ A1B4B1FF94A7A4FF9DAEABFF8F9D9BFF8D9B99FF92A09EFF8F9D9BFF929F9DFF
+ 96A3A1FF909D9BFF7A8583FF86918FFF959D9CFF9BA3A2FFA2AAA9FFA8B0AFFF
+ A8B0AFFFA3ABAAFFB9C1C0FFB1BCBAFFAAB5B3FFA0ADABFF95A3A1FF91A29FFF
+ 9FB2AFFFB0C5C2FFCADFDCFFCFE4E1FFC0D3D0FF3E4F4CFF7C8A88FF99A6A4FF
+ 677270FF545F5DFF7C8784FF76817EFF747F7CFF6F7A77FF6D7875FF788380FF
+ 77827FFF616C69FF687370FF6B7673FF616C69FF596461FF5F6A67FF5C6764FF
+ 55605DFF586360FF59635DFF515C54FF525D55FF636E66FF79867EFF8C9991FF
+ 96A39BFF98A79FFF92A199FF96A59DFF9AABA2FF9FB0A7FFA1B2A9FFA1B2A9FF
+ 9EB1A8FF9FAFA8FFABB9B5FFA0ABA8FF98A6A2FF9EACA8FFA5B3AFFFAAB8B4FF
+ B3C2BEFFBFCECAFFD4E5E1FFDDEEEAFFE1F2EEFFE1F2EEFFDEF2EDFFC2D6D1FF
+ 7A8E89FF344843FF475553FF4B5957FF4C5A58FF4C5A58FF505E5CFF566462FF
+ 566462FF52605EFF475553FF4B5957FF52605EFF576563FF515F5DFF455351FF
+ 404E4CFF42504EFF44534FFF44534FFF475551FF4A5854FF4A5854FF42504CFF
+ 35403DFF2A3532FF1C2522FF151E1BFF363F3CFF555E5BFF5D6461FF707774FF
+ 737A77FF717A77FF707976FF6F7A77FF7D8B87FF8C9A96FF95A39FFFA8B6B2FF
+ B1C0BCFFA9B8B4FFA3B4B0FFA8B9B5FFA9BAB6FFA4B5B1FF97ABA6FF8FA39EFF
+ 8DA19CFF8FA39EFF92A6A1FFB1C5C0FFB3C7C2FFA9BDB8FFB2C6C1FFADC1BCFF
+ 9BAFAAFF99ADA8FFA4B8B3FFA1B5B0FF9FB3AEFFA0B4AFFFA2B6B1FFA4B8B3FF
+ A4B8B3FFA2B7AFFF9EB5ADFFACC4BAFFC8E0D6FFBFD7CDFFB0C7BFFFABC2BAFF
+ 9AB1A9FF9EB5ADFF96ACA7FF94AAA5FF92A7A4FF8EA3A0FF8A9F9CFF869B98FF
+ 839896FF839693FF81928FFF778682FF6D7C78FF71807CFF4D5C58FF32413DFF
+ 404F4BFF4E5D59FF4B5A56FF4F5E5AFF52615DFF54635FFFC0D5D2FFAEC3C0FF
+ AEC3C0FFA4B9B6FFA0B5B2FF9FB4B1FF8FA4A1FF94A9A6FFB2C7C4FFA2B7B4FF
+ A2B7B4FFA9BEBBFFA4B9B6FFA0B5B2FF9AAFACFF8CA19EFF96ABA8FF9EB3B0FF
+ A7BCB9FFACC1BEFFA9BEBBFFA2B7B4FF9AAFACFF95AAA7FF8BA09DFF91A6A3FF
+ 90A5A2FF9AAFACFF97ACA9FF809592FF495E5BFF5C6D6AFF636B6AFF636867FF
+ 676D6CFF6A706FFF676F6EFF737E7CFF7F8A88FF768482FF748280FF7E918EFF
+ 839693FF839895FF8AA19DFF879E9AFF819A96FF8BA29EFF8FA4A1FF97AAA7FF
+ 99ACA9FF9BAEABFF98ABA8FF8C9F9CFF97AAA7FFB8CBC8FFBFD2CFFFC4D7D4FF
+ C3D6D3FFBBCECBFFB5C8C5FFB4C7C4FFB3C6C3FFAFC4C1FFB6CBC8FFBED5D1FF
+ B8CDCAFFAEC3C0FFB1C6C3FFAEC3C0FFA9BCB9FFABBEBBFFB1C2BFFFA2B3B0FF
+ A2B3B0FF92A3A0FF8B9997FF889694FF717F7DFF707E7CFF84938FFF879692FF
+ 889793FF899894FF8E9D99FF91A09CFF8C9B97FF83928EFF889793FF92A19DFF
+ 97A6A2FF93A29EFF8E9D99FF8E9D99FF909F9BFF919F9BFF909C96FF96A29CFF
+ 909E9AFF8E9D99FFADBBBAFFD5E5E4FFDAECEDFFC6D8D9FF8D9FA0FF849697FF
+ 869695FF829390FF7B8886FF808E8AFF85918BFF78847EFF788381FF7B8684FF
+ 7B8684FF788381FF7B8684FF828F8DFF8A9795FF8C9997FF849290FF8C9A98FF
+ 899795FF7D8E8BFF7F908DFF8E9F9CFF91A4A1FF8C9D9AFF8F9D9BFF83918FFF
+ 869492FF8D9B99FF8A9795FF8B9896FF8F9C9AFF8B9896FF7B8684FF7F8A88FF
+ 8B9392FF979F9EFFA0A8A7FFA1A9A8FF9EA4A3FF989E9DFFA1A9A8FF9FA7A6FF
+ 96A19FFF889593FF7D8B89FF798C89FF809592FF899E9BFFA9C0BCFFADC4C0FF
+ B9CECBFF3B4E4BFF7B8C89FFA1AFADFF7B8684FF697472FF616C69FF737E7BFF
+ 848F8CFF7B8683FF67726FFF6B7673FF727D7AFF67726FFF697471FF6F7A77FF
+ 67726FFF5F6A67FF67726FFF687370FF636E6BFF65716BFF6A746EFF5C675FFF
+ 566159FF626D65FF727F77FF818E86FF919E96FF9FACA4FF96A59DFF96A59DFF
+ 97A89FFF9BACA3FF9EAFA6FFA0B1A8FF9DB0A7FF9DAEA5FF9BA9A5FF939E9BFF
+ 94A29EFFA5B3AFFFABB9B5FFA1AFABFF9CABA7FFA3B2AEFFB1C2BEFFD4E5E1FF
+ EBFCF8FFE2F3EFFFD1E5E0FFD3E7E2FFDAEEE9FFDCF0EBFFA8B6B4FF9AA8A6FF
+ 7F8D8BFF657371FF5B6967FF63716FFF6F7D7BFF758381FF667472FF697775FF
+ 6E7C7AFF6E7C7AFF647270FF576563FF53615FFF556361FF5B6A66FF566561FF
+ 52605CFF515F5BFF52605CFF53615DFF535E5BFF505B58FF323B38FF19221FFF
+ 0A1310FF262F2CFF404744FF666D6AFF656C69FF58615EFF5B6461FF55605DFF
+ 667470FF83918DFF95A39FFFA6B4B0FFB1C0BCFFAFBEBAFFACBDB9FFB0C1BDFF
+ B2C3BFFFADBEBAFFA1B5B0FF96AAA5FF8FA39EFF8DA19CFF869A95FF96AAA5FF
+ 9BAFAAFF9BAFAAFFA6BAB5FFACC0BBFFA6BAB5FFA3B7B2FFA7BBB6FFA2B6B1FF
+ 9CB0ABFF9BAFAAFF9DB1ACFFA0B4AFFF9FB3AEFF9DB2AAFF99B0A8FFABC3B9FF
+ CAE2D8FFC1D9CFFFB1C8C0FFA9C0B8FF98AFA7FF9DB4ACFF869C97FF8AA09BFF
+ 8FA4A1FF92A7A4FF91A6A3FF8BA09DFF849997FF819491FF849592FF7A8985FF
+ 6B7A76FF62716DFF374642FF31403CFF3D4C48FF505F5BFF465551FF4A5955FF
+ 4E5D59FF51605CFFB5CAC7FFACC1BEFFB1C6C3FFA4B9B6FFA5BAB7FFADC2BFFF
+ 9EB3B0FF9DB2AFFFA3B8B5FF94A9A6FF98ADAAFFA5BAB7FFA7BCB9FFABC0BDFF
+ B0C5C2FFABC0BDFFA0B5B2FF9FB4B1FFA0B5B2FFA4B9B6FFA6BBB8FFA5BAB7FF
+ A2B7B4FFA1B6B3FF8DA29FFF91A6A3FF8A9F9CFF92A7A4FF92A7A4FF859A97FF
+ 465B58FF627370FF717978FF686D6CFF6B706FFF737978FF707877FF747F7DFF
+ 7D8886FF788684FF707E7CFF778A87FF7A8D8AFF7C918EFF889F9BFF89A09CFF
+ 859E9AFF8EA5A1FF8FA4A1FF92A5A2FF93A6A3FF9AADAAFF9CAFACFF8FA29FFF
+ 94A7A4FFB1C4C1FFB6C9C6FFB8CBC8FFB7CAC7FFB8CBC8FFBBCECBFFBDD0CDFF
+ B4C7C4FFA7BCB9FFACC1BEFFB8CFCBFFB6CBC8FFADC2BFFFADC2BFFFA9BEBBFF
+ A5B8B5FFA8BBB8FFB3C4C1FFA5B6B3FFA6B7B4FF98A9A6FF93A19FFF8E9C9AFF
+ 72807EFF6C7A78FF82918DFF83928EFF83928EFF84938FFF8B9A96FF91A09CFF
+ 8D9C98FF859490FF879692FF889793FF8C9B97FF909F9BFF8F9E9AFF8B9A96FF
+ 8E9D99FF95A39FFF8F9B95FF9AA6A0FF94A29EFF8E9D99FFA7B5B4FFD0E0DFFF
+ D9EBECFFC8DADBFF8D9FA0FF809293FF839392FF81928FFF7B8886FF84928EFF
+ 8A9690FF77817BFF848C8BFF808887FF7E8685FF7A8583FF778280FF75807EFF
+ 7A8785FF83908EFF879492FF899795FF879593FF808E8CFF7E8F8CFF879895FF
+ 8C9D9AFF8A9B98FF808E8CFF788684FF828F8DFF8E9B99FF8B9896FF8D9A98FF
+ 939E9CFF8F9A98FF868E8DFF808887FF828A89FF8E9695FF969C9BFF929897FF
+ 909695FF959B9AFF9BA1A0FF9FA7A6FF9FAAA8FF99A6A4FF99A7A5FF96A9A6FF
+ 899E9BFF778E8AFF768D89FF809793FF748986FF405350FF6B7C79FF919F9DFF
+ 8F9A98FF899492FF737C79FF78817EFF8B9491FF919A97FF7D8683FF737C79FF
+ 79827FFF7B8481FF727B78FF7D8683FF78817EFF737C79FF7C8582FF7F8885FF
+ 78817EFF77817BFF6B756FFF566159FF4D5850FF5D6860FF737E76FF818C84FF
+ 8F9C94FF9EABA3FF95A49CFF93A29AFF92A39AFF95A69DFF9AABA2FF9CADA4FF
+ 9BACA3FF99AAA1FF97A5A1FF99A4A1FF96A4A0FF95A39FFF92A09CFF93A19DFF
+ 9CABA7FFA7B6B2FF9BACA8FFB1C2BEFFD4E5E1FFF1FFFEFFEFFFFEFFE1F5F0FF
+ D8ECE7FFD9EDE8FFEAF8F6FFEAF8F6FFE2F0EEFFD3E1DFFFC5D3D1FFBBC9C7FF
+ B0BEBCFFA7B5B3FFB0BEBCFFACBAB8FFAAB8B6FFAAB8B6FFA8B6B4FFA2B0AEFF
+ A1AFADFFA5B3B1FFA2B1ADFF9EADA9FF9AA8A4FF96A4A0FF96A4A0FF96A4A0FF
+ 99A4A1FF99A4A1FF767F7CFF565F5CFF1C2522FF17201DFF171E1BFF39403DFF
+ 404744FF3D4643FF4E5754FF47524FFF5F6D69FF869490FF94A29EFF9AA8A4FF
+ A4B3AFFFAAB9B5FFA4B5B1FFA8B9B5FFAEBFBBFFB0C1BDFFACC0BBFFA4B8B3FF
+ 9CB0ABFF97ABA6FF92A6A1FF8CA09BFF90A49FFF96AAA5FF9AAEA9FFA3B7B2FF
+ A8BCB7FFA0B4AFFFA7BBB6FFA0B4AFFF98ACA7FF96AAA5FF99ADA8FF9DB1ACFF
+ 9CB0ABFF9AAFA7FF93AAA2FFA8C0B6FFCAE2D8FFC3DBD1FFB1C8C0FFA9C0B8FF
+ 97AEA6FF9DB4ACFF8AA09BFF8EA49FFF92A7A4FF93A8A5FF90A5A2FF889D9AFF
+ 809593FF7C8F8CFF7A8B88FF798884FF6C7B77FF5B6A66FF293834FF303F3BFF
+ 32413DFF41504CFF41504CFF44534FFF495854FF4B5A56FFB2C7C4FFAEC3C0FF
+ B3C8C5FFA2B7B4FFA2B7B4FFADC2BFFF9CB1AEFF95AAA7FFB8CDCAFFA7BCB9FF
+ A5BAB7FFABC0BDFFA5BAB7FFA4B9B6FFA8BDBAFFA5BAB7FFB0C5C2FFA7BCB9FF
+ 9FB4B1FF9FB4B1FFA3B8B5FFA5BAB7FFA5BAB7FFA5BAB7FF93A8A5FF93A8A5FF
+ 869B98FF8BA09DFF8BA09DFF849996FF445754FF637471FF7A8583FF6A706FFF
+ 6B7170FF78807FFF798482FF7C8785FF818E8CFF818F8DFF869794FF899C99FF
+ 829794FF809592FF89A09CFF879E9AFF819894FF869D99FF889D9AFF889B98FF
+ 889B98FF95A8A5FF9EB1AEFF93A6A3FF95A8A5FFADC0BDFFB8CBC8FFB1C4C1FF
+ AABDBAFFACBFBCFFB8CBC8FFBED1CEFFB2C5C2FFA1B4B1FFA2B7B4FFB3C8C5FF
+ B6C9C6FFAFC2BFFFB0C3C0FFADC0BDFFA9BCB9FFB1C2BFFFB0C1BEFFA1B2AFFF
+ A3B4B1FF9AABA8FF9BA9A7FF98A6A4FF788684FF6E7C7AFF879692FF879692FF
+ 869591FF879692FF8F9E9AFF96A5A1FF94A39FFF8C9B97FF83928EFF82918DFF
+ 8B9A96FF9AA9A5FF9CABA7FF93A29EFF909F9BFF98A6A2FF929C96FFA0AAA4FF
+ 9CA7A4FF93A19DFFAAB8B6FFD1E3E2FFDEF3F1FFD1E6E4FF8EA2A3FF7D9290FF
+ 819392FF829291FF7B8987FF899694FF919A97FF78817EFF7E8685FF778280FF
+ 7B8382FF7E8987FF798482FF6F7A78FF707D7BFF7B8886FF74817FFF798684FF
+ 7D8B89FF818F8DFF849290FF859693FF889694FF889694FF859391FF7C8A88FF
+ 84918FFF8C9997FF869391FF869391FF8D9896FF8A9593FF8A9593FF7D8886FF
+ 7C8483FF868E8DFF88908FFF828A89FF88908FFF979F9EFF959D9CFF99A1A0FF
+ 939E9CFF8E9B99FF98A6A4FFA0B1AEFF8C9F9CFF6D827FFF627774FF718683FF
+ 3A4F4CFF4D605DFF5B6C69FF7A8886FF93A09EFF96A3A1FFB1BCB9FF949F9CFF
+ 949F9CFFA7B2AFFF9EA9A6FF899491FF848F8CFF899491FF737E7BFF818C89FF
+ 818C89FF7F8A87FF8C9592FF8F9895FF868F8CFF838C89FF5D6761FF47524AFF
+ 434D47FF5D6860FF7A847EFF87928AFF8F9B95FF99A69EFF9AA8A2FF96A59DFF
+ 94A29CFF96A79EFF9CAAA4FF9FB0A7FF9EACA6FF9CAAA4FF9AA8A4FFA2ADAAFF
+ A0AEAAFF9BA9A5FFA0AEAAFFA8B6B2FF9FAEAAFF8F9E9AFF94A39FFF92A39FFF
+ B4C3BFFFE5F6F2FFF1FFFEFFDFF0ECFFD9EAE6FFEAFBF7FFD8EBE8FFDDF0EDFF
+ DEF0EFFFD9ECE9FFD6E8E7FFD6E9E6FFD3E5E4FFCFE2DFFFD3E3E2FFC6D7D4FF
+ BBCBCAFFBACBC8FFBCCCCBFFBBCCC9FFBBCBCAFFBDCECBFFB7CAC7FFB8CCC7FF
+ BACBC7FFB8C9C5FFB3C4C0FFADBEBAFFA9B8B4FFA5B4B0FFC6D4D0FFD0DEDAFF
+ A1ACA9FF717C79FF232C29FF1A2320FF2D3633FF4C5552FF4B5653FF46524CFF
+ 63716DFF8E9C96FF94A29EFF8B9B94FF93A29EFF9EB0A9FF8D9E9AFF93A59EFF
+ 9DAEAAFFA6BBB3FFACC0BBFFA8BFB7FFA1B7B2FF9BB1ACFFACC2BDFF97ADA8FF
+ 9DB1ACFFA5B9B4FF9EB2ADFFA3B7B2FFA7BBB6FF98ACA7FFADC1BCFFA4B8B3FF
+ 9CB0ABFF99ADA8FF9DB1ACFFA1B5B0FFA1B5B0FFA0B4AFFF8FA69EFFA5BCB4FF
+ CAE1D9FFC4DBD3FFB2C8C3FFA8BEB9FF97ADA8FF9CB2ADFF9DB3AEFF9AAFACFF
+ 95AAA7FF8FA4A1FF889D9AFF819693FF7B908EFF788D8BFF728380FF7A8886FF
+ 768482FF657470FF2E3C3AFF374642FF2C3B37FF34423EFF404E4AFF43514DFF
+ 465450FF46544EFFC2D7D4FFB8CDCAFFA7BCB9FF9AAFACFF9CB1AEFFA7BCB9FF
+ ACC1BEFFA9BEBBFFBACFCCFFB8CDCAFFA8BDBAFFA1B6B3FFAEC3C0FFB1C6C3FF
+ A6BBB8FFA1B6B3FFA5BCB8FFA1B8B4FF9CB3AFFF9AB1ADFF9FB6B2FFA7BEBAFF
+ ABC0BDFFAABFBCFF9DB0ADFF99ACA9FFA1B4B1FF98ABA8FF8A9D9AFF708380FF
+ 586966FF6E7F7CFF707D7BFF6B7876FF6F7C7AFF7B8886FF818F8DFF7D8B89FF
+ 7A8886FF798A87FF80918EFF889B98FF8A9F9CFF869B98FF859A97FF89A09CFF
+ 8BA29EFF89A09CFF859B96FF92A6A1FF92A6A1FF869A95FF889C97FF9CB0ABFF
+ A8BCB7FFA6BAB5FFAEC2BDFFB9CDC8FFAFC3BEFFA5B9B4FFB8CCC7FFC5D9D4FF
+ B6CAC5FFA2B6B1FFA6B7B4FFAEBFBCFFB1C2BFFFADBEBBFFACBDBAFFB3C4C1FF
+ B5C6C3FFB4C2C0FFAFBDBBFFADBBB9FFA0AEACFF95A3A1FF9AA8A6FF9FADABFF
+ 8A9896FF6B7977FF7F908CFF859692FF899A96FF8A9B97FF8E9F9BFF94A5A1FF
+ 95A6A2FF92A39FFF7F908CFF839490FF8B9C98FF91A29EFF8E9F9BFF889995FF
+ 8A9B97FF93A19DFF99A09BFF909691FF909794FF8F9A97FF95A4A0FFDEF3F0FF
+ DAF1EDFFD8F1EDFFB9D4D1FF708886FF748A88FF879998FF7A8A89FF818D8DFF
+ 929A9AFF8C9494FF7B8684FF73807EFF747F7DFF788583FF7A8785FF74817FFF
+ 717E7CFF74817FFF758280FF7B8886FF859290FF8B9896FF889593FF82908EFF
+ 879492FF909D9BFF889593FF84918FFF7F8C8AFF7D8A88FF7F8C8AFF84918FFF
+ 899694FF8C9997FF94A19FFF919E9CFF8A9593FF808B89FF7D8886FF808B89FF
+ 808B89FF7D8886FF949F9DFF879290FF86918FFF929F9DFF93A09EFF859391FF
+ 859693FF93A4A1FF819491FFA0B3B0FFA1B4B1FF728582FF526360FF7B8C89FF
+ 839491FF8FA09DFFAEBFBCFFA9BAB7FFA4B5B2FFA2B3B0FFA4B2B0FF9FADABFF
+ 94A2A0FF8A9896FF889593FF7D8A88FF758280FF788583FF838E8CFF899492FF
+ 8A9593FF899491FF7D8885FF4D5953FF35403DFF626E68FF697471FF929E98FF
+ 9CA7A4FFA1ADA7FF9AA5A2FF9CA8A2FF9DA8A5FF9CAAA4FF9EA9A6FF9CAAA4FF
+ A0ABA8FF9FADA9FFA2B0ACFF9DABA7FF98A6A2FF95A39FFF96A4A0FF9BA9A5FF
+ A2B0ACFFA6B4B0FF9DABA7FF97A6A2FFA4B2AEFFC5D4D0FFE7F6F2FFF1FFFCFF
+ E5F4F0FFD5E6E3FFD4EAE8FFD9F1EFFFD7EFEFFFD1E9E7FFD9F1F1FFE6FEFCFF
+ E0F8F8FFCEE6E4FFDBF0F1FFDAF0EEFFD4E9EAFFCCE2E0FFC7DCDDFFC7DDDBFF
+ C6DBDCFFC4DAD8FFC1DAD6FFBDD6D2FFBCD5D1FFBED7D3FFC2D9D5FFC0D7D3FF
+ BED3D0FFBDD2CFFFB8CBC8FFC6D9D6FFC7D8D5FFD0E1DEFFB4C2C0FF3E4C4AFF
+ 041210FF42504CFF54605AFF637068FF697771FF92A199FF95A59EFF84958CFF
+ 98A8A1FF8DA097FF8B9D96FF8BA097FF8BA098FF89A197FF92A9A1FF9CB5ABFF
+ 9DB5ADFF95ADA5FF99B0ABFF9EB5B0FF9FB5B0FF9BB1ACFF9DB3AEFFA5BBB6FF
+ A7BDB8FFA2B8B3FFA0B4AFFFA3B7B2FFA5B6B2FFA1B2AEFFA0B1ADFFA4B5B1FF
+ A3B4B0FFA0B1ADFF9DB2AFFFA3BAB6FFC9E0DCFFB5CCC8FFB2C9C5FF9BB2AEFF
+ 8FA6A2FF8EA5A1FF94ABA7FF90A6A4FF899F9DFF839997FF849A98FF859B99FF
+ 7E9492FF748987FF788887FF7E8E8DFF6E7C7BFF6C7A78FF394545FF1D2A28FF
+ 44524EFF202B28FF39453FFF3C4842FF414B45FF414C44FFBCD1CEFFB7CCC9FF
+ B0C5C2FFABC0BDFFA7BCB9FFA5BAB7FFA4B9B6FFA3B8B5FFB6CBC8FFBACFCCFF
+ AEC3C0FFA3B8B5FFAABFBCFFADC2BFFFAABFBCFFADC4C0FFAAC1BDFFA4BDB9FF
+ 9FB6B2FF9BB2AEFF9EB5B1FFA5BCB8FFADC2BFFFAFC4C1FFA9BCB9FFA0B3B0FF
+ A3B6B3FF9BAEABFF95A6A3FF7D8E8BFF61726FFF728380FF758381FF717F7DFF
+ 73817FFF7D8B89FF81928FFF7F908DFF7E8F8CFF81928FFF7B8E8BFF839693FF
+ 859A97FF829794FF829794FF889D9AFF8BA29EFF89A09CFF869A95FF91A5A0FF
+ 93A7A2FF8CA09BFF8CA09BFF9AAEA9FFA8BCB7FFAEC2BDFFACC0BBFFB8CCC7FF
+ B2C6C1FFA9BDB8FFB4C8C3FFB7CBC6FFABBFBAFFA3B7B2FFA6B4B2FFAFBDBBFF
+ B3C1BFFFB0BEBCFFAFBDBBFFB3C1BFFFB3C1BFFFAFBDBBFFAFBDBBFFB3C1BFFF
+ ACBAB8FFA1AFADFF9FADABFF9FADABFF8F9D9BFF788684FF758682FF7D8E8AFF
+ 82938FFF859692FF899A96FF91A29EFF94A5A1FF92A39FFF91A29EFF90A19DFF
+ 91A29EFF91A29EFF8B9C98FF859692FF899A96FF94A29EFF9AA09BFF939792FF
+ 909593FF8A9592FF8C9D99FFD0E6E1FFD4EDE9FFD8F3EFFFD5F0ECFF8CA7A3FF
+ 647C7AFF798E8CFF778688FF849092FF8F9699FF838B8BFF818B8BFF798684FF
+ 788583FF7E8B89FF818E8CFF7D8A88FF7C8987FF7E8B89FF788583FF798684FF
+ 7E8B89FF818E8CFF7F8C8AFF7B8886FF7F8C8AFF879492FF879492FF859290FF
+ 828F8DFF818E8CFF83908EFF869391FF8A9795FF8C9997FFA2AFADFF9FACAAFF
+ 96A3A1FF899694FF828F8DFF828F8DFF83908EFF808D8BFF8C9795FF848F8DFF
+ 83908EFF8B9896FF8C9997FF84918FFF83918FFF8A9896FF9EAFACFFB8C9C6FF
+ B3C4C1FF829390FF546764FF7D908DFF859895FF91A4A1FFADC0BDFFA8BBB8FF
+ A3B6B3FFA1B4B1FFA3B4B1FFA1B2AFFF9CADAAFF97A8A5FFA0AEACFF95A3A1FF
+ 8C9997FF8B9896FF8F9C9AFF929F9DFF929D9BFF909B99FF6C7774FF4F5A57FF
+ 4C5754FF76817EFF6F7A77FF86918EFF909B98FF98A3A0FF95A09DFF9AA5A2FF
+ 9FAAA7FF9EA9A6FF9AA5A2FF98A3A0FF9CA7A4FFA2ADAAFFA2B0ACFFA0AEAAFF
+ 9DABA7FF9AA8A4FF99A7A3FF9AA8A4FF9EACA8FFA2B0ACFF9DABA7FFA0AEAAFF
+ A5B3AFFFB5C3BFFFD3E1DDFFEEFCF8FFF0FEFAFFE1F2EFFFC4DCDAFFD2EEEEFF
+ DDF9F9FFD6F2F2FFCDE9E9FFCDE9E9FFD1EBEBFFCFE9E9FFCFE9E9FFD0EAEAFF
+ D4ECECFFD5EDEDFFD7EFEFFFD8F0F0FFD4ECECFFCEE9E6FFC1DCD9FFC2E0DBFF
+ C8E6E1FFCDEBE6FFCEE9E5FFC6E1DDFFBED7D3FFB8D1CDFFBFD6D2FFBDD4D0FF
+ CADFDCFFE0F3F0FFD9EAE7FF9CADAAFF485956FF11201CFF4D5B55FF616E66FF
+ 67766EFF87968EFF9FB0A7FF93A49BFF92A59CFF9EB1A8FF93A89FFF96ABA2FF
+ 93ABA1FF90A89EFF93ACA2FF9CB5ABFF9CB7ADFF97B2A8FF9BB2ADFF9FB6B1FF
+ 9EB5B0FF98AFAAFF99AFAAFFA1B7B2FFA6BCB7FFA5BBB6FF9DB1ACFFA1B5B0FF
+ A4B5B1FFA2B3AFFFA2B3AFFFA5B6B2FFA6B5B1FFA0B1ADFF9DB2AFFFA7BDBBFF
+ CDE3E1FFB8CECCFFB6CCCAFFA3B9B7FF97ADABFF91A7A5FF95ABA9FF95ABA9FF
+ 90A6A4FF889E9CFF859B99FF859B99FF829896FF7E9391FF7B8D8EFF728183FF
+ 606E6DFF6B7978FF3B4948FF162321FF3A4844FF2A3532FF3D4943FF434D47FF
+ 48534BFF4A554DFFBACFCCFFB5CAC7FFB4C9C6FFB4C9C6FFAABFBCFF9EB3B0FF
+ 9FB4B1FFAABFBCFFA2B7B4FFB1C6C3FFB0C5C2FFA6BBB8FFA7BCB9FFA6BBB8FF
+ A7BCB9FFB0C7C3FFAFC6C2FFA8C1BDFFA3BAB6FF9CB3AFFF9BB2AEFF9FB6B2FF
+ A9BEBBFFB1C6C3FFA8BBB8FF9AADAAFF9DB0ADFF9BAEABFFA0B1AEFF91A29FFF
+ 768784FF849592FF7C8A88FF788684FF788684FF7D8B89FF80918EFF80918EFF
+ 81928FFF849592FF7E918EFF849794FF849996FF839895FF859A97FF8BA09DFF
+ 8EA5A1FF8EA5A1FF8EA29DFF96AAA5FF9AAEA9FF96AAA5FF8EA29DFF91A5A0FF
+ A0B4AFFFAEC2BDFFAABEB9FFB5C9C4FFB5C9C4FFB4C8C3FFB9CDC8FFB4C8C3FF
+ ADC1BCFFB4C8C3FFA7B5B3FFAFBDBBFFB3C1BFFFB2C0BEFFAFBDBBFFAFBDBBFF
+ ADBBB9FFAAB8B6FFACBAB8FFB3C1BFFFB4C2C0FFABB9B7FFA3B1AFFF9EACAAFF
+ 93A19FFF869492FF6D7E7AFF768783FF7D8E8AFF80918DFF859692FF8E9F9BFF
+ 94A5A1FF95A6A2FF8FA09CFF8B9C98FF899A96FF889995FF859692FF849591FF
+ 8D9E9AFF9BA9A5FFA1A7A2FF999D98FF949B98FF8C9794FF899A96FFBFD5D0FF
+ D3EAE6FFDDF8F4FFD7F2EEFFA9C4C0FF576F6DFF748987FF758486FF869294FF
+ 8C9598FF889090FF828C8CFF7B8886FF788583FF7B8886FF7C8987FF7A8785FF
+ 798684FF7B8886FF7B8886FF778482FF758280FF788583FF778482FF758280FF
+ 778482FF7C8987FF84918FFF83908EFF83908EFF828F8DFF83908EFF859290FF
+ 879492FF899694FF98A5A3FF9BA8A6FF96A3A1FF8B9896FF83908EFF83908EFF
+ 859290FF869391FF889391FF8A9593FF8A9795FF8B9896FF8B9896FF899694FF
+ 869492FF849290FF95A6A3FFAFC0BDFFB0C1BEFF8A9B98FF546764FF7F928FFF
+ 849794FF8DA09DFFA5B8B5FFA5B8B5FFA5B8B5FFA4B7B4FFA2B3B0FF9DAEABFF
+ 98A9A6FF94A5A2FFA1AFADFF98A6A4FF8F9C9AFF8B9896FF8C9997FF8E9B99FF
+ 8C9795FF879290FF6B7673FF515C59FF586360FF808B88FF7B8683FF899491FF
+ 919C99FF949F9CFF909B98FF98A3A0FFA0ABA8FF9EA9A6FF97A29FFF949F9CFF
+ 9AA5A2FFA1ACA9FF96A4A0FF99A7A3FF9BA9A5FF9AA8A4FF97A5A1FF96A4A0FF
+ 99A7A3FF9CAAA6FF9AA8A4FFA5B3AFFFA5B3AFFFA0AEAAFFB4C2BEFFDBE9E5FF
+ F2FFFCFFEEFFFCFFD8EEECFFD3EDEDFFD3EDEDFFD7F1F1FFDCF6F6FFDBF5F5FF
+ D2ECECFFCAE4E4FFD0EAEAFFD2ECECFFD7EFEFFFDAF2F2FFDAF2F2FFD6EEEEFF
+ D1E9E9FFCBE6E3FFCDE8E5FFCBE9E4FFCBE6E2FFC8E3DFFFC4DFDBFFC1DCD8FF
+ C3DCD8FFC3DCD8FFCAE1DDFFBFD6D2FFD3E8E5FFE1F6F3FFE5F8F5FFEBFEFBFF
+ 9DAEABFF0F1E1AFF36443EFF5C6B63FF798880FF83928AFF9AABA2FF9DAEA5FF
+ 8A9D94FF9CAFA6FF95AAA1FF98ADA4FF95ADA3FF90A89EFF8EA79DFF92ABA1FF
+ 96AFA5FF96AFA5FF94ABA6FF98AFAAFF97AEA9FF91A8A3FF90A6A1FF96ACA7FF
+ 9FB3AEFFA3B7B2FF9AAEA9FFA0B4AFFFA5B6B2FFA4B5B1FFA7B6B2FFA9B8B4FF
+ A8B7B3FFA1B2AEFF91A4A1FFA0B5B2FFC7DCD9FFB0C5C2FFB1C6C3FFA5BAB7FF
+ 9AAFACFF8FA4A1FF889D9AFF8A9F9CFF869B98FF7C918EFF748986FF738885FF
+ 748986FF738885FF788A89FF617372FF546463FF6C7C7BFF445552FF152321FF
+ 31403CFF32403CFF283630FF303C36FF37443CFF3C4941FFBCD1CEFFB3C8C5FF
+ AFC4C1FFAEC3C0FFA1B6B3FF93A8A5FF9FB4B1FFB6CBC8FF95AAA7FFABC0BDFF
+ B3C8C5FFAEC3C0FFAEC3C0FFAABFBCFFA8BDBAFFB0C7C3FFB1C8C4FFABC4C0FF
+ A7BEBAFFA1B8B4FF9AB1ADFF99B0ACFFA1B6B3FFAABFBCFFA5B8B5FF97AAA7FF
+ 9BAEABFF9BAEABFFA2B3B0FF95A6A3FF7C8D8AFF8B9C99FF7F8D8BFF7C8A88FF
+ 7A8886FF7A8886FF7A8B88FF7B8C89FF7D8E8BFF80918EFF829592FF839693FF
+ 829794FF839895FF859A97FF899E9BFF8BA29EFF8DA4A0FF8B9F9AFF91A5A0FF
+ 98ACA7FF99ADA8FF91A5A0FF8FA39EFF9FB3AEFFB3C7C2FFA6BAB5FFACC0BBFF
+ AFC3BEFFB8CCC7FFC0D4CFFFB7CBC6FFB2C6C1FFC0D4CFFFAEBCBAFFB1BFBDFF
+ B3C1BFFFB1BFBDFFADBBB9FFACBAB8FFABB9B7FFAAB8B6FFA5B3B1FFABB9B7FF
+ AEBCBAFFABB9B7FFA4B2B0FF9DABA9FF95A3A1FF8E9C9AFF6A7B77FF748581FF
+ 7D8E8AFF7F908CFF82938FFF8A9B97FF92A39FFF96A7A3FF8D9E9AFF889995FF
+ 859692FF859692FF849591FF859692FF8E9F9BFF9CAAA6FFA2A8A3FF9CA09BFF
+ 99A09DFF909B98FF889995FFA8BEB9FFCAE1DDFFDCF5F1FFCEE7E3FFC5DEDAFF
+ 5F7573FF798E8CFF728183FF818D8FFF889194FF8C9696FF828E8EFF7D8A88FF
+ 788583FF768381FF758280FF73807EFF717E7CFF707D7BFF7B8886FF74817FFF
+ 717E7CFF758280FF788583FF758280FF73807EFF74817FFF808D8BFF808D8BFF
+ 7F8C8AFF7D8A88FF7C8987FF7E8B89FF828F8DFF869391FF8C9997FF93A09EFF
+ 94A19FFF8B9896FF818E8CFF7F8C8AFF808D8BFF808D8BFF85908EFF8E9997FF
+ 8F9C9AFF8B9896FF8A9795FF8D9A98FF889694FF7E8C8AFF7D8E8BFF9CADAAFF
+ AABBB8FF99AAA7FF5B6E6BFF879A97FF859895FF899C99FF8FA29FFF96A9A6FF
+ 9FB2AFFFA3B6B3FFA2B3B0FF9AABA8FF92A3A0FF8D9E9BFF8F9D9BFF8A9896FF
+ 84918FFF7F8C8AFF818E8CFF84918FFF838E8CFF7D8886FF76817EFF4D5855FF
+ 4D5855FF727D7AFF7F8A87FF8F9A97FF97A29FFF919C99FF919C99FF97A29FFF
+ 9DA8A5FF9DA8A5FF99A4A1FF97A29FFF9AA5A2FF9EA9A6FF97A5A1FF9CAAA6FF
+ A0AEAAFF9EACA8FF97A5A1FF92A09CFF919F9BFF92A09CFF97A5A1FFA2B0ACFF
+ A2B0ACFF98A6A2FF9BA9A5FFB9C7C3FFE0EEEAFFF1FFFFFFEAFFFEFFD7F1F1FF
+ CDE7E7FFD5EFEFFFE0FAFAFFDFF9F9FFD6F0F0FFD0EAEAFFD1EBEBFFD1EBEBFF
+ D2EAEAFFCCE4E4FFC1D9D9FFB9D1D1FFBBD3D3FFC1D9D7FFC9E4E0FFCBE9E4FF
+ CEE9E5FFCBE6E2FFC9E4E0FFCCE7E3FFD2EBE7FFD2EBE7FFD9F0ECFFD6EDE9FF
+ E1F6F3FFD6EBE8FFD4E7E4FFEFFFFFFFD4E5E2FF667773FF1E2E27FF3E4D45FF
+ 7F8E86FF889990FF8E9F96FFA1B2A9FF90A39AFF97AAA1FF95AAA1FF99AEA5FF
+ 97AFA5FF92AAA0FF8BA49AFF8CA59BFF92ABA1FF98B0A8FF90A7A2FF94ABA6FF
+ 96ADA8FF93AAA5FF91A7A2FF92A8A3FF9AAEA9FF9FB3AEFF9CB0ABFFA2B6B1FF
+ A8B9B5FFA7B8B4FFA9B8B4FFABBAB6FFA8B7B3FFA0B1ADFF95A8A5FFA5BAB7FF
+ CCE1DEFFB3C8C5FFB7CCC9FFB1C6C3FFA7BCB9FF9BB0ADFF92A7A4FF91A6A3FF
+ 8A9F9CFF7E9390FF778C89FF768B88FF758A87FF728784FF758786FF5F7170FF
+ 526463FF667675FF445552FF162724FF233430FF283733FF2B3B34FF32403AFF
+ 3A4842FF3F4E46FFBDD2CFFFB2C7C4FFADC2BFFFAABFBCFF9BB0ADFF8DA29FFF
+ 98ADAAFFB0C5C2FF9FB4B1FFB1C6C3FFB4C9C6FFB0C5C2FFB4C9C6FFB4C9C6FF
+ B3C8C5FFBBD2CEFFB5CCC8FFAEC7C3FFACC3BFFFA9C0BCFFA1B8B4FF99B0ACFF
+ 9CB1AEFFA5BAB7FFAABDBAFF9EB1AEFFA1B4B1FF9CAFACFF9BACA9FF899A97FF
+ 6D7E7BFF7D8E8BFF7F8D8BFF808E8CFF7E8C8AFF7B8987FF778885FF788986FF
+ 7A8B88FF7A8B88FF849794FF829592FF809592FF829794FF849996FF859A97FF
+ 859C98FF869D99FF7E928DFF849893FF8FA39EFF95A9A4FF94A8A3FF96AAA5FF
+ A5B9B4FFB8CCC7FFA7BBB6FFA6BAB5FFA5B9B4FFB2C6C1FFBED2CDFFB3C7C2FF
+ A9BDB8FFB4C8C3FFB7C5C3FFB5C3C1FFB2C0BEFFAFBDBBFFAAB8B6FFA9B7B5FF
+ ABB9B7FFAFBDBBFFA4B2B0FFA2B0AEFFA3B1AFFFA7B5B3FFA7B5B3FFA0AEACFF
+ 98A6A4FF94A2A0FF6A7975FF768581FF7F8E8AFF7E8D89FF7D8C88FF84938FFF
+ 8D9C98FF93A29EFF9BAAA6FF96A5A1FF92A19DFF91A09CFF8D9C98FF899894FF
+ 8B9A96FF919F9BFF9FA5A0FF999F9AFF9AA19EFF949F9CFF8C9B97FF94A8A3FF
+ C0D5D2FFD2EBE7FFD1EAE6FFD0E9E5FF607674FF708281FF6A797BFF7C888AFF
+ 7F888BFF828C8CFF838F8FFF818E8CFF7D8A88FF7A8785FF798684FF798684FF
+ 768381FF73807EFF798684FF73807EFF73807EFF798684FF7D8A88FF7A8785FF
+ 758280FF73807EFF808D8BFF808D8BFF7E8B89FF7A8785FF788583FF7A8785FF
+ 808D8BFF869391FF8A9795FF93A09EFF97A4A2FF909D9BFF859290FF7F8C8AFF
+ 7C8987FF798684FF7E8987FF8A9593FF8C9997FF859290FF859290FF8A9795FF
+ 849290FF778583FF798A87FF98A9A6FFABBCB9FFA8B9B6FF607370FF93A6A3FF
+ 91A4A1FF96A9A6FF8B9E9BFF91A4A1FF9AADAAFF9FB2AFFFA0B1AEFF9BACA9FF
+ 95A6A3FF92A3A0FF8E9C9AFF8E9C9AFF8A9795FF84918FFF859290FF8A9795FF
+ 899492FF818C8AFF737E7BFF495451FF4D5855FF6A7572FF7A8582FF848F8CFF
+ 939E9BFF8E9996FF97A29FFF97A29FFF99A4A1FF9CA7A4FF9EA9A6FF9EA9A6FF
+ 9CA7A4FF9AA5A2FFA2B0ACFFA6B4B0FFA8B6B2FFA5B3AFFF9DABA7FF96A4A0FF
+ 92A09CFF919F9BFF99A7A3FF9DABA7FFA2B0ACFF9FADA9FF95A39FFF9DABA7FF
+ C4D2CEFFECFDFAFFE7FDFBFFE3FBF9FFE1F9F7FFDCF4F2FFD0E8E6FFC9E1DFFF
+ D2EAE8FFE0F8F6FFD4ECEAFFD2EAE8FFCBE3E1FFBBD3D1FFA4BCBAFF98B0AEFF
+ A3BBB9FFB7CFCDFFAAC5C1FFBCD7D3FFD1ECE8FFDDF8F4FFE7FFFCFFEAFFFFFF
+ E6FDF9FFDCF3EFFFE2F9F5FFECFFFFFFE7FCF9FFD5EAE7FFD2E7E4FFE0F5F2FF
+ DEF1EEFFCBDCD8FF475750FF1B2B24FF596962FF8F9F98FF92A29BFF9CAEA7FF
+ 9BADA6FFA0B2ABFF9BB0A8FF9EB3ABFF9EB5ADFF9CB3ABFF96ADA5FF95ACA4FF
+ 9CB3ABFFA4BBB3FF96ACA7FF99AFAAFF9EB4AFFFA0B6B1FF9EB4AFFF9BB1ACFF
+ 9DB1ACFFA0B4AFFFA0B1ADFFA6B7B3FFABBAB6FFAAB9B5FFAAB9B5FFABBAB6FF
+ A8B7B3FFA0B1ADFF97AAA7FFA1B6B3FFC4D9D6FFAABFBCFFAFC4C1FFA9BEBBFF
+ A1B6B3FF98ADAAFF96ABA8FF8FA4A1FF839895FF778C89FF738885FF738885FF
+ 6D827FFF657A77FF6A7F7DFF5E7371FF4D625FFF4A5D5AFF324542FF1C2F2CFF
+ 253934FF293A36FF2A3B37FF32423BFF394942FF3D4D46FFB9CECBFFB4C9C6FF
+ B1C6C3FFAEC3C0FFA2B7B4FF93A8A5FF93A8A5FF9CB1AEFFA9BEBBFFB4C9C6FF
+ ADC2BFFFA4B9B6FFAABFBCFFB0C5C2FFB7CCC9FFC2D9D5FFB9D0CCFFAEC7C3FF
+ ADC4C0FFAEC5C1FFA8BFBBFF9DB4B0FF9EB3B0FFA5BAB7FFA4B7B4FF99ACA9FF
+ 9EB1AEFF9AADAAFF9AABA8FF879895FF6A7B78FF798A87FF7D8B89FF82908EFF
+ 83918FFF808E8CFF7B8C89FF7C8D8AFF7C8D8AFF798A87FF8A9D9AFF869996FF
+ 859A97FF8A9F9CFF8CA19EFF899E9BFF879E9AFF889F9BFF869A95FF8A9E99FF
+ 8FA39EFF91A5A0FF93A7A2FF98ACA7FF9FB3AEFFA5B9B4FFAEC2BDFFABBFBAFF
+ A5B9B4FFAFC3BEFFBCD0CBFFB2C6C1FFA3B7B2FFA5B9B4FFBCCAC8FFB6C4C2FF
+ B1BFBDFFADBBB9FFA9B7B5FFA6B4B2FFABB9B7FFB2C0BEFFA9B7B5FF9FADABFF
+ 9CAAA8FFA4B2B0FFA8B6B4FFA0AEACFF99A7A5FF98A6A4FF677672FF74837FFF
+ 7D8C88FF7A8985FF758480FF7A8985FF859490FF8C9B97FF94A39FFF91A09CFF
+ 91A09CFF93A29EFF91A09CFF8C9B97FF8A9995FF8D9B97FF9FA6A1FF9BA19CFF
+ 9EA5A2FF9DA8A5FF96A5A1FF8CA09BFFC1D6D3FFD7EEEAFFCDE4E0FFC0D7D3FF
+ 5E7371FF596B6AFF606F71FF7B888AFF7A8688FF788282FF7C8888FF7E8B89FF
+ 7D8A88FF7C8987FF7E8B89FF818E8CFF7F8C8AFF7A8785FF788583FF74817FFF
+ 768381FF7D8A88FF818E8CFF7C8987FF778482FF758280FF808D8BFF818E8CFF
+ 808D8BFF7D8A88FF798684FF7A8785FF808D8BFF869391FF7B8886FF84918FFF
+ 8A9795FF889593FF84918FFF84918FFF84918FFF818E8CFF7E8987FF879290FF
+ 899694FF859290FF859290FF889593FF83918FFF798785FF70817EFF899A97FF
+ 9AABA8FFA1B2AFFF526562FF93A6A3FF9BAEABFFA6B9B6FFA7BAB7FFA5B8B5FF
+ A2B5B2FF9EB1AEFF9CADAAFF96A7A4FF91A29FFF8E9F9CFF98A6A4FF9CAAA8FF
+ 99A6A4FF919E9CFF909D9BFF95A2A0FF939E9CFF899492FF697471FF4E5956FF
+ 636E6BFF76817EFF7B8683FF75807DFF8E9996FF919C99FF9AA5A2FF98A3A0FF
+ 98A3A0FF9CA7A4FFA2ADAAFFA3AEABFF9EA9A6FF98A3A0FF94A29EFF96A4A0FF
+ 99A7A3FF9CAAA6FF9EACA8FF9FADA9FF9FADA9FF9EACA8FF9EACA8FF9CAAA6FF
+ A2B0ACFFA8B6B2FF9CAAA6FF95A39FFFAFBDB9FFD6E5E1FFEDFFFFFFEAFFFFFF
+ EBFFFFFFDFF7F5FFD4ECEAFFD0E8E6FFD4ECEAFFDAF2F0FFE3FBF9FFDEF6F4FF
+ D5EDEBFFBFD7D5FF9FB7B5FF89A19FFF90A8A6FFA5BDBBFF9AB5B1FFA9C4C0FF
+ B9D4D0FFC5E0DCFFD7F0ECFFE7FFFCFFEBFFFEFFE4FBF7FFDDF4F0FFE8FFFBFF
+ DEF3F0FFD8EDEAFFE2F7F4FFD5EAE7FFCEE3E0FFE8FCF7FFADBEBAFF36463FFF
+ 384841FF899992FF9AACA5FF8C9E97FF8EA099FF9EB0A9FF9AAFA7FF9CB1A9FF
+ 9EB5ADFFA0B7AFFF9CB3ABFF99B0A8FF9EB5ADFFA7BEB6FF98AEA9FF98AEA9FF
+ 9CB2ADFFA3B9B4FFA3B9B4FF9EB4AFFF9CB0ABFF9CB0ABFF9FB0ACFFA4B5B1FF
+ A9B8B4FFA7B6B2FFA8B7B3FFAAB9B5FFA8B7B3FFA1B2AEFF9AADAAFF99AEABFF
+ B6CBC8FFA0B5B2FFA7BCB9FF9FB4B1FF9DB2AFFF9DB2AFFF90A5A2FF899E9BFF
+ 7B908DFF708582FF6E8380FF6D827FFF647976FF596E6BFF5D726FFF5A6F6CFF
+ 4C615EFF3C514EFF394E4BFF435855FF536762FF5B6F6AFF6D817CFF738480FF
+ 788A83FF7A8C85FFB5CAC7FFB4C9C6FFB3C8C5FFB0C5C2FFABC0BDFFA3B8B5FF
+ 9AAFACFF94A9A6FFA1B6B3FFAEC3C0FFAABFBCFFA0B5B2FFA3B8B5FFA8BDBAFF
+ AFC4C1FFBCD3CFFFB7CECAFFA8C1BDFFA4BBB7FFA8BFBBFFA7BEBAFFA0B7B3FF
+ A1B6B3FFA9BEBBFF9EB1AEFF91A4A1FF96A9A6FF99ACA9FFA2B3B0FF92A3A0FF
+ 728380FF7C8D8AFF748280FF7E8C8AFF859391FF83918FFF7F908DFF81928FFF
+ 7F908DFF798A87FF8A9D9AFF859895FF859A97FF8EA3A0FF91A6A3FF8DA29FFF
+ 889F9BFF89A09CFF91A5A0FF94A8A3FF91A5A0FF8DA19CFF92A6A1FF9CB0ABFF
+ 9BAFAAFF91A5A0FFA3B7B2FFA6BAB5FFA4B8B3FFABBFBAFFBBCFCAFFB7CBC6FF
+ AABEB9FFA9BDB8FFB9C7C5FFB3C1BFFFAFBDBBFFAEBCBAFFAAB8B6FFA5B3B1FF
+ A8B6B4FFB0BEBCFFADBBB9FF9FADABFF9AA8A6FFA2B0AEFFA3B1AFFF99A7A5FF
+ 94A2A0FF99A7A5FF667571FF758480FF7E8D89FF798884FF72817DFF768581FF
+ 82918DFF8B9A96FF8B9A96FF899894FF8B9A96FF91A09CFF92A19DFF8D9C98FF
+ 8B9A96FF8D9B97FF9DA49FFF969D98FF98A19EFF9BA9A5FF9BAAA6FF869A95FF
+ C5DAD7FFDDF4F0FFC9E0DCFFC0D7D3FF8CA19FFF6D7F7EFF677678FF798688FF
+ 788486FF768282FF758181FF7B8886FF7D8A88FF7D8A88FF808D8BFF859290FF
+ 828F8DFF7A8785FF7A8785FF778482FF778482FF7C8987FF7D8A88FF798684FF
+ 778482FF788583FF798684FF7E8B89FF828F8DFF818E8CFF7D8A88FF7A8785FF
+ 7C8987FF7F8C8AFF74817FFF798684FF7A8785FF788583FF7B8886FF83908EFF
+ 879492FF869391FF7F8A88FF838E8CFF84918FFF859290FF859290FF859290FF
+ 818F8DFF7E8C8AFF748582FF899A97FF98A9A6FFA2B3B0FF485B58FF8B9E9BFF
+ 93A6A3FF9EB1AEFFA8BBB8FFA5B8B5FFA3B6B3FFA1B4B1FFA0B1AEFF99AAA7FF
+ 8E9F9CFF869794FF96A4A2FF9CAAA8FF9BA8A6FF929F9DFF919E9CFF96A3A1FF
+ 95A09EFF899492FF687370FF4C5754FF66716EFF75807DFF7C8784FF727D7AFF
+ 909B98FF939E9BFF97A29FFF98A3A0FF9BA6A3FF9EA9A6FFA1ACA9FFA0ABA8FF
+ 9DA8A5FF9AA5A2FF8B9995FF899793FF889692FF8E9C98FF97A5A1FF9EACA8FF
+ A0AEAAFF9FADA9FF9FADA9FF9CAAA6FF9EACA8FFA4B2AEFFA2B0ACFF9EACA8FF
+ A5B3AFFFB2C1BDFFE3F6F3FFE8FFFBFFEBFFFDFFE6FDF9FFE6FDF9FFE8FFFBFF
+ E0F7F3FFD4EBE7FFE4FDF9FFE0F9F5FFDEF7F3FFD4EDE9FFB6D1CDFF99B4B0FF
+ 93AEAAFF9CB7B3FFB4CDC9FFB4CDC9FFADC6C2FFAAC3BFFFBED5D1FFDAF1EDFF
+ E8FFFBFFE6FDF9FFD9F0ECFFDCF3EFFFD6EDE9FFD9F0ECFFE2F9F5FFD5ECE8FF
+ CAE1DDFFD6ECE7FFE8F9F5FF889A93FF475952FF72847DFF94A69FFF7C8E87FF
+ 7A8F87FF8FA49CFF93A8A0FF93A8A0FF97ACA4FF9DB2AAFF9CB1A9FF96ABA3FF
+ 99AEA6FFA0B5ADFF9AB0ABFF94AAA5FF96AAA5FF9FB3AEFFA3B7B2FF9EB2ADFF
+ 9BACA8FF9AABA7FF9BAAA6FFA0AFABFFA2B1ADFFA1B0ACFFA4B2AEFFA9B7B3FF
+ AAB8B4FFA6B5B1FFA6B7B3FF9BAFAAFFB5C9C4FFAABEB9FFB7CBC6FFB1C5C0FF
+ B8CCC7FFC6DAD5FFB3C7C2FFB0C4BFFFA7BBB6FF9DB1ACFF97ABA6FF95A9A4FF
+ 8EA29DFF839994FF768C87FF778E89FF738A85FF6A817CFF748B86FF839A95FF
+ 8AA09BFF97ADA8FF95ABA6FF9AAEA9FF9EB2ADFF9FB3AEFFB3C8C5FFB3C8C5FF
+ AFC4C1FFACC1BEFFAEC3C0FFB0C5C2FFA8BDBAFF9CB1AEFF97ACA9FFACC1BEFF
+ B2C7C4FFABC0BDFFAABFBCFFA8BDBAFFAABFBCFFB5CCC8FFB2C9C5FF9FB8B4FF
+ 99B0ACFF9FB6B2FFA2B9B5FF9EB5B1FFA1B6B3FFABC0BDFFA8BBB8FF95A8A5FF
+ 96A9A6FF9BAEABFFA8B9B6FF98A9A6FF71827FFF748582FF6B7977FF798785FF
+ 83918FFF83918FFF81928FFF829390FF80918EFF798A87FF7F928FFF7A8D8AFF
+ 7B908DFF879C99FF8CA19EFF879C99FF819894FF829995FF8A9E99FF8EA29DFF
+ 8B9F9AFF879B96FF95A9A4FFA9BDB8FFA6BAB5FF94A8A3FF889C97FF95A9A4FF
+ 99ADA8FFA2B6B1FFB5C9C4FFBACEC9FFB3C7C2FFB3C7C2FFB5C3C1FFB0BEBCFF
+ AEBCBAFFAFBDBBFFABB9B7FFA4B2B0FFA5B3B1FFADBBB9FFADBBB9FF9EACAAFF
+ 9AA8A6FFA0AEACFF9CAAA8FF8F9D9BFF8D9B99FF97A5A3FF687773FF778682FF
+ 81908CFF7B8A86FF73827EFF778682FF84938FFF8E9D99FF98A7A3FF94A39FFF
+ 93A29EFF96A5A1FF94A39FFF8D9C98FF889793FF899793FF919B95FF8A918CFF
+ 8B9491FF909E9AFF94A39FFF7D8E8AFFC3D6D3FFDCF1EEFFD9EEEBFFE1F6F3FF
+ DAEFEDFFA2B4B3FF7C8B8DFF738284FF727F81FF778383FF798585FF808D8BFF
+ 83908EFF828F8DFF859290FF899694FF84918FFF7A8785FF7D8A88FF798684FF
+ 778482FF798684FF778482FF74817FFF758280FF798684FF717E7CFF798684FF
+ 818E8CFF83908EFF7E8B89FF788583FF768381FF778482FF879492FF84918FFF
+ 7C8987FF74817FFF74817FFF7A8785FF7E8B89FF7C8987FF7A8583FF7A8583FF
+ 7A8785FF7F8C8AFF7F8C8AFF7C8987FF7A8886FF7B8987FF94A5A2FFA6B7B4FF
+ B3C4C1FFBBCCC9FF506360FF889B98FF849794FF889B98FF849794FF899C99FF
+ 94A7A4FFA1B4B1FFABBCB9FFA6B7B4FF97A8A5FF899A97FF8C9A98FF95A3A1FF
+ 96A3A1FF8D9A98FF8D9A98FF94A19FFF949F9DFF889391FF6A7572FF3F4A47FF
+ 4F5A57FF5E6966FF76817EFF737E7BFF919C99FF8C9794FF939E9BFF98A3A0FF
+ 9EA9A6FFA0ABA8FF9EA9A6FF9CA7A4FF9BA6A3FF9CA7A4FFA0AEAAFF97A5A1FF
+ 8E9C98FF8D9B97FF92A09CFF95A39FFF92A09CFF8E9C98FF9DABA7FF9BA9A5FF
+ 98A6A2FF9AA8A4FFA2B0ACFFA8B6B2FFA2B0ACFF96A5A1FFB7CAC7FFDBF0EDFF
+ EDFFFFFFEDFFFFFFE3F8F5FFE0F7F3FFE1F8F4FFDDF4F0FFCFE6E2FFCFE8E4FF
+ D9F2EEFFE3FCF8FFD5F0ECFFBAD5D1FFABC6C2FFACC7C3FFD3ECE8FFCFE8E4FF
+ C3DCD8FFBBD4D0FFCAE1DDFFE1F8F4FFE8FFFBFFE0F7F3FFE0F7F3FFDDF4F0FF
+ DDF4F0FFDBF2EEFFD6EDE9FFD9F0ECFFD8EFEBFFCCE3DFFFD6EAE5FFCBDDD6FF
+ 6C7E77FF5B6D66FF869891FF7B8D86FF7A8F87FF8CA199FF91A69EFF8FA49CFF
+ 93A8A0FF9BB0A8FF9BB0A8FF95AAA2FF94A9A1FF9AAFA7FFA3B7B2FF96ACA7FF
+ 95A9A4FF9EB2ADFFA5B9B4FFA1B5B0FF9EAFABFF9DAEAAFF95A4A0FF99A8A4FF
+ 9CABA7FF9CABA7FFA1AFABFFA8B6B2FFABB9B5FFA8B7B3FF93A4A0FF819590FF
+ 9DB1ACFF9CB0ABFFB0C4BFFFAEC2BDFFBDD1CCFFD5E9E4FFD1E5E0FFD4E8E3FF
+ D0E4DFFFC5D9D4FFBCD0CBFFB8CCC7FFB4C8C3FFAFC3BEFFABC1BCFFACC3BEFF
+ B0C7C2FFADC4BFFFB4CBC6FFB0C7C2FFA1B8B3FFACC3BEFFADC3BEFFB0C6C1FF
+ B3C9C4FFB3CAC5FFC2D7D4FFC1D6D3FFB9CECBFFADC2BFFFA6BBB8FFA6BBB8FF
+ A4B9B6FFA0B5B2FFA0B5B2FFABC0BDFFB7CCC9FFB6CBC8FFA8BDBAFF9FB4B1FF
+ A8BDBAFFB7CECAFFA7BEBAFF9FB8B4FF9FB6B2FFA1B8B4FFA2B9B5FFA2B9B5FF
+ A6BBB8FFACC1BEFFA3B6B3FF9BAEABFF9EB1AEFFA3B6B3FFA3B4B1FF9EAFACFF
+ 869794FF61726FFF6D7B79FF7C8A88FF859391FF808E8CFF7C8D8AFF839491FF
+ 879895FF839491FF8FA29FFF899C99FF839895FF859A97FF8CA19EFF91A6A3FF
+ 90A7A3FF8DA4A0FF80948FFF829691FF90A49FFF8EA29DFF869A95FF9EB2ADFF
+ B4C8C3FFA9BDB8FF9AAEA9FF93A7A2FF9CB0ABFFADC1BCFFACC0BBFF9EB2ADFF
+ A3B7B2FFB7CBC6FFBBC9C7FFABB9B7FFA7B5B3FFB2C0BEFFB2C0BEFFA3B1AFFF
+ 9EACAAFFA6B4B2FFABB9B7FFA9B7B5FFA5B3B1FF9EACAAFF97A5A3FF94A2A0FF
+ 94A2A0FF96A4A2FF62706CFF62706CFF808E8AFF74827EFF798783FF8E9C98FF
+ 788682FF7E8C88FF8C9A96FF93A19DFF94A29EFF909E9AFF8E9C98FF909E9AFF
+ 8E9C98FF899793FF99A39DFF939D97FF8E9996FF8C9A96FF8A9995FF8E9F9BFF
+ A0B3B0FFB5C8C5FFD9ECE9FFEEFFFEFFE3F5F4FFD7E9E8FFADBCBEFF879698FF
+ 8A999BFF717F7EFF798585FF788583FF7A8785FF808D8BFF879492FF889593FF
+ 83908EFF7D8A88FF798684FF7E8B89FF818E8CFF7C8987FF73807EFF6F7C7AFF
+ 727F7DFF778482FF798684FF758280FF788583FF818E8CFF83908EFF7C8987FF
+ 74817FFF717E7CFF828F8DFF7C8987FF74817FFF6D7A78FF6C7977FF707D7BFF
+ 768381FF7A8785FF7E8987FF76817FFF73807EFF7D8A88FF83908EFF818E8CFF
+ 7E8C8AFF818F8DFF849592FF8D9E9BFFA9BAB7FFB9CAC7FF94A7A4FF5E716EFF
+ 9DB0ADFF97AAA7FF95A8A5FF91A4A1FF91A4A1FF98ABA8FFA4B5B2FFA7B8B5FF
+ A0B1AEFF97A8A5FF95A3A1FF92A09EFF95A2A0FF9AA7A5FF98A5A3FF8F9C9AFF
+ 8A9593FF889391FF6D7875FF46514EFF414C49FF5F6A67FF6F7A77FF75807DFF
+ 838E8BFF919C99FF919C99FF97A29FFF9DA8A5FF9FAAA7FF9DA8A5FF9BA6A3FF
+ 9EA9A6FFA1ACA9FFA1AFABFF9EACA8FF9AA8A4FF98A6A2FF97A5A1FF96A4A0FF
+ 93A19DFF919F9BFF9CAAA6FF9DABA7FF9DABA7FF9AA8A4FF97A5A1FF98A6A2FF
+ 9EACA8FFA2B1ADFF93A4A1FFB1C4C1FFD8EBE8FFEDFFFDFFEBFEFBFFE0F5F2FF
+ DCF1EEFFDDF4F0FFD9F0ECFFCEE5E1FFD3ECE8FFD4EDE9FFE0FBF7FFC9E4E0FF
+ A1BCB8FFC9E4E0FFD1EAE6FFD4EBE7FFD8EFEBFFDDF4F0FFE2F9F5FFE4FBF7FF
+ E1F8F4FFDFF6F2FFD9F0ECFFD4EBE7FFD8EFEBFFD8EFEBFFCFE8E4FFD3ECE8FF
+ D6EFEBFFCDE4E0FFCBDFDAFFCDE1DCFFA5B9B4FF445853FF728681FF80948FFF
+ 70847FFF849893FF849893FF899D98FF90A19DFF92A39FFF92A39FFF97A8A4FF
+ A2B3AFFFA9BDB8FFA2B6B1FF9EB2ADFF9CB0ABFF9DB1ACFF9DAEAAFF99AAA6FF
+ 9BAAA6FF9FAEAAFF9DACA8FF9CABA7FF99A7A3FF96A4A0FF9CA7A4FFA5B0ADFF
+ ABB6B3FFAAB8B4FF93A39CFF74867FFF7C8E87FF788A83FF7F918AFF8B9D96FF
+ 80928BFF97A9A2FFABBDB6FFBBCDC6FFCFE1DAFFD9EBE4FFD5E7E0FFCCDED7FF
+ C4D6CFFFBFD4CCFFBFD6CEFFB6CEC6FFBBD3CBFFBED6CEFFB5CCC7FFB5CCC7FF
+ BCD3CEFFB9D0CBFFBBD2CDFFBBD2CDFFBAD1CCFFB7D1CBFFBDD2CFFFBED3D0FF
+ B9CECBFFAFC4C1FFA7BCB9FFA3B8B5FF9DB2AFFF96ABA8FFA4B9B6FFADC2BFFF
+ B8CDCAFFB8CDCAFFADC2BFFFA4B9B6FFABC0BDFFB8CFCBFFA3BAB6FF9BB4B0FF
+ 99B0ACFF9BB2AEFF9DB4B0FF9DB4B0FFA3B8B5FFAABFBCFFA7BAB7FF9EB1AEFF
+ 9BAEABFF9AADAAFF9DAEABFFA0B1AEFF8C9D9AFF667774FF697775FF748280FF
+ 7C8A88FF7D8B89FF7B8C89FF7F908DFF839491FF849592FF8FA29FFF8A9D9AFF
+ 839895FF849996FF899E9BFF8FA4A1FF91A8A4FF91A8A4FF93A7A2FF899D98FF
+ 8CA09BFF90A49FFF8A9E99FF91A5A0FFA8BCB7FFB8CCC7FFB1C5C0FF98ACA7FF
+ 8DA19CFF9BAFAAFFA4B8B3FF9EB2ADFF9CB0ABFFA3B7B2FFBAC8C6FFB6C4C2FF
+ B2C0BEFFAEBCBAFFA9B7B5FFA7B5B3FFA9B7B5FFADBBB9FFAFBDBBFFADBBB9FF
+ A8B6B4FFA0AEACFF97A5A3FF92A09EFF919F9DFF92A09EFF6E7C78FF5E6C68FF
+ 788682FF72807CFF778581FF8A9894FF768480FF818F8BFF879591FF8F9D99FF
+ 97A5A1FF98A6A2FF93A19DFF8E9C98FF8D9B97FF929D9AFF909C96FF8E9A94FF
+ 8E9996FF909E9AFF919F9BFF94A39FFFA1B2AFFFB0C3C0FFBDD0CDFFDBEEEBFF
+ D7E9E8FFD4E6E5FFBFCED0FF9CABADFF94A3A5FF7F8F8EFF818F8EFF808D8BFF
+ 808D8BFF828F8DFF859290FF869391FF84918FFF828F8DFF7C8987FF7F8C8AFF
+ 808D8BFF7C8987FF758280FF727F7DFF73807EFF768381FF74817FFF717E7CFF
+ 717E7CFF768381FF7D8A88FF7D8A88FF73807EFF687573FF758280FF758280FF
+ 758280FF758280FF758280FF758280FF74817FFF74817FFF7F8A88FF778280FF
+ 74817FFF7C8987FF828F8DFF828F8DFF808E8CFF82908EFF859693FF8A9B98FF
+ A5B6B3FFB0C1BEFF9FB2AFFF718481FF8EA19EFF91A4A1FF97AAA7FF8FA29FFF
+ 8A9D9AFF90A3A0FF9DAEABFFA1B2AFFF9AABA8FF91A29FFF8F9D9BFF8C9A98FF
+ 909D9BFF97A4A2FF96A3A1FF869391FF747F7DFF687371FF606B68FF3A4542FF
+ 36413EFF55605DFF687370FF707B78FF808B88FF8D9895FF919C99FF929D9AFF
+ 949F9CFF97A29FFF9AA5A2FF9CA7A4FF9CA7A4FF9BA6A3FFA3B1ADFFA0AEAAFF
+ 9CAAA6FF9AA8A4FF99A7A3FF97A5A1FF94A29EFF919F9BFF94A29EFF95A39FFF
+ 97A5A1FF97A5A1FF96A4A0FF96A4A0FF98A6A2FF9AA8A4FF909E9CFF9FB0ADFF
+ BBCCC9FFD6E9E6FFEAFDFAFFEFFFFFFFE9FCF9FFDFF4F1FFE6FDF9FFCEE5E1FF
+ DEF7F3FFDFF8F4FFD2EDE9FFCAE5E1FFBBD6D2FFCDE8E4FFD9F0ECFFDAF1EDFF
+ DDF4F0FFE1F8F4FFE4FBF7FFE3FAF6FFDFF6F2FFDBF2EEFFD9F0ECFFD2E9E5FF
+ D7EEEAFFD6EFEBFFCEE7E3FFCFE8E4FFD0E9E5FFC5DEDAFFC4DAD5FFC4D8D3FF
+ A3B7B2FF617570FF768A85FF839792FF728681FF849893FF7F938EFF819590FF
+ 869793FF889995FF8C9D99FF92A39FFF9BACA8FFA1B2AEFF91A29EFF91A5A0FF
+ 98ACA7FF9DB1ACFF9DAEAAFF99AAA6FF9DACA8FFA3B2AEFF99A8A4FF9AA9A5FF
+ 98A6A2FF8F9D99FF8B9693FF8C9794FF929D9AFF96A4A0FF9BABA4FF7C8E87FF
+ 80928BFF7E9089FF869891FF8FA19AFF83958EFF93A59EFF80928BFF91A39CFF
+ AABCB5FFC2D4CDFFD1E3DCFFD6E8E1FFD4E6DFFFD0E5DDFFCDE4DCFFC4DCD4FF
+ C7DED6FFC4DCD4FFBDD4CFFFC3DAD5FFCCE3DEFFC7DED9FFBDD4CFFFBDD4CFFF
+ BAD4CEFFBAD4CEFFB9CECBFFBDD2CFFFBCD1CEFFB5CAC7FFAFC4C1FFA9BEBBFF
+ A1B6B3FF98ADAAFFA5BAB7FFABC0BDFFB4C9C6FFB8CDCAFFB1C6C3FFAABFBCFF
+ AEC3C0FFB7CECAFFAFC6C2FFA4BDB9FF9FB6B2FF9CB3AFFF9AB1ADFF98AFABFF
+ 9DB2AFFFA3B8B5FFA9BCB9FFA3B6B3FF9EB1AEFF96A9A6FF9AABA8FFA7B8B5FF
+ 99AAA7FF738481FF6A7876FF6E7C7AFF778583FF7F8D8BFF7F908DFF7E8F8CFF
+ 829390FF899A97FF8B9E9BFF889B98FF839895FF829794FF859A97FF8A9F9CFF
+ 8EA5A1FF91A8A4FFA3B7B2FF93A7A2FF899D98FF91A5A0FF91A5A0FF839792FF
+ 97ABA6FFC5D9D4FFB9CDC8FF9DB1ACFF8B9F9AFF93A7A2FFA0B4AFFFA2B6B1FF
+ A3B7B2FFA9BDB8FFB0BEBCFFBAC8C6FFBBC9C7FFB0BEBCFFA9B7B5FFACBAB8FF
+ ADBBB9FFA9B7B5FFAEBCBAFFACBAB8FFA7B5B3FFA0AEACFF98A6A4FF93A19FFF
+ 92A09EFF92A09EFF6E7C78FF4A5552FF606B68FF67726FFF6F7A77FF7E8986FF
+ 6E7976FF7E8986FF7A8582FF7F8A87FF8C9794FF949F9CFF8D9895FF808B88FF
+ 818C89FF8C9794FF8B9791FF8B9791FF8F9A97FF919F9BFF93A19DFF94A39FFF
+ 9DABA9FFA5B6B3FFADBEBBFFD2E3E0FFCEE0DFFFCFE1E0FFCEE0E1FFAFC1C2FF
+ 9CAEAFFF95A5A4FF8C9A99FF8D9A98FF8B9896FF889593FF859290FF84918FFF
+ 859290FF879492FF7F8C8AFF7F8C8AFF7D8A88FF7B8886FF788583FF768381FF
+ 74817FFF74817FFF788583FF788583FF758280FF768381FF808D8BFF889593FF
+ 7D8A88FF6A7775FF707D7BFF717E7CFF727F7DFF74817FFF758280FF768381FF
+ 768381FF768381FF808B89FF798482FF758280FF7C8987FF828F8DFF83908EFF
+ 82908EFF83918FFF96A7A4FF99AAA7FFB2C3C0FFB4C5C2FFBDD0CDFF9BAEABFF
+ 899C99FFA0B3B0FF98ABA8FF8FA29FFF889B98FF8A9D9AFF96A7A4FF9BACA9FF
+ 98A9A6FF92A3A0FF8D9B99FF889694FF8A9795FF94A19FFF96A3A1FF899694FF
+ 76817FFF687371FF57625FFF323D3AFF2D3835FF4A5552FF5B6663FF646F6CFF
+ 747F7CFF808B88FF929D9AFF8F9A97FF8D9895FF929D9AFF99A4A1FF9DA8A5FF
+ 9BA6A3FF98A3A0FF9FADA9FF9EACA8FF9CAAA6FF9CAAA6FF9CAAA6FF9BA9A5FF
+ 98A6A2FF95A39FFF909E9AFF919F9BFF92A09CFF95A39FFF97A5A1FF98A6A2FF
+ 96A4A0FF94A29EFF9BA9A5FF97A6A2FF99A8A4FFA6B7B3FFBECFCBFFD2E6E1FF
+ E0F4EFFFE2F8F3FFECFFFEFFD6EDE8FFEAFFFEFFE6FFFAFFC1DDD7FFC7E3DDFF
+ CFEEE7FFCFEBE5FFE0F7F3FFE2F7F4FFE4F9F6FFE6FBF8FFE7FCF9FFE4F9F6FF
+ DDF4F0FFD8EFEBFFD9F0ECFFD2E9E5FFD4EDE9FFD8F1EDFFD0E9E5FFCCE7E3FF
+ CAE5E1FFC1DAD6FFC2D7D4FFBCD1CEFFA3B8B5FF839895FF6E8380FF829794FF
+ 758885FF7D908DFF829390FF829390FF81928FFF829390FF879593FF8D9B99FF
+ 93A19FFF95A6A3FF9CADA9FF99AAA6FF96A7A3FF93A4A0FF8E9D99FF8C9B97FF
+ 95A4A0FFA1B0ACFF9AA8A4FF9DABA7FF9EA9A6FF949F9CFF85908DFF7F8A87FF
+ 89928FFF919C99FF96A69FFF7F918AFF81938CFF82948DFF8A9C95FF90A29BFF
+ 869891FF90A29BFF889A93FF889A93FF8D9F98FF99ABA4FFADBFB8FFC1D3CCFF
+ D1E3DCFFD9EBE4FFD5EAE1FFD0E8DEFFD3E8DFFFCAE2D8FFC1D8D0FFC9E0D8FF
+ CDE3DEFFBFD5D0FFC3DAD5FFC2D9D4FFC0D9D5FFC0D9D5FFB7CCC9FFBCD1CEFF
+ BDD2CFFFB9CECBFFB6CBC8FFB3C8C5FFACC1BEFFA5BAB7FFA2B7B4FFA5BAB7FF
+ ADC2BFFFB3C8C5FFB2C7C4FFADC2BFFFB1C6C3FFB7CECAFFB2C9C5FFA7C0BCFF
+ A0B7B3FF9CB3AFFF99B0ACFF97AEAAFF9DB2AFFFA4B9B6FF9FB2AFFFA2B5B2FF
+ A2B5B2FF97AAA7FF95A6A3FFA3B4B1FF9BACA9FF788986FF6B7977FF697775FF
+ 717F7DFF7F8D8BFF7F908DFF7A8B88FF7D8E8BFF879895FF839693FF849794FF
+ 829794FF819693FF809592FF829794FF869D99FF89A09CFFA0B4AFFF9AAEA9FF
+ 8DA19CFF92A6A1FF95A9A4FF819590FF8DA19CFFC2D6D1FFB5C9C4FFA9BDB8FF
+ A0B4AFFF9FB3AEFF9EB2ADFF9DB1ACFFA5B9B4FFB1C5C0FFA8B6B4FFB1BFBDFF
+ B9C7C5FFBAC8C6FFB6C4C2FFB0BEBCFFA7B5B3FF9FADABFFA6B4B2FFA6B4B2FF
+ A4B2B0FF9FADABFF99A7A5FF96A4A2FF95A3A1FF97A5A3FF6E7976FF35403DFF
+ 4B5653FF616C69FF6B7673FF76817EFF67726FFF798481FF737E7BFF6F7A77FF
+ 788380FF85908DFF808B88FF717C79FF717C79FF7F8A87FF89958FFF8A9690FF
+ 8A9894FF8C9A96FF8E9C98FF919F9BFF94A2A0FF98A6A4FFB0BEBCFFD4E5E2FF
+ D4E4E3FFCFE1E0FFD4E6E7FFB5C7C8FF97A9AAFF9FAFAEFF94A2A1FF97A4A2FF
+ 97A4A2FF919E9CFF889593FF84918FFF869391FF899694FF828F8DFF7E8B89FF
+ 7A8785FF798684FF7A8785FF798684FF758280FF717E7CFF7A8785FF818E8CFF
+ 808D8BFF7B8886FF83908EFF909D9BFF889593FF758280FF7A8785FF758280FF
+ 6F7C7AFF6A7775FF6C7977FF727F7DFF7A8785FF808D8BFF818C8AFF7C8785FF
+ 788583FF7C8987FF828F8DFF859290FF83918FFF82908EFFA3B4B1FFAABBB8FF
+ C1D2CFFFB9CAC7FFD3E6E3FFBCCFCCFF859895FFB5C8C5FF9CAFACFF96A9A6FF
+ 90A3A0FF8DA09DFF91A29FFF95A6A3FF98A9A6FF99AAA7FF98A6A4FF8F9D9BFF
+ 8B9896FF8D9A98FF8D9A98FF869391FF7E8987FF7A8583FF646F6CFF3F4A47FF
+ 37423FFF4D5855FF5B6663FF636E6BFF717C79FF7A8582FF919C99FF909B98FF
+ 8F9A97FF939E9BFF98A3A0FF9CA7A4FF9CA7A4FF9BA6A3FF98A6A2FF98A6A2FF
+ 99A7A3FF9CAAA6FF9FADA9FF9FADA9FF9CAAA6FF9AA8A4FF95A39FFF93A19DFF
+ 919F9BFF94A29EFF99A7A3FF9CAAA6FF99A7A3FF96A4A0FF9AA8A4FF96A4A0FF
+ 909E9AFF8C9B97FF909F9BFF9FB0ACFFB3C7C2FFC4D8D3FFE6FCF7FFE4FBF6FF
+ EAFFFEFFDFF9F3FFBEDAD4FFC4E0DAFFD2F1EAFFD3EFE9FFE6FBF8FFE8FBF8FF
+ E9FCF9FFE9FEFBFFE9FEFBFFE5FAF7FFDEF5F1FFD8EFEBFFDAF1EDFFCEE7E3FF
+ D3ECE8FFDAF3EFFFD2EDE9FFCEE9E5FFCBE6E2FFBFDAD6FFC0D7D3FFC0D5D2FF
+ A8BDBAFF9AAFACFF5C716EFF809592FF7D908DFF758885FF859693FF879895FF
+ 879895FF859693FF849290FF859391FF8B9997FF909E9CFF9CADA9FF97A8A4FF
+ 91A29EFF8D9E9AFF889793FF82918DFF84938FFF8B9A96FF98A6A2FF9AA8A4FF
+ 9CA7A4FF97A29FFF8C9794FF85908DFF8D9693FF949F9CFF84948DFF7A8C85FF
+ 7D8F88FF82948DFF889A93FF8A9C95FF899B94FF91A39CFF99ABA4FF91A39CFF
+ 879992FF84968FFF8B9D96FF9CAEA7FFAEC0B9FFBACDC4FFCCDFD6FFCEE3DAFF
+ D8EBE2FFD4E9E0FFD0E5DDFFDAF1E9FFDDF3EEFFCCE2DDFFCEE4DFFFCCE3DEFF
+ CAE1DDFFC7E0DCFFB6CBC8FFB9CECBFFB8CDCAFFB3C8C5FFB0C5C2FFB0C5C2FF
+ ADC2BFFFA8BDBAFF9FB4B1FFA2B7B4FFA9BEBBFFB0C5C2FFB1C6C3FFB0C5C2FF
+ B5CAC7FFBBD2CEFFA9C0BCFF9FB8B4FF9BB2AEFF9AB1ADFF9AB1ADFF9BB2AEFF
+ A3B8B5FFABC0BDFF94A7A4FF9FB2AFFFA7BAB7FF9DB0ADFF91A29FFF94A5A2FF
+ 8A9B98FF6C7D7AFF697775FF667472FF6C7A78FF798785FF7A8B88FF748582FF
+ 768784FF7F908DFF7C8F8CFF7E918EFF7F9491FF7F9491FF7E9390FF7E9390FF
+ 7E9591FF7F9692FF91A5A0FF9BAFAAFF95A9A4FF92A6A1FF95A9A4FF889C97FF
+ 8DA19CFFB1C5C0FFBFD3CEFFBBCFCAFFB5C9C4FFAEC2BDFFA6BAB5FFA1B5B0FF
+ A1B5B0FFA4B8B3FFB3C1BFFFAAB8B6FFAEBCBAFFBFCDCBFFC3D1CFFFB3C1BFFF
+ A5B3B1FFA2B0AEFFA4B2B0FFA4B2B0FFA3B1AFFF9FADABFF9AA8A6FF97A5A3FF
+ 96A4A2FF97A5A3FF7D8885FF35403DFF4E5956FF6F7A77FF76817EFF7A8582FF
+ 6A7572FF788380FF7B8683FF6F7A77FF6F7A77FF7B8683FF7C8784FF717C79FF
+ 707B78FF798481FF82908AFF82908AFF82908CFF83918DFF889692FF8E9C98FF
+ 929F9DFF92A09EFFA9B7B5FFCCDDDAFFDAEAE9FFD7E7E6FFD8EAEBFFB4C6C7FF
+ 879B9CFF92A4A3FF95A3A2FF9BA8A6FF9DAAA8FF98A5A3FF8D9A98FF869391FF
+ 869391FF899694FF84918FFF7F8C8AFF7A8785FF798684FF7B8886FF7B8886FF
+ 768381FF717E7CFF74817FFF818E8CFF83908EFF7B8886FF7E8B89FF8A9795FF
+ 899694FF7C8987FF828F8DFF7B8886FF717E7CFF6A7775FF6A7775FF717E7CFF
+ 7B8886FF83908EFF828D8BFF808B89FF7C8987FF7E8B89FF84918FFF879492FF
+ 849290FF7F8D8BFF95A6A3FFA7B8B5FFBACBC8FFAEBFBCFFCADDDAFFB9CCC9FF
+ 718481FFB6C9C6FFA2B5B2FFA2B5B2FF9DB0ADFF93A6A3FF8B9C99FF899A97FF
+ 90A19EFF97A8A5FF9EACAAFF97A5A3FF919E9CFF8B9896FF818E8CFF778482FF
+ 76817FFF788381FF77827FFF535E5BFF485350FF5A6562FF65706DFF6E7976FF
+ 7A8582FF808B88FF8C9794FF8F9A97FF939E9BFF95A09DFF949F9CFF96A19EFF
+ 99A4A1FF9CA7A4FF96A4A0FF96A4A0FF98A6A2FF9CAAA6FF9FADA9FF9EACA8FF
+ 9BA9A5FF97A5A1FF9AA8A4FF96A4A0FF92A09CFF92A09CFF97A5A1FF9BA9A5FF
+ 9BA9A5FF9AA8A4FF8E9996FF909E9AFF93A19DFF93A29EFF909F9BFF8C9D99FF
+ 8B9F9AFF8CA09BFFC5DBD6FFE9FFFBFFE5FFF9FFD1EBE5FFC9E5DFFFC8E4DEFF
+ CFEEE7FFE1FDF7FFE6FBF8FFE8FBF8FFE8FBF8FFEAFDFAFFE9FEFBFFE7FCF9FF
+ E1F8F4FFDDF4F0FFD4EDE9FFC7E0DCFFCCE5E1FFD5F0ECFFD1ECE8FFCDE8E4FF
+ C7E5E0FFC0DBD7FFB9D0CCFFC2D9D5FFAAC1BDFF9FB6B2FF495E5BFF7B908DFF
+ 899C99FF768986FF7F908DFF869794FF8D9B99FF8A9896FF84918FFF83908EFF
+ 899694FF909E9CFF8B9C98FF8A9B97FF909F9BFF97A6A2FF96A5A1FF8A9995FF
+ 808E8AFF7B8985FF95A09DFF909B98FF8F9A97FF939E9BFF949D9AFF8D9693FF
+ 8C9592FF8D9895FF788680FF7D8E85FF809188FF86978EFF85968DFF83948BFF
+ 8C9D94FF92A39AFF84958CFF899A91FF8E9F96FF8E9F96FF8C9D94FF8C9D94FF
+ 92A39AFF97A89FFFA1B2A9FFA3B7ABFFB2C3BAFFB5C8BFFFBBCEC5FFD2E7DEFF
+ E6FBF3FFE1F8F0FFD8EEE9FFD5ECE7FFD2E9E5FFCFE6E2FFB3C8C5FFB5CAC7FF
+ B1C6C3FFA9BEBBFFA4B9B6FFA5BAB7FFA2B7B4FF9EB3B0FFA0B5B2FFA2B7B4FF
+ A8BDBAFFADC2BFFFADC2BFFFADC2BFFFB5CAC7FFBED5D1FFB2C9C5FFA7C0BCFF
+ A2B9B5FF9FB6B2FF9DB4B0FF9BB2AEFFA0B5B2FFA6BBB8FF96A9A6FF9FB2AFFF
+ AEC1BEFFAABDBAFF99AAA7FF8D9E9BFF7C8D8AFF61726FFF687674FF687674FF
+ 6E7C7AFF768482FF788986FF778885FF788986FF7B8C89FF7B8E8BFF7B8E8BFF
+ 7B908DFF7D928FFF7F9491FF809592FF809793FF7F9692FF899D98FF97ABA6FF
+ 99ADA8FF93A7A2FF91A5A0FF8EA29DFF93A7A2FFA2B6B1FFC6DAD5FFC0D4CFFF
+ B7CBC6FFB4C8C3FFB9CDC8FFBCD0CBFFB3C7C2FFA7BBB6FFC4D2D0FFAEBCBAFF
+ A9B7B5FFBBC9C7FFC2D0CEFFB5C3C1FFACBAB8FFB1BFBDFFA9B7B5FFA9B7B5FF
+ A7B5B3FFA3B1AFFF9CAAA8FF97A5A3FF95A3A1FF96A3A1FF8E9996FF3F4A47FF
+ 5A6562FF7D8885FF7D8885FF7F8A87FF6E7976FF75807DFF7D8885FF727D7AFF
+ 6E7976FF76817EFF7A8582FF75807DFF737E7BFF76817EFF7E8C86FF7E8C86FF
+ 7D8B87FF7F8D89FF879591FF93A19DFF96A3A1FF94A19FFF96A4A2FFB2C0BEFF
+ D3E3E2FFDCECEBFFDCEEEFFFB9CDCEFF849899FF849695FF95A3A2FF9AA7A5FF
+ 9DAAA8FF98A5A3FF8F9C9AFF899694FF889593FF8A9795FF869391FF828F8DFF
+ 7E8B89FF7D8A88FF7E8B89FF7D8A88FF798684FF758280FF758280FF808D8BFF
+ 84918FFF7F8C8AFF808D8BFF879492FF8A9795FF869391FF808D8BFF7D8A88FF
+ 788583FF74817FFF74817FFF768381FF7A8785FF7D8A88FF828D8BFF848F8DFF
+ 828F8DFF828F8DFF869391FF899694FF83918FFF7A8886FF7F908DFF9DAEABFF
+ AABBB8FFA4B5B2FFBACDCAFFA8BBB8FF607370FFAABDBAFFA7BAB7FFA8BBB8FF
+ A3B6B3FF96A9A6FF889996FF81928FFF849592FF8B9C99FF909E9CFF909E9CFF
+ 93A09EFF919E9CFF869391FF798684FF778280FF7A8583FF77827FFF55605DFF
+ 4B5653FF5A6562FF66716EFF717C79FF7F8A87FF848F8CFF87928FFF8D9895FF
+ 939E9BFF95A09DFF929D9AFF909B98FF939E9BFF97A29FFF97A5A1FF98A6A2FF
+ 9BA9A5FF9EACA8FFA0AEAAFF9DABA7FF97A5A1FF92A09CFF9AA8A4FF96A4A0FF
+ 92A09CFF919F9BFF93A19DFF96A4A0FF98A6A2FF99A7A3FF99A4A1FF929D9AFF
+ 8D9895FF909E9AFF99A7A3FF99A8A4FF8C9D99FF7F938EFFA1B7B2FFD7EEE9FF
+ D2E9E4FFC5DFD9FFCEEAE4FFC9E5DFFFD4F3ECFFE8FFFEFFE7FAF7FFE8F9F6FF
+ E5F8F5FFE7FAF7FFE8FBF8FFE7FCF9FFE4FBF7FFE1F8F4FFD3ECE8FFC2DBD7FF
+ C4DFDBFFD1ECE8FFCEE9E5FFC9E4E0FFC4E2DDFFBFDAD6FFB1CAC6FFBED5D1FF
+ AAC1BDFFA3BAB6FF495E5BFF6F8481FF8EA19EFF7D908DFF768784FF7E8F8CFF
+ 899795FF8A9896FF879492FF859290FF8A9795FF8F9C9AFF9BAAA6FF93A4A0FF
+ 93A29EFF93A29EFF91A09CFF8A9995FF899793FF8A9894FF949F9CFF8A9592FF
+ 889390FF929D9AFF99A29FFF909996FF868F8CFF818D87FF788680FF84958CFF
+ 809188FF889990FF85968DFF7E8F86FF8D9E95FF8E9F96FF87988FFF8E9F96FF
+ 93A49BFF92A39AFF8C9D94FF8B9C93FF91A299FF98A9A0FF90A196FF8A9B90FF
+ 8FA097FF94A59CFF99AAA1FFB3C6BDFFD9EBE4FFE8FDF5FFE1F5F0FFDCF2EDFF
+ D8EDEAFFD3EAE6FFB1C6C3FFB3C8C5FFAFC4C1FFA8BDBAFFA3B8B5FFA3B8B5FF
+ A0B5B2FF9BB0ADFFA0B5B2FFA2B7B4FFA5BAB7FFA7BCB9FFA3B8B5FFA2B7B4FF
+ ADC2BFFFB9D0CCFFB0C7C3FFA6BFBBFFA1B8B4FF9EB5B1FF9AB1ADFF96ADA9FF
+ 99AEABFF9EB3B0FF95A8A5FF95A8A5FFA4B7B4FFAEC1BEFFA3B4B1FF8E9F9CFF
+ 768784FF5C6D6AFF5E6C6AFF657371FF6A7876FF6E7C7AFF728380FF788986FF
+ 798A87FF758683FF7F928FFF7C8F8CFF778C89FF7B908DFF829794FF899E9BFF
+ 8BA29EFF8BA29EFF93A7A2FF91A5A0FF96AAA5FF96AAA5FF8B9F9AFF8CA09BFF
+ 98ACA7FF9DB1ACFFBACEC9FFBACEC9FFB6CAC5FFB1C5C0FFB7CBC6FFC2D6D1FF
+ C2D6D1FFBACEC9FFC1CFCDFFB5C3C1FFB0BEBCFFB6C4C2FFBBC9C7FFB7C5C3FF
+ B4C2C0FFB4C2C0FFACBAB8FFADBBB9FFABB9B7FFA7B5B3FFA1AFADFF9CAAA8FF
+ 9AA8A6FF9BA8A6FF95A09DFF454E4BFF626B68FF858E8BFF808986FF858E8BFF
+ 79827FFF7B8481FF77807DFF767F7CFF767F7CFF78817EFF7A8380FF7B8481FF
+ 7A8380FF77827FFF83918BFF83938CFF83918DFF83918DFF8D9B97FF98A6A2FF
+ 98A5A3FF919E9CFF909D9BFF97A5A3FFC1D1D0FFD6E6E5FFDBEDEEFFC7DBDCFF
+ 93A7A8FF879C9AFF96A4A3FF98A5A3FF97A4A2FF93A09EFF8D9A98FF8A9795FF
+ 8B9896FF8D9A98FF899694FF879492FF859290FF83908EFF828F8DFF808D8BFF
+ 7D8A88FF7C8987FF808D8BFF818E8CFF828F8DFF859290FF899694FF8C9997FF
+ 8E9B99FF8F9C9AFF7F8C8AFF7E8B89FF7D8A88FF7C8987FF7B8886FF7C8987FF
+ 7C8987FF7C8987FF838E8CFF879290FF869391FF859290FF889593FF8A9795FF
+ 818F8DFF758381FF758683FF9DAEABFFA2B3B0FFABBCB9FFB9CCC9FFA3B6B3FF
+ 617471FFA1B4B1FFA5B8B5FFA4B7B4FF9FB2AFFF96A9A6FF8E9F9CFF879895FF
+ 859693FF869794FF879593FF879593FF8D9A98FF919E9CFF8D9A98FF83908EFF
+ 7E8987FF7E8987FF727D7AFF515C59FF46514EFF55605DFF616C69FF6E7976FF
+ 7D8885FF808B88FF899491FF8D9895FF929D9AFF95A09DFF96A19EFF949F9CFF
+ 919C99FF909B98FF94A29EFF96A4A0FF9AA8A4FFA0AEAAFFA3B1ADFFA1AFABFF
+ 9CAAA6FF97A5A1FF97A5A1FF97A5A1FF96A4A0FF95A39FFF93A19DFF93A19DFF
+ 95A39FFF97A5A1FFA2AEA8FF97A39DFF8D9993FF8A9892FF92A09AFF98A8A1FF
+ 95A7A0FF90A59DFF8CA39BFFB5CDC5FFBAD2CAFFC0DBD2FFBDDAD1FFBDDAD1FF
+ DBFAF1FFE6FFFCFFE8FBF8FFE7F8F5FFE4F5F2FFE2F5F2FFE4F7F4FFE4F9F6FF
+ E4FBF7FFE3FAF6FFD9F2EEFFC5DEDAFFC4DFDBFFD1ECE8FFCDEBE6FFC7E5E0FF
+ C4E2DDFFC0DBD7FFB5CDCBFFB8D0CEFFACC2C0FFB1C7C5FF5B706EFF5D7270FF
+ 829493FF809291FF7B8B8AFF7E8E8DFF859392FF8A9897FF8E9A9AFF8C9898FF
+ 8A9494FF84918FFF8D9C98FF8C9B97FF8B9A96FF879692FF7E8D89FF7A8985FF
+ 84928EFF919F9BFF8F9A97FF848F8CFF87908DFF969F9CFF9BA4A1FF8E9794FF
+ 7F8885FF77837DFF798781FF84958CFF788980FF83948BFF86978EFF819289FF
+ 91A299FF889990FF9BACA3FF98A9A0FF92A39AFF8C9D94FF899A91FF8D9E95FF
+ 96A79EFF9EAFA6FFA7B7ACFF99A99EFF9BABA0FF9FAFA4FF9AA9A1FFA9BAB1FF
+ D0E2DBFFECFFF9FFE2F6F1FFDDF3EEFFD9EEEBFFD5EAE8FFB0C5C2FFB3C8C5FF
+ B3C8C5FFAEC3C0FFABC0BDFFABC0BDFFA8BDBAFFA3B8B5FF9DB2AFFF9FB4B1FF
+ A1B6B3FF9FB4B1FF98ADAAFF96ABA8FFA2B7B4FFB1C8C4FF91AAA6FF8CA5A1FF
+ 8DA4A0FF90A7A3FF91A8A4FF92A9A5FF97ACA9FF9EB3B0FF889B98FF7F928FFF
+ 8EA19EFFA4B7B4FFA2B3B0FF8D9E9BFF71827FFF576865FF4D5B59FF586664FF
+ 5E6C6AFF5E6C6AFF637471FF70817EFF71827FFF697A77FF879895FF7D908DFF
+ 778A87FF7B8E8BFF869996FF92A5A2FF97ACA9FF98ADAAFFA1B5B0FF8CA09BFF
+ 94A5A1FF99ADA8FF889C97FF889C97FF9BAFAAFFA0B4AFFFA9BDB8FFB7CBC6FF
+ B9CDC8FFA9BDB8FF9FB3AEFFA7BBB6FFB6CAC5FFBED2CDFFAEBFBCFFB5C6C3FF
+ B9C7C5FFB4C5C2FFB6C4C2FFB7C8C5FFB5C3C1FFAABBB8FFAAB8B6FFAABBB8FF
+ ACBAB8FFA8B9B6FFA6B4B2FFA1B2AFFFA2B0AEFFA3B1AFFF96A19EFF45504DFF
+ 646F6CFF86918EFF808B88FF8C9794FF848F8CFF86918EFF6F7A77FF788380FF
+ 7F8A87FF7D8885FF7C8784FF7F8A87FF808B88FF7D8885FF8C9A94FF8D9D96FF
+ 8C9A96FF8B9995FF92A09CFF9AA8A4FF95A2A0FF8A9795FF9AA7A5FF8C9997FF
+ B5C3C1FFCBDBDAFFD5E7E6FFD4E6E5FFA6BBB9FF97A9A8FF97A5A3FF96A3A1FF
+ 929F9DFF8D9A98FF8A9795FF8B9896FF8E9B99FF919E9CFF8C9997FF8C9997FF
+ 8A9795FF889593FF879290FF828F8DFF838E8CFF818E8CFF859290FF7D8A88FF
+ 7C8987FF859290FF8D9A98FF8E9B99FF8E9B99FF8F9C9AFF83908EFF808D8BFF
+ 7D8A88FF7B8886FF7B8886FF7D8A88FF818E8CFF83908EFF838E8CFF899492FF
+ 8B9694FF889593FF8A9795FF8B9896FF7F8D8BFF717F7DFF738481FF9FB0ADFF
+ A0B1AEFFB3C6C3FFBFD2CFFFA3B8B5FF677978FF99AEABFFA0B3B0FF9CAFACFF
+ 97AAA7FF95A8A5FF95A8A5FF94A5A2FF8FA09DFF8A9B98FF8F9D9BFF899795FF
+ 869492FF899694FF879492FF7E8B89FF768381FF73807EFF76817EFF54625EFF
+ 4A5552FF55635FFF626D6AFF6E7C78FF7E8986FF7E8C88FF909B98FF8E9C98FF
+ 929D9AFF96A4A0FF9CA7A4FF99A7A3FF939E9BFF8B9995FF8D9B97FF909E9AFF
+ 98A6A2FFA0AEAAFFA7B5B1FFA8B6B2FFA4B2AEFFA0AEAAFF95A39FFF99A7A3FF
+ 9CAAA6FF9BA9A5FF96A4A0FF93A19DFF94A29EFF96A4A0FF8F9B95FF97A39DFF
+ 9DA9A3FF9AA6A0FF919F99FF8D9B95FF8F9F98FF93A59EFF889D95FF9AB1A9FF
+ ABC3BBFFC0D8D0FFA9C4BBFFAEC9C0FFDFFCF3FFD7F2E9FFE7FCF9FFE5F8F5FF
+ E1F4F1FFDFF2EFFFDFF4F1FFE2F7F4FFE3FAF6FFE3FAF6FFE3FCF8FFCCE5E1FF
+ C9E4E0FFD5F0ECFFD2EDE9FFCAE8E3FFC9E4E0FFC4DFDBFFBED6D4FFB7CFCDFF
+ AFC5C3FFC0D6D4FF6E8381FF4D6260FF718382FF7D8F8EFF899998FF859594FF
+ 869493FF8C9A99FF95A1A1FF929E9EFF859191FF788583FF4B5955FF5F6E6AFF
+ 7A8884FF84938FFF7C8A86FF707E7AFF717F7BFF7C8A86FF838E8BFF7B8683FF
+ 828B88FF929B98FF969F9CFF868F8CFF77807DFF717D77FF76847EFF7E8F86FF
+ 6C7D74FF7B8C83FF87988FFF86978EFF96A79EFF85968DFF8D9E95FF8C9D94FF
+ 8B9C93FF8D9E95FF90A198FF91A299FF90A198FF8E9F96FF9DACA4FF90A095FF
+ 96A79EFFA1B2A9FF98A9A0FF9CADA4FFC0D2CBFFE0F5EDFFE1F5F0FFDEF2EDFF
+ D9EEEBFFD6EBE8FFB8CFCBFFB1C8C4FFACC3BFFFACC3BFFFADC4C0FFA9C0BCFF
+ A4BBB7FFA1B8B4FF9EB5B1FF95ACA8FF93AAA6FF98AFABFF98AFABFF96ADA9FF
+ 9FB6B2FFADC4C0FFB5CECAFF93ACA8FF839A96FF8FA6A2FF9CB3AFFF9BB2AEFF
+ A4B9B6FFB5CAC7FF91A4A1FF8A9D9AFF849794FF91A4A1FF9FB0ADFF899A97FF
+ 6C7D7AFF667774FF3D4C48FF364541FF4D5C58FF5B6A66FF64736FFF677672FF
+ 5E6D69FF6E7D79FF7F8E8AFF94A5A1FF93A4A0FF7B8C88FF7E8F8BFF9CADA9FF
+ A2B3AFFF8D9E9AFF92A39FFFA3B4B0FFA2B1ADFF92A39FFF93A4A0FF96A7A3FF
+ 9AABA7FFA5B6B2FFB4C8C3FFC4D8D3FFC9DFDAFFBBD1CCFFA6BCB7FF9FB5B0FF
+ A6BCB7FFAFC5C0FFAFC2BFFFA8BBB8FFA3B4B1FFA2B5B2FFACBDBAFFB3C6C3FF
+ BACBC8FFBACDCAFFAFC0BDFFA9BCB9FFA9BAB7FFA5B8B5FFA1B2AFFF99ACA9FF
+ 9DAEABFFA4B5B2FF96A5A1FF4D5B57FF515F5BFF82908CFF869490FF8B9995FF
+ 96A4A0FF84928EFF8D9B97FF899793FF85938FFF889692FF8E9C98FF909E9AFF
+ 8B9995FF869490FF919F9BFF8F9D99FF8F9D99FF93A19DFF99A7A3FF9AA8A4FF
+ 94A29EFF8E9C98FF919F9BFF98A6A2FFA9B7B3FFCCDAD8FFD6E4E2FFD3E1DFFF
+ C3D1CFFF889694FF919F9DFF9AA8A6FF98A6A4FF8B9997FF859391FF8B9997FF
+ 909D9BFF8D9A98FF939E9CFF8F9A98FF8D9896FF8B9694FF88908FFF818C8AFF
+ 858D8CFF8A9593FF7C8987FF7D8A88FF83908EFF899694FF8B9896FF8B9896FF
+ 929F9DFF9CA9A7FF7E8B89FF84918FFF879492FF84918FFF7D8A88FF7A8785FF
+ 808D8BFF879492FF818C89FF909996FF8F9895FF8A9592FF95A09DFF93A19DFF
+ 849290FF7E8C8AFF7F908DFF95A6A3FFB1C3C2FFB2C7C5FFBDD2D0FF9CB2B0FF
+ 3C5051FF92A8A6FF9BB0ADFF94A9A6FF8EA3A0FF8BA09DFF869B98FF819491FF
+ 7F928FFF829592FF839491FF859693FF879895FF8B9997FF8E9C9AFF8B9997FF
+ 7C8A88FF6D7B79FF6B7975FF64736FFF3D4B47FF586763FF667470FF6F7E7AFF
+ 6E7C78FF72817DFF82908CFF82918DFF899793FF909F9BFF96A4A0FF95A4A0FF
+ 96A4A0FF97A5A1FF97A5A1FF93A19DFF8F9D99FF8C9A96FF8C9A96FF909E9AFF
+ 95A39FFF98A6A2FF97A5A1FF95A39FFF93A19DFF92A09CFF92A09CFF94A29EFF
+ 96A4A0FF98A6A2FF939F99FF9BA7A1FFA2AEA8FF9FADA7FF97A59FFF909E98FF
+ 8D9D96FF8C9E97FF93A59EFF899E96FF93A8A0FFAFC4BCFFC0D7CFFFC6DDD5FF
+ D3EAE2FFE4FBF3FFE2F9F5FFDAF1EDFFDAF1EDFFE0F7F3FFDCF3EFFFD3EAE6FF
+ D6EFEBFFE3FCF8FFDDF6F2FFDAF3EFFFD5EEEAFFD3ECE8FFD6EFEBFFD5F0ECFF
+ CBE4E0FFBDD6D2FFBDD6D2FFB1C8C4FFBBD0CDFFACC1BEFF879C99FF536865FF
+ 657875FF758885FF899A97FF81928FFF7F908DFF81928FFF758381FF5A6866FF
+ 4A5856FF4B5856FF576561FF5A6862FF65716BFF697771FF67736DFF636F69FF
+ 6F7B75FF818D87FF84908AFF6C7872FF69756FFF828E88FF8D9993FF7E8A84FF
+ 74807AFF78847EFF7C8A84FF7B8B84FF7A8A83FF7C8C85FF86968FFF91A19AFF
+ 92A29BFF8C9C95FF899992FF8C9C95FF8C9C95FF8C9C95FF92A29BFF97A7A0FF
+ 8F9F98FF82928BFF94A69FFF9BB0A7FF8BA098FF8CA199FFA1B6AEFF9AAFA7FF
+ A4B9B1FFD8EFE7FFE0F7EFFFDBF2EAFFD4EAE5FFD0E6E1FFB8CFCBFFB5CCC8FF
+ B2C9C5FFADC4C0FFA5BCB8FF9DB4B0FF98AFABFF97AEAAFFA1B8B4FF9CB3AFFF
+ 9CB3AFFFA1B8B4FFA0B7B3FF9CB3AFFFA1B8B4FFAAC1BDFFA1BAB6FFAEC7C3FF
+ ACC3BFFF9AB1ADFF9BB2AEFFACC3BFFFAEC3C0FF9EB3B0FFAEC1BEFF9EB1AEFF
+ 859895FF7B8E8BFF7B8C89FF6B7C79FF61726FFF6C7D7AFF5B6A66FF42514DFF
+ 4A5955FF505F5BFF4F5E5AFF4B5A56FF52615DFF7A8985FF697874FF84938FFF
+ 909F9BFF81908CFF7A8985FF889793FF95A4A0FF94A39FFF98A7A3FFA9B8B4FF
+ A9B8B4FFA1B0ACFF9FB0ACFF9DAEAAFF99AAA6FF9EAFABFFA5B9B4FFBBCFCAFF
+ CBE1DCFFC8DED9FFB8CEC9FFABC1BCFFA5BCB7FFA4BBB6FFBACDCAFFB5C8C5FF
+ AEC1BEFFAABDBAFFAABDBAFFAABDBAFFAABDBAFFA9BCB9FFA8BBB8FFA4B7B4FF
+ A1B4B1FF9FB2AFFF99ACA9FF93A6A3FF95A8A5FF9BAEABFF99A8A4FF53625EFF
+ 53625EFF7E8D89FF808F8BFF83928EFF8D9C98FF7C8B87FF879692FF889793FF
+ 889793FF889793FF889793FF899894FF8D9C98FF909F9BFF93A19DFF909E9AFF
+ 8F9D99FF92A09CFF98A6A2FF9BA9A5FF98A6A2FF94A29EFF94A29EFF98A6A2FF
+ A4B2AEFFCEDCD8FFE1EFEBFFD8E6E2FFCDDBD7FFABB9B5FF95A3A1FF96A4A2FF
+ 92A09EFF8B9997FF899795FF8D9B99FF919E9CFF909D9BFF929D9BFF8F9A98FF
+ 909897FF8F9796FF8A9291FF848C8BFF868E8DFF899492FF848F8DFF83908EFF
+ 889593FF8D9A98FF8D9A98FF8D9A98FF93A09EFF9CA9A7FF818E8CFF828F8DFF
+ 84918FFF84918FFF83908EFF84918FFF869391FF889692FF88918EFF929C96FF
+ 8D9693FF89928FFF939E9BFF93A19DFF889593FF83918FFF869794FF97AAA7FF
+ B0C2C1FFB1C6C4FFBACFD0FF9AAFB0FF3A4F50FF879D9BFF8CA2A0FF879E9AFF
+ 869B98FF869B98FF839895FF7C918EFF7C8F8CFF7E918EFF8A9B98FF889996FF
+ 839491FF81928FFF899795FF8D9B99FF889694FF7F8D8BFF6E7D79FF697874FF
+ 43524EFF5D6C68FF687773FF72817DFF71807CFF788783FF8C9B97FF899894FF
+ 889793FF8D9C98FF91A09CFF92A19DFF91A09CFF909F9BFF919F9BFF8E9C98FF
+ 8A9894FF879591FF879591FF8B9995FF8F9D99FF92A09CFF94A29EFF93A19DFF
+ 909E9AFF8E9C98FF8D9B97FF8D9B97FF8E9C98FF8F9D99FF8F9B95FF94A09AFF
+ 97A59FFF98A6A0FF97A59FFF96A49EFF98A8A1FF9BABA4FF92A49DFF9DAFA8FF
+ A2B4ADFFA4B6AFFFB1C6BEFFCCE1D9FFDFF4ECFFE2F9F1FFDFF6F2FFD5EEEAFF
+ D5EEEAFFDAF3EFFFD7F0ECFFCFE8E4FFD3ECE8FFDEF7F3FFDAF3EFFFDDF6F2FF
+ DDF6F2FFD8F1EDFFD4EDE9FFD1EAE6FFCAE3DFFFC2DBD7FFC0D7D3FFB0C7C3FF
+ B2C7C4FFA6BBB8FF8EA3A0FF4A5F5CFF6D807DFF7A8D8AFF778885FF6D7E7BFF
+ 677875FF667774FF5B6967FF455351FF3A4846FF3C4B47FF485652FF4C5852FF
+ 505C56FF56625CFF5D6963FF66726CFF737F79FF7D8983FF79857FFF6B7771FF
+ 6D7973FF84908AFF909C96FF85918BFF77837DFF72807AFF7D8B85FF7E8E87FF
+ 808E88FF83938CFF8F9D97FF99A9A2FF9BA9A3FF95A59EFF93A19BFF97A7A0FF
+ 9BA9A3FF99A9A2FF9AA8A2FF97A7A0FF8D9B95FF7E8E87FF91A69EFF9CB3ABFF
+ 91A69EFF8AA199FF9AAFA7FF8EA59DFF93A8A0FFBAD1C9FFDBF0E8FFD7EEE6FF
+ D7ECE4FFD2E9E1FFA7BEBAFFABC2BEFFAEC5C1FFAAC1BDFFA2B9B5FF9DB4B0FF
+ 9DB4B0FF9EB5B1FFA2B9B5FF9FB6B2FF9DB4B0FF9DB4B0FF9BB2AEFF9BB2AEFF
+ A0B7B3FFA7BEBAFF8FA8A4FFAFC8C4FFB7CECAFF9DB4B0FF95ACA8FFAAC1BDFF
+ AEC3C0FF9CB1AEFFAFC2BFFFA8BBB8FF95A8A5FF869996FF7C8D8AFF657673FF
+ 5A6B68FF657673FF44534FFF313F3BFF4E5C58FF72807CFF7A8884FF606E6AFF
+ 414F4BFF4E5C58FF596763FF74827EFF8E9C98FF8F9D99FF7F8D89FF798783FF
+ 8A9894FF9FADA9FF8B9A96FF99A8A4FF9BAAA6FF98A7A3FF9EAFABFF9FB0ACFF
+ 9CADA9FFA2B3AFFF95A9A4FFACC0BBFFC1D7D2FFC6DCD7FFBED4CFFFB2C8C3FF
+ A5BCB7FF9CB3AEFFB2C5C2FFB2C5C2FFB2C5C2FFAFC2BFFFABBEBBFFA9BCB9FF
+ AABDBAFFABBEBBFFA7BAB7FFA2B5B2FF9FB2AFFF9DB0ADFF97AAA7FF90A3A0FF
+ 8FA29FFF94A7A4FF9FAEAAFF5F6E6AFF5C6B67FF7F8E8AFF81908CFF859490FF
+ 8F9E9AFF81908CFF869591FF8B9A96FF8F9E9AFF8B9A96FF83928EFF82918DFF
+ 8B9A96FF94A39FFF94A29EFF909E9AFF8C9A96FF8D9B97FF93A19DFF97A5A1FF
+ 98A6A2FF97A5A1FF96A4A0FF9BA9A5FF9BA9A5FFC6D4D0FFE8F6F2FFDFEDE9FF
+ DCEAE6FFD5E3DFFFA6B4B2FF98A9A6FF919F9DFF909E9CFF919F9DFF909E9CFF
+ 919E9CFF93A09EFF919C9AFF8F9A98FF8F9A98FF919C9AFF8F9796FF88908FFF
+ 878F8EFF889391FF889391FF879492FF8B9896FF909D9BFF8F9C9AFF8E9B99FF
+ 94A19FFF9DAAA8FF859290FF818E8CFF7F8C8AFF808D8BFF84918FFF879492FF
+ 879492FF869490FF8D9693FF939D97FF8B9491FF88918EFF929D9AFF93A19DFF
+ 8B9896FF899795FF92A3A0FFA2B5B2FFB4C6C5FFB4C9C7FFB8CDCEFF99AEAFFF
+ 405556FF829896FF819795FF7E9591FF809592FF839895FF829794FF7C918EFF
+ 7B8E8BFF7D908DFF849592FF829390FF7D8E8BFF7B8C89FF83918FFF899795FF
+ 859391FF7C8A88FF6B7975FF687672FF43514DFF5C6A66FF65736FFF6E7C78FF
+ 6E7C78FF788682FF919F9BFF8E9C98FF8A9894FF8A9894FF8E9C98FF919F9BFF
+ 919F9BFF8F9D99FF95A39FFF93A19DFF8F9D99FF8D9B97FF8D9B97FF8F9D99FF
+ 92A09CFF95A39FFF94A29EFF92A09CFF909E9AFF8E9C98FF8C9A96FF8A9894FF
+ 8A9894FF8A9894FF8F9B95FF909C96FF909E98FF92A09AFF96A49EFF9AA8A2FF
+ 9EAEA7FFA1B1AAFF96A8A1FF9EB0A9FF9EB0A9FF97A9A2FF9DB2AAFFB6CBC3FF
+ D1E6DEFFDDF4ECFFDCF3EFFFD3ECE8FFD2EBE7FFD7F0ECFFD4EDE9FFCEE7E3FF
+ D0E9E5FFD9F2EEFFD5EEEAFFDEF7F3FFE2FBF7FFDAF3EFFFCFE8E4FFC9E2DEFF
+ C6DFDBFFC4DDD9FFC2D9D5FFB4CBC7FFACC1BEFFA1B6B3FF9AAFACFF384D4AFF
+ 728582FF7B8E8BFF738481FF6B7C79FF687976FF697A77FF616F6DFF4F5D5BFF
+ 43514FFF43524EFF495753FF4C5A54FF495751FF47554FFF53615BFF67756FFF
+ 707E78FF6C7A74FF6F7D77FF6D7B75FF74827CFF85938DFF919F99FF8B9993FF
+ 7A8882FF6D7B75FF7B8983FF7F8D87FF85918BFF899791FF96A29CFF9FADA7FF
+ A2AEA8FF9BA9A3FF95A19BFF98A6A0FF9EAAA4FF9CAAA4FF9EAAA4FF9CAAA4FF
+ 99A59FFF909E98FF91A39CFFA2B7AFFF9BADA6FF8EA39BFF97A9A2FF8DA29AFF
+ 8C9E97FFA1B6AEFFD9EBE4FFD9EEE6FFDCEEE7FFD6EBE3FF9EB5B1FFA4BBB7FF
+ A8BFBBFFA5BCB8FFA2B9B5FFA2B9B5FFA1B8B4FFA0B7B3FFA5BCB8FFA3BAB6FF
+ 9DB4B0FF96ADA9FF94ABA7FF9BB2AEFFA4BBB7FFABC2BEFF9BB4B0FF9EB7B3FF
+ 9EB5B1FF96ADA9FF8CA39FFF8BA29EFF97ACA9FFA4B9B6FF9DB0ADFFA1B4B1FF
+ 9BAEABFF94A7A4FF8D9E9BFF728380FF5C6D6AFF606E6CFF4B5955FF273531FF
+ 323D3AFF515F5BFF747F7CFF72807CFF525D5AFF4A5854FF57625FFF667470FF
+ 848F8CFF93A19DFF899491FF768480FF848F8CFF9DABA7FF8A9995FF91A09CFF
+ 8C9B97FF8A9995FF94A5A1FF99AAA6FF9BACA8FFA6B7B3FF97ABA6FFA7BBB6FF
+ B6CCC7FFBDD3CEFFBCD2CDFFB7CDC8FFADC4BFFFA5BCB7FFA7BAB7FFABBEBBFF
+ AEC1BEFFABBEBBFFA7BAB7FFA7BAB7FFACBFBCFFB2C5C2FFAEC1BEFFA8BBB8FF
+ A3B6B3FF9FB2AFFF98ABA8FF90A3A0FF8DA09DFF8FA29FFF9AA9A5FF667571FF
+ 61706CFF7D8C88FF81908CFF879692FF91A09CFF889793FF899894FF8F9E9AFF
+ 94A39FFF8F9E9AFF859490FF81908CFF869591FF8D9C98FF93A19DFF8E9C98FF
+ 899793FF879591FF8B9995FF909E9AFF93A19DFF94A29EFF95A39FFFA1AFABFF
+ 93A19DFFB2C0BCFFDFEDE9FFE5F3EFFFE9F7F3FFEAF9F5FFBCCAC8FFA4B5B2FF
+ 95A3A1FF97A5A3FF9AA8A6FF94A2A0FF929F9DFF94A19FFF929D9BFF8F9A98FF
+ 919C9AFF949F9DFF939B9AFF8C9493FF88908FFF889391FF889391FF879492FF
+ 8B9896FF8F9C9AFF8E9B99FF8D9A98FF93A09EFF9CA9A7FF8B9896FF859290FF
+ 7E8B89FF7A8785FF7B8886FF7E8B89FF808D8BFF818F8BFF8D9693FF929C96FF
+ 8C9592FF8A9390FF949F9CFF93A19DFF8C9997FF8E9C9AFFA0B1AEFFB2C5C2FF
+ BCCECDFFB8CDCBFFB2C7C8FF97ACADFF4F6465FF8BA19FFF839997FF7F9692FF
+ 809592FF839895FF839895FF7E9390FF809390FF839693FF7A8B88FF7C8D8AFF
+ 7E8F8CFF80918EFF869492FF859391FF798785FF6B7977FF687672FF667470FF
+ 404E4AFF586662FF606E6AFF697773FF6B7975FF75837FFF879591FF8C9A96FF
+ 8E9C98FF8B9995FF8A9894FF8E9C98FF919F9BFF919F9BFF99A7A3FF97A5A1FF
+ 95A39FFF93A19DFF93A19DFF95A39FFF97A5A1FF98A6A2FF95A39FFF94A29EFF
+ 94A29EFF92A09CFF919F9BFF8F9D99FF8E9C98FF8D9B97FF939F99FF919D97FF
+ 8E9C96FF909E98FF94A29CFF98A6A0FF9AAAA3FF9AAAA3FFA0B2ABFF92A49DFF
+ 90A29BFF9BADA6FF99AEA6FF9BB0A8FFBBD0C8FFE2F9F1FFDDF4F0FFD6EFEBFF
+ D4EDE9FFD7F0ECFFD6EFEBFFD1EAE6FFD2EBE7FFD8F1EDFFD3ECE8FFDDF6F2FF
+ E0F9F5FFD8F1EDFFCCE5E1FFC6DFDBFFC3DCD8FFC1DAD6FFC0D7D3FFBAD1CDFF
+ AFC4C1FFA4B9B6FFA5BAB7FF283D3AFF6E817EFF778A87FF728380FF728380FF
+ 778885FF7F908DFF7D8B89FF6C7A78FF5D6B69FF566561FF6A7874FF717F79FF
+ 6A7872FF5B6963FF606E68FF72807AFF73817BFF65736DFF6D7B75FF72807AFF
+ 798781FF84928CFF8E9C96FF8E9C96FF7E8C86FF6C7A74FF78847EFF7E8A84FF
+ 84908AFF8A9690FF939F99FF9DA9A3FF9DA9A3FF99A59FFF97A39DFF9AA6A0FF
+ 9BA7A1FF9AA6A0FF9AA6A0FF9CA8A2FF9FABA5FFA1ADA7FF91A19AFFA5B7B0FF
+ A4B4ADFF95A7A0FF9AAAA3FF98AAA3FF97A7A0FF9DAFA8FFCCDCD5FFD0E2DBFF
+ D8E8E1FFD5E7E0FFA7BEBAFFA9C0BCFFA5BCB8FF9EB5B1FF9DB4B0FF9DB4B0FF
+ 96ADA9FF8CA39FFFA2B9B5FFA7BEBAFFA4BBB7FF9CB3AFFF9BB2AEFFA5BCB8FF
+ ACC3BFFFACC3BFFFB0C9C5FF9CB5B1FF93AAA6FF94ABA7FF8DA4A0FF829995FF
+ 8BA09DFF9FB4B1FFA1B4B1FF9FB2AFFF91A4A1FF879A97FF869794FF748582FF
+ 627370FF63716FFF4C5754FF303B38FF2C3532FF2F3A37FF525B58FF6E7976FF
+ 5F6865FF535E5BFF5B6461FF5B6663FF717A77FF889390FF8D9693FF7E8986FF
+ 828B88FF909B98FF9CAAA6FF9EADA9FF96A5A1FF91A09CFF96A7A3FF95A6A2FF
+ 94A5A1FF9EAFABFF9FB3AEFFABBFBAFFB7CDC8FFBDD3CEFFC0D6D1FFC0D6D1FF
+ B9D0CBFFB1C8C3FFACBFBCFFAEC1BEFFADC0BDFFA6B9B6FF9DB0ADFF9BAEABFF
+ A1B4B1FFA8BBB8FFB2C5C2FFAABDBAFFA3B6B3FF9FB2AFFF97AAA7FF8DA09DFF
+ 879A97FF889B98FF8E9D99FF677672FF606F6BFF74837FFF7A8985FF808F8BFF
+ 899894FF84938FFF879692FF8C9B97FF91A09CFF91A09CFF8D9C98FF889793FF
+ 869591FF869591FF94A29EFF909E9AFF8A9894FF889692FF899793FF8C9A96FF
+ 8F9D99FF919F9BFF919F9BFFA5B3AFFF909E9AFF99A7A3FFC7D5D1FFE1EFEBFF
+ EEFCF8FFE8F7F3FFC8D6D4FFACBDBAFF98A9A6FF97A8A5FF9DABA9FF99A7A5FF
+ 95A3A1FF96A4A2FF919E9CFF8E9B99FF919C9AFF96A19FFF949F9DFF8D9896FF
+ 8B9392FF899492FF85908EFF84918FFF889593FF8D9A98FF8C9997FF8A9795FF
+ 909D9BFF99A6A4FF95A2A0FF8F9C9AFF869391FF7B8886FF73807EFF73807EFF
+ 788583FF7D8B87FF89928FFF909A94FF8E9794FF8F9895FF96A19EFF909E9AFF
+ 8B9896FF919F9DFFA8B9B6FFBCCFCCFFC0D2D1FFB8CDCBFFA9BEBFFF94A9AAFF
+ 607576FF96ACAAFF8BA19FFF859C98FF829794FF829794FF809592FF7E9390FF
+ 829592FF879A97FF788986FF7C8D8AFF80918EFF849592FF8A9896FF889694FF
+ 798785FF697775FF6B7975FF677571FF404E4AFF586662FF616F6BFF6A7874FF
+ 6C7A76FF75837FFF7B8985FF8A9894FF94A29EFF8E9C98FF879591FF889692FF
+ 8D9B97FF8F9D99FF919F9BFF909E9AFF8F9D99FF8F9D99FF909E9AFF919F9BFF
+ 92A09CFF93A19DFF93A19DFF94A29EFF95A39FFF96A4A0FF97A5A1FF96A4A0FF
+ 94A29EFF93A19DFF939F99FF929E98FF8F9D97FF919F99FF93A19BFF95A39DFF
+ 93A39CFF92A29BFF9FB1AAFF91A39CFF93A59EFFA0B2ABFF9EB3ABFF9EB3ABFF
+ C0D5CDFFECFFFBFFE1F8F4FFDBF4F0FFD9F2EEFFDBF4F0FFDAF3EFFFD7F0ECFF
+ D7F0ECFFD8F1EDFFD8F1EDFFDDF6F2FFDDF6F2FFD6EFEBFFD0E9E5FFCBE4E0FF
+ C5DEDAFFBED7D3FFB6CDC9FFBCD3CFFFB3C8C5FFA9BEBBFFADC2BFFF293E3BFF
+ 687B78FF768986FF6C7D7AFF6E7F7CFF748582FF7D8E8BFF818F8DFF788684FF
+ 6D7B79FF677672FF85938FFF94A29CFF909E98FF7B8983FF75837DFF818F89FF
+ 7F8D87FF6F7D77FF6A7872FF707E78FF75837DFF7C8A84FF87958FFF8D9B95FF
+ 82908AFF72807AFF79857FFF818B85FF87918BFF8B958FFF929C96FF9AA49EFF
+ 9AA49EFF96A09AFFA0AAA4FFA1ABA5FFA2ACA6FFA3ADA7FFA0AAA4FF9DA7A1FF
+ 9CA6A0FF9BA7A1FF94A29CFFA5B5AEFFA8B6B0FF9BABA4FF9CAAA4FFA1B1AAFF
+ A3B1ABFFA2B2ABFFADBBB5FFB5C5BEFFC1CFC9FFC5D5CEFFA3BAB6FFA4BBB7FF
+ 9EB5B1FF96ADA9FF96ADA9FF9BB2AEFF96ADA9FF89A09CFF95ACA8FFA3BAB6FF
+ A9C0BCFFA2B9B5FFA1B8B4FFAAC1BDFFA9C0BCFF9FB6B2FFA6BFBBFFA1BAB6FF
+ 9BB2AEFF97AEAAFF9AB1ADFFA1B8B4FFA0B5B2FF9AAFACFFA4B7B4FFA2B5B2FF
+ 94A7A4FF8C9F9CFF8E9F9CFF7C8D8AFF637471FF5B6967FF37423FFF424B48FF
+ 565F5CFF4E5754FF545D5AFF646D6AFF545D5AFF4B5451FF5E6764FF5B6461FF
+ 656E6BFF7B8481FF8B9491FF8C9592FF89928FFF889390FF97A5A1FF9DACA8FF
+ 9CABA7FF9DACA8FF9FB0ACFF97A8A4FF91A29EFF9CADA9FF9BAFAAFFA8BCB7FF
+ B5CBC6FFBCD2CDFFC0D6D1FFBFD5D0FFB7CEC9FFAEC5C0FFACBFBCFFACBFBCFF
+ A9BCB9FFA1B4B1FF98ABA8FF95A8A5FF9AADAAFFA1B4B1FFABBEBBFFA3B6B3FF
+ 9CAFACFF98ABA8FF91A4A1FF879A97FF7F928FFF7E918EFF879692FF6C7B77FF
+ 64736FFF707F7BFF778682FF7D8C88FF81908CFF7F8E8AFF808F8BFF84938FFF
+ 8A9995FF91A09CFF94A39FFF92A19DFF8D9C98FF889793FF94A29EFF92A09CFF
+ 8F9D99FF8D9B97FF8D9B97FF8F9D99FF919F9BFF92A09CFF8E9C98FFA4B2AEFF
+ 919F9BFF8D9B97FFA9B7B3FFCDDBD7FFEAF8F4FFE1F0ECFFCCDDDAFFB5C6C3FF
+ 9EAFACFF97A8A5FF9CAAA8FF9DABA9FF9AA8A6FF97A5A3FF94A19FFF909D9BFF
+ 929D9BFF96A19FFF96A19FFF909B99FF8E9695FF8B9694FF859290FF859290FF
+ 899694FF8C9997FF8B9896FF889593FF8D9A98FF96A3A1FF9CA9A7FF97A4A2FF
+ 8D9A98FF808D8BFF758280FF717E7CFF74817FFF788682FF848D8AFF8F9993FF
+ 919A97FF929B98FF949F9CFF8B9995FF8A9795FF98A6A4FFACBDBAFFC0D3D0FF
+ BED0CFFFB6CBC9FFA3B8B9FF94A9AAFF6D8283FF98AEACFF8EA4A2FF869D99FF
+ 819693FF7E9390FF7C918EFF7A8F8CFF7F928FFF859895FF7B8C89FF7A8B88FF
+ 798A87FF798A87FF818F8DFF849290FF7D8B89FF73817FFF6C7A76FF64726EFF
+ 3A4844FF52605CFF5E6C68FF697773FF687672FF707E7AFF788682FF8A9894FF
+ 94A29EFF8D9B97FF83918DFF84928EFF889692FF899793FF899793FF8A9894FF
+ 8B9995FF8C9A96FF8E9C98FF8F9D99FF909E9AFF919F9BFF8F9D99FF92A09CFF
+ 95A39FFF98A6A2FF9AA8A4FF99A7A3FF98A6A2FF96A4A0FF929E98FF939F99FF
+ 919F99FF92A09AFF92A09AFF92A09AFF92A29BFF92A29BFF8C9E97FF93A59EFF
+ 98AAA3FF96A8A1FF97ACA4FFABC0B8FFCFE4DCFFE9FFF8FFE3FAF6FFDFF8F4FF
+ DDF6F2FFDDF6F2FFDDF6F2FFDCF5F1FFDAF3EFFFD8F1EDFFDDF6F2FFDEF7F3FF
+ DBF4F0FFD7F0ECFFD5EEEAFFD2EBE7FFC9E2DEFFBFD8D4FFACC3BFFFB7CECAFF
+ B2C7C4FFA9BEBBFFB0C5C2FF405552FF657875FF778A87FF748582FF71827FFF
+ 6F807DFF738481FF7B8987FF7F8D8BFF7F8D8BFF7E8D89FF82908CFF94A29CFF
+ 97A59FFF87958FFF7F8D87FF889690FF899791FF7F8D87FF707E78FF717F79FF
+ 73817BFF798781FF83918BFF899791FF83918BFF7A8882FF808A84FF86908AFF
+ 8B958FFF8D9791FF929C96FF99A39DFF9BA59FFF98A29CFF96A09AFF98A29CFF
+ A1ABA5FFACB6B0FFAEB8B2FFA7B1ABFFA0AAA4FF9EA8A2FF9BA7A1FFA3B1ABFF
+ A8B6B0FFA1AFA9FF9CAAA4FFA0AEA8FFA3B1ABFF9FADA7FF96A49EFF9DABA5FF
+ A5B3ADFFA9B7B1FF94ABA7FF9BB2AEFF9AB1ADFF93AAA6FF96ADA9FFA2B9B5FF
+ A5BCB8FF9EB5B1FF94ABA7FFA4BBB7FFA7BEBAFF9BB2AEFF9AB1ADFFA6BDB9FF
+ A6BDB9FF9AB1ADFF9BB4B0FFA1BAB6FFA0B7B3FF9AB1ADFFA3BAB6FFB0C7C3FF
+ A8BDBAFF92A7A4FF92A5A2FF9BAEABFF99ACA9FF98ABA8FF9CADAAFF879895FF
+ 657673FF576563FF49524FFF545B58FF686F6CFF59605DFF4E5552FF555C59FF
+ 535A57FF5F6663FF585F5CFF5D6461FF646B68FF6E7572FF818885FF939A97FF
+ 959C99FF8A9390FF909E9AFF98A7A3FF9AA9A5FF9DACA8FF9EAFABFF95A6A2FF
+ 93A4A0FFA2B3AFFF98ACA7FFA5B9B4FFAFC5C0FFB3C9C4FFB4CAC5FFB4CAC5FF
+ B0C7C2FFAAC1BCFFA6B9B6FFA7BAB7FFA5B8B5FFA0B3B0FF9AADAAFF97AAA7FF
+ 99ACA9FF9CAFACFFA1B4B1FF98ABA8FF92A5A2FF90A3A0FF8C9F9CFF829592FF
+ 7B8E8BFF798C89FF7C8B87FF6C7B77FF657470FF6D7C78FF778682FF7D8C88FF
+ 808F8BFF808F8BFF7D8C88FF81908CFF889793FF8F9E9AFF93A29EFF93A29EFF
+ 91A09CFF8F9E9AFF8C9A96FF8E9C98FF909E9AFF919F9BFF919F9BFF92A09CFF
+ 92A09CFF93A19DFF8D9B97FF9BA9A5FF95A39FFF93A19DFF93A19DFFAFBDB9FF
+ DFEDE9FFE1F0ECFFD9EAE7FFC6D9D6FFACBFBCFF9AADAAFF9AABA8FF9EAFACFF
+ 9CAAA8FF94A2A0FF95A3A1FF909E9CFF8F9C9AFF94A19FFF97A2A0FF929D9BFF
+ 8E9997FF8E9997FF8D9A98FF8C9997FF8E9B99FF909D9BFF8C9997FF889593FF
+ 8B9896FF93A09EFF98A5A3FF93A09EFF8B9896FF83908EFF7D8A88FF788583FF
+ 73807EFF6F7D79FF838C89FF8F9993FF929B98FF929B98FF8E9996FF84928EFF
+ 8A9795FFA0AEACFFB4C5C2FFC4D7D4FFBBCDCCFFB8CDCBFFA9BEBFFF9CB1B2FF
+ 778C8DFF91A7A5FF8BA19FFF849B97FF809592FF7F9491FF7C918EFF788D8AFF
+ 7C8F8CFF819491FF80918EFF7D8E8BFF778885FF748582FF7B8987FF818F8DFF
+ 7D8B89FF758381FF6D7B77FF636E6BFF36413EFF4F5A57FF5F6A67FF6B7673FF
+ 687370FF6C7774FF7A8582FF87928FFF8C9794FF85908DFF838E8BFF8A9592FF
+ 8D9895FF889390FF869490FF889692FF8A9894FF8D9B97FF8F9D99FF919F9BFF
+ 92A09CFF92A09CFF909E9AFF93A19DFF98A6A2FF9CAAA6FF9DABA7FF9CAAA6FF
+ 9AA8A4FF98A6A2FF98A49EFF99A59FFF96A49EFF92A09AFF8E9C96FF8E9C96FF
+ 92A29BFF96A69FFF8A9C95FF8D9F98FF90A29BFF8FA19AFF90A59DFFA3B8B0FF
+ C6DBD3FFE1F8F0FFE3FAF6FFDFF8F4FFDDF6F2FFDCF5F1FFDDF6F2FFDDF6F2FF
+ DAF3EFFFD5EEEAFFDAF3EFFFDBF4F0FFDAF3EFFFD5EEEAFFD3ECE8FFD1EAE6FF
+ C9E2DEFFBFD8D4FFB0C7C3FFB7CECAFFAEC3C0FFA4B9B6FFAFC4C1FF5D726FFF
+ 607370FF738683FF7D8E8BFF788986FF738481FF748582FF7E8C8AFF889694FF
+ 8D9B99FF8D9C98FF82918DFF8E9E97FF92A29BFF889891FF85958EFF8E9E97FF
+ 93A39CFF8F9F98FF879790FF81918AFF7F8F88FF83938CFF889891FF86968FFF
+ 809089FF7C8A84FF848E88FF8C938EFF909792FF919893FF959C97FF9CA39EFF
+ A0A7A2FF9FA6A1FF929994FF909792FF979E99FFA6ADA8FFAFB6B1FFADB4AFFF
+ A9B0ABFFA7B1ABFF9EAAA4FFA0ACA6FFA9B5AFFFABB7B1FFA2AEA8FFA1ADA7FF
+ A3AFA9FF9EAAA4FF95A19BFF97A39DFF9AA6A0FF9CA8A2FF91A8A4FF9DB4B0FF
+ A0B7B3FF97AEAAFF97AEAAFFA5BCB8FFAEC5C1FFACC3BFFFA3BAB6FFAFC6C2FF
+ A9C0BCFF94ABA7FF92A9A5FFA4BBB7FFACC3BFFFA4BBB7FFA7C0BCFFA3BCB8FF
+ 9FB6B2FF9EB5B1FFA0B7B3FF9EB5B1FF91A6A3FF829794FF839693FF8EA19EFF
+ 8EA19EFF8EA19EFF94A5A2FF859693FF6C7D7AFF647270FF464F4CFF474E4BFF
+ 5E6562FF5F6663FF59605DFF555C59FF49504DFF565D5AFF474E4BFF585F5CFF
+ 5F6663FF5F6663FF707774FF8C9390FF959C99FF89928FFFA0AEAAFFA4B3AFFF
+ 9FAEAAFF9BAAA6FF97A8A4FF8E9F9BFF91A29EFFA6B7B3FFA1B5B0FFA9BDB8FF
+ ADC3BEFFACC2BDFFABC1BCFFAFC5C0FFB1C8C3FFB1C8C3FFAABDBAFFAABDBAFF
+ A8BBB8FFA3B6B3FF9CAFACFF96A9A6FF91A4A1FF90A3A0FF99ACA9FF91A4A1FF
+ 8C9F9CFF8C9F9CFF8A9D9AFF829592FF7B8E8BFF798C89FF6B7A76FF62716DFF
+ 5D6C68FF657470FF72817DFF7A8985FF7D8C88FF7F8E8AFF808F8BFF859490FF
+ 8B9A96FF8F9E9AFF8F9E9AFF8F9E9AFF909F9BFF92A19DFF84928EFF889692FF
+ 8D9B97FF919F9BFF92A09CFF92A09CFF92A09CFF92A09CFF8E9C98FF94A29EFF
+ 99A7A3FF9DABA7FF899793FF99A7A3FFD6E4E0FFE7F6F2FFEAFBF8FFDAEDEAFF
+ BDD0CDFFA1B4B1FF9BACA9FFA0B1AEFF9DABA9FF8F9D9BFF97A5A3FF919F9DFF
+ 8F9C9AFF93A09EFF97A2A0FF939E9CFF8F9A98FF8F9A98FF95A2A0FF93A09EFF
+ 94A19FFF94A19FFF8E9B99FF889593FF8A9795FF919E9CFF909D9BFF8A9795FF
+ 84918FFF828F8DFF83908EFF7D8A88FF717E7CFF667470FF838C89FF909A94FF
+ 939C99FF8F9895FF899491FF7E8C88FF8A9795FFA7B5B3FFBCCDCAFFC8DBD8FF
+ BACCCBFFBCD1CFFFB2C7C8FFA7BCBDFF7F9495FF8AA09EFF889E9CFF839A96FF
+ 819693FF829794FF7F9491FF7A8F8CFF7C8F8CFF7F928FFF899A97FF879895FF
+ 81928FFF7E8F8CFF83918FFF859391FF7E8C8AFF74817FFF76817EFF687370FF
+ 384340FF525D5AFF646F6CFF727D7AFF6D7875FF6F7A77FF798481FF808B88FF
+ 808B88FF7B8683FF828D8AFF919C99FF949F9CFF8B9693FF818F8BFF83918DFF
+ 879591FF8A9894FF8D9B97FF8F9D99FF909E9AFF909E9AFF94A29EFF97A5A1FF
+ 9CAAA6FFA0AEAAFFA1AFABFFA0AEAAFF9DABA7FF9AA8A4FFA2AEA8FFA2AEA8FF
+ 9CAAA4FF93A19BFF8A9892FF899791FF90A099FF98A8A1FF9DAFA8FF879992FF
+ 859790FF96A8A1FF96ABA3FF92A79FFFB3C8C0FFE2F9F1FFE1F8F4FFDEF7F3FF
+ DBF4F0FFDAF3EFFFDBF4F0FFDCF5F1FFD8F1EDFFD2EBE7FFD2EBE7FFD7F0ECFF
+ D7F0ECFFD2EBE7FFCEE7E3FFCBE4E0FFC5DEDAFFBED7D3FFBAD1CDFFBAD1CDFF
+ ABC0BDFF9FB4B1FFABC0BDFF708582FF596C69FF6C7F7CFF788986FF768784FF
+ 738481FF768784FF818F8DFF899795FF8B9997FF879692FF94A39FFF98A8A1FF
+ 98A8A1FF92A29BFF93A39CFF9BABA4FFA0B0A9FFA0B0A9FFA1B1AAFF96A69FFF
+ 90A099FF93A39CFF91A19AFF86968FFF7C8C85FF7A8882FF848E88FF8C938EFF
+ 909792FF909792FF949B96FF9DA49FFFA2A9A4FFA2A9A4FFA0A7A2FF959C97FF
+ 909792FF989F9AFFA1A8A3FFA3AAA5FFA4ABA6FFA6B0AAFF9EAAA4FF9CA8A2FF
+ A9B5AFFFB2BEB8FFA8B4AEFFA3AFA9FFA4B0AAFF9EAAA4FF96A29CFF97A39DFF
+ 9BA7A1FFA1ADA7FF9AB1ADFFA7BEBAFFAAC1BDFF9CB3AFFF8EA5A1FF8EA5A1FF
+ 98AFABFF9EB5B1FFA9C0BCFFA8BFBBFFA0B7B3FF99B0ACFF9EB5B1FFA9C0BCFF
+ A8BFBBFF9EB5B1FFA4BDB9FFA2BBB7FF95ACA8FF869D99FF8EA5A1FF9FB6B2FF
+ 98ADAAFF809592FF8A9D9AFF859895FF7C8F8CFF798C89FF829390FF81928FFF
+ 697A77FF4D5B59FF323B38FF363D3AFF525956FF5A615EFF59605DFF545B58FF
+ 474E4BFF545B58FF5D6461FF4D5451FF4A514EFF585F5CFF636A67FF676E6BFF
+ 737A77FF838C89FF99A7A3FF8D9C98FF8F9E9AFF9CABA7FF9AABA7FF8A9B97FF
+ 859692FF8D9E9AFF839792FFA2B6B1FFB9CFCAFFB8CEC9FFB0C6C1FFAEC4BFFF
+ AAC1BCFFA2B9B4FF9AADAAFFA1B4B1FFA3B6B3FF9CAFACFF92A5A2FF8EA19EFF
+ 8FA29FFF91A4A1FF9FB2AFFF98ABA8FF8C9F9CFF849794FF839693FF819491FF
+ 748784FF647774FF6F7E7AFF556460FF5A6965FF6B7A76FF687773FF73827EFF
+ 84938FFF7F8E8AFF808F8BFF859490FF8C9B97FF909F9BFF91A09CFF91A09CFF
+ 92A19DFF92A19DFF9BA9A5FF93A19DFF909E9AFF95A39FFF96A4A0FF909E9AFF
+ 8E9C98FF919F9BFF919F9BFF93A19DFF92A09CFF95A39FFF98A6A2FF9AA8A4FF
+ BAC8C4FFEBFAF6FFE3F6F3FFD3E8E5FFD2E5E2FFC9DCD9FFB0C3C0FF9DB0ADFF
+ 98A9A6FF8FA09DFF9EACAAFF99A7A5FF94A2A0FF92A09EFF93A09EFF919E9CFF
+ 8C9997FF879492FF8E9B99FF8C9997FF8E9B99FF929F9DFF909D9BFF889593FF
+ 84918FFF859290FF94A19FFF95A2A0FF909D9BFF859290FF818E8CFF818E8CFF
+ 7A8785FF707E7AFF808986FF97A19BFF969F9CFF838C89FF7A8582FF7F8D89FF
+ 94A19FFFAEBCBAFFC7D8D5FFBDD0CDFFC4D6D5FFC3D8D6FFAFC4C5FF9BB0B1FF
+ 8BA0A1FF7A908EFF8DA3A1FF829995FF7C918EFF7E9390FF7D928FFF768B88FF
+ 768986FF788B88FF7F908DFF889996FF8A9B98FF81928FFF7B8987FF798785FF
+ 758381FF707D7BFF747F7CFF5B6461FF323B38FF656E6BFF68716EFF6F7875FF
+ 757E7BFF6D7673FF6D7673FF757E7BFF7B8481FF7C8582FF7F8885FF858E8BFF
+ 8C9592FF8E9996FF8C9A96FF8D9B97FF8F9D99FF93A19DFF97A5A1FF9AA8A4FF
+ 9AA8A4FF9AA8A4FF97A5A1FF98A6A2FF9AA8A4FF9BA9A5FF9CAAA6FF9CAAA6FF
+ 9CAAA6FF9BA9A5FF939F99FF97A39DFF98A6A0FF96A49EFF92A09AFF92A09AFF
+ 96A69FFF9CACA5FF96A8A1FF9DAFA8FF98AAA3FF91A39CFF95AAA2FF9EB3ABFF
+ B1C6BEFFCBE2DAFFDBF2EEFFDBF4F0FFD9F2EEFFD4EDE9FFD5EEEAFFD8F1EDFF
+ D3ECE8FFC8E1DDFFD0E9E5FFD5EEEAFFD2EBE7FFC9E2DEFFC7E0DCFFCCE5E1FF
+ C8E1DDFFBCD5D1FFB4CBC7FFB8CFCBFFB7CCC9FFAFC4C1FF9AAFACFF778C89FF
+ 6D807DFF819491FF869794FF7F908DFF7C8D8AFF7E8F8CFF83918FFF82908EFF
+ 859391FF899894FF94A5A1FF98AAA3FF9DAFA8FF9CAEA7FF96A8A1FF94A69FFF
+ 9CAEA7FFA7B9B2FFA4B6AFFF9AACA5FF92A49DFF8A9C95FF8B9D96FF96A8A1FF
+ 899B94FF66766FFF727E78FF7E8882FF89938DFF8F9993FF919B95FF929C96FF
+ 97A19BFF9CA6A0FF9EA8A2FF9DA7A1FF9CA6A0FF9AA49EFF9AA49EFF9BA59FFF
+ 9DA7A1FF9EA8A2FF9AA6A0FF9FABA5FFA3AFA9FFA4B0AAFFA4B0AAFFA3AFA9FF
+ 9FABA5FF9AA6A0FF929E98FF8C9892FF8C9892FF95A19BFFA9C0BCFFB3CAC6FF
+ B4CBC7FFA6BDB9FF98AFABFF95ACA8FF99B0ACFF9BB2AEFFA5BCB8FFACC3BFFF
+ A9C0BCFF9FB6B2FF9BB2AEFFA1B8B4FFA3BAB6FF9DB4B0FF8DA6A2FF9DB6B2FF
+ A6BDB9FF99B0ACFF8EA5A1FF92A9A5FF9AAFACFF9CB1AEFF8EA19EFF859895FF
+ 758885FF6A7D7AFF71827FFF768784FF697A77FF576563FF3A4340FF3A413EFF
+ 565D5AFF5E6562FF575E5BFF4D5451FF434A47FF5A615EFF666D6AFF555C59FF
+ 4B524FFF4F5653FF525956FF555C59FF656C69FF77807DFF84928EFF93A29EFF
+ 9AA9A5FF93A29EFF8FA09CFF96A7A3FF96A7A3FF8FA09CFF7B8F8AFF8B9F9AFF
+ A0B6B1FFB1C7C2FFB0C6C1FFA4BAB5FF98AFAAFF94ABA6FF99ACA9FFA0B3B0FF
+ A5B8B5FFA2B5B2FF9AADAAFF94A7A4FF92A5A2FF92A5A2FF9CAFACFF99ACA9FF
+ 90A3A0FF869996FF7F928FFF7B8E8BFF708380FF657875FF576662FF404F4BFF
+ 4C5B57FF657470FF697874FF71807CFF7F8E8AFF7E8D89FF889793FF8C9B97FF
+ 909F9BFF91A09CFF909F9BFF8E9D99FF8E9D99FF8E9D99FF94A29EFF8E9C98FF
+ 8D9B97FF93A19DFF95A39FFF92A09CFF92A09CFF95A39FFF94A29EFF95A39FFF
+ 92A09CFF93A19DFF95A39FFF94A29EFFAEBCB8FFD9E8E4FFE5F8F5FFD5EAE7FF
+ D1E4E1FFCCDFDCFFBBCECBFFABBEBBFFA3B4B1FF98A9A6FF9CAAA8FF97A5A3FF
+ 92A09EFF909E9CFF919E9CFF8F9C9AFF899694FF84918FFF869391FF859290FF
+ 889593FF8E9B99FF8F9C9AFF899694FF869391FF879492FF879492FF8E9B99FF
+ 909D9BFF879492FF808D8BFF7E8B89FF7A8785FF75837FFF838C89FF97A19BFF
+ 97A09DFF8A9390FF87928FFF8D9B97FF9EABA9FFB3C1BFFFC1D2CFFFBBCECBFF
+ BFD1D0FFBACFCDFFAABFC0FFA2B7B8FF99AEAFFF869C9AFF97ADABFF8BA29EFF
+ 829794FF7E9390FF798E8BFF718683FF6F827FFF708380FF7E8F8CFF859693FF
+ 889996FF829390FF808E8CFF7F8D8BFF7B8987FF768381FF747F7CFF59625FFF
+ 323B38FF5D6663FF5F6865FF69726FFF767F7CFF757E7BFF767F7CFF79827FFF
+ 7C8582FF7D8683FF7F8885FF848D8AFF89928FFF899491FF95A09DFF93A19DFF
+ 93A19DFF94A29EFF94A29EFF93A19DFF92A09CFF909E9AFF96A4A0FF96A4A0FF
+ 96A4A0FF96A4A0FF95A39FFF95A39FFF95A39FFF95A39FFF96A29CFF9BA7A1FF
+ 9DABA5FF9DABA5FF98A6A0FF96A49EFF97A7A0FF9AAAA3FF91A39CFF9BADA6FF
+ 99ABA4FF96A8A1FF98ADA5FF9AAFA7FFA8BDB5FFBFD6CEFFD2E9E5FFD2EBE7FF
+ CEE7E3FFC9E2DEFFCBE4E0FFD2EBE7FFD5EEEAFFD1EAE6FFCFE8E4FFD0E9E5FF
+ CDE6E2FFC9E2DEFFC8E1DDFFC9E2DEFFC5DEDAFFBED7D3FFB6CDC9FFB4CBC7FF
+ ACC1BEFFA7BCB9FF9BB0ADFF7D928FFF718481FF7F928FFF8E9F9CFF879895FF
+ 849592FF879895FF8B9997FF889694FF869492FF879692FF90A19DFF97A9A2FF
+ A0B2ABFFA2B4ADFF9CAEA7FF94A69FFF92A49DFF94A69FFF91A39CFF94A69FFF
+ 9BADA6FF98AAA3FF8EA099FF92A49DFF92A49DFF84948DFF75817BFF7A8680FF
+ 848E88FF89958FFF909A94FF94A09AFF9BA59FFF9DA9A3FFA2ACA6FF9FABA5FF
+ A0AAA4FF9EAAA4FFA1ABA5FFA1ADA7FFA5AFA9FFA4B0AAFFA4B0AAFFA5B1ABFF
+ A7B3ADFFABB7B1FFAEBAB4FFABB7B1FFA0ACA6FF95A19BFF909C96FF8A9690FF
+ 8A9690FF919D97FFA7BEBAFFACC3BFFFADC4C0FFA4BBB7FF9BB2AEFF96ADA9FF
+ 94ABA7FF91A8A4FF9DB4B0FFAAC1BDFFAEC5C1FFA2B9B5FF98AFABFF9BB2AEFF
+ A0B7B3FFA0B7B3FF8FA8A4FF94ADA9FF9AB1ADFF9BB2AEFF98AFABFF96ADA9FF
+ 99AEABFF9BB0ADFF99ACA9FF92A5A2FF829592FF738683FF758683FF7A8B88FF
+ 748582FF687674FF414C49FF3B4441FF545D5AFF606966FF565F5CFF464F4CFF
+ 414A47FF626B68FF6A7370FF5C6562FF515A57FF4D5653FF4A5350FF4A5350FF
+ 555E5BFF626D6AFF6A7874FF82918DFF93A29EFF92A19DFF91A29EFF9AABA7FF
+ 9CADA9FF94A5A1FF8A9E99FF899D98FF96ACA7FFB0C6C1FFB7CDC8FFA9BFBAFF
+ 9EB5B0FF9FB6B1FF9BAEABFFA0B3B0FFA3B6B3FFA1B4B1FF97AAA7FF8C9F9CFF
+ 849794FF819491FF839693FF839693FF7D908DFF708380FF647774FF5D706DFF
+ 556865FF4D605DFF41504CFF2E3D39FF3D4C48FF606F6BFF6D7C78FF72817DFF
+ 7C8B87FF808F8BFF889793FF8A9995FF8C9B97FF8C9B97FF8A9995FF899894FF
+ 8B9A96FF8D9C98FF92A09CFF8D9B97FF8C9A96FF909E9AFF93A19DFF92A09CFF
+ 92A09CFF94A29EFF9AA8A4FF9AA8A4FF95A39FFF96A4A0FF98A6A2FF93A19DFF
+ A4B2AEFFC6D5D1FFDDF0EDFFD1E6E3FFCADFDCFFC6DBD8FFBDD2CFFFAEC3C0FF
+ A1B4B1FF98ABA8FF98A9A6FF93A4A1FF909E9CFF8E9C9AFF8E9C9AFF8C9A98FF
+ 869492FF818F8DFF818E8CFF808D8BFF859290FF8C9997FF8C9997FF879492FF
+ 83908EFF84918FFF7D8A88FF889593FF909D9BFF8A9795FF808D8BFF7A8785FF
+ 788583FF768480FF818A87FF909A94FF919A97FF8D9693FF96A19EFF9FADA9FF
+ ADBAB8FFBECCCAFFC8D9D6FFC5D8D5FFC3D5D4FFB2C7C5FFA1B6B7FFA3B8B9FF
+ 9CB1B2FF839997FF8EA4A2FF869D99FF809592FF7D928FFF7A8F8CFF758A87FF
+ 758885FF768986FF7A8B88FF7D8E8BFF7E8F8CFF7C8D8AFF7D8B89FF7C8A88FF
+ 768482FF707D7BFF6F7A77FF57605DFF3F4845FF616A67FF616A67FF68716EFF
+ 757E7BFF78817EFF767F7CFF757E7BFF757E7BFF78817EFF7E8784FF838C89FF
+ 868F8CFF86918EFF939E9BFF92A09CFF93A19DFF93A19DFF92A09CFF919F9BFF
+ 919F9BFF909E9AFF9CAAA6FF9AA8A4FF98A6A2FF96A4A0FF95A39FFF96A4A0FF
+ 96A4A0FF97A5A1FF9BA7A1FFA0ACA6FFA3B1ABFFA3B1ABFF9EACA6FF9AA8A2FF
+ 97A7A0FF98A8A1FF92A49DFF9AACA5FF98AAA3FF95A7A0FF96ABA3FF98ADA5FF
+ A8BDB5FFC3DAD2FFD1E8E4FFCFE8E4FFCAE3DFFFC3DCD8FFC3DCD8FFCBE4E0FF
+ D5EEEAFFD9F2EEFFCFE8E4FFC9E2DEFFC7E0DCFFC9E2DEFFC8E1DDFFC2DBD7FF
+ BED7D3FFBED7D3FFBFD6D2FFB5CCC8FFA7BCB9FFA5BAB7FFA1B6B3FF899E9BFF
+ 7A8D8AFF839693FF8C9D9AFF859693FF849592FF8C9D9AFF94A2A0FF92A09EFF
+ 8E9C9AFF8C9B97FF8FA09CFF95A7A0FF9BADA6FF9CAEA7FF98AAA3FF92A49DFF
+ 8D9F98FF8A9C95FF8A9C95FF8B9D96FF98AAA3FF9AACA5FF8D9F98FF889A93FF
+ 899B94FF84948DFF7C8A84FF7B8983FF7F8B85FF83918BFF8D9993FF92A09AFF
+ 97A39DFF96A49EFF99A59FFF96A49EFF98A49EFF97A59FFF9BA7A1FF9CAAA4FF
+ A2AEA8FFA1AFA9FFA0AEA8FF9BA9A3FF98A6A0FF9FADA7FFA8B6B0FFAAB8B2FF
+ A1AFA9FF98A6A0FF93A19BFF909E98FF8F9D97FF94A29CFF9BB2AEFF9DB4B0FF
+ 9EB5B1FF9EB5B1FF9CB3AFFF99B0ACFF94ABA7FF90A7A3FF97AEAAFFA4BBB7FF
+ A8BFBBFF9CB3AFFF94ABA7FF99B0ACFFA1B8B4FFA3BAB6FF99B2AEFF8FA8A4FF
+ 8EA5A1FF95ACA8FF98AFABFF90A7A3FF8CA19EFF8EA3A0FF8A9D9AFF8B9E9BFF
+ 849794FF778A87FF738481FF71827FFF667774FF596765FF46514EFF343F3CFF
+ 4C5552FF5C6764FF5C6562FF4B5653FF4A5350FF6C7774FF6F7875FF646F6CFF
+ 5D6663FF586360FF58615EFF525D5AFF525B58FF4F5A57FF566460FF5C6B67FF
+ 71807CFF8B9A96FF93A4A0FF8E9F9BFF8FA09CFF98A9A5FF99ADA8FF96AAA5FF
+ 9AB0ABFFA9BFBAFFB2C8C3FFB0C6C1FFAEC5C0FFB2C9C4FF9DB0ADFF9BAEABFF
+ 98ABA8FF92A5A2FF869996FF768986FF6B7E7BFF687B78FF5B6E6BFF5D706DFF
+ 5A6D6AFF526562FF4C5F5CFF4A5D5AFF455855FF3F524FFF404F4BFF303F3BFF
+ 3A4945FF5B6A66FF707F7BFF758480FF7C8B87FF869591FF859490FF879692FF
+ 899894FF899894FF8A9995FF8D9C98FF91A09CFF95A4A0FF95A39FFF919F9BFF
+ 8E9C98FF8E9C98FF8F9D99FF8F9D99FF8E9C98FF8E9C98FF97A5A1FF98A6A2FF
+ 93A19DFF94A29EFF98A6A2FF93A19DFF9CAAA6FFB7C6C2FFD1E4E1FFCFE4E1FF
+ CBE0DDFFC6DBD8FFBDD2CFFFA8BDBAFF98ABA8FF96A9A6FF97A8A5FF92A3A0FF
+ 8F9D9BFF8D9B99FF8E9C9AFF8C9A98FF879593FF82908EFF83908EFF828F8DFF
+ 869391FF8B9896FF8A9795FF83908EFF7E8B89FF7E8B89FF7B8886FF84918FFF
+ 8C9997FF8B9896FF84918FFF7C8987FF778482FF75837FFF7E8784FF86908AFF
+ 848D8AFF87908DFF99A4A1FFA7B5B1FFB4C1BFFFC4D2D0FFC5D6D3FFC8DBD8FF
+ C6D8D7FFAEC3C1FF9DB2B3FFA5BABBFF9DB2B3FF7B918FFF819795FF7F9692FF
+ 7F9491FF7F9491FF7E9390FF7B908DFF7A8D8AFF7A8D8AFF7B8C89FF7A8B88FF
+ 788986FF778885FF798785FF768482FF6E7C7AFF677472FF65706DFF535C59FF
+ 4F5855FF67706DFF67706DFF656E6BFF6B7471FF6C7572FF6A7370FF666F6CFF
+ 67706DFF707976FF7B8481FF828B88FF87908DFF8A9390FF899491FF8A9894FF
+ 8F9D99FF92A09CFF94A29EFF97A5A1FF99A7A3FF9BA9A5FF9FADA9FF9DABA7FF
+ 9AA8A4FF97A5A1FF97A5A1FF98A6A2FF9AA8A4FF9CAAA6FFA1ADA7FFA4B0AAFF
+ A5B3ADFFA4B2ACFF9FADA7FF9BA9A3FF98A8A1FF98A8A1FF99ABA4FF9CAEA7FF
+ 94A69FFF8FA19AFF91A69EFF97ACA4FFB0C5BDFFD4EBE3FFDBF2EEFFD7F0ECFF
+ D1EAE6FFC8E1DDFFC4DDD9FFC8E1DDFFD1EAE6FFD8F1EDFFD0E9E5FFC5DEDAFF
+ C2DBD7FFC8E1DDFFC6DFDBFFBAD3CFFFB5CECAFFB9D2CEFFC0D7D3FFB3CAC6FF
+ A4B9B6FFA2B7B4FFA0B5B2FF899E9BFF7A8D8AFF839693FF8A9B98FF829390FF
+ 7E8F8CFF859693FF8E9C9AFF8C9A98FF889694FF859490FF8FA09CFF8FA19AFF
+ 8C9E97FF869891FF859790FF899B94FF8C9E97FF8C9E97FF98AAA3FF8B9D96FF
+ 90A29BFF99ABA4FF91A39CFF879992FF7D8F88FF6E8079FF74847DFF73837CFF
+ 74847DFF7B8B84FF86968FFF8E9E97FF90A099FF8F9F98FF9BABA4FF9BABA4FF
+ 9CACA5FF9EAEA7FFA2B2ABFFA6B6AFFFABBBB4FFADBDB6FFACBCB5FFA2B2ABFF
+ 9CAAA4FF9EAEA7FFA6B4AEFFA8B8B1FFA8B6B0FFA6B6AFFF919F99FF8F9F98FF
+ 919F99FF92A29BFFA2B9B5FFA0B7B3FFA0B7B3FFA4BBB7FFA6BDB9FFA4BBB7FF
+ 9FB6B2FF9CB3AFFF9CB3AFFFA2B9B5FF9FB6B2FF94ABA7FF90A7A3FF99B0ACFF
+ 9FB6B2FF9DB4B0FF95AEAAFF90A9A5FF94ABA7FF96ADA9FF8CA39FFF7E9591FF
+ 829794FF91A6A3FF899C99FF8FA29FFF8B9E9BFF7E918EFF768784FF70817EFF
+ 627370FF53615FFF42504CFF2A3834FF3F4A47FF566460FF626D6AFF596763FF
+ 56615EFF73817DFF7A8582FF707E7AFF66716EFF5E6C68FF616C69FF5E6C68FF
+ 56615EFF485652FF485753FF475652FF51605CFF677672FF788985FF82938FFF
+ 8A9B97FF92A39FFF8DA19CFF99ADA8FF9FB5B0FF9FB5B0FFA2B8B3FFACC2BDFF
+ B0C7C2FFAEC5C0FF97AAA7FF8DA09DFF859895FF819491FF798C89FF6D807DFF
+ 667976FF667976FF536663FF546764FF526562FF516461FF556865FF5A6D6AFF
+ 576A67FF4F625FFF4E5D59FF42514DFF3E4D49FF52615DFF6B7A76FF74837FFF
+ 7B8A86FF879692FF879692FF899894FF8B9A96FF8C9B97FF8D9C98FF91A09CFF
+ 97A6A2FF9CABA7FF96A4A0FF93A19DFF8F9D99FF8C9A96FF8C9A96FF8E9C98FF
+ 8E9C98FF8C9A96FF8C9A96FF909E9AFF8E9C98FF909E9AFF96A4A0FF92A09CFF
+ 98A6A2FFADBCB8FFC6DBD8FFD4EBE7FFD4EBE7FFCBE2DEFFC1D6D3FFA2B7B4FF
+ 8EA19EFF95A8A5FF95A8A5FF90A3A0FF8D9E9BFF8C9D9AFF909E9CFF8F9D9BFF
+ 8A9896FF859391FF869391FF84918FFF859290FF8A9795FF889593FF828F8DFF
+ 7E8B89FF7F8C8AFF7A8785FF7C8987FF828F8DFF879492FF889593FF84918FFF
+ 7E8B89FF7A8884FF818A87FF838D87FF7C8582FF7E8784FF8F9A97FF9BA9A5FF
+ A9B6B4FFBCCAC8FFB0C1BEFFBACDCAFFBFD1D0FFADC2C0FFA2B7B8FFACC1C2FF
+ 9FB4B5FF778D8BFF7D9391FF819894FF849996FF849996FF809592FF7B908DFF
+ 778A87FF728582FF7E8F8CFF7B8C89FF798A87FF7B8C89FF7E8C8AFF798785FF
+ 717F7DFF6C7977FF68716EFF555C59FF5E6562FF666D6AFF656C69FF606764FF
+ 636A67FF656C69FF646B68FF5F6663FF636A67FF717875FF7E8582FF848B88FF
+ 888F8CFF8B9491FF899491FF8C9A96FF919F9BFF94A29EFF95A39FFF97A5A1FF
+ 9BA9A5FF9EACA8FF9AA8A4FF98A6A2FF96A4A0FF95A39FFF95A39FFF98A6A2FF
+ 9BA9A5FF9DABA7FFA5B1ABFFA5B1ABFFA2B0AAFF9FADA7FF9CAAA4FF9AA8A2FF
+ 99A9A2FF9AAAA3FF9AACA5FF9BADA6FF95A7A0FF91A39CFF91A69EFF94A9A1FF
+ ADC2BAFFD4EBE3FFDEF5F1FFDAF3EFFFD6EFEBFFD0E9E5FFC9E2DEFFC7E0DCFF
+ CCE5E1FFD2EBE7FFD0E9E5FFC5DEDAFFC0D9D5FFC5DEDAFFC2DBD7FFB5CECAFF
+ AFC8C4FFB3CCC8FFB3CAC6FFABC2BEFFA0B5B2FF9DB2AFFF96ABA8FF7D928FFF
+ 708380FF7C8F8CFF8A9B98FF80918EFF788986FF7A8B88FF7E8C8AFF7B8987FF
+ 788684FF778682FF8C9D99FF8A9F97FF849991FF7B9088FF7B9088FF849991FF
+ 8BA098FF8BA098FF899E96FF7D928AFF81968EFF8BA098FF859A92FF7E938BFF
+ 788D85FF6D827AFF7D8F88FF7E9089FF81938CFF879992FF8FA19AFF95A7A0FF
+ 97A9A2FF96A8A1FF8B9D96FF8B9D96FF8D9F98FF90A29BFF95A7A0FF9AACA5FF
+ 9FB1AAFFA2B4ADFFB2C4BDFFACBEB7FFABBBB4FFADBFB8FFAEBEB7FFA6B8B1FF
+ A6B6AFFFA7B9B2FFB4C4BDFFB5C7C0FFB9C9C2FFB8CAC3FFB4CBC7FFADC4C0FF
+ A9C0BCFFAAC1BDFFAAC1BDFFA5BCB8FFA1B8B4FFA0B7B3FFA3BAB6FFA5BCB8FF
+ 9EB5B1FF92A9A5FF90A7A3FF97AEAAFF98AFABFF91A8A4FF98B1ADFF8CA5A1FF
+ 889F9BFF8DA4A0FF91A8A4FF8CA39FFF8A9F9CFF8DA29FFF94A7A4FF97AAA7FF
+ 90A3A0FF809390FF788986FF738481FF687976FF5A6B68FF394844FF25332FFF
+ 394743FF53615DFF64726EFF667470FF5F6D69FF768480FF83918DFF7D8B87FF
+ 6E7C78FF62706CFF63716DFF6A7874FF64726EFF576561FF4D5C58FF556460FF
+ 4F5E5AFF465551FF596A66FF839490FF95A6A2FF8D9E9AFF849893FF9DB1ACFF
+ ABC1BCFFA9BFBAFFA7BDB8FFAEC4BFFFAEC5C0FFA7BEB9FF91A4A1FF839693FF
+ 7A8D8AFF7D908DFF7D908DFF788B88FF788B88FF7E918EFF778A87FF758885FF
+ 6F827FFF6A7D7AFF6A7D7AFF6A7D7AFF627572FF586B68FF5E6D69FF566561FF
+ 44534FFF455450FF606F6BFF71807CFF788783FF84938FFF879692FF889793FF
+ 899894FF899894FF889793FF8A9995FF8E9D99FF91A09CFF93A19DFF93A19DFF
+ 8F9D99FF8A9894FF8B9995FF919F9BFF919F9BFF8E9C98FF8B9995FF93A19DFF
+ 94A29EFF95A39FFF9AA8A4FF96A4A0FF9BA9A5FFAEBDB9FFB8CDCAFFD2E9E5FF
+ D6EDE9FFCDE4E0FFC4D9D6FF9EB3B0FF849794FF90A3A0FF93A6A3FF8FA29FFF
+ 8D9E9BFF8D9E9BFF92A09EFF92A09EFF8E9C9AFF899795FF859290FF828F8DFF
+ 83908EFF879492FF869391FF828F8DFF828F8DFF859290FF768381FF74817FFF
+ 788583FF828F8DFF889593FF879492FF859290FF85938FFF88918EFF89938DFF
+ 7F8885FF7C8582FF838E8BFF889692FF94A19FFFAAB8B6FFA8B9B6FFB3C6C3FF
+ BDCFCEFFB1C6C4FFA5BABBFFA7BCBDFF91A6A7FF667C7AFF728886FF7B928EFF
+ 839895FF839895FF819693FF809592FF7E918EFF788B88FF798A87FF778885FF
+ 788986FF7D8E8BFF808E8CFF7B8987FF768482FF768381FF7D8683FF616865FF
+ 6D7471FF636A67FF646B68FF616865FF676E6BFF6D7471FF646B68FF616865FF
+ 676E6BFF777E7BFF818885FF818885FF848B88FF89928FFF919C99FF94A29EFF
+ 97A5A1FF97A5A1FF94A29EFF92A09CFF94A29EFF97A5A1FF9AA8A4FF9AA8A4FF
+ 99A7A3FF98A6A2FF99A7A3FF9BA9A5FF9EACA8FF9FADA9FFA3AFA9FFA2AEA8FF
+ 9EACA6FF9CAAA4FF9AA8A2FF9AA8A2FF9AAAA3FF9BABA4FF95A7A0FF9AACA5FF
+ 99ABA4FF99ABA4FF95AAA2FF8EA39BFFA0B5ADFFC3DAD2FFD7EEEAFFD2EBE7FF
+ D0E9E5FFD0E9E5FFCCE5E1FFC6DFDBFFC5DEDAFFC9E2DEFFCCE5E1FFC5DEDAFF
+ C1DAD6FFC0D9D5FFBDD6D2FFB5CECAFFAEC7C3FFADC6C2FFABC2BEFFA9C0BCFF
+ A3B8B5FFA1B6B3FF98ADAAFF7B908DFF6E817EFF7A8D8AFF81928FFF7A8B88FF
+ 778885FF798A87FF7E8C8AFF7F8D8BFF82908EFF849591FF798A86FF7F948CFF
+ 81968EFF7B9088FF7A8F87FF82978FFF869B93FF839890FF8EA39BFF8EA39BFF
+ 98ADA5FF99AEA6FF8EA39BFF93A8A0FFA3B8B0FFA7BCB4FFB9CEC6FFBACFC7FF
+ B9CEC6FFB3C8C0FFAABFB7FFA5BAB2FFA7BCB4FFAABFB7FFBACFC7FFBBD0C8FF
+ BDD2CAFFC1D6CEFFC6DBD3FFCCE1D9FFD1E6DEFFD4E9E1FFD2E7DFFFD2E7DFFF
+ DEF0E9FFEAFFF7FFEEFFF9FFE2F7EFFFDEF0E9FFDEF3EBFFE4F6EFFFE8FDF5FF
+ EDFFF8FFEAFFF7FFC0D7D3FFB5CCC8FFABC2BEFFA7BEBAFFA2B9B5FF9AB1ADFF
+ 98AFABFF9BB2AEFFA2B9B5FFA6BDB9FFA3BAB6FF98AFABFF94ABA7FF98AFABFF
+ 94ABA7FF8BA29EFF95AEAAFF859E9AFF7C938FFF869D99FF98AFABFF9EB5B1FF
+ 92A7A4FF849996FF819491FF849794FF7C8F8CFF6E817EFF677875FF647572FF
+ 596A67FF4A5B58FF2F3E3AFF253430FF3E4D49FF53625EFF63726EFF697874FF
+ 62716DFF73827EFF788783FF7E8D89FF798884FF6E7D79FF6E7D79FF798884FF
+ 7A8985FF707F7BFF677672FF71807CFF697874FF586763FF647571FF8C9D99FF
+ 9FB0ACFF98A9A5FF8EA29DFF9EB2ADFFADC3BEFFB3C9C4FFB1C7C2FFAEC4BFFF
+ ABC2BDFFA9C0BBFF99ACA9FF899C99FF809390FF869996FF8B9E9BFF889B98FF
+ 8A9D9AFF91A4A1FF91A4A1FF91A4A1FF8A9D9AFF7D908DFF738683FF6C7F7CFF
+ 637673FF5B6E6BFF667571FF677672FF4A5955FF3A4945FF586763FF73827EFF
+ 798884FF81908CFF869591FF889793FF899894FF879692FF859490FF859490FF
+ 879692FF899894FF96A4A0FF97A5A1FF919F9BFF8A9894FF8A9894FF919F9BFF
+ 919F9BFF8C9A96FF8C9A96FF98A6A2FF9AA8A4FF97A5A1FF99A7A3FF94A29EFF
+ 99A7A3FFABBAB6FFACC1BEFFCCE3DFFFD1E8E4FFCDE4E0FFCCE1DEFFA4B9B6FF
+ 819693FF8CA19EFF90A3A0FF8DA09DFF8B9C99FF8D9E9BFF90A19EFF91A29FFF
+ 909E9CFF8C9A98FF899694FF84918FFF828F8DFF83908EFF828F8DFF7F8C8AFF
+ 808D8BFF84918FFF768381FF73807EFF768381FF7E8B89FF818E8CFF7F8C8AFF
+ 83908EFF8A9894FF8A9390FF8E9892FF87908DFF818A87FF7F8A87FF7B8985FF
+ 879492FFA0AEACFFA7B8B5FFAEC1BEFFBACCCBFFB4C9C7FFA6BBBCFF9EB3B4FF
+ 819697FF556B69FF6D8381FF788F8BFF7F9491FF7E9390FF7E9390FF829794FF
+ 859895FF819491FF7A8B88FF788986FF7C8D8AFF829390FF83918FFF7B8987FF
+ 788684FF7D8A88FF88918EFF676E6BFF79807DFF646B68FF69706DFF666D6AFF
+ 6B726FFF717875FF616865FF606764FF6A716EFF7C8380FF828986FF7D8481FF
+ 7F8683FF87908DFF8F9A97FF92A09CFF97A5A1FF96A4A0FF92A09CFF919F9BFF
+ 94A29EFF97A5A1FF9DABA7FF9DABA7FF9DABA7FF9DABA7FF9DABA7FF9DABA7FF
+ 9DABA7FF9EACA8FF9EAAA4FF9EAAA4FF9CAAA4FF9CAAA4FF9DABA5FF9DABA5FF
+ 9CACA5FF9BABA4FF96A8A1FF9AACA5FF9AACA5FF9CAEA7FF97ACA4FF8CA199FF
+ 9CB1A9FFC0D7CFFFD5ECE8FFCCE5E1FFCAE3DFFFCCE5E1FFCBE4E0FFC3DCD8FF
+ BFD8D4FFC0D9D5FFC4DDD9FFC5DEDAFFC1DAD6FFBBD4D0FFB9D2CEFFB8D1CDFF
+ B3CCC8FFACC5C1FFA9C0BCFFA8BFBBFFA5BAB7FFA8BDBAFFA2B7B4FF849996FF
+ 738683FF7C8F8CFF8A9B98FF899A97FF8C9D9AFF92A3A0FF96A4A2FF96A4A2FF
+ 9CAAA8FFA2B3AFFFAFC0BCFFBFD4CCFFC9DED6FFC7DCD4FFC8DDD5FFD3E8E0FF
+ DAEFE7FFD8EDE5FFC4D9D1FFBFD4CCFFBBD0C8FFAEC3BBFFA4B9B1FFBACFC7FF
+ D6EBE3FFDBF0E8FFD7EEE6FFDAF1E9FFD6EDE5FFC3DAD2FFADC4BCFFA3BAB2FF
+ A9C0B8FFB4CBC3FFC1D8D0FFC2D9D1FFC4DBD3FFC8DFD7FFCDE4DCFFD3EAE2FF
+ D8EFE7FFDCF3EBFFBFD6CEFFBCD3CBFFC7DCD4FFD9F0E8FFE4F9F1FFDBF2EAFF
+ D8EDE5FFD8EFE7FFDEF3EBFFE4FBF3FFE9FEF6FFE2F9F1FFC5DCD8FFB7CECAFF
+ ABC2BEFFA5BCB8FF9DB4B0FF94ABA7FF93AAA6FF99B0ACFF99B0ACFFA4BBB7FF
+ A7BEBAFF9FB6B2FF9AB1ADFF9AB1ADFF96ADA9FF8DA4A0FF809793FF879E9AFF
+ 8CA39FFF8FA4A1FF8FA4A1FF90A5A2FF8FA4A1FF8EA19EFF778A87FF7E8F8CFF
+ 7B8C89FF71827FFF6C7D7AFF687674FF596765FF465452FF2A3935FF293834FF
+ 455450FF556460FF61706CFF687773FF61706CFF707F7BFF64736FFF798884FF
+ 859490FF7F8E8AFF7E8D89FF879894FF8D9C98FF869591FF83928EFF81908CFF
+ 81908CFF84938FFF899A96FF93A4A0FF9FB0ACFFA8B9B5FF95A9A4FF94A8A3FF
+ 9CB2ADFFABC1BCFFAAC0BBFFA0B6B1FF9FB6B1FFAAC0BBFFA9BCB9FF96A9A6FF
+ 8C9F9CFF92A5A2FF96A9A6FF90A3A0FF8EA19EFF93A6A3FF8A9D9AFF8FA29FFF
+ 8FA29FFF839693FF768986FF708380FF6E817EFF6E7F7CFF6A7876FF71807CFF
+ 505F5BFF374642FF566561FF778682FF7D8C88FF81908CFF8B9A96FF8B9C98FF
+ 8D9E9AFF8D9E9AFF8B9C98FF8A9B97FF8B9C98FF8D9E9AFF9CABA7FF9CABA7FF
+ 95A4A0FF8A9995FF889793FF8D9C98FF8C9B97FF859490FF859490FF91A29EFF
+ 95A4A0FF8E9F9BFF8B9C98FF859692FF8A9B97FF9DAEAAFFABC0BDFFCEE3E0FF
+ D2E9E5FFD2E9E5FFD8EFEBFFB2C9C5FF89A09CFF92A9A5FF8BA29EFF889D9AFF
+ 869B98FF8A9D9AFF8EA19EFF92A3A0FF8FA09DFF8D9B99FF8F9C9AFF889593FF
+ 83908EFF818E8CFF7E8B89FF7A8785FF7B8886FF7F8C8AFF7A8785FF788583FF
+ 7B8886FF7D8A88FF798684FF74817FFF7C8987FF899793FF868F8CFF909792FF
+ 8E9592FF87908DFF838C89FF7A8582FF84918FFF9FADABFF9EACAAFFA3B4B1FF
+ B1C3C2FFB3C8C6FFA8BDBEFF9DB2B3FF809596FF586E6CFF7A908EFF829794FF
+ 849996FF7C918EFF788D8AFF7C918EFF7F928FFF7C8F8CFF859693FF849592FF
+ 899A97FF8D9E9BFF889996FF7D8E8BFF7D8B89FF82908EFF7C8785FF5C6562FF
+ 77807DFF626B68FF6A7370FF646D6AFF636A67FF656C69FF59605DFF5B625FFF
+ 666F6CFF79827FFF7E8784FF77817BFF7A8380FF838E8BFF848F8CFF899793FF
+ 909E9AFF93A19DFF93A19DFF94A29EFF9AA8A4FFA0AEAAFF99A7A3FF99A7A3FF
+ 9AA8A4FF99A7A3FF99A7A3FF97A5A1FF96A4A0FF97A29FFF9AA6A0FF9BA7A1FF
+ 9EAAA4FFA1ADA7FFA3AFA9FFA0AEA8FF9EACA6FF9AAAA3FF9EAEA7FF9CAEA7FF
+ 99ABA4FF99ABA4FF96A8A1FF8DA29AFFA3B8B0FFCCE2DDFFD9F0ECFFCDE6E2FF
+ CAE1DDFFCBE4E0FFCBE2DEFFC1DAD6FFBCD3CFFFBAD3CFFFC0D7D3FFC4DDD9FF
+ C3DAD6FFB8D1CDFFB9D0CCFFBCD5D1FFBAD1CDFFAEC5C1FFA4B9B6FFA5B9B4FF
+ A2B5B2FFA9BDB8FFAABBB8FF8D9E9AFF758683FF7A8B87FFA9B7B5FFABBAB6FF
+ AFBDBBFFB2C1BDFFAEBBB9FFA7B5B1FFA9B6B4FFAFBEBAFFA2B4ADFFB5CAC1FF
+ C2D7CFFFC1D6CEFFC6DBD3FFD8EDE5FFE7FCF4FFEAFFF7FFDAEFE7FFC4D9D1FF
+ A8BDB5FF8FA49CFF8FA49CFFAEC5BDFFC7DCD4FFBBD1CCFFB8CEC9FFBDD4CFFF
+ BBD2CDFFA9C0BBFF92A9A4FF8DA49FFF9FB6B1FFB4CBC6FFAEC5C0FFAFC6C1FF
+ B1C8C3FFB5CCC7FFBAD1CCFFC0D7D2FFC6DDD8FFC9E0DBFFD6EDE5FFC6DDD5FF
+ C2D9D1FFCFE6DEFFD9F0E8FFD4EBE3FFD0E7DFFFD2E9E1FFCCE3DBFFD4EBE3FF
+ D7EEE6FFD0E7DFFFBAD1CDFFC1D8D4FFC0D7D3FFB1C8C4FF9FB6B2FF95ACA8FF
+ 91A8A4FF8EA5A1FF8DA4A0FF9DB4B0FFA7BEBAFFA4BBB7FF9CB3AFFF95ACA8FF
+ 8AA19DFF7F9692FF6C817EFF7E9390FF849996FF798C89FF718481FF798C89FF
+ 809390FF81928FFF768784FF859391FF849290FF879593FF6B7977FF63706EFF
+ 7C8987FF5F6C6AFF35433FFF33413DFF54625EFF5F6D69FF5E6C68FF6C7A76FF
+ 72817DFF81908CFF6E7F7BFF778884FF80918DFF82938FFF7E8F8BFF798D88FF
+ 7E8F8BFF82938FFF91A09CFF97A6A2FF93A4A0FF899A96FF879894FF8FA09CFF
+ 98A9A5FF9BACA8FF99ADA8FF9CB0ABFF9FB3AEFF9FB3AEFF9EB4AFFFA0B6B1FF
+ A2B8B3FFA2B8B3FF96A9A6FF94A6A5FF8EA09FFF889A99FF889A99FF889A99FF
+ 859796FF7F9190FF7D8F8EFF849695FF899B9AFF879998FF7C8E8DFF708281FF
+ 687A79FF677875FF64716FFF64716FFF5D6A68FF556260FF5A6866FF6A7876FF
+ 728380FF728380FF839491FF8A9D9AFF8BA09DFF849996FF819894FF879E9AFF
+ 8BA29EFF8A9F9CFF98ABA8FF9CADAAFF9EB1AEFFA1B4B1FFA4B7B4FFA9BCB9FF
+ ADC2BFFFB2C7C4FFB4C9C6FFAFC6C2FFBDD2CFFFCBE2DEFFCAE1DDFFC3DAD6FF
+ B1C8C4FF98AFABFFA4B7B4FFBDD0CDFFD5EAE7FFDBF2EEFFD0E9E5FFC5E0DCFF
+ C6E1DDFFC9E7E2FFB8D6D1FFA5C0BCFF90A9A5FF859C98FF849996FF889B98FF
+ 8C9D9AFF8E9F9CFF919F9DFF859391FF859391FF889694FF83918FFF849290FF
+ 808E8CFF717F7DFF7A8886FF788684FF7A8886FF7F8D8BFF7C8A88FF778583FF
+ 7B8987FF869490FF868D8AFF888E89FF868B89FF909794FFA0A7A4FF969F9CFF
+ 808B89FF7A8785FF899795FF859693FF9EB0AFFFB3C8C6FFACC1C2FFA3B8B9FF
+ 899E9FFF5B716FFF8CA19FFF889B98FF7E918EFF7A8D8AFF809390FF879A97FF
+ 849794FF7B8E8BFF849794FF819491FF7F928FFF7D908DFF7D908DFF7E918EFF
+ 80918EFF80918EFF7D8E8BFF495755FF6A7775FF657270FF6A7573FF5D6866FF
+ 5F6865FF606966FF58625CFF5E6862FF69756FFF76827CFF7A8882FF78877FFF
+ 74847DFF73837CFF83918DFF8B9693FF929D9AFF96A19EFF98A3A0FF98A3A0FF
+ 99A4A1FF9AA5A2FF9FAAA7FF9EA9A6FF9EA9A6FF9DA8A5FF9CA7A4FF9BA6A3FF
+ 9AA5A2FF9AA5A2FFA0A7A4FF9FA6A3FF9FA6A3FF9DA6A3FF9EA7A4FF9DA8A5FF
+ 9EA9A6FF9DABA7FF96A4A0FF96A5A1FF9EADA9FF93A4A0FF95A6A2FF97A8A4FF
+ 91A5A0FFB1C5C0FFCEE3E0FFC7DEDAFFC3D8D5FFC3DAD6FFC8DDDAFFC7DEDAFF
+ C1D6D3FFB7CECAFFB6CBC8FFB2C9C5FFB4C9C6FFB8CFCBFFB9CECBFFB2C9C5FF
+ ADC2BFFFAEC1BEFFBAC9C5FFBAC8C2FFB3C1BDFFB4C2BCFFBAC5C2FFADB9B3FF
+ A3AEABFFABB7B1FF9EA9A6FF9AA6A0FF95A09DFF94A09AFF95A09DFF94A09AFF
+ 919C99FF8D9993FF9DAEA5FF99ADA1FFADC0B7FFC2D5CCFFC2D5CCFFCBDED5FF
+ E1F6EDFFEFFFFBFFDFF6EEFFC1D8D0FF8DA39EFF7F9590FFA2B8B3FFB6CDC8FF
+ BBD1CCFFC8DFDBFFBBD4D0FFBDD6D2FFBDD6D2FFB9D2CEFFB4CDC9FFB4CDC9FF
+ B9D2CEFFBED7D3FFB1CAC6FFB1CAC6FFB3CCC8FFB7D0CCFFBBD4D0FFBDD6D2FF
+ BED7D3FFBDD6D2FFC0D7D2FFC5DCD7FFCBE2DDFFD0E7E2FFD2E9E4FFD4EBE6FF
+ D6EDE8FFD9F0EBFFD3EAE5FFD3EAE5FFD2E9E4FFD2E9E4FFA3BAB6FFB2C9C5FF
+ BDD4D0FFB8CFCBFFAAC1BDFF9DB4B0FF91A8A4FF89A09CFFA5BCB8FFA1B8B4FF
+ 9AB1ADFF9BB2AEFFA3BAB6FFA7BEBAFF98AFABFF849B97FF778A87FF7E918EFF
+ 7F928FFF778A87FF70817EFF6E7F7CFF6B7C79FF677875FF6C7A78FF798785FF
+ 7F8C8AFF899694FF758280FF687573FF747F7DFF525D5BFF36413EFF333E3BFF
+ 54625EFF64726EFF65736FFF6E7C78FF687773FF6D7C78FF6D7E7AFF72837FFF
+ 788985FF7B8C88FF7A8E89FF7B8F8AFF7D918CFF7F938EFF879894FF93A29EFF
+ 96A7A3FF91A29EFF8D9E9AFF8FA09CFF90A19DFF8E9F9BFF8FA39EFF97ABA6FF
+ 9FB3AEFF9FB3AEFF9CB2ADFF9BB1ACFF9AB0ABFF98AEA9FF99ACA9FF96A8A7FF
+ 94A6A5FF94A6A5FF92A4A3FF8B9D9CFF839594FF7E908FFF859796FF809291FF
+ 788A89FF718382FF6D7F7EFF6E807FFF718382FF778786FF8B9896FF8C9997FF
+ 869391FF788684FF707E7CFF717F7DFF70817EFF6E7F7CFF859895FF8FA29FFF
+ 93A8A5FF98AFABFFACC3BFFFBCD5D1FFB5CCC8FF9DB4B0FFD5EAE7FFD9ECE9FF
+ D9EEEBFFDBF0EDFFDCF1EEFFDFF4F1FFE3FAF6FFE7FEFAFFE5FEFAFFDFF8F4FF
+ E6FFFBFFEAFFFFFFE5FFFCFFE6FFFDFFE6FFFDFFDDF6F2FFB8CBC8FFBED1CEFF
+ CCDFDCFFD6EDE9FFD7F0ECFFD1ECE8FFD0EEE9FFD3F3EEFFCCECE7FFC0DED9FF
+ ADC8C4FF9CB5B1FF90A7A3FF8A9F9CFF8FA09DFF93A4A1FF919F9DFF859391FF
+ 859391FF879593FF82908EFF83918FFF818F8DFF73817FFF748280FF717F7DFF
+ 748280FF7B8987FF7E8C8AFF7D8B89FF82908EFF8B9995FF929996FF909691FF
+ 8A8F8DFF919895FF9FA6A3FF959E9BFF889391FF8C9997FF8D9B99FF7B8C89FF
+ 859796FF9DB2B0FFA8BDBEFFAABFC0FF8A9FA0FF546A68FF8CA19FFF8A9D9AFF
+ 829592FF7A8D8AFF7A8D8AFF7C8F8CFF778A87FF6E817EFF768986FF778A87FF
+ 798C89FF7C8F8CFF7F928FFF809390FF7E918EFF7D908DFF7B8D8CFF425251FF
+ 616F6DFF616F6DFF616E6CFF5C6765FF636C69FF5C6562FF5B655FFF636D67FF
+ 6E7A74FF77857FFF7A8981FF77887FFF73867DFF73867DFF8A9894FF919C99FF
+ 97A29FFF9BA6A3FF9DA8A5FF9DA8A5FF9DA8A5FF9EA9A6FF9DA8A5FF9DA8A5FF
+ 9DA8A5FF9DA8A5FF9EA9A6FF9EA9A6FF9EA9A6FF9EA9A6FF9EA5A2FF9EA5A2FF
+ 9EA5A2FF9FA6A3FF9DA6A3FF9DA6A3FF9BA6A3FF9BA6A3FF96A4A0FF99A7A3FF
+ 9AA9A5FF909F9BFF93A4A0FF8D9E9AFF839792FFACC0BBFFC0D3D0FFC6DBD8FF
+ C8DDDAFFC2D7D4FFBFD4D1FFC1D6D3FFBCD1CEFFB2C7C4FFC1D6D3FFB7CCC9FF
+ AEC3C0FFA9BEBBFFA5BAB7FFA4B9B6FFA9BEBBFFB5C6C2FFACB8B2FFADB7B1FF
+ A4AEA8FFA1ABA5FFA2ACA6FF939D97FF88928CFF8F9993FF8D9791FF8F9993FF
+ 939D97FF98A29CFF99A39DFF97A19BFF919B95FF8A978FFF96A59DFF94A59AFF
+ A2B6AAFFB2C6BAFFB5C8BFFFC5D8CFFFDDF2E9FFE9FEF5FFE7FEF6FFBDD4CCFF
+ 94AAA5FF95ABA6FFADC4BFFFB4CBC6FFB3CAC6FFBDD4D0FFCFE7E5FFC8E3E0FF
+ C4DCDAFFBBD6D3FFBBD3D1FFBCD7D4FFC3DBD9FFC6E1DEFFC1D9D7FFBAD5D2FF
+ B6CECCFFB1CCC9FFB4CCCAFFB6D1CEFFBED6D4FFC1DAD6FFC6DDD8FFCBE2DDFF
+ D0E7E2FFD4EBE6FFD5ECE7FFD6EDE8FFD8EFEAFFDAF1ECFFD7EEE9FFD5ECE7FF
+ D1E8E3FFCEE5E0FFA1B8B4FFABC2BEFFB1C8C4FFABC2BEFFA2B9B5FF9CB3AFFF
+ 99B0ACFF96ADA9FFA4BBB7FF9CB3AFFF92A9A5FF93AAA6FF9FB6B2FFA8BFBBFF
+ A2B9B5FF95ACA8FF90A3A0FF889B98FF819491FF7D908DFF798A87FF70817EFF
+ 6B7C79FF6B7C79FF717F7DFF798785FF7F8C8AFF8B9896FF7E8B89FF707D7BFF
+ 707B79FF545F5DFF394441FF343F3CFF54625EFF667470FF6A7874FF72807CFF
+ 677672FF677672FF70817DFF70817DFF71827EFF768783FF7B8F8AFF80948FFF
+ 819590FF80948FFF849591FF8D9E9AFF93A4A0FF91A29EFF8D9E9AFF8B9C98FF
+ 8A9B97FF889995FF8EA29DFF9DB1ACFFA9BDB8FFABBFBAFFA9BDB8FFA8BCB7FF
+ A7BBB6FFA3B7B2FF9CAFACFF8DA09DFF819491FF7F928FFF7E918EFF7C8F8CFF
+ 819491FF8B9E9BFF7C8F8CFF7F928FFF879A97FF94A7A4FFA4B7B4FFB2C5C2FF
+ BBCECBFFC1D2CFFFC4D2D0FFCBD9D7FFCDDBD9FFC9D7D5FFC6D4D2FFC8D9D6FF
+ CDDEDBFFCFE0DDFFD5E8E5FFE2F5F2FFE6F9F6FFDDF2EFFFDCF1EEFFE3FAF6FF
+ E1F6F3FFD4E9E6FFD5E8E5FFD7EAE7FFD8EDEAFFD9EEEBFFDAEFECFFDCF1EEFF
+ DFF6F2FFE3FAF6FFE9FFFEFFE3FCF8FFE8FFFDFFE7FFFCFFDCF7F3FFE0FBF7FF
+ E8FFFFFFEAFFFFFFD5E8E5FFC4D7D4FFBFD2CFFFCDE4E0FFD8F1EDFFD5F0ECFF
+ D3F1ECFFD8F6F1FFD7F5F0FFD2F0EBFFC6E1DDFFB1CAC6FF9CB3AFFF8EA3A0FF
+ 8FA09DFF91A29FFF919F9DFF869492FF879593FF889694FF818F8DFF818F8DFF
+ 82908EFF778583FF73817FFF6F7D7BFF707E7CFF768482FF7D8B89FF808E8CFF
+ 83918FFF899793FF969F9CFF929994FF8A918EFF919A97FF9FA8A5FF9AA5A2FF
+ 9BA8A6FFAFBDBBFF9CADAAFF8B9E9BFF8EA09FFF9CB1AFFFA7BCBDFFA8C0C0FF
+ 8EA6A6FF667C7AFF829795FF869996FF849794FF7E918EFF7A8D8AFF7A8D8AFF
+ 778A87FF718481FF6F827FFF718481FF768986FF7C8F8CFF819491FF809390FF
+ 7B8E8BFF768986FF80908FFF445453FF5F6D6BFF687573FF5E6967FF5C6765FF
+ 69726FFF5B625FFF575E59FF626C66FF707C76FF788680FF7A8981FF7A8B82FF
+ 7B8E85FF7E9188FF889692FF8C9A96FF92A09CFF95A39FFF96A4A0FF96A4A0FF
+ 96A4A0FF97A5A1FF93A19DFF93A19DFF94A29EFF95A39FFF96A4A0FF97A5A1FF
+ 98A6A2FF9AA5A2FF9CA3A0FF9DA4A1FF9EA5A2FF9DA6A3FF9DA6A3FF9CA5A2FF
+ 98A3A0FF97A29FFF96A4A0FF9AA8A4FF96A5A1FF8C9B97FF94A5A1FF859692FF
+ 7A8B87FFADC1BCFFBBCFCAFFC9DDD8FFCFE3DEFFC4D8D3FFB9CDC8FFB6CAC5FF
+ B1C5C0FFAABEB9FFB4C8C3FFABBFBAFFA1B5B0FF99ADA8FF92A6A1FF92A6A1FF
+ 9CB0ABFFABBCB8FFA1ADA7FFA4AEA8FF9BA59FFF959F99FF949E98FF86908AFF
+ 7B857FFF828C86FF848E88FF89938DFF8F9993FF939D97FF929C96FF8F9993FF
+ 8C9690FF88958DFF8C9B93FF8E9F94FF9DAEA3FFA9BAAFFFAFC2B9FFC6D9D0FF
+ DAEFE6FFDCF1E8FFE5FAF2FFBBD0C8FFA5BBB6FFADC3BEFFAAC1BCFFA2B9B4FF
+ A9C0BCFFB4CBC7FFC1D8D4FFC1DAD6FFC6DDD9FFC9E2DEFFD0E7E3FFD0E9E5FF
+ D0E7E3FFCCE5E1FFD1E8E4FFCBE4E0FFC7DEDAFFBFD8D4FFBFD6D2FFBED7D3FF
+ C4DBD7FFC6DDD9FFC1D8D3FFC5DCD7FFCBE2DDFFD0E7E2FFD2E9E4FFD4EBE6FF
+ D7EEE9FFD9F0EBFFE0F7F2FFDEF5F0FFDBF2EDFFD8EFEAFFA5BCB8FFACC3BFFF
+ AEC5C1FFA6BDB9FF9EB5B1FF9CB3AFFF9CB3AFFF9AB1ADFF8FA6A2FF97AEAAFF
+ 9EB5B1FF9DB4B0FF9AB1ADFF9CB3AFFFA5BCB8FFACC3BFFFA5B8B5FF94A7A4FF
+ 899C99FF899C99FF869794FF7B8C89FF7D8E8BFF899A97FF758381FF768482FF
+ 778482FF788583FF6E7B79FF616E6CFF5F6A68FF576260FF3F4A47FF394441FF
+ 576561FF65736FFF697773FF74827EFF707F7BFF758480FF788985FF738480FF
+ 71827EFF758682FF7D918CFF849893FF849893FF819590FF869793FF8A9B97FF
+ 8C9D99FF8A9B97FF869793FF869793FF8A9B97FF8D9E9AFF819590FF92A6A1FF
+ 9EB2ADFF9DB1ACFF99ADA8FF9BAFAAFF9BAFAAFF98ACA7FF97AAA7FF889B98FF
+ 819491FF889B98FF8FA29FFF94A7A4FFA3B6B3FFB6C9C6FFBBCECBFFC2D5D2FF
+ CCDFDCFFD6E9E6FFDDF0EDFFE0F3F0FFE0F3F0FFDFF2EFFFDBECE9FFDDEEEBFF
+ DEEFECFFDEEFECFFDFF0EDFFE1F2EFFFE2F3F0FFE1F2EFFFD8EBE8FFD0E3E0FF
+ CADDDAFFC9DCD9FFCADDDAFFCFE2DFFFDAEDEAFFE5F8F5FFE2F5F2FFE5F8F5FF
+ E6FBF8FFE8FDFAFFE9FEFBFFECFFFEFFECFFFFFFECFFFFFFE3FCF8FFDFF8F4FF
+ E5FEFAFFE6FFFBFFDAF5F1FFDCF7F3FFE5FFFCFFE5FEFAFFEBFEFBFFCADDDAFF
+ B7CCC9FFC5DCD8FFD3EAE6FFCDE6E2FFC8E3DFFFCEECE7FFCFEDE8FFD4EFEBFF
+ D0E9E5FFBFD8D4FFADC2BFFF9DB2AFFF94A7A4FF90A19EFF93A19FFF899795FF
+ 8A9896FF8A9896FF808E8CFF808E8CFF82908EFF798785FF778583FF72807EFF
+ 707E7CFF73817FFF798785FF7D8B89FF7E8C8AFF808E8AFF87928FFF828C86FF
+ 79827FFF7E8986FF8C9794FF8C9A96FF96A4A2FFAFC0BDFFB0C3C0FFB0C5C2FF
+ B2C7C5FFACC2C0FFA0B8B8FF99B1B1FF8FA7A7FF839997FF6C817FFF788B88FF
+ 7F928FFF7E918EFF7C8F8CFF7E918EFF809390FF7F928FFF788B88FF788B88FF
+ 798C89FF7D908DFF809390FF7E918EFF778A87FF708380FF7B8B8AFF4C5A59FF
+ 616E6CFF737E7CFF596462FF58605FFF69706DFF545B58FF4B524DFF5D645FFF
+ 6F7973FF77837DFF7C8981FF829189FF8A9B92FF8FA097FF869490FF8A9894FF
+ 8F9D99FF919F9BFF919F9BFF919F9BFF919F9BFF93A19DFF919F9BFF919F9BFF
+ 92A09CFF93A19DFF94A29EFF94A29EFF95A39FFF97A29FFF9AA3A0FF9CA5A2FF
+ 9EA7A4FF9FA8A5FF9EA7A4FF9AA5A2FF97A29FFF93A19DFF95A39FFF9AA8A4FF
+ 96A5A1FF8F9E9AFF9AABA7FF8A9B97FF7E8F8BFFB9CAC6FFC2D3CFFFC1D2CEFF
+ C2D3CFFFBECFCBFFAFC0BCFF9EAFABFF98A9A5FF9BACA8FF99AAA6FF99AAA6FF
+ 9AABA7FF9AABA7FF92A39FFF8C9D99FF90A19DFF9BAAA6FF9BA7A1FFA2ACA6FF
+ 9AA49EFF939D97FF949E98FF8A948EFF828C86FF89938DFF8C9690FF8E9892FF
+ 8D9791FF89938DFF858F89FF838D87FF87918BFF89968EFF86958DFF8B9C91FF
+ 9AABA0FFA5B6ABFFAFC2B9FFCDE0D7FFE1F4EBFFD9EEE5FFD7ECE4FFC0D5CDFF
+ BFD5D0FFBDD3CEFFA0B7B2FF96ADA8FFA4BBB7FFA6BDB9FFAEC5C1FFB3CAC6FF
+ BCD1CEFFC3DAD6FFCBE0DDFFCEE5E1FFD0E5E2FFD0E7E3FFCCE1DEFFCFE6E2FF
+ D4E9E6FFD3EAE6FFD1E6E3FFCBE2DEFFC7DCD9FFC4DBD7FFCAE1DCFFCDE4DFFF
+ D0E7E2FFD1E8E3FFD2E9E4FFD2E9E4FFD5ECE7FFD7EEE9FFE3FAF5FFE4FBF6FF
+ E5FCF7FFE6FDF8FF9FB6B2FFACC3BFFFB7CECAFFB6CDC9FFAEC5C1FFA3BAB6FF
+ 95ACA8FF8AA19DFF8CA39FFF9BB2AEFFAAC1BDFFACC3BFFFA1B8B4FF9BB2AEFF
+ A2B9B5FFAEC5C1FFA3B6B3FF96A9A6FF92A5A2FF96A9A6FF8E9F9CFF7D8E8BFF
+ 7F908DFF8FA09DFF83918FFF82908EFF859290FF7F8C8AFF74817FFF657270FF
+ 5F6A68FF6B7674FF3E4946FF3D4845FF5F6D69FF6C7A76FF6A7874FF73817DFF
+ 71807CFF7A8985FF7C8D89FF778884FF748581FF768783FF7B8F8AFF80948FFF
+ 819590FF7F938EFF7F938EFF829691FF869A95FF879B96FF859994FF849893FF
+ 889C97FF8DA19CFF829691FF92A6A1FF9AAEA9FF96AAA5FF97ABA6FFA2B6B1FF
+ ABBCB8FFA9BAB6FFAFC0BDFFB0C1BEFFBCCDCAFFCFE0DDFFD8E9E6FFD7E8E5FF
+ DAEBE8FFE2F3F0FFEEFFFCFFEFFFFDFFEEFFFCFFE9FAF7FFE3F4F1FFDFF0EDFF
+ DFF0EDFFDFF2EFFFE3F6F3FFDAEDEAFFCFE2DFFFC8DBD8FFBDD0CDFFA8BBB8FF
+ 8EA19EFF7B8E8BFF80918EFF5B6C69FF566764FF869794FFB8C9C6FFCADBD8FF
+ D2E3E0FFDEEFECFFE0F3F0FFE3F6F3FFE4F9F6FFE5FAF7FFE5FAF7FFE5FAF7FF
+ E7FEFAFFE9FFFCFFE6FFFBFFDFF8F4FFE4FDF9FFE7FFFCFFDEF9F5FFE3FEFAFF
+ E8FFFFFFE8FFFDFFEDFFFFFFCEE1DEFFB7CCC9FFC0D7D3FFC9E0DCFFC0D9D5FF
+ BDD8D4FFC6E1DDFFCCE7E3FFD1ECE8FFD3ECE8FFCBE4E0FFC3D8D5FFB7CCC9FF
+ A5B8B5FF94A7A4FF93A4A1FF8B9C99FF8E9F9CFF8C9D9AFF80918EFF7E8F8CFF
+ 80918EFF798A87FF778885FF738481FF6F807DFF6F807DFF748582FF7A8B88FF
+ 7B8C89FF7B8A86FF92A09CFF8E9A94FF818C89FF818F8BFF919F9BFF98A7A3FF
+ A0B1AEFFB3C6C3FFBED1CEFFC6DBD8FFC0D6D4FFAAC2C0FF98B0B0FF89A3A3FF
+ 859F9FFF8BA3A1FF607573FF708380FF7C8F8CFF7D908DFF7A8D8AFF7C8F8CFF
+ 809390FF829592FF859895FF809390FF7D908DFF7D908DFF7F928FFF7E918EFF
+ 798C89FF758683FF748281FF586464FF616E6CFF778280FF575F5EFF515756FF
+ 5D6461FF4C514FFF474D48FF5A615CFF6F7671FF76807AFF7B8880FF86958DFF
+ 91A098FF97A69EFF8F9D99FF92A09CFF95A39FFF97A5A1FF96A4A0FF95A39FFF
+ 96A4A0FF97A5A1FF98A6A2FF98A6A2FF98A6A2FF98A6A2FF98A6A2FF98A6A2FF
+ 98A6A2FF98A6A2FF99A4A1FF9BA6A3FF9DA8A5FF9EA9A6FF9DA8A5FF9BA6A3FF
+ 98A3A0FF94A29EFF94A29EFF94A39FFF96A5A1FF94A39FFF9EAFABFF95A6A2FF
+ 8B9C98FFBDCECAFFC1D0CCFFAAB9B5FFA3B2AEFFAEBDB9FFA6B5B1FF8C9B97FF
+ 859490FF93A29EFF909F9BFF95A4A0FF9EADA9FFA2B1ADFF9BAAA6FF909F9BFF
+ 8D9C98FF92A09CFF919D97FF9BA59FFF949E98FF8B958FFF8C9690FF858F89FF
+ 7F8983FF86908AFF8E9892FF8F9993FF8E9892FF89938DFF838D87FF828C86FF
+ 858F89FF88958DFF87968EFF86978CFF8FA095FF97A89DFFA7B8AFFFCBDED5FF
+ E7FAF1FFE5F8EFFFD7ECE4FFD2E7DFFFD6ECE7FFCCE2DDFFB3C9C4FFB1C7C2FF
+ AABFBCFF8BA09DFFA2B7B4FFA3B8B5FFA4B7B4FFA1B6B3FFA6B9B6FFACC1BEFF
+ BBCECBFFC2D7D4FFC6D9D6FFCCE1DEFFD8EBE8FFDCF1EEFFDEF1EEFFD7ECE9FF
+ D5E8E5FFD1E6E3FFD4EBE6FFD4EBE6FFD3EAE5FFD1E8E3FFCFE6E1FFCFE6E1FF
+ D2E9E4FFD5ECE7FFDDF4EFFFE0F7F2FFE5FCF7FFEAFFFCFFA7BEBAFFB1C8C4FF
+ B7CECAFFB4CBC7FFADC4C0FFA5BCB8FF9BB2AEFF91A8A4FF98AFABFF9AB1ADFF
+ A1B8B4FFA8BFBBFFA6BDB9FF9DB4B0FF97AEAAFF96ADA9FF9CAFACFF98ABA8FF
+ 9CAFACFFA2B5B2FF98A9A6FF829390FF7B8C89FF839491FF859391FF869492FF
+ 929F9DFF8E9B99FF889593FF74817FFF636E6CFF7C8785FF3A4542FF3F4A47FF
+ 667470FF75837FFF6F7D79FF72807CFF6C7B77FF72817DFF788985FF788985FF
+ 788985FF778884FF768A85FF778B86FF7A8E89FF7C908BFF788C87FF7D918CFF
+ 879B96FF8FA39EFF8DA19CFF879B96FF869A95FF8A9E99FF889C97FF96AAA5FF
+ 9EB2ADFF9FB3AEFFADC1BCFFC8DCD7FFDBECE8FFDBECE8FFE2F3F0FFE4F5F2FF
+ E6F7F4FFE6F7F4FFE3F4F1FFE0F1EEFFDEEFECFFDEEFECFFCFE0DDFFD5E6E3FF
+ DFF0EDFFE5F6F3FFE7F8F5FFE4F5F2FFDFF0EDFFD9ECE9FFDEF3F0FFD2E9E5FF
+ CCE1DEFFCCE1DEFFC4D9D6FFABBEBBFF859895FF6B7E7BFF6D7E7BFF536461FF
+ 60716EFF9EAFACFFD0DEDCFFD5E3E1FFD5E3E1FFE1EFEDFFEFFFFDFFEFFFFFFF
+ EDFFFFFFEDFFFFFFEDFFFFFFECFFFEFFECFFFFFFECFFFFFFE0F9F5FFD6EFEBFF
+ D5EEEAFFD5EEEAFFCDE8E4FFD6F1EDFFE4FFFBFFE6FFFBFFE8FDFAFFCCE1DEFF
+ B8CDCAFFBAD1CDFFBFD6D2FFBBD4D0FFBCD5D1FFC2DDD9FFC8E3DFFFCDE8E4FF
+ D0E9E5FFCEE5E1FFCCE3DFFFC6DBD8FFB2C5C2FF99ACA9FF95A6A3FF91A29FFF
+ 96A7A4FF93A4A1FF839491FF7E8F8CFF80918EFF798A87FF748582FF758683FF
+ 728380FF70817EFF748582FF7D8E8BFF81928FFF80918DFF97A6A2FF95A59EFF
+ 869591FF879692FFA2B1ADFFB8C9C5FFC0D3D0FFC7DCD9FFC5DAD7FFC8DFDBFF
+ B3CBC9FF9DB5B3FF96B0B0FF8EA8A8FF849E9EFF88A09EFF6B807EFF7A8D8AFF
+ 849794FF829592FF7D908DFF7C8F8CFF7D908DFF7E918EFF899C99FF829592FF
+ 7B8E8BFF7B8E8BFF7F928FFF829592FF7F928FFF7C8D8AFF758382FF6D7979FF
+ 646F6DFF7A8281FF606665FF555B5AFF595E5CFF4E5351FF4F5550FF626863FF
+ 717873FF777E79FF7C877FFF88958DFF909F97FF91A098FF93A19DFF96A4A0FF
+ 98A6A2FF98A6A2FF96A4A0FF95A39FFF96A4A0FF98A6A2FF97A5A1FF97A5A1FF
+ 97A5A1FF97A5A1FF97A5A1FF97A5A1FF97A5A1FF96A4A0FF9AA5A2FF9BA6A3FF
+ 9CA7A4FF9DA8A5FF9CA7A4FF99A7A3FF97A5A1FF96A4A0FF92A19DFF8B9A96FF
+ 95A4A0FF93A29EFF95A6A2FF96A7A3FF90A19DFFABBAB6FFB3C1BDFF96A4A0FF
+ 909B98FFA1AFABFFA7B2AFFF92A09CFF8F9A97FF9CAAA6FF99A4A1FF98A6A2FF
+ 9DA8A5FF9CAAA6FF97A29FFF8B9995FF8A9592FF8E9996FF8F9993FF99A39DFF
+ 929C96FF858F89FF828C86FF7D8781FF77817BFF7C8680FF848E88FF88928CFF
+ 8C9690FF8E9892FF8D9791FF8B958FFF89938DFF87948CFF8A9991FF7F9085FF
+ 7F9085FF84958AFF91A299FFB7C8BFFFD9ECE3FFE3F6EDFFE2F4EDFFE3F8F0FF
+ E3F7F2FFDAF0EBFFD9EFEAFFDCF2EDFFBACFCCFF839895FF819491FF839693FF
+ 899A97FF8B9E9BFF92A3A0FF94A7A4FF9BACA9FF9BAEABFF9DAEABFFA1B4B1FF
+ ABBCB9FFAEC1BEFFB4C5C2FFB7CAC7FFC1D2CFFFC5D8D5FFBAD0CBFFB9D0CBFF
+ B9D0CBFFBAD1CCFFBDD4CFFFC5DCD7FFD0E7E2FFD7EEE9FFDEF5F0FFE0F7F2FF
+ E4FBF6FFE7FEF9FFA9C0BCFFAEC5C1FFB0C7C3FFACC3BFFFA9C0BCFFA9C0BCFF
+ A7BEBAFFA4BBB7FF9EB5B1FF97AEAAFF96ADA9FF9DB4B0FF9FB6B2FF98AFABFF
+ 8FA6A2FF8CA39FFF98ABA8FF96A9A6FF99ACA9FF9EB1AEFF9CADAAFF90A19EFF
+ 889996FF889996FF6D7B79FF6B7977FF7C8987FF7D8A88FF83908EFF727F7DFF
+ 596462FF798482FF414C49FF414C49FF65736FFF75837FFF73817DFF788682FF
+ 71807CFF74837FFF72837FFF798A86FF7F908CFF7C8D89FF738782FF728681FF
+ 788C87FF80948FFF7B918CFF7D938EFF869C97FF8EA49FFF8DA19CFF869A95FF
+ 859994FF8B9F9AFF849591FF8FA09CFF92A39FFF90A19DFFA3B4B0FFC3D4D0FF
+ D6E5E1FFD3E2DEFFD9EAE6FFD9EAE6FFCCDDD9FFB5C6C2FFABBCB8FFB2C3BFFF
+ B8C9C5FFB6C7C3FFB9CAC6FFBECFCBFFCBDCD8FFDDEEEAFFE9FAF6FFE5F6F2FF
+ D4E5E1FFC1D5D0FFCDE4E0FFC2DBD7FFC2D9D5FFCDE4E0FFD2E9E5FFC8DDDAFF
+ B8CBC8FFACBFBCFFA1B2AFFF9BACA9FFA9B7B5FFC4D2D0FFD1DEDCFFCCD9D7FF
+ CCD9D7FFD6E3E1FFDEEFECFFDFF2EFFFE1F6F3FFE3F8F5FFE3F8F5FFE3F8F5FF
+ E4FBF7FFE5FCF8FFE3FCF8FFDCF5F1FFDCF5F1FFD6EFEBFFC6E1DDFFCBE6E2FF
+ DCF7F3FFE3FCF8FFE2F9F5FFCBE0DDFFB5CAC7FFAEC5C1FFB4CBC7FFB7D0CCFF
+ BAD3CFFFBDD6D2FFC5DEDAFFCBE4E0FFCCE3DFFFC7DEDAFFC9E0DCFFC9E0DCFF
+ B9CECBFFA5B8B5FF97A8A5FF95A6A3FF9DAEABFF9AABA8FF879895FF7E8F8CFF
+ 7F908DFF788986FF758683FF7A8B88FF7A8B88FF758683FF778885FF81928FFF
+ 899A97FF899A96FF839490FF84968FFF71827EFF6C7D79FF93A4A0FFBACEC9FF
+ C3D6D3FFBDD2CFFFC6DBD8FFC8DFDBFFADC5C3FF97AFADFF98B2B2FF92ACACFF
+ 859F9FFF8BA3A1FF6F8482FF7C8F8CFF849794FF819491FF7B8E8BFF7A8D8AFF
+ 7B8E8BFF7A8D8AFF889B98FF809390FF798C89FF7A8D8AFF7F928FFF829592FF
+ 7F928FFF7C8D8AFF788685FF7C8888FF586361FF6F7776FF656B6AFF5C6261FF
+ 565B59FF545755FF5C605BFF6A706BFF757C77FF777E79FF7D8880FF8A978FFF
+ 8F9E96FF8C9B93FF909F9BFF92A19DFF93A29EFF93A29EFF91A09CFF8F9E9AFF
+ 909F9BFF92A19DFF909F9BFF909F9BFF91A09CFF92A19DFF93A29EFF93A29EFF
+ 94A39FFF94A39FFF96A4A0FF97A5A1FF97A5A1FF97A5A1FF97A5A1FF97A6A2FF
+ 97A6A2FF97A6A2FF92A19DFF81908CFF91A09CFF8C9B97FF7E8F8BFF899A96FF
+ 859692FF82918DFF98A49EFF8C9892FF8C9690FF97A39DFFA4AEA8FFA2AEA8FF
+ A2ACA6FFA2AEA8FF9EA8A2FF98A49EFF97A19BFF95A19BFF949E98FF8B9791FF
+ 8B958FFF8E9892FF919B95FF9DA7A1FF959F99FF858F89FF818B85FF7D8781FF
+ 78827CFF7C8680FF838D87FF858F89FF88928CFF8C9690FF909A94FF909A94FF
+ 8E9892FF8A978FFF8F9E96FF7F8F84FF7E8E83FF839388FF84958CFF97A89FFF
+ B2C3BAFFBCCFC6FFD9EBE4FFE5FAF2FFE3F7F2FFDDF1ECFFE8FCF7FFE9FDF8FF
+ CCE1DEFFB4C7C4FF95A6A2FF8D9E9AFF899894FF889995FF91A09CFF91A29EFF
+ 8E9D99FF859692FF6C7B77FF70817DFF798884FF7D8E8AFF869591FF91A29EFF
+ A3B2AEFFADBEBAFFB3C9C4FFB1C8C3FFAFC6C1FFB0C7C2FFB5CCC7FFC2D9D4FF
+ D1E8E3FFDBF2EDFFE0F7F2FFDFF6F1FFDEF5F0FFDDF4EFFF95ACA8FFA2B9B5FF
+ B0C7C3FFB6CDC9FFB7CECAFFB4CBC7FFABC2BEFFA1B8B4FF9DB4B0FF99B0ACFF
+ 99B0ACFF9CB3AFFF99B0ACFF92A9A5FF94ABA7FF9BB2AEFF94A7A4FF8DA09DFF
+ 8A9D9AFF8EA19EFF97A8A5FF9BACA9FF9BACA9FF99AAA7FF707E7CFF677573FF
+ 74817FFF778482FF899694FF808D8BFF65706EFF8B9694FF4C5754FF434E4BFF
+ 5F6D69FF6E7C78FF73817DFF818F8BFF7E8D89FF83928EFF70817DFF7C8D89FF
+ 859692FF82938FFF758984FF718580FF7A8E89FF869A95FF879D98FF839994FF
+ 849A95FF879D98FF869A95FF829691FF879B96FF93A7A2FF97A8A4FF9BACA8FF
+ 93A4A0FF879894FF8FA09CFFA8B7B3FFAFBEBAFFA5B4B0FF96A5A1FFA0B1ADFF
+ 9DAEAAFF8A9B97FF879894FF97A8A4FF9FB0ACFF98A9A5FFAABBB7FFA4B5B1FF
+ A7B8B4FFBCCDC9FFD8E9E5FFE6F7F3FFDFF0ECFFD0E4DFFFDBF2EEFFCBE4E0FF
+ C1DAD6FFC5DEDAFFCCE3DFFFCBE2DEFFCEE1DEFFD1E4E1FFCCDDDAFFBFD0CDFF
+ B3C1BFFFB4C2C0FFC5D2D0FFD5E2E0FFD9E4E2FFD0DDDBFFD3E4E1FFD6E9E6FF
+ DBF0EDFFE0F5F2FFE3F8F5FFE6FBF8FFE9FFFCFFECFFFFFFE0F9F5FFE0F9F5FF
+ E6FFFBFFDDF6F2FFC3DEDAFFBFDAD6FFCDE8E4FFD4EDE9FFE2F9F5FFCBE2DEFF
+ AFC6C2FFA3BAB6FFA9C0BCFFB4CBC7FFB8CFCBFFB3CCC8FFC6DDD9FFCDE4E0FF
+ CCE3DFFFC5DCD8FFC7DEDAFFCDE4E0FFC4DBD7FFB4C9C6FF96A9A6FF98A9A6FF
+ A1B2AFFF9EAFACFF899A97FF7F908DFF7E8F8CFF778885FF798A87FF80918EFF
+ 81928FFF7A8B88FF798A87FF839491FF8B9C99FF8D9E9AFF93A4A0FF90A59DFF
+ 748883FF667A75FF8EA29DFFBAD0CBFFBFD4D1FFAFC4C1FFBCD3CFFFC8DFDBFF
+ B1C9C7FF97AFADFF92ACACFF88A2A2FF809A9AFF91A9A7FF617674FF6E817EFF
+ 758885FF748784FF728582FF748784FF768986FF758885FF879A97FF809390FF
+ 798C89FF7A8D8AFF7F928FFF809390FF7A8D8AFF758683FF748281FF7B8787FF
+ 444F4DFF5B6362FF606665FF5A605FFF4D5250FF4E514FFF616560FF6E746FFF
+ 767D78FF787F7AFF7F8A82FF8E9B93FF91A098FF8A9B92FF91A09CFF92A19DFF
+ 93A29EFF92A19DFF909F9BFF8E9D99FF8F9E9AFF91A09CFF909F9BFF91A09CFF
+ 92A19DFF94A39FFF96A5A1FF98A7A3FF99A8A4FF9AA9A5FF94A39FFF94A39FFF
+ 94A29EFF93A29EFF94A39FFF95A4A0FF97A6A2FF98A7A3FF92A19DFF7A8985FF
+ 8D9C98FF84938FFF6B7C78FF7B8C88FF778884FF606F6BFF7B8781FF858F89FF
+ 89938DFF8B958FFF97A19BFFA6B0AAFFA6B0AAFF9BA59FFF9EA8A2FF99A39DFF
+ 98A29CFF9BA59FFF9BA59FFF96A09AFF939D97FF949E98FF919B95FF9EA8A2FF
+ 97A19BFF87918BFF838D87FF808A84FF7C8680FF808A84FF8D9791FF88928CFF
+ 838D87FF848E88FF89938DFF8F9993FF929C96FF929D95FF93A098FF839388FF
+ 87978CFF8F9F94FF86958DFF819289FF8B9C93FF91A299FFC4D6CFFFDEF0E9FF
+ E0F1EDFFD6EAE5FFDBEFEAFFD7EBE6FFD7ECE9FFEFFFFFFFEAF9F5FFC7D6D2FF
+ 9CABA7FF869591FF899894FF92A19DFF95A4A0FF91A09CFF7C8B87FF84938FFF
+ 8E9D99FF97A6A2FFA1B0ACFFAFBEBAFFC0CFCBFFCBDCD8FFDAF0EBFFD4EBE6FF
+ CBE2DDFFC4DBD6FFC2D9D4FFC9E0DBFFD5ECE7FFDEF5F0FFDBF2EDFFD7EEE9FF
+ D3EAE5FFCFE6E1FFAFC6C2FF9BB2AEFF9AB1ADFFAFC6C2FFB5CCC8FFA6BDB9FF
+ A2B9B5FFAEC5C1FF9BB2AEFF9DB4B0FF92A9A5FF869D99FF91A8A4FFA6BDB9FF
+ A0B7B3FF889F9BFF91A4A1FF90A3A0FF8B9E9BFF899C99FF93A4A1FF9BACA9FF
+ 95A6A3FF899A97FF8B9997FF82908EFF7B8886FF7B8886FF7D8A88FF7E8B89FF
+ 7F8A88FF7F8A88FF495451FF56615EFF606E6AFF667470FF717F7BFF7D8B87FF
+ 7B8A86FF71807CFF7B8C88FF7C8D89FF7E8F8BFF80918DFF7F938EFF7F938EFF
+ 7E928DFF7E928DFF8FA5A0FF90A7A2FF8CA39EFF859C97FF879D98FF8DA39EFF
+ 8EA29DFF879B96FF90A19DFF7E8F8BFF73827EFF7C8B87FF91A09CFFA0AEAAFF
+ 9FADA9FF97A6A2FF9FAFA8FFA1B1AAFF9FAFA8FF97A7A0FF90A099FF93A39CFF
+ A1B1AAFFAEBEB7FFA5B5AEFFABBBB4FFA6B6AFFFA2B2ABFFBBCBC4FFDFEFE8FF
+ E3F3ECFFCBDCD8FFCCE3DFFFC7E0DCFFB8D1CDFFC4DDD9FFC7DEDAFFB5CCC8FF
+ B8CBC8FFADC0BDFFBCCDCAFFB4C5C2FFBAC8C6FFBAC8C6FFB5C2C0FFBFCCCAFF
+ D7E2E0FFDDEAE8FFD4E5E2FFD0E3E0FFCDE2DFFFD0E5E2FFD7ECE9FFE1F6F3FF
+ E8FFFBFFECFFFFFFE6FFFBFFE4FDF9FFE0F9F5FFD4EDE9FFBFDAD6FFB5D0CCFF
+ C3DEDAFFDAF5F1FFDDF6F2FFD6EDE9FFBBD2CEFFA7BEBAFFA6BDB9FFA6BDB9FF
+ A8BFBBFFB4CBC7FFC5DAD7FFC8DFDBFFCAE1DDFFC7DEDAFFC3DAD6FFC5DCD8FF
+ CEE5E1FFD6EDE9FFC0D3D0FFA2B5B2FF8C9F9CFF97AAA7FFB0C3C0FFB6C9C6FF
+ A4B7B4FF90A3A0FF90A3A0FF8A9D9AFF859895FF879A97FF8EA19EFF91A4A1FF
+ 8C9F9CFF879B96FF8EA29DFFA0B7AFFF889E99FF90A6A1FFA1B7B2FFA8BEB9FF
+ C5DAD7FFC7DEDAFFBCD3CFFFBCD3CFFFAFC7C5FF99B1AFFF89A1A1FF859D9DFF
+ 849C9CFF829896FF6C817FFF526562FF637673FF768986FF677A77FF6D807DFF
+ 7D908DFF708380FF748784FF7A8D8AFF7B8E8BFF778A87FF768986FF798C89FF
+ 748784FF6E7F7CFF687675FF697575FF646F6DFF676F6EFF6F7574FF616766FF
+ 505553FF4F5452FF727873FF727873FF707772FF767D78FF87928AFF98A59DFF
+ 99A8A0FF8FA097FF8E9D99FF8FA09CFF90A19DFF8FA09CFF8C9D99FF889995FF
+ 869793FF869793FF8B9C98FF869793FF859692FF8A9B97FF91A29EFF91A29EFF
+ 879894FF7E8F8BFF82938FFF80918DFF83928EFF82938FFF7D8E8AFF778884FF
+ 788985FF7D8E8AFF738480FF6C7D79FF6F7E7AFF6B7A76FF62716DFF63726EFF
+ 5F6E6AFF505E5AFF7E8882FF8A928BFF8A928BFF8F9790FFA2AAA3FFA8B0A9FF
+ A2AAA3FFA3ABA4FFA5ADA6FFA4ACA5FFA4ACA5FFA5ADA6FFA6AEA7FFA3ABA4FF
+ 9CA49DFF969E97FF919B95FF9CA6A0FFA2ACA6FF97A19BFF838D87FF78827CFF
+ 7E8882FF88928CFF8E9892FF828C86FF808A84FF88928CFF8B958FFF87918BFF
+ 8E9892FF9BA69EFF8E9B93FF87958AFF818F84FF809085FF899890FF91A098FF
+ 92A39AFF91A299FFA3B3ACFFDEF0E9FFDBECE8FFD8E9E5FFBACEC9FFABBFBAFF
+ DCEFECFFDAEDEAFFE6F5F1FFEAF8F2FFE1EFE9FFC5D3CDFFA4B2ACFF8E9C96FF
+ 85938DFF818F89FF8F9D97FFA0AEA8FFAFBDB7FFBAC8C2FFCDDBD5FFE1EFE9FF
+ E3F1EBFFD8E8E1FFE0F6F1FFDCF3EEFFD9F0EBFFDBF2EDFFE1F8F3FFE3FAF5FF
+ DCF3EEFFD4EBE6FFCBE2DDFFCFE6E1FFCEE5E0FFC9E0DBFFC0D7D3FFACC3BFFF
+ A2B9B5FFA9C0BCFFAAC1BDFFA0B7B3FF9EB5B1FFA7BEBAFF98AFABFFA0B7B3FF
+ 9CB3AFFF90A7A3FF93AAA6FF9EB5B1FF96ADA9FF819894FF8EA19EFF8A9D9AFF
+ 819491FF7A8D8AFF7F908DFF899A97FF8C9D9AFF879895FF7B8987FF73817FFF
+ 6B7876FF6A7775FF6E7B79FF73807EFF778280FF798482FF4D5855FF5C6764FF
+ 64726EFF65736FFF6A7874FF75837FFF798884FF768581FF758682FF788985FF
+ 7C8D89FF81928EFF839792FF879B96FF889C97FF879D98FF738A85FF7B928DFF
+ 829994FF859C97FF899F9AFF8AA09BFF849893FF788C87FF7C8D89FF72837FFF
+ 707F7BFF7C8B87FF8E9C98FF98A6A2FF99A7A3FF97A5A1FFA5B3ADFFA5B5AEFF
+ A2B2ABFF9AAAA3FF91A19AFF90A099FF9AAAA3FFA4B4ADFFA1B1AAFFA6B6AFFF
+ A1B1AAFF9CACA5FFAFBFB8FFD2E2DBFFE5F5EEFFE2F4EDFFD5EAE7FFCBE4E0FF
+ B7CECAFFBCD3CFFFBCD3CFFFB4C9C6FFC2D5D2FFBFD2CFFFC9DAD7FFBCCDCAFF
+ BCCAC8FFBAC8C6FFAFBCBAFFB4C1BFFFCBD8D6FFD9E6E4FFD4E5E2FFD0E3E0FF
+ CDE2DFFFCFE4E1FFD5EAE7FFDDF2EFFFE4FBF7FFE9FFFCFFE9FFFEFFE7FFFCFF
+ E5FEFAFFDCF5F1FFC9E4E0FFBED9D5FFC6E1DDFFD5F0ECFFDCF5F1FFD5EEEAFF
+ BED5D1FFAAC1BDFFAAC1BDFFA7BEBAFFA7BCB9FFB0C5C2FFC5DAD7FFC8DDDAFF
+ CADFDCFFC7DEDAFFC2D9D5FFBDD6D2FFBED7D3FFC1DAD6FFC7DCD9FFC0D3D0FF
+ B1C4C1FFADC0BDFFBCCFCCFFCCDFDCFFC6D9D6FFB4C7C4FFA1B4B1FF9AADAAFF
+ 93A6A3FF91A4A1FF95A8A5FF9AADAAFF9BAEABFF9BAFAAFFB1C7C2FFC4DBD3FF
+ B1C7C2FFB9CFCAFFC5DBD6FFBFD5D0FFCBE0DDFFC6DDD9FFCAE1DDFFBBD2CEFF
+ AEC4C2FFA6BEBCFF9DB2B3FF88A0A0FF7A8F90FF748A88FF748987FF4C5F5CFF
+ 576A67FF768986FF708380FF6F827FFF7A8D8AFF748784FF728582FF7A8D8AFF
+ 7E918EFF7C8F8CFF7B8E8BFF7A8D8AFF728582FF687B78FF778786FF717F7EFF
+ 5E6B69FF586361FF616968FF606665FF5C6360FF666D6AFF6C726DFF6F7671FF
+ 727974FF747E78FF7E8B83FF8B9A92FF8FA097FF899C93FF849591FF879894FF
+ 8A9B97FF8C9D99FF8C9D99FF8D9E9AFF8FA09CFF91A29EFF92A39FFF8B9C98FF
+ 82938FFF798A86FF748581FF72837FFF738480FF748581FF5E6F6BFF5E726DFF
+ 697A76FF738480FF788985FF7A8B87FF81928EFF899A96FFADBEBAFFA8B9B5FF
+ B1C0BCFFB4C3BFFFACBBB7FFA0AFABFF879692FF65736DFF77817BFF919992FF
+ 99A19AFF959D96FF9BA39CFF9EA69FFF9AA29BFF9BA39CFFA2AAA3FFA2AAA3FF
+ A4ACA5FFA6AEA7FFA5ADA6FF9FA7A0FF969E97FF8E968FFF8B958FFF8E9892FF
+ 8F9993FF8A948EFF818B85FF7C8680FF7D8781FF808A84FF8B958FFF838D87FF
+ 838D87FF8D9791FF8F9993FF89938DFF8B958FFF95A098FF97A49CFF95A398FF
+ 919F94FF8E9C91FF8B9A92FF8E9D95FF94A39BFF98A9A0FF95A59EFFD0E0D9FF
+ CFE0DCFFCCDDD9FFB2C3BFFFA3B7B2FFD4E7E4FFD7E8E4FFE2F1EDFFEBF9F3FF
+ EDFBF5FFE3F1EBFFDAE8E2FFD9E7E1FFDDEBE5FFDFEDE7FFD1DFD9FFD6E4DEFF
+ E1EFE9FFECFAF4FFEEFCF6FFE5F3EDFFDAE8E2FFD2E2DBFFB5CBC6FFB6CDC8FF
+ B6CDC8FFB9D0CBFFC4DBD6FFD2E9E4FFD3EAE5FFCDE4DFFFCBE2DDFFCFE6E1FF
+ CEE5E0FFC8DFDAFFC6DDD9FFBAD1CDFFAFC6C2FFACC3BFFFA9C0BCFFA4BBB7FF
+ A0B7B3FFA1B8B4FF9FB6B2FFA9C0BCFFAAC1BDFF9DB4B0FF96ADA9FF95ACA8FF
+ 889F9BFF768D89FF90A3A0FF8C9F9CFF829592FF7A8D8AFF7C8D8AFF839491FF
+ 869794FF849592FF8C9A98FF82908EFF778482FF717E7CFF717E7CFF74817FFF
+ 778280FF76817FFF4F5A57FF5F6A67FF677571FF64726EFF667470FF73817DFF
+ 7D8C88FF808F8BFF778884FF7A8B87FF7E8F8BFF839490FF869A95FF8A9E99FF
+ 8CA09BFF8BA19CFF778E89FF7C9690FF829C96FF859F99FF889F9AFF879D98FF
+ 7F938EFF748883FF60716DFF61726EFF6D7C78FF7E8D89FF8C9A96FF92A09CFF
+ 98A3A0FF9AA8A4FF9FADA7FFA0AEA8FF9EACA6FF97A59FFF8F9D97FF8D9B95FF
+ 93A19BFF99A7A1FF9EACA6FFA2B0AAFFA1AFA9FF9DABA5FFA3B1ABFFB8C6C0FF
+ D1DFD9FFDFEFE8FFE2F5F2FFDCF3EFFFC7DCD9FFC8DDDAFFC6DBD8FFC1D4D1FF
+ D1E4E1FFD2E5E2FFCFE0DDFFBCCDCAFFB8C9C6FFB6C7C4FFA7B5B3FFA7B5B3FF
+ C1CFCDFFD8E6E4FFD6E7E4FFD2E5E2FFCFE4E1FFCFE4E1FFD2E7E4FFD8EDEAFF
+ DDF4F0FFE2F9F5FFE9FFFEFFE8FFFDFFE6FFFBFFE0F9F5FFD1ECE8FFC6E1DDFF
+ C6E1DDFFCDE8E4FFD8F3EFFFD3EEEAFFBFD8D4FFB0C7C3FFAFC6C2FFA9BEBBFF
+ A5B8B5FFABBEBBFFB9CCC9FFBBD0CDFFC0D5D2FFC1D8D4FFC0D7D3FFB9D2CEFF
+ B3CCC8FFAFC8C4FFB4C9C6FFBDD2CFFFB5CAC7FFA1B6B3FF9EB3B0FFADC2BFFF
+ B1C6C3FFA6BBB8FFA5BAB7FFA4B9B6FFA4B9B6FFA7BCB9FFACC1BEFFB2C7C4FF
+ B8CDCAFFBCD2CDFFBFD3CEFFCCE1D9FFC1D5D0FFCBDFDAFFD8ECE7FFCDE3DEFF
+ CDE2DFFFC9DEDBFFBACFCCFF99AEABFF849997FF879D9BFF8B9FA0FF809596FF
+ 7E9293FF869B99FF788A89FF475A57FF4B5E5BFF738683FF778A87FF6E817EFF
+ 738683FF738683FF768986FF7B8E8BFF7D908DFF7B8E8BFF7A8D8AFF7B8E8BFF
+ 788B88FF738683FF708281FF6D7D7CFF606E6CFF5E6B69FF6A7573FF6B7372FF
+ 69726FFF747D7AFF7A817CFF7C8680FF7D8781FF79857FFF78877FFF7D8E85FF
+ 7F9289FF7F9289FF889995FF899A96FF879894FF839490FF7E8F8BFF7B8C88FF
+ 7B8C88FF7C8D89FF71827EFF748581FF768783FF758682FF778884FF81928EFF
+ 93A4A0FFA1B2AEFFA9BDB8FFAAC0BBFFB5C9C4FFC0D4CFFFC6DAD5FFC7DBD6FF
+ CBDFDAFFD1E5E0FFCFE0DCFFC8D9D5FFD0DFDBFFD8E7E3FFD3E2DEFFC2D1CDFF
+ 9BAAA6FF6E7C76FF6B7771FF97A29AFFA8B3ABFF9AA59DFF95A098FF97A29AFF
+ 98A39BFF9AA59DFF9CA79FFF9EA9A1FFA0ABA3FFA2ADA5FFA0ABA3FF98A39BFF
+ 8E9991FF869189FF8B958FFF858F89FF808A84FF808A84FF848E88FF858F89FF
+ 808A84FF79837DFF828C86FF7E8882FF838D87FF8D9791FF8F9993FF87918BFF
+ 858F89FF8A958DFF939E96FF97A298FF95A398FF8E9C91FF86938BFF84938BFF
+ 8E9D95FF99A8A0FF99A9A2FFD0E0D9FFD9E8E4FFD8E9E5FFC1D2CEFFB2C3BFFF
+ D6E7E4FFD5E6E2FFD0DFDBFFD4E4DDFFD4E4DDFFD0E0D9FFD0E0D9FFD6E6DFFF
+ DBEBE4FFDCECE5FFDEEEE7FFD2E2DBFFD1E1DAFFDAEAE3FFD7E7E0FFC6D6CFFF
+ BECEC7FFC1D3CCFFABC1BCFFB0C7C2FFADC4BFFFA6BDB8FFB0C7C2FFC4DBD6FF
+ CAE1DCFFC3DAD5FFC9E0DBFFCEE5E0FFCDE4DFFFC7DED9FFB8CFCBFFBAD1CDFF
+ B8CFCBFFB4CBC7FFB3CAC6FFB1C8C4FFAAC1BDFFA1B8B4FF9EB5B1FFA5BCB8FF
+ A8BFBBFFA2B9B5FF9DB4B0FF99B0ACFF8EA5A1FF819894FF7E918EFF7A8D8AFF
+ 768986FF778A87FF7F908DFF849592FF829390FF7C8D8AFF8A9896FF83918FFF
+ 788583FF6D7A78FF697674FF697674FF677270FF626D6BFF5F6A67FF6C7774FF
+ 707E7AFF6C7A76FF6C7A76FF778581FF7E8D89FF7D8C88FF778884FF788985FF
+ 7A8B87FF7C8D89FF7D918CFF7F938EFF80948FFF7F9590FF869D98FF7F9993FF
+ 76908AFF6F8983FF6D847FFF6B827DFF697F7AFF677B76FF4C5D59FF556662FF
+ 6B7A76FF83928EFF909E9AFF93A19DFF9BA6A3FFA5B0ADFF9BA9A3FF9DABA5FF
+ 9DABA5FF9AA8A2FF96A49EFF94A29CFF96A49EFF99A7A1FF9FADA7FFA1AFA9FF
+ A4B2ACFFA3B1ABFF9EACA6FF9DABA5FFA8B6B0FFB5C5BEFFD9EAE6FFDFF2EFFF
+ D5E8E5FFDBEEEBFFD6E9E6FFCBDEDBFFD3E6E3FFCDE0DDFFC8D9D6FFB4C5C2FF
+ B3C4C1FFB5C6C3FFA5B6B3FFA4B5B2FFC0D1CEFFDAEBE8FFD7EAE7FFD6E9E6FF
+ D2E7E4FFD0E5E2FFD0E5E2FFD3E8E5FFD7EEEAFFDCF3EFFFE5FEFAFFE3FCF8FF
+ E0F9F5FFDBF4F0FFD2EDE9FFCAE5E1FFC7E2DEFFC7E2DEFFD6F1EDFFD3EEEAFF
+ C3DCD8FFB4CDC9FFB4C9C6FFAABFBCFFA1B4B1FFA4B7B4FFA8BBB8FFAEC1BEFF
+ B6CBC8FFC0D7D3FFC6DDD9FFC2DBD7FFBAD5D1FFB6CFCBFFB2C9C5FFBCD1CEFF
+ BBD0CDFFACC1BEFFA3B8B5FFA8BDBAFFAFC4C1FFAFC4C1FFB6CBC8FFBCD1CEFF
+ C3D8D5FFC7DCD9FFC9DEDBFFCADFDCFFCEE3E0FFD1E7E2FFC3D7D2FFC5DAD2FF
+ BDD1CCFFC5D9D4FFD2E6E1FFCADED9FFC5D8D5FFC7DCD9FFD4E7E4FFB8CBC8FF
+ 9EB0AFFF90A2A1FF7F9192FF697B7CFF5D6F70FF5F7170FF6D7F7EFF4B5E5BFF
+ 506360FF6F827FFF758885FF6D807DFF6D807DFF6B7E7BFF708380FF6E817EFF
+ 697C79FF637673FF627572FF697C79FF718481FF768986FF687A79FF637574FF
+ 576865FF556361FF5E6B69FF5E6967FF5D6865FF687370FF6D7771FF6A7670FF
+ 67736DFF63716BFF63746BFF677A71FF6A7F76FF6D8279FF687C77FF6C7D79FF
+ 70817DFF748581FF788985FF7E8F8BFF859692FF8A9B97FF9CADA9FFA4B5B1FF
+ ACBDB9FFAFC0BCFFAFC0BCFFB3C4C0FFBDCECAFFC3D7D2FFBFD5D0FFBED4CFFF
+ C2D8D3FFC9DFDAFFCADED9FFC5D9D4FFC2D6D1FFC4D8D3FFC9DAD6FFBDCECAFF
+ BFCECAFFC2D1CDFFBECDC9FFB6C5C1FF9BAAA6FF77857FFF606D65FF949F97FF
+ A8B3ABFF96A199FF8F9A92FF97A29AFF9CA79FFF9EA9A1FF9BA69EFF9CA79FFF
+ 9EA9A1FF9EA9A1FF9BA69EFF95A098FF8E9991FF89948CFF8D9791FF848E88FF
+ 7C8680FF7D8781FF848E88FF858F89FF7D8781FF747E78FF79837DFF77817BFF
+ 7D8781FF86908AFF88928CFF838D87FF818B85FF848F87FF88938BFF8D988EFF
+ 8D9B90FF88968BFF818E86FF828F87FF8A9991FF95A49CFFA1AFA9FFCCDCD5FF
+ D9E8E4FFDFEEEAFFCDDEDAFFBDCECAFFCBDCD9FFC1D2CEFFDAEAE3FFD8E8E1FF
+ D0E0D9FFC8D8D1FFC7D7D0FFCADAD3FFC9D9D2FFC4D4CDFFC2D2CBFFB8C8C1FF
+ B6C6BFFFBFCFC8FFC6D6CFFFC3D3CCFFBFCFC8FFBDCFC8FFB9CFCAFFBFD6D1FF
+ B8CFCAFFAAC1BCFFAEC5C0FFC4DBD6FFCDE4DFFFC6DDD8FFC7DED9FFCBE2DDFF
+ CBE2DDFFC6DDD8FFADC4C0FFB3CAC6FFB5CCC8FFB1C8C4FFB1C8C4FFB4CBC7FF
+ AFC6C2FFA5BCB8FF95ACA8FF97AEAAFF99B0ACFF9DB4B0FFA3BAB6FFA5BCB8FF
+ A0B7B3FF9AB1ADFF859895FF7B8E8BFF748784FF7A8D8AFF889996FF8D9E9BFF
+ 899A97FF839491FF8C9A98FF8A9896FF828F8DFF768381FF727F7DFF707D7BFF
+ 6A7573FF5F6A68FF606B68FF687370FF6A7874FF667470FF697773FF717F7BFF
+ 6F7E7AFF677672FF788985FF7A8B87FF7C8D89FF7F908CFF80948FFF849893FF
+ 879B96FF869C97FF90AAA4FF829E98FF748E88FF69837DFF657C77FF647B76FF
+ 677D78FF6B7F7AFF495A56FF50615DFF697874FF889692FF9AA5A2FF9BA6A3FF
+ A3ACA9FFADB8B5FFA4B2ACFFA5B4ACFFA6B5ADFFA6B5ADFFA4B3ABFFA2B1A9FF
+ A1B0A8FFA1B0A8FFA4B3ABFFA1B0A8FFA1B0A8FFA3B2AAFF9DACA4FF93A29AFF
+ 93A29AFF99A7A1FFB8C7C3FFC5D6D3FFC4D5D2FFCFE0DDFFCFE0DDFFC4D5D2FF
+ CADBD8FFBECFCCFFBED1CEFFAFC2BFFFB2C5C2FFB7CAC7FFABBEBBFFACBFBCFF
+ C6D9D6FFDCEFECFFDAEDEAFFDAEDEAFFD6EBE8FFD3E8E5FFCFE4E1FFD0E5E2FF
+ D3EAE6FFD7EEEAFFE2FBF7FFE0F9F5FFDBF4F0FFD5EEEAFFD0EBE7FFCFEAE6FF
+ CDE8E4FFCBE6E2FFD3F1ECFFD4EFEBFFC5DEDAFFB7D0CCFFB6CBC8FFABC0BDFF
+ A0B3B0FFA3B4B1FFA4B5B2FFA9BCB9FFB4C9C6FFC0D7D3FFCBE2DEFFCCE5E1FF
+ C8E3DFFFC4DFDBFFBBD2CEFFB9CECBFFBCD1CEFFC4D9D6FFC3D8D5FFBED3D0FF
+ C3D8D5FFCFE4E1FFD1E6E3FFD4E9E6FFD5EAE7FFD1E6E3FFCADFDCFFC5DAD7FF
+ C6DBD8FFC8DED9FFD0E4DFFFCBDDD6FFC8D9D5FFCBDCD8FFD0E1DDFFBFD0CCFF
+ ADBEBBFFB5C8C5FFD3E4E1FFDFF0EDFFE4F4F3FFD7E7E6FFB8C7C9FF91A0A2FF
+ 6C7B7DFF546463FF5D6F6EFF576A67FF5E716EFF6A7D7AFF6C7F7CFF6A7D7AFF
+ 687B78FF627572FF738683FF6F827FFF687B78FF627572FF5F726FFF627572FF
+ 6C7F7CFF748784FF7B908EFF6F8482FF556A67FF495C59FF50615EFF556361FF
+ 5F6D69FF72807CFF79857FFF707E78FF6C7C75FF6F817AFF788D84FF829A90FF
+ 8BA399FF90A89EFFA5B9B4FFA8BCB7FFADC1BCFFB2C6C1FFB7CBC6FFBED2CDFF
+ C7DBD6FFCCE0DBFFC5D9D4FFC8DCD7FFCCE0DBFFCDE1DCFFCCE0DBFFCADED9FF
+ C7DBD6FFC6DAD5FFC2D9D4FFC0D7D2FFC2D9D4FFC8DFDAFFC9DFDAFFC3D9D4FF
+ BED4CFFFC1D5D0FFC0D1CDFFB5C6C2FFB4C3BFFFB2C1BDFFABBAB6FFABBAB6FF
+ A2B0ACFF8A9892FF606D65FF8D9B90FF9CAA9FFF8B998EFF89978CFF95A398FF
+ 99A79CFF9AA89DFF9AA89DFF9AA89DFF99A79CFF97A59AFF94A297FF919F94FF
+ 8F9D92FF8F9C94FF909A94FF89938DFF828C86FF808A84FF808A84FF7E8882FF
+ 77817BFF707A74FF76807AFF757F79FF79837DFF7F8983FF828C86FF828C86FF
+ 828C86FF859088FF89948CFF8A958BFF8B968CFF8A958BFF86938BFF88958DFF
+ 8E9B93FF91A098FF97A59FFFAFBDB7FFB6C5C1FFBAC9C5FFB4C3BFFFACBBB7FF
+ ADBEBBFFA1B2AEFFA3B5AEFF9FB2A9FF98ABA2FF94A79EFF98ABA2FFA0B3AAFF
+ A0B3AAFF9AADA4FF9FB2A9FFA3B6ADFFA7BAB1FFAFC2B9FFBFD2C9FFCCDFD6FF
+ C6D9D0FFB5CAC2FFB6CCC7FFBCD3CEFFB8CFCAFFACC3BEFFB0C7C2FFC6DDD8FF
+ D4EBE6FFD3EAE5FFC4DBD6FFC9E0DBFFCAE1DCFFC5DCD7FFB1C8C4FFB1C8C4FF
+ AEC5C1FFA7BEBAFFA5BCB8FFA8BFBBFFA8BFBBFFA6BDB9FF9EB5B1FF98AFABFF
+ 96ADA9FF99B0ACFF9CB3AFFF9BB2AEFF99B0ACFF99B0ACFF9CAFACFF8A9D9AFF
+ 788B88FF758885FF7A8B88FF7B8C89FF798A87FF788986FF818F8DFF818F8DFF
+ 798684FF6A7775FF626F6DFF5E6B69FF545F5DFF444F4DFF56615EFF616C69FF
+ 667470FF697773FF73817DFF7F8D89FF7D8C88FF73827EFF697A76FF6B7C78FF
+ 6F807CFF748581FF798D88FF80948FFF859994FF879D98FF79938DFF6E8A84FF
+ 68827CFF647E78FF637A75FF5E7570FF5E746FFF607671FF566763FF52635FFF
+ 64726EFF85938FFF9DA8A5FFA0ABA8FFA4ADAAFFACB6B0FFAAB6B0FFA8B7AFFF
+ A8B7AFFFA8B7AFFFA8B7AFFFA7B6AEFFA3B2AAFFA0AFA7FFA9B8B0FFA1B0A8FF
+ 9AA9A1FF9BAAA2FF9DACA4FF9CABA3FF9BAAA2FF9CAAA4FF9FADA9FFACBAB8FF
+ A9B7B5FFB5C3C1FFBCCAC8FFBACBC8FFC5D6D3FFBBCCC9FFBACDCAFFB1C4C1FF
+ B6C9C6FFB7CCC9FFB0C5C2FFB8CFCBFFCFE4E1FFDAEFECFFDBEEEBFFDCEFECFF
+ D9EEEBFFD4E9E6FFCEE3E0FFCDE2DFFFCFE6E2FFD3EAE6FFDDF6F2FFDDF6F2FF
+ DAF3EFFFD4EDE9FFD3EEEAFFD7F2EEFFD8F3EFFFD6F1EDFFD5F3EEFFD3F1ECFF
+ C3DEDAFFB7D0CCFFB5CCC8FFABC0BDFFA2B3B0FFA4B5B2FFA4B5B2FFA7BAB7FF
+ AFC2BFFFB4CBC7FFBAD3CFFFBDD8D4FFBFDDD8FFC3DEDAFFBED5D1FFB0C5C2FF
+ AFC4C1FFC0D5D2FFC4D9D6FFB7CCC9FFB5CAC7FFC0D5D2FFC6DBD8FFC4D9D6FF
+ BFD4D1FFB7CCC9FFB0C5C2FFAEC3C0FFB2C7C4FFB6CCC7FFBDD1CCFFB6C8C1FF
+ BFD0CCFFC3D4D0FFC1D2CEFFA9BAB6FF8B9C99FF9BACA9FF96A7A4FFBAC8C6FF
+ DEECEBFFEDFBFAFFE9F6F8FFDAE7E9FFC1CDCFFFA8B6B5FFA4B4B3FFABBEBBFF
+ B0C3C0FFAFC2BFFFAFC2BFFFB1C4C1FFB0C3C0FFAEC1BEFFA2B5B2FFA1B4B1FF
+ A0B3B0FF9EB1AEFF97AAA7FF90A3A0FF91A4A1FF95AAA7FF97ADABFF94AAA8FF
+ 889F9BFF859A97FF91A4A1FF95A6A3FF9CABA7FFADBCB8FFB7C5BFFFADBDB6FF
+ A7B9B2FFACC1B9FFB5CDC3FFBBD4CAFFC0D9CFFFC5DED4FFC1D7D2FFC4D8D3FF
+ C4D8D3FFC3D7D2FFC0D4CFFFC0D4CFFFC2D6D1FFC4D8D3FFC3D7D2FFC1D5D0FF
+ C0D4CFFFC4D8D3FFC9DDD8FFCCE0DBFFCADED9FFC6DCD7FFC0D7D2FFBAD4CEFF
+ BCD3CEFFC1D8D3FFC2D8D3FFBDD3CEFFB8CEC9FFB8CEC9FFB7CBC6FFB4C5C1FF
+ B8C7C3FFB5C4C0FFAAB9B5FFA8B7B3FFA2B0ACFF8F9D97FF6E7D75FF90A095FF
+ 9CAA9FFF8E9E93FF919F94FF97A79CFF9AA89DFF98A89DFF9AA89DFF98A89DFF
+ 98A69BFF92A297FF909E93FF8D9D92FF919F94FF93A196FF97A19BFF949E98FF
+ 909A94FF8A948EFF848E88FF7E8882FF79837DFF77817BFF79837DFF7A847EFF
+ 7C8680FF7F8983FF818B85FF848E88FF86908AFF87928AFF88938BFF889389FF
+ 889389FF8A958BFF8A978FFF8C9991FF8B9890FF8B9890FF94A29CFF99A7A1FF
+ 98A7A3FF95A4A0FF95A4A0FF99A8A4FF9BACA9FF98A9A5FF9AACA5FF97AAA1FF
+ 90A39AFF8C9F96FF90A39AFF96A9A0FF95A89FFF8EA198FF92A59CFF97AAA1FF
+ 93A69DFF8EA198FF9DB0A7FFBBCEC5FFC9DCD3FFC4D9D0FFB7CDC8FFB9D0CBFF
+ B7CEC9FFB1C8C3FFB2C9C4FFBFD6D1FFCDE4DFFFD4EBE6FFC4DBD6FFCAE1DCFF
+ CCE3DEFFC8DFDAFFB7CECAFFB2C9C5FFAEC5C1FFAAC1BDFFA4BBB7FF9FB6B2FF
+ 9EB5B1FFA0B7B3FFA6BDB9FF9EB5B1FF9AB1ADFF98AFABFF8FA6A2FF849B97FF
+ 829995FF89A09CFF8FA29FFF819491FF758885FF6F827FFF6D7E7BFF697A77FF
+ 6D7E7BFF758683FF798785FF7A8886FF73807EFF63706EFF5E6B69FF5E6B69FF
+ 56615FFF46514FFF485350FF56615EFF5E6C68FF62706CFF697773FF768480FF
+ 788783FF73827EFF788985FF798A86FF7B8C88FF7E8F8BFF819590FF879B96FF
+ 8B9F9AFF8CA29DFFA3BFB9FF9AB9B2FF9AB6B0FF9EB8B2FF9DB4AFFF91A8A3FF
+ 8AA09BFF899F9AFF697A76FF566763FF5B6965FF7B8985FF9AA5A2FFA1AAA7FF
+ 9DA6A3FF9FA9A3FFA4B0AAFFA3B0A8FFA2AFA7FFA5B2AAFFA8B5ADFFA9B6AEFF
+ A5B2AAFFA1AEA6FFABB8B0FFA5B2AAFF9DAAA2FF9BA8A0FFA1AEA6FFA8B5ADFF
+ A8B5ADFFA3AFA9FFA0ABA8FFA8B5B3FF9FACAAFFA8B6B4FFB3C1BFFFBBC9C7FF
+ C9DAD7FFBECFCCFFB1C4C1FFAEC1BEFFAFC4C1FFAEC5C1FFADC4C0FFC0D9D5FF
+ D8EFEBFFD8EFEBFFD8EDEAFFDBEEEBFFD9EEEBFFD3E8E5FFCCE1DEFFC9DEDBFF
+ CBE2DEFFD0E7E3FFD3ECE8FFD8F1EDFFD9F2EEFFD6EFEBFFD6F1EDFFDEF9F5FF
+ E1FCF8FFDFFAF6FFD6F4EFFFD4F2EDFFC3DEDAFFB5CECAFFB4CBC7FFABC0BDFF
+ A4B5B2FFA7B8B5FFA9BAB7FFA8BBB8FFA9BCB9FFA6BDB9FFA5BEBAFFA9C4C0FF
+ B1CFCAFFB9D7D2FFC4DDD9FFB8CFCBFFB0C7C3FFB5CCC8FFB6CDC9FFAFC6C2FF
+ A8BFBBFFA8BFBBFFA6BDB9FFA6BDB9FFA6BDB9FFA5BCB8FFA4BBB7FFA3BAB6FF
+ A3BAB6FFA5BBB6FFA1B5B0FF97A9A2FFA9B8B4FFABBAB6FFA7B6B2FF8F9E9AFF
+ 717F7DFF8C9A98FF879593FF929F9DFFA9B5B5FFC7D3D3FFDFEBEDFFE7F3F5FF
+ E3ECEFFFD9E5E5FFC0D0CFFFC2D5D2FFC0D3D0FFC1D4D1FFC4D7D4FFC1D4D1FF
+ C3D6D3FFD1E4E1FFCCDFDCFFCBDEDBFFCCDFDCFFCDE0DDFFC5D8D5FFBBCECBFF
+ BACDCAFFBFD4D1FFB0C8C6FFB9D1CFFFBED5D1FFC7DCD9FFD4E7E4FFD1E2DFFF
+ CCDDD9FFD5E6E2FFD2E2DBFFCBDDD6FFCADCD5FFCCE1D9FFC9E1D7FFC1DAD0FF
+ BDD8CEFFC1DCD2FFBBD1CCFFC0D4CFFFC5D9D4FFC8DCD7FFCADED9FFCCE0DBFF
+ CFE3DEFFD2E6E1FFD2E6E1FFCFE3DEFFCDE1DCFFCDE1DCFFCEE2DDFFCDE1DCFF
+ C9DDD8FFC3D9D4FFC7DED9FFBFD9D3FFBCD6D0FFBED8D2FFC0D7D2FFBAD1CCFF
+ B6CCC7FFB6CCC7FFB1C5C0FFAEC2BDFFB6C7C3FFB4C5C1FFAAB9B5FFA5B4B0FF
+ 9BA9A5FF86948EFF76857DFF91A297FF9CACA1FF97A89DFF9AAA9FFF98A99EFF
+ 96A69BFF98A99EFF97A79CFF96A79CFF97A79CFF92A398FF8E9E93FF8A9B90FF
+ 8B9B90FF8D9D92FF939F99FF949E98FF919B95FF8B958FFF848E88FF7F8983FF
+ 7C8680FF7B857FFF7C8680FF7E8882FF808A84FF808A84FF818B85FF838D87FF
+ 838D87FF828D85FF7D8880FF808B81FF859086FF89948AFF8D9890FF8D9890FF
+ 8A978FFF89968EFF9AA8A2FF9BA9A3FF9CABA7FF93A29EFF8F9E9AFF95A4A0FF
+ 98A6A4FF9CADA9FFA1B3ACFF9DB2A9FF96ABA2FF8FA49BFF8EA39AFF8FA49BFF
+ 8A9F96FF82978EFF9AAFA6FF9AAFA6FF93A89FFF8A9F96FF8BA097FF9EB3AAFF
+ BACFC6FFCEE3DAFFBFD5D0FFBBD2CDFFBAD1CCFFBAD1CCFFB7CEC9FFB7CEC9FF
+ C2D9D4FFD0E7E2FFC6DDD8FFCDE4DFFFCFE6E1FFCCE3DEFFB8CDCAFFB3CAC6FF
+ B4C9C6FFB6CDC9FFB0C5C2FFA0B7B3FF98ADAAFF99B0ACFF9CB1AEFF97AEAAFF
+ 98ADAAFF95ACA8FF889D9AFF788F8BFF7C918EFF8A9F9CFF829592FF839693FF
+ 899C99FF90A3A0FF91A29FFF90A19EFF9BACA9FFABBCB9FFBACBC8FFC0CECCFF
+ BCCAC8FFB3C1BFFFB7C5C3FFC3D1CFFFC3D0CEFFB7C4C2FFB7C5C1FFC6D4D0FF
+ CCDBD7FFC5D4D0FFC1D0CCFFC5D4D0FFC8D7D3FFC3D4D0FFC9DAD6FFC8D9D5FF
+ C6D7D3FFC4D5D1FFC2D6D1FFC2D6D1FFC3D7D2FFC2D8D3FFB1CBC5FFA9C3BDFF
+ A5BFB9FFA7BEB9FFA0B6B1FF90A6A1FF869A95FF839792FF758682FF5B6A66FF
+ 54625EFF75807DFF96A19EFF9DA6A3FF959E9BFF929B98FF9FABA5FF9DAAA2FF
+ 9EABA3FFA3B0A8FFAAB7AFFFAEBBB3FFACB9B1FFA9B6AEFFA7B4ACFFA8B5ADFF
+ A5B2AAFFA0ADA5FFA4B1A9FFABB8B0FFA6B3ABFF9BA7A1FFA5B0ADFFAEB9B7FF
+ A0ADABFFA8B5B3FFB4C2C0FFBCCAC8FFC9D7D5FFB9CAC7FFA7B8B5FFA5B8B5FF
+ A6BBB8FFA2B9B5FFA7BEBAFFC6DDD9FFDDF4F0FFD8EFEBFFD6EBE8FFDAEDEAFF
+ D7ECE9FFD2E7E4FFCADFDCFFC6DBD8FFC8DFDBFFCDE4E0FFCBE2DEFFD3ECE8FF
+ DAF1EDFFD7F0ECFFDAF3EFFFE2FBF7FFE6FFFBFFE1FCF8FFD8F6F1FFD4F2EDFF
+ C2DDD9FFB3CCC8FFB2C9C5FFABC0BDFFA3B6B3FFA8BBB8FFB0C3C0FFB0C3C0FF
+ AABFBCFFA3BAB6FF9EB7B3FFA2BDB9FFAFCDC8FFBED9D5FFBBD4D0FFB7CECAFF
+ ACC3BFFFA5BCB8FFA8BFBBFFACC3BFFFA8BFBBFF9FB6B2FF9EB5B1FFA4BBB7FF
+ ACC3BFFFB2C9C5FFB1C8C4FFA9C0BCFF9EB5B1FF97ACA9FFA4B8B3FF93A4A0FF
+ A1B0ACFF9BAAA6FF93A29EFF7E8C88FF657270FF8B9896FF8D9896FF7C8785FF
+ 838E8CFFAEB9B7FFD6E0E0FFE1EBEBFFDEE8E8FFDCE8E8FFD5E6E3FFCADDDAFF
+ C1D4D1FFC9DCD9FFD1E4E1FFC7DAD7FFCDE0DDFFE9FCF9FFC8DBD8FFC4D7D4FF
+ C4D7D4FFC4D7D4FFBED1CEFFB8CBC8FFBED1CEFFC8DDDAFFC9E1DFFFCBE3E1FF
+ C6DDD9FFC4DBD7FFCADFDCFFC4D7D4FFC0D3D0FFCBDFDAFFC6DAD5FFC8DCD7FF
+ CEE2DDFFD0E6E1FFC7DFD7FFB8D0C8FFB2CDC4FFB6D1C8FFC7DDD8FFC9DFDAFF
+ CDE1DCFFCAE0DBFFC8DCD7FFC2D8D3FFC2D6D1FFC0D6D1FFB4C8C3FFB7CDC8FF
+ C2D6D1FFC7DDD8FFCCE0DBFFC9DFDAFFC8DCD7FFC4DAD5FFC4DBD6FFBDD4CFFF
+ BAD1CCFFBDD4CFFFBFD6D1FFBDD3CEFFBAD0CBFFBAD0CBFFB4C8C3FFAFC3BEFF
+ B5C6C2FFB5C6C2FFABBCB8FFA8B7B3FF9BAAA6FF84938FFF6C7B73FF87978CFF
+ 96A59DFF98A89DFF99A8A0FF93A398FF8D9C94FF95A59AFF95A49CFF97A79CFF
+ 98A79FFF95A59AFF8E9D95FF88988DFF86958DFF87968EFF86928CFF87918BFF
+ 848E88FF808A84FF7C8680FF78827CFF757F79FF747E78FF7B857FFF7E8882FF
+ 818B85FF808A84FF808A84FF808A84FF7D8781FF79847CFF747F77FF7B867CFF
+ 869187FF8D988EFF919C94FF929D95FF919E96FF929F97FF9BA8A0FF9EACA6FF
+ AAB8B2FF9EAEA7FF93A39CFF92A29BFF8E9D99FF96A5A1FF9FB1AAFFA0B3AAFF
+ 9EB1A8FF9AADA4FF9CAFA6FF9FB2A9FF9DB0A7FF96A9A0FF92A59CFF98ABA2FF
+ A3B6ADFFA4B7AEFF92A59CFF81948BFF8DA097FFA4B9B0FFBBD2CAFFB4CCC4FF
+ B6CEC6FFBED6CEFFBBD3CBFFB6CEC6FFC1D8D3FFD4EBE6FFC8DFDAFFCFE6E1FF
+ D3EAE5FFD0E7E2FFBBCDCCFFB3C8C6FFB2C4C3FFB1C6C4FFB1C3C2FFA8BDBBFF
+ A7B9B8FFA6BBB9FFA3B5B4FFA5BAB8FFABBDBCFFADC2C0FFB3C5C4FFB7CCCAFF
+ C1D3D2FFC7D9D8FFD0E3E0FFD3E6E3FFD6E9E6FFD7EAE7FFD8EBE8FFD9ECE9FF
+ DCEFECFFDEF1EEFFDFF2EFFFDEEFECFFD6E7E4FFDAEBE8FFE6F7F4FFE0F1EEFF
+ DAEBE8FFE3F4F1FFDFF0EDFFDEEFECFFDDEEEBFFDDEEEBFFE1F2EFFFE3F4F1FF
+ E0F1EEFFD7EAE7FFDBEEEBFFD8EBE8FFD6E9E6FFD5E8E5FFD6E9E6FFD5E8E5FF
+ D3E6E3FFD1E4E1FFCADED9FFB9CDC8FFBBCFCAFFB5C9C4FF97A8A4FF8D9E9AFF
+ 91A29EFF889793FF7A8985FF818F8BFF7E8C88FF6A7572FF939E9BFFA3AEABFF
+ A9B2AFFF929B98FF929E98FF939F99FF96A29CFF9DA9A3FFA4B0AAFFA8B4AEFF
+ A6B2ACFFA4B0AAFF98A49EFF9FABA5FFA7B3ADFFA7B3ADFFA1ADA7FF9BA7A1FF
+ 9DA9A3FFA3AFA9FFA9B4B1FFAFBAB7FFB1BFBBFFAFBDB9FFABB9B5FFAFBEBAFF
+ BECDC9FFC9DAD6FFB8C9C5FFA1B2AEFFA0B4AFFFA7BBB6FFA8BCB7FFBED4CFFF
+ D8EEE9FFD2E8E3FFD4E9E6FFD7ECE9FFDAEFECFFDAEFECFFD7ECE9FFD1E6E3FF
+ CCE1DEFFC9DEDBFF9FB4B1FFB6CDC9FFDBF0EDFFD6EDE9FFD7EEEAFFE8FFFBFF
+ E6FDF9FFECFFFFFFE5FEFAFFD2EBE7FFCDE6E2FFACC3BFFFBBD2CEFFB0C7C3FF
+ A3B8B5FFA4B9B6FFABC0BDFFACC1BEFFABC2BEFFA6BDB9FFA0B7B3FF9DB6B2FF
+ A2BBB7FFA7C0BCFFB1C8C4FFB4C9C6FFB6CBC8FFB3C8C5FFACC1BEFFA7BCB9FF
+ A4B9B6FFA4B9B6FFADC2BFFFA9BEBBFFA3B8B5FFA1B6B3FFA7BCB9FFAEC3C0FF
+ AABFBCFFA1B6B3FFA1B4B1FF8B9C99FF899795FF889694FF879492FF76817FFF
+ 6A7370FF8E9794FF8A918EFF8B928FFF848D8AFF818A87FF97A19BFFC1CBC5FF
+ DEEAE4FFE5F3EFFFDDF0EDFFCFE4E2FFC5DAD8FFC4D9D7FFC4D9D7FFC3D8D6FF
+ C6DBD9FFCBE0DEFFC2D7D5FFC5DAD8FFD1E6E4FFCADFDDFFCADFDDFFCADFDDFF
+ BDD2D0FFD0E5E3FFC8DEDCFFCAE0DEFFCBE1DFFFCAE0DEFFC7DDDBFFC8DDDBFF
+ CADFDDFFCCE1DEFFCDE2DFFFD0E5E2FFD0E5E2FFCBE2DEFFC8DFDBFFCAE1DDFF
+ CDE4E0FFCEE5E1FFD5ECE8FFD4EBE7FFD0E5E2FFC8DFDBFFC9DEDBFFCBE2DEFF
+ CADFDCFFC3DAD6FFB4C9C6FFBCD3CFFFC4D9D6FFC2D9D5FFC0D5D2FFC0D7D3FF
+ C2D7D4FFC0D5D2FFBED3D0FFB7CCC9FFB2C7C4FFB6CBC8FFBDD2CFFFC0D3D0FF
+ B9CCC9FFB1C4C1FFA7BAB7FFAEC1BEFFB3C6C3FFB0C3C0FFABBEBBFFA8B9B6FF
+ A0B1AEFF99A8A4FF64726CFF909D95FF8F9B95FF89968EFF8A9690FF8B9890FF
+ 95A19BFF8E9B93FF8D9993FF96A39BFF9EAAA4FF9CA9A1FF929E98FF89968EFF
+ 88948EFF8A9690FF78827CFF7E8882FF808A84FF79837DFF727C76FF717B75FF
+ 717B75FF6F7973FF6A746EFF757F79FF78827CFF717B75FF707A74FF79837DFF
+ 7E8882FF7A857DFF808881FF818A80FF868F85FF8F988EFF97A298FF9AA59BFF
+ 97A298FF909E93FF919F94FF94A39BFF9EADA5FFA3B2AAFF9DACA4FF91A098FF
+ 8E9F96FF93A49BFF9CACA5FFA2B2ABFFA5B5AEFFA3B3ACFFA1B1AAFFA1B1AAFF
+ 9EAEA7FF98A8A1FF9BABA4FF9EAEA7FFA1B1AAFF9EAEA7FF99A9A2FF96A69FFF
+ 97A7A0FF97AAA1FFADC2B9FFBDD5CBFFBDD5CBFFB4CCC2FFBAD2C8FFC3DBD1FF
+ C9E0D8FFD2E9E1FFD2E9E1FFD0E7DFFFD3E9E4FFD7EDE8FFC8DAD9FFC7D9D8FF
+ CBDDDCFFD3E5E4FFD8EAE9FFD8EAE9FFD9EBEAFFDCEEEDFFE0F2F1FFE1F3F2FF
+ E1F3F2FFE1F3F2FFE1F3F2FFE2F4F3FFE4F6F5FFE6F8F7FFDCEFECFFDCEFECFF
+ DCEFECFFDDF0EDFFDEF1EEFFDEF1EEFFDEF1EEFFDEF1EEFFE3F6F3FFE5F8F5FF
+ E0F3F0FFE1F4F1FFE7FAF7FFDFF2EFFFDBEEEBFFE7FAF7FFE4F7F4FFE4F7F4FF
+ E4F7F4FFE3F6F3FFE4F7F4FFE6F9F6FFE4F7F4FFE1F4F1FFE3F6F3FFE0F3F0FF
+ DDF0EDFFDCEFECFFDCEFECFFDCEFECFFDAEDEAFFD8EBE8FFDDEEEAFFCFE0DCFF
+ D2E3DFFFCFE0DCFFBDCCC8FFBBCAC6FFBAC9C5FFA7B6B2FF93A19DFF98A6A2FF
+ 97A29FFF7E8986FF9AA5A2FF9EA9A6FFA5AEABFF99A29FFF99A59FFF99A59FFF
+ 9CA8A2FFA1ADA7FFA5B1ABFFA7B3ADFFA4B0AAFFA0ACA6FF99A59FFF9CA8A2FF
+ A3AFA9FFA8B4AEFFA1ADA7FF97A39DFF97A39DFFA0ACA6FFA0ABA8FFA8B3B0FF
+ AEBCB8FFB1BFBBFFB1BFBBFFB4C2BEFFBBCAC6FFC3D2CEFFC7D8D4FFAABBB7FF
+ A4B5B1FFADBEBAFFB5C9C4FFCFE3DEFFDFF3EEFFD2E6E1FFCEE3E0FFD2E7E4FF
+ D7ECE9FFD9EEEBFFD6EBE8FFCFE4E1FFC8DDDAFFC4D9D6FFA6BBB8FFB8CDCAFF
+ D5EAE7FFCEE3E0FFCEE3E0FFE1F6F3FFE2F7F4FFEDFFFFFFEAFFFDFFD7EEEAFF
+ D0E7E3FFAAC1BDFFB8CFCBFFAFC6C2FFA3BAB6FFA4BBB7FFB2C9C5FFAEC5C1FF
+ AAC1BDFFA6BDB9FFA3BAB6FFA1B8B4FF9FB6B2FF9EB5B1FFA3B8B5FFAABFBCFF
+ B2C7C4FFB5CAC7FFB2C7C4FFACC1BEFFA7BCB9FFA4B9B6FFA5BAB7FFA5BAB7FF
+ A3B8B5FFA1B6B3FFA5BAB7FFA9BEBBFFA6BBB8FF9EB3B0FF9EB0AFFF889A99FF
+ 8A9896FF879593FF838E8CFF6E7977FF646B68FF888F8CFF838984FF898F8AFF
+ 8C938EFF888F8AFF848F87FF96A199FFBDCAC2FFDFEDE7FFE6F9F6FFD5EAE8FF
+ C5DAD8FFC0D5D3FFC5DAD8FFC9DEDCFFC6DBD9FFC0D5D3FFCBE0DEFFBED3D1FF
+ C8DDDBFFC8DDDBFFCEE3E1FFD7ECEAFFCADFDDFFCBE0DEFFC5DBD9FFC9DFDDFF
+ CFE5E3FFD3E9E7FFD3E9E7FFD0E6E4FFCDE3E1FFCAE0DEFFCAE0DEFFCCE2E0FF
+ CCE2E0FFC7DDDBFFC4DAD8FFC8DEDCFFCEE4E2FFD4EAE8FFD6EDE9FFD6EDE9FF
+ CFE6E2FFC7DEDAFFC5DCD8FFCAE1DDFFCEE5E1FFCDE4E0FFC9E0DCFFCFE6E2FF
+ D0E7E3FFC9E0DCFFC3DAD6FFBFD6D2FFB9D0CCFFB4C9C6FFB9CCC9FFC1D4D1FF
+ C6D9D6FFC2D5D2FFB9CCC9FFB5C8C5FFBACDCAFFC1D4D1FFB6C9C6FFB5C8C5FF
+ B0C3C0FFABBEBBFFAABDBAFFA9BCB9FFA0B3B0FF97A8A4FF545F5CFF828C86FF
+ 86908AFF848E88FF89938DFF8D9791FF98A29CFF929C96FF89938DFF8A948EFF
+ 8C9690FF8C9690FF8A948EFF87918BFF858F89FF848E88FF848E88FF858F89FF
+ 828C86FF7C8680FF79837DFF79837DFF757F79FF6E7872FF707A74FF79837DFF
+ 7E8882FF7E8882FF7E8882FF808A84FF808A84FF7F8A82FF848C85FF838C82FF
+ 868F85FF90998FFF99A49AFF9DA89EFF98A399FF919C92FF98A69BFF9CAA9FFF
+ 9EAEA3FF9FAFA4FF9DADA2FF9AAA9FFF96A79CFF94A59AFF9DABA5FFA1AFA9FF
+ A3B1ABFFA1AFA9FFA1AFA9FFA2B0AAFF9DABA5FF97A59FFF99A7A1FF9AA8A2FF
+ 9CAAA4FF9DABA5FF9BA9A3FF96A49EFF8F9D97FF8A9B92FF97ACA3FFAFC7BBFF
+ B7CFC3FFB0C8BCFFB5CDC3FFBDD5CBFFC6DED4FFD3EBE1FFD1E8E0FFCFE6DEFF
+ D1E7E2FFD5EBE6FFD8EBE8FFD8EBE8FFDDF0EDFFE5F8F5FFE9FCF9FFE9FCF9FF
+ EAFDFAFFEEFFFEFFEDFFFDFFECFFFCFFEBFEFBFFEAFDFAFFEAFDFAFFE8FBF8FF
+ E5F8F5FFE3F6F3FFEEFFFEFFEDFFFDFFECFFFCFFECFFFCFFEBFEFBFFEBFEFBFF
+ E9FCF9FFE9FCF9FFE4F7F4FFEBFEFBFFE9FCF9FFE8FBF8FFEAFDFAFFE2F5F2FF
+ E0F3F0FFEEFFFEFFE6F9F6FFE7FAF7FFE8FBF8FFE7FAF7FFE6F9F6FFE5F8F5FF
+ E6F9F6FFE7FAF7FFE8FBF8FFE5F8F5FFE3F6F3FFE2F5F2FFE3F6F3FFE2F5F2FF
+ E0F3F0FFDEF1EEFFE6F7F3FFDFF0ECFFE1F2EEFFDEEFEBFFD8E7E3FFDAE9E5FF
+ D0DFDBFFB5C4C0FFAEBCB8FFACBAB6FFA9B4B1FF8F9A97FF9FAAA7FF95A09DFF
+ A0A9A6FFA1AAA7FF9CA8A2FF9DA9A3FF9FABA5FFA2AEA8FFA5B1ABFFA6B2ACFF
+ A5B1ABFFA2AEA8FFA3AFA9FFA0ACA6FFA6B2ACFFAEBAB4FFA7B3ADFF98A49EFF
+ 98A49EFFA5B1ABFFA1ACA9FFA5B0ADFFA7B5B1FFABB9B5FFAFBDB9FFB5C3BFFF
+ BBCAC6FFC0CFCBFFCBDCD8FFB9CAC6FFB7C8C4FFC0D1CDFFC6DAD5FFD5E9E4FF
+ DDF1ECFFD2E6E1FFC9DEDBFFCEE3E0FFD5EAE7FFD9EEEBFFD8EDEAFFD1E6E3FF
+ C7DCD9FFC1D6D3FFB7CCC9FFC0D5D2FFD5EAE7FFCADFDCFFC9DEDBFFDCF1EEFF
+ E1F6F3FFEDFFFFFFEBFFFEFFD9F0ECFFD1E8E4FFA8BFBBFFB5CCC8FFAEC5C1FF
+ A4BBB7FFA5BCB8FFB3CAC6FFADC4C0FFA7BEBAFFA5BCB8FFA6BDB9FFA4BBB7FF
+ 9EB5B1FF98AFABFF9AAFACFFA0B5B2FFA6BBB8FFA9BEBBFFA8BDBAFFA5BAB7FF
+ A2B7B4FFA0B5B2FF9DB2AFFFA1B6B3FFA2B7B4FF9FB4B1FF9FB4B1FFA1B6B3FF
+ 9EB3B0FF99AEABFF9BADACFF8A9C9BFF8E9C9AFF879593FF7F8A88FF687371FF
+ 5D6461FF808784FF838984FF848A85FF888F8AFF868D88FF758078FF737E76FF
+ 96A39BFFC1CFC9FFE9FAF6FFE6F9F6FFDCEFECFFCDE0DDFFC6D9D6FFC6D9D6FF
+ BFD2CFFFB3C6C3FFB0C3C0FFA0B3B0FFBACDCAFFC3D6D3FFC1D4D1FFCFE2DFFF
+ C6D9D6FFB6CBC8FFD1E8E4FFCEE5E1FFCBE2DEFFC8DFDBFFC8DFDBFFC7DEDAFF
+ C6DDD9FFC4DBD7FFC5DCD8FFCAE1DDFFD0E7E3FFD1E8E4FFCFE6E2FFCFE6E2FF
+ D4EBE7FFDAF1EDFFD5EAE7FFD6EBE8FFCFE4E1FFC3D8D5FFBDD2CFFFC2D7D4FF
+ CBE0DDFFCFE4E1FFD1E6E3FFD4E9E6FFD3E8E5FFD0E5E2FFCEE3E0FFCCE1DEFF
+ C5DAD7FFBDD2CFFFCADDDAFFC4D7D4FFBED1CEFFBCCFCCFFBDD0CDFFBCCFCCFF
+ B7CAC7FFB3C6C3FFBACDCAFFB5C8C5FFAEC1BEFFA9BCB9FFA9BCB9FFA6B9B6FF
+ 95A8A5FF869793FF4D5855FF7D8781FF838D87FF858F89FF8B958FFF8F9993FF
+ 9AA49EFF929C96FF838D87FF7D8781FF77817BFF79837DFF808A84FF858F89FF
+ 848E88FF808A84FF88928CFF858F89FF7F8983FF79837DFF79837DFF79837DFF
+ 737D77FF69736DFF6E7872FF717B75FF79837DFF818B85FF818B85FF7B857FFF
+ 78827CFF79847CFF868E87FF828B81FF848D83FF8F988EFF9CA79DFFA2ADA3FF
+ 9BA69CFF929D93FF9CAA9FFFA1AFA4FF9EAEA3FF99A99EFF9CACA1FFA2B2A7FF
+ 9DAEA3FF93A499FF9BA9A3FF9EACA6FF9EACA6FF9DABA5FFA0AEA8FFA3B1ABFF
+ 9EACA6FF96A49EFF94A29CFF92A09AFF92A09AFF97A59FFF9DABA5FF9EACA6FF
+ 9AA8A2FF93A49BFF8CA198FFA9C1B5FFB6CEC2FFB1C9BDFFB3CBC1FFB9D1C7FF
+ C3DBD1FFD2EAE0FFCCE3DBFFCAE1D9FFCBE1DCFFD0E6E1FFDEF1EEFFDCEFECFF
+ DEF1EEFFE2F5F2FFE2F5F2FFDEF1EEFFE0F3F0FFE5F8F5FFE2F5F2FFE1F4F1FF
+ E2F5F2FFE4F7F4FFE7FAF7FFE7FAF7FFE4F7F4FFE0F3F0FFE4F7F4FFE6F9F6FF
+ E7FAF7FFE6F9F6FFE2F5F2FFE1F4F1FFE2F5F2FFE4F7F4FFE2F5F2FFEAFDFAFF
+ E7FAF7FFE5F8F5FFE9FCF9FFE3F6F3FFE0F3F0FFE9FCF9FFE4F7F4FFE5F8F5FF
+ E6F9F6FFE6F9F6FFE1F4F1FFDCEFECFFDEF1EEFFE3F6F3FFDEF1EEFFDEF1EEFF
+ DFF2EFFFE1F4F1FFE3F6F3FFE1F4F1FFDDF0EDFFD9ECE9FFDEEFEBFFE1F2EEFF
+ E1F2EEFFDCEDE9FFDBEAE6FFDCEBE7FFCBDAD6FFB0BFBBFFBECCC8FFB2C0BCFF
+ A8B3B0FF8F9A97FF9CA7A4FF8C9794FF9AA3A0FFA5AEABFF9CA8A2FF9CA8A2FF
+ 9CA8A2FF9EAAA4FFA1ADA7FFA5B1ABFFA8B4AEFFA9B5AFFFAEBAB4FFA4B0AAFF
+ A5B1ABFFADB9B3FFA7B3ADFF98A49EFF9BA7A1FFACB8B2FFACB7B4FFA8B3B0FF
+ A1AFABFFA1AFABFFA7B5B1FFB2C0BCFFBBCAC6FFC2D1CDFFBFD0CCFFC1D2CEFF
+ C9DAD6FFCFE0DCFFCDE1DCFFD1E5E0FFD5E9E4FFD4E8E3FFCCE1DEFFD0E5E2FF
+ D8EDEAFFDEF3F0FFDEF3F0FFD8EDEAFFCDE2DFFFC5DAD7FFC1D6D3FFC4D9D6FF
+ D3E8E5FFC6DBD8FFC4D9D6FFD6EBE8FFD9EEEBFFE7FCF9FFE8FFFBFFDAF1EDFF
+ D4EBE7FFA8BFBBFFB4CBC7FFAEC5C1FFA3BAB6FFA2B9B5FFABC2BEFFA8BFBBFF
+ A6BDB9FFA5BCB8FFA5BCB8FFA3BAB6FF9FB6B2FF9BB2AEFFA4B9B6FFA2B7B4FF
+ 9FB4B1FF9CB1AEFF9AAFACFF9BB0ADFF9DB2AFFF9FB4B1FF9BB0ADFFA0B5B2FF
+ A1B6B3FF9AAFACFF95AAA7FF95AAA7FF96ABA8FF94A9A6FF97A9A8FF8B9D9CFF
+ 919F9DFF889694FF7E8987FF677270FF5C6360FF7E8582FF898F8AFF838984FF
+ 7D847FFF7B827DFF747F77FF737E76FF808D85FF92A09AFFC8D7D3FFE1F2EFFF
+ F0FFFEFFE3F4F1FFD3E4E1FFCEDFDCFFC7D8D5FFBDCECBFFA1B2AFFF99AAA7FF
+ C7D8D5FFD6E7E4FFC9DAD7FFD8E9E6FFD6E7E4FFC2D5D2FFD8EDEAFFD4EBE7FF
+ D1E8E4FFCFE6E2FFCDE4E0FFC9E0DCFFC3DAD6FFBED5D1FFBDD4D0FFC5DCD8FF
+ D1E8E4FFD9F0ECFFD7EEEAFFD1E8E4FFCFE6E2FFD3EAE6FFD2E7E4FFD7ECE9FF
+ D3E8E5FFC6DBD8FFBCD1CEFFBED3D0FFC7DCD9FFCDE2DFFFCEE3E0FFD1E6E3FF
+ D2E7E4FFD2E7E4FFD6EBE8FFD8EDEAFFD3E8E5FFC9DEDBFFCFE2DFFFC6D9D6FF
+ BFD2CFFFC4D7D4FFD2E5E2FFDAEDEAFFD5E8E5FFCDE0DDFFBACDCAFFB9CCC9FF
+ B6C9C6FFB3C6C3FFAFC2BFFFA2B5B2FF899C99FF748581FF515C59FF818B85FF
+ 87918BFF86908AFF8A948EFF8A948EFF919B95FF87918BFF808A84FF78827CFF
+ 717B75FF727C76FF7B857FFF848E88FF86908AFF858F89FF858F89FF848E88FF
+ 7F8983FF78827CFF77817BFF78827CFF747E78FF6D7771FF6D7771FF6A746EFF
+ 707A74FF7D8781FF7D8781FF737D77FF6F7973FF747F77FF828A83FF7D867CFF
+ 7E877DFF8C958BFF9DA89EFFA5B0A6FF9EA99FFF949F95FF97A59AFFA3B1A6FF
+ A3B3A8FF9AAA9FFF9BABA0FFA4B4A9FFA0B1A6FF92A398FF99A7A1FF9BA9A3FF
+ 9BA9A3FF9CAAA4FFA2B0AAFFA7B5AFFFA3B1ABFF9BA9A3FFA0AEA8FF9CAAA4FF
+ 99A7A1FF9AA8A2FF9EACA6FFA3B1ABFFA5B3ADFFA4B5ACFF98ADA4FFB3CBBFFF
+ BED6CAFFB7CFC3FFB8D0C6FFBDD5CBFFC4DCD2FFD0E8DEFFD0E7DFFFCCE3DBFF
+ CDE3DEFFD2E8E3FFE0F1EEFFDFF0EDFFE1F2EFFFE5F6F3FFE5F6F3FFE3F4F1FF
+ E7F8F5FFEEFFFCFFE2F3F0FFE3F4F1FFE5F6F3FFE7F8F5FFE9FAF7FFE9FAF7FF
+ E7F8F5FFE5F6F3FFE1F4F1FFE5F8F5FFE8FBF8FFE6F9F6FFE2F5F2FFE0F3F0FF
+ E3F6F3FFE6F9F6FFE2F5F2FFE7FAF7FFDFF2EFFFDAEDEAFFE0F3F0FFDCEFECFF
+ D2E5E2FFD3E6E3FFE0F3F0FFDEF1EEFFDEF1EEFFDEF1EEFFD5E8E5FFC9DCD9FF
+ C7DAD7FFCCDFDCFFCCDFDCFFCEE1DEFFD2E5E2FFD6E9E6FFD8EBE8FFD6E9E6FF
+ D0E3E0FFCBDEDBFFC8D9D5FFD3E4E0FFD5E6E2FFD3E4E0FFD8E7E3FFD6E5E1FF
+ C4D3CFFFB4C3BFFFC7D5D1FFB1BFBBFF9FAAA7FF87928FFF98A3A0FF8A9592FF
+ 97A09DFFA1AAA7FF9FABA5FF9DA9A3FF9BA7A1FF9AA6A0FF9BA7A1FF9FABA5FF
+ A5B1ABFFAAB6B0FFADB9B3FFA1ADA7FF9DA9A3FFA1ADA7FF9DA9A3FF94A09AFF
+ 9BA7A1FFACB8B2FFB0BBB8FFABB6B3FFA3B1ADFFA2B0ACFFA8B6B2FFB1BFBBFF
+ B7C6C2FFBCCBC7FFB7C8C4FFB8C9C5FFB7C8C4FFBDCECAFFC9DDD8FFD2E6E1FF
+ D5E9E4FFD9EDE8FFD4E9E6FFD7ECE9FFDDF2EFFFE3F8F5FFE5FAF7FFE1F6F3FF
+ D7ECE9FFCFE4E1FFC2D7D4FFC1D6D3FFCDE2DFFFC2D7D4FFC1D6D3FFCDE2DFFF
+ CBE0DDFFD7ECE9FFE2F9F5FFD8EFEBFFD5ECE8FFA8BFBBFFB3CAC6FFADC4C0FF
+ A2B9B5FFA0B7B3FFA4BBB7FFA6BDB9FFA7BEBAFFA5BCB8FFA0B7B3FF9DB4B0FF
+ 9CB3AFFF9DB4B0FFAABFBCFFA7BCB9FFA2B7B4FF9EB3B0FF9DB2AFFF9EB3B0FF
+ A0B5B2FFA1B6B3FF9DB2AFFFA1B6B3FF9FB4B1FF95AAA7FF8DA29FFF8CA19EFF
+ 8EA3A0FF8FA4A1FF8EA09FFF859796FF8D9B99FF82908EFF798482FF66716FFF
+ 5C6360FF7D8481FF848A85FF878D88FF818883FF787F7AFF758078FF7C877FFF
+ 7B8880FF76827CFF919F9BFFB3C1BFFFD3E1DFFFDCEAE8FFDFEDEBFFE0EEECFF
+ D4E2E0FFC1CFCDFFA0AEACFF92A09EFFB8C6C4FFC6D4D2FFC2D0CEFFDDEBE9FF
+ DFEDEBFFC8D9D6FFC3D6D3FFC9DEDBFFD4E9E6FFDEF3F0FFE1F6F3FFDDF2EFFF
+ D4E9E6FFCDE2DFFFC5DAD7FFC6DBD8FFCBE0DDFFD1E6E3FFCEE3E0FFC4D9D6FF
+ C1D6D3FFC4D9D6FFCADFDCFFD3E8E5FFD5EAE7FFCCE1DEFFC2D7D4FFC3D8D5FF
+ CADFDCFFCFE4E1FFD4E9E6FFD6EBE8FFD5EAE7FFD4E9E6FFD6EBE8FFD7ECE9FF
+ D0E5E2FFC6DBD8FFCBDEDBFFCFE2DFFFD1E4E1FFCBDEDBFFC1D4D1FFBCCFCCFF
+ BFD2CFFFC5D8D5FFC4D7D4FFC5D8D5FFC2D5D2FFB9CCC9FFAEC1BEFF9EB1AEFF
+ 879A97FF758682FF525D5AFF828C86FF86908AFF838D87FF848E88FF818B85FF
+ 858F89FF7A847EFF7B857FFF79837DFF76807AFF76807AFF7A847EFF808A84FF
+ 858F89FF88928CFF818B85FF858F89FF848E88FF7D8781FF78827CFF79837DFF
+ 7B857FFF79837DFF76807AFF6F7973FF707A74FF7A847EFF7B857FFF737D77FF
+ 727C76FF78837BFF79817AFF757E74FF788177FF889187FF9BA69CFFA5B0A6FF
+ A0ABA1FF96A197FF92A095FFA5B3A8FFACBCB1FFA3B3A8FF9EAEA3FFA4B4A9FF
+ A1B2A7FF96A79CFF98A6A0FF9AA8A2FF9CAAA4FF9DABA5FFA4B2ACFFAAB8B2FF
+ A9B7B1FFA3B1ABFFAFBDB7FFB0BEB8FFAFBDB7FFABB9B3FFA4B2ACFFA0AEA8FF
+ 9FADA7FF9FB0A7FFA8BDB4FFBED6CAFFC3DBCFFFBCD4C8FFC1D9CFFFC7DFD5FF
+ C9E1D7FFD1E9DFFFD9F0E8FFD4EBE3FFD4EAE5FFD9EFEAFFDBECE9FFDCEDEAFF
+ E1F2EFFFE5F6F3FFE2F3F0FFDCEDEAFFDEEFECFFE3F4F1FFE1F2EFFFE4F5F2FF
+ E6F7F4FFE6F7F4FFE3F4F1FFE2F3F0FFE3F4F1FFE4F5F2FFE5F8F5FFE3F6F3FF
+ E1F4F1FFE0F3F0FFE0F3F0FFDFF2EFFFDDF0EDFFDBEEEBFFE0F3F0FFE4F7F4FF
+ D8EBE8FFCEE1DEFFD2E5E2FFCCDFDCFFBDD0CDFFB8CBC8FFD1E4E1FFCBDEDBFF
+ CBDEDBFFCCDFDCFFC4D7D4FFB3C6C3FFACBFBCFFAEC1BEFFC0D3D0FFC0D3D0FF
+ C2D5D2FFC4D7D4FFC6D9D6FFC4D7D4FFC0D3D0FFBCCFCCFFAEBFBBFFB8C9C5FF
+ BACBC7FFC0D1CDFFD1E0DCFFCBDAD6FFBBCAC6FFB8C7C3FFC4D2CEFFAFBDB9FF
+ 9CA7A4FF848F8CFF9AA5A2FF8F9A97FF98A19EFF9BA4A1FFA1ADA7FFA1ADA7FF
+ 9EAAA4FF9BA7A1FF99A59FFF9AA6A0FF9DA9A3FFA1ADA7FFA9B5AFFFA2AEA8FF
+ 9CA8A2FF9AA6A0FF98A49EFF99A59FFFA2AEA8FFADB9B3FFA7B2AFFFA8B3B0FF
+ A7B5B1FFABB9B5FFAFBDB9FFB1BFBBFFB0BFBBFFB0BFBBFFB7C8C4FFABBCB8FF
+ 97A8A4FFA1B2AEFFC6DAD5FFDDF1ECFFDCF0EBFFDDF1ECFFDBF0EDFFDBF0EDFF
+ DDF2EFFFE3F8F5FFE7FCF9FFE6FBF8FFDFF4F1FFD9EEEBFFCBE0DDFFC6DBD8FF
+ D2E7E4FFCADFDCFFC8DDDAFFD0E5E2FFC9DEDBFFD3E8E5FFDEF5F1FFD6EDE9FF
+ D3EAE6FFA4BBB7FFAEC5C1FFACC3BFFFA3BAB6FFA0B7B3FFA3BAB6FFA6BDB9FF
+ A7BEBAFFA2B9B5FF9BB2AEFF96ADA9FF97AEAAFF9AB1ADFF9CB1AEFF9CB1AEFF
+ 9EB3B0FFA1B6B3FFA3B8B5FFA2B7B4FF9EB3B0FF9AAFACFF9CB1AEFFA0B5B2FF
+ 9DB2AFFF93A8A5FF8BA09DFF8A9F9CFF8A9F9CFF899E9BFF869897FF7D8F8EFF
+ 83918FFF788684FF737E7CFF646F6DFF5B625FFF79807DFF787E79FF888E89FF
+ 8C938EFF7E8580FF747F77FF7A857DFF7A877FFF74807AFF747F7CFF818E8CFF
+ 98A3A1FFADBAB8FFC5D0CEFFC9D6D4FFB5C0BEFF96A3A1FF9DA8A6FF7E8B89FF
+ 899492FF8D9A98FFA2ADABFFCAD7D5FFCCD7D5FFB7C5C3FFAABBB8FFAABFBCFF
+ B2C5C2FFB7CCC9FFC2D5D2FFCCE1DEFFDBEEEBFFE2F7F4FFDDF0EDFFCFE4E1FF
+ C9DCD9FFC8DDDAFFC7DAD7FFBED3D0FFBED1CEFFC1D6D3FFBBD0CDFFC6DBD8FF
+ CDE2DFFFC9DEDBFFC3D8D5FFC4D9D6FFC9DEDBFFCCE1DEFFCFE4E1FFD4E9E6FF
+ D5EAE7FFD4E9E6FFD4E9E6FFD5EAE7FFD0E5E2FFC9DEDBFFC5D8D5FFC4D7D4FF
+ C2D5D2FFBFD2CFFFBBCECBFFB7CAC7FFB3C6C3FFB1C4C1FFCADDDAFFC6D9D6FF
+ BACDCAFFAABDBAFF9DB0ADFF93A6A3FF859895FF7A8B87FF56615EFF858F89FF
+ 89938DFF86908AFF87918BFF838D87FF88928CFF7D8781FF78827CFF7B857FFF
+ 7D8781FF7D8781FF7B857FFF7B857FFF7F8983FF828C86FF78827CFF7F8983FF
+ 808A84FF79837DFF747E78FF76807AFF7A847EFF7C8680FF79837DFF747E78FF
+ 727C76FF757F79FF77817BFF76807AFF757F79FF78837BFF737B74FF717A70FF
+ 767F75FF868F85FF98A399FFA2ADA3FF9FAAA0FF97A298FF94A297FFA5B3A8FF
+ AFBFB4FFAABAAFFFA4B4A9FFA4B4A9FFA2B3A8FF9DAEA3FF98A6A0FF9DABA5FF
+ A1AFA9FFA1AFA9FFA4B2ACFFAAB8B2FFABB9B3FFA9B7B1FFA5B3ADFFADBBB5FF
+ B5C3BDFFB5C3BDFFADBBB5FFA4B2ACFF9EACA6FF9BACA3FFA9BEB5FFBED6CAFF
+ C5DDD1FFC1D9CDFFC8E0D6FFCEE6DCFFCDE5DBFFD1E9DFFFD7EEE6FFD1E8E0FF
+ D0E6E1FFD6ECE7FFBACBC7FFC0D1CDFFCADBD7FFD0E1DDFFCADBD7FFBDCECAFF
+ B7C8C4FFB9CAC6FFCBDCD8FFD1E2DEFFD7E8E4FFD7E8E4FFD4E5E1FFD5E6E2FF
+ DDEEEAFFE4F5F1FFDEF1EEFFCFE2DFFFC2D5D2FFC2D5D2FFCADDDAFFCADDDAFF
+ BCCFCCFFAEC1BEFFD5E8E5FFDEF1EEFFD4E7E4FFC7DAD7FFC6D9D6FFBFD2CFFF
+ B1C4C1FFADC0BDFFC2D5D2FFBBCECBFFBDD0CDFFC7DAD7FFC4D7D4FFB5C8C5FF
+ ACBFBCFFADC0BDFFC0D3D0FFBCCFCCFFB7CAC7FFB4C7C4FFB3C6C3FFB3C6C3FF
+ B2C5C2FFB1C4C1FFA8B9B5FFA8B9B5FFA0B1ADFFADBEBAFFC7D6D2FFBBCAC6FF
+ A6B5B1FFACBBB7FFAFBDB9FFA5B3AFFF9CA7A4FF86918EFFA0ABA8FF99A4A1FF
+ 9FA8A5FF9CA5A2FF9CA8A2FF9FABA5FFA2AEA8FFA1ADA7FF9DA9A3FF9AA6A0FF
+ 99A59FFF9AA6A0FF9FABA5FFA2AEA8FF9FABA5FF98A49EFF98A49EFFA1ADA7FF
+ A9B5AFFFAAB6B0FFA0ABA8FFA4AFACFFA7B5B1FFABB9B5FFAEBCB8FFAEBCB8FF
+ ADBCB8FFAEBDB9FFAFC0BCFFADBEBAFF9EAFABFFA8B9B5FFCFE3DEFFE1F5F0FF
+ DDF1ECFFE3F7F2FFDDF2EFFFDAEFECFFD9EEEBFFDCF1EEFFE2F7F4FFE4F9F6FF
+ E1F6F3FFDDF2EFFFDAEFECFFD2E7E4FFDBF0EDFFD4E9E6FFD3E8E5FFD8EDEAFF
+ CFE4E1FFD8EDEAFFDDF4F0FFD6EDE9FFCFE6E2FF9CB3AFFFA6BDB9FFA9C0BCFF
+ A5BCB8FFA5BCB8FFA3BAB6FFA2B9B5FF9FB6B2FF9CB3AFFF98AFABFF97AEAAFF
+ 97AEAAFF98AFABFF91A6A3FF92A7A4FF96ABA8FF9BB0ADFF9FB4B1FF9EB3B0FF
+ 99AEABFF94A9A6FF96ABA8FF9BB0ADFF9BB0ADFF95AAA7FF90A5A2FF8EA3A0FF
+ 899E9BFF849996FF859796FF798B8AFF7D8B89FF717F7DFF6F7A78FF65706EFF
+ 5B625FFF777E7BFF7B817CFF818782FF848B86FF7F8681FF78837BFF77827AFF
+ 77847CFF79857FFF747F7CFF717C79FF77807DFF828D8AFF939C99FF929D9AFF
+ 858E8BFF747F7CFF969F9CFF848F8CFF848D8AFF7A8582FF939C99FFB8C3C0FF
+ BCC5C2FFB7C5C1FFA3B2AEFF9DB1ACFF9AABA7FF92A6A1FF97A8A4FFA5B9B4FF
+ C0D1CDFFD2E6E1FFE2F3EFFFCFE3DEFFC8D9D5FFCDE1DCFFD3E4E0FFCBDFDAFF
+ C8D9D5FFC9DDD8FFBED1CEFFC7DAD7FFCDE0DDFFC9DCD9FFC5D8D5FFC6D9D6FF
+ C9DCD9FFC9DCD9FFC7DAD7FFCFE2DFFFD5E8E5FFD5E8E5FFD5E8E5FFD7EAE7FF
+ D6E9E6FFD3E6E3FFC3D6D3FFBCCFCCFFBBCECBFFC7DAD7FFDAEDEAFFE2F5F2FF
+ DBEEEBFFD0E3E0FFC3D6D3FFB8CBC8FFA7BAB7FF97AAA7FF91A4A1FF8DA09DFF
+ 819491FF768783FF5C6764FF8A948EFF8E9892FF8A948EFF8B958FFF89938DFF
+ 8F9993FF858F89FF79837DFF7E8882FF838D87FF848E88FF818B85FF7C8680FF
+ 78827CFF77817BFF757F79FF78827CFF76807AFF717B75FF707A74FF747E78FF
+ 77817BFF757F79FF77817BFF77817BFF747E78FF717B75FF737D77FF78827CFF
+ 77817BFF727D75FF717972FF727B71FF788177FF879086FF95A096FF9EA99FFF
+ 9CA79DFF97A298FF99A79CFFA0AEA3FFA5B5AAFFA7B7ACFFA5B5AAFFA1B1A6FF
+ 9EAFA4FF9EAFA4FF9AA8A2FFA2B0AAFFA7B5AFFFA3B1ABFFA1AFA9FFA4B2ACFF
+ A8B6B0FFA9B7B1FF9EACA6FFA3B1ABFFA9B7B1FFADBBB5FFADBBB5FFAAB8B2FF
+ A6B4AEFFA2B3AAFFA2B7AEFFBED6CAFFCCE4D8FFCAE2D6FFCDE5DBFFCDE5DBFF
+ CAE2D8FFCEE6DCFFD3EAE2FFCCE3DBFFCAE0DBFFD1E7E2FF8D9E9AFF98A9A5FF
+ A9BAB6FFB5C6C2FFB1C2BEFFA3B4B0FF99AAA6FF98A9A5FF95A6A2FF9FB0ACFF
+ AABBB7FFAEBFBBFFAFC0BCFFB5C6C2FFC3D4D0FFD0E1DDFFEDFFFDFFD3E6E3FF
+ BCCFCCFFBDD0CDFFCCDFDCFFCDE0DDFFB5C8C5FF9CAFACFFC8DBD8FFD7EAE7FF
+ D2E5E2FFC3D6D3FFBFD2CFFFB8CBC8FFAFC2BFFFAFC2BFFFBFD2CFFFB9CCC9FF
+ BFD2CFFFD1E4E1FFD7EAE7FFCCDFDCFFC4D7D4FFC5D8D5FFC6D9D6FFBED1CEFF
+ B2C5C2FFAABDBAFFA7BAB7FFA9BCB9FFACBFBCFFADC0BDFFB5C6C2FFA9BAB6FF
+ 97A8A4FFA6B7B3FFC3D2CEFFB0BFBBFF94A39FFF9BAAA6FF97A5A1FF99A7A3FF
+ 9AA5A2FF889390FFA4AFACFFA1ACA9FFA7B0ADFFA0A9A6FF939F99FF9AA6A0FF
+ A3AFA9FFA7B3ADFFA4B0AAFF9FABA5FF9BA7A1FF99A59FFF919D97FF9BA7A1FF
+ 9CA8A2FF929E98FF94A09AFFA2AEA8FFA7B3ADFFA1ADA7FFA0ABA8FFA3AEABFF
+ A3B1ADFFA4B2AEFFA5B3AFFFA9B7B3FFAFBEBAFFB4C3BFFFA2B3AFFFB9CAC6FF
+ BECFCBFFC6D7D3FFDBEFEAFFDCF0EBFFD7EBE6FFE7FBF6FFDDF2EFFFD7ECE9FF
+ D3E8E5FFD5EAE7FFDCF1EEFFE0F5F2FFE0F5F2FFDDF2EFFFE0F5F2FFD5EAE7FF
+ DDF2EFFFD6EBE8FFD5EAE7FFDAEFECFFD0E5E2FFDAEFECFFDFF6F2FFD6EDE9FF
+ CCE3DFFF95ACA8FF9FB6B2FFA6BDB9FFA8BFBBFFAAC1BDFFA0B7B3FF9BB2AEFF
+ 96ADA9FF95ACA8FF99B0ACFF9CB3AFFF9CB3AFFF9AB1ADFF99AEABFF96ABA8FF
+ 94A9A6FF95AAA7FF98ADAAFF9BB0ADFF9BB0ADFF99AEABFF90A5A2FF96ABA8FF
+ 9AAFACFF98ADAAFF96ABA8FF93A8A5FF8A9F9CFF819693FF899B9AFF7B8D8CFF
+ 7C8A88FF6F7D7BFF707B79FF687371FF5E6562FF777E7BFF888E89FF787E79FF
+ 717873FF7B827DFF7F8A82FF79847CFF748179FF78857DFF7B857FFF78817EFF
+ 78817EFF77807DFF717A77FF6D7673FF747D7AFF7F8885FF7B8481FF87908DFF
+ 909996FF7D8683FF858E8BFF9FA8A5FFA5AEABFFB8C3C0FFA3B2AEFFA7B8B4FF
+ A9BAB6FFA3B4B0FF99AAA6FF96A7A3FF9DAEAAFFA6B7B3FFCEDFDBFFC1D2CEFF
+ C1D2CEFFD4E5E1FFDFF0ECFFD8E9E5FFCDDEDAFFCADBD7FFD1E2DFFFD5E8E5FF
+ D7EAE7FFD0E3E0FFCBDEDBFFCCDFDCFFCCDFDCFFCBDEDBFFCADDDAFFD3E6E3FF
+ D9ECE9FFD6E9E6FFD3E6E3FFD2E5E2FFD2E5E2FFCFE2DFFFDAEDEAFFDDF0EDFF
+ DEF1EEFFD8EBE8FFCCDFDCFFC0D3D0FFB8CBC8FFB6C9C6FFBCCFCCFFAFC2BFFF
+ 9EB1AEFF95A8A5FF97AAA7FF94A7A4FF829592FF70817DFF5D6865FF8A948EFF
+ 8C9690FF87918BFF88928CFF86908AFF8C9690FF838D87FF7E8882FF828C86FF
+ 88928CFF8A948EFF88928CFF808A84FF76807AFF6F7973FF7C8680FF7A847EFF
+ 757F79FF707A74FF747E78FF7A847EFF79837DFF747E78FF77817BFF7C8680FF
+ 7A847EFF737D77FF76807AFF7E8882FF7B857FFF707B73FF727A73FF747D73FF
+ 7C857BFF889187FF939E94FF9AA59BFF9AA59BFF96A197FF9DABA0FF99A79CFF
+ 98A89DFF9FAFA4FFA1B1A6FF9DADA2FF99AA9FFF9AABA0FF9CAAA4FFA6B4AEFF
+ ABB9B3FFA5B3ADFF9EACA6FF9FADA7FFA4B2ACFFA6B4AEFFAEBCB6FFA8B6B0FF
+ A1AFA9FFA0AEA8FFA3B1ABFFA7B5AFFFA7B5AFFFA5B6ADFF9DB2A9FFC0D8CCFF
+ D5EDE1FFD3EBDFFFD1E9DFFFCAE2D8FFC5DDD3FFC9E1D7FFD7EEE6FFD0E7DFFF
+ CEE4DFFFD5EBE6FF8E9E97FFA4B4ADFFB3C3BCFFAEBEB7FFA0B0A9FF99A9A2FF
+ 97A7A0FF95A59EFF8A9A93FF91A19AFF9BABA4FF9FAFA8FF9BABA4FF9BABA4FF
+ AABAB3FFBACBC7FFD5E8E5FFE3F6F3FFDAEDEAFFC9DCD9FFCEE1DEFFCFE2DFFF
+ BCCFCCFFABBEBBFFAFC2BFFFC2D5D2FFCEE1DEFFC7DAD7FFBDD0CDFFB9CCC9FF
+ B5C8C5FFAEC1BEFFBCCFCCFFB9CCC9FFB9CCC9FFBCCFCCFFBFD2CFFFBCCFCCFF
+ B3C6C3FFABBEBBFFA9BCB9FFA7BAB7FFAABDBAFFB0C3C0FFB2C5C2FFAFC2BFFF
+ ABBEBBFFA9BCB9FFB0C1BDFFAEBFBBFFB1C2BEFF9AABA7FFA8B7B3FFAEBDB9FF
+ 869591FF8F9E9AFF98A6A2FF909E9AFF919C99FF8D9895FF8B9693FF9AA5A2FF
+ A6AFACFF9BA4A1FF939F99FF96A29CFF9AA6A0FF9AA6A0FF94A09AFF929E98FF
+ 9EAAA4FFAEBAB4FFA2AEA8FFA7B3ADFFA1ADA7FF94A09AFF97A39DFFA7B3ADFF
+ AAB6B0FF9FABA5FFA9B4B1FFADB8B5FFAEBCB8FFACBAB6FFA8B6B2FFA8B6B2FF
+ ADBCB8FFB2C1BDFFA0B1ADFFA6B7B3FFB5C6C2FFCBDCD8FFDAEEE9FFE1F5F0FF
+ DFF3EEFFDCF0EBFFD3E8E5FFD7ECE9FFDAEFECFFDAEFECFFD8EDEAFFD7ECE9FF
+ D9EEEBFFDBF0EDFFDCF1EEFFDEF3F0FFDDF2EFFFDAEFECFFD6EBE8FFD5EAE7FF
+ D8EDEAFFDBF0EDFFDDF4F0FFDBF2EEFFC7DEDAFF8AA19DFF9CB3AFFF9EB5B1FF
+ A6BDB9FFB0C7C3FFA8BFBBFF9EB5B1FF9AB1ADFF9FB6B2FF9CB3AFFF94ABA7FF
+ 99B0ACFFA6BDB9FF9EB3B0FF9CB1AEFF99AEABFF99AEABFF9AAFACFF98ADAAFF
+ 96ABA8FF93A8A5FF8EA3A0FF8FA4A1FF8FA4A1FF8FA4A1FF8DA29FFF8A9F9CFF
+ 889D9AFF869B98FF8A9C9BFF819392FF768482FF707E7CFF6F7A78FF5F6A68FF
+ 626966FF787F7CFF7D837EFF808681FF7E8580FF7A817CFF77827AFF79847CFF
+ 76837BFF727F77FF77817BFF787F7AFF7D847FFF828984FF7E8580FF777E79FF
+ 7B827DFF858C87FF7F8681FF878E89FF888F8AFF848B86FF8D948FFFA0A7A2FF
+ A8AFAAFFA0AAA4FFA4B2ACFF9DADA6FF9BABA4FF9FAFA8FF9FAFA8FF99A9A2FF
+ 93A39CFF92A29BFFAEBEB7FFABBBB4FFABBBB4FFB5C5BEFFC5D5CEFFD0E0D9FF
+ D2E2DBFFCDDEDAFFB8C9C6FFCEDFDCFFDBECE9FFD6E7E4FFD5E6E3FFDCEDEAFF
+ D6E7E4FFC6D7D4FFC7D8D5FFC5D6D3FFD7E8E5FFDCEDEAFFC9DAD7FFC6D7D4FF
+ C3D4D1FFACBDBAFFBFD2CFFFBDD0CDFFC2D5D2FFCADDDAFFC5D8D5FFB6C9C6FF
+ B2C5C2FFB8CBC8FFB2C5C2FFADC0BDFFA5B8B5FF9DB0ADFF94A7A4FF8A9D9AFF
+ 809390FF7B8C88FF646F6CFF89938DFF838D87FF7C8680FF7E8882FF7F8983FF
+ 8B958FFF86908AFF87918BFF8B958FFF8B958FFF848E88FF7F8983FF7F8983FF
+ 7E8882FF7B857FFF818B85FF7B857FFF737D77FF717B75FF737D77FF76807AFF
+ 76807AFF757F79FF828C86FF808A84FF828C86FF86908AFF848E88FF7D8781FF
+ 79837DFF79847CFF727A73FF737C72FF7D867CFF8E978DFF98A399FF9AA59BFF
+ 99A49AFF99A49AFF9AA89DFF9BA99EFF98A89DFFA2B2A7FFB0C0B5FFA9B9AEFF
+ 9DAEA3FFA4B5AAFF9EACA6FFA7B5AFFFAFBDB7FFB0BEB8FFAAB8B2FFA7B5AFFF
+ A9B7B1FFADBBB5FFA8B6B0FFABB9B3FFABB9B3FFA8B6B0FFA6B4AEFFA6B4AEFF
+ A2B0AAFF99AAA1FF99AEA5FFA6BEB2FFC5DDD1FFD5EDE1FFCDE5DBFFCAE2D8FF
+ CDE5DBFFC9E1D7FFD3EAE2FFCAE1D9FFC8DED9FFCFE5E0FF8F9F98FFA1B1AAFF
+ ADBDB6FFA5B5AEFF95A59EFF8C9C95FF899992FF889891FF92A29BFF8F9F98FF
+ 90A099FF94A49DFF96A69FFF95A59EFF99A9A2FF9FAFA8FFC6D7D4FFD9ECE9FF
+ D5E8E5FFC2D5D2FFC0D3D0FFC1D4D1FFB9CCC9FFB4C7C4FFB7CAC7FFC0D3D0FF
+ C1D4D1FFBACDCAFFB7CAC7FFBACDCAFFB7CAC7FFAEC1BEFFB5C8C5FFB2C5C2FF
+ B0C3C0FFB2C5C2FFB4C7C4FFB1C4C1FFA9BCB9FFA2B5B2FFAABDBAFFA8BBB8FF
+ A8BBB8FFABBEBBFFACBFBCFFAABDBAFFA7BAB7FFA5B8B5FFA5B6B2FFABBCB8FF
+ AEBFBBFFA2B3AFFFADBCB8FFB1C0BCFF95A4A0FF889793FF98A6A2FF8E9C98FF
+ 8E9996FF8B9693FF899491FF97A29FFFA0A9A6FF939C99FF86928CFF939F99FF
+ 99A59FFF94A09AFF94A09AFF9BA7A1FF9EAAA4FF9BA7A1FF96A29CFF97A39DFF
+ 929E98FF8C9892FF929E98FF9EAAA4FF9EAAA4FF95A19BFF9FAAA7FFA2ADAAFF
+ A3B1ADFFA2B0ACFFA1AFABFFA4B2AEFFABBAB6FFB2C1BDFF9EAFABFFA5B6B2FF
+ B6C7C3FFCBDCD8FFD3E7E2FFD2E6E1FFD1E5E0FFD5E9E4FFD4E9E6FFD7ECE9FF
+ DAEFECFFD9EEEBFFD7ECE9FFD6EBE8FFD8EDEAFFDAEFECFFD5EAE7FFD6EBE8FF
+ D6EBE8FFD3E8E5FFCFE4E1FFCEE3E0FFD1E6E3FFD4E9E6FFDAF1EDFFD8EFEBFF
+ C0D7D3FF8BA29EFF9FB6B2FFA0B7B3FFA6BDB9FFABC2BEFFA5BCB8FF99B0ACFF
+ 94ABA7FF99B0ACFF99B0ACFF92A9A5FF95ACA8FF9FB6B2FF9DB2AFFF99AEABFF
+ 94A9A6FF92A7A4FF92A7A4FF93A8A5FF92A7A4FF91A6A3FF8BA09DFF8BA09DFF
+ 8A9F9CFF889D9AFF859A97FF819693FF7D928FFF7B908DFF728483FF6F8180FF
+ 6A7876FF687674FF677270FF576260FF5C6360FF747B78FF797F7AFF7C827DFF
+ 7B827DFF787F7AFF768179FF7A857DFF78857DFF748179FF77817BFF7A817CFF
+ 7E8580FF828984FF7E8580FF777E79FF79807BFF818883FF868D88FF8D948FFF
+ 8D948FFF878E89FF8E9590FFA0A7A2FFABB2ADFFA8B2ACFFA5B3ADFF99A9A2FF
+ 94A29CFF98A8A1FF9FADA7FF9DADA6FF98A6A0FF93A39CFFA0AEA8FF9FAFA8FF
+ A1AFA9FFA6B6AFFFAEBCB6FFB5C5BEFFBBC9C3FFBCCCC5FFB7C8C5FFC9DAD7FF
+ D0E1DEFFC6D7D4FFC4D5D2FFD0E1DEFFD4E5E2FFCDDEDBFFCCDDDAFFCBDCD9FF
+ D1E2DFFFD0E1DEFFC8D9D6FFC9DAD7FFC6D7D4FFB9CAC7FFB2C5C2FFB3C6C3FF
+ BACDCAFFC4D7D4FFC2D5D2FFB5C8C5FFAEC1BEFFB0C3C0FFA5B8B5FFA3B6B3FF
+ A0B3B0FF9CAFACFF96A9A6FF8DA09DFF839693FF7D8E8AFF5C6764FF88928CFF
+ 86908AFF7C8680FF7D8781FF808A84FF8C9690FF858F89FF848E88FF88928CFF
+ 87918BFF818B85FF7D8781FF7F8983FF818B85FF808A84FF7E8882FF7B857FFF
+ 79837DFF78827CFF79837DFF78827CFF77817BFF76807AFF7A847EFF838D87FF
+ 858F89FF808A84FF808A84FF858F89FF828C86FF79847CFF757D76FF767F75FF
+ 7F887EFF90998FFF99A49AFF9BA69CFF9BA69CFF9CA79DFFA1AFA4FFA2B0A5FF
+ 9BABA0FFA2B2A7FFAFBFB4FFAABAAFFFA2B3A8FFA9BAAFFFA1AFA9FFA7B5AFFF
+ AEBCB6FFB0BEB8FFAEBCB6FFACBAB4FFADBBB5FFB0BEB8FFACBAB4FFA5B3ADFF
+ A6B4AEFFADBBB5FFACBAB4FFA2B0AAFF9FADA7FFA2B3AAFF99AEA5FFA3BBAFFF
+ BFD7CBFFD0E8DCFFC9E1D7FFC8E0D6FFCBE3D9FFC6DED4FFCFE6DEFFC6DDD5FF
+ C3D9D4FFC7DDD8FF92A09AFF9FADA7FFA8B6B0FFA0AEA8FF919F99FF899791FF
+ 87958FFF87958FFF93A19BFF8A9892FF87958FFF909E98FF9BA9A3FF9EACA6FF
+ 9BA9A3FF98A8A1FFAEBFBCFFCDE0DDFFD6E9E6FFC7DAD7FFBFD2CFFFBCCFCCFF
+ BACDCAFFBED1CEFFCADDDAFFC8DBD8FFBDD0CDFFB3C6C3FFB6C9C6FFBFD2CFFF
+ BCCFCCFFB1C4C1FFAEC1BEFFABBEBBFFA9BCB9FFA9BCB9FFABBEBBFFAABDBAFF
+ A4B7B4FF9FB2AFFFA8BBB8FFA7BAB7FFA5B8B5FFA6B9B6FFA7BAB7FFA6B9B6FF
+ A4B7B4FFA1B4B1FF9AABA7FFA7B8B4FFA8B9B5FFAABBB7FFABBAB6FFACBBB7FF
+ A1B0ACFF778682FFA0AEAAFF93A19DFF919C99FF8F9A97FF8E9996FF98A3A0FF
+ 9CA5A2FF8D9693FF84908AFF929E98FF94A09AFF8A9690FF8D9993FF9EAAA4FF
+ 9FABA5FF909C96FF98A49EFF939F99FF8F9B95FF939F99FF9CA8A2FFA1ADA7FF
+ 9DA9A3FF97A39DFF9CA7A4FF9FAAA7FF9EACA8FF9DABA7FF9CAAA6FF9EACA8FF
+ A4B3AFFFAAB9B5FFA1B2AEFFA6B7B3FFBACBC7FFD3E4E0FFD6EAE5FFCDE1DCFF
+ CEE2DDFFD9EDE8FFD7ECE9FFD9EEEBFFDAEFECFFD9EEEBFFD7ECE9FFD6EBE8FF
+ D7ECE9FFD8EDEAFFD7ECE9FFD7ECE9FFD7ECE9FFD5EAE7FFD3E8E5FFD2E7E4FF
+ D3E8E5FFD5EAE7FFDAF1EDFFD7EEEAFFB5CCC8FF8DA4A0FFA3BAB6FFA5BCB8FF
+ A7BEBAFFA7BEBAFFA4BBB7FF97AEAAFF91A8A4FF95ACA8FF98AFABFF94ABA7FF
+ 94ABA7FF9AB1ADFFA1B6B3FF9BB0ADFF94A9A6FF90A5A2FF90A5A2FF91A6A3FF
+ 93A8A5FF93A8A5FF899E9BFF899E9BFF879C99FF849996FF7F9491FF798E8BFF
+ 748986FF718683FF657776FF677978FF677573FF667472FF636E6CFF525D5BFF
+ 59605DFF747B78FF757B76FF797F7AFF79807BFF777E79FF768179FF7A857DFF
+ 79867EFF76837BFF78827CFF79837DFF7D8781FF808A84FF7B857FFF747E78FF
+ 737D77FF78827CFF848E88FF8C9690FF8D9791FF87918BFF8B958FFF9CA6A0FF
+ AAB4AEFFAEB8B2FFABB7B1FF99A7A1FF919D97FF93A19BFF9FABA5FF9FADA7FF
+ 9DA9A3FF97A59FFF97A39DFF98A6A0FF9FABA5FFA1AFA9FFA8B4AEFFAEBCB6FF
+ BBC7C1FFC1CFC9FFB7C5C3FFC4D5D2FFC8D9D6FFBECFCCFFBCCDCAFFC7D8D5FF
+ CDDEDBFFC8D9D6FFCEDFDCFFD4E5E2FFCDDEDBFFC5D6D3FFCADBD8FFCBDCD9FF
+ C7D8D5FFC8D9D6FFA9BCB9FFA8BBB8FFADC0BDFFB7CAC7FFBBCECBFFB6C9C6FF
+ ADC0BDFFA8BBB8FF9EB1AEFF9EB1AEFF9DB0ADFF9CAFACFF97AAA7FF8EA19EFF
+ 829592FF7C8D89FF525D5AFF89938DFF8D9791FF818B85FF7F8983FF858F89FF
+ 919B95FF858F89FF88928CFF8B958FFF8A948EFF838D87FF7F8983FF818B85FF
+ 838D87FF828C86FF79837DFF7C8680FF7F8983FF808A84FF7D8781FF7A847EFF
+ 79837DFF78827CFF747E78FF848E88FF87918BFF7B857FFF7C8680FF8A948EFF
+ 8A948EFF7B867EFF767E77FF778076FF80897FFF8F988EFF97A298FF99A49AFF
+ 9AA59BFF9CA79DFFA9B7ACFFA8B6ABFF9FAFA4FFA2B2A7FFAEBEB3FFACBCB1FF
+ A5B6ABFFACBDB2FFA6B4AEFFA8B6B0FFABB9B3FFAEBCB6FFAEBCB6FFADBBB5FF
+ ABB9B3FFAAB8B2FFB0BEB8FFA3B1ABFFA5B3ADFFB3C1BBFFB3C1BBFFA3B1ABFF
+ A1AFA9FFADBEB5FF9BB0A7FFA1B9ADFFBAD2C6FFCAE2D6FFC6DED4FFC8E0D6FF
+ CBE3D9FFC4DCD2FFCEE5DDFFC7DED6FFC2D8D3FFC2D8D3FF8D9B95FF96A49EFF
+ 9CAAA4FF98A6A0FF8F9D97FF899791FF899791FF8C9A94FF8E9C96FF899791FF
+ 899791FF94A29CFF9DABA5FF9EACA6FF9DABA5FF9CACA5FF9BACA8FFC1D4D1FF
+ D7EAE7FFD2E5E2FFCCDFDCFFC3D6D3FFBDD0CDFFC0D3D0FFC4D7D4FFBFD2CFFF
+ B1C4C1FFA4B7B4FFA6B9B6FFAFC2BFFFADC0BDFFA3B6B3FFA6B9B6FFA4B7B4FF
+ A2B5B2FFA2B5B2FFA3B6B3FFA2B5B2FF9EB1AEFF9BAEABFFA1B4B1FFA3B6B3FF
+ A4B7B4FFA4B7B4FFA6B9B6FFA7BAB7FFA3B6B3FF9DB0ADFF98A9A5FFA7B8B4FF
+ A1B2AEFFABBCB8FFA3B2AEFFA1B0ACFFA5B4B0FF6A7975FF9FADA9FF909E9AFF
+ 8E9996FF8F9A97FF8F9A97FF96A19EFF98A19EFF8A9390FF929E98FF95A19BFF
+ 909C96FF86928CFF87938DFF94A09AFF9CA8A2FF9AA6A0FFA3AFA9FF99A59FFF
+ 95A19BFF9EAAA4FFA8B4AEFFA7B3ADFFA0ACA6FF9DA9A3FFA3AEABFFA6B1AEFF
+ A5B3AFFFA4B2AEFFA2B0ACFFA0AEAAFFA1B0ACFFA3B2AEFFA2B3AFFFA4B5B1FF
+ B8C9C5FFD5E6E2FFDDF1ECFFD3E7E2FFD4E8E3FFE1F5F0FFDCF1EEFFDCF1EEFF
+ DBF0EDFFDAEFECFFD9EEEBFFD8EDEAFFD8EDEAFFD9EEEBFFDAEFECFFDAEFECFF
+ DAEFECFFD9EEEBFFD8EDEAFFD7ECE9FFD8EDEAFFD8EDEAFFDCF3EFFFD8EFEBFF
+ A8BFBBFF8CA39FFFA2B9B5FFA7BEBAFFA8BFBBFFA4BBB7FFA6BDB9FF9AB1ADFF
+ 93AAA6FF97AEAAFF9BB2AEFF9AB1ADFF98AFABFF99B0ACFF9CB1AEFF97ACA9FF
+ 91A6A3FF8DA29FFF8DA29FFF8DA29FFF8DA29FFF8CA19EFF899E9BFF889D9AFF
+ 869B98FF829794FF7D928FFF788D8AFF728784FF6F8481FF697B7AFF6C7E7DFF
+ 6C7A78FF667472FF5F6A68FF4B5654FF555C59FF737A77FF767C77FF7A807BFF
+ 7A817CFF777E79FF768179FF7B867EFF7A877FFF77847CFF76807AFF79837DFF
+ 7C8680FF7C8680FF78827CFF727C76FF707A74FF707A74FF7A847EFF848E88FF
+ 89938DFF87918BFF8A948EFF98A29CFFA6B0AAFFADB7B1FFAEBAB4FFA0ACA6FF
+ 95A19BFF96A29CFF9CA8A2FF9EAAA4FF9DA9A3FF9DA9A3FF9BA7A1FF9CA8A2FF
+ 9EAAA4FF9FABA5FFA3AFA9FFAAB6B0FFB4C0BAFFB9C7C1FFB0BFBBFFBBCCC9FF
+ C1D2CFFFBFD0CDFFC0D1CEFFC6D7D4FFC1D2CFFFB4C5C2FFC5D6D3FFD8E9E6FF
+ D2E3E0FFC7D8D5FFCFE0DDFFCCDDDAFFC5D6D3FFD1E2DFFFB0C3C0FFA7BAB7FF
+ 9FB2AFFFA4B7B4FFB2C5C2FFBACDCAFFB3C6C3FFA7BAB7FFA5B8B5FFA4B7B4FF
+ A1B4B1FF9DB0ADFF96A9A6FF8B9E9BFF7F928FFF798A86FF4B5653FF89938DFF
+ 929C96FF86908AFF848E88FF8A948EFF959F99FF87918BFF8D9791FF929C96FF
+ 919B95FF8A948EFF858F89FF848E88FF838D87FF808A84FF78827CFF7C8680FF
+ 818B85FF808A84FF7C8680FF79837DFF7A847EFF7C8680FF77817BFF808A84FF
+ 818B85FF7C8680FF7E8882FF86908AFF86908AFF7F8A82FF777F78FF788177FF
+ 7F887EFF8C958BFF929D93FF939E94FF95A096FF99A49AFFA8B6ABFFAAB8ADFF
+ A0B0A5FFA1B1A6FFADBDB2FFABBBB0FFA3B4A9FFA8B9AEFFA9B7B1FFA8B6B0FF
+ A7B5AFFFA9B7B1FFABB9B3FFAAB8B2FFA5B3ADFFA1AFA9FFAEBCB6FFA9B7B1FF
+ ACBAB4FFB3C1BBFFB3C1BBFFAAB8B2FFABB9B3FFB2C3BAFFA0B5ACFFA3BBAFFF
+ B9D1C5FFC8E0D4FFC7DFD5FFC9E1D7FFCCE4DAFFC5DDD3FFCFE6DEFFCBE2DAFF
+ C6DCD7FFC3D9D4FF88978FFF8C9B93FF909F97FF909F97FF8B9A92FF86958DFF
+ 87968EFF8B9A92FF8D9C94FF8F9E96FF94A39BFF98A79FFF95A49CFF909F97FF
+ 93A29AFF9AAAA3FF93A4A0FFB3C6C3FFC6D9D6FFC7DAD7FFC8DBD8FFC2D5D2FF
+ BACDCAFFBCCFCCFFBACDCAFFBDD0CDFFB7CAC7FFABBEBBFFA9BCB9FFAFC2BFFF
+ AFC2BFFFA8BBB8FFA6B9B6FFA4B7B4FFA1B4B1FF9FB2AFFF9DB0ADFF9AADAAFF
+ 96A9A6FF92A5A2FF9AADAAFFA0B3B0FFA4B7B4FFA5B8B5FFA8BBB8FFABBEBBFF
+ A6B9B6FF9DB0ADFF9CADA9FFA7B8B4FF9FB0ACFFA7B8B4FF9EADA9FF9DACA8FF
+ A9B8B4FF758480FF8F9D99FF808E8AFF818C89FF889390FF8A9592FF919C99FF
+ 97A09DFF8D9693FF9FABA5FF97A39DFF929E98FF929E98FF8E9A94FF8A9690FF
+ 95A19BFFA5B1ABFFA4B0AAFF99A59FFF95A19BFF9CA8A2FFA3AFA9FFA1ADA7FF
+ 9BA7A1FF98A49EFFA3AEABFFA8B3B0FFABB9B5FFAFBDB9FFB0BEBAFFAEBCB8FF
+ ACBBB7FFACBBB7FFA6B7B3FFA4B5B1FFB3C4C0FFD0E1DDFFDDF1ECFFD9EDE8FF
+ D8ECE7FFDEF2EDFFDFF4F1FFDEF3F0FFDCF1EEFFDBF0EDFFDAEFECFFDBF0EDFF
+ DBF0EDFFDBF0EDFFD6EBE8FFD6EBE8FFD5EAE7FFD5EAE7FFD6EBE8FFD5EAE7FF
+ D4E9E6FFD4E9E6FFDAF1EDFFD7EEEAFF97AEAAFF89A09CFF9CB3AFFFA2B9B5FF
+ A4BBB7FF9EB5B1FFA5BCB8FF9BB2AEFF95ACA8FF97AEAAFF9BB2AEFF9CB3AFFF
+ 99B0ACFF98AFABFF91A6A3FF8EA3A0FF8A9F9CFF879C99FF869B98FF849996FF
+ 819693FF7E9390FF859A97FF849996FF839895FF809592FF7C918EFF778C89FF
+ 728784FF708582FF6E807FFF6F8180FF6C7A78FF63716FFF596462FF46514FFF
+ 535A57FF757C79FF787E79FF7C827DFF7B827DFF787F7AFF77827AFF7B867EFF
+ 79867EFF76837BFF738078FF76837BFF78857DFF76837BFF738078FF707D75FF
+ 6D7A72FF6B7870FF6E7B73FF79867EFF849189FF88958DFF8D9A92FF97A49CFF
+ A3B0A8FFAAB7AFFFB3BEB6FFAAB5ADFFA2ADA5FF9FAAA2FF9DA8A0FF9AA59DFF
+ 9DA8A0FFA2ADA5FFA8B3ABFFA3AEA6FF9BA69EFF97A29AFF97A29AFF98A39BFF
+ 9AA59DFF98A49EFFA5B3AFFFA9B7B5FFADBBB9FFB1BFBDFFBBC9C7FFC1CFCDFF
+ B7C5C3FFA7B5B3FFB5C3C1FFD4E2E0FFDAE8E6FFD3E1DFFFD6E4E2FFCCDAD8FF
+ C3D1CFFFCFE0DDFFC1D4D1FFB0C3C0FF9BAEABFF96A9A6FFA8BBB8FFBDD0CDFF
+ BBCECBFFADC0BDFFAEC1BEFFAABDBAFFA4B7B4FF9DB0ADFF96A9A6FF8C9F9CFF
+ 829592FF7E8F8BFF45504DFF838D87FF8F9993FF88928CFF86908AFF89938DFF
+ 929C96FF858F89FF88928CFF8E9892FF919B95FF8C9690FF87918BFF858F89FF
+ 828C86FF7D8781FF7A847EFF7C8680FF7D8781FF7B857FFF78827CFF78827CFF
+ 7C8680FF808A84FF818B85FF7A847EFF7A847EFF818B85FF828C86FF7C8680FF
+ 7D8781FF859088FF7C847DFF7D867CFF838C82FF8D968CFF909B91FF909B91FF
+ 939E94FF98A399FFA1AFA4FFA7B5AAFF9FAFA4FF9FAFA4FFAABAAFFFA9B9AEFF
+ 9FB0A5FFA0B1A6FFA8B6B0FFA5B3ADFFA3B1ABFFA6B4AEFFAAB8B2FFABB9B3FF
+ A6B4AEFFA2B0AAFFA6B4AEFFB0BEB8FFB2C0BAFFABB9B3FFA9B7B1FFAFBDB7FF
+ B1BFB9FFABBCB3FFA6BBB2FFA8C0B4FFBDD5C9FFCBE3D7FFC9E1D7FFCBE3D9FF
+ CEE6DCFFC6DED4FFC8DFD7FFC8DFD7FFC5DBD6FFC1D7D2FF91A098FF909F97FF
+ 93A29AFF95A49CFF909F97FF8A9991FF899890FF8C9B93FF8B9A92FF8F9E96FF
+ 96A59DFF99A8A0FF94A39BFF8F9E96FF96A59DFFA1B1AAFF94A5A1FFA5B8B5FF
+ AABDBAFFA9BCB9FFB0C3C0FFB1C4C1FFAFC2BFFFB4C7C4FFADC0BDFFB7CAC7FF
+ BACDCAFFB2C5C2FFAEC1BEFFB3C6C3FFB4C7C4FFAFC2BFFFAEC1BEFFADC0BDFF
+ ABBEBBFFA8BBB8FFA3B6B3FF9DB0ADFF98ABA8FF94A7A4FF97AAA7FFA0B3B0FF
+ A4B7B4FFA2B5B2FFA6B9B6FFACBFBCFFA8BBB8FF9EB1AEFFA2B3AFFFA8B9B5FF
+ A3B4B0FFA3B4B0FFA0AFABFFA2B1ADFFA9B8B4FF94A39FFF899793FF7C8A86FF
+ 818C89FF8A9592FF8C9794FF949F9CFF9FA8A5FF9DA6A3FFA1ADA7FF95A19BFF
+ 95A19BFF9FABA5FF99A59FFF8B9791FF919D97FFA5B1ABFFA0ACA6FF9CA8A2FF
+ 97A39DFF96A29CFF99A59FFF9BA7A1FF99A59FFF97A39DFF9DA8A5FFA2ADAAFF
+ A8B6B2FFB1BFBBFFB6C4C0FFB9C7C3FFB8C7C3FFB8C7C3FFB4C5C1FFB4C5C1FF
+ BECFCBFFD1E2DEFFDDF1ECFFE0F4EFFFDEF2EDFFDCF0EBFFE0F5F2FFDDF2EFFF
+ DAEFECFFD9EEEBFFDBF0EDFFDCF1EEFFDDF2EFFFDCF1EEFFD6EBE8FFD5EAE7FF
+ D4E9E6FFD6EBE8FFD7ECE9FFD7ECE9FFD5EAE7FFD3E8E5FFD5ECE8FFD5ECE8FF
+ 8BA29EFF89A09CFF97AEAAFF9CB3AFFF9EB5B1FF95ACA8FF9EB5B1FF99B0ACFF
+ 95ACA8FF94ABA7FF97AEAAFF98AFABFF97AEAAFF94ABA7FF91A6A3FF8EA3A0FF
+ 8BA09DFF899E9BFF889D9AFF849996FF809592FF7C918EFF7F9491FF7F9491FF
+ 7E9390FF7C918EFF798E8BFF748986FF708582FF6E8380FF738584FF728483FF
+ 6D7B79FF647270FF5C6765FF4C5755FF5B625FFF7C8380FF767C77FF7A807BFF
+ 7A817CFF777E79FF768179FF7A857DFF78857DFF75827AFF738078FF74837BFF
+ 76837BFF718078FF717E76FF718078FF727F77FF6C7B73FF6E7B73FF75847CFF
+ 839088FF8A9991FF94A199FF99A8A0FFA4B1A9FFA9B6AEFFB3BEB6FFAEB9B1FF
+ A9B4ACFFA5B0A8FF9EA9A1FF98A39BFF99A49CFF9FAAA2FFACB7AFFFA6B1A9FF
+ 9EA9A1FF99A49CFF99A49CFF99A49CFF97A29AFF939F99FF9AA8A4FF97A5A3FF
+ 94A2A0FF98A6A4FFA5B3B1FFB1BFBDFFB0BEBCFFA7B5B3FFA3B1AFFFC1CFCDFF
+ D5E3E1FFD8E6E4FFD4E2E0FFCBD9D7FFC5D3D1FFC7D8D5FFCDDEDBFFBED1CEFF
+ A5B8B5FF94A7A4FFA0B3B0FFB8CBC8FFBCCFCCFFB1C4C1FFAFC2BFFFABBEBBFF
+ A5B8B5FF9FB2AFFF99ACA9FF92A5A2FF8A9D9AFF879894FF434E4BFF79837DFF
+ 858F89FF87918BFF88928CFF848E88FF8B958FFF828C86FF7B857FFF838D87FF
+ 87918BFF858F89FF838D87FF838D87FF818B85FF7E8882FF7C8680FF7B857FFF
+ 78827CFF76807AFF757F79FF78827CFF7E8882FF828C86FF88928CFF79837DFF
+ 77817BFF848E88FF848E88FF78827CFF7A847EFF89948CFF868E87FF868F85FF
+ 8B948AFF929B91FF929D93FF919C92FF949F95FF9AA59BFF9DABA0FFA5B3A8FF
+ 9EAEA3FF9CACA1FFA8B8ADFFA8B8ADFF9EAFA4FF9CADA2FFA5B3ADFFA3B1ABFF
+ A3B1ABFFA7B5AFFFACBAB4FFAEBCB6FFADBBB5FFAAB8B2FFA0AEA8FFB1BFB9FF
+ B3C1BBFFA4B2ACFF9FADA7FFACBAB4FFAEBCB6FFA2B3AAFFA8BDB4FFACC4B8FF
+ C2DACEFFCEE6DAFFC9E1D7FFC9E1D7FFCCE4DAFFC6DED4FFBCD3CBFFC1D8D0FF
+ C1D7D2FFBCD2CDFF9CA9A1FF99A69EFF9BA8A0FF9FACA4FF9CA9A1FF94A199FF
+ 909D95FF94A199FF909D95FF8C9991FF8C9991FF929F97FF96A39BFF97A49CFF
+ 9BA8A0FF9EACA6FF92A39FFF9CAFACFF9AADAAFF97AAA7FFA0B3B0FFA3B6B3FF
+ A3B6B3FFABBEBBFF94A7A4FFA0B3B0FFA5B8B5FF9FB2AFFF9CAFACFF9FB2AFFF
+ 9DB0ADFF95A8A5FFA8BBB8FFAABDBAFFACBFBCFFACBFBCFFA9BCB9FFA5B8B5FF
+ A1B4B1FF9EB1AEFF9BAEABFFA2B5B2FFA2B5B2FF9CAFACFF9FB2AFFFA9BCB9FF
+ A8BBB8FF9FB2AFFFA9BAB6FFA8B9B5FFA9BAB6FF9FB0ACFFA3B2AEFFA4B3AFFF
+ 9DACA8FFACBBB7FF97A5A1FF8A9894FF8E9996FF95A09DFF909B98FF95A09DFF
+ A3ACA9FFA5AEABFF9FABA5FF96A29CFF939F99FF98A49EFF98A49EFF94A09AFF
+ 98A49EFFA2AEA8FF9FABA5FFA2AEA8FF9CA8A2FF929E98FF919D97FF9CA8A2FF
+ A1ADA7FF9DA9A3FFA1ACA9FFA3AEABFFA4B2AEFFA8B6B2FFADBBB7FFB0BEBAFF
+ B0BFBBFFB0BFBBFFBACBC7FFC4D5D1FFCDDEDAFFD3E4E0FFDAEEE9FFE3F7F2FF
+ E4F8F3FFDFF3EEFFDEF3F0FFDAEFECFFD7ECE9FFD6EBE8FFD9EEEBFFDCF1EEFF
+ DCF1EEFFDCF1EEFFDAEFECFFD8EDEAFFD8EDEAFFDAEFECFFDCF1EEFFDDF2EFFF
+ DAEFECFFD6EBE8FFD2E9E5FFD9F0ECFF8BA29EFF95ACA8FF9DB4B0FF9DB4B0FF
+ 9CB3AFFF91A8A4FF99B0ACFF99B0ACFF97AEAAFF94ABA7FF93AAA6FF95ACA8FF
+ 95ACA8FF94ABA7FF9BB0ADFF97ACA9FF92A7A4FF8EA3A0FF8CA19EFF8A9F9CFF
+ 869B98FF849996FF7F9491FF7F9491FF7D928FFF7B908DFF778C89FF728784FF
+ 6E8380FF6B807DFF748685FF728483FF6D7B79FF677573FF616C6AFF515C5AFF
+ 5C6360FF7B827FFF717772FF757B76FF757C77FF747B76FF747F77FF79847CFF
+ 78857DFF75827AFF73827AFF75867DFF75847CFF6F8077FF707F77FF75867DFF
+ 77867EFF72837AFF74837BFF76877EFF7F8E86FF899A91FF93A29AFF99AAA1FF
+ A1B0A8FFA5B4ACFFB0BDB5FFACB7AFFFA8B3ABFFA7B2AAFFA3AEA6FF9BA69EFF
+ 97A29AFF98A39BFFA7B2AAFFA7B2AAFFA6B1A9FFA3AEA6FFA1ACA4FFA1ACA4FF
+ A3AEA6FFA4B0AAFF99A7A3FF97A5A3FF93A19FFF92A09EFF98A6A4FFA4B2B0FF
+ ABB9B7FFACBAB8FF99A7A5FFA9B7B5FFC4D2D0FFD0DEDCFFCCDAD8FFCCDAD8FF
+ CBD9D7FFBFD0CDFFC8D9D6FFC8DBD8FFB8CBC8FF9EB1AEFF9AADAAFFACBFBCFF
+ B5C8C5FFAFC2BFFFADC0BDFFABBEBBFFA7BAB7FFA3B6B3FF9EB1AEFF97AAA7FF
+ 8EA19EFF899A96FF495451FF747E78FF7F8983FF89938DFF8D9791FF838D87FF
+ 87918BFF838D87FF79837DFF7E8882FF808A84FF7C8680FF7B857FFF7F8983FF
+ 818B85FF808A84FF7E8882FF7A847EFF76807AFF747E78FF77817BFF7B857FFF
+ 7F8983FF818B85FF87918BFF7E8882FF7C8680FF828C86FF828C86FF7E8882FF
+ 818B85FF8A958DFF8C948DFF8C958BFF8F988EFF949D93FF919C92FF8F9A90FF
+ 929D93FF99A49AFF9EACA1FFA6B4A9FF9EAEA3FF99A99EFFA5B5AAFFA9B9AEFF
+ A2B3A8FFA0B1A6FFA5B3ADFFA5B3ADFFA5B3ADFFA7B5AFFFA9B7B1FFAAB8B2FF
+ AAB8B2FFA9B7B1FFA5B3ADFFB0BEB8FFB1BFB9FFA7B5AFFFA1AFA9FFA5B3ADFF
+ A7B5AFFFA3B4ABFFA5BAB1FFADC5B9FFC4DCD0FFCFE7DBFFC6DED4FFC3DBD1FF
+ C7DFD5FFC2DAD0FFBAD1C9FFC2D9D1FFC4DAD5FFBFD5D0FF9AA79FFF96A39BFF
+ 98A59DFF9EABA3FF9EABA3FF95A29AFF919E96FF95A29AFF9BA8A0FF8B9890FF
+ 808D85FF85928AFF8F9C94FF909D95FF8A978FFF83918BFF8FA09CFF99ACA9FF
+ 9CADAAFF99ACA9FFA2B3B0FFA0B3B0FF9FB0ADFFA4B7B4FF9EAFACFFA4B7B4FF
+ A8B9B6FF9FB2AFFF9FB0ADFF9FB2AFFF9BACA9FF8DA09DFF95A6A3FF98ABA8FF
+ A1B2AFFFA4B7B4FFA8B9B6FFA5B8B5FFA5B6B3FFA2B5B2FFA2B3B0FFA5B8B5FF
+ A2B3B0FF96A9A6FF9AABA8FFA5B8B5FFA9BAB7FFA1B2AFFFAEBFBBFFA9BAB6FF
+ AFC0BCFF9CADA9FFA3B2AEFFA2B1ADFF8E9D99FFB4C3BFFFA4B2AEFF95A39FFF
+ 97A29FFF99A4A1FF8D9895FF8C9794FF9AA3A0FF9FA8A5FFA2AEA8FF9AA6A0FF
+ 8E9A94FF87938DFF8D9993FF9BA7A1FFA3AFA9FFA2AEA8FF9BA7A1FFA4B0AAFF
+ 9FABA5FF8E9A94FF8C9892FF9CA8A2FFA6B2ACFFA2AEA8FFADB9B3FFAAB6B0FF
+ A3B1ADFFA0AEAAFF9FADA9FF9FADA9FF9EADA9FF9EADA9FFB3C4C0FFC5D6D2FF
+ D0E1DDFFCEDFDBFFD0E4DFFFDEF2EDFFE4F8F3FFDFF2EFFFDBF0EDFFD7ECE9FF
+ D3E8E5FFD4E9E6FFD7ECE9FFDBF0EDFFDBF0EDFFDBF0EDFFD9EEEBFFD8EDEAFF
+ D7ECE9FFDAEFECFFDDF2EFFFDDF2EFFFDAEFECFFD6EBE8FFD2E9E5FFDDF6F2FF
+ 91A8A4FFA0B9B5FFA7BEBAFFA1BAB6FF9FB6B2FF8FA8A4FF98AFABFF98B1ADFF
+ 9AB1ADFF94ADA9FF93AAA6FF92ABA7FF96ADA9FF95ACA8FF9EB5B1FF99AEABFF
+ 91A6A3FF8BA09DFF899E9BFF889D9AFF889D9AFF879C99FF829794FF829794FF
+ 809592FF7D928FFF788D8AFF738885FF708380FF6D807DFF6F8180FF6F7F7EFF
+ 687674FF64716FFF5B6866FF4B5654FF505956FF6E7572FF6A716CFF6F7671FF
+ 717873FF707772FF727D75FF78837BFF7A857DFF76837BFF75847CFF77887FFF
+ 76857DFF6F8077FF728179FF798A81FF7D8C84FF77887FFF7A8981FF788980FF
+ 7C8B83FF84958CFF909F97FF96A79EFF9DACA4FFA2B1A9FFAFBCB4FFA7B4ACFF
+ A4AEA8FFA4B1A9FFA6B0AAFF9DAAA2FF96A09AFF909D95FFA2ACA6FFA5B2AAFF
+ AAB4AEFFA2AFA7FF9BA59FFF95A29AFF9AA49EFF9EAAA4FF9FADA9FFA2B0ACFF
+ A3B0AEFF9EADA9FF9CA9A7FF9FAEAAFFA8B6B4FFAEBDB9FF96A4A2FF98A7A3FF
+ B3C1BFFFC6D5D1FFC3D1CFFFCDDCD8FFD1DFDDFFBBCCC9FFBECFCCFFCCDFDCFF
+ C9DAD7FFA9BCB9FF9AABA8FFA2B5B2FFAFC0BDFFACBFBCFFAFC0BDFFACBFBCFF
+ ACBDBAFFA8BBB8FFA4B5B2FF98ABA8FF8E9F9CFF879692FF515C59FF757F79FF
+ 7D8781FF8E9892FF949E98FF858F89FF88928CFF87918BFF808A84FF838D87FF
+ 808A84FF79837DFF77817BFF7C877FFF818B85FF828D85FF7E8882FF79847CFF
+ 757F79FF768179FF7A847EFF7F8A82FF808A84FF7F8A82FF838D87FF859088FF
+ 838D87FF7E8981FF7F8983FF869189FF8A948EFF89948CFF8E978DFF8D968CFF
+ 8F988EFF929B91FF8E998FFF8B968CFF8E998FFF95A096FFA2B0A5FFAAB8ADFF
+ 9EAEA3FF97A79CFFA3B3A8FFABBBB0FFA6B7ACFFA6B7ACFFA9B7B1FFA9B7B1FF
+ A8B6B0FFA6B4AEFFA3B1ABFFA1AFA9FFA0AEA8FFA0AEA8FFB0BEB8FFAFBDB7FF
+ B0BEB8FFAFBDB7FFA8B6B0FFA1AFA9FFA3B1ABFFAABAB3FFA2B7AEFFABC3B9FF
+ C5DDD3FFCFE7DDFFC2DAD0FFBED6CCFFC1D8D0FFBDD4CCFFBFD6CEFFC9E0D8FF
+ CDE3DEFFC7DDD8FF8C9690FF97A19BFF9CA6A0FF97A19BFF939D97FF96A09AFF
+ 96A09AFF929C96FF939D97FF8E9892FF89938DFF86908AFF838D87FF858F89FF
+ 919B95FF9CA8A2FF9AA9A5FF98A9A5FF9AA9A5FF97A8A4FF99A8A4FF98A9A5FF
+ 9DACA8FF9EAFABFFA9B8B4FF91A29EFF9BAAA6FFA8B9B5FFA4B3AFFFA6B7B3FF
+ A9B8B4FF93A4A0FF909F9BFF9AABA7FFA1B0ACFF9CADA9FFA3B2AEFFB0C1BDFF
+ B6C5C1FFAEBFBBFF9DACA8FFA1B2AEFFA6B5B1FFA2B3AFFFA4B3AFFFA6B7B3FF
+ A9B8B4FFA4B5B1FFAABBB7FFA9BAB6FF9FB0ACFF93A4A0FF99A8A4FFA3B2AEFF
+ 9EADA9FF8E9D99FF909E9AFF93A19DFF909B98FF919C99FF98A3A0FF939E9BFF
+ 919A97FF9CA5A2FFA3ADA7FFA5AFA9FF9AA49EFF88928CFF8A948EFF9DA7A1FF
+ A6B0AAFF9FA9A3FF9DA7A1FF99A39DFF959F99FF959F99FF9AA49EFFA1ABA5FF
+ A6B0AAFFA9B3ADFF9CA8A2FFA6B3ABFFA4B2ACFF9AA8A2FF94A29CFF98A6A0FF
+ 98A8A1FF93A39CFFA2B3AFFFCEDFDBFFDAEBE8FFD4E5E2FFE0F3F0FFE2F5F2FF
+ D7EAE7FFDAEDEAFFDEF3F0FFDBF0EDFFDBF0EDFFDFF4F1FFDFF4F1FFDAEFECFF
+ D9EEEBFFDCF1EEFFDBF0EDFFD4E9E6FFD2E7E4FFD8EDEAFFDDF2EFFFDAEFECFF
+ D5EAE7FFD2E9E5FFC9E1DFFFDEF9F6FF9BB3B1FFADC8C5FFB1C9C7FFA7C2BFFF
+ ABC3C1FFA0BBB8FFA4BCBAFF9AB5B2FF94ACAAFF8CA7A4FF879F9DFF829D9AFF
+ 8BA3A1FF95ADABFF99B2AEFF97AEAAFF8AA19DFF7A918DFF738A86FF788F8BFF
+ 819693FF849996FF839693FF839693FF819491FF7C8F8CFF758885FF708380FF
+ 71827FFF71827FFF667675FF738180FF667472FF606D6BFF5C6967FF535E5CFF
+ 5C6764FF6B7471FF6C7670FF6C7670FF707A74FF76807AFF79817AFF777F78FF
+ 7A827BFF7E8981FF76827CFF73817BFF75817BFF73817BFF75817BFF74827CFF
+ 77837DFF76847EFF79857FFF76847EFF7C8882FF86948EFF95A19BFF9AA8A2FF
+ 9EAAA4FF9DABA5FFA0ACA6FFA3B1ABFFA9B4B1FFA6B4AEFFA8B3B0FFA3B1ABFF
+ 9AA5A2FF8D9B95FF909B98FF99A7A1FFA3AEABFF9EACA6FF99A4A1FF94A29CFF
+ 95A09DFF96A29CFF95A09DFF99A59FFF9EA9A6FF9DABA5FF9EA9A6FFA1AFA9FF
+ AAB8B4FFB2C0BAFFB6C5C1FF9EAEA7FFACBBB7FFC7D7D0FFBFD0CCFFBACCC5FF
+ C5D6D2FFC8D9D5FFC4D5D1FFC2D3CFFFCAD9D5FFC3D4D0FFB1C0BCFFA7B8B4FF
+ ACBBB7FFA5B6B2FFAEBDB9FFABBCB8FFB2C1BDFFACBDB9FFA0AFABFF9BACA8FF
+ 9AA9A5FF8C9B97FF6C7774FF6D7875FF8C9794FF838E8BFF9AA5A2FF8B9693FF
+ 85918BFF838F89FF79867EFF7D8A82FF818E86FF808D85FF7D8A82FF7C8A7FFF
+ 7F8C84FF839186FF818C84FF778278FF737E76FF7A857BFF828D85FF838E84FF
+ 808B83FF7E897FFF79847CFF7E897FFF838E86FF859086FF869189FF89948AFF
+ 919C94FF97A298FF969F95FF919A90FF929B91FF959E94FF8E998FFF889389FF
+ 8E998FFF9CA79DFF9DABA0FFA2B0A5FFA4B4A9FFA5B5AAFFA2B2A7FFA1B1A6FF
+ A1B2A7FFA4B5AAFF9EACA6FFA6B4AEFFABB9B3FFA9B7B1FFA8B6B0FFA6B4AEFF
+ 9FADA7FF96A49EFFA1AFA9FFA9B7B1FF9EACA6FFA4B2ACFF95A39DFFA6B4AEFF
+ A1AFA9FFA5B5AEFFA2B9B1FFA3BBB3FFB8D0C8FFC8E0D8FFC4DCD4FFC1D9D1FF
+ C4DBD6FFC1D8D3FFBFD6D1FFC4DBD6FFCAE1DCFFCBE2DDFF858F89FF8F9993FF
+ 949E98FF8E9892FF88928CFF88928CFF88928CFF858F89FF8B958FFF8B958FFF
+ 8E9892FF919B95FF8E9892FF89938DFF8C9690FF909C96FF96A4A0FF99A8A4FF
+ 9CABA7FF9AA9A5FF95A4A0FF94A39FFF99A8A4FF9EADA9FFA7B6B2FF93A29EFF
+ 98A7A3FFA3B2AEFF9EADA9FFA2B1ADFFA7B6B2FF9AA9A5FF99A8A4FFA1B0ACFF
+ A2B1ADFF9CABA7FFA0AFABFFABBAB6FFADBCB8FFA5B4B0FFA7B6B2FFABBAB6FF
+ ABBAB6FFA6B5B1FFA4B3AFFFA4B3AFFFA2B1ADFF9EADA9FF9CADA9FFA6B7B3FF
+ A9BAB6FFA2B3AFFFA0AFABFFA1B0ACFF98A7A3FF899894FF96A4A0FF93A19DFF
+ 8A9592FF889390FF929D9AFF949F9CFF9AA3A0FFAAB3B0FFA8B2ACFFA6B0AAFF
+ 9BA59FFF8C9690FF8C9690FF98A29CFF9EA8A2FF9BA59FFFA7B1ABFF9FA9A3FF
+ 96A09AFF96A09AFF9CA6A0FFA2ACA6FFA2ACA6FF9FA9A3FF9AA79FFF9FACA4FF
+ 9AA9A1FF909F97FF8F9D97FF9AA8A2FF9FAFA8FF9DADA6FFA6B7B3FFCEDFDBFF
+ DAEBE8FFD5E6E3FFDEF1EEFFE1F4F1FFD8EAE9FFDAECEBFFDAEFECFFD7ECE9FF
+ D8EDEAFFDDF2EFFFDDF2EFFFD9EEEBFFD9EEEBFFDCF1EEFFDAEFECFFD4E9E6FF
+ D2E7E4FFD9EEEBFFDEF3F0FFDBF0EDFFD6EBE8FFD3EAE6FFCFE7E5FFDAF5F2FF
+ A3BEBBFFA0BBB8FFA9C4C1FFA6C1BEFFA7C2BFFFA1BCB9FF9CB7B4FF96B1AEFF
+ 90ABA8FF8BA6A3FF86A19EFF839E9BFF89A4A1FF92ADAAFF92ABA7FF90A9A5FF
+ 889F9BFF7C938FFF778E8AFF7A918DFF7C918EFF798E8BFF809390FF809390FF
+ 7F928FFF7B8E8BFF788986FF768784FF768784FF778885FF6B7978FF717F7EFF
+ 64716FFF5B6866FF596664FF4F5C5AFF57625FFF65706DFF66706AFF67716BFF
+ 6B756FFF727C76FF767E77FF757D76FF79817AFF7F8780FF78827CFF75817BFF
+ 75817BFF75817BFF75817BFF76827CFF77837DFF78847EFF7A8680FF78847EFF
+ 7A8680FF85918BFF939F99FF9EAAA4FFA4B0AAFFA6B2ACFF9EACA8FFA2B0ACFF
+ A4B2AEFFA5B3AFFFA8B6B2FFA8B6B2FFA0AEAAFF95A39FFF93A19DFF98A6A2FF
+ 9DABA7FF9EACA8FF99A7A3FF94A29EFF95A39FFF99A7A3FF99A39DFF9DA7A1FF
+ 9EAAA4FF9EAAA4FF9CA8A2FF9FABA5FFA4B2ACFFABB9B3FFBACAC3FFA5B5AEFF
+ A9B9B2FFC1D1CAFFC8DAD3FFC5D7D0FFC7D9D2FFC9DBD4FFCBDAD6FFC6D5D1FF
+ CAD9D5FFC7D6D2FFB7C6C2FFB0BFBBFFB0BFBBFFA7B6B2FFA8B7B3FFA7B6B2FF
+ ACBBB7FFA9B8B4FF9CABA7FF9BAAA6FF99A8A4FF8B9A96FF879290FF576260FF
+ 899491FF798481FF7D8885FF8B9693FF88948EFF8F9B95FF85928AFF839088FF
+ 818E86FF818E86FF839186FF87958AFF8B998EFF8D9B90FF879288FF7D887EFF
+ 788379FF7D887EFF838E84FF828D83FF7E897FFF7C877DFF7C877DFF7F8A80FF
+ 828D83FF859086FF89948AFF8F9A90FF95A096FF99A49AFF98A197FF939C92FF
+ 939C92FF969F95FF8E998FFF869187FF8B968CFF98A399FF9AA89DFFA1AFA4FF
+ A4B4A9FFA3B3A8FF9EAEA3FF9CACA1FFA0B1A6FFA6B7ACFFAAB8B2FFACBAB4FF
+ ACBAB4FFA7B5AFFF9DABA5FF97A59FFF97A59FFF9AA8A2FFA5B3ADFFACBAB4FF
+ A1AFA9FFA8B6B0FF9BA9A3FFABB9B3FFA2B0AAFFA3B3ACFF9AB0ABFFA1B8B3FF
+ BCD3CEFFCDE4DFFFC5DCD7FFC1D8D3FFC8DFDAFFC9E0DBFFC4DBD6FFC7DED9FF
+ CCE3DEFFCFE6E1FF858F89FF909A94FF959F99FF8F9993FF858F89FF818B85FF
+ 828C86FF838D87FF89938DFF89938DFF8C9690FF919B95FF909A94FF8B958FFF
+ 8A948EFF8B9791FF93A19DFF9AA9A5FFA0AFABFF9DACA8FF94A39FFF909F9BFF
+ 95A4A0FF9CABA7FFA5B4B0FF96A5A1FF98A7A3FF9EADA9FF99A8A4FF9DACA8FF
+ A5B4B0FFA2B1ADFFA5B4B0FFA7B6B2FFA2B1ADFF9BAAA6FF9DACA8FFA5B4B0FF
+ A3B2AEFF9AA9A5FFAAB9B5FFADBCB8FFABBAB6FFA5B4B0FFA2B1ADFFA1B0ACFF
+ 9CABA7FF96A5A1FF96A7A3FFA7B8B4FFB2C3BFFFADBEBAFFA8B7B3FFA5B4B0FF
+ A0AFABFF99A8A4FF9AA8A4FF95A39FFF8A9592FF889390FF949F9CFF97A29FFF
+ 9BA4A1FFAAB3B0FFA7B1ABFFA0AAA4FF97A19BFF919B95FF929C96FF96A09AFF
+ 9AA49EFF9CA6A0FFAFB9B3FFA4AEA8FF99A39DFF97A19BFF9DA7A1FFA0AAA4FF
+ 9CA6A0FF96A09AFFA0ADA5FFA0ADA5FF95A49CFF8B9A92FF8F9D97FFA0AEA8FF
+ AABAB3FFA9B9B2FFABBCB8FFCDDEDAFFDBECE9FFD7E8E5FFDCEFECFFE0F3F0FF
+ DBEDECFFDCEEEDFFD6EBE8FFD4E9E6FFD5EAE7FFDAEFECFFDAEFECFFD7ECE9FF
+ D7ECE9FFDAEFECFFD8EDEAFFD2E7E4FFD2E7E4FFD9EEEBFFDDF2EFFFDBF0EDFF
+ D7ECE9FFD5ECE8FFD5EDEBFFD4EFECFFB1CCC9FF8FAAA7FFA3BEBBFFA5C0BDFF
+ A3BEBBFF9FBAB7FFA5C0BDFF9EB9B6FF95B0ADFF8EA9A6FF85A09DFF7D9895FF
+ 7E9996FF839E9BFF87A09CFF87A09CFF849B97FF7F9692FF7E9591FF7F9692FF
+ 7A8F8CFF728784FF7E918EFF7F928FFF7F928FFF7C8F8CFF798A87FF778885FF
+ 778885FF788986FF707E7DFF6E7A7AFF636E6CFF586361FF576260FF515C5AFF
+ 525B58FF636C69FF636A65FF636A65FF686F6AFF6F7671FF737A73FF737A73FF
+ 787F78FF7E867FFF78827CFF78827CFF77817BFF77817BFF78827CFF79837DFF
+ 7A847EFF7B857FFF7C8680FF7A847EFF7C8680FF848E88FF949E98FFA3ADA7FF
+ ACB6B0FFAEBAB4FFA4B2AEFFA5B3AFFFA4B2AEFFA4B2AEFFA8B6B2FFACBAB6FF
+ A5B3AFFF9BA9A5FF98A6A2FF96A4A0FF99A7A3FF9FADA9FF9CAAA6FF94A29EFF
+ 96A4A0FF9FADA9FF9DA7A1FFA0AAA4FF9FABA5FF9DA9A3FF9AA6A0FF9BA7A1FF
+ 9EACA6FFA2B0AAFFBBCBC4FFADBDB6FFA5B5AEFFB8C8C1FFD0E2DBFFCEE0D9FF
+ C4D6CFFFC8DAD3FFCCDBD7FFC2D1CDFFC4D3CFFFC4D3CFFFBAC9C5FFB6C5C1FF
+ B3C2BEFFA6B5B1FFA3B2AEFFA1B0ACFFA6B5B1FFA3B2AEFF98A7A3FF98A7A3FF
+ 96A5A1FF889793FF8B9694FF424D4BFF899491FF85908DFF788380FF8A9592FF
+ 74807AFF77837DFF86938BFF818E86FF7D8A82FF7E8B83FF839186FF849287FF
+ 818F84FF7D8B80FF8E998FFF859086FF7F8A80FF838E84FF879288FF848F85FF
+ 7F8A80FF7D887EFF818C82FF828D83FF859086FF889389FF8D988EFF939E94FF
+ 99A49AFF9DA89EFF9CA59BFF969F95FF959E94FF97A096FF8E998FFF859086FF
+ 879288FF919C92FF95A398FF9CAA9FFFA1B1A6FF9FAFA4FF99A99EFF97A79CFF
+ 9BACA1FFA1B2A7FFB7C5BFFFB5C3BDFFB7C5BFFFB6C4BEFFA8B6B0FF99A7A1FF
+ 9CAAA4FFA9B7B1FFA2B0AAFFA6B4AEFF98A6A0FF9FADA7FF95A39DFFA5B3ADFF
+ 9AA8A2FF98A8A1FF97ABA6FFA2B8B3FFC1D7D2FFD2E8E3FFC7DDD8FFC1D7D2FF
+ C9DFDAFFCDE3DEFFC8DED9FFC8DED9FFC8DED9FFCAE0DBFF88928CFF919B95FF
+ 98A29CFF939D97FF88928CFF818B85FF838D87FF86908AFF8D9791FF86908AFF
+ 828C86FF848E88FF87918BFF89938DFF8E9892FF939F99FF95A39FFF9AA9A5FF
+ 9FAEAAFF9DACA8FF98A7A3FF94A39FFF95A4A0FF98A7A3FFA1B0ACFF9AA9A5FF
+ 9BAAA6FF9FAEAAFF9CABA7FF9DACA8FFA3B2AEFFA7B6B2FFAAB9B5FFA8B7B3FF
+ A2B1ADFF9BAAA6FF9DACA8FFA3B2AEFFA1B0ACFF99A8A4FFA3B2AEFFA6B5B1FF
+ A6B5B1FFA2B1ADFFA1B0ACFFA2B1ADFF9DACA8FF96A5A1FF98A9A5FFA3B4B0FF
+ AABBB7FFA6B7B3FFA4B3AFFFA7B6B2FFACBBB7FFAEBDB9FF9AA8A4FF99A7A3FF
+ 929D9AFF949F9CFF9FAAA7FF99A4A1FF919A97FF969F9CFF9DA7A1FF959F99FF
+ 919B95FF949E98FF98A29CFF99A39DFF9CA6A0FFA2ACA6FFA8B2ACFFA2ACA6FF
+ 9BA59FFF99A39DFF9AA49EFF9BA59FFF99A39DFF96A09AFFA5B2AAFFA2AFA7FF
+ 95A49CFF8A9991FF909E98FFA2B0AAFFABBBB4FFA9B9B2FFB0C1BDFFCADBD7FF
+ DBECE9FFDBECE9FFDBEEEBFFE0F3F0FFE0F2F1FFDFF1F0FFD6EBE8FFD3E8E5FF
+ D4E9E6FFD8EDEAFFD8EDEAFFD3E8E5FFD2E7E4FFD5EAE7FFD4E9E6FFD0E5E2FF
+ D1E6E3FFD7ECE9FFDBF0EDFFD9EEEBFFD6EBE8FFD5ECE8FFD8F0EEFFCDE8E5FF
+ B8D3D0FF849F9CFFA1BCB9FFA4BFBCFF9DB8B5FF9AB5B2FFA8C3C0FFA0BBB8FF
+ 98B3B0FF91ACA9FF87A29FFF7D9895FF799491FF7C9794FF829B97FF829B97FF
+ 819894FF809793FF849B97FF869D99FF7F9491FF748986FF7C8F8CFF7F928FFF
+ 809390FF7D908DFF7A8B88FF748582FF71827FFF717F7DFF768282FF6A7676FF
+ 626D6BFF56615FFF56615FFF525D5BFF4C5552FF616A67FF646B66FF646B66FF
+ 676E69FF6E7570FF717871FF707770FF757C75FF7C837CFF7B827DFF78827CFF
+ 78827CFF78827CFF78827CFF79837DFF7A847EFF7B857FFF7C8680FF7D8781FF
+ 7F8983FF86908AFF959F99FFA6B0AAFFAFB9B3FFB0BAB4FFB0BBB8FFACBAB6FF
+ A7B5B1FFA4B2AEFFA7B5B1FFABB9B5FFA7B5B1FF9EACA8FF99A7A3FF93A19DFF
+ 96A4A0FFA0AEAAFFA0AEAAFF96A4A0FF95A39FFF9EACA8FF9FA9A3FFA1ABA5FF
+ A0ACA6FF9EAAA4FF9BA7A1FF9AA6A0FF9BA9A3FF9EACA6FFB7C7C0FFB4C4BDFF
+ A6B6AFFFB1C1BAFFCEE0D9FFCDDFD8FFBFD1CAFFC7D9D2FFC5D4D0FFB9C8C4FF
+ B9C8C4FFBCCBC7FFB7C6C2FFB7C6C2FFB3C2BEFFA4B3AFFFA5B4B0FFA0AFABFF
+ A4B3AFFFA1B0ACFF97A6A2FF97A6A2FF95A4A0FF869591FF919C9AFF56615FFF
+ 7A8582FF86918EFF86918EFF8A9592FF76827CFF85918BFF88958DFF88958DFF
+ 8B9890FF8F9C94FF919F94FF8E9C91FF87958AFF818F84FF909B91FF889389FF
+ 848F85FF889389FF8B968CFF879288FF828D83FF808B81FF838E84FF889389FF
+ 8E998FFF8F9A90FF8E998FFF909B91FF98A399FF9EA99FFF9EA79DFF98A197FF
+ 969F95FF98A197FF8F9A90FF848F85FF838E84FF8C978DFF909E93FF96A499FF
+ 9AAA9FFF9DADA2FF9BABA0FF98A89DFF96A79CFF96A79CFFAEBCB6FFABB9B3FF
+ B2C0BAFFBBC9C3FFB2C0BAFF9EACA6FF9BA9A3FFA8B6B0FFA2B0AAFFA1AFA9FF
+ 8F9D97FF94A29CFF8B9993FF9EACA6FF93A19BFF91A19AFF9AAEA9FFA3B9B4FF
+ C3D7D2FFD3E9E4FFCBDFDAFFC3D9D4FFCADED9FFC9DFDAFFCBDFDAFFC4DAD5FF
+ C1D5D0FFBED4CFFF848E88FF8B958FFF919B95FF8F9993FF87918BFF808A84FF
+ 818B85FF86908AFF8A948EFF7F8983FF79837DFF7B857FFF838D87FF89938DFF
+ 929C96FF97A39DFF97A5A1FF96A5A1FF97A6A2FF98A7A3FF98A7A3FF97A6A2FF
+ 94A39FFF91A09CFF9AA9A5FF9CABA7FF9DACA8FFA0AFABFFA1B0ACFF9CABA7FF
+ 9CABA7FFA4B3AFFFA7B6B2FFA5B4B0FFA2B1ADFF9FAEAAFFA2B1ADFFA6B5B1FF
+ A5B4B0FFA1B0ACFFA2B1ADFFA5B4B0FFA5B4B0FFA4B3AFFFA6B5B1FFA7B6B2FF
+ A2B1ADFF9AA9A5FF97A8A4FF9AABA7FF9BACA8FF9AABA7FF9EADA9FFA4B3AFFF
+ A9B8B4FFA9B8B4FF9BA9A5FF9AA8A4FF939E9BFF97A29FFFA2ADAAFF99A4A1FF
+ 8B9491FF8A9390FF949E98FF8E9892FF8E9892FF96A09AFF9CA6A0FF9CA6A0FF
+ 9EA8A2FFA2ACA6FF99A39DFF9BA59FFF9DA7A1FF9AA49EFF96A09AFF959F99FF
+ 98A29CFF9CA6A0FFA0ADA5FF9FACA4FF95A49CFF8C9B93FF93A19BFFA3B1ABFF
+ AABAB3FFA6B6AFFFB0C1BDFFC3D4D0FFD8E9E6FFDEEFECFFDAEDEAFFE0F3F0FF
+ E5F7F6FFE2F4F3FFD9EEEBFFD6EBE8FFD5EAE7FFD8EDEAFFD6EBE8FFD0E5E2FF
+ CEE3E0FFD0E5E2FFD1E6E3FFCEE3E0FFD0E5E2FFD6EBE8FFD8EDEAFFD5EAE7FF
+ D4E9E6FFD4EBE7FFD8F0EEFFCAE2E0FFB4CCCAFF839B99FFA4BCBAFFA6BEBCFF
+ 9CB4B2FF96AEACFF9EB6B4FF97AFADFF92AAA8FF90A8A6FF8DA5A3FF879F9DFF
+ 869E9CFF89A19FFF8AA39FFF88A19DFF859C98FF829995FF859C98FF879E9AFF
+ 819693FF778C89FF758885FF798C89FF7D908DFF7D908DFF7A8B88FF738481FF
+ 6E7F7CFF6D7B79FF778383FF677171FF65706EFF56615FFF5A6261FF58605FFF
+ 4B524FFF666D6AFF6C736EFF6A716CFF6D736EFF717772FF737771FF727670FF
+ 767A74FF7B827BFF7B827DFF7B827DFF7A817CFF7A817CFF7B827DFF7C837EFF
+ 7D847FFF7D847FFF7E8580FF828984FF858C87FF8B928DFF99A09BFFAAB1ACFF
+ AFB6B1FFAAB4AEFFB0BBB8FFAEBCB8FFA9B7B3FFA4B2AEFFA6B4B0FFAAB8B4FF
+ AAB8B4FFA5B3AFFF98A6A2FF92A09CFF95A39FFFA0AEAAFFA2B0ACFF9AA8A4FF
+ 96A4A0FF99A7A3FFA0AAA4FFA1ABA5FF9FABA5FF9EAAA4FF9DA9A3FF9CA8A2FF
+ 9CAAA4FF9DABA5FFB1C1BAFFB7C7C0FFADBDB6FFB0C0B9FFC6D8D1FFC7D9D2FF
+ BED0C9FFC7D9D2FFC0CFCBFFB4C3BFFFB5C4C0FFB7C6C2FFB3C2BEFFB6C5C1FF
+ B6C5C1FFAAB9B5FFACBBB7FFA6B5B1FFA7B6B2FFA3B2AEFF99A8A4FF99A8A4FF
+ 96A5A1FF869591FF8F9A98FF6B7674FF323D3AFF3A4542FF545F5CFF56615EFF
+ 6D7973FFA0ACA6FF85928AFF8A978FFF8E9B93FF8F9C94FF8D9B90FF8A988DFF
+ 8A988DFF8A988DFF889389FF828D83FF808B81FF869187FF89948AFF869187FF
+ 828D83FF828D83FF838E84FF8D988EFF97A298FF95A096FF8D988EFF8A958BFF
+ 929D93FF9BA69CFF9DA69CFF969F95FF959E94FF98A197FF919C92FF859086FF
+ 828D83FF89948AFF909E93FF94A297FF99A99EFFA0B0A5FFA3B3A8FFA0B0A5FF
+ 96A79CFF8FA095FF9EACA6FF96A49EFF9AA8A2FFA6B4AEFFA2B0AAFF92A09AFF
+ 8D9B95FF96A49EFFA9B7B1FFA6B4AEFF909E98FF93A19BFF8A9892FF9EACA6FF
+ 97A59FFF97A7A0FF9EAFABFFA3B7B2FFC0D1CDFFD3E7E2FFD2E3DFFFCCE0DBFF
+ D1E2DEFFCBDFDAFFCFE0DCFFC8DCD7FFC3D4D0FFBED2CDFF87918BFF89938DFF
+ 8D9791FF909A94FF8B958FFF848E88FF848E88FF88928CFF818B85FF79837DFF
+ 76807AFF7E8882FF89938DFF8F9993FF919B95FF929E98FF96A4A0FF92A19DFF
+ 8F9E9AFF91A09CFF95A4A0FF96A5A1FF92A19DFF8D9C98FF96A5A1FF9DACA8FF
+ 9CABA7FF9FAEAAFFA6B5B1FF9DACA8FF95A4A0FF9FAEAAFFA1B0ACFFA3B2AEFF
+ A4B3AFFFA4B3AFFFA6B5B1FFA7B6B2FFA8B7B3FFA8B7B3FFA8B7B3FFAAB9B5FF
+ A9B8B4FFA9B8B4FFABBAB6FFADBCB8FFA6B5B1FF9CABA7FF9BACA8FF9BACA8FF
+ 9CADA9FFA0B1ADFFA6B5B1FFA6B5B1FFA1B0ACFF9CABA7FF9EACA8FF97A5A1FF
+ 8B9693FF8C9794FF9BA6A3FF97A29FFF8E9794FF8F9895FF909A94FF919B95FF
+ 939D97FF97A19BFF9BA59FFF9DA7A1FF9CA6A0FF99A39DFF8E9892FF96A09AFF
+ 9DA7A1FF9BA59FFF949E98FF929C96FF99A39DFFA1ABA5FF9FACA4FFA3B0A8FF
+ 9EADA5FF98A79FFF9DABA5FFABB9B3FFB0C0B9FFACBCB5FFA9BAB6FFB7C8C4FF
+ D3E4E1FFDFF0EDFFD7EAE7FFDFF2EFFFE8FAF9FFE2F4F3FFDCF1EEFFD8EDEAFF
+ D7ECE9FFD9EEEBFFD6EBE8FFCFE4E1FFCDE2DFFFCFE4E1FFD1E6E3FFCFE4E1FF
+ D1E6E3FFD6EBE8FFD7ECE9FFD4E9E6FFD2E7E4FFD4EBE7FFDAF0EEFFC9E1DFFF
+ 9FB7B5FF879F9DFFA5BDBBFFA4BCBAFF9BB3B1FF95ADABFF9CB4B2FF94ACAAFF
+ 8EA6A4FF8DA5A3FF8CA4A2FF88A09EFF879F9DFF89A19FFF92ABA7FF8FA8A4FF
+ 8AA19DFF839A96FF819894FF829995FF7E9390FF768B88FF708380FF738683FF
+ 778A87FF788B88FF778885FF748582FF71827FFF73817FFF748080FF616B6BFF
+ 687371FF596462FF5B6362FF5B6362FF49504DFF6B726FFF747B76FF717873FF
+ 727873FF747A75FF757973FF727670FF767A74FF7D817BFF7C827DFF7B827DFF
+ 7B827DFF7B827DFF7B827DFF7C837EFF7D847FFF7E8580FF7F8681FF858C87FF
+ 888F8AFF8B928DFF989F9AFFAAB1ACFFAFB6B1FFA7B1ABFFA8B3B0FFAAB8B4FF
+ A9B7B3FFA5B3AFFFA4B2AEFFA9B7B3FFAEBCB8FFAFBDB9FF9AA8A4FF98A6A2FF
+ 98A6A2FF9CAAA6FF9FADA9FF9FADA9FF9BA9A5FF96A4A0FFA0AAA4FFA1ABA5FF
+ 9FABA5FF9EAAA4FF9DA9A3FF9DA9A3FF9BA9A3FF9BA9A3FFA9B9B2FFB2C2BBFF
+ B0C0B9FFB1C1BAFFBBCDC6FFC3D5CEFFC3D5CEFFC7D9D2FFC1D0CCFFB8C7C3FF
+ BAC9C5FFB9C8C4FFB0BFBBFFB2C1BDFFB9C8C4FFB5C4C0FFB3C2BEFFACBBB7FF
+ ABBAB6FFA7B6B2FF9EADA9FF9EADA9FF9BAAA6FF8A9995FF8A9593FF76817FFF
+ 0C1714FF091411FF222D2AFF1F2A27FF404C46FF7D8983FF929F97FF929F97FF
+ 8F9C94FF87948CFF7E8C81FF7C8A7FFF808E83FF869489FF7D887EFF79847AFF
+ 7A857BFF818C82FF859086FF838E84FF818C82FF818C82FF818C82FF8D988EFF
+ 98A399FF97A298FF8D988EFF889389FF8B968CFF929D93FF99A298FF939C92FF
+ 929B91FF98A197FF939E94FF889389FF848F85FF89948AFF92A095FF96A499FF
+ 9DADA2FFA5B5AAFFA8B8ADFFA3B3A8FF98A99EFF90A196FFA4B2ACFF9AA8A2FF
+ 95A39DFF97A59FFF95A39DFF8D9B95FF8C9A94FF92A09AFFA8B6B0FFA6B4AEFF
+ 919F99FF93A19BFF889690FF9CAAA4FF97A59FFF9AA8A2FF9CABA7FF9FB0ACFF
+ BBCAC6FFCFE0DCFFD1E0DCFFCEDFDBFFD4E3DFFFCDDEDAFFD2E1DDFFCDDEDAFF
+ CBDAD6FFC7D8D4FF909A94FF8C9690FF8E9892FF939D97FF939D97FF8B958FFF
+ 88928CFF8B958FFF818B85FF79837DFF77817BFF818B85FF8D9791FF929C96FF
+ 929C96FF8F9B95FF96A4A0FF93A29EFF92A19DFF92A19DFF94A39FFF95A4A0FF
+ 95A4A0FF94A39FFF9CABA7FFA5B4B0FF9EADA9FFA0AFABFFACBBB7FFA2B1ADFF
+ 95A4A0FFA0AFABFF9EADA9FFA2B1ADFFA8B7B3FFAAB9B5FFA7B6B2FFA4B3AFFF
+ A5B4B0FFA9B8B4FFA6B5B1FFA8B7B3FFA8B7B3FFA9B8B4FFADBCB8FFAFBEBAFF
+ A8B7B3FF9DACA8FFA1B2AEFFA0B1ADFFA3B4B0FFA8B9B5FFACBBB7FFA8B7B3FF
+ A1B0ACFF9CABA7FF9EACA8FF94A29EFF848F8CFF85908DFF95A09DFF95A09DFF
+ 8E9794FF919A97FF8B958FFF949E98FF97A19BFF96A09AFF99A39DFFA0AAA4FF
+ 9BA59FFF919B95FF8F9993FF96A09AFF9CA6A0FF9BA59FFF96A09AFF949E98FF
+ 98A29CFF9DA7A1FFA3B0A8FFAAB7AFFFA7B6AEFF9EADA5FF9FADA7FFAAB8B2FF
+ AFBFB8FFADBDB6FF9EAFABFFA9BAB6FFCBDCD9FFDDEEEBFFD4E7E4FFDCEFECFF
+ E8FAF9FFE0F2F1FFDDF2EFFFD9EEEBFFD8EDEAFFDAEFECFFD8EDEAFFD1E6E3FF
+ CFE4E1FFD1E6E3FFD4E9E6FFD2E7E4FFD4E9E6FFD9EEEBFFD9EEEBFFD4E9E6FF
+ D3E8E5FFD5ECE8FFDDF3F1FFCCE4E2FF849C9AFF8BA3A1FFA3BBB9FFA1B9B7FF
+ 9EB6B4FF98B0AEFF9DB5B3FF93ABA9FF8BA3A1FF89A19FFF879F9DFF839B99FF
+ 829A98FF849C9AFF8CA5A1FF8DA6A2FF8AA19DFF829995FF7E9591FF7E9591FF
+ 7C918EFF778C89FF758885FF758885FF748784FF718481FF71827FFF728380FF
+ 758683FF7A8886FF6D7979FF5A6464FF6B7674FF5B6664FF5C6463FF5C6463FF
+ 464D4AFF707774FF787F7AFF747B76FF757B76FF767C77FF777B75FF747872FF
+ 787C76FF7E827CFF7D837EFF7C827DFF7C827DFF7C827DFF7C827DFF7D837EFF
+ 7E847FFF7F8580FF818782FF878D88FF888E89FF888E89FF959B96FFAAB0ABFF
+ B1B7B2FFABB2ADFFA2ADAAFFA8B6B2FFACBAB6FFA6B4B0FFA1AFABFFA5B3AFFF
+ ADBBB7FFB2C0BCFFA1AFABFFA3B1ADFF9DABA7FF95A39FFF9AA8A4FFA5B3AFFF
+ A3B1ADFF98A6A2FFA1ABA5FFA0AAA4FF9EAAA4FF9DA9A3FF9CA8A2FF9BA7A1FF
+ 97A59FFF96A49EFF9EAEA7FFA1B1AAFFA8B8B1FFACBCB5FFADBFB8FFBED0C9FF
+ C9DBD4FFC1D3CCFFC4D3CFFFC0CFCBFFC2D1CDFFBCCBC7FFAAB9B5FFABBAB6FF
+ B8C7C3FFBBCAC6FFB7C6C2FFAEBDB9FFAEBDB9FFAAB9B5FFA2B1ADFFA4B3AFFF
+ A1B0ACFF909F9BFF8F9A98FF7D8886FF394441FF384340FF343F3CFF2C3734FF
+ 28342EFF4B5751FF8A978FFF8A978FFF88958DFF86938BFF849287FF839186FF
+ 859388FF869489FF7A857BFF788379FF7A857BFF828D83FF869187FF848F85FF
+ 828D83FF848F85FF808B81FF889389FF919C92FF949F95FF919C92FF8C978DFF
+ 889389FF879288FF949D93FF8E978DFF8F988EFF97A096FF95A096FF8B968CFF
+ 889389FF8C978DFF8D9B90FF96A499FF9FAFA4FFA2B2A7FF9FAFA4FF99A99EFF
+ 96A79CFF96A79CFFA6B4AEFFA5B3ADFFA2B0AAFF9BA9A3FF94A29CFF919F99FF
+ 93A19BFF96A49EFF9CAAA4FFA0AEA8FF909E98FF93A19BFF85938DFF97A59FFF
+ 919F99FF95A39DFF95A39FFF9AA9A5FFB5C3BFFFC6D5D1FFC1CFCBFFBDCCC8FF
+ C4D2CEFFC3D2CEFFCBD9D5FFCBDAD6FFCCDAD6FFCAD9D5FF939D97FF8C9690FF
+ 8C9690FF929C96FF949E98FF8C9690FF86908AFF87918BFF89938DFF7D8781FF
+ 77817BFF7E8882FF8B958FFF929C96FF949E98FF939F99FF98A6A2FF98A7A3FF
+ 99A8A4FF97A6A2FF95A4A0FF96A5A1FF9AA9A5FF9FAEAAFFA5B4B0FFADBCB8FF
+ A3B2AEFFA2B1ADFFB2C1BDFFA8B7B3FF99A8A4FFA6B5B1FF9DACA8FFA3B2AEFF
+ ABBAB6FFADBCB8FFA7B6B2FFA0AFABFFA1B0ACFFA7B6B2FF9FAEAAFFA1B0ACFF
+ A2B1ADFFA5B4B0FFABBAB6FFAFBEBAFFA8B7B3FF9EADA9FF9FB0ACFF9FB0ACFF
+ A1B2AEFFA4B5B1FFA6B5B1FFA3B2AEFFA2B1ADFFA3B2AEFF9CAAA6FF92A09CFF
+ 838E8BFF86918EFF97A29FFF95A09DFF8A9390FF89928FFF86908AFF949E98FF
+ 99A39DFF949E98FF98A29CFFA3ADA7FF9EA8A2FF8E9892FF96A09AFF98A29CFF
+ 9BA59FFF9BA59FFF99A39DFF97A19BFF97A19BFF98A29CFFA2AFA7FFA9B6AEFF
+ A5B4ACFF99A8A0FF94A29CFF9CAAA4FFA1B1AAFFA0B0A9FF97A8A4FFA0B1ADFF
+ C5D6D3FFDBECE9FFD1E4E1FFD9ECE9FFE7F9F8FFDDEFEEFFDCF1EEFFD8EDEAFF
+ D8EDEAFFDBF0EDFFD9EEEBFFD4E9E6FFD2E7E4FFD4E9E6FFD7ECE9FFD5EAE7FF
+ D7ECE9FFDBF0EDFFDAEFECFFD5EAE7FFD4E9E6FFD7ECE9FFE0F6F4FFCFE7E5FF
+ 718987FF8DA5A3FFA1B9B7FF9FB7B5FFA1B9B7FF9BB3B1FF92AAA8FF89A19FFF
+ 829A98FF839B99FF869E9CFF869E9CFF88A09EFF8BA3A1FF819A96FF859E9AFF
+ 869D99FF809793FF7C938FFF7D9490FF7E9390FF7B908DFF809390FF7C8F8CFF
+ 758885FF6D807DFF6B7C79FF6E7F7CFF758683FF7D8B89FF677373FF555F5FFF
+ 6C7775FF5C6765FF5A6563FF5C6463FF434C49FF727976FF787F7AFF757C77FF
+ 747B76FF777D78FF767D76FF737A73FF797D77FF7E857EFF7D837EFF7D837EFF
+ 7C827DFF7C827DFF7C827DFF7D837EFF7F8580FF7F8580FF828883FF878D88FF
+ 868C87FF838984FF919792FFAAB0ABFFB4BAB5FFAFB6B1FFA2ADAAFFABB9B5FF
+ B0BEBAFFA8B6B2FF9EACA8FF9FADA9FFA8B6B2FFAEBCB8FFA8B6B2FFABB9B5FF
+ A0AEAAFF909E9AFF95A39FFFA9B7B3FFAAB8B4FF9BA9A5FFA2ACA6FFA0AAA4FF
+ 9DA9A3FF9CA8A2FF9AA6A0FF98A49EFF93A19BFF919F99FF94A49DFF90A099FF
+ 9DADA6FFA4B4ADFFA2B4ADFFBBCDC6FFCBDDD6FFB9CBC4FFC6D5D1FFC4D3CFFF
+ C7D6D2FFBCCBC7FFA4B3AFFFA3B2AEFFB4C3BFFFBCCBC7FFB7C6C2FFAFBEBAFF
+ AEBDB9FFABBAB6FFA5B4B0FFA8B7B3FFA5B4B0FF94A39FFF7F8A88FF636E6CFF
+ 586360FF5E6966FF414C49FF424D4AFF1F2B25FF2C3832FF4A574FFF505D55FF
+ 5C6961FF6C7971FF7B897EFF818F84FF7E8C81FF79877CFF7E897FFF7C877DFF
+ 7F8A80FF879288FF8A958BFF889389FF879288FF89948AFF808B81FF828D83FF
+ 889389FF909B91FF95A096FF929D93FF889389FF7F8A80FF90998FFF8B948AFF
+ 8D968CFF97A096FF96A197FF8E998FFF8A958BFF8E998FFF869489FF94A297FF
+ 9EAEA3FF9CACA1FF92A297FF8C9C91FF91A297FF99AA9FFF93A19BFF9FADA7FF
+ A6B4AEFF9DABA5FF92A09AFF8E9C96FF8F9D97FF8E9C96FF95A39DFF9DABA5FF
+ 92A09AFF97A59FFF889690FF96A49EFF8F9D97FF93A19BFF8F9D99FF98A6A2FF
+ B1BFBBFFBDCBC7FFAFBDB9FFA7B5B1FFAFBDB9FFB3C1BDFFC1CFCBFFC4D2CEFF
+ C6D4D0FFC4D2CEFFABB5AFFF9BA59FFF8F9993FF8E9892FF8E9892FF8A948EFF
+ 89938DFF8D9791FF858F89FF86908AFF8A948EFF919B95FF949E98FF939D97FF
+ 939D97FF929E98FF9EACA8FF9EADA9FF9FAEAAFF94A39FFF8B9A96FF99A8A4FF
+ A2B1ADFF94A39FFFAFBEBAFFAEBDB9FFAAB9B5FFA5B4B0FFA4B3AFFFA5B4B0FF
+ A4B3AFFFA1B0ACFFA4B3AFFFA8B7B3FFACBBB7FFACBBB7FFA8B7B3FFA3B2AEFF
+ 9FAEAAFF9EADA9FFA0AFABFF9CABA7FF99A8A4FF9DACA8FFA5B4B0FFA9B8B4FF
+ A7B6B2FFA3B2AEFF93A4A0FF9CADA9FFA3B4B0FFA4B5B1FFA6B5B1FFA6B5B1FF
+ A1B0ACFF9AA9A5FFA1AFABFF889692FF909B98FF848F8CFF889390FF95A09DFF
+ 87908DFF949D9AFF8D9791FF8B958FFF919B95FF9BA59FFF9BA59FFF949E98FF
+ 96A09AFFA1ABA5FF99A39DFF96A09AFF959F99FF97A19BFF9AA49EFF9BA59FFF
+ 96A09AFF929C96FF929F97FF94A199FF98A79FFF9CABA3FF99A7A1FF94A29CFF
+ 95A59EFF9CACA5FFB1C2BEFFA8B9B5FFC3D4D1FFD0E1DEFFD7EAE7FFE7FAF7FF
+ DEF0EFFFDAECEBFFDBF0EDFFD7ECE9FFD3E8E5FFD4E9E6FFD7ECE9FFD7ECE9FF
+ D1E6E3FFCCE1DEFFD9EEEBFFD1E6E3FFD0E5E2FFD7ECE9FFDBF0EDFFD6EBE8FF
+ D4E9E6FFD6EBE8FFD1E7E5FFDEF4F2FF849A98FF95ABA9FFABC1BFFFA3B9B7FF
+ A2B8B6FF97ADABFF9AB0AEFF8EA4A2FF859B99FF869C9AFF8BA19FFF8EA4A2FF
+ 90A6A4FF94AAA8FF92ABA7FF7D9692FF809793FF829995FF748B87FF788F8BFF
+ 889D9AFF839895FF7C8F8CFF7D908DFF778A87FF6E817EFF738481FF7B8C89FF
+ 738481FF61726FFF5E6C6BFF626E6EFF5F6C6AFF5F6C6AFF5D6A68FF4F5A58FF
+ 4E5956FF666F6CFF76807AFF76807AFF76807AFF787F7AFF788079FF79817AFF
+ 7C837CFF7C847DFF7B827DFF79807BFF787F7AFF7B827DFF7E8580FF7F8681FF
+ 7B827DFF767D78FF7B827DFF838A85FF89908BFF878E89FF979E99FFA9B0ABFF
+ B5BCB7FFAFB9B3FFACB7B4FFA5B3AFFFA9B7B3FFB2C0BCFFADBBB7FF9FADA9FF
+ 9DABA7FFA6B4B0FFA0AEAAFFA3B1ADFFA1AFABFF99A7A3FF96A4A0FF9BA9A5FF
+ A1AFABFFA4B2AEFF99A39DFFA5AFA9FFA8B4AEFF9FABA5FF94A09AFF939F99FF
+ 95A39DFF99A7A1FF96A69FFF9AAAA3FF9CACA5FF9BABA4FF9FB1AAFFACBEB7FF
+ B8CAC3FFBDCFC8FFBCCBC7FFC2D1CDFFC7D6D2FFC4D3CFFFB6C5C1FFA9B8B4FF
+ AAB9B5FFB3C2BEFFBAC9C5FFB5C4C0FFAEBDB9FFA8B7B3FFA4B3AFFFA0AFABFF
+ 9BAAA6FF98A7A3FF808B89FF626D6BFF66716EFF87928FFF75807DFF4F5A57FF
+ 5C6862FF5A6660FF5F6C64FF546159FF47544CFF435048FF47554AFF4C5A4FFF
+ 4E5C51FF4C5A4FFF606B61FF747F75FF828D83FF838E84FF838E84FF89948AFF
+ 879288FF808B81FF7A857BFF89948AFF8F9A90FF869187FF848F85FF8E998FFF
+ 909B91FF89948AFF8E978DFF8E978DFF8F988EFF949D93FF97A298FF96A197FF
+ 8F9A90FF89948AFF95A398FF8C9A8FFF8C9C91FF95A59AFF8F9F94FF819186FF
+ 88998EFF9DAEA3FF8A9892FF9DABA5FFA4B2ACFF9AA8A2FF96A49EFF9AA8A2FF
+ 93A19BFF82908AFF8C9A94FFA2B0AAFFA2B0AAFF919F99FF8A9892FF899791FF
+ 919F99FFA1AFA9FF8C9A96FF95A39FFF96A4A0FFA3B1ADFF8E9C98FF85938FFF
+ 9CAAA6FF808E8AFF9EACA8FFAAB8B4FFAEBCB8FFA8B6B2FFA4AEA8FF97A19BFF
+ 8E9892FF8F9993FF919B95FF909A94FF909A94FF939D97FF909A94FF919B95FF
+ 949E98FF99A39DFF9BA59FFF9BA59FFF9BA59FFF9AA6A0FF97A5A1FF9BAAA6FF
+ A6B5B1FFA2B1ADFF94A39FFF9AA9A5FFA6B5B1FFA3B2AEFFABBAB6FFAAB9B5FF
+ A8B7B3FFA6B5B1FFA6B5B1FFA7B6B2FFA8B7B3FFA7B6B2FF98A7A3FF9CABA7FF
+ A1B0ACFFA5B4B0FFA5B4B0FFA4B3AFFFA2B1ADFFA2B1ADFF9DACA8FF9BAAA6FF
+ 9BAAA6FF9EADA9FFA4B3AFFFA7B6B2FFA5B4B0FFA2B1ADFF9FB0ACFFA3B4B0FF
+ A5B6B2FFA4B5B1FFA8B7B3FFACBBB7FFAAB9B5FFA4B3AFFFA3B1ADFF8B9995FF
+ 909B98FF86918EFF899491FF949F9CFF87908DFF929B98FF959F99FF97A19BFF
+ A0AAA4FFA8B2ACFFA7B1ABFF9FA9A3FF99A39DFF98A29CFF9FA9A3FF98A29CFF
+ 929C96FF919B95FF96A09AFF9CA6A0FF9EA8A2FF9EA8A2FF99A69EFF96A39BFF
+ 96A59DFF9DACA4FFA0AEA8FF9FADA7FF9EAEA7FFA1B1AAFFB0C1BDFFAFC0BCFF
+ D1E2DFFFDAEBE8FFD8EBE8FFE2F5F2FFDCEEEDFFDCEEEDFFDCF1EEFFD8EDEAFF
+ D5EAE7FFD6EBE8FFD9EEEBFFD9EEEBFFD4E9E6FFCFE4E1FFD8EDEAFFD2E7E4FF
+ D0E5E2FFD6EBE8FFD9EEEBFFD4E9E6FFD2E7E4FFD4E9E6FFE0F6F4FFE0F6F4FF
+ 798F8DFF869C9AFFA1B7B5FFA1B7B5FFA1B7B5FF94AAA8FFA4BAB8FF97ADABFF
+ 8BA19FFF879D9BFF869C9AFF879D9BFF8CA2A0FF92A8A6FF8AA39FFF7A938FFF
+ 758C88FF728985FF6A817DFF6C837FFF778C89FF7B908DFF738683FF758885FF
+ 718481FF6B7E7BFF738481FF7D8E8BFF788986FF697A77FF647473FF657372FF
+ 5C6A68FF576563FF505E5CFF404D4BFF3E4C48FF53615DFF737F79FF6F7B75FF
+ 6B7771FF6E7872FF758078FF7B867EFF7E8981FF7E8981FF777E79FF757F79FF
+ 787F7AFF7A847EFF808782FF818B85FF838A85FF808A84FF808782FF7E8882FF
+ 848B86FF88928CFF939A95FF9DA7A1FFAAB1ACFFA8B2ACFFAAB5B2FFA4B2AEFF
+ A8B6B2FFB0BEBAFFACBAB6FFA0AEAAFF9EACA8FFA6B4B0FFA5B3AFFFA8B6B2FF
+ A6B4B0FF9EACA8FF9AA8A4FF9DABA7FFA1AFABFFA2B0ACFFA8B2ACFFA8B2ACFF
+ A2AEA8FF9DA9A3FF9EAAA4FFA0ACA6FF9AA8A2FF93A19BFF9AAAA3FF9EAEA7FF
+ 9FAFA8FF9DADA6FFA0B2ABFFAEC0B9FFBACCC5FFBFD1CAFFB6C5C1FFBBCAC6FF
+ C3D2CEFFC4D3CFFFBAC9C5FFADBCB8FFAAB9B5FFAFBEBAFFB2C1BDFFAFBEBAFF
+ ABBAB6FFA8B7B3FFA5B4B0FFA0AFABFF9AA9A5FF95A4A0FF97A2A0FF6C7775FF
+ 586360FF899491FF8A9592FF7C8784FF79857FFF6C7872FF78857DFF748179FF
+ 6F7C74FF6C7971FF6F7D72FF748277FF79877CFF7D8B80FF747F75FF5D685EFF
+ 485349FF4F5A50FF6F7A70FF889389FF848F85FF727D73FF7B867CFF7D887EFF
+ 808B81FF838E84FF859086FF89948AFF8D988EFF919C92FF949D93FF939C92FF
+ 919A90FF90998FFF8F9A90FF939E94FF99A49AFF9DA89EFF859388FF818F84FF
+ 849489FF8E9E93FF8D9D92FF7F8F84FF78897EFF7B8C81FF92A09AFFA1AFA9FF
+ A1AFA9FF8F9D97FF86948EFF8D9B95FF919F99FF8A9892FF85938DFF9DABA5FF
+ A5B3ADFFA0AEA8FFA1AFA9FF9CAAA4FF97A59FFF9CAAA4FF98A6A2FF869591FF
+ 697773FF606F6BFF4E5C58FF485753FF5D6B67FF41504CFF35433FFF43524EFF
+ 566460FF5C6B67FF9CA6A0FF97A19BFF959F99FF9AA49EFF9DA7A1FF99A39DFF
+ 949E98FF929C96FF98A29CFF99A39DFF99A39DFF9AA49EFF9AA49EFF9BA59FFF
+ 9CA6A0FF9AA6A0FF9EACA8FF96A5A1FF9FAEAAFFA7B6B2FF9FAEAAFF9FAEAAFF
+ A7B6B2FFA8B7B3FFA1B0ACFFA1B0ACFFA1B0ACFFA2B1ADFFA3B2AEFFA5B4B0FF
+ A7B6B2FFA9B8B4FF97A6A2FF9AA9A5FF9EADA9FFA3B2AEFFA7B6B2FFA8B7B3FF
+ A8B7B3FFA7B6B2FF9CABA7FF9DACA8FFA0AFABFFA3B2AEFFA5B4B0FFA6B5B1FF
+ A5B4B0FFA4B3AFFFA2B3AFFFA1B2AEFF9DAEAAFF9AABA7FFA0AFABFFA7B6B2FF
+ A8B7B3FFA4B3AFFFA6B4B0FF92A09CFF919C99FF8A9592FF8D9895FF929D9AFF
+ 89928FFF909996FF96A09AFF9EA8A2FFA3ADA7FFA3ADA7FFA0AAA4FF9DA7A1FF
+ 96A09AFF8F9993FFA2ACA6FF9CA6A0FF959F99FF939D97FF98A29CFF9DA7A1FF
+ 9FA9A3FF9FA9A3FF929F97FF8B9890FF87968EFF8E9D95FF96A49EFF97A59FFF
+ 95A59EFF96A69FFFA6B7B3FFAEBFBBFFD8E9E6FFE1F2EFFFD7EAE7FFDDF0EDFF
+ D9EBEAFFDEF0EFFFDCF1EEFFD9EEEBFFD6EBE8FFD8EDEAFFDBF0EDFFDBF0EDFF
+ D7ECE9FFD3E8E5FFD9EEEBFFD4E9E6FFD2E7E4FFD5EAE7FFD6EBE8FFD2E7E4FF
+ D1E6E3FFD2E7E4FFDCF1EFFFDBF0EEFF758A88FF899E9CFFAEC3C1FFB0C5C3FF
+ AABFBDFF96ABA9FF9EB3B1FF96ABA9FF8FA4A2FF8EA3A1FF8DA2A0FF8CA19FFF
+ 8EA3A1FF92A8A6FF88A19DFF869F9BFF7E9591FF7B928EFF7F9692FF7B928EFF
+ 7C918EFF889D9AFF6C7F7CFF6D807DFF687B78FF617471FF677875FF6E7F7CFF
+ 687976FF5C6D6AFF5C6C6BFF5B6B6AFF51625FFF495A57FF435451FF374543FF
+ 364541FF4A5955FF586660FF505E58FF4A5852FF4F5B55FF59665EFF637068FF
+ 67746CFF66736BFF68726CFF67736DFF6B756FFF69756FFF6B756FFF6B7771FF
+ 707A74FF717D77FF7B857FFF76827CFF7F8983FF8D9993FF949E98FFA7B3ADFF
+ B9C3BDFFBCC8C2FFACBAB6FFA9B7B3FFACBAB6FFB3C1BDFFB1BFBBFFA7B5B1FF
+ A5B3AFFFABB9B5FFAAB8B4FFADBBB7FFAAB8B4FFA3B1ADFF9EACA8FFA0AEAAFF
+ A1AFABFF9FADA9FFA6B0AAFFA8B2ACFFA4B0AAFFA0ACA6FF9FABA5FFA0ACA6FF
+ 9AA8A2FF93A19BFF9EAEA7FFA2B2ABFFA2B2ABFFA0B0A9FFA2B4ADFFAFC1BAFF
+ BACCC5FFBFD1CAFFB7C6C2FFBAC9C5FFC2D1CDFFC8D7D3FFC5D4D0FFBAC9C5FF
+ B3C2BEFFB3C2BEFFABBAB6FFAAB9B5FFA8B7B3FFA7B6B2FFA5B4B0FF9FAEAAFF
+ 98A7A3FF92A19DFF9EA9A7FF75807EFF4F5A57FF8C9794FF929D9AFF9DA8A5FF
+ 919D97FF87938DFF7B8880FF7D8A82FF7E8B83FF7E8B83FF7E8C81FF818F84FF
+ 87958AFF8D9B90FF939E94FF929D93FF89948AFF717C72FF566157FF4F5A50FF
+ 657066FF818C82FF788379FF747F75FF7A857BFF889389FF909B91FF8D988EFF
+ 8D988EFF939E94FF9DA69CFF9EA79DFF9CA59BFF959E94FF8C978DFF8B968CFF
+ 919C92FF97A298FF869489FF869489FF86968BFF8D9D92FF93A398FF91A196FF
+ 85968BFF7B8C81FF889690FF9DABA5FFA7B5AFFF9BA9A3FF909E98FF8F9D97FF
+ 8B9993FF82908AFF96A49EFFA9B7B1FFADBBB5FFA4B2ACFF98A6A0FF7A8882FF
+ 596761FF4B5953FF3D4C48FF334440FF1E2D29FF11221EFF0E1D19FF2F403CFF
+ 768581FF8C9D99FF596864FF42534FFF3A4945FF435450FF9BA59FFF9CA6A0FF
+ A0AAA4FFA6B0AAFFA7B1ABFFA0AAA4FF96A09AFF8F9993FF9FA9A3FFA0AAA4FF
+ 9EA8A2FF99A39DFF98A29CFF9AA49EFF9AA49EFF96A29CFFAFBDB9FF93A29EFF
+ 8E9D99FF9BAAA6FF9DACA8FF9BAAA6FF9FAEAAFF9EADA9FF96A5A1FF95A4A0FF
+ 98A7A3FF9CABA7FF9DACA8FF9DACA8FFA0AFABFFA5B4B0FFA3B2AEFFA2B1ADFF
+ A3B2AEFFA7B6B2FFACBBB7FFAEBDB9FFACBBB7FFA9B8B4FF9DACA8FFA1B0ACFF
+ A5B4B0FFA8B7B3FFA8B7B3FFA7B6B2FFA7B6B2FFA8B7B3FF9FB0ACFF9DAEAAFF
+ 97A8A4FF93A4A0FF9AA9A5FFA2B1ADFFA3B2AEFF9EADA9FFAAB8B4FF9AA8A4FF
+ 939E9BFF909B98FF919C99FF929D9AFF8D9693FF8F9895FF909A94FF9DA7A1FF
+ A0AAA4FF949E98FF8D9791FF929C96FF96A09AFF959F99FF9BA59FFF98A29CFF
+ 959F99FF96A09AFF98A29CFF96A09AFF919B95FF8C9690FF9EABA3FF98A59DFF
+ 93A29AFF97A69EFF9BA9A3FF9AA8A2FF9AAAA3FF9DADA6FF98A9A5FFA4B5B1FF
+ D3E4E1FFE0F1EEFFD7EAE7FFDCEFECFFD7E9E8FFDBEDECFFDAEFECFFD8EDEAFF
+ D7ECE9FFD8EDEAFFDAEFECFFDAEFECFFD8EDEAFFD5EAE7FFDAEFECFFD7ECE9FF
+ D5EAE7FFD5EAE7FFD4E9E6FFD2E7E4FFD1E6E3FFD1E6E3FFD1E6E4FFCEE3E1FF
+ 667B79FF7A8F8DFFA0B5B3FFA5BAB8FFA2B7B5FF90A5A3FF8FA4A2FF8A9F9DFF
+ 899E9CFF8EA3A1FF8FA4A2FF899E9CFF849997FF819795FF7F9692FF859E9AFF
+ 7C938FFF768D89FF7D9490FF6C837FFF5C716EFF677C79FF657875FF657875FF
+ 607370FF5B6E6BFF60716EFF667774FF627370FF596A67FF546665FF566B69FF
+ 506562FF4D625FFF516461FF4A5D5AFF4B5F5AFF5C706BFF6F817AFF6B7D76FF
+ 697972FF6B7B74FF72837AFF788980FF7C8B83FF7D8C84FF75837DFF77857FFF
+ 78847EFF72807AFF6F7B75FF6B7973FF707C76FF72807AFF6D7973FF707E78FF
+ 77837DFF7F8D87FF78847EFF9EACA6FFB7C3BDFFB4C2BCFFACBAB6FFA9B7B3FF
+ ABB9B5FFB1BFBBFFB0BEBAFFAAB8B4FFA8B6B2FFACBAB6FFAAB8B4FFADBBB7FF
+ ABB9B5FFA5B3AFFFA2B0ACFFA3B1ADFFA3B1ADFF9FADA9FF919B95FFA2ACA6FF
+ ADB9B3FFA7B3ADFF9BA7A1FF95A19BFF96A49EFF99A7A1FF9FAFA8FFA3B3ACFF
+ A3B3ACFFA1B1AAFFA3B5AEFFAEC0B9FFB9CBC4FFBDCFC8FFB9C8C4FFB7C6C2FF
+ BBCAC6FFC4D3CFFFC7D6D2FFC0CFCBFFB9C8C4FFB6C5C1FFACBBB7FFAAB9B5FF
+ A8B7B3FFA6B5B1FFA3B2AEFF9EADA9FF97A6A2FF92A19DFF8C9795FF7A8583FF
+ 505B58FF8C9794FF86918EFF9BA6A3FF919D97FF98A49EFF8A978FFF8B9890FF
+ 8C9991FF8D9A92FF8D9B90FF8D9B90FF8E9C91FF8F9D92FF949F95FF8A958BFF
+ 828D83FF7C877DFF6F7A70FF616C62FF657066FF737E74FF768177FF7A857BFF
+ 828D83FF8D988EFF95A096FF939E94FF8B968CFF838E84FF858E84FF8A9389FF
+ 919A90FF939C92FF8F9A90FF8C978DFF8A958BFF8A958BFF93A196FF92A095FF
+ 89998EFF839388FF88988DFF95A59AFF96A79CFF8E9F94FF86948EFF99A7A1FF
+ A6B4AEFFA3B1ABFF9DABA5FF9AA8A2FF919F99FF83918BFF7B8983FF82908AFF
+ 77857FFF66746EFF5B6963FF47554FFF36443EFF34443DFF647571FF798D88FF
+ 91A29EFF9AAEA9FF9EAFABFFAFC3BEFFD5E6E2FFE6FAF5FFE7F8F4FFCADED9FF
+ B6C7C3FFB6CAC5FF9FA9A3FF9FA9A3FF9FA9A3FF9EA8A2FF9FA9A3FF9FA9A3FF
+ 9CA6A0FF99A39DFFA5AFA9FFA8B2ACFFA5AFA9FF9DA7A1FF9BA59FFF9EA8A2FF
+ 9DA7A1FF96A29CFFB2C0BCFF95A4A0FF8E9D99FF94A39FFF8A9995FF859490FF
+ 91A09CFF9CABA7FF95A4A0FF93A29EFF97A6A2FF9CABA7FF9BAAA6FF97A6A2FF
+ 99A8A4FFA1B0ACFFA7B6B2FFA3B2AEFFA1B0ACFFA4B3AFFFABBAB6FFAEBDB9FF
+ ABBAB6FFA7B6B2FF9EADA9FFA1B0ACFFA5B4B0FFA7B6B2FFA6B5B1FFA6B5B1FF
+ A6B5B1FFA7B6B2FFA3B4B0FFA2B3AFFF9EAFABFF9AABA7FF9FAEAAFFA5B4B0FF
+ A4B3AFFF9FAEAAFFACBAB6FFA1AFABFF949F9CFF95A09DFF96A19EFF919C99FF
+ 929B98FF8F9895FF86908AFF99A39DFFA1ABA5FF959F99FF8A948EFF919B95FF
+ 9DA7A1FFA3ADA7FF97A19BFF939D97FF8F9993FF8F9993FF919B95FF8F9993FF
+ 89938DFF838D87FFA2AFA7FF9FACA4FF9CABA3FF9CABA3FF99A7A1FF94A29CFF
+ 96A69FFF9DADA6FF95A6A2FFA0B1ADFFCFE0DDFFDFF0EDFFDAEDEAFFDFF2EFFF
+ D5E7E6FFD4E6E5FFD7ECE9FFD6EBE8FFD6EBE8FFD6EBE8FFD8EDEAFFD7ECE9FF
+ D5EAE7FFD3E8E5FFDAEFECFFDAEFECFFD8EDEAFFD4E9E6FFD2E7E4FFD2E7E4FF
+ D2E7E4FFD2E7E4FFD1E6E4FFCCE1DFFF5E7371FF687D7BFF879C9AFF8EA3A1FF
+ 95AAA8FF8DA2A0FF94A9A7FF8EA3A1FF8CA19FFF90A5A3FF91A6A4FF8BA09EFF
+ 859A98FF829896FF758C88FF7E9793FF7B928EFF7D9490FF8CA39FFF829995FF
+ 788D8AFF869B98FF91A4A1FF91A4A1FF90A3A0FF92A5A2FF9AABA8FFA2B3B0FF
+ A3B4B1FF9EB1AEFFA0B5B3FFA7BDBBFFA6BDB9FFA7BEBAFFAEC3C0FFA9BEBBFF
+ A8BEB9FFB5CBC6FFA4B9B1FFA7BCB4FFABBDB6FFAABCB5FFA7BAB1FFA6B9B0FF
+ ABBCB3FFAEBFB6FFA5B5AEFFA6B6AFFFA8B6B0FFA3B3ACFFA0AEA8FF9EAEA7FF
+ A2B0AAFFA6B6AFFF96A49EFFA0B0A9FF9DABA5FF91A19AFF697771FF99A9A2FF
+ AFBDB7FFA3B1ABFFA5B3AFFFA3B1ADFFA4B2AEFFA7B5B1FFA8B6B2FFA4B2AEFF
+ A2B0ACFFA3B1ADFFA8B6B2FFAAB8B4FFA8B6B2FFA3B1ADFFA3B1ADFFA6B4B0FF
+ A6B4B0FFA2B0ACFF89938DFF9BA59FFFA8B4AEFFA8B4AEFFA0ACA6FF9CA8A2FF
+ 98A6A0FF98A6A0FF9CACA5FFA1B1AAFFA3B3ACFFA2B2ABFFA3B5AEFFADBFB8FF
+ B6C8C1FFB8CAC3FFB8C7C3FFB1C0BCFFAFBEBAFFB6C5C1FFBBCAC6FFB9C8C4FF
+ B4C3BFFFB3C2BEFFB4C3BFFFAFBEBAFFA9B8B4FFA4B3AFFFA0AFABFF9CABA7FF
+ 97A6A2FF93A29EFF85908EFF7E8987FF515C59FF848F8CFF808B88FF96A19EFF
+ 8A9690FF95A19BFF95A29AFF919E96FF909D95FF93A098FF97A59AFF97A59AFF
+ 92A095FF8C9A8FFF8C978DFF778278FF6F7A70FF7D887EFF89948AFF808B81FF
+ 6D786EFF616C62FF727D73FF808B81FF818C82FF768177FF778278FF808B81FF
+ 758076FF5F6A60FF50594FFF555E54FF5F685EFF6B746AFF737E74FF758076FF
+ 717C72FF6C776DFF707E73FF758378FF6B7B70FF5D6D62FF5F6F64FF718176FF
+ 7E8F84FF7F9085FF85938DFF83918BFF788680FF687670FF5F6D67FF5B6963FF
+ 505E58FF414F49FF35433DFF3C4A44FF3A4842FF43514BFF616F69FF83918BFF
+ ABB9B3FFD0E0D9FFC2D6D1FFC6DCD7FFCFE3DEFFD0E6E1FFDCF0EBFFDDF3EEFF
+ CFE3DEFFC5DBD6FFC6DAD5FFD5EBE6FFE1F5F0FFDAF0EBFFA1ABA5FF9EA8A2FF
+ 959F99FF8D9791FF8E9892FF99A39DFFA4AEA8FFA8B2ACFF9FA9A3FFA5AFA9FF
+ A4AEA8FF9CA6A0FF9BA59FFFA1ABA5FFA0AAA4FF97A39DFFA2B0ACFF9BAAA6FF
+ A1B0ACFF9CABA7FF7F8E8AFF74837FFF8D9C98FFA8B7B3FFA0AFABFF9DACA8FF
+ 9FAEAAFFA4B3AFFF9FAEAAFF95A4A0FF95A4A0FF9EADA9FFA3B2AEFF9CABA7FF
+ 98A7A3FF9DACA8FFA7B6B2FFAEBDB9FFABBAB6FFA6B5B1FFA0AFABFFA0AFABFF
+ A0AFABFFA1B0ACFFA3B2AEFFA4B3AFFFA5B4B0FFA5B4B0FFA4B5B1FFA7B8B4FF
+ A5B6B2FFA0B1ADFFA0AFABFFA3B2AEFFA3B2AEFFA0AFABFFABB9B5FFA4B2AEFF
+ 929D9AFF98A3A0FF99A4A1FF8F9A97FF959E9BFF8D9693FF7A847EFF8D9791FF
+ 9DA7A1FF9BA59FFF919B95FF919B95FF9BA59FFFA4AEA8FFA1ABA5FF9AA49EFF
+ 919B95FF8E9892FF909A94FF939D97FF949E98FF939D97FF96A39BFF96A39BFF
+ 96A59DFF96A59DFF919F99FF8B9993FF8D9D96FF95A59EFF9CADA9FFA4B5B1FF
+ D1E2DFFFE2F3F0FFDFF2EFFFE2F5F2FFD4E6E5FFCFE1E0FFD5EAE7FFD5EAE7FF
+ D5EAE7FFD5EAE7FFD5EAE7FFD4E9E6FFD2E7E4FFD1E6E3FFD7ECE9FFDAEFECFF
+ D8EDEAFFD2E7E4FFCFE4E1FFD1E6E3FFD2E7E4FFD1E6E3FFCCE1DFFFD4E9E7FF
+ 768B89FF899E9CFFA7BCBAFFA7BCBAFFA8BDBBFF9DB2B0FFA4B9B7FFA3B8B6FF
+ A5BAB8FFA9BEBCFFAABFBDFFAABFBDFFB2C7C5FFBCD1CFFFB2C9C5FFB2CBC7FF
+ B2C9C5FFB7CECAFFC1D8D4FFC1D8D4FFC3D8D5FFCEE3E0FFCFE2DFFFCDE0DDFF
+ CBDEDBFFCCDFDCFFD3E4E1FFD7E8E5FFD9EAE7FFD6E9E6FFB8CECCFFBDD8D5FF
+ BDD6D2FFBAD3CFFFBED7D3FFB9D2CEFFB5CCC7FFBDD4CFFFB8D0C8FFBFD6CEFF
+ C4DBD3FFC1D8D0FFBBD0C7FFB6CBC2FFB7CCC3FFBDD0C7FFBACCC5FFBCCEC7FF
+ C1D1CAFFC0D2CBFFC3D3CCFFC4D6CFFFCADAD3FFCBDDD6FFCCDCD5FFD5E7E0FF
+ CFDFD8FFBCCEC7FF76867FFF9FB1AAFFB3C3BCFFA7B7B0FFA7B5B1FFA6B4B0FF
+ A5B3AFFFA6B4B0FFA7B5B1FFA6B4B0FFA3B1ADFFA1AFABFFA7B5B1FFA8B6B2FF
+ A5B3AFFFA1AFABFFA3B1ADFFA8B6B2FFA9B7B3FFA5B3AFFF97A19BFF99A39DFF
+ 9AA6A0FFA2AEA8FFADB9B3FFB1BDB7FFA2B0AAFF92A09AFF97A7A0FF9EAEA7FF
+ A3B3ACFFA3B3ACFFA5B7B0FFADBFB8FFB3C5BEFFB4C6BFFFBDCCC8FFB3C2BEFF
+ ACBBB7FFAFBEBAFFB3C2BEFFB3C2BEFFB2C1BDFFB2C1BDFFB7C6C2FFB1C0BCFF
+ AAB9B5FFA4B3AFFFA0AFABFF9CABA7FF97A6A2FF94A39FFF939E9CFF848F8DFF
+ 4F5A57FF747F7CFF889390FF9CA7A4FF8C9892FF8A9690FF909D95FF8B9890FF
+ 8A978FFF8F9C94FF96A499FF98A69BFF919F94FF89978CFF889389FF8C978DFF
+ 8F9A90FF8A958BFF79847AFF687369FF646F65FF6A756BFF545F55FF636E64FF
+ 5B665CFF3F4A40FF39443AFF4A554BFF465147FF2F3A30FF2F382EFF2A3329FF
+ 262F25FF262F25FF263127FF242F25FF1E291FFF172218FF1C2A1FFF29372CFF
+ 2F3F34FF2C3C31FF314136FF425247FF536459FF5B6C61FF4D5B55FF505E58FF
+ 55635DFF616F69FF74827CFF84928CFF84928CFF7B8983FF82908AFF87958FFF
+ 83918BFF84928CFF909E98FF98A6A0FFA8B6B0FFC0D0C9FFCDE1DCFFC9DFDAFF
+ C5DBD6FFB2C8C3FFBBD1CCFFCBE1DCFFC8DED9FFDBF1ECFFB6CCC7FFC8DED9FF
+ CFE5E0FFC6DCD7FFA0AAA4FF9FA9A3FF97A19BFF8D9791FF8E9892FF9AA49EFF
+ A5AFA9FFA7B1ABFF959F99FF9FA9A3FFA2ACA6FF9CA6A0FF9EA8A2FFA7B1ABFF
+ A7B1ABFF9DA9A3FF97A5A1FF9BAAA6FFACBBB7FFAAB9B5FF8F9E9AFF879692FF
+ 9DACA8FFB0BFBBFFADBCB8FFA8B7B3FFA9B8B4FFACBBB7FFA2B1ADFF92A19DFF
+ 91A09CFF9AA9A5FFA7B6B2FF9EADA9FF99A8A4FF9EADA9FFABBAB6FFB3C2BEFF
+ B0BFBBFFABBAB6FFA7B6B2FFA2B1ADFF9FAEAAFF9FAEAAFFA4B3AFFFA7B6B2FF
+ A7B6B2FFA6B5B1FFA4B5B1FFA9BAB6FFA8B9B5FF9FB0ACFF9AA9A5FF9BAAA6FF
+ 9FAEAAFF9FAEAAFFA7B5B1FFA4B2AEFF8D9895FF97A29FFF98A3A0FF8A9592FF
+ 969F9CFF8A9390FF7D8781FF858F89FF909A94FF959F99FF929C96FF8F9993FF
+ 96A09AFFA0AAA4FFA7B1ABFFA0AAA4FF97A19BFF939D97FF949E98FF97A19BFF
+ 97A19BFF96A09AFF95A29AFF93A098FF94A39BFF99A8A0FF9AA8A2FF97A59FFF
+ 97A7A0FF9BABA4FF9CADA9FFA6B7B3FFD4E5E2FFE5F6F3FFE0F3F0FFE3F6F3FF
+ D6E8E7FFD2E4E3FFD6EBE8FFD6EBE8FFD7ECE9FFD6EBE8FFD4E9E6FFD2E7E4FF
+ D1E6E3FFD0E5E2FFD2E7E4FFD7ECE9FFD6EBE8FFCEE3E0FFCADFDCFFCEE3E0FF
+ D1E6E3FFD0E5E2FFCCDEDDFFD8EAE9FF819392FF99ABAAFFB9CBCAFFB5C7C6FF
+ AFC1C0FF9FB1B0FF9DAFAEFFACBEBDFFBFD1D0FFC4D6D5FFBCCECDFFBACCCBFF
+ CADCDBFFDDF2F0FFE5FCF8FFDBF4F0FFE1F8F4FFE4FBF7FFDBF2EEFFD4EBE7FF
+ D3E8E5FFCEE3E0FFDBEEEBFFD7EAE7FFD2E5E2FFD1E4E1FFD3E4E1FFD2E3E0FF
+ D2E3E0FFD0E3E0FFC7DFDDFFCBE8E5FFC7E2DEFFC1DCD8FFC4DFDBFFBFDAD6FF
+ BBD5CFFFC0DAD4FFC6E1D8FFCBE3DBFFCCE4DCFFCAE2DAFFC6DED4FFC3DBD1FF
+ C4DCD2FFC9DED5FFBED3CBFFBDD2CAFFC0D2CBFFC1D6CEFFC7D9D2FFC6DBD3FF
+ C8DAD3FFC5DAD2FFCDDFD8FFCEE3DBFFCFE1DAFFCFE4DCFF788A83FF90A59DFF
+ A3B5AEFFA7B9B2FFADBCB8FFADBBB7FFAAB8B4FFA9B7B3FFABB9B5FFABB9B5FF
+ A8B6B2FFA4B2AEFFABB9B5FFA9B7B3FFA5B3AFFFA0AEAAFFA3B1ADFFA9B7B3FF
+ ABB9B5FFA7B5B1FFA2ACA6FF9DA7A1FF97A39DFF9DA9A3FFADB9B3FFB5C1BBFF
+ A8B6B0FF97A59FFF93A39CFF9CACA5FFA4B4ADFFA6B6AFFFA9BBB4FFAFC1BAFF
+ B3C5BEFFB2C4BDFFC1D0CCFFB7C6C2FFB0BFBBFFB0BFBBFFB2C1BDFFB0BFBBFF
+ AFBEBAFFB1C0BCFFB2C1BDFFAFBEBAFFAAB9B5FFA5B4B0FFA2B1ADFF9DACA8FF
+ 98A7A3FF94A39FFF99A4A2FF879290FF515C59FF646F6CFF8A9592FF98A3A0FF
+ 909C96FF8A9690FF93A098FF929F97FF93A098FF96A39BFF9AA89DFF9AA89DFF
+ 97A59AFF93A196FF808B81FF7D887EFF747F75FF6A756BFF667167FF69746AFF
+ 69746AFF657066FF7B867CFF889389FF859086FF737E74FF6F7A70FF7B867CFF
+ 7C877DFF707B71FF7C857BFF767F75FF6C756BFF626B61FF576258FF505B51FF
+ 4B564CFF49544AFF536156FF616F64FF6E7E73FF77877CFF7D8D82FF86968BFF
+ 92A398FF9BACA1FFA4B2ACFFA7B5AFFFABB9B3FFB1BFB9FFB7C5BFFFB6C4BEFF
+ AAB8B2FF9CAAA4FF8D9B95FF93A19BFF94A29CFF9CAAA4FFA6B4AEFF9DABA5FF
+ 94A29CFF9BABA4FF8FA5A0FFADC4BFFFCDE4DFFFC1D8D3FFC1D8D3FFC2D9D4FF
+ B4CBC6FFD2E9E4FFD1E8E3FFC6DDD8FFB9D0CBFFB4CBC6FF9DA7A1FFA3ADA7FF
+ A3ADA7FF9CA6A0FF9AA49EFF9FA9A3FFA0AAA4FF9BA59FFF949E98FFA0AAA4FF
+ A6B0AAFFA1ADA7FFA8B2ACFFB1BDB7FFB2BEB8FFA9B5AFFF98A6A2FF99A8A4FF
+ A8B7B3FFB1C0BCFFA9B8B4FFA9B8B4FFB0BFBBFFADBCB8FFB5C4C0FFAEBDB9FF
+ AEBDB9FFAFBEBAFFA2B1ADFF8F9E9AFF8C9B97FF95A4A0FFB3C2BEFFA9B8B4FF
+ A2B1ADFFA6B5B1FFB2C1BDFFBAC9C5FFB7C6C2FFB0BFBBFFAFBEBAFFA7B6B2FF
+ A1B0ACFFA1B0ACFFA8B7B3FFADBCB8FFADBCB8FFAAB9B5FFA8B9B5FFADBEBAFF
+ ACBDB9FFA0B1ADFF98A7A3FF99A8A4FF9FAEAAFFA4B3AFFFA3B1ADFFA2B0ACFF
+ 8A9592FF95A09DFF96A19EFF87928FFF959E9BFF87908DFF8F9993FF87918BFF
+ 87918BFF8E9892FF919B95FF8F9993FF97A19BFFA4AEA8FF9EA8A2FF9AA49EFF
+ 959F99FF949E98FF939D97FF909A94FF88928CFF828C86FF84908AFF808D85FF
+ 828E88FF8B9993FF93A19BFF94A29CFF93A19BFF92A29BFF96A5A1FFA2B3AFFF
+ D4E5E2FFE5F6F3FFE1F2EFFFE2F5F2FFD9ECE9FFD9ECE9FFD7ECE9FFD8EDEAFF
+ D8EDEAFFD7ECE9FFD4E9E6FFD1E6E3FFD0E5E2FFD0E5E2FFCEE3E0FFD5EAE7FF
+ D4E9E6FFCBE0DDFFC7DCD9FFCCE1DEFFD0E5E2FFCEE3E0FFD8EBE8FFD5E6E3FF
+ 667675FF6D7E7BFF889897FF8B9C99FF91A1A0FF889996FF869695FFA4B5B2FF
+ C5D5D4FFC9DAD7FFB2C2C1FFA1B2AFFFADBDBCFFC2D5D2FFB5CAC7FFB1C8C4FF
+ CFE4E1FFEBFFFDFFE9FEFBFFEBFFFDFFEFFFFFFFE4F7F4FFE0F3F0FFDBEEEBFF
+ DAEBE8FFDAEBE8FFDBECE9FFDBECE9FFDCEDEAFFDDF0EDFFD4EDE9FFD7F5F0FF
+ D2EDE9FFC9E4E0FFCEE9E5FFCDE8E4FFCAE6E0FFD0ECE6FFCDE8DFFFCBE6DDFF
+ CAE2DAFFC8E0D8FFC9E1D9FFCBE4DAFFCCE4DCFFCEE5DDFFCEE3DBFFCBE0D8FF
+ C8DCD7FFC6DDD5FFC7DDD8FFC4DBD3FFBED4CFFFB8CFC7FFCCE2DDFFC5DCD4FF
+ CDE1DCFFE3F8F0FF819590FF8B9D96FF9BACA8FFAEBFBBFFAEBDB9FFADBBB7FF
+ AAB8B4FFA8B6B2FFA9B7B3FFABB9B5FFA7B5B1FFA2B0ACFFAFBDB9FFACBAB6FF
+ A6B4B0FFA0AEAAFFA2B0ACFFAAB8B4FFACBAB6FFA8B6B2FF9FABA5FFA0ACA6FF
+ 9FABA5FF9DA9A3FFA2AEA8FFA9B5AFFFA7B5AFFFA2B0AAFF91A19AFF9BABA4FF
+ A5B5AEFFA9B9B2FFADBDB6FFB1C3BCFFB5C5BEFFB3C3BCFFBECDC9FFB5C4C0FF
+ AEBDB9FFAEBDB9FFADBCB8FFA9B8B4FFA7B6B2FFA9B8B4FFACBBB7FFAAB9B5FF
+ A9B8B4FFA7B6B2FFA5B4B0FF9FAEAAFF98A7A3FF92A19DFF8F9D99FF86918EFF
+ 586360FF5A6562FF828D8AFF87928FFF8F9B95FF939F99FF89968EFF8C9991FF
+ 8F9C94FF8F9C94FF8D9A92FF8B998EFF8C978FFF8C978DFF88938BFF8C978DFF
+ 838E86FF6B766CFF5C675FFF5F6A60FF67726AFF687369FF68736BFF758076FF
+ 808B83FF848F85FF859088FF879288FF87928AFF859086FF7D867CFF818A80FF
+ 858E84FF848D83FF7F8A80FF7F8A80FF828D83FF869187FF869489FF8B998EFF
+ 92A297FF97A79CFF97A79CFF94A499FF97A89DFF9DAEA3FFA1B0A8FF9EADA5FF
+ 9AA8A2FF97A69EFF99A7A1FF9CABA3FF9DABA5FF9CABA3FFABB9B3FFA2B1A9FF
+ 92A09AFF92A199FF9EACA6FF9CABA3FF99A7A1FFA2B2ABFF8DA29AFFA2BAB2FF
+ C2D8D3FFBBD2CDFFCCE2DDFFCFE6E1FFB3C9C4FFC7DED9FFC4DAD5FFBFD6D1FF
+ C5DBD6FFCAE1DCFF9DA49FFFA6ADA8FFAEB5B0FFAEB5B0FFA3ADA7FF9AA49EFF
+ 959F99FF949E98FFA5B1ABFFA3AFA9FFA6B2ACFFACBAB4FFB3BFB9FFADBBB5FF
+ A6B4AEFFA1AFA9FF9BA9A5FF99A7A3FFA4B2AEFFACBAB6FFA6B4B0FFA8B6B2FF
+ ACBAB6FFA5B3AFFFB0BEBAFFADBBB7FFACBAB6FFABB9B5FFA4B2AEFF9BA9A5FF
+ 99A7A3FF9DABA7FFA2B1ADFFB3C2BEFFA2B1ADFF9CABA7FFB7C6C2FFB3C2BEFF
+ A5B4B0FFB8C7C3FFA8B7B3FFA3B2AEFF9FAEAAFFA2B1ADFFA9B8B4FFAFBEBAFF
+ B0BFBBFFAEBDB9FFA6B7B3FFA0B1ADFF9FB0ACFFA0B1ADFF9EADA9FF97A6A2FF
+ 9AA9A5FFA4B3AFFF9FADA9FF9EACA8FF96A19EFF87928FFF818C89FF87928FFF
+ 8C9592FF89928FFF8E9A94FF8C9892FF8E9A94FF94A09AFF929E98FF8C9892FF
+ 8E9A94FF96A29CFF95A19BFF9AA6A0FF939F99FF84908AFF818D87FF8E9A94FF
+ 96A29CFF94A09AFF97A19BFF94A09AFF8E9996FF8B9693FF939E9BFF99A7A3FF
+ 95A39FFF899894FF92A19DFF8C9B97FFD8E7E3FFDCEDE9FFE0F1EDFFD9EAE6FF
+ D9EAE6FFD6E9E6FFD8EDEAFFDEF3F0FFE2F7F4FFDDF2EFFFD3E8E5FFCEE3E0FF
+ D2E7E4FFD8EDEAFFD2E7E4FFD2E7E4FFD0E5E2FFCFE4E1FFCEE3E0FFCEE3E0FF
+ CDE2DFFFCFE2DFFFCEDFDCFFCCDBD7FFA0AEACFF5B6A66FF859391FF8F9E9AFF
+ 808E8CFFA9B8B4FFA3B1AFFFA6B5B1FFAEBCBAFFB4C3BFFFAFBDBBFFA5B4B0FF
+ A4B2B0FFAAB9B5FFA1B2AEFFA1B2AEFFA8B9B5FFB6C7C3FFC5D6D2FFD4E5E1FF
+ E5F6F2FFF1FFFEFFEAFBF7FFE6F7F3FFE2F1EDFFDEEDE9FFDDECE8FFE1F0ECFF
+ E6F5F1FFE6FAF5FFDDF4EFFFE1FDF7FFE2FCF6FFD9F3EDFFD7F1EBFFDCF6F0FF
+ DAF4EEFFD1EBE5FFDBF5EFFFD5EFE9FFD7F1EBFFD8F2ECFFD1EBE5FFD1ECE3FF
+ CEE8E2FFC3DAD5FFC8DED9FFCDE1DCFFCCE1DEFFC7DED9FFC4DBD7FFC1D8D3FF
+ B7D0CCFFAEC8C2FFB3CAC6FFCDE4DFFFCBE0DDFFD2E6E1FF9EAFACFF798884FF
+ A0AEACFFB0BFBBFFAEBCB8FFA9B7B3FFA8B6B2FFAAB8B4FFA9B7B3FFA5B3AFFF
+ A4B2AEFFA8B6B2FFABB9B5FFA5B3AFFFA8B6B2FFA8B6B2FFA3B1ADFFA9B7B3FF
+ ACBAB6FF9EACA8FF9AA8A2FF9FADA7FF8F9D97FF9DABA5FFA6B4AEFF97A59FFF
+ A2B0AAFFAEBCB6FFABB9B3FFA1AFA9FF8E9C96FFA5B3ADFFAAB8B2FFA4B4ADFF
+ BCCAC4FFADBDB6FFB4C3BFFFAEBDB9FFAAB9B5FFABBAB6FFADBCB8FFADBCB8FF
+ ACBBB7FFADBCB8FFACBBB7FFADBCB8FFACBBB7FFA8B7B3FFA3B2AEFF9DACA8FF
+ 98A7A3FF96A5A1FF92A19DFF82908AFF697771FF56645EFF808E88FF7E8C86FF
+ 87938DFF919D97FF848E88FF8E9892FF97A19BFF98A29CFF909A94FF88938BFF
+ 89908BFF89948CFF939D97FF859088FF7B857FFF6E7971FF5C6660FF5F6A62FF
+ 6C7670FF6E7971FF747E78FF79847CFF7E8882FF818C84FF818B85FF808B83FF
+ 808A84FF818C84FF8E978DFF90998FFF939C92FF99A298FF9DA89EFF9EA99FFF
+ 9BA69CFF97A298FF95A398FF97A59AFF99A99EFF9CACA1FF9DADA2FF9CACA1FF
+ 99AA9FFF98A99EFFA0B0A5FF97A79CFF99A8A0FFA6B6ABFFA9B8B0FF9FAFA4FF
+ 9CABA3FFA2B2A7FF9FAEA6FF9FAFA4FF9EADA5FF9DADA2FF9CABA3FF9CACA1FF
+ 9FAEA6FFA0B1A8FF97ACA3FFA3BBB1FFC8DDD5FFC9E0D8FFC6DBD3FFC3DAD2FF
+ B9CEC6FFC1D8D0FFC6DAD5FFBAD0CBFFBBCECBFFC3D8D5FF9CA39EFFA1A8A3FF
+ A6ADA8FFA7AEA9FFA1ABA5FF9DA7A1FF9CA6A0FF9CA6A0FF9FABA5FFA5B1ABFF
+ A5B3ADFFA5B3ADFFAFBDB7FFBAC8C2FFB0C0B9FF9CACA5FFA9B7B3FFA5B3AFFF
+ ADBBB7FFB1BFBBFFA6B4B0FFA4B2AEFFA3B1ADFF99A7A3FFB5C3BFFFB4C2BEFF
+ B4C2BEFFB3C1BDFFADBBB7FFA6B4B0FFA7B5B1FFADBBB7FFA4B3AFFFB3C2BEFF
+ A4B3AFFF9DACA8FFB3C2BEFFAEBDB9FF9FAEAAFFAFBEBAFFB6C5C1FFB0BFBBFF
+ AAB9B5FFAAB9B5FFAEBDB9FFB0BFBBFFAFBEBAFFACBBB7FFABBCB8FFA4B5B1FF
+ A2B3AFFFA2B3AFFF9FAEAAFF95A4A0FF91A09CFF94A39FFFA3B1ADFFA0AEAAFF
+ 98A3A0FF899491FF85908DFF8A9592FF909996FF8F9895FF9BA7A1FF97A39DFF
+ 97A39DFF9AA6A0FF98A49EFF919D97FF909C96FF95A19BFF8E9A94FF96A29CFF
+ 94A09AFF8A9690FF8A9690FF96A29CFF9DA9A3FF9AA6A0FF9FA8A5FFA2ABA8FF
+ 9FAAA7FF9AA5A2FF99A4A1FF9BA6A3FF94A29EFF8C9A96FF869591FF879692FF
+ C1D0CCFFDFEEEAFFE0F1EDFFD7E8E4FFD6E7E3FFD0E4DFFFDBEEEBFFD9EEEBFF
+ D9EEEBFFD8EDEAFFD7ECE9FFD7ECE9FFD7ECE9FFD8EDEAFFD7ECE9FFD6EBE8FF
+ D4E9E6FFD2E7E4FFD0E5E2FFCFE4E1FFCFE4E1FFD1E4E1FFCBDAD6FFCFDDD9FF
+ AAB8B4FF4C5A56FF808E8AFF97A5A1FF919F9BFFA8B6B2FF9DABA7FF9AA8A4FF
+ 9FADA9FFAAB8B4FFA8B6B2FF9CAAA6FF9AA8A4FFA1AFABFF9FAEAAFF9CABA7FF
+ 9BAAA6FF9EADA9FFA3B2AEFFAFBEBAFFC7D6D2FFDCEBE7FFEFFEFAFFEFFEFAFF
+ EEFDF9FFEDFCF8FFEBFAF6FFE9F8F4FFE8F7F3FFE5F6F2FFDEF4EFFFE0FAF4FF
+ E2F9F4FFDAF4EEFFD8EFEAFFD6F0EAFFD9F0EBFFD5EFE9FFDDF4EFFFD6F0EAFF
+ D6EDE8FFD9F3EDFFDCF3EEFFD1EBE5FFCEE5E0FFD1E8E3FFCADFDCFFCDE2DFFF
+ CDE2DFFFC9E0DCFFC4DDD9FFC0D9D5FFB2CDC9FFA5C0BCFFB5CECAFFCCE5E1FF
+ CCE1DEFFD2E5E2FFA0B1AEFF768482FF9DAAA8FFAAB7B5FFAAB8B4FFA6B4B0FF
+ A5B3AFFFA7B5B1FFA5B3AFFFA1AFABFFA1AFABFFA4B2AEFFADBBB7FFA7B5B1FF
+ A9B7B3FFA9B7B3FFA4B2AEFFABB9B5FFAFBDB9FFA3B1ADFF9DABA5FFA2B0AAFF
+ 93A19BFFA0AEA8FFA8B6B0FF99A7A1FFA1AFA9FFABB9B3FFA7B5AFFF9FADA7FF
+ 92A09AFFA5B3ADFFA7B5AFFFA4B2ACFFBBC9C3FFB0BEB8FFB4C3BFFFB4C3BFFF
+ B0BFBBFFACBBB7FFAAB9B5FFACBBB7FFADBCB8FFACBBB7FFA5B4B0FFA7B6B2FF
+ A9B8B4FFA9B8B4FFA5B4B0FF9FAEAAFF99A8A4FF96A5A1FF8E9E97FF7F8F88FF
+ 697771FF57655FFF82908AFF808E88FF85918BFF8A9690FF86908AFF8D9791FF
+ 939D97FF929C96FF8E9590FF8A918CFF8D948FFF929994FF8A948EFF808A84FF
+ 7E8882FF76807AFF66706AFF646E68FF6A746EFF66706AFF727C76FF757F79FF
+ 79837DFF7C8680FF7E8882FF828C86FF87918BFF8B968EFF8C948DFF90998FFF
+ 969F95FF9DA69CFF9FAAA0FF9FAAA0FF9DA89EFF9AA59BFF95A398FF9AA89DFF
+ 9FAFA4FFA5B5AAFFA8B8ADFFA5B5AAFFA0B1A6FF9DAEA3FFA8B8ADFF9EAEA3FF
+ 94A499FF97A79CFFA5B5AAFFAFBFB4FFA9B9AEFF9DADA2FFA4B4A9FFA4B4A9FF
+ A4B4A9FFA3B3A8FFA2B2A7FFA2B2A7FFA3B3A8FFA3B4A9FF96A9A0FFA2B7AEFF
+ C4D9D0FFC7DCD3FFC2D7CFFFC3D8D0FFB8CDC5FFC3D8D0FFC0D4CFFFB7CBC6FF
+ B7CAC7FFC2D5D2FF9AA19CFF9BA29DFF9DA49FFF9FA6A1FF9EA8A2FFA0AAA4FF
+ A2ACA6FFA3ADA7FF9BA7A1FFA5B1ABFF9EACA6FF94A29CFFA2B0AAFFBDCBC5FF
+ B9C9C2FFA0B0A9FFABB9B5FFA7B5B1FFAFBDB9FFB3C1BDFFAAB8B4FFA8B6B2FF
+ A6B4B0FF9BA9A5FFB3C1BDFFB3C1BDFFB5C3BFFFB4C2BEFFADBBB7FFA6B4B0FF
+ A8B6B2FFAFBDB9FFA1B0ACFFAEBDB9FFA3B2AEFF9FAEAAFFB0BFBBFFA9B8B4FF
+ 9CABA7FFA7B6B2FFB9C8C4FFB4C3BFFFAEBDB9FFACBBB7FFAEBDB9FFAEBDB9FF
+ ACBBB7FFA9B8B4FFAEBFBBFFA7B8B4FFA4B5B1FFA5B6B2FFA5B4B0FF9CABA7FF
+ 92A19DFF8D9C98FFA0AEAAFF9DABA7FF96A19EFF8A9592FF86918EFF8A9592FF
+ 909996FF909996FFA1ADA7FF9DA9A3FF9BA7A1FF9DA9A3FF9CA8A2FF97A39DFF
+ 94A09AFF94A09AFF8C9892FF94A09AFF95A19BFF8E9A94FF8F9B95FF97A39DFF
+ 9CA8A2FF99A59FFF9EA7A4FFA5AEABFFA6B1AEFFA2ADAAFF9DA8A5FF9AA5A2FF
+ 95A39FFF92A09CFF84938FFF899894FFA1B0ACFFD9E8E4FFDBECE8FFD6E7E3FF
+ D8E9E5FFD3E7E2FFD9ECE9FFD1E6E3FFCDE2DFFFD1E6E3FFD8EDEAFFDDF2EFFF
+ DAEFECFFD6EBE8FFDAEFECFFD8EDEAFFD5EAE7FFD1E6E3FFCFE4E1FFCEE3E0FF
+ CEE3E0FFD0E3E0FFD1E0DCFFD7E5E1FFBECCC8FF3A4844FF6F7D79FF8A9894FF
+ 8A9894FF8C9A96FF9AA8A4FF8E9C98FF919F9BFFA3B1ADFFA6B4B0FF98A6A2FF
+ 95A39FFF9FADA9FF9CABA7FF9BAAA6FF99A8A4FF95A4A0FF92A19DFF98A7A3FF
+ ACBBB7FFC1D0CCFFD9E8E4FFDEEDE9FFE7F6F2FFEDFCF8FFEDFCF8FFE8F7F3FF
+ E1F0ECFFD9EAE6FFCCE2DDFFCCE3DEFFCFE5E0FFCEE5E0FFCAE0DBFFC4DBD6FF
+ CAE0DBFFD3EAE5FFD3E9E4FFD7EEE9FFD1E7E2FFD4EBE6FFE1F7F2FFD5ECE7FF
+ CEE4DFFFE2F8F3FFDBEEEBFFDAEFECFFD9EEEBFFD5ECE8FFD2EBE7FFCDE6E2FF
+ BDD8D4FFADC8C4FFB9D2CEFFCBE4E0FFCFE4E1FFD4E7E4FFAABBB8FF7A8886FF
+ A1AEACFFAAB7B5FFAEBCB8FFAAB8B4FFA9B7B3FFABB9B5FFA9B7B3FFA4B2AEFF
+ A3B1ADFFA6B4B0FFACBAB6FFA6B4B0FFA7B5B1FFA6B4B0FFA1AFABFFAAB8B4FF
+ B0BEBAFFA6B4B0FF9BA9A3FFA2B0AAFF93A19BFF9FADA7FFA8B6B0FF98A6A0FF
+ 9EACA6FFA4B2ACFFA1AFA9FF9CAAA4FF97A59FFFA5B3ADFFA2B0AAFFA3B1ABFF
+ B8C6C0FFB3C1BBFFB4C3BFFFBBCAC6FFB9C8C4FFADBCB8FFA6B5B1FFA9B8B4FF
+ ACBBB7FFAAB9B5FFA4B3AFFFA6B5B1FFA8B7B3FFA8B7B3FFA5B4B0FF9EADA9FF
+ 96A5A1FF91A09CFF8B9B94FF7D8D86FF687670FF56645EFF83918BFF818F89FF
+ 828E88FF828E88FF87918BFF8C9690FF8F9993FF8D9791FF8A918CFF8A918CFF
+ 909792FF979E99FF818B85FF7C8680FF828C86FF818B85FF717B75FF69736DFF
+ 66706AFF5B655FFF6B756FFF6E7872FF717B75FF757F79FF7A847EFF828C86FF
+ 8C9690FF939E96FF8B938CFF90998FFF98A197FF9DA69CFF9EA99FFF9EA99FFF
+ 9DA89EFF9CA79DFF9BA99EFF9EACA1FFA1B1A6FFA6B6ABFFA9B9AEFFA9B9AEFF
+ A7B8ADFFA6B7ACFFA7B7ACFFA6B6ABFF9AAA9FFF90A095FF9AAA9FFFAEBEB3FF
+ AFBFB4FFA2B2A7FFA5B5AAFFA5B5AAFFA6B6ABFFA7B7ACFFA7B7ACFFA6B6ABFF
+ A6B6ABFFA4B5AAFF97AAA1FFA1B6ADFFC1D6CDFFC3D8CFFFC0D5CDFFC3D8D0FF
+ B9CEC6FFC4D9D1FFC2D6D1FFBCD0CBFFBDD0CDFFC8DBD8FF989F9AFF989F9AFF
+ 99A09BFF9CA39EFF9EA8A2FFA1ABA5FFA1ABA5FFA0AAA4FFA5B1ABFFA8B4AEFF
+ 9DABA5FF909E98FF9BA9A3FFB5C3BDFFBCCCC5FFB2C2BBFFAEBCB8FFA9B7B3FF
+ B0BEBAFFB6C4C0FFAEBCB8FFADBBB7FFABB9B5FF9FADA9FFAFBDB9FFB0BEBAFF
+ B5C3BFFFB5C3BFFFADBBB7FFA3B1ADFFA1AFABFFA5B3AFFF9BAAA6FFA6B5B1FF
+ A2B1ADFFA1B0ACFFADBCB8FFA8B7B3FF9EADA9FFA5B4B0FFAFBEBAFFABBAB6FF
+ A8B7B3FFA8B7B3FFA9B8B4FFAAB9B5FFA9B8B4FFA7B6B2FFACBDB9FFA5B6B2FF
+ A1B2AEFFA4B5B1FFABBAB6FFA9B8B4FFA0AFABFF99A8A4FF9DABA7FF9BA9A5FF
+ 97A29FFF919C99FF8E9996FF8E9996FF919A97FF909996FF9CA8A2FF99A59FFF
+ 98A49EFF9AA6A0FF9BA7A1FF99A59FFF95A19BFF939F99FF929E98FF97A39DFF
+ 96A29CFF8F9B95FF8C9892FF909C96FF929E98FF909C96FF929B98FF97A09DFF
+ 99A4A1FF9AA5A2FF99A4A1FF9AA5A2FF99A7A3FF99A7A3FF8E9D99FF93A29EFF
+ 889793FFCEDDD9FFD4E5E1FFD5E6E2FFDCEDE9FFDAEEE9FFD4E7E4FFCCE1DEFF
+ C8DDDAFFCBE0DDFFD4E9E6FFD9EEEBFFD7ECE9FFD3E8E5FFD8EDEAFFD6EBE8FF
+ D2E7E4FFCFE4E1FFCCE1DEFFCADFDCFFC9DEDBFFCBDEDBFFD3E2DEFFD7E5E1FF
+ CEDCD8FF32403CFF5C6A66FF73817DFF788682FF75837FFF94A29EFF82908CFF
+ 83918DFF9AA8A4FFA2B0ACFF96A4A0FF92A09CFF9DABA7FF97A6A2FF98A7A3FF
+ 9CABA7FF9FAEAAFF9DACA8FF9BAAA6FFA2B1ADFFACBBB7FFC6D5D1FFD1E0DCFF
+ E0EFEBFFEEFDF9FFF3FFFEFFF2FFFDFFEBFAF6FFE4F5F1FFC3D7D2FFBDD3CEFF
+ BED2CDFFBAD0CBFFAFC3BEFF9FB5B0FFA5B9B4FFB2C8C3FFBCD0CBFFD3E9E4FF
+ CBDFDAFFC1D7D2FFD9EDE8FFD5EBE6FFD2E6E1FFEAFEF9FFE9FCF9FFE6FBF8FF
+ E2F7F4FFDDF4F0FFDCF5F1FFDBF4F0FFCDE8E4FFBFDAD6FFB7D0CCFFC3DCD8FF
+ CBE0DDFFD0E3E0FFB0C1BEFF7C8A88FFA5B2B0FFAAB7B5FFAEBCB8FFABB9B5FF
+ AAB8B4FFADBBB7FFABB9B5FFA6B4B0FFA4B2AEFFA7B5B1FFA7B5B1FFA1AFABFF
+ A3B1ADFFA1AFABFF9BA9A5FFA5B3AFFFADBBB7FFA5B3AFFF9AA8A2FFA3B1ABFF
+ 95A39DFFA1AFA9FFABB9B3FF9DABA5FFA1AFA9FFA4B2ACFF9CAAA4FF9AA8A2FF
+ 9EACA6FFA5B3ADFF9EACA6FFA3B1ABFFB5C3BDFFB5C3BDFFB4C3BFFFC0CFCBFF
+ C0CFCBFFAFBEBAFFA4B3AFFFA7B6B2FFABBAB6FFA8B7B3FFAAB9B5FFA9B8B4FF
+ A7B6B2FFA4B3AFFFA0AFABFF99A8A4FF91A09CFF8C9B97FF8C9C95FF7E8E87FF
+ 67756FFF53615BFF818F89FF818F89FF818D87FF7E8A84FF89938DFF8C9690FF
+ 8E9892FF8C9690FF8A918CFF8A918CFF8F9691FF959C97FF7F8983FF7C8680FF
+ 858F89FF86908AFF77817BFF6C7670FF636D67FF545E58FF656F69FF69736DFF
+ 6E7872FF747E78FF7B857FFF838D87FF8D9791FF949F97FF8D958EFF90998FFF
+ 959E94FF97A096FF96A197FF97A298FF99A49AFF9CA79DFFA3B1A6FFA2B0A5FF
+ 9EAEA3FF9FAFA4FFA1B1A6FFA5B5AAFFA9BAAFFFACBDB2FFA0B0A5FFA8B8ADFF
+ A7B7ACFF9AAA9FFF93A398FF9BABA0FFA8B8ADFFAEBEB3FFA0B0A5FFA0B0A5FF
+ A2B2A7FFA5B5AAFFA7B7ACFFA7B7ACFFA5B5AAFFA2B3A8FF9EB1A8FFA6BBB2FF
+ C4D9D0FFC6DBD2FFC3D8D0FFC6DBD3FFBCD1C9FFC7DCD4FFC5D9D4FFC0D4CFFF
+ C3D6D3FFCCDFDCFF949B96FF969D98FF9AA19CFF9FA6A1FFA0AAA4FF9FA9A3FF
+ 9BA59FFF98A29CFFAAB6B0FFAAB6B0FFA6B4AEFFA4B2ACFFA6B4AEFFAEBCB6FF
+ B7C7C0FFBDCDC6FFB9C7C3FFB1BFBBFFB5C3BFFFB7C5C1FFAFBDB9FFACBAB6FF
+ A8B6B2FF9BA9A5FFABB9B5FFAEBCB8FFB5C3BFFFBBC9C5FFB7C5C1FFABB9B5FF
+ A5B3AFFFA5B3AFFF9DACA8FFA4B3AFFFA5B4B0FFA6B5B1FFAAB9B5FFA5B4B0FF
+ 9FAEAAFFA1B0ACFFABBAB6FFA9B8B4FFA8B7B3FFA8B7B3FFA9B8B4FFAAB9B5FF
+ AAB9B5FFA9B8B4FFAABBB7FFA3B4B0FF9CADA9FF9EAFABFFA9B8B4FFAFBEBAFF
+ ACBBB7FFA5B4B0FF9BA9A5FF9AA8A4FF9BA6A3FF9BA6A3FF98A3A0FF939E9BFF
+ 919A97FF909996FF98A49EFF99A59FFF99A59FFF98A49EFF98A49EFF97A39DFF
+ 939F99FF8F9B95FF99A59FFF9AA6A0FF96A29CFF8E9A94FF89958FFF8B9791FF
+ 8D9993FF8E9A94FF8D9693FF8B9491FF899491FF8D9895FF939E9BFF98A3A0FF
+ 99A7A3FF9BA9A5FF92A19DFF96A5A1FF7F8E8AFFBFCECAFFD1E2DEFFD6E7E3FF
+ D7E8E4FFD5E9E4FFD3E6E3FFCFE4E1FFCDE2DFFFCDE2DFFFCFE4E1FFD1E6E3FF
+ D3E8E5FFD4E9E6FFD6EBE8FFD5EAE7FFD2E7E4FFCFE4E1FFCBE0DDFFC9DEDBFF
+ C7DCD9FFC8DBD8FFCEDDD9FFCFDDD9FFD8E6E2FF374541FF54625EFF6D7B77FF
+ 768480FF7B8985FF899793FF788682FF788682FF8E9C98FF98A6A2FF919F9BFF
+ 8F9D99FF98A6A2FF95A4A0FF93A29EFF96A5A1FF9EADA9FFA0AFABFF9DACA8FF
+ 9AA9A5FF9BAAA6FFA9B8B4FFB4C3BFFFC4D3CFFFD3E2DEFFDDECE8FFDFEEEAFF
+ DCEBE7FFD9E8E4FFCEDFDBFFC4D8D3FFBFD0CCFFB3C7C2FF9FB0ACFF879B96FF
+ 879894FF90A49FFFA2B3AFFFC8DCD7FFC2D3CFFFACC0BBFFC3D4D0FFCFE3DEFF
+ D3E4E0FFE3F7F2FFE6F9F6FFE1F6F3FFDBF0EDFFD6EDE9FFD6EFEBFFDAF3EFFF
+ D3EEEAFFCBE6E2FFB9D2CEFFBDD6D2FFC6DBD8FFC9DCD9FFB3C4C1FF778583FF
+ A1AEACFFA3B0AEFFA7B5B1FFA4B2AEFFA5B3AFFFA8B6B2FFA7B5B1FFA2B0ACFF
+ A0AEAAFFA3B1ADFFA5B3AFFFA0AEAAFFA3B1ADFFA0AEAAFF99A7A3FFA2B0ACFF
+ ABB9B5FFA5B3AFFF9CAAA4FFA6B4AEFF98A6A0FFA3B1ABFFAFBDB7FFA5B3ADFF
+ A9B7B1FFA9B7B1FF9AA8A2FF98A6A0FFA6B4AEFFA4B2ACFF9BA9A3FFA5B3ADFF
+ B1BFB9FFB6C4BEFFB3C2BEFFC0CFCBFFC2D1CDFFB3C2BEFFA6B5B1FFA5B4B0FF
+ A7B6B2FFA6B5B1FFADBCB8FFA8B7B3FFA1B0ACFF9CABA7FF99A8A4FF96A5A1FF
+ 92A19DFF8E9D99FF8E9E97FF82928BFF697771FF515F59FF7D8B85FF808E88FF
+ 838F89FF808C86FF8A948EFF8E9892FF919B95FF8F9993FF8D948FFF8A918CFF
+ 8A918CFF8C938EFF848E88FF7E8882FF848E88FF848E88FF757F79FF6C7670FF
+ 636D67FF545E58FF656F69FF6B756FFF747E78FF7C8680FF828C86FF88928CFF
+ 8D9791FF919C94FF909891FF90998FFF8F988EFF8E978DFF8C978DFF909B91FF
+ 949F95FF98A399FFA3B1A6FFA3B1A6FFA1B1A6FFA1B1A6FFA2B2A7FFA4B4A9FF
+ A6B7ACFFA7B8ADFFA3B3A8FFA2B2A7FFA4B4A9FFA4B4A9FF9AAA9FFF92A297FF
+ 9BABA0FFACBCB1FF9EAEA3FF9DADA2FF9FAFA4FFA3B3A8FFA7B7ACFFA8B8ADFF
+ A6B6ABFFA2B3A8FFA6B9B0FFADC2B9FFC9DED5FFCBE0D7FFC9DED6FFCBE0D8FF
+ C0D5CDFFC9DED6FFBFD3CEFFBCD0CBFFBDD0CDFFC3D6D3FF8D948FFF939A95FF
+ 9BA29DFFA1A8A3FFA1ABA5FF9EA8A2FF99A39DFF959F99FF9EAAA4FFA4B0AAFF
+ ACBAB4FFB3C1BBFFAFBDB7FFA9B7B1FFAABAB3FFB1C1BAFFB8C6C2FFAEBCB8FF
+ B1BFBBFFB4C2BEFFAFBDB9FFB0BEBAFFB0BEBAFFA4B2AEFFA3B1ADFFA4B2AEFF
+ ACBAB6FFB7C5C1FFBBC9C5FFB4C2BEFFABB9B5FFA8B6B2FFA7B6B2FFA9B8B4FF
+ ACBBB7FFACBBB7FFA7B6B2FFA2B1ADFF9FAEAAFF9CABA7FFB1C0BCFFB0BFBBFF
+ AFBEBAFFAEBDB9FFADBCB8FFACBBB7FFABBAB6FFABBAB6FFAABBB7FFA3B4B0FF
+ 9AABA7FF97A8A4FFA1B0ACFFACBBB7FFACBBB7FFA7B6B2FF95A39FFF93A19DFF
+ 96A19EFF99A4A1FF95A09DFF8D9895FF89928FFF89928FFF97A39DFF9DA9A3FF
+ 9FABA5FF9AA6A0FF95A19BFF939F99FF8F9B95FF8B9791FF9AA6A0FF99A59FFF
+ 96A29CFF919D97FF8C9892FF8C9892FF8F9B95FF929E98FF939C99FF8C9592FF
+ 87928FFF8B9693FF919C99FF949F9CFF95A39FFF99A7A3FF8D9C98FF8F9E9AFF
+ 82918DFFABBAB6FFCDDEDAFFD6E7E3FFCCDDD9FFC8DCD7FFD5E8E5FFD4E9E6FF
+ D3E8E5FFD0E5E2FFCDE2DFFFCDE2DFFFD1E6E3FFD6EBE8FFD4E9E6FFD4E9E6FF
+ D3E8E5FFD2E7E4FFCFE4E1FFCBE0DDFFC7DCD9FFC6D9D6FFD3E2DEFFD5E3DFFF
+ E1EFEBFF3F4D49FF4B5955FF798783FF7E8C88FF85938FFF889692FF7D8B87FF
+ 7D8B87FF8A9894FF93A19DFF92A09CFF919F9BFF95A39FFF9EADA9FF96A5A1FF
+ 92A19DFF96A5A1FF9AA9A5FF99A8A4FF97A6A2FF98A7A3FF91A09CFF98A7A3FF
+ A4B3AFFFAFBEBAFFB6C5C1FFB9C8C4FFB8C7C3FFB6C5C1FFCAD9D5FFC6D5D1FF
+ C0CFCBFFB6C5C1FFA5B4B0FF96A5A1FF93A29EFF98A7A3FF96A5A1FFB8C7C3FF
+ B7C6C2FFA4B3AFFFAEBDB9FFC0CFCBFFCCDBD7FFDAEBE7FFDCEFECFFD9EEEBFF
+ D5EAE7FFCFE6E2FFCFE8E4FFD6EFEBFFD6F1EDFFD3EEEAFFCAE3DFFFC5DEDAFF
+ CDE2DFFFCADDDAFFBACBC8FF768482FFA2AFADFFA0ADABFFA4B2AEFFA2B0ACFF
+ A4B2AEFFA8B6B2FFA8B6B2FFA3B1ADFFA2B0ACFFA4B2AEFFA5B3AFFFA2B0ACFF
+ A6B4B0FFA3B1ADFF9BA9A5FFA2B0ACFFABB9B5FFA5B3AFFF96A49EFFA1AFA9FF
+ 92A09AFF9BA9A3FFA8B6B0FFA2B0AAFFA7B5AFFFA4B2ACFF9CAAA4FF98A6A0FF
+ ACBAB4FFA4B2ACFF9AA8A2FFA9B7B1FFAEBCB6FFB5C3BDFFB3C2BEFFB9C8C4FF
+ BECDC9FFB8C7C3FFACBBB7FFA4B3AFFFA3B2AEFFA5B4B0FFA8B7B3FFA1B0ACFF
+ 99A8A4FF95A4A0FF96A5A1FF97A6A2FF96A5A1FF94A39FFF8F9F98FF879790FF
+ 707E78FF53615BFF7B8983FF7F8D87FF84908AFF838F89FF8B958FFF8F9993FF
+ 929C96FF919B95FF8F9691FF89908BFF868D88FF858C87FF88928CFF7F8983FF
+ 808A84FF7F8983FF727C76FF6C7670FF68726CFF5B655FFF68726CFF707A74FF
+ 7B857FFF848E88FF89938DFF8C9690FF8D9791FF8E9991FF929A93FF8E978DFF
+ 8A9389FF899288FF8B968CFF909B91FF949F95FF95A096FF9FADA2FFA3B1A6FF
+ A6B6ABFFAABAAFFFABBBB0FFA9B9AEFFA4B5AAFFA1B2A7FFABBBB0FF9BABA0FF
+ 97A79CFFA3B3A8FFA7B7ACFF9DADA2FF98A89DFF9EAEA3FFA3B3A8FFA1B1A6FF
+ A0B0A5FFA3B3A8FFA8B8ADFFAABAAFFFA7B7ACFFA3B4A9FFA6B9B0FFACC1B8FF
+ C9DED5FFCCE1D8FFCBE0D8FFCEE3DBFFC1D6CEFFC8DDD5FFBED2CDFFBBCFCAFF
+ BACDCAFFBBCECBFF838A85FF8D948FFF99A09BFFA0A7A2FF9FA9A3FF9DA7A1FF
+ 9CA6A0FF9CA6A0FF99A59FFFA7B3ADFFB0BEB8FFB0BEB8FFAEBCB6FFAEBCB6FF
+ ABBBB4FFA6B6AFFFB5C3BFFFAAB8B4FFACBAB6FFB0BEBAFFAFBDB9FFB4C2BEFF
+ B8C6C2FFAEBCB8FFA2B0ACFF9DABA7FFA0AEAAFFADBBB7FFB7C5C1FFB5C3BFFF
+ ADBBB7FFA7B5B1FFAEBDB9FFACBBB7FFB1C0BCFFB1C0BCFFA6B5B1FFA3B2AEFF
+ A4B3AFFF9FAEAAFFAFBEBAFFAFBEBAFFAFBEBAFFAEBDB9FFACBBB7FFAAB9B5FF
+ A9B8B4FFA8B7B3FFAABBB7FFA6B7B3FF9DAEAAFF97A8A4FF9EADA9FFA9B8B4FF
+ ABBAB6FFA6B5B1FF97A5A1FF92A09CFF929D9AFF949F9CFF919C99FF889390FF
+ 868F8CFF89928FFF909C96FF9BA7A1FFA0ACA6FF99A59FFF909C96FF8E9A94FF
+ 8E9A94FF8C9892FF96A29CFF95A19BFF95A19BFF939F99FF8F9B95FF8C9892FF
+ 8C9892FF8F9B95FF969F9CFF929B98FF8F9A97FF939E9BFF929D9AFF8E9996FF
+ 8F9D99FF97A5A1FF92A19DFF8A9995FF899894FF8D9C98FFC1D2CEFFD4E5E1FF
+ C9DAD6FFC9DDD8FFD4E7E4FFD2E7E4FFD0E5E2FFCDE2DFFFC9DEDBFFCADFDCFF
+ CEE3E0FFD2E7E4FFCEE3E0FFD0E5E2FFD2E7E4FFD2E7E4FFD0E5E2FFCADFDCFF
+ C4D9D6FFC2D5D2FFCDDCD8FFD7E5E1FFDCEAE6FF35433FFF384642FF8F9D99FF
+ 8D9B97FF8A9894FF8B9995FF899793FF889692FF899793FF8E9C98FF92A09CFF
+ 92A09CFF909E9AFF9FAEAAFF98A7A3FF94A39FFF96A5A1FF98A7A3FF98A7A3FF
+ 9BAAA6FFA0AFABFF9AA9A5FF9FAEAAFFA6B5B1FFADBCB8FFB0BFBBFFB1C0BCFF
+ AEBDB9FFACBBB7FFB6C4C0FFBAC8C4FFB9C7C3FFB1BFBBFFABB9B5FFAAB8B4FF
+ A9B7B3FFA6B4B0FF9BA9A5FFA5B3AFFFAAB8B4FFA7B5B1FFA2B0ACFFA8B6B2FF
+ BECCC8FFD5E4E0FFD4E5E2FFD4E9E6FFD4E9E6FFCEE5E1FFCCE5E1FFD2EBE7FF
+ D6F1EDFFD7F2EEFFD4EDE9FFC8E1DDFFD0E5E2FFC9DCD9FFC0D1CEFF778583FF
+ A5B2B0FFA1AEACFFA2B0ACFFA1AFABFFA4B2AEFFA9B7B3FFAAB8B4FFA6B4B0FF
+ A5B3AFFFA7B5B1FFA3B1ADFFA2B0ACFFA8B6B2FFA5B3AFFF9BA9A5FFA1AFABFF
+ A8B6B2FFA1AFABFF96A49EFFA0AEA8FF8E9C96FF94A29CFFA2B0AAFF9EACA6FF
+ A3B1ABFF9FADA7FFA0AEA8FF99A7A1FFB0BEB8FFA4B2ACFF9AA8A2FFADBBB5FF
+ ACBAB4FFB3C1BBFFB2C1BDFFB1C0BCFFB7C6C2FFBDCCC8FFB4C3BFFFA3B2AEFF
+ 9EADA9FFA6B5B1FFA3B2AEFF9DACA8FF96A5A1FF94A39FFF97A6A2FF98A7A3FF
+ 96A5A1FF92A19DFF8B9B94FF8B9B94FF788680FF5A6862FF7E8C86FF808E88FF
+ 85918BFF84908AFF8D9791FF8F9993FF919B95FF909A94FF8E9590FF89908BFF
+ 868D88FF848B86FF86908AFF7C8680FF7B857FFF7A847EFF707A74FF6F7973FF
+ 6F7973FF646E68FF67716BFF6F7973FF7A847EFF838D87FF87918BFF89938DFF
+ 89938DFF8A958DFF919992FF8B948AFF889187FF8C958BFF939E94FF99A49AFF
+ 98A399FF95A096FFA1AFA4FFA3B1A6FFA3B3A8FFA6B6ABFFA8B8ADFFA8B8ADFF
+ A7B8ADFFA6B7ACFFA5B5AAFF9DADA2FF99A99EFFA0B0A5FFA7B7ACFFA7B7ACFF
+ A0B0A5FF9AAA9FFFACBCB1FFA6B6ABFFA2B2A7FFA2B2A7FFA6B6ABFFA7B7ACFF
+ A4B4A9FF9FB0A5FF9CAFA6FFA3B8AFFFC2D7CEFFC7DCD3FFC9DED6FFCCE1D9FF
+ BFD4CCFFC5DAD2FFC3D7D2FFC0D4CFFFBBCECBFFB8CBC8FF7C837EFF888F8AFF
+ 969D98FF9EA5A0FF9DA7A1FF9DA7A1FFA1ABA5FFA5AFA9FFA4B0AAFFB6C2BCFF
+ B7C5BFFFA9B7B1FFACBAB4FFBDCBC5FFBDCDC6FFADBDB6FFC0CECAFFB2C0BCFF
+ B0BEBAFFB0BEBAFFACBAB6FFAFBDB9FFB1BFBBFFA7B5B1FFABB9B5FFA1AFABFF
+ 9EACA8FFA9B7B3FFB5C3BFFFB6C4C0FFAEBCB8FFA8B6B2FFAEBDB9FFAAB9B5FF
+ B2C1BDFFB3C2BEFFA7B6B2FFA6B5B1FFABBAB6FFA5B4B0FFA5B4B0FFA6B5B1FF
+ A7B6B2FFA7B6B2FFA6B5B1FFA5B4B0FFA4B3AFFFA5B4B0FFA9BAB6FFA8B9B5FF
+ A2B3AFFF9BACA8FFA1B0ACFFABBAB6FFAEBDB9FFA8B7B3FFA3B1ADFF9BA9A5FF
+ 98A3A0FF99A4A1FF95A09DFF8D9895FF8E9794FF939C99FF84908AFF939F99FF
+ 9CA8A2FF95A19BFF8C9892FF8C9892FF8E9A94FF8E9A94FF919D97FF929E98FF
+ 94A09AFF94A09AFF8F9B95FF88948EFF84908AFF85918BFF929B98FF939C99FF
+ 96A19EFF99A4A1FF929D9AFF899491FF8B9995FF97A5A1FF9EADA9FF8B9A96FF
+ 8D9C98FF74837FFFB3C4C0FFD2E3DFFFCDDEDAFFD7EBE6FFD1E4E1FFCCE1DEFF
+ C8DDDAFFC6DBD8FFC5DAD7FFC7DCD9FFCADFDCFFCBE0DDFFC7DCD9FFCADFDCFF
+ CEE3E0FFD0E5E2FFCDE2DFFFC7DCD9FFC0D5D2FFBDD0CDFFB5C4C0FFC9D7D3FF
+ C9D7D3FF212F2BFF263430FFA4B2AEFFA2B0ACFF93A19DFF899793FF8D9B97FF
+ 8A9894FF83918DFF84928EFF8C9A96FF8C9A96FF85938FFF92A19DFF92A19DFF
+ 95A4A0FF9AA9A5FF99A8A4FF97A6A2FF9CABA7FFA3B2AEFF9BAAA6FF9FAEAAFF
+ A5B4B0FFA9B8B4FFABBAB6FFA9B8B4FFA6B5B1FFA3B2AEFFAFBAB7FFB7C2BFFF
+ B6C1BEFFABB6B3FFA8B3B0FFACB7B4FFA9B4B1FFA0ABA8FFA7B2AFFF9AA5A2FF
+ A4AFACFFB0BBB8FFA0ABA8FF98A3A0FFB4BFBCFFD3E1DDFFC9DAD7FFCDE2DFFF
+ D1E6E3FFCCE3DFFFC8E1DDFFCCE5E1FFD0EBE7FFD2EDE9FFCEE7E3FFBFD8D4FF
+ C6DBD8FFC0D3D0FFBBCCC9FF72807EFFA2AFADFF9EABA9FF9CAAA6FF9AA8A4FF
+ 9EACA8FFA4B2AEFFA6B4B0FFA2B0ACFFA1AFABFFA4B2AEFF9FADA9FF9FADA9FF
+ A6B4B0FFA3B1ADFF99A7A3FF9DABA7FFA3B1ADFF9CAAA6FF9FADA7FFA9B7B1FF
+ 95A39DFF98A6A0FFA5B3ADFFA2B0AAFFA7B5AFFFA2B0AAFFA3B1ABFF9AA8A2FF
+ B2C0BAFFA3B1ABFF9AA8A2FFB0BEB8FFABB9B3FFB1BFB9FFB1C0BCFFABBAB6FF
+ B2C1BDFFC0CFCBFFB9C8C4FFA3B2AEFF9CABA7FFA6B5B1FFA4B3AFFF9EADA9FF
+ 98A7A3FF96A5A1FF98A7A3FF97A6A2FF91A09CFF8B9A96FF889891FF8C9C95FF
+ 7E8C86FF606E68FF818F89FF818F89FF85918BFF838F89FF8E9892FF8F9993FF
+ 8F9993FF8E9892FF8D948FFF89908BFF878E89FF868D88FF838D87FF78827CFF
+ 77817BFF78827CFF707A74FF727C76FF747E78FF6A746EFF636D67FF6A746EFF
+ 747E78FF7C8680FF808A84FF828C86FF848E88FF859088FF8F9790FF8A9389FF
+ 889187FF919A90FF9CA79DFFA2ADA3FF9DA89EFF96A197FFA7B5AAFFA3B1A6FF
+ 9BABA0FF99A99EFF9BABA0FFA3B3A8FFABBCB1FFB1C2B7FF95A59AFFA4B4A9FF
+ A9B9AEFFA0B0A5FF9EAEA3FFA5B5AAFFA8B8ADFFA2B2A7FFB0C0B5FFA9B9AEFF
+ A2B2A7FFA0B0A5FFA2B2A7FFA2B2A7FF9EAEA3FF99AA9FFF91A49BFF99AEA5FF
+ BACFC6FFC2D7CEFFC6DBD3FFC9DED6FFBCD1C9FFC1D6CEFFC4D8D3FFC1D5D0FF
+ BACDCAFFB4C7C4FF8D948FFF959C97FF949B96FF979E99FFA4AEA8FFA9B3ADFF
+ ABB5AFFFB6C0BAFFAFBBB5FFB0BCB6FFB5C3BDFFBFCDC7FFC5D3CDFFC1CFC9FF
+ B8C8C1FFB3C3BCFFBBC9C5FFBECCC8FFB7C5C1FFAAB8B4FFA8B6B2FFAFBDB9FF
+ A9B7B3FF9BA9A5FFABB9B5FF94A29EFF96A4A0FFB3C1BDFFBAC8C4FFA4B2AEFF
+ 9BA9A5FFA8B6B2FFADBCB8FFABBAB6FFA8B7B3FFA5B4B0FFA4B3AFFFA5B4B0FF
+ A9B8B4FFACBBB7FF9CABA7FFA7B6B2FFB0BFBBFFAFBEBAFFA9B8B4FFA6B5B1FF
+ A8B7B3FFAAB9B5FFA8B9B5FFAFC0BCFFACBDB9FFA1B2AEFFA3B2AEFFAEBDB9FF
+ B0BFBBFFA9B8B4FFA4B2AEFF9EACA8FF98A3A0FF939E9BFF99A4A1FF9EA9A6FF
+ 9BA4A1FF919A97FF8C9892FF909C96FF96A29CFF98A49EFF929E98FF8C9892FF
+ 919D97FF9AA6A0FF909C96FF8F9B95FF8E9A94FF8C9892FF8A9690FF88948EFF
+ 87938DFF86928CFF8F9895FF8F9895FF8D9895FF8C9794FF8D9895FF8F9A97FF
+ 909E9AFF92A09CFFA8B7B3FFA4B3AFFFA0AFABFF899894FF9AABA7FFCDDEDAFF
+ D6E7E3FFD2E6E1FFD2E5E2FFD0E5E2FFD1E6E3FFD0E5E2FFCEE3E0FFCBE0DDFF
+ C8DDDAFFC6DBD8FFCBE0DDFFCADFDCFFCBE0DDFFCCE1DEFFCDE2DFFFC9DEDBFF
+ C1D6D3FFBDD0CDFFBDCCC8FFC4D2CEFFAAB8B4FF12201CFF2B3935FF818F8BFF
+ 8F9D99FF8B9995FF818F8BFF84928EFF889692FF8B9995FF8D9B97FF8D9B97FF
+ 8C9A96FF8B9995FF8C9B97FF8F9E9AFF93A29EFF96A5A1FF97A6A2FF98A7A3FF
+ 99A8A4FF9AA9A5FF9FAEAAFFA3B2AEFFA7B6B2FFA8B7B3FFA7B6B2FFA6B5B1FF
+ A7B6B2FFA9B8B4FFA3AEABFFA8B3B0FFADB8B5FFAEB9B6FFABB6B3FFA6B1AEFF
+ A5B0ADFFA5B0ADFF9DA8A5FFA1ACA9FFA3AEABFFA7B2AFFFA4AFACFF9AA5A2FF
+ ACB7B4FFD3E1DDFFD6E7E4FFD4E9E6FFD6EBE8FFD4EBE7FFD0E9E5FFD0E9E5FF
+ CFEAE6FFD1ECE8FFD4EDE9FFC4DDD9FFBED3D0FFC3D6D3FFBECFCCFF7A8886FF
+ 859290FFA0ADABFF9FADA9FFA1AFABFFA3B1ADFFA3B1ADFFA2B0ACFFA3B1ADFF
+ A6B4B0FFA8B6B2FFAAB8B4FFA3B1ADFFA0AEAAFFA2B0ACFFA0AEAAFF9AA8A4FF
+ 95A39FFF95A39FFFA5B3ADFFA1AFA9FF9FADA7FFA0AEA8FFA0AEA8FFA0AEA8FF
+ A3B1ABFFA7B5AFFFABB9B3FFAEBCB6FFACBAB4FFA5B3ADFFA3B1ABFFA7B5AFFF
+ ABB9B3FFABB9B3FFAFBEBAFFAFBEBAFFB5C4C0FFBCCBC7FFB8C7C3FFACBBB7FF
+ A6B5B1FFA8B7B3FFA0AFABFF9EADA9FF9BAAA6FF99A8A4FF96A5A1FF92A19DFF
+ 8D9C98FF889793FF889891FF899992FF8A9892FF44524CFF74827CFF7F8D87FF
+ 8B9791FF828E88FF848E88FF8D9791FF8F9993FF89938DFF89908BFF8F9691FF
+ 929994FF909792FF87918BFF818B85FF79837DFF757F79FF747E78FF727C76FF
+ 6F7973FF6B756FFF6C7670FF6C7670FF727C76FF79837DFF79837DFF76807AFF
+ 7D8781FF89948CFF878F88FF8C958BFF929B91FF949D93FF929D93FF949F95FF
+ 9AA59BFFA0ABA1FF96A499FF97A59AFF9EAEA3FF9DADA2FF97A79CFFA3B3A8FF
+ B2C3B8FFB1C2B7FFAABAAFFFA9B9AEFFA2B2A7FF9EAEA3FFA4B4A9FFACBCB1FF
+ A7B7ACFF9AAA9FFF9AAA9FFFA0B0A5FFA4B4A9FFA1B1A6FF9AAA9FFF98A89DFF
+ 9EAEA3FFA4B5AAFF99ACA3FF9FB4ABFFB4C9C0FFCADFD6FFD1E6DEFFC8DDD5FF
+ C0D5CDFFC0D5CDFFBDD1CCFFBBCFCAFFB8CBC8FFB8CBC8FF939A95FF9BA29DFF
+ 979E99FF969D98FF9FA9A3FFA5AFA9FFACB6B0FFBBC5BFFFAAB6B0FFA9B5AFFF
+ AAB8B2FFB3C1BBFFBBC9C3FFBAC8C2FFB3C3BCFFADBDB6FFB6C4C0FFC1CFCBFF
+ C4D2CEFFBBC9C5FFB5C3BFFFB6C4C0FFAEBCB8FFA1AFABFFA3B1ADFF98A6A2FF
+ 9AA8A4FFABB9B5FFB3C1BDFFAAB8B4FFA3B1ADFFA5B3AFFFA6B5B1FFA8B7B3FF
+ A9B8B4FFA4B3AFFF9EADA9FF9FAEAAFFA6B5B1FFAEBDB9FF9BAAA6FF9FAEAAFF
+ A3B2AEFFA4B3AFFFA5B4B0FFA6B5B1FFA8B7B3FFA8B7B3FFA7B8B4FFAEBFBBFF
+ ADBEBAFFA3B4B0FFA5B4B0FFAEBDB9FFB0BFBBFFA9B8B4FFA8B6B2FFA2B0ACFF
+ 99A4A1FF929D9AFF95A09DFF9CA7A4FF9EA7A4FF99A29FFF96A29CFF96A29CFF
+ 9AA6A0FF9CA8A2FF98A49EFF939F99FF95A19BFF9CA8A2FF919D97FF909C96FF
+ 8F9B95FF8D9993FF8B9791FF89958FFF88948EFF87938DFF8E9794FF8B9491FF
+ 87928FFF889390FF8D9895FF909B98FF8D9B97FF8B9995FF92A19DFFA2B1ADFF
+ B8C7C3FFA9B8B4FFABBCB8FFCBDCD8FFD2E3DFFFD7EBE6FFD4E7E4FFD1E6E3FF
+ CFE4E1FFCDE2DFFFCADFDCFFC6DBD8FFC3D8D5FFC1D6D3FFC5DAD7FFC4D9D6FF
+ C4D9D6FFC6DBD8FFC8DDDAFFC6DBD8FFC1D6D3FFBED1CEFFB5C4C0FFC4D2CEFF
+ 8D9B97FF0A1814FF2A3834FF72807CFF83918DFF808E8AFF808E8AFF818F8BFF
+ 85938FFF889692FF8B9995FF8E9C98FF8F9D99FF909E9AFF8A9995FF8D9C98FF
+ 909F9BFF93A29EFF95A4A0FF96A5A1FF97A6A2FF97A6A2FF99A8A4FF9DACA8FF
+ A2B1ADFFA6B5B1FFAAB9B5FFACBBB7FFAFBEBAFFB0BFBBFFAAB5B2FFAAB5B2FF
+ A9B4B1FFA4AFACFF9FAAA7FF9EA9A6FF9FAAA7FFA2ADAAFFA6B1AEFFA8B3B0FF
+ A7B2AFFFA8B3B0FFA5B0ADFF99A4A1FFA5B0ADFFC7D5D1FFD4E5E2FFD1E6E3FF
+ D3E8E5FFD1E8E4FFCDE6E2FFCDE6E2FFCCE7E3FFCEE9E5FFCFE8E4FFC6DFDBFF
+ C2D7D4FFC4D7D4FFBECFCCFF7C8A88FF84918FFF98A5A3FF9AA8A4FF9EACA8FF
+ A3B1ADFFA5B3AFFFA4B2AEFFA2B0ACFFA2B0ACFFA2B0ACFFA5B3AFFF9FADA9FF
+ 9CAAA6FF9EACA8FF9DABA7FF98A6A2FF94A29EFF94A29EFFA6B4AEFFA3B1ABFF
+ A1AFA9FFA1AFA9FFA1AFA9FFA2B0AAFFA5B3ADFFA8B6B0FFA5B3ADFFA9B7B1FF
+ A8B6B0FFA3B1ABFFA2B0AAFFA8B6B0FFADBBB5FFAEBCB6FFB2C1BDFFB2C1BDFF
+ B7C6C2FFBDCCC8FFB8C7C3FFACBBB7FFA6B5B1FFA7B6B2FFA4B3AFFFA0AFABFF
+ 9AA9A5FF96A5A1FF94A39FFF91A09CFF8D9C98FF8A9995FF83938CFF889891FF
+ 83918BFF45534DFF6B7973FF7E8C86FF86928CFF838F89FF88928CFF909A94FF
+ 939D97FF8D9791FF8C938EFF8E9590FF8D948FFF89908BFF87918BFF818B85FF
+ 7A847EFF78827CFF79837DFF76807AFF6F7973FF68726CFF76807AFF717B75FF
+ 6F7973FF6F7973FF6D7771FF6F7973FF7B857FFF8A958DFF8C948DFF8C958BFF
+ 8C958BFF8D968CFF8F9A90FF96A197FF9EA99FFFA3AEA4FF9DABA0FF9BA99EFF
+ A0B0A5FFA0B0A5FF99A99EFFA3B3A8FFACBDB2FFA6B7ACFFADBDB2FFAEBEB3FF
+ A8B8ADFF9CACA1FF9AAA9FFFA3B3A8FFACBCB1FFAEBEB3FF9EAEA3FFA2B2A7FF
+ A4B4A9FFA2B2A7FF9DADA2FF9BABA0FF9DADA2FFA0B1A6FF9DB0A7FFA2B7AEFF
+ B3C8BFFFC6DBD2FFCCE1D9FFC5DAD2FFC1D6CEFFC2D7CFFFBBCFCAFFB7CBC6FF
+ B1C4C1FFADC0BDFF919893FF9CA39EFF9BA29DFF99A09BFF9EA8A2FFA2ACA6FF
+ A8B2ACFFB9C3BDFFAAB6B0FFA7B3ADFFA5B3ADFFACBAB4FFB6C4BEFFB9C7C1FF
+ B1C1BAFFA9B9B2FFB0BEBAFFBECCC8FFC5D3CFFFBFCDC9FFB9C7C3FFBAC8C4FF
+ B8C6C2FFB2C0BCFFACBAB6FFAAB8B4FFAAB8B4FFB0BEBAFFB9C7C3FFBDCBC7FF
+ B8C6C2FFB1BFBBFFA3B2AEFFA9B8B4FFABBAB6FFA5B4B0FF9BAAA6FF99A8A4FF
+ A0AFABFFAAB9B5FFA1B0ACFF9EADA9FF9CABA7FF9EADA9FFA3B2AEFFA6B5B1FF
+ A6B5B1FFA4B3AFFFA6B7B3FFADBEBAFFADBEBAFFA6B7B3FFA8B7B3FFAFBEBAFF
+ AFBEBAFFA9B8B4FFABB9B5FFA5B3AFFF9CA7A4FF919C99FF929D9AFF9BA6A3FF
+ A3ACA9FFA3ACA9FF9CA8A2FF98A49EFF97A39DFF9AA6A0FF99A59FFF94A09AFF
+ 939F99FF97A39DFF919D97FF919D97FF8F9B95FF8D9993FF8B9791FF8A9690FF
+ 88948EFF88948EFF8C9592FF87908DFF828D8AFF85908DFF8D9895FF8F9A97FF
+ 899793FF83918DFF83928EFF92A19DFFB0BFBBFFAEBDB9FFB3C4C0FFC8D9D5FF
+ C8D9D5FFCFE3DEFFD0E3E0FFCDE2DFFFCBE0DDFFC8DDDAFFC5DAD7FFC4D9D6FF
+ C3D8D5FFC2D7D4FFBFD4D1FFBFD4D1FFBFD4D1FFC0D5D2FFC2D7D4FFC2D7D4FF
+ C0D5D2FFC0D3D0FFB2C1BDFFC9D7D3FF64726EFF071511FF34423EFF677571FF
+ 7B8985FF778581FF808E8AFF82908CFF84928EFF879591FF8A9894FF8D9B97FF
+ 8F9D99FF919F9BFF8F9E9AFF909F9BFF92A19DFF95A4A0FF98A7A3FF9AA9A5FF
+ 9AA9A5FF9AA9A5FF9FAEAAFF9FAEAAFFA1B0ACFFA4B3AFFFA7B6B2FFA9B8B4FF
+ A9B8B4FFA8B7B3FFAFBAB7FFAFBAB7FFAEB9B6FFABB6B3FFA7B2AFFFA4AFACFF
+ A4AFACFFA5B0ADFFABB6B3FFABB6B3FFA7B2AFFFA9B4B1FFA9B4B1FF9DA8A5FF
+ A3AEABFFBCCAC6FFD0E1DEFFCEE3E0FFCFE4E1FFCDE4E0FFC9E2DEFFC8E1DDFF
+ C8E3DFFFCAE5E1FFC9E2DEFFC9E2DEFFC8DDDAFFC4D7D4FFBCCDCAFF7E8C8AFF
+ 84918FFF919E9CFF99A7A3FF9FADA9FFA6B4B0FFA9B7B3FFA8B6B2FFA5B3AFFF
+ A2B0ACFFA1AFABFFA8B6B2FFA2B0ACFF9FADA9FFA2B0ACFFA2B0ACFF9DABA7FF
+ 9AA8A4FF9BA9A5FFA0AEA8FF9FADA7FF9DABA5FF9BA9A3FF9BA9A3FF9EACA6FF
+ A1AFA9FFA2B0AAFF9EACA6FFA3B1ABFFA4B2ACFFA1AFA9FFA1AFA9FFA9B7B1FF
+ AFBDB7FFB0BEB8FFB4C3BFFFB5C4C0FFB9C8C4FFBCCBC7FFB6C5C1FFACBBB7FF
+ A6B5B1FFA7B6B2FFA8B7B3FFA3B2AEFF9BAAA6FF95A4A0FF92A19DFF909F9BFF
+ 8E9D99FF8C9B97FF809089FF899992FF7C8A84FF4B5953FF62706AFF808E88FF
+ 818D87FF88948EFF858F89FF8C9690FF909A94FF8D9791FF8D948FFF8C938EFF
+ 89908BFF858C87FF858F89FF7E8882FF78827CFF78827CFF7A847EFF77817BFF
+ 6C7670FF626C66FF77817BFF737D77FF707A74FF6F7973FF6E7872FF727C76FF
+ 7F8983FF8C978FFF8B938CFF848D83FF7E877DFF80897FFF889389FF949F95FF
+ 9CA79DFF9FAAA0FFA0AEA3FF9CAA9FFF9FAFA4FFA0B0A5FF9BABA0FFA2B2A7FF
+ A5B6ABFF99AA9FFFA4B4A9FFADBDB2FFAEBEB3FFA1B1A6FF95A59AFF98A89DFF
+ A8B8ADFFB4C4B9FFA5B5AAFFA6B6ABFFA6B6ABFFA6B6ABFFA5B5AAFFA2B2A7FF
+ A0B0A5FF9EAFA4FFA2B5ACFFA6BBB2FFB4C9C0FFC1D6CDFFC5DAD2FFC2D7CFFF
+ C0D5CDFFC3D8D0FFBCD0CBFFB5C9C4FFADC0BDFFA7BAB7FF848B86FF949B96FF
+ 9AA19CFF9AA19CFF9EA8A2FF9EA8A2FFA2ACA6FFB1BBB5FFB3BFB9FFB1BDB7FF
+ ADBBB5FFB2C0BAFFBBC9C3FFBFCDC7FFB5C5BEFFA9B9B2FFADBBB7FFB3C1BDFF
+ B5C3BFFFB0BEBAFFB0BEBAFFB8C6C2FFBDCBC7FFBDCBC7FFAAB8B4FFA4B2AEFF
+ A2B0ACFFA9B7B3FFB0BEBAFFB2C0BCFFAEBCB8FFAAB8B4FFA7B6B2FFABBAB6FF
+ ADBCB8FFA9B8B4FFA1B0ACFF9CABA7FF9DACA8FFA1B0ACFFA8B7B3FFA4B3AFFF
+ A2B1ADFFA5B4B0FFA6B5B1FFA4B3AFFFA2B1ADFFA2B1ADFFA5B6B2FFABBCB8FF
+ ACBDB9FFA8B9B5FFABBAB6FFAFBEBAFFAEBDB9FFA9B8B4FFA8B6B2FFA5B3AFFF
+ 9EA9A6FF949F9CFF949F9CFF9EA9A6FFA8B1AEFFABB4B1FFA2AEA8FF9BA7A1FF
+ 96A29CFF99A59FFF99A59FFF95A19BFF929E98FF929E98FF909C96FF909C96FF
+ 8E9A94FF8C9892FF8B9791FF89958FFF87938DFF87938DFF87908DFF858E8BFF
+ 838E8BFF86918EFF8A9592FF8B9693FF85938FFF818F8BFF8A9995FF808F8BFF
+ 8C9B97FF95A4A0FFAEBFBBFFCCDDD9FFC7D8D4FFC7DBD6FFCADDDAFFC7DCD9FF
+ C5DAD7FFC4D9D6FFC4D9D6FFC6DBD8FFC7DCD9FFC9DEDBFFC1D6D3FFC0D5D2FF
+ BFD4D1FFBED3D0FFBFD4D1FFBFD4D1FFC0D5D2FFC2D5D2FFB8C7C3FFCDDBD7FF
+ 3E4C48FF111F1BFF4D5B57FF6E7C78FF7E8C88FF768480FF808E8AFF82908CFF
+ 85938FFF899793FF8B9995FF8C9A96FF8D9B97FF8D9B97FF8E9D99FF8E9D99FF
+ 8F9E9AFF92A19DFF96A5A1FF99A8A4FF99A8A4FF98A7A3FF9FAEAAFF9EADA9FF
+ 9DACA8FFA0AFABFFA3B2AEFFA4B3AFFFA3B2AEFFA1B0ACFFA6B4B0FFABB9B5FF
+ B3BEBBFFB4C2BEFFB5C0BDFFAEBCB8FFAAB5B2FFA4B2AEFFA8B3B0FFA6B4B0FF
+ A3AEABFFA5B3AFFFACB7B4FFA2B0ACFFA6B1AEFFB9C7C3FFCEDFDCFFCBE0DDFF
+ CDE2DFFFCBE2DEFFC6DFDBFFC5DEDAFFC4DFDBFFC6E1DDFFC5DEDAFFCAE3DFFF
+ CADFDCFFC2D5D2FFBACBC8FF82908EFF899694FF93A09EFF98A6A2FF9DABA7FF
+ A3B1ADFFA6B4B0FFA5B3AFFFA2B0ACFF9FADA9FF9EACA8FFA9B7B3FFA3B1ADFF
+ A0AEAAFFA3B1ADFFA4B2AEFFA1AFABFF9FADA9FFA1AFABFF9DABA5FF9EACA6FF
+ 9CAAA4FF98A6A0FF99A7A1FF9DABA5FFA0AEA8FFA0AEA8FF9DABA5FFA2B0AAFF
+ A4B2ACFFA1AFA9FFA2B0AAFFA9B7B1FFAEBCB6FFAFBDB7FFB0BFBBFFB3C2BEFF
+ B6C5C1FFB7C6C2FFB3C2BEFFACBBB7FFA8B7B3FFA8B7B3FFA8B7B3FFA4B3AFFF
+ 9EADA9FF99A8A4FF95A4A0FF91A09CFF8D9C98FF899894FF7F8F88FF8A9A93FF
+ 788680FF505E58FF5E6C66FF82908AFF7F8B85FF8D9993FF818B85FF848E88FF
+ 87918BFF87918BFF89908BFF89908BFF888F8AFF878E89FF838D87FF7A847EFF
+ 737D77FF727C76FF76807AFF737D77FF69736DFF5E6862FF66706AFF69736DFF
+ 6D7771FF727C76FF76807AFF7B857FFF838D87FF8B968EFF8B938CFF828B81FF
+ 7A8379FF7D867CFF89948AFF97A298FF9EA99FFF9EA99FFF9FADA2FF9AA89DFF
+ 9CACA1FF9FAFA4FF9EAEA3FFA5B5AAFFA4B5AAFF94A59AFF95A59AFFA4B4A9FF
+ AFBFB4FFA9B9AEFF9AAA9FFF93A398FF9AAA9FFFA4B4A9FFA1B1A6FFA0B0A5FF
+ A0B0A5FFA2B2A7FFA5B5AAFFA3B3A8FF9EAEA3FF98A99EFFA1B4ABFFA9BEB5FF
+ B6CBC2FFC0D5CCFFC2D7CFFFC0D5CDFFBED3CBFFBFD4CCFFBDD1CCFFB8CCC7FF
+ B0C3C0FFABBEBBFF7E8580FF8D948FFF909792FF8F9691FF949E98FF97A19BFF
+ 9FA9A3FFB1BBB5FFBAC6C0FFBBC7C1FFB9C7C1FFBAC8C2FFC0CEC8FFC3D1CBFF
+ B8C8C1FFAABAB3FFADBBB7FFACBAB6FFA9B7B3FFA9B7B3FFAEBCB8FFB5C3BFFF
+ B8C6C2FFB6C4C0FFB5C3BFFFA3B1ADFF9FADA9FFADBBB7FFB3C1BDFFA9B7B3FF
+ A4B2AEFFAAB8B4FFA8B7B3FFA9B8B4FFAAB9B5FFACBBB7FFABBAB6FFA8B7B3FF
+ A3B2AEFF9FAEAAFFA4B3AFFFA4B3AFFFA8B7B3FFADBCB8FFAAB9B5FFA2B1ADFF
+ A0AFABFFA4B3AFFFA5B6B2FFA8B9B5FFA9BAB6FFA8B9B5FFABBAB6FFADBCB8FF
+ ADBCB8FFAAB9B5FFA3B1ADFFA3B1ADFF9FAAA7FF99A4A1FF9AA5A2FFA3AEABFF
+ ACB5B2FFADB6B3FFAAB6B0FFA1ADA7FF9BA7A1FF9CA8A2FF9DA9A3FF99A59FFF
+ 95A19BFF95A19BFF8F9B95FF8F9B95FF8D9993FF8B9791FF89958FFF88948EFF
+ 86928CFF86928CFF828B88FF87908DFF899491FF899491FF86918EFF848F8CFF
+ 83918DFF85938FFF8F9E9AFF7B8A86FF7D8C88FF859490FFA7B8B4FFCEDFDBFF
+ CCDDD9FFCBDFDAFFCADDDAFFC7DCD9FFC6DBD8FFC5DAD7FFC5DAD7FFC7DCD9FF
+ C9DEDBFFCADFDCFFC6DBD8FFC5DAD7FFC3D8D5FFC1D6D3FFBFD4D1FFBED3D0FF
+ BFD4D1FFC2D5D2FFC0CFCBFFCAD8D4FF22302CFF283632FF677571FF7D8B87FF
+ 83918DFF798783FF798783FF7D8B87FF84928EFF8A9894FF8E9C98FF8F9D99FF
+ 8E9C98FF8D9B97FF879692FF869591FF859490FF889793FF8D9C98FF91A09CFF
+ 91A09CFF909F9BFF96A5A1FF97A6A2FF99A8A4FF9EADA9FFA3B2AEFFA8B7B3FF
+ ABBAB6FFACBBB7FFA2B1ADFFA5B4B0FFAAB8B4FFACBBB7FFADBBB7FFA8B7B3FF
+ A3B1ADFF9EADA9FFA4B2AEFFA3B2AEFF9FADA9FFA1B0ACFFAAB8B4FFA4B3AFFF
+ A6B4B0FFB5C4C0FFCCDDDAFFCADFDCFFCBE0DDFFC8DFDBFFC4DDD9FFC2DBD7FF
+ C1DCD8FFC3DEDAFFC4DDD9FFC9E2DEFFC9DEDBFFC0D3D0FFB9CAC7FF83918FFF
+ 8F9C9AFF9CA9A7FF97A5A1FF9AA8A4FF9EACA8FF9FADA9FF9EACA8FF9CAAA6FF
+ 9BA9A5FF9CAAA6FFA5B3AFFF9EACA8FF9CAAA6FF9FADA9FFA0AEAAFF9EACA8FF
+ 9DABA7FF9FADA9FFA2B0AAFFA5B3ADFFA3B1ABFF9DABA5FF9DABA5FFA4B2ACFF
+ A7B5AFFFA4B2ACFFA0AEA8FFA5B3ADFFA6B4AEFFA3B1ABFFA3B1ABFFA8B6B0FF
+ ACBAB4FFACBAB4FFAAB9B5FFAEBDB9FFB2C1BDFFB1C0BCFFAFBEBAFFADBCB8FF
+ ABBAB6FFAAB9B5FFA5B4B0FFA3B2AEFFA0AFABFF9EADA9FF9AA9A5FF94A39FFF
+ 8C9B97FF869591FF7E8E87FF879790FF74827CFF4F5D57FF5E6C66FF808E88FF
+ 7C8882FF8A9690FF88928CFF858F89FF838D87FF838D87FF868D88FF878E89FF
+ 888F8AFF8A918CFF848E88FF7B857FFF727C76FF707A74FF737D77FF727C76FF
+ 6C7670FF656F69FF606A64FF656F69FF6B756FFF707A74FF76807AFF7F8983FF
+ 86908AFF89948CFF919992FF8A9389FF858E84FF8A9389FF95A096FFA0ABA1FF
+ A4AFA5FFA4AFA5FFA0AEA3FF99A79CFF9BABA0FFA1B1A6FFA2B2A7FFACBCB1FF
+ ACBDB2FF9CADA2FF95A59AFF9FAFA4FFAABAAFFFAABAAFFF9FAFA4FF94A499FF
+ 93A398FF97A79CFF98A89DFF96A69BFF96A69BFF9AAA9FFF9FAFA4FF9FAFA4FF
+ 9AAA9FFF94A59AFF9CAFA6FFA9BEB5FFBACFC6FFC2D7CEFFC3D8D0FFBFD4CCFF
+ BCD1C9FFB9CEC6FFBBCFCAFFB8CCC7FFB4C7C4FFB2C5C2FF838A85FF8B928DFF
+ 858C87FF808782FF87918BFF919B95FF9FA9A3FFB5BFB9FFB9C5BFFFBECAC4FF
+ BBC9C3FFB7C5BFFFBAC8C2FFBFCDC7FFB7C7C0FFABBBB4FFAEBCB8FFACBAB6FF
+ ACBAB6FFB0BEBAFFB4C2BEFFB4C2BEFFAEBCB8FFA8B6B2FFC2D0CCFFAEBCB8FF
+ A9B7B3FFB8C6C2FFBCCAC6FFADBBB7FFA7B5B1FFAEBCB8FFA6B5B1FFA4B3AFFF
+ A4B3AFFFA9B8B4FFAEBDB9FFB0BFBBFFABBAB6FFA6B5B1FF9DACA8FF9CABA7FF
+ A3B2AEFFADBCB8FFACBBB7FFA3B2AEFFA2B1ADFFA9B8B4FFA5B6B2FFA5B6B2FF
+ A6B7B3FFA6B7B3FFA9B8B4FFAAB9B5FFABBAB6FFABBAB6FFA4B2AEFFA3B1ADFF
+ A0ABA8FF9BA6A3FF9FAAA7FFA7B2AFFFACB5B2FFA9B2AFFFA8B4AEFF9FABA5FF
+ 99A59FFF9AA6A0FF99A59FFF95A19BFF929E98FF939F99FF909C96FF8F9B95FF
+ 8E9A94FF8C9892FF8A9690FF88948EFF87938DFF86928CFF818A87FF88918EFF
+ 8B9693FF899491FF838E8BFF808B88FF82908CFF879591FF7F8E8AFF7B8A86FF
+ 869591FF84938FFF99AAA6FFC0D1CDFFC8D9D5FFCEE2DDFFCFE2DFFFCBE0DDFF
+ C9DEDBFFC7DCD9FFC6DBD8FFC5DAD7FFC4D9D6FFC4D9D6FFC9DEDBFFC9DEDBFF
+ C7DCD9FFC4D9D6FFC0D5D2FFBDD2CFFFBDD2CFFFC1D4D1FFC0CFCBFFBCCAC6FF
+ 182622FF475551FF778581FF869490FF82908CFF7C8A86FF75837FFF798783FF
+ 808E8AFF889692FF8E9C98FF919F9BFF92A09CFF92A09CFF899894FF869591FF
+ 84938FFF879692FF8D9C98FF91A09CFF91A09CFF8F9E9AFF99A8A4FF9CABA7FF
+ 9FAEAAFFA1B0ACFFA3B2AEFFA6B5B1FFABBAB6FFAFBEBAFFAEBDB9FFAAB9B5FF
+ A5B4B0FFA2B1ADFFA1B0ACFFA1B0ACFFA0AFABFFA0AFABFFA4B3AFFFA6B5B1FF
+ 9FAEAAFF9EADA9FFA5B4B0FFA2B1ADFFA1B0ACFFADBEBAFFC8DBD8FFC7DCD9FF
+ C8DDDAFFC6DDD9FFC1DAD6FFBFD8D4FFBED9D5FFBFDAD6FFC3DCD8FFC5DEDAFF
+ C6DBD8FFC1D4D1FFBACBC8FF808E8CFF8E9B99FFA1AEACFF9DABA7FFA0AEAAFF
+ A3B1ADFFA3B1ADFFA1AFABFFA0AEAAFF9FADA9FFA0AEAAFFA6B4B0FFA0AEAAFF
+ 9CAAA6FF9FADA9FFA1AFABFF9FADA9FF9FADA9FFA2B0ACFFA0AEA8FFA6B4AEFF
+ A3B1ABFF9CAAA4FF9CAAA4FFA5B3ADFFA8B6B0FFA3B1ABFFA3B1ABFFA8B6B0FF
+ A9B7B1FFA4B2ACFFA2B0AAFFA6B4AEFFA8B6B0FFA7B5AFFFA6B5B1FFADBCB8FF
+ B0BFBBFFADBCB8FFABBAB6FFADBCB8FFADBCB8FFABBAB6FFA3B2AEFFA2B1ADFF
+ A1B0ACFFA0AFABFF9DACA8FF96A5A1FF8D9C98FF869591FF7F8F88FF81918AFF
+ 73817BFF4A5852FF65736DFF7C8A84FF7A8680FF838F89FF929C96FF8A948EFF
+ 858F89FF848E88FF868D88FF858C87FF858C87FF89908BFF86908AFF7F8983FF
+ 78827CFF757F79FF757F79FF757F79FF727C76FF6F7973FF737D77FF757F79FF
+ 757F79FF747E78FF7A847EFF858F89FF8E9892FF909B93FF8F9790FF8E978DFF
+ 8F988EFF929B91FF97A298FF9DA89EFFA2ADA3FFA5B0A6FFA4B2A7FF9DABA0FF
+ 9EAEA3FFA2B2A7FFA3B3A8FFB0C0B5FFB4C5BAFFA7B8ADFFA4B4A9FFA3B3A8FF
+ A4B4A9FFA5B5AAFFA0B0A5FF99A99EFF98A89DFF9CACA1FF9AAA9FFF99A99EFF
+ 99A99EFF9DADA2FFA1B1A6FFA3B3A8FFA0B0A5FF9BACA1FF97AAA1FFA8BDB4FF
+ BCD1C8FFC4D9D0FFC3D8D0FFBFD4CCFFBACFC7FFB6CBC3FFB6CAC5FFB4C8C3FF
+ B2C5C2FFB2C5C2FF858C87FF8A918CFF838A85FF808782FF89938DFF929C96FF
+ 9DA7A1FFAEB8B2FFB3BFB9FFBAC6C0FFB6C4BEFFADBBB5FFADBBB5FFB6C4BEFF
+ B6C6BFFFAFBFB8FFAFBDB9FFAFBDB9FFB0BEBAFFB3C1BDFFB4C2BEFFB1BFBBFF
+ AEBCB8FFADBBB7FFB3C1BDFFAAB8B4FFA6B4B0FFABB9B5FFAEBCB8FFA8B6B2FF
+ A0AEAAFF9DABA7FFA7B6B2FFA4B3AFFFA2B1ADFFA2B1ADFFA5B4B0FFA9B8B4FF
+ ABBAB6FFACBBB7FFA2B1ADFF9AA9A5FF9DACA8FFA9B8B4FFADBCB8FFA6B5B1FF
+ A4B3AFFFAAB9B5FFA5B6B2FFA3B4B0FFA2B3AFFFA3B4B0FFA6B5B1FFA7B6B2FF
+ AAB9B5FFACBBB7FFACBAB6FFA7B5B1FFA0ABA8FF9AA5A2FF9FAAA7FFA7B2AFFF
+ A9B2AFFFA3ACA9FFA2AEA8FF9BA7A1FF96A29CFF95A19BFF939F99FF8E9A94FF
+ 8D9993FF909C96FF929E98FF929E98FF909C96FF8F9B95FF8D9993FF8B9791FF
+ 89958FFF89958FFF848D8AFF87908DFF87928FFF85908DFF818C89FF808B88FF
+ 82908CFF85938FFF788783FF7F8E8AFF8A9995FF7D8C88FF8A9B97FFB5C6C2FF
+ C0D1CDFFC6DAD5FFCDE0DDFFCBE0DDFFCADFDCFFC9DEDBFFC7DCD9FFC4D9D6FF
+ C2D7D4FFC1D6D3FFC5DAD7FFC6DBD8FFC7DCD9FFC4D9D6FFBFD4D1FFBBD0CDFF
+ BBD0CDFFBED1CEFFBDCCC8FFAFBDB9FF1F2D29FF667470FF7D8B87FF879591FF
+ 7B8985FF7F8D89FF7C8A86FF7D8B87FF808E8AFF83918DFF889692FF8D9B97FF
+ 919F9BFF93A19DFF8F9E9AFF8B9A96FF889793FF8B9A96FF92A19DFF97A6A2FF
+ 97A6A2FF94A39FFF9AA9A5FF9FAEAAFFA3B2AEFFA2B1ADFF9DACA8FF9DACA8FF
+ A4B3AFFFAAB9B5FFB2C3BFFFACBDB9FFA4B5B1FFA0B1ADFFA0B1ADFFA2B3AFFF
+ A3B4B0FFA3B4B0FFA1B2AEFFA5B6B2FF9DAEAAFF9AABA7FF9FB0ACFF9CADA9FF
+ 9DAEAAFFACBDB9FFC4D7D4FFC4D9D6FFC5DAD7FFC2D9D5FFBDD6D2FFBBD4D0FF
+ BAD5D1FFBBD6D2FFC1DAD6FFBFD8D4FFC2D7D4FFC5D8D5FFBDCECBFF7A8886FF
+ 869391FF9FACAAFF9EACA8FFA3B1ADFFA8B6B2FFAAB8B4FFA8B6B2FFA4B2AEFF
+ A2B0ACFFA0AEAAFFAAB8B4FFA3B1ADFF9FADA9FFA1AFABFFA2B0ACFFA0AEAAFF
+ A1AFABFFA4B2AEFF9DABA5FFA3B1ABFFA1AFA9FF98A6A0FF98A6A0FFA3B1ABFF
+ A5B3ADFF9FADA7FFA2B0AAFFA7B5AFFFA8B6B0FFA3B1ABFFA1AFA9FFA3B1ABFF
+ A5B3ADFFA3B1ABFFA8B7B3FFAFBEBAFFB1C0BCFFACBBB7FFAAB9B5FFADBCB8FF
+ AEBDB9FFAAB9B5FFA4B3AFFFA2B1ADFFA0AFABFF9FAEAAFF9CABA7FF97A6A2FF
+ 909F9BFF8A9995FF86968FFF7F8F88FF798781FF485650FF73817BFF7C8A84FF
+ 7E8A84FF7E8A84FF909A94FF87918BFF828C86FF848E88FF878E89FF838A85FF
+ 818883FF848B86FF818B85FF7F8983FF7D8781FF7B857FFF78827CFF76807AFF
+ 757F79FF757F79FF7C8680FF808A84FF818B85FF7F8983FF838D87FF8D9791FF
+ 929C96FF909B93FF8C948DFF919A90FF959E94FF949D93FF909B91FF939E94FF
+ 9DA89EFFA5B0A6FFA7B5AAFFA0AEA3FF9EAEA3FF9DADA2FF9CACA1FFA9B9AEFF
+ B1C2B7FFA8B9AEFFA8B8ADFFA2B2A7FFA0B0A5FFA3B3A8FFA2B2A7FF9EAEA3FF
+ 9FAFA4FFA4B4A9FFA2B2A7FFA1B1A6FFA1B1A6FFA2B2A7FFA4B4A9FFA5B5AAFF
+ A5B5AAFFA3B4A9FF95A89FFFA8BDB4FFBCD1C8FFC2D7CEFFC0D5CDFFBFD4CCFF
+ BBD0C8FFB6CBC3FFB6CAC5FFB2C6C1FFAFC2BFFFADC0BDFF818883FF89908BFF
+ 888F8AFF8B928DFF959F99FF98A29CFF98A29CFFA2ACA6FFAFBBB5FFB6C2BCFF
+ B1BFB9FFA4B2ACFFA2B0AAFFB0BEB8FFB7C7C0FFB5C5BEFFAFBDB9FFAEBCB8FF
+ AFBDB9FFAEBCB8FFACBAB6FFADBBB7FFB4C2BEFFBDCBC7FFB0BEBAFFB3C1BDFF
+ B0BEBAFFAAB8B4FFADBBB7FFB3C1BDFFAAB8B4FF9AA8A4FFACBBB7FFA9B8B4FF
+ A4B3AFFF9DACA8FF99A8A4FF9CABA7FFA5B4B0FFADBCB8FFAFBEBAFF9FAEAAFF
+ 9AA9A5FFA6B5B1FFAEBDB9FFA9B8B4FFA5B4B0FFA8B7B3FFA7B6B2FFA2B3AFFF
+ A2B1ADFFA3B2AEFFA5B4B0FFA5B4B0FFA9B8B4FFADBCB8FFB3C1BDFFABB9B5FF
+ A0ABA8FF98A3A0FF9DA8A5FFA6B1AEFFA4AFACFF9DA8A5FFA4B0AAFF9EAAA4FF
+ 9AA6A0FF98A49EFF95A19BFF8F9B95FF909C96FF94A09AFF95A19BFF94A09AFF
+ 939F99FF919D97FF8F9B95FF8D9993FF8C9892FF8B9791FF88918EFF868F8CFF
+ 818C89FF808B88FF818C89FF828D8AFF818F8BFF818F8BFF879591FF869591FF
+ 899793FF73827EFF879692FFBAC9C5FFC4D3CFFFC1D2CEFFC7DAD7FFC6DBD8FF
+ C7DCD9FFC8DDDAFFC8DDDAFFC6DBD8FFC4D9D6FFC2D7D4FFC0D5D2FFC3D8D5FF
+ C4D9D6FFC2D7D4FFBDD2CFFFB9CECBFFB9CECBFFBCCFCCFFBBCAC6FFA8B6B2FF
+ 2A3834FF7C8A86FF7E8C88FF85938FFF768480FF83918DFF889692FF85938FFF
+ 82908CFF808E8AFF82908CFF879591FF8C9A96FF909E9AFF8F9E9AFF8A9995FF
+ 879692FF8A9995FF91A09CFF96A5A1FF96A5A1FF94A39FFF8C9B97FF94A39FFF
+ 9CABA7FF9CABA7FF98A7A3FF9AA9A5FFA5B4B0FFB0BFBBFFAAB9B5FFA5B6B2FF
+ A5B4B0FFA4B5B1FFA9B8B4FFA7B8B4FFA6B5B1FFA1B2AEFF9FAEAAFFA3B4B0FF
+ 9EADA9FF97A8A4FF9EADA9FF9BACA8FFA1B0ACFFAEBFBBFFC2D5D2FFC3D6D3FF
+ C2D7D4FFBFD6D2FFBCD3CFFFBAD1CDFFB9D2CEFFBAD3CFFFC2D9D5FFBDD4D0FF
+ C1D6D3FFC9DCD9FFBFD0CDFF758381FF7D8B89FF99A7A5FF95A39FFF9BA9A5FF
+ A4B2AEFFA7B5B1FFA5B3AFFFA0AEAAFF9AA8A4FF97A5A1FFA6B4B0FF9FADA9FF
+ 9BA9A5FF9CAAA6FF9EACA8FF9CAAA6FF9CAAA6FF9FADA9FF9FADA7FFA7B5AFFF
+ A5B3ADFF9BA9A3FF9BA9A3FFA6B4AEFFA9B7B1FFA2B0AAFFA0AEA8FFA5B3ADFF
+ A6B4AEFFA1AFA9FF9FADA7FFA2B0AAFFA3B1ABFFA1AFA9FFABBAB6FFB2C1BDFF
+ B3C2BEFFACBBB7FFAAB9B5FFADBCB8FFAEBDB9FFAAB9B5FFA6B5B1FFA3B2AEFF
+ 9FAEAAFF9CABA7FF9AA9A5FF97A6A2FF92A19DFF8F9E9AFF8E9D99FF81918AFF
+ 818F89FF4A5852FF808E88FF808E88FF85918BFF7F8B85FF848E88FF7C8680FF
+ 7B857FFF818B85FF868D88FF818982FF7E8580FF818982FF79837DFF7C877FFF
+ 7F8983FF7E8981FF79837DFF758078FF747E78FF747F77FF707A74FF7A857DFF
+ 818B85FF848F87FF89938DFF8F9A92FF8C9690FF838E86FF90998FFF97A096FF
+ 9CA59BFF98A197FF90998FFF909B91FF9DA89EFFABB6ACFFAAB5ABFF9FADA2FF
+ 9DABA0FF97A79CFF92A297FF9EAEA3FFAABAAFFFA2B3A8FFA1B1A6FF9DADA2FF
+ A0B0A5FFA6B6ABFFA6B6ABFFA0B0A5FFA0B0A5FFA5B5AAFFA1B1A6FFA1B1A6FF
+ A1B1A6FFA0B0A5FF9FAFA4FF9FAFA4FFA0B0A5FFA1B2A7FF95A89FFFA9BEB5FF
+ BBD0C7FFBFD4CBFFBED3CBFFBED3CBFFBCD1C9FFB8CDC5FFB9CDC8FFB4C8C3FF
+ ADC0BDFFA9BCB9FF8B928FFF848B88FF7F8683FF848B88FF88918EFF8E9794FF
+ 959E9BFF9DA6A3FFBEC9C6FFBCC7C4FFA8B6B2FFAEBCB8FFADBBB7FFA2B0ACFF
+ AAB9B5FFA4B3AFFFABB9B5FFADBBB7FFADBBB7FFADBBB7FFB3C1BDFFB9C7C3FF
+ B8C6C2FFB2C0BCFFB0BEBAFFB1BFBBFFB0BEBAFFADBBB7FFAFBDB9FFB2C0BCFF
+ AEBCB8FFA6B4B0FFB1BFBBFFA8B6B2FFA3B1ADFFA2B0ACFF9EACA8FF99A7A3FF
+ 9EACA8FFA9B7B3FFAEBCB8FFA3B1ADFF9BA9A5FFA0AEAAFFADBBB7FFB4C2BEFF
+ AFBDB9FFA6B4B0FFAAB8B4FFA6B5B1FFA5B3AFFFA4B2AEFFA6B4B0FFA8B6B2FF
+ A8B6B2FFA7B5B1FFABB9B5FFAAB8B4FF95A39FFF9EACA8FF919F9BFFA6B4B0FF
+ 9CAAA6FFA1ACA9FF9BA6A3FF9BA6A3FF9BA6A3FF99A4A1FF98A3A0FF95A09DFF
+ 939E9BFF919C99FF8F9A97FF8F9A97FF8D9895FF8C9794FF8A9592FF899491FF
+ 889390FF87928FFF848F8CFF828D8AFF828D8AFF838E8BFF808B88FF7B8683FF
+ 7D8885FF838E8BFF7B8683FF7F8D89FF8A9592FF788682FF6F7D79FF9BA9A5FF
+ C5D3CFFFBDCCC8FFBED1CEFFBFD4D1FFC3D8D5FFC5DAD7FFC2D7D4FFBDD2CFFF
+ B8CDCAFFB6CBC8FFC3D8D5FFC3D8D5FFC2D7D4FFBED3D0FFBACFCCFFB9CECBFF
+ BACFCCFFBED1CEFFCDDCD8FF9DABA7FF1F2D29FF778581FF768480FF83918DFF
+ 808E8AFF798783FF7B8985FF7B8985FF7D8B87FF808E8AFF869490FF8A9894FF
+ 8E9C98FF8F9D99FF909F9BFF8E9D99FF8B9A96FF899894FF8B9A96FF909F9BFF
+ 96A5A1FF9AA9A5FF97A6A2FF9AA9A5FF9EADA9FF9FAEAAFF9FAEAAFFA0AFABFF
+ A2B1ADFFA4B3AFFFB2C1BDFFACBBB7FFA6B4B0FFA4B3AFFFA7B5B1FFA7B6B2FF
+ A6B4B0FFA2B1ADFF9FADA9FF9CABA7FF9BA9A5FF99A8A4FF9CAAA6FF9EADA9FF
+ A2B0ACFFA2B1ADFFC0D1CDFFCCE0DBFFC6DAD5FFB6CCC7FFB8CEC9FFBBD1CCFF
+ BAD0CBFFBED4CFFFC3D9D4FFBBD1CCFFC0D4CFFFC2D6D1FFB6CAC5FF7D8E8AFF
+ 899A96FF93A4A0FF8F9E9AFF92A09CFF97A5A1FF9EACA8FFA2B0ACFFA0AEAAFF
+ 98A6A2FF909E9AFF97A5A1FF9AA8A4FF9DABA7FF9FADA9FF9FADA9FF9EACA8FF
+ 9EACA8FF9EACA8FF9DABA7FF99A7A3FF9FADA9FFA0AEAAFF97A5A1FF9BA9A5FF
+ A5B3AFFFA4B2AEFF9DABA7FFA6B4B0FFAAB8B4FFA5B3AFFFA4B2AEFFA7B5B1FF
+ A5B3AFFFA0AEAAFFA9B7B3FFB2C0BCFFB5C3BFFFAEBCB8FFA9B7B3FFABB9B5FF
+ ACBAB6FFA9B7B3FFA7B5B1FFA8B6B2FFA8B6B2FFA4B2AEFF9EACA8FF98A6A2FF
+ 95A39FFF94A29EFF8E9D99FF8A9995FF889692FF404E4AFF7C8A86FF7A8884FF
+ 87938DFF8A9690FF89948CFF8B968EFF8C978FFF88938BFF848C85FF7E877DFF
+ 7B837CFF7B847AFF7D8880FF7D887EFF7C877FFF7C877DFF7B867EFF7B867CFF
+ 7B867EFF7B867CFF79847CFF818C82FF848F87FF818C82FF808B83FF869187FF
+ 8D9890FF8F9A90FF939C92FF9FA79DFFA8B0A6FF99A298FF8F988EFFA2ABA1FF
+ B3BCB2FFA7B2A8FFA5B0A6FF9FADA2FF9CAA9FFF9AA89DFF9AA89DFF9BABA0FF
+ 9DADA2FF9EAEA3FF9CAA9FFFA0AEA3FFA3B1A6FFA0AEA3FF9BA99EFF98A69BFF
+ 9BA99EFF9FADA2FFA5B3A8FF99A79CFF96A499FF9FADA2FFA2B0A5FF9EACA1FF
+ 9EACA1FFA3B3A8FF9BAFA3FFABC1B5FFBAD0C4FFBED4C8FFC0D5CCFFC2D7CEFF
+ BACFC6FFAEC3BAFFB5CAC2FFB5CAC2FFB5C9C4FFB4C8C3FF8D9491FF878E8BFF
+ 848B88FF89908DFF8D9693FF909996FF959E9BFF9AA3A0FFBBC6C3FFC2CDCAFF
+ AFBDB9FFACBAB6FFAAB8B4FFA8B6B2FFB1C0BCFFA5B4B0FFADBBB7FFB0BEBAFF
+ B0BEBAFFAFBDB9FFB1BFBBFFB4C2BEFFB0BEBAFFA9B7B3FFAFBDB9FFAFBDB9FF
+ ADBBB7FFA9B7B3FFABB9B5FFB0BEBAFFAEBCB8FFA9B7B3FFB1BFBBFFA9B7B3FF
+ A4B2AEFFA2B0ACFF9DABA7FF99A7A3FF9EACA8FFA7B5B1FFA3B1ADFF9EACA8FF
+ 9AA8A4FF9CAAA6FFA3B1ADFFA9B7B3FFAAB8B4FFA8B6B2FFABB9B5FFA9B7B3FF
+ A7B5B1FFA7B5B1FFA7B5B1FFA5B3AFFFA1AFABFF9DABA7FFA7B5B1FFA5B3AFFF
+ 98A6A2FF99A7A3FF92A09CFF9CAAA6FF9AA8A4FF9CAAA6FF99A4A1FF99A4A1FF
+ 97A29FFF95A09DFF939E9BFF929D9AFF909B98FF909B98FF8C9794FF8B9693FF
+ 8A9592FF899491FF87928FFF86918EFF85908DFF848F8CFF848F8CFF818C89FF
+ 7F8A87FF818C89FF7F8A87FF7B8683FF7C8784FF818C89FF838E8BFF848F8CFF
+ 899491FF7A8582FF727D7AFF9DA8A5FFC4CFCCFFBBC9C5FFC0D3D0FFC0D5D2FF
+ C3D8D5FFC3D8D5FFC2D7D4FFBED3D0FFBBD0CDFFB9CECBFFC0D5D2FFC3D8D5FF
+ C4D9D6FFC3D8D5FFC0D5D2FFBED3D0FFBDD2CFFFC0D3D0FFC0CFCBFF919F9BFF
+ 1E2C28FF74827EFF6F7D79FF7B8985FF7C8A86FF7B8985FF7D8B87FF7C8A86FF
+ 7D8B87FF808E8AFF84928EFF889692FF8B9995FF8D9B97FF91A09CFF909F9BFF
+ 8F9E9AFF8E9D99FF8F9E9AFF91A09CFF94A39FFF96A5A1FF97A6A2FF9AA9A5FF
+ 9DACA8FF9EADA9FF9EADA9FF9FAEAAFFA2B1ADFFA5B4B0FFACBAB6FFA9B7B3FF
+ A7B5B1FFA8B6B2FFABB9B5FFA9B7B3FFA4B2AEFF9EACA8FF9FADA9FF9DABA7FF
+ 9AA8A4FF99A7A3FF99A7A3FF9BA9A5FF9CAAA6FF9CABA7FFC5D6D2FFCDE1DCFF
+ C4D8D3FFB8CCC7FFBFD3CEFFC5D9D4FFC0D4CFFFBFD3CEFFC4D8D3FFBED2CDFF
+ C2D6D1FFC4D8D3FFB9CDC8FF80948FFF8FA39EFF9AABA7FF92A19DFF95A39FFF
+ 98A6A2FF9EACA8FFA2B0ACFFA1AFABFF9CAAA6FF97A5A1FF9AA8A4FF9BA9A5FF
+ 9CAAA6FF9CAAA6FF9DABA7FF9DABA7FF9EACA8FF9FADA9FF9EACA8FF99A7A3FF
+ 9FADA9FFA2B0ACFF9AA8A4FF9DABA7FFA3B1ADFF9EACA8FF9DABA7FFA4B2AEFF
+ A8B6B2FFA4B2AEFFA3B1ADFFA7B5B1FFA8B6B2FFA5B3AFFFA3B1ADFFADBBB7FF
+ B2C0BCFFAEBCB8FFABB9B5FFAFBDB9FFB1BFBBFFB0BEBAFFABB9B5FFA8B6B2FF
+ A3B1ADFFA1AFABFFA0AEAAFF9BA9A5FF95A39FFF909E9AFF879593FF889694FF
+ 8C9A96FF53615DFF6E7C78FF75837FFF828E88FF87938DFF89948CFF89948CFF
+ 89948CFF88938BFF879086FF848D83FF838C82FF828B81FF7E897FFF7D887EFF
+ 7C877DFF7B867CFF7B867CFF7A857BFF7A857BFF7A857BFF7F8A80FF818C82FF
+ 818C82FF7F8A80FF828D83FF89948AFF8C978DFF89948AFF939B91FF99A197FF
+ A1A99FFF9AA298FF8E978DFF9CA59BFFABB4AAFFA6AFA5FFACB7ADFFA4AFA5FF
+ 9CAA9FFF9CAA9FFFA1AFA4FFA5B3A8FFA2B2A7FF9FAFA4FF9BA99EFFA0AEA3FF
+ A5B3A8FFA5B3A8FFA2B0A5FFA0AEA3FFA2B0A5FFA6B4A9FFA6B4A9FF9DABA0FF
+ 97A59AFF9BA99EFFA3B1A6FFA7B5AAFFA9B7ACFFAABAAFFF9FB3A7FFAEC4B8FF
+ BBD1C5FFBAD0C4FFBACFC6FFBCD1C8FFB9CEC5FFB1C6BDFFB7CCC4FFB4C9C1FF
+ B1C5C0FFADC1BCFF8E9592FF8A918EFF8A918EFF909794FF929B98FF919A97FF
+ 929B98FF959E9BFFAFBAB7FFC8D3D0FFBBC9C5FFADBBB7FFA7B5B1FFAEBCB8FF
+ BAC9C5FFA6B5B1FFABB9B5FFAFBDB9FFB0BEBAFFAEBCB8FFAFBDB9FFB0BEBAFF
+ ACBAB6FFA5B3AFFFACBAB6FFADBBB7FFAAB8B4FFA6B4B0FFA9B7B3FFAEBCB8FF
+ AFBDB9FFACBAB6FFB1BFBBFFABB9B5FFA6B4B0FFA3B1ADFF9EACA8FF9AA8A4FF
+ 9DABA7FFA4B2AEFF9CAAA6FF9CAAA6FF9CAAA6FF9BA9A5FF9BA9A5FF9FADA9FF
+ A7B5B1FFACBAB6FFA7B5B1FFA6B4B0FFA6B4B0FFA7B5B1FFA7B5B1FFA3B1ADFF
+ 9CAAA6FF97A5A1FFA2B0ACFF9DABA7FF9DABA7FF92A09CFF95A39FFF8F9D99FF
+ 97A5A1FF99A7A3FF98A3A0FF96A19EFF939E9BFF909B98FF8E9996FF8D9895FF
+ 8D9895FF8E9996FF8B9693FF8B9693FF8A9592FF889390FF87928FFF86918EFF
+ 85908DFF848F8CFF85908DFF7F8A87FF7C8784FF7E8986FF7E8986FF7C8784FF
+ 7C8784FF7F8A87FF8A9592FF86918EFF889390FF7A8582FF717C79FF97A29FFF
+ BDC8C5FFB5C3BFFFB9CCC9FFB8CDCAFFBACFCCFFBBD0CDFFBBD0CDFFB9CECBFF
+ B6CBC8FFB4C9C6FFB9CECBFFBFD4D1FFC6DBD8FFC9DEDBFFC7DCD9FFC3D8D5FF
+ BFD4D1FFBFD2CFFFBDCCC8FF8A9894FF273531FF788682FF6E7C78FF75837FFF
+ 7B8985FF7D8B87FF808E8AFF808E8AFF808E8AFF818F8BFF83918DFF869490FF
+ 899793FF8B9995FF91A09CFF92A19DFF93A29EFF94A39FFF94A39FFF93A29EFF
+ 91A09CFF909F9BFF93A29EFF95A4A0FF99A8A4FF9BAAA6FF9EADA9FFA1B0ACFF
+ A6B5B1FFAAB9B5FFA5B3AFFFA5B3AFFFA7B5B1FFABB9B5FFAEBCB8FFAAB8B4FF
+ A1AFABFF99A7A3FF9DABA7FF9BA9A5FF99A7A3FF97A5A1FF95A39FFF96A4A0FF
+ 97A5A1FF97A6A2FFC5D6D2FFCADED9FFC0D4CFFFB6CAC5FFC2D6D1FFC8DCD7FF
+ C1D5D0FFBDD1CCFFC4D8D3FFBFD3CEFFC3D7D2FFC4D8D3FFBBCFCAFF869A95FF
+ 96AAA5FFA1B2AEFF99A8A4FF9AA8A4FF9AA8A4FF9DABA7FFA0AEAAFFA2B0ACFF
+ A1AFABFF9FADA9FF9DABA7FF9CAAA6FF9CAAA6FF9BA9A5FF9CAAA6FF9DABA7FF
+ 9EACA8FF9EACA8FF9FADA9FF98A6A2FF9EACA8FFA2B0ACFF9DABA7FF9FADA9FF
+ A2B0ACFF99A7A3FF9AA8A4FF9FADA9FFA1AFABFF9EACA8FF9EACA8FFA3B1ADFF
+ A6B4B0FFA6B4B0FFA1AFABFFAAB8B4FFB0BEBAFFAFBDB9FFADBBB7FFB0BEBAFF
+ B3C1BDFFB3C1BDFFAEBCB8FFA7B5B1FFA0AEAAFF9EACA8FFA0AEAAFF9DABA7FF
+ 94A29EFF8B9995FF82908EFF869492FF8E9C98FF6E7C78FF5A6864FF73817DFF
+ 7D8983FF838F89FF89948CFF88938BFF869189FF869189FF8A9389FF8B948AFF
+ 8B948AFF8A9389FF818C82FF808B81FF7E897FFF7B867CFF79847AFF788379FF
+ 788379FF778278FF7A857BFF7A857BFF79847AFF7A857BFF828D83FF8B968CFF
+ 8B968CFF859086FF9AA298FF979F95FF9EA69CFF9EA69CFF939C92FF99A298FF
+ A8B1A7FFABB4AAFFADB8AEFFA4AFA5FF99A79CFF9BA99EFFA3B1A6FFA8B6ABFF
+ A3B3A8FF9DADA2FF98A69BFF9EACA1FFA5B3A8FFA6B4A9FFA4B2A7FFA1AFA4FF
+ A1AFA4FFA2B0A5FFA4B2A7FF9FADA2FF97A59AFF94A297FF9BA99EFFA6B4A9FF
+ AAB8ADFFA5B5AAFFA5B9ADFFB6CCC0FFC1D7CBFFBDD3C7FFB7CCC3FFB9CEC5FF
+ BBD0C7FFB8CDC4FFB4C9C1FFB0C5BDFFAABEB9FFA5B9B4FF8D9491FF8A918EFF
+ 8C9390FF939A97FF949D9AFF909996FF8D9693FF8E9794FF9DA8A5FFC9D4D1FF
+ C7D5D1FFB3C1BDFFA6B4B0FFAFBDB9FFBDCCC8FFA6B5B1FFA8B6B2FFACBAB6FF
+ ACBAB6FFA9B7B3FFAAB8B4FFAEBCB8FFADBBB7FFA9B7B3FFA7B5B1FFAAB8B4FF
+ ABB9B5FFA9B7B3FFABB9B5FFB0BEBAFFB0BEBAFFADBBB7FFB1BFBBFFAEBCB8FF
+ AAB8B4FFA4B2AEFF9FADA9FF9CAAA6FF9EACA8FFA1AFABFFA2B0ACFFA1AFABFF
+ 9EACA8FF9BA9A5FF9AA8A4FF9EACA8FFA6B4B0FFACBAB6FFA2B0ACFFA1AFABFF
+ A1AFABFFA3B1ADFFA4B2AEFFA2B0ACFF9EACA8FF9AA8A4FF9EACA8FF98A6A2FF
+ A1AFABFF8F9D99FF97A5A1FF85938FFF95A39FFF97A5A1FF97A29FFF949F9CFF
+ 909B98FF8D9895FF8B9693FF8B9693FF8C9794FF8D9895FF8D9895FF8C9794FF
+ 8C9794FF8B9693FF8A9592FF899491FF889390FF87928FFF87928FFF808B88FF
+ 7C8784FF7E8986FF7F8A87FF7D8885FF7D8885FF7F8A87FF899491FF848F8CFF
+ 889390FF7B8683FF6C7774FF8B9693FFB3BEBBFFB2C0BCFFB1C4C1FFB1C6C3FF
+ B4C9C6FFB8CDCAFFBACFCCFFB7CCC9FFB2C7C4FFADC2BFFFAEC3C0FFB7CCC9FF
+ C3D8D5FFCADFDCFFCADFDCFFC4D9D6FFBED3D0FFBCCFCCFFCAD9D5FF8A9894FF
+ 364440FF818F8BFF768480FF798783FF7E8C88FF7E8C88FF85938FFF85938FFF
+ 85938FFF84928EFF83918DFF85938FFF899793FF8C9A96FF8C9B97FF8F9E9AFF
+ 93A29EFF96A5A1FF96A5A1FF94A39FFF909F9BFF8D9C98FF8D9C98FF909F9BFF
+ 94A39FFF98A7A3FF9CABA7FFA3B2AEFFAAB9B5FFB0BFBBFFA3B1ADFFA3B1ADFF
+ A5B3AFFFAAB8B4FFADBBB7FFA9B7B3FFA0AEAAFF97A5A1FF99A7A3FF99A7A3FF
+ 99A7A3FF96A4A0FF94A29EFF94A29EFF95A39FFF96A5A1FFBCCDC9FFC6DAD5FF
+ C0D4CFFFB6CAC5FFBED2CDFFC3D7D2FFBFD3CEFFBED2CDFFC2D6D1FFBFD3CEFF
+ C2D6D1FFC1D5D0FFB8CCC7FF869A95FF97ABA6FFA1B2AEFF9FAEAAFF9EACA8FF
+ 9DABA7FF9CAAA6FF9DABA7FF9FADA9FFA0AEAAFFA1AFABFF9EACA8FF9EACA8FF
+ 9EACA8FF9FADA9FFA0AEAAFFA0AEAAFF9FADA9FF9DABA7FFA0AEAAFF97A5A1FF
+ 9AA8A4FF9FADA9FF9CAAA6FFA1AFABFFA4B2AEFF9AA8A4FF98A6A2FF9AA8A4FF
+ 9AA8A4FF97A5A1FF97A5A1FF9AA8A4FF9EACA8FFA1AFABFFA2B0ACFFA9B7B3FF
+ AFBDB9FFB0BEBAFFADBBB7FFADBBB7FFAEBCB8FFB0BEBAFFADBBB7FFA7B5B1FF
+ A0AEAAFF9DABA7FF9DABA7FF99A7A3FF92A09CFF8C9A96FF859391FF879593FF
+ 8C9A96FF83918DFF4A5854FF75837FFF7B8781FF818D87FF8A958DFF87928AFF
+ 848F87FF859088FF8A9389FF8D968CFF8E978DFF8D968CFF879288FF859086FF
+ 818C82FF7C877DFF79847AFF768177FF747F75FF747F75FF747F75FF778278FF
+ 79847AFF7C877DFF848F85FF8E998FFF919C92FF8D988EFF9AA298FF8E968CFF
+ 929A90FF98A096FF8E978DFF90998FFFA1AAA0FFABB4AAFFACB7ADFFA6B1A7FF
+ 9EACA1FF9FADA2FFA5B3A8FFA8B6ABFFA5B5AAFFA2B2A7FF9EACA1FFA3B1A6FF
+ A9B7ACFFAAB8ADFFA7B5AAFFA2B0A5FF9EACA1FF9DABA0FFA2B0A5FFA7B5AAFF
+ A3B1A6FF98A69BFF98A69BFFA2B0A5FFA6B4A9FFA0B0A5FFA5B9ADFFB8CEC2FF
+ C5DBCFFFBFD5C9FFB4C9C0FFB4C9C0FFB7CCC3FFB6CBC2FFB4C9C1FFB1C6BEFF
+ AEC2BDFFAABEB9FF8A918EFF878E8BFF89908DFF909794FF919A97FF8D9693FF
+ 89928FFF89928FFF8F9A97FFC2CDCAFFCBD9D5FFBCCAC6FFABB9B5FFADBBB7FF
+ BAC9C5FFA7B6B2FFABB9B5FFADBBB7FFABB9B5FFA6B4B0FFA6B4B0FFABB9B5FF
+ ADBBB7FFACBAB6FFA3B1ADFFA9B7B3FFADBBB7FFADBBB7FFAEBCB8FFB2C0BCFF
+ B1BFBBFFAEBCB8FFB0BEBAFFB0BEBAFFADBBB7FFA7B5B1FFA1AFABFF9FADA9FF
+ A0AEAAFFA1AFABFFAAB8B4FFA4B2AEFF9CAAA6FF9AA8A4FF9CAAA6FFA0AEAAFF
+ A3B1ADFFA4B2AEFFA2B0ACFFA0AEAAFF9DABA7FF9DABA7FF9EACA8FF9FADA9FF
+ 9EACA8FF9CAAA6FF9DABA7FF96A4A0FFA1AFABFF92A09CFF98A6A2FF82908CFF
+ 919F9BFF96A4A0FF96A19EFF949F9CFF909B98FF8C9794FF8A9592FF8A9592FF
+ 8C9794FF8D9895FF8C9794FF8B9693FF8B9693FF8A9592FF899491FF889390FF
+ 889390FF889390FF899491FF828D8AFF7E8986FF7F8A87FF7F8A87FF7D8885FF
+ 7E8986FF828D8AFF848F8CFF808B88FF889390FF7E8986FF697471FF818C89FF
+ AAB5B2FFB2C0BCFFB0C3C0FFB1C6C3FFB7CCC9FFBED3D0FFC1D6D3FFBED3D0FF
+ B5CAC7FFAEC3C0FFA5BAB7FFB0C5C2FFBED3D0FFC7DCD9FFC8DDDAFFC2D7D4FF
+ BACFCCFFB8CBC8FFD0DFDBFF818F8BFF3C4A46FF83918DFF7D8B87FF808E8AFF
+ 83918DFF7E8C88FF8A9894FF8B9995FF8A9894FF879591FF85938FFF869490FF
+ 8B9995FF909E9AFF889793FF8C9B97FF91A09CFF95A4A0FF96A5A1FF94A39FFF
+ 909F9BFF8D9C98FF91A09CFF92A19DFF94A39FFF96A5A1FF99A8A4FFA0AFABFF
+ A8B7B3FFAEBDB9FFA4B2AEFFA2B0ACFFA3B1ADFFA6B4B0FFA8B6B2FFA6B4B0FF
+ 9EACA8FF97A5A1FF96A4A0FF98A6A2FF99A7A3FF97A5A1FF95A39FFF94A29EFF
+ 96A4A0FF98A7A3FFB0C1BDFFC4D8D3FFC6DAD5FFB9CDC8FFB8CCC7FFBACEC9FF
+ BCD0CBFFC5D9D4FFC1D5D0FFBFD3CEFFC0D4CFFFBBCFCAFFB1C5C0FF829691FF
+ 94A8A3FF9CADA9FFA2B1ADFFA1AFABFF9FADA9FF9CAAA6FF9BA9A5FF9BA9A5FF
+ 9DABA7FF9FADA9FF9EACA8FF9EACA8FF9FADA9FFA3B1ADFFA5B3AFFFA5B3AFFF
+ A0AEAAFF9CAAA6FFA2B0ACFF96A4A0FF96A4A0FF9AA8A4FF98A6A2FFA0AEAAFF
+ A7B5B1FFA0AEAAFF9CAAA6FF9BA9A5FF99A7A3FF96A4A0FF94A29EFF93A19DFF
+ 97A5A1FF9CAAA6FF9FADA9FFA4B2AEFFABB9B5FFAEBCB8FFACBAB6FFAAB8B4FF
+ ABB9B5FFAFBDB9FFA7B5B1FFA6B4B0FFA2B0ACFF9DABA7FF98A6A2FF93A19DFF
+ 919F9BFF8F9D99FF8C9A98FF889694FF869490FF8D9B97FF43514DFF7B8985FF
+ 7B8781FF838F89FF8A958DFF88938BFF869189FF859088FF889187FF8A9389FF
+ 8B948AFF8B948AFF8D988EFF8A958BFF848F85FF7E897FFF79847AFF758076FF
+ 737E74FF737E74FF768177FF7E897FFF848F85FF848F85FF879288FF8E998FFF
+ 939E94FF939E94FF8B9389FF7A8278FF7C847AFF858D83FF7E877DFF818A80FF
+ 949D93FFA1AAA0FFA8B3A9FFA8B3A9FFA6B4A9FFA5B3A8FFA5B3A8FFA6B4A9FF
+ A7B7ACFFA9B9AEFFA5B3A8FFAAB8ADFFAFBDB2FFB2C0B5FFAFBDB2FFAAB8ADFF
+ A5B3A8FFA3B1A6FFA1AFA4FFAEBCB1FFB2C0B5FFA6B4A9FF9FADA2FFA4B2A7FF
+ A9B7ACFFA6B6ABFF9EB2A6FFB4CABEFFC6DCD0FFC0D6CAFFB4C9C0FFB0C5BCFF
+ AFC4BBFFADC2B9FFB6CBC3FFB7CCC4FFB7CBC6FFB8CCC7FF868D8AFF828986FF
+ 838A87FF8A918EFF8B9491FF89928FFF87908DFF88918EFF909B98FFB7C2BFFF
+ C0CECAFFC1CFCBFFB6C4C0FFADBBB7FFB5C4C0FFA8B7B3FFAFBDB9FFB2C0BCFF
+ B0BEBAFFA9B7B3FFA5B3AFFFA8B6B2FFABB9B5FFAAB8B4FFA3B1ADFFAAB8B4FF
+ AEBCB8FFADBBB7FFADBBB7FFB1BFBBFFB2C0BCFFAFBDB9FFAFBDB9FFB2C0BCFF
+ B1BFBBFFA9B7B3FFA4B2AEFFA4B2AEFFA4B2AEFFA2B0ACFFACBAB6FFA2B0ACFF
+ 98A6A2FF97A5A1FF9CAAA6FFA0AEAAFF9EACA8FF9AA8A4FFA5B3AFFFA2B0ACFF
+ 9DABA7FF9BA9A5FF9CAAA6FF9CAAA6FF9BA9A5FF99A7A3FF9CAAA6FF96A4A0FF
+ 9CAAA6FF97A5A1FF96A4A0FF85938FFF8C9A96FF95A39FFF95A09DFF939E9BFF
+ 909B98FF8D9895FF8B9693FF8B9693FF8B9693FF8B9693FF889390FF889390FF
+ 87928FFF87928FFF86918EFF86918EFF85908DFF85908DFF889390FF838E8BFF
+ 818C89FF808B88FF7D8885FF7A8582FF7F8A87FF86918EFF828D8AFF7C8784FF
+ 87928FFF838E8BFF6F7A77FF818C89FFA9B4B1FFB4C2BEFFAEC1BEFFAFC4C1FF
+ B5CAC7FFBDD2CFFFC2D7D4FFC0D5D2FFB7CCC9FFAFC4C1FFA2B7B4FFACC1BEFF
+ BACFCCFFC4D9D6FFC5DAD7FFC0D5D2FFB9CECBFFB7CAC7FFCAD9D5FF707E7AFF
+ 3C4A46FF82908CFF7F8D89FF82908CFF889692FF83918DFF8D9B97FF8E9C98FF
+ 8D9B97FF8A9894FF869490FF879591FF8D9B97FF93A19DFF899894FF8C9B97FF
+ 8F9E9AFF93A29EFF94A39FFF92A19DFF909F9BFF8E9D99FF99A8A4FF99A8A4FF
+ 97A6A2FF96A5A1FF96A5A1FF9AA9A5FFA1B0ACFFA6B5B1FFA6B4B0FFA3B1ADFF
+ A1AFABFFA2B0ACFFA4B2AEFFA2B0ACFF9CAAA6FF96A4A0FF94A29EFF97A5A1FF
+ 9AA8A4FF99A7A3FF95A39FFF94A29EFF96A4A0FF99A8A4FFA5B6B2FFC2D6D1FF
+ CBDFDAFFBCD0CBFFB3C7C2FFB2C6C1FFBACEC9FFCBDFDAFFC1D5D0FFBFD3CEFF
+ BFD3CEFFB7CBC6FFACC0BBFF7F938EFF92A6A1FF98A9A5FF9FAEAAFFA1AFABFF
+ A0AEAAFF9EACA8FF9BA9A5FF9AA8A4FF9BA9A5FF9DABA7FF9EACA8FF9DABA7FF
+ 9DABA7FFA1AFABFFA6B4B0FFA7B5B1FFA3B1ADFF9EACA8FFA2B0ACFF97A5A1FF
+ 97A5A1FF98A6A2FF94A29EFF9CAAA6FFA6B4B0FFA2B0ACFFA3B1ADFF9FADA9FF
+ 9CAAA6FF9BA9A5FF96A4A0FF92A09CFF94A29EFF9AA8A4FF96A4A0FF9AA8A4FF
+ A3B1ADFFABB9B5FFABB9B5FFA7B5B1FFAAB8B4FFB0BEBAFFA3B1ADFFA4B2AEFF
+ A2B0ACFF9CAAA6FF95A39FFF919F9BFF919F9BFF92A09CFF8B9997FF889694FF
+ 83918DFF8F9D99FF465450FF7E8C88FF7A8680FF86928CFF88938BFF89948CFF
+ 89948CFF87928AFF868F85FF858E84FF879086FF899288FF8E998FFF8B968CFF
+ 859086FF7F8A80FF7A857BFF788379FF778278FF778278FF788379FF818C82FF
+ 869187FF828D83FF7F8A80FF818C82FF859086FF859086FF7E867CFF71796FFF
+ 757D73FF7F877DFF7B847AFF818A80FF949D93FF9DA69CFF9EA99FFFA2ADA3FF
+ A3B1A6FFA1AFA4FF9EACA1FF9DABA0FFA0B0A5FFA5B5AAFFA1AFA4FFA5B3A8FF
+ AAB8ADFFAFBDB2FFAFBDB2FFACBAAFFFA8B6ABFFA6B4A9FF9CAA9FFFA8B6ABFF
+ AFBDB2FFAAB8ADFFA2B0A5FFA3B1A6FFA8B6ABFFA9B9AEFFA1B5A9FFB8CEC2FF
+ CBE1D5FFC8DED2FFBCD1C8FFB6CBC2FFB2C7BEFFADC2B9FFAFC4BCFFB1C6BEFF
+ B4C8C3FFB7CBC6FF848B88FF7F8683FF7E8582FF848B88FF87908DFF87908DFF
+ 88918EFF8B9491FFA1ACA9FFACB7B4FFACBAB6FFC1CFCBFFC3D1CDFFB2C0BCFF
+ B3C2BEFFAAB9B5FFABB9B5FFB1BFBBFFB3C1BDFFAFBDB9FFABB9B5FFACBAB6FF
+ ACBAB6FFA9B7B3FFA6B4B0FFABB9B5FFACBAB6FFA7B5B1FFA6B4B0FFACBAB6FF
+ B2C0BCFFB3C1BDFFAEBCB8FFB4C2BEFFB3C1BDFFACBAB6FFA7B5B1FFA9B7B3FF
+ A8B6B2FFA4B2AEFFA8B6B2FFA0AEAAFF98A6A2FF98A6A2FF9DABA7FF9FADA9FF
+ 9CAAA6FF98A6A2FFA1AFABFF9FADA9FF9DABA7FF9DABA7FF9EACA8FF9EACA8FF
+ 9BA9A5FF99A7A3FF9BA9A5FF97A5A1FF93A19DFF9DABA7FF909E9AFF8A9894FF
+ 869490FF92A09CFF929D9AFF919C99FF8F9A97FF8E9996FF8C9794FF8A9592FF
+ 899491FF889390FF87928FFF87928FFF87928FFF86918EFF86918EFF86918EFF
+ 85908DFF85908DFF848F8CFF838E8BFF838E8BFF818C89FF7A8582FF76817EFF
+ 7D8885FF889390FF87928FFF7A8582FF838E8BFF899491FF7D8885FF8E9996FF
+ B0BBB8FFB6C4C0FFB1C4C1FFAFC4C1FFB1C6C3FFB7CCC9FFBED3D0FFBFD4D1FF
+ BACFCCFFB4C9C6FFA4B9B6FFAEC3C0FFBACFCCFFC3D8D5FFC5DAD7FFC1D6D3FF
+ BCD1CEFFBACDCAFFC9D8D4FF6B7975FF485652FF8A9894FF82908CFF83918DFF
+ 8E9C98FF8C9A96FF8D9B97FF8F9D99FF8E9C98FF8A9894FF85938FFF869490FF
+ 8D9B97FF94A29EFF8F9E9AFF909F9BFF91A09CFF91A09CFF91A09CFF91A09CFF
+ 909F9BFF909F9BFF9AA9A5FF99A8A4FF97A6A2FF94A39FFF94A39FFF98A7A3FF
+ A0AFABFFA6B5B1FFA5B3AFFFA3B1ADFFA1AFABFFA3B1ADFFA4B2AEFFA0AEAAFF
+ 98A6A2FF919F9BFF94A29EFF98A6A2FF9BA9A5FF99A7A3FF94A29EFF919F9BFF
+ 93A19DFF95A4A0FF9BACA8FFBACEC9FFC6DAD5FFB6CAC5FFABBFBAFFA9BDB8FF
+ B4C8C3FFC7DBD6FFC1D5D0FFC0D4CFFFC0D4CFFFB5C9C4FFABBFBAFF819590FF
+ 94A8A3FF9AABA7FF99A8A4FF9EACA8FFA1AFABFFA2B0ACFF9FADA9FF9DABA7FF
+ 9DABA7FF9EACA8FFA0AEAAFF9BA9A5FF98A6A2FF9AA8A4FFA0AEAAFFA5B3AFFF
+ A4B2AEFFA2B0ACFFA2B0ACFF9AA8A4FF9DABA7FF9CAAA6FF94A29EFF98A6A2FF
+ A1AFABFF9EACA8FFA4B2AEFF9FADA9FF9DABA7FF9DABA7FF99A7A3FF92A09CFF
+ 93A19DFF99A7A3FF93A19DFF96A4A0FF9FADA9FFA8B6B2FFA8B6B2FFA2B0ACFF
+ A4B2AEFFABB9B5FFA4B2AEFFA1AFABFF9CAAA6FF98A6A2FF96A4A0FF94A29EFF
+ 92A09CFF919F9BFF808E8CFF869492FF85938FFF8E9C98FF4D5B57FF7B8985FF
+ 75817BFF88948EFF859088FF8A958DFF8E9991FF8B968EFF868F85FF828B81FF
+ 858E84FF8A9389FF8B968CFF889389FF838E84FF7F8A80FF7D887EFF7D887EFF
+ 7E897FFF7F8A80FF7A857BFF7F8A80FF808B81FF7C877DFF7A857BFF7C877DFF
+ 7A857BFF768177FF7B8379FF767E74FF80887EFF8B9389FF8A9389FF949D93FF
+ A2ABA1FFA3ACA2FF9BA69CFF9DA89EFF9CAA9FFF9CAA9FFF9CAA9FFF9CAA9FFF
+ 9CACA1FF9FAFA4FF9DABA0FFA0AEA3FFA4B2A7FFA8B6ABFFA9B7ACFFA8B6ABFF
+ A4B2A7FFA1AFA4FFA2B0A5FFA1AFA4FFA2B0A5FFA4B2A7FFA2B0A5FF9FADA2FF
+ A1AFA4FFA5B5AAFFA6BAAEFFBBD1C5FFCDE3D7FFCAE0D4FFC0D5CCFFBCD1C8FF
+ B6CBC2FFAFC4BBFFA9BEB6FFAABFB7FFACC0BBFFAEC2BDFF848B88FF7D8481FF
+ 7C8380FF818885FF848D8AFF868F8CFF8A9390FF8F9895FFB1BCB9FFA6B1AEFF
+ 9CAAA6FFBECCC8FFCBD9D5FFB7C5C1FFB3C2BEFFACBBB7FFA3B1ADFFADBBB7FF
+ B4C2BEFFB4C2BEFFB1BFBBFFB1BFBBFFB0BEBAFFACBAB6FFA9B7B3FFACBAB6FF
+ A9B7B3FFA1AFABFFA0AEAAFFA8B6B2FFB1BFBBFFB6C4C0FFAEBCB8FFB5C3BFFF
+ B5C3BFFFADBBB7FFA9B7B3FFABB9B5FFABB9B5FFA6B4B0FFA5B3AFFFA0AEAAFF
+ 9CAAA6FF9BA9A5FF9EACA8FFA0AEAAFF9EACA8FF9CAAA6FF98A6A2FF99A7A3FF
+ 9BA9A5FF9FADA9FFA2B0ACFFA2B0ACFF9FADA9FF9CAAA6FF9AA8A4FF97A5A1FF
+ 8C9A96FFA0AEAAFF8C9A96FF8E9C98FF818F8BFF8F9D99FF8F9A97FF8F9A97FF
+ 8F9A97FF8D9895FF8B9693FF899491FF87928FFF85908DFF899491FF899491FF
+ 899491FF899491FF899491FF889390FF889390FF889390FF818C89FF828D8AFF
+ 848F8CFF808B88FF77827FFF727D7AFF7B8683FF899491FF8E9996FF7A8582FF
+ 818C89FF8C9794FF889390FF9BA6A3FFB7C2BFFFB8C6C2FFBBCECBFFB6CBC8FF
+ B4C9C6FFB8CDCAFFC0D5D2FFC4D9D6FFC2D7D4FFBED3D0FFA8BDBAFFB1C6C3FF
+ BCD1CEFFC4D9D6FFC5DAD7FFC2D7D4FFBFD4D1FFBED1CEFFD1E0DCFF72807CFF
+ 596763FF96A4A0FF889692FF85938FFF93A19DFF95A39FFF8C9A96FF8E9C98FF
+ 8E9C98FF899793FF84928EFF85938FFF8D9B97FF94A29EFF96A5A1FF95A4A0FF
+ 93A29EFF91A09CFF909F9BFF909F9BFF909F9BFF91A09CFF96A5A1FF95A4A0FF
+ 93A29EFF92A19DFF94A39FFF9AA9A5FFA4B3AFFFABBAB6FFA4B2AEFFA2B0ACFF
+ A2B0ACFFA4B2AEFFA5B3AFFFA0AEAAFF95A39FFF8D9B97FF95A39FFF99A7A3FF
+ 9CAAA6FF99A7A3FF92A09CFF8E9C98FF8F9D99FF91A09CFF92A39FFFB1C5C0FF
+ BDD1CCFFAEC2BDFFA4B8B3FFA3B7B2FFADC1BCFFBFD3CEFFC1D5D0FFC1D5D0FF
+ C1D5D0FFB6CAC5FFADC1BCFF849893FF98ACA7FF9EAFABFF94A39FFF9BA9A5FF
+ A2B0ACFFA5B3AFFFA3B1ADFFA0AEAAFFA0AEAAFFA1AFABFFA1AFABFF9AA8A4FF
+ 93A19DFF93A19DFF9AA8A4FFA2B0ACFFA6B4B0FFA6B4B0FFA1AFABFF9CAAA6FF
+ A2B0ACFFA1AFABFF94A29EFF95A39FFF9CAAA6FF99A7A3FFA0AEAAFF9BA9A5FF
+ 9AA8A4FF9CAAA6FF98A6A2FF909E9AFF909E9AFF97A5A1FF95A39FFF97A5A1FF
+ 9FADA9FFA7B5B1FFA5B3AFFF9CAAA6FF9CAAA6FFA3B1ADFFA6B4B0FF9EACA8FF
+ 96A4A0FF95A39FFF98A6A2FF98A6A2FF94A29EFF8E9C98FF748280FF849290FF
+ 889692FF8E9C98FF53615DFF778581FF707C76FF8A9690FF828D85FF8A958DFF
+ 929D95FF8F9A92FF879086FF828B81FF858E84FF8C958BFF879288FF859086FF
+ 828D83FF7F8A80FF7F8A80FF818C82FF848F85FF869187FF818C82FF828D83FF
+ 808B81FF7E897FFF818C82FF848F85FF7F8A80FF778278FF788076FF7A8278FF
+ 8A9288FF959D93FF97A096FFA2ABA1FFACB5ABFFA6AFA5FFA4AFA5FFA2ADA3FF
+ 9FADA2FFA1AFA4FFA5B3A8FFA7B5AAFFA4B4A9FFA2B2A7FFA5B3A8FFA5B3A8FF
+ A7B5AAFFA9B7ACFFA9B7ACFFA6B4A9FFA2B0A5FF9FADA2FFB3C1B6FFA5B3A8FF
+ 9DABA0FFA3B1A6FFA6B4A9FFA0AEA3FF9FADA2FFA2B2A7FFA2B6AAFFB5CBBFFF
+ C4DACEFFC1D7CBFFB9CEC5FFB6CBC2FFB1C6BDFFA9BEB5FFAEC3BBFFADC2BAFF
+ ACC0BBFFACC0BBFF3C4340FF6D7471FF868D8AFF757C79FF6E7774FF868F8CFF
+ 909996FF828B88FFABB6B3FFA6B1AEFFB2C0BCFFCBD9D5FFCBD9D5FFB6C4C0FF
+ AEBDB9FFBBCAC6FFA5B3AFFFACBAB6FFB1BFBBFFB1BFBBFFB3C1BDFFB6C4C0FF
+ B1BFBBFFA9B7B3FFA6B4B0FFAEBCB8FFB1BFBBFFABB9B5FFA5B3AFFFA7B5B1FF
+ ABB9B5FFACBAB6FFADBBB7FFB1BFBBFFB6C4C0FFB5C3BFFFA8B6B2FF9DABA7FF
+ A1AFABFFACBAB6FFA4B2AEFF9FADA9FF9DABA7FFA0AEAAFFA0AEAAFF9DABA7FF
+ 9DABA7FFA0AEAAFF99A7A3FF9BA9A5FF9EACA8FF9EACA8FF9DABA7FF9BA9A5FF
+ 9BA9A5FF9BA9A5FF9AA8A4FF9CAAA6FF919F9BFF93A19DFF9EACA8FF8A9894FF
+ 768480FF82908CFF8C9794FF87928FFF909B98FF95A09DFF8B9693FF899491FF
+ 8E9996FF8A9592FF87928FFF848F8CFF818C89FF828D8AFF85908DFF87928FFF
+ 85908DFF838E8BFF838E8BFF848F8CFF848F8CFF838E8BFF808B88FF7C8784FF
+ 77827FFF747F7CFF848F8CFF8A9592FF8A9592FF828D8AFF828D8AFF939E9BFF
+ ABB6B3FFB9C7C3FFBFD2CFFFB7CCC9FFB7CCC9FFBDD2CFFFC3D8D5FFC3D8D5FF
+ C4D9D6FFC7DCD9FFB1C6C3FFA8BDBAFFA9BEBBFFB8CDCAFFC6DBD8FFC7DCD9FF
+ C4D9D6FFC5D8D5FFD4E3DFFF586662FF5A6864FF899793FF94A29EFF8F9D99FF
+ 818F8BFF93A19DFF899793FF899793FF8F9D99FF93A19DFF8B9995FF818F8BFF
+ 869490FF94A29EFF8F9E9AFF909F9BFF91A09CFF92A19DFF94A39FFF95A4A0FF
+ 96A5A1FF97A6A2FF909F9BFF96A5A1FF9BAAA6FF98A7A3FF8F9E9AFF8C9B97FF
+ 97A6A2FFA5B4B0FFA8B6B2FFA0AEAAFF9CAAA6FFA2B0ACFFA7B5B1FFA0AEAAFF
+ 95A39FFF8E9C98FF8B9995FF8F9D99FF97A5A1FF9CAAA6FF96A4A0FF8D9B97FF
+ 8D9B97FF92A19DFF8B9C98FFA3B7B2FFB6CAC5FFB4C8C3FFACC0BBFFAEC2BDFF
+ B3C7C2FFB4C8C3FFC2D6D1FFC4D8D3FFC2D6D1FFB3C7C2FFB5C9C4FF788C87FF
+ A6BAB5FFA7B8B4FF9BAAA6FF98A6A2FF98A6A2FF9DABA7FFA0AEAAFF9DABA7FF
+ 9BA9A5FF9CAAA6FFA3B1ADFFA4B2AEFF9FADA9FF9BA9A5FF9FADA9FFA5B3AFFF
+ A1AFABFF96A4A0FF9CAAA6FF9AA8A4FF99A7A3FF9CAAA6FFA0AEAAFFA1AFABFF
+ 9FADA9FF9CAAA6FF9DABA7FF9CAAA6FF9DABA7FF9EACA8FF99A7A3FF92A09CFF
+ 93A19DFF98A6A2FF9CAAA6FF9AA8A4FF9AA8A4FF9DABA7FFA1AFABFFA1AFABFF
+ 9DABA7FF99A7A3FF9FADA9FF97A5A1FF919F9BFF93A19DFF95A39FFF92A09CFF
+ 8D9B97FF899793FF849290FF748280FF8A9894FF798783FF73817DFF697773FF
+ 7E8A84FF88948EFF848F87FF859088FF87928AFF89948CFF8A9389FF889187FF
+ 858E84FF848D83FF8B968CFF848F85FF7F8A80FF808B81FF7C877DFF758076FF
+ 768177FF7D887EFF869187FF859086FF859086FF859086FF879288FF8A958BFF
+ 8D988EFF8F9A90FF959D93FF979F95FF9AA298FF9CA49AFF9CA59BFFA0A99FFF
+ A5AEA4FFA8B1A7FFABB6ACFFABB6ACFFA7B5AAFFA3B1A6FF9FADA2FF9EACA1FF
+ 9EAEA3FFA1B1A6FFA3B1A6FFA7B5AAFFA9B7ACFFA9B7ACFFA9B7ACFFA9B7ACFF
+ A2B0A5FF99A79CFFA0AEA3FFA4B2A7FFA7B5AAFFA6B4A9FFA1AFA4FF9DABA0FF
+ 9DABA0FF9DADA2FFA2B6AAFFB4CABEFFC5DBCFFFC5DBCFFFBBD0C7FFB3C8BFFF
+ AFC4BBFFADC2B9FFAFC4BCFFAEC3BBFFACC0BBFFA9BDB8FF424946FF5A615EFF
+ 6C7370FF6E7572FF6F7875FF7E8784FF89928FFF8A9390FF99A4A1FFA5B0ADFF
+ A7B5B1FFA7B5B1FFB9C7C3FFCEDCD8FFC0CFCBFFA2B1ADFFB4C2BEFFB3C1BDFF
+ AFBDB9FFA9B7B3FFA4B2AEFFA4B2AEFFACBAB6FFB3C1BDFFA5B3AFFFAAB8B4FF
+ AAB8B4FFA5B3AFFFA3B1ADFFA6B4B0FFA8B6B2FFA7B5B1FFB0BEBAFFB1BFBBFF
+ B1BFBBFFADBBB7FFA9B7B3FFA7B5B1FFA8B6B2FFAAB8B4FF9BA9A5FF9CAAA6FF
+ 9FADA9FFA3B1ADFFA1AFABFF9DABA7FFA0AEAAFFA7B5B1FF9AA8A4FF9AA8A4FF
+ 9BA9A5FF9CAAA6FF9DABA7FF9CAAA6FF9AA8A4FF99A7A3FF9CAAA6FF9BA9A5FF
+ 94A29EFF95A39FFF9AA8A4FF8D9B97FF7D8B87FF7B8985FF8F9A97FF889390FF
+ 8A9592FF899491FF828D8AFF828D8AFF889390FF86918EFF8C9794FF889390FF
+ 86918EFF86918EFF899491FF8C9794FF8C9794FF8A9592FF848F8CFF85908DFF
+ 85908DFF848F8CFF838E8BFF808B88FF7E8986FF7D8885FF7B8683FF7F8A87FF
+ 7F8A87FF7C8784FF848F8CFF9CA7A4FFB7C2BFFFC6D4D0FFBFD2CFFFB9CECBFF
+ BACFCCFFBFD4D1FFC3D8D5FFC2D7D4FFC4D9D6FFC7DCD9FFB7CCC9FFADC2BFFF
+ ABC0BDFFB6CBC8FFC3D8D5FFC8DDDAFFC8DDDAFFCBDEDBFFD8E7E3FF495753FF
+ 677571FF717F7BFF808E8AFF879591FF85938FFF96A4A0FF8B9995FF869490FF
+ 879591FF8C9A96FF8A9894FF84928EFF889692FF93A19DFF8D9C98FF8D9C98FF
+ 8F9E9AFF91A09CFF93A29EFF95A4A0FF96A5A1FF97A6A2FF8F9E9AFF91A09CFF
+ 93A29EFF94A39FFF91A09CFF909F9BFF93A29EFF98A7A3FFA5B3AFFFA0AEAAFF
+ A0AEAAFFA6B4B0FFA8B6B2FFA0AEAAFF97A5A1FF93A19DFF8D9B97FF8C9A96FF
+ 909E9AFF96A4A0FF95A39FFF909E9AFF8E9C98FF909F9BFF82938FFF9DB1ACFF
+ B6CAC5FFB9CDC8FFB4C8C3FFB6CAC5FFB9CDC8FFB9CDC8FFBBCFCAFFBDD1CCFF
+ BDD1CCFFB0C4BFFFB4C8C3FF7A8E89FFA8BCB7FFA9BAB6FF9AA9A5FF97A5A1FF
+ 98A6A2FF9EACA8FFA1AFABFF9EACA8FF9BA9A5FF9CAAA6FF9EACA8FF9CAAA6FF
+ 97A5A1FF94A29EFF9AA8A4FFA5B3AFFFA6B4B0FFA1AFABFF9FADA9FF9DABA7FF
+ 9CAAA6FF9DABA7FFA0AEAAFFA1AFABFFA0AEAAFF9EACA8FFA2B0ACFFA1AFABFF
+ A2B0ACFFA2B0ACFF9AA8A4FF8E9C98FF889692FF899793FF99A7A3FF99A7A3FF
+ 9BA9A5FF9EACA8FFA1AFABFFA0AEAAFF9BA9A5FF96A4A0FF9DABA7FF96A4A0FF
+ 909E9AFF909E9AFF919F9BFF8E9C98FF889692FF84928EFF7F8D8BFF778583FF
+ 899793FF7E8C88FF6C7A76FF62706CFF77837DFF87938DFF869189FF88938BFF
+ 8A958DFF8C978FFF8E978DFF8D968CFF8A9389FF899288FF8B968CFF848F85FF
+ 808B81FF808B81FF7C877DFF768177FF788379FF7F8A80FF828D83FF828D83FF
+ 838E84FF859086FF879288FF8A958BFF8C978DFF8E998FFF90988EFF8F978DFF
+ 8D958BFF8D958BFF8F988EFF98A197FFA3ACA2FFABB4AAFFA7B2A8FFA8B3A9FF
+ A5B3A8FFA2B0A5FF9EACA1FF9CAA9FFF9BABA0FF9DADA2FFA3B1A6FFA5B3A8FF
+ A5B3A8FFA3B1A6FFA4B2A7FFA5B3A8FFA1AFA4FF9AA89DFF9DABA0FF9FADA2FF
+ A1AFA4FFA2B0A5FF9FADA2FF9DABA0FF9CAA9FFF9AAA9FFFA8BCB0FFB6CCC0FF
+ C4DACEFFC6DCD0FFC0D5CCFFB8CDC4FFAFC4BBFFA8BDB4FFACC1B9FFABC0B8FF
+ AABEB9FFA8BCB7FF656C69FF626966FF676E6BFF737A77FF757E7BFF737C79FF
+ 7A8380FF87908DFF8F9A97FFA0ABA8FF9AA8A4FF8C9A96FF9DABA7FFC0CECAFF
+ BCCBC7FF9BAAA6FFA8B6B2FF9DABA7FF9EACA8FFAFBDB9FFBBC9C5FFB4C2BEFF
+ A7B5B1FFA0AEAAFFA4B2AEFFA7B5B1FFA5B3AFFFA0AEAAFF9EACA8FFA2B0ACFF
+ A4B2AEFFA2B0ACFFAFBDB9FFB0BEBAFFABB9B5FFA3B1ADFFA5B3AFFFACBAB6FF
+ A9B7B3FF9EACA8FF93A19DFF98A6A2FFA0AEAAFFA4B2AEFF9FADA9FF99A7A3FF
+ 9DABA7FFA5B3AFFF9CAAA6FF99A7A3FF97A5A1FF99A7A3FF9DABA7FF9DABA7FF
+ 9AA8A4FF96A4A0FF9BA9A5FF95A39FFF96A4A0FF97A5A1FF95A39FFF95A39FFF
+ 8B9995FF768480FF99A4A1FF929D9AFF8B9693FF85908DFF838E8BFF85908DFF
+ 899491FF8A9592FF8F9A97FF8C9794FF899491FF889390FF8B9693FF8E9996FF
+ 8F9A97FF909B98FF87928FFF87928FFF86918EFF85908DFF85908DFF85908DFF
+ 86918EFF86918EFF848F8CFF87928FFF87928FFF86918EFF8F9A97FFA3AEABFF
+ B6C1BEFFBDCBC7FFBDD0CDFFB9CECBFFBCD1CEFFC1D6D3FFC2D7D4FFC0D5D2FF
+ C2D7D4FFC8DDDAFFBFD4D1FFB6CBC8FFB0C5C2FFB7CCC9FFC1D6D3FFC8DDDAFF
+ CCE1DEFFD2E5E2FFDDECE8FF44524EFF74827EFF6F7D79FF788682FF808E8AFF
+ 8F9D99FF99A7A3FF8C9A96FF82908CFF7F8D89FF85938FFF879591FF84928EFF
+ 889692FF92A09CFF8A9995FF8B9A96FF8C9B97FF8E9D99FF909F9BFF92A19DFF
+ 93A29EFF94A39FFF909F9BFF8E9D99FF8D9C98FF909F9BFF96A5A1FF98A7A3FF
+ 94A39FFF8E9D99FF9EACA8FF9BA9A5FF9EACA8FFA5B3AFFFA6B4B0FF9FADA9FF
+ 96A4A0FF93A19DFF919F9BFF8B9995FF8B9995FF919F9BFF94A29EFF92A09CFF
+ 8F9D99FF8F9E9AFF7D8E8AFF9AAEA9FFB7CBC6FFBFD3CEFFBED2CDFFC0D4CFFF
+ C1D5D0FFBFD3CEFFC3D7D2FFC3D7D2FFBFD3CEFFAFC3BEFFB0C4BFFF738782FF
+ 9FB3AEFF9EAFABFF99A8A4FF96A4A0FF98A6A2FF9EACA8FFA1AFABFF9EACA8FF
+ 9CAAA6FF9DABA7FF9DABA7FF99A7A3FF92A09CFF8E9C98FF95A39FFFA1AFABFF
+ A7B5B1FFA6B4B0FFA5B3AFFFA2B0ACFF9FADA9FF9EACA8FF9FADA9FFA1AFABFF
+ A1AFABFFA0AEAAFF98A6A2FF9AA8A4FFA0AEAAFFA6B4B0FFA3B1ADFF99A7A3FF
+ 92A09CFF92A09CFF96A4A0FF97A5A1FF9AA8A4FF9DABA7FFA0AEAAFF9FADA9FF
+ 9AA8A4FF97A5A1FF97A5A1FF93A19DFF8E9C98FF8D9B97FF8D9B97FF8D9B97FF
+ 889692FF83918DFF7F8D8BFF7F8D8BFF899793FF889692FF697773FF5F6D69FF
+ 737F79FF87938DFF87928AFF89948CFF8D9890FF8F9A92FF929B91FF919A90FF
+ 8F988EFF8E978DFF8A958BFF869187FF838E84FF818C82FF7C877DFF79847AFF
+ 7C877DFF838E84FF818C82FF828D83FF859086FF879288FF8A958BFF8C978DFF
+ 8D988EFF8E998FFF949C92FF90988EFF899187FF848C82FF848D83FF8D968CFF
+ 9CA59BFFA6AFA5FFADB8AEFFAFBAB0FFAEBCB1FFADBBB0FFAAB8ADFFA7B5AAFF
+ A5B5AAFFA6B6ABFFA9B7ACFFAAB8ADFFA8B6ABFFA5B3A8FFA6B4A9FFA9B7ACFF
+ A7B5AAFFA2B0A5FF9FADA2FF9FADA2FF9FADA2FFA1AFA4FFA2B0A5FFA1AFA4FF
+ 9EACA1FF9AAA9FFFACC0B4FFB6CCC0FFC1D7CBFFC4DACEFFC2D7CEFFBDD2C9FF
+ B3C8BFFFA9BEB5FFA9BEB6FFA9BEB6FFA8BCB7FFA7BBB6FF787F7CFF6F7673FF
+ 6F7673FF787F7CFF77807DFF707976FF737C79FF7F8885FF7E8986FF85908DFF
+ 8B9995FF8F9D99FF93A19DFF9EACA8FFB1C0BCFFC2D1CDFFA3B1ADFFA2B0ACFF
+ ABB9B5FFB3C1BDFFA9B7B3FF98A6A2FF9EACA8FFB1BFBBFFA3B1ADFFA8B6B2FF
+ A8B6B2FFA0AEAAFF9BA9A5FF9CAAA6FF9FADA9FF9FADA9FFA5B3AFFFADBBB7FF
+ AAB8B4FFA0AEAAFFA1AFABFFAAB8B4FFA3B1ADFF919F9BFF92A09CFF95A39FFF
+ 9BA9A5FFA1AFABFF9EACA8FF98A6A2FF96A4A0FF9AA8A4FF9DABA7FF98A6A2FF
+ 94A29EFF97A5A1FF9CAAA6FF9EACA8FF9AA8A4FF95A39FFF97A5A1FF8F9D99FF
+ 96A4A0FF99A7A3FF92A09CFF9CAAA6FF98A6A2FF788682FF98A3A0FF98A3A0FF
+ 8D9895FF848F8CFF899491FF8C9794FF8B9693FF8D9895FF8E9996FF8C9794FF
+ 899491FF87928FFF889390FF8A9592FF8D9895FF8E9996FF8B9693FF899491FF
+ 87928FFF85908DFF85908DFF86918EFF889390FF8A9592FF929D9AFF96A19EFF
+ 97A29FFF98A3A0FFA0ABA8FFACB7B4FFB2BDBAFFB0BEBAFFB8CBC8FFB6CBC8FF
+ BACFCCFFBFD4D1FFC0D5D2FFBED3D0FFC1D6D3FFC7DCD9FFC6DBD8FFBFD4D1FF
+ BACFCCFFBBD0CDFFC1D6D3FFC7DCD9FFCBE0DDFFD0E3E0FFD5E4E0FF53615DFF
+ 62706CFF84928EFF7D8B87FF73817DFF92A09CFF96A4A0FF8C9A96FF82908CFF
+ 7D8B87FF808E8AFF7F8D89FF7D8B87FF84928EFF919F9BFF8A9995FF8B9A96FF
+ 8B9A96FF8C9B97FF8D9C98FF8E9D99FF8F9E9AFF8F9E9AFF909F9BFF8E9D99FF
+ 8D9C98FF8F9E9AFF97A6A2FF9DACA8FF9AA9A5FF93A29EFF99A7A3FF94A29EFF
+ 96A4A0FFA0AEAAFFA5B3AFFF9EACA8FF94A29EFF8E9C98FF95A39FFF909E9AFF
+ 8F9D99FF92A09CFF92A09CFF8F9D99FF909E9AFF92A19DFF839490FF9FB3AEFF
+ BACEC9FFC2D6D1FFC1D5D0FFC4D8D3FFC5D9D4FFC2D6D1FFC6DAD5FFC5D9D4FF
+ BFD3CEFFAEC2BDFFB0C4BFFF718580FF9BAFAAFF99AAA6FF99A8A4FF96A4A0FF
+ 96A4A0FF9DABA7FFA0AEAAFF9EACA8FF9CAAA6FF9EACA8FFA2B0ACFF9DABA7FF
+ 95A39FFF92A09CFF95A39FFF9CAAA6FFA0AEAAFFA1AFABFFA8B6B2FFA6B4B0FF
+ A2B0ACFF9FADA9FF9FADA9FFA0AEAAFFA1AFABFFA2B0ACFF8E9C98FF909E9AFF
+ 98A6A2FFA2B0ACFFA4B2AEFF9EACA8FF9AA8A4FF9BA9A5FF95A39FFF96A4A0FF
+ 97A5A1FF9AA8A4FF9CAAA6FF9EACA8FF9EACA8FF9DABA7FF92A09CFF92A09CFF
+ 8F9D99FF8C9A96FF8D9B97FF8F9D99FF8C9A96FF879591FF859391FF879593FF
+ 879591FF919F9BFF6F7D79FF606E6AFF75817BFF85918BFF859088FF88938BFF
+ 8B968EFF8E9991FF929B91FF929B91FF90998FFF8F988EFF8A958BFF89948AFF
+ 869187FF828D83FF7D887EFF7B867CFF808B81FF869187FF848F85FF869187FF
+ 89948AFF8C978DFF8E998FFF8E998FFF8D988EFF8D988EFF9DA59BFF99A197FF
+ 929A90FF8B9389FF879086FF8C958BFF959E94FF9CA59BFFA1ACA2FFA4AFA5FF
+ A6B4A9FFA6B4A9FFA5B3A8FFA3B1A6FFA1B1A6FFA2B2A7FFA8B6ABFFABB9AEFF
+ AAB8ADFFA8B6ABFFAAB8ADFFADBBB0FFAAB8ADFFA4B2A7FFA6B4A9FFA4B2A7FF
+ A2B0A5FFA4B2A7FFA7B5AAFFA7B5AAFFA2B0A5FF9BABA0FFACC0B4FFB6CCC0FF
+ C0D6CAFFC0D6CAFFBDD2C9FFBBD0C7FFB6CBC2FFB1C6BDFFAABFB7FFA9BEB6FF
+ A8BCB7FFA7BBB6FF636A67FF686F6CFF6D7471FF707774FF707976FF747D7AFF
+ 7A8380FF7E8784FF848F8CFF85908DFF8D9B97FF909E9AFF7A8884FF616F6BFF
+ 657470FF7D8C88FF717F7BFF64726EFF6C7A76FF909E9AFFADBBB7FFB1BFBBFF
+ ABB9B5FFAAB8B4FFA1AFABFFAAB8B4FFADBBB7FFA4B2AEFF99A7A3FF97A5A1FF
+ 9BA9A5FF9DABA7FF93A19DFFA5B3AFFFACBAB6FFA5B3AFFFA3B1ADFFA8B6B2FF
+ A0AEAAFF909E9AFF93A19DFF909E9AFF94A29EFF9EACA8FFA3B1ADFF9FADA9FF
+ 9AA8A4FF98A6A2FF9EACA8FF98A6A2FF94A29EFF96A4A0FF9CAAA6FF9EACA8FF
+ 9AA8A4FF95A39FFF99A7A3FF919F9BFF98A6A2FF99A7A3FF919F9BFF9CAAA6FF
+ 9AA8A4FF7C8A86FF848F8CFF909B98FF87928FFF7F8A87FF899491FF8A9592FF
+ 838E8BFF87928FFF8C9794FF8A9592FF889390FF86918EFF86918EFF87928FFF
+ 8A9592FF8C9794FF8E9996FF8B9693FF87928FFF848F8CFF838E8BFF848F8CFF
+ 86918EFF87928FFF95A09DFF97A29FFF97A29FFF99A4A1FFA4AFACFFB3BEBBFF
+ BCC7C4FFBAC8C4FFB4C7C4FFB1C6C3FFB5CAC7FFBCD1CEFFBED3D0FFBCD1CEFF
+ BED3D0FFC3D8D5FFC6DBD8FFC5DAD7FFC2D7D4FFC0D5D2FFC1D6D3FFC3D8D5FF
+ C5DAD7FFC6D9D6FFCAD9D5FF74827EFF33413DFF8D9B97FF7D8B87FF5C6A66FF
+ 899793FF92A09CFF899793FF82908CFF7F8D89FF7E8C88FF778581FF72807CFF
+ 7D8B87FF8F9D99FF8C9B97FF8C9B97FF8B9A96FF8B9A96FF8B9A96FF8A9995FF
+ 8A9995FF8A9995FF8B9A96FF8E9D99FF8E9D99FF8C9B97FF91A09CFF9CABA7FF
+ 9FAEAAFF9CABA7FF9BA9A5FF93A19DFF92A09CFF9DABA7FFA6B4B0FFA2B0ACFF
+ 96A4A0FF8D9B97FF98A6A2FF97A5A1FF98A6A2FF98A6A2FF92A09CFF8C9A96FF
+ 909E9AFF97A6A2FF90A19DFFA8BCB7FFBDD1CCFFC1D5D0FFBFD3CEFFC2D6D1FF
+ C4D8D3FFC2D6D1FFBDD1CCFFBCD0CBFFB9CDC8FFACC0BBFFB2C6C1FF788C87FF
+ A4B8B3FFA2B3AFFF9AA9A5FF96A4A0FF94A29EFF99A7A3FF9CAAA6FF9BA9A5FF
+ 9BA9A5FF9EACA8FFA4B2AEFF9FADA9FF9BA9A5FF9AA8A4FF9AA8A4FF9AA8A4FF
+ 9BA9A5FF9DABA7FFA8B6B2FFA6B4B0FFA3B1ADFFA0AEAAFF9EACA8FF9EACA8FF
+ A0AEAAFFA2B0ACFF98A6A2FF95A39FFF96A4A0FF9BA9A5FF9AA8A4FF94A29EFF
+ 909E9AFF919F9BFF94A29EFF94A29EFF94A29EFF94A29EFF97A5A1FF9BA9A5FF
+ A0AEAAFFA4B2AEFF96A4A0FF98A6A2FF95A39FFF8F9D99FF8E9C98FF909E9AFF
+ 8E9C98FF879591FF899795FF879593FF83918DFF909E9AFF798783FF5F6D69FF
+ 7A8680FF7F8B85FF818C84FF848F87FF88938BFF8B968EFF8F988EFF8F988EFF
+ 8E978DFF8D968CFF8B968CFF8D988EFF8A958BFF838E84FF7D887EFF7D887EFF
+ 848F85FF89948AFF879288FF889389FF8A958BFF8C978DFF8D988EFF8C978DFF
+ 8B968CFF8A958BFF939B91FF959D93FF969E94FF969E94FF959E94FF969F95FF
+ 99A298FF9BA49AFF9EA99FFFA1ACA2FFA4B2A7FFA6B4A9FFA5B3A8FFA5B3A8FF
+ A4B4A9FFA5B5AAFF9FADA2FFA3B1A6FFA6B4A9FFA6B4A9FFA8B6ABFFAAB8ADFF
+ A5B3A8FF9DABA0FFAAB8ADFFA7B5AAFFA5B3A8FFA6B4A9FFA8B6ABFFA6B4A9FF
+ A1AFA4FF9AAA9FFFB2C6BAFFBDD3C7FFC4DACEFFBDD3C7FFB3C8BFFFAFC4BBFF
+ B2C7BEFFB4C9C0FFABC0B8FFAABFB7FFA8BCB7FFA6BAB5FF5A615EFF676E6BFF
+ 6D7471FF6B726FFF6D7673FF79827FFF7E8784FF79827FFF9CA7A4FFA7B2AFFF
+ AAB8B4FF9DABA7FF84928EFF667470FF495854FF374642FF42504CFF2A3834FF
+ 263430FF4C5A56FF808E8AFF9DABA7FF9EACA8FF97A5A1FF9BA9A5FFA5B3AFFF
+ A9B7B3FFA2B0ACFF99A7A3FF97A5A1FF98A6A2FF98A6A2FF869490FF9AA8A4FF
+ A9B7B3FFAAB8B4FFA7B5B1FFA6B4B0FFA1AFABFF98A6A2FF8F9D99FF8A9894FF
+ 8E9C98FF9BA9A5FFA7B5B1FFA8B6B2FFA3B1ADFFA0AEAAFF9EACA8FF9AA8A4FF
+ 96A4A0FF97A5A1FF9BA9A5FF9DABA7FF9BA9A5FF98A6A2FF9DABA7FF99A7A3FF
+ 9AA8A4FF99A7A3FF94A29EFF96A4A0FF93A19DFF84928EFF6C7774FF86918EFF
+ 828D8AFF788380FF86918EFF848F8CFF77827FFF7E8986FF848F8CFF85908DFF
+ 86918EFF86918EFF86918EFF86918EFF899491FF8B9693FF8E9996FF8C9794FF
+ 889390FF848F8CFF828D8AFF828D8AFF838E8BFF838E8BFF9AA5A2FF98A3A0FF
+ 929D9AFF8F9A97FF98A3A0FFACB7B4FFBCC7C4FFC1CFCBFFB6C9C6FFB0C5C2FF
+ B2C7C4FFB9CECBFFBDD2CFFFBBD0CDFFB9CECBFFBACFCCFFBFD4D1FFC3D8D5FF
+ C3D8D5FFBDD2CFFFBACFCCFFBBD0CDFFBBD0CDFFBBCECBFFC7D6D2FF9DABA7FF
+ 15231FFF7C8A86FF808E8AFF54625EFF7F8D89FF93A19DFF85938FFF818F8BFF
+ 7E8C88FF7C8A86FF72807CFF6C7A76FF788682FF8B9995FF8B9A96FF8B9A96FF
+ 8B9A96FF8A9995FF899894FF899894FF889793FF889793FF869591FF8D9C98FF
+ 8E9D99FF899894FF8C9B97FF98A7A3FF9FAEAAFF9EADA9FFA0AEAAFF98A6A2FF
+ 96A4A0FFA0AEAAFFA8B6B2FFA5B3AFFF9BA9A5FF94A29EFF99A7A3FF9AA8A4FF
+ 9DABA7FF9DABA7FF95A39FFF8E9C98FF93A19DFF9BAAA6FF9AABA7FFAEC2BDFF
+ BED2CDFFBED2CDFFBCD0CBFFC0D4CFFFC2D6D1FFC0D4CFFFC1D5D0FFBED2CDFF
+ B9CDC8FFABBFBAFFB1C5C0FF768A85FFA0B4AFFF9DAEAAFF9DACA8FF96A4A0FF
+ 92A09CFF94A29EFF97A5A1FF97A5A1FF99A7A3FF9DABA7FFA1AFABFF9DABA7FF
+ 9DABA7FFA0AEAAFF9FADA9FF9CAAA6FF9BA9A5FF9EACA8FFA4B2AEFFA4B2AEFF
+ A3B1ADFFA0AEAAFF9DABA7FF9DABA7FF9FADA9FFA1AFABFFA5B3AFFF9FADA9FF
+ 9BA9A5FF9CAAA6FF9BA9A5FF95A39FFF92A09CFF93A19DFF919F9BFF92A09CFF
+ 919F9BFF919F9BFF92A09CFF96A4A0FF9CAAA6FFA1AFABFF9AA8A4FF9FADA9FF
+ 9BA9A5FF909E9AFF8C9A96FF8E9C98FF8B9995FF82908CFF879593FF818F8DFF
+ 818F8BFF899793FF84928EFF566460FF7F8B85FF7A8680FF808B83FF828D85FF
+ 869189FF89948CFF8D968CFF8D968CFF8B948AFF8A9389FF8D988EFF919C92FF
+ 8F9A90FF848F85FF7C877DFF7F8A80FF869187FF8B968CFF879288FF879288FF
+ 89948AFF8A958BFF8A958BFF8B968CFF8A958BFF8A958BFF7F877DFF878F85FF
+ 91998FFF9AA298FF9FA89EFFA2ABA1FFA4ADA3FFA6AFA5FF9FAAA0FFA2ADA3FF
+ A3B1A6FFA4B2A7FFA4B2A7FFA4B2A7FFA3B3A8FFA5B5AAFF9BA99EFFA1AFA4FF
+ A5B3A8FFA6B4A9FFA9B7ACFFAAB8ADFFA4B2A7FF9CAA9FFFA3B1A6FFA2B0A5FF
+ A2B0A5FFA3B1A6FFA3B1A6FFA1AFA4FF9DABA0FF98A89DFFBCD0C4FFC5DBCFFF
+ CAE0D4FFBED4C8FFAEC3BAFFA8BDB4FFAABFB6FFAEC3BAFFABC0B8FFAABFB7FF
+ A8BCB7FFA6BAB5FF6A716EFF6B726FFF6A716EFF6B726FFF727B78FF7C8582FF
+ 7C8582FF757E7BFF909B98FFA9B4B1FFB9C7C3FFBAC8C4FFB8C6C2FFB4C2BEFF
+ 9DACA8FF82918DFF73817DFF6F7D79FF5F6D69FF45534FFF35433FFF43514DFF
+ 6E7C78FF93A19DFF93A19DFF98A6A2FF9BA9A5FF9AA8A4FF9BA9A5FF9BA9A5FF
+ 96A4A0FF8E9C98FF85938FFF92A09CFFA0AEAAFFA8B6B2FFA5B3AFFF9EACA8FF
+ 98A6A2FF95A39FFF879591FF85938FFF8B9995FF98A6A2FFA3B1ADFFA5B3AFFF
+ A4B2AEFFA5B3AFFF9DABA7FF9CAAA6FF9AA8A4FF99A7A3FF9AA8A4FF9BA9A5FF
+ 9CAAA6FF9CAAA6FF9AA8A4FF9BA9A5FF96A4A0FF96A4A0FF99A7A3FF93A19DFF
+ 8E9C98FF95A39FFF56615EFF7A8582FF788380FF6C7774FF7A8582FF75807DFF
+ 66716EFF717C79FF75807DFF798481FF7F8A87FF828D8AFF838E8BFF85908DFF
+ 889390FF8B9693FF8C9794FF8A9592FF889390FF85908DFF838E8BFF828D8AFF
+ 828D8AFF828D8AFF97A29FFF97A29FFF939E9BFF8F9A97FF95A09DFFA5B0ADFF
+ B5C0BDFFBAC8C4FFBED1CEFFB5CAC7FFB2C7C4FFB9CECBFFBED3D0FFBBD0CDFF
+ B4C9C6FFB0C5C2FFB4C9C6FFBACFCCFFBBD0CDFFB4C9C6FFAFC4C1FFB2C7C4FF
+ B4C9C6FFB3C6C3FFBDCCC8FFB5C3BFFF1A2824FF586662FF8C9A96FF5D6B67FF
+ 6D7B77FF889692FF83918DFF7C8A86FF788682FF788682FF72807CFF6D7B77FF
+ 778581FF879591FF889793FF889793FF899894FF899894FF8A9995FF8A9995FF
+ 8B9A96FF8B9A96FF879692FF909F9BFF91A09CFF8B9A96FF8F9E9AFF9BAAA6FF
+ 9FAEAAFF98A7A3FFA0AEAAFF9DABA7FF9EACA8FFA3B1ADFFA4B2AEFF9FADA9FF
+ 9DABA7FF9EACA8FF98A6A2FF98A6A2FF9AA8A4FF9DABA7FF9AA8A4FF95A39FFF
+ 97A5A1FF9CABA7FF9AABA7FFADC1BCFFBDD1CCFFBED2CDFFBCD0CBFFC0D4CFFF
+ C2D6D1FFBFD3CEFFC8DCD7FFC3D7D2FFBBCFCAFFABBFBAFFAEC2BDFF70847FFF
+ 97ABA6FF91A29EFFA0AFABFF97A5A1FF909E9AFF8F9D99FF919F9BFF92A09CFF
+ 96A4A0FF9CAAA6FFA2B0ACFF9DABA7FF9DABA7FFA1AFABFFA0AEAAFF9AA8A4FF
+ 9AA8A4FF9FADA9FF9FADA9FFA1AFABFFA2B0ACFFA0AEAAFF9DABA7FF9BA9A5FF
+ 9CAAA6FF9FADA9FFA8B6B2FFA1AFABFF9DABA7FF9FADA9FF9FADA9FF9AA8A4FF
+ 96A4A0FF96A4A0FF8D9B97FF8F9D99FF919F9BFF919F9BFF8F9D99FF8E9C98FF
+ 919F9BFF93A19DFF94A29EFF9BA9A5FF99A7A3FF8D9B97FF889692FF8D9B97FF
+ 8A9894FF818F8BFF83918FFF7C8A88FF889692FF85938FFF8F9D99FF4B5955FF
+ 88948EFF7D8983FF828D85FF848F87FF88938BFF8A958DFF8E978DFF8D968CFF
+ 8C958BFF8A9389FF8F9A90FF95A096FF939E94FF859086FF7C877DFF808B81FF
+ 879288FF8C978DFF889389FF889389FF89948AFF8B968CFF8D988EFF8F9A90FF
+ 919C92FF929D93FF7E867CFF858D83FF90988EFF9AA298FFA0A99FFFA5AEA4FF
+ A9B2A8FFADB6ACFF99A49AFF9AA59BFF99A79CFF97A59AFF95A398FF95A398FF
+ 94A499FF97A79CFF9DABA0FFA1AFA4FFA3B1A6FFA4B2A7FFA7B5AAFFAAB8ADFF
+ A6B4A9FF9FADA2FF99A79CFF9CAA9FFF9FADA2FFA0AEA3FF9EACA1FF9DABA0FF
+ 9CAA9FFF9BABA0FFBFD3C7FFC6DCD0FFCAE0D4FFC0D6CAFFB3C8BFFFADC2B9FF
+ AABFB6FFA9BEB5FFA9BEB6FFA8BDB5FFA6BAB5FFA5B9B4FF717875FF646B68FF
+ 5D6461FF686F6CFF787F7CFF7D8683FF7C8582FF79827FFF7F8885FF939E9BFF
+ ADB8B5FFB8C6C2FFBAC8C4FFB8C6C2FFB5C3BFFFB2C1BDFFA2B0ACFF9AA8A4FF
+ 8E9C98FF869490FF85938FFF808E8AFF6C7A76FF576561FF8D9B97FF8D9B97FF
+ 8D9B97FF92A09CFF9CAAA6FFA0AEAAFF95A39FFF869490FF8B9995FF8E9C98FF
+ 98A6A2FFA1AFABFF9FADA9FF93A19DFF8B9995FF8A9894FF82908CFF83918DFF
+ 8B9995FF95A39FFF9AA8A4FF9AA8A4FF9DABA7FFA2B0ACFF9CAAA6FF9DABA7FF
+ 9CAAA6FF9BA9A5FF99A7A3FF9AA8A4FF9CAAA6FF9FADA9FF92A09CFF98A6A2FF
+ 919F9BFF93A19DFF9FADA9FF93A19DFF8E9C98FFA6B4B0FF424D4AFF6C7774FF
+ 6A7572FF5B6663FF697471FF626D6AFF535E5BFF616C69FF67726FFF6E7976FF
+ 76817EFF7C8784FF7F8A87FF818C89FF85908DFF889390FF8A9592FF899491FF
+ 87928FFF86918EFF848F8CFF848F8CFF838E8BFF838E8BFF85908DFF8D9895FF
+ 949F9CFF97A29FFF9EA9A6FFABB6B3FFB5C0BDFFB7C5C1FFC6D9D6FFB9CECBFF
+ B4C9C6FFB9CECBFFBFD4D1FFBBD0CDFFB0C5C2FFA9BEBBFFACC1BEFFB3C8C5FF
+ B4C9C6FFABC0BDFFA6BBB8FFABC0BDFFAFC4C1FFB1C4C1FFAAB9B5FFB5C3BFFF
+ 273531FF374541FF94A29EFF667470FF586662FF72807CFF82908CFF778581FF
+ 717F7BFF74827EFF74827EFF72807CFF788682FF83918DFF859490FF869591FF
+ 879692FF899894FF8A9995FF8C9B97FF8D9C98FF8E9D99FF8D9C98FF95A4A0FF
+ 95A4A0FF909F9BFF96A5A1FFA1B0ACFF9FAEAAFF93A29EFF9BA9A5FF9EACA8FF
+ A3B1ADFFA4B2AEFF9DABA7FF97A5A1FF9AA8A4FFA3B1ADFF97A5A1FF93A19DFF
+ 94A29EFF9BA9A5FF9EACA8FF9CAAA6FF9BA9A5FF9BAAA6FF95A6A2FFA9BDB8FF
+ BDCECAFFBED2CDFFC0D1CDFFC2D6D1FFC5D6D2FFBFD3CEFFC4D5D1FFBDD1CCFF
+ B8C9C5FFA7BBB6FFAFC0BCFF718580FF9BACA8FF94A5A1FFA2B1ADFF98A6A2FF
+ 8E9C98FF8C9A96FF8D9B97FF8F9D99FF95A39FFF9CAAA6FFA6B4B0FFA0AEAAFF
+ 9EACA8FFA0AEAAFF9DABA7FF96A4A0FF96A4A0FF9DABA7FF9BA9A5FF9EACA8FF
+ A1AFABFFA0AEAAFF9CAAA6FF9AA8A4FF9BA9A5FF9DABA7FFA7B5B1FF9FADA9FF
+ 9BA9A5FF9BA9A5FF98A6A2FF909E9AFF899793FF879591FF899793FF8D9B97FF
+ 92A09CFF92A09CFF8D9B97FF899793FF879591FF879591FF899793FF93A19DFF
+ 93A19DFF889692FF869490FF8E9C98FF8D9B97FF85938FFF81908CFF7C8B87FF
+ 92A09CFF869490FF97A5A1FF45534FFF8F9B95FF84908AFF859088FF87928AFF
+ 8A958DFF8D9890FF909891FF8F988EFF8D958EFF8C958BFF919C92FF98A399FF
+ 95A096FF869187FF7C877DFF808B81FF889389FF8C978DFF8B968CFF8C978DFF
+ 8C978DFF8E998FFF929D93FF96A197FF9AA59BFF9DA89EFF8B948AFF8F988EFF
+ 959D93FF98A197FF9CA59BFFA1AAA0FFA7B0A6FFABB4AAFFAEB9AFFFAEB9AFFF
+ AAB8ADFFA6B4A9FFA2B0A5FFA1AFA4FFA2B0A5FFA4B2A7FF99A79CFF9CAA9FFF
+ 9CAA9FFF9BA99EFF9EACA1FFA3B1A6FFA2B0A5FF9DABA0FF94A297FF99A79CFF
+ 9EACA1FFA0AEA3FF9EACA1FF9DABA0FF9FADA2FFA0B0A5FFBCCFC6FFC0D8CEFF
+ C6DBD2FFC0D8CEFFBCD1C8FFB5CDC3FFAFC4BCFFA6BDB5FFA6BBB3FFA3BAB2FF
+ A4B8B3FFA2B8B3FF707573FF656A68FF6B706EFF666D6AFF737A77FF858C89FF
+ 7B827FFF79827FFF7D8683FF899491FFA6B1AEFFC0CBC8FFC5D0CDFFB9C7C3FF
+ B6C4C0FFBDCBC7FFB0BEBAFF9BA9A5FF97A5A1FFA1AFABFFA8B6B2FFADBBB7FF
+ A2B0ACFF899793FFB5C3BFFFA6B4B0FF909E9AFF82908CFF879591FF96A4A0FF
+ 9FADA9FF9FADA9FF909E9AFF9AA8A4FF99A7A3FF98A6A2FF9BA9A5FF909E9AFF
+ 85938FFF8A9894FF83918DFF768480FF8A9894FF9EACA8FF97A5A1FF9BA9A5FF
+ A6B4B0FF9EACA8FF9EACA8FF9DABA7FFA0AEAAFFA2B0ACFF9CAAA6FF94A29EFF
+ 99A7A3FFA4B2AEFF9EACA8FFA1AFABFF9EACA8FF96A4A0FF93A19DFF98A6A2FF
+ 9FADA9FFA1AFABFF4A5552FF3C4744FF67726FFF596461FF485350FF3C4744FF
+ 4E5956FF55605DFF535E5BFF5B6663FF697471FF77827FFF818C89FF85908DFF
+ 86918EFF86918EFF879591FF84928EFF808E8AFF7E8C88FF808E8AFF869490FF
+ 8D9B97FF92A09CFF8D9B97FF7D8B87FF8C9A96FF889692FF92A09CFFA8B6B2FF
+ A2B0ACFFB5C4C0FFB0C1BEFFBFD2CFFFB8CBC8FFBACDCAFFBCCFCCFFBACDCAFF
+ BBCECBFFA3B6B3FFA6B9B6FFA4B7B4FFA4B7B4FFA2B5B2FF9BAEABFF92A5A2FF
+ 90A3A0FF96A7A4FF9CABA7FFADBBB7FF3F4D49FF3F4D49FF8B9995FF798783FF
+ 5E6C68FF63716DFF7B8985FF788682FF74827EFF6F7D79FF6E7C78FF73817DFF
+ 7D8B87FF85938FFF82918DFF839490FF859692FF859692FF899A96FF8E9F9BFF
+ 8E9F9BFF899A96FF8FA09CFF8FA09CFF90A19DFF91A29EFF94A5A1FF9AABA7FF
+ A0B1ADFFA7B6B2FFA2B0ACFF9DABA7FFA4B2AEFFA5B3AFFF9CAAA6FF9EACA8FF
+ A4B2AEFF9FADA9FF9DABA7FF96A4A0FF93A19DFF96A4A0FF98A6A2FF93A19DFF
+ 8F9D99FF8D9B97FFA8B7B3FFADBEBAFFB8C7C3FFBCCDC9FFBFCECAFFBFD0CCFF
+ C4D3CFFFC6D7D3FFBECDC9FFC4D5D1FFC0CFCBFFAFC0BCFFBAC9C5FF788985FF
+ A6B5B1FF91A09CFF9EACA8FFA0AEAAFF9DABA7FF96A4A0FF93A19DFF96A4A0FF
+ 98A6A2FF96A4A0FF9CAAA6FF99A7A3FF99A7A3FF9CAAA6FF9CAAA6FF98A6A2FF
+ 99A7A3FF9DABA7FF9FADA9FF96A4A0FF9CAAA6FFA4B2AEFF9DABA7FF9BA9A5FF
+ 9FADA9FF9BA9A5FF93A19DFF96A4A0FF9AA8A4FF9BA9A5FF99A7A3FF94A29EFF
+ 8F9D99FF8C9A96FF93A19BFF92A09AFF95A39DFF95A39DFF86948EFF798781FF
+ 7F8D87FF919F99FF8D9B95FF7F8D87FF77857FFF7F8D87FF8B9993FF8D9B95FF
+ 87958FFF83918BFF809089FF889891FF8A9892FF96A49EFF8F9D97FF55635DFF
+ 77837DFF7F8B85FF8B958FFF88928CFF86908AFF88928CFF8D948FFF8E968FFF
+ 8C938EFF8A928BFF879288FF8C978DFF8C978DFF848F85FF818C82FF869187FF
+ 8E998FFF919C92FF8F9A90FF8F9A90FF909B91FF909B91FF929D93FF949F95FF
+ 96A197FF97A298FF95A096FF949F95FF9BA49AFF97A298FF929D93FF9FAAA0FF
+ B0BBB1FFAFBAB0FFAFBAB0FFA9B4AAFFA1ACA2FF9FAAA0FFA1ACA2FFA4AFA5FF
+ A5B0A6FFA2B0A5FFA5B3A8FFA4B2A7FFA2B0A5FFA3B1A6FFAAB8ADFFAEBCB1FF
+ A7B5AAFF9BA99EFF99A79CFFA3B1A6FF9BA99EFF8E9C91FF8E9C91FF909E93FF
+ 97A59AFFA4B3ABFFBACFC7FFBED6CEFFC2D9D1FFBCD4CCFFB7CEC6FFAFC7BFFF
+ A5BBB6FF9BB2ADFF9FB5B0FF9DB4AFFF9CB2ADFF9AB1ACFF686D6BFF666B69FF
+ 6F7472FF646967FF6B726FFF828986FF7E8582FF818885FF7E8784FF89928FFF
+ A1ACA9FFBDC8C5FFC6D1CEFFBFCAC7FFB9C7C3FFBDCBC7FFB5C3BFFFA1AFABFF
+ 9BA9A5FFA0AEAAFFA4B2AEFFABB9B5FFA6B4B0FF94A29EFFADBBB7FFABB9B5FF
+ A4B2AEFF9AA8A4FF94A29EFF92A09CFF8D9B97FF869490FF92A09CFF9DABA7FF
+ A5B3AFFFAAB8B4FFA6B4B0FF92A09CFF879591FF8E9C98FF96A4A0FF869490FF
+ 8F9D99FF99A7A3FF8F9D99FF919F9BFF9CAAA6FF96A4A0FF9DABA7FF9CAAA6FF
+ 9EACA8FFA2B0ACFF9FADA9FF98A6A2FF99A7A3FF9FADA9FF99A7A3FF9CAAA6FF
+ 9AA8A4FF93A19DFF919F9BFF96A4A0FF9CAAA6FF9DABA7FF4C5754FF27322FFF
+ 424D4AFF414C49FF4A5552FF4A5552FF505B58FF45504DFF56615EFF5F6A67FF
+ 6E7976FF7D8885FF87928FFF8B9693FF8A9592FF889390FF869490FF83918DFF
+ 808E8AFF7E8C88FF7F8D89FF83918DFF899793FF8C9A96FF919F9BFF818F8BFF
+ 8A9894FF889692FF9BA9A5FFB8C6C2FFB2C0BCFFBAC9C5FFC5D6D3FFC4D7D4FF
+ B5C8C5FFBFD2CFFFC3D6D3FFB5C8C5FFACBFBCFF93A6A3FF899C99FF879A97FF
+ 879A97FF859895FF798C89FF697C79FF5F726FFF5F706DFF576662FF9EACA8FF
+ 54625EFF3D4B47FF84928EFF8F9D99FF7E8C88FF6E7C78FF7A8884FF798783FF
+ 768480FF73817DFF73817DFF788682FF82908CFF889793FF81908CFF849591FF
+ 869793FF839490FF839490FF869793FF869793FF82938FFF899A96FF899A96FF
+ 899A96FF8A9B97FF8FA09CFF98A9A5FFA0B1ADFFA6B7B3FFA5B3AFFFA0AEAAFF
+ A6B4B0FFA7B5B1FF9CAAA6FF9DABA7FFA2B0ACFF9CAAA6FFA0AEAAFF9BA9A5FF
+ 99A7A3FF9CAAA6FF9DABA7FF98A6A2FF96A4A0FF97A5A1FFA6B5B1FFACBBB7FF
+ B5C4C0FFBCCBC7FFC1D0CCFFC3D2CEFFC4D3CFFFC5D4D0FFBFCECAFFC5D4D0FF
+ BECDC9FFADBCB8FFB1C0BCFF758480FFA2B1ADFF94A39FFF9AA8A4FF9BA9A5FF
+ 99A7A3FF95A39FFF95A39FFF99A7A3FF98A6A2FF94A29EFF9FADA9FF9FADA9FF
+ A2B0ACFFA3B1ADFF9EACA8FF97A5A1FF98A6A2FF9EACA8FFA2B0ACFF9AA8A4FF
+ A2B0ACFFAAB8B4FFA2B0ACFF9EACA8FF9FADA9FF99A7A3FF97A5A1FF93A19DFF
+ 909E9AFF909E9AFF93A19DFF93A19DFF909E9AFF8C9A96FF8E9C96FF889690FF
+ 818F89FF7A8882FF717F79FF6A7872FF6D7B75FF74827CFF82908AFF7F8D87FF
+ 7D8B85FF7F8D87FF83918BFF87958FFF87958FFF85938DFF8C9C95FF91A19AFF
+ 8D9B95FF95A39DFF8B9993FF53615BFF77837DFF818D87FF8B958FFF89938DFF
+ 87918BFF88928CFF8D948FFF8F9691FF8D948FFF8B938CFF8A958DFF8E998FFF
+ 8C978DFF859086FF838E84FF889389FF8E998FFF909B91FF8F9A90FF8F9A90FF
+ 8E998FFF8E998FFF8E998FFF8F9A90FF909B91FF919C92FF939E94FF919C92FF
+ 98A399FF99A49AFF95A096FFA0ABA1FFABB6ACFFA6B1A7FFA9B4AAFFA7B2A8FF
+ A5B0A6FFA4AFA5FFA4AFA5FFA3AEA4FFA1ACA2FF9FAAA0FFA0AEA3FFA0AEA3FF
+ 9EACA1FFA1AFA4FFAAB8ADFFB2C0B5FFADBBB0FFA4B2A7FF9CAA9FFFA0AEA3FF
+ 97A59AFF8D9B90FF8B998EFF859388FF869489FF92A199FFAFC4BCFFB6CDC8FF
+ BCD3CEFFBAD1CCFFB4CBC6FFACC3BEFFA0B7B2FF96ADA8FF98AFAAFF98AFAAFF
+ 97AEA9FF97AEA9FF616664FF696E6CFF747977FF606563FF616865FF7D8481FF
+ 7E8582FF808784FF77807DFF7D8683FF919C99FFAFBAB7FFBFCAC7FFBCC7C4FF
+ B4C2BEFFB4C2BEFFB7C5C1FFA5B3AFFF9DABA7FF9DABA7FF9BA9A5FFA3B1ADFF
+ A7B5B1FF9DABA7FF99A7A3FFA3B1ADFFAAB8B4FFA7B5B1FFA0AEAAFF99A7A3FF
+ 919F9BFF899793FF7D8B87FF818F8BFF909E9AFF9DABA7FF98A6A2FF879591FF
+ 85938FFF93A19DFF9BA9A5FF8E9C98FF909E9AFF94A29EFF8D9B97FF92A09CFF
+ 9DABA7FF9DABA7FF9BA9A5FF99A7A3FF9CAAA6FFA3B1ADFFA6B4B0FFA2B0ACFF
+ 9DABA7FF9CAAA6FF97A5A1FF9AA8A4FF99A7A3FF93A19DFF919F9BFF96A4A0FF
+ 99A7A3FF99A7A3FF55605DFF25302DFF384340FF3E4946FF57625FFF606B68FF
+ 646F6CFF535E5BFF66716EFF6E7976FF7B8683FF86918EFF8D9895FF8D9895FF
+ 899491FF85908DFF85938FFF83918DFF808E8AFF7E8C88FF7D8B87FF7F8D89FF
+ 818F8BFF83918DFF899793FF7D8B87FF7F8D89FF7D8B87FF95A39FFFB9C7C3FF
+ BAC8C4FFBAC9C5FFC0D1CEFFBFD2CFFFB3C6C3FFBBCECBFFB5C8C5FFA0B3B0FF
+ A0B3B0FF97AAA7FF6D807DFF637673FF586B68FF516461FF495C59FF3E514EFF
+ 394C49FF3B4C49FF354440FF889692FF576561FF394743FF7E8C88FF8D9B97FF
+ 7D8B87FF62706CFF75837FFF72807CFF6F7D79FF6E7C78FF717F7BFF768480FF
+ 7B8985FF7E8D89FF7B8A86FF81928EFF869793FF839490FF81928EFF849591FF
+ 869793FF859692FF889995FF879894FF869793FF889995FF8FA09CFF98A9A5FF
+ A2B3AFFFA7B8B4FFACBAB6FFA7B5B1FFADBBB7FFADBBB7FFA1AFABFFA0AEAAFF
+ A4B2AEFF9EACA8FFA1AFABFF9FADA9FFA0AEAAFFA3B1ADFFA2B0ACFF9EACA8FF
+ 9FADA9FFA4B2AEFFA6B5B1FFAAB9B5FFB0BFBBFFB9C8C4FFC0CFCBFFC4D3CFFF
+ C4D3CFFFC2D1CDFFC1D0CCFFC4D3CFFFBCCBC7FFAAB9B5FFA8B7B3FF73827EFF
+ 9BAAA6FF98A7A3FF94A29EFF96A4A0FF95A39FFF94A29EFF97A5A1FF9BA9A5FF
+ 97A5A1FF909E9AFF9FADA9FFA2B0ACFFA6B4B0FFA7B5B1FF9FADA9FF95A39FFF
+ 95A39FFF9AA8A4FF9BA9A5FF95A39FFFA0AEAAFFAAB8B4FFA3B1ADFF9EACA8FF
+ 9DABA7FF96A4A0FF9DABA7FF94A29EFF8A9894FF889692FF8C9A96FF8F9D99FF
+ 8D9B97FF899793FF93A19BFF899791FF788680FF6A7872FF67756FFF6B7973FF
+ 6C7A74FF687670FF6B7973FF798781FF808E88FF7E8C86FF808E88FF8B9993FF
+ 93A19BFF92A09AFF93A39CFF94A49DFF8D9B95FF919F99FF87958FFF515F59FF
+ 79857FFF85918BFF8B958FFF89938DFF89938DFF8A948EFF8E9590FF8F9691FF
+ 8F9691FF8D958EFF8D9890FF909B91FF8D988EFF879288FF859086FF8A958BFF
+ 8E998FFF8E998FFF8E998FFF8D988EFF8C978DFF8B968CFF8B968CFF8B968CFF
+ 8B968CFF8B968CFF939E94FF919C92FF99A49AFF9DA89EFF9BA69CFFA5B0A6FF
+ ACB7ADFFA1ACA2FFA3AEA4FFA6B1A7FFA9B4AAFFA9B4AAFFA6B1A7FFA2ADA3FF
+ 9FAAA0FF9DA89EFF9FADA2FF9FADA2FF9DABA0FF9FADA2FFA7B5AAFFB0BEB3FF
+ AEBCB1FFA6B4A9FF9EACA1FF9DABA0FF93A196FF8F9D92FF8F9D92FF839186FF
+ 808E83FF8E9D95FFA8BDB5FFB2C8C3FFBDD3CEFFBED4CFFFB9CFCAFFB2C8C3FF
+ A7BDB8FF9DB3AEFF97ADA8FF96ACA7FF96ACA7FF96ACA7FF5B605EFF696E6CFF
+ 767B79FF5E6361FF5E6562FF7D8481FF7C8380FF787F7CFF727B78FF727B78FF
+ 808B88FFA0ABA8FFB6C1BEFFB7C2BFFFAEBCB8FFABB9B5FFB0BEBAFFA2B0ACFF
+ 9EACA8FF9BA9A5FF94A29EFF9AA8A4FFA2B0ACFF9DABA7FF95A39FFF9DABA7FF
+ A2B0ACFFA1AFABFFA1AFABFFA2B0ACFFA1AFABFF9EACA8FF93A19DFF879591FF
+ 8F9D99FF9EACA8FF98A6A2FF8E9C98FF95A39FFFA1AFABFF9BA9A5FF96A4A0FF
+ 96A4A0FF98A6A2FF97A5A1FF9AA8A4FFA0AEAAFFA1AFABFF99A7A3FF97A5A1FF
+ 9AA8A4FFA3B1ADFFABB9B5FFAAB8B4FFA0AEAAFF98A6A2FF9BA9A5FF9EACA8FF
+ 9CAAA6FF96A4A0FF94A29EFF97A5A1FF98A6A2FF95A39FFF626D6AFF37423FFF
+ 4F5A57FF55605DFF67726FFF6F7A77FF7D8885FF7A8582FF808B88FF838E8BFF
+ 889390FF8C9794FF8C9794FF889390FF838E8BFF808B88FF83918DFF82908CFF
+ 7F8D89FF7D8B87FF7C8A86FF7B8985FF7A8884FF7B8985FF7B8985FF7B8985FF
+ 798783FF72807CFF83918DFFA5B3AFFFB6C4C0FFBAC9C5FFB3C4C1FFB8CBC8FF
+ AFC2BFFFB8CBC8FFB4C7C4FF9CAFACFF8C9F9CFF708380FF394C49FF2D403DFF
+ 253835FF293C39FF304340FF314441FF2D403DFF2E3F3CFF3B4A46FF667470FF
+ 43514DFF404E4AFF93A19DFF909E9AFF7C8A86FF717F7BFF768480FF6D7B77FF
+ 667470FF697773FF72807CFF788682FF768480FF72807CFF71807CFF7B8C88FF
+ 859692FF859692FF849591FF899A96FF8E9F9BFF90A19DFF8D9E9AFF8C9D99FF
+ 8B9C98FF8E9F9BFF95A6A2FF9CADA9FFA1B2AEFFA5B4B0FFABB9B5FFA6B4B0FF
+ ADBBB7FFAEBCB8FFA3B1ADFFA2B0ACFFA5B3AFFF9FADA9FFA1AFABFFA1AFABFF
+ A4B2AEFFA7B5B1FFA4B2AEFFA1AFABFFA5B3AFFFADBBB7FFACBBB7FFABBAB6FF
+ ACBBB7FFB3C2BEFFBBCAC6FFC1D0CCFFC2D1CDFFC1D0CCFFC3D2CEFFC2D1CDFF
+ BECDC9FFAFBEBAFFA5B4B0FF778682FF95A4A0FF9BAAA6FF8F9D99FF919F9BFF
+ 92A09CFF93A19DFF97A5A1FF9AA8A4FF93A19DFF8A9894FF9CAAA6FF9CAAA6FF
+ 9FADA9FFA2B0ACFF9DABA7FF94A29EFF919F9BFF93A19DFF95A39FFF8F9D99FF
+ 9AA8A4FFA5B3AFFFA0AEAAFF9EACA8FF9FADA9FF9AA8A4FF9BA9A5FF94A29EFF
+ 8C9A96FF879591FF889692FF899793FF889692FF879591FF899791FF818F89FF
+ 6D7B75FF5A6862FF596761FF64726CFF67756FFF5F6D67FF64726CFF798781FF
+ 83918BFF7E8C86FF818F89FF919F99FF9AA8A2FF96A49EFF8F9F98FF91A19AFF
+ 8A9892FF909E98FF87958FFF52605AFF7C8882FF89958FFF8A948EFF8A948EFF
+ 8A948EFF8B958FFF8F9691FF909792FF909792FF8F9790FF919C94FF919C92FF
+ 8E998FFF889389FF889389FF8D988EFF8F9A90FF8C978DFF8D988EFF8C978DFF
+ 8B968CFF8A958BFF8A958BFF8A958BFF8A958BFF8B968CFF909B91FF8C978DFF
+ 929D93FF98A399FF99A49AFFA5B0A6FFABB6ACFF9FAAA0FF9EA99FFFA4AFA5FF
+ A9B4AAFFA9B4AAFFA5B0A6FFA0ABA1FF9FAAA0FFA0ABA1FFA3B1A6FFA1AFA4FF
+ 9DABA0FF9BA99EFFA0AEA3FFA7B5AAFFA5B3A8FF9EACA1FF9BA99EFF96A499FF
+ 8D9B90FF8E9C91FF919F94FF859388FF839186FF94A39BFFA6BBB3FFB0C6C1FF
+ BBD1CCFFBCD2CDFFB8CEC9FFB3C9C4FFACC2BDFFA5BBB6FF99AFAAFF98AEA9FF
+ 96ACA7FF94AAA5FF505553FF606563FF707573FF5D6260FF636A67FF818885FF
+ 7B827FFF727976FF767F7CFF6F7875FF788380FF96A19EFFB0BBB8FFB5C0BDFF
+ ADBBB7FFA9B7B3FFA8B6B2FFA0AEAAFFA2B0ACFFA0AEAAFF94A29EFF96A4A0FF
+ 9DABA7FF99A7A3FFA2B0ACFFA2B0ACFF9FADA9FF9BA9A5FF9EACA8FFA3B1ADFF
+ A4B2AEFFA0AEAAFFB6C4C0FF9CAAA6FF9CAAA6FFA6B4B0FF99A7A3FF8F9D99FF
+ 8F9D99FF8A9894FF9EACA8FFA3B1ADFFA3B1ADFFA2B0ACFFA4B2AEFFA1AFABFF
+ 9BA9A5FF9BA9A5FF9CAAA6FF99A7A3FF98A6A2FF9EACA8FFA6B4B0FFA5B3AFFF
+ 98A6A2FF8B9995FF9DABA7FF9FADA9FF9EACA8FF98A6A2FF96A4A0FF96A4A0FF
+ 93A19DFF8D9B97FF727D7AFF46514EFF5F6A67FF636E6BFF737E7BFF788380FF
+ 8A9592FF8D9895FF939E9BFF929D9AFF909B98FF8D9895FF899491FF87928FFF
+ 848F8CFF838E8BFF83918DFF82908CFF808E8AFF7E8C88FF7C8A86FF7A8884FF
+ 798783FF788682FF74827EFF808E8AFF7C8A86FF74827EFF75837FFF8B9995FF
+ ADBBB7FFBCCBC7FFB6C7C4FFB7CAC7FFA6B9B6FFACBFBCFFB1C4C1FF9BAEABFF
+ 728582FF374A47FF2F423FFF263936FF253835FF314441FF3E514EFF3E514EFF
+ 354845FF2F403DFF1E2D29FF394743FF313F3BFF3A4844FF93A19DFF899793FF
+ 7E8C88FF808E8AFF7B8985FF6E7C78FF64726EFF6C7A76FF7D8B87FF879591FF
+ 82908CFF778581FF6C7B77FF798884FF84938FFF869591FF879692FF8D9C98FF
+ 93A29EFF95A4A0FF93A29EFF92A19DFF92A19DFF95A4A0FF9AA9A5FF9DACA8FF
+ 9DACA8FF9CABA7FFA2B0ACFF9EACA8FFA7B5B1FFA9B7B3FFA0AEAAFFA0AEAAFF
+ A4B2AEFF9EACA8FFA1AFABFFA1AFABFFA3B1ADFFA6B4B0FFA4B2AEFFA1AFABFF
+ A6B4B0FFAEBCB8FFB3C2BEFFAEBDB9FFABBAB6FFADBCB8FFB5C4C0FFBDCCC8FF
+ C1D0CCFFC2D1CDFFC2D1CDFFBFCECAFFBFCECAFFB7C6C2FFA8B7B3FF808F8BFF
+ 909F9BFF9BAAA6FF899793FF8D9B97FF909E9AFF919F9BFF94A29EFF96A4A0FF
+ 8F9D99FF869490FF9AA8A4FF97A5A1FF98A6A2FF9EACA8FF9EACA8FF98A6A2FF
+ 93A19DFF92A09CFF9BA9A5FF92A09CFF99A7A3FFA1AFABFF9BA9A5FF99A7A3FF
+ 9CAAA6FF98A6A2FF879591FF8A9894FF8C9A96FF8A9894FF869490FF84928EFF
+ 869490FF899793FF899791FF85938DFF74827CFF5E6C66FF586660FF62706AFF
+ 66746EFF616F69FF6C7A74FF7C8A84FF84928CFF7F8D87FF83918BFF92A09AFF
+ 95A39DFF8C9A94FF91A19AFF94A49DFF8E9C96FF95A39DFF8C9A94FF55635DFF
+ 7C8882FF87938DFF89938DFF8A948EFF8B958FFF8C9690FF8E9590FF8F9691FF
+ 909792FF919992FF929D95FF919C92FF8C978DFF889389FF8A958BFF909B91FF
+ 8F9A90FF8A958BFF8C978DFF8C978DFF8B968CFF8B968CFF8C978DFF8D988EFF
+ 8E998FFF8E998FFF8C978DFF859086FF89948AFF8D988EFF909B91FF9FAAA0FF
+ A9B4AAFFA0ABA1FF9AA59BFF9EA99FFFA1ACA2FF9FAAA0FF9BA69CFF9AA59BFF
+ 9CA79DFF9FAAA0FFA0AEA3FF9FADA2FF9BA99EFF97A59AFF99A79CFF9DABA0FF
+ 9BA99EFF95A398FF9BA99EFF99A79CFF8F9D92FF8B998EFF8B998EFF818F84FF
+ 808E83FF909F97FFA9BEB6FFB2C8C3FFB8CEC9FFB4CAC5FFACC2BDFFA7BDB8FF
+ A2B8B3FF9EB4AFFF97ADA8FF96ACA7FF94AAA5FF92A8A3FF464B49FF535856FF
+ 686D6BFF5E6361FF666D6AFF818885FF7B827FFF777E7BFF767F7CFF6B7471FF
+ 6E7976FF899491FFA3AEABFFAAB5B2FFA6B4B0FFA4B2AEFFA4B2AEFF9FADA9FF
+ A5B3AFFFA5B3AFFF98A6A2FF97A5A1FF9BA9A5FF95A39FFF9EACA8FF9EACA8FF
+ 9CAAA6FF9BA9A5FF9EACA8FFA4B2AEFFA3B1ADFF9EACA8FFACBAB6FF94A29EFF
+ 9AA8A4FFA4B2AEFF95A39FFF8E9C98FF889692FF6F7D79FF94A29EFFA3B1ADFF
+ A3B1ADFFA2B0ACFFACBAB6FFAAB8B4FFA0AEAAFFA2B0ACFFA0AEAAFF9CAAA6FF
+ 97A5A1FF97A5A1FF9CAAA6FF9CAAA6FF909E9AFF808E8AFF9BA9A5FF9DABA7FF
+ 9CAAA6FF98A6A2FF96A4A0FF95A39FFF8F9D99FF879591FF889390FF505B58FF
+ 606B68FF697471FF808B88FF85908DFF909B98FF8C9794FF98A3A0FF95A09DFF
+ 919C99FF8D9895FF8B9693FF8C9794FF8E9996FF909B98FF889692FF869490FF
+ 84928EFF82908CFF808E8AFF7F8D89FF7E8C88FF7E8C88FF778581FF84928EFF
+ 7D8B87FF7C8A86FF768480FF7C8A86FFA3B1ADFFB5C4C0FFACBDBAFFAABDBAFF
+ 92A5A2FF8B9E9BFF849794FF778A87FF748784FF5E716EFF6A7D7AFF566966FF
+ 405350FF324542FF2B3E3BFF273A37FF293C39FF2F403DFF2D3C38FF566460FF
+ 5F6D69FF43514DFF85938FFF7E8C88FF788682FF72807CFF75837FFF6A7874FF
+ 62706CFF6C7A76FF7F8D89FF8C9A96FF899793FF818F8BFF6F7E7AFF798884FF
+ 83928EFF84938FFF869591FF8A9995FF8D9C98FF8C9B97FF92A19DFF8F9E9AFF
+ 8E9D99FF91A09CFF96A5A1FF99A8A4FF98A7A3FF95A4A0FFA1AFABFF9EACA8FF
+ A8B6B2FFACBAB6FFA4B2AEFFA5B3AFFFAAB8B4FFA4B2AEFFA5B3AFFFA2B0ACFF
+ A2B0ACFFA5B3AFFFA5B3AFFFA3B1ADFFA6B4B0FFACBAB6FFB2C1BDFFAFBEBAFF
+ ACBBB7FFADBCB8FFB2C1BDFFBAC9C5FFC1D0CCFFC5D4D0FFC1D0CCFFB8C7C3FF
+ BBCAC6FFBAC9C5FFA9B8B4FF899894FF8A9995FF99A8A4FF818F8BFF889692FF
+ 8E9C98FF8F9D99FF909E9AFF919F9BFF8E9C98FF879591FF9AA8A4FF98A6A2FF
+ 9AA8A4FFA0AEAAFFA0AEAAFF9BA9A5FF99A7A3FF9AA8A4FF9FADA9FF94A29EFF
+ 97A5A1FF9AA8A4FF8F9D99FF8B9995FF8C9A96FF879591FF73817DFF7E8C88FF
+ 899793FF8D9B97FF8A9894FF889692FF8B9995FF8F9D99FF8E9C96FF8A9892FF
+ 7D8B85FF6B7973FF606E68FF5F6D67FF606E68FF606E68FF67756FFF73817BFF
+ 7B8983FF7F8D87FF899791FF96A49EFF98A6A0FF919F99FF98A8A1FF9BABA4FF
+ 96A49EFF9CAAA4FF909E98FF56645EFF7A8680FF838F89FF86908AFF88928CFF
+ 8B958FFF8B958FFF8D948FFF8D948FFF909792FF929A93FF929D95FF8F9A90FF
+ 8A958BFF879288FF8C978DFF929D93FF909B91FF889389FF8E998FFF8E998FFF
+ 8D988EFF8D988EFF8E998FFF8F9A90FF909B91FF919C92FF909B91FF8A958BFF
+ 8C978DFF8D988EFF8E998FFF9EA99FFFACB7ADFFA7B2A8FF9AA59BFF9AA59BFF
+ 98A399FF95A096FF939E94FF929D93FF949F95FF97A298FF96A499FF98A69BFF
+ 96A499FF93A196FF95A398FF99A79CFF97A59AFF919F94FFA3B1A6FFAAB8ADFF
+ A2B0A5FF94A297FF8E9C91FF849287FF829085FF8B9A92FFB1C6BEFFB8CEC9FF
+ BBD1CCFFB2C8C3FFA5BBB6FF9DB3AEFF98AEA9FF95ABA6FF91A7A2FF91A7A2FF
+ 90A6A1FF90A6A1FF454A48FF505553FF676C6AFF616664FF636A67FF777E7BFF
+ 757C79FF7D8481FF767F7CFF69726FFF67726FFF7D8885FF96A19EFF9FAAA7FF
+ 9EACA8FF9EACA8FFA0AEAAFF9CAAA6FFA3B1ADFFA4B2AEFF98A6A2FF95A39FFF
+ 97A5A1FF909E9AFF919F9BFF97A5A1FF99A7A3FF97A5A1FF99A7A3FF9FADA9FF
+ A2B0ACFFA2B0ACFF9DABA7FF8F9D99FFA0AEAAFFAAB8B4FF9DABA7FFA6B4B0FF
+ A8B6B2FF879591FF8C9A96FF9FADA9FF9BA9A5FF96A4A0FFA7B5B1FFABB9B5FF
+ A5B3AFFFADBBB7FFA0AEAAFF9DABA7FF97A5A1FF94A29EFF99A7A3FF9EACA8FF
+ 96A4A0FF899793FF98A6A2FF9BA9A5FF9BA9A5FF99A7A3FF99A7A3FF99A7A3FF
+ 919F9BFF889692FF929D9AFF596461FF687370FF717C79FF85908DFF889390FF
+ 919C99FF8F9A97FF97A29FFF95A09DFF929D9AFF919C99FF919C99FF949F9CFF
+ 98A3A0FF9AA5A2FF8E9C98FF8D9B97FF8A9894FF889692FF879591FF879591FF
+ 889692FF899793FF85938FFF8A9894FF7D8B87FF8D9B97FF8D9B97FF84928EFF
+ A1AFABFFABBAB6FFA1B2AFFF8B9E9BFF718481FF7F928FFF849794FF7D908DFF
+ 97AAA7FFA6B9B6FF96A9A6FF839693FF657875FF415451FF243734FF1D302DFF
+ 304340FF4A5B58FF83928EFF9DABA7FF98A6A2FF566460FF889692FF83918DFF
+ 7F8D89FF707E7AFF6B7975FF667470FF64726EFF697773FF74827EFF7D8B87FF
+ 82908CFF83918DFF758480FF7D8C88FF83928EFF859490FF889793FF8B9A96FF
+ 8A9995FF869591FF8F9E9AFF8A9995FF869591FF889793FF91A09CFF98A7A3FF
+ 9BAAA6FF9BAAA6FFA0AEAAFF9EACA8FFA8B6B2FFADBBB7FFA6B4B0FFA6B4B0FF
+ ABB9B5FFA4B2AEFFADBBB7FFA7B5B1FFA4B2AEFFA6B4B0FFA8B6B2FFA6B4B0FF
+ A7B5B1FFABB9B5FFAAB9B5FFACBBB7FFAEBDB9FFB1C0BCFFB5C4C0FFBBCAC6FF
+ C2D1CDFFC7D6D2FFBFCECAFFB0BFBBFFB2C1BDFFB5C4C0FFA5B4B0FF8D9C98FF
+ 84938FFF96A5A1FF778581FF83918DFF8C9A96FF8D9B97FF8C9A96FF8E9C98FF
+ 8F9D99FF8E9C98FF99A7A3FF9CAAA6FFA2B0ACFFA4B2AEFF9DABA7FF96A4A0FF
+ 9AA8A4FFA4B2AEFFA1AFABFF96A4A0FF9AA8A4FF9CAAA6FF8E9C98FF85938FFF
+ 83918DFF7B8985FF768480FF7F8D89FF8B9995FF93A19DFF94A29EFF93A19DFF
+ 93A19DFF94A29EFF8C9A94FF84928CFF7B8983FF74827CFF6A7872FF606E68FF
+ 5B6963FF5C6A64FF697771FF707E78FF7C8A84FF889690FF92A09AFF98A6A0FF
+ 9BA9A3FF9CAAA4FF99A9A2FF9BABA4FF94A29CFF99A7A1FF8D9B95FF53615BFF
+ 78847EFF828E88FF848E88FF87918BFF8A948EFF8A948EFF8B928DFF8C938EFF
+ 8F9691FF929A93FF909B93FF8D988EFF879288FF859086FF8D988EFF949F95FF
+ 909B91FF879288FF929D93FF919C92FF909B91FF8F9A90FF8E998FFF8F9A90FF
+ 8F9A90FF909B91FF929D93FF8F9A90FF929D93FF919C92FF8D988EFF9BA69CFF
+ ABB6ACFFA8B3A9FFA2ADA3FF9EA99FFF99A49AFF96A197FF949F95FF929D93FF
+ 909B91FF8E998FFF909E93FF93A196FF94A297FF92A095FF93A196FF96A499FF
+ 94A297FF8E9C91FF9CAA9FFFB3C1B6FFB3C1B6FFA0AEA3FF98A69BFF94A297FF
+ 909E93FF93A29AFFADBFB8FFB6CAC5FFBCD0CBFFB3C7C2FFA6BAB5FF9DB1ACFF
+ 97ABA6FF93A7A2FF93A7A2FF93A7A2FF92A6A1FF92A6A1FF4B504EFF545957FF
+ 6B706EFF646967FF5E6562FF6A716EFF6D7471FF7F8683FF7C8582FF6D7673FF
+ 697471FF7D8885FF949F9CFF9EA9A6FF9FADA9FFA1AFABFF9DABA7FF98A6A2FF
+ 9EACA8FF9FADA9FF94A29EFF919F9BFF93A19DFF8B9995FF93A19DFF9AA8A4FF
+ 9CAAA6FF93A19DFF8D9B97FF919F9BFF9BA9A5FFA1AFABFF95A39FFF8C9A96FF
+ 9FADA9FFA4B2AEFF95A39FFFABB9B5FFB9C7C3FF9AA8A4FF95A39FFFA6B4B0FF
+ 99A7A3FF8D9B97FF9DABA7FFA2B0ACFF9DABA7FFA9B7B3FF9DABA7FF9CAAA6FF
+ 98A6A2FF95A39FFF9DABA7FFA7B5B1FFA4B2AEFF9AA8A4FF98A6A2FF9BA9A5FF
+ 9DABA7FF9CAAA6FF9EACA8FF9EACA8FF97A5A1FF8D9B97FF8B9693FF5C6764FF
+ 747F7CFF788380FF808B88FF7C8784FF8D9895FF95A09DFF97A29FFF97A29FFF
+ 96A19EFF96A19EFF97A29FFF99A4A1FF9BA6A3FF9DA8A5FF94A29EFF92A09CFF
+ 8F9D99FF8C9A96FF8C9A96FF8D9B97FF909E9AFF92A09CFF9AA8A4FF94A29EFF
+ 82908CFFA0AEAAFFABB9B5FF99A7A3FFABB9B5FFAAB9B5FFABBCB9FF708380FF
+ 546764FF96A9A6FFCCDFDCFFC0D3D0FFB5C8C5FFABBEBBFFA7BAB7FFABBEBBFF
+ A7BAB7FF8EA19EFF6D807DFF617471FF768986FF96A7A4FFAAB9B5FF9DABA7FF
+ 82908CFF3D4B47FF7A8884FF7B8985FF7B8985FF717F7BFF697773FF6B7975FF
+ 6D7B77FF6B7975FF6B7975FF707E7AFF798783FF82908CFF798884FF7F8E8AFF
+ 84938FFF879692FF8C9B97FF91A09CFF8E9D99FF889793FF8E9D99FF879692FF
+ 808F8BFF83928EFF8E9D99FF9AA9A5FFA2B1ADFFA5B4B0FF99A7A3FF97A5A1FF
+ A1AFABFFA6B4B0FF9EACA8FF9EACA8FFA2B0ACFF9BA9A5FFB3C1BDFFABB9B5FF
+ A5B3AFFFA8B6B2FFABB9B5FFA9B7B3FFA9B7B3FFAAB8B4FFA1B0ACFFA8B7B3FF
+ B0BFBBFFB6C5C1FFB9C8C4FFBDCCC8FFC4D3CFFFC9D8D4FFBDCCC8FFAAB9B5FF
+ AAB9B5FFAFBEBAFF9FAEAAFF8D9C98FF808F8BFF94A39FFF707E7AFF7E8C88FF
+ 8A9894FF8B9995FF8A9894FF8D9B97FF92A09CFF94A29EFF95A39FFF9FADA9FF
+ A8B6B2FFA6B4B0FF97A5A1FF8E9C98FF98A6A2FFA9B7B3FFA6B4B0FF9EACA8FF
+ A3B1ADFFA7B5B1FF9AA8A4FF8F9D99FF8A9894FF818F8BFF85938FFF8A9894FF
+ 92A09CFF9AA8A4FF9EACA8FF9DABA7FF99A7A3FF95A39FFFA4B2ACFF97A59FFF
+ 919F99FF94A29CFF8F9D97FF818F89FF788680FF798781FF7D8B85FF818F89FF
+ 8B9993FF95A39DFF96A49EFF919F99FF92A09AFF98A6A0FF92A29BFF94A49DFF
+ 8D9B95FF92A09AFF87958FFF505E58FF78847EFF838F89FF838D87FF86908AFF
+ 8A948EFF8A948EFF8B928DFF8B928DFF8E9590FF929A93FF8F9A92FF8B968CFF
+ 859086FF848F85FF8D988EFF95A096FF919C92FF879288FF949F95FF939E94FF
+ 919C92FF8F9A90FF8E998FFF8D988EFF8D988EFF8D988EFF8C978DFF8A958BFF
+ 8F9A90FF8D988EFF869187FF919C92FF9FAAA0FF9DA89EFFABB6ACFFA6B1A7FF
+ A0ABA1FF9CA79DFF9AA59BFF96A197FF909B91FF8A958BFF909E93FF94A297FF
+ 95A398FF93A196FF93A196FF94A297FF909E93FF8A988DFF869489FFA9B7ACFF
+ B3C1B6FFA2B0A5FF9DABA0FF9EACA1FF9CAA9FFF9BAAA2FF9BADA6FFA7BBB6FF
+ B1C5C0FFADC1BCFFA2B6B1FF9AAEA9FF94A8A3FF90A49FFF98ACA7FF97ABA6FF
+ 95A9A4FF93A7A2FF525755FF545957FF575C5AFF6B706EFF5E6562FF4B524FFF
+ 303734FF666D6AFF78817EFF7F8885FF77827FFF7B8683FF99A4A1FF98A3A0FF
+ 95A39FFFA9B7B3FF94A29EFF9BA9A5FFA0AEAAFF9EACA8FF95A39FFF909E9AFF
+ 919F9BFF95A39FFF92A09CFF95A39FFF96A4A0FF92A09CFF8C9A96FF8D9B97FF
+ 94A29EFF9CAAA6FF94A29EFF919F9BFF8F9D99FF93A19DFF9CAAA6FFA5B3AFFF
+ AAB8B4FFADBBB7FF95A39FFF9FADA9FFAEBCB8FFB0BEBAFF74827EFFA9B7B3FF
+ 97A5A1FFA4B2AEFFA0AEAAFF9DABA7FF9FADA9FFA4B2AEFFA1AFABFF9CAAA6FF
+ 9FADA9FFA8B6B2FF9BA9A5FFABB9B5FF99A7A3FF9BA9A5FF99A7A3FF9FADA9FF
+ AAB8B4FF7B8985FF828D8AFF5C6764FF6C7774FF7B8683FF798481FF85908DFF
+ 899491FF8E9996FF9AA5A2FF9CA7A4FF9FAAA7FF9FAAA7FF99A4A1FF95A09DFF
+ 9AA5A2FFA2ADAAFF9EACA8FF9EACA8FF9CAAA6FF9BA9A5FF9BA9A5FF9BA9A5FF
+ 99A7A3FF95A39FFFA4B2AEFF9FADA9FF99A7A3FF8E9C98FF788682FF63716DFF
+ 5F6D69FF657470FF627370FF627572FFA2B5B2FFB5C8C5FFCCDFDCFFBDD0CDFF
+ B4C7C4FFA7BAB7FFACBFBCFFA8BBB8FFA4B7B4FFA5B8B5FFA8BBB8FFABBEBBFF
+ A9BCB9FFA8B9B6FF9FAEAAFF9CAAA6FF818F8BFF35433FFF7B8985FF808E8AFF
+ 7C8A86FF7A8884FF6D7B77FF768480FF7D8B87FF7A8884FF73817DFF707E7AFF
+ 768480FF7E8C88FF85938FFF7F8D89FF7E8C88FF818F8BFF7C8A86FF778581FF
+ 818F8BFF93A19DFF97A5A1FF8D9B97FF879591FF8B9995FF95A39FFF9EACA8FF
+ A4B2AEFFA8B6B2FFA5B3AFFFA9B7B3FFACBAB6FFAAB8B4FFA5B3AFFFA4B2AEFF
+ A8B6B2FFADBBB7FFAAB8B4FFAAB8B4FFA9B7B3FFA8B6B2FFAAB8B4FFACBAB6FF
+ ADBBB7FFABB9B5FFA4B3AFFFA8B7B3FFAEBDB9FFB4C3BFFFB8C7C3FFBCCBC7FF
+ BFCECAFFC0CFCBFFBECDC9FFB9C8C4FFB4C3BFFFB8C7C3FFA3B2AEFF94A39FFF
+ 657470FF92A19DFF768480FF798783FF808E8AFF84928EFF82908CFF818F8BFF
+ 8A9894FF96A4A0FF94A29EFF93A19DFF98A6A2FF9DABA7FF99A7A3FF909E9AFF
+ 909E9AFF98A6A2FF94A29EFF9AA8A4FF9DABA7FF9DABA7FF9CAAA6FF9BA9A5FF
+ 94A29EFF8C9A96FF9FADA9FF9AA8A4FF95A39FFF95A39FFF98A6A2FF9BA9A5FF
+ 9BA9A5FF99A7A3FF96A49EFF97A59FFF99A7A1FF99A7A1FF99A7A1FF97A59FFF
+ 94A29CFF93A19BFF94A29CFF95A39DFF99A7A1FF9EACA6FFA1AFA9FFA0AEA8FF
+ 9CAAA4FF98A6A0FF92A29BFF91A19AFF8F9D97FF86948EFF93A19BFF5D6B65FF
+ 66726CFF7F8B85FF7F8983FF838D87FF88928CFF8A948EFF8A918CFF8A918CFF
+ 8E9590FF919992FF869189FF8D988EFF859086FF7F8A80FF889389FF8D988EFF
+ 8C978DFF919C92FF848F85FF8D988EFF929D93FF8F9A90FF8D988EFF909B91FF
+ 929D93FF919C92FF848F85FF89948AFF8C978DFF8B968CFF8B968CFF929D93FF
+ 9BA69CFFA1ACA2FFA5B0A6FFA4AFA5FFA3AEA4FFA0ABA1FF9CA79DFF97A298FF
+ 939E94FF909B91FF869489FF909E93FF97A59AFF98A69BFF9BA99EFF9EACA1FF
+ 96A499FF8A988DFF8D9B90FF9DABA0FFADBBB0FFB8C6BBFFB1BFB4FF96A499FF
+ 93A196FFACBBB3FFB6C6BFFFABBCB8FFAABBB7FFAEBFBBFFA3B4B0FF8FA09CFF
+ 8C9D99FF97A8A4FF8E9F9BFF90A19DFF92A39FFF94A5A1FF5F6462FF505553FF
+ 444947FF5A5F5DFF606764FF545B58FF19201DFF242B28FF565F5CFF727B78FF
+ 75807DFF76817EFF939E9BFFA2ADAAFF9AA8A4FF9AA8A4FF97A5A1FF99A7A3FF
+ 9BA9A5FF9CAAA6FF9BA9A5FF97A5A1FF92A09CFF8F9D99FF93A19DFF96A4A0FF
+ 97A5A1FF92A09CFF8C9A96FF8B9995FF8F9D99FF95A39FFF97A5A1FF92A09CFF
+ 8E9C98FF8F9D99FF94A29EFF9BA9A5FFA0AEAAFFA1AFABFF9EACA8FFA2B0ACFF
+ ADBBB7FFAEBCB8FF84928EFF808E8AFFAAB8B4FFC6D4D0FFAAB8B4FFA3B1ADFF
+ A2B0ACFFA7B5B1FFA9B7B3FFA6B4B0FFA5B3AFFFA9B7B3FFABB9B5FFAAB8B4FF
+ 9EACA8FF9BA9A5FF99A7A3FF9FADA9FF9EACA8FF798783FF7C8784FF5D6865FF
+ 77827FFF899491FF7E8986FF7D8885FF808B88FF8D9895FF939E9BFF8D9895FF
+ 8B9693FF929D9AFF9DA8A5FFA1ACA9FF9EA9A6FF9AA5A2FF9FADA9FF8D9B97FF
+ 8F9D99FFA3B1ADFFA4B2AEFF919F9BFF8F9D99FFA1AFABFFA9B7B3FF919F9BFF
+ 6E7C78FF465450FF1E2C28FF05130FFF04120EFF0D1C18FF61726FFF768986FF
+ B7CAC7FFC2D5D2FFBDD0CDFFB7CAC7FFB2C5C2FFB0C3C0FFA3B6B3FFA1B4B1FF
+ A0B3B0FFA3B6B3FFA8BBB8FFA9BCB9FFA5B8B5FFA2B3B0FFA0AFABFF95A39FFF
+ 99A7A3FF42504CFF8D9B97FF7F8D89FF74827EFF687672FF687672FF6B7975FF
+ 6F7D79FF72807CFF73817DFF73817DFF74827EFF75837FFF778581FF74827EFF
+ 75837FFF778581FF788682FF768480FF798783FF7F8D89FF8F9D99FF899793FF
+ 85938FFF8A9894FF92A09CFF99A7A3FF9CAAA6FF9DABA7FF9CAAA6FFA2B0ACFF
+ A7B5B1FFA7B5B1FFA3B1ADFFA1AFABFFA3B1ADFFA6B4B0FFA8B6B2FFAAB8B4FF
+ AAB8B4FFA9B7B3FFABB9B5FFAEBCB8FFAEBCB8FFAAB8B4FFA7B6B2FFABBAB6FF
+ B1C0BCFFB6C5C1FFBBCAC6FFBECDC9FFC1D0CCFFC2D1CDFFBAC9C5FFB9C8C4FF
+ B4C3BFFFB5C4C0FFA5B4B0FF9CABA7FF72817DFF91A09CFF74827EFF788682FF
+ 818F8BFF899793FF889692FF84928EFF85938FFF8B9995FF92A09CFF92A09CFF
+ 99A7A3FFA1AFABFFA1AFABFF99A7A3FF97A5A1FF9AA8A4FF9BA9A5FFA0AEAAFF
+ A1AFABFF9FADA9FF9EACA8FF9FADA9FF9CAAA6FF96A4A0FF9CAAA6FF9AA8A4FF
+ 97A5A1FF97A5A1FF99A7A3FF9CAAA6FF9DABA7FF9DABA7FF9CAAA4FF9CAAA4FF
+ 9BA9A3FF9AA8A2FF98A6A0FF96A49EFF94A29CFF93A19BFF9CAAA4FF9DABA5FF
+ 9EACA6FFA0AEA8FFA0AEA8FF9DABA5FF97A59FFF92A09AFF93A39CFF92A29BFF
+ 919F99FF8A9892FF95A39DFF64726CFF69756FFF84908AFF838D87FF858F89FF
+ 87918BFF87918BFF888F8AFF878E89FF878E89FF889089FF838E86FF89948AFF
+ 808B81FF79847AFF818C82FF859086FF828D83FF879288FF7F8A80FF869187FF
+ 8B968CFF8B968CFF8C978DFF8F9A90FF909B91FF8D988EFF7C877DFF838E84FF
+ 879288FF879288FF8A958BFF939E94FF9EA99FFFA4AFA5FFA6B1A7FFA6B1A7FF
+ A5B0A6FFA4AFA5FFA1ACA2FF9EA99FFF9BA69CFF99A49AFF8E9C91FF93A196FF
+ 95A398FF94A297FF97A59AFF9CAA9FFF99A79CFF919F94FF8D9B90FF93A196FF
+ 99A79CFFA5B3A8FFA7B5AAFF95A398FF93A196FFA8B7AFFFC3D3CCFFB4C5C1FF
+ ACBDB9FFACBDB9FFA2B3AFFF90A19DFF8A9B97FF91A29EFF90A19DFF8D9E9AFF
+ 889995FF849591FF6C716FFF585D5BFF464B49FF5A5F5DFF6D7471FF757C79FF
+ 2F3633FF171E1BFF37403DFF656E6BFF707B78FF6F7A77FF85908DFFA8B3B0FF
+ A2B0ACFF94A29EFF9BA9A5FF97A5A1FF95A39FFF99A7A3FF9DABA7FF9CAAA6FF
+ 93A19DFF8B9995FF8F9D99FF92A09CFF93A19DFF919F9BFF8D9B97FF8B9995FF
+ 8D9B97FF909E9AFF98A6A2FF93A19DFF8E9C98FF8C9A96FF8F9D99FF94A29EFF
+ 98A6A2FF9AA8A4FF9FADA9FF9AA8A4FFABB9B5FFB3C1BDFF9FADA9FF4B5955FF
+ 7F8D89FF8C9A96FF9FADA9FF98A6A2FF96A4A0FF9CAAA6FFA2B0ACFFA2B0ACFF
+ A0AEAAFFA0AEAAFF9DABA7FF8B9995FF8E9C98FF8A9894FF8C9A96FF99A7A3FF
+ 8D9B97FF7E8C88FF87928FFF4E5956FF586360FF788380FF86918EFF8C9794FF
+ 808B88FF7D8885FFA6B1AEFF99A4A1FF8A9592FF838E8BFF848F8CFF87928FFF
+ 86918EFF838E8BFF52605CFF45534FFF4B5955FF5F6D69FF5E6C68FF4A5854FF
+ 475551FF55635FFF4A5854FF465450FF42504CFF3E4C48FF394743FF3B4945FF
+ 485652FF566561FF6B7C79FF829592FFB5C8C5FFC5D8D5FFB3C6C3FFBCCFCCFF
+ AFC2BFFFB1C4C1FF9DB0ADFF9CAFACFF9EB1AEFFA2B5B2FFA6B9B6FFA4B7B4FF
+ 9EB1AEFF99AAA7FF9FAEAAFF899793FFA8B6B2FF4C5A56FF909E9AFF7F8D89FF
+ 6F7D79FF606E6AFF62706CFF5F6D69FF5F6D69FF667470FF707E7AFF75837FFF
+ 717F7BFF6B7975FF727D7AFF75807DFF77827FFF77827FFF7C8784FF808B88FF
+ 7D8885FF76817EFF87928FFF848F8CFF848F8CFF889390FF909B98FF98A3A0FF
+ 9AA5A2FF9AA5A2FF96A4A0FF9BA9A5FFA1AFABFFA3B1ADFFA1AFABFF9FADA9FF
+ A0AEAAFFA2B0ACFFA3B1ADFFA7B5B1FFA9B7B3FFA9B7B3FFADBBB7FFB3C1BDFF
+ B1BFBBFFABB9B5FFADBCB8FFAFBEBAFFB4C3BFFFB9C8C4FFBECDC9FFC1D0CCFF
+ C3D2CEFFC3D2CEFFBBCAC6FFBDCCC8FFB6C5C1FFAEBDB9FFA3B2AEFFA2B1ADFF
+ 7D8C88FF83928EFF6E7C78FF72807CFF7D8B87FF899793FF8E9C98FF899793FF
+ 85938FFF85938FFF8D9B97FF8E9C98FF95A39FFF9FADA9FFA2B0ACFF9DABA7FF
+ 97A5A1FF95A39FFF9FADA9FFA2B0ACFFA2B0ACFF9EACA8FF9DABA7FF9FADA9FF
+ 9FADA9FF9BA9A5FF9CAAA6FF9CAAA6FF9BA9A5FF99A7A3FF98A6A2FF98A6A2FF
+ 9BA9A5FF9EACA8FF9DABA5FF9CAAA4FF9BA9A3FF9AA8A2FF99A7A1FF99A7A1FF
+ 99A7A1FF99A7A1FFA1AFA9FFA1AFA9FFA1AFA9FFA2B0AAFFA1AFA9FF9DABA5FF
+ 97A59FFF92A09AFF97A7A0FF93A39CFF92A09AFF8C9A94FF93A19BFF697771FF
+ 65716BFF838F89FF838D87FF828C86FF828C86FF838D87FF868D88FF868D88FF
+ 848B86FF828A83FF818C84FF879288FF7E897FFF778278FF818C82FF869187FF
+ 838E84FF879288FF808B81FF859086FF889389FF89948AFF8C978DFF8F9A90FF
+ 8B968CFF859086FF7A857BFF838E84FF89948AFF8A958BFF8E998FFF9AA59BFF
+ A5B0A6FFA9B4AAFFA8B3A9FFA9B4AAFFA9B4AAFFA8B3A9FFA7B2A8FFA6B1A7FF
+ A4AFA5FFA3AEA4FF99A79CFF99A79CFF96A499FF92A095FF95A398FF9BA99EFF
+ 9DABA0FF9AA89DFF96A499FF92A095FF8C9A8FFF95A398FF9FADA2FF95A398FF
+ 93A196FFA2B1A9FFCCDCD5FFB9CAC6FFAABBB7FFA5B6B2FF9FB0ACFF94A5A1FF
+ 8D9E9AFF8D9E9AFF8C9D99FF839490FF768783FF6F807CFF616664FF575C5AFF
+ 4A4F4DFF525755FF606764FF7C8380FF454C49FF252C29FF2C3532FF5B6461FF
+ 6A7572FF707B78FF76817EFF9FAAA7FFA3B1ADFF9EACA8FF9CAAA6FF98A6A2FF
+ 94A29EFF95A39FFF98A6A2FF98A6A2FF93A19DFF8E9C98FF889692FF8B9995FF
+ 8E9C98FF909E9AFF909E9AFF8F9D99FF909E9AFF909E9AFF97A5A1FF93A19DFF
+ 8E9C98FF8C9A96FF8D9B97FF919F9BFF96A4A0FF99A7A3FF9FADA9FF8E9C98FF
+ A6B4B0FFB2C0BCFFB1BFBBFF55635FFF5F6D69FF5E6C68FFA2B0ACFFA0AEAAFF
+ 9EACA8FF9FADA9FF9FADA9FF9CAAA6FF9AA8A4FF99A7A3FF889692FF6C7A76FF
+ 7C8A86FF768480FF73817DFF818F8BFF72807CFF768480FF818C89FF35403DFF
+ 313C39FF5A6562FF7A8582FF8C9794FF818C89FF7A8582FF7F8A87FF8C9794FF
+ 96A19EFF8D9895FF798481FF65706DFF55605DFF4D5855FF4A5854FF566460FF
+ 5F6D69FF5E6C68FF5B6965FF596763FF505E5AFF45534FFF596763FF63716DFF
+ 717F7BFF7C8A86FF7F8D89FF7F8D89FF82908CFF869591FF81928FFF7E918EFF
+ 98ABA8FFBED1CEFFB6C9C6FFC8DBD8FFAABDBAFFA9BCB9FF9FB2AFFF9EB1AEFF
+ 9DB0ADFFA0B3B0FFA3B6B3FFA0B3B0FF99ACA9FF94A5A2FF9BAAA6FF808E8AFF
+ 9FADA9FF55635FFF788682FF818F8BFF6E7C78FF697773FF63716DFF5D6B67FF
+ 596763FF5F6D69FF6A7874FF707E7AFF6E7C78FF697773FF6D7875FF77827FFF
+ 7B8683FF77827FFF7A8582FF828D8AFF818C89FF77827FFF7E8986FF7F8A87FF
+ 7F8A87FF818C89FF8A9592FF95A09DFF9BA6A3FF9AA5A2FF96A4A0FF99A7A3FF
+ 9DABA7FF9EACA8FF9DABA7FF9DABA7FFA0AEAAFFA2B0ACFF9CAAA6FFA1AFABFF
+ A4B2AEFFA5B3AFFFADBBB7FFB8C6C2FFB8C6C2FFAFBDB9FFB1C0BCFFB3C2BEFF
+ B6C5C1FFBBCAC6FFC0CFCBFFC3D2CEFFC3D2CEFFC2D1CDFFBFCECAFFC4D3CFFF
+ B8C7C3FFA5B4B0FF9DACA8FF9DACA8FF7F8E8AFF687773FF6B7975FF6A7874FF
+ 717F7BFF7F8D89FF899793FF8A9894FF889692FF899793FF909E9AFF909E9AFF
+ 94A29EFF9BA9A5FF9FADA9FF9CAAA6FF95A39FFF8F9D99FF9AA8A4FF9EACA8FF
+ 9FADA9FF9AA8A4FF97A5A1FF99A7A3FF98A6A2FF95A39FFF9CAAA6FF9EACA8FF
+ 9EACA8FF9BA9A5FF96A4A0FF94A29EFF97A5A1FF9AA8A4FF9AA8A2FF99A7A1FF
+ 99A7A1FF99A7A1FF9BA9A3FF9EACA6FFA1AFA9FFA3B1ABFF9EACA6FF9EACA6FF
+ 9FADA7FFA2B0AAFFA3B1ABFFA1AFA9FF9DABA5FF99A7A1FF99A9A2FF92A29BFF
+ 92A09AFF8D9B95FF8E9C96FF6C7A74FF5B6761FF7E8A84FF808A84FF7E8882FF
+ 7D8781FF808A84FF878E89FF89908BFF868D88FF838B84FF7C877FFF828D83FF
+ 79847AFF758076FF828D83FF8A958BFF889389FF8B968CFF89948AFF8B968CFF
+ 8B968CFF8A958BFF8D988EFF8E998FFF869187FF7C877DFF848F85FF8F9A90FF
+ 95A096FF939E94FF97A298FFA3AEA4FFADB8AEFFAFBAB0FFACB7ADFFACB7ADFF
+ ACB7ADFFACB7ADFFABB6ACFFAAB5ABFFA9B4AAFFA8B3A9FFA4B2A7FFA0AEA3FF
+ 9BA99EFF98A69BFF99A79CFF9CAA9FFF9EACA1FF9DABA0FFA3B1A6FF9CAA9FFF
+ 919F94FF95A398FF9FADA2FF98A69BFF94A297FFA0AFA7FFC9D9D2FFB6C7C3FF
+ A3B4B0FF9BACA8FF99AAA6FF96A7A3FF8FA09CFF8B9C98FF80918DFF778884FF
+ 6B7C78FF647571FF646967FF5F6462FF555A58FF545957FF59605DFF818885FF
+ 525956FF29302DFF262F2CFF4C5552FF626D6AFF7E8986FF727D7AFF929D9AFF
+ 97A5A1FFA3B1ADFF9CAAA6FF9BA9A5FF98A6A2FF94A29EFF909E9AFF909E9AFF
+ 92A09CFF95A39FFF8A9894FF8B9995FF8C9A96FF8F9D99FF919F9BFF919F9BFF
+ 8F9D99FF8D9B97FF96A4A0FF93A19DFF8F9D99FF8B9995FF8A9894FF8B9995FF
+ 8E9C98FF919F9BFF98A6A2FF8A9894FFA3B1ADFFA6B4B0FFA7B5B1FF8F9D99FF
+ 7B8985FF8E9C98FF84928EFF899793FF8A9894FF83918DFF798783FF73817DFF
+ 72807CFF73817DFF93A19DFF778581FF869490FF788682FF677571FF6A7874FF
+ 5A6864FF64726EFF596461FF212C29FF2C3734FF4D5855FF5F6A67FF707B78FF
+ 75807DFF808B88FF7A8582FF747F7CFF606B68FF444F4CFF394441FF4B5653FF
+ 6A7572FF808B88FF7C8A86FF899793FF919F9BFF909E9AFF909E9AFF909E9AFF
+ 84928EFF73817DFF697773FF717F7BFF7C8A86FF84928EFF8B9995FF95A39FFF
+ 9EACA8FFA3B2AEFF97A8A5FF7E918EFF8DA09DFFBED1CEFFBBCECBFFC3D6D3FF
+ A1B4B1FFA6B9B6FF9FB2AFFF9CAFACFF9BAEABFF9DB0ADFFA0B3B0FFA1B4B1FF
+ 9CAFACFF99AAA7FF94A39FFF82908CFF8E9C98FF6C7A76FF616F6BFF85938FFF
+ 6F7D79FF6F7D79FF697773FF63716DFF5D6B67FF5D6B67FF62706CFF677571FF
+ 6A7874FF6B7975FF646F6CFF717C79FF77827FFF707B78FF6F7A77FF77827FFF
+ 7B8683FF788380FF7D8885FF7E8986FF7B8683FF788380FF7F8A87FF8C9794FF
+ 95A09DFF95A09DFF97A5A1FF97A5A1FF95A39FFF94A29EFF94A29EFF98A6A2FF
+ 9EACA8FFA2B0ACFF95A39FFF9BA9A5FF9DABA7FF9DABA7FFAAB8B4FFBCCAC6FF
+ BFCDC9FFB7C5C1FFB6C5C1FFB6C5C1FFB7C6C2FFBCCBC7FFC2D1CDFFC4D3CFFF
+ C3D2CEFFC1D0CCFFBECDC9FFC3D2CEFFB6C5C1FF9DACA8FF97A6A2FF94A39FFF
+ 808F8BFF52615DFF72807CFF6B7975FF697773FF717F7BFF7C8A86FF83918DFF
+ 889692FF8D9B97FF98A6A2FF97A5A1FF96A4A0FF97A5A1FF99A7A3FF99A7A3FF
+ 92A09CFF8C9A96FF93A19DFF9AA8A4FF9DABA7FF99A7A3FF95A39FFF94A29EFF
+ 92A09CFF8F9D99FF97A5A1FF9AA8A4FF9CAAA6FF9AA8A4FF96A4A0FF95A39FFF
+ 98A6A2FF9BA9A5FF9AA8A2FF9AA8A2FF9AA8A2FF9AA8A2FF9DABA5FFA0AEA8FF
+ A4B2ACFFA6B4AEFF9EACA6FF9EACA6FF9FADA7FFA1AFA9FFA4B2ACFFA3B1ABFF
+ A0AEA8FF9DABA5FF98A8A1FF8F9F98FF92A09AFF8F9D97FF8C9A94FF76847EFF
+ 59655FFF828E88FF828C86FF808A84FF7E8882FF818B85FF878E89FF888F8AFF
+ 868D88FF828A83FF79847CFF7D887EFF747F75FF707B71FF7F8A80FF869187FF
+ 838E84FF869187FF889389FF8A958BFF89948AFF889389FF8A958BFF8C978DFF
+ 859086FF7C877DFF8E998FFF9BA69CFFA0ABA1FF9BA69CFF9CA79DFFA8B3A9FF
+ B0BBB1FFAEB9AFFFB0BBB1FFAFBAB0FFAEB9AFFFACB7ADFFAAB5ABFFA9B4AAFF
+ A8B3A9FFA8B3A9FFA9B7ACFFA5B3A8FFA2B0A5FFA1AFA4FFA1AFA4FF9FADA2FF
+ 9DABA0FF9CAA9FFFA4B2A7FFA3B1A6FF9BA99EFF9CAA9FFFA3B1A6FF9BA99EFF
+ 97A59AFFA3B2AAFFC3D3CCFFB7C6C2FFA5B4B0FF97A6A2FF93A29EFF92A19DFF
+ 8B9A96FF83928EFF798884FF758480FF71807CFF707F7BFF666B69FF5D6260FF
+ 555A58FF575C5AFF5F6663FF909794FF636A67FF2D3431FF1F2825FF3C4542FF
+ 586360FF8D9895FF77827FFF8F9A97FF8D9B97FF9BA9A5FF9DABA7FFA0AEAAFF
+ 9FADA9FF98A6A2FF8E9C98FF8B9995FF919F9BFF99A7A3FF94A29EFF919F9BFF
+ 8F9D99FF909E9AFF92A09CFF919F9BFF8C9A96FF879591FF95A39FFF94A29EFF
+ 919F9BFF8B9995FF85938FFF818F8BFF818F8BFF82908CFF7E8C88FF8A9894FF
+ A1AFABFF9BA9A5FF8E9C98FF9BA9A5FF75837FFF92A09CFF889692FF94A29EFF
+ 9CAAA6FF98A6A2FF909E9AFF909E9AFF95A39FFF98A6A2FFA1AFABFF8E9C98FF
+ 919F9BFF84928EFF6E7C78FF677571FF5F6D69FF5E6C68FF3B4643FF101B18FF
+ 222D2AFF3F4A47FF4E5956FF616C69FF65706DFF687370FF4B5653FF515C59FF
+ 535E5BFF56615EFF646F6CFF77827FFF7F8A87FF7B8683FF879591FF7B8985FF
+ 7D8B87FF8F9D99FF95A39FFF899793FF7F8D89FF808E8AFF899793FF8E9C98FF
+ 909E9AFF8C9A96FF899793FF8A9894FF8B9995FF889793FFA0B1AEFF8B9E9BFF
+ A4B7B4FFC3D6D3FFB9CCC9FFB2C5C2FF9DB0ADFFA8BBB8FF98ABA8FF96A9A6FF
+ 95A8A5FF99ACA9FF9FB2AFFFA1B4B1FF9FB2AFFF9EAFACFF8D9C98FF899793FF
+ 869490FF889692FF596763FF818F8BFF73817DFF687672FF6B7975FF677571FF
+ 616F6BFF5E6C68FF5E6C68FF616F6BFF65736FFF687672FF606B68FF6A7572FF
+ 707B78FF6D7875FF6A7572FF6E7976FF76817EFF7A8582FF7C8784FF7F8A87FF
+ 7B8683FF737E7BFF76817EFF848F8CFF8C9794FF8B9693FF96A4A0FF93A19DFF
+ 8E9C98FF8B9995FF8C9A96FF919F9BFF98A6A2FF9DABA7FF93A19DFF98A6A2FF
+ 96A4A0FF94A29EFFA3B1ADFFBDCBC7FFC5D3CFFFBDCBC7FFBAC9C5FFB9C8C4FF
+ BAC9C5FFBECDC9FFC4D3CFFFC6D5D1FFC4D3CFFFC0CFCBFFB9C8C4FFBCCBC7FF
+ B1C0BCFF99A8A4FF96A5A1FF8E9D99FF879692FF4B5A56FF7D8B87FF72807CFF
+ 697773FF6B7975FF717F7BFF798783FF82908CFF8B9995FF909E9AFF93A19DFF
+ 92A09CFF8F9D99FF8F9D99FF909E9AFF8C9A96FF869490FF8F9D99FF98A6A2FF
+ 9EACA8FF9BA9A5FF97A5A1FF96A4A0FF95A39FFF93A19DFF93A19DFF96A4A0FF
+ 98A6A2FF99A7A3FF99A7A3FF9BA9A5FF9DABA7FF9FADA9FF9EACA6FF9DABA5FF
+ 9DABA5FF9DABA5FF9EACA6FF9FADA7FFA0AEA8FFA1AFA9FFA3B1ABFFA2B0AAFF
+ A1AFA9FFA2B0AAFFA2B0AAFFA1AFA9FF9DABA5FF9AA8A2FF97A7A0FF8C9C95FF
+ 92A09AFF93A19BFF8E9C96FF83918BFF5D6963FF8C9892FF87918BFF858F89FF
+ 848E88FF848E88FF858C87FF848B86FF818883FF7E867FFF808B83FF838E84FF
+ 778278FF727D73FF7F8A80FF859086FF808B81FF818C82FF7E897FFF828D83FF
+ 838E84FF838E84FF859086FF8A958BFF889389FF838E84FF8E998FFF9DA89EFF
+ A2ADA3FF9AA59BFF9AA59BFFA8B3A9FFAEB9AFFFAAB5ABFFB2BDB3FFB0BBB1FF
+ AEB9AFFFABB6ACFFA9B4AAFFA7B2A8FFA7B2A8FFA6B1A7FFA8B6ABFFA4B2A7FF
+ A4B2A7FFA8B6ABFFA8B6ABFFA2B0A5FF9CAA9FFF9BA99EFF9BA99EFFA0AEA3FF
+ 9DABA0FF9EACA1FFA4B2A7FF9DABA0FF9AA89DFFA4B3ABFFC3D1CBFFBECDC9FF
+ AFBEBAFF99A8A4FF8B9A96FF879692FF7F8E8AFF758480FF778682FF7B8A86FF
+ 81908CFF859490FF5C615FFF515654FF4D5250FF4D5250FF4D5451FF848B88FF
+ 666D6AFF383F3CFF222B28FF363F3CFF4D5855FF8C9794FF7A8582FF9DA8A5FF
+ 96A4A0FF9AA8A4FFA0AEAAFFA4B2AEFFA6B4B0FFA0AEAAFF95A39FFF8F9D99FF
+ 92A09CFF97A5A1FF9AA8A4FF95A39FFF919F9BFF919F9BFF94A29EFF93A19DFF
+ 8D9B97FF879591FF92A09CFF93A19DFF92A09CFF8D9B97FF869490FF7F8D89FF
+ 7D8B87FF7D8B87FF6E7C78FF8E9C98FF93A19DFF95A39FFF909E9AFF8B9995FF
+ 63716DFF62706CFF808E8AFF8C9A96FF96A4A0FF94A29EFF93A19DFF98A6A2FF
+ 9DABA7FF9EACA8FF98A6A2FF919F9BFF83918DFF7F8D89FF707E7AFF677571FF
+ 697773FF53615DFF242F2CFF010C09FF121D1AFF27322FFF36413EFF525D5AFF
+ 57625FFF535E5BFF606B68FF67726FFF687370FF67726FFF727D7AFF86918EFF
+ 8F9A97FF8B9693FF97A5A1FF82908CFF798783FF84928EFF8F9D99FF8C9A96FF
+ 889692FF899793FF818F8BFF8D9B97FF98A6A2FF9CAAA6FFA0AEAAFFA4B2AEFF
+ A2B0ACFF9BAAA6FF9DAEABFF96A9A6FFB9CCC9FFBACDCAFFB6C9C6FFAEC1BEFF
+ A5B8B5FFA1B4B1FF93A6A3FF92A5A2FF93A6A3FF98ABA8FF9DB0ADFF9DB0ADFF
+ 98ABA8FF94A5A2FF889793FF8A9894FF7F8D89FF8E9C98FF596763FF6F7D79FF
+ 7F8D89FF616F6BFF687672FF65736FFF606E6AFF5E6C68FF5F6D69FF606E6AFF
+ 5F6D69FF5E6C68FF636E6BFF666F6CFF6B7471FF707976FF717A77FF707976FF
+ 747D7AFF7B8481FF7A8380FF818A87FF7F8885FF77807DFF7A8380FF89928FFF
+ 919A97FF8C9794FF95A39FFF919F9BFF8D9B97FF8A9894FF8B9995FF909E9AFF
+ 94A29EFF97A5A1FF96A4A0FF98A6A2FF919F9BFF8B9995FF9BA9A5FFBAC8C4FF
+ C6D4D0FFBFCDC9FFC0CFCBFFBDCCC8FFBDCCC8FFC1D0CCFFC7D6D2FFCAD9D5FF
+ C6D5D1FFC1D0CCFFB9C8C4FFB8C7C3FFB0BFBBFF9BAAA6FF98A7A3FF899894FF
+ 8D9C98FF4A5955FF7F8D89FF75837FFF6E7C78FF6E7C78FF717F7BFF768480FF
+ 7F8D89FF889692FF84928EFF8D9B97FF92A09CFF8F9D99FF8E9C98FF909E9AFF
+ 8E9C98FF889692FF8D9B97FF96A4A0FF9BA9A5FF98A6A2FF96A4A0FF99A7A3FF
+ 9DABA7FF9EACA8FF9AA8A4FF99A7A3FF99A7A3FF9BA9A5FF9EACA8FF9FADA9FF
+ 9EACA8FF9DABA7FF9CAAA4FF9DABA5FF9EACA6FF9FADA7FF9FADA7FF9FADA7FF
+ 9FADA7FF9EACA6FFA5B3ADFFA4B2ACFFA2B0AAFFA1AFA9FFA1AFA9FF9FADA7FF
+ 9BA9A3FF97A59FFF9AAAA3FF8D9D96FF94A29CFF96A49EFF8C9A94FF889690FF
+ 58645EFF8B9791FF858F89FF86908AFF86908AFF848E88FF838A85FF808782FF
+ 7F8681FF7F8780FF848F87FF859086FF79847AFF737E74FF818C82FF879288FF
+ 818C82FF808B81FF7B867CFF818C82FF838E84FF818C82FF828D83FF889389FF
+ 8B968CFF8A958BFF869187FF97A298FF9EA99FFF96A197FF98A399FFA8B3A9FF
+ AFBAB0FFA9B4AAFFB1BCB2FFAFBAB0FFACB7ADFFAAB5ABFFA8B3A9FFA7B2A8FF
+ A7B2A8FFA7B2A8FFA2B0A5FF9EACA1FFA0AEA3FFA8B6ABFFA9B7ACFFA3B1A6FF
+ 9EACA1FF9EACA1FF9BA99EFF9FADA2FF9AA89DFF9AA89DFFA2B0A5FF9DABA0FF
+ 98A69BFF9EADA5FFC2D0CAFFC7D6D2FFBDCCC8FFA0AFABFF889793FF7F8E8AFF
+ 778682FF6D7C78FF7A8985FF83928EFF8F9E9AFF96A5A1FF6F7472FF676E6BFF
+ 666B69FF575E5BFF444B48FF7A817EFF717875FF585F5CFF2B3431FF39423FFF
+ 45504DFF838E8BFF77827FFFACB7B4FFA8B3B0FFA1AFABFFA2B0ACFFA6B5B1FF
+ AAB8B4FFA6B5B1FF9DABA7FF94A39FFF92A09CFF92A19DFF9AA8A4FF93A29EFF
+ 8F9D99FF8F9E9AFF95A39FFF96A5A1FF92A09CFF8B9A96FF8F9D99FF91A09CFF
+ 94A29EFF909F9BFF8A9894FF83928EFF818F8BFF808F8BFF798783FF94A39FFF
+ 7C8A86FF8D9C98FFA9B7B3FF93A29EFF7E8C88FF5F6D69FF8D9B97FF94A29EFF
+ 96A4A0FF909E9AFF8E9C98FF909E9AFF8D9B97FF879591FF8D9B97FF8B9995FF
+ 707B78FF727D7AFF697471FF5D6865FF636E6BFF3C4744FF05100DFF000502FF
+ 182320FF1B2623FF121D1AFF303B38FF4D5855FF606B68FF66716EFF7C8784FF
+ 899491FF7F8A87FF77827FFF7E8986FF87928FFF899491FFA0ABA8FF96A4A0FF
+ 82908CFF73817DFF7F8D89FF96A4A0FF95A39FFF83918DFF8E9C98FF96A4A0FF
+ 99A7A3FF97A5A1FF9AA8A4FFA3B1ADFFA7B5B1FFA3B2AEFF99AAA7FF98ABA8FF
+ BDD0CDFFA8BBB8FFB6C9C6FFB9CCC9FFB2C5C2FF94A7A4FF92A5A2FF94A5A2FF
+ 96A7A4FF9AABA8FF9DAEABFF98A9A6FF8E9F9CFF869794FF859490FF85938FFF
+ 788682FF83918DFF576561FF5B6965FF8C9A96FF63716DFF64726EFF606E6AFF
+ 5E6966FF606B68FF646F6CFF636E6BFF5D6865FF56615EFF646D6AFF5D6663FF
+ 606966FF6E7774FF737C79FF6F7875FF6E7774FF747D7AFF747D7AFF7F8885FF
+ 828B88FF7E8784FF838C89FF939C99FF9BA4A1FF949F9CFF96A4A0FF93A19DFF
+ 909E9AFF8F9D99FF909E9AFF92A09CFF94A29EFF95A39FFF99A7A3FF9AA8A4FF
+ 8F9D99FF85938FFF96A4A0FFB7C5C1FFC6D4D0FFBFCDC9FFC3D2CEFFBECFCBFF
+ BFCECAFFC4D3CFFFCAD9D5FFCCDBD7FFC8D7D3FFC3D2CEFFBDCCC8FFBAC9C5FF
+ B3C2BEFFA0AFABFF9BAAA6FF859490FF8F9E9AFF4B5955FF798783FF73817DFF
+ 717F7BFF73817DFF768480FF788682FF808E8AFF899793FF82908CFF909E9AFF
+ 9BA9A5FF9BA9A5FF9AA8A4FF9CAAA6FF9BA9A5FF95A39FFF8A9894FF92A09CFF
+ 97A5A1FF94A29EFF93A19DFF9AA8A4FFA3B1ADFFA7B5B1FFA4B2AEFFA1AFABFF
+ 9EACA8FF9EACA8FFA0AEAAFF9FADA9FF9BA9A5FF96A4A0FF97A59FFF99A7A1FF
+ 9CAAA4FF9FADA7FFA1AFA9FFA2B0AAFFA1AFA9FFA1AFA9FFA4B2ACFFA2B0AAFF
+ A0AEA8FFA0AEA8FFA1AFA9FF9FADA7FF9CAAA4FF99A7A1FFA0AEA8FF919F99FF
+ 95A39DFF96A49EFF87958FFF84928CFF4E5A54FF818D87FF7E8882FF828C86FF
+ 858F89FF848E88FF808A84FF7D8781FF818883FF818B85FF7B867EFF7D887EFF
+ 717C74FF6D786EFF7D8880FF848F85FF7E8981FF7E897FFF818C84FF879288FF
+ 89948CFF848F85FF828D85FF879288FF8C978FFF8E998FFF7F8A80FF929D93FF
+ 9AA59BFF939E94FF97A298FFAAB5ABFFB2BDB3FFADB8AEFFAFBAB0FFAEB9AFFF
+ ABB6ACFFA9B4AAFFA8B3A9FFA8B3A9FFA9B4AAFFA7B5AAFF9DABA0FF98A69BFF
+ 9BA99EFFA5B3A8FFA8B6ABFFA3B1A6FF9FADA2FFA2B0A5FFA3B1A6FFA2B0A5FF
+ 98A69BFF97A59AFFA0AEA3FF9DABA0FF94A297FF96A59DFFBECEC7FFCCDBD7FF
+ C7D6D2FFA7B6B2FF899894FF7E8D89FF768581FF6C7B77FF7B8A86FF879692FF
+ 95A4A0FF9BAAA6FF7C8380FF6B7471FF69706DFF6B7471FF4D5653FF505956FF
+ 79827FFF717A77FF3B4441FF303936FF4F5855FF78817EFF838C89FF949D9AFF
+ AEB7B4FFB2BDBAFFA7B6B2FFA0B1ADFFA1B0ACFFA1B2AEFF9DACA8FF8FA09CFF
+ 8C9B97FF8C9D99FF96A5A1FF91A29EFF909F9BFF8E9F9BFF93A29EFF94A5A1FF
+ 96A5A1FF92A39FFF8F9E9AFF889995FF8B9A96FF8FA09CFF8F9E9AFF82938FFF
+ 7E8D89FF7D8E8AFF798884FF80918DFF8D9C98FF81928EFF9CABA7FF7B8C88FF
+ 798884FF83928EFF859490FF899894FF8F9D99FF919F9BFF8F9D99FF8B9995FF
+ 889390FF85908DFF838E8BFF798481FF78817EFF5F6865FF747D7AFF79827FFF
+ 606966FF1B2421FF08110EFF060F0CFF0B1411FF1D2623FF38413EFF535C59FF
+ 6A7370FF78817EFF737C79FF7B8481FF848D8AFF87908DFF858E8BFF838C89FF
+ 858E8BFF86918EFFA5B0ADFF95A09DFF87928FFF85908DFF838E8BFF808B88FF
+ 85908DFF8F9A97FF97A29FFF9AA5A2FF9FAAA7FFA3AEABFFA4AFACFFA3AEABFF
+ A0ABA8FF9CAAA6FF92A3A0FFAFC2BFFFB1C4C1FFA2B5B2FFAEBFBCFFBBCCC9FF
+ ACBDBAFF98A9A6FF91A29FFF8D9B99FF919F9DFF93A19FFF8F9D9BFF94A2A0FF
+ 929F9DFF808D8BFF8C9B97FF808F8BFF8C9A96FF808E8AFF687672FF293733FF
+ 6E7976FF747F7CFF687370FF5D6865FF636C69FF5A6360FF616A67FF717A77FF
+ 646D6AFF646D6AFF69726FFF626D6AFF636E6BFF697471FF6B7673FF6A7572FF
+ 707B78FF798481FF707B78FF76817EFF7F8A87FF848F8CFF828D8AFF85908DFF
+ 97A29FFFABB6B3FF94A29EFF9AA8A4FF919F9BFF7F8D89FF808E8AFF909E9AFF
+ 93A19DFF879591FF94A29EFF99A7A3FF92A09CFF869490FF93A19DFFB2C0BCFF
+ C1CFCBFFBAC9C5FFC4D5D1FFC0D4CFFFC0D1CDFFBFD0CCFFC1D2CEFFC5D6D2FF
+ CADBD7FFCEDFDBFFCDDCD8FFBFCECAFFB5C3BFFFADBBB7FF8F9D99FF8B9995FF
+ 899793FF4D5B57FF6C7A76FF72807CFF778581FF778581FF74827EFF768480FF
+ 82908CFF8E9C98FF96A4A0FF98A6A2FF9FADA9FFA6B4B0FFA6B4B0FFA0AEAAFF
+ 99A7A3FF97A5A1FF9DABA5FF9AA8A2FF99A7A1FF9BA9A3FF9AA8A2FF97A59FFF
+ 9AA8A2FF9FADA7FF9DABA5FFA0AEA8FF9EACA6FF9BA9A3FF9FADA7FFA5B3ADFF
+ A1AFA9FF97A59FFF9AA8A2FF96A49EFF93A19BFF96A49EFF9CAAA4FFA2B0AAFF
+ A3B1ABFFA3B1ABFFA0AEA8FFA0AEA8FFA0AEA8FF9FADA7FF9FADA7FF9FADA7FF
+ 9FADA7FF9FADA7FF99A7A1FF9DA9A3FF97A39DFF8C9892FF88948EFF828E88FF
+ 414D47FF808C86FF85918BFF84908AFF838F89FF84908AFF84908AFF838F89FF
+ 818B85FF7D8781FF7E8882FF7C877FFF757F79FF6D7870FF6E7872FF78837BFF
+ 7E8882FF7E8981FF7A847EFF7C877FFF7F8983FF808B83FF818B85FF848F87FF
+ 88928CFF8B968EFF8C9A8FFF919F94FF94A297FF94A297FF99A79CFFA2B0A5FF
+ A8B6ABFFA8B6ABFFA6B4A9FFAAB8ADFFADBBB0FFACBAAFFFA8B6ABFFA4B2A7FF
+ A2B0A5FFA3B1A6FFAEBCB1FF9AAA9FFF93A398FFA0B0A5FFA9B9AEFFA2B2A7FF
+ 9BABA0FF9CACA1FF9BABA0FFA2B2A7FFA5B5AAFFA2B2A7FFA0B0A5FFA0B0A5FF
+ 9CACA1FF96A59DFFB2C2BBFFCCDCD5FFCEDED7FFB8C8C1FFA3B3ACFF91A19AFF
+ 85958EFF879790FF778780FF8C9C95FF9EAEA7FFA0B0A9FF757E7BFF707976FF
+ 69726FFF6C7572FF565F5CFF545D5AFF727B78FF6C7572FF3D4643FF28312EFF
+ 3E4744FF6B7471FF818A87FF949D9AFFABB4B1FFB0BBB8FFA0AFABFF9AABA7FF
+ 9DAEAAFFA3B4B0FFA3B4B0FF9AABA7FF95A6A2FF95A6A2FF97A8A4FF95A6A2FF
+ 93A4A0FF93A4A0FF94A5A1FF95A6A2FF95A6A2FF95A6A2FF8A9B97FF879894FF
+ 889995FF8E9F9BFF8D9E9AFF849591FF80918DFF81928EFF71827EFF82938FFF
+ 8D9E9AFF849591FF8A9B97FF839490FF8A9B97FF92A39FFF82918DFF83928EFF
+ 85938FFF84928EFF82908CFF7F8D89FF808B88FF7F8A87FF87908DFF7D8683FF
+ 737C79FF5D6663FF7B827FFF707774FF484F4CFF070E0BFF141D1AFF1F2825FF
+ 363F3CFF525B58FF656E6BFF6E7774FF707976FF717A77FF79827FFF7C8582FF
+ 808986FF858E8BFF87908DFF87908DFF858E8BFF828B88FF9EA9A6FF96A19EFF
+ 86918EFF788380FF737E7BFF77827FFF7F8A87FF838E8BFF8E9996FF919C99FF
+ 97A29FFF9EA9A6FFA4AFACFFA8B3B0FFAAB5B2FFA9B7B3FF9EAFACFFB8CBC8FF
+ B8CBC8FFA6B9B6FFAEBFBCFFB6C7C4FFA6B7B4FF92A3A0FF98A6A4FF92A09EFF
+ 96A3A1FF94A19FFF8C9997FF909D9BFF929D9BFF83908EFF8B9995FF808F8BFF
+ 8A9894FF7F8D89FF697773FF283632FF697471FF6F7A77FF6E7774FF646D6AFF
+ 68716EFF5D6663FF636A67FF727976FF686F6CFF68716EFF69726FFF646F6CFF
+ 66716EFF6C7774FF6D7875FF6B7673FF6F7A77FF77827FFF747F7CFF76817EFF
+ 7A8582FF7C8784FF7B8683FF7E8986FF8F9A97FFA1ACA9FF84928EFF8F9D99FF
+ 919F9BFF869490FF818F8BFF879591FF899793FF84928EFF94A29EFF9BA9A5FF
+ 99A7A3FF8F9D99FF94A29EFFA9B7B3FFBDCBC7FFC3D2CEFFC1D2CEFFBFD3CEFF
+ BFD3CEFFBFD3CEFFC2D3CFFFC4D5D1FFC5D6D2FFC6D7D3FFC7D6D2FFBBCAC6FF
+ B1BFBBFFABB9B5FF919F9BFF8D9B97FF8F9A97FF57625FFF677571FF687672FF
+ 6E7C78FF75837FFF768480FF778581FF83918DFF919F9BFF8F9D99FF93A19DFF
+ 99A7A3FF9FADA9FFA1AFABFF9DABA7FF99A7A3FF97A5A1FF93A19BFF92A09AFF
+ 95A39DFF98A6A0FF97A59FFF96A49EFF9BA9A3FFA3B1ABFF9DABA5FFA0AEA8FF
+ 9FADA7FF9BA9A3FF9DABA5FFA3B1ABFFA2B0AAFF9DABA5FFA1AFA9FF9FADA7FF
+ 9CAAA4FF9BA9A3FF9DABA5FFA0AEA8FFA1AFA9FFA1AFA9FFA3B1ABFFA3B1ABFF
+ A1AFA9FFA0AEA8FF9EACA6FF9CAAA4FF9BA9A3FF9AA8A2FF9AA6A0FF9CA8A2FF
+ 98A49EFF8F9B95FF8C9892FF838F89FF48544EFF838F89FF808C86FF7E8A84FF
+ 7D8983FF7D8983FF7E8A84FF7C8882FF78847EFF75817BFF7A847EFF7A847EFF
+ 77817BFF727C76FF747E78FF7B857FFF808A84FF7F8983FF7B857FFF7D8781FF
+ 808A84FF818B85FF828C86FF848E88FF89938DFF8C978FFF8F9C94FF94A297FF
+ 96A499FF96A499FF9AA89DFFA2B0A5FFA7B5AAFFA6B4A9FFA5B3A8FFA8B6ABFF
+ ACBAAFFFADBBB0FFAAB8ADFFA7B5AAFFA7B5AAFFA8B6ABFFABBBB0FF9FAFA4FF
+ 98A89DFF9EAEA3FFA5B5AAFFA4B4A9FFA0B0A5FF9EAEA3FF9AAA9FFF9DADA2FF
+ 9EAEA3FF9FAFA4FFA1B1A6FFA2B2A7FF9BABA0FF91A196FFACBCB5FFCADAD3FF
+ D2E2DBFFC1D1CAFFAFBFB8FF9BABA4FF8B9B94FF8A9A93FF7B8B84FF8E9E97FF
+ 9FAFA8FFA2B2ABFF717A77FF79827FFF707976FF727B78FF68716EFF5F6865FF
+ 6E7774FF6A7370FF4F5855FF2B3431FF303936FF5D6663FF828B88FF9AA3A0FF
+ AFB8B5FFB6C1BEFFA9B8B4FFA4B5B1FFA6B7B3FFABBCB8FFABBCB8FFA1B2AEFF
+ 96A7A3FF91A29EFF98A9A5FF99AAA6FF99AAA6FF97A8A4FF96A7A3FF96A7A3FF
+ 97A8A4FF99AAA6FF8D9E9AFF8A9B97FF8B9C98FF8D9E9AFF8A9B97FF839490FF
+ 80918DFF81928EFF7B8C88FF8D9E9AFF95A6A2FF8FA09CFF778884FF839490FF
+ 8D9E9AFF8FA09CFF859490FF82918DFF7F8D89FF7B8985FF798783FF788682FF
+ 7B8683FF7B8683FF7D8683FF7C8582FF727B78FF5E6764FF7F8683FF686F6CFF
+ 474E4BFF29302DFF515A57FF535C59FF5C6562FF6A7370FF737C79FF727B78FF
+ 717A77FF737C79FF7F8885FF7D8683FF7E8784FF848D8AFF8B9491FF8C9592FF
+ 868F8CFF808986FF99A4A1FFA0ABA8FF939E9BFF747F7CFF66716EFF727D7AFF
+ 7C8784FF7A8582FF7E8986FF818C89FF86918EFF8C9794FF95A09DFF9CA7A4FF
+ A3AEABFFA4B2AEFFA8B9B6FFC1D4D1FFBFD2CFFFAABDBAFFADBEBBFFB0C1BEFF
+ A0B1AEFF8E9F9CFF9AA8A6FF95A3A1FF97A4A2FF909D9BFF83908EFF879492FF
+ 8E9997FF84918FFF879591FF7F8E8AFF889692FF7C8A86FF6C7A76FF273531FF
+ 616C69FF67726FFF6E7774FF68716EFF6E7774FF616A67FF636A67FF707774FF
+ 69706DFF6C7572FF6C7572FF6A7572FF6D7875FF717C79FF717C79FF6F7A77FF
+ 727D7AFF788380FF7B8683FF77827FFF75807DFF747F7CFF737E7BFF76817EFF
+ 838E8BFF919C99FF889692FF919F9BFF98A6A2FF93A19DFF889692FF818F8BFF
+ 85938FFF8D9B97FF909E9AFF97A5A1FF9BA9A5FF96A4A0FF92A09CFF9CAAA6FF
+ B5C3BFFFCAD9D5FFB9CAC6FFB9CDC8FFBDD1CCFFC1D5D0FFC5D6D2FFC5D6D2FF
+ C4D5D1FFC3D4D0FFC6D5D1FFBCCBC7FFAFBDB9FFA8B6B2FF92A09CFF8D9B97FF
+ 8E9996FF5E6966FF677571FF606E6AFF65736FFF73817DFF788682FF768480FF
+ 808E8AFF919F9BFF899793FF8D9B97FF92A09CFF96A4A0FF99A7A3FF99A7A3FF
+ 98A6A2FF96A4A0FF909E98FF919F99FF96A49EFF99A7A1FF97A59FFF94A29CFF
+ 9AA8A2FFA4B2ACFF9FADA7FFA3B1ABFFA2B0AAFF9DABA5FF9BA9A3FF9EACA6FF
+ 9FADA7FF9EACA6FFA1AFA9FFA1AFA9FFA0AEA8FF9EACA6FF9DABA5FF9DABA5FF
+ 9FADA7FFA2B0AAFFA6B4AEFFA5B3ADFFA2B0AAFF9FADA7FF9CAAA4FF99A7A1FF
+ 97A59FFF96A49EFF98A49EFF99A59FFF9AA6A0FF939F99FF919D97FF828E88FF
+ 525E58FF84908AFF7B8781FF7A8680FF78847EFF78847EFF79857FFF77837DFF
+ 74807AFF717D77FF757F79FF78827CFF78827CFF757F79FF76807AFF7C8680FF
+ 7F8983FF7E8882FF7A847EFF7D8781FF7F8983FF818B85FF828C86FF848E88FF
+ 88928CFF8C978FFF909D95FF94A297FF96A499FF96A499FF9AA89DFFA2B0A5FF
+ A6B4A9FFA4B2A7FFA1AFA4FFA4B2A7FFA8B6ABFFAAB8ADFFA9B7ACFFA8B6ABFF
+ A9B7ACFFAAB8ADFFAABAAFFFA7B7ACFFA0B0A5FF9BABA0FFA0B0A5FFA7B7ACFF
+ A6B6ABFFA0B0A5FF99A99EFF99A99EFF99A99EFF9BABA0FFA1B1A6FFA5B5AAFF
+ 9EAEA3FF92A297FFA1B1AAFFC2D2CBFFD1E1DAFFC8D8D1FFBBCBC4FFA7B7B0FF
+ 92A29BFF8C9C95FF85958EFF94A49DFFA3B3ACFFA8B8B1FF6D7673FF818A87FF
+ 77807DFF79827FFF7A8380FF6E7774FF717A77FF6D7673FF5D6663FF313A37FF
+ 232C29FF4A5350FF7A8380FF99A29FFFB1BAB7FFC0CBC8FFB1C0BCFFAEBFBBFF
+ AFC0BCFFB3C4C0FFB2C3BFFFA8B9B5FF9AABA7FF90A19DFF95A6A2FF97A8A4FF
+ 99AAA6FF98A9A5FF96A7A3FF96A7A3FF98A9A5FF9AABA7FF96A7A3FF95A6A2FF
+ 92A39FFF8FA09CFF889995FF82938FFF80918DFF80918DFF8A9B97FF90A19DFF
+ 94A5A1FF9EAFABFF748581FF839490FF849591FF82938FFF82918DFF7E8D89FF
+ 7A8884FF75837FFF74827EFF73817DFF747F7CFF737E7BFF737C79FF7C8582FF
+ 737C79FF5A6360FF757C79FF5A615EFF535A57FF626966FF7F8885FF6E7774FF
+ 616A67FF646D6AFF6B7471FF6E7774FF737C79FF79827FFF808986FF7F8885FF
+ 808986FF858E8BFF8C9592FF8E9794FF8B9491FF87908DFF95A09DFFAFBAB7FF
+ ACB7B4FF838E8BFF697471FF727D7AFF7C8784FF77827FFF77827FFF788380FF
+ 7A8582FF7E8986FF848F8CFF8C9794FF929D9AFF94A29EFFA5B6B3FFBED1CEFF
+ BED1CEFFACBFBCFFACBDBAFFADBEBBFF9FB0ADFF91A29FFF97A5A3FF93A19FFF
+ 95A2A0FF8A9795FF7A8785FF7E8B89FF8A9593FF84918FFF818F8BFF7E8D89FF
+ 83918DFF788682FF6E7C78FF263430FF596461FF606B68FF656E6BFF636C69FF
+ 6F7875FF636C69FF626966FF6D7471FF666D6AFF6B7471FF727B78FF717C79FF
+ 737E7BFF737E7BFF717C79FF717C79FF76817EFF7C8784FF7F8A87FF798481FF
+ 747F7CFF747F7CFF737E7BFF737E7BFF798481FF818C89FF96A4A0FF95A39FFF
+ 98A6A2FF98A6A2FF8C9A96FF808E8AFF85938FFF93A19DFF899793FF8D9B97FF
+ 93A19DFF95A39FFF8F9D99FF919F9BFFACBAB6FFCAD9D5FFB2C3BFFFB3C7C2FF
+ B9CDC8FFBED2CDFFC5D6D2FFC8D9D5FFCADBD7FFCADBD7FFC8D7D3FFC1D0CCFF
+ AFBDB9FFA7B5B1FF94A29EFF8B9995FF8B9693FF636E6BFF6B7975FF606E6AFF
+ 63716DFF74827EFF7A8884FF75837FFF7C8A86FF8C9A96FF879591FF8C9A96FF
+ 909E9AFF919F9BFF94A29EFF97A5A1FF97A5A1FF95A39FFF95A39DFF98A6A0FF
+ 9CAAA4FF9EACA6FF99A7A1FF94A29CFF99A7A1FFA3B1ABFFA0AEA8FFA5B3ADFF
+ A7B5AFFFA3B1ABFF9DABA5FF9AA8A2FF9AA8A2FF9AA8A2FF9AA8A2FF9DABA5FF
+ 9FADA7FF9EACA6FF9BA9A3FF9BA9A3FF9FADA7FFA4B2ACFFA5B3ADFFA4B2ACFF
+ A2B0AAFF9EACA6FF9BA9A3FF97A59FFF95A39DFF94A29CFF96A29CFF97A39DFF
+ 9AA6A0FF94A09AFF919D97FF7A8680FF59655FFF808C86FF79857FFF77837DFF
+ 76827CFF76827CFF78847EFF78847EFF76827CFF74807AFF727C76FF757F79FF
+ 757F79FF717B75FF707A74FF76807AFF7A847EFF7A847EFF78827CFF7A847EFF
+ 7D8781FF7E8882FF7F8983FF828C86FF86908AFF89948CFF8C9991FF909E93FF
+ 92A095FF94A297FF9AA89DFFA3B1A6FFA6B4A9FFA3B1A6FF9FADA2FFA1AFA4FF
+ A3B1A6FFA5B3A8FFA6B4A9FFA6B4A9FFA6B4A9FFA6B4A9FFAABAAFFFAFBFB4FF
+ A8B8ADFF9AAA9FFF9AAA9FFFA7B7ACFFA9B9AEFFA0B0A5FF96A69BFF98A89DFF
+ 97A79CFF96A69BFF9BABA0FFA2B2A7FFA2B2A7FF9CACA1FF98A8A1FFBACAC3FF
+ CCDCD5FFC8D8D1FFC1D1CAFFB0C0B9FF9AAAA3FF92A29BFF8D9D96FF96A69FFF
+ A0B0A9FFA6B6AFFF69726FFF7F8885FF77807DFF7B8481FF808986FF77807DFF
+ 77807DFF6E7774FF57605DFF303936FF161F1CFF2F3835FF626B68FF8A9390FF
+ AAB3B0FFC3CECBFFADBBB7FFAEBDB9FFB2C1BDFFB6C5C1FFB7C6C2FFB3C2BEFF
+ A8B7B3FF9FAEAAFF94A39FFF96A5A1FF97A6A2FF98A7A3FF97A6A2FF97A6A2FF
+ 98A7A3FF99A8A4FF9FAEAAFF9FAEAAFF9CABA7FF94A39FFF8C9B97FF899894FF
+ 899894FF899894FF93A29EFF8C9B97FF8F9E9AFFA8B7B3FF889793FF8F9E9AFF
+ 879692FF81908CFF7A8985FF768581FF73817DFF717F7BFF707E7AFF6D7B77FF
+ 6A7572FF66716EFF767F7CFF79827FFF6A7370FF505956FF6B726FFF505754FF
+ 525956FF6D7471FF78817EFF636C69FF59625FFF67706DFF77807DFF7B8481FF
+ 79827FFF7A8380FF7E8784FF7F8885FF828B88FF868F8CFF8A9390FF8E9794FF
+ 919A97FF939C99FF8C9794FFB0BBB8FFBAC5C2FF97A29FFF75807DFF737E7BFF
+ 77827FFF737E7BFF7C8784FF7C8784FF7E8986FF808B88FF85908DFF8A9592FF
+ 8E9996FF8F9D99FF97A8A5FFB3C6C3FFB8CBC8FFABBEBBFFADBEBBFFADBEBBFF
+ A2B3B0FF99AAA7FF94A2A0FF919F9DFF93A09EFF889593FF778482FF7B8886FF
+ 899492FF859290FF7C8A86FF7C8B87FF7D8B87FF72807CFF717F7BFF283632FF
+ 545F5CFF5D6865FF59625FFF5B6461FF6C7572FF626B68FF616865FF69706DFF
+ 606764FF656E6BFF717A77FF727D7AFF737E7BFF6E7976FF6B7673FF6E7976FF
+ 75807DFF7B8683FF818C89FF7C8784FF798481FF7B8683FF7A8582FF77827FFF
+ 77827FFF7A8582FF8D9B97FF879591FF8A9894FF93A19DFF8F9D99FF83918DFF
+ 82908CFF8B9995FF879591FF869490FF8C9A96FF92A09CFF8F9D99FF919F9BFF
+ AAB8B4FFC7D6D2FFB7C8C4FFB6CAC5FFB8CCC7FFBBCFCAFFC2D3CFFFC7D8D4FF
+ CCDDD9FFCFE0DCFFC7D6D2FFC4D3CFFFADBBB7FFA5B3AFFF98A6A2FF8D9B97FF
+ 8C9794FF6E7976FF6A7874FF62706CFF65736FFF75837FFF7B8985FF788682FF
+ 7E8C88FF8C9A96FF899793FF8F9D99FF92A09CFF909E9AFF92A09CFF98A6A2FF
+ 98A6A2FF94A29EFF97A59FFF99A7A1FF9DABA5FF9FADA7FF9BA9A3FF96A49EFF
+ 9AA8A2FFA2B0AAFF9BA9A3FFA0AEA8FFA6B4AEFFA7B5AFFFA3B1ABFF9DABA5FF
+ 9BA9A3FF9CAAA4FF9BA9A3FF9EACA6FFA1AFA9FFA0AEA8FF9CAAA4FF9CAAA4FF
+ 9FADA7FFA3B1ABFFA2B0AAFFA1AFA9FF9FADA7FF9CAAA4FF9AA8A2FF97A59FFF
+ 95A39DFF94A29CFF95A19BFF939F99FF98A49EFF919D97FF8E9A94FF6E7A74FF
+ 5C6862FF79857FFF76827CFF74807AFF737F79FF737F79FF76827CFF77837DFF
+ 76827CFF75817BFF707A74FF737D77FF707A74FF69736DFF66706AFF6B756FFF
+ 717B75FF737D77FF757F79FF77817BFF79837DFF7B857FFF7C8680FF7E8882FF
+ 828C86FF869189FF85928AFF89978CFF8C9A8FFF909E93FF99A79CFFA4B2A7FF
+ A6B4A9FFA3B1A6FFA3B1A6FFA3B1A6FFA3B1A6FFA4B2A7FFA5B3A8FFA5B3A8FF
+ A4B2A7FFA3B1A6FFA9B9AEFFB3C3B8FFADBDB2FF9AAA9FFF96A69BFFA3B3A8FF
+ A8B8ADFFA0B0A5FF93A398FF97A79CFF96A69BFF90A095FF90A095FF98A89DFF
+ A1B1A6FFA5B5AAFF98A8A1FFB8C8C1FFC9D9D2FFC8D8D1FFC6D6CFFFB9C9C2FF
+ A5B5AEFF9DADA6FF90A099FF93A39CFF98A8A1FF9DADA6FF69726FFF77807DFF
+ 737C79FF78817EFF79827FFF77807DFF7D8683FF69726FFF4B5451FF363F3CFF
+ 19221FFF1D2623FF48514EFF747D7AFF99A29FFFBAC5C2FFABB9B5FFB0BFBBFF
+ B4C3BFFFB2C1BDFFB1C0BCFFAFBEBAFFA9B8B4FFA3B2AEFF99A8A4FF97A6A2FF
+ 96A5A1FF97A6A2FF99A8A4FF98A7A3FF96A5A1FF93A29EFF9BAAA6FF9EADA9FF
+ 9BAAA6FF91A09CFF8A9995FF8C9B97FF8F9E9AFF91A09CFF9CABA7FF96A5A1FF
+ 93A29EFF9EADA9FF95A4A0FF96A5A1FF899894FF7C8B87FF7B8A86FF788783FF
+ 768480FF75837FFF75837FFF717F7BFF6B7673FF646F6CFF767F7CFF6B7471FF
+ 5F6865FF515A57FF717875FF5F6663FF5D6461FF666D6AFF7A8380FF626B68FF
+ 58615EFF69726FFF7B8481FF7D8683FF7A8380FF7C8582FF7E8784FF7E8784FF
+ 7F8885FF818A87FF858E8BFF8C9592FF949D9AFF99A29FFF818C89FF9EA9A6FF
+ B1BCB9FFA3AEABFF87928FFF76817EFF717C79FF6F7A77FF7A8582FF7C8784FF
+ 818C89FF86918EFF8B9693FF8F9A97FF919C99FF919F9BFF8C9D9AFFAABDBAFF
+ B5C8C5FFACBFBCFFAEBFBCFFACBDBAFFA2B3B0FF9DAEABFF93A19FFF919F9DFF
+ 93A09EFF899694FF798684FF7B8886FF879290FF818E8CFF768480FF7A8985FF
+ 778581FF6C7A76FF74827EFF2A3834FF525D5AFF5F6A67FF565F5CFF57605DFF
+ 68716EFF5F6865FF5F6663FF666D6AFF5C6360FF5F6865FF68716EFF6D7875FF
+ 6E7976FF687370FF646F6CFF687370FF707B78FF75807DFF818C89FF7E8986FF
+ 7F8A87FF838E8BFF818C89FF7C8784FF7B8683FF7F8A87FF7F8D89FF7C8A86FF
+ 83918DFF92A09CFF97A5A1FF8F9D99FF869490FF869490FF899793FF8A9894FF
+ 8E9C98FF93A19DFF92A09CFF96A4A0FFADBBB7FFC5D4D0FFC0D1CDFFBCD0CBFF
+ BACEC9FFB9CDC8FFBDCECAFFC2D3CFFFC7D8D4FFCBDCD8FFC3D2CEFFC3D2CEFF
+ AAB8B4FFA3B1ADFF9DABA7FF919F9BFF919C99FF7E8986FF616F6BFF63716DFF
+ 697773FF73817DFF798783FF7D8B87FF85938FFF8F9D99FF899793FF92A09CFF
+ 95A39FFF919F9BFF94A29EFF9BA9A5FF9BA9A5FF94A29EFF95A39DFF94A29CFF
+ 98A6A0FF9DABA5FF9DABA5FF9AA8A2FF9BA9A3FFA0AEA8FF97A59FFF99A7A1FF
+ 9FADA7FFA6B4AEFFA7B5AFFFA2B0AAFFA0AEA8FFA3B1ABFFA4B2ACFFA5B3ADFF
+ A5B3ADFFA4B2ACFFA1AFA9FF9FADA7FFA0AEA8FFA1AFA9FF9FADA7FF9EACA6FF
+ 9DABA5FF9BA9A3FF99A7A1FF97A59FFF95A39DFF94A29CFF939F99FF8E9A94FF
+ 94A09AFF8D9993FF89958FFF636F69FF616D67FF75817BFF74807AFF717D77FF
+ 6F7B75FF6F7B75FF707C76FF717D77FF717D77FF6F7B75FF6E7872FF717B75FF
+ 6E7872FF656F69FF606A64FF656F69FF6C7670FF6F7973FF727C76FF757F79FF
+ 77817BFF79837DFF79837DFF7C8680FF808A84FF848F87FF818E86FF859388FF
+ 88968BFF8E9C91FF99A79CFFA4B2A7FFA6B4A9FFA1AFA4FFA8B6ABFFA6B4A9FF
+ A4B2A7FFA4B2A7FFA5B3A8FFA5B3A8FFA3B1A6FFA2B0A5FFA4B4A9FFAFBFB4FF
+ ACBCB1FF9CACA1FF95A59AFF9FAFA4FFA6B6ABFFA4B4A9FF95A59AFF9AAA9FFF
+ 99A99EFF8F9F94FF8A9A8FFF90A095FF9CACA1FFA3B3A8FF9EAEA7FFBBCBC4FF
+ C9D9D2FFC9D9D2FFCCDCD5FFC3D3CCFFB1C1BAFFA9B9B2FF9AAAA3FF97A7A0FF
+ 98A8A1FF9DADA6FF6F7875FF727B78FF717A77FF78817EFF6F7875FF747D7AFF
+ 838C89FF646D6AFF424B48FF454E4BFF29322FFF151E1BFF2D3633FF525B58FF
+ 77807DFF9AA5A2FFA6B4B0FFAEBDB9FFB1C0BCFFABBAB6FFA5B4B0FFA6B5B1FF
+ A7B6B2FFA5B4B0FFA4B3AFFF9FAEAAFF99A8A4FF9AA9A5FF9DACA8FF9BAAA6FF
+ 94A39FFF8C9B97FF909F9BFF95A4A0FF91A09CFF859490FF7E8D89FF81908CFF
+ 879692FF899894FF96A5A1FFA1B0ACFF99A8A4FF7F8E8AFF8F9E9AFF99A8A4FF
+ 92A19DFF7B8A86FF81908CFF7D8C88FF7A8884FF7A8884FF7B8985FF788682FF
+ 727D7AFF6B7673FF6C7572FF626B68FF67706DFF5C6562FF707774FF656C69FF
+ 707774FF717875FF7D8683FF67706DFF5D6663FF69726FFF737C79FF717A77FF
+ 747D7AFF7D8683FF838C89FF7D8683FF77807DFF78817EFF818A87FF8B9491FF
+ 929B98FF969F9CFF828D8AFF8B9693FF9EA9A6FFABB6B3FFA0ABA8FF85908DFF
+ 75807DFF75807DFF75807DFF7A8582FF838E8BFF8B9693FF929D9AFF949F9CFF
+ 949F9CFF919F9BFF8A9B98FFA9BCB9FFB7CAC7FFB1C4C1FFB0C1BEFFA9BAB7FF
+ 9DAEABFF99AAA7FF919F9DFF8D9B99FF909D9BFF879492FF778482FF788583FF
+ 7F8A88FF74817FFF72807CFF788783FF72807CFF677571FF75837FFF2D3B37FF
+ 535E5BFF636E6BFF5E6764FF5C6562FF666F6CFF5B6461FF5B625FFF646B68FF
+ 5A615EFF5D6663FF5F6865FF687370FF6F7A77FF6A7572FF65706DFF687370FF
+ 6D7875FF6F7A77FF828D8AFF818C89FF838E8BFF86918EFF848F8CFF808B88FF
+ 838E8BFF8A9592FF85938FFF84928EFF879591FF8E9C98FF94A29EFF94A29EFF
+ 909E9AFF8D9B97FF8B9995FF92A09CFF97A5A1FF95A39FFF909E9AFF97A5A1FF
+ ADBBB7FFC2D1CDFFC2D3CFFFBDD1CCFFBACEC9FFB8CCC7FFBACBC7FFBECFCBFF
+ C3D4D0FFC6D7D3FFC3D2CEFFC6D5D1FFAAB8B4FFA2B0ACFFA1AFABFF93A19DFF
+ 939E9BFF87928FFF5B6965FF677571FF707E7AFF717F7BFF74827EFF7D8B87FF
+ 879591FF8B9995FF869490FF919F9BFF96A4A0FF93A19DFF96A4A0FFA0AEAAFF
+ 9FADA9FF96A4A0FF9BA9A3FF97A59FFF97A59FFF9DABA5FFA1AFA9FF9EACA6FF
+ 9CAAA4FF9DABA5FF9EACA6FF99A7A1FF9AA8A2FFA2B0AAFFA5B3ADFFA3B1ABFF
+ A2B0AAFFA6B4AEFFA5B3ADFFA4B2ACFFA3B1ABFFA3B1ABFFA4B2ACFFA4B2ACFF
+ A2B0AAFFA0AEA8FF9FADA7FF9EACA6FF9CAAA4FF9AA8A2FF97A59FFF95A39DFF
+ 93A19BFF92A09AFF909C96FF89958FFF909C96FF89958FFF86928CFF5C6862FF
+ 68746EFF75817BFF77837DFF74807AFF6F7B75FF6D7973FF6C7872FF6C7872FF
+ 6A7670FF68746EFF68726CFF6E7872FF6F7973FF68726CFF636D67FF66706AFF
+ 6B756FFF6E7872FF727C76FF747E78FF77817BFF78827CFF79837DFF7C8680FF
+ 808A84FF838E86FF828F87FF859388FF88968BFF8E9C91FF9AA89DFFA5B3A8FF
+ A5B3A8FF9FADA2FFA5B3A8FFA2B0A5FF9FADA2FF9FADA2FFA1AFA4FFA2B0A5FF
+ A1AFA4FF9EACA1FF9CACA1FFA6B6ABFFA8B8ADFF9DADA2FF96A69BFF9BABA0FF
+ A5B5AAFFAABAAFFFA3B3A8FFA6B6ABFFA2B2A7FF97A79CFF91A196FF94A499FF
+ 99A99EFF9BABA0FFA0B0A9FFBCCCC5FFC9D9D2FFCBDBD4FFD0E0D9FFC8D8D1FF
+ B6C6BFFFADBDB6FFA0B0A9FF99A9A2FF98A8A1FF9FAFA8FF78817EFF727B78FF
+ 737C79FF79827FFF69726FFF747D7AFF89928FFF636C69FF3B4441FF4D5653FF
+ 333C39FF0E1714FF161F1CFF323B38FF525B58FF747F7CFF94A29EFFA0AFABFF
+ A7B6B2FFA2B1ADFF9FAEAAFFA7B6B2FFAFBEBAFFB2C1BDFFAFBEBAFFA6B5B1FF
+ 9EADA9FF9DACA8FFA1B0ACFF9EADA9FF93A29EFF889793FF879692FF8C9B97FF
+ 879692FF788783FF6F7E7AFF73827EFF788783FF798884FF7E8D89FF9DACA8FF
+ 95A4A0FF5E6D69FF84938FFF9EADA9FFA4B3AFFF879692FF82918DFF7C8B87FF
+ 788682FF778581FF788682FF768480FF727D7AFF6C7774FF656E6BFF666F6CFF
+ 79827FFF656E6BFF5D6461FF525956FF727976FF7B827FFF646D6AFF5A6360FF
+ 5F6865FF737C79FF79827FFF6F7875FF6E7774FF79827FFF89928FFF7C8582FF
+ 707976FF717A77FF7E8784FF8B9491FF909996FF8F9895FF899491FF818C89FF
+ 929D9AFFB2BDBAFFB5C0BDFF96A19EFF7F8A87FF7F8A87FF77827FFF7E8986FF
+ 899491FF939E9BFF99A4A1FF9AA5A2FF98A3A0FF93A19DFF8E9F9CFFADC0BDFF
+ BCCFCCFFB5C8C5FFB1C2BFFFA6B7B4FF98A9A6FF94A5A2FF8D9B99FF899795FF
+ 8B9896FF83908EFF74817FFF727F7DFF75807EFF677472FF707E7AFF778682FF
+ 6E7C78FF64726EFF778581FF2F3D39FF545F5CFF66716EFF69726FFF626B68FF
+ 67706DFF58615EFF585F5CFF636A67FF5A615EFF5D6663FF5A6360FF687370FF
+ 737E7BFF707B78FF6B7673FF6C7774FF6E7976FF6C7774FF838E8BFF828D8AFF
+ 85908DFF87928FFF848F8CFF828D8AFF899491FF939E9BFF93A19DFF909E9AFF
+ 899793FF82908CFF84928EFF8C9A96FF93A19DFF95A39FFF899793FF97A5A1FF
+ 9FADA9FF96A4A0FF8C9A96FF93A19DFFABB9B5FFBFCECAFFBCCDC9FFB9CDC8FF
+ B7CBC6FFB7CBC6FFBBCCC8FFBECFCBFFC3D4D0FFC5D6D2FFC8D7D3FFCBDAD6FF
+ ADBBB7FFA3B1ADFFA2B0ACFF92A09CFF909B98FF87928FFF5B6965FF6E7C78FF
+ 778581FF707E7AFF6E7C78FF7A8884FF84928EFF83918DFF82908CFF8F9D99FF
+ 96A4A0FF93A19DFF98A6A2FFA3B1ADFFA2B0ACFF99A7A3FFA6B4AEFF9FADA7FF
+ 9CAAA4FFA2B0AAFFA5B3ADFFA1AFA9FF9BA9A3FF99A7A1FFABB9B3FF9FADA7FF
+ 9AA8A2FF9EACA6FFA1AFA9FF9FADA7FF9FADA7FFA4B2ACFF9FADA7FF9DABA5FF
+ 9CAAA4FF9FADA7FFA4B2ACFFA6B4AEFFA4B2ACFFA1AFA9FFA0AEA8FF9FADA7FF
+ 9DABA5FF9AA8A2FF97A59FFF94A29CFF919F99FF909E98FF8E9A94FF86928CFF
+ 8D9993FF87938DFF84908AFF59655FFF6D7973FF78847EFF7D8983FF78847EFF
+ 737F79FF6E7A74FF6C7872FF6A7670FF67736DFF64706AFF646E68FF6D7771FF
+ 717B75FF6C7670FF68726CFF6A746EFF6E7872FF6F7973FF737D77FF757F79FF
+ 78827CFF79837DFF7A847EFF7C8680FF818B85FF848F87FF85928AFF88968BFF
+ 8A988DFF8F9D92FF9BA99EFFA5B3A8FFA4B2A7FF9EACA1FF9EACA1FF9BA99EFF
+ 98A69BFF99A79CFF9CAA9FFF9EACA1FF9CAA9FFF9AA89DFF96A69BFF9EAEA3FF
+ A3B3A8FF9EAEA3FF98A89DFF9AAA9FFFA5B5AAFFAFBFB4FFB2C2B7FFB1C1B6FF
+ ABBBB0FFA2B2A7FF9EAEA3FF9DADA2FF9AAA9FFF95A59AFF9EAEA7FFB9C9C2FF
+ C7D7D0FFCADAD3FFD0E0D9FFC9D9D2FFB5C5BEFFABBBB4FF9CACA5FF93A39CFF
+ 90A099FF98A8A1FF656E6BFF717A77FF6D7673FF737C79FF77807DFF808986FF
+ 838C89FF5B6461FF535C59FF3D4643FF242D2AFF1D2623FF1B2421FF151E1BFF
+ 303936FF626D6AFF8C9A96FF94A29EFFA7B5B1FFB2C0BCFFA7B5B1FF94A29EFF
+ 98A6A2FFAAB8B4FFB8C6C2FFAEBCB8FFA2B0ACFF9FADA9FFA6B4B0FFA5B3AFFF
+ 92A09CFF7C8A86FF84928EFF8E9C98FF889692FF7D8B87FF7B8985FF74827EFF
+ 6C7A76FF717F7BFF7B8985FF93A19DFF6F7D79FF465450FF889692FF909E9AFF
+ 899793FF93A19DFF7C8B87FF7C8B87FF7C8A86FF7A8884FF768480FF72807CFF
+ 717C79FF6E7976FF707976FF646D6AFF79827FFF6C7572FF444B48FF575E5BFF
+ 808784FF707774FF5D6663FF656E6BFF6E7774FF727B78FF727B78FF737C79FF
+ 77807DFF7C8582FF87908DFF808986FF6C7572FF87908DFF8F9895FF7D8683FF
+ 909996FF919A97FF8C9794FF7D8885FF899491FF949F9CFFB5C0BDFF939E9BFF
+ 889390FF87928FFF87928FFF87928FFF889390FF8B9693FF909B98FF95A09DFF
+ 98A3A0FF97A5A1FF899A97FFB1C4C1FFB6C9C6FFB5C8C5FFB2C3C0FF9FB0ADFF
+ 95A6A3FF839491FF8B9997FF8D9B99FF8A9795FF7E8B89FF74817FFF6D7A78FF
+ 677270FF5E6B69FF63716DFF6B7A76FF6E7C78FF697773FF63716DFF32403CFF
+ 505B58FF6D7875FF5F6865FF6A7370FF636C69FF57605DFF5C6360FF5F6663FF
+ 5D6461FF5F6865FF626B68FF616C69FF6A7572FF6B7673FF65706DFF6C7774FF
+ 747F7CFF6E7976FF7C8784FF828D8AFF8A9592FF8E9996FF889390FF818C89FF
+ 838E8BFF8C9794FF83918DFF8B9995FF889692FF7A8884FF788682FF869490FF
+ 92A09CFF92A09CFF95A39FFF92A09CFF9AA8A4FFA1AFABFF95A39FFF899793FF
+ 9DABA7FFBFCECAFFBDCECAFFB9CDC8FFBACEC9FFBFD3CEFFC1D2CEFFBCCDC9FF
+ BACBC7FFBCCDC9FFBFCECAFFC9D8D4FFC5D3CFFFAFBDB9FF9EACA8FF9BA9A5FF
+ 9AA5A2FF929D9AFF606E6AFF7F8D89FF808E8AFF7B8985FF73817DFF75837FFF
+ 869490FF7C8A86FF879591FF8E9C98FF95A39FFF98A6A2FF98A6A2FF9AA8A4FF
+ 9EACA8FFA2B0ACFF909E98FF98A6A0FF9FADA7FFA3B1ABFFA7B5AFFFA9B7B1FF
+ A3B1ABFF9BA9A3FF9CAAA4FF97A59FFF9AA8A2FFA3B1ABFFA7B5AFFFA2B0AAFF
+ 9FADA7FFA1AFA9FFA1AFA9FF9FADA7FF9DABA5FF9BA9A3FF9CAAA4FF9EACA6FF
+ A2B0AAFFA4B2ACFF9FADA7FFA1AFA9FFA2B0AAFF9EACA6FF97A59FFF919F99FF
+ 8F9D97FF909E98FF939F99FF89958FFF88948EFF85918BFF87938DFF3F4B45FF
+ 707C76FF7E8A84FF77837DFF77837DFF76827CFF717D77FF6C7872FF69756FFF
+ 68746EFF69756FFF6B756FFF6C7670FF6F7973FF717B75FF6B756FFF636D67FF
+ 626C66FF68726CFF6A746EFF6D7771FF727C76FF77817BFF7B857FFF7D8781FF
+ 7D8781FF7D8880FF85928AFF839186FF839186FF88968BFF909E93FF96A499FF
+ 99A79CFF99A79CFF9DABA0FFA0AEA3FFA1AFA4FF9EACA1FF9CAA9FFF9DABA0FF
+ 9DABA0FF9BA99EFF9AAA9FFF9EAEA3FFA3B3A8FFA2B2A7FF9EAEA3FF98A89DFF
+ 94A499FF93A398FFAABAAFFFB7C7BCFFBACABFFFAFBFB4FFA8B8ADFFAABAAFFF
+ A5B5AAFF9BABA0FFA1B1AAFFACBCB5FFC3D3CCFFCFDFD8FFCBDBD4FFCADAD3FF
+ BFCFC8FFA7B7B0FF9EAEA7FF97A7A0FF94A49DFF97A7A0FF6C7572FF737C79FF
+ 656E6BFF616A67FF646D6AFF757E7BFF7E8784FF57605DFF454E4BFF37403DFF
+ 262F2CFF242D2AFF212A27FF131C19FF212A27FF48514EFF717C79FF83918DFF
+ A0AEAAFFB5C3BFFFB3C1BDFFA5B3AFFF9EACA8FFA0AEAAFFB0BEBAFFA7B5B1FF
+ 9BA9A5FF95A39FFF9BA9A5FFA1AFABFF9BA9A5FF8F9D99FF8C9A96FF96A4A0FF
+ 919F9BFF8B9995FF8D9B97FF889692FF83918DFF899793FF82908CFF889692FF
+ 6B7975FF3D4B47FF919F9BFF9DABA7FF869490FF808E8AFF7B8A86FF7A8985FF
+ 798783FF778581FF75837FFF74827EFF75807DFF747F7CFF6B7471FF626B68FF
+ 67706DFF707976FF414845FF646B68FF777E7BFF686F6CFF5B6461FF636C69FF
+ 6C7572FF707976FF717A77FF737C79FF77807DFF7C8582FF868F8CFF838C89FF
+ 727B78FF87908DFF8F9895FF838C89FF8F9895FF8A9390FF8C9794FF899491FF
+ 818C89FF949F9CFFACB7B4FFAFBAB7FF98A3A0FF909B98FF919C99FF96A19EFF
+ 939E9BFF8D9895FF929D9AFF9DA8A5FF9CA7A4FF919F9BFF8A9B98FFAFC2BFFF
+ B0C3C0FFADC0BDFFAABBB8FF9AABA8FF95A6A3FF869794FF8B9997FF879593FF
+ 7E8B89FF73807EFF6D7A78FF6A7775FF646F6DFF586563FF5E6C68FF62716DFF
+ 64726EFF5C6A66FF55635FFF293733FF4B5653FF687370FF646D6AFF6F7875FF
+ 68716EFF5E6764FF636A67FF646B68FF606764FF626B68FF5E6764FF606B68FF
+ 6C7774FF6D7875FF65706DFF6C7774FF76817EFF717C79FF7D8885FF7C8784FF
+ 7E8986FF838E8BFF838E8BFF808B88FF828D8AFF87928FFF899793FF94A29EFF
+ 93A19DFF85938FFF7E8C88FF85938FFF8B9995FF899793FF919F9BFF8D9B97FF
+ 96A4A0FFA5B3AFFFA2B0ACFF97A5A1FFA1AFABFFB9C8C4FFBBCCC8FFB7CBC6FF
+ B8CCC7FFBED2CDFFC2D3CFFFC0D1CDFFC0D1CDFFC4D5D1FFC7D6D2FFC5D4D0FF
+ C0CECAFFB3C1BDFFA1AFABFF94A29EFF97A29FFF9FAAA7FF6A7874FF899793FF
+ 869490FF7D8B87FF788682FF7C8A86FF8F9D99FF899793FF818F8BFF899793FF
+ 92A09CFF97A5A1FF98A6A2FF9AA8A4FF9DABA7FFA1AFABFF97A59FFF9BA9A3FF
+ 9FADA7FFA2B0AAFFA7B5AFFFACBAB4FFA7B5AFFF9FADA7FFA1AFA9FF9CAAA4FF
+ 9DABA5FFA4B2ACFFA7B5AFFFA3B1ABFFA1AFA9FFA3B1ABFFA1AFA9FFA0AEA8FF
+ 9EACA6FF9DABA5FF9DABA5FF9DABA5FF9DABA5FF9EACA6FF97A59FFF9AA8A2FF
+ 9CAAA4FF9AA8A2FF95A39DFF909E98FF8D9B95FF8D9B95FF939F99FF8B9791FF
+ 8B9791FF85918BFF828E88FF37433DFF64706AFF6F7B75FF717D77FF727E78FF
+ 727E78FF707C76FF6C7872FF6A7670FF6A7670FF6B7771FF6F7973FF6F7973FF
+ 6F7973FF6F7973FF67716BFF5D6761FF5C6660FF616B65FF656F69FF6C7670FF
+ 757F79FF78827CFF76807AFF76807AFF79837DFF7E8981FF818E86FF829085FF
+ 859388FF8D9B90FF95A398FF9BA99EFF9DABA0FF9CAA9FFF9EACA1FF9EACA1FF
+ 9FADA2FFA1AFA4FFA1AFA4FFA0AEA3FFA1AFA4FFA3B1A6FF9BABA0FF9EAEA3FF
+ A3B3A8FFA6B6ABFFA6B6ABFFA3B3A8FFA1B1A6FF9FAFA4FFA3B3A8FFAABAAFFF
+ B1C1B6FFB2C2B7FFABBBB0FFA5B5AAFFA9B9AEFFB1C1B6FFA0B0A9FFA9B9B2FF
+ BFCFC8FFCCDCD5FFCADAD3FFC9D9D2FFBFCFC8FFA9B9B2FF99A9A2FF93A39CFF
+ 91A19AFF95A59EFF68716EFF727B78FF636C69FF5D6663FF616A67FF79827FFF
+ 848D8AFF5B6461FF444D4AFF3B4441FF2D3633FF2B3431FF28312EFF17201DFF
+ 19221FFF353E3BFF5E6966FF7C8784FF9FAAA7FFB5C0BDFFBBC6C3FFB5C0BDFF
+ A8B3B0FF9CA7A4FFA5B0ADFFA3AEABFF9DA8A5FF96A19EFF98A3A0FF9EA9A6FF
+ 9FAAA7FF9BA6A3FF8E9996FF96A19EFF939E9BFF909B98FF95A09DFF929D9AFF
+ 8E9996FF96A19EFF9CA7A4FF929D9AFF808B88FF394441FF899491FF98A3A0FF
+ 86918EFF82908CFF7A8985FF788783FF75837FFF73817DFF72807CFF74827EFF
+ 788380FF7A8582FF646D6AFF5E6764FF535C59FF6E7774FF3C4340FF6B726FFF
+ 6A716EFF5E6562FF5E6764FF656E6BFF6D7673FF727B78FF737C79FF767F7CFF
+ 7B8481FF7F8885FF818A87FF828B88FF757E7BFF808986FF89928FFF87908DFF
+ 8D9693FF818A87FF818C89FF8F9A97FF808B88FF9BA6A3FFA8B3B0FFC0CBC8FF
+ 98A3A0FF85908DFF8A9592FF9BA6A3FFA0ABA8FF97A29FFF95A09DFF9DA8A5FF
+ 9CA7A4FF8E9C98FF8B9C99FFAEC1BEFFABBEBBFFA5B8B5FFA2B3B0FF96A7A4FF
+ 95A6A3FF899A97FF8D9B99FF859391FF7A8785FF707D7BFF707D7BFF727F7DFF
+ 6E7977FF626F6DFF5F6D69FF5D6C68FF5E6C68FF54625EFF4A5854FF24322EFF
+ 4B5653FF646F6CFF5F6865FF69726FFF646D6AFF5C6562FF616865FF5F6663FF
+ 5A615EFF5C6562FF5C6562FF5E6966FF6A7572FF6B7673FF626D6AFF687370FF
+ 707B78FF6B7673FF85908DFF7F8A87FF7D8885FF828D8AFF889390FF899491FF
+ 8A9592FF8D9895FF889692FF93A19DFF96A4A0FF8C9A96FF85938FFF879591FF
+ 879591FF82908CFF919F9BFF879591FF8C9A96FFA0AEAAFFA5B3AFFF9EACA8FF
+ A5B3AFFFB7C6C2FFBECFCBFFB9CDC8FFB8CCC7FFBDD1CCFFC1D2CEFFC0D1CDFF
+ C3D4D0FFC8D9D5FFCCDBD7FFBECDC9FFB6C4C0FFB2C0BCFFA3B1ADFF92A09CFF
+ 99A4A1FFAAB5B2FF5A6864FF83918DFF818F8BFF75837FFF717F7BFF75837FFF
+ 8B9995FF8B9995FF7D8B87FF85938FFF8F9D99FF95A39FFF97A5A1FF98A6A2FF
+ 9CAAA6FF9FADA9FF9EACA6FF9EACA6FF9CAAA4FF9DABA5FFA4B2ACFFACBAB4FF
+ A9B7B1FFA2B0AAFFA4B2ACFF9FADA7FF9EACA6FFA2B0AAFFA4B2ACFFA1AFA9FF
+ A0AEA8FFA1AFA9FFA1AFA9FFA1AFA9FFA1AFA9FFA1AFA9FFA0AEA8FF9DABA5FF
+ 9AA8A2FF99A7A1FF94A29CFF97A59FFF9AA8A2FF9AA8A2FF97A59FFF92A09AFF
+ 8F9D97FF8D9B95FF8E9A94FF8A9690FF8B9791FF838F89FF7D8983FF303C36FF
+ 5B6761FF64706AFF6A7670FF6C7872FF6F7B75FF6E7A74FF6C7872FF6B7771FF
+ 6C7872FF6D7973FF6F7973FF6D7771FF6D7771FF6B756FFF626C66FF59635DFF
+ 59635DFF5E6862FF606A64FF6B756FFF76807AFF77817BFF727C76FF707A74FF
+ 76807AFF7D8880FF7E8B83FF818F84FF87958AFF8F9D92FF96A499FF9BA99EFF
+ 9CAA9FFF9BA99EFF99A79CFF93A196FF95A398FF9DABA0FFA1AFA4FF9EACA1FF
+ A0AEA3FFA8B6ABFF99A99EFF9BABA0FF9EAEA3FFA2B2A7FFA5B5AAFFA4B4A9FF
+ A1B1A6FF9EAEA3FFA5B5AAFFA4B4A9FFABBBB0FFB1C1B6FFA5B5AAFF95A59AFF
+ 9AAA9FFFAEBEB3FFA1B1AAFFA8B8B1FFBDCDC6FFCBDBD4FFC9D9D2FFC6D6CFFF
+ BBCBC4FFA5B5AEFF96A69FFF91A19AFF90A099FF95A59EFF636C69FF727B78FF
+ 6B7471FF67706DFF6A7370FF7C8582FF828B88FF555E5BFF4B5451FF414A47FF
+ 2E3734FF262F2CFF242D2AFF17201DFF18211EFF2D3633FF545F5CFF798481FF
+ 9BA6A3FFA7B2AFFFABB6B3FFAEB9B6FFA6B1AEFF97A29FFF96A19EFF9DA8A5FF
+ 9FAAA7FF9AA5A2FF96A19EFF95A09DFF939E9BFF909B98FF848F8CFF889390FF
+ 838E8BFF838E8BFF899491FF848F8CFF808B88FF8A9592FF949F9CFF95A09DFF
+ 9EA9A6FF4E5956FF87928FFF8A9592FF848F8CFF8E9C98FF7B8985FF768581FF
+ 717F7BFF6D7B77FF6D7B77FF707E7AFF788380FF7C8784FF646D6AFF5B6461FF
+ 4F5855FF616A67FF3D4441FF626966FF626966FF59605DFF68716EFF6D7673FF
+ 737C79FF767F7CFF78817EFF7A8380FF7E8784FF818A87FF7C8582FF7E8784FF
+ 767F7CFF747D7AFF7D8683FF87908DFF89928FFF7C8582FF7E8986FF8B9693FF
+ 828D8AFF939E9BFFA1ACA9FFB4BFBCFF9FAAA7FF99A4A1FF808B88FF909B98FF
+ 9DA8A5FF9DA8A5FF98A3A0FF95A09DFF949F9CFF909E9AFF8D9E9BFFAFC2BFFF
+ AABDBAFFA3B6B3FFA0B1AEFF94A5A2FF94A5A2FF899A97FF869492FF83918FFF
+ 7C8987FF74817FFF73807EFF768381FF76817FFF6E7B79FF65736FFF5F6E6AFF
+ 62706CFF576561FF485652FF263430FF505B58FF616C69FF5A6360FF646D6AFF
+ 606966FF5A6360FF5F6663FF5A615EFF545B58FF58615EFF5F6865FF5B6663FF
+ 626D6AFF636E6BFF5D6865FF636E6BFF67726FFF5C6764FF848F8CFF7F8A87FF
+ 808B88FF87928FFF8D9895FF8E9996FF909B98FF939E9BFF83918DFF889692FF
+ 899793FF879591FF899793FF8E9C98FF8B9995FF83918DFF94A29EFF869490FF
+ 85938FFF94A29EFF9AA8A4FF98A6A2FFA6B4B0FFBDCCC8FFC3D4D0FFBBCFCAFF
+ B9CDC8FFBACEC9FFBDCECAFFBCCDC9FFBFD0CCFFC5D6D2FFC8D7D3FFBBCAC6FF
+ B0BEBAFFAAB8B4FFA1AFABFF98A6A2FF9BA6A3FFA3AEABFF364440FF73817DFF
+ 7A8884FF6E7C78FF6A7874FF6B7975FF808E8AFF899793FF808E8AFF869490FF
+ 8E9C98FF92A09CFF93A19DFF95A39FFF9AA8A4FF9FADA9FFA2B0AAFF9EACA6FF
+ 98A6A0FF97A59FFF9FADA7FFA9B7B1FFA9B7B1FFA3B1ABFFA5B3ADFFA1AFA9FF
+ 9EACA6FF9FADA7FFA0AEA8FF9FADA7FF9EACA6FF9EACA6FFA1AFA9FFA2B0AAFF
+ A5B3ADFFA5B3ADFFA4B2ACFFA1AFA9FF9DABA5FF9AA8A2FF99A7A1FF9BA9A3FF
+ 9EACA6FF9FADA7FF9CAAA4FF97A59FFF93A19BFF909E98FF88948EFF85918BFF
+ 86928CFF7C8882FF79857FFF303C36FF5F6B65FF68746EFF68746EFF6B7771FF
+ 6F7B75FF707C76FF6E7A74FF6C7872FF6C7872FF6D7973FF6A746EFF69736DFF
+ 69736DFF68726CFF616B65FF5A645EFF5B655FFF626C66FF606A64FF69736DFF
+ 737D77FF757F79FF727C76FF717B75FF757F79FF7B867EFF7D8A82FF808E83FF
+ 849287FF8A988DFF919F94FF96A499FF98A69BFF99A79CFF93A196FF8A988DFF
+ 8A988DFF96A499FF9CAA9FFF99A79CFF9DABA0FFA8B6ABFFA0B0A5FF9FAFA4FF
+ A0B0A5FFA2B2A7FFA3B3A8FFA2B2A7FF9DADA2FF98A89DFFA2B2A7FFA3B3A8FF
+ A8B8ADFFA9B9AEFF9EAEA3FF8F9F94FF8E9E93FF98A89DFFA0B0A9FFA5B5AEFF
+ BBCBC4FFCCDCD5FFC9D9D2FFC3D3CCFFB4C4BDFF9DADA6FF95A59EFF90A099FF
+ 90A099FF95A59EFF666F6CFF747D7AFF6E7774FF6B7471FF68716EFF717A77FF
+ 77807DFF505956FF4A5350FF414A47FF2D3633FF232C29FF232C29FF1A2320FF
+ 151E1BFF212A27FF424D4AFF6D7875FF939E9BFF9BA6A3FF9BA6A3FFA0ABA8FF
+ 9DA8A5FF929D9AFF919C99FF9AA5A2FF9EA9A6FF98A3A0FF919C99FF8E9996FF
+ 8B9693FF87928FFF85908DFF86918EFF808B88FF818C89FF899491FF828D8AFF
+ 7E8986FF8A9592FF818C89FF8D9895FFA3AEABFF6F7A77FF97A29FFF8C9794FF
+ 85908DFF8B9995FF7C8A86FF758480FF6E7C78FF697773FF687672FF6D7B77FF
+ 76817EFF7B8683FF6E7774FF616A67FF5C6562FF565F5CFF454C49FF535A57FF
+ 646B68FF626966FF707976FF737C79FF767F7CFF78817EFF79827FFF7A8380FF
+ 7C8582FF7E8784FF7E8784FF7D8683FF78817EFF6C7572FF727B78FF858E8BFF
+ 868F8CFF808986FF87928FFF848F8CFF86918EFF828D8AFF9CA7A4FF9BA6A3FF
+ AFBAB7FFC4CFCCFF99A4A1FF8D9895FF889390FF919C99FF98A3A0FF95A09DFF
+ 8F9A97FF8B9995FF90A19EFFB2C5C2FFAEC1BEFFA6B9B6FFA2B3B0FF94A5A2FF
+ 91A29FFF849592FF798785FF7D8B89FF7D8A88FF73807EFF6B7876FF6A7775FF
+ 6B7674FF677472FF65736FFF5B6A66FF62706CFF586662FF44524EFF25332FFF
+ 525D5AFF596461FF5F6865FF67706DFF636C69FF606966FF666D6AFF5F6663FF
+ 5A615EFF606966FF636C69FF596461FF5A6562FF5D6865FF5D6865FF66716EFF
+ 67726FFF57625FFF727D7AFF747F7CFF7B8683FF848F8CFF87928FFF86918EFF
+ 899491FF8E9996FF889692FF82908CFF7C8A86FF7F8D89FF8B9995FF94A29EFF
+ 919F9BFF889692FF93A19DFF889692FF8A9894FF96A4A0FF96A4A0FF92A09CFF
+ A4B2AEFFC0CFCBFFC0D1CDFFB8CCC7FFB5C9C4FFB6CAC5FFB9CAC6FFB9CAC6FF
+ BDCECAFFC3D4D0FFC6D5D1FFC1D0CCFFB3C1BDFFA1AFABFF99A7A3FF9AA8A4FF
+ 97A29FFF8D9895FF1E2C28FF707E7AFF82908CFF778581FF74827EFF6F7D79FF
+ 7F8D89FF8D9B97FF869490FF8A9894FF8E9C98FF8F9D99FF8E9C98FF919F9BFF
+ 98A6A2FF9EACA8FFA3B1ABFFA0AEA8FF9AA8A2FF97A59FFF9EACA6FFA8B6B0FF
+ AAB8B2FFA5B3ADFFA7B5AFFFA5B3ADFFA2B0AAFFA0AEA8FFA0AEA8FFA1AFA9FF
+ A0AEA8FF9DABA5FFA2B0AAFFA3B1ABFFA5B3ADFFA6B4AEFFA6B4AEFFA4B2ACFF
+ A1AFA9FF9FADA7FF9EACA6FF9FADA7FF9FADA7FF9FADA7FF9DABA5FF98A6A0FF
+ 93A19BFF8F9D97FF88948EFF84908AFF808C86FF75817BFF75817BFF34403AFF
+ 64706AFF6C7872FF69756FFF6D7973FF717D77FF727E78FF707C76FF6D7973FF
+ 6C7872FF6B7771FF69736DFF68726CFF6A746EFF69736DFF636D67FF5B655FFF
+ 5C6660FF626C66FF626C66FF67716BFF6D7771FF727C76FF747E78FF76807AFF
+ 77817BFF78837BFF7B8880FF7C8A7FFF808E83FF859388FF8D9B90FF95A398FF
+ 9EACA1FFA3B1A6FF98A69BFF8F9D92FF8D9B90FF96A499FF9DABA0FF9DABA0FF
+ A1AFA4FFAAB8ADFFAABAAFFFAABAAFFFAABAAFFFAABAAFFFA9B9AEFFA6B6ABFF
+ A2B2A7FF9FAFA4FF99A99EFFA4B4A9FFAABAAFFFA6B6ABFFA2B2A7FFA1B1A6FF
+ 99A99EFF8D9D92FF99A9A2FF9CACA5FFB4C4BDFFCADAD3FFCBDBD4FFC3D3CCFF
+ B4C4BDFF9DADA6FF94A49DFF8E9E97FF8D9D96FF91A19AFF656E6BFF6C7572FF
+ 666F6CFF69726FFF656E6BFF6D7673FF818A87FF6F7875FF525B58FF505956FF
+ 424B48FF39423FFF3C4542FF313A37FF212A27FF1F2825FF2F3A37FF5E6966FF
+ 8C9794FF9DA8A5FF9FAAA7FFA1ACA9FF9DA8A5FF96A19EFF9DA8A5FFA0ABA8FF
+ 9EA9A6FF97A29FFF939E9BFF949F9CFF929D9AFF8F9A97FF919C99FF8E9996FF
+ 87928FFF8A9592FF939E9BFF8C9794FF87928FFF949F9CFF98A3A0FF949F9CFF
+ 828D8AFF747F7CFF95A09DFF8E9996FF8B9693FF8A9592FF7B8985FF74837FFF
+ 6D7B77FF677571FF677571FF6C7A76FF76817EFF7C8784FF79827FFF6C7572FF
+ 666F6CFF545D5AFF4D5451FF505754FF686F6CFF6F7673FF737C79FF737C79FF
+ 747D7AFF757E7BFF77807DFF78817EFF79827FFF79827FFF838C89FF7D8683FF
+ 7E8784FF6C7572FF6C7572FF7F8885FF7E8784FF838C89FF7F8A87FF808B88FF
+ 919C99FF899491FFA2ADAAFF8A9592FF9BA6A3FFAAB5B2FFBEC9C6FF9DA8A5FF
+ 808B88FF818C89FF929D9AFF98A3A0FF8F9A97FF818F8BFF92A3A0FFB4C7C4FF
+ AFC2BFFFA7BAB7FFA1B2AFFF90A19EFF8A9B98FF7C8D8AFF778583FF7E8C8AFF
+ 7E8B89FF717E7CFF64716FFF5E6B69FF606B69FF5D6A68FF5E6C68FF505F5BFF
+ 5A6864FF515F5BFF394743FF202E2AFF515C59FF515C59FF616A67FF656E6BFF
+ 616A67FF616A67FF676E6BFF606764FF5C6360FF666F6CFF67706DFF5A6562FF
+ 596461FF5C6764FF5E6966FF6A7572FF6C7774FF5D6865FF65706DFF697471FF
+ 737E7BFF7D8885FF818C89FF7F8A87FF838E8BFF899491FF94A29EFF879591FF
+ 7B8985FF7C8A86FF899793FF93A19DFF919F9BFF8A9894FF8D9B97FF8A9894FF
+ 94A29EFFA2B0ACFF9EACA8FF94A29EFFA4B2AEFFBFCECAFFB8C9C5FFB1C5C0FF
+ B0C4BFFFB3C7C2FFB8C9C5FFB9CAC6FFBFD0CCFFC5D6D2FFC6D5D1FFC8D7D3FF
+ B9C7C3FF9EACA8FF909E9AFF909E9AFF8D9895FF808B88FF1D2B27FF788682FF
+ 899793FF7B8985FF7D8B87FF75837FFF7D8B87FF8C9A96FF879591FF8A9894FF
+ 8E9C98FF8E9C98FF8D9B97FF8F9D99FF96A4A0FF9CAAA6FFA1AFA9FFA2B0AAFF
+ 9EACA6FF9BA9A3FF9EACA6FFA6B4AEFFA9B7B1FFA7B5AFFFA8B6B0FFA9B7B1FF
+ A6B4AEFFA2B0AAFFA3B1ABFFA5B3ADFFA3B1ABFF9DABA5FFA2B0AAFFA2B0AAFF
+ A2B0AAFFA1AFA9FFA1AFA9FFA1AFA9FFA1AFA9FFA1AFA9FF9BA9A3FF9AA8A2FF
+ 98A6A0FF97A59FFF96A49EFF93A19BFF8E9C96FF8A9892FF8A9690FF828E88FF
+ 7B8781FF6D7973FF727E78FF35413BFF65716BFF67736DFF68746EFF6D7973FF
+ 727E78FF74807AFF727E78FF6E7A74FF6B7771FF69756FFF6B756FFF6B756FFF
+ 6C7670FF6C7670FF656F69FF5B655FFF59635DFF5E6862FF616B65FF636D67FF
+ 69736DFF6F7973FF757F79FF78827CFF78827CFF78837BFF76837BFF79877CFF
+ 7E8C81FF859388FF8E9C91FF9AA89DFFA8B6ABFFB0BEB3FFA6B4A9FFA0AEA3FF
+ 9BA99EFF9CAA9FFFA2B0A5FFA8B6ABFFABB9AEFFACBAAFFFA6B6ABFFA8B8ADFF
+ ABBBB0FFABBBB0FFA8B8ADFFA6B6ABFFA5B5AAFFA6B6ABFFA1B1A6FFAFBFB4FF
+ B3C3B8FFACBCB1FFABBBB0FFADBDB2FFA0B0A5FF8B9B90FF92A29BFF92A29BFF
+ A9B9B2FFC4D4CDFFC9D9D2FFC4D4CDFFB8C8C1FFA6B6AFFF94A49DFF8D9D96FF
+ 899992FF8B9B94FF616A67FF626B68FF5D6663FF69726FFF636C69FF67706DFF
+ 87908DFF88918EFF717A77FF717A77FF646D6AFF5A6360FF5E6764FF535C59FF
+ 3C4542FF313A37FF29322FFF515A57FF808986FF9BA4A1FFA4ADAAFFA5AEABFF
+ A2ABA8FF9DA6A3FFA0A9A6FFA0A9A6FF9CA5A2FF97A09DFF98A19EFF98A19EFF
+ 909996FF858E8BFF818A87FF7B8481FF717A77FF747D7AFF7B8481FF707976FF
+ 6A7370FF77807DFF848D8AFF7D8683FF49524FFF6C7572FF87908DFF848D8AFF
+ 8D9693FF889390FF798783FF73827EFF6D7B77FF687672FF697773FF707E7AFF
+ 7A8582FF808B88FF7A8380FF727B78FF5E6764FF5A6360FF4A514EFF59605DFF
+ 646B68FF757C79FF747D7AFF737C79FF737C79FF757E7BFF77807DFF79827FFF
+ 7A8380FF7A8380FF848D8AFF7A8380FF828B88FF6D7673FF666F6CFF727B78FF
+ 6C7572FF7D8683FF75807DFF838E8BFF8B9693FF8D9895FF9CA7A4FF939E9BFF
+ 85908DFF7E8986FFB4BFBCFFB4BFBCFFA2ADAAFF889390FF838E8BFF8E9996FF
+ 8C9794FF7C8A86FF94A5A2FFB4C7C4FFADC0BDFFA1B4B1FF99AAA7FF879895FF
+ 829390FF738481FF7B8987FF7D8B89FF798684FF6C7977FF616E6CFF5E6B69FF
+ 606B69FF5D6A68FF5B6965FF495854FF53615DFF4A5854FF32403CFF212F2BFF
+ 586360FF56615EFF5C6562FF5F6865FF5A6360FF5B6461FF626966FF5C6360FF
+ 5A615EFF666F6CFF6C7572FF626D6AFF616C69FF5E6966FF586360FF616C69FF
+ 697471FF606B68FF65706DFF636E6BFF697471FF747F7CFF7D8885FF808B88FF
+ 828D8AFF86918EFF97A5A1FF8B9995FF7F8D89FF7E8C88FF83918DFF889692FF
+ 8A9894FF899793FF8E9C98FF8A9894FF94A29EFFA2B0ACFF9FADA9FF97A5A1FF
+ A6B4B0FFC2D1CDFFB5C6C2FFAFC3BEFFAFC3BEFFB4C8C3FFB8C9C5FFB9CAC6FF
+ BDCECAFFC4D5D1FFC2D1CDFFC3D2CEFFBAC8C4FFA2B0ACFF899793FF808E8AFF
+ 889390FF8F9A97FF303E3AFF84928EFF879591FF72807CFF7C8A86FF75837FFF
+ 768480FF808E8AFF7E8C88FF85938FFF8C9A96FF8F9D99FF8F9D99FF8F9D99FF
+ 93A19DFF96A4A0FF99A7A1FF9EACA6FF9FADA7FF9BA9A3FF9BA9A3FF9FADA7FF
+ A3B1ABFFA3B1ABFFA2B0AAFFA6B4AEFFA5B3ADFFA1AFA9FFA2B0AAFFA5B3ADFF
+ A1AFA9FF99A7A1FFA3B1ABFFA0AEA8FF9BA9A3FF98A6A0FF96A49EFF97A59FFF
+ 9AA8A2FF9CAAA4FF95A39DFF92A09AFF8E9C96FF8D9B95FF8D9B95FF8D9B95FF
+ 8A9892FF87958FFF84908AFF7B8781FF727E78FF67736DFF707C76FF37433DFF
+ 626E68FF5E6A64FF64706AFF6A7670FF707C76FF737F79FF717D77FF6D7973FF
+ 6A7670FF68746EFF66706AFF67716BFF6C7670FF6D7771FF67716BFF5C6660FF
+ 59635DFF5D6761FF59635DFF606A64FF68726CFF6E7872FF717B75FF737D77FF
+ 77817BFF7A857DFF738078FF78867BFF7F8D82FF869489FF8F9D92FF9AA89DFF
+ A6B4A9FFAFBDB2FFADBBB0FFADBBB0FFA5B3A8FF9BA99EFF9FADA2FFACBAAFFF
+ ADBBB0FFA5B3A8FF99A99EFFA0B0A5FFA5B5AAFFA4B4A9FF9EAEA3FF9BABA0FF
+ 9EAEA3FFA3B3A8FFA3B3A8FFAABAAFFFB0C0B5FFB1C1B6FFADBDB2FFA6B6ABFF
+ 9DADA2FF94A499FF97A7A0FF91A19AFFA2B2ABFFBBCBC4FFC1D1CAFFC0D0C9FF
+ B9C9C2FFACBCB5FF99A9A2FF91A19AFF8A9A93FF8A9A93FF646B68FF5F6865FF
+ 5F6663FF6A7370FF606764FF555E5BFF757C79FF7B8481FF8E9592FF8B9491FF
+ 7B827FFF6B7471FF707774FF666F6CFF525956FF444D4AFF262F2CFF434C49FF
+ 6B7471FF8A9390FF99A29FFF9DA6A3FF9CA5A2FF9AA3A0FF929B98FF929B98FF
+ 919A97FF929B98FF949D9AFF8E9794FF7B8481FF67706DFF59625FFF505956FF
+ 434C49FF434C49FF48514EFF3A4340FF313A37FF3D4643FF2C3532FF3F4845FF
+ 17201DFF6D7673FF848D8AFF7B8481FF868F8CFF808986FF798481FF73817DFF
+ 6F7A77FF6C7774FF6E7976FF75807DFF818A87FF87908DFF757E7BFF737C79FF
+ 515855FF616865FF424946FF636A67FF5C6360FF747B78FF757E7BFF757E7BFF
+ 757E7BFF77807DFF7A8380FF7D8683FF7E8784FF7E8784FF818A87FF757E7BFF
+ 828B88FF6D7673FF616A67FF666F6CFF5C6562FF737C79FF7D8683FF8D9693FF
+ 77807DFF7D8683FF88918EFFAAB5B2FF97A09DFF899491FF8C9794FFC1CCC9FF
+ CFDAD7FF9DA8A5FF75807DFF7C8784FF87928FFF7D8B87FF95A6A3FFB3C6C3FF
+ A9BCB9FF9BAEABFF91A29FFF7F908DFF7B8C89FF6E7F7CFF798785FF768482FF
+ 6D7A78FF626F6DFF5D6A68FF606D6BFF636E6CFF5E6B69FF5E6C68FF4A5854FF
+ 52605CFF495753FF333E3BFF283330FF646F6CFF616C69FF5C6562FF5D6663FF
+ 58615EFF59625FFF616865FF5B625FFF5B625FFF69726FFF707976FF6A7572FF
+ 697471FF5F6A67FF4F5A57FF545F5CFF5F6A67FF5B6663FF65706DFF5D6865FF
+ 5C6764FF697471FF77827FFF7E8986FF808B88FF818C89FF929D9AFF899793FF
+ 838E8BFF7E8C88FF7F8A87FF7E8C88FF85908DFF889692FF96A19EFF899793FF
+ 8D9895FF97A5A1FF9AA5A2FF95A39FFFABB6B3FFC8D6D2FFB8C9C5FFB4C5C1FF
+ B4C5C2FFB7C8C4FFB9CAC7FFB7C8C4FFBCCAC8FFC0CFCBFFBCCAC8FFBAC9C5FF
+ B6C3C1FFA6B4B0FF889593FF75837FFF889391FFA7B2AFFF485350FF919F9BFF
+ 86918EFF6A7874FF7B8683FF768480FF747F7CFF788682FF788380FF7F8D89FF
+ 8C9794FF919F9BFF939E9BFF909E9AFF939E9BFF92A09CFF8F9D97FF98A6A0FF
+ 9CAAA4FF98A6A0FF95A39DFF98A6A0FF9BA9A3FF9CAAA4FF9BA9A3FFA0AEA8FF
+ A1AFA9FF9DABA5FF9EACA6FFA1AFA9FF9CAAA4FF93A19BFFA3B1ABFF9EACA6FF
+ 96A49EFF909E98FF8D9B95FF8F9D97FF93A19BFF96A49EFF919F99FF8D9B95FF
+ 889690FF87958FFF8A9892FF8B9993FF8A9892FF889690FF7A8680FF717D77FF
+ 6C7670FF626E68FF737D77FF39453FFF646E68FF59655FFF626C66FF66726CFF
+ 707A74FF727E78FF737D77FF6D7973FF6C7670FF6A746EFF5D6761FF636B64FF
+ 6A716CFF6F7770FF6A716CFF5F6A62FF5D6761FF606B63FF515B55FF5D6860FF
+ 69736DFF6E7971FF6D7771FF6E7971FF757F79FF7B8880FF738176FF79877CFF
+ 818F84FF88968BFF8D9B90FF95A398FF9DABA0FFA3B1A6FFACBAAFFFB0BEB3FF
+ A5B3A8FF94A297FF97A59AFFA8B6ABFFA8B6ABFF9AA89DFF96A69BFF9EAEA3FF
+ A5B4ACFFA1B1A6FF98A79FFF94A499FF99A8A0FFA0B0A5FF92A199FF93A398FF
+ 9EADA5FFACBCB1FFAAB9B1FF9EAEA3FF9EADA5FFA8B7AFFFA2B2ABFF96A69FFF
+ A1B1AAFFB5C5BEFFBACAC3FFB9C9C2FFB6C6BFFFACBCB5FFA1B1AAFF98A6A0FF
+ 909E98FF8E9C96FF676D68FF656C67FF676D68FF656C67FF606661FF5E6560FF
+ 6A706BFF777E79FF6E746FFF868D88FF9CA29DFF959C97FF7E847FFF6A716CFF
+ 636964FF606762FF4D5653FF37423FFF333E3BFF545F5CFF818C89FF97A29FFF
+ 939E9BFF899491FF7D8885FF6E7976FF5F6A67FF5E6966FF697471FF737E7BFF
+ 747F7CFF717C79FF868F8CFF858E8BFF87908DFF87908DFF78817EFF616A67FF
+ 535C59FF515A57FF49524FFF4B5451FF3C4542FF69726FFF747D7AFF808986FF
+ 808986FF7E8784FF7C8380FF7A817EFF787F7CFF757C79FF707774FF707774FF
+ 7D8481FF8D9491FF868D8AFF737A77FF474C4AFF636866FF474C4AFF676C6AFF
+ 676C6AFF717875FF79837DFF76807AFF747E78FF757F79FF78827CFF7B857FFF
+ 7A847EFF78827CFF7E8882FF7D8781FF717B75FF67716BFF67716BFF606A64FF
+ 616B65FF717B75FF7F8683FF7E8582FF808784FF868D8AFF8A918EFF8A9390FF
+ 909794FF929B98FF8C9592FF929B98FFBFCAC7FFD8E3E0FFABB6B3FF7E8986FF
+ 7D8B87FF879692FFA1B5B0FFA3B9B4FF9EB4AFFF90A6A1FF869A95FF7D918CFF
+ 72837FFF657672FF6C7D79FF697A76FF697874FF687773FF687672FF65736FFF
+ 5E6C68FF586662FF57625FFF4C5754FF56615EFF535E5BFF3D4643FF404946FF
+ 505956FF69726FFF606966FF59625FFF59625FFF5F6865FF5D6663FF555E5BFF
+ 5C6562FF6A7370FF6F7973FF747E78FF6D7771FF66706AFF656F69FF5B655FFF
+ 59635DFF67716BFF67716BFF525C56FF656F69FF76807AFF66706AFF707A74FF
+ 848E88FF77807DFF848D8AFF889391FF848C8BFF818C8AFF8B9392FF889391FF
+ 858D8CFF8A9593FF979F9EFF939E9CFF919998FF95A09EFF9DA5A4FF95A09EFF
+ 9FA7A6FFB9C4C2FFB6C3C1FFB3C1BFFFAFBDBCFFACBAB8FFAEBCBBFFB4C2C0FF
+ B8C4C4FFB7C4C2FFB6C2C2FFB6C3C1FFB2BEBEFFA5B2B0FF909C9CFF828F8DFF
+ 889494FF97A2A0FF65706EFF899492FF9BA3A2FF737E7CFF757D7CFF778280FF
+ 626A69FF85908EFF777F7EFF7B8684FF868E8DFF8B9694FF8F9796FF8D9896FF
+ 8F9796FF8D9895FF8E9C96FF92A09AFF96A49EFF98A6A0FF97A59FFF97A59FFF
+ 98A6A0FF99A7A1FF9AA8A2FF9CAAA4FF9FADA7FFA1AFA9FFA2B0AAFF9FADA7FF
+ 9CAAA4FF9AA8A2FF9BA9A3FF9AA8A2FF98A6A0FF97A59FFF96A49EFF96A49EFF
+ 97A59FFF97A59FFF99A7A1FF92A09AFF8B9993FF8A9892FF8E9C96FF919F99FF
+ 8E9C96FF8C9892FF818B85FF6F7973FF7D847FFF737D77FF616863FF56605AFF
+ 4D544FFF535D57FF69706BFF606A64FF676E69FF717B75FF707772FF5F6963FF
+ 5F6661FF69706BFF626962FF5D655BFF5D645DFF646C62FF666D66FF60695FFF
+ 59615AFF565F55FF5F6760FF626B61FF616C64FF606B61FF647169FF6D7B70FF
+ 727F77FF717F74FF758378FF79897EFF78887DFF7B8B80FF88988DFF8E9E93FF
+ 95A59AFFA7B7ACFFA5B5AAFFAABAAFFFA9B9AEFF9BABA0FF8B9B90FF8B9B90FF
+ 9CACA1FFAEBEB3FF97A69EFF9CABA3FFA2B0AAFFA3B2AAFF9FADA7FF99A8A0FF
+ 96A49EFF95A49CFF97A59FFF98A79FFF9BA9A3FF9FAEA6FFA3B1ABFFA3B2AAFF
+ A1AFA9FF9FADA7FF91A19AFF99A9A2FFA5B5AEFFB2C2BBFFBACAC3FFB9C9C2FF
+ B5C3BDFFB0BEB8FFA2B0AAFF8F9B95FF94A09AFF88948EFF616762FF636964FF
+ 666C67FF676D68FF626863FF5F6560FF676D68FF727873FF656B66FF757B76FF
+ 8B918CFF9CA29DFFA2A8A3FF999F9AFF818782FF6A716CFF77807DFF66716EFF
+ 606B68FF6E7976FF7E8986FF828D8AFF7C8784FF76817EFF919C99FF8E9996FF
+ 8C9794FF8D9895FF909B98FF919C99FF8E9996FF8A9592FF808986FF828B88FF
+ 87908DFF89928FFF7A8380FF606966FF4D5653FF464F4CFF454E4BFF4A5350FF
+ 3E4744FF6D7673FF78817EFF828B88FF808986FF7D8683FF777C7AFF747977FF
+ 737876FF727775FF6E7371FF6C716FFF727775FF7C817FFF868B89FF797E7CFF
+ 4D5250FF565B59FF494E4CFF595E5CFF797E7CFF757C79FF79807BFF747E78FF
+ 727C76FF737D77FF77817BFF78827CFF77817BFF76807AFF757F79FF77817BFF
+ 6F7973FF69736DFF6B756FFF636D67FF616B65FF6E7872FF767B79FF7A7F7DFF
+ 808583FF838886FF828986FF838A87FF8A918EFF929996FF949D9AFF7F8885FF
+ 909B98FFB9C4C1FFCCD7D4FFCFDAD7FFB1BFBBFF7E8D89FFA8BCB7FFA8BEB9FF
+ A2B8B3FF93A9A4FF899D98FF80948FFF768783FF6B7C78FF72837FFF6E7F7BFF
+ 6B7A76FF697874FF697773FF677571FF64726EFF616F6BFF67706DFF5C6562FF
+ 616A67FF58615EFF444D4AFF48514EFF57605DFF656E6BFF636C69FF5A6360FF
+ 58615EFF5E6764FF5E6764FF5A6360FF606966FF6D7673FF636D67FF6B756FFF
+ 6B756FFF6B756FFF6F7973FF66706AFF646E68FF717B75FF6C7670FF5A645EFF
+ 6A746EFF78827CFF67716BFF717B75FF86908AFF7D8781FF7F8885FF828A89FF
+ 7D8584FF818988FF919998FF939B9AFF8B9392FF8D9594FF858D8CFF858D8CFF
+ 848C8BFF8C9493FF969E9DFF969E9DFFA5ADACFFC5D0CEFFB5BFBFFFB0BCBCFF
+ ADB9B9FFACB8B8FFB1BDBDFFB6C2C2FFB7C3C3FFB5C1C1FFADB9B9FFAEBABAFF
+ ACB8B8FFA1ADADFF8F9B9BFF838F8FFF899595FF97A4A2FF5F6766FF88908FFF
+ 919998FF757D7CFF757D7CFF737B7AFF676F6EFF808887FF777F7EFF7B8382FF
+ 808887FF838B8AFF858D8CFF878F8EFF899190FF8A9592FF8B9791FF8D9B95FF
+ 919F99FF93A19BFF94A29CFF94A29CFF96A49EFF98A6A0FF97A59FFF99A7A1FF
+ 9CAAA4FF9FADA7FF9FADA7FF9DABA5FF9AA8A2FF99A7A1FF9BA9A3FF9AA8A2FF
+ 99A7A1FF97A59FFF96A49EFF95A39DFF95A39DFF95A39DFF8F9D97FF8E9C96FF
+ 8E9C96FF909E98FF92A09AFF8F9D97FF889690FF838F89FF87918BFF7B827DFF
+ 7F8681FF727974FF5F6661FF4D544FFF3C433EFF505752FF5E6560FF5D645FFF
+ 646B66FF707772FF707772FF666D68FF626964FF666E67FF666A64FF61665DFF
+ 5F645BFF61665DFF5D655BFF565E54FF515A50FF515A50FF5F685EFF626B61FF
+ 616C62FF606B61FF637166FF6C7A6FFF707E73FF6F7D72FF748479FF79897EFF
+ 75857AFF75857AFF839388FF8D9D92FF98A89DFFACBCB1FFA0B0A5FFA3B3A8FF
+ A3B3A8FF9DADA2FF94A499FF91A196FF95A59AFF9AAA9FFF9DABA5FFA2B0AAFF
+ A8B6B0FFA9B7B1FFA5B3ADFFA0AEA8FF9DABA5FF9BA9A3FF9BA9A3FF9BA9A3FF
+ 9DABA5FF9EACA6FF9DABA5FF9BA9A3FF98A6A0FF96A49EFF8F9F98FF95A59EFF
+ A2B2ABFFB1C1BAFFBBCBC4FFBBCBC4FFB3C1BBFFAAB8B2FFA0ACA6FF8E9A94FF
+ 949E98FF838D87FF5C625DFF5F6560FF646A65FF686E69FF636964FF5F6560FF
+ 636964FF6C726DFF6B716CFF6D736EFF747A75FF848A85FF9CA29DFFACB2ADFF
+ A9AFAAFF9CA39EFFA8B1AEFFA4AFACFFA3AEABFFA3AEABFF9EA9A6FF96A19EFF
+ 949F9CFF97A29FFF87928FFF8C9794FF919C99FF909B98FF8A9592FF848F8CFF
+ 838E8BFF85908DFF7F8885FF818A87FF848D8AFF858E8BFF79827FFF666F6CFF
+ 565F5CFF515A57FF4F5855FF555E5BFF4A5350FF77807DFF7E8784FF858E8BFF
+ 808986FF7B8481FF737876FF6F7472FF6F7472FF717674FF6F7472FF696E6CFF
+ 676C6AFF696E6CFF7C817FFF767B79FF5D6260FF4D5250FF494E4CFF505553FF
+ 787D7BFF6C7370FF757C77FF727C76FF717B75FF727C76FF747E78FF757F79FF
+ 747E78FF737D77FF737D77FF77817BFF717B75FF6F7973FF727C76FF68726CFF
+ 616B65FF6B756FFF6D7270FF777C7AFF808583FF808583FF7B827FFF7C8380FF
+ 858C89FF8F9693FF909996FF7A8380FF788380FF8B9693FFAEB9B6FFDCE7E4FF
+ D5E3DFFF9EADA9FFABBFBAFFA8BEB9FFA2B6B1FF94A8A3FF889C97FF7F938EFF
+ 778884FF6E7F7BFF72817DFF6E7D79FF677672FF64736FFF64726EFF64726EFF
+ 65736FFF64726EFF6E7774FF69726FFF69726FFF58615EFF4A5350FF4D5653FF
+ 626B68FF636C69FF656E6BFF59625FFF525B58FF555E5BFF57605DFF555E5BFF
+ 5A6360FF636C69FF656F69FF6C7670FF69736DFF68726CFF6C7670FF656F69FF
+ 636D67FF707A74FF69736DFF5B655FFF68726CFF6F7973FF5F6963FF67716BFF
+ 7D8781FF7D8781FF7C8582FF7E8784FF78817EFF7D8683FF919A97FF949D9AFF
+ 8A9390FF8A9390FF848D8AFF848D8AFF818A87FF87908DFF8E9794FF8D9693FF
+ A0A9A6FFC2CDCAFFB4BFBDFFACB9B7FFA8B5B3FFAAB7B5FFAFBCBAFFB1BEBCFF
+ AFBCBAFFABB8B6FFA3B0AEFFA1AEACFF9FACAAFF99A6A4FF8C9997FF83908EFF
+ 889593FF929F9DFF505857FF7F8885FF7C8582FF6F7875FF6F7875FF666F6CFF
+ 69726FFF717A77FF747D7AFF757E7BFF77807DFF77807DFF78817EFF7B8481FF
+ 818A87FF848F8CFF85918BFF87958FFF8B9993FF8E9C96FF909E98FF92A09AFF
+ 95A39DFF97A59FFF93A19BFF95A39DFF98A6A0FF9AA8A2FF9BA9A3FF9AA8A2FF
+ 98A6A0FF97A59FFF9CAAA4FF9BA9A3FF98A6A0FF96A49EFF95A39DFF94A29CFF
+ 93A19BFF93A19BFF8D9B95FF8F9D97FF919F99FF92A09AFF919F99FF8D9B95FF
+ 889690FF86928CFF838D87FF7E8580FF7B827DFF6E7570FF676E69FF4E5550FF
+ 373E39FF585F5AFF555C57FF5A615CFF626964FF6A716CFF6D746FFF6A716CFF
+ 636A65FF5F6760FF6A6E68FF656A61FF61665DFF5E635AFF555D53FF4C544AFF
+ 4A5248FF4D554BFF5A6359FF5F685EFF606B61FF5F6A60FF646F65FF6C776DFF
+ 6E7C71FF6D7B70FF717F74FF78867BFF758378FF78867BFF89978CFF94A297FF
+ 9BA99EFFA7B5AAFFA8B6ABFFA4B2A7FFA1AFA4FF9FADA2FF9FADA2FF9DABA0FF
+ 98A69BFF94A297FF9CA8A2FFA0ACA6FFA5B1ABFFA7B3ADFFA4B0AAFFA0ACA6FF
+ 9DA9A3FF9BA7A1FF9BA7A1FF9DA9A3FFA0ACA6FFA0ACA6FF9DA9A3FF98A49EFF
+ 95A19BFF919F99FF8A9A93FF8F9F98FF9CACA5FFAEBEB7FFBECCC6FFBECCC6FF
+ B1BFB9FFA3B1ABFF99A59FFF8B9791FF919B95FF7A847EFF5A605BFF5C625DFF
+ 616762FF646A65FF616762FF5D635EFF606661FF686E69FF6B716CFF6D736EFF
+ 6C726DFF6C726DFF7B817CFF979D98FFB3B9B4FFC2C9C4FFA4ADAAFFA9B4B1FF
+ AEB9B6FFAAB5B2FF9FAAA7FF98A3A0FF9AA5A2FFA1ACA9FF8B9693FF8D9895FF
+ 8C9794FF848F8CFF7C8784FF7A8582FF7F8A87FF86918EFF838C89FF828B88FF
+ 808986FF7E8784FF79827FFF747D7AFF707976FF707976FF666F6CFF6A7370FF
+ 5B6461FF828B88FF838C89FF858E8BFF7E8784FF79827FFF757A78FF6F7472FF
+ 6D7270FF717674FF717674FF6C716FFF666B69FF656A68FF737876FF6F7472FF
+ 757A78FF575C5AFF444947FF616664FF646967FF646967FF737A75FF717B75FF
+ 717B75FF727C76FF727C76FF727C76FF717B75FF717B75FF717B75FF747E78FF
+ 6E7872FF6D7771FF707A74FF66706AFF5E6862FF69706BFF6C716FFF767B79FF
+ 7E8381FF7D8280FF7A817EFF7D8481FF848B88FF89908DFF88918EFF808986FF
+ 7F8A87FF7A8582FF828D8AFFB1BCB9FFCCDAD6FFB7C6C2FFA9BDB8FFA3B9B4FF
+ 9BAFAAFF8EA29DFF829691FF788C87FF738480FF6D7E7AFF6E7D79FF6B7A76FF
+ 677672FF64736FFF64726EFF64726EFF667470FF687370FF6A7370FF6F7875FF
+ 707976FF58615EFF4B5451FF47504DFF6A7370FF646D6AFF68716EFF5B6461FF
+ 505956FF505956FF515A57FF515A57FF545D5AFF59625FFF68726CFF6A746EFF
+ 626C66FF5F6963FF646E68FF606A64FF626C66FF727C76FF737D77FF6B756FFF
+ 737D77FF76807AFF68726CFF6D7771FF828C86FF89938DFF808986FF828B88FF
+ 7A8380FF7A8380FF88918EFF8A9390FF828B88FF858E8BFF87908DFF88918EFF
+ 858E8BFF88918EFF8C9592FF87908DFF98A19EFFBBC4C1FFB5C0BEFFAAB7B5FF
+ A4B1AFFFA6B3B1FFAAB7B5FFA7B4B2FFA1AEACFF9CA9A7FF9DAAA8FF95A2A0FF
+ 8E9B99FF8B9896FF879492FF808D8BFF7E8B89FF818C8AFF47504DFF767F7CFF
+ 6C7572FF6B7471FF6B7471FF5E6764FF6C7572FF656E6BFF6B7471FF6C7572FF
+ 6D7673FF6E7774FF6F7875FF737C79FF79827FFF7E8784FF818D87FF83918BFF
+ 889690FF8B9993FF8E9C96FF919F99FF96A49EFF99A7A1FF8F9D97FF919F99FF
+ 94A29CFF96A49EFF98A6A0FF97A59FFF96A49EFF95A39DFF9BA9A3FF9AA8A2FF
+ 97A59FFF95A39DFF92A09AFF919F99FF909E98FF909E98FF8D9B95FF8C9A94FF
+ 8A9892FF87958FFF84928CFF84928CFF87958FFF8B9791FF808782FF7C837EFF
+ 727974FF656C67FF6B726DFF505752FF2F3631FF525954FF545B56FF5B625DFF
+ 606762FF626964FF676E69FF6A716CFF636A65FF5A615AFF686D64FF656A61FF
+ 63685FFF5F645BFF535B51FF474F45FF454D43FF495147FF525B51FF596258FF
+ 5C675DFF5D685EFF626D63FF6A756BFF6D7B70FF6C7A6FFF6C7A6FFF748277FF
+ 748277FF7E8C81FF96A499FF9FADA2FF98A69BFF96A499FFAAB8ADFFA2B0A5FF
+ 9AA89DFF98A69BFF9BA99EFF9EACA1FF9CAA9FFF99A79CFF98A49EFF9BA7A1FF
+ 9EAAA4FFA1ADA7FFA0ACA6FF9DA9A3FF99A59FFF97A39DFF94A09AFF99A59FFF
+ A0ACA6FFA3AFA9FFA1ADA7FF9CA8A2FF96A29CFF909E98FF86948EFF889891FF
+ 94A49DFFAABAB3FFBECCC6FFC0CEC8FFB0BEB8FF9FADA7FF919D97FF84908AFF
+ 8C9690FF76807AFF595F5AFF595F5AFF5B615CFF5E645FFF5C625DFF595F5AFF
+ 5E645FFF656B66FF5F6560FF696F6AFF6F7570FF6E746FFF747A75FF888E89FF
+ 9FA5A0FFAEB5B0FF9AA3A0FF9EA9A6FFA0ABA8FF9AA5A2FF919C99FF8A9592FF
+ 899491FF8A9592FF919C99FF8D9895FF87928FFF7F8A87FF7B8683FF7B8683FF
+ 808B88FF848F8CFF818A87FF818A87FF808986FF7E8784FF7F8885FF818A87FF
+ 818A87FF808986FF77807DFF79827FFF656E6BFF868F8CFF838C89FF838C89FF
+ 7D8683FF79827FFF777C7AFF6F7472FF6A6F6DFF6E7371FF707573FF6C716FFF
+ 686D6BFF676C6AFF6F7472FF656A68FF838886FF626765FF383D3BFF7C817FFF
+ 515654FF6E7371FF707772FF717873FF737A75FF737A75FF737A75FF717873FF
+ 717873FF707772FF6B726DFF6C736EFF656C67FF656C67FF6C736EFF666D68FF
+ 616863FF6B726DFF6C716FFF747977FF797E7CFF777C7AFF787F7CFF7E8582FF
+ 808784FF7D8481FF88918EFF7D8683FF838E8BFF86918EFF848F8CFFA0ABA8FF
+ B7C5C1FFACBBB7FFA6B7B3FF9EB2ADFF95A9A4FF8A9E99FF81928EFF768783FF
+ 70817DFF6D7E7AFF6D7C78FF6D7C78FF6D7B77FF6C7A76FF6B7975FF6B7975FF
+ 6E7976FF6E7976FF6D7673FF7A8380FF7B8481FF5C6562FF4C5552FF39423FFF
+ 6B7471FF656E6BFF69726FFF5E6764FF535C59FF515A57FF535C59FF555E5BFF
+ 58615EFF5B6461FF5F6661FF646B66FF626964FF656C67FF6E7570FF6C736EFF
+ 6C736EFF7A817CFF6F7671FF6C736EFF717873FF717873FF69706BFF6A716CFF
+ 7A817CFF868D88FF838A87FF89908DFF828986FF7D8481FF838A87FF828986FF
+ 828986FF8C9390FF818885FF838A87FF828986FF878E8BFF8C9390FF858C89FF
+ 929996FFB0B9B6FFB2BDBBFFA7B2B0FFA1ACAAFFA4AFADFFA5B0AEFF9FAAA8FF
+ 98A3A1FF97A2A0FF99A4A2FF8A9593FF7E8987FF7D8886FF7F8A88FF7A8583FF
+ 707B79FF697472FF47504DFF707774FF686F6CFF6B726FFF686F6CFF5F6663FF
+ 6F7673FF606764FF606764FF646B68FF686F6CFF6C7370FF6D7471FF707774FF
+ 747B78FF757E7BFF7C8882FF808C86FF85918BFF89958FFF8C9892FF919D97FF
+ 96A29CFF9AA6A0FF8E9A94FF8F9B95FF929E98FF94A09AFF96A29CFF97A39DFF
+ 96A29CFF96A29CFF9AA6A0FF99A59FFF96A29CFF94A09AFF929E98FF909C96FF
+ 8F9B95FF8F9B95FF86928CFF86928CFF84908AFF808C86FF7D8983FF7D8983FF
+ 7F8B85FF828E88FF808881FF7B827BFF6B726BFF5C635CFF666D66FF4F564FFF
+ 262D26FF3D443DFF565D56FF585F58FF596059FF5B625BFF636A63FF6A716AFF
+ 666D66FF5C635CFF5E635AFF60635AFF5E635AFF5D6259FF52574EFF454A41FF
+ 3E463CFF40483EFF475046FF515A50FF596258FF5C655BFF5F6A60FF677268FF
+ 6D786EFF6E796FFF707E73FF748277FF707E73FF79877CFF98A69BFFA5B3A8FF
+ 98A69BFF8D9B90FF9BA99EFF97A59AFF93A196FF93A196FF95A398FF97A59AFF
+ 98A69BFF97A59AFF9CA8A2FF9DA9A3FFA0ACA6FFA3AFA9FFA3AFA9FFA2AEA8FF
+ 9FABA5FF9CA8A2FF929E98FF97A39DFF9FABA5FFA6B2ACFFA8B4AEFFA2AEA8FF
+ 98A49EFF8E9C96FF84928CFF84948DFF909E98FFA5B3ADFFBAC8C2FFBECCC6FF
+ B1BDB7FFA0ACA6FF8F9993FF7E8882FF858F89FF7A847EFF545A55FF525853FF
+ 545A55FF585E59FF575D58FF555B56FF585E59FF5E645FFF676D68FF696F6AFF
+ 686E69FF6A706BFF757B76FF868C87FF929893FF949B96FFA0A9A6FFA1ACA9FF
+ 9FAAA7FF99A4A1FF949F9CFF909B98FF8A9592FF828D8AFF828D8AFF808B88FF
+ 7D8885FF7B8683FF7A8582FF788380FF76817EFF747F7CFF79827FFF7E8784FF
+ 818A87FF828B88FF858E8BFF868F8CFF808986FF79827FFF7C8582FF7D8683FF
+ 69726FFF87908DFF818A87FF7F8885FF7A8380FF78817EFF727775FF6B706EFF
+ 666B69FF696E6CFF6B706EFF686D6BFF656A68FF666B69FF676C6AFF5A5F5DFF
+ 777C7AFF5B605EFF2A2F2DFF7B807EFF4A4F4DFF737876FF6C736EFF6F7671FF
+ 717873FF717873FF6F7671FF6D746FFF6C736EFF6D746FFF686F6AFF686F6AFF
+ 626964FF646B66FF6F7671FF6E7570FF6D746FFF787F7AFF6B706EFF737876FF
+ 757A78FF727775FF747B78FF7B827FFF7B827FFF737A77FF848D8AFF79827FFF
+ 828D8AFF889390FF7E8986FF919C99FFB0BEBAFFB4C3BFFFA3B4B0FF9AAEA9FF
+ 92A6A1FF8B9F9AFF82938FFF768783FF70817DFF70817DFF687773FF6A7975FF
+ 6C7A76FF6C7A76FF6B7975FF6B7975FF6F7A77FF707B78FF7B8481FF87908DFF
+ 868F8CFF656E6BFF525B58FF2B3431FF68716EFF626B68FF5C6562FF57605DFF
+ 505956FF4D5653FF4E5754FF525B58FF565F5CFF59625FFF5E6560FF676E69FF
+ 69706BFF707772FF787F7AFF6F7671FF656C67FF6C736EFF626964FF646B66FF
+ 666D68FF676E69FF666D68FF646B66FF6C736EFF79807BFF7D8481FF868D8AFF
+ 828986FF7D8481FF818885FF808784FF838A87FF909794FF818885FF7F8683FF
+ 79807DFF7C8380FF7F8683FF757C79FF7B827FFF969D9AFFACB4B3FF9FAAA8FF
+ 9CA4A3FF9CA7A5FF9BA3A2FF8F9A98FF8D9594FF8F9A98FF8B9392FF7A8583FF
+ 717978FF707B79FF747C7BFF6B7674FF626A69FF5A6360FF484F4CFF5F6663FF
+ 616865FF5F6663FF5A615EFF5B625FFF626966FF535A57FF585F5CFF5D6461FF
+ 636A67FF676E6BFF69706DFF69706DFF6B726FFF6C7370FF747E78FF76827CFF
+ 7C8680FF7E8A84FF848E88FF87938DFF909A94FF929E98FF8A948EFF8A9690FF
+ 8E9892FF8F9B95FF939D97FF929E98FF959F99FF939F99FF98A29CFF94A09AFF
+ 949E98FF909C96FF909A94FF8D9993FF8F9993FF8D9993FF87918BFF86928CFF
+ 89938DFF87938DFF86908AFF7E8A84FF79837DFF757F79FF767E77FF727972FF
+ 686F68FF565D56FF5F665FFF5B625BFF3D443DFF484F48FF565D56FF515851FF
+ 4F564FFF565D56FF606760FF656C65FF626962FF5C635CFF565950FF55584FFF
+ 545950FF545950FF4C5148FF40453CFF383D34FF363E34FF40483EFF4A5349FF
+ 555E54FF596258FF5B665CFF636E64FF687369FF6A756BFF747F75FF758378FF
+ 6A786DFF6D7B70FF8A988DFF9FADA2FF9AA89DFF94A297FF909E93FF92A095FF
+ 97A59AFF9BA99EFF9CAA9FFF9AA89DFF97A59AFF95A398FF9DA9A3FF9DA9A3FF
+ 9FABA5FFA2AEA8FFA4B0AAFFA4B0AAFFA1ADA7FF9EAAA4FF95A19BFF95A19BFF
+ 99A59FFFA1ADA7FFA7B3ADFFA4B0AAFF98A49EFF8D9993FF899791FF879790FF
+ 8F9D97FFA1AFA9FFB3C1BBFFB8C6C0FFADB9B3FF9FABA5FF8E9892FF747E78FF
+ 7F8983FF838D87FF4A504BFF4A504BFF4E544FFF545A55FF545A55FF505651FF
+ 505651FF535954FF6A706BFF686E69FF646A65FF636964FF6F7570FF838984FF
+ 929893FF969D98FF9AA3A0FF99A4A1FF949F9CFF8E9996FF8C9794FF8B9693FF
+ 818C89FF747F7CFF7E8986FF808B88FF818C89FF818C89FF7F8A87FF7D8885FF
+ 798481FF788380FF767F7CFF7C8582FF7F8885FF7F8885FF828B88FF858E8BFF
+ 7F8885FF757E7BFF818A87FF848D8AFF707976FF8D9693FF838C89FF7D8683FF
+ 757E7BFF717A77FF6D7270FF686D6BFF666B69FF696E6CFF676C6AFF626765FF
+ 5F6462FF616664FF606563FF5D6260FF6A6F6DFF5A5F5DFF373C3AFF5F6462FF
+ 505553FF646967FF676E69FF6A716CFF6E7570FF6E7570FF6B726DFF686F6AFF
+ 676E69FF686F6AFF69706BFF69706BFF636A65FF666D68FF737A75FF727974FF
+ 6E7570FF787F7AFF6A6F6DFF767B79FF7B807EFF747977FF717875FF777E7BFF
+ 787F7CFF727976FF7C8582FF79827FFF85908DFF86918EFF77827FFF8E9996FF
+ B2C0BCFFB8C7C3FF9EAFABFF96A7A3FF90A19DFF8C9D99FF839490FF768783FF
+ 71807CFF72817DFF677571FF687672FF6B7673FF697471FF687370FF6A7572FF
+ 6F7A77FF747F7CFF88918EFF8C9592FF868F8CFF68716EFF59625FFF242D2AFF
+ 666F6CFF5F6865FF535C59FF535C59FF4E5754FF48514EFF454E4BFF47504DFF
+ 4B5451FF4E5754FF616863FF666D68FF646B66FF666D68FF6B726DFF606762FF
+ 545B56FF59605BFF646B66FF69706BFF69706BFF6D746FFF727974FF6F7671FF
+ 6F7671FF7A817CFF737A75FF7C837EFF7A817CFF79807BFF808782FF7F8681FF
+ 7C837EFF858C87FF818883FF79807BFF6C736EFF6D746FFF707772FF666D68FF
+ 69706BFF808782FFA5ACA9FF98A19EFF939A97FF8F9895FF868D8AFF757E7BFF
+ 757C79FF7B8481FF747B78FF6C7572FF6A716EFF68716EFF676E6BFF5C6562FF
+ 59605DFF59605DFF4C5350FF515853FF616863FF555C57FF4E5550FF5C635EFF
+ 565D58FF4C534EFF565D58FF5A615CFF5F6661FF616863FF616863FF606762FF
+ 616863FF626964FF686F6AFF69736DFF707772FF717B75FF777E79FF7A847EFF
+ 838A85FF86908AFF868D88FF86908AFF8A918CFF8A948EFF8F9691FF8F9993FF
+ 939A95FF919B95FF959C97FF929C96FF929994FF8F9993FF8F9691FF8D9791FF
+ 8F9691FF8D9791FF929994FF8D9791FF8C938EFF87918BFF868D88FF7C8680FF
+ 737A75FF6B726DFF656C65FF636A63FF656C65FF4E554EFF4F564FFF626962FF
+ 5D645DFF606760FF5A615AFF4D544DFF4A514AFF565D56FF606760FF5B625BFF
+ 535A53FF505750FF565950FF50534AFF4D5047FF4D5047FF484B42FF3C4138FF
+ 343930FF31392FFF3D453BFF495147FF545D53FF576056FF596258FF5F685EFF
+ 646D63FF636E64FF677268FF727D73FF6C776DFF69746AFF808B81FF96A197FF
+ 9BA69CFF9EA99FFF99A49AFF99A49AFF9BA69CFF9FAAA0FFA2ADA3FFA2ADA3FF
+ 9EA99FFF99A49AFF9CA6A0FF9BA59FFF9CA6A0FF9FA9A3FFA3ADA7FFA4AEA8FF
+ A1ABA5FF9DA7A1FF959F99FF8F9993FF8C9690FF959F99FFA2ACA6FFA7B1ABFF
+ 9EA8A2FF919D97FF92A09AFF909E98FF92A09AFF9EACA6FFADB9B3FFB1BDB7FF
+ AAB4AEFF9FA9A3FF929C96FF6D7771FF7B827DFF909792FF424843FF434944FF
+ 4A504BFF525853FF535954FF4D534EFF494F4AFF4A504BFF535954FF616762FF
+ 6D736EFF6F7570FF727873FF7F8580FF909691FF99A09BFF9FA8A5FF9DA8A5FF
+ 96A19EFF8C9794FF87928FFF848F8CFF77827FFF67726FFF7A8582FF7C8784FF
+ 7D8885FF7A8582FF76817EFF75807DFF788380FF7B8683FF79827FFF7C8582FF
+ 7A8380FF77807DFF7B8481FF848D8AFF848D8AFF7D8683FF89928FFF8D9693FF
+ 79827FFF959E9BFF87908DFF7D8683FF707976FF69726FFF6A6F6DFF686D6BFF
+ 696E6CFF6B706EFF686D6BFF606563FF5C615FFF5D6260FF616664FF6C716FFF
+ 6D7270FF686D6BFF555A58FF4C514FFF5E6361FF525755FF636A65FF676E69FF
+ 6B726DFF6B726DFF676E69FF646B66FF636A65FF646B66FF656C67FF666D68FF
+ 606762FF626964FF6D746FFF69706BFF626964FF69706BFF6A6F6DFF7C817FFF
+ 848987FF7A7F7DFF717875FF767D7AFF79807DFF767D7AFF7A8380FF79827FFF
+ 87928FFF909B98FF929D9AFFACB7B4FFB4C2BEFF98A7A3FF9BAAA6FF91A29EFF
+ 8C9D99FF8A9B97FF82938FFF748581FF6F7E7AFF71807CFF6D7B77FF6D7B77FF
+ 6D7875FF6A7572FF697471FF6D7875FF75807DFF7C8784FF8A9390FF87908DFF
+ 7E8784FF666F6CFF5E6764FF222B28FF666F6CFF5E6764FF58615EFF5A6360FF
+ 565F5CFF4C5552FF444D4AFF424B48FF444D4AFF464F4CFF585F5AFF585F5AFF
+ 4E5550FF4D544FFF545B56FF515853FF4E5550FF5A615CFF515853FF585F5AFF
+ 585F5AFF5D645FFF686F6AFF626964FF5D645FFF676E69FF6C736EFF737A75FF
+ 717873FF737A75FF7E8580FF7B827DFF717873FF727974FF767D78FF6B726DFF
+ 5D645FFF606762FF6A716CFF666D68FF6C736EFF848B86FFA0A7A4FF949B98FF
+ 8B928FFF848B88FF727976FF5E6562FF5B625FFF666D6AFF5F6663FF626966FF
+ 676E6BFF666D6AFF5D6461FF535A57FF555C59FF5D645FFF585F5AFF525954FF
+ 6B726DFF575E59FF4F5651FF666D68FF575E59FF515853FF585F5AFF5A615CFF
+ 5C635EFF5C635EFF5A615CFF59605BFF5A615CFF5B625DFF5E6560FF616863FF
+ 646B66FF686F6AFF6B726DFF717873FF787F7AFF7D847FFF828984FF838A85FF
+ 858C87FF888F8AFF8B928DFF8D948FFF8F9691FF909792FF929994FF919893FF
+ 909792FF8F9691FF8E9590FF8E9590FF8E9590FF8E9590FF99A09BFF8F9691FF
+ 828984FF79807BFF757C77FF707772FF676E69FF606762FF5B625BFF5B625BFF
+ 626962FF444B44FF373E37FF565D56FF616861FF616861FF616861FF4F564FFF
+ 4A514AFF596059FF5F665FFF515851FF434A43FF424640FF5C5F56FF52554CFF
+ 4A4D44FF494C43FF464940FF3E4138FF353A31FF33382FFF3E433AFF495147FF
+ 545C52FF565F55FF576056FF5B645AFF5E675DFF5F685EFF535E54FF6A756BFF
+ 707B71FF6E796FFF7D887EFF8F9A90FF98A399FF9FAAA0FFA3AEA4FF9BA69CFF
+ 939E94FF939E94FF9AA59BFF9FAAA0FF9EA99FFF9BA69CFF9DA7A1FF9CA6A0FF
+ 9CA6A0FFA0AAA4FFA4AEA8FFA5AFA9FFA2ACA6FF9FA9A3FF909A94FF858F89FF
+ 7E8882FF88928CFF9BA59FFFA7B1ABFFA3ADA7FF9AA49EFF9CA8A2FF96A49EFF
+ 96A49EFF9DABA5FFA8B4AEFFAAB6B0FFA5AFA9FF9DA7A1FF959F99FF69736DFF
+ 787F7AFF979E99FF454B46FF4F5550FF535954FF4C524DFF484E49FF4B514CFF
+ 4E544FFF4C524DFF494F4AFF5D635EFF676D68FF626863FF696F6AFF818782FF
+ 959B96FF99A09BFF9EA7A4FF98A3A0FF8F9A97FF909B98FF919C99FF7B8683FF
+ 65706DFF66716EFF798481FF808B88FF7F8A87FF7A8582FF7C8784FF838E8BFF
+ 7C8784FF6F7A77FF78817EFF79827FFF79827FFF7A8380FF7C8582FF7D8683FF
+ 7D8683FF7E8784FF7D8683FF808986FF5F6865FF939C99FF949D9AFF77807DFF
+ 6D7673FF6F7875FF696E6CFF606563FF5C615FFF5E6361FF5D6260FF575C5AFF
+ 575C5AFF5C615FFF616664FF6D7270FF5E6361FF6D7270FF444947FF434846FF
+ 4F5452FF555A58FF5D635EFF636964FF666C67FF626863FF606661FF616762FF
+ 616762FF5E645FFF5F6560FF5F6560FF606661FF626863FF646A65FF646A65FF
+ 626863FF606661FF5B605EFF757A78FF797E7CFF757A78FF7C8380FF747B78FF
+ 717875FF878E8BFF808986FF868F8CFF85908DFF85908DFF8F9A97FF9DA8A5FF
+ 9CAAA6FF93A29EFF93A29EFF8FA09CFF83928EFF7D8C88FF81908CFF798884FF
+ 6F7D79FF717F7BFF747F7CFF6F7A77FF6C7774FF6F7A77FF77807DFF7A8380FF
+ 767F7CFF717A77FF757E7BFF8E9794FF78817EFF67706DFF57605DFF262F2CFF
+ 59625FFF656E6BFF5F6865FF58615EFF515A57FF4E5754FF4D5653FF47504DFF
+ 39423FFF2D3633FF424944FF3D433EFF373D38FF3A403BFF494F4AFF595F5AFF
+ 5F6560FF5D635EFF555B56FF535954FF535954FF585E59FF5F6560FF636964FF
+ 626863FF5F6560FF5F665FFF6B726BFF6D746DFF636A63FF636A63FF6F766FFF
+ 737A73FF6B726BFF6C736CFF6D746DFF6B726BFF646B64FF626962FF666D66FF
+ 6B726BFF6D746DFF979D98FF838984FF939994FF838984FF484E49FF4D534EFF
+ 6B716CFF575D58FF595F5AFF565C57FF505651FF606661FF595F5AFF626863FF
+ 3F4540FF535954FF535954FF646B64FF5A615AFF6A716AFF616861FF686F68FF
+ 515851FF585F58FF6A716AFF5C635CFF656C65FF596059FF495049FF5F665FFF
+ 6A716AFF5E655EFF5D635EFF636964FF5E645FFF5C625DFF646A65FF656B66FF
+ 696F6AFF767C77FF737974FF7B817CFF828883FF838984FF858B86FF8B918CFF
+ 8F9590FF8F9590FF8F9590FF969C97FF828883FF777D78FF6F7570FF6E746FFF
+ 818782FF7C827DFF747A75FF8A908BFF676D68FF5C625DFF5D635EFF575D58FF
+ 686E69FF5B615CFF4E524CFF494E45FF62675EFF656A61FF3C4138FF32372EFF
+ 4A4F46FF50554CFF3C4138FF484D44FF3D4239FF61665DFF5D6259FF70756CFF
+ 363B32FF484D44FF72756CFF7A7B72FF77786FFF62635AFF464940FF35382FFF
+ 2F3229FF2D3229FF30352CFF384036FF535B51FF5B6359FF5F675DFF656D63FF
+ 5A6359FF5F685EFF6A7369FF636C62FF687167FF6E776DFF747D73FF8B948AFF
+ A4ADA3FFA8B1A7FFAAB3A9FFA0A99FFF959E94FF919A90FF959E94FF9BA49AFF
+ 9EA79DFF9EA79DFF979E99FF9FA6A1FF9BA29DFF9BA29DFFA7AEA9FFA9B0ABFF
+ A1A8A3FFA2A9A4FF838A85FF8E9590FF909792FF878E89FF888F8AFF969D98FF
+ 9EA5A0FF99A39DFF9EAAA4FF939F99FF909C96FF9CA8A2FFA9B3ADFFA7B1ABFF
+ 9FA9A3FF99A39DFF8E9590FF6E7570FF646A65FF6D736EFF575D58FF5B615CFF
+ 585E59FF4F5550FF484E49FF464C47FF414742FF393F3AFF444A45FF595F5AFF
+ 686E69FF676D68FF6D736EFF828883FF949A95FF99A09BFFA4ADAAFF9EA9A6FF
+ 949F9CFF909B98FF8D9895FF76817EFF626D6AFF65706DFF7A8582FF7C8784FF
+ 7B8683FF798481FF7A8582FF7D8885FF7C8784FF77827FFF7B8481FF7B8481FF
+ 7B8481FF7B8481FF7B8481FF7B8481FF7B8481FF7B8481FF77807DFF7D8683FF
+ 59625FFF858E8BFF87908DFF6F7875FF67706DFF656E6BFF696E6CFF606563FF
+ 5B605EFF5D6260FF5C615FFF575C5AFF565B59FF5A5F5DFF606563FF686D6BFF
+ 555A58FF606563FF404543FF464B49FF515654FF4E5351FF585E59FF606661FF
+ 656B66FF636964FF626863FF636964FF626863FF5F6560FF606661FF5F6560FF
+ 5E645FFF5D635EFF5C625DFF5D635EFF5E645FFF606661FF5C615FFF737876FF
+ 767B79FF747977FF7A817EFF737A77FF6E7572FF7F8683FF757E7BFF7C8582FF
+ 7D8885FF808B88FF8E9996FFA0ABA8FFA3B1ADFF9DABA7FF96A5A1FF92A39FFF
+ 879692FF7F8E8AFF81908CFF758480FF697773FF6C7A76FF6A7572FF67726FFF
+ 65706DFF67726FFF6E7774FF727B78FF717A77FF6F7875FF6D7673FF828B88FF
+ 7E8784FF79827FFF606966FF262F2CFF505956FF525B58FF5A6360FF535C59FF
+ 4C5552FF4B5451FF4D5653FF4D5653FF47504DFF434A47FF343A35FF353B36FF
+ 363C37FF3A403BFF454B46FF535954FF5E645FFF646A65FF5D635EFF5C625DFF
+ 5B615CFF5B615CFF5C625DFF5D635EFF5B615CFF5A605BFF5E655EFF565D56FF
+ 585F58FF636A63FF636A63FF5A615AFF5E655EFF6B726BFF5B625BFF5B625BFF
+ 5C635CFF5C635CFF5A615AFF585F58FF596059FF5D645DFF858B86FF7C827DFF
+ 777B76FF707671FF636762FF535954FF535752FF555B56FF60645FFF616762FF
+ 616560FF656B66FF5F635EFF686E69FF4F534EFF626863FF636A63FF6F766FFF
+ 666D66FF7A817AFF777E77FF757C75FF4D544DFF444B44FF5A615AFF535A53FF
+ 616861FF5D645DFF4F564FFF5E655EFF6F766FFF6D746DFF4D534EFF636964FF
+ 6A6E69FF656B66FF6E726DFF686E69FF575B56FF494F4AFF5D615CFF6A706BFF
+ 797D78FF797F7AFF777B76FF717772FF6E726DFF676D68FF5E625DFF666C67FF
+ 5C605BFF585E59FF535752FF4B514CFF5E625DFF5A605BFF666A65FF545A55FF
+ 4C504BFF4D534EFF5A5E59FF515752FF474B46FF565A54FF565B52FF50554CFF
+ 43483FFF3B4037FF3C4138FF373C33FF32372EFF373C33FF41463DFF4C5148FF
+ 3F443BFF53584FFF51564DFF7C8178FF4D5249FF4A4D44FF3F4037FF56574EFF
+ 72736AFF696A61FF676A61FF53564DFF494C43FF34372EFF33382FFF494E45FF
+ 3F443BFF454D43FF4D554BFF555D53FF6A7369FF5B645AFF5C655BFF5E675DFF
+ 656E64FF666F65FF656E64FF767F75FF8D968CFF969F95FFACB5ABFFA4ADA3FF
+ 9AA399FF969F95FF99A298FF9CA59BFF9CA59BFF9BA49AFF949B96FF9AA19CFF
+ 979E99FF99A09BFFA5ACA7FFA5ACA7FFA4ABA6FFAEB5B0FF979E99FF969D98FF
+ 959C97FF949B96FF909792FF8C938EFF8E9590FF939A95FF9DA7A1FF8D9993FF
+ 8D9993FF9FABA5FFABB5AFFFA2ACA6FF99A39DFF98A29CFF8B928DFF6C736EFF
+ 606661FF656B66FF636964FF646A65FF616762FF5B615CFF575D58FF545A55FF
+ 4C524DFF444A45FF3E443FFF555B56FF686E69FF6C726DFF717772FF828883FF
+ 959B96FF9EA5A0FFACB5B2FFA8B3B0FF9DA8A5FF95A09DFF8C9794FF727D7AFF
+ 606B68FF687370FF7E8986FF7A8582FF798481FF7A8582FF77827FFF747F7CFF
+ 76817EFF7B8683FF79827FFF79827FFF7A8380FF7B8481FF7B8481FF7B8481FF
+ 7A8380FF7A8380FF77807DFF818A87FF59625FFF7B8481FF7E8784FF727B78FF
+ 6C7572FF646D6AFF6B706EFF636866FF5D6260FF5C615FFF5A5F5DFF555A58FF
+ 535856FF535856FF676C6AFF6A6F6DFF535856FF555A58FF3F4442FF494E4CFF
+ 555A58FF474C4AFF50544FFF5A5E59FF636762FF656964FF656964FF666A65FF
+ 636762FF5E625DFF616560FF616560FF60645FFF5B5F5AFF575B56FF575B56FF
+ 5C605BFF616560FF5C615FFF6C716FFF6F7472FF707573FF767D7AFF707774FF
+ 6A716EFF737A77FF707976FF767F7CFF788380FF7C8784FF8D9895FFA3AEABFF
+ A9B7B3FFA5B3AFFF9AA9A5FF97A6A2FF8A9995FF83928EFF82908CFF73817DFF
+ 687370FF6D7875FF6A7572FF697471FF69726FFF69726FFF6D7471FF6F7673FF
+ 717875FF727976FF747D7AFF757E7BFF7B8481FF7C8582FF5C6562FF2C3532FF
+ 5F6865FF636C69FF555E5BFF4F5855FF49524FFF47504DFF4A5350FF4E5754FF
+ 4F5855FF515855FF454B46FF4B4F4AFF4F534EFF4E524DFF4C504BFF4F534EFF
+ 595D58FF636762FF5E625DFF5F635EFF5E625DFF5B5F5AFF585C57FF565A55FF
+ 575B56FF585C57FF51554FFF4A4E48FF4C504AFF575B55FF575B55FF4E524CFF
+ 51554FFF5D615BFF595D57FF545852FF555953FF595D57FF535751FF474B45FF
+ 434741FF484C46FF757974FF828681FF696A66FF545853FF5B5C58FF444843FF
+ 51524EFF929691FF636460FF6A6E69FF6D6E6AFF636762FF5F605CFF6C706BFF
+ 5D5E5AFF6E726DFF666A64FF676B65FF575B55FF676B65FF747872FF7B7F79FF
+ 5F635DFF575B55FF5F635DFF4F534DFF4F534DFF595D57FF595D57FF5F635DFF
+ 666A64FF5E625CFF5C605BFF6B6F6AFF6E6F6BFF646863FF60615DFF545853FF
+ 575854FF646863FF454642FF525651FF61625EFF60645FFF5C5D59FF535752FF
+ 4D4E4AFF444843FF4E4F4BFF585C57FF565753FF5D615CFF585955FF494D48FF
+ 595A56FF595D58FF494A46FF474B46FF575854FF383C37FF42433FFF595D58FF
+ 41423EFF4D4F49FF3E4138FF565A4FFF45493EFF34382DFF41453AFF393D32FF
+ 2D3126FF43473CFF606459FF494D42FF33372CFF41453AFF383C31FF65695EFF
+ 484C41FF42463BFF3A3B32FF47453DFF56574EFF484940FF515249FF494A41FF
+ 4E5148FF44473EFF45483FFF555A51FF32372EFF4B5047FF4F574DFF40483EFF
+ 666E64FF545C52FF5C655BFF616A60FF656E64FF656E64FF6C756BFF7E877DFF
+ 90998FFF98A197FFAAB3A9FFA4ADA3FF9EA79DFF9CA59BFF9DA69CFF9EA79DFF
+ 9BA49AFF98A197FF959C97FF969D98FF929994FF979E99FFA1A8A3FF9EA5A0FF
+ A0A7A2FFB2B9B4FFA9B0ABFF9DA49FFF99A09BFF9DA49FFF959C97FF858C87FF
+ 828984FF8D948FFF88928CFF7A847EFF7C8680FF929C96FF9FA9A3FF959F99FF
+ 8B928DFF89908BFF757B76FF585E59FF4C504BFF4A4E49FF5D635EFF5F6560FF
+ 606661FF5E645FFF5B615CFF575D58FF535954FF4E544FFF3E443FFF515752FF
+ 656B66FF6D736EFF737974FF818782FF989E99FFA8AFAAFFAEB7B4FFADB8B5FF
+ A5B0ADFF9DA8A5FF919C99FF75807DFF646F6CFF6E7976FF838E8BFF7D8885FF
+ 7D8885FF818C89FF7B8683FF707B78FF727D7AFF7C8784FF767F7CFF78817EFF
+ 79827FFF7B8481FF7C8582FF7C8582FF7B8481FF7B8481FF6F7875FF7B8481FF
+ 4D5653FF666F6CFF69726FFF67706DFF666F6CFF5A6360FF646967FF5F6462FF
+ 5B605EFF5C615FFF5F6462FF5F6462FF5E6361FF5C615FFF454A48FF4A4F4DFF
+ 393E3CFF353A38FF272C2AFF323735FF474C4AFF383D3BFF474B46FF535752FF
+ 5E625DFF626661FF636762FF646863FF616560FF5C605BFF5D615CFF60645FFF
+ 616560FF5C605BFF565A55FF555954FF5A5E59FF60645FFF5A5F5DFF636866FF
+ 696E6CFF6E7371FF727976FF707774FF6B726FFF6C7370FF757E7BFF7A8380FF
+ 7B8683FF7F8A87FF8F9A97FFA5B0ADFFADBBB7FFA9B7B3FF9FAEAAFF9BAAA6FF
+ 8D9C98FF859490FF83918DFF73817DFF6C7774FF77827FFF6E7976FF6E7976FF
+ 6E7774FF6C7572FF6B726FFF6B726FFF6E7572FF717875FF767F7CFF656E6BFF
+ 747D7AFF767F7CFF515A57FF28312EFF5B6461FF5F6865FF535C59FF4F5855FF
+ 4A5350FF464F4CFF444D4AFF464F4CFF49524FFF4D5451FF515752FF555954FF
+ 575B56FF555954FF4D514CFF484C47FF4C504BFF555954FF535752FF555954FF
+ 565A55FF545853FF515550FF515550FF565A55FF5B5F5AFF484C46FF555953FF
+ 585C56FF4E524CFF4D514BFF585C56FF595D57FF51554FFF5C605AFF555953FF
+ 565A54FF5D615BFF575B55FF4A4E48FF474B45FF4F534DFF4B4C48FF6E6F6BFF
+ 6D6E6AFF676864FF6C6D69FF535450FF535450FF898A86FF5C5D59FF656662FF
+ 666763FF545551FF575854FF696A66FF5E5F5BFF6A6C66FF747872FF71756FFF
+ 5E625CFF5B5F59FF5F635DFF5C605AFF494D47FF464A44FF585C56FF50544EFF
+ 494D47FF595D57FF5B5F59FF535751FF5C605AFF5B5F59FF5A5B57FF5C5D59FF
+ 686965FF7F807CFF858682FF6A6B67FF5A5B57FF6B6C68FF555652FF5A5B57FF
+ 5C5D59FF5A5B57FF5A5B57FF5C5D59FF5A5B57FF545551FF4B4C48FF575854FF
+ 565753FF62635FFF5A5B57FF484945FF555652FF585955FF454642FF575854FF
+ 656662FF4A4B47FF444541FF50514DFF464743FF565852FF30332AFF4E5247FF
+ 53574CFF484C41FF474B40FF3E4237FF363A2FFF41453AFF81857AFF4A4E43FF
+ 3E4237FF5E6257FF4B4F44FF54584DFF3E4237FF474B40FF5F5D55FF535149FF
+ 3E3F36FF3A3B32FF2E2F26FF37382FFF484B42FF63665DFF4E5148FF4E5148FF
+ 373C33FF595E55FF555D53FF31392FFF474F45FF4B5349FF4D554BFF525B51FF
+ 4E574DFF4F584EFF646D63FF7C857BFF8A9389FF919A90FFA0A99FFF9EA79DFF
+ 9CA59BFF9CA59BFF9DA69CFF9BA49AFF97A096FF939C92FF939A95FF8E9590FF
+ 878E89FF8E9590FF99A09BFF939A95FF919893FFA2A9A4FFA2A9A4FF989F9AFF
+ 909792FF8D948FFF868D88FF7C837EFF7B827DFF818883FF727C76FF6C7670FF
+ 6D7771FF7A847EFF8C9690FF8F9993FF808782FF6C736EFF636964FF505651FF
+ 4C504BFF4E524DFF626863FF656B66FF676D68FF666C67FF606661FF5A605BFF
+ 585E59FF595F5AFF444A45FF4E544FFF5C625DFF666C67FF6D736EFF7B817CFF
+ 959B96FFACB3AEFFA7B0ADFFA9B4B1FFA6B1AEFFA0ABA8FF95A09DFF798481FF
+ 6A7572FF75807DFF848F8CFF818C89FF848F8CFF8B9693FF86918EFF7A8582FF
+ 7A8582FF838E8BFF7D8683FF7E8784FF808986FF808986FF7F8885FF7D8683FF
+ 7A8380FF78817EFF77807DFF808986FF4A5350FF5A6360FF5C6562FF5F6865FF
+ 616A67FF545D5AFF636866FF5C615FFF525755FF494E4CFF444947FF3F4442FF
+ 363B39FF2D3230FF343937FF3C413FFF373C3AFF303533FF262B29FF292E2CFF
+ 494E4CFF404543FF454944FF515550FF5B5F5AFF60645FFF626661FF646863FF
+ 616560FF5D615CFF575B56FF5D615CFF616560FF5E625DFF585C57FF555954FF
+ 585C57FF5D615CFF5B605EFF5D6260FF676C6AFF707573FF717875FF737A77FF
+ 737A77FF6F7673FF78817EFF7E8784FF7F8A87FF848F8CFF95A09DFFACB7B4FF
+ B4C2BEFFB1BFBBFFA6B4B0FFA0AEAAFF919F9BFF8A9894FF85938FFF768480FF
+ 75807DFF889390FF6C7572FF6C7572FF6D7471FF6B726FFF69706DFF69706DFF
+ 6B726FFF6E7572FF6E7774FF5D6663FF77807DFF77807DFF535C59FF27302DFF
+ 434C49FF3C4542FF4C5552FF4D5653FF4D5653FF48514EFF424B48FF3F4845FF
+ 414A47FF464D4AFF434944FF424641FF444843FF4A4E49FF4A4E49FF454944FF
+ 454944FF4A4E49FF50544FFF525651FF535752FF515550FF50544FFF535752FF
+ 5A5E59FF616560FF565A54FF63685FFF666B62FF5C6158FF5A5F56FF63685FFF
+ 63685FFF5A5F56FF62675EFF5D6259FF5E635AFF646960FF646960FF5F645BFF
+ 63685FFF6D7269FF5D5F59FF61615BFF61615BFF60605AFF63635DFF65655FFF
+ 62625CFF5D5D57FF595953FF5A5A54FF5C5C56FF464640FF55554FFF64645EFF
+ 5B5B55FF5F615BFF646862FF70756CFF747970FF6C7168FF6B7067FF585D54FF
+ 4C5148FF4D5249FF484D44FF555A51FF4D5249FF5C6158FF5A5F56FF494E45FF
+ 5F645BFF6B6F69FF636460FF61605CFF5E5D59FF706F6BFF8A8985FF858480FF
+ 6D6C68FF63625EFF656460FF61605CFF5B5A56FF5A5955FF61605CFF696864FF
+ 676662FF5F5E5AFF565551FF61605CFF5C5B57FF64635FFF5A5955FF4A4945FF
+ 565551FF565551FF454440FF3C3B37FF34332FFF5B5A56FF5B5A56FF262521FF
+ 282723FF464640FF4A4D44FF44483DFF505449FF55594EFF484C41FF474B40FF
+ 41453AFF272B20FF696D62FF404439FF4B4F44FF6C7065FF5D6156FF5E6257FF
+ 4E5247FF5B5F54FF66645CFF58564EFF413F37FF65635BFF42433AFF494A41FF
+ 4B4C43FF7E7F76FF42453CFF40433AFF464B42FF4A4F46FF42473EFF3A3F36FF
+ 42473EFF555D53FF424A40FF586056FF545C52FF485046FF555D53FF687066FF
+ 7B8379FF90988EFF979F95FF979F95FF979F95FF979F95FF959D93FF8F978DFF
+ 889086FF838B81FF818782FF7C827DFF747A75FF7C827DFF8A908BFF858B86FF
+ 7E847FFF878D88FF8F9590FF8C928DFF808681FF6F7570FF6A706BFF707671FF
+ 747A75FF6F7671FF727C76FF757F79FF6F7973FF6C7670FF818883FF919893FF
+ 7C827DFF555B56FF4D534EFF464C47FF515550FF5C605BFF575D58FF555B56FF
+ 575D58FF5A605BFF595F5AFF555B56FF555B56FF585E59FF4A504BFF494F4AFF
+ 4F5550FF595F5AFF616762FF6C726DFF868C87FF9FA6A1FF99A29FFF9BA6A3FF
+ 98A3A0FF96A19EFF8F9A97FF77827FFF6B7673FF77827FFF818C89FF828D8AFF
+ 87928FFF8C9794FF8C9794FF87928FFF85908DFF889390FF858E8BFF858E8BFF
+ 858E8BFF838C89FF7F8885FF7A8380FF757E7BFF717A77FF757E7BFF767F7CFF
+ 39423FFF47504DFF48514EFF4A5350FF4F5855FF464F4CFF343937FF363B39FF
+ 383D3BFF3E4341FF4C514FFF595E5CFF5B605EFF565B59FF525755FF555A58FF
+ 565B59FF4A4F4DFF3B403EFF292E2CFF494E4CFF464B49FF484C47FF515550FF
+ 595D58FF5B5F5AFF5D615CFF60645FFF60645FFF5D615CFF555954FF595D58FF
+ 5C605BFF5B5F5AFF565A55FF525651FF525651FF545853FF5D6260FF5A5F5DFF
+ 676C6AFF717674FF6C7370FF727976FF787F7CFF717875FF747D7AFF7C8582FF
+ 808B88FF87928FFF9BA6A3FFB4BFBCFFBDCBC7FFBAC8C4FFACBAB6FFA6B4B0FF
+ 98A6A2FF919F9BFF8A9894FF788682FF798481FF909B98FF6A7370FF6A7370FF
+ 6C7370FF6D7471FF6E7572FF6E7572FF6E7572FF6E7572FF757E7BFF646D6AFF
+ 77807DFF6C7572FF5B6461FF424B48FF58615EFF555E5BFF444D4AFF4B5451FF
+ 505956FF4D5653FF454E4BFF404946FF444D4AFF4B524FFF4B514CFF474B46FF
+ 484C47FF535752FF575B56FF4F534EFF4A4E49FF4C504BFF595D58FF595D58FF
+ 575B56FF565A55FF575B56FF5C605BFF636762FF686C66FF676B65FF5F645BFF
+ 62675EFF6B7067FF686D64FF5B6057FF595E55FF646960FF72776EFF70756CFF
+ 6D7269FF696E65FF676C63FF696E65FF6E736AFF75786FFF7F7F79FF6E6E68FF
+ 696963FF595953FF43433DFF55554FFF6C6C66FF5F5F59FF5A5A54FF53534DFF
+ 595953FF45453FFF5B5B55FF60605AFF585852FF5E5E58FF61645BFF6E736AFF
+ 7B8077FF6F746BFF777C73FF696E65FF71766DFF7E837AFF5D6259FF62675EFF
+ 3D4239FF4B5047FF5E635AFF51564DFF5B6057FF53564DFF5A5955FF767571FF
+ 6F6E6AFF54534FFF5A5955FF6F6E6AFF71706CFF696864FF64635FFF62615DFF
+ 5F5E5AFF605F5BFF686763FF6D6C68FF656460FF595854FF64635FFF706F6BFF
+ 666561FF64635FFF5C5B57FF53524EFF5D5C58FF555450FF605F5BFF595854FF
+ 41403CFF72716DFF84837FFF53524EFF4C4B47FF44443EFF52554CFF42463BFF
+ 575B50FF63675CFF494D42FF45493EFF4F5348FF3C4035FF53574CFF484C41FF
+ 4F5348FF4B4F44FF4C5045FF707469FF7C8075FF8C8D83FF605E56FF535149FF
+ 46443CFF75736BFF56574EFF52534AFF494A41FF76776EFF363930FF474A41FF
+ 585D54FF3D4239FF373C33FF545950FF60655CFF6F746BFF424A40FF6B7369FF
+ 6B7369FF4E564CFF485046FF4E564CFF636B61FF868E84FF8A9288FF8B9389FF
+ 8C948AFF8A9288FF858D83FF7C847AFF737B71FF6D756BFF686E69FF6B716CFF
+ 656B66FF676D68FF757B76FF767C77FF707671FF747A75FF888E89FF888E89FF
+ 787E79FF626863FF5F6560FF6D736EFF737974FF6B726DFF787F7AFF7B857FFF
+ 727C76FF66706AFF737A75FF828984FF6F7570FF494F4AFF4A504BFF4B514CFF
+ 5D615CFF666A65FF4E544FFF424843FF3B413CFF424843FF4A504BFF494F4AFF
+ 454B46FF444A45FF4C524DFF434944FF424843FF4C524DFF535954FF595F5AFF
+ 6E746FFF858C87FF8B9491FF8A9592FF838E8BFF808B88FF7E8986FF6D7875FF
+ 65706DFF737E7BFF7E8986FF818C89FF818C89FF808B88FF818C89FF848F8CFF
+ 828D8AFF7D8885FF7C8582FF7D8683FF7D8683FF7C8582FF78817EFF737C79FF
+ 6D7673FF6A7370FF626B68FF5C6562FF1C2522FF303936FF343D3AFF363F3CFF
+ 404946FF3F4845FF767B79FF737876FF6B706EFF646967FF646967FF666B69FF
+ 5D6260FF4F5452FF5A5F5DFF555A58FF5A5F5DFF505553FF414644FF1C211FFF
+ 3A3F3DFF393E3CFF464A45FF4F504CFF535450FF52534FFF535450FF585955FF
+ 5B5C58FF5A5B57FF595A56FF585955FF565753FF52534FFF4F504CFF4C4D49FF
+ 4A4B47FF474B46FF595E5CFF535856FF626765FF6B706EFF5F6663FF666D6AFF
+ 737A77FF6B726FFF6E7774FF77807DFF7E8986FF889390FF9DA8A5FFB6C1BEFF
+ BFCDC9FFBBC9C5FFB2C0BCFFACBAB6FFA1AFABFF9AA8A4FF919C99FF788380FF
+ 747F7CFF8A9592FF6E7774FF6C7572FF6C7370FF6E7572FF707774FF6E7572FF
+ 6A6F6DFF646B68FF6A7370FF5F6865FF67706DFF515A57FF5A6360FF5B6461FF
+ 717A77FF79827FFF464F4CFF4F5855FF57605DFF545D5AFF4B5451FF48514EFF
+ 4E5754FF59605DFF656964FF5F605CFF61625EFF6B6C68FF6A6B67FF5D5E5AFF
+ 545551FF555652FF646561FF60615DFF5C5D59FF5D5E5AFF62635FFF696A66FF
+ 70716DFF73756FFF6A6C66FF62655CFF64675EFF6D7067FF686B62FF595C53FF
+ 575A51FF60635AFF74776EFF7A7D74FF75786FFF676A61FF62655CFF6A6D64FF
+ 6D7067FF696C63FF5C5C56FF64645EFF7B7B75FF7B7B75FF5E5E58FF54544EFF
+ 5F5F59FF61615BFF5D5D57FF53534DFF61615BFF4F4F49FF666660FF5D5D57FF
+ 585852FF64645EFF7B7E75FF7B7E75FF7B7E75FF63665DFF71746BFF64675EFF
+ 72756CFF7D8077FF75786FFF7D8077FF45483FFF494C43FF60635AFF54574EFF
+ 5B5E55FF464940FF3D3C38FF656460FF777672FF6B6A66FF656460FF62615DFF
+ 5D5C58FF5D5C58FF686763FF6D6C68FF6F6E6AFF6E6D69FF71706CFF73726EFF
+ 6E6D69FF676662FF61605CFF72716DFF64635FFF5C5B57FF585753FF595854FF
+ 61605CFF4D4C48FF595854FF63625EFF53524EFF504F4BFF61605CFF63625EFF
+ 4F4E4AFF373731FF4D4E44FF4D4F43FF606256FF6F7165FF616357FF4E5044FF
+ 505246FF5B5D51FF626458FF636559FF606256FF47493DFF54564AFF77796DFF
+ 838579FF97988EFF65635BFF524F47FF504E46FF5C5A52FF605E56FF4F4D45FF
+ 4F5047FF5D5E55FF363930FF51544BFF60635AFF676A61FF62675EFF60655CFF
+ 6D7269FF6E736AFF3E463CFF656D63FF5C645AFF3F473DFF434B41FF464E44FF
+ 4A5248FF636B61FF777F75FF798177FF7B8379FF7A8278FF757D73FF6D756BFF
+ 646C62FF5F675DFF5C625DFF6D736EFF696F6AFF5D635EFF636964FF6A706BFF
+ 6B716CFF6F7570FF868C87FF7E847FFF707671FF666C67FF666C67FF6E746FFF
+ 747A75FF757C77FF737A75FF707A74FF6D746FFF686F6AFF69706BFF686F6AFF
+ 606661FF545A55FF6A6E69FF6E726DFF7C807BFF7F837EFF7D817CFF636A63FF
+ 545853FF565D56FF626661FF5D645DFF525651FF474E47FF4E524DFF3E453EFF
+ 3C403BFF444B44FF4B4F4AFF4B524BFF5D615CFF717772FF858C87FF7F8885FF
+ 747D7AFF717A77FF717A77FF656E6BFF606966FF707976FF808986FF838C89FF
+ 7D8683FF737C79FF747D7AFF7C8582FF79827FFF6D7673FF6E7572FF707774FF
+ 727976FF737A77FF727976FF6E7572FF6A716EFF686F6CFF737A77FF69706DFF
+ 2A312EFF444B48FF4E5552FF525956FF616865FF666D6AFF606563FF606563FF
+ 5C615FFF5B605EFF636866FF6B706EFF666B69FF5A5F5DFF535856FF494E4CFF
+ 545957FF555A58FF505553FF282D2BFF474C4AFF494E4CFF444541FF494A46FF
+ 4A4B47FF474844FF474844FF4D4E4AFF52534FFF52534FFF5C5D59FF575854FF
+ 4F504CFF494A46FF464743FF444541FF42433FFF3E423DFF535856FF4B504EFF
+ 5B605EFF626765FF525956FF59605DFF69706DFF626966FF6C7572FF767F7CFF
+ 7F8885FF87928FFF9EA7A4FFB4BFBCFFBDC8C5FFB7C5C1FFB5C3BFFFB0BFBBFF
+ A8B6B2FFA2B0ACFF93A19DFF76817EFF6D7875FF828D8AFF6F7875FF6B7471FF
+ 69706DFF686F6CFF69706DFF646B68FF5B605EFF515654FF484F4AFF4A514CFF
+ 565D58FF404742FF585F5AFF5B625DFF616863FF646B66FF4F5651FF59605BFF
+ 606762FF5C635EFF525954FF4F5651FF585F5AFF646A65FF646863FF61635DFF
+ 656662FF70726CFF6D6E6AFF5D5F59FF565753FF5A5C56FF646561FF5F615BFF
+ 5B5C58FF5D5F59FF666763FF71736DFF777874FF7A7C76FF666960FF72756CFF
+ 74776EFF676A61FF62655CFF676A61FF63665DFF585B52FF5E6158FF6C6F66FF
+ 6B6E65FF5D6057FF5C5F56FF6C6F66FF72756CFF696C63FF55554FFF55554FFF
+ 595953FF676761FF6B6B65FF5D5D57FF5F5F59FF75756FFF5E5E58FF54544EFF
+ 6A6A64FF595953FF6D6D67FF5A5A54FF585852FF6B6B65FF5E6158FF5D6057FF
+ 65685FFF595C53FF787B72FF6A6D64FF6E7168FF6B6E65FF63665DFF94978EFF
+ 71746BFF63665DFF585B52FF42453CFF676A61FF71746BFF686862FF4F4F49FF
+ 42413DFF5D5D57FF787773FF6C6C66FF5F5E5AFF6C6C66FF565551FF5E5E58FF
+ 62615DFF5D5D57FF5B5A56FF5F5F59FF64635FFF666660FF6A6965FF7F7F79FF
+ 72716DFF676761FF676662FF6F6F69FF74736FFF585852FF83827EFF75756FFF
+ 797874FF60605AFF5F5E5AFF666660FF54534FFF6D6D67FF5A5B51FF595B4FFF
+ 515248FF686A5EFF83847AFF626458FF3C3D33FF47493DFF525349FF54564AFF
+ 5C5D53FF55574BFF63645AFF56584CFF3F4036FF53544AFF66645CFF525048FF
+ 64625AFF4D4E45FF78766EFF5A5B52FF66675EFF505148FF373A31FF4E5148FF
+ 595C53FFA0A39AFF9A9F96FF545950FF5B6057FF565B52FF52574EFF666E64FF
+ 50554CFF3C443AFF5E635AFF676F65FF575C53FF565E54FF676C63FF697167FF
+ 6F746BFF6F776DFF6E736AFF666E64FF63685FFF5D655BFF626660FF798079FF
+ 787C76FF5E655EFF5C605AFF646B64FF6D716BFF717871FF7F837DFF6C736CFF
+ 646862FF676E67FF6D716BFF6A716AFF727670FF7D847DFF6E766FFF656D66FF
+ 686F68FF6F766FFF697069FF5A615AFF5C635CFF6D716BFF6F736DFF747872FF
+ 838781FF868A84FF7A7C76FF878C83FF646660FF4B5047FF767872FF70756CFF
+ 5C5E58FF6B7067FF5F615BFF5E635AFF5F615BFF5D6259FF8C8E88FF676C63FF
+ 5C5E58FF6C706AFF727671FF767A75FF90948FFF979B96FF545853FF616560FF
+ 767A75FF6D716CFF6A6E69FF676B66FF6C706BFF6C706BFF6A6E69FF737772FF
+ 797D78FF70746FFF676B66FF646863FF8C908BFF676B66FF636762FF656964FF
+ 666A65FF5F635EFF656964FF4D514CFF414540FF4E524DFF5A5E59FF575B56FF
+ 545853FF595D58FF636964FF666C67FF666C67FF656B66FF6A706BFF707671FF
+ 717772FF6D736EFF565C57FF575D58FF5F6560FF5C625DFF555B56FF242A25FF
+ 3B413CFF434944FF484945FF4B4C48FF464743FF494A46FF52534FFF4A4B47FF
+ 3F403CFF444541FF51524EFF5A5B57FF5A5B57FF454642FF383935FF363733FF
+ 454642FF4A4E49FF525853FF5A615CFF606762FF59605BFF535A55FF585F5AFF
+ 606762FF676E69FF6E7570FF6A716CFF727974FF89938DFFA5ACA7FFB3BDB7FF
+ BAC4BEFFBDC9C3FFB2C2BBFFABBDB6FFA8B8B1FFA0B0A9FF8F9F98FF7C8A84FF
+ 6E7C76FF6B7973FF727E78FF49554FFF848E88FF36403AFF555C57FF49504BFF
+ 666C67FF6E746FFF454943FF444842FF434741FF4C504AFF646862FF767A74FF
+ 6C706AFF555953FF464A44FF4C504AFF525650FF565A54FF575B55FF565A54FF
+ 535751FF50544EFF7C7E78FF6B6E65FF5F615BFF74776EFF5F615BFF787B72FF
+ 6E706AFF5A5D54FF666862FF7D8077FF62645EFF52554CFF5A5C56FF5D6057FF
+ 72746EFF80837AFF65685FFF6C6F66FF5C5F56FF73766DFF50534AFF595C53FF
+ 72756CFF72756CFF676A61FF70736AFF696C63FF666960FF65685FFF64675EFF
+ 686B62FF5C5F56FF6C6F66FF686B62FF565950FF62655CFF5E6158FF71746BFF
+ 64675EFF5F6259FF8F9289FF4E5148FF575A51FF71746BFF787B72FF70736AFF
+ 64675EFF83867DFF696C63FF5A5D54FF484B42FF6B6E65FF80837AFF64675EFF
+ 60635AFF6B6E65FF5E6158FF686B62FF75786FFF797C73FF71746BFF696C63FF
+ 6F7269FF7A7D74FF7F8279FF61645BFF464842FF686B62FF6E706AFF575A51FF
+ 60625CFF52554CFF5B5D57FF4E5148FF6F716BFF7D8077FF70726CFF84877EFF
+ 52544EFF53564DFF686A64FF7C7F76FF686A64FF6C6F66FF747670FF7C7F76FF
+ 959791FF81847BFF5B5D57FF55584FFF52544EFF585B52FF646660FF686B62FF
+ 63655FFF5B5E55FF55584FFF72766BFF63665DFF5C6055FF7D8077FF777B70FF
+ 5F6259FF6F7368FF666960FF5E6257FF474A41FF5E6257FF64675EFF81857AFF
+ 6D7067FF63665DFF5D5E55FF6C6D64FF72736AFF61645BFF707168FF71746BFF
+ 5C5F56FF6E7168FF50534AFF72756CFF696C63FF5D6057FF5D6057FF5E6158FF
+ 696C63FF62655CFF6A6D64FF5C6158FF63665DFF6C7168FF6D7067FF6D7269FF
+ 71746BFF686D64FF73766DFF676C63FF6E7168FF72776EFF696C63FF656A61FF
+ 71746BFF72776EFF6C6F66FF72776EFF6C6F66FF747970FF6B6E65FF8C9188FF
+ 80837AFF656A61FF676A61FF51564DFF565950FF72776EFF60635AFF494E45FF
+ 6E7168FF7F847BFF696E65FF60655CFF676C63FF6F746BFF63685FFF5B6057FF
+ 61665DFF65685FFF71746BFF61645BFF73766DFF767970FF72756CFF6A6D64FF
+ 595C53FF5E6158FF5F6259FF6A6D64FF63665DFF63665DFF54574EFF64675EFF
+ 65685FFF63665DFF7D8077FF6D7067FF71746BFF94978EFF52534FFF6B6C68FF
+ B3B4B0FFE4E5E1FF989995FF72736FFF696A66FF676864FF686965FF6F706CFF
+ 737470FF6F706CFF6B6C68FF6D6E6AFF6E6F6BFF6D6E6AFF666763FF62635FFF
+ 7F807CFF6A6B67FF656662FF70716DFF676864FF5D5E5AFF696A66FF545551FF
+ 4A4B47FF565753FF62635FFF60615DFF5C5D59FF5D5E5AFF585C57FF5D635EFF
+ 626863FF636964FF676D68FF6C726DFF6E746FFF6B716CFF737974FF5E645FFF
+ 4F5550FF5C625DFF5C625DFF333934FF333934FF333732FF454642FF4A4B47FF
+ 454642FF41423EFF3E3F3BFF343531FF393A36FF50514DFF4F504CFF595A56FF
+ 5B5C58FF4C4D49FF40413DFF40413DFF494A46FF4D514CFF515752FF5A615CFF
+ 565D58FF585F5AFF59605BFF5C635EFF69706BFF666D68FF69706BFF6B726DFF
+ 737A75FF858C87FF9DA49FFFB0B7B2FFBAC1BCFFBBC5BFFFB3C1BBFF9FB1AAFF
+ 90A099FF86968FFF7E8E87FF74827CFF6A7872FF68746EFF49554FFF3D4741FF
+ 6A746EFF555C57FF585F5AFF545A55FF565C57FF5E625CFF555751FF595C53FF
+ 5F6259FF65685FFF6E7168FF72756CFF6B6E65FF5F6259FF575A51FF6E7168FF
+ 75786FFF676A61FF65685FFF71746BFF6E7168FF5D6057FF686B62FF696C63FF
+ 5E6158FF65685FFF666960FF9B9E95FF91948BFF63665DFF6E7168FF7D8077FF
+ 6B6E65FF676A61FF70736AFF75786FFF84877EFF81847BFF666960FF565950FF
+ 71746BFF60635AFF696C63FF71746BFF52554CFF60635AFF63665DFF767970FF
+ 7C7F76FF74776EFF61645BFF585B52FF666960FF6F7269FF6A6D64FF686B62FF
+ 585B52FF64675EFF5F6259FF71746BFF65685FFF63665DFF52554CFF595C53FF
+ 7D8077FF767970FF6B6E65FF767970FF6F7269FF75786FFF80837AFF85887FFF
+ 666960FF565950FF54574EFF54574EFF65685FFF65685FFF777A71FF80837AFF
+ 82857CFF75786FFF686B62FF64675EFF666960FF676A61FF686B62FF5E6158FF
+ 4F5249FF686B62FF6D7067FF676A61FF777A71FF666960FF5D6057FF5A5D54FF
+ 5E6158FF6C6F66FF6B6E65FF7F8279FF64675EFF6C6F66FF65685FFF65685FFF
+ 5B5E55FF62655CFF676A61FF65685FFF6D7067FF686B62FF73766DFF6A6D64FF
+ 60635AFF60635AFF686B62FF70736AFF73766DFF73766DFF6E7168FF7F8279FF
+ 6E7168FF60635AFF6D7067FF676A61FF595C53FF65685FFF5B5E55FF6D7067FF
+ 686B62FF70736AFF64675EFF787B72FF6D7067FF686B62FF64675EFF6E7168FF
+ 75786FFF6B6E65FF7C7F76FF82857CFF6D7067FF797C73FF65685FFF6E7168FF
+ 60635AFF6C6F66FF72756CFF61645BFF65685FFF6B6E65FF82857CFF72756CFF
+ 70736AFF74776EFF71746BFF75786FFF7E8178FF7B7E75FF7A7D74FF6E7168FF
+ 71746BFF74776EFF696C63FF65685FFF6B6E65FF6B6E65FF686C61FF6A6E63FF
+ 676B60FF7B7F74FF71756AFF808479FF6D7166FF5F6358FF676B60FF696D62FF
+ 676B60FF72766BFF65695EFF595D52FF6E7267FF71756AFF6E7267FF6D7166FF
+ 75796EFF767A6FFF6A6E63FF6A6E63FF71756AFF6D7166FF8B8F84FF7C8075FF
+ 84887DFF777B70FF878A81FF6B6E65FF6C6F66FF8C8F86FF5C5F56FF6B6E65FF
+ 65685FFF52554CFF60635AFF64675EFF474A41FF464940FF585B52FF64675EFF
+ 5B5E55FF6C6F66FF646561FF5B5C58FF767773FF9B9C98FF6B6C68FF656662FF
+ 686965FF696A66FF4A4B47FF5D5E5AFF636460FF61625EFF676864FF6A6B67FF
+ 6D6E6AFF767773FF747571FF656662FF60615DFF555652FF4B4C48FF676864FF
+ 646561FF636460FF5D5E5AFF52534FFF4F504CFF5B5C58FF666763FF656662FF
+ 636460FF656662FF626661FF676B66FF666A65FF5F635EFF5A5E59FF5D615CFF
+ 60645FFF616560FF636762FF5A5E59FF484C47FF5D615CFF4A4E49FF2C302BFF
+ 292D28FF313530FF333430FF3C3D39FF434440FF4C4D49FF4D4E4AFF3D3E3AFF
+ 3B3C38FF50514DFF4B4C48FF545551FF52534FFF4C4D49FF3E3F3BFF40413DFF
+ 40413DFF424641FF4F5550FF5B625DFF4B524DFF585F5AFF5F6661FF5A615CFF
+ 6A716CFF59605BFF606762FF69706BFF707772FF777E79FF89908BFFA1A8A3FF
+ ADB4AFFFAAB4AEFFA3B1ABFF91A19AFF84928CFF82908AFF7F8D87FF727E78FF
+ 5A6660FF4C5650FF4B554FFF535A55FF636A65FF828883FF6A706BFF737772FF
+ 6A6E69FF747872FF61635DFF676A61FF72756CFF7B7E75FF797C73FF71746BFF
+ 6F7269FF72756CFF5D6057FF6F7269FF777A71FF70736AFF6E7168FF74776EFF
+ 71746BFF65685FFF7B7E75FF71746BFF6E7168FF797C73FF686B62FF74776EFF
+ 787B72FF7C7F76FF767970FF797C73FF6E7168FF70736AFF6F7269FF70736AFF
+ 787B72FF5E6158FF64675EFF5F6259FF6C6F66FF52554CFF8F9289FF878A81FF
+ 5F6259FF6A6D64FF676A61FF6C6F66FF767970FF797C73FF70736AFF62655CFF
+ 595C53FF5A5D54FF54574EFF61645BFF676A61FF80837AFF767970FF74776EFF
+ 53564DFF45483FFF777A71FF8F9289FF9A9D94FF6B6E65FF4E5148FF61645BFF
+ 696C63FF6F7269FF91948BFF80837AFF6C6F66FF82857CFF878A81FF686B62FF
+ 585B52FF494C43FF5A5D54FF71746BFF83867DFF83867DFF7C7F76FF74776EFF
+ 64675EFF53564DFF5C5F56FF63665DFF65685FFF72756CFF71746BFF72756CFF
+ 7C7F76FF676A61FF797C73FF878A81FF63665DFF6B6E65FF6C6F66FF6E7168FF
+ 5F6259FF64675EFF72756CFF64675EFF6F7269FF797C73FF7A7D74FF70736AFF
+ 61645BFF6B6E65FF7B7E75FF74776EFF6C6F66FF6A6D64FF6E7168FF767970FF
+ 7E8178FF83867DFF686B62FF70736AFF70736AFF6C6F66FF6F7269FF73766DFF
+ 74776EFF75786FFF686B62FF70736AFF666960FF696C63FF696C63FF80837AFF
+ 73766DFF63665DFF6B6E65FF6E7168FF72756CFF686B62FF72756CFF767970FF
+ 5D6057FF60635AFF61645BFF64675EFF53564DFF63665DFF72756CFF64675EFF
+ 64675EFF64675EFF70736AFF61645BFF5F6259FF63665DFF5E6158FF63665DFF
+ 6E7168FF6F7269FF70736AFF64675EFF666960FF6B6E65FF64675EFF64675EFF
+ 686B62FF63665DFF7E8277FF74786DFF696D62FF787C71FF707469FF707469FF
+ 666A5FFF6A6E63FF6A6E63FF83877CFF75796EFF6B6F64FF6B6F64FF6D7166FF
+ 787C71FF71756AFF6E7267FF71756AFF7A7E73FF787C71FF6F7368FF777B70FF
+ 82867BFF7D8176FF7B7F74FF6F7368FF7C8075FF72766BFF7B7E75FF6A6D64FF
+ 70736AFFA6A9A0FF71746BFF81847BFF73766DFF6A6D64FF62655CFF63665DFF
+ 40433AFF484B42FF595C53FF7D8077FF6E7168FF70736AFF666763FF585955FF
+ 4F504CFF575854FF40413DFF62635FFF646561FF4C4D49FF3E3F3BFF4F504CFF
+ 51524EFF50514DFF5F605CFF676864FF6A6B67FF767773FF6B6C68FF737470FF
+ 7E7F7BFF969793FF81827EFF888985FF676864FF545551FF5C5D59FF5D5E5AFF
+ 61625EFF646561FF636460FF5E5F5BFF5D5E5AFF5F605CFF646863FF666A65FF
+ 616560FF525651FF494D48FF4C504BFF545853FF595D58FF4F534EFF5C605BFF
+ 4B4F4AFF626661FF4B4F4AFF464A45FF40443FFF414540FF3F403CFF3F403CFF
+ 40413DFF4D4E4AFF585955FF474844FF3A3B37FF444541FF444541FF4B4C48FF
+ 444541FF4A4B47FF3E3F3BFF474844FF42433FFF454944FF474D48FF59605BFF
+ 484F4AFF5A615CFF5E6560FF515853FF5E6560FF444B46FF49504BFF585F5AFF
+ 616863FF646B66FF757C77FF939A95FFA3AAA5FFA0A7A2FF8F9B95FF828E88FF
+ 79857FFF7D8983FF828C86FF757F79FF5F6963FF505752FF666D68FF6B716CFF
+ 626863FF8E928DFF70746FFF7A7E79FF7F837EFF8F938DFF757771FF72756CFF
+ 767970FF7F8279FF7C7F76FF71746BFF6E7168FF75786FFF73766DFF686B62FF
+ 6D7067FF83867DFF888B82FF797C73FF74776EFF7D8077FF777A71FF676A61FF
+ 676A61FF777A71FF6B6E65FF62655CFF74776EFF95988FFF72756CFF6F7269FF
+ 686B62FF6B6E65FF5E6158FF60635AFF6B6E65FF4A4D44FF95988FFFB3B6ADFF
+ 6A6D64FF5E6158FF9A9D94FF73766DFF696C63FF63665DFF676A61FF5D6057FF
+ 696C63FF72756CFF7C7F76FF81847BFF7A7D74FF81847BFF797C73FF787B72FF
+ 6A6D64FF75786FFF676A61FF6D7067FF60635AFF63665DFF5F6259FF6D7067FF
+ 777A71FF6F7269FF696C63FF666960FF63665DFF6C6F66FF8A8D84FF61645BFF
+ 474A41FF6A6D64FF7A7D74FF6D7067FF777A71FF797C73FF666960FF676A61FF
+ 676A61FF676A61FF6A6D64FF70736AFF767970FF7A7D74FF75786FFF797C73FF
+ 84877EFF8E9188FF868980FF81847BFF7F8279FF6E7168FF81847BFFA3A69DFF
+ 686B62FF74776EFF777A71FF666960FF5C5F56FF575A51FF565950FF4B4E45FF
+ 6A6D64FF6C6F66FF696C63FF65685FFF4C4F46FF5D6057FF60635AFF60635AFF
+ 61645BFF61645BFF63665DFF676A61FF6C6F66FF6F7269FF6A6D64FF65685FFF
+ 70736AFF73766DFF686B62FF6B6E65FF6A6D64FF575A51FF6C6F66FF61645BFF
+ 52554CFF565950FF60635AFF70736AFF6D7067FF676A61FF61645BFF61645BFF
+ 6B6E65FF5F6259FF5F6259FF61645BFF4C4F46FF4B4E45FF53564DFF6A6D64FF
+ 595C53FF565950FF676A61FF72756CFF767970FF64675EFF5E6158FF54574EFF
+ 595C53FF5E6158FF55584FFF54574EFF5A5D54FF585B52FF64675EFF5B5E55FF
+ 60635AFF696C63FF696C63FF6F7269FF74776EFF6C6F66FF6E7267FF6B6F64FF
+ 62665BFF686C61FF6B6F64FF696D62FF63675CFF6C7065FF6C7065FF888C81FF
+ 6E7267FF5E6257FF6A6E63FF707469FF797D72FF777B70FF8F9388FF83877CFF
+ 81857AFF7B7F74FF696D62FF63675CFF686C61FF676B60FF767A6FFF65695EFF
+ 777B70FF7A7E73FF71746BFF73766DFF63665DFF8A8D84FF6B6E65FF75786FFF
+ 5C5F56FF6E7168FF6D7067FF7E8178FF6E7168FF70736AFF65685FFF7E8178FF
+ 75786FFF7B7E75FF696A66FF6C6D69FF666763FF696A66FF52534FFF70716DFF
+ 70716DFF5F605CFF646561FF646561FF5A5B57FF535450FF595A56FF61625EFF
+ 62635FFF636460FF72736FFF71726EFF676864FF7A7B77FF60615DFF6B6C68FF
+ 696A66FF696A66FF6E6F6BFF797A76FF7F807CFF757672FF656662FF5A5B57FF
+ 575854FF585955FF4E524DFF555954FF585C57FF525651FF4F534EFF545853FF
+ 5C605BFF60645FFF6B6F6AFF787C77FF5C605BFF70746FFF727671FF888C87FF
+ 757974FF525651FF646561FF5D5E5AFF4C4D49FF444541FF444541FF3B3C38FF
+ 373834FF454642FF383935FF3A3B37FF2D2E2AFF3E3F3BFF333430FF464743FF
+ 3D3E3AFF434742FF444A45FF595F5AFF565C57FF666C67FF686E69FF5B615CFF
+ 5F6560FF494F4AFF404641FF4F5550FF585E59FF5B615CFF6E746FFF8C928DFF
+ 9CA29DFF989F9AFF858C87FF757F79FF6A746EFF6B756FFF747B76FF767D78FF
+ 777E79FF797F7AFF666C67FF636762FF5F635EFF7C7D79FF6A6B67FF666763FF
+ 747571FF7E807AFF898B85FF797C73FF70736AFF75786FFF777A71FF6F7269FF
+ 6A6D64FF6C6F66FF767970FF63665DFF63665DFF7B7E75FF868980FF7A7D74FF
+ 71746BFF75786FFF75786FFF75786FFF6B6E65FF5F6259FF72756CFF80837AFF
+ 7D8077FF6E7168FF6D7067FF6E7168FF6B6E65FF6E7168FF60635AFF686B62FF
+ 81847BFF6C6F66FF888B82FFB3B6ADFF50534AFF51544BFF74776EFF61645BFF
+ 5C5F56FF62655CFF767970FF696C63FF6F7269FF5B5E55FF50534AFF5B5E55FF
+ 63665DFF82857CFF7E8178FF787B72FF676A61FF74776EFF6A6D64FF767970FF
+ 71746BFF7D8077FF72756CFF7D8077FF7C7F76FF888B82FF94978EFF8B8E85FF
+ 8C8F86FF9FA299FF8E9188FF8B8E85FF777A71FF676A61FF55584FFF63665DFF
+ 8A8D84FF84877EFF7A7D74FF6A6D64FF61645BFF63665DFF61645BFF5C5F56FF
+ 63665DFF71746BFF6B6E65FF5C5F56FF6A6D64FF787B72FF74776EFF71746BFF
+ 72756CFF75786FFF676A61FF93968DFF585B52FF6D7067FF787B72FF6B6E65FF
+ 6C6F66FF62655CFF6A6D64FF686B62FF83867DFF767970FF70736AFF7B7E75FF
+ 6E7168FF7E8178FF6A6D64FF6C6F66FF6D7067FF6D7067FF6B6E65FF6B6E65FF
+ 6D7067FF6F7269FF6F7269FF62655CFF6E7168FF767970FF6D7067FF777A71FF
+ 7A7D74FF60635AFF61645BFF585B52FF595C53FF5B5E55FF595C53FF50534AFF
+ 5F6259FF74776EFF565950FF595C53FF6E7168FF676A61FF60635AFF676A61FF
+ 5F6259FF62655CFF5F6259FF797C73FF696C63FF63665DFF70736AFF7B7E75FF
+ 868980FF7B7E75FF767970FF6E7168FF74776EFF777A71FF6B6E65FF676A61FF
+ 6D7067FF6C6F66FF70736AFF6A6D64FF71746BFF787B72FF797C73FF80837AFF
+ 84877EFF7A7D74FF61655AFF71756AFF73776CFF6F7368FF83877CFF82867BFF
+ 797D72FF777B70FF6E7267FF7F8378FF65695EFF5F6358FF6A6E63FF62665BFF
+ 666A5FFF6A6E63FF65695EFF52564BFF585C51FF6C7065FF6E7267FF71756AFF
+ 81857AFF8F9388FF7D8176FF666A5FFF81857AFF9A9E93FF676A61FF71746BFF
+ 51544BFF5E6158FF5B5E55FF64675EFF51544BFF71746BFF898C83FF8C8F86FF
+ 84877EFF81847BFF777A71FF7E8178FF72756CFF666960FF71726EFF60615DFF
+ 555652FF71726EFF6E6F6BFF81827EFF7E7F7BFF80817DFF898A86FF767773FF
+ 6C6D69FF646561FF5B5C58FF656662FF6C6D69FF5D5E5AFF676864FF71726EFF
+ 797A76FF979894FF868783FF7A7B77FF7E7F7BFF777874FF72736FFF82837FFF
+ 8A8B87FF80817DFF72736FFF6D6E6AFF6C6D69FF696A66FF4D514CFF5A5E59FF
+ 676B66FF6B6F6AFF6A6E69FF6A6E69FF666A65FF616560FF767A75FF878B86FF
+ 737772FF777B76FF7D817CFF8E928DFF868A85FF636762FF676864FF72736FFF
+ 696A66FF585955FF51524EFF4D4E4AFF4D4E4AFF585955FF595A56FF555652FF
+ 3D3E3AFF535450FF42433FFF555652FF41423EFF454944FF535752FF5D635EFF
+ 6F7570FF787E79FF7F8580FF818782FF767C77FF6D736EFF606661FF666C67FF
+ 676D68FF666C67FF707671FF808681FF868C87FF818782FF7C827DFF757B76FF
+ 727873FF767C77FF787E79FF797D78FF787C77FF797D78FF666A65FF61625EFF
+ 767773FF7F807CFF777874FF6B6C68FF696A66FF696B65FF81837DFF73766DFF
+ 696C63FF6C6F66FF74776EFF777A71FF777A71FF767970FF6D7067FF70736AFF
+ 6B6E65FF666960FF70736AFF7C7F76FF73766DFF5E6158FF7C7F76FF80837AFF
+ 7E8178FF70736AFF83867DFF787B72FF6E7168FF65685FFF767970FF81847BFF
+ 797C73FF767970FF6B6E65FF72756CFF8D9087FF878A81FF7E8178FF979A91FF
+ 6F7269FF6E7168FF7E8178FF979A91FF80837AFF9A9D94FF82857CFF6F7269FF
+ 75786FFF585B52FF4E5148FF585B52FF3F4239FF464940FF52554CFF54574EFF
+ 54574EFF74776EFF71746BFF787B72FF686B62FF6C6F66FF70736AFF8D9087FF
+ 787B72FF686B62FF6B6E65FF676A61FF75786FFF878A81FF91948BFF8B8E85FF
+ 8A8D84FF91948BFF777A71FF6C6F66FF7B7E75FF65685FFF6C6F66FF676A61FF
+ 686B62FF6C6F66FF63665DFF4E5148FF41443BFF41443BFF494C43FF31342BFF
+ 41443BFF4C4F46FF4E5148FF5C5F56FF696C63FF80837AFF686B62FF8A8D84FF
+ 55584FFF676A61FF6B6E65FF696C63FF70736AFF62655CFF64675EFF62655CFF
+ 676A61FF595C53FF575A51FF65685FFF696C63FF74776EFF85887FFF83867DFF
+ 7E8178FF797C73FF74776EFF72756CFF74776EFF75786FFF65685FFF585B52FF
+ 60635AFF676A61FF65685FFF787B72FF888B82FF797C73FF72756CFF63665DFF
+ 696C63FF6C6F66FF767970FF64675EFF6A6D64FF71746BFF63665DFF62655CFF
+ 7C7F76FF75786FFF666960FF70736AFF6F7269FF71746BFF666960FF6F7269FF
+ 62655CFF6F7269FF777A71FF6C6F66FF7A7D74FF878A81FF7B7E75FF74776EFF
+ 7A7D74FF7F8279FF767970FF797C73FF898C83FF8F9289FF7F8279FF7C7F76FF
+ 82857CFF84877EFF7E8178FF82857CFF83867DFF777A71FF868A7FFF909489FF
+ 82867BFF696D62FF85897EFF83877CFF81857AFF84887DFF767A6FFF7D8176FF
+ 6C7065FF707469FF707469FF5D6156FF5F6358FF606459FF85897EFF6B6F64FF
+ 666A5FFF6F7368FF686C61FF5E6257FF5E6257FF5C6055FF676B60FF505449FF
+ 6E7267FF8A8E83FF51544BFF585B52FF4B4E45FF53564DFF63665DFF74776EFF
+ 75786FFF878A81FF7F8279FF72756CFF777A71FF7E8178FF91948BFF979A91FF
+ 979A91FF83867DFF6A6B67FF61625EFF5A5B57FF7A7B77FF7D7E7AFF888985FF
+ 737470FF6C6D69FF878884FF6B6C68FF71726EFF71726EFF5A5B57FF6C6D69FF
+ 81827EFF686965FF6C6D69FF636460FF5C5D59FF686965FF676864FF595A56FF
+ 80817DFF82837FFF6A6B67FF787975FF7F807CFF7A7B77FF7A7B77FF81827EFF
+ 7E7F7BFF737470FF656662FF6F706CFF787975FF7A7B77FF777874FF71726EFF
+ 666763FF5A5B57FF676864FF70716DFF6A6B67FF676864FF6E6F6BFF696A66FF
+ 7B7C78FF6E6F6BFF646561FF767773FF737470FF6A6B67FF777874FF81827EFF
+ 757672FF676864FF7A7B77FF757672FF595A56FF767773FF62635FFF757672FF
+ 585955FF5A5E59FF5D615CFF545A55FF757B76FF747A75FF848A85FF9CA29DFF
+ 818782FF848A85FF848A85FF7E847FFF777D78FF767C77FF7A807BFF7A807BFF
+ 767C77FF707671FF7B7F7AFF7A7E79FF80847FFF8A8E89FF8C908BFF82837FFF
+ 747571FF6C6D69FF787975FF71706CFF8E8D89FF8B8A86FF7C7B77FF868581FF
+ 71706CFF75756FFF72746EFF75786FFF73766DFF6F7269FF72756CFF7B7E75FF
+ 83867DFF868980FF7E8178FF8B8E85FF878A81FF777A71FF7A7D74FF8C8F86FF
+ 898C83FF74776EFF73766DFF787B72FF80837AFF777A71FF8A8D84FF6E7168FF
+ 787B72FF91948BFF7D8077FF91948BFF80837AFF74776EFF70736AFF6C6F66FF
+ 7B7E75FF7B7E75FF72756CFF80837AFF767970FF72756CFF71746BFF797C73FF
+ 787B72FF71746BFF777A71FF676A61FF7B7E75FF6D7067FF80837AFF9C9F96FF
+ 6B6E65FF575A51FF676A61FF5A5D54FF484B42FF5F6259FF5E6158FF6E7168FF
+ 6A6D64FF767970FF52554CFF888B82FF7E8178FF7C7F76FF868980FF73766DFF
+ 6E7168FF6B6E65FF7E8178FF52554CFF4A4D44FF71746BFF70736AFF6C6F66FF
+ 85887FFF7B7E75FF777A71FF797C73FF6C6F66FF52554CFF464940FF4C4F46FF
+ 50534AFF4C4F46FF4D5047FF43463DFF5B5E55FF54574EFF4E5148FF64675EFF
+ 71746BFF868980FF777A71FF8A8D84FF686B62FF767970FF6F7269FF787B72FF
+ 7B7E75FF696C63FF696C63FF61645BFF55584FFF64675EFF6E7168FF6A6D64FF
+ 71746BFF6F7269FF7A7D74FF797C73FF777A71FF74776EFF71746BFF6C6F66FF
+ 676A61FF63665DFF63665DFF5F6259FF5F6259FF575A51FF4D5047FF55584FFF
+ 62655CFF5F6259FF81847BFF73766DFF73766DFF696C63FF878A81FF85887FFF
+ 83867DFF6B6E65FF777A71FF6C6F66FF80837AFF75786FFF5F6259FF676A61FF
+ 65685FFF60635AFF54574EFF60635AFF585B52FF6A6D64FF767970FF6B6E65FF
+ 777A71FF82857CFF6D7067FF696C63FF74776EFF797C73FF6F7269FF71746BFF
+ 81847BFF888B82FF797C73FF7A7D74FF82857CFF81847BFF777A71FF7A7D74FF
+ 7C7F76FF6F7269FF8D9186FF878B80FF707469FF565A4FFF7A7E73FF6A6E63FF
+ 696D62FF777B70FF767A6FFF777B70FF6E7267FF73776CFF696D62FF64685DFF
+ 767A6FFF6F7368FF777B70FF6E7267FF6E7267FF6F7368FF707469FF75796EFF
+ 6B6F64FF4F5348FF585C51FF464A3FFF53574CFF4E5247FF6C6F66FF686B62FF
+ 6C6F66FF6A6D64FF6D7067FF72756CFF74776EFF65685FFF666960FF60635AFF
+ 7A7D74FF777A71FF81847BFF777A71FF8F9289FF8C8F86FF90918DFFA5A6A2FF
+ 939490FF7C7D79FF5B5C58FF71726EFF747571FF787975FF7A7B77FF5B5C58FF
+ 70716DFF767773FF545551FF696A66FF898A86FF6B6C68FF5D5E5AFF545551FF
+ 585955FF666763FF71726EFF52534FFF757672FF6B6C68FF6C6D69FF747571FF
+ 737470FF6F706CFF777874FF82837FFF797A76FF656662FF6D6E6AFF71726EFF
+ 71726EFF6E6F6BFF6B6C68FF686965FF5F605CFF555652FF696A66FF50514DFF
+ 444541FF4C4D49FF70716DFF61625EFF777874FF6C6D69FF80817DFF7E7F7BFF
+ 646561FF5A5B57FF81827EFFA2A39FFF8D8E8AFF6A6B67FF50514DFF4E4F4BFF
+ 373834FF62635FFF545551FF6F706CFF51524EFF565753FF575B56FF3D433EFF
+ 646A65FF5C625DFF747A75FF9AA09BFF737974FF7D837EFF878D88FF7C827DFF
+ 767C77FF7D837EFF848A85FF828883FF7C827DFF7B7F7AFF82837FFF7C7D79FF
+ 7F7E7AFF888985FF92918DFF8F8E8AFF878682FF83827EFF858480FF757470FF
+ 898884FF7E7D79FF64635FFF8C8B87FF6F6E6AFF82827CFF777973FF878A81FF
+ 8B8E85FF7C7F76FF6E7168FF73766DFF7E8178FF82857CFF84877EFF868980FF
+ 878A81FF84877EFF82857CFF84877EFF888B82FF8A8D84FF8D9087FF9C9F96FF
+ 8B8E85FF575A51FF74776EFF7B7E75FF82857CFF787B72FF777A71FF92958CFF
+ 7B7E75FF6E7168FF71746BFF686B62FF6B6E65FF6D7067FF74776EFF90938AFF
+ 797C73FF8A8D84FF8D9087FF6A6D64FFAAADA4FF6F7269FF7D8077FF767970FF
+ 8D9087FF6D7067FF73766DFF979A91FF75786FFF6F7269FF81847BFF767970FF
+ 686B62FF82857CFF7E8178FF81847BFF6E7168FF70736AFF75786FFF8E9188FF
+ 6D7067FF74776EFF888B82FF6B6E65FF62655CFF65685FFF7C7F76FF6F7269FF
+ 6A6D64FF6B6E65FF575A51FF686B62FF8B8E85FF6E7168FF72756CFF8C8F86FF
+ 878A81FF62655CFF55584FFF65685FFF63665DFF4B4E45FF53564DFF5B5E55FF
+ 7D8077FF63665DFF4C4F46FF5F6259FF5F6259FF676A61FF6B6E65FF7A7D74FF
+ 72756CFF8A8D84FF84877EFF9C9F96FF9DA097FF888B82FF797C73FF6E7168FF
+ 5F6259FF90938AFFA6A9A0FF8B8E85FF8A8D84FF7C7F76FF787B72FF7C7F76FF
+ 83867DFF898C83FF898C83FF80837AFF73766DFF686B62FF60635AFF6B6E65FF
+ 73766DFF6D7067FF63665DFF666960FF72756CFF797C73FF6D7067FF787B72FF
+ 81847BFF5E6158FF71746BFF7D8077FF8E9188FF777A71FF7C7F76FF696C63FF
+ 797C73FF6D7067FF575A51FF60635AFF5C5F56FF50534AFF42453CFF64675EFF
+ 61645BFF65685FFF787B72FF84877EFF8D9087FF80837AFF777A71FF767970FF
+ 82857CFF84877EFF70736AFF65685FFF676A61FF676A61FF6B6E65FF70736AFF
+ 7D8077FF7D8077FF74776EFF797C73FF7E8178FF73766DFF72766BFF6F7368FF
+ 6E7267FF707469FFA0A499FF7A7E73FF686C61FF777B70FF6A6E63FF696D62FF
+ 62665BFF61655AFF565A4FFF676B60FF8F9388FF84887DFF676B60FF71756AFF
+ 777B70FF71756AFF787C71FF8E9287FF7E8277FF4B4F44FF595D52FF53574CFF
+ 585C51FF3D4136FF82857CFF888B82FF5C5F56FF73766DFF777A71FF767970FF
+ 6D7067FF62655CFF7E8178FF878A81FF5E6158FF72756CFF7C7F76FF7F8279FF
+ 75786FFF81847BFF959692FFABACA8FFAAABA7FF989995FF696A66FF787975FF
+ 767773FF71726EFF777874FF797A76FF6F706CFF5E5F5BFF5F605CFF6E6F6BFF
+ 6F706CFF636460FF6F706CFF666763FF52534FFF444541FF4E4F4BFF686965FF
+ 787975FF777874FF696A66FF81827EFF7A7B77FF676864FF6E6F6BFF737470FF
+ 767773FF868783FF80817DFF6C6D69FF6C6D69FF797A76FF777874FF6F706CFF
+ 61625EFF4F504CFF4C4D49FF565753FF4B4C48FF51524EFF3B3C38FF545551FF
+ 5E5F5BFF71726EFF898A86FF71726EFF71726EFF7A7B77FF72736FFF777874FF
+ 7E7F7BFF70716DFF595A56FF595A56FF565753FF5E5F5BFF676864FF5A5B57FF
+ 4D4E4AFF555652FF5A5E59FF4F534EFF5F635EFF6A6E69FF6E726DFF939792FF
+ 9EA29DFF727671FF787C77FF777B76FF828681FF797D78FF737772FF6C706BFF
+ 6C706BFF929691FF979692FF83827EFF878480FF8C8B87FF86837FFF8C8985FF
+ 94918DFF888581FF757470FF73726EFF787773FF767571FF6C6B67FF757470FF
+ 84837FFF84847EFF7F817BFF83867DFF787B72FF84877EFF787B72FF6B6E65FF
+ 7E8178FF6E7168FF73766DFF7B7E75FF878A81FF898C83FF70736AFF70736AFF
+ 898C83FF81847BFF8B8E85FF72756CFF696C63FF70736AFF75786FFF7E8178FF
+ 80837AFF767970FF464940FF75786FFF989B92FF565950FF6B6E65FF62655CFF
+ 7C7F76FF666960FF7E8178FF6C6F66FF6E7168FF7B7E75FF767970FF6A6D64FF
+ 5E6158FF50534AFF61645BFF60635AFF6F7269FF64675EFF6F7269FF63665DFF
+ 6B6E65FF686B62FF6F7269FF6F7269FF6E7168FF70736AFF7E8178FF8D9087FF
+ 91948BFF8C8F86FF898C83FF83867DFF7B7E75FF787B72FF7D8077FF7F8279FF
+ 73766DFF63665DFF70736AFF686B62FF62655CFF61645BFF5F6259FF60635AFF
+ 6A6D64FF767970FF6F7269FF74776EFF80837AFF85887FFF80837AFF82857CFF
+ 767970FF5A5D54FF61645BFF686B62FF64675EFF565950FF55584FFF676A61FF
+ 7A7D74FF81847BFF7A7D74FF8C8F86FF7B7E75FF82857CFF7B7E75FF91948BFF
+ 888B82FF969990FF83867DFF70736AFF74776EFF868980FF7E8178FF90938AFF
+ 6F7269FF83867DFF8C8F86FF878A81FF8F9289FF84877EFF95988FFF73766DFF
+ 71746BFF74776EFF767970FF5A5D54FF7F8279FF82857CFF6D7067FF7A7D74FF
+ 797C73FF787B72FF686B62FF73766DFF7D8077FF767970FF696C63FF75786FFF
+ 85887FFF85887FFF7E8178FF8A8D84FF81847BFF7C7F76FF878A81FF7D8077FF
+ 6E7168FF767970FF64675EFF5D6057FF5D6057FF676A61FF6F7269FF73766DFF
+ 7C7F76FF878A81FF777A71FF74776EFF7A7D74FF94978EFFA3A69DFF868980FF
+ 63665DFF5B5E55FF93968DFF80837AFF81847BFF73766DFF787B72FF61645BFF
+ 696C63FF696C63FF6C7065FF787C71FF666A5FFF6F7368FF686C61FF6E7267FF
+ 787C71FFAEB2A7FF9B9F94FF676B60FF71756AFF45493EFF707469FF6B6F64FF
+ 74786DFF75796EFF7C8075FF6A6E63FF797D72FF65695EFF666A5FFF666A5FFF
+ 84887DFF75796EFF52564BFF75796EFF686C61FF868A7FFF7D8077FF91948BFF
+ 686B62FF686B62FF60635AFF70736AFF7D8077FF80837AFF72756CFF868980FF
+ 60635AFF7A7D74FF7F8279FF898C83FF696C63FF5C5F56FF676864FF6D6E6AFF
+ 676864FF81827EFF72736FFF7E7F7BFF80817DFF787975FF676864FF72736FFF
+ 82837FFF8D8E8AFF8C8D89FF80817DFF70716DFF676864FF6D6E6AFF737470FF
+ 757672FF71726EFF6E6F6BFF6F706CFF6F706CFF6C6D69FF8A8B87FF8A8B87FF
+ 757672FF5A5B57FF545551FF5E5F5BFF757672FF8E8F8BFF7B7C78FF72736FFF
+ 72736FFF686965FF535450FF585955FF7A7B77FF939490FF636460FF595A56FF
+ 5C5D59FF555652FF4D4E4AFF4E4F4BFF60615DFF646561FF70716DFF5D5E5AFF
+ 646561FF797A76FF7B7C78FF757672FF7C7D79FF858682FF6E6F6BFF696A66FF
+ 61625EFF6A6B67FF787975FF6D6E6AFF5F605CFF62635FFF616560FF515550FF
+ 636762FF787C77FF787C77FF898D88FF8E928DFF6F736EFF787C77FF7C807BFF
+ 898D88FF818580FF797D78FF70746FFF6C706BFF91928EFF96938FFF8B8884FF
+ 8F8C88FF94918DFF888581FF817E7AFF8E8B87FF999894FF8E8D89FF8A8985FF
+ 92918DFF93928EFF858480FF7F807CFF858480FF80827CFF80827CFF82857CFF
+ 7E8178FF91948BFF878A81FF72756CFF7A7D74FF676A61FF5C5F56FF585B52FF
+ 5E6158FF6E7168FF6A6D64FF64675EFF6F7269FF71746BFF72756CFF64675EFF
+ 696C63FF75786FFF777A71FF777A71FF73766DFF666960FF585B52FF6F7269FF
+ 63665DFF70736AFF5B5E55FF696C63FF60635AFF797C73FF898C83FF73766DFF
+ 64675EFF696C63FF585B52FF5F6259FF666960FF6E7168FF696C63FF7B7E75FF
+ 868980FF74776EFF797C73FF6C6F66FF797C73FF666960FF70736AFF70736AFF
+ 65685FFF5A5D54FF666960FF83867DFF94978EFF94978EFFB6B9B0FFA3A69DFF
+ 878A81FF74776EFF75786FFF7F8279FF81847BFF7D8077FF686B62FF6D7067FF
+ 6E7168FF676A61FF61645BFF63665DFF6A6D64FF70736AFF64675EFF676A61FF
+ 75786FFF7D8077FF7E8178FF878A81FF878A81FF75786FFF7D8077FF81847BFF
+ 80837AFF7A7D74FF797C73FF81847BFF8A8D84FF8E9188FF84877EFF95988FFF
+ 81847BFF7B7E75FF6D7067FF7E8178FF7D8077FF8E9188FF8C8F86FF73766DFF
+ 6A6D64FF72756CFF6F7269FF81847BFF595C53FF5B5E55FF5B5E55FF666960FF
+ 5D6057FF787B72FF7C7F76FF8D9087FF7C7F76FF898C83FF7B7E75FF666960FF
+ 7C7F76FF777A71FF6C6F66FF80837AFF82857CFF85887FFF868980FF82857CFF
+ 6E7168FF767970FF7B7E75FF90938AFF868980FF82857CFF75786FFF7D8077FF
+ 7E8178FF80837AFF888B82FF868980FF7F8279FF82857CFF74776EFF6E7168FF
+ 6E7168FF75786FFF797C73FF777A71FF787B72FF7D8077FF75786FFF6F7269FF
+ 6D7067FF7D8077FF8B8E85FF7F8279FF767970FF83867DFF777A71FF6F7269FF
+ 787B72FF65685FFF64675EFF5D6057FF70736AFF676A61FF5D6156FF63675CFF
+ 585C51FF666A5FFF595D52FF5C6055FF565A4FFF6D7166FF8D9186FF707469FF
+ 6F7368FF5B5F54FF5B5F54FF5C6055FF4A4E43FF505449FF676B60FF868A7FFF
+ 9FA398FF71756AFF5F6358FF63675CFF808479FF74786DFF73776CFF6F7368FF
+ 585C51FF878B80FF585B52FF767970FF5B5E55FF575A51FF4F5249FF63665DFF
+ 686B62FF686B62FF60635AFF7E8178FF585B52FF70736AFF666960FF878A81FF
+ 777A71FF767970FF747571FF7D7E7AFF747571FF9C9D99FF7F807CFF6D6E6AFF
+ 7B7C78FF81827EFF787975FF797A76FF878884FF979894FF8F908CFF767773FF
+ 6A6B67FF6F706CFF6C6D69FF6E6F6BFF71726EFF6E6F6BFF656662FF61625EFF
+ 6C6D69FF7A7B77FF939490FF878884FF7E7F7BFF70716DFF5D5E5AFF62635FFF
+ 7F807CFF939490FF7C7B77FF71706CFF757470FF797874FF6E6D69FF64635FFF
+ 5C5B57FF504F4BFF7B7A76FF5D5C58FF6B6A66FF61605CFF656460FF555450FF
+ 6E6D69FF63625EFF696A66FF60615DFF666763FF80817DFF898A86FF767773FF
+ 767773FF92938FFF71726EFF777874FF72736FFF6D6E6AFF6B6C68FF6C6D69FF
+ 838480FFAAABA7FF858682FF6D6E6AFF767773FF878884FF7C7D79FF797A76FF
+ 7A7B77FF6B6C68FF888985FF8B8C88FF969793FF8B8C88FF80817DFF72736FFF
+ 646561FF80817DFF96938FFF85807DFF75726EFF7D7A76FF8C8985FF878480FF
+ 82817DFF8F8E8AFF91908CFF82837FFF858682FF888985FF7C7D79FF757974FF
+ 80817DFF858781FF72746EFF6B6E65FF6D7067FF888B82FF868980FF767970FF
+ 7C7F76FF71746BFF7D8077FF6E7168FF676A61FF73766DFF7A7D74FF696C63FF
+ 5C5F56FF686B62FF676A61FF5C5F56FF60635AFF686B62FF65685FFF6A6D64FF
+ 74776EFF74776EFF72756CFF6A6D64FF5E6158FF62655CFF65685FFF5B5E55FF
+ 5B5E55FF71746BFF5E6158FF64675EFF6D7067FF888B82FF666960FF60635AFF
+ 4D5047FF4D5047FF51544BFF787B72FF82857CFF777A71FF7D8077FF6C6F66FF
+ 7F8279FF5B5E55FF6E7168FF75786FFF70736AFF65685FFF696C63FF7D8077FF
+ 868980FF82857CFF85887FFF888B82FF8C8F86FF8E9188FF90938AFF888B82FF
+ 72756CFF5D6057FF5D6057FF6D7067FF797C73FF777A71FF70736AFF6C6F66FF
+ 6C6F66FF6B6E65FF6B6E65FF686B62FF71746BFF767970FF74776EFF7E8178FF
+ 868980FF7E8178FF7D8077FF7B7E75FF7C7F76FF7E8178FF7D8077FF777A71FF
+ 75786FFF777A71FF70736AFF8E9188FF8D9087FF898C83FF797C73FF7C7F76FF
+ 70736AFF777A71FF95988FFF888B82FF7E8178FF7C7F76FF7B7E75FF8E9188FF
+ 73766DFF6D7067FF6E7168FF777A71FF63665DFF70736AFF70736AFF80837AFF
+ 676A61FF666960FF75786FFF6E7168FF73766DFF676A61FF6D7067FF898C83FF
+ 8F9289FF95988FFF787B72FF80837AFF6B6E65FF74776EFF7B7E75FF84877EFF
+ 787B72FF8C8F86FF7F8279FF7C7F76FF83867DFF888B82FF83867DFF84877EFF
+ 868980FF80837AFF7C7F76FF797C73FF7A7D74FF7F8279FF80837AFF7B7E75FF
+ 767970FF74776EFF6D7067FF6A6D64FF65685FFF6C6F66FF73766DFF696C63FF
+ 6B6E65FF80837AFF787B72FF73766DFF82857CFF676A61FF5B5E55FF5F6259FF
+ 7E8178FF6E7168FF65695EFF666A5FFF666A5FFF7D8176FF74786DFF868A7FFF
+ 808479FF7D8176FF767A6FFF777B70FF707469FF81857AFF62665BFF73776CFF
+ 505449FF5E6257FF3F4338FF64685DFF777B70FF5D6156FF686C61FF73776CFF
+ 81857AFF7B7F74FF5D6156FF52564BFF3F4338FF63675CFF686B62FF74776EFF
+ 5C5F56FF64675EFF64675EFF72756CFF63665DFF62655CFF595C53FF797C73FF
+ 5C5F56FF767970FF4E5148FF686B62FF6F7269FF8A8D84FF92938FFF9D9E9AFF
+ 878884FFA2A39FFF757672FF595A56FF6A6B67FF6D6E6AFF848581FF7D7E7AFF
+ 7E7F7BFF838480FF7C7D79FF6E6F6BFF6C6D69FF747571FF8C8D89FF7E7F7BFF
+ 747571FF71726EFF6F706CFF71726EFF838480FF999A96FF8F908CFF7D7E7AFF
+ 838480FF838480FF676864FF62635FFF787975FF81827EFF757470FF7C7B77FF
+ 8A8985FF84837FFF6A6965FF676662FF7B7A76FF898884FF94938FFF71706CFF
+ 7C7B77FF82817DFF82817DFF7C7B77FF908F8BFF858480FF72736FFF767773FF
+ 757672FF82837FFF8F908CFF787975FF6B6C68FF848581FF6C6D69FF737470FF
+ 70716DFF686965FF666763FF6A6B67FF8A8B87FFB9BAB6FF9C9D99FF878884FF
+ 848581FF858682FF777874FF747571FF7A7B77FF767773FF91928EFF8F908CFF
+ 959692FF8B8C88FF898A86FF81827EFF6E6F6BFF82817DFF898682FF85807DFF
+ 6C6965FF696662FF83807CFF868581FF7C7B77FF838480FF91928EFF838480FF
+ 878884FF8E928DFF848883FF7C827DFF878B86FF8D918BFF999B95FF80837AFF
+ 7A7D74FF898C83FF84877EFF797C73FF7D8077FF7B7E75FF83867DFF7E8178FF
+ 75786FFF6E7168FF7A7D74FF71746BFF5D6057FF72756CFF74776EFF6A6D64FF
+ 6C6F66FF6D7067FF62655CFF65685FFF74776EFF7A7D74FF80837AFF898C83FF
+ 7F8279FF62655CFF6C6F66FF6C6F66FF6A6D64FF5F6259FF5E6158FF64675EFF
+ 65685FFF7C7F76FF575A51FF5D6057FF5B5E55FF6B6E65FF6E7168FF888B82FF
+ 81847BFF7A7D74FF83867DFF71746BFF90938AFF75786FFF71746BFF73766DFF
+ 75786FFF777A71FF777A71FF777A71FF797C73FF7C7F76FF7D8077FF7E8178FF
+ 7E8178FF7E8178FF81847BFF82857CFF787B72FF6C6F66FF65685FFF6C6F66FF
+ 7B7E75FF888B82FF868980FF787B72FF70736AFF71746BFF63665DFF5A5D54FF
+ 5D6057FF60635AFF5B5E55FF60635AFF696C63FF676A61FF70736AFF666960FF
+ 62655CFF676A61FF63665DFF565950FF50534AFF53564DFF4F5249FF74776EFF
+ 84877EFF84877EFF82857CFF7F8279FF70736AFF6C6F66FF81847BFF888B82FF
+ 878A81FF7C7F76FF787B72FF898C83FF868980FF80837AFF80837AFF82857CFF
+ 83867DFF6C6F66FF878A81FF7A7D74FF73766DFF60635AFF5E6158FF65685FFF
+ 5C5F56FF4B4E45FF595C53FF6F7269FF71746BFF72756CFF5F6259FF70736AFF
+ 6F7269FF6E7168FF878A81FF767970FF73766DFF92958CFF8A8D84FF7F8279FF
+ 878A81FF8A8D84FF7A7D74FF7E8178FF878A81FF7C7F76FF898C83FF85887FFF
+ 83867DFF84877EFF83867DFF7C7F76FF73766DFF6D7067FF62655CFF666960FF
+ 676A61FF6F7269FF73766DFF62655CFF595C53FF65685FFF6E7168FF6E7168FF
+ 92958CFF898C83FF7B7E75FF70736AFF868980FF75786FFF83877CFF797D72FF
+ 72766BFF7C8075FF65695EFF7D8176FF7D8176FF6F7368FF676B60FF72766BFF
+ 6C7065FF8B8F84FF73776CFF888C81FF72766BFF81857AFF71756AFF787C71FF
+ 71756AFF6C7065FF797D72FF696D62FF606459FF6F7368FF64685DFF707469FF
+ 666A5FFF595D52FF90938AFF84877EFF6E7168FF797C73FF72756CFF75786FFF
+ 666960FF81847BFF666960FF777A71FF6C6F66FF95988FFF65685FFF565950FF
+ 51544BFF686B62FF959692FF969793FF767773FF858682FF72736FFF797A76FF
+ 80817DFF6D6E6AFF5D5E5AFF60615DFF656662FF696A66FF6C6D69FF6A6B67FF
+ 636460FF5B5C58FF858682FF71726EFF656662FF6A6B67FF71726EFF70716DFF
+ 70716DFF757672FF8E8F8BFF7A7B77FF7E7F7BFF7C7D79FF5D5E5AFF535450FF
+ 61625EFF656662FF5C5B57FF706D69FF8D8A86FF94918DFF827F7BFF7C7975FF
+ 85827EFF86837FFF86837FFF74716DFF6F6C68FF85827EFF7B7874FF8A8783FF
+ 8D8A86FF8C8B87FF6F706CFF7E7F7BFF797A76FF797A76FF888985FF7F807CFF
+ 6E6F6BFF747571FF777874FF6E6F6BFF636460FF6E6F6BFF81827EFF7D7E7AFF
+ 70716DFF747571FF8A8B87FF878884FF848581FF7B7C78FF767773FF80817DFF
+ 8A8B87FF868783FF868783FF7D7E7AFF80817DFF7D7E7AFF8E8F8BFF969793FF
+ 848581FF92918DFF787571FF95928EFF8D8A86FF73706CFF71706CFF757470FF
+ 797874FF888985FF71726EFF666A65FF717570FF7B817CFF717772FF656C67FF
+ 656B66FF616861FF888C86FF6E7168FF6D7067FF777A71FF767970FF787B72FF
+ 7C7F76FF82857CFF63665DFF72756CFF7A7D74FF65685FFF73766DFF898C83FF
+ 83867DFF9FA299FF85887FFF82857CFF8B8E85FF8D9087FF7A7D74FF6F7269FF
+ 6F7269FF6C6F66FF7A7D74FFA5A89FFF84877EFF8B8E85FF686B62FF979A91FF
+ 6F7269FF696C63FF6E7168FF676A61FF60635AFF6D7067FF565950FF696C63FF
+ 7F8279FF9A9D94FF9DA097FF969990FF83867DFF7A7D74FF83867DFF6E7168FF
+ 8E9188FF898C83FF81847BFF71746BFF6F7269FF7B7E75FF7C7F76FF72756CFF
+ 7A7D74FF8E9188FF989B92FF91948BFF85887FFF7A7D74FF7A7D74FF84877EFF
+ 8A8D84FF8A8D84FF696C63FF55584FFF55584FFF696C63FF6C6F66FF595C53FF
+ 53564DFF5E6158FF62655CFF54574EFF575A51FF61645BFF5D6057FF5E6158FF
+ 676A61FF686B62FF6E7168FF60635AFF585B52FF585B52FF53564DFF474A41FF
+ 44473EFF4A4D44FF464940FF62655CFF6E7168FF676A61FF767970FF7D8077FF
+ 7C7F76FF767970FF7A7D74FF83867DFF7E8178FF6F7269FF74776EFF7D8077FF
+ 84877EFF75786FFF81847BFF888B82FF90938AFF7A7D74FF92958CFF84877EFF
+ 7F8279FF6F7269FF7E8178FF8B8E85FF7C7F76FF6D7067FF73766DFF797C73FF
+ 74776EFF686B62FF64675EFF676A61FF72756CFF686B62FFA2A59CFF7F8279FF
+ 7D8077FF868980FF888B82FF7C7F76FF83867DFF84877EFF74776EFF7A7D74FF
+ 888B82FF80837AFF8E9188FF8A8D84FF85887FFF82857CFF81847BFF7E8178FF
+ 75786FFF6D7067FF65685FFF676A61FF676A61FF71746BFF7C7F76FF72756CFF
+ 666960FF6C6F66FF53564DFF565950FF898C83FF9EA198FF9EA198FF7E8178FF
+ 84877EFF7D8077FF7E8277FF767A6FFF6C7065FF6D7166FF4C5045FF606459FF
+ 65695EFF5E6257FF6C7065FF6B6F64FF62665BFF6F7368FF6E7267FF71756AFF
+ 72766BFF75796EFF5F6358FF6D7166FF6A6E63FF71756AFF767A6FFF6E7267FF
+ 71756AFF969A8FFF64685DFF6F7368FF74786DFF5C6055FF8A8D84FF85887FFF
+ 85887FFF92958CFF7B7E75FF6E7168FF5E6158FF90938AFF7C7F76FF6B6E65FF
+ 666960FF989B92FF888B82FF6F7269FF6D7067FF71746BFF838480FF898A86FF
+ 80817DFF7B7C78FF6A6B67FF8D8E8AFF8D8E8AFF82837FFF7F807CFF81827EFF
+ 81827EFF80817DFF848581FF868783FF7E7F7BFF72736FFF91928EFF7F807CFF
+ 72736FFF787975FF868783FF8C8D89FF888985FF848581FF7B7C78FF797A76FF
+ 838480FF868783FF767773FF696A66FF646561FF5E5F5BFF898682FF7A7773FF
+ 716E6AFF6B6864FF676460FF726F6BFF7A7773FF706D69FF696662FF716E6AFF
+ 63605CFF75726EFF696662FF7D7A76FF716E6AFF797874FF6A6965FF777874FF
+ 787975FF787975FF848581FF8A8B87FF82837FFF7C7D79FF7F807CFF767773FF
+ 6B6C68FF767773FF878884FF7F807CFF6E6F6BFF6E6F6BFF787975FF81827EFF
+ 81827EFF797A76FF7A7B77FF838480FF858682FF80817DFF787975FF6D6E6AFF
+ 6B6C68FF686965FF7F807CFF8D8E8AFF7C7D79FF858480FF7E7D79FF93908CFF
+ 8F8C88FF777672FF706F6BFF71726EFF737470FF737772FF7E827DFF737974FF
+ 747A75FF737A75FF6C736EFF727974FF7B827DFF788079FF60645EFF4F5249FF
+ 5D6057FF62655CFF63665DFF6F7269FF6D7067FF70736AFF6F7269FF787B72FF
+ 8A8D84FF696C63FF6C6F66FF90938AFF8E9188FFA6A9A0FF8B8E85FF84877EFF
+ 8A8D84FF8D9087FF81847BFF7C7F76FF7F8279FF7D8077FF71746BFF85887FFF
+ 7F8279FF888B82FF83867DFF8A8D84FF75786FFF777A71FF6E7168FF64675EFF
+ 71746BFF7C7F76FF787B72FF72756CFF7C7F76FF7F8279FF888B82FF7D8077FF
+ 8F9289FF8E9188FF989B92FF7D8077FF7D8077FF80837AFF92958CFF81847BFF
+ 81847BFF92958CFF90938AFF7C7F76FF777A71FF868980FF7C7F76FF81847BFF
+ 82857CFF81847BFF81847BFF84877EFF82857CFF7D8077FF91948BFF6F7269FF
+ 5D6057FF666960FF6A6D64FF5E6158FF5F6259FF6E7168FF73766DFF5D6057FF
+ 5D6057FF696C63FF666960FF61645BFF64675EFF64675EFF61645BFF595C53FF
+ 51544BFF4C4F46FF474A41FF43463DFF45483FFF4A4D44FF4B4E45FF666960FF
+ 767970FF6B6E65FF82857CFF868980FF868980FF7A7D74FF7C7F76FF7D8077FF
+ 70736AFF696C63FF7F8279FF81847BFF8C8F86FF70736AFF7F8279FF8F9289FF
+ 80837AFF8B8E85FF83867DFF8D9087FF73766DFF75786FFF6D7067FF787B72FF
+ 70736AFF71746BFF6D7067FF696C63FF6D7067FF595C53FF5E6158FF65685FFF
+ 777A71FF666960FF8C8F86FF6C6F66FF74776EFF797C73FF868980FF82857CFF
+ 84877EFF80837AFF74776EFF74776EFF7B7E75FF7A7D74FF74776EFF72756CFF
+ 70736AFF71746BFF7A7D74FF81847BFF7F8279FF787B72FF797C73FF71746BFF
+ 63665DFF64675EFF74776EFF74776EFF70736AFF787B72FF686B62FF60635AFF
+ 767970FF83867DFF94978EFF75786FFF7E8178FF8F9289FF787C71FF7E8277FF
+ 7B7F74FF82867BFF64685DFF6C7065FF6D7166FF767A6FFF787C71FF6D7166FF
+ 62665BFF5F6358FF6E7267FF5E6257FF6F7368FF65695EFF6C7065FF797D72FF
+ 6B6F64FF676B60FF64685DFF74786DFF6E7267FF72766BFF7C8075FF6A6E63FF
+ 7B7F74FF797D72FF80837AFF84877EFF94978EFF9FA299FF888B82FF81847BFF
+ 6A6D64FF999C93FF898C83FF64675EFF5F6259FF7D8077FF888B82FF7B7E75FF
+ 95988FFF90938AFF696A66FF6E6F6BFF858682FF747571FF595A56FF838480FF
+ 737470FF7D7E7AFF858682FF7B7C78FF757672FF767773FF72736FFF686965FF
+ 656662FF6A6B67FF80817DFF777874FF6C6D69FF676864FF71726EFF81827EFF
+ 888985FF878884FF696A66FF7A7B77FF838480FF888985FF8E8F8BFF858682FF
+ 737470FF6B6C68FF504D49FF726F6BFF9B9894FF9F9C98FF83807CFF787571FF
+ 7E7B77FF7D7A76FF6C6965FF8D8A86FF86837FFF7B7874FF84817DFF84817DFF
+ 74716DFF7D7C78FF73726EFF70716DFF7A7B77FF81827EFF7E7F7BFF81827EFF
+ 878884FF848581FF72736FFF737470FF6E6F6BFF70716DFF767773FF72736FFF
+ 797A76FF90918DFF7F7E7AFF807F7BFF7B7A76FF7B7A76FF807F7BFF7C7B77FF
+ 797874FF81807CFF777672FF6F6E6AFF6D6C68FF64635FFF73726EFF7D7C78FF
+ 6B6A66FF72716DFF878682FF767571FF74736FFF7A7975FF787773FF737470FF
+ 6F706CFF646863FF797D78FF727873FF6E746FFF626964FF5C635EFF6C7670FF
+ 7B857FFF757D76FF7A7E78FF6F7269FF80837AFF71746BFF666960FF72756CFF
+ 64675EFF60635AFF8E9188FF787B72FF878A81FF666960FF5A5D54FF767970FF
+ 696C63FF74776EFF7C7F76FF6D7067FF6D7067FF74776EFF73766DFF7A7D74FF
+ 868980FF868980FF75786FFF6B6E65FF81847BFF6D7067FF999C93FF70736AFF
+ 7B7E75FF74776EFF868980FF696C63FF75786FFF6D7067FF7F8279FF6A6D64FF
+ 787B72FF6A6D64FF696C63FF696C63FFA2A59CFF989B92FF9FA299FF90938AFF
+ 797C73FF83867DFF8E9188FF8D9087FF91948BFF989B92FF989B92FF8B8E85FF
+ 7D8077FF75786FFF777A71FF767970FF6E7168FF64675EFF64675EFF6E7168FF
+ 787B72FF7C7F76FF7C7F76FF6C6F66FF5B5E55FF55584FFF565950FF585B52FF
+ 585B52FF595C53FF83867DFF65685FFF5E6158FF696C63FF64675EFF595C53FF
+ 575A51FF55584FFF52554CFF575A51FF585B52FF52554CFF4F5249FF51544BFF
+ 55584FFF565950FF575A51FF767970FF8D9087FF7A7D74FF8F9289FF8B8E85FF
+ 8C8F86FF7D8077FF6E7168FF75786FFF71746BFF6C6F66FF80837AFF74776EFF
+ 8D9087FF797C73FF70736AFF767970FF666960FF7E8178FF82857CFF91948BFF
+ 7D8077FF878A81FF74776EFF767970FF767970FF868980FF797C73FF72756CFF
+ 868980FF70736AFF5D6057FF6C6F66FF6E7168FF686B62FF5D6057FF61645BFF
+ 696C63FF767970FF7D8077FF868980FF868980FF80837AFF7D8077FF74776EFF
+ 6E7168FF74776EFF666960FF676A61FF676A61FF6A6D64FF767970FF81847BFF
+ 80837AFF767970FF7A7D74FF74776EFF64675EFF61645BFF6D7067FF6D7067FF
+ 696C63FF70736AFF7A7D74FF777A71FF6F7269FF65685FFF888B82FF72756CFF
+ 75786FFF8D9087FF7C8075FF8B8F84FF868A7FFF909489FF777B70FF6E7267FF
+ 63675CFF7A7E73FF787C71FF767A6FFF6B6F64FF6F7368FF7C8075FF676B60FF
+ 797D72FF6B6F64FF64685DFF62665BFF5B5F54FF71756AFF707469FF8D9186FF
+ 85897EFF797D72FF6F7368FF5F6358FF7B7F74FF6B6F64FF81837DFF7C7F76FF
+ 7C7E78FF7B7E75FF73756FFF888B82FF757771FF9B9E95FF8B8D87FF6C6F66FF
+ 6D6F69FF6D7067FF757771FF62655CFF8B8D87FF7D7F79FF696A66FF555652FF
+ 767773FF71726EFF6B6C68FF9FA09CFF737470FF7A7B77FF868783FF7B7C78FF
+ 81827EFF939490FF8C8D89FF71726EFF6B6C68FF7B7C78FF7C7D79FF848581FF
+ 82837FFF777874FF747571FF7D7E7AFF81827EFF7F807CFF71726EFF80817DFF
+ 737470FF676864FF787975FF7C7D79FF71726EFF72736FFF62615DFF706F6BFF
+ 878480FF888783FF7D7A76FF7E7D79FF86837FFF7C7B77FF686561FF94938FFF
+ 9C9995FF757470FF96938FFF7E7D79FF73706CFF797874FF7D7E7AFF6D6E6AFF
+ 7B7C78FF878884FF737470FF696A66FF767773FF7B7C78FF60615DFF5D5E5AFF
+ 595A56FF646561FF757672FF737470FF6F706CFF7B7C78FF848581FF777874FF
+ 6E6D69FF767773FF83827EFF777874FF7B7A76FF92938FFF777672FF737470FF
+ 787773FF6B6C68FF777672FF7D7E7AFF6F6E6AFF767773FF7B7A76FF60615DFF
+ 72716DFF8A8B87FF787975FF656662FF6C706BFF777B76FF767C77FF808681FF
+ 8B918CFF828984FF787F7AFF7D847FFF737D77FF585F5AFF6B6F69FF676A61FF
+ 7E807AFF6D7067FF686A64FF83867DFF7D7F79FF7C7F76FFA4A6A0FF71746BFF
+ 80827CFF6C6F66FF60625CFF75786FFF60625CFF64675EFF63655FFF585B52FF
+ 5F615BFF6D7067FF6F716BFF71746BFF6F716BFF65685FFF80827CFF83867DFF
+ 7A7C76FF787B72FF848680FF83867DFF767872FF71746BFF80827CFF5F6259FF
+ 797B75FF71746BFF979993FF75786FFF7E807AFF60635AFF62645EFF5E6158FF
+ 989A94FF6A6D64FF696B65FF75786FFF676963FF81847BFF80837AFF85887FFF
+ 81847BFF787B72FF7F8279FF90938AFF90938AFF81847BFF85887FFF84877EFF
+ 7B7E75FF6D7067FF666960FF696C63FF6E7168FF70736AFF7B7E75FF878A81FF
+ 85887FFF767970FF75786FFF80837AFF7A7D74FF696C63FFA3A69DFF80837AFF
+ 767970FF83867DFF80837AFF767970FF73766DFF72756CFF585B52FF686B62FF
+ 71746BFF6D7067FF6B6E65FF72756CFF75786FFF72756CFF696C63FF83867DFF
+ 90938AFF6D7067FF7E8178FF7E8178FF90938AFF8C8F86FF74776EFF8D9087FF
+ 959791FF8A8D84FF888A84FF696C63FF93958FFF93968DFF858781FF71746BFF
+ 6D6F69FF686B62FF8D8F89FF7C7F76FF7C7E78FF7B7E75FF868980FF7D8077FF
+ 7D8077FF92958CFF797C73FF6D7067FF8B8E85FF74776EFF7C7F76FF797C73FF
+ 565950FF696C63FF4F5249FF82857CFF75786FFF72756CFF676A61FF7E8178FF
+ 80837AFF7F8279FF888B82FF7D8077FF71746BFF7D8077FF7D8077FF7D8077FF
+ 797C73FF75786FFF7A7D74FF7E8178FF74776EFF65685FFF65685FFF6A6D64FF
+ 686B62FF6C6F66FF787B72FF72756CFF676A61FF686B62FF595C53FF71746BFF
+ 71746BFF686B62FF9A9D94FF82857CFF6B6E65FF73766DFF5E6257FF73776CFF
+ 71756AFF868A7FFF81857AFF7B7F74FF72766BFF9A9E93FF707469FF7B7F74FF
+ 6F7368FF82867BFF82867BFF6E7267FF787C71FF6B6F64FF6D7166FF61655AFF
+ 686C61FF898D82FF5D6156FF52564BFF4D5146FF5B5F54FF61655AFF787C71FF
+ ADB1A6FF878B80FF8A8B87FF8C8E88FF797A76FF73756FFF838480FF7F817BFF
+ 757672FF81837DFF959692FF848680FF70716DFF696B65FF71726EFF777973FF
+ 6E6F6BFF60615DFF747873FF60645FFF535752FF4D514CFF595D58FF828681FF
+ 898D88FF60645FFF676B66FF838782FF8F938EFF717570FF838782FF70746FFF
+ 747873FF797D78FF7F807CFF80817DFF8E8F8BFF6D6E6AFF656662FF7B7C78FF
+ 6C6D69FF6E6F6BFF636460FF72736FFF6C6D69FF71726EFF6E6F6BFF62635FFF
+ 60615DFF4C4D49FF6E6F6BFF60615DFF61605CFF6E6F6BFF767571FF6C6D69FF
+ 6B6A66FF70716DFF7F7E7AFF7F807CFF8D8C88FF868783FF9B9A96FF6F706CFF
+ 6D6C68FF7D7E7AFF6C6D69FF6A6B67FF80817DFF979894FF666763FF7B7C78FF
+ 81827EFF6B6C68FF71726EFF51524EFF666763FF52534FFF6C6D69FF676864FF
+ 91928EFF80817DFF6F706CFF6A6E69FF666763FF6E726DFF80817DFF7A7E79FF
+ 747571FF7A7E79FF898A86FF7E827DFF7C7D79FF838782FF6F706CFF60645FFF
+ 737470FF626661FF737470FF585C57FF767773FF6B6F6AFF6B6F6AFF737772FF
+ 535752FF686C67FF6B6F6AFF747873FF818580FF646A65FF717772FF727873FF
+ 8C928DFF898F8AFF858984FF7D817BFF8B8F8AFF949892FF8C908BFF949892FF
+ 999D98FF828680FF838782FF81857FFF767A75FF70746EFF6D716CFF626660FF
+ 636762FF797D77FF737772FF60645EFF626661FF5C605AFF5E625DFF636761FF
+ 5C605BFF6B6F69FF7C807BFF797D77FF7D817CFF71756FFF636762FF777B75FF
+ 828681FF6D6F69FF838480FF81817BFF706F6BFF71716BFF767571FF83837DFF
+ 8F8E8AFF70706AFF6E6D69FF7C7C76FF71706CFF55554FFF61605CFF4D4D47FF
+ 605F5BFF545650FF777A71FF70756CFF6C7168FF6B7067FF83887FFF6D7269FF
+ 7F847BFF6D7269FF7B8077FF7D8279FF81867DFF878C83FF898E85FF81867DFF
+ 72776EFF656A61FF7A7F76FF7D8279FF7E837AFF7C8178FF7E837AFF868B82FF
+ 8E938AFF92978EFF9BA097FF868B82FF7E837AFF868B82FF73786FFF8C9188FF
+ 797E75FF7D8279FF878C83FF7E837AFF747970FF7F847BFF949990FF92978EFF
+ 888D84FF8D9289FF949990FF82877EFF73786FFF8E938AFF949990FF7F847BFF
+ 848980FF868980FF7D7F79FF686862FF5B5A56FF666660FF7A7975FF878781FF
+ 908F8BFF999993FF81807CFF7B7B75FF7E7D79FF7F7F79FF7A7975FF888882FF
+ 9D9C98FFA1A39DFF6D7067FF7A7F76FF83887FFF7E837AFF787D74FF787D74FF
+ 787D74FF757A71FF7A7F76FF8E938AFF747970FF747970FF6F746BFF7E837AFF
+ 6A6F66FF777C73FF8C9188FF6D7269FF6C7168FF6B7067FF797E75FF7A7F76FF
+ 666B62FF858A81FF686D64FF787D74FF767B72FF91968DFF8C9188FF6B7067FF
+ 696E65FF595E55FF60655CFF61665DFF656A61FF555A51FF4D5249FF797E75FF
+ 565B52FF70756CFF696E65FF83887FFF6A6F66FF747970FF686D64FF5F645BFF
+ 5D6259FF73786FFF5F645BFF7C8178FF9DA299FF71766DFF858A81FF686D64FF
+ 757A71FF666B62FF6E736AFF5F645BFF80857CFF93988FFF797E75FF83887FFF
+ 979C93FF80857CFF797F74FF777D72FF7B8176FF7E8479FF767C71FF6E7469FF
+ 7B8176FF92988DFF878D82FF8D9388FF9CA297FFACB2A7FF898A86FF91928EFF
+ 91928EFF8E8F8BFF8E8F8BFF868783FF82837FFF898A86FF80817DFF757672FF
+ 6E6F6BFF757672FF838480FF8D8E8AFF8E8F8BFF8B8C88FF636762FF6D716CFF
+ 757974FF6C706BFF646863FF717570FF767A75FF686C67FF5E625DFF5C605BFF
+ 616560FF5F635EFF7C807BFF636762FF6C706BFF858984FF6D6E6AFF676864FF
+ 71726EFF71726EFF71726EFF6F706CFF60615DFF61625EFF62635FFF70716DFF
+ 737470FF868783FF898A86FF797A76FF737470FF60615DFF838480FF72736FFF
+ 666763FF656662FF636460FF636460FF71726EFF868783FF676864FF6F706CFF
+ 757672FF888985FF8D8E8AFF838480FF777874FF81827EFF72736FFF656662FF
+ 6B6C68FF737470FF565753FF666763FF787975FF747571FF888985FF72736FFF
+ 6D6E6AFF636460FF70716DFF757672FF848581FF7C7D79FF9A9E99FF7E827DFF
+ 6C706BFF7F837EFF90948FFF7E827DFF777B76FF8D918CFF838782FF818580FF
+ 787C77FF80847FFF747873FF636762FF696D68FF5C605BFF656964FF4E524DFF
+ 666A65FF5C605BFF5B5F5AFF626661FF434742FF555954FF686C67FF686C67FF
+ 737772FF656964FF787C77FF787C77FF898D88FF858984FF888C87FF7C807BFF
+ 80847FFF848883FF80847FFF8A8E89FF858984FF666A65FF686C67FF6B6F6AFF
+ 676B66FF686C67FF6A6E69FF626661FF656964FF7B7F7AFF737772FF666A65FF
+ 6E726DFF6C706BFF757974FF838782FF7F837EFF8A8E89FF8C908BFF7F837EFF
+ 787C77FF737772FF6E726DFF757974FF7C807BFF777B76FF7D7E7AFF7A7975FF
+ 6C6B67FF73726EFF757470FF7B7A76FF878682FF706F6BFF676662FF6C6B67FF
+ 555450FF5F5E5AFF62615DFF5A5955FF676662FF757771FF525650FF565B52FF
+ 656A61FF666B62FF7E837AFF72776EFF80857CFF7C8178FF7C8178FF797E75FF
+ 767B72FF73786FFF6F746BFF63685FFF53584FFF474C43FF4E534AFF4D5249FF
+ 545950FF656A61FF797E75FF80857CFF747970FF656A61FF5D6259FF787D74FF
+ 93988FFF93988FFF747970FF8B9087FF7D8279FF81867DFF7C8178FF898E85FF
+ 80857CFF70756CFF787D74FF82877EFF80857CFF7F847BFF8A8F86FF7D8279FF
+ 787D74FF93988FFF959A91FF858A81FF8A8F86FF7F847BFF61625EFF5C5B57FF
+ 5B5A56FF63625EFF6B6A66FF6E6D69FF6F6E6AFF706F6BFF6E6D69FF62615DFF
+ 63625EFF6E6D69FF777672FF81807CFF7F7E7AFF70726CFF5D615BFF71766DFF
+ 878C83FF898E85FF73786FFF62675EFF6D7269FF858A81FF898E85FF70756CFF
+ 555A51FF787D74FF83887FFF858A81FF6F746BFF7F847BFF83887FFF83887FFF
+ 8C9188FF747970FF6A6F66FF6F746BFF6C7168FF898E85FF7C8178FF8C9188FF
+ 73786FFF676C63FF666B62FF6C7168FF7A7F76FF5F645BFF545950FF61665DFF
+ 545950FF5D6259FF51564DFF575C53FF4E534AFF60655CFF5D6259FF71766DFF
+ 5C6158FF747970FF7A7F76FF82877EFF6D7269FF565B52FF646960FF82877EFF
+ A5AAA1FF7D8279FF8A8F86FF6B7067FF7D8279FF7B8077FF747970FF656A61FF
+ 72776EFF777C73FF646960FF6E736AFF81867DFF777C73FF80867BFF71776CFF
+ 6B7166FF757B70FF7B8176FF787E73FF797F74FF7F857AFF6B7166FF6E7469FF
+ 777D72FF81877CFF6D6E6AFF6C6D69FF757672FF7B7C78FF787975FF7B7C78FF
+ 7E7F7BFF787975FF8D8E8AFF838480FF7F807CFF848581FF858682FF80817DFF
+ 7F807CFF848581FF757974FF787C77FF6D716CFF636762FF696D68FF6E726DFF
+ 6D716CFF717570FF868A85FF757974FF6D716CFF6C706BFF7E827DFF666A65FF
+ 656964FF757974FF737470FF656662FF60615DFF7E7F7BFF848581FF696A66FF
+ 636460FF636460FF7C7D79FF72736FFF5D5E5AFF696A66FF70716DFF6D6E6AFF
+ 7D7E7AFF7F807CFF7D7E7AFF797A76FF787975FF757672FF686965FF5D5E5AFF
+ 636460FF71726EFF6A6B67FF6A6B67FF62635FFF797A76FF6A6B67FF848581FF
+ 7F807CFF82837FFF72736FFF6F706CFF80817DFF878884FF898A86FF777874FF
+ 767773FF747571FF7F807CFF767773FF5F605CFF5F605CFF686965FF737470FF
+ 6B6C68FF6D6E6AFF919590FF7B7F7AFF6A6E69FF777B76FF8B8F8AFF858984FF
+ 7E827DFF8B8F8AFF80847FFF878B86FF797D78FF828681FF868A85FF747873FF
+ 6F736EFF686C67FF767A75FF636762FF727671FF636762FF5D615CFF60645FFF
+ 444843FF4E524DFF797D78FF6C706BFF6C706BFF686C67FF757974FF6A6E69FF
+ 6B6F6AFF656964FF7B7F7AFF888C87FF969A95FF898D88FF727671FF747873FF
+ 7D817CFF737772FF747873FF777B76FF757974FF797D78FF7D817CFF737772FF
+ 717570FF828681FF7A7E79FF747873FF7D817CFF767A75FF7B7F7AFF8A8E89FF
+ 838782FF888C87FF8D918CFF8B8F8AFF898D88FF919590FF979B96FF888C87FF
+ 7A7E79FF7F837EFF90918DFF81827EFF6D6E6AFF737470FF6F706CFF70716DFF
+ 878884FF81827EFF737470FF6D6E6AFF494A46FF70716DFF696A66FF656662FF
+ 686965FF8A8C86FF71756FFF767B72FF83887FFF6E736AFF70756CFF5D6259FF
+ 52574EFF575C53FF81867DFF7B8077FF72776EFF6B7067FF656A61FF5D6259FF
+ 52574EFF4A4F46FF575C53FF5A5F56FF5C6158FF5B6057FF5B6057FF5D6259FF
+ 646960FF6A6F66FF676C63FF686D64FF6F746BFF73786FFF787D74FF969B92FF
+ 7E837AFF72776EFF898E85FF888D84FF7E837AFF7B8077FF80857CFF7B8077FF
+ 767B72FF80857CFF7A7F76FF72776EFF787D74FF91968DFF8C9188FF868B82FF
+ 91968DFF777C73FF646561FF61625EFF585955FF4C4D49FF4B4C48FF575854FF
+ 666763FF6D6E6AFF6A6B67FF6C6D69FF6F706CFF6E6F6BFF686965FF646561FF
+ 636460FF62645EFF6D716BFF71766DFF7E837AFF83887FFF71766DFF666B62FF
+ 858A81FFB3B8AFFF9BA097FF686D64FF4D5249FF6E736AFF73786FFF757A71FF
+ 71766DFF7F847BFF7D8279FF868B82FF8F948BFF777C73FF72776EFF80857CFF
+ 72776EFF6A6F66FF898E85FF7A7F76FF63685FFF6D7269FF6C7168FF5C6158FF
+ 61665DFF5F645BFF71766DFF8D9289FF62675EFF62675EFF50554CFF4A4F46FF
+ 686D64FF71766DFF656A61FF757A71FF63685FFF6D7269FF61665DFF787D74FF
+ 797E75FF5F645BFF6F746BFF71766DFF7E837AFF696E65FF8C9188FF787D74FF
+ 7B8077FF6E736AFF898E85FF848980FF81867DFF7E837AFF7B8077FF81867DFF
+ 8B9087FF8F948BFF868C81FF787E73FF71776CFF7B8176FF83897EFF81877CFF
+ 7D8378FF7D8378FF71776CFF70766BFF757B70FF7E8479FF797A76FF646561FF
+ 646561FF6B6C68FF6A6B67FF787975FF7C7D79FF656662FF70716DFF6B6C68FF
+ 6E6F6BFF787975FF787975FF6F706CFF72736FFF7E7F7BFF777B76FF747873FF
+ 5E625DFF585C57FF6A6E69FF6A6E69FF666A65FF767A75FF7A7E79FF7B7F7AFF
+ 787C77FF737772FF818580FF888C87FF888C87FF838782FF8D8E8AFF82837FFF
+ 6D6E6AFF8D8E8AFF92938FFF72736FFF797A76FF747571FF8B8C88FF81827EFF
+ 72736FFF878884FF8D8E8AFF7E7F7BFF848581FF838480FF777874FF80817DFF
+ 8B8C88FF8E8F8BFF848581FF777874FF71726EFF72736FFF70716DFF6E6F6BFF
+ 70716DFF797A76FF636460FF797A76FF7B7C78FF6C6D69FF787975FF82837FFF
+ 9E9F9BFFA8A9A5FFC1C2BEFF91928EFF7C7D79FF797A76FF80817DFF838480FF
+ 747571FF6A6B67FF7D7E7AFF777874FF6C6D69FF737470FF626661FF70746FFF
+ 686C67FF5E625DFF70746FFF818580FF797D78FF6C706BFF777B76FF838782FF
+ 70746FFF7C807BFF919590FF818580FF797D78FF787C77FF80847FFF757974FF
+ 7E827DFF6F736EFF6B6F6AFF70746FFF5B5F5AFF5E625DFF828681FF717570FF
+ 6F736EFF787C77FF80847FFF747873FF70746FFF727671FF6F736EFF898D88FF
+ 989C97FF858984FF6D716CFF70746FFF818580FF888C87FF7B7F7AFF787C77FF
+ 727671FF777B76FF7E827DFF737772FF696D68FF727671FF757974FF777B76FF
+ 838782FF757974FF717570FF7C807BFF737772FF777B76FF757974FF868A85FF
+ 868A85FF878B86FF90948FFF7E827DFF6C706BFF757974FF92938FFF838480FF
+ 757672FF81827EFF787975FF6C6D69FF81827EFF838480FF686965FF5D5E5AFF
+ 3D3E3AFF595A56FF585955FF474844FF434440FF555751FF3E423CFF4E534AFF
+ 62675EFF5C6158FF72776EFF7D8279FF767B72FF8C9188FF83887FFF7D8279FF
+ 767B72FF71766DFF70756CFF6F746BFF6E736AFF6C7168FF63685FFF747970FF
+ 868B82FF898E85FF797E75FF666B62FF60655CFF646960FF676C63FF676C63FF
+ 70756CFF6A6F66FF6A6F66FF767B72FF73786FFF8B9087FF7E837AFF7E837AFF
+ 757A71FF777C73FF878C83FF878C83FF7C8178FF7C8178FF767B72FF73786FFF
+ 777C73FF878C83FF7D8279FF80857CFF91968DFF73786FFF7E7F7BFF797A76FF
+ 666763FF4E4F4BFF494A46FF5B5C58FF6D6E6AFF747571FF72736FFF7C7D79FF
+ 7C7D79FF757672FF6E6F6BFF656662FF62635FFF686A64FF727670FF686D64FF
+ 666B62FF6B7067FF6C7168FF6F746BFF82877EFF9CA198FF7D8279FF686D64FF
+ 6A6F66FF73786FFF62675EFF686D64FF747970FF73786FFF6D7269FF72776EFF
+ 7D8279FF7B8077FF7E837AFF878C83FF747970FF565B52FF92978EFF7B8077FF
+ 767B72FF90958CFF91968DFF747970FF70756CFF7F847BFF5C6158FF8B9087FF
+ 767B72FF6B7067FF5E635AFF595E55FF70756CFF696E65FF686D64FF6D7269FF
+ 5F645BFF6C7168FF52574EFF6C7168FF858A81FF7A7F76FF6D7269FF61665DFF
+ 61665DFF5A5F56FF848980FF7A7F76FF767B72FF696E65FF797E75FF83887FFF
+ 7F847BFF7F847BFF8D9289FF8D9289FF888D84FF92978EFF7E8479FF7E8479FF
+ 81877CFF858B80FF82887DFF7B8176FF7C8277FF83897EFF767C71FF72786DFF
+ 71776CFF777D72FF8D8E8AFF7D7E7AFF7B7C78FF767773FF676864FF6C6D69FF
+ 6D6E6AFF545551FF5F605CFF5E5F5BFF646561FF6C6D69FF6B6C68FF646561FF
+ 666763FF70716DFF626661FF717570FF6F736EFF6C706BFF6F736EFF60645FFF
+ 5B5F5AFF747873FF656964FF636762FF616560FF666A65FF696D68FF7B7F7AFF
+ 848883FF868A85FF8E8F8BFF92938FFF7E7F7BFF90918DFF91928EFF7D7E7AFF
+ 868783FF787975FF7B7C78FF72736FFF666763FF7B7C78FF81827EFF71726EFF
+ 797A76FF787975FF6E6F6BFF72736FFF747571FF747571FF787975FF7E7F7BFF
+ 81827EFF81827EFF838480FF797A76FF838480FF6D6E6AFF666763FF71726EFF
+ 8F908CFF82837FFF7E7F7BFF81827EFF888985FF858682FFA4A5A1FF7F807CFF
+ 787975FF878884FF7D7E7AFF838480FF8C8D89FF70716DFF8F908CFF6F706CFF
+ 737470FF757672FF5A5E59FF70746FFF6B6F6AFF595D58FF616560FF6F736EFF
+ 6B6F6AFF636762FF6A6E69FF757974FF60645FFF6D716CFF858984FF7A7E79FF
+ 757974FF767A75FF6E726DFF6D716CFF737772FF6A6E69FF6D716CFF797D78FF
+ 717570FF6F736EFF898D88FF7C807BFF767A75FF828681FF7A7E79FF6A6E69FF
+ 616560FF6A6E69FF6F736EFF747873FF6F736EFF696D68FF70746FFF797D78FF
+ 7A7E79FF787C77FF787C77FF70746FFF646863FF696D68FF767A75FF6C706BFF
+ 5F635EFF646863FF616560FF666A65FF7A7E79FF717570FF6E726DFF787C77FF
+ 747873FF7E827DFF7A7E79FF929691FF878B86FF6D716CFF6E726DFF70746FFF
+ 717570FF7E827DFF737470FF6E6F6BFF72736FFF8C8D89FF81827EFF6A6B67FF
+ 747571FF70716DFF71726EFF6D6E6AFF5C5D59FF5B5C58FF6F706CFF545551FF
+ 51524EFF42443EFF464A44FF595E55FF53584FFF51564DFF6A6F66FF797E75FF
+ 6E736AFF80857CFF868B82FF81867DFF7A7F76FF757A71FF747970FF757A71FF
+ 777C73FF787D74FF7A7E78FF757973FF777B75FF828680FF888C86FF838781FF
+ 7B7F79FF777B75FF636761FF6F736DFF757973FF5C605AFF696D67FF787C76FF
+ 6F736DFF787C76FF5B6057FF72776EFF71766DFF646960FF70756CFF83887FFF
+ 888D84FF878C83FF898E85FF888D84FF80857CFF82877EFF777C73FF7A7F76FF
+ 8D9289FF797E75FF81827EFF848581FF7E7F7BFF737470FF72736FFF777874FF
+ 72736FFF666763FF737470FF6C6D69FF555652FF51524EFF666763FF6A6B67FF
+ 5E5F5BFF5F615BFF6F736DFF73786FFF787D74FF7B8077FF7E837AFF7B8077FF
+ 71766DFF666B62FF585D54FF5A5F56FF7C8178FF8B9087FF7D8279FF757A71FF
+ 7F847BFF777C73FF666B62FF646960FF71766DFF7D8279FF70756CFF6D7269FF
+ 7A7F76FF757A71FF6E736AFF73786FFF72776EFF63685FFF60655CFF6D7269FF
+ 72776EFF73786FFF686D64FF73786FFF72776EFF686D64FF686D64FF61665DFF
+ 6E736AFF82877EFF7A7F76FF6E736AFF61665DFF82877EFF6B7067FF696E65FF
+ 676C63FF555A51FF61665DFF696E65FF72776EFF696E65FF797E75FF6F746BFF
+ 797E75FF83887FFF71766DFF81867DFF797E75FF797E75FF8F948BFF8A8F86FF
+ 7B8077FF858A81FF73796EFF757B70FF797F74FF7B8176FF787E73FF72786DFF
+ 72786DFF757B70FF767C71FF6D7368FF666C61FF656B60FF7E7F7BFF898A86FF
+ 939490FF868783FF6E6F6BFF666763FF636460FF585955FF7D7E7AFF7C7D79FF
+ 7B7C78FF777874FF71726EFF6B6C68FF666763FF636460FF7F837EFF7D817CFF
+ 727671FF6C706BFF6E726DFF686C67FF676B66FF717570FF7E827DFF5F635EFF
+ 535752FF6A6E69FF585C57FF575B56FF636762FF7D817CFF797A76FF82837FFF
+ 7D7E7AFF848581FF888985FF838480FF81827EFF6F706CFF8B8C88FF848581FF
+ 71726EFF7C7D79FF82837FFF81827EFF979894FF9FA09CFF6B6C68FF6B6C68FF
+ 676864FF62635FFF696A66FF757672FF757672FF6D6E6AFF5B5C58FF6A6B67FF
+ 949591FF8F908CFF9C9D99FF8B8C88FF949591FF7F807CFF737470FF747571FF
+ 6A6B67FF61625EFF72736FFF656662FF686965FF80817DFF646561FF676864FF
+ 838480FF686965FF888985FF676864FF7C7D79FF797A76FF696D68FF686C67FF
+ 60645FFF60645FFF656964FF60645FFF676B66FF7E827DFF6B6F6AFF6F736EFF
+ 5E625DFF6C706BFF7A7E79FF70746FFF70746FFF6A6E69FF6E726DFF757974FF
+ 747873FF6B6F6AFF6E726DFF7B7F7AFF7A7E79FF70746FFF848883FF828681FF
+ 80847FFF8F938EFF7E827DFF727671FF656964FF70746FFF6A6E69FF6D716CFF
+ 666A65FF686C67FF727671FF6E726DFF686C67FF727671FF7F837EFF747873FF
+ 626661FF5F635EFF646863FF585C57FF4E524DFF555954FF5B5F5AFF575B56FF
+ 696D68FF6A6E69FF6B6F6AFF717570FF6C706BFF7B7F7AFF7B7F7AFF929691FF
+ 8F938EFF747873FF6C706BFF757974FF7A7E79FF7C807BFF6B6C68FF656662FF
+ 636460FF787975FF72736FFF666763FF7A7B77FF7B7C78FF5C5D59FF5F605CFF
+ 555652FF474844FF6A6B67FF555652FF535450FF31332DFF3F433DFF646960FF
+ 454A41FF555A51FF757A71FF81867DFF7B8077FF83887FFF90958CFF8B9087FF
+ 83887FFF7B8077FF757A71FF70756CFF6D7269FF6B7067FF838781FF747872FF
+ 6A6E68FF6C706AFF727670FF7A7E78FF8B8F89FF9DA19BFF7C807AFF878B85FF
+ 747872FF393D37FF595D57FF777B75FF60645EFF474B45FF61665DFF60655CFF
+ 676C63FF777C73FF747970FF63685FFF80857CFFC0C5BCFF969B92FF9DA299FF
+ 888D84FF82877EFF7F847BFF7B8077FF898E85FF868B82FF7C7D79FF7E7F7BFF
+ 81827EFF878884FF8F908CFF92938FFF878884FF797A76FF797A76FF6E6F6BFF
+ 40413DFF20211DFF2C2D29FF393A36FF4B4C48FF6E706AFF70746EFF80857CFF
+ 8B9087FF878C83FF81867DFF80857CFF7B8077FF72776EFF777C73FF63685FFF
+ 767B72FF878C83FF8F948BFF797E75FF83887FFF8C9188FF83887FFF676C63FF
+ 60655CFF767B72FF6B7067FF666B62FF878C83FF898E85FF848980FF82877EFF
+ 878C83FF72776EFF666B62FF6A6F66FF656A61FF6F746BFF83887FFF666B62FF
+ 686D64FF777C73FF82877EFF565B52FF53584FFF767B72FF646960FF696E65FF
+ 666B62FF8A8F86FF6F746BFF5D6259FF5B6057FF60655CFF62675EFF6D7269FF
+ 6D7269FF646960FF6F746BFF70756CFF73786FFF787D74FF898E85FF90958CFF
+ 82877EFF7D8279FF8E938AFF898E85FF7A7F76FF81867DFF71776CFF6A7065FF
+ 676D62FF6C7267FF747A6FFF757B70FF6C7267FF63695EFF777D72FF6C7267FF
+ 63695EFF61675CFF7A7B77FF90918DFF949591FF888985FF838480FF7D7E7AFF
+ 737470FF6E6F6BFF797A76FF7E7F7BFF7D7E7AFF797A76FF7E7F7BFF888985FF
+ 858682FF787975FFA2A6A1FF8A8E89FF757974FF6A6E69FF696D68FF757974FF
+ 7C807BFF747873FF7F837EFF5F635EFF5A5E59FF80847FFF6C706BFF717570FF
+ 7C807BFF939792FF7C7D79FF72736FFF767773FF767773FF81827EFF8B8C88FF
+ 7B7C78FF747571FF686965FF767773FF757672FF838480FF858682FF7D7E7AFF
+ 868783FF7F807CFF757672FF7C7D79FF7A7B77FF737470FF757672FF7B7C78FF
+ 71726EFF5F605CFF838480FF7D7E7AFF6B6C68FF595A56FF686965FF7C7D79FF
+ 9A9B97FFB4B5B1FF767773FF81827EFF787975FF767773FF6D6E6AFF6B6C68FF
+ 636460FF70716DFF70716DFF6B6C68FF81827EFF787975FF848581FF797A76FF
+ 8E8F8BFF888985FF70746FFF686C67FF5F635EFF656964FF6D716CFF656964FF
+ 6B6F6AFF868A85FF737772FF70746FFF696D68FF7A7E79FF787C77FF6E726DFF
+ 737772FF636762FF747873FF80847FFF797D78FF6E726DFF70746FFF7C807BFF
+ 80847FFF70746FFF696D68FF777B76FF80847FFFA0A49FFF999D98FFA0A49FFF
+ 939792FF9A9E99FF727671FF7C807BFF7E827DFF858984FF878B86FF6C706BFF
+ 626661FF7C807BFF7F837EFF787C77FF646863FF565A55FF4E524DFF3E423DFF
+ 3C403BFF4F534EFF696D68FF515550FF585C57FF60645FFF686C67FF666A65FF
+ 575B56FF636762FF5D615CFF656964FF737772FF737772FF6B6F6AFF6E726DFF
+ 70746FFF656964FF6E726DFF666A65FF5C605BFF676B66FF636762FF646863FF
+ 80847FFF818580FF696D68FF6A6E69FF4F534EFF4D514CFF656964FF5F635EFF
+ 555954FF393D37FF3F433DFF7D8279FF4A4F46FF6A6F66FF868B82FF80857CFF
+ 7D8279FF747970FF90958CFF8F948BFF8B9087FF848980FF7C8178FF747970FF
+ 6E736AFF6A6F66FF656963FF6E726CFF838781FF949892FF8F938DFF80847EFF
+ 7E827CFF898D87FF797D77FF959993FF979B95FF535751FF545852FF494D47FF
+ 464A44FF5A5E58FF686D64FF5A5F56FF62675EFF7F847BFF7B8077FF5B6057FF
+ 777C73FFC2C7BEFF81867DFF969B92FF7E837AFF7C8178FF8B9087FF7E837AFF
+ 83887FFF949990FF80847FFF777B76FF737772FF7A7E79FF828681FF848883FF
+ 838782FF828681FF797D78FF868A85FF646863FF363A35FF2B2F2AFF2D312CFF
+ 4E524DFF8C908AFF6A6E68FF6D7269FF70756CFF71766DFF70756CFF73786FFF
+ 7F847BFF8A8F86FF8F948BFF7F847BFF7C8178FF70756CFF81867DFF6E736AFF
+ 7A7F76FF888D84FF8F948BFF73786FFF6D7269FF8B9087FF7C8178FF6D7269FF
+ 858A81FF72776EFF797E75FF6B7067FF7C8178FF777C73FF6D7269FF62675EFF
+ 4D5249FF5C6158FF595E55FF595E55FF5C6158FF878C83FF9FA49BFF52574EFF
+ 40453CFF2C3128FF343930FF565B52FF575C53FF73786FFF646960FF62675EFF
+ 747970FF93988FFF696E65FF6F746BFF60655CFF565B52FF656A61FF71766DFF
+ 666B62FF5B6057FF81867DFF80857CFF757A71FF73786FFF7E837AFF7C8178FF
+ 70756CFF6E736AFF6A7065FF686E63FF666C61FF686E63FF6E7469FF70766BFF
+ 6B7166FF63695EFF6F756AFF646A5FFF5B6156FF5C6257FF82837FFF8B8C88FF
+ 777874FF6B6C68FF80817DFF838480FF6D6E6AFF61625EFF737470FF7A7B77FF
+ 767773FF6E6F6BFF787975FF8A8B87FF858682FF71726EFF8F938EFF8D918CFF
+ 949893FF868A85FF6A6E69FF6F736EFF818580FF7B7F7AFF7B7F7AFF727671FF
+ 757974FF939792FF7E827DFF949893FF929691FF8B8F8AFF969793FF737470FF
+ 747571FF70716DFF81827EFF949591FF7D7E7AFF848581FF81827EFF8B8C88FF
+ 7C7D79FF777874FF72736FFF737470FF888985FF868783FF696A66FF71726EFF
+ 6E6F6BFF636460FF656662FF70716DFF6E6F6BFF60615DFF60615DFF72736FFF
+ 62635FFF747571FF787975FF81827EFF6C6D69FF7E7F7BFF8F908CFFA0A19DFF
+ 969793FF969793FF777874FF7B7C78FF6B6C68FF6F706CFF8A8B87FF7C7D79FF
+ 80817DFF848581FF747571FF7B7C78FF858682FF7C7D79FF757974FF7C807BFF
+ 737772FF696D68FF70746FFF727671FF6D716CFF6D716CFF737772FF6C706BFF
+ 6F736EFF838782FF787C77FF6D716CFF777B76FF5E625DFF626661FF737772FF
+ 6C706BFF666A65FF6C706BFF7D817CFF878B86FF757974FF60645FFF717570FF
+ 777B76FF959994FF888C87FF8D918CFF737772FF70746FFF8B8F8AFF868A85FF
+ 80847FFF959994FFA7ABA6FF858984FF676B66FF777B76FF868A85FF868A85FF
+ 787C77FF676B66FF585C57FF4B4F4AFF555954FF747873FF767A75FF4F534EFF
+ 4D514CFF5B5F5AFF6A6E69FF646863FF4D514CFF565A55FF5D615CFF4C504BFF
+ 595D58FF6C706BFF686C67FF6F736EFF7B7F7AFF757974FF5E625DFF616560FF
+ 636762FF737772FF6E726DFF686C67FF757974FF676B66FF6E726DFF696D68FF
+ 373B36FF444843FF464A45FF4C504BFF363A35FF272B25FF242822FF787D74FF
+ 41463DFF73786FFF91968DFF82877EFF858A81FF747970FF848980FF868B82FF
+ 888D84FF888D84FF848980FF7E837AFF787D74FF757A71FF737771FF6E726CFF
+ 797D77FF949892FFA2A6A0FF979B95FF858983FF7D817BFF80847EFF7E827CFF
+ 8E928CFF81857FFF959993FF5E625CFF424640FF656963FF454A41FF666B62FF
+ 686D64FF555A51FF5F645BFF767B72FF7D8279FF787D74FF60655CFF81867DFF
+ 6B7067FF72776EFF91968DFF7F847BFF7E837AFF9CA198FF858984FF777B76FF
+ 6F736EFF727671FF6F736EFF626661FF5C605BFF5E625DFF6E726DFF919590FF
+ 8C908BFF7A7E79FF7D817CFF6E726DFF6E726DFF939791FF757973FF666B62FF
+ 666B62FF797E75FF82877EFF7D8279FF7F847BFF8B9087FF6A6F66FF8A8F86FF
+ 92978EFF686D64FF777C73FF6B7067FF70756CFF6B7067FF70756CFF7E837AFF
+ 9A9F96FFB8BDB4FF898E85FF62675EFF73786FFF5B6057FF5D6259FF6B7067FF
+ 7E837AFF61665DFF656A61FF8A8F86FF797E75FF6D7269FF62675EFF7A7F76FF
+ 4B5047FF5E635AFF868B82FF5D6259FF7F847BFF474C43FF51564DFF71766DFF
+ 5A5F56FF666B62FF656A61FF646960FF595E55FF5E635AFF666B62FF7F847BFF
+ 777C73FF61665DFF5C6158FF676C63FF62675EFF5F645BFF6E736AFF6B7067FF
+ 6A6F66FF71766DFF7A7F76FF7A7F76FF6F746BFF656A61FF5A6055FF666C61FF
+ 6F756AFF6A7065FF61675CFF5E6459FF656B60FF6C7267FF7B8176FF6E7469FF
+ 63695EFF61675CFF90918DFF6D6E6AFF70716DFF7E7F7BFF747571FF7C7D79FF
+ 878884FF737470FF8A8B87FF959692FF70716DFF62635FFF696A66FF7E7F7BFF
+ 9FA09CFF8D8E8AFF7D817CFF797D78FF828681FF8F938EFF898D88FF797D78FF
+ 7D817CFF8F938EFF838782FF737772FF80847FFF747873FF717570FF797D78FF
+ 6C706BFF7F837EFF82837FFF858682FF747571FF939490FF979894FF767773FF
+ 8F908CFFACADA9FF6B6C68FF878884FF787975FF767773FF757672FF767773FF
+ 82837FFF646561FF70716DFF5A5B57FF4D4E4AFF5B5C58FF72736FFF787975FF
+ 6A6B67FF5A5B57FF5B5C58FF999A96FF71726EFF696A66FF656662FF777874FF
+ 80817DFF8B8C88FF7F807CFF989995FF8D8E8AFF7D7E7AFF7C7D79FF7C7D79FF
+ 7D7E7AFF767773FF70716DFF81827EFF898A86FF7B7C78FF6A6B67FF6E6F6BFF
+ 838480FF979894FF7E827DFF8A8E89FF636762FF8B8F8AFFA2A6A1FF8D918CFF
+ 6A6E69FF80847FFF7E827DFF858984FF757974FF7B7F7AFF757974FF757974FF
+ 8F938EFF7B7F7AFF5A5E59FF60645FFF646863FF878B86FF858984FF979B96FF
+ 757974FF545853FF565A55FF70746FFF666A65FF7A7E79FF767A75FF7A7E79FF
+ 6D716CFF6F736EFF717570FF848883FF6C706BFF727671FF717570FF7C807BFF
+ 686C67FF787C77FF747873FF636762FF7B7F7AFF747873FF767A75FF70746FFF
+ 898D88FF7A7E79FF666A65FF646863FF5D615CFF3D413CFF4E524DFF636762FF
+ 525651FF6A6E69FF6E726DFF5E625DFF797D78FF4D514CFF5A5E59FF838782FF
+ 8C908BFF6A6E69FF5B615CFF575D58FF6F7570FF6E746FFF7B817CFF626863FF
+ 757B76FF828883FF727873FF6B716CFF6C726DFF595F5AFF3E443FFF2A302BFF
+ 5B615CFF394039FF434741FF555A51FF5B6057FF858A81FF8D9289FF787D74FF
+ 8F948BFF93988FFF8D9289FF8D9289FF81867DFF767B72FF8E938AFF767B72FF
+ 80857CFF747970FF595D57FF515550FF676B66FF70746FFF727671FF6F736EFF
+ 636762FF737772FF7D817CFF848883FF9B9F9AFF868A85FF878B86FF949893FF
+ 7D817CFF8A8E88FF4F544BFF555A51FF7E837AFF7B8077FF70756CFF6A6F66FF
+ 50554CFF5E635AFF656A61FF60655CFF696E65FF5D6259FF7B8077FF7E837AFF
+ 8B9087FF7D8279FF939994FF555B56FF969C97FF9CA29DFF717772FF5B615CFF
+ 676D68FF5F6560FF5F6560FF555B56FF575D58FF525853FF626863FF747A75FF
+ 6C726DFF777E77FF868A84FF92978EFF7D8279FF6A6F66FF7E837AFF8D9289FF
+ 8B9087FF90958CFF7D8279FF8A8F86FF6F746BFF6B7067FF8F948BFF6B7067FF
+ 888D84FF9CA198FF70756CFF70756CFF777C73FF80857CFF7D8279FF6E736AFF
+ 61665DFF5C6158FF4F544BFF646960FF5B6057FF646960FF767B72FF797E75FF
+ 80857CFF7A7F76FF70756CFF7E837AFF90958CFF73786FFF797E75FF747970FF
+ 8E938AFF8D9289FF868B82FF92978EFF61665DFF60655CFF888D84FF747970FF
+ 5F645BFF6E736AFF6D7269FF7B8077FF686D64FF5E635AFF70756CFF676C63FF
+ 575C53FF6A6F66FF7E837AFF777C73FF696E65FF747970FF656A61FF81867DFF
+ 7B8077FF767B72FF60665BFF656B60FF646A5FFF646A5FFF60665BFF787E73FF
+ 6F756AFFAAB0A5FF61675CFF6A7065FF6E7469FF686E63FF5A5B57FF71726EFF
+ 81827EFF6A6B67FF585955FF757672FF81827EFF60615DFF7B7C78FF71726EFF
+ 60615DFF7C7D79FF82837FFF6C6D69FF797A76FF7C7D79FF80847FFF7E827DFF
+ 80847FFF888C87FF8F938EFF8E928DFF878B86FF818580FF6F736EFF666A65FF
+ 797D78FF757974FF747873FF787C77FF696D68FF767A75FF797A76FF888985FF
+ 7F807CFF6B6C68FF878884FF999A96FFB4B5B1FFA9AAA6FF8A8B87FF8E8F8BFF
+ 8A8B87FFA4A5A1FF9B9C98FF72736FFF6F706CFF6A6B67FF62635FFF61625EFF
+ 676864FF70716DFF737470FF6D6E6AFF666763FF636460FF62635FFF7D7E7AFF
+ 5C5D59FF636460FF5D5E5AFF6A6B67FF80817DFF979894FF898A86FF82837FFF
+ 7B7C78FF8A8B87FF8A8B87FF6A6B67FF61625EFF747571FF71726EFF6F706CFF
+ 7D7E7AFF92938FFF959692FF878884FF81827EFF898A86FF828681FF828681FF
+ 787C77FF989C97FF8F938EFF717570FF696D68FF717570FF848883FF828681FF
+ 737772FF80847FFF848883FF838782FF898D88FF666A65FF7B7F7AFF7E827DFF
+ 717570FF6A6E69FF636762FF70746FFF717570FF757974FF5D615CFF70746FFF
+ 656964FF787C77FF797D78FF818580FF717570FF737772FF777B76FF6B6F6AFF
+ 646863FF727671FF828681FF646863FF5E625DFF7C807BFF6F736EFF676B66FF
+ 6F736EFF757974FF636762FF696D68FF70746FFF686C67FF8B8F8AFF70746FFF
+ 5A5E59FF4B4F4AFF6C706BFF838782FF6D716CFF7B7F7AFF858984FF7C807BFF
+ 999D98FF8C908BFF616560FF666A65FF696D68FF787C77FF707671FF777D78FF
+ 838984FF6C726DFF757B76FF6E746FFF737974FF626863FF585E59FF353B36FF
+ 272D28FF2D332EFF434944FF616762FF787E79FF474E47FF585C56FF6E736AFF
+ 747970FF7D8279FF858A81FF898E85FF8C9188FF7A7F76FF868B82FF8E938AFF
+ 73786FFF757A71FF7A7F76FF7A7F76FF858A81FF8B8F89FF90948FFF868A85FF
+ 868A85FF6C706BFF5B5F5AFF595D58FF4B4F4AFF515550FF50544FFF666A65FF
+ 737772FF7B7F7AFF7F837EFF898D88FF989C97FF949893FF80847EFF7A7F76FF
+ 777C73FF63685FFF5B6057FF63685FFF63685FFF6D7269FF575C53FF585D54FF
+ 61665DFF7C8178FF898E85FF8B9087FF81867DFF7F847BFF9EA49FFF757B76FF
+ 828883FF777D78FF777D78FF737974FF7A807BFF6A706BFF707671FF686E69FF
+ 777D78FF5E645FFF4E544FFF737974FF797F7AFF616861FF797D77FF7E837AFF
+ 777C73FF73786FFF7F847BFF878C83FF83887FFF81867DFF949990FF8D9289FF
+ 83887FFF747970FF878C83FF82877EFF81867DFF979C93FF797E75FF7C8178FF
+ 787D74FF6A6F66FF575C53FF464B42FF3A3F36FF33382FFF545950FF696E65FF
+ 5E635AFF656A61FF73786FFF757A71FF80857CFF7E837AFF989D94FF777C73FF
+ 777C73FF797E75FF8B9087FF6F746BFF72776EFF767B72FF5F645BFF6B7067FF
+ 6D7269FF848980FF8A8F86FF7A7F76FF7C8178FF747970FF656A61FF767B72FF
+ 72776EFF70756CFF81867DFF7F847BFF6F746BFF71766DFF797E75FF757A71FF
+ 72776EFF72776EFF6F746BFF6A6F66FF71766DFF5A5F56FF62685DFF5D6358FF
+ 6B7166FF5A6055FF5C6257FF60665BFF5D6358FF7B8176FF565C51FF5F655AFF
+ 63695EFF60665BFF535450FF656662FF747571FF6F706CFF696A66FF72736FFF
+ 7F807CFF82837FFF636460FF555652FF555652FF80817DFF8B8C88FF6F706CFF
+ 747571FF81827EFF7B7F7AFF7F837EFF7E827DFF797D78FF7D817CFF868A85FF
+ 838782FF797D78FF656964FF60645FFF6E726DFF6D716CFF6C706BFF6C706BFF
+ 60645FFF6A6E69FF6F706CFF6D6E6AFF8B8C88FF858682FF868783FF70716DFF
+ 767773FF8C8D89FF979894FF90918DFF797A76FF7E7F7BFF888985FF898A86FF
+ 90918DFF838480FF8F908CFF7D7E7AFF6F706CFF6E6F6BFF72736FFF70716DFF
+ 696A66FF646561FF656662FF666763FF646561FF868783FF767773FF696A66FF
+ 72736FFF7E7F7BFF72736FFF797A76FF7A7B77FF7D7E7AFF848581FF7C7D79FF
+ 737470FF7B7C78FF787975FF989995FFA6A7A3FF949591FF888985FF8F908CFF
+ 8F908CFF82837FFF898D88FF6B6F6AFF646863FF777B76FF7B7F7AFF757974FF
+ 929691FF858984FF777B76FF757974FF717570FF80847FFF868A85FF888C87FF
+ 8D918CFF717570FF6E726DFF888C87FF8B8F8AFF727671FF6E726DFF5A5E59FF
+ 5B5F5AFF6D716CFF666A65FF6D716CFF60645FFF737772FF7B7F7AFF888C87FF
+ 727671FF747873FF5C605BFF767A75FF797D78FF484C47FF636762FF6F736EFF
+ 7B7F7AFF646863FF787C77FF777B76FF6D716CFF7C807BFF5F635EFF727671FF
+ 6E726DFF70746FFF878B86FF7C807BFF797D78FF777B76FF878B86FF888C87FF
+ 717570FF7A7E79FF8C908BFF757974FF797D78FF8C908BFF686C67FF7D817CFF
+ 7D817CFF929691FF515752FF6F7570FF878D88FF6D736EFF5E645FFF565C57FF
+ 6C726DFF747A75FF6C726DFF595F5AFF5A605BFF595F5AFF525853FF727873FF
+ 606661FF383F38FF484C46FF52574EFF646960FF646960FF72776EFF888D84FF
+ 80857CFF777C73FF80857CFF92978EFF70756CFF7E837AFF70756CFF7A7F76FF
+ 7B8077FF888C86FF818580FF7B7E7CFF7C7F7DFF6C6F6DFF717472FF7C7F7DFF
+ 5E615FFF494C4AFF353836FF565957FF5D605EFF6B6E6CFF565957FF565957FF
+ 8E918FFF868A85FF888C86FF8D9289FF83887FFF878C83FF898E85FF82877EFF
+ 7B8077FF666B62FF646960FF60655CFF5D6259FF898E85FF83887FFF868B82FF
+ 70756CFF7C8178FF717772FF707671FF5B615CFF454B46FF636964FF676D68FF
+ 777D78FF666C67FF848A85FF717772FF8B918CFF777D78FF545A55FF757B76FF
+ 848A85FF646B64FF7E827CFF73786FFF777C73FF7F847BFF7D8279FF7A7F76FF
+ 787D74FF72776EFF767B72FF6F746BFF82877EFF7C8178FF7F847BFF9A9F96FF
+ 7A7F76FF848980FF797E75FF80857CFF7F847BFF71766DFF656A61FF666B62FF
+ 6F746BFF757A71FF5B6057FF6F746BFF63685FFF646960FF6A6F66FF656A61FF
+ 70756CFF72776EFF666B62FF5A5F56FF595E55FF575C53FF757A71FF7D8279FF
+ 7F847BFF6E736AFF686D64FF51564DFF5F645BFF858A81FF7C8178FF7D8279FF
+ 898E85FF5B6057FF585D54FF676C63FF6F746BFF73786FFF83887FFF949990FF
+ 90958CFF83887FFF70756CFF73786FFF757A71FF70756CFF7A7F76FF63685FFF
+ 83887FFF656A61FF6E7469FF646A5FFF82887DFF6A7065FF72786DFF6B7166FF
+ 73796EFF6C7267FF63695EFF686E63FF6A7065FF666C61FF838480FF747571FF
+ 676864FF6C6D69FF6F706CFF5E5F5BFF5D5E5AFF747571FF747571FF737470FF
+ 6C6D69FF6D6E6AFF70716DFF72736FFF767773FF72736FFF7D817CFF848883FF
+ 858984FF7B7F7AFF727671FF757974FF828681FF8C908BFF787C77FF717570FF
+ 717570FF6D716CFF686C67FF646863FF626661FF6A6E69FF8B8C88FF8C8D89FF
+ 9B9C98FF939490FFADAEAAFFE3E4E0FFB0B1ADFF787975FF60615DFF80817DFF
+ 91928EFF8F908CFF888985FF8E8F8BFF9FA09CFFA2A39FFFA1A29EFF8C8D89FF
+ 7A7B77FF787975FF7E7F7BFF7C7D79FF737470FF6C6D69FF676864FF5A5B57FF
+ 747571FF9B9C98FF838480FF6D6E6AFF6E6F6BFF666763FF72736FFF80817DFF
+ 8B8C88FF82837FFF898A86FF91928EFF8A8B87FF959692FF8D8E8AFFB0B1ADFF
+ B6B7B3FF939490FF7F807CFF8C8D89FF939490FF878884FF939792FF8A8E89FF
+ 7C807BFF636762FF6C706BFF666A65FF878B86FF747873FF70746FFF747873FF
+ 7C807BFF80847FFF787C77FF7D817CFF90948FFF919590FF6B6F6AFF80847FFF
+ 8E928DFF8B8F8AFFB8BCB7FF969A95FF747873FF666A65FF6F736EFF6B6F6AFF
+ 60645FFF70746FFF7A7E79FF8B8F8AFF6C706BFF727671FF727671FF717570FF
+ 6E726DFF595D58FF676B66FF6B6F6AFF7E827DFF818580FF737772FF727671FF
+ 696D68FF6E726DFF5F635EFF6C706BFF6D716CFF747873FF6B6F6AFF727671FF
+ 7A7E79FF7B7F7AFF818580FF838782FF777B76FF747873FF797D78FF6D716CFF
+ 777B76FF8F938EFF848883FF959994FF858984FF6E726DFF6E746FFF6A706BFF
+ 707671FF6D736EFF5D635EFF434944FF464C47FF555B56FF515752FF5B615CFF
+ 737974FF676D68FF3D433EFF585E59FF3B413CFF373E37FF4F534DFF42473EFF
+ 5C6158FF5A5F56FF5A5F56FF60655CFF545950FF6E736AFF767B72FF8A8F86FF
+ 767B72FF82877EFF7A7F76FF71766DFF686D64FF666A64FF898D88FF7F8280FF
+ 828583FF757876FF7C7F7DFF8B8E8CFF7C7F7DFF777A78FF626563FF626563FF
+ 626563FF616462FF444745FF4D504EFF797C7AFF676B66FF989C96FF92978EFF
+ 797E75FF959A91FFA2A79EFF8D9289FF8C9188FF757A71FF5D6259FF50554CFF
+ 40453CFF50554CFF474C43FF484D44FF3F443BFF494E45FF313732FF494F4AFF
+ 434944FF3A403BFF4B514CFF464C47FF6E746FFF606661FF747A75FF585E59FF
+ 6C726DFF727873FF626863FF676D68FF686E69FF6B726BFF828680FF6B7067FF
+ 757A71FF868B82FF7C8178FF757A71FF7A7F76FF747970FF787D74FF7E837AFF
+ 8C9188FF92978EFF83887FFFA8ADA4FF93988FFF8F948BFF71766DFF686D64FF
+ 5C6158FF50554CFF43483FFF40453CFF4F544BFF646960FF81867DFF92978EFF
+ 7F847BFF757A71FF6A6F66FF555A51FF585D54FF595E55FF272C23FF363B32FF
+ 3E433AFF383D34FF4C5148FF686D64FF777C73FF6F746BFF858A81FF63685FFF
+ 5A5F56FF6E736AFF62675EFF6D7269FF848980FF5E635AFF61665DFF666B62FF
+ 696E65FF666B62FF6F746BFF8D9289FF979C93FF82877EFF777C73FF7E837AFF
+ 747970FF767B72FF797E75FF6D7269FF999E95FF858A81FF6A7065FF646A5FFF
+ 7D8378FF72786DFF70766BFF72786DFF797F74FF5F655AFF6F756AFF6F756AFF
+ 6D7368FF696F64FF949591FF90918DFF81827EFF787975FF7B7C78FF787975FF
+ 737470FF797A76FF757672FF7C7D79FF7C7D79FF6C6D69FF70716DFF848581FF
+ 858682FF7D7E7AFF888C87FF838782FF868A85FF8D918CFF888C87FF80847FFF
+ 8B8F8AFF9EA29DFF8A8E89FF868A85FF7E827DFF7B7F7AFF747873FF6C706BFF
+ 70746FFF747873FF8D8E8AFF848581FF767773FF777874FF7C7D79FFD7D8D4FF
+ A8A9A5FF787975FF7C7D79FF6B6C68FF747571FF8B8C88FF91928EFF858682FF
+ 82837FFF969793FF747571FF7F807CFF90918DFF989995FF90918DFF81827EFF
+ 7B7C78FF7E7F7BFF70716DFF565753FF71726EFF7C7D79FF666763FF676864FF
+ 7A7B77FF71726EFF898A86FF80817DFF979894FFA1A29EFF9E9F9BFF868783FF
+ 72736FFF9B9C98FF9C9D99FF868783FF838480FF979894FF9C9D99FF8B8C88FF
+ 848581FF8D8E8AFF757974FFB9BDB8FFBDC1BCFF898D88FF8A8E89FF757974FF
+ 8B8F8AFF8F938EFF838782FF818580FF8E928DFF8A8E89FF7B7F7AFF7F837EFF
+ 8D918CFF989C97FF7B7F7AFF727671FF676B66FF70746FFFBFC3BEFFB4B8B3FF
+ 919590FF787C77FF7A7E79FF6E726DFF696D68FF777B76FF7F837EFF90948FFF
+ 676B66FF727671FF797D78FF80847FFF787C77FF787C77FF6B6F6AFF848883FF
+ 8B8F8AFF8D918CFF747873FF757974FF7A7E79FF6E726DFF767A75FF686C67FF
+ 6B6F6AFF6A6E69FF626661FF5E625DFF525651FF545853FF6C706BFF8C908BFF
+ 939792FF7A7E79FF959994FF7F837EFF7F837EFF6E726DFF616560FF676B66FF
+ 9EA29DFFABAFAAFF6B716CFF757C77FF818883FF858C87FF666D68FF464D48FF
+ 3D443FFF4C534EFF414843FF3F4641FF454C47FF383F3AFF1F2621FF444B46FF
+ 303732FF3B423BFF40443EFF40453CFF62675EFF5A5F56FF4F544BFF585D54FF
+ 5A5F56FF81867DFF6A6F66FF777C73FF767B72FF7A7F76FF8E938AFF73786FFF
+ 6F746BFF5D615BFF525651FF565957FF757876FF7C7F7DFF777A78FF727573FF
+ 686B69FF797C7AFF9C9F9DFF717472FF757876FF676A68FF5C5F5DFF787B79FF
+ 727573FF565A55FF656963FF646960FF6B7067FFAFB4ABFFC2C7BEFF8D9289FF
+ 6E736AFF4E534AFF71766DFF676C63FF63685FFF50554CFF565B52FF4D5249FF
+ 51564DFF484D44FF313732FF353C37FF454C47FF515853FF4B524DFF3D443FFF
+ 747B76FF656C67FF666D68FF5F6661FF5F6661FF646B66FF79807BFF707772FF
+ 565D58FF737A73FF6F736DFF5B6057FF6C7168FF858A81FF7E837AFF767B72FF
+ 7C8178FF787D74FF7F847BFF92978EFF787D74FF7A7F76FF5B6057FF6F746BFF
+ 7E837AFF72776EFF868B82FF676C63FF50554CFF4A4F46FF3C4138FF2C3128FF
+ 3A3F36FF585D54FF777C73FF8B9087FF81867DFF82877EFF7E837AFF6E736AFF
+ 767B72FF7D8279FF767B72FF696E65FF666B62FF757A71FF72776EFF6D7269FF
+ 777C73FF90958CFF7A7F76FF81867DFF72776EFF6B7067FF5F645BFF5C6158FF
+ 797E75FF80857CFF767B72FF777C73FF72776EFF646960FF646960FF7C8178FF
+ 848980FF70756CFF7F847BFF888D84FF73786FFF7E837AFF696E65FF72776EFF
+ 8A8F86FF83887FFF70766BFF73796EFF73796EFF7E8479FF686E63FF787E73FF
+ 757B70FF5C6257FF878D82FF848A7FFF82887DFF82887DFF9C9D99FF92938FFF
+ 979894FFA4A5A1FF9D9E9AFF8B8C88FF8C8D89FF9A9B97FF7D7E7AFF787975FF
+ 898A86FF8D8E8AFF92938FFF969793FF8B8C88FF92938FFF838782FF6F736EFF
+ 6F736EFF888C87FF979B96FF8F938EFF868A85FF8A8E89FF818580FF858984FF
+ 7C807BFF848883FF80847FFF737772FF7C807BFF7A7E79FF888985FF7D7E7AFF
+ 7D7E7AFF91928EFF646561FF868783FF878884FF989995FFA0A19DFF878884FF
+ 7F807CFF757672FF80817DFF91928EFF888985FF898A86FF797A76FF7D7E7AFF
+ 878884FF91928EFF91928EFF888985FF81827EFF7F807CFF80817DFF646561FF
+ 7F807CFF6D6E6AFF5A5B57FF61625EFF777874FF70716DFF6F706CFF797A76FF
+ 9E9F9BFF989995FF92938FFF878884FF636460FF767773FF8B8C88FF7C7D79FF
+ 777874FF82837FFF878884FF81827EFF838480FF8E8F8BFF555954FFA2A6A1FF
+ 9EA29DFF7D817CFF929691FF90948FFF9DA19CFFACB0ABFF888C87FF7B7F7AFF
+ 8E928DFF919590FF8C908BFF919590FF8B8F8AFF8D918CFF7B7F7AFF80847FFF
+ 7B7F7AFF737772FF888C87FF7F837EFF80847FFF90948FFF80847FFF747873FF
+ 7B7F7AFF858984FF888C87FF969A95FF676B66FF797D78FF676B66FF8D918CFF
+ 8C908BFF80847FFF646863FF979B96FF919590FF717570FF70746FFF777B76FF
+ 858984FF727671FF838782FF616560FF5A5E59FF525651FF5A5E59FF60645FFF
+ 5B5F5AFF636762FF6A6E69FF7D817CFF919590FF787C77FF777B76FF696D68FF
+ 8C908BFF9EA29DFF919590FF5E625DFF858984FF8D938EFF646A65FF7E8580FF
+ 878E89FF8C938EFF7A817CFF787F7AFF5C635EFF474E49FF474E49FF404742FF
+ 3A413CFF333A35FF29302BFF333A35FF282F2AFF313932FF1C201AFF41463DFF
+ 61665DFF4F544BFF484D44FF63685FFF767B72FF848980FF6B7067FF72776EFF
+ 747970FF747970FF989D94FF81867DFF8C9188FF7D817BFF414540FF2E312FFF
+ 3D403EFF4E514FFF5F6260FF646765FF565957FF616462FF8D908EFF737674FF
+ 878A88FF696C6AFF515452FF646765FF525553FF4D514CFF5E625CFF464B42FF
+ 42473EFF72776EFF898E85FF777C73FF757A71FF7B8077FF81867DFF83887FFF
+ 949990FF80857CFF92978EFF82877EFF83887FFF6B7369FF5E645FFF3F4641FF
+ 4D544FFF575E59FF525954FF464D48FF6F7671FF646B66FF676E69FF7B827DFF
+ 6D746FFF5B625DFF7E8580FF7F8681FF59605BFF6F7770FF646862FF5C6158FF
+ 6B7067FF7F847BFF7D8279FF71766DFF6D7269FF6C7168FF8D9289FFABB0A7FF
+ 8A8F86FF868B82FF70756CFF696E65FF7E837AFF71766DFF676C63FF4B5047FF
+ 3A3F36FF3D4239FF393E35FF33382FFF484D44FF696E65FF5E635AFF71766DFF
+ 6B7067FF767B72FF7C8178FF72776EFF80857CFF8C9188FF81867DFF767B72FF
+ 63685FFF6A6F66FF63685FFF6B7067FF656A61FF6A6F66FF70756CFF8B9087FF
+ 777C73FF70756CFF797E75FF6B7067FF6B7067FF72776EFF73786FFF7C8178FF
+ 787D74FF6D7269FF70756CFF7B8077FF7A7F76FF70756CFF6D7269FF72776EFF
+ 6F746BFF7B8077FF5E635AFF757A71FF6D7269FF6E736AFF73796EFF7E8479FF
+ 6D7368FF878D82FF747A6FFF848A7FFF81877CFF767C71FF93998EFF90968BFF
+ 92988DFF9AA095FFA5A6A2FF838480FF8B8C88FFA5A6A2FF989995FF838480FF
+ 82837FFF848581FFA3A4A0FF8E8F8BFF9C9D99FF9B9C98FF969793FF8C8D89FF
+ 787975FF8A8B87FF7F837EFF6F736EFF686C67FF787C77FF8A8E89FF8A8E89FF
+ 7E827DFF757974FF777B76FF7F837EFF727671FF7F837EFF80847FFF757974FF
+ 888C87FF868A85FF6C6D69FF7A7B77FF858682FF797A76FF6E6F6BFF8C8D89FF
+ A7A8A4FF797A76FF6F706CFFA1A29EFFCACBC7FF9D9E9AFF7F807CFF92938FFF
+ 8F908CFF90918DFF9C9D99FF898A86FF7A7B77FF7E7F7BFF888985FF8B8C88FF
+ 858682FF7F807CFF8C8D89FF737470FF949591FF7B7C78FF6B6C68FF61625EFF
+ 696A66FF6A6B67FF5B5C58FF797A76FFA0A19DFF7F807CFF838480FF9C9D99FF
+ 70716DFF656662FF787975FF8E8F8BFF90918DFF7A7B77FF747571FF878884FF
+ 8F908CFF868783FF656964FF757974FF555954FF585C57FF646863FF6C706BFF
+ 6D716CFF6E726DFF737772FF676B66FF858984FF898D88FF828681FF868A85FF
+ 797D78FF80847FFF7D817CFF969A95FFA5A9A4FFA3A7A2FF7F837EFF70746FFF
+ 797D78FF999D98FF7D817CFF757974FF888C87FF929691FF8F938EFF9A9E99FF
+ 676B66FF80847FFF80847FFF717570FF7C807BFF8F938EFF787C77FF6E726DFF
+ 727671FF757974FF5D615CFF6C706BFF6B6F6AFF626661FF6A6E69FF575B56FF
+ 474B46FF4C504BFF626661FF6B6F6AFF787C77FF8F938EFF797D78FF646863FF
+ 797D78FF6E726DFF989C97FF7F837EFF7C807BFF989C97FF868A85FF626661FF
+ 747873FF686E69FF9FA5A0FF888F8AFF636A65FF787F7AFF919893FFAAB1ACFF
+ 6F7671FF343B36FF303732FF313833FF2D342FFF323934FF3A413CFF232A25FF
+ 2C332EFF353D36FF343832FF5D6259FF666B62FF5A5F56FF4F544BFF575C53FF
+ 646960FF565B52FF70756CFF7A7F76FF6C7168FF72776EFF83887FFF7C8178FF
+ 878C83FF858983FF9FA2A0FF6B6D6DFF424444FF262828FF313333FF4F5151FF
+ 575959FF666868FF676969FF6C6E6EFF6A6C6CFF484A4AFF2B2D2DFF2B2D2DFF
+ 333535FF3D403EFF383C36FF30352CFF494E45FF676C63FF7C8178FF7F847BFF
+ 72776EFF797E75FF6C7168FF6E736AFF787D74FF7D8279FF848980FF7D8279FF
+ 797E75FF71796FFF777D78FF5B625DFF5E6560FF4C534EFF585F5AFF4D544FFF
+ 565D58FF646B66FF6A716CFF6F7671FF686F6AFF59605BFF6B726DFF6F7671FF
+ 585F5AFF6C746DFF6A6E68FF6C7168FF6C7168FF72776EFF787D74FF71766DFF
+ 6D7269FF777C73FF858A81FF959A91FF868B82FF70756CFF7A7F76FF70756CFF
+ 797E75FF82877EFF6E736AFF676C63FF5C6158FF50554CFF484D44FF4E534AFF
+ 63685FFF787D74FF797E75FF81867DFF6E736AFF6D7269FF6A6F66FF585D54FF
+ 61665DFF6B7067FF6F746BFF7D8279FF6C7168FF676C63FF60655CFF81867DFF
+ 767B72FF676C63FF797E75FF848980FF6D7269FF73786FFF898E85FF81867DFF
+ 73786FFF5E635AFF666B62FF797E75FF757A71FF6F746BFF7B8077FF7A7F76FF
+ 72776EFF7B8077FF60655CFF555A51FF747970FF6D7269FF63685FFF787D74FF
+ 61665DFF656A61FF61675CFF6F756AFF5E6459FF72786DFF797F74FF71776CFF
+ 7A8075FF797F74FF757B70FF71776CFF747A6FFF80867BFF7F807CFF72736FFF
+ 787975FF7D7E7AFF8A8B87FFBABBB7FFC1C2BEFF8A8B87FF90918DFF7E7F7BFF
+ 898A86FF7D7E7AFF7F807CFF90918DFF8C8D89FFA2A39FFF8C908BFF898D88FF
+ 80847FFF777B76FF7A7E79FF838782FF838782FF7C807BFF7F837EFF848883FF
+ 6F736EFF7B7F7AFF7D817CFF787C77FF979B96FF999D98FF969793FF888985FF
+ A5A6A2FF9A9B97FF898A86FF52534FFF969793FF8A8B87FF888985FF7B7C78FF
+ 82837FFF6E6F6BFF72736FFF878884FF747571FF747571FF8D8E8AFF8B8C88FF
+ 8B8C88FF8D8E8AFF8A8B87FF858682FF888985FF8E8F8BFF8F908CFF72736FFF
+ 949591FF7B7C78FF71726EFF60615DFF686965FF7C7D79FF81827EFF7D7E7AFF
+ 9A9B97FF8A8B87FF949591FFA1A29EFF747571FF7F807CFF7A7B77FF7F807CFF
+ 898A86FF989995FFA5A6A2FFA4A5A1FF8F908CFF787975FF757974FF656964FF
+ 525651FF787C77FF5F635EFF5A5E59FF5A5E59FF565A55FF636762FF5F635EFF
+ 858984FF7D817CFF636762FF5F635EFF595D58FF70746FFF7A7E79FF7C807BFF
+ 81827EFF9DA19CFF8B8C88FF8E928DFF80817DFF7E827DFF797A76FF727671FF
+ 8F908CFF979B96FF939490FF9A9E99FF676864FF848883FF878884FF80847FFF
+ 949591FF757974FF6D6E6AFF6B6F6AFF848581FF676B66FF6A6B67FF7A7E79FF
+ 656662FF686C67FF676864FF6E726DFF60615DFF747873FF848883FF6D716CFF
+ 686C67FF929691FF848883FF636762FF767A75FF6D716CFF7E827DFF828681FF
+ 6F736EFF8D918CFF767A75FF848883FF919590FF777B76FF858B86FF7D847FFF
+ 707671FF89908BFF808681FF8A918CFF858B86FF979E99FF525853FF3C433EFF
+ 1E241FFF242B26FF454B46FF212823FF3A403BFF3A403BFF4B524BFF626660FF
+ 5E625CFF737771FF71756FFF5C605AFF656963FF555953FF6D716BFF7E827CFF
+ 60645EFF6D716BFF60645EFF646862FF61655FFF696D67FF818482FF7E8080FF
+ 767878FF474949FF2D2F2FFF3A3C3CFF444646FF585A5AFF686A6AFF646666FF
+ 2A2C2CFF1A1C1CFF212323FF242626FF3A3C3CFF2E312FFF40443EFF3E433AFF
+ 5B6057FF585D54FF63685FFF7A7F76FF696E65FF71766DFF858A81FF7B8077FF
+ 6D7269FF878C83FF7B8077FF83887FFF7F847BFF959A91FF787F78FF79817AFF
+ 7B817CFF4B534CFF646A65FF555D56FF454B46FF707871FF878D88FF646C65FF
+ 6D736EFF788079FF757B76FF6C746DFF6F7570FF8F968FFF6D7269FF747970FF
+ 676C63FF62675EFF767B72FF7E837AFF868B82FF9FA49BFFACB1A8FF9A9F96FF
+ 8E938AFF565B52FF797E75FF868B82FF8E938AFFBCC1B8FF6A6F66FF7A7F76FF
+ 757973FF585D54FF4B4F49FF5E635AFF747872FF7C8178FF787C76FF7E837AFF
+ 6A6E68FF6E736AFF737771FF6A6F66FF7B7F79FF898E85FF787C76FF797E75FF
+ 71756FFF878C83FF71756FFF73786FFF6A6E68FF7D8279FF767A74FF7C8178FF
+ 757973FF7E837AFF80847EFF848980FF8F938DFF7A7F76FF6A6E68FF7F847BFF
+ 737771FF686D64FF767A74FF6B7067FF60645EFF787D74FF6E726CFF50554CFF
+ 858983FF62675EFF6A6E68FF777C73FF60645EFF646960FF686D64FF73796EFF
+ 656B60FF676D62FF858B80FF5E6459FF6F756AFF71776CFF63695EFF5D6358FF
+ 5E6459FF686E63FF80847FFF9CA09BFF838782FF929691FF7E827DFFA9ADA8FF
+ D0D4CFFF90948FFF676B66FF929691FFA0A49FFF9A9E99FFA7ABA6FF7F837EFF
+ 535752FF848883FF858886FF8A8D8BFF909391FF909391FF868987FF7F8280FF
+ 878A88FF969997FF7A7D7BFF959896FF989B99FF757876FF858886FF7D807EFF
+ 868987FF8E918FFF8F9290FF8F9290FFA3A6A4FF929593FF8E918FFF8B8E8CFF
+ 6F7270FF838684FF7E817FFF6E716FFF888B89FF848785FF767977FF6C6F6DFF
+ 5C5F5DFF7F837EFF6B6F6AFF6D716BFF71756FFF848882FF888C86FF81857FFF
+ 8D918BFF90948EFF7E827CFF8D918BFF686C66FF838781FF7C807AFF878B85FF
+ 5E625CFF777B76FF6A6E69FF7B7E7CFF757876FF707371FF7F8280FF818482FF
+ 808381FF909391FF767977FF9EA19FFF777A78FF818482FF7C7F7DFF8D908EFF
+ 919492FF7D817CFF858984FFA5A9A3FF9EA29CFF5C605AFF646862FF626660FF
+ 727670FF747872FF7D817BFF5F635DFF70746EFF6A6E68FF646862FF6D716BFF
+ 666A64FF7A7E79FF868783FF747573FF7F7D7CFF727371FF868483FF7F807EFF
+ 888685FF6A6B69FF9A9897FF70716FFF7B7978FF757674FF8B8988FF8B8C8AFF
+ 6B6968FF989997FF807E7DFF888987FF8B8988FF7A7B79FF888685FF717270FF
+ 7C7A79FF5B5C5AFF636160FF7B7C7AFF5F5D5CFF787977FF757372FF949593FF
+ 706E6DFF777874FF747873FF7D817BFF7A7E78FF71756FFF868A84FF80847EFF
+ 696D67FF8B8F89FF838781FF777B75FF797D77FF9B9F99FF868A84FF949892FF
+ 8F938DFF8D918CFF757974FF727775FF7E817FFF6F7472FF848785FF8B908EFF
+ 717472FF848987FF7C7F7DFF5F6462FF4E514FFF535856FF656866FF6B706EFF
+ 707371FF727775FF717772FF717772FF6F7570FF6F7570FF7B817CFF888E89FF
+ 878D88FF7E847FFF636964FF646A65FF636964FF6E746FFF7A807BFF707671FF
+ 676D68FF707671FF6C716FFF3A3F3DFF282D2BFF707573FF828785FF595E5CFF
+ 545957FF3F4442FF555A58FF3C413FFF1A1F1DFF121715FF232826FF2C312FFF
+ 2B302EFF303631FF50544EFF5F645BFF62675EFF61665DFF63685FFF5B6057FF
+ 575C53FF60655CFF757A71FF999E95FF82877EFF80857CFF858A81FF91968DFF
+ 747970FF82877EFF7F847BFF8C948AFF7E827CFF6A7268FF71756FFF676F65FF
+ 5E625CFF676F65FF6C706AFF71796FFF8E928CFF5F675DFF5E625CFF788076FF
+ 5D615BFF6F746BFF6E736AFF787D74FF676C63FF747970FF60655CFF565B52FF
+ 52574EFF888D84FF898E85FF7B8077FF6C7168FF787D74FF666B62FF777C73FF
+ 7A7F76FF81867DFF7D7F79FF6E706AFF636460FF666862FF70716DFF767872FF
+ 787975FF7A7C76FF7D7E7AFF8A8C86FF80817DFF747670FF7B7C78FF797B75FF
+ 7D7E7AFF959791FF656964FF676B65FF7E827DFF828680FF6B6F6AFF6B6F69FF
+ 757974FF696D67FF767A75FF787C76FF727671FF737771FF7E827DFF7D817BFF
+ 7A7E79FF848882FF8C928DFF787F78FF757B76FF697069FF787E79FF676E67FF
+ 686E69FF5D645DFF5B615CFF535A53FF5C625DFF5F665FFF6E746FFFB7BEB7FF
+ 545A55FF656C65FF71796FFF60685EFF4F574DFF6C746AFF525A50FF6B7369FF
+ 50584EFF71796FFF70786EFF626A60FF6C746AFF71796FFF787C77FF898D88FF
+ 828681FF959994FF6F736EFF7B7F7AFF8D918CFF686C67FF737772FF7E827DFF
+ 747873FF6C706BFF9B9F9AFFA9ADA8FF838782FF8C908BFF868987FF8C8F8DFF
+ 8D908EFF848785FF7A7D7BFF7E817FFF919492FFA3A6A4FF848785FF8A8D8BFF
+ 8E918FFF828583FF999C9AFF848785FF878A88FF959896FF8D908EFF999C9AFF
+ 959896FF979A98FF989B99FF878A88FF808381FF828583FF7A7D7BFF777A78FF
+ 7A7D7BFF8B8E8CFF858886FF707371FF727573FF7D817CFF737772FF595D57FF
+ 777B75FF8D918BFF6F736DFF828680FF9FA39DFF747872FF8C908AFF979B95FF
+ 81857FFF8F938DFF797D77FFA4A8A2FF8E928CFF7F837DFF727573FF7A7D7BFF
+ 787B79FF747775FF757876FF757876FF7E817FFF909391FF7B7E7CFF878A88FF
+ 8F9290FF7B7E7CFF6E716FFF8D908EFF6A6D6BFF7A7E79FF828681FF949892FF
+ 939791FF6D716BFF7A7E78FF6E726CFF737771FF757973FF8C908AFF7D817BFF
+ 828680FF81857FFF7E827CFF7F837DFF80847EFF949892FF7B7C7AFF858382FF
+ 8D8B8AFF8A8887FF747271FF737170FF767473FF767473FF7E7C7BFF737170FF
+ 92908FFF888685FF7D7B7AFF8F8D8CFF7A7877FF696766FF787675FF878584FF
+ 858382FF807E7DFF858382FF7D7B7AFF868483FF716F6EFF6F6D6CFF787675FF
+ 737170FF757372FF807E7DFF868483FF797776FF70716DFF7F837EFF80847EFF
+ 7B7F79FF7A7E78FF979B95FF91958FFF6C706AFF7B7F79FF828680FF8D918BFF
+ 747872FF666A64FF868A84FF7E827CFF7F837DFFA7ABA5FF898C8AFF727573FF
+ 6A6D6BFF636664FF858886FF8F9290FF828583FF7D807EFF6B6E6CFF666967FF
+ 676A68FF707371FF757876FF737674FF6F7270FF6D706EFF5F6462FF5B605EFF
+ 545957FF4F5452FF595E5CFF6B706EFF757A78FF757A78FF777C7AFF717674FF
+ 727775FF858A88FF8D9290FF717674FF5C615FFF676C6AFF7C817FFF5D6260FF
+ 3F4442FF444947FF6E7371FF7E8381FF686D6BFF626765FF424745FF2B302EFF
+ 141917FF0A0F0DFF0D1210FF1D2220FF343937FF454B46FF585C56FF585D54FF
+ 575C53FF5F645BFF646960FF575C53FF555A51FF6A6F66FF5E635AFF6A6F66FF
+ 656A61FF71766DFF9DA299FF92978EFF73786FFF70756CFF5B6057FF6F746BFF
+ 7C8178FF8F948BFF9EA39AFF898E85FF71766DFF787D74FF7D8279FF6E736AFF
+ 6D7269FF777C73FF7F847BFF6D7269FF595E55FF6A6F66FF70756CFF787D74FF
+ 6F746BFF6F746BFF656A61FF5D6259FF4A4F46FF4D5249FF5F645BFF82877EFF
+ 51564DFF676C63FF50554CFF555A51FF82877EFF63685FFF7E7F7BFF767773FF
+ 747571FF7C7D79FF858682FF868783FF82837FFF7F807CFF777874FF82837FFF
+ 81827EFF7A7B77FF747571FF696A66FF646561FF6C6D69FF6D716CFF565A55FF
+ 575B56FF656964FF6B6F6AFF7A7E79FF818580FF717570FF838782FF777B76FF
+ 676B66FF6D716CFF7E827DFF7C807BFF747873FF7B7F7AFF8C928DFF797F7AFF
+ 777D78FF6C726DFF7C827DFF6B716CFF6A706BFF5F6560FF393F3AFF3F4540FF
+ 4C524DFF414742FF3D433EFF6C726DFF3B413CFF606760FF545B54FF4F574DFF
+ 444C42FF4A5248FF394137FF545C52FF373F35FF3C443AFF586056FF535B51FF
+ 656D63FF71796FFF7C807BFF747873FF7D817CFF9EA29DFF7F837EFF7D817CFF
+ 747873FF696D68FF70746FFF959994FFA0A49FFF717570FF636762FF777B76FF
+ 7C807BFF8F938EFF949795FF848785FF6C6F6DFF606361FF6E716FFF838684FF
+ 858886FF7A7D7BFF787B79FF686B69FF6C6F6DFF747775FF929593FF797C7AFF
+ 7E817FFF909391FF7F8280FF929593FF7A7D7BFF909391FF9A9D9BFF828583FF
+ 8C8F8DFF818482FF7C7F7DFF858886FF757876FF949795FF969997FF7B7E7CFF
+ 8A8D8BFF80847FFF90948FFF8B8F89FFB1B5AFFFA9ADA7FF6F736DFF7A7E78FF
+ 9A9E98FF7F837DFF838781FF7C807AFF737771FF848882FF626660FF91958FFF
+ 8E928CFF6F736DFF777A78FF717472FF777A78FF797C7AFF6C6F6DFF6B6E6CFF
+ 808381FF919492FF828583FF8A8D8BFF999C9AFF868987FF767977FF838684FF
+ 646765FF7E827DFF666A65FF6B6F69FF71756FFF6D716BFF838781FF767A74FF
+ 71756FFF71756FFF777B75FF7B7F79FF6D716BFF727670FF757973FF676B65FF
+ 6E726CFF7B7F79FF4E4F4DFF616260FF696A68FF898A88FF787977FF7E7F7DFF
+ 626361FF5D5E5CFF636462FF5A5B59FF747573FF727371FF5B5C5AFF767775FF
+ 767775FF3B3C3AFF5E5F5DFF767775FF717270FF7E7F7DFF7B7C7AFF848583FF
+ 8E8F8DFF878886FF848583FF767775FF878886FF6E6F6DFF80817FFF6F706EFF
+ 828381FF6F706CFF5F635EFF5C605AFF575B55FF555953FF767A74FF838781FF
+ 757973FF8D918BFF757973FF858983FF7F837DFF646862FF8C908AFF727670FF
+ 747872FF90948EFF696C6AFF595C5AFF555856FF494C4AFF555856FF474A48FF
+ 5C5F5DFF4A4D4BFF414442FF474A48FF4F5250FF565957FF5D605EFF5D605EFF
+ 505351FF424543FF606563FF5D6260FF555A58FF4D5250FF4F5452FF5B605EFF
+ 666B69FF6A6F6DFF7B807EFF707573FF717674FF8C918FFF989D9BFF7C817FFF
+ 6A6F6DFF797E7CFF696E6CFF7B807EFF7E8381FF575C5AFF6D7270FF828785FF
+ 5C615FFF707573FF686D6BFF505553FF464B49FF363B39FF1A1F1DFF212624FF
+ 414644FF4E544FFF5E625CFF565B52FF545950FF676C63FF70756CFF5C6158FF
+ 575C53FF6F746BFF7C8178FF6B7067FF656A61FF63685FFF959A91FF7C8178FF
+ 747970FF787D74FF656A61FF5D6259FF575C53FF676C63FF7A7F76FF777C73FF
+ 7E837AFF9A9F96FF83887FFF868B82FF6A6F66FF6D7269FF7A7F76FF777C73FF
+ 80857CFF7C8178FF6F746BFF7A7F76FF878C83FF777C73FF72776EFF6E736AFF
+ 646960FF42473EFF3E433AFF4A4F46FF60655CFF5A5F56FF3E433AFF62675EFF
+ 6A6F66FF82877EFF686C67FF666A65FF686C67FF6F736EFF717570FF6A6E69FF
+ 626661FF5F635EFF656964FF6A6E69FF777B76FF797D78FF6B6F6AFF636762FF
+ 616560FF5B5F5AFF5D615CFF474B46FF454944FF4D514CFF4E524DFF595D58FF
+ 6D716CFF757974FF616560FF626661FF6B6F6AFF878B86FF9A9E99FF8B8F8AFF
+ 7F837EFF8C908BFF848A85FF747A75FF757B76FF6D736EFF7D837EFF6B716CFF
+ 6A706BFF5E645FFF5E645FFF585E59FF535954FF404641FF3F4540FF454B46FF
+ 323833FF444B44FF4B524BFF51594FFF525A50FF454D43FF485046FF676F65FF
+ 4D554BFF384036FF343C32FF3B4339FF565E54FF6C746AFF818580FF636762FF
+ 686C67FF8E928DFF888C87FF939792FF7B7F7AFF7A7E79FF757974FF7F837EFF
+ 888C87FF686C67FF60645FFF7F837EFF7E827DFF747873FF8F9290FF818482FF
+ 6C6F6DFF656866FF7B7E7CFF939694FF888B89FF6B6E6CFF7D807EFF646765FF
+ 636664FF656866FF7A7D7BFF626563FF676A68FF707371FF6C6F6DFF747775FF
+ 666967FF7B7E7CFF8D908EFF7F8280FF828583FF7F8280FF868987FF898C8AFF
+ 7E817FFF919492FF949795FF858886FF8C8F8DFF848785FF7B7F7AFF7C807AFF
+ 757973FF686C66FF777B75FF838781FF787C76FF81857FFF848882FF747872FF
+ 6D716BFF878B85FF6E726CFF7C807AFF787C76FF777B76FF797C7AFF686B69FF
+ 747775FF7F8280FF6F7270FF717472FF888B89FF919492FF838684FF9DA09EFF
+ 868987FF929593FF898C8AFF717472FF818482FF848785FF5F635EFF5E625CFF
+ 61655FFF6B6F69FF80847EFF7F837DFF757973FF6B6F69FF6E726CFF7B7F79FF
+ 60645EFF6C706AFF727670FF595D57FF5D615BFF595D58FF4E4F4DFF454644FF
+ 323331FF464745FF565755FF6F706EFF717270FF818280FF6F706EFF565755FF
+ 494A48FF4C4D4BFF414240FF4F504EFF5C5D5BFF353634FF4D4E4CFF6B6C6AFF
+ 656664FF7F807EFF737472FF848583FF8D8E8CFF8F908EFF848583FF6D6E6CFF
+ 838482FF6D6E6CFF7A7B79FF6F706EFF929391FF828381FF787C77FF7A7E78FF
+ 797D77FF666A64FF686C66FF70746EFF71756FFF929690FF81857FFF777B75FF
+ 898D87FF80847EFF737771FF60645EFF61655FFF484C47FF262927FF252826FF
+ 323533FF3A3D3BFF464947FF343735FF636664FF484B49FF3B3E3CFF3A3D3BFF
+ 383B39FF3B3E3CFF4B4E4CFF585B59FF4D504EFF383B39FF484D4BFF4C514FFF
+ 4D5250FF4B504EFF494E4CFF4A4F4DFF4D5250FF505553FF696E6CFF646967FF
+ 606563FF6E7371FF808583FF7C817FFF797E7CFF888D8BFF4D5250FF6B706EFF
+ 888D8BFF757A78FF6B706EFF686D6BFF525755FF5D6260FF8C918FFF747977FF
+ 787D7BFF6F7472FF464B49FF434846FF595E5CFF555B56FF60645EFF5F645BFF
+ 60655CFF6F746BFF797E75FF6A6F66FF5E635AFF6A6F66FF81867DFF7D8279FF
+ 747970FF63685FFF70756CFF5E635AFF656A61FF787D74FF82877EFF7A7F76FF
+ 747970FF787D74FF797E75FF6E736AFF676C63FF6D7269FFA4A9A0FFAAAFA6FF
+ 91968DFF767B72FF71766DFF71766DFF70756CFF6E736AFF71766DFF7A7F76FF
+ 9A9F96FF82877EFF797E75FF72776EFF81867DFF62675EFF50554CFF353A31FF
+ 6F746BFF6B7067FF454A41FF5E635AFF40453CFF828680FF2F332EFF373B36FF
+ 454944FF535752FF585C57FF5A5E59FF616560FF6A6E69FF656964FF60645FFF
+ 6E726DFF717570FF5A5E59FF545853FF575B56FF4A4E49FF3D413CFF343833FF
+ 353934FF393D38FF333732FF343833FF484C47FF5D615CFF6C706BFF686C67FF
+ 666A65FF70746FFF757974FF727671FF929691FFCACEC9FF858B86FF797F7AFF
+ 808681FF7A807BFF8A908BFF777D78FF767C77FF6B716CFF686E69FF626863FF
+ 626863FF5D635EFF6D736EFF595F5AFF626863FF606661FF656C65FF676F65FF
+ 71796FFF60685EFF70786EFF8A9288FF757D73FF5C645AFF586056FF60685EFF
+ 6D756BFF737B71FF797D78FF626661FF5A5E59FF6F736EFF6B6F6AFF7F837EFF
+ 70746FFF797D78FF898D88FF6C706BFF6A6E69FF636762FF6E726DFF888C87FF
+ 757974FF575B56FF505351FF686B69FF787B79FF777A78FF787B79FF818482FF
+ 7F8280FF747775FF838684FF747775FF787B79FF6A6D6BFF747775FF646765FF
+ 656866FF565957FF666967FF5C5F5DFF666967FF6B6E6CFF7B7E7CFF7D807EFF
+ 6A6D6BFF7D807EFF919492FF858886FF8F9290FF868987FF858886FF8B8E8CFF
+ 7D807EFF868987FF8D918CFF777B76FF686C67FF60645FFF797D78FF7F837EFF
+ 6E726DFF919590FF7A7E79FF858984FF7A7E79FF858984FF848883FF80847FFF
+ 717570FF888C87FF7E817FFF6D706EFF797C7AFF878A88FF7D807EFF808381FF
+ 8E918FFF8B8E8CFF888B89FF969997FF7D807EFF868987FF8B8E8CFF717472FF
+ 848785FF848785FF797D78FF777B76FF717570FF747873FF7A7E79FF898D88FF
+ 7F837EFF6B6F6AFF6B6F6AFF737772FF5D615CFF6E726DFF737772FF5B5F5AFF
+ 575B56FF40443FFF494A48FF40413FFF3B3C3AFF353634FF50514FFF4A4B49FF
+ 5E5F5DFF7A7B79FF6F706EFF717270FF545553FF424341FF3D3E3CFF393A38FF
+ 424341FF414240FF545553FF6E6F6DFF656664FF7B7C7AFF676866FF6D6E6CFF
+ 70716FFF737472FF5A5B59FF4E4F4DFF60615FFF676866FF666765FF6E6F6DFF
+ 858684FF80817FFF6D716CFF777B76FF878B86FF797D78FF727671FF757974FF
+ 727671FF888C87FF858984FF797D78FF696D68FF626661FF3E423DFF414540FF
+ 30342FFF161A15FF262927FF181B19FF161917FF2A2D2BFF3F4240FF373A38FF
+ 545755FF2B2E2CFF363937FF393C3AFF373A38FF333634FF3B3E3CFF4B4E4CFF
+ 4E514FFF454846FF303533FF363B39FF3F4442FF434846FF414644FF3F4442FF
+ 404543FF434846FF555A58FF616664FF595E5CFF4F5452FF5E6361FF6F7472FF
+ 727775FF747977FF6C716FFF6F7472FF737876FF767B79FF646967FF767B79FF
+ 929795FF656A68FF767B79FF606563FF6D7270FF767B79FF5F6462FF626765FF
+ 727775FF646A65FF656963FF70746EFF6C706AFF686C66FF71756FFF70746EFF
+ 676B65FF666A64FF686C66FF828680FF858983FF878B85FF767A74FF7A7E78FF
+ 6F736DFF757973FF666A64FF70746EFF7A7E78FF7A7E78FF777B75FF777B75FF
+ 6D716BFF5B5F59FF70746EFF565A54FF6F736DFF7B7F79FF8F938DFF91958FFF
+ 737771FF959993FF7E827CFF777B75FF949892FF8A8E88FF868A84FF787C76FF
+ 888C86FF747872FF7B7F79FF727670FF626660FF7B7F79FF585C56FF40443EFF
+ 31352FFF2A2E28FF20241FFF2C302BFF3F433EFF4D514CFF4F534EFF4E524DFF
+ 585C57FF646863FF686C67FF5F635EFF686C67FF656964FF484C47FF3A3E39FF
+ 363A35FF232722FF2D312CFF262A25FF232722FF2C302BFF363A35FF333732FF
+ 313530FF393D38FF434742FF4B4F4AFF595D58FF6C706BFF6B6F6AFF575B56FF
+ 626661FF8D918CFF6F7570FF6A706BFF797F7AFF767C77FF848A85FF6F7570FF
+ 707671FF686E69FF606661FF676D68FF787E79FF727873FF767C77FF555B56FF
+ 767C77FF737974FF7C837CFF727972FF798079FF707770FF7D847DFF8A918AFF
+ 798079FF6F766FFF7A817AFF7F867FFF798079FF6C736CFF717570FF7A7E79FF
+ 70746FFF7C807BFF676B66FF6D716CFF757974FF8D918CFF959994FF838782FF
+ 888C87FF777B76FF646863FF646863FF5B5F5AFF5C605BFF3D403EFF555856FF
+ 6B6E6CFF717472FF727573FF717472FF6A6D6BFF5F6260FF565957FF525553FF
+ 636664FF5B5E5CFF6D706EFF757876FF7D807EFF5E615FFF676A68FF565957FF
+ 6B6E6CFF666967FF6E716FFF717472FF575A58FF787B79FF989B99FF868987FF
+ 969997FF7F8280FF7E817FFF909391FF797C7AFF838684FFB8BCB7FF696D68FF
+ 6A6E69FF70746FFF6E726DFF7F837EFF727671FF747873FF686C67FF90948FFF
+ 858984FF757974FF848883FF8C908BFF7C807BFF868A85FF7F8280FF7B7E7CFF
+ 818482FF888B89FF878A88FF8A8D8BFF8B8E8CFF838684FF969997FF828583FF
+ 8F9290FF747775FF848785FF868987FF737674FF868987FF7D817CFF7A7E79FF
+ 737772FF777B76FF6C706BFF848883FF828681FF727671FF616560FF5A5E59FF
+ 5A5E59FF6A6E69FF656964FF595D58FF515550FF30342FFF3F403EFF3C3D3BFF
+ 464745FF494A48FF6F706EFF414240FF2A2B29FF2A2B29FF3E3F3DFF696A68FF
+ 6D6E6CFF4C4D4BFF40413FFF3D3E3CFF3A3B39FF4D4E4CFF5A5B59FF6A6B69FF
+ 5D5E5CFF616260FF4B4C4AFF3F403EFF414240FF3E3F3DFF2E2F2DFF30312FFF
+ 353634FF4D4E4CFF414240FF4E4F4DFF4B4C4AFF4F504EFF323631FF313530FF
+ 424641FF414540FF4D514CFF6A6E69FF737772FF838782FF7D817CFF989C97FF
+ 686C67FF5C605BFF60645FFF6A6E69FF3E423DFF484C47FF2B2E2CFF262927FF
+ 1D201EFF2B2E2CFF2D302EFF333634FF3C3F3DFF303331FF1D201EFF2C2F2DFF
+ 353836FF2D302EFF212422FF232624FF323533FF3F4240FF333836FF333836FF
+ 363B39FF383D3BFF353A38FF313634FF333836FF393E3CFF484D4BFF656A68FF
+ 626765FF4C514FFF555A58FF6A6F6DFF6B706EFF626765FF6E7371FF7B807EFF
+ 797E7CFF707573FF4B504EFF717674FFABB0AEFF616664FF676C6AFF565B59FF
+ 5E6361FF696E6CFF616664FF666B69FF707573FF686E69FF6D716CFF7B7F79FF
+ 70746EFF5E625CFF636761FF6C706AFF6A6E68FF6A6E68FF696D67FF7E827CFF
+ 7C807AFF8C908AFF7E827CFF969A94FF80847EFF727670FF626660FF666A64FF
+ 686C66FF595D57FF50544EFF676B65FF777B75FF6A6E68FF71756FFF535751FF
+ 666A64FF565A54FF727670FF8F938DFF61655FFF71756FFF8D918BFF7A7E78FF
+ 848882FF949892FFA4A8A2FF999D97FF929690FF828680FF8D918BFF858983FF
+ 71756FFF727670FF636761FF6E726CFF3F433DFF0C100AFF1C201BFF212520FF
+ 2B2F2AFF343833FF353934FF30342FFF30342FFF353934FF454944FF474B46FF
+ 535752FF565A55FF484C47FF3B3F3AFF313530FF242823FF262A25FF363A35FF
+ 3A3E39FF373B36FF383C37FF2E322DFF272B26FF313530FF373B36FF282C27FF
+ 191D18FF222621FF323631FF363A35FF484C47FF6B6F6AFF595F5AFF5D635EFF
+ 767C77FF747A75FF7E847FFF676D68FF6C726DFF696F6AFF767C77FF6E746FFF
+ 787E79FF6D736EFF707671FF5E645FFF757B76FF646A65FF787F78FF6D746DFF
+ 717871FF767D76FF767D76FF838A83FF757C75FF818881FF747B74FF7A817AFF
+ 666D66FF4E554EFF747873FF929691FF868A85FFA5A9A4FF8C908BFF757974FF
+ 858984FF9FA39EFF949893FF848883FF838782FF767A75FF797D78FF80847FFF
+ 6F736EFF6D716CFF6D706EFF6A6D6BFF6B6E6CFF757876FF808381FF808381FF
+ 727573FF646765FF484B49FF343735FF3C3F3DFF363937FF4F5250FF656866FF
+ 787B79FF575A58FF575A58FF575A58FF5D605EFF626563FF636664FF565957FF
+ 535654FF6F7270FF888B89FF818482FF7C7F7DFF737674FF797C7AFF848785FF
+ 797C7AFF6E716FFFC0C4BFFF646863FF5E625DFF737772FFA0A49FFFCACEC9FF
+ A0A49FFF838782FF757974FF858984FF838782FF767A75FF7E827DFF8C908BFF
+ 898D88FF7D817CFF6F7270FF7F8280FF818482FF7B7E7CFF818482FF878A88FF
+ 818482FF7D807EFF939694FF828583FF959896FF727573FF878A88FF898C8AFF
+ 787B79FF848785FF7D817CFF737772FF70746FFF818580FF646863FF727671FF
+ 747873FF757974FF6F736EFF565A55FF727671FF797D78FF5E625DFF626661FF
+ 5A5E59FF3A3E39FF4D504EFF454846FF3A3D3BFF4E514FFF757876FF555856FF
+ 2F3230FF363937FF3C3F3DFF414442FF676A68FF5D605EFF4B4E4CFF4C4F4DFF
+ 424543FF565957FF515452FF535654FF474A48FF3B3E3CFF323533FF1A1D1BFF
+ 262927FF202321FF1F2220FF222523FF181B19FF272A28FF282B29FF2F3230FF
+ 282B29FF373A38FF3C403BFF30342FFF363A35FF262A25FF252924FF464A45FF
+ 5B5F5AFF6D716CFF838782FFA5A9A4FF8E928DFF7E827DFF9B9F9AFFA3A7A2FF
+ 8B8F8AFF929691FF979A98FF9B9E9CFF828583FF727573FF424543FF3C3F3DFF
+ 141715FF222523FF272A28FF2D302EFF303331FF292C2AFF1A1D1BFF131614FF
+ 1F2220FF313432FF2D3230FF292E2CFF2A2F2DFF2E3331FF2D3230FF282D2BFF
+ 292E2CFF2F3432FF4B504EFF686D6BFF676C6AFF515654FF525755FF5C615FFF
+ 5C615FFF595E5CFF3E4341FF525755FF6B706EFF5A5F5DFF333836FF4A4F4DFF
+ 656A68FF3E4341FF5C615FFF5B605EFF616664FF666B69FF636866FF606563FF
+ 646967FF6A706BFF6F736EFF797D77FF727670FF676B65FF686C66FF676B65FF
+ 666A64FF6E726CFF737771FF696D67FF636761FF6A6E68FF6D716BFF7B7F79FF
+ 7B7F79FF70746EFF8E928CFF8C908AFF939791FF858983FF686C66FF676B65FF
+ 6A6E68FF595D57FF5E625CFF696D67FF656963FF3B3F39FF50544EFF868A84FF
+ 81857FFF7C807AFF8E928CFF888C86FF7D817BFF929690FFA1A59FFFA2A6A0FF
+ 8B8F89FF868A84FF7E827CFF7F837DFF939791FF80847EFF6E726CFF969A94FF
+ 626660FF484C46FF272D28FF171D18FF0C120DFF121813FF1E241FFF252B26FF
+ 252B26FF252B26FF222823FF2E342FFF353B36FF3A403BFF414742FF3B413CFF
+ 333934FF353B36FF1C201BFF40443FFF474B46FF383C37FF373B36FF343833FF
+ 363A35FF474B46FF2C302BFF242823FF191D18FF1E221DFF2C302BFF292D28FF
+ 272B26FF343833FF505651FF5D635EFF7D837EFF7D837EFF828883FF6A706BFF
+ 737974FF757B76FF6D736EFF5C625DFF696F6AFF686E69FF747A75FF858B86FF
+ 8B918CFF707671FF6B726BFF6E756EFF6E756EFF7B827BFF686F68FF838A83FF
+ 737A73FF8A918AFF727972FF7D847DFF656C65FF464D46FF787C77FF969A95FF
+ 838782FFBABEB9FFA8ACA7FF787C77FF7E827DFF8C908BFF8A8E89FF929691FF
+ 979B96FF828681FF828681FF898D88FF767A75FF787C77FF767977FF717472FF
+ 707371FF757876FF777A78FF767977FF7A7D7BFF818482FF808381FF4E514FFF
+ 393C3AFF222523FF303331FF3E413FFF515452FF323533FF404341FF545755FF
+ 484B49FF5D605EFF5B5E5CFF3D403EFF555856FF676A68FF6C6F6DFF727573FF
+ 555856FF606361FF6D706EFF6C6F6DFF727573FF4F5250FF5B5F5AFF6B6F6AFF
+ 7F837EFF676B66FF828681FF8D918CFF686C67FF9B9F9AFF7F837EFF5D615CFF
+ 646863FF70746FFF696D68FF6B6F6AFF767A75FF646863FF595C5AFF7A7D7BFF
+ 7A7D7BFF6B6E6CFF767977FF7E817FFF797C7AFF7B7E7CFF7D807EFF909391FF
+ 818482FF777A78FF8E918FFF747775FF8D908EFF797C7AFF969A95FF828681FF
+ 80847FFF9A9E99FF6C706BFF656964FF646863FF727671FF7A7E79FF555954FF
+ 838782FF7F837EFF525651FF60645FFF5A5E59FF3E423DFF2F3230FF4E514FFF
+ 555856FF868987FF939694FF7E817FFF555856FF757876FF808381FF323533FF
+ 5D605EFF757876FF616462FF5E615FFF4C4F4DFF616462FF474A48FF424543FF
+ 3A3D3BFF292C2AFF2E312FFF141715FF2D302EFF272A28FF232624FF222523FF
+ 101311FF111412FF2B2E2CFF343735FF3C3F3DFF595C5AFF40443FFF424641FF
+ 545853FF3B3F3AFF222621FF333732FF484C47FF5E625DFF7D817CFF767A75FF
+ 838782FF6A6E69FF737772FF828681FF9FA39EFF868A85FF929593FF989B99FF
+ 878A88FF969997FF858886FFA2A5A3FF5E615FFF737674FF3D403EFF292C2AFF
+ 1A1D1BFF171A18FF141715FF0E110FFF101311FF181B19FF292E2CFF282D2BFF
+ 313634FF404543FF474C4AFF464B49FF474C4AFF4C514FFF595E5CFF6B706EFF
+ 646967FF4D5250FF434846FF404543FF404543FF474C4AFF3C413FFF2F3432FF
+ 4C514FFF4B504EFF4B504EFF535856FF3A3F3DFF3F4442FF363B39FF4B504EFF
+ 5C615FFF656A68FF676C6AFF616664FF656A68FF787D7BFF6C706BFF737771FF
+ 767A74FF7A7E78FF7A7E78FF686C66FF61655FFF6F736DFF7C807AFF636761FF
+ 71756FFF71756FFF7F837DFF727670FF888C86FF878B85FF959993FF8A8E88FF
+ 969A94FF969A94FF7C807AFF777B75FF858983FF838781FF6C706AFF868A84FF
+ 797D77FF666A64FF5C605AFF5C605AFF757973FF848882FF868A84FF959993FF
+ 7C807AFF7F837DFF7A7E78FF80847EFF676B65FF737771FF6C706AFFA4A8A2FF
+ 959993FFAFB3ADFF7F837DFF666A64FF878B85FF727670FF848A85FF595F5AFF
+ 2B312CFF1A201BFF212722FF262C27FF202621FF171D18FF282E29FF343A35FF
+ 282E29FF202621FF2B312CFF242A25FF1C221DFF292F2AFF151914FF2E322DFF
+ 272B26FF20241FFF414540FF595D58FF575B56FF5A5E59FF727671FF656964FF
+ 414540FF20241FFF111510FF080C07FF0E120DFF232722FF2F3530FF404641FF
+ 656B66FF666C67FF696F6AFF4F5550FF5A605BFF606661FF5E645FFF606661FF
+ 828883FF787E79FF676D68FF7B817CFF7B817CFF6D736EFF686F68FF787F78FF
+ 737A73FF7C837CFF575E57FF7A817AFF646B64FF7B827BFF545B54FF6C736CFF
+ 636A63FF545B54FF90948FFF7E827DFF8B8F8AFFBABEB9FFC2C6C1FF8B8F8AFF
+ 696D68FF7D817CFF7C807BFF868A85FF80847FFF7D817CFF989C97FF6F736EFF
+ 717570FF8A8E89FF848785FF787B79FF8B8E8CFF626563FF616462FF6C6F6DFF
+ 8A8D8BFF929593FF767977FF909391FF7A7D7BFF646765FF323533FF141715FF
+ 383B39FF4A4D4BFF353836FF464947FF474A48FF474A48FF4C4F4DFF3B3E3CFF
+ 343735FF4B4E4CFF4C4F4DFF5E615FFF505351FF656866FF444745FF464947FF
+ 6C6F6DFF7F8280FF5E615FFF7D807EFF858886FF838684FF858886FF717472FF
+ 606361FF6D706EFF7A7D7BFF838684FF818482FF7D807EFF707371FF7C7F7DFF
+ 646765FF777A78FF808381FF717472FF7C7F7DFF6A6D6BFF5E615FFF646765FF
+ 666967FF8D908EFF686B69FF7D807EFF8A8D8BFF838684FF7C7F7DFF7E817FFF
+ 7C7F7DFF747775FF9FA2A0FFC0C3C1FF7C7F7DFF868987FF8E918FFF6C6F6DFF
+ 4A4D4BFF5F6260FF6D706EFF515452FF484B49FF535654FF333634FF616462FF
+ 737674FF5A5D5BFF646967FF353A38FF2B302EFF545957FF686D6BFF525755FF
+ 4A4F4DFF5C615FFF858A88FF4A4F4DFF3E4341FF4E5351FF696E6CFF5D6260FF
+ 494E4CFF888D8BFF3D4240FF232826FF191E1CFF1C211FFF181D1BFF181D1BFF
+ 1C211FFF181D1BFF232826FF232826FF0D1210FF171C1AFF151A18FF1B201EFF
+ 444947FF3F4442FF242725FF414442FF3C3F3DFF414442FF303331FF414442FF
+ 3F4240FF525553FF4C4F4DFF474A48FF5F6260FF717472FF636664FF686B69FF
+ 898C8AFF9B9E9CFF898C8AFFA9ACAAFF929593FF7A7D7BFF929593FF919492FF
+ 818482FF949795FF898C8AFF787B79FF6F7270FF575A58FF393C3AFF444745FF
+ 575A58FF4B4E4CFF3C413FFF515654FF5C615FFF656A68FF727775FF6E7371FF
+ 5D6260FF575C5AFF646967FF6A6F6DFF717674FF424745FF5A5F5DFF303533FF
+ 3A3F3DFF404543FF353A38FF1D2220FF282D2BFF3F4442FF3B403EFF373C3AFF
+ 383D3BFF2C312FFF3E4341FF4F5452FF444947FF636866FF727775FF7F8482FF
+ 666B69FF767B79FF727671FF777B76FF6A6E69FF6A6E69FF60645FFF565A55FF
+ 6E726DFF787C77FF717570FF656964FF9CA09BFF747873FF676B66FF848883FF
+ 5E625DFF80847FFF7A7E79FF737772FF616560FF6F736EFF929691FF929691FF
+ 888C87FF989C97FF838782FF6C706BFF8F938EFF818580FF70746FFF7D817CFF
+ 6D716CFF878B86FF7E827DFF767A75FF8D918CFF666A65FF626661FF686C67FF
+ 7F837EFF818580FF767A75FF90948FFF979B96FF848883FF777B76FF999D98FF
+ 696D68FF626661FF838984FF6E7570FF505752FF363D38FF29302BFF282F2AFF
+ 2A312CFF2B322DFF171E19FF3E4540FF373E39FF4D544FFF29302BFF282F2AFF
+ 313833FF1D231EFF383C37FF242823FF2F332EFF3B3F3AFF737772FF686C67FF
+ 525651FF5E625DFF6B6F6AFF7F837EFF70746FFF535752FF464A45FF313530FF
+ 232722FF30342FFF3D433EFF525853FF676D68FF808681FF686E69FF7F8580FF
+ 747A75FF5B615CFF636964FF6F7570FF6B716CFF7E847FFF999F9AFF787E79FF
+ 505651FF5E645FFF5A605BFF7C827DFF7F8580FF6C726DFF6F7570FF787E79FF
+ 6E746FFF616762FF434944FF515752FF535954FF474D48FF888C87FF828681FF
+ 858984FF9B9F9AFFA4A8A3FF888C87FF777B76FF858984FF737772FF9A9E99FF
+ 7B7F7AFF9A9E99FFB3B7B2FF70746FFF8D918CFF717570FF7E817FFF626563FF
+ 727573FF686B69FF828583FF8B8E8CFF858886FF6E716FFF8B8E8CFFA2A5A3FF
+ A4A7A5FF8A8D8BFF6F7270FF474A48FF353836FF141715FF3F4240FF414442FF
+ 3F4240FF404341FF404341FF323533FF272A28FF2E312FFF282B29FF4C4F4DFF
+ 575A58FF878A88FF7B7E7CFF6D706EFF707371FF787B79FF545755FF7B7E7CFF
+ 7D807EFF9C9F9DFF8B8E8CFF7F8280FF454846FF424543FF666967FF666967FF
+ 646765FF6B6E6CFF646765FF6E716FFF545755FF6C6F6DFF858886FF777A78FF
+ 797C7AFF6C6F6DFF6D706EFF6D706EFF5A5D5BFF717472FF7C7F7DFF7D807EFF
+ 808381FF818482FF7D807EFF777A78FF757876FF777A78FF747775FF888B89FF
+ 747775FF7C7F7DFF878A88FF838684FF5B5E5CFF797C7AFF6B6E6CFF5B5E5CFF
+ 7A7D7BFF909391FF7D807EFF6C6F6DFF737674FF6A6D6BFF454A48FF2B302EFF
+ 1D2220FF282D2BFF373C3AFF393E3CFF383D3BFF3B403EFF3F4442FF414644FF
+ 353A38FF3A3F3DFF474C4AFF464B49FF464B49FF474C4AFF595E5CFF505553FF
+ 4E5351FF404543FF222725FF121715FF141917FF121715FF0F1412FF0A0F0DFF
+ 050A08FF121715FF151A18FF1A1F1DFF272C2AFF1A1F1DFF1B1E1CFF2B2E2CFF
+ 2D302EFF313432FF3B3E3CFF5D605EFF5D605EFF4E514FFF414442FF383B39FF
+ 424543FF555856FF565957FF525553FF555856FF565957FF363937FF6D706EFF
+ 757876FF606361FF686B69FF6F7270FF686B69FF707371FF808381FF898C8AFF
+ 979A98FF838684FF595C5AFF585B59FF707371FF757876FF4F5452FF555A58FF
+ 4E5351FF4A4F4DFF595E5CFF616664FF616664FF656A68FF5B605EFF6C716FFF
+ 7B807EFF656A68FF7C817FFF525755FF3A3F3DFF242927FF2D3230FF1E2321FF
+ 1F2422FF2B302EFF323735FF3E4341FF4B504EFF4E5351FF494E4CFF646967FF
+ 696E6CFF787D7BFF6A6F6DFF707573FF666B69FF777C7AFF767A75FF737772FF
+ 626661FF6B6F6AFF6B6F6AFF5C605BFF5B5F5AFF4E524DFF626661FF575B56FF
+ 80847FFF6C706BFF6D716CFF828681FF5D615CFF6A6E69FF656964FF646863FF
+ 555954FF585C57FF6D716CFF747873FF838782FFA7ABA6FF919590FF6B6F6AFF
+ 828681FF7D817CFF7E827DFF878B86FF5E625DFF595D58FF777B76FF626661FF
+ 6C706BFF767A75FF7A7E79FF8D918CFF828681FF7F837EFF7D817CFF7E827DFF
+ 737772FF818580FF979B96FFB4B8B3FF838782FF6B716CFF6C726DFF6C736EFF
+ 6E7570FF6B726DFF5F6661FF545B56FF545B56FF5B625DFF262D28FF323934FF
+ 5B625DFF676E69FF606762FF5C635EFF636A65FF676E69FF585C57FF5C605BFF
+ 6C706BFF616560FF8A8E89FF818580FF5C605BFF474B46FF555954FF6F736EFF
+ 747873FF747873FF7D817CFF737772FF626661FF646863FF4B514CFF4E544FFF
+ 626863FF6B716CFF6E746FFF6F7570FF797F7AFF767C77FF6F7570FF8B918CFF
+ 7F8580FF717772FF878D88FF868C87FF686E69FF5F6560FF797F7AFF686E69FF
+ 5D635EFF727873FF8C928DFF7A807BFF4F5550FF393F3AFF333934FF3D433EFF
+ 3D433EFF2F3530FF7E827DFF858984FF7F837EFF797D78FF7F837EFF7F837EFF
+ 7F837EFF888C87FF787C77FF919590FF747873FF8A8E89FF9DA19CFF727671FF
+ 979B96FF6F736EFF7F8280FF6E716FFF8A8D8BFF848785FF858886FF7C7F7DFF
+ 737674FF6C6F6DFF737674FF777A78FF8E918FFF6E716FFF848785FF7B7E7CFF
+ 666967FF3B3E3CFF232624FF252826FF3B3E3CFF555856FF595C5AFF4E514FFF
+ 3B3E3CFF262927FF292C2AFF4E514FFF565957FF888B89FF888B89FF6E716FFF
+ 555856FF626563FF6C6E6EFF6C6E6EFF565858FF626464FF727474FF878989FF
+ 818383FF8B8D8DFF9A9C9CFF696B6BFF353737FF343636FF494B4BFF707272FF
+ 616363FF767878FF717472FF767977FF777A78FF6C6F6DFF777A78FF757876FF
+ 646765FF7D807EFF777A78FF646765FF5C5F5DFF656866FF676A68FF5D605EFF
+ 585B59FF5D605EFF6B6D6DFF5D5F5FFF5B5D5DFF4C4E4EFF505252FF6C6E6EFF
+ 565858FF7D7F7FFF585A5AFF606262FF747676FF5B5D5DFF686A6AFF616363FF
+ 707272FF5D5F5FFF303533FF202523FF181D1BFF222725FF2E3331FF323735FF
+ 363B39FF3B403EFF323735FF505553FF454A48FF494E4CFF404543FF3D4240FF
+ 585D5BFF393E3CFF4B504EFF4E5351FF575C5AFF515654FF414644FF464B49FF
+ 555A58FF585D5BFF434846FF282D2BFF212624FF151A18FF0D1210FF161B19FF
+ 121715FF0D1210FF171919FF141616FF212323FF212323FF3A3C3CFF5A5C5CFF
+ 5A5C5CFF242626FF282A2AFF2A2C2CFF2E3030FF3B3D3DFF454747FF373939FF
+ 252727FF252727FF0B0E0CFF3C3F3DFF535654FF464947FF484B49FF5D605EFF
+ 626563FF555856FF5B5E5CFF505351FF575A58FF686B69FF727573FF777A78FF
+ 666967FF444745FF575C5AFF585D5BFF4C514FFF474C4AFF5A5F5DFF686D6BFF
+ 6C716FFF737876FF505553FF686D6BFF767B79FF6D7270FF7A7F7DFF6B706EFF
+ 555A58FF404543FF646967FF585D5BFF383D3BFF202523FF262B29FF393E3CFF
+ 4B504EFF5A5F5DFF444947FF424745FF3E4341FF515654FF5C615FFF808583FF
+ 818684FF747977FF787B79FF767977FF606361FF595C5AFF494C4AFF353836FF
+ 3F4240FF3E413FFF343735FF313432FF494C4AFF535654FF6C6F6DFF868987FF
+ 7A7D7BFF7A7D7BFF727573FF6E716FFF616462FF5C5F5DFF626563FF616462FF
+ 6B6E6CFF868987FF8C8F8DFF6A6D6BFF757876FF696C6AFF666967FF7A7D7BFF
+ 707371FF7C7F7DFF676A68FF585B59FF626563FF858886FF7B7E7CFF959896FF
+ 878A88FF9A9D9BFF7E817FFF8C8F8DFF7A7D7BFF868987FF828583FF7D807EFF
+ 727573FF717674FF565C57FF484F4AFF4C534EFF656C67FF777E79FF707772FF
+ 626964FF5D645FFF464D48FF383F3AFF7E8580FF7C837EFF878E89FF7A817CFF
+ 79807BFF8C938EFF787C77FF6E726DFF70746FFF545853FF70746FFF6D716CFF
+ 575B56FF4A4E49FF464A45FF575B56FF5F635EFF6A6E69FF7D817CFF777B76FF
+ 5E625DFF515550FF424843FF373D38FF404641FF383E39FF545A55FF454B46FF
+ 616762FF7A807BFF8D938EFFBCC2BDFFAEB4AFFF7F8580FF828883FF8B918CFF
+ 6A706BFF464C47FF606563FF6A6F6DFF646967FF5F6462FF6E7371FF6F7472FF
+ 535856FF3A3F3DFF444947FF4A4F4DFF484D4BFF3B403EFF787C77FF858984FF
+ 7F837EFF737772FF767A75FF7B7F7AFF7F837EFF898D88FF8D918CFF7F837EFF
+ 8F938EFF7B7F7AFF888C87FF90948FFF999D98FF8C908BFF8B8E8CFF868987FF
+ A3A6A4FF979A98FF787B79FF696C6AFF717472FF888B89FF828583FF6D706EFF
+ 8A8D8BFF585B59FF797C7AFF7B7E7CFF7E817FFF727573FF666967FF4F5250FF
+ 4F5250FF535654FF4C4F4DFF535654FF585B59FF474A48FF5B5E5CFF6A6D6BFF
+ 545755FF676A68FF656866FF4E514FFF373A38FF5C5F5DFF989A9AFF7A7C7CFF
+ 7A7C7CFF5A5C5CFF8D8F8FFF828484FF9EA0A0FF939595FFB3B5B5FF7D7F7FFF
+ 313333FF111313FF1C1E1EFF535555FF545656FF6E7070FF616462FF7B7E7CFF
+ 7A7D7BFF656866FF626563FF5A5D5BFF595C5AFF7A7D7BFF525553FF404341FF
+ 373A38FF3F4240FF494C4AFF444745FF3A3D3BFF343735FF4A4C4CFF414343FF
+ 4F5151FF4C4E4EFF464848FF4D4F4FFF343636FF303232FF4B4D4DFF5E6060FF
+ 575959FF303232FF3B3D3DFF464848FF636565FF757777FF3E4341FF262B29FF
+ 262B29FF3E4341FF3E4341FF242927FF1F2422FF313634FF3F4442FF474C4AFF
+ 565B59FF6D7270FF535856FF3B403EFF4E5351FF434846FF4A4F4DFF424745FF
+ 404543FF3E4341FF414644FF595E5CFF6C716FFF686D6BFF747977FF525755FF
+ 4E5351FF292E2CFF0E1311FF181D1BFF111614FF1E2321FF2D2F2FFF202222FF
+ 434545FF464848FF545656FF585A5AFF595B5BFF1C1E1EFF191B1BFF2A2C2CFF
+ 2B2D2DFF2A2C2CFF2C2E2EFF171919FF090B0BFF1A1C1CFF1C1F1DFF232624FF
+ 2F3230FF2F3230FF343735FF535654FF5F6260FF484B49FF4D504EFF474A48FF
+ 4E514FFF606361FF707371FF777A78FF717472FF656866FF585D5BFF5C615FFF
+ 515654FF484D4BFF4B504EFF434846FF2E3331FF252A28FF323735FF4E5351FF
+ 575C5AFF4F5452FF4A4F4DFF535856FF505553FF4B504EFF626765FF797E7CFF
+ 747977FF6A6F6DFF787D7BFF737876FF585D5BFF4B504EFF494E4CFF2A2F2DFF
+ 191E1CFF272C2AFF484D4BFF828785FF909593FF717674FF717472FF6B6E6CFF
+ 4E514FFF424543FF303331FF212422FF313432FF353836FF3E413FFF3C3F3DFF
+ 343735FF3B3E3CFF464947FF505351FF595C5AFF555856FF737674FF6C6F6DFF
+ 676A68FF707371FF797C7AFF717472FF636664FF5F6260FF676A68FF5D605EFF
+ 767977FF717472FF636664FF686B69FF5C5F5DFF616462FF777A78FF616462FF
+ 616462FF686B69FF5B5E5CFF737674FF737674FF868987FF909391FF8E918FFF
+ 5A5D5BFF5C5F5DFF666967FF5F6260FF606361FF4B504EFF4F5651FF323934FF
+ 2A312CFF464D48FF616863FF636A65FF5F6661FF636A65FF6F7671FF646B66FF
+ 8D948FFF8A918CFF878E89FF787F7AFF717873FF737A75FFA4AAA5FF7B7F7AFF
+ 747873FF60645FFF727671FF666A65FF666A65FF797D78FF7B7F7AFF787C77FF
+ 717570FF727671FF7D817CFF797D78FF60645FFF4A4E49FF5D635EFF575D58FF
+ 4A504BFF363C37FF454B46FF323833FF3E443FFF5B615CFF6D736EFF959B96FF
+ 8F9590FF676D68FF626863FF6D736EFF606661FF4D534EFF484D4BFF6E7371FF
+ 757A78FF5F6462FF5C615FFF646967FF5F6462FF575C5AFF656A68FF6A6F6DFF
+ 696E6CFF616664FF6E726DFF7A7E79FF7F837EFF818580FF848883FF7B7F7AFF
+ 797D78FF868A85FF797D78FF6F736EFF8B8F8AFF727671FF7B7F7AFF878B86FF
+ 898D88FF818580FF8D908EFF7C7F7DFF8B8E8CFF8E918FFF7F8280FF828583FF
+ 7C7F7DFF888B89FF858886FF767977FFA3A6A4FF7A7D7BFF898C8AFF757876FF
+ 848785FF999C9AFF848785FF717472FF717472FF6F7270FF606361FF646765FF
+ 6A6D6BFF595C5AFF6C6F6DFF747775FF5B5E5CFF606361FF5E615FFF565957FF
+ 464947FF777A78FFA8AAAAFF8C8E8EFF959797FF747676FF949696FF797B7BFF
+ 8B8D8DFF757777FF7A7C7CFF838585FF656767FF2F3131FF060808FF1E2020FF
+ 1F2121FF3E4040FF626563FF7D807EFF737674FF5A5D5BFF484B49FF363937FF
+ 353836FF414442FF323533FF2F3230FF2B2E2CFF2E312FFF3C3F3DFF434644FF
+ 323533FF1B1E1CFF3B3D3DFF3D3F3FFF3A3C3CFF424444FF3F4141FF343636FF
+ 363838FF0F1111FF292B2BFF343636FF343636FF4F5151FF464848FF2D2F2FFF
+ 343636FF7D7F7FFF828785FF707774FF6F7673FF7B827FFF6F7673FF4D5451FF
+ 404744FF4B524FFF2D3431FF202724FF525956FF69706DFF4E5552FF353C39FF
+ 272E2BFF353C39FF454C49FF373E3BFF2F3633FF272E2BFF232A27FF313835FF
+ 3E4542FF383F3CFF505754FF424946FF535A57FF333A37FF101714FF161D1AFF
+ 171E1BFF2F3432FF2A2C2CFF232525FF595B5BFF686A6AFF616363FF454747FF
+ 4B4D4DFF2B2D2DFF1F2121FF2C2E2EFF222424FF161818FF171919FF090B0BFF
+ 030505FF181A1AFF222523FF0B0E0CFF101311FF1D201EFF1C1F1DFF303331FF
+ 454846FF3B3E3CFF464947FF3B3E3CFF2E312FFF2B2E2CFF323533FF3A3D3BFF
+ 4D504EFF636664FF5A5F5DFF636866FF5E6361FF5A5F5DFF5E6361FF545957FF
+ 3E4341FF333836FF393E3CFF4A4F4DFF535856FF505553FF464B49FF4C514FFF
+ 444947FF343937FF121715FF353A38FF424745FF4D5250FF707573FF777C7AFF
+ 5A5F5DFF474C4AFF444947FF343937FF2F3432FF1D2220FF181D1BFF363B39FF
+ 555A58FF484D4BFF555856FF434644FF252826FF313432FF404341FF3C3F3DFF
+ 3B3E3CFF282B29FF2E312FFF373A38FF2E312FFF343735FF333634FF323533FF
+ 4C4F4DFF535654FF494C4AFF444745FF4D504EFF616462FF6F7270FF737674FF
+ 6C6F6DFF606361FF545755FF474A48FF535654FF555856FF555856FF626563FF
+ 5F6260FF5A5D5BFF8E918FFF626563FF545755FF323533FF3D403EFF4D504EFF
+ 4C4F4DFF3A3D3BFF5D605EFF6C6F6DFF464947FF373A38FF444745FF454846FF
+ 585B59FF444947FF2E3530FF1E2822FF1E2822FF2B352FFF303A34FF313B35FF
+ 4A544EFF6C7670FF77817BFF858F89FF7A847EFF8A948EFF76807AFF76807AFF
+ 747E78FF5C635EFFA3A9A4FF7E827DFF878B86FF7A7E79FF828681FF70746FFF
+ 70746FFF7D817CFF7F837EFF747873FF6C706BFF6B6F6AFF6F736EFF747873FF
+ 6B6F6AFF585C57FF848A85FF949A95FF7C827DFF727873FF636964FF5A605BFF
+ 3F4540FF494F4AFF666C67FF6E746FFF676D68FF525853FF434944FF3F4540FF
+ 4A504BFF5C625DFF626765FF5D6260FF5A5F5DFF696E6CFF737876FF636866FF
+ 565B59FF636866FF6A6F6DFF6F7472FF727775FF717674FF5E625DFF6A6E69FF
+ 777B76FF858984FF898D88FF767A75FF6B6F6AFF777B76FF636762FF727671FF
+ 616560FF5B5F5AFF6B6F6AFF5C605BFF828681FF6F736EFF7D807EFF6F7270FF
+ 7A7D7BFF878A88FF7C7F7DFF888B89FF727573FF707371FF575A58FF5B5E5CFF
+ 8A8D8BFF808381FF888B89FF727573FF8F9290FFB0B3B1FF686B69FF737674FF
+ 898C8AFF949795FF8C8F8DFF808381FF6C6F6DFF545755FF4C4F4DFF5B5E5CFF
+ 626563FF737674FF757876FF7C7F7DFF646765FF858886FF888A8AFF777979FF
+ 666868FF676969FF545656FF646666FF676969FF656767FF676969FF858787FF
+ 7F8181FF555757FF242626FF2C2E2EFF1D1F1FFF343636FF5E615FFF6B6E6CFF
+ 626563FF5B5E5CFF505351FF464947FF434644FF272A28FF252826FF2B2E2CFF
+ 2B2E2CFF2B2E2CFF373A38FF424543FF313432FF151816FF3D3F3FFF404242FF
+ 252727FF1E2020FF242626FF1F2121FF424444FF1F2121FF111313FF181A1AFF
+ 0E1010FF3F4141FF4C4E4EFF494B4BFF282A2AFF3E4342FF606563FF6A716EFF
+ 6F7673FF6A716EFF666D6AFF666D6AFF626966FF5A615EFF3E4542FF2C3330FF
+ 4E5552FF474E4BFF39403DFF3C4340FF2C3330FF434A47FF424946FF39403DFF
+ 3A413EFF353C39FF202724FF19201DFF212825FF232A27FF2E3532FF2E3532FF
+ 3D4441FF282F2CFF09100DFF0D1411FF232A27FF3C4340FF1B1D1DFF1F2121FF
+ 4D4F4FFF616363FF484A4AFF222424FF252727FF262828FF272929FF222424FF
+ 141616FF0F1111FF1A1C1CFF1E2020FF1F2121FF262828FF131614FF000301FF
+ 0D100EFF1D201EFF111412FF141715FF2C2F2DFF343735FF444745FF404341FF
+ 343735FF323533FF323533FF272A28FF2B2E2CFF454846FF2E3331FF393E3CFF
+ 383D3BFF3A3F3DFF4D5250FF595E5CFF5C615FFF626765FF595E5CFF4B504EFF
+ 4F5452FF4D5250FF545957FF535856FF505553FF353A38FF2F3432FF363B39FF
+ 2F3432FF2D3230FF474C4AFF626765FF686D6BFF656A68FF3D4240FF3C413FFF
+ 414644FF242927FF171C1AFF141917FF2B302EFF292E2CFF323533FF2B2E2CFF
+ 181B19FF292C2AFF3A3D3BFF3F4240FF4E514FFF494C4AFF6A6D6BFF727573FF
+ 6C6F6DFF626563FF464947FF2C2F2DFF313432FF363937FF3A3D3BFF323533FF
+ 373A38FF3C3F3DFF393C3AFF454846FF555856FF545755FF5E615FFF5A5D5BFF
+ 5A5D5BFF4E514FFF404341FF505351FF6D706EFF797C7AFF6C6F6DFF525553FF
+ 595C5AFF2D302EFF343735FF373A38FF3A3D3BFF242725FF212422FF484B49FF
+ 4D504EFF2D302EFF262927FF1D201EFF373A38FF3A3F3DFF1A211CFF131D17FF
+ 18221CFF27312BFF2D3731FF2F3933FF3F4943FF56605AFF56605AFF727C76FF
+ 59635DFF78827CFF656F69FF737D77FF7A847EFF5C635EFF6A706BFF5E625DFF
+ 757974FF5B5F5AFF5D615CFF626661FF686C67FF5E625DFF4E524DFF4B4F4AFF
+ 545853FF585C57FF565A55FF616560FF696D68FF5F635EFF5A605BFF717772FF
+ 6B716CFF7F8580FF747A75FF7E847FFF5F6560FF5C625DFF686E69FF5F6560FF
+ 606661FF5F6560FF474D48FF2C322DFF303631FF474D48FF5A5F5DFF555A58FF
+ 464B49FF444947FF515654FF575C5AFF5C615FFF6B706EFF5A5F5DFF5E6361FF
+ 626765FF666B69FF616560FF717570FF7B7F7AFF838782FF868A85FF767A75FF
+ 656964FF686C67FF6C706BFF787C77FF616560FF5B5F5AFF7D817CFF6E726DFF
+ 888C87FF858984FF7D807EFF797C7AFF7D807EFF7B7E7CFF5D605EFF727573FF
+ 656866FF6A6D6BFF565957FF626563FF6C6F6DFF717472FF757876FF6B6E6CFF
+ 848785FF8D908EFF878A88FF8F9290FF898C8AFF808381FF818482FF7B7E7CFF
+ 6D706EFF666967FF4B4E4CFF545755FF686B69FF777A78FF727573FF828583FF
+ 5F6260FF656866FF595B5BFF545657FF484A4BFF5E6061FF37393AFF484A4BFF
+ 363839FF2C2E2FFF6F7172FF6B6D6EFF5B5D5EFF525455FF464849FF5A5C5DFF
+ 4D4F50FF6A6C6CFF686B69FF6D706EFF6B6E6CFF717472FF606361FF636664FF
+ 707371FF3F4240FF2A2D2BFF272A28FF252826FF282B29FF2F3230FF303331FF
+ 262927FF191C1AFF141616FF242627FF303233FF1E2021FF2D2F30FF292B2CFF
+ 363839FF202223FF27292AFF2D2F30FF1B1D1EFF1E2021FF454748FF686A6BFF
+ 505253FF2B302FFF3E4341FF525956FF616865FF656C69FF6B726FFF747B78FF
+ 737A77FF69706DFF5B625FFF4E5552FF424946FF373E3BFF383F3CFF353C39FF
+ 343B38FF474E4BFF525956FF3F4643FF3F4643FF444B48FF333A37FF242B28FF
+ 282F2CFF2E3532FF343B38FF39403DFF373E3BFF333A37FF1E2522FF1C2320FF
+ 3A413EFF414845FF2B2D2DFF37393AFF464849FF535556FF383A3BFF262829FF
+ 202223FF2F3132FF262829FF202223FF212324FF232526FF232526FF2C2E2FFF
+ 363839FF333535FF101311FF080B09FF101311FF171A18FF111412FF141715FF
+ 212422FF262927FF0D100EFF303331FF484B49FF4A4D4BFF343735FF0B0E0CFF
+ 090C0AFF343735FF424745FF4B504EFF444947FF3D4240FF484D4BFF515654FF
+ 585D5BFF646967FF535856FF353A38FF444947FF3A3F3DFF464B49FF393E3CFF
+ 505553FF414644FF393E3CFF3A3F3DFF414644FF414644FF3F4442FF464B49FF
+ 494E4CFF3E4341FF4E5351FF464B49FF424745FF323735FF494E4CFF3E4341FF
+ 424745FF3D4240FF363838FF414343FF3C3E3EFF424444FF3C3E3EFF393B3BFF
+ 5A5C5CFF6B6D6DFF5F6161FF656767FF747676FF757777FF696B6BFF5B5D5DFF
+ 555757FF5F6161FF575959FF404242FF373939FF2F3131FF212323FF2B2D2DFF
+ 383A3AFF2F3131FF4D4F4FFF696B6BFF818383FF797B7BFF525454FF3F4141FF
+ 494B4BFF474949FF434545FF424444FF5D5F5FFF4E5050FF3B3D3DFF373939FF
+ 353737FF373939FF2C2E2EFF2A2C2CFF353737FF1E2020FF343636FF2F3131FF
+ 292B2BFF262B29FF3B423DFF39433DFF434D47FF57615BFF646E68FF606A64FF
+ 545E58FF4B554FFF4C5650FF545E58FF5D6761FF6D7771FF66706AFF6B756FFF
+ 707A74FF666D68FF585E59FF494D48FF626661FF474B46FF434742FF4B4F4AFF
+ 5B5F5AFF535752FF464A45FF4D514CFF646863FF676B66FF555954FF5F635EFF
+ 777B76FF777B76FF3B413CFF313732FF383E39FF535954FF5E645FFF6D736EFF
+ 727873FF737974FF444A45FF3E443FFF454B46FF484E49FF3A403BFF313732FF
+ 343A35FF363C37FF383D3BFF555A59FF515655FF343938FF2F3433FF424746FF
+ 575C5BFF656A69FF444948FF444948FF464B4AFF4A4F4EFF787C77FF8A8E89FF
+ 8D918CFF888C87FF888C87FF7E827DFF6C706BFF656964FF5E625DFF575B56FF
+ 757974FF626661FF959994FF979B96FF70746FFF888C87FF949795FF848785FF
+ 717472FF626563FF464947FF6F7270FF6D706EFF777A78FF676A68FF7A7D7BFF
+ 696C6AFF7A7D7BFF828583FF838684FF8B8E8CFF707371FF707371FF818482FF
+ 7B7E7CFF797C7AFF8E918FFF919492FF838684FF838684FF767977FF6A6D6BFF
+ 717472FF6C6F6DFF575A58FF6C6F6DFF454846FF3B3E3CFF464848FF343636FF
+ 393B3CFF3D3F3FFF333536FF3B3D3DFF464849FF373939FF4B4D4EFF393B3BFF
+ 2E3031FF404242FF464849FF5E6060FF656768FF9D9F9FFF898C8AFF8C8F8DFF
+ 8C8F8DFF888B89FF5C5F5DFF5D605EFF7D807EFF4B4E4CFF353836FF262927FF
+ 202321FF272A28FF292C2AFF1F2220FF1B1E1CFF1F2220FF0A0C0CFF121414FF
+ 343637FF090B0BFF212324FF363838FF3E4041FF4C4E4EFF333536FF333535FF
+ 393B3CFF242626FF3B3D3EFF404242FF565859FF4F5453FF3D4240FF414644FF
+ 545957FF6A6F6DFF696E6CFF535856FF444947FF434846FF4E5351FF4C514FFF
+ 282D2BFF3E4341FF474C4AFF181D1BFF141917FF1A211EFF3B423FFF161D1AFF
+ 131A17FF313835FF424946FF484F4CFF535A57FF5A615EFF323936FF434A47FF
+ 434A47FF59605DFF4F5653FF3E4542FF4D5451FF373E3BFF2D3231FF414343FF
+ 353738FF3C3E3EFF2C2E2FFF373939FF2C2E2FFF3C3E3EFF262829FF2A2C2CFF
+ 3E4041FF3C3E3EFF1E2021FF1C1E1EFF2C2E2FFF292B2BFF151816FF0D100EFF
+ 030604FF010402FF0C0F0DFF1A1D1BFF181B19FF0C0F0DFF1A1D1BFF1C1F1DFF
+ 1B1E1CFF303331FF464947FF2D302EFF141715FF212624FF313634FF3F4643FF
+ 3F4442FF373E3BFF3C413FFF3C4340FF3D4240FF444B48FF484D4BFF353C39FF
+ 616664FF505754FF4F5452FF282F2CFF515654FF505553FF434846FF3F4442FF
+ 4F5452FF545957FF454A48FF4E5351FF616664FF5C615FFF515654FF454A48FF
+ 3A3F3DFF2B302EFF525755FF414644FF404543FF444947FF565B5AFF626766FF
+ 616665FF6D7271FF676C6BFF565B5AFF5D6261FF5A5F5EFF4C5150FF474C4BFF
+ 5E6362FF636867FF646968FF646968FF575C5BFF636867FF686D6CFF454A48FF
+ 373C3BFF373C3AFF343938FF3F4442FF3B403FFF1B201EFF272C2BFF3B403EFF
+ 4E5352FF595E5CFF4D5251FF474C4AFF4B504FFF383D3BFF4A4C4CFF3F4240FF
+ 4A4C4CFF606361FF454747FF474A48FF282A2AFF2C2F2DFF1D1F1FFF1A1D1BFF
+ 414343FF2C2F2DFF3D3F3FFF343735FF3C3E3EFF626765FF4C534EFF606A64FF
+ 7D847FFF86908AFF808782FF6C7670FF5B625DFF4E5852FF6C736EFF545E58FF
+ 878E89FF79837DFF7C837EFF6A746EFF666D68FF717873FF636964FF424641FF
+ 60645FFF595D58FF4B4F4AFF343833FF3B3F3AFF3F433EFF363A35FF40443FFF
+ 5A5E59FF575B56FF393D38FF434742FF666A65FF6E746FFF6F7570FF353C37FF
+ 343A35FF383F3AFF4B514CFF484F4AFF707671FF777E79FF666C67FF585F5AFF
+ 454B46FF29302BFF1E241FFF313833FF414742FF333A35FF383F3CFF49504DFF
+ 59605DFF616865FF555C59FF363D3AFF303734FF484F4CFF2D3431FF2A302FFF
+ 292F2EFF2C3231FF747775FF757876FF737674FF8A8D8BFF767977FF6F7270FF
+ 636664FF747775FF717472FF797C7AFF7F8280FF939694FF787B79FF999C9AFF
+ 6B6E6CFF787B79FF8D9290FF898E8CFF808583FF808583FF585D5BFF494E4CFF
+ 6C716FFF5A5F5DFF585D5BFF717674FF6A6F6DFF737876FF838886FF858A88FF
+ 888D8BFF7D8280FF7C817FFF707573FF858A88FF6A6F6DFF868B89FF727775FF
+ 999E9CFFA1A6A4FF7B807EFF717674FF646967FF5C615FFF5E6361FF5C615FFF
+ 4E5351FF3C413FFF323735FF1B201EFF313635FF323735FF212625FF292E2CFF
+ 292E2DFF282D2BFF404544FF555A58FF373C3BFF2C312FFF565B5AFF585D5BFF
+ 606564FF9EA3A1FF7B807EFF6E7371FF888D8BFF8F9492FF5F6462FF494E4CFF
+ 575C5AFF585D5BFF5D6260FF525755FF3A3F3DFF090E0CFF454A48FF353A38FF
+ 373C3AFF2F3432FF292E2CFF3C413FFF242928FF525755FF454A49FF515654FF
+ 616665FF313634FF4D5251FF494E4CFF3F4443FF353A38FF353A39FF3B403EFF
+ 3D4241FF3A3F3DFF4D504EFF595C5AFF585B59FF444745FF6B6E6CFF595C5AFF
+ 3C3F3DFF1E211FFF444745FF535654FF484B49FF272A28FF2B2E2CFF242725FF
+ 040705FF141917FF262D2AFF353E3BFF27302DFF222B28FF3A4340FF3E4744FF
+ 4C5552FF7C8582FF646D6AFF707976FF6E7774FF6C7572FF48514EFF606966FF
+ 4E5754FF2D3431FF434846FF545957FF454A49FF353A38FF454A49FF4B504EFF
+ 3C4140FF373C3AFF2A2F2EFF303533FF2D3231FF434846FF282D2CFF1F2422FF
+ 090E0DFF131816FF191E1CFF0B100EFF040907FF0C110FFF191E1CFF1D2220FF
+ 1D2220FF1D2220FF1D2220FF232826FF1B201EFF0F1412FF1C211FFF3C413FFF
+ 4C514FFF474C4AFF3D4441FF47504DFF404744FF37403DFF39403DFF2A3330FF
+ 464D4AFF8A9390FF646B68FF39423FFF49504DFF565F5CFF4D5451FF434C49FF
+ 3A413EFF3B423FFF404543FF424745FF383D3BFF4C514FFF3C413FFF4E5351FF
+ 565B59FF727775FF6E7371FF7B807EFF5F6462FF4A4F4DFF2B302EFF404543FF
+ 2C312FFF1B201EFF353C39FF5E6562FF636A67FF747B78FF363D3AFF535A57FF
+ 4C5350FF585F5CFF646B68FF49504DFF636A67FF6D7471FF777E7BFF606764FF
+ 676E6BFF545B58FF606764FF525954FF484F4CFF49504BFF4D5451FF4F5651FF
+ 565D5AFF5F6661FF5D6461FF252C27FF141B18FF313833FF484F4CFF505752FF
+ 3C4340FF161D18FF242927FF1B211CFF0A0F0DFF333934FF434846FF2C322DFF
+ 373C3AFF323833FF313634FF393F3AFF494E4CFF5B615CFF444947FF4F5550FF
+ 6F7472FF5E645FFF4E544FFF555C57FF717772FF616863FF666C67FF7E8580FF
+ 777D78FF7E8580FF666C67FF868D88FF838984FF787F7AFF8F9590FFB1B8B3FF
+ 737974FF6F7570FF414742FF4D534EFF454B46FF505651FF3C423DFF4C524DFF
+ 434944FF4B514CFF3A403BFF4C524DFF3D433EFF464C47FF464C47FF3F4540FF
+ 555B56FF4A504BFF454C47FF646E68FF4F5651FF3D4741FF343B36FF4F5953FF
+ 525954FF68726CFF727974FF79837DFF6C736EFF6F7973FF606762FF5F6963FF
+ 5C635EFF76807AFF5B6860FF404F47FF324139FF43524AFF6C7A74FF606E68FF
+ 67756FFF505E58FF42504AFF4F5D59FF566460FF4E5C58FF797C7AFF797C7AFF
+ 676A68FF696C6AFF585B59FF656866FF5D605EFF636664FF686B69FF666967FF
+ 666967FF717472FF646765FF858886FF6C6F6DFF7C7F7DFF5B605EFF767B79FF
+ 6F7472FF6F7472FF626765FF4F5452FF646967FF6D7270FF707573FF7F8482FF
+ 737876FF7A7F7DFF808583FF797E7CFF8C918FFF9A9F9DFF9CA19FFF8A8F8DFF
+ 959A98FF787D7BFF8E9391FF757A78FF8E9391FF8C918FFF6A6F6DFF6C716FFF
+ 6B706EFF696E6CFF676C6AFF606563FF4F5452FF3D4240FF3F4442FF242927FF
+ 303533FF2C312FFF222725FF313634FF373C3AFF3C413FFF2C312FFF3B403EFF
+ 3D4240FF303533FF5E6361FF444947FF484D4BFF666B69FF5D6260FF4E5351FF
+ 535856FF5A5F5DFF585D5BFF616664FF676C6AFF5B605EFF3F4442FF585D5BFF
+ 565B59FF363B39FF494E4CFF4D5250FF515654FF4E5351FF3F4442FF4E5351FF
+ 474C4AFF585D5BFF3C413FFF363B39FF4D5250FF393E3CFF353A38FF444947FF
+ 505553FF4F5452FF4A4F4DFF4A4F4DFF4E5351FF4F5452FF515452FF5F605EFF
+ 5F605EFF575856FF6B6C6AFF616260FF5C5D5BFF636462FF434442FF484947FF
+ 444543FF2C2D2BFF323331FF313230FF181917FF202321FF242B28FF3B4441FF
+ 3D4643FF434C49FF565F5CFF48514EFF3A4340FF515A57FF59625FFF606966FF
+ 666F6CFF6F7875FF606966FF5A6360FF3A4340FF1A2320FF1E2321FF2A2F2DFF
+ 2E3331FF363B39FF4D5250FF565B59FF494E4CFF3C413FFF404543FF424745FF
+ 2E3331FF282D2BFF0B100EFF131816FF0C110FFF141917FF0D1210FF0E1311FF
+ 111614FF131816FF171C1AFF1D2220FF232826FF272C2AFF242927FF232826FF
+ 2E3331FF444947FF505553FF515654FF515654FF555C59FF4F5653FF47504DFF
+ 3B4441FF2C3532FF29322FFF3B4441FF49524FFF444D4AFF353E3BFF303936FF
+ 414A47FF3C4542FF414A47FF58615EFF4C5552FF3E4744FF474C4AFF5C615FFF
+ 585D5BFF545957FF333836FF3E4341FF404543FF4F5452FF676C6AFF838886FF
+ 868B89FF848987FF5D6260FF575C5AFF444947FF434A47FF252C29FF3B4441FF
+ 4D5653FF6E7774FF4D5653FF565F5CFF454E4BFF444D4AFF47504DFF4B5451FF
+ 616A67FF59625FFF6F7875FF78817EFF88918EFF737C79FF78827CFF6D7771FF
+ 656F69FF68726CFF6D7771FF6E7872FF727C76FF78827CFF909A94FF636D67FF
+ 39433DFF222C26FF18221CFF1F2923FF2B352FFF2E3832FF202621FF272D28FF
+ 252B26FF313732FF363C37FF313732FF373D38FF323833FF595F5AFF656B66FF
+ 464C47FF4C524DFF656B66FF575D58FF525853FF5D635EFF535954FF4B514CFF
+ A1A7A2FF6D736EFFAFB5B0FF7D837EFF929893FF7A807BFF777D78FF9DA39EFF
+ 9DA39EFF676D68FF7F8580FF999F9AFF6B716CFF505651FF5A605BFF424843FF
+ 202621FF313732FF3B413CFF565C57FF454B46FF3C423DFF444A45FF5B615CFF
+ 4D534EFF333934FF2A302BFF3D433EFF5A605BFF555C57FF49504BFF616B65FF
+ 6F7973FF66706AFF68726CFF616B65FF5D6761FF59635DFF6C7670FF6E7872FF
+ 555F59FF555F59FF4B554FFF5D6761FF6A746EFF8E9B93FF697870FF5D6E63FF
+ 4E5E53FF47584DFF67766EFF6A7B72FF84938BFF708178FF7B8983FF6E7E77FF
+ 5C6A66FF4D5C58FF797C7AFF838684FF737674FF6E716FFF5B5E5CFF676A68FF
+ 4E514FFF3D403EFF2A2D2BFF303331FF3F4240FF444745FF3F4240FF535654FF
+ 555856FF6C6F6DFF808583FF878C8AFF595E5CFF505553FF6B706EFF676C6AFF
+ 666B69FF737876FF707573FF717674FF646967FF7D8280FF909593FF7B807EFF
+ 727775FF6E7371FF767B79FF606563FF626765FF484D4BFF5C615FFF464B49FF
+ 585D5BFF545957FF575C5AFF585D5BFF535856FF4B504EFF474C4AFF464B49FF
+ 424745FF3C413FFF3C413FFF212624FF262B29FF222725FF1F2422FF2F3432FF
+ 323735FF393E3CFF3F4442FF393E3CFF494E4CFF373C3AFF5E6361FF3D4240FF
+ 4A4F4DFF515654FF363B39FF4A4F4DFF555A58FF5B605EFF666B69FF656A68FF
+ 555A58FF474C4AFF5A5F5DFF676C6AFF565B59FF3E4341FF393E3CFF545957FF
+ 515654FF414644FF363B39FF3D4240FF585D5BFF5D6260FF4E5351FF363B39FF
+ 3D4240FF353A38FF434846FF3D4240FF343937FF343937FF3F4442FF4B504EFF
+ 4A4F4DFF424745FF464947FF4A4D4BFF434644FF494C4AFF3F4240FF393C3AFF
+ 474A48FF767977FF5F6260FF515452FF4B4E4CFF353836FF343735FF424543FF
+ 3C3F3DFF444947FF565D5AFF626B68FF5A6360FF565F5CFF5B6461FF3E4744FF
+ 1E2724FF212A27FF27302DFF262F2CFF303936FF3F4845FF5F6865FF58615EFF
+ 4E5754FF47504DFF303533FF222725FF181D1BFF0F1412FF070C0AFF121715FF
+ 242927FF292E2CFF222725FF383D3BFF393E3CFF353A38FF222725FF262B29FF
+ 141917FF060B09FF1A1F1DFF242927FF232826FF141917FF0D1210FF191E1CFF
+ 2B302EFF353A38FF5B605EFF585D5BFF5D6260FF6B706EFF717674FF6D7270FF
+ 6D7270FF717875FF4C5350FF3D4643FF434C49FF353E3BFF1B2421FF303936FF
+ 424B48FF242D2AFF323B38FF47504DFF545D5AFF3C4542FF414A47FF58615EFF
+ 4C5552FF4A5350FF464B49FF3D4240FF3F4442FF565B59FF393E3CFF222725FF
+ 303533FF666B69FF565B59FF666B69FF737876FF878C8AFF747977FF656A68FF
+ 4C514FFF484F4CFF3D4441FF2D3633FF333C39FF49524FFF4B5451FF4C5552FF
+ 49524FFF434C49FF444D4AFF505956FF545D5AFF424B48FF565F5CFF5C6562FF
+ 646D6AFF5F6865FF7A847EFF707A74FF69736DFF6A746EFF6C7670FF6C7670FF
+ 6B756FFF6C7670FF747E78FF7A847EFF6D7771FF57615BFF4A544EFF404A44FF
+ 39433DFF3D4741FF383E39FF474D48FF515752FF373D38FF2C322DFF3B413CFF
+ 3C423DFF3E443FFF1F2520FF404641FF3B413CFF4D534EFF797F7AFF6D736EFF
+ 5D635EFF515752FF828883FF737974FF868C87FF777D78FF8A908BFF8D938EFF
+ 9FA5A0FFB1B7B2FF8A908BFF868C87FF8D938EFF707671FF939994FF858B86FF
+ 7D837EFF898F8AFF5F6560FF535954FF414742FF4A504BFF404641FF3F4540FF
+ 313732FF353B36FF222823FF343A35FF464C47FF343A35FF2E342FFF474D48FF
+ 5B615CFF6E7570FF6B726DFF5D6761FF727C76FF6F7973FF838D87FF6B756FFF
+ 646E68FF444E48FF616B65FF68726CFF555F59FF58625CFF4B554FFF525C56FF
+ 4D5751FF646F67FF4F5C54FF58685DFF526055FF3A4A3FFF4B5850FF4B5A52FF
+ 66736BFF4C5B53FF5B6761FF4B5953FF3A4542FF2F3D39FF6F7270FF7F8280FF
+ 7A7D7BFF808381FF6D706EFF707371FF4F5250FF3A3D3BFF262927FF282B29FF
+ 3B3E3CFF4A4D4BFF5B5E5CFF5E615FFF595C5AFF585B59FF575C5AFF4B504EFF
+ 282D2BFF2A2F2DFF515654FF606563FF5E6361FF606563FF787D7BFF747977FF
+ 555A58FF5A5F5DFF686D6BFF616664FF666B69FF656A68FF747977FF626765FF
+ 616664FF4C514FFF5A5F5DFF4A4F4DFF595E5CFF585D5BFF5E6361FF5C615FFF
+ 545957FF4B504EFF484D4BFF4B504EFF4A4F4DFF454A48FF454A48FF323735FF
+ 3B403EFF3B403EFF3E4341FF474C4AFF3C413FFF404543FF414644FF313634FF
+ 3C413FFF3A3F3DFF484D4BFF393E3CFF474C4AFF464B49FF474C4AFF505553FF
+ 3C413FFF343937FF4D5250FF525755FF4E5351FF626765FF5F6462FF5A5F5DFF
+ 585D5BFF4E5351FF515654FF616664FF696E6CFF575C5AFF585D5BFF484D4BFF
+ 676C6AFF676C6AFF787D7BFF616664FF575C5AFF4F5452FF4A4F4DFF3B403EFF
+ 292E2CFF272C2AFF393E3CFF4D5250FF4F5452FF474C4AFF3B3E3CFF3E413FFF
+ 444745FF6A6D6BFF505351FF3E413FFF3A3D3BFF6A6D6BFF787B79FF666967FF
+ 676A68FF515452FF3E413FFF444745FF424543FF474C4AFF5A615EFF616A67FF
+ 5E6764FF636C69FF717A77FF67706DFF535C59FF525B58FF444D4AFF434C49FF
+ 444D4AFF3E4744FF6E7774FF69726FFF707976FF767F7CFF7B807EFF696E6CFF
+ 626765FF474C4AFF131816FF040907FF1A1F1DFF252A28FF2F3432FF383D3BFF
+ 363B39FF303533FF282D2BFF2F3432FF2D3230FF2A2F2DFF2A2F2DFF313634FF
+ 282D2BFF111614FF0D1210FF242927FF3A3F3DFF414644FF545957FF636866FF
+ 666B69FF5C615FFF616664FF727775FF737876FF666B69FF6D7471FF5B6461FF
+ 626B68FF656E6BFF535C59FF515A57FF5D6663FF5B6461FF4E5754FF49524FFF
+ 424B48FF3D4643FF616A67FF78817EFF646D6AFF6F7673FF656A68FF4F5452FF
+ 535856FF6F7472FF595E5CFF2E3331FF303533FF5C615FFF696E6CFF616664FF
+ 5F6462FF747977FF848987FF868B89FF6D7270FF585F5CFF6A716EFF49524FFF
+ 424B48FF38413EFF4B5451FF4D5653FF59625FFF464F4CFF47504DFF49524FFF
+ 464F4CFF515A57FF6D7673FF656E6BFF656E6BFF7C8582FF76807AFF6E7872FF
+ 66706AFF67716BFF6D7771FF707A74FF717B75FF6F7973FF5F6963FF747E78FF
+ 67716BFF545E58FF5E6862FF616B65FF58625CFF5A645EFF5F6560FF676D68FF
+ 797F7AFF535954FF454B46FF5F6560FF5E645FFF6E746FFF666C67FF6E746FFF
+ 7D837EFF767C77FF757B76FF878D88FFACB2ADFF7F8580FF797F7AFF808681FF
+ 5D635EFF8D938EFF525853FF737974FF494F4AFF696F6AFF7D837EFF676D68FF
+ 696F6AFF757B76FF919792FF7D837EFF8A908BFFB5BBB6FF9DA39EFF797F7AFF
+ 5C625DFF676D68FF727873FF6B716CFF4F5550FF3E443FFF1A201BFF0D130EFF
+ 2F3530FF383E39FF363C37FF3A403BFF3E443FFF707671FF7A817CFF5F6963FF
+ 6E7872FF737D77FF76807AFF6F7973FF7F8983FF747E78FF646E68FF737D77FF
+ 68726CFF6E7872FF5B655FFF515B55FF333D37FF364139FF37423AFF4D5B50FF
+ 5B665CFF4F5D52FF5A655DFF47544CFF535E56FF334038FF4B554FFF535F59FF
+ 5D6663FF5B6663FF636664FF6C6F6DFF696C6AFF7B7E7CFF6D706EFF717472FF
+ 616462FF626563FF5F6260FF4F5250FF4A4D4BFF616462FF7A7D7BFF6F7270FF
+ 535654FF333634FF242927FF272C2AFF494E4CFF5C615FFF555A58FF565B59FF
+ 535856FF444947FF444947FF6C716FFF666B69FF545957FF464B49FF3F4442FF
+ 555A58FF5E6361FF5E6361FF575C5AFF5D6260FF515654FF525755FF3E4341FF
+ 3F4442FF3D4240FF4F5452FF525755FF525755FF525755FF535856FF4E5351FF
+ 3D4240FF2C312FFF3C413FFF323735FF3B403EFF3D4240FF474C4AFF4C514FFF
+ 3A3F3DFF404543FF4B504EFF454A48FF494E4CFF686D6BFF595E5CFF636866FF
+ 5D6260FF5D6260FF575C5AFF555A58FF484D4BFF686D6BFFA1A6A4FF979C9AFF
+ 777C7AFF848987FF616664FF5E6361FF898E8CFF848987FF898E8CFF606563FF
+ 707573FF6D7270FF878C8AFF696E6CFF6B706EFF5A5F5DFF717674FF626765FF
+ 5E6361FF616664FF484D4BFF4F5452FF4E5351FF424745FF363B39FF333836FF
+ 363B39FF383D3BFF313432FF333634FF4D504EFF8E918FFF7E817FFF646765FF
+ 494C4AFF5C5F5DFF676A68FF636664FF777A78FF676A68FF494C4AFF3F4240FF
+ 353836FF393E3CFF353C39FF3D4643FF47504DFF565F5CFF6A7370FF6E7774FF
+ 666F6CFF616A67FF424B48FF4E5754FF4F5855FF3A4340FF626B68FF636C69FF
+ 6C7572FF6C7572FF616664FF656A68FF7F8482FF7F8482FF505553FF292E2CFF
+ 181D1BFF060B09FF484D4BFF3D4240FF393E3CFF363B39FF373C3AFF303533FF
+ 383D3BFF414644FF292E2CFF323735FF323735FF2A2F2DFF323735FF464B49FF
+ 4A4F4DFF404543FF1B201EFF353A38FF4B504EFF555A58FF666B69FF777C7AFF
+ 6F7472FF595E5CFF858C89FF7E8582FF6B726FFF6F7673FF858C89FF7F8683FF
+ 737A77FF7E8582FF6C7370FF484F4CFF222926FF1C2320FF585F5CFF7A817EFF
+ 535A57FF404744FF404543FF535856FF636866FF5E6361FF606563FF5C615FFF
+ 4D5250FF333836FF626765FF686D6BFF6B706EFF676C6AFF737876FF7D8280FF
+ 7E8381FF707774FF787F7CFF6B7471FF717A77FF535C59FF636C69FF626B68FF
+ 69726FFF424B48FF545D5AFF59625FFF555E5BFF6B7471FF848D8AFF7F8885FF
+ 727B78FF868F8CFF69736DFF626C66FF5B655FFF5D6761FF68726CFF747E78FF
+ 79837DFF78827CFF747E78FF88928CFF77817BFF606A64FF6B756FFF76807AFF
+ 717B75FF757F79FF757B76FF727873FF8A908BFF7B817CFF767C77FF878D88FF
+ 838984FF999F9AFF858B86FF7A807BFF858B86FF7D837EFF7C827DFF777D78FF
+ 9BA19CFF747A75FF686E69FF6B716CFF6B716CFF8A908BFF7A807BFF6B716CFF
+ 585E59FF5E645FFF595F5AFF646A65FF5A605BFF686E69FF676D68FF747A75FF
+ 767C77FF818782FF9CA29DFF787E79FF5B615CFF585E59FF6A706BFF6C726DFF
+ 6A706BFF656B66FF646A65FF424843FF4C524DFF494F4AFF434944FF3F4540FF
+ 383E39FF616762FF747B76FF717873FF7B827DFF888F8AFF5E6560FF5B625DFF
+ 69706BFF7A817CFF777E79FF828984FF737A75FF777E79FF6B726DFF6B726DFF
+ 515853FF535B54FF404841FF4E594FFF60695FFF667167FF79817AFF5F6A62FF
+ 69716AFF4F5A52FF4F5651FF5E6862FF6F7673FF6E7774FF5C5F5DFF646765FF
+ 646765FF7C7F7DFF717472FF777A78FF6B6E6CFF727573FF737674FF727573FF
+ 5D605EFF666967FF525553FF393C3AFF2C2F2DFF232624FF1F2422FF1B201EFF
+ 515654FF646967FF4C514FFF484D4BFF393E3CFF1E2321FF0D1210FF454A48FF
+ 505553FF474C4AFF3E4341FF353A38FF373C3AFF2A2F2DFF434846FF494E4CFF
+ 595E5CFF5E6361FF5B605EFF454A48FF3A3F3DFF333836FF373C3AFF343937FF
+ 2E3331FF2A2F2DFF2B302EFF292E2CFF1C211FFF0D1210FF1D2220FF181D1BFF
+ 1C211FFF191E1CFF282D2BFF2E3331FF1E2321FF2F3432FF333836FF313634FF
+ 242927FF4A4F4DFF2F3432FF4C514FFF454A48FF565B59FF626765FF535856FF
+ 3A3F3DFF4C514FFF747977FF6C716FFF686D6BFF929795FF737876FF5D6260FF
+ 7D8280FF797E7CFF939896FF545957FF585D5BFF585D5BFF727775FF727775FF
+ 666B69FF575C5AFF5C615FFF494E4CFF4C514FFF545957FF575C5AFF575C5AFF
+ 515654FF484D4BFF444947FF474C4AFF4A4F4DFF494E4CFF4B4E4CFF343735FF
+ 3D403EFF686B69FF646765FF595C5AFF4F5250FF535654FF505351FF555856FF
+ 676A68FF5A5D5BFF4A4D4BFF494C4AFF4E514FFF6B706EFF424946FF3F4845FF
+ 3B4441FF37403DFF39423FFF434C49FF49524FFF49524FFF3A4340FF404946FF
+ 3A4340FF27302DFF3F4845FF57605DFF6E7774FF737C79FF717674FF737876FF
+ 828785FF8D9290FF868B89FF787D7BFF626765FF494E4CFF505553FF3F4442FF
+ 414644FF404543FF484D4BFF373C3AFF414644FF4B504EFF373C3AFF454A48FF
+ 535856FF5B605EFF616664FF606563FF4C514FFF343937FF1F2422FF1E2321FF
+ 2D3230FF4C514FFF636866FF676C6AFF626765FF606563FF606764FF7A817EFF
+ 69706DFF575E5BFF6B726FFF6D7471FF646B68FF767D7AFF787F7CFF6F7673FF
+ 575E5BFF303734FF424946FF646B68FF474E4BFF282F2CFF1F2422FF292E2CFF
+ 363B39FF313634FF505553FF636866FF6A6F6DFF545957FF323735FF585D5BFF
+ 777C7AFF5C615FFF494E4CFF434846FF606563FF6D7471FF717875FF747D7AFF
+ 7E8784FF59625FFF5F6865FF666F6CFF747D7AFF515A57FF69726FFF7E8784FF
+ 79827FFF7A8380FF79827FFF848D8AFF707976FF666F6CFF6A746EFF626C66FF
+ 57615BFF535D57FF5B655FFF66706AFF68726CFF626C66FF6E7872FF8C9690FF
+ 97A19BFF8F9993FF8E9892FF8F9993FF8C9690FF8B958FFF7D837EFF787E79FF
+ 898F8AFF8F9590FF8D938EFF878D88FF7F8580FF8C928DFF848A85FF7F8580FF
+ 787E79FF818782FFB5BBB6FF7C827DFF707671FF6D736EFF494F4AFF424843FF
+ 3D433EFF4B514CFF595F5AFF505651FF6B716CFF747A75FF515752FF5B615CFF
+ 4D534EFF737974FF686E69FF6D736EFF656B66FF646A65FF636964FF606661FF
+ 646A65FF535954FF555B56FF4F5550FF626863FF6A706BFF727873FF676D68FF
+ 636964FF555B56FF545A55FF595F5AFF494F4AFF434944FF646B66FF646B66FF
+ 656C67FF878E89FF747B76FF7B827DFF656C67FF636A65FF757C77FF818883FF
+ 727974FF7A817CFF777E79FF818883FF6A716CFF6A726BFF626962FF61695FFF
+ 60685EFF61695FFF757C75FF666D66FF787F78FF6A716AFF707671FF737974FF
+ 727775FF707573FF5A5D5BFF656866FF606361FF6E716FFF6C6F6DFF848785FF
+ 7C7F7DFF797C7AFF6C6F6DFF7E817FFF5F6260FF676A68FF2F3230FF1E211FFF
+ 2B2E2CFF454846FF464B49FF3F4442FF5C615FFF636866FF686D6BFF747977FF
+ 636866FF616664FF444947FF505553FF333836FF282D2BFF333836FF3A3F3DFF
+ 434846FF383D3BFF2F3432FF343937FF404543FF505553FF535856FF494E4CFF
+ 3C413FFF363B39FF3C413FFF353A38FF272C2AFF181D1BFF141917FF181D1BFF
+ 1A1F1DFF181D1BFF161B19FF161B19FF161B19FF0F1412FF1D2220FF1E2321FF
+ 0E1311FF252A28FF313634FF2F3432FF1F2422FF323735FF232826FF373C3AFF
+ 3B403EFF555A58FF474C4AFF565B59FF5C615FFF676C6AFF6B706EFF505553FF
+ 474C4AFF666B69FF5A5F5DFF444947FF434846FF4C514FFF7D8280FF5E6361FF
+ 505553FF525755FF535856FF787D7BFF5F6462FF666B69FF616664FF4F5452FF
+ 4E5351FF4C514FFF575C5AFF4B504EFF414644FF484D4BFF636866FF7A7F7DFF
+ 7C817FFF737876FF666B69FF3B403EFF313634FF2F3432FF303533FF323735FF
+ 474C4AFF444947FF3E4341FF484D4BFF4E5351FF404543FF434846FF494E4CFF
+ 525755FF838886FF5A615EFF535C59FF4B5451FF3D4643FF343D3AFF444D4AFF
+ 5B6461FF626B68FF757E7BFF616A67FF4A5350FF48514EFF444D4AFF616A67FF
+ 747D7AFF7C8582FF7D8280FF808583FF737876FF6B706EFF797E7CFF878C8AFF
+ 888D8BFF868B89FF707573FF585D5BFF4B504EFF2F3432FF3A3F3DFF383D3BFF
+ 535856FF5D6260FF464B49FF515654FF5D6260FF626765FF5D6260FF515654FF
+ 454A48FF3E4341FF515654FF373C3AFF242927FF2A2F2DFF3A3F3DFF444947FF
+ 4B504EFF505553FF49504DFF5A615EFF636A67FF5F6663FF59605DFF575E5BFF
+ 666D6AFF7E8582FF757C79FF808784FF909794FF747B78FF646B68FF787F7CFF
+ 707774FF616865FF4C514FFF393E3CFF3B403EFF353A38FF505553FF505553FF
+ 696E6CFF727775FF454A48FF5C615FFF7C817FFF666B69FF575C5AFF3F4442FF
+ 585D5BFF686F6CFF69706DFF67706DFF68716EFF4B5451FF464F4CFF59625FFF
+ 77807DFF707976FF6A7370FF7E8784FF858E8BFF8F9895FF7B8481FF929B98FF
+ 8F9895FF88918EFF8D9791FF858F89FF77817BFF6D7771FF707A74FF76807AFF
+ 707A74FF646E68FF707A74FF78827CFF848E88FF828C86FF7B857FFF858F89FF
+ 949E98FF949E98FF878D88FF8A908BFF848A85FF8C928DFF868C87FF757B76FF
+ 797F7AFF797F7AFFA1A7A2FF929893FF737974FF555B56FF808681FF4E544FFF
+ 535954FF515752FF4A504BFF525853FF333934FF505651FF434944FF4D534EFF
+ 575D58FF5F6560FF6E746FFF5E645FFF4E544FFF757B76FF787E79FF676D68FF
+ 707671FF6B716CFF6E746FFF656B66FF696F6AFF5F6560FF7E847FFF7C827DFF
+ 757B76FF555B56FF4F5550FF565C57FF4B514CFF4E544FFF565C57FF565C57FF
+ 4B514CFF2C322DFF414843FF3C433EFF363D38FF545B56FF7B827DFF8F9691FF
+ 828984FF79807BFF6C736EFF79807BFF6B726DFF767D78FF767D78FF808782FF
+ 656C67FF606760FF7A7E78FF7C8178FF70756CFF5E635AFF6F736DFF6C706AFF
+ 828680FF6D716BFF676B66FF646863FF5E615FFF5C5F5DFF5A5D5BFF616462FF
+ 484B49FF454846FF4F5250FF8C8F8DFF9A9D9BFF979A98FF666967FF686B69FF
+ 333634FF525553FF2F3230FF393C3AFF414442FF545755FF545957FF686D6BFF
+ 797E7CFF636866FF686D6BFF676C6AFF545957FF7D8280FF787D7BFF7C817FFF
+ 5F6462FF595E5CFF5B605EFF535856FF5D6260FF616664FF4A4F4DFF454A48FF
+ 434846FF515654FF575C5AFF595E5CFF505553FF4D5250FF383D3BFF3A3F3DFF
+ 353A38FF292E2CFF202523FF1E2321FF1E2321FF1D2220FF121715FF171C1AFF
+ 191E1CFF0F1412FF191E1CFF131816FF000100FF131816FF191E1CFF1F2422FF
+ 232826FF2B302EFF2E3331FF252A28FF252A28FF373C3AFF414644FF484D4BFF
+ 474C4AFF4C514FFF575C5AFF515654FF4B504EFF555A58FF474C4AFF585D5BFF
+ 515654FF5E6361FF737876FF5D6260FF3A3F3DFF464B49FF4C514FFF777C7AFF
+ 414644FF535856FF505553FF4A4F4DFF4B504EFF3F4442FF4F5452FF525755FF
+ 545957FF545957FF555A58FF515654FF424745FF323735FF474C4AFF242927FF
+ 272C2AFF151A18FF181D1BFF161B19FF2F3432FF1E2321FF2A2F2DFF3E4341FF
+ 464B49FF3A3F3DFF424745FF353A38FF232826FF4B524FFF555E5BFF59625FFF
+ 5F6865FF545D5AFF404946FF454E4BFF535C59FF505956FF5B6461FF3D4643FF
+ 2F3835FF505956FF404946FF545D5AFF555E5BFF58615EFF565B59FF777C7AFF
+ 767B79FF676C6AFF707573FF787D7BFF787D7BFF838886FF6F7472FF6C716FFF
+ 6D7270FF4B504EFF505553FF424745FF464B49FF333836FF3E4341FF414644FF
+ 434846FF3E4341FF333836FF313634FF444947FF5A5F5DFF7B807EFF696E6CFF
+ 434846FF262B29FF2E3331FF4C514FFF525755FF434846FF515855FF272E2BFF
+ 39403DFF646B68FF5F6663FF575E5BFF6D7471FF7C8380FF838A87FF676E6BFF
+ 7A817EFF828986FF777E7BFF727976FF5B625FFF484F4CFF3D4240FF4B504EFF
+ 5A5F5DFF3D4240FF4D5250FF535856FF686D6BFF5A5F5DFF7E8381FF686D6BFF
+ 6F7472FF6C716FFF7F8482FF636866FF656A68FF616865FF5F6663FF5A6360FF
+ 5A6360FF4F5855FF454E4BFF565F5CFF757E7BFF808986FF6C7572FF6B7471FF
+ 78817EFF98A19EFF747D7AFF7E8784FF89928FFF9CA5A2FF9AA49EFF959F99FF
+ 8B958FFF848E88FF88928CFF8E9892FF86908AFF78827CFF858F89FF79837DFF
+ 838D87FF8C9690FF838D87FF88928CFF88928CFF727C76FF8F9590FF9AA09BFF
+ 828883FF848A85FF7E847FFF757B76FF8F9590FF8A908BFF848A85FF808681FF
+ 8A908BFF555B56FF4D534EFF3D433EFF656B66FF2B312CFF353B36FF363C37FF
+ 191F1AFF242A25FF2D332EFF363C37FF5D635EFF626863FF888E89FF828883FF
+ 6A706BFF505651FF606661FF626863FF7F8580FF4F5550FF636964FF6E746FFF
+ 7D837EFF646A65FF757B76FF757B76FF848A85FF737974FF7A807BFF6E746FFF
+ 4B514CFF5D635EFF646A65FF525853FF595F5AFF484E49FF2F3631FF2F3631FF
+ 252C27FF080F0AFF282F2AFF2A312CFF444B46FF5A615CFF717873FF787F7AFF
+ 616863FF656C67FF676E69FF787F7AFF636A65FF626962FF5F635DFF75786FFF
+ 71746BFF575A51FF686A64FF6D6F69FF80827CFF5D5F59FF5B5C58FF61625EFF
+ 646563FF5F605EFF303331FF4B4E4CFF5F6260FF3C3F3DFF515452FF505351FF
+ 626563FF959896FF595C5AFF5A5D5BFF424543FF4E514FFF454846FF4F5250FF
+ 474A48FF616462FF707573FF787D7BFF686D6BFF353A38FF333836FF1B201EFF
+ 1B201EFF202523FF505553FF535856FF6E7371FF595E5CFF535856FF535856FF
+ 7A7F7DFF797E7CFF6D7270FF848987FF696E6CFF8B908EFF717674FF696E6CFF
+ 494E4CFF848987FF888D8BFF656A68FF676C6AFF737876FF575C5AFF424745FF
+ 4E5351FF5B605EFF4A4F4DFF212624FF202523FF2E3331FF151A18FF000402FF
+ 0A0F0DFF151A18FF282D2BFF2F3432FF383D3BFF2F3432FF1E2321FF262B29FF
+ 353A38FF333836FF222725FF383D3BFF2D3230FF3E4341FF434846FF303533FF
+ 3D4240FF3D4240FF4B504EFF2D3230FF4B504EFF565B59FF494E4CFF5A5F5DFF
+ 636866FF616664FF676C6AFF6A6F6DFF5C615FFF595E5CFF6A6F6DFF626765FF
+ 4C514FFF4A4F4DFF5A5F5DFF4F5452FF4E5351FF363B39FF4A4F4DFF404543FF
+ 414644FF282D2BFF525956FF3B423FFF333A37FF2A312EFF1A211EFF282F2CFF
+ 39403DFF313835FF2E3532FF282F2CFF2B322FFF3F4643FF4D5451FF464D4AFF
+ 2E3532FF1B221FFF3E4744FF363F3CFF28312EFF434C49FF3E4744FF48514EFF
+ 343D3AFF363F3CFF28312EFF303936FF37403DFF343D3AFF262F2CFF1C2522FF
+ 242D2AFF323B38FF202523FF3B403EFF313634FF1F2422FF343937FF464B49FF
+ 3D4240FF343937FF4F5452FF4A4F4DFF5A5F5DFF787D7BFF7F8482FF6D7270FF
+ 5F6462FF626765FF5F6462FF5B605EFF797E7CFF727775FF4D5250FF6D7270FF
+ 878C8AFF575C5AFF7C817FFF878C8AFF747977FF656A68FF5F6462FF505553FF
+ 494E4CFF424745FF464B49FF4E5351FF4E5351FF575C5AFF6C716FFF6E7371FF
+ 5F6462FF585D5BFF878C8AFF727775FF5D6260FF5E6361FF757A78FF838886FF
+ 707573FF525755FF676C6AFF4F5452FF4E5351FF474C4AFF505553FF3D4240FF
+ 565B59FF6C716FFF545957FF666B69FF787D7BFF7D8280FF5C615FFF676C6AFF
+ 545957FF6B726FFF636A67FF5F6865FF67706DFF7A8380FF88918EFF8A9390FF
+ 87908DFF858E8BFF7B8481FF7C8582FF7C8582FF7A8380FF77807DFF757E7BFF
+ 757E7BFF77807DFF949E98FF8C9690FF8F9993FF8F9993FF86908AFF86908AFF
+ 8B958FFF848E88FF727C76FF9DA7A1FF86908AFF919B95FF9BA59FFF8F9993FF
+ 9FA9A3FF828C86FF8C928DFF8C928DFF999F9AFF909691FF848A85FF878D88FF
+ 7A807BFF848A85FF818782FF8C928DFF8D938EFF717772FF737974FF4C524DFF
+ 434944FF4D534EFF2A302BFF404641FF323833FF4B514CFF2E342FFF272D28FF
+ 7E847FFF777D78FF696F6AFF7D837EFFCAD0CBFF9CA29DFF696F6AFF7A807BFF
+ 5B615CFF585E59FF5A605BFF484E49FF7D837EFF6C726DFF8A908BFF6A706BFF
+ 5F6560FF5D635EFF8D938EFF6F7570FF5B615CFF737974FF6E746FFF6E746FFF
+ 8F9590FF787E79FF7D837EFF7C827DFF808681FF717772FF696F6AFF303631FF
+ 383E39FF2E342FFF444A45FF444A45FF545A55FF818782FF747A75FF838984FF
+ 767C77FF686F68FF878B85FF8F9289FF80837AFF787B72FF80827CFF72746EFF
+ 656761FF73756FFF70716DFF4F504CFF3F403EFF4F504EFF454846FF4F5250FF
+ 5D605EFF424543FF5F6260FF5B5E5CFF474A48FF444745FF3B3E3CFF4D504EFF
+ 4E514FFF454846FF606361FF747775FF757876FF6C6F6DFF666B69FF636866FF
+ 545957FF2E3331FF3F4442FF3F4442FF3F4442FF2C312FFF575C5AFF5D6260FF
+ 565B59FF5D6260FF626765FF5E6361FF636866FF868B89FF696E6CFF838886FF
+ 676C6AFF6A6F6DFF6C716FFF8C918FFF727775FF717674FFA1A6A4FF6E7371FF
+ 5E6361FF6E7371FF727775FF747977FF7C817FFF787D7BFF5C615FFF464B49FF
+ 4A4F4DFF4D5250FF313634FF1D2220FF1B201EFF141917FF141917FF060B09FF
+ 1E2321FF414644FF353A38FF151A18FF131816FF232826FF2B302EFF373C3AFF
+ 212624FF202523FF272C2AFF282D2BFF2E3331FF101513FF151A18FF434846FF
+ 313634FF1B201EFF3E4341FF4D5250FF414644FF494E4CFF5F6462FF464B49FF
+ 4D5250FF4A4F4DFF353A38FF515654FF656A68FF414644FF5E6361FF5A5F5DFF
+ 5E6361FF4B504EFF595E5CFF4D5250FF494E4CFF303533FF353C39FF373E3BFF
+ 3A413EFF323936FF2D3431FF363D3AFF363D3AFF242B28FF434A47FF3D4441FF
+ 3D4441FF474E4BFF4D5451FF484F4CFF3D4441FF363D3AFF3A4340FF3A4340FF
+ 343D3AFF3D4643FF3A4340FF3B4441FF29322FFF1F2825FF1B2421FF222B28FF
+ 2A3330FF2B3431FF212A27FF161F1CFF19221FFF222B28FF171C1AFF292E2CFF
+ 282D2BFF1B201EFF181D1BFF1B201EFF202523FF292E2CFF222725FF3E4341FF
+ 515654FF4E5351FF515654FF5C615FFF585D5BFF474C4AFF636866FF5B605EFF
+ 656A68FF898E8CFF9BA09EFF7A7F7DFF5D6260FF636866FF696E6CFF747977FF
+ 707573FF737876FF767B79FF696E6CFF666B69FF6D7270FF606563FF868B89FF
+ 8A8F8DFF707573FF707573FF818684FF858A88FF7F8482FF696E6CFF6F7472FF
+ 757A78FF707573FF606563FF585D5BFF696E6CFF828785FF6C716FFF636866FF
+ 5E6361FF474C4AFF5B605EFF616664FF707573FF646967FF646967FF666B69FF
+ 646967FF777C7AFF707573FF797E7CFF5C615FFF555C59FF646B68FF5B6461FF
+ 555E5BFF5A6360FF68716EFF77807DFF7F8885FF828B88FF868F8CFF858E8BFF
+ 838C89FF7F8885FF7B8481FF7A8380FF7C8582FF7E8784FF6D7771FF6A746EFF
+ 727C76FF747E78FF6A746EFF6A746EFF6E7872FF68726CFF707A74FF9BA59FFF
+ 8D9791FF949E98FF8A948EFF747E78FF97A19BFF9FA9A3FF888E89FF858B86FF
+ 9CA29DFF939994FF969C97FF8E948FFF7E847FFF7B817CFF9AA09BFF888E89FF
+ 919792FF979D98FF9EA49FFF646A65FF4F5550FF535954FF464C47FF4A504BFF
+ 4D534EFF5E645FFF696F6AFF5C625DFF535954FF545A55FF666C67FF565C57FF
+ 858B86FF7F8580FF606661FF5D635EFF484E49FF4B514CFF595F5AFF4D534EFF
+ 727873FF5D635EFF707671FF646A65FF666C67FF6F7570FF7E847FFF6B716CFF
+ 393F3AFF3B413CFF4E544FFF575D58FF707671FF717772FF909691FF909691FF
+ 7C827DFF979D98FF8C928DFF7D837EFF7D837EFF898F8AFF8F9590FF888E89FF
+ 858B86FF7B817CFF808681FF898F8AFF838984FF676B65FF6E706AFF878A81FF
+ 83867DFF71746BFF72746EFF71736DFF70726CFF7D7F79FF646561FF434440FF
+ 282927FF262725FF373A38FF4B4E4CFF6D706EFF494C4AFF424543FF3A3D3BFF
+ 3C3F3DFF3F4240FF3B3E3CFF424543FF464947FF2D302EFF525553FF535654FF
+ 565957FF414442FF555A58FF5E6361FF707573FF5B605EFF676C6AFF747977FF
+ 8D9290FF7E8381FF747977FF838886FF4F5452FF4B504EFF555A58FF646967FF
+ 545957FF848987FF636866FF6E7371FF707573FF6F7472FF6D7270FF717674FF
+ 6C716FFF6A6F6DFF7F8482FF636866FF5B605EFF666B69FF6E7371FF7B807EFF
+ 898E8CFF8A8F8DFF565B59FF585D5BFF666B69FF686D6BFF535856FF414644FF
+ 313634FF1B201EFF545957FF2A2F2DFF2F3432FF565B59FF525755FF2B302EFF
+ 1A1F1DFF1F2422FF1F2422FF2C312FFF323735FF383D3BFF282D2BFF1A1F1DFF
+ 1F2422FF0D1210FF101513FF343937FF323735FF282D2BFF3F4442FF5E6361FF
+ 656A68FF545957FF5D6260FF505553FF5B605EFF505553FF363B39FF535856FF
+ 676C6AFF3F4442FF464B49FF424745FF424745FF363B39FF494E4CFF515654FF
+ 595E5CFF4C514FFF353C39FF3F4643FF333A37FF232A27FF2A312EFF39403DFF
+ 3B423FFF383F3CFF4C5350FF49504DFF4A514EFF4C5350FF49504DFF414845FF
+ 3D4441FF3E4542FF39423FFF3C4542FF434C49FF3B4441FF424B48FF3C4542FF
+ 3A4340FF2E3734FF232C29FF232C29FF252E2BFF252E2BFF1E2724FF161F1CFF
+ 151E1BFF19221FFF1B201EFF1C211FFF292E2CFF303533FF262B29FF252A28FF
+ 323735FF3A3F3DFF353A38FF333836FF3A3F3DFF484D4BFF545957FF535856FF
+ 4A4F4DFF434846FF4E5351FF585D5BFF575C5AFF636866FF808583FF858A88FF
+ 797E7CFF7B807EFF707573FF707573FF747977FF7F8482FF838886FF6D7270FF
+ 626765FF747977FF5B5E5CFF7E817FFF7F8280FF616462FF5F6260FF757876FF
+ 838684FF888B89FF676A68FF727573FF818482FF7B7E7CFF555856FF383B39FF
+ 515452FF7E817FFF797E7CFF737876FF6C716FFF4C514FFF595E5CFF606563FF
+ 717674FF656A68FF696E6CFF6F7472FF606563FF6B706EFF5F6462FF5C615FFF
+ 525755FF4A514EFF515855FF535C59FF535C59FF525B58FF5F6865FF727B78FF
+ 7A8380FF77807DFF808986FF7F8885FF7B8481FF767F7CFF717A77FF6F7875FF
+ 707976FF737C79FF68726CFF67716BFF717B75FF707A74FF606A64FF5B655FFF
+ 5E6862FF58625CFF67716BFF78827CFF67716BFF828C86FF909A94FF77817BFF
+ 7D8781FF76807AFFA0A6A1FF898F8AFF999F9AFF828883FF9CA29DFF929893FF
+ 8C928DFF828883FFA9AFAAFF828883FF888E89FF919792FF969C97FF656B66FF
+ 515752FF414742FF404641FF494F4AFF6F7570FF6E746FFF8C928DFF8C928DFF
+ 555B56FF7B817CFF5A605BFF3C423DFF454B46FF585E59FF505651FF4B514CFF
+ 474D48FF393F3AFF444A45FF454B46FF595F5AFF474D48FF484E49FF4D534EFF
+ 545A55FF606661FF555B56FF646A65FF404641FF404641FF636964FF5C625DFF
+ 4A504BFF454B46FFBCC0BBFFBDC1BCFF878B86FFB3B7B2FF8F938EFF939792FF
+ 737772FF848883FF878B86FFB0B4AFFFC2C6C1FF848883FF7A7E79FF737772FF
+ 8E928DFF8D918BFF7D7F79FF94978EFF90938AFF7B7E75FF797B75FF767872FF
+ 646660FF555751FF838480FF696A66FF4D4E4CFF3F403EFF4C4F4DFF3F4240FF
+ 595C5AFF474A48FF4C4F4DFF494C4AFF4A4D4BFF444745FF414442FF343735FF
+ 2E312FFF2A2D2BFF454846FF3D403EFF444745FF4E514FFF3B403EFF3F4442FF
+ 686D6BFF6B706EFF6F7472FF727775FF939896FF8C918FFF666B69FF797E7CFF
+ 454A48FF1E2321FF2B302EFF5B605EFF636866FF777C7AFF616664FF404543FF
+ 626765FF878C8AFF828785FF414644FF494E4CFF6A6F6DFF666B69FF626765FF
+ 636866FF666B69FF676C6AFF6D7270FF747977FF747977FF4B504EFF4A4F4DFF
+ 515654FF535856FF4B504EFF434846FF3E4341FF3B403EFF5D6260FF545957FF
+ 5C615FFF666B69FF616664FF5D6260FF5C615FFF545957FF717674FF595E5CFF
+ 5E6361FF747977FF5F6462FF434846FF525755FF686D6BFF777C7AFF6B706EFF
+ 757A78FF606563FF595E5CFF606563FF434846FF3C413FFF5C615FFF787D7BFF
+ 757A78FF656A68FF676C6AFF5F6462FF494E4CFF434846FF464B49FF3D4240FF
+ 2F3432FF232826FF2F3432FF3B403EFF3C413FFF2E3331FF404744FF434A47FF
+ 2C3330FF1E2522FF2F3633FF373E3BFF3B423FFF4E5552FF414845FF414845FF
+ 464D4AFF4B524FFF484F4CFF3F4643FF3B423FFF3D4441FF4F5855FF47504DFF
+ 515A57FF424B48FF4C5552FF363F3CFF404946FF3E4744FF444D4AFF39423FFF
+ 2F3835FF29322FFF242D2AFF1C2522FF19221FFF1B2421FF181D1BFF0D1210FF
+ 1D2220FF303533FF2F3432FF373C3AFF3D4240FF2D3230FF414644FF393E3CFF
+ 3F4442FF525755FF5A5F5DFF515654FF4A4F4DFF4D5250FF2E3331FF424745FF
+ 6F7472FF7A7F7DFF6F7472FF8E9391FF9DA2A0FF757A78FF868B89FF757A78FF
+ 767B79FF7F8482FF818684FF686D6BFF505553FF646967FF7D807EFF7C7F7DFF
+ 717472FF717472FF7F8280FF858886FF8A8D8BFF989B99FF838684FF7D807EFF
+ 7C7F7DFF7A7D7BFF686B69FF525553FF525553FF606361FF818684FF767B79FF
+ 737876FF565B59FF4F5452FF3D4240FF5B605EFF717674FF787D7BFF7A7F7DFF
+ 626765FF5F6462FF525755FF4D5250FF5C615FFF5C6360FF59605DFF646D6AFF
+ 646D6AFF59625FFF59625FFF69726FFF707976FF6B7471FF868F8CFF87908DFF
+ 868F8CFF818A87FF7C8582FF78817EFF767F7CFF77807DFF7A847EFF7A847EFF
+ 838D87FF818B85FF6F7973FF6A746EFF707A74FF6E7872FF646E68FF606A64FF
+ 454F49FF616B65FF848E88FF79837DFF66706AFF47514BFF606661FF656B66FF
+ 929893FF646A65FF656B66FF4E544FFF747A75FF919792FF7E847FFF656B66FF
+ 707671FF6D736EFF7B817CFF7E847FFF8C928DFF717772FF4B514CFF4F5550FF
+ 6E746FFF545A55FF5E645FFF737974FF515752FF727873FF5A605BFF4F5550FF
+ 3E443FFF4C524DFF4B514CFF535954FF626863FF383E39FF4B514CFF5B615CFF
+ 656B66FF5E645FFF575D58FF606661FF5D635EFF5D635EFF4F5550FF656B66FF
+ 5F6560FF616762FF747A75FF6A706BFF4C524DFF373D38FF646863FF80847FFF
+ 565A55FF8B8F8AFF7D817CFF989C97FF797D78FF868A85FF777B76FF9EA29DFF
+ A4A8A3FF7F837EFF8F938EFF929691FF919590FF878B85FF999D97FF9BA097FF
+ 8E9188FF777C73FF71736DFF70746EFF6E706AFF686C66FF5E5F5BFF4D514CFF
+ 3B3C3AFF2C2F2DFF575A58FF464947FF696C6AFF656866FF646765FF4C4F4DFF
+ 484B49FF4D504EFF424543FF414442FF2D302EFF313432FF2A2D2BFF2D302EFF
+ 2B2E2CFF454846FF3E4341FF272C2AFF474C4AFF5F6462FF6E7371FF5D6260FF
+ 646967FF535856FF646967FF606563FF505553FF1D2220FF1A1F1DFF2F3432FF
+ 484D4BFF353A38FF585D5BFF323735FF545957FF787D7BFF878C8AFF4C514FFF
+ 515654FF616664FF767B79FF707573FF656A68FF646967FF707573FF747977FF
+ 6A6F6DFF616664FF6F7472FF5D6260FF4F5452FF4E5351FF4E5351FF484D4BFF
+ 545957FF6D7270FF3E4341FF595E5CFF737876FF6A6F6DFF505553FF515654FF
+ 5D6260FF595E5CFF636866FF414644FF4B504EFF727775FF7A7F7DFF5D6260FF
+ 454A48FF494E4CFF484D4BFF595E5CFF6D7270FF4E5351FF878C8AFF9BA09EFF
+ 4D5250FF828785FF646967FF757A78FF767B79FF757A78FF767B79FF5E6361FF
+ 4A4F4DFF535856FF474C4AFF3F4442FF2E3331FF2E3331FF383D3BFF474C4AFF
+ 393E3CFF242927FF39403DFF39423FFF313A37FF3B4441FF4B5451FF3C4542FF
+ 303936FF434C49FF3A4340FF353E3BFF343D3AFF38413EFF3A4340FF353E3BFF
+ 323B38FF323B38FF29322FFF212A27FF3C4542FF464F4CFF5C6562FF48514EFF
+ 5B6461FF69726FFF5A6360FF4D5653FF3F4845FF39423FFF323B38FF262F2CFF
+ 1B2421FF151E1BFF222725FF1D2220FF272C2AFF292E2CFF222725FF323735FF
+ 373C3AFF1E2321FF111614FF373C3AFF484D4BFF3C413FFF3F4442FF585D5BFF
+ 5C615FFF494E4CFF585D5BFF313634FF3A3F3DFF555A58FF4C514FFF4F5452FF
+ 747977FF8E9391FF808583FF696E6CFF6B706EFF6F7472FF7C817FFF747977FF
+ 565B59FF696E6CFF7C7F7DFF787B79FF6E716FFF747775FF868987FF888B89FF
+ 838684FF8B8E8CFF8F9290FF8D908EFF868987FF7F8280FF7C7F7DFF7D807EFF
+ 7B7E7CFF777A78FF848987FF818684FF858A88FF686D6BFF616664FF515654FF
+ 6C716FFF7C817FFF959A98FF848987FF6E7371FF696E6CFF747977FF797E7CFF
+ 828785FF7A817EFF7F8683FF838C89FF77807DFF59625FFF4A5350FF565F5CFF
+ 656E6BFF68716EFF7F8885FF838C89FF88918EFF89928FFF868F8CFF808986FF
+ 7C8582FF7A8380FF79837DFF79837DFF838D87FF838D87FF77817BFF7A847EFF
+ 88928CFF8A948EFF6B756FFF77817BFF606A64FF545E58FF5C6660FF606A64FF
+ 606A64FF555F59FF404641FF323833FF515752FF2E342FFF494F4AFF3E443FFF
+ 595F5AFF656B66FF747A75FF656B66FF727873FF636964FF616762FF5E645FFF
+ 717772FF5C625DFF818782FF7B817CFF7C827DFF676D68FF606661FF828883FF
+ 898F8AFF717772FF6C726DFF696F6AFF525853FF5C625DFF525853FF505651FF
+ 6B716CFF444A45FF565C57FF696F6AFF6F7570FF747A75FF757B76FF7B817CFF
+ 787E79FF6D736EFF6D736EFF636964FF6A706BFF626863FF565C57FF676D68FF
+ 6D736EFF5C625DFF484C47FF767A75FF5D615CFF737772FF838782FF9CA09BFF
+ 919590FF949893FF7E827DFF999D98FF90948FFF949893FF999D98FFA0A49FFF
+ 848883FF838781FF8B8F89FF8A9288FF989D94FF9BA399FF888C86FF686F68FF
+ 5A5E58FF535A53FF3E423DFF343A35FF2B2E2CFF212624FF505351FF4F5250FF
+ 707371FF616462FF5A5D5BFF3F4240FF454846FF626563FF3D403EFF5A5D5BFF
+ 444745FF313432FF0E110FFF1B1E1CFF090C0AFF0F1210FF3F4442FF363B39FF
+ 5A5F5DFF707573FF7E8381FF5F6462FF5E6361FF575C5AFF717674FF565B59FF
+ 646967FF4F5452FF414644FF222725FF2D3230FF171C1AFF3F4442FF5C615FFF
+ 777C7AFF5C615FFF656A68FF5F6462FF6A6F6DFF595E5CFF5C615FFF616664FF
+ 585D5BFF535856FF5C615FFF616664FF686D6BFF7A7F7DFF727775FF686D6BFF
+ 5C615FFF606563FF616664FF4C514FFF484D4BFF616664FF5C615FFF4E5351FF
+ 4D5250FF4B504EFF3E4341FF3B403EFF3F4442FF3C413FFF434846FF4E5351FF
+ 666B69FF747977FF898E8CFF828785FF5F6462FF626765FF4F5452FF575C5AFF
+ 7B807EFF585D5BFF797E7CFFA0A5A3FF5F6462FF6B706EFF7A7F7DFF5C615FFF
+ 707573FF828785FF636866FF626765FF797E7CFF707573FF525755FF494E4CFF
+ 313634FF363B39FF3F4442FF5C615FFF545957FF484F4CFF3A413EFF363F3CFF
+ 39423FFF49524FFF515A57FF404946FF343D3AFF3D4643FF424B48FF323B38FF
+ 232C29FF1E2724FF1C2522FF19221FFF17201DFF17201DFF0B1411FF131C19FF
+ 363F3CFF555E5BFF6E7774FF68716EFF757E7BFF828B88FF616A67FF57605DFF
+ 4F5855FF4E5754FF48514EFF37403DFF232C29FF18211EFF2E3331FF373C3AFF
+ 3B403EFF2A2F2DFF1C211FFF2A2F2DFF3B403EFF373C3AFF161B19FF1E2321FF
+ 212624FF282D2BFF484D4BFF696E6CFF606563FF404543FF232826FF1C211FFF
+ 131816FF3F4442FF6E7371FF494E4CFF2E3331FF606563FF6C716FFF5C615FFF
+ 636866FF575C5AFF686D6BFF777C7AFF585D5BFF636866FF505351FF6C6F6DFF
+ 717472FF666967FF717472FF828583FF848785FF838684FF7D807EFF8D908EFF
+ 909391FF7E817FFF717472FF797C7AFF8B8E8CFF979A98FF838886FF949997FF
+ 9BA09EFF767B79FF818684FF8D9290FF979C9AFF7C817FFF919694FF848987FF
+ 959A98FF828785FF8A8F8DFF898E8CFF818684FF838A87FF7D8481FF808986FF
+ 79827FFF666F6CFF5A6360FF5E6764FF646D6AFF656E6BFF656E6BFF6D7673FF
+ 79827FFF818A87FF838C89FF818A87FF7D8683FF7B8481FF7C8680FF79837DFF
+ 7F8983FF7F8983FF747E78FF78827CFF858F89FF87918BFF727C76FF88928CFF
+ 7E8882FF626C66FF5A645EFF5D6761FF5B655FFF58625CFF646A65FF343A35FF
+ 282E29FF060C07FF2B312CFF363C37FF404641FF3D433EFF373D38FF2F3530FF
+ 525853FF666C67FF737974FF5E645FFF6E746FFF767C77FF6C726DFF7E847FFF
+ 818782FF787E79FF565C57FF636964FF878D88FF5D635EFF777D78FF656B66FF
+ 545A55FF646A65FF505651FF3E443FFF595F5AFF4C524DFF535954FF5F6560FF
+ 646A65FF6C726DFF7B817CFF787E79FF888E89FF7C827DFF626863FF515752FF
+ 717772FF737974FF5D635EFF707671FF787E79FF6C726DFF747873FF989C97FF
+ 767A75FF636762FF777B76FF7A7E79FF797D78FF7D817CFF828681FF969A95FF
+ 8F938EFF9CA09BFF828681FF838782FF757974FF8C908AFF787F78FF626A60FF
+ 6F776DFF929A90FF959C95FF7A817AFF575E57FF3A413AFF464C47FF3C423DFF
+ 353A38FF383D3BFF595C5AFF474A48FF414442FF303331FF656866FF6C6F6DFF
+ 525553FF444745FF2C2F2DFF4B4E4CFF494C4AFF333634FF242725FF282B29FF
+ 232624FF252826FF272C2AFF444947FF6C716FFF717674FF818684FF6B706EFF
+ 6D7270FF6F7472FF565B59FF4F5452FF505553FF555A58FF595E5CFF444947FF
+ 3D4240FF434846FF303533FF717674FF838886FF555A58FF575C5AFF616664FF
+ 666B69FF5C615FFF444947FF525755FF4D5250FF464B49FF4A4F4DFF4B504EFF
+ 616664FF8C918FFF4D5250FF565B59FF4F5452FF4C514FFF525755FF434846FF
+ 353A38FF434846FF666B69FF3E4341FF2D3230FF393E3CFF444947FF4C514FFF
+ 515654FF4E5351FF545957FF6B706EFF6B706EFF4F5452FF606563FF6E7371FF
+ 6C716FFFA5AAA8FF737876FF5E6361FF787D7BFF7D8280FF717674FF858A88FF
+ 7D8280FF525755FF7B807EFF616664FF757A78FF7F8482FF616664FF676C6AFF
+ 7E8381FF6E7371FF676C6AFF656A68FF4C514FFF4C514FFF424745FF575C5AFF
+ 484D4BFF3D4441FF404744FF3C4542FF3F4845FF3E4744FF3C4542FF444D4AFF
+ 47504DFF3C4542FF424B48FF343D3AFF27302DFF232C29FF232C29FF212A27FF
+ 222B28FF262F2CFF444D4AFF58615EFF646D6AFF6E7774FF69726FFF717A77FF
+ 69726FFF646D6AFF6F7875FF666F6CFF606966FF616A67FF5F6865FF545D5AFF
+ 454E4BFF3D4643FF2C312FFF363B39FF333836FF2A2F2DFF282D2BFF2A2F2DFF
+ 343937FF454A48FF3F4442FF272C2AFF181D1BFF2A2F2DFF4C514FFF5A5F5DFF
+ 474C4AFF2E3331FF1F2422FF383D3BFF252A28FF2A2F2DFF626765FF696E6CFF
+ 5A5F5DFF777C7AFF6B706EFF6A6F6DFF757A78FF4C514FFF505553FF6A6F6DFF
+ 454A48FF464B49FF111412FF30312FFF363735FF2B2C2AFF333432FF424341FF
+ 494A48FF4E4F4DFF5D5E5CFF676866FF6F706EFF6C6D6BFF636462FF636462FF
+ 737472FF838684FF727775FF858A88FF8B908EFF626765FF6F7472FF7D8280FF
+ 858A88FF646967FF646967FF5B605EFF959A98FF777C7AFF797E7CFF767B79FF
+ 5C615FFF6D7471FF616865FF5F6865FF606966FF646D6AFF666F6CFF636C69FF
+ 5A6360FF525B58FF505956FF5B6461FF6B7471FF79827FFF828B88FF87908DFF
+ 8A9390FF8B9491FF89938DFF838D87FF86908AFF848E88FF77817BFF78827CFF
+ 7E8882FF7A847EFF77817BFF7E8882FF7B857FFF6F7973FF747E78FF717B75FF
+ 5B655FFF545E58FF5F6560FF5A605BFF5F6560FF323833FF181E19FF161C17FF
+ 313732FF585E59FF565C57FF545A55FF666C67FF6F7570FF848A85FF666C67FF
+ 656B66FF6E746FFF757B76FF969C97FF9BA19CFF8C928DFF646A65FF4C524DFF
+ 5F6560FF5A605BFF727873FF5E645FFF555B56FF5A605BFF494F4AFF4A504BFF
+ 606661FF555B56FF626863FF676D68FF6E746FFF6E746FFF858B86FF6C726DFF
+ 8E948FFF858B86FF4D534EFF494F4AFF6B716CFF737974FF727873FF777D78FF
+ 676D68FF6D736EFF585C57FF71726EFF464743FF42433FFF60615DFF62635FFF
+ 686965FF848581FF8D8E8AFF787975FF6A6B67FF6F706CFF6E6F6BFF757672FF
+ 737470FF6A6E68FF747B74FF454E44FF343D33FF424B41FF525A53FF6B736CFF
+ 7D857EFF777F78FF474E49FF333A35FF29302DFF323936FF383D3BFF494E4CFF
+ 4F5452FF353A38FF707573FF797E7CFF4D5250FF303533FF292E2CFF2C312FFF
+ 383D3BFF292E2CFF343937FF191E1CFF272C2AFF393E3CFF2E3331FF505754FF
+ 686D6BFF5F6663FF898E8CFF868D8AFF7A7F7DFF656C69FF555A59FF69706DFF
+ 3D4240FF2F3633FF383D3BFF434A47FF2A2F2DFF414644FF353A38FF545957FF
+ 555A58FF585D5BFF737876FF6C716FFF575C5AFF606563FF6B706EFF656A68FF
+ 4E5351FF4C514FFF5E6361FF5B605EFF5D6260FF7B807EFF5C615FFF686D6BFF
+ 505553FF373C3AFF454A48FF545957FF5D6260FF707573FF525755FF515654FF
+ 5A5F5DFF585D5BFF474C4AFF434846FF4B504EFF4A4F4DFF525755FF5E6361FF
+ 5B605EFF505553FF6D7270FF5B605EFF383D3BFF797E7CFF747977FF777C7AFF
+ 565B59FF7E8381FF929795FF6B706EFF6F7472FF656A68FF5F6462FF787D7BFF
+ 767B79FF6B706EFF6E7371FF636866FF4E5351FF4B504EFF3F4442FF575C5AFF
+ 5C615FFF717674FF606563FF656A68FF414644FF2E3331FF373E3BFF3E4744FF
+ 4B524FFF3D4643FF353C39FF4D5653FF565D5AFF303936FF39403DFF353E3BFF
+ 3C4340FF454E4BFF515855FF545D5AFF5D6461FF656C69FF656C69FF848B88FF
+ 7C8380FF737A77FF606764FF828986FF777E7BFF656E6BFF858E8BFF79827FFF
+ 6E7774FF6D7673FF6F7875FF6D7673FF6B7471FF6B7471FF414845FF3E4542FF
+ 333836FF3B423FFF4E5351FF3E4542FF323735FF434A47FF3A3F3DFF545B58FF
+ 505553FF282F2CFF1C211FFF2D3431FF2D3230FF121916FF1A211EFF2D3431FF
+ 464D4AFF515855FF59605DFF6E7572FF7B827FFF767B79FF757A78FF818684FF
+ 8F9492FF525755FF474C4AFF636866FF393E3CFF343937FF2A2D2BFF252826FF
+ 1C1F1DFF212422FF2A2D2BFF232624FF222523FF333634FF3F4240FF333432FF
+ 383937FF555654FF686967FF646563FF5D5E5CFF5F605EFF5A5D5BFF5C615FFF
+ 606563FF3C413FFF383D3BFF303533FF434846FF424745FF414644FF202523FF
+ 646967FF4A4F4DFF6A6F6DFF7A7F7DFF494E4CFF525755FF606764FF4D5451FF
+ 404744FF454C49FF4F5653FF4E5552FF434A47FF39423FFF303936FF3C4542FF
+ 4E5754FF5F6865FF6E7774FF79827FFF818A87FF858E8BFF8B958FFF848E88FF
+ 88928CFF89938DFF808A84FF808A84FF848E88FF7C8680FF7F8983FF77817BFF
+ 737D77FF6F7973FF77817BFF737D77FF69706BFF787F7AFF777D78FF797F7AFF
+ 878D88FF7D837EFF6D736EFF6C726DFF5D635EFF686E69FF646A65FF6D736EFF
+ 676D68FF4F5550FF707671FF6C726DFF696F6AFF636964FF666C67FF757B76FF
+ 6F7570FF696F6AFF6E746FFF585E59FF4A504BFF686E69FF6C726DFF676D68FF
+ 646A65FF4F5550FF4A504BFF727873FF838984FF646A65FF686E69FF6A706BFF
+ 767C77FF6E746FFF838984FF535954FF7C827DFF747A75FF616762FF575D58FF
+ 525853FF444A45FF5C625DFF666C67FF595F5AFF898D88FF7D817CFF848882FF
+ 4B4C48FF555953FF686965FF595D57FF50514DFF797D77FF6D6E6AFF636761FF
+ 787975FF595D57FF484945FF3C403AFF646561FF626660FF60685EFF5B6359FF
+ 5F675DFF495248FF252C25FF313932FF5C645DFF6C746DFF838B84FF646B66FF
+ 525954FF5A615CFF363D3AFF383F3CFF2B322FFF242B28FF323936FF3C4340FF
+ 3E4542FF444B48FF2F3633FF242B28FF2A312EFF333A37FF2D3431FF2F3633FF
+ 3D4441FF434A47FF363D38FF444E48FF505752FF5F6865FF5D6461FF5F6766FF
+ 808685FF7D8584FF7E8384FF68706FFF575D5CFF0F1815FF262D2AFF3D4741FF
+ 2C332EFF151C17FF232826FF535856FF3E4341FF494E4CFF6F7472FF717674FF
+ 808583FF656A68FF7E8381FF848987FF7C817FFF595E5CFF797E7CFF606563FF
+ 434846FF5B605EFF7D8280FF5F6462FF7F8482FF535856FF757A78FF555A58FF
+ 464B49FF4D5250FF525755FF4E5351FF525755FF626765FF595E5CFF4C514FFF
+ 535856FF4C514FFF6F7472FF666B69FF5B605EFF565B59FF5B605EFF656A68FF
+ 707573FF767B79FF555A58FF444947FF333836FF4B504EFF6A6F6DFF6F7472FF
+ 626765FF474C4AFF4B504EFF666B69FF696E6CFF6F7472FF4D5250FF515654FF
+ 474C4AFF525755FF505553FF565B59FF646967FF727775FF787D7BFF797E7CFF
+ 7F8482FF868B89FF676C6AFF767D7AFF7F8482FF707774FF595E5CFF4C5350FF
+ 545957FF5F6663FF565B59FF535A57FF666B69FF7C8380FF767B79FF909794FF
+ 818684FF828785FF878A88FF7F8280FF777C7AFF767B79FF747977FF737876FF
+ 7D8280FF8A918EFF6D7471FF777E7BFF676E6BFF656C69FF767F7CFF6C7572FF
+ 6E7774FF98A19EFF6D7673FF656E6BFF515855FF505956FF4C5350FF2B3431FF
+ 2B322FFF39423FFF343B38FF2A3330FF3E4542FF48514EFF1B221FFF242D2AFF
+ 1E2522FF2A3330FF515D57FF434F49FF5B655FFF58625CFF56605AFF656F69FF
+ 747E78FF888F8AFF777E79FF707772FF848B86FF7E8580FF808681FF666C67FF
+ 5E645FFF424843FF3C433EFF373E39FF1B221DFF2F3631FF1C221DFF161C17FF
+ 212722FF343A35FF4A504BFF4E524DFF60645FFF585C57FF474B46FF656964FF
+ 767773FF4D4E4AFF3C3F3DFF3C3F3DFF343735FF2B2E2CFF202321FF111412FF
+ 1C1F1DFF3E413FFF505351FF3A3D3BFF3F4240FF4F5250FF717472FF575A58FF
+ 595C5AFF6A6D6BFF595C5AFF5F6260FF646967FF272C2AFF252A28FF373C3AFF
+ 444947FF3B423FFF303734FF2F3633FF4E5552FF676E6BFF717A77FF6A7370FF
+ 939C99FF88918EFF7C8784FF889390FF86918EFF7F8A87FF7D8885FF76817EFF
+ 757E7BFF808986FF575E5BFF69706DFF69706DFF5E6562FF515855FF6B726FFF
+ 888D8BFF626765FF888E89FF909691FF747A75FF808681FF999F9AFF717772FF
+ 878D88FF747A75FF9CA29DFF6C726DFF616762FF5F6560FF636964FF707671FF
+ 6E746FFF747A75FF6C726DFF5D635EFF767C77FF878D88FF6F7570FF6E746FFF
+ 818782FF7C827DFF5F6560FF646A65FF5D635EFF717772FF5C625DFF606661FF
+ 575D58FF686E69FF5B5E5CFF4C4F4DFF5E615FFF5B5E5CFF6B6E6CFF666967FF
+ 808381FF7D807EFF7E817FFF7D807EFF545755FF666967FF686B69FF828583FF
+ 838684FF575B56FF7B7F79FFB6BEB4FF5F635DFF747C72FF323630FF5E665CFF
+ 4A4E48FF727A70FF727670FF6B7369FF666A64FF626A60FF81857FFF4C544AFF
+ 3A3E38FF51564DFF444940FF6D7269FF787D74FF6B7369FF545950FF2B3329FF
+ 2C342AFF4E564CFF6F786EFF777F78FF8B938CFFA3ABA4FF1F2825FF2A3330FF
+ 2A3330FF2C3532FF3D4643FF49524FFF4C5552FF545D5AFF8A9390FF6D7673FF
+ 606966FF646D6AFF636C69FF606966FF57605DFF46504AFF3A443EFF48534BFF
+ 4B554FFF56605AFF525A59FF535B5AFF6B7373FF666E6EFF9DA5A5FF8A9292FF
+ 798180FF2D3633FF1D2623FF141E18FF162119FF29342CFF393E3CFF353A38FF
+ 363B39FF747977FF949997FF676C6AFF5E6361FF767B79FF676C6AFF696E6CFF
+ 6D7270FF535856FF6D7270FF595E5CFF424745FF4F5452FF6F7472FF5E6361FF
+ 7B807EFF585D5BFF717674FF666B69FF575C5AFF636866FF595E5CFF525755FF
+ 5A5F5DFF666B69FF545957FF444947FF484D4BFF414644FF4B504EFF515654FF
+ 4E5351FF474C4AFF4F5452FF5F6462FF5E6361FF505553FF3F4442FF333836FF
+ 282D2BFF363B39FF4A4F4DFF515654FF4D5250FF404543FF393E3CFF4C514FFF
+ 4F5452FF5E6361FF515654FF5F6462FF585D5BFF5C615FFF5A5F5DFF5F6462FF
+ 696E6CFF767B79FF7F8482FF7D8280FF7C817FFF828785FF797E7CFF818684FF
+ 808583FF6F7472FF5A5F5DFF545957FF606563FF6D7270FF737876FF6A6F6DFF
+ 757A78FF888D8BFF818684FF9BA09EFF878C8AFF858A88FF868785FF7D7E7CFF
+ 747775FF777A78FF7A7D7BFF7B7E7CFF7F8482FF878C8AFF848B88FF808784FF
+ 6A716EFF5C6360FF5E6764FF57605DFF58615EFF6D7673FF7A8380FF7B8481FF
+ 737C79FF78817EFF747D7AFF5A6360FF49524FFF464F4CFF3D4643FF2F3835FF
+ 37403DFF3C4542FF161F1CFF262F2CFF222B28FF2F3A37FF6F7B75FF65736DFF
+ 808C86FF7F8B85FF717D77FF707C76FF6D7771FF747E78FF818883FF7C837EFF
+ 909792FF878E89FF848A85FF6B716CFF696F6AFF535A55FF575E59FF525C56FF
+ 38423CFF505A54FF404742FF383F3AFF3B423DFF464D48FF5B615CFF5A605BFF
+ 6E726DFF6C706BFF60645FFF7C807BFF90918DFF71726EFF2D302EFF222523FF
+ 161917FF171A18FF181B19FF0E110FFF121513FF2A2D2BFF646765FF585B59FF
+ 666967FF777A78FF989B99FF858886FF8A8D8BFF969997FF616260FF757674FF
+ 8C8F8DFF636664FF6A6D6BFF727573FF686D6BFF545957FF4F5653FF4E5552FF
+ 646B68FF6D7471FF69726FFF57605DFF7B8481FF707B78FF6B7673FF6A7874FF
+ 5D6865FF525D5AFF55605DFF535E5BFF535C59FF5D6663FF555C59FF565D5AFF
+ 69706DFF8A918EFF7A7F7DFF646967FF767B79FF737876FF848A85FF8D938EFF
+ 717772FF6F7570FF7C827DFF545A55FF666C67FF4C524DFF797F7AFF616762FF
+ 676D68FF686E69FF686E69FF6B716CFF5A605BFF565C57FF787E79FF686E69FF
+ 6D736EFF727873FF646A65FF6B716CFF878D88FF969C97FF767C77FF616762FF
+ 474D48FF616762FF696F6AFF7B817CFF696F6AFF676D68FF6F7270FF636664FF
+ 727573FF707371FF7E817FFF727573FF7F8280FF777A78FF7F8280FF888B89FF
+ 6C6F6DFF797C7AFF6A6D6BFF767977FF6F7270FF484C47FF525952FF6F776DFF
+ 5C645AFF535B51FF4D554BFF3A4238FF464E44FF4C544AFF5A6258FF5A6258FF
+ 586056FF636B61FFA2AAA0FF8B9389FF60685EFF474F45FF55584FFF676A61FF
+ 71766DFF868B82FF868B82FF676C63FF4D554BFF3C443AFF5C655BFF636C62FF
+ 737C72FF858E84FF353E3BFF47504DFF4C5552FF4B5451FF525B58FF525B58FF
+ 4E5754FF535C59FF6C7572FF565F5CFF555E5BFF68716EFF79827FFF868F8CFF
+ 838C89FF737D77FF838D87FF8D9890FF818B85FF7F8983FF777F7EFF6E7675FF
+ 767E7EFF6A7272FF6A7272FF666E6EFF747C7BFF505956FF3F4845FF18221CFF
+ 1D2820FF444F47FF444947FF3A3F3DFF383D3BFF414644FF4C514FFF4B504EFF
+ 363B39FF484D4BFF565B59FF505553FF686D6BFF595E5CFF696E6CFF5D6260FF
+ 4F5452FF4B504EFF515654FF535856FF686D6BFF4E5351FF565B59FF686D6BFF
+ 565B59FF686D6BFF5F6462FF555A58FF686D6BFF6F7472FF545957FF434846FF
+ 444947FF3E4341FF444947FF4D5250FF474C4AFF383D3BFF3F4442FF4F5452FF
+ 434846FF262B29FF282D2BFF2F3432FF3C413FFF474C4AFF4C514FFF464B49FF
+ 373C3AFF2C312FFF3D4240FF434846FF414644FF515654FF555A58FF676C6AFF
+ 5D6260FF585D5BFF616664FF666B69FF6A6F6DFF767B79FF858A88FF808583FF
+ 757A78FF777C7AFF717674FF757A78FF747977FF6A6F6DFF5C615FFF585D5BFF
+ 616664FF6D7270FF808583FF727775FF767B79FF828785FF767B79FF8E9391FF
+ 787D7BFF747977FF767775FF6E6F6DFF686B69FF6D706EFF757876FF797C7AFF
+ 7A7F7DFF7D8280FF888F8CFF7E8582FF757C79FF69706DFF5E6764FF616A67FF
+ 636C69FF5A6360FF606966FF5E6764FF5A6360FF58615EFF656E6BFF77807DFF
+ 7F8885FF818A87FF707976FF636C69FF6A7370FF6A7370FF505956FF5C6562FF
+ 555E5BFF5F6A67FF727E78FF6F7D77FF8C9892FF929E98FF7D8983FF7C8882FF
+ 717B75FF76807AFF858C87FF808782FF949B96FF89908BFF868C87FF727873FF
+ 7A807BFF6B726DFF767D78FF737D77FF5E6862FF7D8781FF757C77FF6E7570FF
+ 69706BFF6B726DFF727873FF696F6AFF737772FF6F736EFF5E625DFF6B6F6AFF
+ 797A76FF656662FF434644FF272A28FF171A18FF242725FF2E312FFF252826FF
+ 212422FF2B2E2CFF414442FF414442FF5D605EFF6A6D6BFF858886FF777A78FF
+ 7F8280FF818482FF676866FF777876FF868987FF606361FF757876FF848785FF
+ 7D8280FF707573FF6D7471FF6F7673FF7A817EFF747B78FF656E6BFF48514EFF
+ 656E6BFF5A6562FF7F8A87FF75837FFF636E6BFF5D6865FF6B7673FF6D7875FF
+ 666F6CFF656E6BFF606764FF535A57FF5B625FFF7D8481FF696E6CFF474C4AFF
+ 656A68FF838886FF686E69FF777D78FF686E69FF5C625DFF636964FF494F4AFF
+ 5E645FFF424843FF767C77FF6A706BFF6B716CFF585E59FF535954FF5F6560FF
+ 5A605BFF5F6560FF404641FF565C57FF737974FF8A908BFF8D938EFF797F7AFF
+ 6B716CFF717772FF828883FF5D635EFF3A403BFF505651FF666C67FF7C827DFF
+ 6E746FFF666C67FF747775FF6A6D6BFF6F7270FF6A6D6BFF737674FF696C6AFF
+ 727573FF717472FF6E716FFF808381FF767977FF818482FF696C6AFF757876FF
+ 747775FF5E625DFF6B726BFF60685EFF747C72FF61695FFF6D756BFF343C32FF
+ 4D554BFF3B4339FF464E44FF60685EFF697167FF5D655BFF8D958BFF90988EFF
+ 858D83FF747C72FF7A7D74FF6A6D64FF63685FFF83887FFF8B9087FF81867DFF
+ 727A70FF434B41FF565F55FF5B645AFF656E64FF6F786EFF59625FFF6E7774FF
+ 717A77FF67706DFF5E6764FF4F5855FF434C49FF464F4CFF4C5552FF4D5653FF
+ 5E6764FF6F7875FF747D7AFF7E8784FF89928FFF87918BFF8B958FFF95A098FF
+ 7D8781FF727C76FF6B7372FF5D6564FF596161FF495151FF454D4DFF485050FF
+ 666E6DFF6D7673FF7B8481FF57615BFF545F57FF69746CFF7A7F7DFF838886FF
+ 797E7CFF363B39FF2B302EFF707573FF555A58FF494E4CFF4D5250FF424745FF
+ 6A6F6DFF646967FF6B706EFF656A68FF5E6361FF4A4F4DFF3A3F3DFF4B504EFF
+ 575C5AFF414644FF363B39FF5C615FFF454A48FF5C615FFF646967FF555A58FF
+ 767B79FF7C817FFF585D5BFF4C514FFF4B504EFF474C4AFF585D5BFF515654FF
+ 404543FF333836FF3B403EFF474C4AFF3B403EFF232826FF323735FF3E4341FF
+ 585D5BFF5B605EFF565B59FF4C514FFF303533FF252A28FF494E4CFF474C4AFF
+ 434846FF4C514FFF595E5CFF676C6AFF606563FF545957FF606563FF676C6AFF
+ 646967FF707573FF878C8AFF7F8482FF6B706EFF6C716FFF6C716FFF737876FF
+ 7D8280FF828785FF7D8280FF767B79FF757A78FF787D7BFF797E7CFF6C716FFF
+ 6E7371FF737876FF5D6260FF717674FF5E6361FF606563FF5C5D5BFF5B5C5AFF
+ 5B5E5CFF616462FF686B69FF6D706EFF6E7371FF717674FF7C8380FF787F7CFF
+ 878E8BFF848B88FF6E7774FF77807DFF7B8481FF5B6461FF646D6AFF58615EFF
+ 4A5350FF29322FFF2B3431FF59625FFF757E7BFF7D8683FF79827FFF7A8380FF
+ 8E9794FF8A9390FF78817EFF77807DFF6A7370FF717C79FF6C7872FF687670FF
+ 7E8A84FF88948EFF717D77FF7D8983FF79837DFF88928CFF818883FF777E79FF
+ 878E89FF7E8580FF848A85FF797F7AFF868C87FF7A817CFF7D847FFF7C8680FF
+ 6B756FFF909A94FF919893FF919893FF8A918CFF868D88FF989E99FF898F8AFF
+ 868A85FF7C807BFF656964FF616560FF686965FF5E5F5BFF6B6E6CFF404341FF
+ 2F3230FF434644FF4C4F4DFF3F4240FF363937FF363937FF252826FF2E312FFF
+ 535654FF5B5E5CFF6A6D6BFF5E615FFF666967FF5C5F5DFF636462FF686967FF
+ 646765FF363937FF575A58FF717472FF737876FF757A78FF757C79FF7B827FFF
+ 818885FF767D7AFF6D7673FF4C5552FF5F6865FF525D5AFF7E8986FF73817DFF
+ 67726FFF6F7A77FF8A9592FF8D9895FF78817EFF69726FFF676E6BFF656C69FF
+ 555C59FF505754FF3C413FFF353A38FF5E6361FF767B79FF505651FF636964FF
+ 666C67FF565C57FF5B615CFF545A55FF717772FF555B56FF828883FF7F8580FF
+ 747A75FF4C524DFF454B46FF5E645FFF696F6AFF7E847FFF515752FF717772FF
+ 828883FF939994FFA4AAA5FF8C928DFF777D78FF8B918CFF959B96FF7A807BFF
+ 626863FF686E69FF717772FF7B817CFF7D837EFF828883FF676A68FF626563FF
+ 595C5AFF4E514FFF515452FF525553FF646765FF797C7AFF656866FF737674FF
+ 707371FF787B79FF626563FF7B7E7CFF858886FF838782FF838A83FF60685EFF
+ 6E766CFF848C82FF798177FF666E64FF7A8278FF798177FF464E44FF6B7369FF
+ 7C847AFF5C645AFF6C746AFF71796FFF889086FF91998FFF95988FFF797C73FF
+ 686D64FF80857CFF747970FF73786FFF848C82FF535B51FF5C655BFF5F685EFF
+ 656E64FF687167FF}
+ BitmapAlign = baCenter
+ Scale = 1.000000000000000000
+ ScaleMode = smNormal
+ TabOrder = 0
+ OnPaintStage = Image32PaintStage
+ end
+ object PnlSettings: TPanel
+ Left = 324
+ Top = 0
+ Width = 143
+ Height = 285
+ Align = alRight
+ TabOrder = 1
+ object Label3: TLabel
+ Left = 8
+ Top = 32
+ Width = 57
+ Height = 13
+ Caption = 'Twirl Power:'
+ end
+ object Panel4: TPanel
+ Left = 1
+ Top = 1
+ Width = 141
+ Height = 16
+ Align = alTop
+ BevelOuter = bvNone
+ Caption = 'Twirl Distortion'
+ Color = clDark
+ Font.Color = clBase
+ Font.Height = 11
+ Font.Name = 'Tahoma'
+ Font.Pitch = fpVariable
+ Font.Style = []
+ Font.Weight = 40
+ ParentFont = False
+ TabOrder = 0
+ end
+ object gbTwist: TGaugeBar
+ Left = 8
+ Top = 48
+ Width = 129
+ Height = 12
+ Backgnd = bgPattern
+ HandleSize = 16
+ Max = 50
+ Min = -50
+ ShowArrows = False
+ ShowHandleGrip = True
+ Style = rbsMac
+ Position = 0
+ OnChange = gbTwistChange
+ end
+ object rbGetPixelFS: TRadioButton
+ Left = 8
+ Top = 96
+ Width = 129
+ Height = 17
+ Caption = 'TBitmap32.PixelFS'
+ TabOrder = 2
+ TabStop = False
+ OnClick = gbTwistChange
+ end
+ object rbPixelS: TRadioButton
+ Left = 8
+ Top = 72
+ Width = 105
+ Height = 17
+ Caption = 'TBitmap32.PixelS'
+ Checked = True
+ TabOrder = 3
+ OnClick = gbTwistChange
+ end
+ end
+end
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.cfg
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.cfg 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.cfg 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,39 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J-
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q-
+-$R-
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$YD
+-$Z1
+-cg
+-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+-H+
+-W+
+-M
+-$M16384,1048576
+-K$00400000
+-LE"d:\program\borland\delphi7\Projects\Bpl"
+-LN"d:\program\borland\delphi7\Projects\Bpl"
+-U"../../../"
+-O"../../../"
+-I"../../../"
+-R"../../../"
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.dof
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.dof 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.dof 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,141 @@
+[FileVersion]
+Version=7.0
+[Compiler]
+A=8
+B=0
+C=1
+D=1
+E=0
+F=0
+G=1
+H=1
+I=1
+J=0
+K=0
+L=1
+M=0
+N=1
+O=1
+P=1
+Q=0
+R=0
+S=0
+T=0
+U=0
+V=1
+W=0
+X=1
+Y=1
+Z=1
+ShowHints=1
+ShowWarnings=1
+UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+NamespacePrefix=
+SymbolDeprecated=1
+SymbolLibrary=1
+SymbolPlatform=1
+UnitLibrary=1
+UnitPlatform=1
+UnitDeprecated=1
+HResultCompat=1
+HidingMember=1
+HiddenVirtual=1
+Garbage=1
+BoundsError=1
+ZeroNilCompat=1
+StringConstTruncated=1
+ForLoopVarVarPar=1
+TypedConstVarPar=1
+AsgToTypedConst=1
+CaseLabelRange=1
+ForVariable=1
+ConstructingAbstract=1
+ComparisonFalse=1
+ComparisonTrue=1
+ComparingSignedUnsigned=1
+CombiningSignedUnsigned=1
+UnsupportedConstruct=1
+FileOpen=1
+FileOpenUnitSrc=1
+BadGlobalSymbol=1
+DuplicateConstructorDestructor=1
+InvalidDirective=1
+PackageNoLink=1
+PackageThreadVar=1
+ImplicitImport=1
+HPPEMITIgnored=1
+NoRetVal=1
+UseBeforeDef=1
+ForLoopVarUndef=1
+UnitNameMismatch=1
+NoCFGFileFound=1
+MessageDirective=1
+ImplicitVariants=1
+UnicodeToLocale=1
+LocaleToUnicode=1
+ImagebaseMultiple=1
+SuspiciousTypecast=1
+PrivatePropAccessor=1
+UnsafeType=1
+UnsafeCode=1
+UnsafeCast=1
+[Linker]
+MapFile=0
+OutputObjs=0
+ConsoleApp=1
+DebugInfo=0
+RemoteSymbols=0
+MinStackSize=16384
+MaxStackSize=1048576
+ImageBase=4194304
+ExeDescription=
+[Directories]
+OutputDir=
+UnitOutputDir=
+PackageDLLOutputDir=
+PackageDCPOutputDir=
+SearchPath=
+Packages=vcl;rtl;dbrtl;adortl;vcldb;vclx;bdertl;vcldbx;ibxpress;dsnap;cds;bdecds;qrpt;teeui;teedb;tee;dss;teeqr;visualclx;visualdbclx;dsnapcrba;dsnapcon;VclSmp;vclshlctrls;vclie;xmlrtl;inet;inetdbbde;inetdbxpress;inetdb;nmfast;webdsnap;websnap;soaprtl;dbexpress;dbxcds;indy;dclOffice2k;GR32_D6;GR32_DSGN_D6;GR32_Add_Package_D6;TabletD6;tb2k_d6;tbx_d6;ThemeManager6;ImportedVCLs
+Conditionals=
+DebugSourceDirs=
+UsePackages=0
+[Parameters]
+RunParams=
+HostApplication=
+Launcher=
+UseLauncher=0
+DebugCWD=
+[Language]
+ActiveLang=
+ProjectLang=
+RootDir=C:\Program Files\Borland\Delphi7\Bin\
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1030
+CodePage=1252
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+[Excluded Packages]
+c:\program files\borland\delphi7\Projects\Bpl\GR32_ThirdParty.bpl=(untitled)
+c:\program files\borland\delphi7\Projects\Bpl\PS_D7.bpl=Photoshop VCL Components (Mattias Andersson)
+c:\program files\borland\delphi7\Projects\Bpl\PS_dsgn_D7.bpl=Photoshop IDE Wizard (Mattias Andersson)
+c:\program files\borland\delphi7\Projects\Bpl\LUT_Install.bpl=LUTControl
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program PixelF_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {MainForm};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TMainForm, MainForm);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/PixelF_Ex/PixelF_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,186 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ QForms, QStdCtrls, QExtCtrls, QControls,
+ SysUtils, Classes, GR32, GR32_Image, GR32_Layers, GR32_Polygons;
+
+type
+ TForm1 = class(TForm)
+ Image: TImage32;
+ Panel1: TPanel;
+ Antialiase: TCheckBox;
+ Label1: TLabel;
+ LineAlpha: TScrollBar;
+ Label2: TLabel;
+ FillAlpha: TScrollBar;
+ FillMode: TRadioGroup;
+ Button1: TButton;
+ LineThickness: TScrollBar;
+ Label3: TLabel;
+ ThickOutline: TCheckBox;
+ Label4: TLabel;
+ BitmapList: TBitmap32List;
+ AntialiasMode: TRadioGroup;
+ Memo1: TMemo;
+ Memo2: TMemo;
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure ImageResize(Sender: TObject);
+ procedure ParamsChanged(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure ThicknessChanged(Sender: TObject);
+ private
+ Polygon: TPolygon32;
+ Outline: TPolygon32;
+ UseOutlinePoly: Boolean;
+ LineSize: Single;
+ procedure Build;
+ procedure Draw;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.xfm}
+
+procedure TForm1.Draw;
+var
+ AAMode: TAntialiasMode;
+begin
+ Case AntialiasMode.ItemIndex of
+ 0: AAMode := am16times;
+ 1: AAMode := am8times;
+ 2: AAMode := am4times;
+ else
+ AAMode := am4times;
+ end;
+
+ Image.Bitmap.BeginUpdate;
+ Image.Bitmap.Clear(clWhite32);
+ Image.Bitmap.Draw(50, 50, BitmapList.Bitmaps[0].Bitmap);
+ Polygon.Antialiased := Antialiase.Checked;
+ Polygon.AntialiasMode := AAMode;
+
+ if UseOutlinePoly then
+ begin
+ Outline.Antialiased := Antialiase.Checked;
+ Outline.AntialiasMode := AAMode;
+ end;
+
+ if FillMode.ItemIndex = 0 then Polygon.FillMode := pfAlternate else Polygon.FillMode := pfWinding;
+
+ Polygon.DrawFill(Image.Bitmap, SetAlpha(clGreen32, FillAlpha.Position));
+
+ if UseOutlinePoly then
+ Outline.DrawFill(Image.Bitmap, SetAlpha(clBlack32, LineAlpha.Position))
+ else
+ Polygon.DrawEdge(Image.Bitmap, SetAlpha(clBlack32, LineAlpha.Position));
+
+ Image.Bitmap.EndUpdate;
+ Image.Bitmap.Changed;
+ Image.Refresh; // force repaint
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ AntialiasMode.ItemIndex := 1;
+ FillMode.ItemIndex := 0;
+ Polygon := TPolygon32.Create;
+end;
+
+procedure TForm1.FormDestroy(Sender: TObject);
+begin
+ Outline.Free;
+ Polygon.Free;
+end;
+
+procedure TForm1.ImageMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ if Button = mbLeft then Polygon.Add(FixedPoint(X, Y))
+ else Polygon.Clear;
+ Build;
+ Draw;
+end;
+
+procedure TForm1.ImageResize(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ Build;
+ Draw;
+end;
+
+procedure TForm1.ParamsChanged(Sender: TObject);
+begin
+ AntialiasMode.Enabled := Antialiase.Checked and ThickOutline.Checked;
+ Draw;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+begin
+ Polygon.NewLine;
+end;
+
+procedure TForm1.Build;
+var
+ TmpPoly: TPolygon32;
+begin
+ Outline.Free;
+ Outline := nil;
+
+ if UseOutlinePoly then
+ begin
+ TmpPoly := Polygon.Outline;
+ Outline := TmpPoly.Grow(Fixed(LineSize / 2), 0.5);
+ Outline.FillMode := pfWinding;
+ TmpPoly.Free;
+ end;
+
+ if UseOutlinePoly then
+ Label4.Caption := Format('(%.1f)', [LineSize])
+ else
+ Label4.Caption := '(1)';
+end;
+
+procedure TForm1.ThicknessChanged(Sender: TObject);
+begin
+ AntialiasMode.Enabled := Antialiase.Checked and ThickOutline.Checked;
+ UseOutlinePoly := ThickOutline.Checked;
+ LineSize := LineThickness.Position / 10;
+ Build;
+ Draw;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/Polygons_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/Polygons_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/Polygons_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,21 @@
+program Polygons_Ex;
+
+{$I GR32.inc}
+
+{%File '..\..\GR32.inc'}
+
+uses
+ {$IFDEF CLX}
+ QForms,
+ {$ELSE}
+ Forms,
+ {$ENDIF}
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/Polygons_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Polygons_Ex/Polygons_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,139 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ {$IFDEF LINUX}Libc,{$ENDIF}
+ {$IFDEF MSWINDOWS}Windows, {$ENDIF}
+ SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
+ QStdCtrls, QExtCtrls, GR32, GR32_Image, QButtons;
+
+type
+ TForm1 = class(TForm)
+ Image: TImage32;
+ Panel1: TPanel;
+ Edit1: TEdit;
+ Label1: TLabel;
+ Button1: TButton;
+ Label2: TLabel;
+ SpeedButton1: TSpeedButton;
+ SpeedButton2: TSpeedButton;
+ SpeedButton3: TSpeedButton;
+ SpeedButton4: TSpeedButton;
+ SpeedButton5: TSpeedButton;
+ Label3: TLabel;
+ procedure Edit1Change(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure ImageResize(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure SpeedButton1Click(Sender: TObject);
+ public
+ AALevel: Integer;
+ procedure Draw;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.xfm}
+
+procedure TForm1.Draw;
+begin
+ Image.Bitmap.Clear;
+ Image.Bitmap.RenderText(10, 10, Edit1.Text, AALevel, $FFFFFFFF);
+end;
+
+procedure TForm1.Edit1Change(Sender: TObject);
+begin
+ Draw;
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ with Image.Bitmap.Font do
+ begin
+ Name := 'Tahoma';
+ Size := 20;
+ Style := [fsBold, fsItalic];
+ end;
+end;
+
+procedure TForm1.ImageResize(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ Draw;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+var
+ I: Integer;
+ tStart, tStop: {$IFDEF MSWINDOWS}Cardinal{$ELSE}timespec{$ENDIF};
+ tResult: Double;
+begin
+ {$IFDEF MSWINDOWS}
+ tStart := GetTickCount;
+ {$ELSE}
+ if clock_gettime(CLOCK_REALTIME, tStart) = -1 then
+ raise Exception.Create('Could not get time.');
+ {$ENDIF}
+
+ Screen.Cursor := crHourGlass;
+ with Image.Bitmap do
+ for I := 0 to 100 do
+ RenderText(
+ Random(Width - 40),
+ Random(Height - 40),
+ IntToStr(Random(100)),
+ AALevel,
+ Color32(Random(255), Random(255), Random(255), Random(255)));
+ Screen.Cursor := crDefault;
+
+ {$IFDEF MSWINDOWS}
+ tStop := GetTickCount;
+ tResult := (tStop - tStart) / 1000;
+ {$ELSE}
+ if clock_gettime(CLOCK_REALTIME, tStop) = -1 then
+ raise Exception.Create('Could not get time.');
+
+ tResult := (tStop.tv_sec - tStart.tv_sec) +
+ (tStop.tv_nsec - tStart.tv_nsec) / 1000000000;
+ {$ENDIF}
+
+ Label3.Caption := FloatToStr(tResult) + 's';
+end;
+
+procedure TForm1.SpeedButton1Click(Sender: TObject);
+begin
+ AALevel := TControl(Sender).Tag;
+ Draw;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/RenderText_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/RenderText_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/RenderText_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program RenderText_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/RenderText_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/RenderText_Ex/RenderText_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/GR32_RotLayer.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/GR32_RotLayer.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/GR32_RotLayer.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,186 @@
+unit GR32_RotLayer;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+{$I GR32.inc}
+
+uses
+{$IFDEF CLX}
+ Qt, Types,
+ {$IFDEF LINUX}Libc,{$ENDIF}
+ {$IFDEF MSWINDOWS}Windows, {$ENDIF}
+{$ELSE}
+ Windows,
+{$ENDIF}
+ Classes, SysUtils, GR32, GR32_Layers, GR32_Transforms,
+{$IFDEF CLX}
+ QControls, QGraphics, QConsts, QForms
+{$ELSE}
+ Messages, Controls, Graphics, Forms
+{$ENDIF};
+
+type
+ TCustomAffineLayer = class(TCustomLayer)
+ private
+ FAlphaHit: Boolean;
+ FTransformation: TAffineTransformation;
+ FBitmapCenter: TFloatPoint;
+ FBitmap: TBitmap32;
+ procedure BitmapChanged(Sender: TObject);
+ procedure SetBitmap(Value: TBitmap32);
+ protected
+ procedure AdjustTransformation; virtual;
+ function DoHitTest(X, Y: Integer): Boolean; override;
+ procedure Paint(Buffer: TBitmap32); override;
+ property Transformation: TAffineTransformation read FTransformation;
+ public
+ constructor Create(ALayerCollection: TLayerCollection); override;
+ destructor Destroy; override;
+ property AlphaHit: Boolean read FAlphaHit write FAlphaHit;
+ property Bitmap: TBitmap32 read FBitmap write SetBitmap;
+ end;
+
+ TAffineLayer = class(TCustomAffineLayer)
+ public
+ property Transformation;
+ end;
+
+ TRotLayer = class(TCustomAffineLayer)
+ private
+ FPosition: TFloatPoint;
+ FScaled: Boolean;
+ FAngle: Single;
+ procedure SetAngle(Value: Single);
+ procedure SetPosition(const Value: TFloatPoint);
+ procedure SetScaled(Value: Boolean);
+ procedure SetBitmapCenter(const Value: TFloatPoint);
+ protected
+ procedure AdjustTransformation; override;
+ public
+ property Angle: Single read FAngle write SetAngle;
+ property BitmapCenter: TFloatPoint read FBitmapCenter write SetBitmapCenter;
+ property Scaled: Boolean read FScaled write SetScaled;
+ property Position: TFloatPoint read FPosition write SetPosition;
+ end;
+
+implementation
+
+{ TCustomAffineLayer }
+
+type TATAccess = class(TAffineTransformation);
+
+procedure TCustomAffineLayer.AdjustTransformation;
+begin
+ // do nothing here
+end;
+
+procedure TCustomAffineLayer.BitmapChanged(Sender: TObject);
+begin
+ Transformation.SrcRect := FloatRect(0, 0, Bitmap.Width - 1, Bitmap.Height - 1);
+ Changed;
+end;
+
+constructor TCustomAffineLayer.Create(ALayerCollection: TLayerCollection);
+begin
+ inherited;
+ FBitmap := TBitmap32.Create;
+ FBitmap.OnChange := BitmapChanged;
+ FTransformation := TAffineTransformation.Create;
+end;
+
+destructor TCustomAffineLayer.Destroy;
+begin
+ FTransformation.Free;
+ FBitmap.Free;
+ inherited;
+end;
+
+function TCustomAffineLayer.DoHitTest(X, Y: Integer): Boolean;
+var
+ BX, BY: Integer;
+ Pt: TPoint;
+begin
+ with TATAccess(Transformation) do Transform(X, Y, BX, BY); // BX,BY - in 'FBitmap' coordinates
+ Pt := Point(BX, BY);
+ if PtInRect(Rect(0, 0, Bitmap.Width, Bitmap.Height), Pt) then Result := True;
+ if Result and AlphaHit and (Bitmap.PixelS[BX, BY] and $FF000000 = 0) then
+ Result := False;
+end;
+
+procedure TCustomAffineLayer.Paint(Buffer: TBitmap32);
+begin
+ AdjustTransformation;
+ Transform(Buffer, FBitmap, Transformation);
+end;
+
+procedure TCustomAffineLayer.SetBitmap(Value: TBitmap32);
+begin
+ FBitmap.Assign(Value);
+end;
+
+{ TRotLayer }
+
+procedure TRotLayer.AdjustTransformation;
+begin
+ Transformation.Clear;
+ Transformation.Translate(-BitmapCenter.X, -BitmapCenter.Y);
+ Transformation.Rotate(0, 0, Angle);
+ Transformation.Translate(Position.X, Position.Y);
+ if Scaled and Assigned(LayerCollection) and Assigned(LayerCollection.CoordXForm) then
+ with LayerCollection.CoordXForm^ do
+ begin
+ Transformation.Scale(ScaleX / 65536, ScaleY / 65536);
+ Transformation.Translate(ShiftX, ShiftY);
+ end;
+end;
+
+procedure TRotLayer.SetAngle(Value: Single);
+begin
+ FAngle := Value;
+ Changed;
+end;
+
+procedure TRotLayer.SetBitmapCenter(const Value: TFloatPoint);
+begin
+ FBitmapCenter := Value;
+ Changed;
+end;
+
+procedure TRotLayer.SetPosition(const Value: TFloatPoint);
+begin
+ FPosition := Value;
+ Changed;
+end;
+
+procedure TRotLayer.SetScaled(Value: Boolean);
+begin
+ FScaled := Value;
+ Changed;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,124 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ QForms, QStdCtrls, QExtCtrls, QControls,
+ GR32, GR32_Image, GR32_RotLayer, GR32_Transforms, GR32_RangeBars, Classes;
+
+type
+ TForm1 = class(TForm)
+ ImgView: TImgView32;
+ GaugeBar1: TGaugeBar;
+ Label1: TLabel;
+ GaugeBar2: TGaugeBar;
+ Label2: TLabel;
+ GaugeBar3: TGaugeBar;
+ Label3: TLabel;
+ GaugeBar4: TGaugeBar;
+ Label4: TLabel;
+ CheckBox1: TCheckBox;
+ procedure FormCreate(Sender: TObject);
+ procedure GaugeBar1Change(Sender: TObject);
+ procedure GaugeBar2Change(Sender: TObject);
+ procedure GaugeBar4Change(Sender: TObject);
+ procedure CheckBox1Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ L: TRotLayer;
+ procedure FillBitmap(B: TBitmap32; N: Integer);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+uses Math;
+
+{$R *.xfm}
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ ImgView.Bitmap.SetSize(200, 200);
+ FillBitmap(ImgView.Bitmap, 0);
+ L := TRotLayer.Create(ImgView.Layers);
+ L.Bitmap := TBitmap32.Create;
+ with L.Bitmap do
+ begin
+ BeginUpdate;
+ SetSize(100, 60);
+ L.BitmapCenter := FloatPoint(Width / 2, Height / 2);
+ FillBitmap(L.Bitmap, 127);
+ SetBorderTransparent(L.Bitmap, Rect(0, 0, Width - 1, Height - 1));
+ DrawMode := dmBlend;
+ StretchFilter := sfLinear;
+ EndUpdate;
+ Changed;
+ end;
+ L.Scaled := True;
+ L.Position := FloatPoint(100, 100);
+end;
+
+procedure TForm1.GaugeBar1Change(Sender: TObject);
+begin
+ L.Angle := GaugeBar1.Position;
+end;
+
+procedure TForm1.GaugeBar2Change(Sender: TObject);
+var
+ P: TFloatPoint;
+begin
+ P := L.Position;
+ P.X := GaugeBar2.Position;
+ P.Y := GaugeBar3.Position;
+ L.Position := P;
+end;
+
+procedure TForm1.GaugeBar4Change(Sender: TObject);
+begin
+ ImgView.Scale := Power(10, GaugeBar4.Position / 100);
+ ImgView.Update;
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ L.Scaled := not L.Scaled;
+end;
+
+procedure TForm1.FillBitmap(B: TBitmap32; N: Integer);
+var
+ X, Y: Integer;
+begin
+ for Y := 0 to B.Height - 1 do
+ for X := 0 to B.Width - 1 do
+ B[X, Y] := Color32(Random(127) + N, Random(127) + N, Random(127) + N, Random(127) + N);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/MainUnit.xfm
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/MainUnit.xfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/MainUnit.xfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,130 @@
+object Form1: TForm1
+ Left = 278
+ Top = 130
+ Width = 339
+ Height = 484
+ HorzScrollBar.Range = 289
+ ActiveControl = CheckBox1
+ Caption = 'Form1'
+ Color = clButton
+ Font.Color = clText
+ Font.Height = 11
+ Font.Name = 'MS Sans Serif'
+ Font.Pitch = fpVariable
+ Font.Style = []
+ Font.Weight = 40
+ ParentFont = False
+ Scaled = False
+ OnCreate = FormCreate
+ PixelsPerInch = 96
+ object Label1: TLabel
+ Left = 28
+ Top = 317
+ Width = 76
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'RotLayer.Angle:'
+ end
+ object Label2: TLabel
+ Left = 28
+ Top = 349
+ Width = 96
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'RotLayer.Position.X:'
+ end
+ object Label3: TLabel
+ Left = 28
+ Top = 377
+ Width = 96
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'RotLayer.Position.Y:'
+ end
+ object Label4: TLabel
+ Left = 28
+ Top = 445
+ Width = 85
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'ImgView32.Scale:'
+ end
+ object ImgView: TImgView32
+ Left = 4
+ Top = 8
+ Width = 325
+ Height = 297
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Scale = 1.000000000000000000
+ ScrollBars.Color = clDark
+ ScrollBars.ShowHandleGrip = True
+ ScrollBars.Style = rbsMac
+ SizeGrip = sgAuto
+ TabOrder = 0
+ end
+ object GaugeBar1: TGaugeBar
+ Left = 136
+ Top = 317
+ Width = 153
+ Height = 16
+ Anchors = [akLeft, akBottom]
+ Backgnd = bgPattern
+ Max = 180
+ Min = -180
+ ShowHandleGrip = True
+ Style = rbsMac
+ Position = 0
+ OnChange = GaugeBar1Change
+ end
+ object GaugeBar2: TGaugeBar
+ Left = 136
+ Top = 349
+ Width = 153
+ Height = 16
+ Anchors = [akLeft, akBottom]
+ Backgnd = bgPattern
+ Max = 200
+ ShowHandleGrip = True
+ Style = rbsMac
+ Position = 100
+ OnChange = GaugeBar2Change
+ end
+ object GaugeBar3: TGaugeBar
+ Left = 136
+ Top = 377
+ Width = 153
+ Height = 16
+ Anchors = [akLeft, akBottom]
+ Backgnd = bgPattern
+ Max = 200
+ ShowHandleGrip = True
+ Style = rbsMac
+ Position = 100
+ OnChange = GaugeBar2Change
+ end
+ object GaugeBar4: TGaugeBar
+ Left = 136
+ Top = 445
+ Width = 153
+ Height = 16
+ Anchors = [akLeft, akBottom]
+ Backgnd = bgPattern
+ Min = -100
+ ShowHandleGrip = True
+ Style = rbsMac
+ Position = 0
+ OnChange = GaugeBar4Change
+ end
+ object CheckBox1: TCheckBox
+ Left = 24
+ Top = 409
+ Width = 125
+ Height = 17
+ Anchors = [akLeft, akBottom]
+ Caption = 'RotLayer.Scaled:'
+ Checked = True
+ State = cbChecked
+ TabOrder = 5
+ OnClick = CheckBox1Click
+ end
+end
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/RotLayer_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/RotLayer_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/RotLayer_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program RotLayer_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/RotLayer_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/RotLayer_Ex/RotLayer_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,113 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
+ GR32, GR32_Image, GR32_Transforms, Math, GR32_RangeBars;
+
+type
+ TForm1 = class(TForm)
+ Src: TImage32;
+ Dst: TImage32;
+ Angle: TGaugeBar;
+ procedure FormCreate(Sender: TObject);
+ procedure AngleChange(Sender: TObject);
+ public
+ procedure ScaleRot(Alpha: Single);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.xfm}
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Dst.Bitmap.SetSize(Src.Bitmap.Width, Src.Bitmap.Height);
+
+ // erase the transparency of edge pixels
+ SetBorderTransparent(Src.Bitmap, Rect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1));
+
+ // show the picture
+ ScaleRot(0);
+end;
+
+procedure TForm1.ScaleRot(Alpha: Single);
+var
+ SrcR: Integer;
+ SrcB: Integer;
+ T: TAffineTransformation;
+ Sx, Sy, Scale: Single;
+begin
+ SrcR := Src.Bitmap.Width - 1;
+ SrcB := Src.Bitmap.Height - 1;
+ T := TAffineTransformation.Create;
+ T.SrcRect := FloatRect(0, 0, SrcR + 1, SrcB + 1);
+ try
+ // shift the origin
+ T.Clear;
+
+ // move the origin to a center for scaling and rotation
+ T.Translate(-SrcR / 2, -SrcB / 2);
+ T.Rotate(0, 0, Alpha);
+ Alpha := Alpha * 3.14159265358979 / 180;
+
+ // get the width and height of rotated image (without scaling)
+ Sx := Abs(SrcR * Cos(Alpha)) + Abs(SrcB * Sin(Alpha));
+ Sy := Abs(SrcR * Sin(Alpha)) + Abs(SrcB * Cos(Alpha));
+
+ // calculate a new scale so that the image fits in original boundaries
+ Sx := Src.Bitmap.Width / Sx;
+ Sy := Src.Bitmap.Height / Sy;
+ scale := Min(Sx, Sy);
+
+ T.Scale(Scale, Scale);
+
+ // move the origin back
+ T.Translate(SrcR / 2, SrcB / 2);
+
+ // transform the bitmap
+ Dst.BeginUpdate;
+ Dst.Bitmap.Clear(clGray32);
+ Transform(Dst.Bitmap, Src.Bitmap, T);
+ Dst.EndUpdate;
+ Dst.Repaint;
+ finally
+ T.Free;
+ end;
+end;
+
+procedure TForm1.AngleChange(Sender: TObject);
+begin
+ ScaleRot(-Angle.Position);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/Rotate_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/Rotate_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/Rotate_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Rotate_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/Rotate_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Rotate_Ex/Rotate_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,134 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
+ GR32, GR32_Transforms, QStdCtrls, GR32_Image, GR32_Layers;
+
+type
+ TForm1 = class(TForm)
+ Image32: TImage32;
+ Button1: TButton;
+ Edit1: TEdit;
+ Button2: TButton;
+ BitmapList: TBitmap32List;
+ Label1: TLabel;
+ procedure Button1Click(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ public
+ Velocities: TArrayOfFloatPoint;
+ procedure IdleHandler(Sender: TObject; var Done: Boolean);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.xfm}
+
+procedure TForm1.Button1Click(Sender: TObject);
+var
+ X: Integer;
+ ALayer: TBitmapLayer;
+ L: TFloatRect;
+ I: Integer;
+begin
+ Image32.BeginUpdate;
+ for X := 0 to 49 do
+ begin
+ // create a new layer...
+ ALayer := TBitmapLayer.Create(Image32.Layers);
+ with ALayer do
+ begin
+ Bitmap := BitmapList.Bitmaps[Random(BitmapList.Bitmaps.Count)].Bitmap;
+ Bitmap.DrawMode := dmBlend;
+ Bitmap.MasterAlpha := Random(255);
+
+ // put it somethere
+ L.Left := Random(Image32.Width);
+ L.Top := Random(Image32.Height);
+ L.Right := L.Left + Bitmap.Width;
+ L.Bottom := L.Top + Bitmap.Height;
+ ALayer.Location := L;
+
+ I := Length(Velocities);
+ SetLength(Velocities, I + 1);
+ Velocities[I] := FloatPoint(Random - 0.5, Random - 0.5);
+ end;
+ end;
+ Image32.EndUpdate;
+ Image32.Changed;
+ Edit1.Text := IntToStr(Image32.Layers.Count) + ' layers';
+end;
+
+procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
+var
+ I: Integer;
+ R: TFloatRect;
+begin
+ if Image32.Layers.Count = 0 then Exit;
+ Image32.BeginUpdate;
+ for I := 0 to Image32.Layers.Count - 1 do
+ begin
+ with TBitmapLayer(Image32.Layers[I]) do
+ begin
+ Bitmap.MasterAlpha := (Bitmap.MasterAlpha + 1) mod 256;
+ R := Location;
+ with Velocities[I] do
+ begin
+ OffsetRectF(R, X, Y);
+ X := X + (Random - 0.5) * 0.1;
+ Y := Y + (Random - 0.5) * 0.1;
+ if (R.Left < 0) and (X < 0) then X := 1;
+ if (R.Top < 0) and (Y < 0) then Y := 1;
+ if (R.Right > Image32.Width) and (X > 0) then X := -1;
+ if (R.Bottom > Image32.Height) and (Y > 0) then Y := -1;
+ end;
+ Location := R;
+ end;
+ end;
+ Image32.EndUpdate;
+ Image32.Invalidate;
+end;
+
+procedure TForm1.Button2Click(Sender: TObject);
+begin
+ Image32.Layers.Clear;
+ Velocities := nil;
+ Edit1.Text := '0 layers';
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Application.OnIdle := IdleHandler;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/Sprites_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/Sprites_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/Sprites_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Sprites_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/Sprites_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Sprites_Ex/Sprites_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,601 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, QGraphics, QControls, QForms, QDialogs,
+ GR32, GR32_Image, GR32_Transforms, GR32_Layers, QExtCtrls, QStdCtrls, QButtons,
+ QComCtrls, QGrids, GR32_RangeBars;
+
+type
+ TOpType = (opNone, opTranslate, opScale, opRotate, opSkew);
+ TOpRec = record
+ OpType: TOpType;
+ Dx, Dy: Extended; // shifts for opTranslate mode
+ Sx, Sy: Extended; // scale factors for opScale mode
+ Cx, Cy, Alpha: Extended; // rotation center and angle (deg) for opRotate mode
+ Fx, Fy: Extended; // skew factors for opSkew mode
+ end;
+ TOpRecs = array[0..7] of TOpRec;
+
+const
+ OpTypes: array [0..4] of TOpType = (opNone, opTranslate, opScale, opRotate,
+ opSkew);
+
+type
+ TTransformMode = (tmAffine, tmProjective, tmBilinear);
+
+ TForm1 = class(TForm)
+ Src: TImage32;
+ Dst: TImage32;
+ PageControl1: TPageControl;
+ TabSheet1: TTabSheet;
+ Panel2: TPanel;
+ Shape1: TShape;
+ Shape2: TShape;
+ StringGrid: TStringGrid;
+ ListBox: TListBox;
+ Button1: TButton;
+ Label9: TLabel;
+ CodeString: TEdit;
+ Panel1: TPanel;
+ Label1: TLabel;
+ ComboBox: TComboBox;
+ Label10: TLabel;
+ RadioGroup1: TRadioGroup;
+ Panel3: TPanel;
+ TabSheet2: TTabSheet;
+ Label18: TLabel;
+ OpacityBar: TGaugeBar;
+ PageControl: TPageControl;
+ tabDummy: TTabSheet;
+ tabTranslate: TTabSheet;
+ tabSkew: TTabSheet;
+ tabRotate: TTabSheet;
+ tabScale: TTabSheet;
+ Label2: TLabel;
+ Label3: TLabel;
+ Label4: TLabel;
+ Label5: TLabel;
+ eDx: TEdit;
+ eDy: TEdit;
+ sbDx: TGaugeBar;
+ sbDy: TGaugeBar;
+ Label11: TLabel;
+ Label13: TLabel;
+ Label16: TLabel;
+ Label15: TLabel;
+ eCx: TEdit;
+ eAlpha: TEdit;
+ eCy: TEdit;
+ sbAlpha: TGaugeBar;
+ Label6: TLabel;
+ Label7: TLabel;
+ Label8: TLabel;
+ eSy: TEdit;
+ eSx: TEdit;
+ sbSx: TGaugeBar;
+ sbSy: TGaugeBar;
+ Label12: TLabel;
+ Label14: TLabel;
+ Label17: TLabel;
+ eFx: TEdit;
+ eFy: TEdit;
+ sbFx: TGaugeBar;
+ sbFy: TGaugeBar;
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure ListBoxClick(Sender: TObject);
+ procedure ComboBoxChange(Sender: TObject);
+ procedure TranslationChanged(Sender: TObject);
+ procedure ScaleChanged(Sender: TObject);
+ procedure TranslationScrolled(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure ScaleScrolled(Sender: TObject);
+ procedure RotationChanged(Sender: TObject);
+ procedure RotationScrolled(Sender: TObject);
+ procedure SkewChanged(Sender: TObject);
+ procedure SkewScrolled(Sender: TObject);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure OpacityChange(Sender: TObject);
+ procedure PageControl1Change(Sender: TObject);
+
+ procedure RubberLayerMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure RubberLayerMouseMove(Sender: TObject; Shift: TShiftState; X,
+ Y: Integer; Layer: TCustomLayer);
+ procedure RubberLayerMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+
+ procedure AppEventsIdle(Sender: TObject; var Done: Boolean);
+ protected
+ LoadingValues: Boolean;
+ DraggedVertex: Integer;
+ LastMousePos: TPoint;
+ StippleStart: Single;
+ procedure PaintHandles(Sender: TObject; BackBuffer: TBitmap32);
+ public
+ Operation: TOpRecs;
+ Current: ^TOpRec;
+ AT: TAffineTransformation;
+ PT: TProjectiveTransformation;
+ TT: TTransformation;
+ Vertices: array[0..3] of TPoint;
+ Mode: TTransformMode;
+ procedure ClearTransformations;
+ procedure DoTransform;
+ procedure GenTransform;
+ procedure PrepareSource;
+ procedure ShowSettings(OperationNum: Integer);
+ procedure InitVertices; // for projective mapping
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+function GetVal(Src: string; var Dst: Extended): Boolean;
+var
+ Code: Integer;
+begin
+ Val(Src, Dst, Code);
+ Result := Code = 0;
+end;
+
+{$R *.xfm}
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ with TCustomLayer.Create(Dst.Layers) do
+ begin
+ OnPaint := PaintHandles;
+ end;
+
+ DraggedVertex := -1;
+ Dst.SetupBitmap; // set the destination bitmap size to match the image size
+ PrepareSource;
+ ClearTransformations;
+ ShowSettings(0);
+ AT := TAffineTransformation.Create;
+ PT := TProjectiveTransformation.Create;
+ TT := AT;
+ DoTransform;
+
+ Application.OnIdle := AppEventsIdle;
+ StringGrid.Col := 0;
+ StringGrid.Row := 0;
+end;
+
+procedure TForm1.ClearTransformations;
+var
+ I: Integer;
+begin
+ FillChar(Operation[0], SizeOf(TOpRecs), 0);
+ for I := 0 to 7 do
+ begin
+ Operation[I].Sx := 1;
+ Operation[I].Sy := 1;
+ Operation[I].Cx := Src.Bitmap.Width / 2;
+ Operation[I].Cy := Src.Bitmap.Height / 2;
+ end;
+end;
+
+procedure TForm1.PrepareSource;
+begin
+ // make the border pixels transparent while keeping their RGB components
+ SetBorderTransparent(Src.Bitmap,
+ Rect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1));
+end;
+
+procedure TForm1.DoTransform;
+var
+ i, j: Integer;
+ P: PColor32;
+begin
+ Application.ProcessMessages;
+ GenTransform;
+ Dst.BeginUpdate;
+
+ // Fill Dst with checkerboard pattern
+ P := Dst.Bitmap.PixelPtr[0, 0];
+ for j := 0 to Dst.Bitmap.Height - 1 do
+ for i := 0 to Dst.Bitmap.Width - 1 do
+ begin
+ if Odd(i shr 4) = Odd(j shr 4) then P^ := clGray32
+ else P^ := clWhite32;
+ Inc(P);
+ end;
+
+ Transform(Dst.Bitmap, Src.Bitmap, TT);
+ Dst.EndUpdate;
+ Dst.Repaint;
+
+ if Mode = tmAffine then
+ begin
+ // fill the string grid
+ for j := 0 to 2 do
+ for i := 0 to 2 do
+ StringGrid.Cells[i, j] := Format('%.3g', [AT.Matrix[i, j]]);
+ StringGrid.Col := 3; // hide grid cursor
+ end;
+end;
+
+procedure TForm1.GenTransform;
+var
+ I: Integer;
+ Rec: TOpRec;
+ S: string;
+begin
+ TT.SrcRect := FloatRect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1);
+ if Mode = tmProjective then
+ begin
+ PT.X0 := Vertices[0].X;
+ PT.Y0 := Vertices[0].Y;
+ PT.X1 := Vertices[1].X;
+ PT.Y1 := Vertices[1].Y;
+ PT.X2 := Vertices[2].X;
+ PT.Y2 := Vertices[2].Y;
+ PT.X3 := Vertices[3].X;
+ PT.Y3 := Vertices[3].Y;
+ end
+ else {if Mode = tmAffine then }
+ begin
+ // affine mode
+ AT.Clear;
+ for I := 0 to 7 do
+ begin
+ Rec := Operation[I];
+ case Rec.OpType of
+ opTranslate: AT.Translate(Rec.Dx, Rec.Dy);
+ opScale: AT.Scale(Rec.Sx, Rec.Sy);
+ opRotate: AT.Rotate(Rec.Cx, Rec.Cy, Rec.Alpha);
+ opSkew: AT.Skew(Rec.Fx, Rec.Fy);
+ end;
+ case Rec.OpType of
+ opTranslate: s := s + Format('Translate(%.3g, %.3g); ', [Rec.Dx, Rec.Dy]);
+ opScale: s := s + Format('Scale(%.3g, %.3g); ', [Rec.Sx, Rec.Sy]);
+ opRotate: s := s + Format('Rotate(%.3g, %.3g, %3g); ', [Rec.Cx, Rec.Cy, Rec.Alpha]);
+ opSkew: s := s + Format('Skew(%.3g, %.3g); ', [Rec.Fx, Rec.Fy]);
+ end;
+ end;
+ if Length(s) = 0 then s := 'Clear;';
+ CodeString.Text := s;
+ end;
+end;
+
+procedure TForm1.FormDestroy(Sender: TObject);
+begin
+ AT.Free;
+ PT.Free;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+begin
+ ClearTransformations;
+ ShowSettings(Listbox.ItemIndex);
+ DoTransform;
+end;
+
+procedure TForm1.ListBoxClick(Sender: TObject);
+begin
+ ShowSettings(ListBox.ItemIndex);
+end;
+
+procedure TForm1.ShowSettings(OperationNum: Integer);
+begin
+ LoadingValues := True;
+ ListBox.ItemIndex := OperationNum;
+ Current := @Operation[OperationNum];
+ Combobox.ItemIndex := Ord(Current.OpType);
+ PageControl.ActivePageIndex := Ord(Current.OpType);
+ eDx.Text := Format('%.4g', [Current.Dx]);
+ eDy.Text := Format('%.4g', [Current.Dy]);
+ sbDx.Position := Round(Current.Dx * 10);
+ sbDy.Position := Round(Current.Dy * 10);
+ eSx.Text := Format('%.4g', [Current.Sx]);
+ eSy.Text := Format('%.4g', [Current.Sy]);
+ sbSx.Position := Round(Current.Sx * 100);
+ sbSy.Position := Round(Current.Sy * 100);
+ eCx.Text := Format('%.4g', [Current.Cx]);
+ eCy.Text := Format('%.4g', [Current.Cy]);
+ eAlpha.Text := Format('%.4g', [Current.Alpha]);
+ sbAlpha.Position := Round(Current.Alpha * 2);
+ eFx.Text := Format('%.4g', [Current.Fx]);
+ eFy.Text := Format('%.4g', [Current.Fy]);
+ sbFx.Position := Round(Current.Fx * 100);
+ sbFy.Position := Round(Current.Fy * 100);
+ LoadingValues := False;
+end;
+
+procedure TForm1.ComboBoxChange(Sender: TObject);
+begin
+ Current.OpType := OpTypes[ComboBox.ItemIndex];
+ ShowSettings(ListBox.ItemIndex);
+ DoTransform;
+end;
+
+procedure TForm1.TranslationChanged(Sender: TObject);
+var
+ Tx, Ty: Extended;
+begin
+ if LoadingValues then Exit;
+ if GetVal(eDx.Text, Tx) and GetVal(eDy.Text, Ty) then
+ begin
+ Current.Dx := Tx;
+ Current.Dy := Ty;
+ DoTransform;
+ LoadingValues := True;
+ sbDx.Position := Round(Current.Dx * 10);
+ sbDy.Position := Round(Current.Dy * 10);
+ LoadingValues := False;
+ end;
+end;
+
+procedure TForm1.TranslationScrolled(Sender: TObject);
+begin
+ if LoadingValues then Exit;
+ Current.Dx := sbDx.Position / 10;
+ Current.Dy := sbDy.Position / 10;
+ DoTransform;
+ LoadingValues := True;
+ eDx.Text := FloatToStr(Current.Dx);
+ eDy.Text := FloatToStr(Current.Dy);
+ LoadingValues := False;
+end;
+
+procedure TForm1.ScaleChanged(Sender: TObject);
+var
+ Sx, Sy: Extended;
+begin
+ if LoadingValues then Exit;
+ if GetVal(eSx.Text, Sx) and GetVal(eSy.Text, Sy) then
+ begin
+ Current.Sx := Sx;
+ Current.Sy := Sy;
+ DoTransform;
+ LoadingValues := True;
+ sbSx.Position := Round(Current.Sx * 100);
+ sbSy.Position := Round(Current.Sy * 100);
+ LoadingValues := False;
+ end;
+end;
+
+procedure TForm1.ScaleScrolled(Sender: TObject);
+begin
+ if LoadingValues then Exit;
+ Current.Sx := sbSx.Position / 100;
+ Current.Sy := sbSy.Position / 100;
+ DoTransform;
+ LoadingValues := True;
+ eSx.Text := FloatToStr(Current.Sx);
+ eSy.Text := FloatToStr(Current.Sy);
+ LoadingValues := False;
+end;
+
+procedure TForm1.RotationChanged(Sender: TObject);
+var
+ Cx, Cy, Alpha: Extended;
+begin
+ if LoadingValues then Exit;
+ if GetVal(eCx.Text, Cx) and GetVal(eCy.Text, Cy) and
+ GetVal(eAlpha.Text, Alpha) then
+ begin
+ Current.Cx := Cx;
+ Current.Cy := Cy;
+ Current.Alpha := Alpha;
+ DoTransform;
+ LoadingValues := True;
+ sbAlpha.Position := Round(Alpha * 2);
+ LoadingValues := False;
+ end;
+end;
+
+procedure TForm1.RotationScrolled(Sender: TObject);
+begin
+ if LoadingValues then Exit;
+ Current.Alpha := sbAlpha.Position / 2;
+ DoTransform;
+ LoadingValues := True;
+ eAlpha.Text := FloatToStr(Current.Alpha / 2);
+ LoadingValues := False;
+end;
+
+procedure TForm1.SkewChanged(Sender: TObject);
+var
+ Fx, Fy: Extended;
+begin
+ if LoadingValues then Exit;
+ if GetVal(eFx.Text, Fx) and GetVal(eFy.Text, Fy) then
+ begin
+ Current.Fx := Fx;
+ Current.Fy := Fy;
+ DoTransform;
+ LoadingValues := True;
+ sbFx.Position := Round(Current.Fx * 10);
+ sbFy.Position := Round(Current.Fy * 10);
+ LoadingValues := False;
+ end;
+end;
+
+procedure TForm1.SkewScrolled(Sender: TObject);
+begin
+ if LoadingValues then Exit;
+ Current.Fx := sbFx.Position / 10;
+ Current.Fy := sbFy.Position / 10;
+ DoTransform;
+ LoadingValues := True;
+ eFx.Text := FloatToStr(Current.Fx);
+ eFy.Text := FloatToStr(Current.Fy);
+ LoadingValues := False;
+end;
+
+procedure TForm1.RadioGroup1Click(Sender: TObject);
+const
+ STRETCH_FILTER: array [0..1] of TStretchFilter = (sfNearest, sfLinear);
+begin
+ Src.Bitmap.StretchFilter := STRETCH_FILTER[RadioGroup1.ItemIndex];
+ DoTransform;
+end;
+
+procedure TForm1.OpacityChange(Sender: TObject);
+begin
+ OpacityBar.Update;
+ Src.Bitmap.MasterAlpha := OpacityBar.Position;
+ DoTransform;
+end;
+
+procedure TForm1.InitVertices;
+begin
+ Vertices[0].X := 0;
+ Vertices[0].Y := 0;
+ Vertices[1].X := Src.Bitmap.Width - 1;
+ Vertices[1].Y := 0;
+ Vertices[2].X := Src.Bitmap.Width - 1;
+ Vertices[2].Y := Src.Bitmap.Height - 1;
+ Vertices[3].X := 0;
+ Vertices[3].Y := Src.Bitmap.Height - 1;
+end;
+
+procedure TForm1.PageControl1Change(Sender: TObject);
+begin
+ if PageControl1.ActivePage = TabSheet1 then
+ begin
+ Mode := tmAffine;
+ TT := AT;
+ RadioGroup1.Parent := TabSheet1;
+ end
+ else {if PageControl1.ActivePage = TabSheet2 then }
+ begin
+ // set current transformation as projective
+ Mode := tmProjective;
+ TT := PT;
+ InitVertices;
+ RadioGroup1.Parent := TabSheet2;
+ end;
+ DoTransform;
+end;
+
+procedure TForm1.RubberLayerMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+var
+ I: Integer;
+begin
+ if Mode = tmAffine then Exit;
+
+ DraggedVertex := -1;
+
+ // find the vertex to drag
+ for I := 0 to 3 do
+ if (Abs(Vertices[I].X - X) < 3) and (Abs(Vertices[I].Y - Y) < 3) then
+ begin
+ DraggedVertex := I;
+ Break;
+ end;
+
+ // or drag all of them, (DragVertex = 4)
+ if DraggedVertex = -1 then DraggedVertex := 4;
+
+ // store current mouse position
+ LastMousePos := Point(X, Y);
+end;
+
+procedure TForm1.RubberLayerMouseMove(Sender: TObject; Shift: TShiftState;
+ X, Y: Integer; Layer: TCustomLayer);
+var
+ Dx, Dy, I: Integer;
+begin
+ if Mode = tmAffine then Exit;
+
+ if DraggedVertex = -1 then Exit; // mouse is not pressed
+
+ Dx := X - LastMousePos.X;
+ Dy := Y - LastMousePos.Y;
+ LastMousePos := Point(X, Y);
+
+ // update coords
+ if DraggedVertex = 4 then
+ begin
+ for I := 0 to 3 do
+ begin
+ Inc(Vertices[I].X, Dx);
+ Inc(Vertices[I].Y, Dy);
+ end;
+ end
+ else
+ begin
+ Inc(Vertices[DraggedVertex].X, Dx);
+ Inc(Vertices[DraggedVertex].Y, Dy);
+ end;
+
+ DoTransform;
+end;
+
+procedure TForm1.RubberLayerMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ DraggedVertex := -1;
+end;
+
+procedure TForm1.AppEventsIdle(Sender: TObject; var Done: Boolean);
+begin
+ StippleStart := StippleStart - 0.05;
+ Dst.Invalidate;
+end;
+
+procedure TForm1.PaintHandles(Sender: TObject; BackBuffer: TBitmap32);
+var
+ I, X0, Y0, X1, Y1: Integer;
+
+ procedure PaintVertex(X, Y: Integer);
+ begin
+ BackBuffer.FillRectS(X - 2, Y - 2, X + 2, Y + 2, clWhite32);
+ BackBuffer.FrameRectS(X - 3, Y - 3, X + 3, Y + 3, clBlack32);
+ end;
+
+begin
+ if PageControl1.ActivePage = TabSheet1 then Exit;
+
+ BackBuffer.SetStipple([clBlack32, clBlack32, clWhite32, clWhite32]);
+ BackBuffer.StippleStep := 0.5;
+ BackBuffer.StippleCounter := StippleStart;
+
+ X0 := Vertices[3].X;
+ Y0 := Vertices[3].Y;
+ for I := 0 to 3 do
+ begin
+ X1 := Vertices[I].X;
+ Y1 := Vertices[I].Y;
+ BackBuffer.LineFSP(X0, Y0, X1, Y1);
+ X0 := X1;
+ Y0 := Y1;
+ end;
+ for I := 0 to 3 do PaintVertex(Vertices[I].X, Vertices[I].Y);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/MainUnit.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/MainUnit.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/Transform_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/Transform_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/Transform_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Transform_Ex;
+
+uses
+ QForms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/Transform_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Clx/Transform_Ex/Transform_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="ByteMaps_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj ByteMaps_Ex.obj"/>
+ <RESFILES value="ByteMaps_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value="vcljpg50.lib"/>
+ <SPARELIBS value="Vcl50.lib vcljpg50.lib GR32_CB5.lib"/>
+ <PACKAGES value="Vcl50.bpi GR32_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="ByteMaps_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -4 -b- -k -y -v -vi-
+ -c -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("ByteMaps_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, Form1);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TForm1), &Form1);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program ByteMaps_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.drc
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.drc 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.drc 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,563 @@
+/* VER150
+ Generiert vom Borland Delphi Pascal Compiler
+ da -GD or --drc beim Compilieren angegeben war.
+
+ Sie enthält Compiler-generierte Ressourcen, die mit der ausführbaren Datei verbunden sind.
+ Wenn sie leer ist, wurden keine vom Compiler generierten Ressourcen mit der
+ produzierten ausführbaren Datei verbunden.
+*/
+
+#define JConsts_sChangeJPGSize 65248
+#define JConsts_sJPEGError 65249
+#define JConsts_sJPEGImageFile 65250
+#define ExtCtrls_clNameInactiveBorder 65264
+#define ExtCtrls_clNameInactiveCaption 65265
+#define ExtCtrls_clNameInactiveCaptionText 65266
+#define ExtCtrls_clNameInfoBk 65267
+#define ExtCtrls_clNameInfoText 65268
+#define ExtCtrls_clNameMenu 65269
+#define ExtCtrls_clNameMenuText 65270
+#define ExtCtrls_clNameNone 65271
+#define ExtCtrls_clNameScrollBar 65272
+#define ExtCtrls_clName3DDkShadow 65273
+#define ExtCtrls_clName3DLight 65274
+#define ExtCtrls_clNameWindow 65275
+#define ExtCtrls_clNameWindowFrame 65276
+#define ExtCtrls_clNameWindowText 65277
+#define ComStrs_sInvalidComCtl32 65278
+#define WinHelpViewer_hNoKeyword 65279
+#define ExtCtrls_clNameSkyBlue 65280
+#define ExtCtrls_clNameCream 65281
+#define ExtCtrls_clNameMedGray 65282
+#define ExtCtrls_clNameActiveBorder 65283
+#define ExtCtrls_clNameActiveCaption 65284
+#define ExtCtrls_clNameAppWorkSpace 65285
+#define ExtCtrls_clNameBackground 65286
+#define ExtCtrls_clNameBtnFace 65287
+#define ExtCtrls_clNameBtnHighlight 65288
+#define ExtCtrls_clNameBtnShadow 65289
+#define ExtCtrls_clNameBtnText 65290
+#define ExtCtrls_clNameCaptionText 65291
+#define ExtCtrls_clNameDefault 65292
+#define ExtCtrls_clNameGrayText 65293
+#define ExtCtrls_clNameHighlight 65294
+#define ExtCtrls_clNameHighlightText 65295
+#define ExtCtrls_clNameMaroon 65296
+#define ExtCtrls_clNameGreen 65297
+#define ExtCtrls_clNameOlive 65298
+#define ExtCtrls_clNameNavy 65299
+#define ExtCtrls_clNamePurple 65300
+#define ExtCtrls_clNameTeal 65301
+#define ExtCtrls_clNameGray 65302
+#define ExtCtrls_clNameSilver 65303
+#define ExtCtrls_clNameRed 65304
+#define ExtCtrls_clNameLime 65305
+#define ExtCtrls_clNameYellow 65306
+#define ExtCtrls_clNameBlue 65307
+#define ExtCtrls_clNameFuchsia 65308
+#define ExtCtrls_clNameAqua 65309
+#define ExtCtrls_clNameWhite 65310
+#define ExtCtrls_clNameMoneyGreen 65311
+#define Consts_SIconToClipboard 65312
+#define Consts_SCannotOpenClipboard 65313
+#define Consts_SDuplicateMenus 65314
+#define Consts_SPictureLabel 65315
+#define Consts_SPictureDesc 65316
+#define Consts_SPreviewLabel 65317
+#define Consts_SDockedCtlNeedsName 65318
+#define Consts_SDockTreeRemoveError 65319
+#define Consts_SDockZoneNotFound 65320
+#define Consts_SDockZoneHasNoCtl 65321
+#define Consts_SSeparator 65322
+#define HelpIntfs_hNoTableOfContents 65323
+#define HelpIntfs_hNothingFound 65324
+#define HelpIntfs_hNoContext 65325
+#define HelpIntfs_hNoTopics 65326
+#define ExtCtrls_clNameBlack 65327
+#define Consts_SmkcPgDn 65328
+#define Consts_SmkcEnd 65329
+#define Consts_SmkcHome 65330
+#define Consts_SmkcLeft 65331
+#define Consts_SmkcUp 65332
+#define Consts_SmkcRight 65333
+#define Consts_SmkcDown 65334
+#define Consts_SmkcIns 65335
+#define Consts_SmkcDel 65336
+#define Consts_SmkcShift 65337
+#define Consts_SmkcCtrl 65338
+#define Consts_SmkcAlt 65339
+#define Consts_srNone 65340
+#define Consts_sAllFilter 65341
+#define Consts_SInsertLineError 65342
+#define Consts_SInvalidClipFmt 65343
+#define Consts_SMsgDlgNo 65344
+#define Consts_SMsgDlgOK 65345
+#define Consts_SMsgDlgCancel 65346
+#define Consts_SMsgDlgHelp 65347
+#define Consts_SMsgDlgAbort 65348
+#define Consts_SMsgDlgRetry 65349
+#define Consts_SMsgDlgIgnore 65350
+#define Consts_SMsgDlgAll 65351
+#define Consts_SMsgDlgNoToAll 65352
+#define Consts_SMsgDlgYesToAll 65353
+#define Consts_SmkcBkSp 65354
+#define Consts_SmkcTab 65355
+#define Consts_SmkcEsc 65356
+#define Consts_SmkcEnter 65357
+#define Consts_SmkcSpace 65358
+#define Consts_SmkcPgUp 65359
+#define Consts_SHelpButton 65360
+#define Consts_SCloseButton 65361
+#define Consts_SIgnoreButton 65362
+#define Consts_SRetryButton 65363
+#define Consts_SAbortButton 65364
+#define Consts_SAllButton 65365
+#define Consts_SCannotDragForm 65366
+#define Consts_SVMetafiles 65367
+#define Consts_SVEnhMetafiles 65368
+#define Consts_SVIcons 65369
+#define Consts_SVBitmaps 65370
+#define Consts_SMsgDlgWarning 65371
+#define Consts_SMsgDlgError 65372
+#define Consts_SMsgDlgInformation 65373
+#define Consts_SMsgDlgConfirm 65374
+#define Consts_SMsgDlgYes 65375
+#define Consts_SCannotFocus 65376
+#define Consts_SParentRequired 65377
+#define Consts_SMDIChildNotVisible 65378
+#define Consts_SVisibleChanged 65379
+#define Consts_SCannotShowModal 65380
+#define Consts_SMenuIndexError 65381
+#define Consts_SMenuReinserted 65382
+#define Consts_SMenuNotFound 65383
+#define Consts_SNoTimers 65384
+#define Consts_SGroupIndexTooLow 65385
+#define Consts_SNoMDIForm 65386
+#define Consts_SControlParentSetToSelf 65387
+#define Consts_SOKButton 65388
+#define Consts_SCancelButton 65389
+#define Consts_SYesButton 65390
+#define Consts_SNoButton 65391
+#define Consts_SInvalidPixelFormat 65392
+#define Consts_SInvalidImage 65393
+#define Consts_SScanLine 65394
+#define Consts_SChangeIconSize 65395
+#define Consts_SUnknownExtension 65396
+#define Consts_SUnknownClipboardFormat 65397
+#define Consts_SOutOfResources 65398
+#define Consts_SNoCanvasHandle 65399
+#define Consts_SInvalidImageSize 65400
+#define Consts_SInvalidImageList 65401
+#define Consts_SReplaceImage 65402
+#define Consts_SImageIndexError 65403
+#define Consts_SImageReadFail 65404
+#define Consts_SImageWriteFail 65405
+#define Consts_SWindowDCError 65406
+#define Consts_SWindowClass 65407
+#define RTLConsts_SListCountError 65408
+#define RTLConsts_SListIndexError 65409
+#define RTLConsts_SMemoryStreamError 65410
+#define RTLConsts_SPropertyException 65411
+#define RTLConsts_SReadError 65412
+#define RTLConsts_SReadOnlyProperty 65413
+#define RTLConsts_SRegGetDataFailed 65414
+#define RTLConsts_SResNotFound 65415
+#define RTLConsts_SSeekNotImplemented 65416
+#define RTLConsts_SSortedListError 65417
+#define RTLConsts_SUnknownGroup 65418
+#define RTLConsts_SUnknownProperty 65419
+#define RTLConsts_SWriteError 65420
+#define Consts_SInvalidBitmap 65421
+#define Consts_SInvalidIcon 65422
+#define Consts_SInvalidMetafile 65423
+#define RTLConsts_SCantWriteResourceStreamError 65424
+#define RTLConsts_SCheckSynchronizeError 65425
+#define RTLConsts_SClassNotFound 65426
+#define RTLConsts_SDuplicateClass 65427
+#define RTLConsts_SDuplicateItem 65428
+#define RTLConsts_SDuplicateName 65429
+#define RTLConsts_SDuplicateString 65430
+#define RTLConsts_SFCreateErrorEx 65431
+#define RTLConsts_SFOpenErrorEx 65432
+#define RTLConsts_SInvalidImage 65433
+#define RTLConsts_SInvalidName 65434
+#define RTLConsts_SInvalidProperty 65435
+#define RTLConsts_SInvalidPropertyPath 65436
+#define RTLConsts_SInvalidPropertyValue 65437
+#define RTLConsts_SInvalidRegType 65438
+#define RTLConsts_SListCapacityError 65439
+#define SysConst_SShortDayNameMon 65440
+#define SysConst_SShortDayNameTue 65441
+#define SysConst_SShortDayNameWed 65442
+#define SysConst_SShortDayNameThu 65443
+#define SysConst_SShortDayNameFri 65444
+#define SysConst_SShortDayNameSat 65445
+#define SysConst_SLongDayNameSun 65446
+#define SysConst_SLongDayNameMon 65447
+#define SysConst_SLongDayNameTue 65448
+#define SysConst_SLongDayNameWed 65449
+#define SysConst_SLongDayNameThu 65450
+#define SysConst_SLongDayNameFri 65451
+#define SysConst_SLongDayNameSat 65452
+#define RTLConsts_SAncestorNotFound 65453
+#define RTLConsts_SAssignError 65454
+#define RTLConsts_SBitsIndexError 65455
+#define SysConst_SShortMonthNameOct 65456
+#define SysConst_SShortMonthNameNov 65457
+#define SysConst_SShortMonthNameDec 65458
+#define SysConst_SLongMonthNameJan 65459
+#define SysConst_SLongMonthNameFeb 65460
+#define SysConst_SLongMonthNameMar 65461
+#define SysConst_SLongMonthNameApr 65462
+#define SysConst_SLongMonthNameMay 65463
+#define SysConst_SLongMonthNameJun 65464
+#define SysConst_SLongMonthNameJul 65465
+#define SysConst_SLongMonthNameAug 65466
+#define SysConst_SLongMonthNameSep 65467
+#define SysConst_SLongMonthNameOct 65468
+#define SysConst_SLongMonthNameNov 65469
+#define SysConst_SLongMonthNameDec 65470
+#define SysConst_SShortDayNameSun 65471
+#define SysConst_SIntfCastError 65472
+#define SysConst_SSafecallException 65473
+#define SysConst_SAssertError 65474
+#define SysConst_SAbstractError 65475
+#define SysConst_SModuleAccessViolation 65476
+#define SysConst_SOSError 65477
+#define SysConst_SUnkOSError 65478
+#define SysConst_SShortMonthNameJan 65479
+#define SysConst_SShortMonthNameFeb 65480
+#define SysConst_SShortMonthNameMar 65481
+#define SysConst_SShortMonthNameApr 65482
+#define SysConst_SShortMonthNameMay 65483
+#define SysConst_SShortMonthNameJun 65484
+#define SysConst_SShortMonthNameJul 65485
+#define SysConst_SShortMonthNameAug 65486
+#define SysConst_SShortMonthNameSep 65487
+#define SysConst_SWriteAccess 65488
+#define SysConst_SVarArrayCreate 65489
+#define SysConst_SVarArrayBounds 65490
+#define SysConst_SVarArrayLocked 65491
+#define SysConst_SInvalidVarCast 65492
+#define SysConst_SInvalidVarOp 65493
+#define SysConst_SInvalidVarOpWithHResultWithPrefix 65494
+#define SysConst_SVarTypeCouldNotConvert 65495
+#define SysConst_SVarTypeConvertOverflow 65496
+#define SysConst_SVarOverflow 65497
+#define SysConst_SVarInvalid 65498
+#define SysConst_SVarBadType 65499
+#define SysConst_SVarNotImplemented 65500
+#define SysConst_SVarUnexpected 65501
+#define SysConst_SExternalException 65502
+#define SysConst_SAssertionFailed 65503
+#define SysConst_SZeroDivide 65504
+#define SysConst_SOverflow 65505
+#define SysConst_SUnderflow 65506
+#define SysConst_SInvalidPointer 65507
+#define SysConst_SInvalidCast 65508
+#define SysConst_SAccessViolationArg3 65509
+#define SysConst_SAccessViolationNoArg 65510
+#define SysConst_SStackOverflow 65511
+#define SysConst_SControlC 65512
+#define SysConst_SPrivilege 65513
+#define SysConst_SException 65514
+#define SysConst_SExceptTitle 65515
+#define SysConst_SInvalidFormat 65516
+#define SysConst_SArgumentMissing 65517
+#define SysConst_SDispatchError 65518
+#define SysConst_SReadAccess 65519
+#define SysConst_SInvalidInteger 65520
+#define SysConst_STimeEncodeError 65521
+#define SysConst_SDateEncodeError 65522
+#define SysConst_SOutOfMemory 65523
+#define SysConst_SInOutError 65524
+#define SysConst_SFileNotFound 65525
+#define SysConst_SInvalidFilename 65526
+#define SysConst_STooManyOpenFiles 65527
+#define SysConst_SAccessDenied 65528
+#define SysConst_SEndOfFile 65529
+#define SysConst_SDiskFull 65530
+#define SysConst_SInvalidInput 65531
+#define SysConst_SDivByZero 65532
+#define SysConst_SRangeError 65533
+#define SysConst_SIntOverflow 65534
+#define SysConst_SInvalidOp 65535
+STRINGTABLE
+BEGIN
+ JConsts_sChangeJPGSize, "Die Größe einer JPEG-Grafik kann nicht verändert werden"
+ JConsts_sJPEGError, "JPEG-Fehler #%d"
+ JConsts_sJPEGImageFile, "JPEG-Grafikdatei"
+ ExtCtrls_clNameInactiveBorder, "Inaktiver Rahmen"
+ ExtCtrls_clNameInactiveCaption, "Inaktiver Titel"
+ ExtCtrls_clNameInactiveCaptionText, "Inaktiver Titeltext"
+ ExtCtrls_clNameInfoBk, "Info-Hintergrund"
+ ExtCtrls_clNameInfoText, "Info-Text"
+ ExtCtrls_clNameMenu, "Menühintergrund"
+ ExtCtrls_clNameMenuText, "Menütext"
+ ExtCtrls_clNameNone, "Ohne"
+ ExtCtrls_clNameScrollBar, "Bildlaufleiste"
+ ExtCtrls_clName3DDkShadow, "3D Dunkler Schatten"
+ ExtCtrls_clName3DLight, "3D Hell"
+ ExtCtrls_clNameWindow, "Fensterhintergrund"
+ ExtCtrls_clNameWindowFrame, "Fensterrahmen"
+ ExtCtrls_clNameWindowText, "Fenstertext"
+ ComStrs_sInvalidComCtl32, "Dieses Element benötigt COMCTL32.DLL in der Version 4.70 oder höher"
+ WinHelpViewer_hNoKeyword, "Es wurden keine Schlüsselwörter für die Hilfe angegeben."
+ ExtCtrls_clNameSkyBlue, "Himmelblau"
+ ExtCtrls_clNameCream, "Creme"
+ ExtCtrls_clNameMedGray, "Mittelgrau"
+ ExtCtrls_clNameActiveBorder, "Aktiver Rahmen"
+ ExtCtrls_clNameActiveCaption, "Aktive Titelleiste"
+ ExtCtrls_clNameAppWorkSpace, "Anwendungsarbeitsbereich"
+ ExtCtrls_clNameBackground, "Hintergrund"
+ ExtCtrls_clNameBtnFace, "Schalterfläche"
+ ExtCtrls_clNameBtnHighlight, "Schalterhervorhebung"
+ ExtCtrls_clNameBtnShadow, "Schalterschatten"
+ ExtCtrls_clNameBtnText, "Schaltertext"
+ ExtCtrls_clNameCaptionText, "Titeltext"
+ ExtCtrls_clNameDefault, "Vorgabe"
+ ExtCtrls_clNameGrayText, "Grauer Text"
+ ExtCtrls_clNameHighlight, "Hervorgehobener Hintergrund"
+ ExtCtrls_clNameHighlightText, "Hervorgehobener Text"
+ ExtCtrls_clNameMaroon, "Braun"
+ ExtCtrls_clNameGreen, "Grün"
+ ExtCtrls_clNameOlive, "Olivgrün"
+ ExtCtrls_clNameNavy, "Dunkelblau"
+ ExtCtrls_clNamePurple, "Purpur"
+ ExtCtrls_clNameTeal, "Grünblau"
+ ExtCtrls_clNameGray, "Grau"
+ ExtCtrls_clNameSilver, "Silber"
+ ExtCtrls_clNameRed, "Rot"
+ ExtCtrls_clNameLime, "Limone"
+ ExtCtrls_clNameYellow, "Gelb"
+ ExtCtrls_clNameBlue, "Blau"
+ ExtCtrls_clNameFuchsia, "Fuchsie"
+ ExtCtrls_clNameAqua, "Aquamarin"
+ ExtCtrls_clNameWhite, "Weiß"
+ ExtCtrls_clNameMoneyGreen, "Dollargrün"
+ Consts_SIconToClipboard, "Zwischenablage unterstützt keine Symbole"
+ Consts_SCannotOpenClipboard, "Zwischenablage kann nicht geöffnet werden"
+ Consts_SDuplicateMenus, "Menü '%s' wird bereits von einem anderen Formular benutzt"
+ Consts_SPictureLabel, "Grafik:"
+ Consts_SPictureDesc, " (%dx%d)"
+ Consts_SPreviewLabel, "Vorschau"
+ Consts_SDockedCtlNeedsName, "Angedocktes Steuerelement muss einen Namen haben."
+ Consts_SDockTreeRemoveError, "Fehler beim Entfernen des Steuerelements aus der Andock-Hierarchie"
+ Consts_SDockZoneNotFound, " - Andockzone nicht gefunden"
+ Consts_SDockZoneHasNoCtl, " - Andockzone besitzt kein Steuerelement"
+ Consts_SSeparator, "Separator"
+ HelpIntfs_hNoTableOfContents, "Inhaltsverzeichnis konnte nicht gefunden werden"
+ HelpIntfs_hNothingFound, "Für %s sind keine Hilfeinformationen vorhanden."
+ HelpIntfs_hNoContext, "Keine kontextsensitive Hilfe installiert"
+ HelpIntfs_hNoTopics, "Es ist keine themenbasierte Hilfe installiert."
+ ExtCtrls_clNameBlack, "Schwarz"
+ Consts_SmkcPgDn, "BildAb"
+ Consts_SmkcEnd, "Ende"
+ Consts_SmkcHome, "Start"
+ Consts_SmkcLeft, "Links"
+ Consts_SmkcUp, "Nach oben"
+ Consts_SmkcRight, "Rechts"
+ Consts_SmkcDown, "Nach unten"
+ Consts_SmkcIns, "Einfg"
+ Consts_SmkcDel, "Entf"
+ Consts_SmkcShift, "Umsch+"
+ Consts_SmkcCtrl, "Strg+"
+ Consts_SmkcAlt, "Alt+"
+ Consts_srNone, "(Ohne)"
+ Consts_sAllFilter, "Alle"
+ Consts_SInsertLineError, "Zeile kann nicht eingefügt werden"
+ Consts_SInvalidClipFmt, "Ungültiges Format der Zwischenablage"
+ Consts_SMsgDlgNo, "&Nein"
+ Consts_SMsgDlgOK, "OK"
+ Consts_SMsgDlgCancel, "Abbrechen"
+ Consts_SMsgDlgHelp, "&Hilfe"
+ Consts_SMsgDlgAbort, "&Abbrechen"
+ Consts_SMsgDlgRetry, "&Wiederholen"
+ Consts_SMsgDlgIgnore, "&Ignorieren"
+ Consts_SMsgDlgAll, "&Alle"
+ Consts_SMsgDlgNoToAll, "&Alle Nein"
+ Consts_SMsgDlgYesToAll, "A&lle Ja"
+ Consts_SmkcBkSp, "Rück"
+ Consts_SmkcTab, "Tab"
+ Consts_SmkcEsc, "Esc"
+ Consts_SmkcEnter, "Enter"
+ Consts_SmkcSpace, "Leerzeichen"
+ Consts_SmkcPgUp, "BildAuf"
+ Consts_SHelpButton, "&Hilfe"
+ Consts_SCloseButton, "&Schließen"
+ Consts_SIgnoreButton, "&Ignorieren"
+ Consts_SRetryButton, "&Wiederholen"
+ Consts_SAbortButton, "Abbrechen"
+ Consts_SAllButton, "&Alle"
+ Consts_SCannotDragForm, "Formulare können nicht gezogen werden"
+ Consts_SVMetafiles, "Metadateien"
+ Consts_SVEnhMetafiles, "Erweiterte Metadateien"
+ Consts_SVIcons, "Symbole"
+ Consts_SVBitmaps, "Bitmaps"
+ Consts_SMsgDlgWarning, "Warnung"
+ Consts_SMsgDlgError, "Fehler"
+ Consts_SMsgDlgInformation, "Informationen"
+ Consts_SMsgDlgConfirm, "Bestätigung"
+ Consts_SMsgDlgYes, "&Ja"
+ Consts_SCannotFocus, "Ein deaktiviertes oder unsichtbares Fenster kann nicht den Fokus erhalten"
+ Consts_SParentRequired, "Element '%s' hat kein übergeordnetes Fenster"
+ Consts_SMDIChildNotVisible, "Untergeordnetes MDI-Formular kann nicht verborgen werden"
+ Consts_SVisibleChanged, "Eigenschaft Visible kann in OnShow oder OnHide nicht verändert werden"
+ Consts_SCannotShowModal, "Aus einem sichtbaren Fenster kann kein modales gemacht werden"
+ Consts_SMenuIndexError, "Menüindex außerhalb des zulässigen Bereichs"
+ Consts_SMenuReinserted, "Menü zweimal eingefügt"
+ Consts_SMenuNotFound, "Untermenü ist nicht im Menü"
+ Consts_SNoTimers, "Nicht genügend Timer verfügbar"
+ Consts_SGroupIndexTooLow, "GroupIndex kann nicht kleiner sein als der GroupIndex eines vorhergehenden Menüelementes"
+ Consts_SNoMDIForm, "Formular kann nicht erstellt werden. Zur Zeit sind keine MDI-Formulare aktiv"
+ Consts_SControlParentSetToSelf, "Steuerelement kann nicht sich selbst als Vorfahr haben"
+ Consts_SOKButton, "OK"
+ Consts_SCancelButton, "Abbrechen"
+ Consts_SYesButton, "&Ja"
+ Consts_SNoButton, "&Nein"
+ Consts_SInvalidPixelFormat, "Ungültiges Pixel-Format"
+ Consts_SInvalidImage, "Ungültiges Bild"
+ Consts_SScanLine, "Bereichsüberschreitung bei Zeilenindex"
+ Consts_SChangeIconSize, "Die Größe eines Symbols kann nicht geändert werden"
+ Consts_SUnknownExtension, "Unbekannte Bilddateierweiterung (.%s)"
+ Consts_SUnknownClipboardFormat, "Format der Zwischenablage wird nicht unterstützt"
+ Consts_SOutOfResources, "Systemressourcen erschöpft."
+ Consts_SNoCanvasHandle, "Leinwand/Bild erlaubt kein Zeichnen"
+ Consts_SInvalidImageSize, "Ungültige Grafikgröße"
+ Consts_SInvalidImageList, "Ungültige ImageList"
+ Consts_SReplaceImage, "Bild kann nicht ersetzt werden"
+ Consts_SImageIndexError, "Ungültiger ImageList-Index"
+ Consts_SImageReadFail, "ImageList-Daten konnten nicht aus dem Stream gelesen werden"
+ Consts_SImageWriteFail, "ImageList-Daten konnten nicht in den Stream geschrieben werden"
+ Consts_SWindowDCError, "Fehler beim Erstellen des Fenster-Gerätekontexts"
+ Consts_SWindowClass, "Fehler beim Erzeugen einer Fensterklasse"
+ RTLConsts_SListCountError, "Zu viele Einträge in der Liste (%d)"
+ RTLConsts_SListIndexError, "Listenindex überschreitet das Maximum (%d)"
+ RTLConsts_SMemoryStreamError, "Expandieren des Speicher-Stream wegen Speichermangel nicht möglich"
+ RTLConsts_SPropertyException, "Fehler beim Lesen von %s%s%s: %s"
+ RTLConsts_SReadError, "Stream-Lesefehler"
+ RTLConsts_SReadOnlyProperty, "Eigenschaft kann nur gelesen werden"
+ RTLConsts_SRegGetDataFailed, "Fehler beim Holen der Daten für '%s'"
+ RTLConsts_SResNotFound, "Ressource %s wurde nicht gefunden"
+ RTLConsts_SSeekNotImplemented, "%s.Seek nicht implementiert"
+ RTLConsts_SSortedListError, "Operation für sortierte Listen nicht zulässig"
+ RTLConsts_SUnknownGroup, "%s befindet sich nicht in einer Gruppe für Klassenregistrierungen"
+ RTLConsts_SUnknownProperty, "Eigenschaft %s existiert nicht."
+ RTLConsts_SWriteError, "Stream-Schreibfehler"
+ Consts_SInvalidBitmap, "Bitmap ist ungültig"
+ Consts_SInvalidIcon, "Ungültiges Symbol"
+ Consts_SInvalidMetafile, "Metadatei ist ungültig"
+ RTLConsts_SCantWriteResourceStreamError, "In einen zum Lesen geöffneten Ressourcen-Stream kann nicht geschrieben werden"
+ RTLConsts_SCheckSynchronizeError, "CheckSynchronize wurde vom Thread $%x aufgerufen, der NICHT der Haupt-Thread ist."
+ RTLConsts_SClassNotFound, "Klasse %s nicht gefunden"
+ RTLConsts_SDuplicateClass, "Klasse mit der Bezeichnung %s existiert bereits"
+ RTLConsts_SDuplicateItem, "Liste gestattet keine doppelten Einträge ($0%x)"
+ RTLConsts_SDuplicateName, "Komponente mit der Bezeichnung %s existiert bereits"
+ RTLConsts_SDuplicateString, "In der Stringliste sind Duplikate nicht erlaubt"
+ RTLConsts_SFCreateErrorEx, "Datei \"%s\" kann nicht erstellt werden. %s"
+ RTLConsts_SFOpenErrorEx, "Datei %s kann nicht geöffnet werden. %s"
+ RTLConsts_SInvalidImage, "Ungültiges Stream-Format"
+ RTLConsts_SInvalidName, "''%s'' ist kein gültiger Komponentenname"
+ RTLConsts_SInvalidProperty, "Ungültiger Eigenschaftswert"
+ RTLConsts_SInvalidPropertyPath, "Ungültiger Pfad für Eigenschaft"
+ RTLConsts_SInvalidPropertyValue, "Ungültiger Eigenschaftswert"
+ RTLConsts_SInvalidRegType, "Ungültiger Datentyp für '%s'"
+ RTLConsts_SListCapacityError, "Kapazität der Liste ist erschöpft (%d)"
+ SysConst_SShortDayNameMon, "Mo"
+ SysConst_SShortDayNameTue, "Di"
+ SysConst_SShortDayNameWed, "Mi"
+ SysConst_SShortDayNameThu, "Do"
+ SysConst_SShortDayNameFri, "Fr"
+ SysConst_SShortDayNameSat, "Sa"
+ SysConst_SLongDayNameSun, "Sonntag"
+ SysConst_SLongDayNameMon, "Montag"
+ SysConst_SLongDayNameTue, "Dienstag"
+ SysConst_SLongDayNameWed, "Mittwoch"
+ SysConst_SLongDayNameThu, "Donnerstag"
+ SysConst_SLongDayNameFri, "Freitag"
+ SysConst_SLongDayNameSat, "Samstag"
+ RTLConsts_SAncestorNotFound, "Vorfahr für '%s' nicht gefunden"
+ RTLConsts_SAssignError, "%s kann nicht zu %s zugewiesen werden"
+ RTLConsts_SBitsIndexError, "Bits-Index außerhalb des zulässigen Bereichs"
+ SysConst_SShortMonthNameOct, "Okt"
+ SysConst_SShortMonthNameNov, "Nov"
+ SysConst_SShortMonthNameDec, "Dez"
+ SysConst_SLongMonthNameJan, "Januar"
+ SysConst_SLongMonthNameFeb, "Februar"
+ SysConst_SLongMonthNameMar, "März"
+ SysConst_SLongMonthNameApr, "April"
+ SysConst_SLongMonthNameMay, "Mai"
+ SysConst_SLongMonthNameJun, "Juni"
+ SysConst_SLongMonthNameJul, "Juli"
+ SysConst_SLongMonthNameAug, "August"
+ SysConst_SLongMonthNameSep, "September"
+ SysConst_SLongMonthNameOct, "Oktober"
+ SysConst_SLongMonthNameNov, "November"
+ SysConst_SLongMonthNameDec, "Dezember"
+ SysConst_SShortDayNameSun, "So"
+ SysConst_SIntfCastError, "Schnittstelle nicht unterstützt"
+ SysConst_SSafecallException, "Exception in safecall-Methode"
+ SysConst_SAssertError, "%s (%s, Zeile %d)"
+ SysConst_SAbstractError, "Abstrakter Fehler"
+ SysConst_SModuleAccessViolation, "Zugriffsverletzung bei Adresse %p in Modul '%s'. %s von Adresse %p"
+ SysConst_SOSError, "Systemfehler. Code: %d.\r\n%s"
+ SysConst_SUnkOSError, "Ein Aufruf einer Betriebssystemfunktion ist fehlgeschlagen"
+ SysConst_SShortMonthNameJan, "Jan"
+ SysConst_SShortMonthNameFeb, "Feb"
+ SysConst_SShortMonthNameMar, "Mär"
+ SysConst_SShortMonthNameApr, "Apr"
+ SysConst_SShortMonthNameMay, "Mai"
+ SysConst_SShortMonthNameJun, "Jun"
+ SysConst_SShortMonthNameJul, "Jul"
+ SysConst_SShortMonthNameAug, "Aug"
+ SysConst_SShortMonthNameSep, "Sep"
+ SysConst_SWriteAccess, "Schreiben"
+ SysConst_SVarArrayCreate, "Fehler beim Erzeugen von Variante oder sicherem Array"
+ SysConst_SVarArrayBounds, "Variante oder sicherer Array-Index außerhalb des gültigen Bereichs"
+ SysConst_SVarArrayLocked, "Variante oder sicherer Array ist gesperrt"
+ SysConst_SInvalidVarCast, "Ungültige Variant-Typumwandlung"
+ SysConst_SInvalidVarOp, "Ungültige Variant-Operation"
+ SysConst_SInvalidVarOpWithHResultWithPrefix, "Ungültige Variant-Operation (%s%.8x)\n%s"
+ SysConst_SVarTypeCouldNotConvert, "Variante des Typs (%s) konnte nicht in Typ (%s) konvertiert werden"
+ SysConst_SVarTypeConvertOverflow, "Überlauf bei der Konvertierung einer Variante vom Typ (%s) in Typ (%s)"
+ SysConst_SVarOverflow, "Variant-Überlauf"
+ SysConst_SVarInvalid, "Ungültiges Argument"
+ SysConst_SVarBadType, "Ungültiger Variant-Typ"
+ SysConst_SVarNotImplemented, "Operation nicht unterstützt"
+ SysConst_SVarUnexpected, "Unerwarteter Variant-Fehler"
+ SysConst_SExternalException, "Externe Exception %x"
+ SysConst_SAssertionFailed, "Auswertung von assert fehlgeschlagen"
+ SysConst_SZeroDivide, "Gleitkommadivision durch Null"
+ SysConst_SOverflow, "Gleitkommaüberlauf"
+ SysConst_SUnderflow, "Gleitkommaunterlauf"
+ SysConst_SInvalidPointer, "Ungültige Zeigeroperation"
+ SysConst_SInvalidCast, "Ungültige Typumwandlung"
+ SysConst_SAccessViolationArg3, "Zugriffsverletzung bei Adresse %p. %s von Adresse %p"
+ SysConst_SAccessViolationNoArg, "Zugriffsverletzung"
+ SysConst_SStackOverflow, "Stack-Überlauf"
+ SysConst_SControlC, "Strg+C gedrückt"
+ SysConst_SPrivilege, "Privilegierte Anweisung"
+ SysConst_SException, "Exception %s in Modul %s bei %p.\r\n%s%s\r\n"
+ SysConst_SExceptTitle, "Anwendungsfehler"
+ SysConst_SInvalidFormat, "Format '%s' ungültig oder nicht kompatibel mit Argument"
+ SysConst_SArgumentMissing, "Kein Argument für Format '%s'"
+ SysConst_SDispatchError, "Variant-Methodenaufruf nicht unterstützt"
+ SysConst_SReadAccess, "Lesen"
+ SysConst_SInvalidInteger, "'%s' ist kein gültiger Integerwert"
+ SysConst_STimeEncodeError, "Ungültiges Argument zum Codieren der Uhrzeit"
+ SysConst_SDateEncodeError, "Ungültiges Argument zum Codieren des Datums"
+ SysConst_SOutOfMemory, "Zu wenig Arbeitsspeicher"
+ SysConst_SInOutError, "E/A-Fehler %d"
+ SysConst_SFileNotFound, "Datei nicht gefunden"
+ SysConst_SInvalidFilename, "Ungültiger Dateiname"
+ SysConst_STooManyOpenFiles, "Zu viele geöffnete Dateien"
+ SysConst_SAccessDenied, "Dateizugriff verweigert"
+ SysConst_SEndOfFile, "Versuch hinter dem Dateiende zu lesen"
+ SysConst_SDiskFull, "Zu wenig Speicherplatz"
+ SysConst_SInvalidInput, "Ungültige numerische Eingabe"
+ SysConst_SDivByZero, "Division durch Null"
+ SysConst_SRangeError, "Fehler bei Bereichsprüfung"
+ SysConst_SIntOverflow, "Integerüberlauf"
+ SysConst_SInvalidOp, "Ungültige Gleitkommaoperation"
+END
+
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/ByteMaps_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ByteMaps_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,284 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ ExtCtrls, StdCtrls, ComCtrls, Math, Clipbrd, ExtDlgs, GR32, GR32_ByteMaps,
+ GR32_RangeBars, GR32_Image, GR32_Layers, ToolWin, ImgList, Menus, JPeg;
+
+type
+ TForm1 = class(TForm)
+ Panel1: TPanel;
+ Panel3: TPanel;
+ Panel4: TPanel;
+ ImageList1: TImageList;
+ CoolBar: TCoolBar;
+ ToolBar1: TToolBar;
+ bNew: TToolButton;
+ bOpen: TToolButton;
+ bSave: TToolButton;
+ bCopy: TToolButton;
+ ToolBar2: TToolBar;
+ Label2: TLabel;
+ Panel2: TPanel;
+ ScaleBar: TGaugeBar;
+ bLinear: TToolButton;
+ ToolButton7: TToolButton;
+ Label1: TLabel;
+ PaletteCombo: TComboBox;
+ ToolBar3: TToolBar;
+ ToolButton4: TToolButton;
+ ToolButton5: TToolButton;
+ MainMenu: TMainMenu;
+ mnFile: TMenuItem;
+ mnNew: TMenuItem;
+ mnOpen: TMenuItem;
+ mnSave: TMenuItem;
+ N1: TMenuItem;
+ mnExit: TMenuItem;
+ mnEdit: TMenuItem;
+ mnCopy: TMenuItem;
+ ToolButton8: TToolButton;
+ Image: TImgView32;
+ OpenPictureDialog: TOpenPictureDialog;
+ SavePictureDialog: TSavePictureDialog;
+ procedure PaletteComboChange(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure NewClick(Sender: TObject);
+ procedure ScaleChange(Sender: TObject);
+ procedure CheckBox1Click(Sender: TObject);
+ procedure CopyClick(Sender: TObject);
+ procedure SaveClick(Sender: TObject);
+ procedure ImageMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure ImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure mnExitClick(Sender: TObject);
+ procedure OpenClick(Sender: TObject);
+ private
+ procedure WMEraseBkgnd(var Msg: TMessage); message WM_ERASEBKGND;
+ public
+ DataSet: TByteMap;
+ palGrayscale: TPalette32;
+ palGreens: TPalette32;
+ palReds: TPalette32;
+ palRainbow: TPalette32;
+ OldMousePos: TPoint;
+ MouseDragging: Boolean;
+ procedure GenPalettes;
+ procedure GenSampleData(W, H: Integer);
+ procedure PaintData;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.DFM}
+
+{ TForm1 }
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ PaletteCombo.ItemIndex := 0;
+ GenPalettes;
+ DataSet := TByteMap.Create;
+end;
+
+procedure TForm1.FormDestroy(Sender: TObject);
+begin
+ DataSet.Free;
+end;
+
+procedure TForm1.GenPalettes;
+var
+ i: Integer;
+ f: Single;
+begin
+ for i := 0 to 255 do
+ begin
+ f := i / 255;
+ palGrayscale[i] := HSLtoRGB(0, 0, f * 0.9 + 0.1);
+ palGreens[i] := HSLtoRGB(f * 0.4, 0.5, f * 0.4 + 0.2);
+ palReds[i] := HSLtoRGB(0.8 + f * 0.3 , 0.7 + f * 0.3, f * 0.85 + 0.1);
+ palRainbow[i] := HSLtoRGB(0.66 - f * 0.7, 1, 0.4 + 0.4 * f);
+ end;
+end;
+
+procedure TForm1.GenSampleData(W, H: Integer);
+var
+ i, j: Integer;
+
+ function Clamp(FloatVal: Extended): Byte;
+ begin
+ if FloatVal <= 0 then Result := 0
+ else if FloatVal >= 1 then Result := 255
+ else Result := Round(FloatVal * 255);
+ end;
+
+begin
+ DataSet.SetSize(W, H);
+ for j := 0 to H - 1 do
+ for i := 0 to W - 1 do
+ begin
+ // just some noise
+ DataSet[i, j] := Clamp(0.5 +
+ 0.5 * Sin(i + Random(10)) / 100 +
+ 0.5 * Cos(j / 11) +
+ 0.2 * Sin((i + j) / 3));
+ end;
+end;
+
+procedure TForm1.PaintData;
+var
+ P: PPalette32;
+begin
+ case PaletteCombo.ItemIndex of
+ 0: P := @palGrayScale;
+ 1: P := @palGreens;
+ 2: P := @palReds;
+ else
+ P := @palRainbow;
+ end;
+ DataSet.WriteTo(Image.Bitmap, P^);
+end;
+
+procedure TForm1.PaletteComboChange(Sender: TObject);
+begin
+ PaintData;
+end;
+
+procedure TForm1.NewClick(Sender: TObject);
+begin
+ GenSampleData(300, 220);
+ PaintData;
+ mnSave.Enabled := True;
+ mnCopy.Enabled := True;
+ bSave.Enabled := True;
+ bCopy.Enabled := True;
+end;
+
+procedure TForm1.ScaleChange(Sender: TObject);
+var
+ NewScale: Single;
+begin
+ NewScale := Power(10, ScaleBar.Position / 100);
+ ScaleBar.Repaint; // update the scale bar before the image is repainted
+ Image.Scale := NewScale;
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ if bLinear.Down then Image.Bitmap.StretchFilter := sfLinear
+ else Image.Bitmap.StretchFilter := sfNearest;
+end;
+
+procedure TForm1.CopyClick(Sender: TObject);
+begin
+ Clipboard.Assign(Image.Bitmap);
+end;
+
+procedure TForm1.SaveClick(Sender: TObject);
+begin
+ Application.ProcessMessages;
+ with SavePictureDialog do
+ if Execute then Image.Bitmap.SaveToFile(FileName);
+end;
+
+procedure TForm1.ImageMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ if Button = mbLeft then
+ begin
+ OldMousePos := Point(X, Y);
+ MouseDragging := True;
+ Image.Cursor := crSizeAll;
+ end
+ else ReleaseCapture;
+end;
+
+procedure TForm1.ImageMouseMove(Sender: TObject; Shift: TShiftState; X,
+ Y: Integer; Layer: TCustomLayer);
+begin
+ if MouseDragging then
+ begin
+ Image.Scroll(OldMousePos.X - X, OldMousePos.Y - Y);
+ OldMousePos := Point(X, Y);
+ Image.Update;
+ end;
+end;
+
+procedure TForm1.ImageMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ if Button = mbLeft then
+ begin
+ MouseDragging := False;
+ Image.Cursor := crDefault;
+ end;
+end;
+
+procedure TForm1.mnExitClick(Sender: TObject);
+begin
+ Close;
+end;
+
+procedure TForm1.OpenClick(Sender: TObject);
+var
+ B: TBitmap32;
+begin
+ Application.ProcessMessages;
+ with OpenPictureDialog do
+ if Execute then
+ begin
+ { Create a temporary bitmap }
+ B := TBitmap32.Create;
+ try
+ B.LoadFromFile(FileName);
+ { Convert it to grayscale values and store it into the byte map }
+ DataSet.ReadFrom(B, ctWeightedRGB);
+ finally
+ B.Free;
+ end;
+ PaintData;
+ mnSave.Enabled := True;
+ mnCopy.Enabled := True;
+ bSave.Enabled := True;
+ bCopy.Enabled := True;
+ end;
+end;
+
+procedure TForm1.WMEraseBkgnd(var Msg: TMessage);
+begin
+ { Accelerate repainting of the form a little bit }
+ Msg.Result := -1;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/FineResample_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/FineResample_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/FineResample_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program FineResample_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/FineResample_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/FineResample_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/MainUnit.dfm
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/MainUnit.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/MainUnit.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,62 @@
+object Form1: TForm1
+ Left = 192
+ Top = 114
+ Width = 294
+ Height = 228
+ Caption = 'FineResample Ex'
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ DesignSize = (
+ 286
+ 201)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Image32: TImage32
+ Left = 12
+ Top = 12
+ Width = 161
+ Height = 170
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BitmapAlign = baTopLeft
+ Scale = 1.000000000000000000
+ ScaleMode = smStretch
+ TabOrder = 0
+ end
+ object RadioGroup1: TRadioGroup
+ Left = 185
+ Top = 12
+ Width = 93
+ Height = 157
+ Anchors = [akTop, akRight]
+ Caption = 'StretchFilter'
+ ItemIndex = 0
+ Items.Strings = (
+ 'sfNearest'
+ 'sfDraft'
+ 'sfLinear '
+ 'sfCosine'
+ 'sfSpline'
+ 'sfLanczos'
+ 'sfMitchell')
+ TabOrder = 1
+ OnClick = RadioGroup1Click
+ end
+ object CheckBox1: TCheckBox
+ Left = 185
+ Top = 172
+ Width = 93
+ Height = 17
+ Anchors = [akTop, akRight]
+ Caption = 'FullEdge'
+ Checked = True
+ State = cbChecked
+ TabOrder = 2
+ OnClick = CheckBox1Click
+ end
+end
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/FineResample_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,102 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, ExtCtrls, GR32, GR32_Image, GR32_Transforms;
+
+type
+ TForm1 = class(TForm)
+ Image32: TImage32;
+ RadioGroup1: TRadioGroup;
+ CheckBox1: TCheckBox;
+ procedure FormCreate(Sender: TObject);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure CheckBox1Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.dfm}
+
+procedure TForm1.FormCreate(Sender: TObject);
+var
+ I, J: Integer;
+begin
+ Image32.Bitmap.SetSize(16, 16);
+ for I := 0 to 15 do
+ for J := 0 to 15 do
+ if (I + J) mod 2 = 0 then Image32.Bitmap.Pixel[I, J] := clBlack32
+ else Image32.Bitmap.Pixel[I, J] := clWhite32;
+ for I := 0 to 15 do
+ begin
+ Image32.Bitmap.Pixel[I, 9] := Gray32(I * 255 div 15);
+ Image32.Bitmap.Pixel[I, 10] := Gray32(I * 255 div 15);
+ end;
+
+ for I := 0 to 7 do
+ begin
+ Image32.Bitmap.Pixel[I * 2, 11] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2 + 1, 11] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2, 12] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2 + 1, 12] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2, 13] := Gray32(I * 255 div 7);
+ Image32.Bitmap.Pixel[I * 2 + 1, 13] := Gray32(I * 255 div 7);
+ end;
+
+ with Image32.Bitmap do
+ begin
+ for I := 1 to 4 do
+ for J := 1 to 4 do
+ Pixels[I, J] := $FF5F5F5F;
+ for I := 2 to 3 do
+ for J := 2 to 3 do
+ Pixels[I, J] := $FFAFAFAF;
+ end;
+end;
+
+procedure TForm1.RadioGroup1Click(Sender: TObject);
+begin
+ Image32.Bitmap.StretchFilter := TStretchFilter(RadioGroup1.ItemIndex);
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ GR32_Transforms.FullEdge := CheckBox1.Checked;
+ Image32.Bitmap.Changed;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,46 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="GradLines_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj GradLines_Ex.obj"/>
+ <RESFILES value="GradLines_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="Vcl50.lib GR32_CB5.lib"/>
+ <PACKAGES value="Vcl50.bpi GR32_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="GradLines_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+ <IDEOPTIONS>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("GradLines_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, Form1);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TForm1), &Form1);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program GradLines_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/GradLines_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/GradLines_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,318 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+// TPaintBox32 and DrawLineFSP example
+// Author: Alex Denissov
+// http://g32.org
+
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, GR32, GR32_Blend, ExtCtrls, GR32_Image;
+
+type
+ TVector2f = record
+ X, Y: Single;
+ end;
+
+ TLine = class
+ public
+ Bitmap: TBitmap32;
+ P1, P2: TVector2f; // positions
+ V1, V2: TVector2f; // velocities
+ C1, C2, C3: TColor32; // colors that define gradient pattern
+ t1, t2, t3: Single;
+ MaxVelocity: Single;
+ constructor Create(ABitmap: TBitmap32);
+ procedure Advance(DeltaT: Single);
+ function GetLength: Single;
+ procedure Paint;
+ end;
+
+ TForm1 = class(TForm)
+ PaintBox: TPaintBox32;
+ Button1: TButton;
+ Button2: TButton;
+ Button3: TButton;
+ RadioGroup1: TRadioGroup;
+ RadioGroup2: TRadioGroup;
+ Label1: TLabel;
+ Panel1: TPanel;
+ procedure Button1Click(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure Button3Click(Sender: TObject);
+ procedure BitmapLayerMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure BitmapLayerMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure RadioGroup2Click(Sender: TObject);
+ protected
+ Lines: array of TLine;
+ P: TPoint; // mouse shift
+ M: Boolean; // mouse down flag
+ FadeCount: Integer;
+ Pass: Integer;
+ DrawPasses: Integer;
+ procedure AppEventsIdle(Sender: TObject; var Done: Boolean);
+ public
+ procedure AddLine;
+ procedure AddLines(N: Integer);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+uses Math;
+
+function vAdd(const A, B: TVector2f): TVector2f;
+begin
+ Result.X := A.X + B.X;
+ Result.Y := A.Y + B.Y;
+end;
+
+function vSub(const A, B: TVector2f): TVector2f;
+begin
+ Result.X := A.X - B.X;
+ Result.Y := A.Y - B.Y;
+end;
+
+function vLen(const A: TVector2f): Single;
+begin
+ Result := SqRt(SqR(A.X) + SqR(A.Y));
+end;
+
+function vDot(const A, B: TVector2f): Single;
+begin
+ Result := A.X * B.X + A.Y * B.Y;
+end;
+
+function vScale(const A: TVector2f; Factor: Single): TVector2f;
+begin
+ Result.X := A.X * Factor;
+ Result.Y := A.Y * Factor;
+end;
+
+{$R *.DFM}
+
+
+{ TLine }
+
+procedure TLine.Advance(DeltaT: Single);
+
+{}procedure AdvancePoint(var P, V: TVector2f; t: Single);
+ begin
+ { apply velocities }
+ P.X := P.X + V.X * t;
+ P.Y := P.Y + V.Y * t;
+
+ { reflect from walls }
+ if P.X < 0 then
+ begin
+ P.X := 0;
+ V.X := -V.X;
+ end;
+ if P.X >= Form1.PaintBox.Width then
+ begin
+ P.X := Form1.PaintBox.Width - 1;
+ V.X := - V.X;
+ end;
+ if P.Y < 0 then
+ begin
+ P.Y := 0;
+ V.Y := -V.Y;
+ end;
+ if P.Y >= Form1.PaintBox.Height then
+ begin
+ P.Y := Form1.PaintBox.Height - 1;
+ V.Y := - V.Y
+ end;
+
+ { change velocity a little bit }
+ V.X := V.X + t * (Random - 0.5) / 4;
+ V.Y := V.Y + t * (Random - 0.5) / 4;
+
+ { limit velocity }
+ if vLen(V1) > MaxVelocity then V1 := vScale(V1, 1 / vLen(V1));
+ if vLen(V2) > MaxVelocity then V2 := vScale(V2, 1 / vLen(V2));
+ end;
+begin
+ AdvancePoint(P1, V1, DeltaT);
+ AdvancePoint(P2, V2, DeltaT);
+
+ C1 := HSLtoRGB(t1, Sin(t1 / 1.8) * 0.4 + 0.6, 0.5);
+ C1 := SetAlpha(C1, Round(Sin(t1) * 25 + 50));
+ t1 := t1 + Random / 300;
+
+ C2 := HSLtoRGB(t2, Sin(t2 / 1.8) * 0.4 + 0.6, 0.5);
+ C2 := SetAlpha(C2, Round(Sin(t2) * 25 + 50));
+ t2 := t2 + Random / 400;
+
+ C3 := HSLtoRGB(t3, Sin(t3 / 1.8) * 0.4 + 0.6, 0.5);
+ C3 := SetAlpha(C3, Round(Sin(t3) * 25 + 50));
+ t3 := t3 + Random / 400;
+end;
+
+constructor TLine.Create(ABitmap: TBitmap32);
+begin
+ Bitmap := ABitmap;
+ MaxVelocity := 1;
+end;
+
+function TLine.GetLength: Single;
+begin
+ Result := vLen(vSub(P1, P2));
+end;
+
+procedure TLine.Paint;
+var
+ L: Single;
+begin
+ // this shows how to draw a gradient line
+ L := GetLength;
+ if L < 1 then Exit;
+ Bitmap.SetStipple([C1, C2, C3]);
+ Bitmap.StippleStep := 2 / L; {2 = 3 - 1 = Number of colors in a pattern - 1}
+ Bitmap.StippleCounter := 0;
+ Bitmap.LineFSP(P1.X, P1.Y, P2.X, P2.Y);
+end;
+
+{ TForm1 }
+
+procedure TForm1.AddLine;
+var
+ L: TLine;
+begin
+ SetLength(Lines, Length(Lines) + 1);
+ L := TLine.Create(PaintBox.Buffer);
+ Lines[High(Lines)] := L;
+ L.t1 := Random * 3;
+ L.t2 := Random * 3;
+ L.t3 := Random * 3;
+ L.P1.X := Random(PaintBox.Buffer.Width - 1);
+ L.P2.X := Random(PaintBox.Buffer.Width - 1);
+ L.P1.Y := Random(PaintBox.Buffer.Height - 1);
+ L.P2.Y := Random(PaintBox.Buffer.Height - 1);
+ Panel1.Caption := IntToStr(Length(Lines));
+end;
+
+procedure TForm1.AddLines(N: Integer);
+var
+ i: Integer;
+begin
+ for i := 0 to N - 1 do AddLine;
+end;
+
+procedure TForm1.AppEventsIdle(Sender: TObject; var Done: Boolean);
+var
+ I, J: Integer;
+ P: PColor32;
+begin
+ for J := 0 to DrawPasses - 1 do
+ for I := 0 to High(Lines) do
+ begin
+ Lines[I].Advance(1);
+ Lines[I].Paint;
+ end;
+
+ if FadeCount > 0 then
+ begin
+ if Pass = 0 then with PaintBox.Buffer do
+ begin
+ P := @Bits[0];
+ for I := 0 to Width * Height -1 do
+ begin
+ BlendMem($10000000, P^);
+ Inc(P);
+ end;
+ EMMS;
+ end;
+ Dec(Pass);
+ if (Pass < 0) or (Pass > FadeCount) then Pass := FadeCount;
+ end;
+ PaintBox.Invalidate;
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ FadeCount := 7;
+ DrawPasses := 2;
+ Application.OnIdle := AppEventsIdle;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+begin
+ AddLine;
+end;
+
+procedure TForm1.Button2Click(Sender: TObject);
+begin
+ AddLines(10);
+end;
+
+procedure TForm1.Button3Click(Sender: TObject);
+var
+ I: Integer;
+begin
+ for I := High(Lines) downto 0 do Lines[I].Free;
+ Lines := nil;
+ PaintBox.Buffer.Clear;
+ Panel1.Caption := '0';
+end;
+
+procedure TForm1.BitmapLayerMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ // X and Y here are relative to layer origin
+ P := Point(X, Y);
+ M := True;
+end;
+
+procedure TForm1.BitmapLayerMouseUp(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ M := False;
+end;
+
+procedure TForm1.RadioGroup1Click(Sender: TObject);
+const
+ FC: array [0..2] of Integer = (0, 7, 1);
+begin
+ FadeCount := FC[RadioGroup1.ItemIndex];
+end;
+
+procedure TForm1.RadioGroup2Click(Sender: TObject);
+begin
+ DrawPasses := (RadioGroup2.ItemIndex + 1) * 3 - 2;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="Image32_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj Image32_Ex.obj"/>
+ <RESFILES value="Image32_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="Vcl50.lib GR32_CB5.lib"/>
+ <PACKAGES value="Vcl50.bpi GR32_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="Image32_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("Image32_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, Form1);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TForm1), &Form1);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Image32_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.drc
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.drc 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.drc 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,519 @@
+/* VER150
+ Generiert vom Borland Delphi Pascal Compiler
+ da -GD or --drc beim Compilieren angegeben war.
+
+ Sie enthält Compiler-generierte Ressourcen, die mit der ausführbaren Datei verbunden sind.
+ Wenn sie leer ist, wurden keine vom Compiler generierten Ressourcen mit der
+ produzierten ausführbaren Datei verbunden.
+*/
+
+#define ExtCtrls_clNameInactiveCaptionText 65280
+#define ExtCtrls_clNameInfoBk 65281
+#define ExtCtrls_clNameInfoText 65282
+#define ExtCtrls_clNameMenu 65283
+#define ExtCtrls_clNameMenuText 65284
+#define ExtCtrls_clNameNone 65285
+#define ExtCtrls_clNameScrollBar 65286
+#define ExtCtrls_clName3DDkShadow 65287
+#define ExtCtrls_clName3DLight 65288
+#define ExtCtrls_clNameWindow 65289
+#define ExtCtrls_clNameWindowFrame 65290
+#define ExtCtrls_clNameWindowText 65291
+#define WinHelpViewer_hNoKeyword 65292
+#define ExtCtrls_clNameMedGray 65296
+#define ExtCtrls_clNameActiveBorder 65297
+#define ExtCtrls_clNameActiveCaption 65298
+#define ExtCtrls_clNameAppWorkSpace 65299
+#define ExtCtrls_clNameBackground 65300
+#define ExtCtrls_clNameBtnFace 65301
+#define ExtCtrls_clNameBtnHighlight 65302
+#define ExtCtrls_clNameBtnShadow 65303
+#define ExtCtrls_clNameBtnText 65304
+#define ExtCtrls_clNameCaptionText 65305
+#define ExtCtrls_clNameDefault 65306
+#define ExtCtrls_clNameGrayText 65307
+#define ExtCtrls_clNameHighlight 65308
+#define ExtCtrls_clNameHighlightText 65309
+#define ExtCtrls_clNameInactiveBorder 65310
+#define ExtCtrls_clNameInactiveCaption 65311
+#define ExtCtrls_clNameOlive 65312
+#define ExtCtrls_clNameNavy 65313
+#define ExtCtrls_clNamePurple 65314
+#define ExtCtrls_clNameTeal 65315
+#define ExtCtrls_clNameGray 65316
+#define ExtCtrls_clNameSilver 65317
+#define ExtCtrls_clNameRed 65318
+#define ExtCtrls_clNameLime 65319
+#define ExtCtrls_clNameYellow 65320
+#define ExtCtrls_clNameBlue 65321
+#define ExtCtrls_clNameFuchsia 65322
+#define ExtCtrls_clNameAqua 65323
+#define ExtCtrls_clNameWhite 65324
+#define ExtCtrls_clNameMoneyGreen 65325
+#define ExtCtrls_clNameSkyBlue 65326
+#define ExtCtrls_clNameCream 65327
+#define Consts_SmkcShift 65328
+#define Consts_SmkcCtrl 65329
+#define Consts_SmkcAlt 65330
+#define Consts_SIconToClipboard 65331
+#define Consts_SDuplicateMenus 65332
+#define Consts_SDockedCtlNeedsName 65333
+#define Consts_SDockTreeRemoveError 65334
+#define Consts_SDockZoneNotFound 65335
+#define Consts_SDockZoneHasNoCtl 65336
+#define HelpIntfs_hNoTableOfContents 65337
+#define HelpIntfs_hNothingFound 65338
+#define HelpIntfs_hNoContext 65339
+#define HelpIntfs_hNoTopics 65340
+#define ExtCtrls_clNameBlack 65341
+#define ExtCtrls_clNameMaroon 65342
+#define ExtCtrls_clNameGreen 65343
+#define Consts_SMsgDlgYesToAll 65344
+#define Consts_SmkcBkSp 65345
+#define Consts_SmkcTab 65346
+#define Consts_SmkcEsc 65347
+#define Consts_SmkcEnter 65348
+#define Consts_SmkcSpace 65349
+#define Consts_SmkcPgUp 65350
+#define Consts_SmkcPgDn 65351
+#define Consts_SmkcEnd 65352
+#define Consts_SmkcHome 65353
+#define Consts_SmkcLeft 65354
+#define Consts_SmkcUp 65355
+#define Consts_SmkcRight 65356
+#define Consts_SmkcDown 65357
+#define Consts_SmkcIns 65358
+#define Consts_SmkcDel 65359
+#define Consts_SVIcons 65360
+#define Consts_SVBitmaps 65361
+#define Consts_SMsgDlgWarning 65362
+#define Consts_SMsgDlgError 65363
+#define Consts_SMsgDlgInformation 65364
+#define Consts_SMsgDlgConfirm 65365
+#define Consts_SMsgDlgYes 65366
+#define Consts_SMsgDlgNo 65367
+#define Consts_SMsgDlgOK 65368
+#define Consts_SMsgDlgCancel 65369
+#define Consts_SMsgDlgHelp 65370
+#define Consts_SMsgDlgAbort 65371
+#define Consts_SMsgDlgRetry 65372
+#define Consts_SMsgDlgIgnore 65373
+#define Consts_SMsgDlgAll 65374
+#define Consts_SMsgDlgNoToAll 65375
+#define Consts_SGroupIndexTooLow 65376
+#define Consts_SNoMDIForm 65377
+#define Consts_SControlParentSetToSelf 65378
+#define Consts_SOKButton 65379
+#define Consts_SCancelButton 65380
+#define Consts_SYesButton 65381
+#define Consts_SNoButton 65382
+#define Consts_SHelpButton 65383
+#define Consts_SCloseButton 65384
+#define Consts_SIgnoreButton 65385
+#define Consts_SRetryButton 65386
+#define Consts_SAbortButton 65387
+#define Consts_SAllButton 65388
+#define Consts_SCannotDragForm 65389
+#define Consts_SVMetafiles 65390
+#define Consts_SVEnhMetafiles 65391
+#define Consts_SInvalidImageSize 65392
+#define Consts_SInvalidImageList 65393
+#define Consts_SImageIndexError 65394
+#define Consts_SImageReadFail 65395
+#define Consts_SImageWriteFail 65396
+#define Consts_SWindowDCError 65397
+#define Consts_SWindowClass 65398
+#define Consts_SCannotFocus 65399
+#define Consts_SParentRequired 65400
+#define Consts_SMDIChildNotVisible 65401
+#define Consts_SVisibleChanged 65402
+#define Consts_SCannotShowModal 65403
+#define Consts_SMenuIndexError 65404
+#define Consts_SMenuReinserted 65405
+#define Consts_SMenuNotFound 65406
+#define Consts_SNoTimers 65407
+#define RTLConsts_SReadError 65408
+#define RTLConsts_SReadOnlyProperty 65409
+#define RTLConsts_SResNotFound 65410
+#define RTLConsts_SSeekNotImplemented 65411
+#define RTLConsts_SSortedListError 65412
+#define RTLConsts_SUnknownGroup 65413
+#define RTLConsts_SUnknownProperty 65414
+#define RTLConsts_SWriteError 65415
+#define Consts_SInvalidBitmap 65416
+#define Consts_SInvalidIcon 65417
+#define Consts_SInvalidMetafile 65418
+#define Consts_SInvalidPixelFormat 65419
+#define Consts_SChangeIconSize 65420
+#define Consts_SUnknownClipboardFormat 65421
+#define Consts_SOutOfResources 65422
+#define Consts_SNoCanvasHandle 65423
+#define RTLConsts_SClassNotFound 65424
+#define RTLConsts_SDuplicateClass 65425
+#define RTLConsts_SDuplicateItem 65426
+#define RTLConsts_SDuplicateName 65427
+#define RTLConsts_SDuplicateString 65428
+#define RTLConsts_SFCreateErrorEx 65429
+#define RTLConsts_SFOpenErrorEx 65430
+#define RTLConsts_SInvalidImage 65431
+#define RTLConsts_SInvalidName 65432
+#define RTLConsts_SInvalidPropertyPath 65433
+#define RTLConsts_SInvalidPropertyValue 65434
+#define RTLConsts_SListCapacityError 65435
+#define RTLConsts_SListCountError 65436
+#define RTLConsts_SListIndexError 65437
+#define RTLConsts_SMemoryStreamError 65438
+#define RTLConsts_SPropertyException 65439
+#define SysConst_SShortDayNameWed 65440
+#define SysConst_SShortDayNameThu 65441
+#define SysConst_SShortDayNameFri 65442
+#define SysConst_SShortDayNameSat 65443
+#define SysConst_SLongDayNameSun 65444
+#define SysConst_SLongDayNameMon 65445
+#define SysConst_SLongDayNameTue 65446
+#define SysConst_SLongDayNameWed 65447
+#define SysConst_SLongDayNameThu 65448
+#define SysConst_SLongDayNameFri 65449
+#define SysConst_SLongDayNameSat 65450
+#define RTLConsts_SAncestorNotFound 65451
+#define RTLConsts_SAssignError 65452
+#define RTLConsts_SBitsIndexError 65453
+#define RTLConsts_SCantWriteResourceStreamError 65454
+#define RTLConsts_SCheckSynchronizeError 65455
+#define SysConst_SShortMonthNameDec 65456
+#define SysConst_SLongMonthNameJan 65457
+#define SysConst_SLongMonthNameFeb 65458
+#define SysConst_SLongMonthNameMar 65459
+#define SysConst_SLongMonthNameApr 65460
+#define SysConst_SLongMonthNameMay 65461
+#define SysConst_SLongMonthNameJun 65462
+#define SysConst_SLongMonthNameJul 65463
+#define SysConst_SLongMonthNameAug 65464
+#define SysConst_SLongMonthNameSep 65465
+#define SysConst_SLongMonthNameOct 65466
+#define SysConst_SLongMonthNameNov 65467
+#define SysConst_SLongMonthNameDec 65468
+#define SysConst_SShortDayNameSun 65469
+#define SysConst_SShortDayNameMon 65470
+#define SysConst_SShortDayNameTue 65471
+#define SysConst_SAssertError 65472
+#define SysConst_SAbstractError 65473
+#define SysConst_SModuleAccessViolation 65474
+#define SysConst_SOSError 65475
+#define SysConst_SUnkOSError 65476
+#define SysConst_SShortMonthNameJan 65477
+#define SysConst_SShortMonthNameFeb 65478
+#define SysConst_SShortMonthNameMar 65479
+#define SysConst_SShortMonthNameApr 65480
+#define SysConst_SShortMonthNameMay 65481
+#define SysConst_SShortMonthNameJun 65482
+#define SysConst_SShortMonthNameJul 65483
+#define SysConst_SShortMonthNameAug 65484
+#define SysConst_SShortMonthNameSep 65485
+#define SysConst_SShortMonthNameOct 65486
+#define SysConst_SShortMonthNameNov 65487
+#define SysConst_SVarArrayBounds 65488
+#define SysConst_SVarArrayLocked 65489
+#define SysConst_SInvalidVarCast 65490
+#define SysConst_SInvalidVarOp 65491
+#define SysConst_SInvalidVarOpWithHResultWithPrefix 65492
+#define SysConst_SVarTypeCouldNotConvert 65493
+#define SysConst_SVarTypeConvertOverflow 65494
+#define SysConst_SVarOverflow 65495
+#define SysConst_SVarInvalid 65496
+#define SysConst_SVarBadType 65497
+#define SysConst_SVarNotImplemented 65498
+#define SysConst_SVarUnexpected 65499
+#define SysConst_SExternalException 65500
+#define SysConst_SAssertionFailed 65501
+#define SysConst_SIntfCastError 65502
+#define SysConst_SSafecallException 65503
+#define SysConst_SUnderflow 65504
+#define SysConst_SInvalidPointer 65505
+#define SysConst_SInvalidCast 65506
+#define SysConst_SAccessViolationArg3 65507
+#define SysConst_SAccessViolationNoArg 65508
+#define SysConst_SStackOverflow 65509
+#define SysConst_SControlC 65510
+#define SysConst_SPrivilege 65511
+#define SysConst_SException 65512
+#define SysConst_SExceptTitle 65513
+#define SysConst_SInvalidFormat 65514
+#define SysConst_SArgumentMissing 65515
+#define SysConst_SDispatchError 65516
+#define SysConst_SReadAccess 65517
+#define SysConst_SWriteAccess 65518
+#define SysConst_SVarArrayCreate 65519
+#define SysConst_SInvalidInteger 65520
+#define SysConst_SOutOfMemory 65521
+#define SysConst_SInOutError 65522
+#define SysConst_SFileNotFound 65523
+#define SysConst_SInvalidFilename 65524
+#define SysConst_STooManyOpenFiles 65525
+#define SysConst_SAccessDenied 65526
+#define SysConst_SEndOfFile 65527
+#define SysConst_SDiskFull 65528
+#define SysConst_SInvalidInput 65529
+#define SysConst_SDivByZero 65530
+#define SysConst_SRangeError 65531
+#define SysConst_SIntOverflow 65532
+#define SysConst_SInvalidOp 65533
+#define SysConst_SZeroDivide 65534
+#define SysConst_SOverflow 65535
+STRINGTABLE
+BEGIN
+ ExtCtrls_clNameInactiveCaptionText, "Inaktiver Titeltext"
+ ExtCtrls_clNameInfoBk, "Info-Hintergrund"
+ ExtCtrls_clNameInfoText, "Info-Text"
+ ExtCtrls_clNameMenu, "Menühintergrund"
+ ExtCtrls_clNameMenuText, "Menütext"
+ ExtCtrls_clNameNone, "Ohne"
+ ExtCtrls_clNameScrollBar, "Bildlaufleiste"
+ ExtCtrls_clName3DDkShadow, "3D Dunkler Schatten"
+ ExtCtrls_clName3DLight, "3D Hell"
+ ExtCtrls_clNameWindow, "Fensterhintergrund"
+ ExtCtrls_clNameWindowFrame, "Fensterrahmen"
+ ExtCtrls_clNameWindowText, "Fenstertext"
+ WinHelpViewer_hNoKeyword, "Es wurden keine Schlüsselwörter für die Hilfe angegeben."
+ ExtCtrls_clNameMedGray, "Mittelgrau"
+ ExtCtrls_clNameActiveBorder, "Aktiver Rahmen"
+ ExtCtrls_clNameActiveCaption, "Aktive Titelleiste"
+ ExtCtrls_clNameAppWorkSpace, "Anwendungsarbeitsbereich"
+ ExtCtrls_clNameBackground, "Hintergrund"
+ ExtCtrls_clNameBtnFace, "Schalterfläche"
+ ExtCtrls_clNameBtnHighlight, "Schalterhervorhebung"
+ ExtCtrls_clNameBtnShadow, "Schalterschatten"
+ ExtCtrls_clNameBtnText, "Schaltertext"
+ ExtCtrls_clNameCaptionText, "Titeltext"
+ ExtCtrls_clNameDefault, "Vorgabe"
+ ExtCtrls_clNameGrayText, "Grauer Text"
+ ExtCtrls_clNameHighlight, "Hervorgehobener Hintergrund"
+ ExtCtrls_clNameHighlightText, "Hervorgehobener Text"
+ ExtCtrls_clNameInactiveBorder, "Inaktiver Rahmen"
+ ExtCtrls_clNameInactiveCaption, "Inaktiver Titel"
+ ExtCtrls_clNameOlive, "Olivgrün"
+ ExtCtrls_clNameNavy, "Dunkelblau"
+ ExtCtrls_clNamePurple, "Purpur"
+ ExtCtrls_clNameTeal, "Grünblau"
+ ExtCtrls_clNameGray, "Grau"
+ ExtCtrls_clNameSilver, "Silber"
+ ExtCtrls_clNameRed, "Rot"
+ ExtCtrls_clNameLime, "Limone"
+ ExtCtrls_clNameYellow, "Gelb"
+ ExtCtrls_clNameBlue, "Blau"
+ ExtCtrls_clNameFuchsia, "Fuchsie"
+ ExtCtrls_clNameAqua, "Aquamarin"
+ ExtCtrls_clNameWhite, "Weiß"
+ ExtCtrls_clNameMoneyGreen, "Dollargrün"
+ ExtCtrls_clNameSkyBlue, "Himmelblau"
+ ExtCtrls_clNameCream, "Creme"
+ Consts_SmkcShift, "Umsch+"
+ Consts_SmkcCtrl, "Strg+"
+ Consts_SmkcAlt, "Alt+"
+ Consts_SIconToClipboard, "Zwischenablage unterstützt keine Symbole"
+ Consts_SDuplicateMenus, "Menü '%s' wird bereits von einem anderen Formular benutzt"
+ Consts_SDockedCtlNeedsName, "Angedocktes Steuerelement muss einen Namen haben."
+ Consts_SDockTreeRemoveError, "Fehler beim Entfernen des Steuerelements aus der Andock-Hierarchie"
+ Consts_SDockZoneNotFound, " - Andockzone nicht gefunden"
+ Consts_SDockZoneHasNoCtl, " - Andockzone besitzt kein Steuerelement"
+ HelpIntfs_hNoTableOfContents, "Inhaltsverzeichnis konnte nicht gefunden werden"
+ HelpIntfs_hNothingFound, "Für %s sind keine Hilfeinformationen vorhanden."
+ HelpIntfs_hNoContext, "Keine kontextsensitive Hilfe installiert"
+ HelpIntfs_hNoTopics, "Es ist keine themenbasierte Hilfe installiert."
+ ExtCtrls_clNameBlack, "Schwarz"
+ ExtCtrls_clNameMaroon, "Braun"
+ ExtCtrls_clNameGreen, "Grün"
+ Consts_SMsgDlgYesToAll, "A&lle Ja"
+ Consts_SmkcBkSp, "Rück"
+ Consts_SmkcTab, "Tab"
+ Consts_SmkcEsc, "Esc"
+ Consts_SmkcEnter, "Enter"
+ Consts_SmkcSpace, "Leerzeichen"
+ Consts_SmkcPgUp, "BildAuf"
+ Consts_SmkcPgDn, "BildAb"
+ Consts_SmkcEnd, "Ende"
+ Consts_SmkcHome, "Start"
+ Consts_SmkcLeft, "Links"
+ Consts_SmkcUp, "Nach oben"
+ Consts_SmkcRight, "Rechts"
+ Consts_SmkcDown, "Nach unten"
+ Consts_SmkcIns, "Einfg"
+ Consts_SmkcDel, "Entf"
+ Consts_SVIcons, "Symbole"
+ Consts_SVBitmaps, "Bitmaps"
+ Consts_SMsgDlgWarning, "Warnung"
+ Consts_SMsgDlgError, "Fehler"
+ Consts_SMsgDlgInformation, "Informationen"
+ Consts_SMsgDlgConfirm, "Bestätigung"
+ Consts_SMsgDlgYes, "&Ja"
+ Consts_SMsgDlgNo, "&Nein"
+ Consts_SMsgDlgOK, "OK"
+ Consts_SMsgDlgCancel, "Abbrechen"
+ Consts_SMsgDlgHelp, "&Hilfe"
+ Consts_SMsgDlgAbort, "&Abbrechen"
+ Consts_SMsgDlgRetry, "&Wiederholen"
+ Consts_SMsgDlgIgnore, "&Ignorieren"
+ Consts_SMsgDlgAll, "&Alle"
+ Consts_SMsgDlgNoToAll, "&Alle Nein"
+ Consts_SGroupIndexTooLow, "GroupIndex kann nicht kleiner sein als der GroupIndex eines vorhergehenden Menüelementes"
+ Consts_SNoMDIForm, "Formular kann nicht erstellt werden. Zur Zeit sind keine MDI-Formulare aktiv"
+ Consts_SControlParentSetToSelf, "Steuerelement kann nicht sich selbst als Vorfahr haben"
+ Consts_SOKButton, "OK"
+ Consts_SCancelButton, "Abbrechen"
+ Consts_SYesButton, "&Ja"
+ Consts_SNoButton, "&Nein"
+ Consts_SHelpButton, "&Hilfe"
+ Consts_SCloseButton, "&Schließen"
+ Consts_SIgnoreButton, "&Ignorieren"
+ Consts_SRetryButton, "&Wiederholen"
+ Consts_SAbortButton, "Abbrechen"
+ Consts_SAllButton, "&Alle"
+ Consts_SCannotDragForm, "Formulare können nicht gezogen werden"
+ Consts_SVMetafiles, "Metadateien"
+ Consts_SVEnhMetafiles, "Erweiterte Metadateien"
+ Consts_SInvalidImageSize, "Ungültige Grafikgröße"
+ Consts_SInvalidImageList, "Ungültige ImageList"
+ Consts_SImageIndexError, "Ungültiger ImageList-Index"
+ Consts_SImageReadFail, "ImageList-Daten konnten nicht aus dem Stream gelesen werden"
+ Consts_SImageWriteFail, "ImageList-Daten konnten nicht in den Stream geschrieben werden"
+ Consts_SWindowDCError, "Fehler beim Erstellen des Fenster-Gerätekontexts"
+ Consts_SWindowClass, "Fehler beim Erzeugen einer Fensterklasse"
+ Consts_SCannotFocus, "Ein deaktiviertes oder unsichtbares Fenster kann nicht den Fokus erhalten"
+ Consts_SParentRequired, "Element '%s' hat kein übergeordnetes Fenster"
+ Consts_SMDIChildNotVisible, "Untergeordnetes MDI-Formular kann nicht verborgen werden"
+ Consts_SVisibleChanged, "Eigenschaft Visible kann in OnShow oder OnHide nicht verändert werden"
+ Consts_SCannotShowModal, "Aus einem sichtbaren Fenster kann kein modales gemacht werden"
+ Consts_SMenuIndexError, "Menüindex außerhalb des zulässigen Bereichs"
+ Consts_SMenuReinserted, "Menü zweimal eingefügt"
+ Consts_SMenuNotFound, "Untermenü ist nicht im Menü"
+ Consts_SNoTimers, "Nicht genügend Timer verfügbar"
+ RTLConsts_SReadError, "Stream-Lesefehler"
+ RTLConsts_SReadOnlyProperty, "Eigenschaft kann nur gelesen werden"
+ RTLConsts_SResNotFound, "Ressource %s wurde nicht gefunden"
+ RTLConsts_SSeekNotImplemented, "%s.Seek nicht implementiert"
+ RTLConsts_SSortedListError, "Operation für sortierte Listen nicht zulässig"
+ RTLConsts_SUnknownGroup, "%s befindet sich nicht in einer Gruppe für Klassenregistrierungen"
+ RTLConsts_SUnknownProperty, "Eigenschaft %s existiert nicht."
+ RTLConsts_SWriteError, "Stream-Schreibfehler"
+ Consts_SInvalidBitmap, "Bitmap ist ungültig"
+ Consts_SInvalidIcon, "Ungültiges Symbol"
+ Consts_SInvalidMetafile, "Metadatei ist ungültig"
+ Consts_SInvalidPixelFormat, "Ungültiges Pixel-Format"
+ Consts_SChangeIconSize, "Die Größe eines Symbols kann nicht geändert werden"
+ Consts_SUnknownClipboardFormat, "Format der Zwischenablage wird nicht unterstützt"
+ Consts_SOutOfResources, "Systemressourcen erschöpft."
+ Consts_SNoCanvasHandle, "Leinwand/Bild erlaubt kein Zeichnen"
+ RTLConsts_SClassNotFound, "Klasse %s nicht gefunden"
+ RTLConsts_SDuplicateClass, "Klasse mit der Bezeichnung %s existiert bereits"
+ RTLConsts_SDuplicateItem, "Liste gestattet keine doppelten Einträge ($0%x)"
+ RTLConsts_SDuplicateName, "Komponente mit der Bezeichnung %s existiert bereits"
+ RTLConsts_SDuplicateString, "In der Stringliste sind Duplikate nicht erlaubt"
+ RTLConsts_SFCreateErrorEx, "Datei \"%s\" kann nicht erstellt werden. %s"
+ RTLConsts_SFOpenErrorEx, "Datei %s kann nicht geöffnet werden. %s"
+ RTLConsts_SInvalidImage, "Ungültiges Stream-Format"
+ RTLConsts_SInvalidName, "''%s'' ist kein gültiger Komponentenname"
+ RTLConsts_SInvalidPropertyPath, "Ungültiger Pfad für Eigenschaft"
+ RTLConsts_SInvalidPropertyValue, "Ungültiger Eigenschaftswert"
+ RTLConsts_SListCapacityError, "Kapazität der Liste ist erschöpft (%d)"
+ RTLConsts_SListCountError, "Zu viele Einträge in der Liste (%d)"
+ RTLConsts_SListIndexError, "Listenindex überschreitet das Maximum (%d)"
+ RTLConsts_SMemoryStreamError, "Expandieren des Speicher-Stream wegen Speichermangel nicht möglich"
+ RTLConsts_SPropertyException, "Fehler beim Lesen von %s%s%s: %s"
+ SysConst_SShortDayNameWed, "Mi"
+ SysConst_SShortDayNameThu, "Do"
+ SysConst_SShortDayNameFri, "Fr"
+ SysConst_SShortDayNameSat, "Sa"
+ SysConst_SLongDayNameSun, "Sonntag"
+ SysConst_SLongDayNameMon, "Montag"
+ SysConst_SLongDayNameTue, "Dienstag"
+ SysConst_SLongDayNameWed, "Mittwoch"
+ SysConst_SLongDayNameThu, "Donnerstag"
+ SysConst_SLongDayNameFri, "Freitag"
+ SysConst_SLongDayNameSat, "Samstag"
+ RTLConsts_SAncestorNotFound, "Vorfahr für '%s' nicht gefunden"
+ RTLConsts_SAssignError, "%s kann nicht zu %s zugewiesen werden"
+ RTLConsts_SBitsIndexError, "Bits-Index außerhalb des zulässigen Bereichs"
+ RTLConsts_SCantWriteResourceStreamError, "In einen zum Lesen geöffneten Ressourcen-Stream kann nicht geschrieben werden"
+ RTLConsts_SCheckSynchronizeError, "CheckSynchronize wurde vom Thread $%x aufgerufen, der NICHT der Haupt-Thread ist."
+ SysConst_SShortMonthNameDec, "Dez"
+ SysConst_SLongMonthNameJan, "Januar"
+ SysConst_SLongMonthNameFeb, "Februar"
+ SysConst_SLongMonthNameMar, "März"
+ SysConst_SLongMonthNameApr, "April"
+ SysConst_SLongMonthNameMay, "Mai"
+ SysConst_SLongMonthNameJun, "Juni"
+ SysConst_SLongMonthNameJul, "Juli"
+ SysConst_SLongMonthNameAug, "August"
+ SysConst_SLongMonthNameSep, "September"
+ SysConst_SLongMonthNameOct, "Oktober"
+ SysConst_SLongMonthNameNov, "November"
+ SysConst_SLongMonthNameDec, "Dezember"
+ SysConst_SShortDayNameSun, "So"
+ SysConst_SShortDayNameMon, "Mo"
+ SysConst_SShortDayNameTue, "Di"
+ SysConst_SAssertError, "%s (%s, Zeile %d)"
+ SysConst_SAbstractError, "Abstrakter Fehler"
+ SysConst_SModuleAccessViolation, "Zugriffsverletzung bei Adresse %p in Modul '%s'. %s von Adresse %p"
+ SysConst_SOSError, "Systemfehler. Code: %d.\r\n%s"
+ SysConst_SUnkOSError, "Ein Aufruf einer Betriebssystemfunktion ist fehlgeschlagen"
+ SysConst_SShortMonthNameJan, "Jan"
+ SysConst_SShortMonthNameFeb, "Feb"
+ SysConst_SShortMonthNameMar, "Mär"
+ SysConst_SShortMonthNameApr, "Apr"
+ SysConst_SShortMonthNameMay, "Mai"
+ SysConst_SShortMonthNameJun, "Jun"
+ SysConst_SShortMonthNameJul, "Jul"
+ SysConst_SShortMonthNameAug, "Aug"
+ SysConst_SShortMonthNameSep, "Sep"
+ SysConst_SShortMonthNameOct, "Okt"
+ SysConst_SShortMonthNameNov, "Nov"
+ SysConst_SVarArrayBounds, "Variante oder sicherer Array-Index außerhalb des gültigen Bereichs"
+ SysConst_SVarArrayLocked, "Variante oder sicherer Array ist gesperrt"
+ SysConst_SInvalidVarCast, "Ungültige Variant-Typumwandlung"
+ SysConst_SInvalidVarOp, "Ungültige Variant-Operation"
+ SysConst_SInvalidVarOpWithHResultWithPrefix, "Ungültige Variant-Operation (%s%.8x)\n%s"
+ SysConst_SVarTypeCouldNotConvert, "Variante des Typs (%s) konnte nicht in Typ (%s) konvertiert werden"
+ SysConst_SVarTypeConvertOverflow, "Überlauf bei der Konvertierung einer Variante vom Typ (%s) in Typ (%s)"
+ SysConst_SVarOverflow, "Variant-Überlauf"
+ SysConst_SVarInvalid, "Ungültiges Argument"
+ SysConst_SVarBadType, "Ungültiger Variant-Typ"
+ SysConst_SVarNotImplemented, "Operation nicht unterstützt"
+ SysConst_SVarUnexpected, "Unerwarteter Variant-Fehler"
+ SysConst_SExternalException, "Externe Exception %x"
+ SysConst_SAssertionFailed, "Auswertung von assert fehlgeschlagen"
+ SysConst_SIntfCastError, "Schnittstelle nicht unterstützt"
+ SysConst_SSafecallException, "Exception in safecall-Methode"
+ SysConst_SUnderflow, "Gleitkommaunterlauf"
+ SysConst_SInvalidPointer, "Ungültige Zeigeroperation"
+ SysConst_SInvalidCast, "Ungültige Typumwandlung"
+ SysConst_SAccessViolationArg3, "Zugriffsverletzung bei Adresse %p. %s von Adresse %p"
+ SysConst_SAccessViolationNoArg, "Zugriffsverletzung"
+ SysConst_SStackOverflow, "Stack-Überlauf"
+ SysConst_SControlC, "Strg+C gedrückt"
+ SysConst_SPrivilege, "Privilegierte Anweisung"
+ SysConst_SException, "Exception %s in Modul %s bei %p.\r\n%s%s\r\n"
+ SysConst_SExceptTitle, "Anwendungsfehler"
+ SysConst_SInvalidFormat, "Format '%s' ungültig oder nicht kompatibel mit Argument"
+ SysConst_SArgumentMissing, "Kein Argument für Format '%s'"
+ SysConst_SDispatchError, "Variant-Methodenaufruf nicht unterstützt"
+ SysConst_SReadAccess, "Lesen"
+ SysConst_SWriteAccess, "Schreiben"
+ SysConst_SVarArrayCreate, "Fehler beim Erzeugen von Variante oder sicherem Array"
+ SysConst_SInvalidInteger, "'%s' ist kein gültiger Integerwert"
+ SysConst_SOutOfMemory, "Zu wenig Arbeitsspeicher"
+ SysConst_SInOutError, "E/A-Fehler %d"
+ SysConst_SFileNotFound, "Datei nicht gefunden"
+ SysConst_SInvalidFilename, "Ungültiger Dateiname"
+ SysConst_STooManyOpenFiles, "Zu viele geöffnete Dateien"
+ SysConst_SAccessDenied, "Dateizugriff verweigert"
+ SysConst_SEndOfFile, "Versuch hinter dem Dateiende zu lesen"
+ SysConst_SDiskFull, "Zu wenig Speicherplatz"
+ SysConst_SInvalidInput, "Ungültige numerische Eingabe"
+ SysConst_SDivByZero, "Division durch Null"
+ SysConst_SRangeError, "Fehler bei Bereichsprüfung"
+ SysConst_SIntOverflow, "Integerüberlauf"
+ SysConst_SInvalidOp, "Ungültige Gleitkommaoperation"
+ SysConst_SZeroDivide, "Gleitkommadivision durch Null"
+ SysConst_SOverflow, "Gleitkommaüberlauf"
+END
+
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/Image32_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Image32_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,89 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, ExtCtrls, GR32, GR32_Image, GR32_RangeBars;
+
+type
+ TForm1 = class(TForm)
+ Panel1: TPanel;
+ Panel2: TPanel;
+ Image: TImage32;
+ rgScaleMode: TRadioGroup;
+ rgStretchFilter: TRadioGroup;
+ rgBitmapAlign: TRadioGroup;
+ StaticText1: TStaticText;
+ sbScale: TGaugeBar;
+ procedure rgBitmapAlignClick(Sender: TObject);
+ procedure sbScaleChange(Sender: TObject);
+ procedure rgScaleModeClick(Sender: TObject);
+ procedure rgStretchFilterClick(Sender: TObject);
+ public
+ Time: Single;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.DFM}
+
+procedure TForm1.rgBitmapAlignClick(Sender: TObject);
+const
+ BA_CONSTS: array [0..2] of TBitmapAlign = (baTopLeft, baCenter, baTile);
+begin
+ Image.BitmapAlign := BA_CONSTS[rgBitmapAlign.ItemIndex];
+end;
+
+procedure TForm1.sbScaleChange(Sender: TObject);
+begin
+ sbScale.Update;
+ Image.Scale := sbScale.Position / 100;
+end;
+
+procedure TForm1.rgScaleModeClick(Sender: TObject);
+const
+ SM_CONSTS: array [0..3] of TScaleMode = (smNormal, smStretch, smScale, smResize);
+begin
+ Image.ScaleMode := SM_CONSTS[rgScaleMode.ItemIndex];
+ sbScale.Enabled := rgScaleMode.ItemIndex = 2;
+ StaticText1.Enabled := rgScaleMode.ItemIndex = 2;
+end;
+
+procedure TForm1.rgStretchFilterClick(Sender: TObject);
+const
+ SF_CONSTS: array [0..4] of TStretchFilter =
+ (sfNearest, sfLinear, sfSpline, sfLanczos, sfMitchell);
+begin
+ Image.Bitmap.StretchFilter := SF_CONSTS[rgStretchFilter.ItemIndex];
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="ImgView_Layers_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj NewImageUnit.obj RGBALoaderUnit.obj ImgView_Layers_Ex.obj"/>
+ <RESFILES value="ImgView_Layers_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm NewImageUnit.dfm RGBALoaderUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value="vcljpg50.lib"/>
+ <SPARELIBS value="Vcl50.lib GR32_CB5.lib vcljpg50.lib"/>
+ <PACKAGES value="Vcl50.bpi GR32_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="ImgView_Layers_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,26 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("ImgView_Layers_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, MainForm);
+USEFORMNS("NewImageUnit.pas", Newimageunit, NewImageForm);
+USEFORMNS("RGBALoaderUnit.pas", Rgbaloaderunit, RGBALoaderForm);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TMainForm), &MainForm);
+ Application->CreateForm(__classid(TNewImageForm), &NewImageForm);
+ Application->CreateForm(__classid(TRGBALoaderForm), &RGBALoaderForm);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,17 @@
+program ImgView_Layers_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {MainForm},
+ NewImageUnit in 'NewImageUnit.pas' {NewImageForm},
+ RGBALoaderUnit in 'RGBALoaderUnit.pas' {RGBALoaderForm};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TMainForm, MainForm);
+ Application.CreateForm(TNewImageForm, NewImageForm);
+ Application.CreateForm(TRGBALoaderForm, RGBALoaderForm);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/ImgView_Layers_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,902 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ Menus, ExtCtrls, JPeg, ExtDlgs, StdCtrls, GR32, GR32_Image, GR32_Layers,
+ GR32_RangeBars, GR32_Filters, GR32_Transforms;
+
+type
+ TMainForm = class(TForm)
+ ImgView: TImgView32;
+ SidePanel: TPanel;
+ MainMenu: TMainMenu;
+ mnFileNew: TMenuItem;
+ mnFile: TMenuItem;
+ mnFileOpen: TMenuItem;
+ mnLayers: TMenuItem;
+ mnNewBitmapLayer: TMenuItem;
+ mnDelete: TMenuItem;
+ OpenPictureDialog1: TOpenPictureDialog;
+ pnlImage: TPanel;
+ ScaleCombo: TComboBox;
+ Label1: TLabel;
+ Panel2: TPanel;
+ ImageInterpolate: TCheckBox;
+ pnlBitmapLayer: TPanel;
+ Panel3: TPanel;
+ Label2: TLabel;
+ LayerOpacity: TGaugeBar;
+ LayerInterpolate: TCheckBox;
+ mnNewBitmapRGBA: TMenuItem;
+ LayerRescale: TButton;
+ LayerResetScale: TButton;
+ Cropped: TCheckBox;
+ mnNewCustomLayer: TMenuItem;
+ mnMagnifier: TMenuItem;
+ PnlMagn: TPanel;
+ Label3: TLabel;
+ Panel4: TPanel;
+ MagnOpacity: TGaugeBar;
+ SaveDialog1: TSaveDialog;
+ Label4: TLabel;
+ MagnMagnification: TGaugeBar;
+ Label5: TLabel;
+ MagnRotation: TGaugeBar;
+ MagnInterpolate: TCheckBox;
+ mnSimpleDrawing: TMenuItem;
+ mnArrange: TMenuItem;
+ mnBringFront: TMenuItem;
+ mnSendBack: TMenuItem;
+ N1: TMenuItem;
+ mnLevelUp: TMenuItem;
+ mnLevelDown: TMenuItem;
+ N2: TMenuItem;
+ mnScaled: TMenuItem;
+ N4: TMenuItem;
+ mnFlatten: TMenuItem;
+ N3: TMenuItem;
+ mnFlipHorz: TMenuItem;
+ mnFlipVert: TMenuItem;
+ N5: TMenuItem;
+ mnRotate90: TMenuItem;
+ mnRotate180: TMenuItem;
+ mnRotate270: TMenuItem;
+ N6: TMenuItem;
+ mnPrint: TMenuItem;
+ procedure mnFileNewClick(Sender: TObject);
+ procedure mnFileOpenClick(Sender: TObject);
+ procedure mnNewBitmapLayerClick(Sender: TObject);
+ procedure mnDeleteClick(Sender: TObject);
+ procedure mnLayersClick(Sender: TObject);
+ procedure mnNewBitmapRGBAClick(Sender: TObject);
+ procedure mnMagnifierClick(Sender: TObject);
+ procedure mnSimpleDrawingClick(Sender: TObject);
+ procedure mnArrangeClick(Sender: TObject);
+ procedure mnScaledClick(Sender: TObject);
+ procedure mnReorder(Sender: TObject);
+ procedure ScaleComboChange(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure ImageInterpolateClick(Sender: TObject);
+ procedure LayerOpacityChange(Sender: TObject);
+ procedure LayerInterpolateClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure LayerRescaleClick(Sender: TObject);
+ procedure LayerResetScaleClick(Sender: TObject);
+ procedure CroppedClick(Sender: TObject);
+ procedure MagnChange(Sender: TObject);
+ procedure ImgViewMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure ImgViewPaintStage(Sender: TObject; Buffer: TBitmap32;
+ StageNum: Cardinal);
+ procedure mnFlattenClick(Sender: TObject);
+ procedure ImgViewMouseWheelUp(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+ procedure ImgViewMouseWheelDown(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+ procedure mnFlipHorzClick(Sender: TObject);
+ procedure mnFlipVertClick(Sender: TObject);
+ procedure mnRotate90Click(Sender: TObject);
+ procedure mnRotate180Click(Sender: TObject);
+ procedure mnRotate270Click(Sender: TObject);
+ procedure mnFileClick(Sender: TObject);
+ procedure mnPrintClick(Sender: TObject);
+ private
+ FSelection: TPositionedLayer;
+ procedure SetSelection(Value: TPositionedLayer);
+ procedure WMEraseBkgnd(var Msg: TMessage); message WM_ERASEBKGND;
+ protected
+ RBLayer: TRubberbandLayer;
+ function CreatePositionedLayer: TPositionedLayer;
+ procedure LayerMouseDown(Sender: TObject; Buttons: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure RBResizing(Sender: TObject; const OldLocation: TFloatRect; var NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState);
+ procedure PaintMagnifierHandler(Sender: TObject; Buffer: TBitmap32);
+ procedure PaintSimpleDrawingHandler(Sender: TObject; Buffer: TBitmap32);
+ public
+ procedure CreateNewImage(AWidth, AHeight: Integer; FillColor: TColor32);
+ procedure OpenImage(const FileName: string);
+ property Selection: TPositionedLayer read FSelection write SetSelection;
+ end;
+
+var
+ MainForm: TMainForm;
+
+implementation
+
+uses NewImageUnit, RGBALoaderUnit, Math, GR32_LowLevel, Printers;
+
+{$R *.DFM}
+
+{ TForm1 }
+
+procedure TMainForm.CreateNewImage(AWidth, AHeight: Integer; FillColor: TColor32);
+begin
+ with ImgView do
+ begin
+ Selection := nil;
+ RBLayer := nil;
+ Layers.Clear;
+ Scale := 1;
+ Bitmap.SetSize(AWidth, AHeight);
+ Bitmap.Clear(FillColor);
+ pnlImage.Visible := not Bitmap.Empty;
+ end;
+end;
+
+function TMainForm.CreatePositionedLayer: TPositionedLayer;
+var
+ P: TPoint;
+begin
+ // get coordinates of the center of viewport
+ with ImgView.GetViewportRect do
+ P := ImgView.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));
+
+ Result := TPositionedLayer.Create(ImgView.Layers);
+ Result.Location := FloatRect(P.X - 32, P.Y - 32, P.X + 32, P.Y + 32);
+ Result.Scaled := True;
+ Result.MouseEvents := True;
+ Result.OnMouseDown := LayerMouseDown;
+end;
+
+procedure TMainForm.CroppedClick(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Cropped := Cropped.Checked;
+end;
+
+procedure TMainForm.FormCreate(Sender: TObject);
+begin
+ // by default, PST_CLEAR_BACKGND is executed at this stage,
+ // which, in turn, calls ExecClearBackgnd method of ImgView.
+ // Here I substitute PST_CLEAR_BACKGND with PST_CUSTOM, so force ImgView
+ // to call the OnPaintStage event instead of performing default action.
+ with ImgView.PaintStages[0]^ do
+ begin
+ if Stage = PST_CLEAR_BACKGND then Stage := PST_CUSTOM;
+ end;
+end;
+
+procedure TMainForm.FormDestroy(Sender: TObject);
+begin
+ Selection := nil;
+ RBLayer := nil;
+end;
+
+procedure TMainForm.ImageInterpolateClick(Sender: TObject);
+const
+ STRETCH_FILTER: array [Boolean] of TStretchFilter = (sfNearest, sfLinear);
+begin
+ ImgView.Bitmap.StretchFilter := STRETCH_FILTER[ImageInterpolate.Checked];
+end;
+
+procedure TMainForm.LayerInterpolateClick(Sender: TObject);
+const
+ STRETCH_FILTER: array [Boolean] of TStretchFilter = (sfNearest, sfLinear);
+begin
+ if Selection is TBitmapLayer then
+ begin
+ TBitmapLayer(Selection).Bitmap.StretchFilter := STRETCH_FILTER[LayerInterpolate.Checked];
+ end;
+end;
+
+procedure TMainForm.LayerMouseDown(Sender: TObject; Buttons: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+begin
+ if Sender <> nil then Selection := TPositionedLayer(Sender);
+end;
+
+procedure TMainForm.LayerOpacityChange(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Bitmap.MasterAlpha := LayerOpacity.Position;
+end;
+
+procedure TMainForm.LayerRescaleClick(Sender: TObject);
+var
+ T: TBitmap32;
+begin
+ // resize the layer's bitmap to the size of the layer
+ if Selection is TBitmapLayer then
+ with TBitmapLayer(Selection) do
+ begin
+ T := TBitmap32.Create;
+ T.Assign(Bitmap);
+ with MakeRect(Location) do
+ Bitmap.SetSize(Right - Left, Bottom - Top);
+ T.StretchFilter := sfLinear;
+ T.DrawMode := dmOpaque;
+ T.DrawTo(Bitmap, Rect(0, 0, Bitmap.Width, Bitmap.Height));
+ T.Free;
+ LayerResetScaleClick(Self);
+ end;
+end;
+
+procedure TMainForm.LayerResetScaleClick(Sender: TObject);
+var
+ L: TFloatRect;
+begin
+ // resize the layer to the size of its bitmap
+ if Selection is TBitmapLayer then
+ with RBLayer, TBitmapLayer(Selection).Bitmap do
+ begin
+ L := Location;
+ L.Right := L.Left + Width;
+ L.Bottom := L.Top + Height;
+ Location := L;
+ Changed;
+ end;
+end;
+
+procedure TMainForm.MagnChange(Sender: TObject);
+begin
+ ImgView.Invalidate;
+end;
+
+procedure TMainForm.mnArrangeClick(Sender: TObject);
+var
+ B: Boolean;
+begin
+ B := Selection <> nil;
+ mnBringFront.Enabled := B and (Selection.Index < ImgView.Layers.Count - 2);
+ mnSendBack.Enabled := B and (Selection.Index > 0);
+ mnLevelUp.Enabled := B and (Selection.Index < ImgView.Layers.Count - 2);
+ mnLevelDown.Enabled := B and (Selection.Index > 0);
+ mnScaled.Enabled := B;
+ mnScaled.Checked := B and Selection.Scaled;
+ mnDelete.Enabled := B;
+ B := B and (Selection is TBitmapLayer);
+ mnFlipHorz.Enabled := B;
+ mnFlipVert.Enabled := B;
+ mnRotate90.Enabled := B;
+ mnRotate180.Enabled := B;
+ mnRotate270.Enabled := B;
+end;
+
+procedure TMainForm.mnDeleteClick(Sender: TObject);
+var
+ ALayer: TPositionedLayer;
+begin
+ if Selection <> nil then
+ begin
+ ALayer := Selection;
+ Selection := nil;
+ ALayer.Free;
+ end;
+end;
+
+procedure TMainForm.mnFileNewClick(Sender: TObject);
+begin
+ with NewImageForm do
+ begin
+ ShowModal;
+ if ModalResult = mrOK then
+ CreateNewImage(UpDown1.Position, UpDown2.Position, Color32(Panel1.Color));
+ end;
+end;
+
+procedure TMainForm.mnFileOpenClick(Sender: TObject);
+begin
+ with OpenPictureDialog1 do
+ if Execute then OpenImage(FileName);
+end;
+
+procedure TMainForm.mnLayersClick(Sender: TObject);
+var
+ B: Boolean;
+begin
+ B := not ImgView.Bitmap.Empty;
+ mnNewBitmapLayer.Enabled := B;
+ mnNewBitmapRGBA.Enabled := B;
+ mnNewCustomLayer.Enabled := B;
+ mnFlatten.Enabled := B and (ImgView.Layers.Count > 0);
+end;
+
+procedure TMainForm.mnMagnifierClick(Sender: TObject);
+var
+ L: TPositionedLayer;
+begin
+ L := CreatePositionedLayer;
+ L.OnPaint := PaintMagnifierHandler;
+ L.Tag := 2;
+ Selection := L;
+end;
+
+procedure TMainForm.mnNewBitmapLayerClick(Sender: TObject);
+var
+ B: TBitmapLayer;
+ P: TPoint;
+ W, H: Single;
+begin
+ with OpenPictureDialog1 do
+ if Execute then
+ begin
+ B := TBitmapLayer.Create(ImgView.Layers);
+ with B do
+ try
+ Bitmap.LoadFromFile(FileName);
+ Bitmap.DrawMode := dmBlend;
+
+ with ImgView.GetViewportRect do
+ P := ImgView.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));
+
+ W := Bitmap.Width / 2;
+ H := Bitmap.Height / 2;
+
+ with ImgView.Bitmap do
+ Location := FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);
+
+ Scaled := True;
+ OnMouseDown := LayerMouseDown;
+ except
+ Free;
+ raise;
+ end;
+ Selection := B;
+ end;
+end;
+
+procedure TMainForm.mnNewBitmapRGBAClick(Sender: TObject);
+var
+ B: TBitmapLayer;
+ P: TPoint;
+ Tmp: TBitmap32;
+ W, H: Single;
+begin
+ with RGBALoaderForm do
+ begin
+ ImgRGB.Bitmap.Delete;
+ ImgRGB.Scale := 1;
+ ImgAlpha.Bitmap.Delete;
+ ImgAlpha.Scale := 1;
+ ShowModal;
+ if (ModalResult = mrOK) and not ImgRGB.Bitmap.Empty then
+ begin
+ B := TBitmapLayer.Create(ImgView.Layers);
+ B.Bitmap := ImgRGB.Bitmap;
+ B.Bitmap.DrawMode := dmBlend;
+
+ if not ImgAlpha.Bitmap.Empty then
+ begin
+ Tmp := TBitmap32.Create;
+ try
+ Tmp.SetSize(B.Bitmap.Width, B.Bitmap.Height);
+ ImgAlpha.Bitmap.DrawTo(Tmp, Rect(0, 0, Tmp.Width, Tmp.Height));
+
+ // combine Alpha into already loaded RGB colors
+ IntensityToAlpha(B.Bitmap, Tmp);
+ finally
+ Tmp.Free;
+ end;
+ end;
+
+ with ImgView.GetViewportRect do
+ P := ImgView.ControlToBitmap(Point((Right + Left) div 2, (Top + Bottom) div 2));
+
+ with B do
+ begin
+ W := Bitmap.Width / 2;
+ H := Bitmap.Height / 2;
+
+ with ImgView.Bitmap do
+ Location := FloatRect(P.X - W, P.Y - H, P.X + W, P.Y + H);
+
+ Scaled := True;
+ OnMouseDown := LayerMouseDown;
+ end;
+ Selection := B;
+ end;
+ end;
+end;
+
+procedure TMainForm.mnReorder(Sender: TObject);
+begin
+ // note that the top-most layer is occupied with the rubber-banding layer
+ if Selection <> nil then
+ case TMenuItem(Sender).Tag of
+ 1: // Bring to front, do not use BringToFront here, see note above
+ Selection.Index := ImgView.Layers.Count - 2;
+ 2: Selection.SendToBack;
+ 3: Selection.Index := Selection.Index + 1; // up one level
+ 4: Selection.Index := Selection.Index - 1; // down one level
+ end;
+end;
+
+procedure TMainForm.mnSimpleDrawingClick(Sender: TObject);
+var
+ L: TPositionedLayer;
+begin
+ L := CreatePositionedLayer;
+ L.OnPaint := PaintSimpleDrawingHandler;
+ L.Tag := 1;
+ Selection := L;
+end;
+
+procedure TMainForm.OpenImage(const FileName: string);
+begin
+ with ImgView do
+ try
+ Selection := nil;
+ RBLayer := nil;
+ Layers.Clear;
+ Scale := 1;
+ Bitmap.LoadFromFile(FileName);
+ finally
+ pnlImage.Visible := not Bitmap.Empty;
+ end;
+end;
+
+procedure TMainForm.PaintMagnifierHandler(Sender: TObject; Buffer: TBitmap32);
+var
+ Magnification, Rotation: Single;
+ SrcRect, DstRect: TFloatRect;
+ R: TRect;
+ T: TAffineTransformation;
+ B: TBitmap32;
+ W2, H2: Single;
+ I: Integer;
+begin
+ if Sender is TPositionedLayer then
+ with TPositionedLayer(Sender) do
+ begin
+ Magnification := Power(10, (MagnMagnification.Position / 50));
+ Rotation := -MagnRotation.Position;
+
+ DstRect := GetAdjustedLocation;
+ R := MakeRect(DstRect);
+ B := TBitmap32.Create;
+ try
+ with R do
+ begin
+ B.SetSize(Right - Left, Bottom - Top);
+ W2 := (Right - Left) / 2;
+ H2 := (Bottom - Top) / 2;
+ end;
+
+ SrcRect := DstRect;
+ with SrcRect do
+ begin
+ Left := Left - H2;
+ Right := Right + H2;
+ Top := Top - W2;
+ Bottom := Bottom + W2;
+ end;
+
+ T := TAffineTransformation.Create;
+ try
+ T.SrcRect := SrcRect;
+ T.Translate(-R.Left, -R.Top);
+
+ T.Translate(-W2, -H2);
+ T.Scale(Magnification, Magnification);
+ T.Rotate(0, 0, Rotation);
+ T.Translate(W2, H2);
+
+ if MagnInterpolate.Checked then
+ begin
+ Buffer.BeginUpdate;
+ Buffer.StretchFilter := sfLinear;
+ Transform(B, Buffer, T);
+ Buffer.StretchFilter := sfNearest;
+ Buffer.EndUpdate;
+ end
+ else
+ Transform(B, Buffer, T);
+
+ B.ResetAlpha;
+ B.DrawMode := dmBlend;
+ B.MasterAlpha := MagnOpacity.Position;
+ B.DrawTo(Buffer, R);
+
+ // draw frame
+ for I := 0 to 4 do
+ begin
+ with R do Buffer.RaiseRectTS(Left, Top, Right, Bottom, 35 - I * 8);
+ InflateRect(R, -1, -1);
+ end;
+ finally
+ T.Free;
+ end;
+ finally
+ B.Free;
+ end;
+ end;
+end;
+
+procedure TMainForm.PaintSimpleDrawingHandler(Sender: TObject; Buffer: TBitmap32);
+var
+ Cx, Cy: Single;
+ W2, H2: Single;
+ I: Integer;
+begin
+ if Sender is TPositionedLayer then
+ with TPositionedLayer(Sender).GetAdjustedLocation do
+ begin
+ W2 := (Right - Left) / 2;
+ H2 := (Bottom - Top) / 2;
+ Cx := Left + W2;
+ Cy := Top + H2;
+ Buffer.PenColor := clRed32;
+ Buffer.MoveToF(Cx,Cy);
+ for I := 0 to 240 do
+ begin
+ Buffer.LineToFS(Cx + W2 * I / 200 * Cos(I / 8), Cy + H2 * I / 200 * Sin(I / 8));
+ end;
+ end;
+end;
+
+procedure TMainForm.ScaleComboChange(Sender: TObject);
+var
+ S: string;
+ I: Integer;
+begin
+ S := ScaleCombo.Text;
+ S := StringReplace(S, '%', '', [rfReplaceAll]);
+ S := StringReplace(S, ' ', '', [rfReplaceAll]);
+ if S = '' then Exit;
+ I := StrToIntDef(S, -1);
+ if (I < 1) or (I > 2000) then I := Round(ImgView.Scale * 100)
+ else ImgView.Scale := I / 100;
+ ScaleCombo.Text := IntToStr(I) + '%';
+ ScaleCombo.SelStart := Length(ScaleCombo.Text) - 1;
+end;
+
+procedure TMainForm.SetSelection(Value: TPositionedLayer);
+begin
+ if Value <> FSelection then
+ begin
+ if RBLayer <> nil then
+ begin
+ RBLayer.ChildLayer := nil;
+ RBLayer.LayerOptions := LOB_NO_UPDATE;
+ pnlBitmapLayer.Visible := False;
+ pnlMagn.Visible := False;
+ ImgView.Invalidate;
+ end;
+
+ FSelection := Value;
+
+ if Value <> nil then
+ begin
+ if RBLayer = nil then
+ begin
+ RBLayer := TRubberBandLayer.Create(ImgView.Layers);
+ RBLayer.MinHeight := 1;
+ RBLayer.MinWidth := 1;
+ end
+ else RBLayer.BringToFront;
+ RBLayer.ChildLayer := Value;
+ RBLayer.LayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS or LOB_NO_UPDATE;
+ RBLayer.OnResizing := RBResizing;
+
+ if Value is TBitmapLayer then
+ with TBitmapLayer(Value) do
+ begin
+ pnlBitmapLayer.Visible := True;
+ LayerOpacity.Position := Bitmap.MasterAlpha;
+ LayerInterpolate.Checked := Bitmap.StretchFilter = sfLinear;
+ end
+ else if Value.Tag = 2 then
+ begin
+ // tag = 2 for magnifiers
+ pnlMagn.Visible := True;
+ end;
+ end;
+ end;
+end;
+
+procedure TMainForm.WMEraseBkgnd(var Msg: TMessage);
+begin
+ // disable form background cleaning
+ Msg.Result := 1;
+end;
+
+procedure TMainForm.mnScaledClick(Sender: TObject);
+begin
+ if Selection <> nil then Selection.Scaled := not Selection.Scaled;
+ RBLayer.Scaled := Selection.Scaled;
+end;
+
+procedure TMainForm.ImgViewMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ if Layer = nil then
+ begin
+ Selection := nil;
+ ReleaseCapture;
+ end;
+end;
+
+procedure TMainForm.ImgViewPaintStage(Sender: TObject; Buffer: TBitmap32;
+ StageNum: Cardinal);
+const
+ Colors: array [0..1] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
+var
+ W, I, J, Parity: Integer;
+ Line1, Line2: TArrayOfColor32; // a buffer for a couple of scanlines
+begin
+ with ImgView.Buffer do
+ begin
+ W := Width;
+ SetLength(Line1, W);
+ SetLength(Line2, W);
+ for I := 0 to W - 1 do
+ begin
+ Parity := I shr 3 and $1;
+ Line1[I] := Colors[Parity];
+ Line2[I] := Colors[1 - Parity];
+ end;
+ for J := 0 to Height - 1 do
+ begin
+ Parity := J shr 3 and $1;
+ if Boolean(Parity) then MoveLongword(Line1[0], ScanLine[J]^, W)
+ else MoveLongword(Line2[0], ScanLine[J]^, W);
+ end;
+ end;
+end;
+
+procedure TMainForm.RBResizing(Sender: TObject;
+ const OldLocation: TFloatRect; var NewLocation: TFloatRect;
+ DragState: TDragState; Shift: TShiftState);
+var
+ w, h, cx, cy: Single;
+ nw, nh: Single;
+
+begin
+ if DragState = dsMove then Exit; // we are interested only in scale operations
+ if Shift = [] then Exit; // special processing is not required
+
+ if ssCtrl in Shift then
+ begin
+ { make changes symmetrical }
+
+ with OldLocation do
+ begin
+ cx := (Left + Right) / 2;
+ cy := (Top + Bottom) / 2;
+ w := Right - Left;
+ h := Bottom - Top;
+ end;
+
+ with NewLocation do
+ begin
+ nw := w / 2;
+ nh := h / 2;
+ case DragState of
+ dsSizeL: nw := cx - Left;
+ dsSizeT: nh := cy - Top;
+ dsSizeR: nw := Right - cx;
+ dsSizeB: nh := Bottom - cy;
+ dsSizeTL: begin nw := cx - Left; nh := cy - Top; end;
+ dsSizeTR: begin nw := Right - cx; nh := cy - Top; end;
+ dsSizeBL: begin nw := cx - Left; nh := Bottom - cy; end;
+ dsSizeBR: begin nw := Right - cx; nh := Bottom - cy; end;
+ end;
+ if nw < 2 then nw := 2;
+ if nh < 2 then nh := 2;
+
+ Left := cx - nw;
+ Right := cx + nw;
+ Top := cy - nh;
+ Bottom := cy + nh;
+ end;
+ end;
+end;
+
+procedure TMainForm.mnFlattenClick(Sender: TObject);
+var
+ B: TBitmap32;
+ W, H: Integer;
+begin
+ { deselect everything }
+ Selection := nil;
+ W := ImgView.Bitmap.Width;
+ H := ImgView.Bitmap.Height;
+
+ { Create a new bitmap to store a flattened image }
+ B := TBitmap32.Create;
+ try
+ B.SetSize(W, H);
+ ImgView.PaintTo(B, Rect(0, 0, W, H));
+
+ { destroy all the layers of the original image... }
+ ImgView.Layers.Clear;
+ RBLayer := nil; // note that RBLayer reference is destroyed here as well.
+ // The rubber band will be recreated during the next
+ // SetSelection call. Alternatively, you can delete
+ // all the layers except the rubber band.
+
+ { ...and overwrite it with the flattened one }
+ ImgView.Bitmap := B;
+ finally
+ B.Free;
+ end;
+end;
+
+procedure TMainForm.mnPrintClick(Sender: TObject);
+var
+ B: TBitmap32;
+ W, H: Integer;
+ R: TRect;
+
+ function GetCenteredRectToFit(const src, dst: TRect): TRect;
+ var
+ srcWidth, srcHeight, dstWidth, dstHeight, ScaledSide: Integer;
+ begin
+ with src do begin
+ srcWidth := Right - Left;
+ srcHeight := Bottom - Top;
+ end;
+ with dst do begin
+ dstWidth := Right - Left;
+ dstHeight := Bottom - Top;
+ end;
+ if (srcWidth = 0) or (srcHeight = 0) then exit;
+ if srcWidth / srcHeight > dstWidth / dstHeight then begin
+ ScaledSide := Round(dstWidth * srcHeight / srcWidth);
+ with Result do begin
+ Left := dst.Left;
+ Top := dst.Top + (dstHeight - ScaledSide) div 2;
+ Right := dst.Right;
+ Bottom := Top + ScaledSide;
+ end;
+ end else begin
+ ScaledSide := Round(dstHeight * srcWidth / srcHeight);
+ with Result do begin
+ Left := dst.Left + (dstWidth - ScaledSide) div 2;
+ Top := dst.Top;
+ Right := Left + ScaledSide;
+ Bottom := dst.Bottom;
+ end;
+ end;
+ end;
+
+begin
+ { deselect everything }
+ Selection := nil;
+ W := ImgView.Bitmap.Width;
+ H := ImgView.Bitmap.Height;
+
+ { Create a new bitmap to store a flattened image }
+ B := TBitmap32.Create;
+ Screen.Cursor := crHourGlass;
+ try
+ B.SetSize(W, H);
+ ImgView.PaintTo(B, Rect(0, 0, W, H));
+ Printer.BeginDoc;
+ Printer.Title := 'Graphics32 Demo';
+ B.StretchFilter := sfLinear;
+ R := GetCenteredRectToFit(Rect(0, 0, W, H), Rect(0, 0, Printer.PageWidth, Printer.PageHeight));
+ B.TileTo(Printer.Canvas.Handle, R, Rect(0, 0, W, H));
+ Printer.EndDoc;
+ finally
+ B.Free;
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+procedure TMainForm.ImgViewMouseWheelUp(Sender: TObject;
+ Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
+var
+ s: Single;
+begin
+ s := ImgView.Scale / 1.1;
+ if s < 0.2 then s := 0.2;
+ ImgView.Scale := s;
+ ScaleCombo.Text := IntToStr(Round(s * 100)) + '%';
+end;
+
+procedure TMainForm.ImgViewMouseWheelDown(Sender: TObject;
+ Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
+var
+ s: Single;
+begin
+ s := ImgView.Scale * 1.1;
+ if s > 20 then s := 20;
+ ImgView.Scale := s;
+ ScaleCombo.Text := IntToStr(Round(s * 100)) + '%';
+end;
+
+procedure TMainForm.mnFlipHorzClick(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Bitmap.FlipHorz;
+end;
+
+procedure TMainForm.mnFlipVertClick(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Bitmap.FlipVert;
+end;
+
+procedure TMainForm.mnRotate90Click(Sender: TObject);
+var
+ R: TFloatRect;
+ Cx, Cy, W2, H2: Single;
+begin
+ if Selection is TBitmapLayer then
+ begin
+ R := Selection.Location;
+ TBitmapLayer(Selection).Bitmap.Rotate90;
+ Cx := (R.Left + R.Right) / 2;
+ Cy := (R.Top + R.Bottom) / 2;
+ W2 := (R.Right - R.Left) / 2;
+ H2 := (R.Bottom - R.Top) / 2;
+ RBLayer.Location := FloatRect(Cx - H2, Cy - W2, Cx + H2, Cy + W2);
+ end;
+end;
+
+procedure TMainForm.mnRotate180Click(Sender: TObject);
+begin
+ if Selection is TBitmapLayer then
+ TBitmapLayer(Selection).Bitmap.Rotate180;
+end;
+
+procedure TMainForm.mnRotate270Click(Sender: TObject);
+var
+ R: TFloatRect;
+ Cx, Cy, W2, H2: Single;
+begin
+ if Selection is TBitmapLayer then
+ begin
+ R := Selection.Location;
+ TBitmapLayer(Selection).Bitmap.Rotate270;
+ Cx := (R.Left + R.Right) / 2;
+ Cy := (R.Top + R.Bottom) / 2;
+ W2 := (R.Right - R.Left) / 2;
+ H2 := (R.Bottom - R.Top) / 2;
+ RBLayer.Location := FloatRect(Cx - H2, Cy - W2, Cx + H2, Cy + W2);
+ end;
+end;
+
+procedure TMainForm.mnFileClick(Sender: TObject);
+begin
+ mnPrint.Enabled := not ImgView.Bitmap.Empty;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/NewImageUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/NewImageUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/NewImageUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/NewImageUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/NewImageUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,73 @@
+unit NewImageUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, ExtCtrls, ComCtrls;
+
+type
+ TNewImageForm = class(TForm)
+ Label1: TLabel;
+ ImageWidth: TEdit;
+ UpDown1: TUpDown;
+ Label2: TLabel;
+ ImageHeight: TEdit;
+ UpDown2: TUpDown;
+ Label3: TLabel;
+ Label4: TLabel;
+ Label5: TLabel;
+ Panel1: TPanel;
+ Button1: TButton;
+ Button2: TButton;
+ Button3: TButton;
+ ColorDialog1: TColorDialog;
+ procedure Button1Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ NewImageForm: TNewImageForm;
+
+implementation
+
+{$R *.DFM}
+
+procedure TNewImageForm.Button1Click(Sender: TObject);
+begin
+ with ColorDialog1 do
+ begin
+ Color := Panel1.Color;
+ if Execute then Panel1.Color := Color;
+ end;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/RGBALoaderUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/RGBALoaderUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/RGBALoaderUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/RGBALoaderUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ImgView_Layers_Ex/RGBALoaderUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,116 @@
+unit RGBALoaderUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, GR32_Image, GR32_Filters, ExtCtrls, ExtDlgs, Buttons;
+
+type
+ TRGBALoaderForm = class(TForm)
+ Panel1: TPanel;
+ Bevel1: TBevel;
+ Label1: TLabel;
+ Label2: TLabel;
+ ImgRGB: TImgView32;
+ Button1: TButton;
+ Label3: TLabel;
+ ImgAlpha: TImgView32;
+ Button2: TButton;
+ Label4: TLabel;
+ Button3: TButton;
+ Button4: TButton;
+ OpenPictureDialog: TOpenPictureDialog;
+ SpeedButton1: TSpeedButton;
+ SpeedButton2: TSpeedButton;
+ SpeedButton3: TSpeedButton;
+ SpeedButton4: TSpeedButton;
+ Button5: TButton;
+ procedure Button1Click(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure SpeedButton1Click(Sender: TObject);
+ procedure SpeedButton2Click(Sender: TObject);
+ procedure SpeedButton3Click(Sender: TObject);
+ procedure SpeedButton4Click(Sender: TObject);
+ procedure Button5Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ RGBALoaderForm: TRGBALoaderForm;
+
+implementation
+
+{$R *.DFM}
+
+procedure TRGBALoaderForm.Button1Click(Sender: TObject);
+begin
+ with OpenPictureDialog do
+ if Execute then ImgRGB.Bitmap.LoadFromFile(FileName);
+end;
+
+procedure TRGBALoaderForm.Button2Click(Sender: TObject);
+begin
+ with OpenPictureDialog, ImgAlpha do
+ if Execute then
+ begin
+ Bitmap.LoadFromFile(FileName);
+ ColorToGrayscale(Bitmap, Bitmap);
+ end;
+end;
+
+procedure TRGBALoaderForm.SpeedButton1Click(Sender: TObject);
+begin
+ ImgRGB.Scale := ImgRGB.Scale * 1.5;
+end;
+
+procedure TRGBALoaderForm.SpeedButton2Click(Sender: TObject);
+begin
+ ImgRGB.Scale := ImgRGB.Scale / 1.5;
+end;
+
+procedure TRGBALoaderForm.SpeedButton3Click(Sender: TObject);
+begin
+ ImgAlpha.Scale := ImgAlpha.Scale * 1.5;
+end;
+
+procedure TRGBALoaderForm.SpeedButton4Click(Sender: TObject);
+begin
+ ImgAlpha.Scale := ImgAlpha.Scale / 1.5;
+end;
+
+procedure TRGBALoaderForm.Button5Click(Sender: TObject);
+begin
+ ImgRGB.Scale := 1;
+ ImgAlpha.Scale := 1;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="LineStippling_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj LineStippling_Ex.obj"/>
+ <RESFILES value="LineStippling_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="Vcl50.lib GR32_CB5.lib"/>
+ <PACKAGES value="Vcl50.bpi GR32_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="LineStippling_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("LineStippling_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, Form1);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TForm1), &Form1);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program LineStippling_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/LineStippling_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/LineStippling_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,99 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, GR32, GR32_Image;
+
+type
+ TForm1 = class(TForm)
+ Image: TImage32;
+ ScrollBar1: TScrollBar;
+ procedure ScrollBarChange(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ procedure Spiral(X, Y: Integer);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.DFM}
+
+procedure TForm1.ScrollBarChange(Sender: TObject);
+var
+ Step: Single;
+begin
+ Step := ScrollBar1.Position / 100;
+
+ with Image.Bitmap do
+ begin
+ BeginUpdate;
+ Clear(clBlack32);
+ SetStipple([clWhite32, clWhite32, clWhite32, clWhite32, 0, 0, 0, 0]);
+ StippleStep := Step;
+ Spiral(50, 50);
+
+ SetStipple([clWhite32, $00FFFFFF]);
+ Spiral(150, 50);
+
+ SetStipple([clWhite32, clRed32, clGreen32, 0, 0, 0]);
+ Spiral(50, 150);
+
+ SetStipple([clGreen32, clGreen32, clGreen32, 0, 0, clWhite32, 0, 0]);
+ Spiral(150, 150);
+ EndUpdate;
+ end;
+ Image.Repaint;
+end;
+
+procedure TForm1.Spiral(X, Y: Integer);
+var
+ Theta: Single;
+begin
+ Theta := 0;
+ Image.Bitmap.MoveToF(X, Y);
+ while Theta < 15 * 3.1415926535 do
+ begin
+ Image.Bitmap.LineToFSP(X + Cos(Theta) * Theta, Y + Sin(Theta) * Theta);
+ Theta := Theta + 0.2;
+ end;
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ ScrollBarChange(Sender);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/MainUnit.dfm
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/MainUnit.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/MainUnit.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,7557 @@
+object Form1: TForm1
+ Left = 295
+ Top = 110
+ Width = 524
+ Height = 373
+ Caption = 'Form1'
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ DesignSize = (
+ 516
+ 346)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object ImgView: TImgView32
+ Left = 16
+ Top = 20
+ Width = 367
+ Height = 309
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Bitmap.Data = {
+ 1B010000D40000003A1EC5FF3820C2FF3922C0FF3924C0FF3823C5FF3925C4FF
+ 3C28C1FF3D2ABFFF3F29BEFF3526A6FF33318AFF3A4382FF3C4B83FF354980FF
+ 37488BFF3A5097FF3B589DFF3D5EA3FF4265A7FF446AABFF456BABFF4770AFFF
+ 4D78B7FF537EBDFF527DBCFF4F7AB9FF4C73B7FF486FB3FF496AB3FF4768B1FF
+ 4867B2FF4866B3FF3F5EADFF3E5FAFFF3C5EB1FF395DABFF36569FFF344F8FFF
+ 36487DFF3A4571FF35365CFF313052FF302F51FF383759FF3C3E5DFF3A3C5AFF
+ 383953FF3B3A4EFF3D3945FF41394AFF32264AFF241842FF241C41FF281D4BFF
+ 27135BFF29145FFF2B1758FF321D54FF3F2053FF451F3DFF6D3A38FFA1683BFF
+ B67C1CFFC08409FFC27F04FFC27D04FFC57F0DFFBC7A03FFBE8603FFAB8116FF
+ 64491DFF2E1C15FF241316FF1C1316FF161917FF1B201EFF2A1F27FF271D2AFF
+ 231F32FF242436FF242235FF242131FF221F2EFF25232FFF2A2834FF2E2D36FF
+ 302F38FF2F2F35FF2B2B31FF28282EFF24232DFF23222CFF252231FF252231FF
+ 242131FF241E2FFF292034FF271F30FF26222DFF27242DFF282128FF291F25FF
+ 34262CFF503521FF986723FFBA7D1BFFB77C0EFFBC7F09FFC6850BFFC48408FF
+ C5860EFFC1830DFFC28310FFC28311FFC28311FFC28311FFC28311FFC28311FF
+ C28311FFC28311FFC38412FFC38412FFC38412FFC38412FFC28311FFC28311FF
+ C18210FFBF810FFFBE8211FFBF8514FFC1881BFFC58B21FFC88E27FFC9902DFF
+ CA9031FFC99035FFC68D38FFC08837FFBF8539FFC88E46FFD49C55FFDFA661FF
+ DEA665FFDCA463FFDFA96AFFDFAA6BFFDFA96CFFDCAB6DFFDEAC70FFDCAE74FF
+ DBB077FFD8B07BFFD5AE7AFFC9A575FFCDAB80FFE4C59EFFF9D9B6FFF9DDBBFF
+ FCDEC1FFFDE4CAFFFCE7D8FFF1DFD4FFECDBD2FFF1E0D7FFFAEAE3FFFFF3EBFF
+ FFF3EDFFFAF0E9FFF6EAE8FFF6EDEAFFF8F0F1FFF9F1F2FFF0E9ECFFEAE3E6FF
+ EEE9EBFFFAF5F7FFFDF3F9FFFBF1F7FFF7EFF6FFF9F1F8FFFAF3FAFFFBF4FBFF
+ FAF2FCFFF6F1FAFFFBF5FFFFF7F3FEFFF6F2FEFFF6F2FEFFF6F3FFFFF6F3FFFF
+ F2F2FFFFF0F0FCFFF9F6FFFFF7F5FBFFF5F3F9FFF4F2F8FFF2F2F8FFF4F4FAFF
+ F7F8FCFFF8F9FDFFF2F5F9FFF0F3F7FFEEF3F4FFF0F5F6FFF3F8F9FFF5FAFBFF
+ F4F9FAFFF2F7F8FFF1F4F8FFF1F3F4FFF5EFF0FFF5EDEDFFF5EAEDFFF1EAEFFF
+ ECE8F3FFE7E9F4FFE2E4EEFFE6EAEFFFF3F3F3FFF2EFEBFFE5E1DCFFE9E2DFFF
+ EDE7E8FFE3E2E4FFE1E9E8FFE3F0EEFFF0F5F3FFF5F6F4FFF6F1F0FFF6EEEEFF
+ F7EFEFFFF8F3F2FFF5F1F0FFF2F0EFFFF5F6F4FFF5F4F0FFEAE5E2FFE4DCD5FF
+ D6CAC4FFC2B4A8FFC3AF9EFFC9B49FFFCBB49EFFC3AD94FFB99F87FFB3987DFF
+ B5997BFFBC9D7CFFCBAB88FFBF9B75FFB08C64FFAE895DFFB98F64FFBD9467FF
+ BB8F60FFB48754FFB6894CFFBE9050FFC0904EFFB88945FFB3823EFFB08038FF
+ AE7A33FFA77529FFB27C2FFFB98433FFC08837FFBE8732FFC08430FFC0852FFF
+ BC8027FFB4781EFFC1852BFFBF8526FFBE8121FFBB7F1BFFBD7F15FFBB7E10FF
+ BB7C0CFFBA7C0AFFBE800EFFBA7B0BFFB87B0DFF381DC1FF371FC1FF3721BDFF
+ 3722BEFF3622C1FF3723C2FF3A26BFFF3B28BDFF402ABFFF3627A7FF33318AFF
+ 394281FF3A4A7FFF34487FFF354788FF374E92FF39569BFF3A5BA0FF3F62A6FF
+ 4167A8FF446AABFF456EADFF4974B3FF4E79B8FF517CBBFF507ABBFF4F76BAFF
+ 4B72B7FF496AB3FF4465AEFF4160ABFF3E5CA9FF3E5DACFF3C5DADFF395BAEFF
+ 375BA9FF36569FFF344F8FFF35477CFF39426EFF303359FF302F51FF302F51FF
+ 383759FF3B3D5CFF3A3C5AFF383953FF3C3B4FFF3D3945FF403849FF312549FF
+ 241743FF251C44FF281C4CFF271459FF29145FFF281554FF2F1953FF3A1D54FF
+ 441E42FF6B3A3CFF9B663BFFB27818FFB87C00FFC27F04FFC27D04FFC57F0DFF
+ BC7A03FFBE8603FFAD8116FF64491DFF2F1C14FF251417FF1C1218FF161917FF
+ 1D201EFF291E26FF291C2AFF221E31FF242436FF282737FF272434FF252231FF
+ 262430FF292733FF2C2B35FF2C2B34FF2B2B31FF2A2A30FF27262FFF24232DFF
+ 23222CFF252231FF262332FF252232FF251F30FF292034FF271F30FF26222DFF
+ 27242DFF282128FF291F25FF33252BFF503521FF966521FFB97C1AFFB67B0DFF
+ BC7F09FFC5840AFFC28206FFC4850DFFC0820CFFC1820FFFC18210FFC18210FF
+ C18210FFC18210FFC18210FFC18210FFC18210FFC38412FFC38412FFC28311FF
+ C18210FFC18210FFC18210FFC18210FFC18311FFBE8211FFBD8312FFBD8516FF
+ BF8619FFC0861DFFC18720FFBF8623FFBF8526FFC0872CFFBB8128FFB67D28FF
+ B67E2CFFBC8433FFBF8738FFBD8538FFB98035FFBA8038FFBA8038FFB88138FF
+ B78239FFB6823BFFB7843EFFB58642FFB48744FFB68C4BFFAE8547FFAF894FFF
+ BF9963FFCBA674FFCDA979FFCCA97DFFCCAC83FFD2B392FFCCB092FFCBAE93FF
+ D0B59AFFDCC1A7FFE4CBB1FFE5CDB5FFE4CEB5FFDFC8B2FFDDC8B3FFDECAB8FF
+ E0CCBBFFDBC8B9FFDAC7B8FFE0D0C0FFECDCCCFFF8E6DBFFF6E5DCFFF5E3DCFF
+ F5E5DEFFF9E9E2FFFBEBE4FFFAEAE4FFF7E9E3FFF2E6E2FFF6EAE6FFF9ECEAFF
+ F8ECEAFFF7EBEBFFF5EBEBFFFAF0F0FFFDF5F5FFFFFAF9FFFDF7F8FFFBF5F6FF
+ F9F3F4FFF7F2F3FFF7F2F3FFF8F4F3FFF7F5F4FFF9F7F6FFF8F6F5FFF6F7F5FF
+ F7F8F6FFF8F9F7FFF9FAF8FFF8F9F7FFF8F9F7FFF7F8F6FFF8F6F5FFFCF5F2FF
+ FCF3F0FFFBF1F1FFF9F0F3FFF4F0F6FFF0EFF8FFF0F3F8FFEDF1F2FFF5F6F4FF
+ FAF7F3FFF4F1EDFFF6F1F2FFF9F5FAFFF1F1F7FFE7EFEFFFEAF5F3FFF3F8F7FF
+ F9F7F6FFF8F3F2FFF7EFF0FFF6F0F1FFF9F3F4FFF8F6F6FFF2F2F2FFF2F2F2FF
+ F1EFEFFFEDE9E8FFF2EBE8FFF2E9E6FFE8DCD6FFE8DACEFFECDCCFFFEDDDCDFF
+ E9D6C7FFDECCBBFFDAC6B4FFDDC5B1FFE1C9B1FFECD3B9FFE2C7ACFFD8BA9DFF
+ D7B899FFDDBC9BFFDEBE9BFFD8B593FFD1AD87FFCEA97DFFD1AB7BFFD0A877FF
+ CBA470FFC8A06CFFC69D66FFBE935AFFB5894EFFB48849FFB98B4BFFBC8C4AFF
+ BD8C48FFBE8B45FFBC8841FFB9833CFFB27E32FFB37E2EFFB27D2CFFB37D28FF
+ B27C25FFB37D1FFFB67E1FFFB7801DFFB9831EFFBA811EFFB47D1AFFB47C1DFF
+ 3A1FC2FF3821BFFF3924BDFF3824BDFF3723C2FF3824C3FF3B27C0FF3B28BDFF
+ 3F28C0FF3626A9FF333288FF37417DFF38497CFF32477BFF344784FF354D8FFF
+ 375499FF37589DFF3C5FA3FF3F65A6FF4369AAFF456DAEFF4670B1FF4771B2FF
+ 4C76B7FF4C76B9FF4E75B9FF4B72B7FF4A6BB4FF4363AEFF3D5BA8FF3856A3FF
+ 3E5CABFF3B59AAFF3758A8FF3557A3FF37559CFF354E8CFF344578FF343D69FF
+ 2D3056FF2D2D51FF302E52FF373658FF3B3D5CFF3A3C5AFF393A54FF3C3B4FFF
+ 3E3A46FF3F364AFF302349FF231644FF251B45FF281C4EFF251457FF27155CFF
+ 2C1B5AFF2F1B56FF341B59FF3E1C4BFF633843FF95643EFFB37C1BFFBA7F01FF
+ C27F04FFC27D04FFC57F0DFFBA7A04FFBF8504FFAF8017FF66491CFF311C14FF
+ 291619FF1D1319FF161818FF1C1E1EFF291E26FF281B29FF221F2FFF232335FF
+ 2B2A3AFF2B2838FF292635FF282632FF282632FF282731FF27262FFF26252EFF
+ 282730FF26252EFF24232DFF24232DFF252231FF262332FF252232FF272132FF
+ 292034FF271F30FF26222DFF27242DFF272027FF281E24FF33252BFF4F3420FF
+ 94631FFFB87B19FFB57A0CFFBB7E08FFC48309FFC08004FFC2830BFFBE800AFF
+ BF800DFFBF800DFFBF800DFFBF800DFFBF800DFFBF800DFFBF800DFFBF800DFF
+ C28310FFC1820FFFC0810EFFBF800DFFBF800DFFC1820FFFC28310FFC38612FF
+ C28614FFBF8613FFBE8413FFBC8211FFBC8113FFB98013FFB97F15FFB87F16FF
+ BB8219FFB87E17FFB57A16FFB37B16FFB57C19FFB57E1BFFB47D1CFFB47A1AFF
+ BB7D1FFFBB7D1FFFBA7C1EFFB97C1EFFBA7D1FFFB97F20FFB68022FFB58025FF
+ B07B21FFAE7922FFAB7926FFAD7D2BFFB28131FFB58537FFB5843AFFB2823AFF
+ B37F3CFFB17D3BFFB07C3AFFB17F3DFFB78445FFBA894BFFBA8B4EFFB98C4FFF
+ BC8E54FFB88B52FFB58953FFB68A54FFB58B56FFB88E59FFBE9661FFC79F6EFF
+ D6B388FFD3B38AFFD4B38CFFD6B58EFFDAB992FFDBBC95FFDCBC98FFD9BC97FF
+ E4C6A3FFEACEABFFF1D5B3FFEED3B1FFE8CCADFFE8CCADFFF1D5B6FFF5DEC4FF
+ F2E2D1FFEEE2D6FFEFE3D7FFF2E6DAFFF5E9DDFFF8ECE0FFF9EFE5FFFBF1E7FF
+ EFE5DBFFF0E7DEFFF2E9E0FFF3EAE1FFF2EBE2FFF3ECE3FFF5EDE6FFF7F0E7FF
+ FAF5ECFFFCF5ECFFFFF6EDFFFFF5EEFFFEF5F1FFFBF4F1FFF9F3F4FFF5F3F3FF
+ F8F6F5FFF7F6F2FFFBFBF5FFFDFCF8FFF6F4F4FFF1F1F7FFF0F1FFFFEDF0FEFF
+ EEF4F9FFF3F8F9FFF8FAFAFFFAF8F8FFF9F3F4FFF6EFF2FFF6F0F5FFF7F3F9FF
+ F8F6FCFFF3F3F9FFF1F2F6FFF0EFF3FFF0ECF1FFF7F3F8FFF9F5FAFFF4EFF1FF
+ F3EEEFFFF5EFF0FFF8F0F1FFF7EFEFFFF3EBEBFFF4EBE8FFF5ECE8FFF8EDE9FF
+ FDF1EBFFFAEDE5FFF5E9DFFFF8E9E0FFFFEFE3FFFFEFE3FFF9E9DDFFF3E2D5FF
+ F1DECFFFF0DBCCFFEFD8C8FFEDD7C5FFF0D8C6FFEFD7C1FFE6CAB2FFDBBEA3FF
+ D3B697FFD1B291FFD1AF8BFFD1AD87FFCEAA82FFC8A57AFFC29C72FFBF986BFF
+ BE9661FFBF975DFFBD955AFFB99051FFB48A49FFB28843FFB48A43FFB78E45FF
+ AD813AFFA87E37FFA87E39FF3D24C2FF3B25C1FF3B26BEFF3B28BFFF3A26C5FF
+ 3A26C5FF3D29C2FF3D2AC1FF3D26BEFF3525A8FF323089FF343E7AFF354679FF
+ 32477AFF354983FF354D8FFF375499FF36569DFF3B5DA3FF3F64A8FF456AAEFF
+ 466EAFFF456FB2FF446EB1FF456FB2FF466FB4FF4970B5FF486EB6FF4868B3FF
+ 4262AEFF3D5BA8FF3957A6FF3B59A8FF3855A6FF3253A3FF3454A0FF345398FF
+ 334C8AFF314275FF2F3863FF2A2D53FF2C2C50FF312F53FF353559FF3A3B5DFF
+ 3B3D5BFF3A3B55FF3C3B4FFF3F3B47FF403549FF302049FF251545FF261B49FF
+ 261A4EFF241356FF27155AFF2E1F5DFF2A1958FF2A135DFF341552FF542D46FF
+ 895A3EFFB37D1EFFBE8403FFC28003FFC17E04FFC3800DFFBA7A04FFBF8406FF
+ AF7F19FF6A491BFF331D12FF2A161BFF20131BFF19181AFF1C1E1FFF281D27FF
+ 271A28FF211E2EFF232333FF2E2B3BFF2D2A3AFF2B2837FF292635FF282632FF
+ 272630FF26252FFF25242DFF26252EFF25242DFF24232DFF24222EFF242130FF
+ 252231FF262333FF282233FF292034FF271F30FF26222DFF26232CFF272027FF
+ 271D23FF32242AFF4E331FFF91601CFFB67917FFB57A0CFFBA7D07FFC28107FF
+ BE7E02FFC08109FFBD8008FFBE800AFFBE800AFFBE7F0CFFBE800AFFBE7F0CFF
+ BE800AFFBE7F0CFFBE800AFFC1820FFFC0820CFFBE7F0CFFBD7F09FFBE7F0CFF
+ C0820CFFC38411FFC48713FFC78C18FFC38A16FFC28713FFBD8410FFBD810FFF
+ BA810EFFBA810EFFBA810EFFBA810EFFBA810EFFBA810EFFBB820FFFBC8310FF
+ BF8613FFC18716FFC48817FFC48418FFC48317FFC28216FFC18214FFC18214FF
+ C08315FFC18416FFBF8417FFBD8215FFBE841AFFBC831AFFB77D16FFB67B17FF
+ B9801DFFBA8020FFB67C1CFFC08323FFBF8123FFBD7F21FFBB7E20FFBA7D1FFF
+ B87D20FFB97D23FFB77D24FFBE862DFFBB822CFFB67F2AFFB47D28FFB47E2BFF
+ B7812EFFB98532FFBB8838FFB18139FFAF803CFFB0803EFFB38341FFB58543FF
+ B68946FFB78949FFB58949FFB58949FFBA8F50FFBD9253FFB88F51FFB28649FF
+ AF8648FFB68D4FFFB9935DFFBEA175FFBCA27DFFC1A582FFC6AC88FFCDB18EFF
+ D1B793FFD4B997FFD4BB99FFD3BA9AFFD5BD9FFFDCC2A4FFDDC5A9FFDFC7ABFF
+ E0CAAEFFE7CEB4FFE8D3B8FFF3E0C5FFF1E3C7FFF3E3CCFFF5E4CFFFF4E4D3FF
+ F3E4D4FFF3E4D4FFF0E4D2FFF8EEDCFFFFF9E6FFFFFFEFFFFFFDF2FFF6F2F1FF
+ EFEFF5FFEFEFFFFFEDF0FFFFF1F4FCFFF6F7FBFFFAF7F9FFFAF5F6FFF7F2F4FF
+ F6F0F5FFF5F0F9FFF5F1FCFFF4F0FBFFF5F2FBFFF8F4F9FFF9F4F6FFFAF5F7FF
+ FFFAFCFFFBF7FCFFF2F1F5FFF3F1F7FFF3F1F7FFF4F2F8FFF5F3F9FFF6F4FAFF
+ F7F6FAFFFAF6FBFFFAF6FBFFF9F5FAFFF8F5F7FFFAF5F7FFFCF7F9FFFFFAFCFF
+ FFFAFBFFFCF7F9FFFAF3F6FFF4EDF0FFF4EBEEFFF2E9ECFFF5EAECFFF9EDEDFF
+ F9ECEAFFF4E5E2FFEFDFD8FFFBEAE1FFF5E4D7FFF2DFD0FFF3DFCEFFF2DCCAFF
+ EBD6C1FFE6CEBAFFE4CCB4FFEAD2B4FFECD3B3FFEACFADFFE0C6A2FFD5BA95FF
+ D1B48DFFD4B68DFFD7BA8EFFCBAD84FFC6AA81FFC6A982FF3B23BFFF3924BDFF
+ 3925BAFF3926BDFF3723C2FF3722C4FF3A25C1FF3A26BFFF3A22BCFF3423A8FF
+ 312F88FF323C78FF344578FF334979FF374B84FF364F8FFF38549BFF3757A0FF
+ 3C5DA6FF4165ABFF466AB0FF486FB3FF4770B5FF4770B5FF466FB4FF456EB3FF
+ 466CB4FF4368B2FF4363AFFF3E5DACFF3B59A8FF3856A5FF3853A3FF3452A1FF
+ 31509FFF31509BFF335093FF314985FF2E3D6EFF2D345FFF282B51FF2D2D51FF
+ 313057FF36365AFF3A3A5EFF3B3D5CFF3B3C58FF3C3A50FF403B4AFF3E3248FF
+ 301D48FF251348FF271B4DFF26194FFF231353FF25165AFF241755FF24145BFF
+ 27116AFF311765FF4A2850FF7B513EFFAF7B1DFFBE8200FFC08003FFC17E04FF
+ C3800DFFBA7A04FFBF8308FFB07E1AFF6D4919FF381D0FFF2E181DFF22141FFF
+ 19181CFF1E1D21FF251C26FF241A27FF201D2CFF222232FF2B2838FF2B2838FF
+ 2B2837FF2A2736FF292733FF272630FF272630FF272630FF26252FFF25242EFF
+ 25232FFF24222EFF242130FF252231FF262333FF292334FF292034FF271F30FF
+ 26222DFF26232CFF261F26FF271D23FF302228FF4D321EFF8F5E1AFFB57816FF
+ B57A0CFFBA7D07FFC28107FFBD7D01FFBF8008FFBC7F07FFBD8008FFBD8008FF
+ BD7F09FFBD8008FFBD7F09FFBD8008FFBD7F09FFBD8008FFC1830DFFBF820AFF
+ BD7F09FFBC7F07FFBD7F09FFBF820AFFC2840EFFC48610FFC88B15FFC48A13FF
+ C38610FFBF850EFFBF830BFFBF830BFFBF830BFFBF830BFFBD8207FFBE8308FF
+ BF8307FFBE8206FFBD8204FFBE8305FFC08507FFC2860BFFC1820FFFC0810FFF
+ BF800EFFBE7F0CFFBE800AFFBE800AFFBF810BFFBF820AFFC2850DFFC68A12FF
+ C58812FFBD800CFFBB7E0AFFC18311FFC48515FFC08210FFBD800CFFBD800CFF
+ BE810DFFBD800CFFBD800CFFBB7F0DFFBD8110FFBD8214FFBE8617FFBD8417FF
+ BA8215FFB98116FFB78017FFB98219FFB68218FFB58018FFB57B1BFFB77A1CFF
+ B87B1DFFB77D1EFFB87E1FFFB87E1FFFB97E21FFB87F22FFB98023FFB78025FF
+ B67F24FFB27D23FFB27A21FFAF7A20FFB07B21FFB17B26FFAE7D2FFFAC7E31FF
+ B07F35FFAF8036FFB28038FFB18139FFB2813BFFB0813DFFAE7E3CFFB08340FF
+ B68646FFB7884AFFB98A4DFFB98C4FFFC09154FFBF955AFFCCA76FFFC7A772FF
+ C7A97AFFC8AB7FFFC8AC83FFC9AD84FFCBAD84FFC9AE82FFD9C094FFE4CEA5FF
+ E8D3B3FFE3D3BCFFE4DAD0FFEEE8E9FFF0EFF9FFEEEEFCFFF1F0FAFFF4F2F8FF
+ F8F3F5FFF7F2F3FFF6F1F3FFF5EFF4FFF3F0F9FFF5F1FCFFF4EEF9FFF5EDF4FF
+ F3E7E7FFF0E4E0FFF7EBE7FFFFF5F1FFFFF8F5FFFBF6F5FFFBF6F7FFF8F5F7FF
+ F8F5F7FFF9F6F8FFFBF8FAFFFCF8FDFFFAF9FDFFF9F8FCFFF8F7FBFFF7F5FBFF
+ F3F3F9FFF2F2F8FFF1F1F7FFF0F0F6FFEFEEF7FFEEEDF6FFF4F3FCFFF3F3F9FF
+ F3F3F9FFF5F4F8FFF4F3F7FFF4F1F3FFF3F1F1FFF6F1F2FFF5F1F0FFF3EEEBFF
+ F3EDE8FFF3EDE6FFF6EFE6FFF4EDE4FFF4EBE2FFF2E9E0FFF6ECE5FFF8EEE7FF
+ F7EBE5FFF1E6DEFFEADDD5FFE7DBD1FFECDDD4FFF0E2D6FFEEDFD6FFEADBD2FF
+ EADBD2FF371FB9FF3520B9FF3521B6FF3420B9FF321DBFFF321DC0FF341EBDFF
+ 341FBCFF3B22C0FF3625ACFF32308AFF313A79FF334477FF344A7AFF384C85FF
+ 354E8EFF37539AFF3756A1FF3D5DA8FF4164ADFF4669B2FF486FB4FF4972B7FF
+ 4B74B9FF4B74B9FF4971B9FF466BB5FF4064B0FF3E5DACFF3957A8FF3653A4FF
+ 3451A2FF334E9EFF324E9BFF304E9BFF314E98FF324C8EFF2F457FFF2B3969FF
+ 29305BFF282A52FF302F56FF35345BFF36375DFF393A60FF3B3D5FFF3A3C5AFF
+ 3B394FFF413C4BFF3D3147FF2E1A47FF271249FF281A50FF231751FF201252FF
+ 241658FF231557FF2A1C6AFF38238AFF462E8DFF55356BFF795249FFB27E24FF
+ BF8202FFC08003FFC17E03FFC3800BFFBA7906FFBF820AFFB27E1AFF724A16FF
+ 3C1E0DFF311A1EFF231521FF1C181EFF1D1C20FF241B25FF231925FF1F1D29FF
+ 222230FF272434FF292636FF2B2837FF2B2837FF292733FF282632FF282632FF
+ 292832FF262430FF262430FF262430FF25232FFF23202FFF23202FFF252232FF
+ 292334FF292034FF271F30FF25212CFF26232CFF261F26FF261C22FF302228FF
+ 4C311DFF8D5C18FFB57816FFB67B0DFFBB7E08FFC18006FFBC7C00FFBE7F07FF
+ BC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFC0830BFFBF820AFFBD8008FFBC7F07FFBD8008FFBE8109FFC0830BFF
+ C1840CFFC1840CFFBF830BFFBF820AFFBD8109FFBD8106FFBD8106FFBD8106FF
+ BD8105FFBC8004FFBC8103FFBE8103FFBD8000FFBD8000FFBE8200FFC28303FF
+ C18406FFC48610FFC28412FFC18311FFC0830FFFC0830DFFC0840CFFC2860BFF
+ C3870CFFBE8206FFC3870BFFC2860BFFBF8006FFBF8008FFC4850DFFC88510FF
+ C4850DFFC18307FFC28507FFC28408FFC38509FFC38509FFC2860BFFC4880DFF
+ C48810FFBE810BFFBF850EFFC18612FFBF8612FFC08714FFBF8815FFBE8714FF
+ BC8310FFC18212FFC38215FFC48316FFC38215FFC18214FFC08113FFC18214FF
+ C38416FFC38519FFC08216FFBF8115FFBE8316FFC3851BFFC2861CFFC2841AFF
+ BD8018FFBE831CFFBC811DFFBC801CFFBA7F1CFFB97E1BFFB97D1DFFB97C1EFF
+ B77C1FFFB87D20FFB87F24FFBB7F26FFBA7F29FFBA7E2AFFB87F2AFFBC802CFF
+ B9812FFFB07D2DFFAD7E34FFAB7F38FFAC813EFFAD8342FFAF8544FFB18643FF
+ B18643FFB2894AFFB08D55FFAC8F62FFB7A080FFD5C6B6FFF1E5E3FFF7EFF6FF
+ F4EEF9FFF3EEF7FFF4F0F6FFF6F1F3FFF7F1F2FFF6F1F3FFF3EFF4FFF1EEF7FF
+ F4EFF8FFFCF2F8FFF3E3E4FFDBC6BEFFCEB5A5FFD7BEAAFFE6CEBAFFE9D8C5FF
+ ECDECCFFEADACDFFEADDCFFFEDE0D2FFEFE4D6FFF4E8DCFFF6ECE2FFF9EFE5FF
+ FAF1E8FFFEF5ECFFFBF3ECFFFAF2EBFFF7F1ECFFF8F2EDFFFAF3F0FFFCF5F2FF
+ FBF6F3FFF9F4F3FFF8F2F3FFF9F4F3FFF9F4F3FFF5F0EFFFEFEAE9FFEFEAE9FF
+ F3EEEBFFF2EDEAFFF7F2EFFFF8F3F0FFF4F0EBFFF4F0EBFFF7F3EEFFF7F3EEFF
+ F3EEEBFFF3EEEFFFF5F0F2FFF6F1F3FFF3EEF0FFF0E9ECFFEFE8EBFFF4EBEEFF
+ F7EEF1FFF9F0F3FFF5ECEFFFF3ECEFFF3820BCFF3621BAFF3621B9FF3520BCFF
+ 331DC3FF331CC4FF351DC1FF351EC0FF3F24C7FF3A27B2FF353190FF31397CFF
+ 314176FF33487BFF364A84FF324A8CFF344F99FF3654A1FF3C5CA8FF3F62ACFF
+ 4366B0FF466CB4FF4A72BAFF4F77BFFF4A72BAFF486FB9FF466AB6FF4064B2FF
+ 3E5DACFF3856A7FF3551A5FF344EA2FF304999FF324C99FF334D99FF324E95FF
+ 314A8AFF2D4079FF2A3666FF292F5AFF2B2B53FF33325AFF373660FF363861FF
+ 383A62FF3C3E61FF3A3C5AFF3B394FFF423D4CFF3C3046FF2C1847FF27114CFF
+ 281953FF231753FF1F1151FF221559FF25175EFF35257CFF4733AAFF5840B0FF
+ 5A3B7EFF765050FFB17D2AFFC18307FFC08003FFC17E03FFC3800BFFBA7906FF
+ BF820AFFB67D1AFF784B12FF411F08FF351D1FFF241622FF1C181EFF1F1B21FF
+ 231A24FF231925FF1F1E28FF22222EFF262332FF292636FF2B2837FF2B2837FF
+ 292635FF282534FF282534FF292733FF272433FF282534FF282534FF262332FF
+ 23202FFF221F2EFF242131FF282233FF292034FF282031FF25212CFF25222BFF
+ 251E25FF251B21FF2F2127FF4B301CFF8C5B17FFB57816FFB77C0EFFBC7F09FF
+ C28107FFBC7C00FFBE7F07FFBC7F07FFBD8106FFBD8106FFBD8106FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBF8308FFBE8207FFBE8207FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBC8005FFBC8005FFBF8006FFBD8106FF
+ BF8006FFBE7F05FFBE7F05FFBD7E04FFC08107FFBF8006FFBE7F05FFBF8006FF
+ C18208FFC38509FFC4850BFFC3860EFFBE8211FFBB8012FFBA7F11FFBA800FFF
+ BC800EFFBD820EFFBE840DFFBE840DFFBD8109FFBE820AFFBD8109FFBD8008FF
+ BF810BFFC2840EFFC48310FFC3820FFFC4850DFFC5830CFFC4820BFFC2830BFF
+ C3830DFFC0820CFFBF810BFFBD800AFFB77A06FFBD800CFFC18311FFBD810FFF
+ BE8211FFBE8413FFBD8312FFBB7F0EFFBE800EFFC0810EFFC28310FFC1820FFF
+ BF800DFFBE7F0CFFBF820EFFC0830FFFC18311FFC18311FFC18311FFC28614FF
+ C78818FFC58918FFC48515FFBF8312FFC18311FFBE8210FFC08210FFBE8211FF
+ BF8312FFC18416FFC38618FFC3881BFFC4881EFFC1871EFFC1841CFFBF841DFF
+ BF831FFFBE831FFFBE821EFFBD811DFFBF8220FFC08323FFBE8326FFBE852AFF
+ BE872CFFC38A2FFFC58C2FFFC48C33FFB98433FFAA7E37FFA6824CFFC2A782FF
+ EFDCC7FFFFF5EEFFFFF6F8FFFFF7FDFFF8F0F7FFF7F1F6FFF9F2F5FFF8F3F4FF
+ F6F3F5FFF2F1F5FFF0EEF4FFF2ECF1FFFCEFEDFFEDD7CBFFCCAA92FFB38D6AFF
+ B99167FFC49D70FFC3A274FFC5A679FFC1A176FFC5A57CFFC8AA81FFCEB087FF
+ D4B58EFFD8BB94FFDDC09BFFDFC3A0FFE3C9A5FFE1C8A6FFE3CAA8FFE4CDADFF
+ E9D2B2FFECD7B8FFEFDABBFFF1DAC0FFF1D8C4FFEED4C3FFEFD5C5FFF3DACAFF
+ F2D9C9FFE9D2C3FFE2CDBEFFE0CDC0FFEEDDD0FFFBEBDFFFFEEFE6FFF8E9E0FF
+ F5E8E0FFFDF2EAFFFFF5EDFFF9F0E7FFF7EFE8FFF8F0E9FFFAF1EDFFFAF1EDFF
+ FCF0EEFFFBEFEFFFFBEFEFFFFBEEF0FFFCEFF1FFF9EDEDFFF9EDEDFF3E25C3FF
+ 3C26C2FF3C27C0FF3A25C2FF3821C9FF3820CCFF3A21C9FF3A22C8FF4327CEFF
+ 3E2AB9FF373295FF32397EFF313F79FF32477BFF344784FF2F468AFF324D97FF
+ 34529FFF3B5BA7FF3E60ACFF4063ADFF4368B2FF4A72BAFF5179C1FF456CB6FF
+ 446BB6FF4468B6FF4064B2FF405EAFFF3A58ABFF3752A8FF3650A4FF2D4696FF
+ 324A96FF354E98FF344D93FF314886FF2D3E76FF2A3463FF2A2E57FF2C2B55FF
+ 34335DFF373864FF353864FF383A63FF3A3D63FF3A3C5BFF3A3750FF423D4CFF
+ 3B2F45FF2B1746FF25104EFF281956FF231654FF1C1052FF22145BFF22155FFF
+ 342482FF4832B3FF553CB6FF50327BFF6A4148FFA97326FFBC7D05FFC08004FF
+ C17E03FFC3800BFFBA7A04FFC1810BFFB87D19FF7D4D0DFF472103FF371E1CFF
+ 251722FF1E1620FF1F1B21FF231A24FF221824FF201C27FF22222EFF262332FF
+ 292636FF2C2938FF2C2938FF292635FF272433FF282534FF292635FF272433FF
+ 292635FF292635FF262332FF221F2EFF211E2DFF232030FF272132FF292034FF
+ 282031FF25212CFF25222BFF251E25FF251B21FF2E2026FF4A2F1BFF8C5B17FF
+ B57816FFB87D0FFFBD800AFFC28107FFBC7C00FFBE7F07FFBD8008FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBE8207FF
+ BE8207FFBE8207FFBE8207FFBE8207FFBD8106FFBC8005FFBB7F04FFBE7F05FF
+ BF8006FFC38208FFC18208FFC1820AFFC08109FFBF8008FFBD7D07FFC68610FF
+ C1830DFFBE800AFFBE800AFFBF810BFFC0820CFFBF810BFFBC7E0CFFBD8012FF
+ BA7F11FFBA7F11FFBA800FFFBC800EFFBD810FFFBE830FFFBF850EFFBD800AFF
+ BA7D07FFB97C06FFBC7E08FFBE7F0CFFBF800DFFBD7E0CFFBE7D0AFFBE7D0AFF
+ BF7C07FFBE7B06FFBF7C07FFC07F0CFFC1800DFFBD7E0BFFBB7C09FFB97A08FF
+ BF810FFFC38414FFBF8010FFBD7E0EFFBD8110FFBE8113FFBA7E0DFFBF810FFF
+ C18410FFC38612FFC38612FFC18410FFC0830FFFC08511FFC28713FFBC810DFF
+ BE830FFFC18612FFC38814FFC28614FFBF8410FFBD810FFFBD800CFFC18410FF
+ BF820CFFBE810BFFBC820BFFBE830FFFC18612FFC58917FFC58C19FFC18716FF
+ BF8514FFBD8214FFBC8415FFBE8518FFBF8619FFBD8417FFBC8114FFC18013FF
+ C37F14FFC07F16FFC18017FFC4831AFFC7871BFFCA8920FFC68A26FFC48E37FF
+ B2853CFFB2905BFFD9C09EFFFFF1E0FFFFF7F1FFF8ECECFFFBF0F3FFFDF3F9FF
+ FBF4F9FFFCF6F7FFFBF6F7FFF5F4F6FFF2F1F3FFEEEDEFFFF2EAEAFFF7E5DAFF
+ EACFB5FFCAA278FFB2834DFFB88546FFBC8943FFB1833CFFAC8039FFAA7B37FF
+ AD7E3AFFAF823EFFB18440FFB18441FFB18545FFB58949FFB78C4DFFB48B4DFF
+ B58C4EFFB48D4FFFB99156FFBC975BFFBF9A5EFFC09A60FFBF9861FFC09766FF
+ BA9061FFBC9265FFC69D70FFC9A276FFC19C70FFB49267FFAD8D64FFC2A580FF
+ D6BA97FFE2C7A5FFDBC2A2FFDEC6A8FFEED9BAFFF6E2C3FFF0DBBFFFF0DEC1FF
+ EFDEC3FFF5E2C7FFF8E4CBFFFCE7D1FFFDE8D3FFFDE6D6FFFCE5D5FFFEE7D7FF
+ FBE5D3FFFBE5D3FF492FCFFF462ECEFF442DCBFF412ACCFF3F27D3FF4027D5FF
+ 442AD4FF452CD4FF492CD5FF442EC2FF3C359DFF343A83FF2F3D78FF2E417AFF
+ 324485FF30468DFF2E4894FF3351A0FF3A5AA6FF3B5DA9FF4063ADFF476CB6FF
+ 4B72BCFF4C73BDFF436AB5FF4067B2FF3D61AFFF395DABFF3B59AAFF3755A8FF
+ 334EA4FF314B9FFF2F4694FF324995FF344C94FF354C90FF354885FF313F74FF
+ 2D3564FF2A2E57FF2C2B55FF34335DFF393C69FF3A3F6CFF393C68FF343960FF
+ 363958FF3C3C54FF433C4BFF382B43FF2C194AFF261451FF241454FF1F1355FF
+ 201357FF20145CFF1D1060FF3D2D92FF4833B8FF4C30ACFF4D2D74FF6F464BFF
+ B0762EFFBA7906FFC28107FFC18006FFBF7D06FFC1810BFFBE7E08FFB87D16FF
+ 9E6821FF5A2F08FF3C221BFF24171FFF1E171EFF201920FF201721FF261D27FF
+ 25212CFF1D1B27FF262332FF282534FF2A2737FF2A2737FF282535FF262333FF
+ 262333FF282535FF262333FF262333FF262333FF252232FF252232FF252232FF
+ 252231FF272132FF271E32FF292132FF24202BFF232029FF282128FF261C22FF
+ 2D1F25FF4D321EFF8F5E1AFFB77A18FFB67B0DFFB97C06FFC38208FFC28206FF
+ C1820AFFB67901FFBD8106FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBF8006FFC18006FFC17F08FFC37F08FFC17F08FFC17E09FFC17E09FF
+ BF7F09FFBF7E0BFFBD7E0BFFBC7F0BFFBD7F0DFFBD7F0DFFBC800FFFBC800FFF
+ BC800FFFBD8110FFC08111FFC0810FFFBF800EFFBE7F0CFFBE800AFFBF810BFF
+ C1840CFFC2850DFFBD8008FFBD8008FFBE8109FFC0800AFFC1800DFFC1800DFF
+ C2800FFFC2810EFFC1800DFFC1810BFFC1810BFFC1810BFFC1800DFFC1800DFF
+ C1800DFFBF800DFFC0810EFFBF800DFFBE7F0DFFBD7E0CFFBD7E0CFFBD7F0DFF
+ BE7F0FFFBD8110FFBB8110FFB98110FFBB8110FFBB8110FFBB820FFFBB820FFF
+ BB820FFFBB820FFFB9800DFFB9800DFFBA810EFFBA810EFFBB8110FFBC8310FF
+ BC8211FFBC8211FFBC8211FFB98110FFB98110FFB8800FFFB98110FFB98311FF
+ BA8412FFBB8513FFB88112FFB68112FFB68112FFB68112FFB68112FFB48212FF
+ B48212FFB88112FFC08315FFC78619FFC18013FFBC7B0EFFC2800FFFC38313FF
+ C38317FFC38727FFBD8C3CFFAC8749FFCCB28DFFF9EAD7FFFFF5EEFFF6F0F1FF
+ F9F2F5FFF5EEF1FFFCF3F6FFF3EDEEFFF6F1F2FFF9F7F6FFF0F2F2FFEEF0F0FF
+ F2F0EFFFF6EDE4FFE9D4BFFFC4A27EFFB78A51FFC28C45FFC18735FFC1852BFF
+ C08A2CFFB98324FFBA8124FFBD8225FFBE8326FFBD8427FFBD8429FFBC8328FF
+ BB8227FFB88126FFB88027FFB68127FFB58026FFB57F28FFB57F28FFB37E27FF
+ B37D28FFB37E27FFB27D23FFB27D22FFB27D23FFB27E24FFAF7F27FFAD7E28FF
+ AD7F2BFFAB7F2CFFA87F30FFA88234FFAA863AFFAE8B41FFB29148FFB7974EFF
+ B99B54FFBB9C57FFBF9C5CFFC3A061FFCAA569FFD1AB71FFD5AE77FFD6AE79FF
+ D4AC7BFFD3AB7AFFCDA574FFCDA672FFCEA672FF3E23C7FF3C24C6FF3D25C5FF
+ 3C24C8FF3A21CFFF3A20D1FF3C22CEFF3C22CCFF482BD5FF402ABEFF362F97FF
+ 2E337EFF2C3977FF2E407BFF354689FF344A92FF2F4996FF3351A0FF3959A5FF
+ 3A5CA8FF3F62ACFF456AB4FF486FB9FF486FB9FF3F66B1FF3C63AEFF395DABFF
+ 365AA8FF3755A8FF3452A5FF304BA1FF2F499DFF2F4694FF344994FF354B93FF
+ 364C8EFF344681FF303D71FF2D3360FF2B2D56FF2D2C56FF333460FF373B6BFF
+ 3A3E6EFF373C69FF343861FF36385AFF3C3B55FF433B4CFF382B43FF2A1A4AFF
+ 241352FF221454FF1F1355FF201357FF21145EFF1E0F63FF3A2990FF4931B7FF
+ 492BA2FF4F2D6AFF7A4D4AFFB2742DFFBD7908FFC3810AFFC18006FFBE7C05FF
+ C0800AFFBD7C09FFBC7F17FFAD7524FF714411FF3D2315FF22171AFF1E171CFF
+ 1F181FFF211822FF261D27FF24202BFF1C1B25FF252231FF282534FF2A2737FF
+ 2A2737FF282535FF262333FF272434FF282535FF262235FF262333FF262333FF
+ 262333FF252232FF252232FF252231FF262130FF261D31FF292132FF24202BFF
+ 221F28FF282128FF261C22FF2D1F25FF4D321EFF905F1BFFB97C1AFFB87D0FFF
+ BB7E08FFC38208FFC18105FFC08109FFB87C01FFBD8106FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBF8006FFC17F08FFC37F08FFC37E09FF
+ C37E09FFC17E09FFC17E09FFBF7E0BFFBD7E0BFFBC7F0BFFBA7E0CFFBB7F0DFF
+ B9800DFFBA800FFFB8800FFFBA7F11FFBC800FFFC38411FFC3830DFFC2830BFF
+ C1820AFFC08109FFC08107FFC18208FFC18208FFBF8006FFBF8006FFC08109FF
+ BE8109FFBF810BFFBF800DFFC0810FFFC0810EFFBF810BFFBF820AFFBF810BFF
+ BF810BFFBF810BFFBF810BFFBF810BFFBF810BFFBF820CFFBE810BFFBD800CFF
+ BC7F0BFFBC7F0BFFBD800CFFBC810DFFBD810FFFB98110FFB98110FFB98112FF
+ BB8110FFBB8110FFBB820FFFBB8110FFBB820FFFBA810EFFBA810EFFBA810EFF
+ BA810EFFBB820FFFBB820FFFBD810FFFBD810FFFBB8110FFBA800FFFBA800FFF
+ BA800FFFBA800FFFB98110FFBB8312FFBB8411FFB98110FFB8820FFFB8820FFF
+ B8820FFFB8820FFFB6830FFFB6830FFFB88210FFBD8214FFC58618FFC18111FF
+ BE7F0DFFC58411FFC38313FFBE8119FFB98429FFB28843FFB99B6AFFDBCAB0FF
+ F6EFE6FFF6F3F5FFF3F1F7FFF6F2F7FFF1ECEEFFF7F1F2FFF5F0EFFFF6F4F3FF
+ F6F7F5FFF2F4F4FFF7F8F4FFF7F5EDFFF2E8D6FFD8C1A1FFBD9969FFB98844FF
+ C28A38FFC48727FFC58820FFC78C1FFFBF8417FFC08216FFC38317FFC48418FF
+ C58519FFC38519FFC28418FFC18319FFC08218FFC08218FFC08218FFC08218FF
+ BF8117FFBF8117FFBE8016FFBC7F17FFBC8016FFC08113FFC08111FFBE8211FF
+ BD8214FFBC8415FFBB8316FFBB8318FFB8841AFFB48218FFB18118FFB0801AFF
+ AE801BFFAB7E1CFFA97F1CFFA87E1BFFA87D1CFFA5761AFFA9771DFFAD7B23FF
+ AF7C26FFB07B2AFFAD7A2AFFAB772AFFA87729FFAC782BFFAC782BFFAC7929FF
+ 3F23CAFF3F25CCFF4028CAFF4028CEFF3E25D3FF3C22D3FF3B21CBFF3920C8FF
+ 4427D0FF3C26BAFF332C94FF2D327DFF2D3979FF30427FFF36468BFF334893FF
+ 304A97FF3351A0FF3858A4FF385AA6FF3D60AAFF4267B1FF446BB5FF446BB5FF
+ 3C63ADFF385FAAFF365AA8FF3357A5FF3452A5FF314FA2FF2E499FFF2D479BFF
+ 304694FF354891FF364A91FF37498AFF35437DFF2F3A6CFF2D335EFF2B2D56FF
+ 302F59FF343462FF373B6CFF383D6EFF353B6AFF323863FF36385BFF3C3B55FF
+ 423A4BFF382B45FF271949FF211452FF221454FF1F1355FF221357FF231360FF
+ 1E1167FF36268BFF4A32AEFF45268FFF552F59FF875745FFB47426FFBF7A0BFF
+ C27F0AFFC28107FFBC7D05FFBF8008FFBD7D07FFC18115FFBC8026FF8C5D1FFF
+ 3E2711FF211717FF1C1518FF20181FFF211822FF251D27FF251F2AFF1E1A25FF
+ 242130FF272433FF292636FF292636FF272336FF262235FF272336FF282437FF
+ 272237FF272336FF272336FF262235FF262333FF252232FF252231FF262130FF
+ 261D31FF292132FF24202BFF221F28FF282128FF261C22FF2D1F25FF4E331FFF
+ 92611DFFBC7F1DFFBC8113FFBD800AFFC28107FFBF7F03FFC08109FFBA7E03FF
+ BD8106FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBF8006FF
+ C37F08FFC47E09FFC37E09FFC37E09FFC17E09FFC17E09FFBF7F09FFBD7F09FF
+ BC7F09FFBA7F0BFFBA7F0BFFB9800CFFB7810CFFB7820DFFB8820DFFBA820BFF
+ C3860EFFC6850BFFC5840AFFC38307FFC08206FFBF8105FFBF8105FFBF8105FF
+ BD8105FFBD8105FFBE8207FFBD8109FFBE810BFFBE810DFFBF810FFFBD820EFF
+ BC830AFFBA8408FFBA830AFFBA830AFFBA830AFFBA830AFFBA830AFFBA830AFF
+ BA830AFFBA830AFFB98209FFB98209FFB98209FFB98209FFBA830AFFBA820BFF
+ BB820FFFBB820FFFBB8110FFBD810FFFBD810FFFBD820EFFBD810FFFBD820EFF
+ BF820EFFBF820EFFC0810EFFBF800DFFBF810BFFBF810BFFBF810BFFBF810BFF
+ C1810BFFC27F0AFFC27F0AFFBF7F09FFC0800AFFC1810BFFC2820CFFC1840CFF
+ C0820CFFC0830BFFC0830BFFBF830BFFBF830BFFBF830BFFBF8409FFBD830CFF
+ BE8211FFC18416FFC08210FFC28310FFC68715FFBF8115FFB67C1CFFB08032FF
+ B18E56FFD1BB98FFF0E7DAFFF5F5F5FFF0F2FAFFF0F2FCFFF1F1F7FFEEEBEDFF
+ F6F2F1FFF7F4F0FFF5F6F4FFF1F3F3FFF2F5F3FFFBFBF5FFF2EDDEFFDED0B4FF
+ BFA478FFB28D51FFB58438FFBE862DFFBF8420FFC3881BFFC68A19FFBD810FFF
+ BF810FFFBF810FFFC08210FFC18311FFC18311FFC08210FFBF8010FFBF8010FF
+ BF8010FFBF8010FFBF810FFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBD7F0DFF
+ C2800FFFC2800FFFC0810FFFC08010FFC08111FFC08111FFC08111FFBF8312FF
+ BF8514FFBE8413FFBD8214FFBA8213FFB88011FFB67F10FFB57E0FFFB47D0EFF
+ B88011FFBA7F12FFB97F15FFB97F16FFB87D16FFB67B17FFB47915FFB17815FF
+ B97E1BFFB97E1AFFB97E1AFF4528D1FF442AD1FF452DCFFF442CD0FF4129D5FF
+ 3E25D3FF3E25CDFF3C24CAFF4327CEFF3D28BAFF363095FF323881FF323F7DFF
+ 324481FF334388FF2D428DFF314B98FF34529FFF3757A3FF375AA4FF3B5EA8FF
+ 4166B0FF4168B2FF4067B1FF3C63ADFF3960AAFF365AA6FF3357A5FF3553A4FF
+ 3250A3FF2F4AA0FF30489AFF314592FF364790FF36498DFF354685FF334078FF
+ 2F3969FF2E315DFF2D2F57FF34335DFF343764FF363B6CFF353C6EFF353A6BFF
+ 323863FF36385BFF3B3956FF43384CFF372A44FF241A49FF1F1551FF201553FF
+ 201554FF231458FF24155FFF201369FF332283FF4A319FFF472579FF5F3848FF
+ 97643CFFB5741FFFC27C0BFFC07D08FFC17F08FFBC7D05FFBF8008FFBD7D07FF
+ C08010FFC48622FF9E6E26FF422C10FF211814FF1D1516FF20191EFF211920FF
+ 241C26FF241E29FF1D1924FF23202FFF262332FF282535FF292636FF272336FF
+ 262235FF272237FF282338FF282338FF282338FF272237FF272336FF262333FF
+ 252232FF242130FF262130FF251C30FF282031FF231F2AFF221F28FF282128FF
+ 271D23FF2E2026FF4F3420FF93621EFFBE811FFFBF8416FFBE810BFFC28107FF
+ BE7E02FFC1820AFFBC7F07FFBD8106FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FFBD8105FF
+ BD8105FFBD8105FFBF8006FFC37F08FFC37E09FFC37E09FFC37E09FFC17E09FF
+ C17E09FFBF7F09FFBD8008FFBB7F07FFB98007FFBA8108FFB88108FFB78209FF
+ B78209FFB8830AFFBA830AFFC2860BFFC3840AFFC28309FFC18307FFBE8206FF
+ BD8105FFBD8105FFBD8105FFBD8105FFBC8106FFBD8207FFBB8209FFBC820BFF
+ BC810DFFBD810FFFBB820EFFBA820BFFBA830AFFBA830AFFBA830AFFBA830AFF
+ BA830AFFBA830AFFBA8408FFBC830AFFBA8408FFBB8209FFB98307FFBB8209FF
+ B98307FFBC8308FFBC830AFFBD820EFFBD820EFFBF810FFFBF820EFFBF820EFF
+ C0820CFFC0820CFFC0820CFFC2820CFFC2830BFFC4820BFFC3810AFFC28009FF
+ C28107FFC18006FFC18006FFC48009FFC37F08FFC27E07FFC27E07FFC37F08FF
+ C28009FFC3810AFFC4820BFFC4820BFFC2830BFFC28309FFC28309FFC28309FF
+ C08409FFC08409FFC0830BFFBF810FFFC18212FFC1820FFFC38411FFC68616FF
+ B87E15FFAE7922FFAC823FFFC4A77BFFE9D8C3FFFFFAF5FFF3F6FBFFEFF1FBFF
+ F1F4FCFFEFF2F6FFEFEFEFFFF9F6F2FFF7F6F2FFF3F3F3FFEDEFEFFFF2F3EFFF
+ FBF7ECFFE4D8C0FFBFA882FFAD8C54FFAD833CFFB4822FFFBA8425FFBC831AFF
+ C18618FFC38814FFBA7D07FFBE810DFFBE810DFFBF820EFFBF820EFFBF820EFF
+ BF820EFFBE810DFFBE810DFFBF800DFFBE810DFFBE810DFFBD800AFFBD800CFF
+ BC7F0BFFBC7F0BFFBD7E0BFFC1800DFFC1800DFFBF800DFFBF800DFFBF800DFF
+ BF810BFFC1810BFFBF820AFFBC7F07FFBD8008FFBD8008FFBD8008FFBE8109FF
+ BF8308FFBF820AFFBF820AFFC1820AFFC1820AFFBF810BFFBE810DFFBF810FFF
+ BE8210FFBE8211FFBC8211FFBE8211FFBE8211FFBE8211FF4326CFFF4127CEFF
+ 4129CBFF412ACCFF3F28D0FF3F28D1FF4129CDFF412BCAFF472DCDFF412EB9FF
+ 393595FF333980FF303E79FF30427DFF324287FF2D428DFF334D99FF3553A0FF
+ 3757A3FF375AA4FF3C5FA9FF4167AFFF4068B0FF3E66AEFF3F67AFFF3C63ADFF
+ 395DA9FF365AA8FF3856A7FF3452A3FF314DA1FF324A9CFF304491FF35478EFF
+ 37488BFF344381FF313D73FF2F3766FF2F335CFF313159FF353760FF363966FF
+ 363A6DFF323A6FFF32396AFF313764FF34375DFF3B3957FF43374DFF372945FF
+ 22194BFF1C1651FF201652FF221553FF251457FF24155FFF201466FF2F2179FF
+ 482F89FF4E2B63FF724738FFA4702EFFBB7815FFC47E09FFBF7A05FFC07E07FF
+ BC7D05FFC18208FFBE7F07FFBB7C09FFC38416FFA67422FF4A3410FF231D12FF
+ 1C1512FF1F181BFF211A1FFF221A24FF231D28FF1E1A25FF221F2EFF252231FF
+ 282535FF282535FF272336FF262136FF272138FF282239FF2A243BFF292439FF
+ 282338FF272336FF262333FF252232FF242130FF262130FF251C30FF282031FF
+ 231F2AFF221F28FF282128FF271D23FF2E2026FF4F3420FF94631FFFBF8220FF
+ BF8416FFBE810BFFC28107FFBE7E02FFC1820AFFBD8008FFBD8106FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBF8006FFC17F08FFC37F08FF
+ C37F08FFC17F08FFC17F08FFC17F08FFBF8008FFBD8106FFBC8005FFBB8005FF
+ BB8005FFBA8106FFBA8106FFBB8207FFB98306FFBB8207FFBD8109FFBD800AFF
+ BD8109FFBE820AFFBE820AFFBD8207FFBD8207FFBB8207FFBA8106FFBA8108FF
+ BB8209FFB9810AFFBA810DFFBA810EFFBB820FFFBB820FFFBE810DFFBF810BFF
+ BF810BFFBF810BFFBF810BFFBF810BFFBF810BFFBF820AFFC0800AFFBE8109FF
+ C1810BFFBF820AFFC1810BFFBF820AFFC08109FFBE8109FFBF810BFFBE810BFF
+ BF800DFFBF810BFFBF810BFFC1820AFFC1820AFFC18208FFC48309FFC48309FF
+ C58208FFC58207FFC48106FFC38005FFC48005FFC48005FFC37F08FFC17E09FF
+ C07D08FFC07D08FFC07D08FFBF7F09FFC1810BFFC1810BFFC2820CFFC0820CFF
+ C0810EFFC0810EFFC0810EFFBF820EFFBF820EFFBF820EFFC1820FFFC3820FFF
+ C4820BFFC5850FFFC38416FFB37919FFAE7D31FFB69159FFE4CBABFFFAEDDFFF
+ FFFBFAFFF2F2F8FFF0F3F8FFF1F5F6FFF1F4F2FFF5F6F2FFF9F8F4FFF4F5F3FF
+ F0F2F3FFEFF1F1FFF6F3EEFFF8EEDCFFD9C3A0FFAD8B56FFAD813AFFB3812EFF
+ B88426FFBA841FFFBA8217FFBD8516FFC08511FFB97C06FFBD820EFFBD820EFF
+ BD820EFFBD820EFFBD810FFFBD810FFFBD810FFFBD810FFFBF810FFFBD810FFF
+ BD810FFFBC810DFFBC800EFFBB7F0DFFBB7F0DFFBB800CFFBD800AFFBD8109FF
+ BD8109FFBD8109FFBD8207FFBD8207FFBE8206FFBE8305FFBD8204FFBD8302FF
+ BF8202FFBE8200FFBE8200FFBD8200FFBD8100FFBD8000FFBF8006FFBF8008FF
+ BC7E08FFBC7F09FFBD800CFFBC810DFFBB820FFFBA8310FFB87F0CFFB87F0BFF
+ BA7F0BFF4326CFFF4128CCFF422ACAFF422CCBFF422CD2FF432ED1FF4631CEFF
+ 4732CEFF472FCBFF4130B7FF383591FF2F377AFF2B3973FF2C3E79FF344588FF
+ 344A92FF354F9BFF3655A0FF3858A3FF385BA4FF3D60A9FF4369B1FF426AB2FF
+ 3E66AEFF4068B0FF3D65ADFF3A5FA9FF365AA6FF3756A5FF3351A2FF2F4B9FFF
+ 2F4898FF2E438EFF36458DFF364689FF34417FFF313B71FF303665FF33355EFF
+ 36365EFF393B64FF383A6AFF343A6FFF31396EFF32396BFF313764FF35385EFF
+ 3B3957FF42354DFF362746FF1F194AFF191550FF1E1750FF221652FF261558FF
+ 27165FFF1E1565FF2E2171FF432A74FF583655FF84582FFFAD781EFFBE7C0BFF
+ C37F04FFBD7902FFC07D08FFBB7C04FFC28309FFC08109FFBA7B03FFC1800DFF
+ A8771BFF523F14FF292213FF1E1511FF201819FF20191EFF211923FF221C27FF
+ 1F1B27FF231E2DFF242130FF272434FF282535FF262136FF262136FF272138FF
+ 282239FF2B253CFF2A243BFF292439FF282437FF272336FF252232FF242130FF
+ 262130FF241B2FFF271F30FF231F2AFF221F28FF282128FF281E24FF2F2127FF
+ 503521FF956420FFBE811FFFBC8113FFBC7F09FFC28107FFC08004FFC3840CFF
+ BD8008FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FF
+ BD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FFBD8106FF
+ BF8006FFC18006FFC18006FFC17F08FFC17F08FFC17F08FFC17F08FFBF8006FF
+ BF8006FFBD7F03FFBE8004FFBC8004FFBC8004FFBD8106FFBD8105FFBD8306FF
+ BD8207FFBB7E08FFBC7F0BFFBD800CFFBE810BFFBE820AFFBE820AFFBD8207FF
+ BD8207FFBA8106FFBA8108FFBB8209FFBB810AFFBC810DFFBC810DFFBD810FFF
+ BD810FFFBF800DFFBF800DFFBF800DFFBF800DFFC1800DFFC1800DFFC1810BFF
+ C1810BFFC0800AFFC0800AFFC3800BFFC1810BFFC3800BFFC3800BFFC28009FF
+ C0800AFFBE800AFFBD800AFFBD800CFFBD800AFFBE800AFFBE8109FFC08109FF
+ C08107FFC28107FFC28206FFC48106FFC48106FFC48106FFC48104FFC48104FF
+ C48005FFC18006FFBF8008FFBE7F07FFBE7F07FFBE7F07FFBE8109FFBF810BFF
+ C0820CFFC0810EFFBF820EFFBF810FFFBF810FFFBF810FFFBD810FFFBD810FFF
+ BF810FFFC4840EFFC4820BFFC3810AFFC58411FFBE8119FFB07B24FFB78D4CFF
+ CCAF83FFFCE7D2FFFFF4EEFFFBF6F8FFEFEFF5FFF1F3F4FFF0F5F4FFEFF5F0FF
+ F6FAF5FFF6F7F3FFEFF1F1FFF0F3F7FFF3F5F5FFF5EEE5FFECDAC3FFD1B083FF
+ AE8340FFB57F2AFFBB8121FFBD831CFFBC8419FFBB8215FFBD8312FFBF820CFF
+ BD8008FFC1840CFFC0830DFFC0820CFFBE810BFFBE810DFFBF820EFFC0830FFF
+ C0830FFFC0830FFFBE830FFFBD820EFFBD810FFFBC800EFFBA810EFFBC800FFF
+ BB7F0DFFBC820BFFBC830AFFBB8209FFBB8209FFBD8109FFBC8106FFBC8205FF
+ BC8204FFC18608FFC18706FFC18706FFC38705FFC38705FFC38803FFC38803FF
+ C28505FFC08004FFBD7E06FFBC7D05FFBA7D05FFB87C04FFB67D04FFB47C05FF
+ B47C05FFB37B04FFB37B04FFB57C03FF472BD2FF462ED0FF4731CDFF4631CDFF
+ 422DCFFF402CCBFF3F2BC4FF3D2ABFFF3620B5FF3627A7FF35338CFF303978FF
+ 2C3B73FF2D4178FF354689FF364C94FF37519DFF3756A1FF3959A4FF395CA5FF
+ 4063ACFF456CB1FF446DB2FF4069AEFF3D65ADFF3961A9FF365BA5FF3155A1FF
+ 3251A0FF2D4C9BFF294697FF294292FF2F428DFF35448CFF354587FF33417CFF
+ 303B6FFF313766FF363861FF3A3A62FF3C3D69FF393B6BFF343A6FFF2F396FFF
+ 2F376CFF313766FF35385EFF3A3856FF43344FFF362747FF1D194AFF17164EFF
+ 1E184FFF231751FF261656FF28185FFF1D1562FF2D226AFF3E2660FF63414CFF
+ 996B2BFFB57E0FFFC18105FFC47F00FFBD7B04FFBE7E08FFBA7B03FFC28309FF
+ C28309FFB97A00FFC18006FFAC7B19FF5C4818FF2D2615FF1E160FFF201818FF
+ 1E171CFF1F1721FF221C27FF201C28FF221D2CFF23202FFF262333FF272434FF
+ 262136FF262136FF272138FF28223BFF2B253EFF2B253CFF2A253AFF282437FF
+ 272336FF252232FF242130FF262130FF241B2FFF271F30FF221E29FF221F28FF
+ 282128FF281E24FF2F2127FF503521FF956420FFBC7F1DFFB97E10FFBA7D07FF
+ C28107FFC28206FFC4850DFFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8106FFBF8006FFBF8105FFBF8006FFBF8006FF
+ C18006FFC18006FFC18006FFC18006FFBF7E04FFBF7E04FFC07F05FFC07F05FF
+ C07E07FFC18006FFC18006FFBF8008FFBD7E0BFFBE7F0CFFBE7F0CFFBF810BFF
+ BF820AFFBE8109FFBC8005FFBB7F03FFBF8105FFBF8006FFC08107FFC08107FF
+ C1820AFFC1820AFFC2820CFFC2820CFFBE810DFFBE800EFFBE800EFFBE800EFF
+ BF800DFFBF800DFFBF800DFFBF800DFFBD7E0BFFBE7F0CFFC1810BFFC0820CFF
+ C2820CFFC1810BFFC0800AFFBD7F09FFBB7E0AFFB97E0AFFB97D0BFFB97E0AFF
+ BB7E0AFFBB7E08FFBC7E08FFBC7F07FFBF8008FFBF8006FFC18006FFC18006FF
+ C28107FFC48106FFC48106FFC28206FFC08305FFBD8204FFBD8105FFBD8105FF
+ BD8106FFBD8207FFBE820AFFBF830BFFBF820CFFBD830CFFBD820EFFBD810FFF
+ BD810FFFBB8110FFBB8110FFBF810FFFC4840EFFC4820BFFC3800BFFC28315FF
+ B98221FFAF8133FFC4A26DFFEAD2B4FFFFF1E5FFFCF4F5FFF7F3F8FFEFEFF5FF
+ F0F2F3FFEEF4F3FFEEF5F0FFF1F8F3FFEDF2F1FFEAEEEFFFF0F4F9FFF5F5F5FF
+ E7DBD1FFD0B59AFFC1955FFFB88031FFC2811FFFC48114FFC0810FFFC08210FF
+ BE8210FFBE810DFFC18208FFC78409FFC68308FFC38307FFC48106FFC18105FF
+ C18006FFC28107FFC1820AFFC2830BFFC0820CFFC0820CFFBF810BFFBE810DFF
+ BD800CFFBB800CFFBC7E0CFFBC7E0CFFBF810FFFBE800EFFBE800EFFBD800CFF
+ BD800CFFBC7F0BFFBC7F09FFBC7F09FFB97C06FFB97D05FFBA7E06FFBB7F04FF
+ BC8005FFBD8106FFBD8106FFC08107FFC7840AFFC7840AFFC7840AFFC48309FF
+ C18208FFBE8207FFBC8106FFBB8005FFBD8207FFBD8207FFBE8207FF4730C8FF
+ 4832C7FF4533C2FF4331C0FF3C2BBCFF3423B4FF2C1CA9FF2718A2FF200E9DFF
+ 2A1C99FF333485FF373F7BFF344277FF32437CFF344687FF334990FF39549EFF
+ 3858A1FF3B5BA4FF3C5EA4FF4165ABFF476EB3FF486FB4FF4169B1FF3C61ABFF
+ 375CA6FF3256A2FF2F519DFF2D4C9BFF294796FF234190FF253C8AFF31428BFF
+ 354489FF374587FF33417CFF2D3A6EFF2F3667FF343A65FF393C68FF393D6DFF
+ 373B6EFF323970FF30376EFF2F386AFF313764FF35385EFF3A3757FF41334FFF
+ 362648FF1F174CFF191451FF1E1652FF211654FF251759FF28195DFF23155DFF
+ 36245FFF472849FF764E3CFFA97822FFB98104FFC48303FFC17E00FFC17E04FF
+ C17F08FFB97A00FFC28309FFC3840AFFB97A00FFC18006FFB27E1AFF684F17FF
+ 362B10FF21180EFF1D1718FF1B171DFF1A1621FF221C27FF211D28FF201E2AFF
+ 23202FFF262333FF272434FF262235FF262136FF272138FF29233CFF2C263FFF
+ 2B253CFF2A253AFF292439FF272336FF252232FF242131FF262031FF231A2EFF
+ 281E2FFF241E29FF241F28FF292128FF2A1F22FF322321FF53381EFF956420FF
+ BA7E1EFFB97B0FFFB97A07FFC0800AFFC1810BFFC4840EFFBC7D0AFFBD7E0BFF
+ BD7E0BFFBD7E0BFFBD7F09FFBD7E0BFFBD7F09FFBD7F09FFBD7F09FFBD7F09FF
+ BD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBD8008FFBF8006FF
+ C18105FFC18006FFC18006FFC18006FFC18006FFC38006FFC38006FFC17E04FF
+ C17E04FFC17D06FFC27E07FFC27E07FFC37F08FFC37F08FFC17F08FFBF810BFF
+ BE810DFFC0810EFFBF800DFFC07F0CFFBE7E08FFBC7D05FFBB7C02FFBF8105FF
+ BF8105FFC08107FFC08107FFC3810AFFC3810AFFC4820BFFC2820CFFBE810DFF
+ BC800EFFBE800EFFBE800EFFBE810DFFBE810DFFBE810DFFBE810BFFBD7F09FF
+ BE800AFFBF810BFFC0830BFFC0820CFFBF810BFFBE800AFFBD7E0BFFB87C0AFF
+ B67C0BFFB87C0BFFB87C0BFFB87C0AFFBA7C0AFFBA7D09FFBA7D09FFBC7D0AFF
+ BC7E08FFBE7E08FFBF8008FFC28009FFC28009FFC3810AFFC18208FFC08305FF
+ BE8305FFBD8204FFBD8204FFBE8305FFBE8407FFC08408FFC0850AFFBF830BFF
+ BF820CFFBF820EFFBF810FFFBD8110FFBD8012FFBD8012FFC08010FFC8830EFF
+ C6810CFFC17F0FFFBD821BFFB4812BFFAE8645FFCAB187FFF9EBD5FFF7F1ECFF
+ F4F3F7FFF6F4FAFFF1F1F7FFF0F2F3FFEFF4F3FFECF4F3FFEBF3F2FFE6EEEEFF
+ E8ECEDFFF4F6F7FFFAF1EDFFDBC7B5FFBA9670FFB2803EFFB97D24FFC58418FF
+ C3800BFFBD7D07FFBE800AFFBF820EFFBC7F09FFC28206FFCA880BFFC58207FF
+ C48106FFC27F04FFC17E03FFBF7F03FFC07F05FFC28107FFC18208FFC08109FF
+ C08109FFBE800AFFBD7F09FFBC7F09FFBB7E0AFFBB7E0AFFBB7E0AFFBF810FFF
+ BF810FFFBE800EFFBE800EFFBD800CFFBD800CFFBC7F0BFFBC7F0BFFBD800CFF
+ BD800AFFBC7F0BFFBB7E08FFBA7D07FFB97C06FFB87B05FFB97C04FFC17D06FF
+ C17E04FFC27F05FFC18006FFBF8006FFBE8004FFBB7F04FFBA7E02FFBC8005FF
+ BC8004FFBE7F05FF3E30AEFF382AA7FF30219AFF27198FFF1E1288FF180F84FF
+ 170D85FF170D89FF26189CFF31269AFF343482FF333A73FF333E78FF313F7AFF
+ 304386FF375096FF334F96FF38589FFF3B5BA2FF395BA1FF4163A9FF4B6FB5FF
+ 4C6FB8FF4267B1FF3455A4FF3354A4FF3250A3FF304D9EFF2C4A99FF2A4595FF
+ 274390FF2A418CFF37468BFF374385FF323F7DFF2F3D77FF2E3E73FF303E72FF
+ 303E6FFF2F3D6EFF364175FF333D73FF323970FF30386DFF343A69FF343A63FF
+ 36395FFF393858FF3F334FFF37244BFF271552FF22115AFF21165CFF21165CFF
+ 22175DFF2B195EFF321759FF431F49FF683E39FF96642FFFB27E13FFB77D00FF
+ B87800FFC07D03FFC27F05FFC27F04FFC07F05FFBE7F05FFC08004FFBE7F05FF
+ BE7D0AFFB37A17FF8E6625FF4D330EFF221507FF191618FF161822FF161A25FF
+ 1F1E27FF222026FF1F1E28FF211F2BFF23202FFF252232FF272336FF282338FF
+ 292439FF29233AFF282239FF282239FF282338FF282338FF272336FF262235FF
+ 242033FF251F32FF241B2FFF241A2BFF261C28FF291E26FF271D23FF2A1E1CFF
+ 3A2A1AFF573A15FF9A6923FFAE7316FFBB7912FFC07E0EFFBC7B0EFFBA790CFF
+ BA790CFFBB7A0DFFBA7B0DFFBA7B0DFFBA7B0DFFBA7B0BFFBA7B0DFFBA7B0BFF
+ BA7B0BFFBA7B0BFFB97A0AFFB97A0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBE7F0CFFC07E07FFC27F05FFC27E07FFC17D06FFC17D06FFC17D06FF
+ C27D04FFC17E04FFC38006FFC27F05FFC27F05FFC27F05FFC27F05FFC27F05FF
+ C17E04FFBD7E04FFBA8205FFB88206FFBB800CFFBE7F0FFFBF7E11FFBE7E0EFF
+ C07F0CFFC08109FFBF8006FFBD8106FFBD8008FFBD8008FFBD7F09FFBD7F09FF
+ BD8008FFBD8008FFBA7C0AFFBB7C0CFFBC7E0CFFBC7E0CFFBC7F0BFFBB7E08FF
+ BB7D07FFBA7D05FFC1840CFFBF820AFFBD8008FFBB7F04FFB97D05FFBA7E06FF
+ BB7F07FFBC7F0BFFC18214FFBD7F13FFBC7C10FFB9790DFFB8790BFFBA790CFF
+ BB7A0DFFBC7C0CFFBC7A0AFFBD7B0BFFBD7B0BFFBE7C0BFFC17D0CFFC27E0DFF
+ C27E0DFFC0800AFFBE7F05FFBD8204FFC18406FFC28507FFC38608FFC18608FF
+ C38608FFC18509FFBF8308FFBD8008FFBC7E08FFBD7E0CFFC38013FFC48015FF
+ C37F16FFC37D12FFCD8412FFC77D0DFFC6811AFFC1852CFFB78640FFC4A371FF
+ E7D8B8FFFFFAEBFFF5F9F4FFF1F6F9FFF4F4FAFFF3F3F9FFF4F3F7FFF0F1F5FF
+ EDF2F5FFEAF1F4FFE2ECECFFE7EDECFFFEF8F3FFFFEFE0FFDFBE9DFFBC8D59FF
+ B47F2FFFBA7F1CFFBE8211FFC0830DFFBF820CFFBE810DFFBD800CFFBC7F09FF
+ BE8004FFC08004FFBF8006FFBF8006FFBF8006FFBF8006FFBF8006FFBF8008FF
+ BF8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD7F09FF
+ BD7F09FFBD7F09FFBB7D07FFBC7E08FFBC7E08FFBD7F09FFBE800AFFBE800AFF
+ BF810BFFBF810BFFBD7F09FFBD8008FFBD7F09FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBC7D05FFBE7F07FFC1820AFFC08109FFBC7F07FFBC8005FF
+ BE8109FFC1850AFFBC7F07FFBC8005FFBC7F07FF180B85FF160983FF17077DFF
+ 17077CFF180B7EFF1D1385FF22198EFF261D96FF3C2EB1FF3E33A7FF363682FF
+ 323972FF373F7AFF364381FF334689FF365093FF334F96FF37579EFF3B5BA2FF
+ 3B5EA2FF4365ABFF4E70B6FF4B6EB8FF4163AFFF3B5CACFF3A58ABFF3651A7FF
+ 334DA1FF2E499AFF2C4693FF2A4490FF2F458DFF39498CFF384484FF323F7DFF
+ 2E3E79FF2F4078FF304179FF304179FF2E3F77FF324179FF323D76FF303A70FF
+ 32396BFF343A67FF373B64FF373B5EFF3A3A58FF40334DFF382447FF2B1550FF
+ 25115AFF23145EFF21165EFF23185EFF2D1C5BFF3B1B51FF572D44FF825236FF
+ A77229FFB7810FFFB57E00FFB67903FFBE7F0DFFC1800DFFC1800DFFBE800EFF
+ BE800EFFBD7F0DFFBD7E0EFFBD7C13FFB2791EFF926521FF57370CFF28180BFF
+ 1A161BFF141725FF131926FF1B1E23FF1F1D23FF1F1E28FF201E2AFF23202FFF
+ 252231FF272336FF282437FF292439FF292439FF282239FF282239FF282338FF
+ 282338FF272336FF262235FF242033FF251F32FF241C2DFF251A2AFF281C28FF
+ 291E26FF271D23FF2A1E1CFF3C2A19FF573A15FF885B1EFF9C6314FFA8690FFF
+ AB6B0DFFA5670DFFA3640CFFA2640AFFA3650BFFA5670DFFA3670DFFA5680BFF
+ A3680BFFA5680BFFA3680BFFA5680AFFA3690AFFA76A0CFFA66C0DFFA96D0DFF
+ A96F0FFFAD7111FFAC7212FFAF7313FFB17511FFBC7C10FFBD7D0DFFBD7D0DFF
+ BF7D0DFFBF7D0CFFBF7D0CFFBF7E0BFFBF7F09FFC17E09FFC07D08FFC07E07FF
+ C07E07FFC07E07FFC17E04FFC17E04FFBD7E04FFB78001FFB38002FFB57C08FF
+ B87C0BFFBC7B0EFFC07E0EFFC1800DFFC4820BFFBF8105FFBF8105FFBD8008FF
+ BD7F09FFBD7F09FFBD7F09FFBD8106FFBC8106FFBE810DFFBE810DFFBE810DFF
+ BE810BFFBF820CFFBF830BFFC0830BFFC0830BFFBC7E08FFBD800AFFBF820EFF
+ BE8210FFBB8110FFB87D0FFFB1780BFFAF750CFFAC7010FFA86D10FFA76A0DFF
+ A5680AFFA46709FFA46709FFA6680AFFA76A0AFFA56808FFA56808FFA9690AFF
+ AB6C0AFFAE6F0DFFB0710FFFB47311FFB4740EFFB97C0EFFBA7F0BFFBD800CFF
+ BE810BFFBF830BFFBE820AFFBF820AFFBE8109FFBF820AFFBD7F09FFBC7E08FF
+ BF7E0BFFC28010FFC68114FFC57F14FFC67E12FFCC8010FFCA8115FFC27F22FF
+ B88033FFBA915AFFD4BA95FFEDE5CEFFF5F6ECFFF3FAF7FFF0F8F8FFF4F5F9FF
+ F5F4F8FFF6F2F7FFF4F3F7FFF0F3F7FFEDF4F7FFEAF1F4FFF2F5F3FFFFF6EAFF
+ F9E1C5FFDAB282FFBB8A46FFB57D24FFBB8118FFBE8210FFBE840DFFBD820EFF
+ BC810DFFBD800CFFBC7F09FFBE7F05FFBE8004FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBB7E06FFBD8008FFBF820AFF
+ BE8109FFBC7F07FFBC7F07FFBD8008FFBF820AFFBC7F07FFBC7F07FFBC7F07FF
+ 2A17A4FF2916A1FF2B149EFF2D179FFF2F1DA0FF3525A8FF3B2DB1FF4032B9FF
+ 4131BBFF4236AEFF3B3887FF353973FF38407BFF374482FF334788FF354F92FF
+ 314F96FF36569DFF3B5BA2FF3D5FA5FF4668AEFF4C70B6FF486BB5FF3C5EAAFF
+ 4463B2FF3F5DAEFF3A56AAFF3550A1FF314A9AFF2F4694FF2E4791FF30468DFF
+ 39498CFF364282FF303D7BFF2D3D78FF32427DFF344780FF33467FFF33447CFF
+ 324179FF313F74FF303B6FFF32396AFF353B68FF373C63FF383B61FF3D3B59FF
+ 403448FF3A2742FF2B184BFF251555FF22175BFF22195CFF261B59FF342154FF
+ 432445FF683F44FF90613BFFA8762AFFAD7B11FFAB7903FFAB780AFFB27B13FF
+ B27713FFB17613FFAF7515FFAE7414FFAF7411FFAF7313FFAE7114FFA56E1DFF
+ 8A5E23FF573713FF2A1C10FF1C181DFF171826FF151827FF1A1922FF1C1A20FF
+ 1F1E28FF201E2AFF221F2EFF252231FF272336FF282437FF282338FF282338FF
+ 282239FF282239FF282338FF282338FF272336FF262235FF242033FF251F30FF
+ 261C2CFF251B28FF281D27FF291E26FF241C26FF261D20FF372721FF503520FF
+ 72481EFF824C15FF8B5012FF8B5110FF854C14FF814912FF804713FF804811FF
+ 844D14FF824E12FF844E12FF824E12FF844E11FF824F11FF844E11FF824F11FF
+ 824D0EFF814E0FFF855011FF855213FF895513FF895715FF8D5917FF8F5C13FF
+ A16C12FFA66F0EFFA7700DFFAB720FFFAF7410FFB17710FFB47A11FFB77C0FFF
+ B97C0EFFBB7C0CFFBD7E0CFFBD7E0BFFBF7F09FFC17F08FFC17F08FFC08107FF
+ BB8005FFB98005FFB97C06FFBA7B08FFBC7B08FFC07E07FFC48106FFC58306FF
+ C38104FFC38005FFC17F08FFC17E09FFBF7F09FFBF8006FFBF8204FFBD8204FF
+ BE8308FFBC830AFFBE820AFFBE8308FFC08409FFC1840CFFC4850DFFC28310FF
+ BA7C0AFFB97B0FFFB57B12FFB37815FFAB7314FFA36B12FF9B640FFF956010FF
+ 8B5710FF865511FF86520FFF84500DFF834F0CFF83500AFF85510BFF86520CFF
+ 87530DFF88540DFF8B550EFF8D5710FF8F5912FF915C13FF955E15FF986011FF
+ A76E13FFAA710EFFAD7510FFB17710FFB37A11FFB57B11FFB77C0EFFB97D0CFF
+ BD810FFFBE810DFFBD800CFFBF810BFFC2820CFFC2820CFFC1800DFFC27F0CFF
+ C67F0DFFC8841BFFB97E28FFB28240FFCAA97CFFEEDBC0FFF9F3E6FFF1F3EDFF
+ F6F9F7FFF5F7F7FFF8F5F7FFF9F4F6FFF8F3F5FFF5F4F6FFF2F6F7FFF2F7FAFF
+ F2F2F8FFFCF5F2FFF3E5CFFFD9C096FFC19B5BFFB2832FFFB37C1BFFBC8114FF
+ BF8010FFBF820EFFBE810DFFBD800AFFBD800AFFBC8008FFBE7F07FFBE7F07FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BF820AFFBF820AFFBE8109FFBE8109FFBD8008FFBC7F07FFBB7E06FFBB7E06FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBE8109FFBF820AFFBE8109FFBC7F07FFBC7F07FFBC7F07FFBE8109FF
+ BC7F07FFBC7F07FFBC7F07FF452DC7FF432BC5FF4229C1FF4027BDFF3F27BBFF
+ 3D28BAFF3D2BBAFF3D2CBDFF321FB2FF3A2CA9FF3B3888FF373B75FF373F7BFF
+ 33407EFF304485FF344E91FF314E98FF34559EFF3A5BA4FF4062A8FF476BB1FF
+ 4C70B6FF4467B1FF3759A5FF4160AFFF3F5CADFF3C57A8FF3850A2FF344B99FF
+ 314893FF2E468EFF31468AFF364688FF31407EFF2A3977FF2A3C79FF324481FF
+ 384A87FF374984FF344780FF32437CFF324075FF303B6DFF323A69FF343B66FF
+ 373C63FF3A3C5FFF403B5AFF433345FF3B263FFF2B1948FF261754FF23185CFF
+ 241A5CFF2C1D56FF3A254CFF502E3FFF73483FFF916236FF9C6923FF9A680EFF
+ 996A08FF98690DFF996911FF96620FFF956010FF955F12FF935D10FF945C0DFF
+ 935B0CFF945A0EFF8C5714FF7D521FFF543718FF2E1F16FF1E1A1FFF191A28FF
+ 181828FF1A1923FF1C1922FF1E1C28FF201E2AFF221F2EFF242130FF262235FF
+ 272336FF282338FF282338FF282239FF282239FF282338FF282338FF272336FF
+ 262235FF242033FF251F30FF261D2AFF251B27FF281D25FF271F26FF241C26FF
+ 241C23FF332526FF4B3425FF623C1CFF6F3F15FF754112FF754113FF6F3E18FF
+ 6A3C1AFF6B3A1AFF6A3A18FF6E4017FF704016FF704016FF704016FF704115FF
+ 704115FF704115FF704115FF6C3E0FFF6D3F10FF6E4011FF6F4112FF714313FF
+ 724414FF734515FF764910FF80520BFF865608FF8A5909FF8E5E0CFF96620FFF
+ 9C6611FFA06A13FFA46D12FFAC7213FFAE7310FFB0750EFFB4770FFFB87A10FF
+ BB7B0FFFBD7C0FFFBD7E0EFFBF810FFFBC810DFFBD7F0DFFBC7F0BFFBE7E08FF
+ C07F05FFC17F02FFC18000FFC48102FFC48005FFC37F08FFC37E09FFC37F08FF
+ C18006FFC18202FFBF8202FFBA8003FFBB8104FFBC8106FFBE8308FFBE820AFF
+ BD800CFFBC7E0CFFB97C0EFFB67812FFAE7212FFA2680FFF955F0CFF8D560BFF
+ 85510BFF814F0DFF7D4E11FF764713FF734515FF714313FF704310FF6F420FFF
+ 71420FFF724310FF734410FF784915FF794915FF7A4A16FF7A4B15FF7C4A15FF
+ 7C4A15FF7C4A15FF7F4D11FF8C570EFF905B0AFF945F0EFF9B6510FFA16B14FF
+ A77015FFAB7314FFB07511FFB67B14FFB97E11FFBA7F11FFBE8210FFC0830FFF
+ C0820CFFBD8008FFBB7D07FFC28010FFBE811FFFB07E32FFB9935DFFDFC7A9FF
+ FCF1E3FFFBF8F3FFF1F3F3FFF6F6F6FFF7F5F5FFF8F2F3FFF7F1F2FFF7F2F3FF
+ F4F4F4FFF1F7F6FFF3F7F8FFF9F2F7FFF9E9E3FFD9C4A4FFB5985FFFAA8432FF
+ B07F1DFFB47C11FFBE7F0FFFBF7F0FFFBF800EFFBD800CFFBD8109FFBC8008FF
+ BC8008FFBC7E08FFBE7E08FFBD7F09FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BD8008FFBC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBF820AFFBF820AFFBE8109FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF3E25C9FF4126CAFF
+ 4325CAFF4326C9FF4327C7FF3F27C3FF3C27C0FF3925BEFF311CB4FF3927A8FF
+ 383585FF343872FF353D79FF323F7DFF324386FF344D93FF304D98FF34549FFF
+ 3C5DA6FF4265AEFF496DB3FF496DB3FF4262ADFF3656A2FF3A58A7FF3957A6FF
+ 3B54A4FF3A51A1FF364D99FF324890FF2F438AFF2F4285FF314281FF2C3B79FF
+ 283775FF2A3B7AFF334385FF384A8BFF374988FF354784FF33447DFF314176FF
+ 303B6DFF313A66FF343A63FF363C61FF393B5EFF3E3958FF423047FF3A2440FF
+ 2B1849FF271856FF271960FF2A1C5EFF331F54FF422748FF5C363CFF744634FF
+ 845228FF845216FF82510DFF83560DFF7F5510FF7B500DFF7B4D0DFF7A4B0EFF
+ 7A4911FF78470FFF79470DFF7A460AFF7C460AFF75430EFF71471DFF53361BFF
+ 312219FF1F191EFF1A1A28FF1A1A2AFF1C1928FF1E1A26FF1E1C28FF1F1D29FF
+ 211E2DFF242130FF262235FF272336FF272237FF272237FF282239FF282239FF
+ 282338FF282338FF272336FF262235FF242033FF251F30FF241D2AFF251C26FF
+ 281E24FF272025FF221D26FF231C23FF302626FF473328FF5C3A1DFF683C17FF
+ 6B3D14FF6C3D17FF663C1FFF633B22FF643A23FF633B1FFF683E1BFF6A3F18FF
+ 6A4016FF6A4016FF6A4016FF6A4016FF6A4015FF6A4015FF6C4217FF6C4217FF
+ 6C4316FF6C4316FF6D4417FF6D4417FF6D4515FF6E4514FF6D420FFF70440EFF
+ 74470EFF774B10FF7D4E11FF825212FF885412FF8A5610FF935C13FF965E11FF
+ 9B6010FF9F6311FFA46711FFA96A12FFAC6D13FFAD6F11FFB37713FFB47A11FF
+ B77B11FFB97E10FFBD800CFFBD8106FFBE8103FFC08101FFC38104FFC38006FF
+ C47E09FFC37E09FFC37F08FFC38006FFC18202FFBF8301FFBA7F01FFBB8104FF
+ BE8308FFBF820CFFBC800EFFB67B0EFFB0750EFFAC7010FFA26A11FF996211FF
+ 8C570EFF7E4C0AFF77450BFF72420EFF734313FF714418FF6E4219FF6D421BFF
+ 6C411AFF6B4019FF6B4019FF6C4017FF6C4017FF6C4017FF70441BFF72451AFF
+ 72451AFF72451AFF74441AFF744519FF744519FF764616FF76450DFF7A490BFF
+ 7E4D0FFF855311FF8C5815FF915D16FF976114FF9B6311FFA0680FFFA66E0FFF
+ B17612FFB77D13FFBB8013FFBD8110FFBE810DFFBB7F0DFFBD8117FFB37E24FF
+ AF8647FFCBB189FFEFE2D2FFF9F5F4FFF2F3F7FFF5F6FAFFF7F2F3FFF7F2F1FF
+ FAF0F0FFF7EFEFFFF4EFF0FFF1F1F1FFEDF4F1FFF3F4F2FFFFF3F4FFF4D9CBFF
+ C5A679FFA17E34FFA47C16FFB3820EFFBA7F0BFFBD7E0BFFC07E0EFFC07E0EFF
+ BD7E0BFFBC8008FFBC8008FFBC8008FFBC7D0BFFBC7D0BFFBD7F09FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBF820AFFBF820AFF
+ BE8109FFBD8008FFBD8008FFBD8008FFBC7F07FFBB7E06FFBC7F07FFBC7F07FF
+ BC7F07FF3A21C5FF3C22C9FF4225CEFF482AD1FF482CD3FF472FD1FF4630CFFF
+ 4530CCFF432EC7FF412FB0FF353282FF30346EFF353D78FF374383FF344489FF
+ 334B93FF304D98FF34549FFF3C5FA9FF4467B0FF486CB2FF4569AFFF3E5FA8FF
+ 3756A1FF3654A1FF3853A3FF3B52A2FF39509CFF364B96FF32468DFF2E4184FF
+ 2C3E7DFF2B3D7AFF283A75FF273877FF2B3D7EFF344588FF374A8EFF38498CFF
+ 354788FF334580FF324277FF303C6CFF303964FF323960FF35395CFF37385AFF
+ 3D3756FF3E2E46FF372242FF29184BFF271757FF2A1A61FF301D5CFF3E234FFF
+ 4C2B40FF633934FF714227FF76431BFF73400EFF70400CFF714510FF6D4511FF
+ 683F0EFF6D4211FF6D4014FF6B3F16FF6A3E15FF6D3C14FF6E3C12FF6F3D0FFF
+ 6C3C12FF663E1BFF55371EFF36251CFF201A1BFF1C1A26FF1C1B2BFF1D1A29FF
+ 201B2AFF1D1B27FF1F1D29FF211E2DFF23202FFF252134FF272336FF272237FF
+ 272237FF282239FF282239FF282338FF282338FF272336FF262235FF242033FF
+ 251F30FF241E29FF241D24FF261F24FF272025FF221E24FF231D22FF302724FF
+ 453427FF5D3D20FF653E18FF6A3E15FF6B3F1AFF673F22FF654026FF663E25FF
+ 663E22FF6B401FFF6D411CFF6D421BFF6D421BFF6D421BFF6D421BFF6D421BFF
+ 6D4319FF6C4218FF6C4218FF6C4218FF6C4217FF6B4116FF6B4116FF6B4116FF
+ 6B4116FF6E431CFF6E431CFF6F431AFF6E4318FF704317FF724415FF754414FF
+ 774511FF794510FF7E470EFF814A0DFF854C0EFF8A500FFF8F5311FF915611FF
+ 93590EFF9B610FFF9E660DFFA36A0DFFAA710EFFB0780DFFB57D0CFFBB810AFF
+ BE8308FFBF8006FFC17F08FFC37E09FFC37E09FFC37F08FFC18006FFC18202FF
+ BF8202FFC08206FFBF820AFFBF820EFFBC7F11FFB47912FFAB7111FFA16910FF
+ 986312FF88550CFF83510FFF7C4C12FF764713FF734516FF714419FF70441BFF
+ 71441EFF6F431EFF6E411FFF6E411FFF6E411FFF6E421DFF6E421DFF6F421DFF
+ 6F421DFF6C3F19FF6D401AFF70411BFF71421CFF75441CFF76451DFF77461EFF
+ 78481EFF6F4014FF704213FF734515FF774815FF7A4A16FF7D4C14FF814E10FF
+ 844F0CFF895209FF91590AFF9C630DFFA66D10FFAE7414FFB47915FFB97F16FF
+ BA8019FFB47D1CFFB38335FFC2A16FFFE6D3B8FFF9F3EEFFF0F2FAFFEBEDF5FF
+ F5F5FBFFF4EFF0FFF7EFEFFFF9EFEFFFF7EFEFFFF2F0F0FFEEF0F0FFEBF1ECFF
+ F4F1E9FFFFECE5FFEBC3AAFFB89357FFA27A21FFAD800DFFB98608FFBD8106FF
+ C07D08FFC17C0DFFBF7D0DFFBD7F09FFBC8008FFBC8106FFBB7F07FFBC7D0BFF
+ BC7C0CFFBD7F09FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBB7E06FFBB7E06FFBC7F07FFBD8008FFBE8109FFBE8109FFBF820AFF
+ BF820AFFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBF820AFFBE8109FFBC7F07FFBD8008FFBE8109FFBE8109FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FF331EBBFF351DBDFF391EC1FF3C21C5FF
+ 3F24C8FF4028CAFF412BCAFF422DC9FF4833CCFF4533B4FF3A3485FF33356FFF
+ 383E79FF3A4484FF35438BFF344994FF2E4D98FF3356A0FF3E61ABFF4669B2FF
+ 496BB1FF4365ABFF3D5DA6FF3857A2FF3A56A3FF3B55A2FF3B519FFF394E99FF
+ 374891FF334388FF2E3E80FF2B3D7AFF293B76FF283C76FF2A3C7BFF2F4285FF
+ 35478EFF374A93FF384A91FF35488BFF344683FF334378FF303D6BFF2F3961FF
+ 31375CFF343658FF363557FF3A3453FF3A2C48FF332146FF29164DFF291858FF
+ 301B5FFF382056FF472746FF563036FF653928FF6E3D1DFF6E3D17FF6C3B13FF
+ 693A14FF683C17FF673D1AFF663C19FF6A3E19FF6A3D1BFF683C1DFF673B1EFF
+ 693A1EFF6A3B1CFF6E3B1AFF6A3C1AFF623B1BFF583A21FF3B2A1DFF231A17FF
+ 1E1922FF1D1B27FF1B1827FF1E1B2AFF1D1B27FF1E1C28FF211E2DFF23202FFF
+ 252134FF262235FF272237FF272237FF282239FF282239FF282338FF282338FF
+ 272336FF262235FF242033FF232030FF221E2AFF221D26FF251F24FF272023FF
+ 221E23FF231E1FFF322821FF473524FF604120FF694216FF6C4011FF6D4014FF
+ 6A401BFF69411EFF6A401DFF6B3E1CFF6E411CFF6E411CFF6E411CFF6E411CFF
+ 6E411CFF6E411BFF6E411BFF6E411BFF693C16FF693D14FF693D14FF6A3E15FF
+ 6A3E15FF6A3F14FF6A3F14FF6A3E15FF704321FF6F4221FF6E4120FF6E3F1FFF
+ 6D3F1DFF6D3D19FF6C3D17FF6E3D17FF6F3C14FF703E14FF723F14FF734113FF
+ 764213FF774314FF784513FF7A4611FF834E0FFF85510BFF895509FF8E5C0AFF
+ 97650BFFA26F0EFFAD790FFFB57E0FFFBA7E0CFFBD7E0BFFBF7F09FFC17E09FF
+ C17F08FFBF8006FFBD8105FFBD8106FFC1800DFFBD7C0FFFB97710FFAD7010FF
+ A16610FF945F0FFF895610FF805113FF754711FF724716FF704619FF6F451AFF
+ 6F451BFF6F451BFF70441BFF70441BFF6E411BFF6F421CFF6F431AFF6F431AFF
+ 6F431AFF6F431AFF714419FF714419FF704016FF704016FF714216FF724317FF
+ 764519FF77461AFF78471BFF76461CFF6D4118FF6D421BFF6E431CFF70441BFF
+ 72451AFF744519FF764515FF784612FF7C460FFF814B0EFF89520FFF8F580FFF
+ 965E0FFF9E6614FFA9701AFFAD7720FFA57321FFBB914EFFE0C69EFFFCF0DEFF
+ F8F7F9FFEBEFFAFFEBEEF6FFF1F2F6FFF4F0EFFFF8F1EEFFF7F1F2FFF5F2F4FF
+ F2F1F3FFEEF0F0FFEEF0EAFFF9F0E2FFF5D0BCFFD2A278FFAE8137FFAD8019FF
+ B9860AFFBD8500FFC18104FFC48009FFC27C0BFFC07B0CFFBE7E08FFBC7F07FF
+ BB8005FFBB7F07FFBC7D0BFFBC7D0BFFBD7F09FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBE8109FFBE8109FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBE8109FFBC7F07FFBB7E06FFBC7F07FF
+ BE8109FFBF820AFFBE8109FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF2E1BB2FF
+ 2D19B2FF2E17B5FF3116B9FF3419BCFF361EC0FF3923C2FF3C27C3FF3C27C0FF
+ 4230B1FF3E3889FF393B75FF393F7AFF364080FF324088FF334893FF2F4C97FF
+ 3356A0FF4263ACFF496BB1FF4769AFFF4062A8FF3B5BA4FF3B58A2FF415BA7FF
+ 4058A4FF3E529FFF3A4D98FF37468EFF324285FF2F3E7DFF2D3D78FF273B75FF
+ 273C79FF2C4081FF31458CFF364994FF374C97FF364B96FF364A91FF344685FF
+ 314378FF2E3D6BFF303860FF323659FF343655FF363452FF383251FF362C4AFF
+ 2F2046FF27174DFF2D1856FF372057FF40254CFF4F2D38FF5D3529FF65381DFF
+ 6C3C18FF6E3F19FF6C3F1AFF673D1AFF643B1BFF663B20FF6A3F24FF683C1DFF
+ 683C1DFF663A22FF663A23FF683923FF6A3A22FF6B3C1DFF6A3D1CFF633C1CFF
+ 5D3F24FF412D1CFF251913FF1F1A1CFF1B1A24FF1A1726FF1D1A29FF1D1B27FF
+ 1E1C28FF211E2DFF23202FFF252134FF262235FF262136FF262136FF282239FF
+ 282239FF282338FF282338FF272336FF262235FF242033FF232030FF201D2CFF
+ 201C27FF251F24FF262123FF241F21FF241F1EFF332820FF493523FF634320FF
+ 6B4116FF6D3F10FF6D3F10FF6B3E18FF6B3F1AFF6C3D17FF693A14FF6E3E1AFF
+ 6C3E1CFF6C3E1CFF6C3E1CFF6C3E1CFF6C3F1AFF6C3F1AFF6C3F1AFF6B3E19FF
+ 6C3F19FF6C3F19FF6D401AFF6E411BFF6F431AFF70441BFF70431DFF6C3E1CFF
+ 6C3D1DFF6C3D1DFF6C3D1DFF6C3D1DFF6C3E1CFF6C3E1CFF6C3E1CFF6E411CFF
+ 6D401BFF6D401BFF6D401BFF6C3F19FF6C3F19FF6C3F19FF6E4116FF744414FF
+ 74450FFF75450BFF784A0AFF81540BFF8F600EFF9E6D11FFA97510FFB67D10FF
+ BA7E0CFFBD7F09FFBF8008FFBF8008FFBD8106FFBC8106FFBC7F0BFFBD7B12FF
+ B57314FFA96A10FF9B5F0DFF8C550CFF7F4C0DFF75460EFF6E4312FF6E471BFF
+ 6A431CFF69421CFF67401AFF683F18FF683F18FF6C4017FF6D4118FF6C4017FF
+ 6D4118FF6D4118FF6D4118FF6E4219FF6E4318FF6F4217FF6F4217FF734319FF
+ 734418FF724317FF724317FF734216FF734214FF724115FF704016FF6C411AFF
+ 69421CFF6D431EFF6E441FFF714520FF72451FFF76451FFF77451BFF784618FF
+ 7A4715FF7E4813FF7F490DFF824C0BFF89550FFF966019FF9B6921FF976A26FF
+ C19E66FFF5E0C1FFFFFFF5FFF5F5FBFFEBEFFAFFF0F3F8FFEFEFEFFFF6F3EFFF
+ F7F3F2FFF5F4F8FFF4F4FAFFF3F3F9FFF2F2F2FFF2F1E7FFFFF1DAFFDFB48DFF
+ BC864AFFA7751DFFB58313FFBF8809FFBD8300FFC28101FFC8830AFFC27C0BFF
+ C07C0BFFBE7E08FFBC7F07FFBC8005FFBB8005FFBC7D0AFFBD7E0BFFBD7F09FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBF820AFF
+ BF820AFFBE8109FFBE8109FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BB7E06FFBA7D05FFBC7F07FFBF820AFFC0830BFFBF820AFFBD8008FFBC7F07FF
+ BC7F07FFBC7F07FF4232C6FF412EC5FF3C26C2FF371FBFFF341CBEFF341CBEFF
+ 331DBCFF341FBBFF3722BBFF3927A8FF373182FF363872FF3A3E79FF343D7DFF
+ 323E86FF384B96FF324C98FF3858A3FF4666AFFF4C6CB3FF4969B0FF4162A7FF
+ 3D5BA2FF3956A0FF3A559FFF37509AFF374C97FF374A93FF334388FF29397BFF
+ 283775FF2A3A75FF2D417BFF2E4682FF344A8CFF354B93FF344B97FF354B99FF
+ 374D9BFF3B5199FF3A4E8FFF32437BFF303F6DFF333C62FF2E3354FF363654FF
+ 3E3A57FF3A3550FF2D2843FF2D2649FF2F2053FF351F53FF3E2649FF4A2D3CFF
+ 5A382BFF653E1EFF6A3E19FF6B3F16FF6A3F18FF683F18FF674019FF673F1CFF
+ 6A3E1FFF6C3D21FF6B3E1DFF6B3E1DFF663B20FF663A22FF673822FF693921FF
+ 693A1BFF683B1AFF653C1BFF5D3D20FF4B341EFF302216FF1D1613FF17151BFF
+ 1A1824FF191927FF1E1C28FF1F1D29FF201D2CFF221F2EFF242033FF252134FF
+ 272237FF282338FF272138FF272138FF272237FF272237FF262235FF242033FF
+ 221E31FF211D30FF1D1C2CFF211F2BFF252127FF241E23FF221C21FF251F20FF
+ 342822FF463221FF623E20FF6C3F19FF704016FF724016FF6E3E1CFF6E3D1DFF
+ 723D1CFF703D1CFF693A1AFF683B1AFF693C1BFF693C1BFF6A3D1CFF6B3E1CFF
+ 6B3E1CFF6B3E1CFF6D401EFF6D411CFF6D411CFF6D411CFF6D411CFF6D421BFF
+ 6D421BFF6D421BFF72441BFF72441BFF72431DFF70431DFF70431DFF70431DFF
+ 6F441DFF6F441DFF6C411AFF6C411AFF694019FF683F18FF694019FF68411AFF
+ 6A431CFF6D441DFF6E431CFF6F431AFF6D4217FF6B400FFF6C4108FF784B08FF
+ 8B5A0EFF9D690FFFAC750DFFB67C0BFFBC8008FFBB7F03FFBD8105FFC08409FF
+ BE810BFFB57A0DFFB27317FFA46515FF91540AFF834907FF7A460AFF754511FF
+ 704317FF6A411AFF6C4421FF694321FF684220FF66401DFF68411BFF6A4218FF
+ 6D4217FF6D4318FF6B4019FF6A411AFF6D421BFF6E431CFF6F441DFF70451EFF
+ 72451FFF73471EFF6F431AFF6E4318FF6E4116FF6D4015FF6D4015FF6E4115FF
+ 724218FF714419FF6B4319FF694319FF6A431CFF6C421DFF6D431EFF6F431EFF
+ 71441FFF73441EFF77461EFF76441AFF7A491BFF7B4A18FF75430EFF78480EFF
+ 7F5013FF794B11FF8B622BFFCFB083FFFFEAD4FFFEF4EDFFF3F1F7FFF0F2FAFF
+ F1F3F3FFF6F5F1FFFDFDF7FFEFF0EEFFEDEFF7FFF1F3FDFFEEF0F8FFF6F4F3FF
+ F6EFE0FFEED8B5FFAD7F45FFB77F2EFFB67D1AFFB77E0BFFBC8103FFC28402FF
+ C48205FFC58007FFC27C0AFFC07D0AFFBE7E08FFBC7F07FFBC8005FFBC8005FF
+ BC7E08FFBC7E08FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBC7F07FFBD8008FFBE8109FFBE8109FFBE8109FFBE8109FF
+ BD8008FFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBB7E06FFBC7F07FFBC7F07FFBD8008FFBD8008FFBE8109FF
+ BF820AFFBF820AFFBE8109FFBE8109FFBE8109FF4130C7FF402EC7FF402BC8FF
+ 3F27C9FF3D25C7FF3A23C5FF3923C2FF3823C0FF3821BFFF3927AAFF352F81FF
+ 353771FF3B3F7AFF363F7FFF344086FF384B94FF324D97FF3959A2FF4866ADFF
+ 4B6CB1FF4867ACFF3F5EA3FF3A599EFF3A569DFF3A539BFF39509BFF394F97FF
+ 3B4D94FF344489FF29397BFF2A3775FF2A3A75FF304680FF314A88FF384F93FF
+ 3A529AFF384F9DFF354C9CFF324999FF344994FF384B8EFF31427BFF303E6EFF
+ 323A62FF313355FF383653FF3F3B54FF3C364FFF2C2943FF2D2647FF312150FF
+ 39234DFF452A3EFF523330FF613D1FFF694117FF693F15FF6A3F18FF663F19FF
+ 644018FF654217FF674019FF6C3F1EFF6D3E1FFF6E3E1CFF6C3E1CFF683C1FFF
+ 683B20FF673921FF673A1FFF683A1BFF683B19FF653D1AFF613E1DFF4F361CFF
+ 352514FF231912FF1C1719FF1A1923FF191927FF1E1C28FF1E1C28FF201D2CFF
+ 221F2EFF231F32FF252134FF272237FF272237FF272138FF272138FF272237FF
+ 272237FF262235FF242033FF231F32FF201E31FF1B1B2BFF1F1F2DFF252029FF
+ 241E23FF201A1FFF261E1FFF342824FF483324FF603E21FF6B3F1AFF703F17FF
+ 703F17FF6E3E1CFF6E3D1DFF723D1CFF723D1CFF6B3C1CFF683D1CFF683D1CFF
+ 683D1CFF683D1CFF693F1CFF693F1CFF693F1CFF6B411EFF6B411CFF6B411CFF
+ 6B411CFF6B421BFF6B421BFF6B421BFF6D421BFF704318FF704318FF704318FF
+ 704318FF6E4219FF6E4219FF6D4319FF6D4319FF6D4319FF6A4218FF694019FF
+ 674019FF674019FF69421BFF68441CFF6B441EFF693E1DFF6B401FFF6B411EFF
+ 6B4019FF6B4114FF734712FF835311FF925F0FFFA97112FFB47B0EFFBD8109FF
+ BD8105FFBD8106FFBE820AFFB97D0CFFAF7410FFA06515FF925816FF834D0EFF
+ 79440BFF734210FF724317FF6E411BFF6A401DFF6B4222FF684121FF674020FF
+ 66401EFF67401AFF694019FF6C4218FF6C4218FF6A401BFF68411BFF6B411EFF
+ 6B411CFF6C421FFF6D431EFF6F431EFF70451EFF6D421BFF6D4319FF6D401AFF
+ 6D4118FF6D4118FF6D4217FF704219FF6E4318FF6D4318FF6B4418FF6C441AFF
+ 6C441AFF6D441DFF6F441DFF70441FFF71441EFF72461DFF71431AFF73461BFF
+ 774B1CFF774919FF784B18FF7A4E19FF754D19FF8B6739FFC7AB88FFF5E2D3FF
+ FCF0EEFFF5F1F6FFF2F1F5FFF2F1EDFFF4F5ECFFF5F5EFFFEAECECFFEEF3FCFF
+ F0F4FFFFEFEFF5FFFDF7F2FFF1E3CDFFCEB184FFB28034FFBD821FFFBA7F12FF
+ BC7F0BFFBF8105FFC28205FFC48106FFC38006FFC27D08FFC07D08FFC07E07FF
+ BE7F07FFBE7F05FFBC8005FFBE7F07FFBC7F07FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FF
+ BC7F07FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FFBE8109FFBE8109FF
+ 3D2BCAFF412CCEFF452DD1FF472DD4FF462CD3FF432BD1FF4028CCFF3E27C9FF
+ 3C24C6FF3A26AEFF352C82FF353571FF3E3F7CFF3A4180FF374286FF3A4D91FF
+ 354F95FF3C5BA0FF4966A9FF4969ABFF4461A4FF3B589BFF375497FF375499FF
+ 375098FF395199FF3B5199FF3A4C93FF314186FF28387AFF2A3775FF2C3C77FF
+ 344986FF364F8FFF3C5699FF4059A3FF3C55A5FF3750A0FF314A9AFF304793FF
+ 34498DFF2F417EFF303E6FFF323A62FF333557FF3B3852FF413A4FFF3E374CFF
+ 2E2946FF30264AFF37234DFF412647FF4D2E37FF593628FF643F19FF694215FF
+ 693E17FF673D1AFF633D1BFF633F1BFF644116FF694019FF6C3D1DFF6E3C1EFF
+ 6F3D19FF6D3D19FF6A3D1CFF683C1DFF673B1EFF673B1EFF693C1BFF693D18FF
+ 673D18FF633E1CFF54371CFF3F2917FF2B1B14FF201819FF1C1922FF191925FF
+ 1D1B27FF1E1C28FF1F1C2BFF211E2DFF231F32FF252134FF262136FF272237FF
+ 272138FF272138FF282338FF272237FF272336FF252134FF242033FF211F32FF
+ 1B1B2DFF1E1E2CFF252029FF241D22FF1F1A1CFF261E1EFF362A24FF483625FF
+ 5E3E21FF67401AFF6B4117FF6B4117FF693F1CFF693E1DFF6E3E1AFF6E3E1AFF
+ 6D401BFF6C3F1DFF6C3F1DFF6B3F1AFF6B3F1AFF6B3F1AFF6B3F1AFF6B4019FF
+ 6D421BFF6D421BFF6D4319FF6D4319FF6D4319FF6D4319FF6D4319FF6D4319FF
+ 6C4017FF6C4017FF6C4017FF6C4017FF6C3F19FF6C3F19FF6C3F19FF6B4019FF
+ 6D4319FF6C4218FF6C4218FF6A4218FF6A4218FF6B4319FF6D451BFF6D441DFF
+ 6A3D1CFF6D3F20FF6D4221FF6C421FFF6C401BFF6F4216FF7B4A12FF86520BFF
+ A36B12FFB2780FFFBE810DFFC0830BFFBE810BFFBC7E0CFFB2760CFFA46B10FF
+ 895512FF7A4B13FF73440EFF70410EFF6F4112FF704318FF70411BFF6D3F1DFF
+ 6F411FFF6D401FFF6A3F1EFF693E1DFF663E1BFF67401AFF67401AFF68411BFF
+ 6A401DFF6B411EFF6B401FFF6B411EFF6D401FFF6D401EFF6D401EFF6D411CFF
+ 6D401BFF6D401AFF70401CFF70411BFF70411BFF704219FF6F401AFF6F4118FF
+ 6E4417FF6D4515FF6E4518FF6E4518FF6F451AFF6F451AFF70461BFF70461BFF
+ 70471AFF6E4417FF6E4415FF744B1AFF79511DFF754D19FF754D18FF7A5523FF
+ 997851FFC1A68BFFE3D1C6FFF0E4E2FFF1EBECFFF2EDEEFFF5F2EAFFF9F8EEFF
+ F1F3EDFFE8EDECFFEEF3FCFFF1F3FDFFF5F0F2FFFFF6EAFFE8D0B2FFAE894FFF
+ B47F24FFBE8113FFBD7F0DFFBD7E0BFFC08109FFC28107FFC18006FFC07F05FF
+ C07E07FFC07E07FFC07F05FFC07F05FFC07F05FFBE7F05FFC07F05FFBE7F07FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BB7E06FFBB7E06FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FF3D29CFFF3F2BD1FF462DD5FF492FD7FF4A30D8FF
+ 482FD7FF442ED4FF442CD2FF4229CDFF3E29B4FF362C86FF353472FF3E3F7CFF
+ 3A4180FF364282FF3A4B8EFF375194FF405B9EFF4A66A7FF4A66A6FF415D9EFF
+ 365495FF365293FF385396FF364F95FF385098FF3A4D96FF34468DFF2B3B80FF
+ 263678FF2B3A78FF2F417EFF364D8BFF375193FF3E589EFF405BA5FF3E59A9FF
+ 3A55A6FF364F9FFF344B99FF34488FFF324382FF313D73FF323964FF353658FF
+ 3A364FFF3F3748FF3E3347FF322846FF372749FF3E2648FF492A3FFF55322FFF
+ 5F3822FF653E18FF684115FF673D1AFF653C1CFF623C1CFF633E1CFF663F19FF
+ 683E19FF6C3D1EFF6E3C1EFF6D3D19FF6B3E18FF6A3D1BFF683D1CFF653C1CFF
+ 653C1CFF673D1AFF673D18FF673D18FF633D1AFF59391CFF462D19FF332018FF
+ 241A1AFF1D1821FF191925FF1D1B27FF1E1C28FF1F1C2BFF211E2DFF231F32FF
+ 252134FF262136FF272237FF272138FF272138FF282338FF282338FF272336FF
+ 262235FF242033FF222033FF1B1B2DFF1E1E2CFF261E28FF241D22FF211A1DFF
+ 271F1FFF382D25FF4A3827FF5C3F20FF654119FF694117FF694117FF67401AFF
+ 67401AFF6C3F19FF6C3F19FF6F421DFF6D401EFF6E401EFF6C3F1DFF6D3F1DFF
+ 6B3F1AFF6C3F1AFF6A3E19FF6D401BFF6C411AFF6D401AFF6C4218FF6D4118FF
+ 6C4218FF6D4118FF6D401AFF6C3F1AFF6C3F1AFF6C3F1AFF6C3F1AFF6C3F1AFF
+ 6C3F1AFF6C3F1AFF6C3F1AFF6C411AFF6C411AFF6D421BFF6D4319FF6E411BFF
+ 6E441AFF70441BFF6F441DFF6C3E1CFF6D401FFF6D4221FF6C4120FF693F1CFF
+ 6B3F16FF744311FF7E480BFF985F10FFA96E11FFB97C14FFBD8012FFB97E11FF
+ B2780FFFA56B0CFF925D0DFF774B10FF6E4514FF6A4011FF6A4013FF6F4217FF
+ 704219FF70411BFF6E3E1AFF713F1BFF6F3F1DFF6C3E1CFF6A3D1BFF683E1BFF
+ 663E1BFF653F1CFF68401DFF6B411EFF6D401EFF6D401FFF6C3F1DFF6D3F1DFF
+ 6C3E1CFF6C3E1CFF6C3F1AFF6E3E1AFF6F401AFF71421CFF74431DFF74431DFF
+ 73421AFF71401AFF6E4017FF704317FF6E4415FF6F4516FF6E4616FF6F4619FF
+ 6F4619FF70471AFF704818FF6F4717FF6F4716FF6D4514FF714918FF764F1BFF
+ 6F4814FF754E1AFF856335FFAD8F6CFFB8A18BFFCCB9B1FFDDD0CEFFEAE2E3FF
+ F2EDECFFFAF4EDFFFDFAF2FFF4F5F1FFECF1F0FFECEFF7FFF3F4F8FFFFF8F4FF
+ FFEDD8FFD8B88DFFA77A36FFB57D18FFBD800CFFBE7F0CFFBE800AFFBE800AFF
+ BD8008FFBF8006FFBE7F05FFBE7F05FFC07F05FFC07F05FFC07F05FFC07F05FF
+ C07F05FFC07F05FFC07F05FFBF8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FF
+ BC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBA7D05FFBB7E06FFBB7E06FFBB7E06FFBB7E06FF
+ BB7E06FFBB7E06FFBB7E06FFBB7E06FFBB7E06FFBB7E06FF3D2AD3FF3F2AD3FF
+ 442AD4FF462DD5FF472ED6FF472FD5FF4630D6FF4830D6FF482ED5FF432DBBFF
+ 382D89FF353474FF3D3E7BFF3A3F7CFF36417FFF384A89FF3E5495FF415C9CFF
+ 4863A3FF4763A0FF3F5A9AFF375393FF385294FF3A5497FF364F95FF374F97FF
+ 364992FF2C3E85FF25357AFF263678FF304180FF374988FF405697FF3E589BFF
+ 405AA0FF405BA5FF3E5AA7FF3957A6FF3651A2FF344E9BFF334893FF344687FF
+ 323D76FF323865FF37385AFF39364CFF3A3340FF3B3040FF3A2847FF3F2747FF
+ 472A41FF512F36FF5B342BFF623A21FF653C1BFF653D1AFF623A1DFF623A1EFF
+ 633B1EFF633C1CFF653C1BFF683D1CFF6A3B1FFF6B3B1FFF6A3D18FF693E17FF
+ 673D1AFF633D1BFF633E1CFF633E1CFF663E1BFF683E1BFF663C19FF653C1BFF
+ 5E391DFF51311EFF3A251DFF281A1BFF1D1821FF1B1827FF1C1A26FF1D1B27FF
+ 1E1B2AFF201D2CFF221E31FF242033FF252035FF262136FF262037FF272138FF
+ 282338FF282338FF282437FF272336FF262235FF232134FF1C1B2FFF1E1D2DFF
+ 261E28FF271D23FF261D20FF2D2421FF3A3026FF4B3A27FF5C401EFF644217FF
+ 674216FF674315FF654217FF654217FF6B4215FF6C4116FF6F4020FF6E3E22FF
+ 703E22FF6D3E1FFF6F3D1FFF6C3D1EFF6E3C1EFF6B3C1CFF6F3E1EFF6D3F1DFF
+ 6F3F1DFF6D3F1DFF6F3F1DFF6D3F1DFF6F3F1DFF6D3F1DFF6E3F20FF6D3F20FF
+ 6D3F20FF6D3F20FF6D401FFF6D401FFF6E3F1FFF6E3F1FFF6C3E1CFF6D401BFF
+ 6D401BFF6E411BFF70401CFF6F421CFF71421CFF6F421CFF70401CFF6F411FFF
+ 6D401EFF693F1CFF673D18FF693E17FF704115FF794411FF88500FFF9B6115FF
+ AE7219FFB17619FFAC7316FFA06A13FF925C0FFF7E4E0CFF6F4713FF684317FF
+ 6A4317FF6C4217FF6F431AFF71431AFF71401AFF703F19FF733F1AFF703E1AFF
+ 6D3D19FF6B3E19FF683E19FF67401AFF66411BFF68411BFF6E421DFF6F421DFF
+ 6E401EFF6D401BFF6F3F1BFF6E3E1AFF6D3D19FF6D3E18FF71401AFF724119FF
+ 73421AFF76431BFF76431BFF754319FF744119FF734117FF704318FF704317FF
+ 714418FF6F4518FF704617FF704617FF714718FF714817FF6F4615FF724A16FF
+ 704814FF6F4713FF6E4615FF6B4312FF7D5524FF99764AFFB89C7DFFB39E89FF
+ BFAEA5FFD6C9C7FFEAE2E3FFF5EFF0FFF9F4F1FFF8F5F1FFF6F4F3FFF2F2F2FF
+ EBECF0FFFCF7F4FFFFFFF0FFF6DAB7FFC69E64FFB17E2EFFB57B12FFBD7E0BFF
+ BD800AFFBD800AFFBD800AFFBC8008FFBB8005FFBB8005FFBC8004FFBE8004FF
+ C08004FFC08004FFC27F05FFC27F05FFC27E07FFC27E07FFBF8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBB7E06FFBB7E06FF
+ BB7E06FFBB7E06FFBB7E06FFBB7E06FFBB7E06FFBA7D05FFBB7E06FFBB7E06FF
+ BB7E06FF3E2BD4FF402BD4FF412AD2FF432BD1FF442CD0FF452DD1FF4530D3FF
+ 4830D4FF4A30D7FF452FBDFF3B308DFF363476FF3C3B79FF383E79FF36427CFF
+ 3B4D88FF425795FF435C9AFF465F9DFF455F9BFF415A98FF3B5794FF3B5696FF
+ 3D579AFF375096FF384E96FF33468FFF263A81FF23367AFF2C3E7FFF3A4B8AFF
+ 405593FF4A62A4FF4660A6FF425EA5FF3E5BA5FF3A58A5FF3654A3FF324D9EFF
+ 304999FF314592FF35458AFF323D77FF333767FF3A3959FF3B364BFF39313CFF
+ 3E303CFF412842FF492942FF512F36FF58342CFF603923FF633B1EFF633C1CFF
+ 623B1BFF613B1DFF613B1BFF623C1AFF653D1AFF673C1BFF683D1CFF683C1FFF
+ 683C1DFF673D1AFF653D1AFF633D1AFF623D1BFF613E1CFF613E1CFF643E1CFF
+ 663D1CFF663B1AFF663A1BFF633A21FF563522FF422821FF2C1B1EFF1E1621FF
+ 1A1726FF1C1A26FF1D1B27FF1E1B2AFF201D2CFF221E31FF242033FF252035FF
+ 262136FF262037FF272138FF282338FF282338FF282437FF282437FF262235FF
+ 242235FF1F1D31FF201D2DFF251D27FF291F25FF2C2326FF362A28FF3F322AFF
+ 4C3826FF5C3F20FF65401AFF694117FF694117FF67401AFF694019FF6C4017FF
+ 6E4017FF6D3E1EFF6D3D21FF6D3D21FF6C3C20FF6C3D1EFF6C3D1EFF6C3D1EFF
+ 6C3D1EFF6C3D1DFF6C3D1DFF6C3E1CFF6C3E1CFF6C3E1CFF6C3E1CFF6C3E1CFF
+ 6C3D1DFF6E3F20FF6D3F20FF6D3F20FF6D401FFF6D401FFF6D401FFF6E3F1FFF
+ 6E401EFF6B3E19FF6B3E19FF6C3F19FF6D401AFF70411BFF6E411BFF6F401AFF
+ 6F401AFF71421CFF6E411CFF6A411AFF663F18FF653E18FF683F18FF6C3F19FF
+ 744317FF7B4411FF8D5417FF9C611BFF9D6419FF956017FF8C5913FF7E4F11FF
+ 71450FFF6B4417FF694319FF6C441AFF6E441AFF6F421CFF71421CFF713F1BFF
+ 703E1AFF713F1BFF703E1AFF6E3E1AFF6B3E18FF6B4019FF6A411AFF694319FF
+ 6C431CFF6E421DFF6F421DFF6F421DFF6E411CFF6F3F1BFF6F401AFF6E3F19FF
+ 6E3F19FF72411BFF73421AFF73421AFF74441AFF76441AFF754319FF754319FF
+ 724218FF724119FF704219FF714419FF714419FF704619FF704617FF714718FF
+ 714817FF704716FF724918FF714817FF6D4314FF6A4011FF72481BFF906639FF
+ AC8860FFB99F81FFB4A08EFFC5B6ADFFE0D4D2FFF1E8EBFFF9F2F7FFF7F2F3FF
+ F1ECEDFFF1EFEFFFF3F1F1FFF3EEEFFFFFF4ECFFFFEDD3FFDBB98BFFB68841FF
+ B98128FFB87B13FFBD7F0DFFBE810BFFBC830AFFBA8106FFB78105FFB98005FF
+ BA8106FFBB8104FFBC8004FFBE8004FFC08004FFC27F05FFC27F05FFC37D07FF
+ C27E07FFBF8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBC7F07FFBD8008FFBE8109FFBF820AFFBF820AFFBE8109FFBD8008FF
+ BC7F07FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBB7E06FF
+ BB7E06FFBB7E06FFBB7E06FFBB7E06FF3F2ED3FF412DD3FF422DD0FF432CCEFF
+ 442FCCFF442FCCFF432FCEFF462FD1FF482FD3FF452FBDFF3C318EFF363476FF
+ 3B3B77FF383F78FF38457DFF40538CFF455A97FF445C98FF455D99FF435E97FF
+ 425C98FF415B97FF405B9BFF405A9CFF394F96FF394F97FF334691FF283B84FF
+ 293B82FF35488BFF445697FF4A5E9FFF4D64A8FF4861A9FF435FA6FF3E5BA5FF
+ 3A58A5FF3453A2FF2F4C9DFF2E4797FF2D418EFF33428AFF313B77FF323666FF
+ 3C3B5BFF3D394CFF3A323CFF42333BFF492B3EFF512D39FF59352BFF5E3C1FFF
+ 633F1BFF633E18FF613C1AFF5F3C1BFF5E3C18FF603D15FF643F13FF663F13FF
+ 673D18FF653D1AFF623E1AFF633E1CFF623C1AFF613B1BFF603D1CFF5E3D1CFF
+ 5D3E1DFF5D3E1DFF623F1EFF653E1EFF663A1BFF66391EFF643A23FF5C3828FF
+ 472A25FF2F1C1FFF1F1521FF1C1726FF1C1A26FF1C1A26FF1E1B2AFF201D2CFF
+ 211D30FF231F32FF252035FF252035FF262037FF272138FF282338FF292439FF
+ 292538FF282437FF272336FF252336FF201E32FF1F1C2CFF251C26FF2C2026FF
+ 34292CFF3D2F30FF46332EFF4F3529FF603C24FF693D1EFF6C3D1DFF6C3D1EFF
+ 6B3C21FF6C3C20FF723C1EFF723C1DFF6B3C1CFF683D1CFF683D1CFF683D1CFF
+ 683E1BFF693F1CFF693F1CFF693F1CFF693F1AFF693F1AFF693F1AFF693F1AFF
+ 694019FF694019FF694019FF6B4019FF6C3F1AFF6C3F1AFF6C3F1AFF6C3F19FF
+ 6C3F19FF6C3F19FF6C3F19FF6C3F19FF693D14FF6A3E15FF6B3F16FF6C4218FF
+ 6D4118FF6C4218FF6C4017FF6B3F16FF6F401AFF6C3F19FF694117FF654217FF
+ 644119FF66411BFF6B401FFF6E401EFF713C17FF7F481BFF89501CFF844F16FF
+ 794A12FF744813FF6E4616FF674216FF694216FF6A4218FF6D4319FF6E431CFF
+ 6F421DFF6E411CFF70401EFF6F3F1DFF6F3F1DFF6F3F1BFF6C3F1AFF6C4017FF
+ 6D4217FF6D4417FF6E4616FF6D4619FF6C431CFF6C421FFF6C421FFF6C421FFF
+ 6C421FFF6B411CFF6D411CFF6D421BFF70431DFF70431DFF6F421CFF6F431AFF
+ 71431AFF71431AFF72441BFF72441BFF70401CFF70401CFF71421CFF71421CFF
+ 72441BFF72451AFF73461AFF734718FF744819FF714418FF714418FF6F4217FF
+ 704219FF855630FFA97955FFBC9372FFBCA284FFBEAD98FFDACBC2FFF1E5E5FF
+ F5EBF1FFF5EDF7FFF5F1F7FFF0ECF1FFF1EDF2FFF6F1F2FFFBF2EFFFF4E1D2FF
+ D8BA97FFB99157FFB17F2DFFBB7F1FFFBC7D15FFBF8012FFBD820EFFBA8408FF
+ B78203FFB48102FFB78104FFB98306FFB98005FFBB8104FFBE8004FFC08003FF
+ C27F04FFC37E05FFC57C08FFC37D08FFBF8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBD8008FFC0830BFFC2850DFF
+ C2850DFFC0830BFFBD8008FFBC7F07FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BC7F07FFBC7F07FFBB7E06FFBB7E06FFBB7E06FFBB7E06FFBB7E06FF442FD1FF
+ 4430CFFF4631CEFF4732CBFF4631CAFF4631CAFF442FCBFF452ECCFF472ECCFF
+ 4430B8FF3B328CFF373676FF3A3B77FF383F78FF3C4780FF475890FF485C96FF
+ 435B95FF435B95FF435B95FF435D99FF455F9BFF455E9EFF455D9FFF3A5097FF
+ 3B4E97FF354891FF2C3F88FF2E4289FF3B5193FF4A5E9FFF4D63A5FF4660A6FF
+ 425EA5FF3F5CA6FF3C5CA5FF3B5AA5FF3755A2FF304E9BFF2F4996FF293D8AFF
+ 314088FF2E3977FF313667FF3E3D5FFF403A4DFF3E343AFF4B3638FF502E34FF
+ 58322EFF5D3921FF633F1BFF644018FF633F17FF613C1AFF5E3B1AFF5E3D16FF
+ 603E13FF643F13FF643F13FF673D18FF653D1AFF623E1AFF603E1AFF613C1AFF
+ 613B1BFF603D1CFF5E3C1EFF5F3D1FFF5F3D1FFF603F1EFF643E1EFF643B1BFF
+ 663A1DFF673B23FF623A28FF4C2D24FF331E1DFF23161EFF1E1823FF1D1924FF
+ 1C1A26FF1E1B2AFF1F1C2CFF211E2EFF231F32FF262033FF272134FF262136FF
+ 272237FF262438FF272539FF272539FF262437FF262437FF252434FF211F32FF
+ 1F1C2BFF231B25FF2C2228FF372C2FFF413334FF48342FFF513426FF643B24FF
+ 6B3C20FF6E3C20FF6E3C20FF6C3A23FF6E3A23FF723B20FF703C1EFF683B1AFF
+ 643C19FF653D1AFF653D1AFF663E1BFF67401AFF673F1CFF67401AFF67401AFF
+ 67401AFF67401AFF67401AFF674019FF674019FF674019FF694019FF693E17FF
+ 6A3D17FF693E17FF693E17FF693E17FF693E17FF693E17FF693E17FF673D13FF
+ 683E14FF6A4016FF694117FF6B4117FF694117FF6A4016FF693E17FF6A3D17FF
+ 6B3E18FF694019FF66421AFF68441CFF68421FFF694020FF6D3F20FF6C3B1BFF
+ 76421EFF78441BFF703F13FF673A0FFF673D13FF65401AFF67421CFF673E17FF
+ 683F18FF6B4019FF6C401BFF6D401EFF6D401EFF6E3F1FFF6E401EFF6E401EFF
+ 6D401BFF6D401BFF6D4118FF6D4217FF6F4518FF6F4717FF70471AFF6C431CFF
+ 6C421FFF6C421FFF6C421FFF6C421FFF6C421DFF6E421DFF6E431CFF70451EFF
+ 6F441DFF6F421CFF6E4219FF6E4219FF6F431AFF70441BFF73451CFF72411BFF
+ 72411BFF73421CFF73421CFF72441BFF72441BFF73461BFF73461AFF76491DFF
+ 6F4216FF714117FF704219FF754521FF926442FFB88969FFC1997CFFC0A78DFF
+ CBB9A8FFE8DAD4FFF8EDF0FFF0E8EFFFEEE9F2FFF7F3F9FFF5F4F8FFF5F1F6FF
+ F9F4F3FFFFF6EAFFE8D0B4FFB38E5CFFA4742CFFB77E23FFBA7C16FFBD7E16FF
+ C08113FFBE830FFFBA830AFFB68003FFB57F02FFB88206FFBA8408FFB98007FF
+ BB7F07FFBE7F05FFC07F05FFC07F05FFC27E07FFC27C0AFFC27C0AFFBF7F09FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBB7E06FF
+ BE8109FFC1840CFFC4870FFFC4870FFFC1840CFFBE8109FFBB7E06FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBF820AFF
+ BF820AFFBE8109FFBD8008FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBC7F07FF
+ BC7F07FFBC7F07FF4028C4FF422AC4FF432DC2FF452FC3FF4630C4FF452FC4FF
+ 452EC6FF442DC5FF4229BFFF3A29A8FF373484FF393D78FF3B3E7BFF3B407DFF
+ 3F4782FF414F89FF4B629AFF405B93FF38538CFF354F8BFF374E8CFF384E8FFF
+ 374D8FFF34498DFF40549BFF3B4E97FF33468FFF31458CFF384F93FF475EA2FF
+ 4C66A8FF4A65A8FF415DA4FF3D5DA6FF3C5DA6FF3B5CA5FF3858A1FF33539CFF
+ 304B95FF2D468EFF334893FF34468DFF2F3E7DFF333B70FF3D3E60FF3F3748FF
+ 453536FF573E34FF5B3929FF613A24FF623C1EFF633D1BFF623C1AFF623C1AFF
+ 613A1AFF603A1AFF5F3A18FF613B18FF623C19FF623C19FF643B1AFF623C1AFF
+ 613B19FF603A18FF633C16FF633C16FF643B1AFF643B1BFF613B1DFF603C1EFF
+ 603D1CFF603D1BFF623C19FF643A17FF673B1CFF663D24FF563525FF3D271CFF
+ 291C1AFF20191CFF19151BFF191520FF1A1726FF1C1B2BFF211E2EFF241E2FFF
+ 27202FFF27202FFF272132FF262235FF222338FF22253AFF22253AFF222639FF
+ 252535FF262634FF2B2733FF221E29FF1E1A25FF28242AFF342F31FF3E3230FF
+ 473328FF523421FF643B22FF693B1CFF6B391BFF6C3A1CFF6D3E1FFF6E3F20FF
+ 6D3E1EFF6C3E1CFF693E1DFF673E1DFF673E1DFF683F1EFF683F1EFF69411EFF
+ 69401FFF69411EFF673F1CFF663E1BFF653D1AFF633B18FF633B18FF633B18FF
+ 643C19FF643C19FF683E1BFF673D1AFF663C19FF663C19FF663C19FF673D1AFF
+ 693F1CFF6A401DFF683E1BFF683E1BFF683E1BFF663E1BFF683E1BFF663E1BFF
+ 683E1BFF683E1BFF6A3D1BFF6A3D1BFF6A3D1BFF683E1BFF683E1BFF683D1CFF
+ 683D1CFF6A3D1CFF6F4020FF6E401EFF6E3E1AFF6A3D18FF6A3D18FF693C1AFF
+ 683E1BFF693F1CFF6A401DFF68401DFF6A401DFF6A401DFF6A3F1EFF6A3F1EFF
+ 6C3F1DFF6C3F1DFF683B19FF693D18FF6B3F1AFF6D421BFF6F431AFF6F431AFF
+ 6F431AFF6F431AFF70431EFF6F421DFF6E411CFF6D401BFF6D401BFF6D401AFF
+ 6F421CFF6F421CFF71441EFF6E4219FF6E4017FF6E4116FF714419FF74471CFF
+ 74471CFF75451BFF7B491BFF7C481AFF7A471CFF78461CFF76451DFF73451CFF
+ 73451CFF72451AFF6C3D11FF744519FF72451AFF6F431AFF825833FFA87F5EFF
+ C19B7DFFC2A088FFB99E8AFFCFBBB0FFE8DADEFFF4EAF6FFF4EFF8FFF4F0F5FF
+ F5F3F3FFF6F4F3FFEDEDEDFFFEF8F1FFEFE0C6FFBDA172FFA2772EFFB27B20FF
+ C0811FFFBA7811FFBC7D0FFFBE7F0FFFC08210FFBD820EFFBA8009FFB97F08FF
+ BB800CFFBD820EFFBE810DFFBD800CFFBD7E0BFFBC7D0AFFBC7D0AFFBD7E0BFF
+ BE7F0DFFBF800DFFBC7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBC7F09FFBB7E08FFBB7E08FFBA7D07FFBB7E08FFBD800AFF
+ BE810BFFC0830DFFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF3C22BCFF3C23BBFF3D26B8FF
+ 3D26B6FF3D25B9FF3C23B9FF3A21B9FF3920B6FF341DAFFF32239CFF33337FFF
+ 353C75FF343976FF343976FF3B417CFF3F4B85FF41598FFF3C5B90FF3F5A92FF
+ 3E5992FF3E5593FF3A5091FF394C8FFF384B8FFF3A4C93FF3A4C93FF374C90FF
+ 374D8FFF3E5698FF4964A4FF4F6AAAFF4A68A9FF5372B7FF4868B1FF3D5EA7FF
+ 3859A2FF38589FFF37559CFF365096FF314A90FF324890FF32468DFF2E3E80FF
+ 323D71FF3D3D61FF3F3748FF483433FF593C2DFF5D3A20FF623B1BFF623B1BFF
+ 623B1BFF613A1AFF613A1AFF613A1AFF613A1AFF613A1AFF613A1AFF623B1BFF
+ 633C1CFF633C1CFF623B1BFF613A1AFF613B19FF633C15FF653C15FF663C19FF
+ 663A1BFF623A1DFF623C1EFF603D1CFF603E1AFF633E18FF633C16FF693C1AFF
+ 683E21FF5B3922FF442A1CFF2C1F17FF211919FF1E181DFF1B1722FF1B1827FF
+ 1C1B2BFF201D2DFF231E2DFF251E2DFF251E2BFF292132FF262235FF222338FF
+ 1F233BFF20243CFF1F2439FF252535FF272531FF2A242FFF221D26FF1C1B25FF
+ 26252EFF343133FF403531FF4C3728FF573821FF653D21FF693B1CFF6B391BFF
+ 6A3B1CFF6D3E1EFF6D401FFF6C3F1DFF683E19FF693E1DFF673E1DFF673E1DFF
+ 683F1EFF683F1EFF683F1EFF69401FFF69401FFF673E1DFF663D1CFF653C1BFF
+ 643B1AFF633A19FF643B1AFF643B1AFF653C1BFF653C1BFF653C1BFF643B1AFF
+ 643B1AFF643B1AFF653C1BFF673E1DFF683F1EFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF6A3D1CFF6A3D1CFF6A3D1CFF
+ 6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6D401FFF6C3F1EFF6B3E1DFF
+ 6A3D1CFF693C1BFF6A3D1CFF6B3E1DFF693E1DFF693E1DFF673E1DFF673E1DFF
+ 673E1DFF693E1DFF693E1DFF693F1CFF693F1CFF683C17FF693D18FF6B3F1AFF
+ 6D411CFF6F421CFF6F421CFF6F421CFF6F421CFF72421EFF71411DFF70401CFF
+ 6F3F1BFF6F401AFF70411BFF71421CFF71421CFF73451CFF71431AFF6F4217FF
+ 704318FF73461BFF75481DFF74471CFF75461AFF7C4819FF7E4819FF7A471CFF
+ 78461CFF73451CFF73451CFF73451CFF72441BFF72451AFF72451AFF704318FF
+ 774C25FF906A47FFB28F6EFFBD9F84FFB89B86FFBBA292FFD4C0BBFFEADDE5FF
+ F3EAF7FFF4EFF8FFF0EFF1FFEFF0EEFFF4F3EFFFF5F2EEFFFFF7E9FFE4CEAAFF
+ B49054FFA97921FFB87E17FFBE7C16FFBC7A11FFBD7E0EFFBE800EFFBF810FFF
+ BF810FFFBE800EFFBD7F0DFFBE800EFFBF810FFFBE800EFFBD7F0DFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE810DFFBC7F0BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBE810BFFBD800AFFBC7F09FF
+ BB7E08FFBB7E08FFBB7E08FFBC7F09FFBD800AFFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ 371FBBFF3720B8FF3721B5FF3621B3FF351FB3FF331DB2FF311AB2FF301AAFFF
+ 2A15A7FF2C2098FF31347FFF353F75FF323A75FF2F3772FF353D78FF3C4981FF
+ 374F85FF3B578DFF465F97FF48609AFF455A97FF3E5391FF3C4E8DFF3B4D8EFF
+ 2D3E81FF2F4285FF324889FF3B5290FF4962A0FF5A76B2FF6480BCFF6380BDFF
+ 5C7CBEFF4D6DB4FF3E60A6FF37599FFF3959A0FF3A589FFF375098FF314991FF
+ 324792FF34468DFF313F81FF343F73FF3F4062FF413747FF463330FF563A29FF
+ 5B381EFF603919FF613A1AFF613A1AFF613A1AFF613A1AFF623B1BFF623B1BFF
+ 623B1BFF623B1BFF633C1CFF643D1DFF643D1DFF633C1CFF623B1BFF623C1AFF
+ 633C16FF633C16FF643B1AFF643B1BFF623A1DFF623C1EFF603D1CFF603D1BFF
+ 643F19FF643D17FF693C1AFF683F1FFF5F3B23FF492F1FFF332219FF241915FF
+ 211A1DFF1F1A23FF1C1A26FF1C1C2AFF1D1C2CFF1F1C2BFF231C2BFF231C29FF
+ 282031FF252134FF212237FF21233BFF212439FF212538FF252434FF292531FF
+ 28202AFF221A24FF1F1B26FF2A2730FF383335FF433932FF4E392AFF5A3A23FF
+ 653D20FF693C1BFF6B3A1AFF6A3B1BFF6C3D1EFF6C3F1EFF6B3E1CFF683E19FF
+ 683D1CFF663D1CFF673E1DFF673E1DFF683F1EFF683F1EFF683F1EFF69401FFF
+ 683F1EFF673E1DFF663D1CFF653C1BFF643B1AFF643B1AFF653C1BFF653C1BFF
+ 653C1BFF643B1AFF643B1AFF643B1AFF643B1AFF653C1BFF663D1CFF673E1DFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF
+ 6B3E1DFF6B3E1DFF6A3D1CFF6A3D1CFF6A3D1CFF6B3E1DFF6C3F1EFF6A3F1EFF
+ 683D1CFF663D1CFF663D1CFF663D1CFF683D1CFF683D1CFF683E1BFF683E1BFF
+ 693D18FF6A3E19FF6B3F1AFF6D411CFF6F421CFF6F421CFF6E411BFF6E411BFF
+ 71411DFF70401CFF70401CFF6F3F1BFF6F401AFF70411BFF71421CFF71421CFF
+ 73451CFF72441BFF72451AFF73461BFF75481DFF75481DFF74471CFF744519FF
+ 79461BFF79461BFF78461CFF76451DFF73451CFF71441EFF71451CFF70441BFF
+ 764B20FF6E4318FF70461CFF87603AFFA88564FFBD9D80FFBCA088FFB19987FF
+ C0ACA1FFDDCECBFFF2E6ECFFF5ECF6FFF4F0F6FFEEEDEFFFECECECFFF4F3EFFF
+ F8F2EBFFF6E7D4FFCFB083FFA77D38FFB17D1FFFBE841BFFBF8018FFC3851BFF
+ BF8010FFBE800EFFBE800EFFBE800EFFBF810FFFC08210FFBF810FFFBE800EFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD800CFF
+ BD800CFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFF
+ BF820CFFBE810BFFBD800AFFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FF3D24C2FF3D25BFFF3C26BBFF3B25B9FF3A24B9FF
+ 3922BAFF3820BAFF3720B8FF3420AFFF32269CFF333680FF374276FF374079FF
+ 353E77FF39427BFF3C4981FF374C83FF3A548AFF425B93FF475E96FF455B95FF
+ 425592FF3D508DFF3B4E8BFF354786FF354885FF364B88FF405892FF5570A8FF
+ 6C87BFFF7493C8FF7290C9FF5576B5FF4A6BB0FF4162A7FF3B5BA2FF3B59A0FF
+ 3A569DFF364F97FF334991FF324590FF34468DFF324082FF373F74FF424163FF
+ 413845FF44312CFF533824FF5C3A1DFF613A1AFF613A1AFF623B1BFF633C1CFF
+ 633C1CFF643D1DFF643D1DFF623B1BFF633C1CFF643D1DFF653E1EFF653E1EFF
+ 643D1DFF633C1CFF623C1AFF613B18FF613B18FF643B1AFF623A1DFF613A1EFF
+ 603B1FFF603C1EFF603D1BFF65401AFF653E17FF693D18FF683F1FFF613E24FF
+ 523421FF3A271AFF271B15FF231B1BFF1E1A20FF1B1A24FF1B1B29FF1C1B2BFF
+ 1E1B2AFF231C2BFF231C29FF27202FFF242033FF232137FF22223AFF222338FF
+ 222337FF262333FF2A2330FF29202AFF241C23FF231E27FF2C2A30FF3A3537FF
+ 443832FF50392AFF5A3A23FF653D20FF693C1BFF6B3A1AFF6A3B1BFF6B3D1EFF
+ 6C3F1EFF6A3D1BFF673D1AFF663D1CFF663D1CFF663D1CFF673E1DFF673E1DFF
+ 683F1EFF683F1EFF683F1EFF683F1EFF673E1DFF663D1CFF653C1BFF643B1AFF
+ 643B1AFF653C1BFF663D1CFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 653C1BFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF683D1CFF6A3D1CFF6A3D1CFF6A3D1CFF6A3D1CFF
+ 6A3D1CFF6A3D1CFF6A3D1CFF693C1BFF6A3D1CFF6A3D1CFF6A3D1CFF6B3E1DFF
+ 6C3F1EFF6C3F1EFF6B401FFF663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF
+ 683D1CFF683E1BFF683E1BFF693D18FF6A3E19FF6C401BFF6D411CFF6E411BFF
+ 6E411BFF6E411BFF6D401AFF70401CFF70401CFF70401CFF70401CFF70411BFF
+ 71421CFF71421CFF71421CFF72441BFF73451CFF74471CFF75481DFF76491EFF
+ 75481DFF74471CFF72451AFF77451BFF77451BFF75441CFF73451CFF71441EFF
+ 71441EFF71451CFF71451CFF73471EFF6C4218FF7B522BFF9F7B57FFB9997CFF
+ BA9F85FFB69D89FFB5A293FFCABDB5FFE9DDDDFFF8ECF2FFF6EBF3FFF5EFF4FF
+ F2EFF1FFEEEEEEFFF9F6F1FFFFF3E7FFE5CDAFFFBC965CFFAB7A2AFFBA821DFF
+ C08518FFBD8018FFC3871DFFBF8312FFBE800EFFBD7F0DFFBE800EFFC08210FF
+ C18311FFBF810FFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBD800CFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFF
+ BD800AFFBD800AFFBD800AFFBE810BFFBD800AFFBD800AFFBC7F09FFBC7F09FF
+ BB7E08FFBB7E08FFBB7E08FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF4329C9FF432BC7FF
+ 432CC4FF422CC1FF422AC4FF432BC5FF432BC7FF432CC4FF4430BFFF392EA2FF
+ 31357CFF343F71FF3A447AFF3B457BFF3B457BFF3A487DFF3B5087FF395187FF
+ 3A5288FF3F538CFF42568FFF42548FFF3E508BFF3B4D88FF3A4C87FF394D86FF
+ 3B528AFF4A649AFF6481B4FF7D9ACDFF81A1D2FF7999CEFF5978B5FF5174B4FF
+ 496AAFFF3F60A5FF38569DFF345097FF354C97FF374C97FF314390FF35448DFF
+ 344082FF373F74FF424161FF413743FF443129FF523722FF5E3C1FFF633C1CFF
+ 633C1CFF643D1DFF653E1EFF653E1EFF663F1FFF663F1FFF623B1BFF633C1CFF
+ 643D1DFF653E1EFF653E1EFF643D1DFF633C1CFF623B1BFF613B19FF603B19FF
+ 623B1BFF613B1DFF613A1EFF603B1FFF603C1EFF623D1BFF643F19FF663F18FF
+ 6A3E19FF673E1DFF633E22FF583924FF432C1CFF302118FF231A17FF1F1A1CFF
+ 1A1922FF191925FF1A1B29FF1D1D2BFF221D2CFF251E2BFF261F2EFF251F30FF
+ 232135FF232137FF232137FF232236FF272132FF2B222FFF2D222AFF291F25FF
+ 28202AFF2F2B31FF3A3336FF413531FF4D3627FF583821FF653D20FF693C1BFF
+ 6B3A1AFF693A1AFF6A3C1DFF693D1EFF673C1BFF653A19FF653C1BFF653C1BFF
+ 663D1CFF663D1CFF673E1DFF673E1DFF683F1EFF683F1EFF683F1EFF673E1DFF
+ 653C1BFF643B1AFF643B1AFF643B1AFF653C1BFF653C1BFF623918FF633A19FF
+ 633A19FF643B1AFF653C1BFF653C1BFF653C1BFF653C1BFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF683D1CFF
+ 683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF673C1BFF673C1BFF
+ 683D1CFF693E1DFF693E1DFF6A3F1EFF6A3F1EFF6A3F1EFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF683D1CFF683D1CFF683E1BFF683E1BFF6A3E19FF6B3F1AFF
+ 6C401BFF6D411CFF6E411BFF6E411BFF6D401AFF6D401AFF6E3E1AFF6F3F1BFF
+ 70401CFF70401CFF71421CFF71421CFF71421CFF71421CFF72441BFF74461DFF
+ 75481DFF76491EFF75481DFF74471CFF73461BFF72451AFF72441BFF72441BFF
+ 72431DFF70431DFF71441EFF71441EFF71451CFF71451CFF6B4117FF704720FF
+ 8E6845FFB69574FFC0A289FFB19983FFB4A08FFFC4B5ACFFD8D1CEFFEEE8E9FF
+ FBF0F3FFF5EBF1FFF4EFF1FFF6F3F5FFF4F2F1FFFCF5ECFFFAE5CFFFCCAA7FFF
+ B3823CFFBA8124FFBC8114FFB87C0BFFB57B11FFB77D13FFBE8211FFBE810DFF
+ BC7F0BFFBD800CFFC0830FFFC18410FFBF820EFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBD800CFFBD800CFFBC7F0BFFBC7F0BFFBC7F0BFFBD800AFFBD800AFF
+ BD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBB7E08FFBB7E08FF
+ BC7F09FFBC7F09FFBD800AFFBD800AFFBD800AFFBD800AFFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FF4429CCFF442BC9FF442CC6FF442DC5FF452DC9FF472FCBFF4830CCFF
+ 4932CAFF4B37C6FF3B30A4FF2E3378FF303D6BFF394476FF3C477BFF3B467AFF
+ 374579FF3E5387FF3A4F86FF374C83FF3A4E85FF3E518AFF3F528BFF3E4F88FF
+ 384B84FF354881FF394C85FF42578EFF546CA0FF6D88BBFF829FD2FF84A4D5FF
+ 7C9CD1FF6888C3FF6081C0FF5274B6FF4263A8FF35539AFF304C93FF354C97FF
+ 3B509BFF32428FFF34438CFF333F81FF383F71FF41415FFF413842FF443227FF
+ 553921FF613C20FF643D1DFF643D1DFF643D1DFF653E1EFF653E1EFF653E1EFF
+ 653E1EFF623B1BFF623B1BFF633C1CFF643D1DFF643D1DFF633C1CFF623B1BFF
+ 623B1BFF603A1AFF603A1AFF613B1DFF5F3A1EFF5F3A20FF603B1FFF603C1EFF
+ 623D1BFF633E18FF694019FF6B3F1AFF683E1BFF643E20FF5B3C23FF4F3420FF
+ 3D2A1DFF251B14FF1E191AFF1B191FFF181923FF191A28FF1C1B2BFF221D2CFF
+ 261F2CFF261F2EFF261E2FFF241F34FF232036FF232036FF232135FF262031FF
+ 2A222DFF2F242CFF2B2127FF29212BFF302930FF373035FF3E322EFF4A3226FF
+ 56361FFF653D20FF693C1BFF693A1AFF693A1AFF6A3C1DFF683C1DFF663B1AFF
+ 643918FF653C1BFF653C1BFF653C1BFF663D1CFF663D1CFF673E1DFF673E1DFF
+ 673E1DFF663D1CFF663D1CFF643B1AFF633A19FF633A19FF633A19FF633A19FF
+ 643B1AFF613817FF623918FF633A19FF643B1AFF653C1BFF653C1BFF643B1AFF
+ 643B1AFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF
+ 683D1CFF673C1BFF683D1CFF693E1DFF6A3F1EFF6A3F1EFF693E1DFF693E1DFF
+ 693E1DFF663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF683D1CFF683E1BFF
+ 683E1BFF6B3F1AFF6B3F1AFF6C401BFF6D411CFF6E411BFF6E411BFF6D401AFF
+ 6C3F19FF6D3D19FF6E3E1AFF6F3F1BFF71411DFF72431DFF72431DFF72431DFF
+ 72431DFF72441BFF74461DFF75481DFF75481DFF73461BFF72451AFF72451AFF
+ 73461BFF6F421CFF6F421CFF70431DFF70431DFF70431DFF71451CFF71451CFF
+ 71451CFF6D421BFF815A34FFA78260FFC0A285FFBDA38BFFB39D8BFFC1B0A3FF
+ D9CEC6FFE7E3E2FFF0EDEFFFFAF1F4FFF5ECEFFFF3EEF0FFFAF6F5FFF7F3EEFF
+ F4E8D6FFD6B895FFB0834AFFAC7220FFC2821CFFBE800EFFB57A06FFB77E11FF
+ B67E13FFBC800FFFBD800CFFBC7F0BFFBD800CFFBE810DFFBE810DFFBD800CFF
+ BC7F0BFFBB7E0AFFBC7F0BFFBD800CFFBD800CFFBD800CFFBD800CFFBC7F0BFF
+ BB7E0AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFFBD800AFF
+ BD800AFFB97C06FFBA7D07FFBB7E08FFBD800AFFBE810BFFBE810BFFBE810BFF
+ BE810BFFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FF432ACEFF432BCBFF422CC8FF422CC8FF
+ 432CCAFF452ECCFF4730CEFF4833CBFF4836C5FF3A32A4FF2F377AFF31416CFF
+ 374575FF3A4879FF3B497AFF3B4A7BFF3D4F84FF3B5084FF3D5286FF405287FF
+ 405189FF3E4F87FF3C4A84FF374881FF3B4E87FF43568FFF4B5F98FF526AA0FF
+ 5F79AFFF6E8AC0FF7695CAFF7695CCFF6C8CC7FF6283C2FF5274B6FF4263A8FF
+ 37559CFF344D95FF344B96FF374C97FF32428FFF33428BFF313D7FFF363D6FFF
+ 40405EFF413842FF483429FF573B23FF603B1FFF633C1CFF623B1BFF623B1BFF
+ 623B1BFF623B1BFF623B1BFF613A1AFF613A1AFF613A1AFF623B1BFF633C1CFF
+ 633C1CFF623B1BFF613A1AFF613A1AFF603A1AFF5E3A1CFF5F3B1DFF5D3B1EFF
+ 5D3A20FF5E3C1FFF603C1EFF623D1BFF633B18FF693F1AFF6C401BFF673D1AFF
+ 633C1CFF603D23FF583922FF493321FF2A1E14FF211C19FF1B1A1EFF181923FF
+ 181927FF1A1929FF201B2AFF231C2BFF271E2BFF261F2EFF251F32FF241F34FF
+ 252035FF242033FF282130FF2A202CFF31242CFF2D2028FF28202BFF2E2630FF
+ 342C33FF3B2E2CFF4A3127FF573622FF653D20FF693C1BFF693B19FF693A1AFF
+ 693B1CFF673B1CFF643B1BFF623919FF653C1BFF653C1BFF653C1BFF653C1BFF
+ 663D1CFF663D1CFF673E1DFF673E1DFF653C1BFF643B1AFF633A19FF623918FF
+ 613817FF623918FF623918FF633A19FF613817FF623918FF633A19FF643B1AFF
+ 653C1BFF643B1AFF643B1AFF633A19FF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF683D1CFF683D1CFF683D1CFF
+ 683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF693E1DFF6A3F1EFF6A3F1EFF
+ 6A3F1EFF693E1DFF683D1CFF673C1BFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 693E1DFF693E1DFF693F1CFF693F1CFF6B3F1AFF6C401BFF6D411CFF6D411CFF
+ 6E411BFF6D401AFF6C3F19FF6C3F19FF6C3C18FF6D3D19FF6F3F1BFF71411DFF
+ 72431DFF72431DFF72431DFF72431DFF73451CFF74461DFF75481DFF73461BFF
+ 704318FF6F4217FF714419FF73461BFF6E411BFF6E431CFF6F431AFF6F431AFF
+ 72441BFF73461BFF73461BFF71461BFF7C5228FF9D7650FFB99877FFBEA186FF
+ B9A08CFFC2AFA0FFDCCCC0FFECE2DBFFEFF0EEFFECEEEFFFF7F0F3FFF7EEF1FF
+ F1ECEDFFFBF6F3FFF8F0E3FFE6D4B7FFB58D5CFFAB762DFFB47415FFC58313FF
+ C1830DFFBA8009FFBB8314FFBD8417FFB97D0BFFBC7F0BFFBD800CFFBD800CFF
+ BB7E0AFFBB7E0AFFBC7F0BFFBD800CFFBB7E0AFFBC7F0BFFBD800CFFBE810DFF
+ BE810DFFBD800CFFBC7F0BFFBB7E0AFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBA7D07FFBB7E08FFBD800AFFBE810BFF
+ BE810BFFBD800AFFBC7F09FFBB7E08FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF452CD0FF
+ 452DCFFF442DCBFF432CCAFF442CCCFF452DCDFF472FCFFF4833CCFF4635C2FF
+ 3C35A4FF353E7EFF374771FF3B4A78FF3C4A7AFF3F4D7DFF425182FF374A7DFF
+ 3C5185FF46588DFF47598EFF44538BFF3D4C84FF394781FF35467FFF3C4C87FF
+ 435590FF4A5E98FF485E98FF4D65A1FF5E78B4FF738FCBFF809ED9FF6483C0FF
+ 597AB9FF4B6DAFFF4162A7FF3C5AA1FF385199FF314893FF2E438EFF31418EFF
+ 32418AFF303C7EFF353C6EFF3F3F5DFF413842FF49352AFF583C24FF5E391DFF
+ 613A1AFF613A1AFF603919FF5F3818FF5F3818FF5E3717FF5E3717FF603919FF
+ 613A1AFF623B1BFF623B1BFF623B1BFF623B1BFF613A1AFF5F3919FF603A1CFF
+ 5E3A1CFF5D3B1EFF5D3B1EFF5D3A20FF5E3C1FFF603C1EFF623D1BFF623A17FF
+ 693F1AFF6C401BFF663C19FF623B1BFF623E20FF5E3D23FF533823FF312114FF
+ 271F18FF1F1D1DFF1A1922FF181826FF191828FF1E1928FF211A29FF261D2AFF
+ 271D2DFF271F30FF262033FF261F34FF262033FF27202FFF2A202CFF2E232BFF
+ 2A1F29FF271E2BFF2B2431FF332A34FF3B2D2FFF483129FF583825FF653D21FF
+ 693C1BFF693B19FF683B19FF673C1BFF673B1CFF633A1AFF613818FF643B1AFF
+ 653C1BFF653C1BFF653C1BFF663D1CFF663D1CFF673E1DFF673E1DFF643B1AFF
+ 633A19FF623918FF613817FF613817FF613817FF613817FF623918FF603716FF
+ 613817FF633A19FF643B1AFF653C1BFF643B1AFF633A19FF633A19FF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF683D1CFF
+ 683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF683D1CFF693E1DFF
+ 693E1DFF6A3F1EFF6B401FFF6A3F1EFF693E1DFF673C1BFF663B1AFF683F1EFF
+ 683F1EFF683F1EFF683F1EFF6A3F1EFF6A3F1EFF6A401DFF6A401DFF6B3F1AFF
+ 6C401BFF6D411CFF6D411CFF6E411BFF6D401AFF6C3F19FF6B3E18FF6C3C18FF
+ 6D3D19FF6F3F1BFF71411DFF72431DFF73441EFF72431DFF72431DFF73451CFF
+ 74461DFF74471CFF714419FF6E4116FF6E4116FF704318FF73461BFF6E4219FF
+ 6E4219FF6F431AFF714419FF72451AFF724519FF73461AFF71461BFF896039FF
+ AF8B67FFC3A485FFB69B81FFB49E8CFFD2C2B2FFF1E2D9FFF5EDE6FFF5F6F4FF
+ EBEDEEFFF5F0F2FFF6EFF2FFF0ECEBFFFEF7EEFFFAECD5FFE0C49BFFB48444FF
+ C4842FFFC8841BFFCA8412FFC3860EFFBC820BFFB9800DFFBD8312FFB77B09FF
+ BC7F0BFFBD800CFFBC7F0BFFBA7D09FFB97C08FFBB7E0AFFBD800CFFBB7E0AFF
+ BC7F0BFFBD800CFFBE810DFFBE810DFFBD800CFFBC7F0BFFBB7E0AFFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBC7F09FF
+ BD800AFFBE810BFFBE810BFFBD800AFFBC7F09FFBA7D07FFB97C06FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FF4229CDFF422ACCFF422ACAFF412AC8FF4028CAFF4028CAFF
+ 3F27C7FF3F2AC3FF4534C1FF3D36A5FF394281FF3B4C73FF3D4D78FF3D4C7AFF
+ 3F4D7DFF425182FF405184FF3F5186FF425287FF445489FF495890FF4C5B93FF
+ 43518BFF32427DFF31407EFF324382FF384A89FF3F5394FF485EA0FF4F67A9FF
+ 536DB0FF5571B2FF5776B5FF5273B2FF4C6EB0FF4869AEFF4462A9FF3D59A0FF
+ 344B96FF2E438EFF384895FF2B3A83FF2F3B7DFF3A4173FF3A3A58FF3B323CFF
+ 48352DFF563924FF5F3A1EFF603919FF5F3818FF613A1AFF643D1DFF653E1EFF
+ 643D1DFF623B1BFF653E1EFF653E1EFF643D1DFF633C1CFF623B1BFF603919FF
+ 5F3818FF5E3818FF603A1CFF5D391BFF5A381BFF5A381BFF5B391CFF5C3A1DFF
+ 603C1EFF643E1CFF643C19FF663C19FF663C17FF663C19FF623C1AFF613B1BFF
+ 603C1EFF593B22FF3C2A19FF291F15FF1C1716FF1A181EFF1A1A26FF191828FF
+ 1B1827FF211A29FF241B28FF241A2AFF231B2CFF211B2CFF211B2EFF211B2CFF
+ 241D2CFF261E29FF2C232DFF291F2BFF271F30FF2B2536FF332A37FF3A2C32FF
+ 4A322CFF5A3929FF633A21FF683D1CFF6B3E1CFF6C3F1DFF693E1DFF663D1DFF
+ 643A1DFF633A1AFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF673E1DFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF673E1DFF673E1DFF673E1DFF673E1DFF693E1DFF693E1DFF
+ 693F1CFF693F1CFF6A3E19FF6A3E19FF6B3F1AFF6C401BFF6D401AFF6C3F19FF
+ 6B3E18FF6B3E18FF6D3D19FF6E3E1AFF70401CFF72421EFF73441EFF74451FFF
+ 74451FFF73441EFF704219FF704219FF704318FF714419FF72451AFF72451AFF
+ 73461BFF73461BFF704318FF784B20FF72451AFF724317FF7A4B1FFF744519FF
+ 714418FF82582DFFA78059FFB4916FFFB89A7FFFAC947EFFAD9987FFC7B7AAFF
+ E8DCD2FFF8F0E9FFFBFAF6FFF7F9F9FFF5F2F4FFF1ECEDFFFAF6F1FFFFF8E6FF
+ E8D0ACFFC49E64FFB97E2EFFC47F1EFFC88112FFC8830EFFC2850FFFBE860FFF
+ BD820EFFBA7F0BFFBF820EFFBF820CFFBF820CFFBF820CFFBF820CFFBF820CFF
+ BF820CFFBF820CFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBD800AFFBD800AFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBB7E06FFBB7E06FFBB7E06FF4229CDFF422ACCFF4129C9FF
+ 4129C9FF4129CBFF4128CCFF4028CAFF402BC4FF4433C0FF3E38A5FF3A4480FF
+ 3D4E75FF3F4F7AFF3F4D7DFF404E7EFF435283FF425287FF425489FF45558AFF
+ 47578CFF4C5B93FF4D5B95FF42508BFF32417FFF354685FF364889FF394C8FFF
+ 3D5198FF41579FFF465DA8FF4B64AEFF4E6AB1FF5272B4FF4F71B3FF4F70B5FF
+ 4C6CB3FF4565ACFF3F5BA2FF374E99FF314691FF354794FF2B3A83FF2C3A7CFF
+ 384075FF3B3A5AFF3D3441FF49362FFF533824FF5D3B1EFF613A1AFF603919FF
+ 613A1AFF643D1DFF653E1EFF643D1DFF623B1BFF643D1DFF643D1DFF633C1CFF
+ 623B1BFF623B1BFF613A1AFF603919FF603919FF5F391BFF5D391BFF5B391BFF
+ 5B391BFF5C3A1DFF5F3B1DFF623C1CFF633C1CFF633A19FF663C19FF643C19FF
+ 643C19FF623C1AFF613C1AFF613B1BFF5B3A20FF46311CFF312317FF1F1815FF
+ 1B171CFF181824FF181727FF191625FF1E1726FF241B28FF251B28FF241A2AFF
+ 231B2CFF211B2EFF221C2DFF241D2CFF261D2AFF2A212EFF231C2BFF221D32FF
+ 2B263BFF322C3DFF3B2D38FF493230FF59392CFF643C23FF693E1DFF6B3E1CFF
+ 693F1CFF693E1DFF663D1DFF653B1EFF643B1BFF663D1DFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF693E1DFF693E1DFF693F1CFF693F1CFF6A3E19FF6A3E19FF6B3F1AFF
+ 6C401BFF6D401AFF6C3F19FF6B3E18FF6B3E18FF6F3F1BFF70401CFF71411DFF
+ 72421EFF72431DFF72431DFF71421CFF70411BFF704219FF704219FF704318FF
+ 714419FF714419FF72451AFF72451AFF72451AFF74471CFF774A1EFF75461AFF
+ 77481CFF7B4D1EFF75461AFF794E23FF90683EFFB08C68FFB79879FFB89E86FF
+ B09B86FFA99989FFB6A89CFFD2C6BCFFE4DCD5FFF3F2EEFFF4F5F3FFF1EEF0FF
+ F6F1F0FFFFF7EAFFE9D9BCFFC2A36EFFB18238FFBD7D1FFFC67E13FFC57E0CFF
+ C3810AFFBE840DFFBC840DFFBE810BFFBC7F09FFBE810BFFBE810BFFBE810BFF
+ BE810BFFBE810BFFBE810BFFBE810BFFBE810BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ 4029CBFF402AC9FF402BC8FF402AC9FF4028CCFF4129CDFF412ACCFF412DC6FF
+ 4333C0FF3D38A5FF3B4682FF3E5177FF41527DFF40507FFF404F80FF435185FF
+ 445489FF45568EFF48578FFF4B5A92FF505E98FF4D5B95FF3D4D88FF32417FFF
+ 3B4B8DFF3C4D90FF3A4E95FF394E99FF384F9BFF3C53A1FF425BABFF4763B0FF
+ 4D6DB6FF4F71B7FF5172BBFF4F70B9FF4868B1FF3F5CA6FF385199FF334B93FF
+ 334893FF293A83FF29397BFF364076FF3C3D5FFF3F3847FF4A3734FF4F3524FF
+ 5D3A20FF613A1AFF603919FF613A1AFF633C1CFF643D1DFF633C1CFF623B1BFF
+ 623B1BFF623B1BFF623B1BFF623B1BFF623B1BFF623B1BFF613A1AFF613A1AFF
+ 5F3818FF5F3919FF5E3B1AFF5D3C1BFF5D3B1DFF5F3C1BFF623B1BFF633A1AFF
+ 653A19FF633B18FF613B18FF613B18FF603B19FF603B19FF613B19FF5C3A1CFF
+ 51371FFF392919FF251A16FF1C161BFF191723FF181727FF191625FF1C1524FF
+ 251B28FF251B28FF241A2AFF231C2BFF211B2CFF221C2DFF241D2CFF241D2CFF
+ 262031FF1E192EFF1F1C35FF2C2943FF352F46FF392E3EFF463134FF57392EFF
+ 643E26FF683F1FFF693F1CFF683E1BFF683D1CFF663D1DFF663C1FFF663D1DFF
+ 663D1DFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 673E1DFF673E1DFF673E1DFF673E1DFF693E1DFF693E1DFF693F1CFF693F1CFF
+ 6A3E19FF6B3F1AFF6C401BFF6C401BFF6D401AFF6D401AFF6C3F19FF6B3E18FF
+ 70401CFF70401CFF71411DFF71411DFF71421CFF70411BFF6E3F19FF6E3F19FF
+ 6F4118FF704219FF704318FF704318FF714419FF714419FF714419FF714419FF
+ 7A4B1FFF744519FF714216FF734516FF724317FF72471CFF896137FFA88460FF
+ BA9B7CFFB69D83FFB39E89FFAC9C8CFFAB9D91FFB6AAA0FFCFC4BCFFE3DBD4FF
+ F0EDE8FFF2F1EDFFF2EDEEFFFCF4EDFFF9ECD6FFC8B086FF9F7833FFA67117FF
+ BF7B12FFC57C0AFFC27C07FFBE7E08FFB9810AFFBA820BFFBD8109FFBD8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FF3F29C8FF3F2AC7FF402BC8FF402AC9FF4129CDFF
+ 422ACEFF422BCDFF422EC7FF4232BFFF3D38A5FF3C4783FF405378FF435381FF
+ 425182FF414F83FF425287FF44538BFF475890FF4A5892FF4D5B95FF52609AFF
+ 4A5A95FF3A4987FF304180FF3B4D8EFF3C4F93FF3B4E97FF354C97FF334A98FF
+ 354E9EFF3D58A9FF4461B2FF4D6DB9FF4F72BCFF5173BFFF4D70BAFF4667B0FF
+ 3C5CA5FF38549BFF364F97FF324A92FF283C83FF293B7CFF344076FF3C3D63FF
+ 42394DFF4A3839FF4E3325FF5D3A20FF623B1BFF623B1BFF623B1BFF633C1CFF
+ 633C1CFF633C1CFF623B1BFF603919FF603919FF613A1AFF613A1AFF623B1BFF
+ 623B1BFF623B1BFF633C1CFF613818FF603A18FF5F3C1BFF5E3D1CFF5E3D1CFF
+ 5F3C1BFF613A1AFF623919FF663B1AFF643B1AFF603B19FF603B19FF603B19FF
+ 5F3A18FF623918FF5F3919FF593B22FF432D1BFF2B1E16FF1F1619FF191521FF
+ 1A1727FF1C1726FF1D1623FF241A26FF241A26FF251B28FF231C2BFF211B2CFF
+ 221D2CFF231F2BFF231E2DFF252337FF201D37FF21213FFF2D2C4CFF36324FFF
+ 392D43FF432E36FF52362FFF633E28FF674020FF693F1CFF673D18FF673C1BFF
+ 653C1BFF673D20FF673E1EFF663D1DFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF
+ 653C1BFF653C1BFF653C1BFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF643E1CFF643E1CFF643E1CFF643E1CFF643E1CFF
+ 643E1CFF643E1CFF643E1CFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF673E1DFF673E1DFF673E1DFF673E1DFF693E1DFF
+ 693E1DFF693F1CFF693F1CFF6B3F1AFF6B3F1AFF6C401BFF6D411CFF6E411BFF
+ 6D401AFF6C3F19FF6C3F19FF6E3E1AFF6F3F1BFF70401CFF70401CFF70411BFF
+ 70411BFF6F401AFF6E3F19FF704219FF704219FF704318FF704318FF704318FF
+ 704318FF704318FF704318FF75481CFF73461AFF75461AFF74471BFF71461BFF
+ 7E562CFF9E7A56FFB79879FFB69D83FFB5A18FFFB7A79AFFBCB0A6FFC5BAB2FF
+ D5CBC4FFE6DED7FFF0EAE3FFF4F1ECFFF5F2EEFFFAF3F0FFFDF1E5FFE4D1B0FF
+ AF9158FF9E701CFFB77D14FFC37D0CFFC67E08FFC07D08FFBC7E08FFB88009FF
+ B88108FFBD8008FFBC7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBA7D07FFBA7D07FFBA7D07FFBB7E08FFBB7E08FF
+ BB7E08FFBC7F09FFBC7F09FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBD8008FFBD8008FFBD8008FF402BC8FF402BC7FF
+ 402BC7FF412CC9FF422ACEFF422ACEFF432CCEFF432FC8FF4232BFFF3D38A5FF
+ 3C4783FF415479FF445482FF425182FF425085FF43528AFF44528CFF485992FF
+ 485893FF4C5C97FF53639EFF4A5A95FF394886FF344584FF3B4D8EFF394F91FF
+ 374D94FF334B93FF304A96FF344F9FFF3D5AABFF4664B5FF506EBFFF5071C1FF
+ 4D71BFFF476BB7FF4063ADFF385AA0FF36559AFF365398FF324C92FF283F83FF
+ 293D7EFF323F77FF393B63FF413950FF49383CFF4D3228FF5D3921FF633C1CFF
+ 633C1CFF633C1CFF623B1BFF623B1BFF623B1BFF623B1BFF5F3818FF5F3818FF
+ 603919FF603919FF613A1AFF623B1BFF623B1BFF653C1CFF643918FF633B18FF
+ 613C1AFF603D1BFF603D1BFF613C1AFF623918FF633817FF653C1CFF633C1CFF
+ 5F3C1BFF5F3C1AFF5E3B19FF5F3A18FF623A17FF603919FF5C3C1FFF4A311DFF
+ 332219FF221719FF1A141FFF1A1727FF1E1928FF221926FF231925FF241A26FF
+ 241A27FF221B28FF221D2CFF211E2DFF211F2BFF201F2FFF27273FFF232543FF
+ 262A4DFF2D3056FF333254FF362D47FF3E2D38FF4C322CFF603D29FF663E21FF
+ 683E1BFF673D18FF663B1AFF673C1BFF683C1FFF693D1EFF663D1DFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF633D1BFF633D1BFF
+ 633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF673E1DFF673E1DFF
+ 673E1DFF673E1DFF693E1DFF693E1DFF693F1CFF693F1CFF6B3F1AFF6C401BFF
+ 6D411CFF6D411CFF6E411BFF6E411BFF6D401AFF6C3F19FF6C3C18FF6D3D19FF
+ 6E3E1AFF70401CFF71421CFF71421CFF71421CFF70411BFF71431AFF71431AFF
+ 714419FF714419FF714419FF704318FF704318FF704318FF704318FF74491EFF
+ 7A4D22FF764B20FF7B5329FF916D49FFAB8C6DFFB69D83FFB2A08FFFC6B8ACFF
+ D9CFC8FFE1DBD6FFE8E1DEFFF0EBE8FFF6EFECFFF2EEE9FFF6F3EFFFF6F2EDFF
+ FFF9F2FFF8E7D2FFC8AE80FFA57E34FFAF7B17FFC58715FFC4810CFFC6820BFF
+ C0820CFFBE810BFFBA8108FFB98007FFBC7E08FFBC7E08FFBB7E08FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBA7D07FFBA7D07FF
+ BA7D07FFBB7E08FFBC7F09FFBC7F09FFBD800AFFBD800AFFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBD8008FFBD8008FF
+ BD8008FF412CC8FF412CC8FF412CC8FF422DCAFF422ACEFF422ACEFF422BCDFF
+ 422EC7FF4232BFFF3D38A5FF3B4682FF3F5278FF435381FF425182FF435186FF
+ 44528CFF43538EFF4A5A95FF495994FF4E5E99FF5767A2FF4A5C97FF3B4D8AFF
+ 3C4F8CFF3C518FFF3A5091FF374E92FF334D93FF314C96FF34539EFF3E5DACFF
+ 4465B5FF4C6CBFFF496BBEFF456ABCFF4066B4FF3A5FA9FF35599FFF335499FF
+ 335395FF324F94FF2A4487FF2C4081FF323F77FF373962FF3E3851FF4A3740FF
+ 4F332CFF5D3921FF633C1CFF643D1DFF633C1CFF613A1AFF603919FF613A1AFF
+ 623B1BFF5F3818FF5F3818FF5F3818FF603919FF613A1AFF613A1AFF623B1BFF
+ 643B1AFF653B18FF663C19FF623C19FF613D19FF613D19FF603B19FF623918FF
+ 633817FF673E1EFF643D1DFF613E1DFF5E3D1CFF5F3C1BFF603B19FF653B18FF
+ 623918FF5F3B1DFF51341FFF3C281DFF271B1BFF1B131EFF1B1526FF201928FF
+ 231A27FF231925FF231A24FF231B26FF221B28FF221D2CFF211E2DFF22202CFF
+ 1F1F2FFF262945FF2C3152FF2F355EFF2D335CFF2E2E56FF332E4BFF3F2E3BFF
+ 482F2BFF5C3B28FF653D20FF663E1BFF673D18FF663C19FF663B1AFF673B1CFF
+ 673B1CFF663D1DFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF
+ 633D1BFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF673E1DFF673E1DFF673E1DFF673E1DFF693E1DFF693E1DFF693F1CFF
+ 693F1CFF6C401BFF6C401BFF6D411CFF6E421DFF6F421CFF6E411BFF6D401AFF
+ 6D401AFF6B3B17FF6C3C18FF6E3E1AFF70401CFF72431DFF72431DFF72431DFF
+ 72431DFF73451CFF73451CFF72451AFF72451AFF72451AFF714419FF714419FF
+ 714419FF6D4217FF73491EFF6E441AFF683F18FF7B5630FFA07F5EFFB89D83FF
+ BCA896FFCDBFB3FFE5DCD8FFF9F5F4FFF7F4F6FFF1EEF0FFF2F0F0FFF5F1F0FF
+ F1EDECFFF4F0EFFFF8F2EDFFFFF5EBFFE7D2B7FFB39156FFA4751FFFB98112FF
+ C18208FFC3840CFFC4840EFFC18410FFBD830CFFBD8306FFBB8005FFBB7E0AFF
+ BC7E0CFFBB7E08FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBA7D07FFBB7E08FFBB7E08FFBC7F09FFBD800AFFBE810BFFBE810BFF
+ BF820CFFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FF412FC8FF412FC8FF402EC7FF402DCAFF
+ 402BCEFF402BCEFF3F2ACCFF3F2DC6FF4134BEFF3A37A4FF374580FF3B5076FF
+ 3F527FFF3F5083FF415088FF45538DFF465593FF4C5E9BFF4A5C99FF4F619EFF
+ 5B6DA8FF50629DFF42548FFF475A97FF445996FF3D5694FF385294FF335093FF
+ 325196FF35559CFF3C5CA7FF3F60AFFF4264B8FF3F62B8FF3E62B6FF3C61B1FF
+ 3A5FA9FF375BA1FF345698FF315192FF345194FF2D498AFF2D4384FF303F77FF
+ 32365FFF3A3550FF483643FF4E342EFF5B3922FF643D1DFF653E1EFF643D1DFF
+ 613A1AFF603919FF613A1AFF623B1BFF5F3818FF5F3818FF603919FF603919FF
+ 603919FF603919FF613A1AFF633A19FF693C1AFF693D18FF643D17FF603C16FF
+ 5F3B15FF603A17FF643918FF643918FF683F1FFF663F1FFF603E20FF5D3E1DFF
+ 5E3D1CFF613C1AFF663C19FF653A19FF613B1DFF583922FF452F24FF2B1D1EFF
+ 1A121DFF171221FF1E1726FF211825FF221824FF231A24FF231B26FF201C28FF
+ 201D2CFF1F1F2DFF20202CFF1E2032FF252946FF31395EFF383E6BFF2E3461FF
+ 2A2C55FF342F4FFF423243FF492F2FFF5A3926FF623C1EFF653D1AFF673D18FF
+ 663C19FF663B1AFF65391AFF643819FF663D1DFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF673E1DFF673E1DFF673E1DFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 693E1DFF693E1DFF693F1CFF693F1CFF6C401BFF6D411CFF6E421DFF6E421DFF
+ 6F421CFF6F421CFF6E411BFF6D401AFF6E3E1AFF6F3F1BFF70401CFF72421EFF
+ 72431DFF72431DFF72431DFF71421CFF74461DFF74461DFF74471CFF73461BFF
+ 73461BFF72451AFF72451AFF70451AFF6E441AFF70481EFF673E17FF6C451FFF
+ 967351FFC1A386FFD5BEA8FFDACABDFFE8DFDBFFF0EEEEFFF5F6FAFFEFF2F7FF
+ E8EBF0FFEAEBEFFFEFEFEFFFF1EFEFFFF2F0F0FFF8F1EEFFF1E3D7FFCDB492FF
+ AC823FFFAB7818FFBF820CFFBE7E01FFBE8109FFBD820EFFBE830FFFBD840BFF
+ BD8204FFBC8004FFBC7E0CFFBB7F0EFFBC7F0BFFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FFBC7F09FFBC7F09FFBD800AFF
+ BE810BFFBF820CFFC0830DFFC0830DFFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF4430C9FF
+ 4430C9FF432FC8FF432ECBFF422BCDFF3F2ACDFF3F2ACCFF3F2DC8FF4134C0FF
+ 3A37A5FF364284FF3A4D78FF3D507BFF3E507FFF425287FF46548EFF475996FF
+ 4E619EFF4C5F9CFF5164A1FF5E71AEFF5366A3FF465996FF4E63A0FF48609CFF
+ 425B99FF3A5697FF355295FF345398FF36569FFF3959A4FF385CAAFF395EB0FF
+ 375CB0FF385EB0FF3960AFFF3960AAFF375EA3FF33569AFF2E5092FF345496FF
+ 2F4B8CFF2F4684FF2F3F74FF2E345FFF373350FF433646FF4A3534FF583825FF
+ 613D1FFF643E1EFF643D1DFF613B19FF5F3818FF5F3919FF613B1DFF5F391BFF
+ 5F391BFF5F3919FF603919FF603A18FF603A18FF603A18FF623918FF683E1BFF
+ 673D18FF633B18FF603B15FF5E3A16FF5F3916FF643918FF653A19FF694020FF
+ 674020FF63401FFF603F1EFF613E1DFF623D1BFF643B1AFF643B1AFF633B1EFF
+ 5F3D25FF4F3525FF34211CFF1C1218FF17101DFF1B1423FF1D1623FF221824FF
+ 231A24FF231B25FF201C27FF1E1E2CFF1E1E2EFF1F1F2FFF1A1E36FF1D254AFF
+ 303B67FF384474FF2A3464FF242A55FF343053FF433547FF473133FF553726FF
+ 5E391DFF633D1AFF673D18FF673D18FF653B18FF633817FF623617FF683D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF673E1DFF
+ 673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF683D1CFF663D1DFF663D1DFF663D1DFF643D1DFF
+ 643E1CFF643E1CFF643E1CFF663D1CFF663D1CFF683D1CFF663D1CFF623C1AFF
+ 613D19FF613C1AFF623C19FF623C1AFF623C19FF623C19FF623C19FF623C19FF
+ 643C19FF643C19FF643C19FF643C19FF643C19FF643C19FF663C17FF6B3F1AFF
+ 6B4019FF6B4019FF6C4017FF6C4017FF6E4116FF6E4115FF6E4115FF714314FF
+ 724415FF734418FF734418FF734418FF734418FF724317FF714117FF73421CFF
+ 73421CFF74431DFF73441EFF72431DFF72431DFF70411BFF70411BFF764721FF
+ 734620FF734620FF72461DFF72471CFF73461AFF744519FF744617FF704317FF
+ 764C22FF714B28FF886649FFC2A78DFFE8D3BEFFF1E1D4FFF6EBE3FFEDE8E7FF
+ E8E4E9FFE4E4EAFFE7EAEFFFECEFF4FFEEF1F5FFEFEEF2FFECEBEDFFF5F3F3FF
+ FDF4EBFFE9D4BEFFBF9E70FFAF7F31FFB97F18FFC2850DFFBF8204FFBA7D07FF
+ B87F0CFFBC810DFFBD8109FFBE8103FFBD7F03FFBC7E0CFFBC800FFFBC7F09FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBD800AFFBE810BFFBF820CFFC0830DFFC1840EFFC1840EFFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FF
+ BC7E08FFBC7E08FFBC7E08FFBC7E08FFBC7E08FFBC7E08FFBC7E08FFBB7D07FF
+ BB7D07FFBB7D07FF4B30CDFF492ECBFF452DC9FF452CCAFF452DCDFF452ED0FF
+ 442CD0FF422CCBFF4636C9FF3E38AFFF393E8DFF3B497EFF3F517AFF42557BFF
+ 485788FF4D5C94FF4D619AFF4D659FFF4F67A3FF5169A5FF596DAEFF5C70B1FF
+ 5569AAFF485E9FFF526BABFF5570B0FF526DB0FF4360A5FF314E98FF2A4895FF
+ 314FA0FF3759ACFF446DBCFF3B67B4FF3561AEFF3862ADFF3D66AFFF3C64ACFF
+ 365CA4FF33559BFF3A5BA0FF314D8EFF2F4481FF2E3F72FF2D335CFF353553FF
+ 3F384DFF44343BFF4C3224FF56381DFF5E3B1AFF5F3A18FF5D3714FF5B3614FF
+ 5B3719FF5B391CFF5D3C22FF5C3C1FFF5F3C1BFF613C1AFF613B18FF633C16FF
+ 623C19FF623C19FF613916FF613916FF5E3816FF5E3815FF5F3917FF603A18FF
+ 633A19FF643B1AFF633D1BFF633D1BFF633E1CFF633E1CFF643F1DFF66401EFF
+ 66401EFF683F1FFF693E23FF633A23FF5A3A23FF472E1EFF231614FF191219FF
+ 1C1726FF1C1726FF231A24FF251B21FF1F191EFF1C1B24FF1C2130FF1A1F34FF
+ 20243CFF2B3253FF324070FF2F4078FF324179FF2B386CFF2A305DFF373658FF
+ 3F3748FF3B2B2CFF50392AFF593B20FF603C18FF623C12FF633B11FF643912FF
+ 643813FF623815FF653A19FF653A19FF653A19FF653A19FF653A19FF653A19FF
+ 653A19FF653A19FF673C1BFF673C1BFF673C1BFF673C1BFF673C1BFF673C1BFF
+ 673C1BFF673C1BFF643C19FF643B1AFF663B1AFF663A1BFF683A1BFF663A1DFF
+ 643A1DFF623A1DFF613B1DFF5F3C1BFF5D3C1BFF603D1CFF653F1DFF663D1CFF
+ 693C1BFF653A19FF66421EFF63421BFF613F1BFF623E18FF613D19FF613D17FF
+ 623D17FF623D17FF6A431DFF693F1AFF653C15FF673C15FF6A3F18FF6D401AFF
+ 6D401AFF6E4116FF703F11FF71400EFF71410DFF74420DFF79470DFF7E4A0EFF
+ 814E10FF855011FF895415FF865112FF814E10FF7D4B0FFF7C4A10FF78470FFF
+ 74430BFF713E0CFF774118FF774019FF744119FF72441BFF73471EFF74481FFF
+ 74451FFF71411DFF774626FF6C3F1EFF6A3F1EFF704623FF724A20FF724819FF
+ 774815FF7B4914FF82501CFF73461AFF987357FFD7BAABFFEFDED5FFF6EBE7FF
+ F7F1ECFFEDE8E7FFF4EDF0FFF6F0F5FFF3EDF2FFEEEBEDFFEFEFEFFFF1F0F2FF
+ F0EEF4FFF1EDF2FFF3F0EBFFF3E8D4FFCCB185FFA67C3BFFB57E23FFC7891DFF
+ BF800EFFB77903FFBB7F0DFFB77B09FFB97D05FFC18307FFC38306FFC08003FF
+ BC7F07FFBF820CFFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBD800AFFBD800AFFBD800AFFBD800AFFBC7F09FFBB7E08FF
+ BB7E08FFBA7D07FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FF
+ BC7F07FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7E08FFBC7D0AFFBB7C09FFBB7C09FFBA7B08FFBA7B08FFBB7C09FF
+ BB7C09FFBC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFF4A30CAFF472FCBFF472FCBFF
+ 4930CEFF4931D1FF4932D4FF472FD5FF452ED0FF4333C7FF3B33AFFF393B93FF
+ 3C4783FF40527BFF42557BFF485589FF4A5892FF475E96FF46619AFF4A64A0FF
+ 4F68A6FF596FB0FF5D73B5FF566CAEFF4961A3FF4F6AAAFF536FB0FF5570B3FF
+ 4A68AFFF3C59A4FF32509FFF3754A9FF3D5FB3FF3F6BB8FF3869B3FF3865AFFF
+ 3562ACFF3760A9FF345DA6FF355AA4FF3558A1FF36569DFF304C8DFF304680FF
+ 314071FF2E365EFF333554FF3C3851FF413640FF483226FF55371EFF5C3A1CFF
+ 5F3A18FF5E3815FF5C3814FF593719FF57391CFF57391EFF583A1FFF5E3D1CFF
+ 633F1BFF643F19FF653E17FF623D17FF613C16FF623C1AFF613B19FF613B19FF
+ 603A18FF603A18FF613B19FF623C1AFF633D1BFF633D1BFF633D1BFF643E1CFF
+ 643E1CFF653F1DFF653F1DFF66401EFF663F1FFF6C3F24FF643820FF5F3A1EFF
+ 4E311CFF2D1C13FF1B1215FF1A1622FF1B1625FF201721FF261C22FF211B20FF
+ 191822FF13192CFF101732FF1B203FFF293159FF34457DFF304380FF2D3F7AFF
+ 263469FF242A57FF323355FF403A4BFF413436FF4A3526FF54391EFF5E3C18FF
+ 643E14FF683E14FF693F15FF693D18FF693C1AFF653A19FF653A19FF653A19FF
+ 653A19FF653A19FF653A19FF653A19FF653A19FF673C1BFF673C1BFF673C1BFF
+ 673C1BFF673C1BFF673C1BFF673C1BFF673C1BFF643C19FF643B1AFF663B1AFF
+ 663A1BFF683A1BFF663A1BFF643A1DFF623A1DFF5B3719FF5C3B1AFF5E3E1BFF
+ 603E1AFF623D17FF653C15FF693C16FF6A3E15FF643D11FF623D11FF613C10FF
+ 633C0FFF643D10FF684010FF694110FF6B4211FF6B400DFF6D410CFF6E420CFF
+ 73450FFF784911FF7A4B13FF7B4C14FF7D4E11FF814F0DFF85520CFF89550FFF
+ 8F5A11FF976114FF9F6718FFA56D1CFFA8701EFFAA7220FFA76F1EFFA26A1BFF
+ 9E671CFF9A651CFF96621CFF925D1AFF8F591AFF905720FF89501DFF7D4815FF
+ 744410FF70440FFF724512FF754416FF754319FF78441FFF73431FFF724520FF
+ 72481EFF71471AFF744714FF7E4B13FF844F16FF905E2AFF9D7349FFCAAA93FF
+ F5E0D8FFF9EFEFFFF2F0F0FFF4F2F2FFF1EFEFFFF7F1F6FFF3EDF2FFF3EEF0FF
+ F3F1F1FFF3F1F0FFF3F3F3FFF4F0F5FFF1ECEDFFFAF2E5FFE2D1B0FFBA9A5FFF
+ A97A29FFBB7F1BFFC38313FFBE7F0DFFC38513FFBD810FFFB97E0AFFBC8005FF
+ C28408FFC48407FFBF8204FFBC8008FFBD830CFFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBD8008FFBC7F07FFBC7F07FF
+ BB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FFBC7D0AFFBC7D0BFFBC7D0BFF
+ BD7E0CFFBD7E0CFFBC7D0BFFBC7D0BFFBC7D0BFFBC7D0BFFBC7D0BFFBC7D0BFF
+ 4633CAFF4532C9FF4531CAFF4732CEFF4934D1FF4831D3FF452DD3FF422BCDFF
+ 4330C5FF3C31AFFF3A3A94FF3E4786FF425080FF435280FF46508CFF485496FF
+ 445996FF445F98FF48629EFF4F68A6FF5A70B1FF5F75B7FF556DAFFF4961A3FF
+ 4560A0FF4965A6FF506BAEFF4C6BB0FF405DA8FF32509FFF3452A5FF385DAFFF
+ 3C68B5FF396AB4FF3B68B1FF3562ABFF335CA5FF315AA3FF355AA4FF385BA4FF
+ 315198FF314C8FFF324784FF324074FF2F3661FF353658FF3C3953FF443844FF
+ 493328FF55371EFF5B391BFF5F3A18FF5E3815FF5D3816FF5A381AFF57391CFF
+ 54361BFF56381BFF5D3C1BFF64401CFF66411BFF674019FF633E18FF613C16FF
+ 653F1DFF643E1CFF633D1BFF623C1AFF613B19FF623C1AFF633D1BFF633D1BFF
+ 633D1BFF633D1BFF643E1CFF643E1CFF643E1CFF653F1DFF653F1DFF653F1DFF
+ 6C4021FF633A1AFF5F3919FF54361DFF372417FF201414FF18121DFF1A1622FF
+ 1B131DFF241C23FF221A24FF161525FF101430FF0E1739FF1C224BFF2C3666FF
+ 374881FF334683FF32427DFF29356BFF242A57FF303153FF433A4EFF47393BFF
+ 4D3627FF573A1FFF623E1AFF674117FF6C4218FF6D4118FF6B3F1AFF6A3D1BFF
+ 663B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF663B1AFF643B1AFF623B1BFF613B1BFF
+ 5F3919FF623D1BFF64401CFF663F18FF673E11FF693E0DFF70410DFF74450FFF
+ 71420CFF71420CFF72430BFF75450BFF78490CFF7C4C0CFF7F4F0DFF83520CFF
+ 86550BFF8A590BFF8F5E0EFF956310FF976610FF9A6810FF9B6911FF9E6A10FF
+ A37014FFA57113FFA87214FFAA7514FFAF7815FFB47C17FFB97E1AFFBB801CFF
+ BB801CFFB97E1BFFB67C1DFFB57C21FFB67D27FFB57E29FFB47C2BFFB2792AFF
+ AF7026FFA56720FF975D15FF88550CFF81500AFF7E4E0CFF804D0FFF804A13FF
+ 7A440FFF7C4714FF7A4813FF774510FF79470DFF814D11FF90581DFF97612AFF
+ 9D7142FFC1A17EFFF2DAC8FFFFF5EEFFFAF5F4FFF0EEEEFFF0EFEBFFF3F0ECFF
+ FBF6F7FFF2EFF1FFF2F1F5FFF0F1F5FFE9EBECFFF1F1F1FFF9F7F7FFF9F1EAFF
+ EDE0C6FFC1AA7CFFA47D39FFAD7B23FFC0841AFFBF7E0BFFBD7E0BFFC98C18FF
+ BC830FFFB9810AFFBD8207FFC08408FFC28507FFBE8206FFB9810AFFBB820EFF
+ BA8009FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BA7D07FFBA7D07FFBA7D07FFBA7D07FFBA7D07FFBB7E08FFBB7E08FFBB7E08FF
+ BD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FF
+ BC7D0AFFBD7E0CFFBF800EFFC0810FFFC0810FFFBF800EFFBD7E0CFFBC7D0BFF
+ BC7D0BFFBC7D0BFFBC7D0BFF4236CCFF4034CAFF4031C9FF3F2FCAFF412ECBFF
+ 402BCDFF3F27CBFF3E26C6FF4532C5FF3E33AFFF3B3C94FF3F4888FF425080FF
+ 435181FF454E8EFF475296FF435895FF445F98FF48619FFF4E67A5FF596FB1FF
+ 5D73B5FF536BADFF475FA1FF415C9CFF4460A0FF4C67AAFF4B6AAFFF3F5EA9FF
+ 304F9EFF2F4FA2FF355AACFF3965B2FF3B6AB4FF3D6AB3FF3A65AEFF3760A9FF
+ 385FA9FF395EA8FF395CA6FF2D4D96FF324D90FF354A87FF334175FF313863FF
+ 37385AFF3D3A54FF443A46FF483429FF543820FF59391CFF5D3A19FF5E3917FF
+ 5E3917FF5A381AFF59391CFF53351AFF55371AFF5C3B1AFF633F1BFF67401AFF
+ 674019FF643F19FF643E1BFF653F1DFF643E1CFF623C1AFF613B19FF613B19FF
+ 613B19FF613B19FF623C1AFF633D1BFF633D1BFF643E1CFF643E1CFF643E1CFF
+ 643E1CFF643E1CFF643E1CFF6A421FFF623A17FF613916FF5D3B1DFF432C1CFF
+ 261714FF181118FF191521FF1A121CFF231B26FF211A29FF1B182EFF1B1F42FF
+ 202955FF2A3365FF334078FF314380FF324582FF374782FF323E74FF2B3160FF
+ 313254FF41384CFF443539FF51392DFF5B3D24FF66411FFF6D441DFF6E431CFF
+ 6D401AFF693D18FF673A18FF673C1BFF653C1BFF653C1BFF653C1BFF653C1BFF
+ 653C1BFF653C1BFF653C1BFF643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF
+ 643B1AFF643B1AFF643B1AFF643B1AFF643B1AFF643C19FF623C19FF623C19FF
+ 623C19FF613C1AFF613C1AFF66401DFF67401AFF684016FF6B4112FF71450FFF
+ 784C0DFF80510DFF86540CFF8C5812FF8E5811FF915A11FF925B10FF975F12FF
+ 996211FF9D6611FF9F6A10FFA87214FFAD7615FFB27A15FFB37C14FFB37B10FF
+ B27A0DFFB37C0DFFB57D10FFBA8217FFB98116FFB88013FFB88011FFBA800FFF
+ B9800DFFBB7F0EFFBB7F0EFFBB7F0EFFBA7D0FFFBA7C12FFBB7D17FFBD801EFF
+ BF8224FFBF8127FFBE8026FFBF7E22FFB97A1EFFB07518FFA87116FFA16C15FF
+ 996715FF946014FF905A13FF87500BFF905712FF8E560FFF8B530CFF925914FF
+ 9F6523FFB07335FFB37F4AFFB28F67FFDAC3A9FFFAEBDBFFF8F0E9FFF0EEEDFF
+ EEEFEDFFF2EFEBFFF4F1ECFFFAF6F5FFF2F2F2FFF2F5FAFFEAEEF3FFDEE1E5FF
+ EFEFEFFFFFFBF6FFFAEEDCFFCBB78EFFA8894CFFA07322FFB98221FFC78818FF
+ C28009FFBD7F09FFC1840EFFBA810DFFB9810AFFBD8207FFBF8307FFBD8306FF
+ BA8106FFB5800BFFB6800DFFBA8009FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFB97C06FFB97C06FFB97C06FFB97C06FFB97C06FF
+ BA7D07FFBC7F09FFBC7F09FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FF
+ BC7F07FFBC7F07FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7E08FFBD7E0BFFBE7F0DFFC18210FFC28311FFC28311FF
+ C18210FFBE7F0DFFBD7E0CFFBC7D0BFFBC7D0BFFBC7D0BFF4037CEFF3D34CBFF
+ 3B2FC9FF3B2DC9FF3D2BCAFF412BCAFF4129CBFF4229C7FF4733C2FF4034ACFF
+ 3C3B91FF3F4783FF404E7EFF425080FF444F8DFF455395FF3D5591FF3F5C95FF
+ 47609EFF4C65A3FF546CAEFF5870B2FF526AACFF4961A3FF4863A3FF4B67A7FF
+ 516CAFFF4F6EB3FF4363ACFF3656A2FF3556A6FF395EAEFF3965B2FF3C6BB5FF
+ 3E6BB4FF3E69B2FF4069B2FF4269B3FF3E62AEFF3858A3FF2D4D96FF365194FF
+ 374C8AFF324075FF323865FF37395CFF3D3956FF453B48FF47342CFF523722FF
+ 59391CFF5D3A19FF5F3A18FF5F3A18FF5B391BFF59391CFF55371CFF58381BFF
+ 5D3A19FF603C18FF653E18FF674019FF66411BFF67411EFF633D1BFF623C1AFF
+ 603A18FF5F3917FF5F3917FF5F3917FF5F3917FF603A18FF643E1CFF643E1CFF
+ 633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1AFF67401AFF643B14FF
+ 643C12FF643F1DFF503521FF301E17FF191215FF18141FFF1C141FFF231A27FF
+ 20172CFF201B3AFF2F325FFF3B457BFF3D4B86FF3A4B8AFF304283FF324382FF
+ 374684FF344076FF2E3262FF333155FF3F364BFF423337FF51392DFF5B3D24FF
+ 674220FF6D441DFF6F441DFF6E411BFF6B3E19FF693C1AFF683D1CFF663D1CFF
+ 663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF653C1BFF653C1BFF
+ 653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF653C1BFF643B1BFF643B1AFF
+ 623C19FF613D19FF5F3D19FF5F3D19FF5F3D19FF613D19FF6A431DFF693F14FF
+ 6C3E0EFF74450DFF875612FF946416FF9C6A17FFA16D13FFAA7116FFAC7114FF
+ AC7114FFAC7213FFAF7313FFB17612FFB37811FFB77A12FFBA7C10FFBB7F0EFF
+ BE800EFFBC7F0BFFBA7C06FFB97C04FFBB7F04FFBE8109FFB87C0AFFB87C0AFF
+ B97E0AFFBC7F09FFBD800AFFBF820AFFC1810BFFC1810BFFC1810BFFBD7E0BFF
+ BC7C0CFFBB7B0FFFBC7A13FFBA7A14FFB87715FFB67512FFC38118FFC28115FF
+ BE8014FFBB8117FFB6801BFFB17B1CFFA9731CFFA56E19FFA66D18FFAF741EFF
+ AF731AFFAE7219FFB87C2AFFBC8237FFC28547FFC19060FFCFB696FFEEE2D0FF
+ FBF7ECFFEDEDE7FFEBECEAFFF1F2F0FFF5F2EDFFF8F4EFFFF5F2EDFFEEF0F0FF
+ EDF3F8FFE2E9F2FFE1E5EAFFF8F6F5FFFCF3E6FFE4D1B0FFAD8F56FFA47A2DFF
+ AD791BFFC1851BFFC58411FFC5840AFFC0830BFFB77E05FFB77F08FFB88108FF
+ BA8205FFBB8104FFB98104FFB68108FFB17F0DFFB07E0CFFB88009FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBA7D07FFB97C06FF
+ B87B05FFB87B05FFB97C06FFBA7D07FFBC7F09FFBD800AFFBD8008FFBC7F07FF
+ BC7F07FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FFBD7E0BFFBE7F0CFF
+ C1820FFFC28310FFC28310FFC1820FFFBE7F0CFFBD7E0BFFBC7D0AFFBC7D0AFF
+ BC7D0AFF3D32CFFF3B30CDFF3A2CCAFF3D2CC9FF402EC7FF442FC7FF472EC6FF
+ 452EC0FF412CB1FF3B2E9CFF3A3787FF3E457EFF414E7CFF41507EFF434E8AFF
+ 435291FF38508CFF3C5894FF465F9DFF4A63A3FF4E66A8FF536BADFF5169ABFF
+ 4A64A6FF4964A4FF4F6BABFF5371B2FF4D6CB1FF4262ABFF3B5BA7FF3859A9FF
+ 375CACFF3D67B4FF416EB8FF446FB8FF416CB5FF446BB5FF466DB7FF4163AFFF
+ 3555A0FF31519AFF3B5699FF384D8BFF2D3D72FF313A66FF393B5EFF3B3754FF
+ 433848FF48352EFF503723FF56381DFF5D391BFF603B19FF613C1AFF5C3A1CFF
+ 58381BFF58371DFF58381BFF5D3A19FF603A17FF643D17FF663F19FF68401DFF
+ 67411EFF613B19FF603A18FF5F3917FF5E3816FF5E3816FF5E3816FF5F3917FF
+ 603A18FF643E1CFF643E1CFF633D1BFF633D1BFF633D1BFF623C1AFF623C1AFF
+ 623C19FF613D15FF663E14FF693E13FF6B411CFF5C3D24FF3C281DFF1E1617FF
+ 19141DFF1C1621FF211A29FF1C132DFF201C40FF393D72FF4E5898FF48589DFF
+ 3C5097FF35488BFF334385FF32417FFF2D3871FF282C5DFF2F2D51FF3F364BFF
+ 46363DFF4C3329FF573821FF623C1CFF6A401BFF6E421DFF6F421DFF6F411FFF
+ 6E4120FF693E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF673E1DFF
+ 673E1DFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF663D1CFF
+ 663D1CFF643B1BFF623C1AFF613C1AFF5F3C1AFF5D3D1AFF5D3D1AFF5F3D19FF
+ 623D17FF693F14FF6D3F0FFF75440CFF875310FF9D6818FFAC781EFFB3801FFF
+ B7821AFFB87E15FFB97D13FFBA7C10FFB97B0FFFB97C0EFFBB7C0EFFBC7D0DFF
+ BE7F0DFFBD7C09FFBD7D07FFBF7C07FFBD7B04FFBF7C02FFC07D03FFC38005FF
+ C4820BFFB97A07FFB97B09FFBB7E0AFFBD7F09FFBF810BFFC1820AFFC1820AFF
+ C1820AFFC2830BFFC0800AFFBE7D0AFFBD7D0DFFBE7D11FFBE7D14FFBC7A13FF
+ BA7811FFC07F12FFBE7F0DFFBD7E0CFFBB7F0EFFBA8114FFB88119FFB67F1EFF
+ B47C1DFFB67C1CFFBF8420FFC0821CFFC08420FFC58930FFBD8337FFBB8348FF
+ BD9369FFE4D2BBFFF4F2E7FFFBFEF5FFEAF0EBFFE9EBEBFFEEEFEDFFF2EEE9FF
+ F2EEE9FFF1F1EBFFEBEEECFFE5EDF4FFE4EBF4FFF0F3F8FFFFFBF6FFECDCC5FF
+ C1A477FFA77D36FFB07D21FFBA7F18FFBF8010FFBF7D06FFC3840AFFC3870FFF
+ B57D06FFB37E06FFB88108FFBA8205FFB88003FFB98005FFB7830BFFB18111FF
+ AF7F0FFFB87F0BFFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBC7F09FFBB7E08FFB97C06FFB87B05FFB97C06FFBA7D07FFBC7F09FF
+ BD800AFFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FFBC7F07FF
+ BD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7D0AFFBD7E0BFFBF800DFFC0810EFFC0810EFFBF800DFFBD7E0BFF
+ BC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFF3A29D1FF3A28CFFF3B28CBFF3F2AC6FF
+ 422DBFFF412DB6FF4028AEFF3C26A4FF311E92FF302484FF333177FF3D4378FF
+ 414F79FF40517CFF3F4E86FF3E508DFF3B538FFF405C98FF4763A0FF4661A1FF
+ 475FA1FF4960A4FF4862A4FF4660A2FF4661A1FF536FAFFF5775B6FF4F6FB1FF
+ 4565AEFF4262AEFF3E5FAEFF365CAAFF3E68B3FF4673BCFF4A75BEFF426DB6FF
+ 4067B1FF3F66B0FF3C5EAAFF34549FFF36569FFF405AA0FF364C8DFF2B3A72FF
+ 313968FF383B61FF383654FF3F3546FF483530FF4F3725FF55371EFF5B391CFF
+ 613B1BFF623C1CFF5E3A1CFF58381BFF57371AFF5A381AFF603A1AFF623C19FF
+ 663F19FF663F19FF673F1CFF653F1CFF613B19FF613B19FF603A18FF5F3917FF
+ 603A18FF613B19FF623C1AFF623C1AFF643E1CFF643E1CFF633D1BFF633D1BFF
+ 623C1AFF623C1AFF613B19FF613B18FF5D3812FF664016FF6E4115FF6F421CFF
+ 654228FF483122FF261A1AFF18141AFF1C1621FF21192AFF18112CFF19153FFF
+ 353974FF4A599EFF435AA6FF364E9AFF384C93FF314384FF2C3B7AFF27326CFF
+ 222758FF2B2A51FF3E344BFF47373EFF4B3228FF55361FFF603A1AFF673D18FF
+ 6B3F1AFF6D401BFF6E3F1FFF6E4120FF683F1EFF66401EFF66401EFF66401EFF
+ 66401EFF66401EFF66401EFF66401EFF653F1DFF653F1DFF653F1DFF653F1DFF
+ 653F1DFF653F1DFF653F1DFF653F1DFF643B1AFF623C1AFF613B1BFF5F3C1BFF
+ 5D3B1DFF5D3C1BFF613C1AFF643D16FF6C3E0FFF794810FF8C5615FF9F671AFF
+ AE741BFFB67D1AFFBB8318FFBD8516FFBC800FFFBB7F0DFFBC7E0CFFBA7C0AFF
+ BA7C0AFFBB7C0AFFBB7C0AFFBB7C09FFBE7C0BFFBD7B0AFFBF7B0AFFC07C0BFF
+ C47E0CFFC6800EFFC6800FFFC47F10FFBD7D11FFBC7E12FFBD8012FFBF8010FF
+ BE800EFFBE7F0DFFBC7D0AFFBB7C09FFBD7E0BFFBC7D0AFFBB7C0AFFBC7D0DFF
+ C08113FFC08216FFBF8117FFBE8016FFC08014FFBD7E10FFBB7C0CFFB97D0CFF
+ B77E11FFB98017FFB77F1AFFB77F1AFFB87E15FFC08517FFBD8110FFB97F15FF
+ B88126FFAF7C33FFB98A56FFD0AF8EFFF0E5D7FFF2F3EFFFF1F8F3FFE9F0EBFF
+ E8EDECFFEDEDEDFFF0EBE8FFEEE9E6FFF3F2EEFFEAEFEEFFE1EAF3FFE7EEF7FF
+ FAF7F9FFFBEDE1FFD9BE99FFB18A4CFFB4802DFFBB801CFFC08014FFBF7E0BFF
+ BF7D06FFC2830BFFC18410FFB87F0BFFB47E09FFBA820BFFBD8409FFBA8205FF
+ BC8308FFBB870FFFB68616FFB58313FFB87F0BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBF820CFFBD800AFFBB7E08FFB97C06FF
+ B97C06FFBA7D07FFBC7F09FFBD800AFFBD8008FFBC7F07FFBC7F07FFBB7E06FF
+ BB7E06FFBC7F07FFBC7F07FFBD8008FFBC7F07FFBC7F07FFBC7F07FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7D0AFFBC7D0AFFBC7D0AFFBD7E0BFF
+ BD7E0BFFBC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFFBC7D0AFF3C24D0FF
+ 3D24CCFF3E26C6FF4129BDFF422BAFFF3B279EFF321E8FFF2C1883FF261479FF
+ 261A72FF2E2B70FF3B4176FF414E7AFF40507EFF3E4C86FF3A4C8BFF415A98FF
+ 4864A1FF4D68A8FF4761A3FF42599DFF40579BFF3F599BFF3E589AFF4965A5FF
+ 5978B7FF6080C1FF5577B9FF4E6FB8FF4D70BAFF486CBAFF3D63B1FF3F69B4FF
+ 4A77C0FF4F7AC3FF446DB6FF3960AAFF385DA7FF385AA6FF33539FFF3A59A4FF
+ 445EA4FF364C8DFF273871FF2F3968FF383A62FF373454FF3C3347FF473633FF
+ 503727FF55361FFF5B391CFF613B1BFF623C1CFF5E3A1CFF5A381BFF583619FF
+ 5A381AFF613B1BFF673F1CFF6A401BFF693F1AFF653D1AFF623C19FF623C1AFF
+ 623C1AFF613B19FF613B19FF623C1AFF633D1BFF643E1CFF653F1DFF643E1CFF
+ 643E1CFF633D1BFF633D1BFF623C1AFF613B19FF613B19FF613B19FF593511FF
+ 674019FF724218FF71421CFF6C4529FF503626FF2D1E1BFF1B1419FF1D151FFF
+ 1F192AFF140F2CFF120F3CFF29316DFF41529BFF3954A4FF2C4A99FF364C94FF
+ 2F4083FF293779FF26306CFF23275AFF2A2950FF3C3249FF44333CFF4F352EFF
+ 583924FF613B1DFF643C19FF683B19FF6A3C1AFF6A3B1CFF6A3C1DFF683F1EFF
+ 66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF
+ 66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF66401EFF643B1AFF
+ 623C1AFF613B1DFF5F3A1EFF5D3B1EFF5F3B1DFF623C1AFF693E13FF72420EFF
+ 895415FFA3691DFFB37620FFB77A18FFB67A10FFB77A0CFFB97D0BFFBD7F0DFF
+ BD7F0DFFBB7D0BFFBA7C0AFFB97B09FFBA7B09FFBA7B09FFBB7C0AFFBB7C0AFF
+ BC7A0AFFBC7A0AFFBE7C0CFFC37E0FFFC37E0FFFC07B0CFFBA770AFFBB7B0FFF
+ BA7C10FFBC7E12FFBD8012FFBD8110FFBC800EFFBD7F0DFFBA7F0BFFBE810DFF
+ BA7F0BFFBB7E0AFFB97D0BFFBA7E0DFFBB7F0EFFB97C0EFFB7790DFFBE8218FF
+ BC8016FFBD8012FFBD8110FFBD8214FFBA8114FFB67D14FFB37A11FFBB8012FF
+ BE8413FFB87C0AFFB1790EFFAB7B23FFA77D3CFFC4A078FFF3DBC7FFFFF7F0FF
+ EFF4F3FFE8F1EEFFE7F0EDFFEEF2F3FFF8F5F7FFF9F3F4FFF4EFEEFFF5F6F4FF
+ EEF3F2FFE6EEF5FFEEF1F6FFFDF1EFFFF0D9C3FFD0AB79FFB8873DFFC2872AFF
+ C38219FFC07E0EFFC3800DFFC3830DFFBF800DFFBA7E0CFFB87F0CFFB57E0BFF
+ BC840DFFC1860BFFBE8308FFBE850CFFC08A15FFBC8A1AFFBB8617FFB87F0CFF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFC0830DFF
+ BF820CFFBC7F09FFBA7D07FFB97C06FFBA7D07FFBC7F09FFBD800AFFBD8008FF
+ BC7F07FFBC7F07FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FFBC7F07FF
+ BC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7F07FFBC7E08FF
+ BB7C09FFBB7C09FFBA7B08FFBA7B08FFBB7C09FFBB7C09FFBC7D0AFFBC7D0AFF
+ BC7D0AFFBC7D0AFF3F21C8FF4324C5FF4528BDFF4028ACFF3A2395FF311D80FF
+ 2A1774FF271570FF2D1C77FF211468FF2B286DFF41457FFF414E82FF3D4D82FF
+ 3F4E8DFF3D4E91FF405999FF4865A2FF526EAEFF526EAFFF4C66A9FF4862A5FF
+ 4C66A8FF526CAEFF5773B3FF6685C4FF7B9BDCFF6284C6FF6385CBFF4C6FB9FF
+ 4D71BFFF3A60AEFF4169B4FF3E69B2FF3F68B1FF3C65AEFF3960AAFF385DA7FF
+ 385AA6FF3959A5FF4261ACFF415AA2FF304688FF273871FF2F3969FF333760FF
+ 343355FF433A4EFF463637FF4F3829FF543722FF5A391FFF633D1FFF653F1FFF
+ 633F21FF603E20FF5C3A1DFF5F3B1DFF633D1BFF673F1CFF693F1AFF693F1AFF
+ 663E1BFF643E1CFF653F1DFF633D1BFF613B19FF603A18FF603A18FF613B19FF
+ 633D1BFF653F1DFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF5E3818FF663E1BFF73421AFF74431DFF693E23FF543625FF
+ 36231EFF1A1114FF1D151CFF1E1829FF17122FFF171844FF2F3A78FF3E55A0FF
+ 3354A4FF264797FF2E4590FF304387FF304082FF2C3773FF282E63FF33335BFF
+ 423953FF44353DFF4A322CFF543623FF5F3B1DFF653D1AFF693C1AFF683B19FF
+ 663819FF633718FF653C1BFF643E1CFF633D1BFF603A18FF5E3816FF5F3917FF
+ 633D1BFF66401EFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF
+ 633D1BFF633D1BFF68401DFF633D1BFF603A1CFF613920FF623D23FF663E22FF
+ 683E1BFF6D3F10FF7E4A0EFF955E15FFAD701AFFB57818FFBA7B13FFBF7F13FF
+ C08010FFBE7D10FFBB7B0FFFBA7C12FFBB7D11FFBB7D11FFBB7D11FFBD7D11FF
+ BC7D0FFFBB7C0EFFBE7F11FFBE7E0EFFBC7C0CFFBB7B0BFFBC7A09FFBC7A09FF
+ BD7B0AFFBC7D0BFFBA7B0BFFB97D0CFFB77D0CFFB87F0CFFB9800CFFB9810AFF
+ BC820BFFBA820BFFBA8009FFB9810AFFBC820BFFBC840DFFBC830FFFBC830FFF
+ BE8210FFBB8012FFBE841DFFBA8019FFB77B11FFB67B0DFFBA7D0FFFBB8012FF
+ BC8016FFBC8016FFBA7F11FFB67C0BFFBF8718FFB4821EFF9D7124FFB2905BFF
+ E6CDB3FFFDEDE6FFF4EFEEFFEBEFF0FFE9F0EDFFE9F0EDFFEEF0F1FFF4F0F5FF
+ FAF3F8FFFBF4F7FFEDEDEDFFEDEFEFFFE8EBEFFFF9F5F4FFFFECDFFFD1AE8CFF
+ AF7F3FFFC0852FFFC18220FFC28115FFBF7C0FFFBE7C0BFFBE7F0DFFBF8010FF
+ BB8012FFB88011FFBC8310FFBD820EFFBF820AFFBF820AFFBF820AFFBC810DFF
+ B88112FFB98213FFB87C0AFFBD800CFFC0830FFFC0830FFFBE810DFFBD800CFF
+ BD800CFFBE810DFFBA7D09FFBA7D09FFBA7D09FFBA7D09FFBA7D09FFBA7D09FF
+ BA7D09FFBA7D09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBD800AFFBD800AFFBC7F09FFBB7E08FFBB7E08FFBC7F09FF
+ BD800AFFBD800AFFBA7D05FFBB7E06FFBB7E06FFBC7F07FFBC7F07FFBD8008FF
+ BE8109FFBE8109FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FF
+ BD7F09FFBD7F09FFBE800AFFBE800AFFBE800AFF492CBDFF4228B2FF3920A0FF
+ 2F188CFF2A1578FF26146FFF2A166FFF2A1873FF1B0967FF1D0E6AFF2C2675FF
+ 3C3C82FF3B4581FF374580FF3B498BFF3D5093FF445F9FFF4C68A8FF5571B2FF
+ 5672B3FF536DB0FF516BAEFF556FB2FF5A76B7FF5170AFFF5B7CBBFF6F8FD0FF
+ 5B7EC0FF6082C8FF4D70B9FF5074C0FF436AB5FF4069B2FF3E69B2FF4069B2FF
+ 4067B1FF4065AFFF3B60AAFF3658A4FF3454A0FF3D5BA8FF3C559DFF2E4486FF
+ 283873FF323B6DFF353962FF343355FF3E374CFF443638FF4D372CFF523723FF
+ 59371FFF623C1EFF643D1DFF633D1FFF603C1EFF5E391DFF5F3B1DFF633D1BFF
+ 683E1BFF6A3E19FF693F1AFF673E1DFF653F1DFF653F1DFF633D1BFF613B19FF
+ 603A18FF603A18FF613B19FF633D1BFF653F1DFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF613B1BFF5F3B1DFF653E1EFF71401AFF
+ 703E1AFF693D20FF583724FF39261FFF221616FF1F151BFF1C1524FF1A1731FF
+ 282B57FF3E4D8BFF415CA6FF2E53A5FF24499BFF2C4791FF2F4488FF314184FF
+ 2E3B79FF2D3269FF36355FFF3F3853FF42323DFF4B3530FF553724FF5C3A1DFF
+ 613B19FF653A19FF653A19FF65391CFF643A1DFF623B1BFF633D1BFF623C1AFF
+ 603A18FF5E3816FF5F3917FF623C1AFF653F1DFF633D1BFF633D1BFF633D1BFF
+ 633D1BFF633D1BFF633D1BFF633D1BFF633D1BFF673F1CFF643E1CFF643C1FFF
+ 633B1FFF653A1FFF683C1DFF6E4017FF75430EFF8E5712FFA26816FFB47618FF
+ BB7C14FFBE7D11FFC07F12FFC27F12FFBD7C10FFBD7C13FFBB7C14FFBE7C15FF
+ BD7F15FFBF7E15FFBE7E12FFBD7D11FFBD7E10FFBD7E0EFFBD7E0EFFBC7E0CFF
+ BB7E0AFFBB7C09FFBB7D07FFBB7D07FFBB7D07FFBD800CFFBB800CFFBA7F0BFF
+ BA7F0BFFBA8009FFB88009FFB88009FFB88009FFB9810AFFBA820BFFBB830CFF
+ BE830FFFBE830FFFBE8210FFBF810FFFBA7F11FFBE841DFFB88119FFB77D13FF
+ B97D0CFFBB7F0EFFBF8010FFBD7F13FFBD7F13FFBD7F13FFC0841AFFBF8722FF
+ B08028FFAD8747FFCEB18AFFF2DED3FFFBF0F2FFF0EDEFFFECEEEFFFEBF0EFFF
+ EBF0EFFFF0EFF3FFF2EEF4FFF5EDF4FFF5EDF4FFF0EDEFFFEDEDEDFFF5F3F2FF
+ FAF0E6FFE6CBB1FFBC9362FFB0762AFFBC7A1BFFC17F19FFC07E15FFBD7C0FFF
+ BD7C0FFFBD7E10FFBD8012FFBD8215FFBB8314FFBB8110FFBC810DFFBE800AFF
+ C08109FFBE800AFFBD800CFFBA800FFFBB8012FFB67A08FFBB7E0AFFBE810DFF
+ BE810DFFBD800CFFBC7F0BFFBC7F0BFFBE810DFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBE810BFFBD800AFFBC7F09FF
+ BB7E08FFBB7E08FFBB7E08FFBC7F09FFBD800AFFBB7E06FFBC7F07FFBC7F07FF
+ BC7F07FFBD8008FFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD7F09FFBD7F09FFBD7F09FF
+ BD7F09FFBD7F09FFBD7F09FFBD7F09FFBD7F09FFBE800AFFBE800AFFBE800AFF
+ 3B2792FF36228CFF2F1A81FF291477FF261370FF27126FFF251073FF250D79FF
+ 2E1489FF382495FF3F3397FF3D3A90FF373D84FF333F7FFF384688FF405495FF
+ 435E9EFF4766A5FF506CADFF536EB1FF516BB1FF516CAFFF5671B4FF5A76B7FF
+ 5978B7FF597AB9FF6687C6FF567ABAFF5A7DC1FF486BB4FF4C70BCFF466DB8FF
+ 426BB4FF416BB2FF426AB2FF436BB3FF4469B3FF3D62ACFF3557A3FF2F4F9BFF
+ 3A58A5FF364F99FF2B4084FF283A75FF333E70FF353B66FF323256FF3A3249FF
+ 44363AFF4B362EFF503625FF56371EFF5E3A1CFF623B1BFF603A1CFF5F391BFF
+ 603A1CFF603A1AFF643B1AFF663C19FF6A3E19FF693F1AFF683F1EFF69401FFF
+ 653F1DFF633D1BFF613B19FF603A18FF603A18FF613B19FF633D1BFF653F1DFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF613B1BFF
+ 603D23FF643D21FF6C3C1AFF6D3B17FF683C1FFF5C3925FF412B20FF2A1B18FF
+ 251A1CFF1C141FFF1A1933FF343C64FF4B5E9BFF4262ABFF2E54A6FF2C52A4FF
+ 2D4A95FF2E448BFF324287FF303F7DFF31386FFF383A63FF3E3954FF3E303BFF
+ 4B3732FF543827FF5A391FFF5E3917FF5F3917FF633A19FF643A1DFF643C1FFF
+ 613A1AFF613C1AFF603B19FF5E3917FF5D3816FF5D3816FF603B19FF633E1CFF
+ 623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF
+ 643E1CFF653F1DFF683F1FFF683C1DFF683919FF6E3D15FF794614FF854F10FF
+ A06718FFB17319FFBB7D17FFBF7F13FFBE7D10FFC07D10FFC07C11FFBF7B10FF
+ BF7D14FFBF7E15FFC17F16FFC08014FFC18013FFC18111FFC08010FFBF800EFF
+ BC7D0AFFBD7E0BFFBD7F09FFBD8008FFBD8008FFBC8005FFBB7F04FFBA7E03FF
+ BF820AFFBF820AFFBE800AFFBD800AFFBC7F09FFB97F08FFB87E07FFB87D09FF
+ BC800EFFBD810FFFBE8211FFC08111FFC08113FFBF7F13FFBF7E12FFBD7C13FF
+ BD831AFFBA8217FFBB8012FFBC810DFFC0810EFFC1820FFFC18111FFBF7F13FF
+ C07E17FFC58828FFB68029FFAD8037FFC7A675FFEFD7BFFFFDEDEEFFF9EFFBFF
+ EFEBF0FFEEEEEEFFF0F0F0FFF1F1F1FFF0EFF3FFF0ECF2FFF0E8F2FFEFE8EFFF
+ F9F4F6FFF5F0EDFFFEF5ECFFEBD8C3FFBA976FFFA47434FFB77820FFC27D16FF
+ BF7C15FFBE7D14FFBE7D14FFBD7D11FFBD7D11FFBC7E12FFBD8215FFC08517FF
+ BC800FFFBE800EFFBE7F0CFFBF7F09FFBF7E0BFFBE7F0CFFBE7F0FFFBE7F0FFF
+ B77907FFBA7D09FFBC7F0BFFBD800CFFBB7E0AFFBA7D09FFBB7E0AFFBD800CFF
+ BE810DFFBE810DFFBE810DFFBE810DFFBE810DFFBE810DFFBE810DFFBE810DFF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BF820CFFBE810BFFBD800AFFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBC7F09FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FFBF820AFFBF820AFF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BE8109FFBE8109FFBE8109FF2D1E72FF27176EFF21106BFF200E6CFF261273FF
+ 2C177EFF30168BFF311695FF4A2FB5FF553DBFFF4D3EB1FF3A3696FF343984FF
+ 333F7FFF394886FF445794FF435E9EFF4563A4FF4D68ABFF4F6AADFF4F69AFFF
+ 506AB0FF546FB2FF5773B4FF5E7CBDFF5879B8FF5C7FBEFF5579B9FF557ABEFF
+ 456BB3FF4970BAFF4C73BDFF4972BBFF456FB6FF426AB2FF4169B1FF4368B2FF
+ 3E63ADFF3758A7FF31509FFF3D5BA8FF324D97FF283F83FF2B3D7AFF364175FF
+ 373D68FF34335AFF37314AFF44363CFF49362FFF4F3525FF55351EFF5C371BFF
+ 603919FF5E381AFF5C3618FF603A1CFF613A1AFF633A19FF663C19FF693D18FF
+ 693F1CFF6B401FFF6A4120FF653F1DFF633D1BFF613B19FF603A18FF603A18FF
+ 613B19FF633D1BFF653F1DFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF613B1DFF603C24FF613B23FF683A18FF6A3A16FF673E1EFF
+ 5E3C24FF473021FF321F1AFF2C1E1FFF1C141EFF181830FF2E3A62FF465E9AFF
+ 3F62ABFF3058AAFF325AACFF31509BFF2F488EFF2F4488FF304180FF303B74FF
+ 383B67FF3E3A57FF3D313DFF493633FF533928FF583A1FFF5E3B1AFF603A1AFF
+ 603A1AFF633B1FFF623C1EFF5F3919FF603B19FF603B19FF5E3917FF5C3715FF
+ 5D3816FF5F3A18FF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF623D1BFF
+ 623D1BFF623D1BFF623D1BFF633D1BFF673E1DFF6A401DFF6A3D17FF6E3D11FF
+ 784310FF8C5315FF9B6115FFAF731AFFB87917FFBD7F15FFC07F12FFBD7C0FFF
+ BD7C0FFFBF7B12FFBE7C13FFBE7D10FFBF7E11FFC07F12FFC18111FFC18111FF
+ C0810FFFBF800EFFBE7F0CFFBB7D07FFBC7E08FFBD8008FFBE8207FFBE8207FF
+ BD8106FFBB7F03FFBA7E02FFC08109FFC08109FFBE800AFFBD7F09FFBC7F0BFF
+ BA7F0BFFB97D0BFFB97D0CFFBD8012FFBE8113FFC08014FFC07F16FFC17F16FF
+ BF7C15FFC07B14FFBD7A13FFBC7F17FFB98013FFBD8110FFC0830FFFC2840EFF
+ C38411FFC68316FFC3811AFFBE7E1FFFBD812DFFAA772EFFB1894FFFE1C5A3FF
+ FFEEE1FFFAEDF5FFF3ECF9FFF1EDF2FFF2F0F0FFF2F0F0FFF3F0F2FFF2EEF3FF
+ F1EDF3FFF0EBF4FFF1EAF1FFF8F2F3FFFFF7F0FFFFF2DFFFDAC09CFFA67D46FF
+ A67023FFC48321FFC88419FFBE7D14FFBE7F17FFBE8016FFBC7E12FFBA7C10FF
+ BA7D0FFFBD8012FFC08413FFBB7F0EFFBD7F0DFFBD7E0BFFBC7E08FFBC7D0AFF
+ BD7E0CFFBE7F0DFFBE7F0DFFBC7E0CFFBE810DFFBF820EFFBE810DFFBB7E0AFF
+ BA7D09FFBB7E0AFFBC7F0BFFBE810DFFBE810DFFBE810DFFBE810DFFBE810DFF
+ BE810DFFBE810DFFBE810DFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBF820CFFBE810BFFBD800AFFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBE8109FFBE8109FFBE8109FFBE8109FFBE8109FF
+ BF820AFFBF820AFFBF820AFFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBE8109FFBE8109FFBE8109FF292069FF211666FF
+ 1A0B67FF1A076EFF241081FF351D99FF462AB3FF4D30C3FF492BC4FF5037C7FF
+ 4235AFFF302C91FF303683FF354280FF3B4983FF3F538DFF46629FFF4866A7FF
+ 4E6BAEFF506DB2FF526CB2FF526CB2FF546FB2FF5773B4FF5977B8FF5273B2FF
+ 5679B8FF567ABAFF567CBDFF4B72B7FF5178C2FF5980CAFF5079C2FF4973BAFF
+ 4169B1FF3F65ADFF4164AEFF3F62ACFF3A5BAAFF3756A5FF415FACFF324D97FF
+ 294084FF2E407DFF364175FF373C69FF35355DFF37324DFF42353DFF49362FFF
+ 4F3426FF553420FF5C371BFF5E381AFF5D3719FF5B3517FF603A1CFF623B1BFF
+ 663B1AFF693C1AFF6A3E19FF693F1CFF6A3F1EFF683F1FFF653F1DFF633D1BFF
+ 613B19FF603A18FF603A18FF613B19FF633D1BFF653F1DFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF613B1DFF5B3922FF5F3921FF
+ 663C19FF683D16FF69401FFF603F25FF4D3323FF38231BFF2D1B1AFF1D141EFF
+ 14162EFF25345BFF3C5894FF3D62ACFF305AADFF325AADFF3755A2FF314A92FF
+ 2E448BFF304281FF303D75FF363C67FF3D3B58FF3E3641FF453431FF513828FF
+ 593B22FF5D3E1DFF613E1DFF603D1CFF613A1EFF60391DFF5E3818FF603B19FF
+ 603B19FF5F3A18FF5D3816FF5D3816FF5F3A18FF613C1AFF613C1AFF613C1AFF
+ 613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF623B1BFF663D1CFF
+ 6B3E18FF704010FF79440BFF88510CFFA06515FFB3751BFFB77816FFBA7C12FF
+ BC7D0FFFBE7D10FFBC7B0EFFBA7A0EFFBD7B12FFBF7E12FFBC7C0CFFBF7E0BFF
+ C07F0CFFC1800DFFC1800DFFC07F0CFFBD7E0BFFBC7E08FFBA7C06FFBB7D07FF
+ BD7F09FFBE8109FFBE8109FFBD8008FFBC7F07FFBB7E06FFBE7D0AFFBE7D0AFF
+ BD7E0CFFBD7E0CFFBC7D0DFFBB7F0EFFBB7E10FFB97E11FFBB7F15FFBC7F17FF
+ BE7E18FFC07E18FFC17D18FFBF7B16FFC07917FFBD7914FFBC7A13FFBB7D11FF
+ BD8110FFBE8210FFC28511FFC48515FFC8851EFFC78526FFC0822EFFB37D36FF
+ A67B42FFC4A479FFF6E1CBFFFFF4ECFFEFE7F1FFF1EDF9FFF2F1F5FFF3F1F1FF
+ F3F0F2FFF2EEF3FFF3EFF4FFF4F0F5FFF5F1F7FFF8F3F5FFF1EAE7FFFFFBEDFF
+ FFE9CBFFD1B07FFFB0853CFFB78228FFC68620FFC18014FFBE8016FFBE8119FF
+ BE8218FFBE8014FFBA7E0DFFBB7D0BFFBC7E0CFFBF820EFFBD800CFFBD800CFF
+ BC7F0BFFBB7E0AFFBB7D0BFFBD7E0CFFBE7F0DFFBE7F0DFFC28412FFC38513FF
+ C38513FFC08210FFBD7F0DFFBA7C0AFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7F0BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBF820CFFBE810BFF
+ BC7F09FFBB7E08FFBB7E08FFBB7E08FFBC7F09FFBC7F09FFBF820AFFBF820AFF
+ BF820AFFBE8109FFBE8109FFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FF1D1568FF211771FF291984FF332097FF3F28ACFF462EBCFF4B30C6FF
+ 4A2FCCFF4028C4FF4530C2FF3E33ADFF353496FF363C87FF384583FF394781FF
+ 354782FF405B9BFF4563A4FF4D6AAFFF4F6CB1FF4F69AFFF4D67ADFF4F6AADFF
+ 506EAFFF5576B5FF5376B5FF597CBBFF587EBEFF567CBDFF4D74B9FF5077C1FF
+ 587FC9FF517BC2FF4C74BCFF466CB4FF4066AEFF4063ADFF3F62ACFF3B5CABFF
+ 3859A8FF3E5CA9FF2E4894FF293F86FF314281FF364076FF343A67FF36365EFF
+ 39344FFF42353DFF483530FF4E3428FF543520FF5A371DFF5F391BFF5D3719FF
+ 5C3618FF603A1CFF623B1BFF683D1CFF6B3E1CFF6B3F1AFF6B3E1CFF683D1CFF
+ 653C1CFF653F1DFF633D1BFF613B19FF603A18FF603A18FF613B19FF633D1BFF
+ 653F1DFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 613B1DFF58361FFF5D3921FF653D1AFF673E17FF66411BFF624022FF513622FF
+ 402A1FFF2A1714FF1F141CFF141830FF22325CFF3A5794FF3C63AEFF305AADFF
+ 2E56A9FF3959A5FF304C93FF2E478DFF314586FF2E3D75FF333966FF3A3B57FF
+ 3E3744FF433431FF4F3828FF583D23FF5C3F20FF603E20FF613D1FFF5F3A1EFF
+ 5E391DFF5E3818FF603B19FF613C1AFF603B19FF5E3917FF5E3917FF5F3A18FF
+ 613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF613C1AFF
+ 613B1BFF633B1EFF643B1AFF6C3F13FF77460EFF89530CFF9D6311FFB27416FF
+ BF8018FFBD7D11FFBC7B0EFFBB7A0DFFBC7D0FFFBC7C10FFBA7910FFBC7B12FF
+ BF7F13FFBC7C0CFFBC7D0AFFBF7E0BFFBE7F0CFFC07F0CFFBD7E0BFFBC7D0AFF
+ BC7D0AFFBA7B08FFBA7D09FFBC7D0AFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7D0AFFBB7C0AFFBB7C0AFFBC7C0CFFBC7D0DFFBB7E10FFB97E10FFBA7F12FF
+ B87E14FFB87E15FFB97F16FFBC7F17FFBE7F17FFC07E17FFC07D16FFBF7B16FF
+ BE7A15FFBD7A13FFBD7C13FFBD8012FFBE8113FFC08315FFC3851BFFC58624FF
+ C5862EFFC1873FFFB38447FFBA976BFFE1C9ABFFFFF3E3FFF7F2EFFFEBE9EFFF
+ F0F2FAFFF2F4F5FFF3F2F4FFF3EFF4FFF4EEF3FFF3EFF4FFF5F1F6FFF5F4F6FF
+ FAF5F6FFFAEFEBFFFFF3E0FFEACDA6FFC0995BFFB78834FFC28B28FFC3871DFF
+ BF7F13FFBF8319FFBD8319FFBE8316FFBE8211FFBD7F0DFFBB7E08FFBB7E08FF
+ BB7F07FFBE810BFFBC820BFFBB800CFFBA7F0BFFBA7E0CFFBD7F0DFFBE810DFF
+ BF800DFFC48614FFC58715FFC48614FFC18311FFBD7F0DFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7E0AFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBD800AFFBC7F09FFBC7F09FFBB7E08FFBB7E08FFBC7F09FFBD800AFF
+ BE810BFFBF820AFFBF820AFFBE8109FFBE8109FFBE8109FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FF231684FF302096FF402EB1FF4E38C6FF
+ 533AD0FF4D35CFFF432CCAFF3C27C3FF422FC4FF4234BBFF433DACFF3F409AFF
+ 384086FF384381FF3A4484FF324284FF375193FF3F5D9EFF4B68ADFF4E6BB0FF
+ 4D66AEFF4A64AAFF4B68ABFF4F6DAEFF5172B1FF577BB7FF5E81C0FF5D83C3FF
+ 547ABBFF4C73B8FF4B73BBFF5079C2FF4C74BCFF4A72BAFF4A70B8FF476DB5FF
+ 4669B3FF4063ADFF3B5CABFF3758A7FF34529FFF253F8BFF263C83FF324483FF
+ 344076FF333968FF36355FFF383451FF40353FFF483530FF4E3428FF553522FF
+ 5B381EFF603A1CFF5F391BFF5D3719FF61391CFF653C1CFF693F1CFF6D411CFF
+ 6E411CFF6A3D1BFF653A19FF613818FF653F1DFF633D1BFF613B19FF603A18FF
+ 603A18FF613B19FF633D1BFF653F1DFF623C1AFF623C1AFF623C1AFF623C1AFF
+ 623C1AFF623C1AFF623C1AFF613B1DFF58361EFF5E3B21FF663F19FF663E14FF
+ 633F17FF603F1EFF573A25FF4C3226FF2F1B16FF21161EFF151931FF23355EFF
+ 3A5996FF3D65B0FF325BB0FF3158ADFF3557A3FF2E4C93FF304A90FF33498AFF
+ 2E3F77FF303965FF363856FF3D3643FF433733FF4E3A29FF553C22FF5B3E1FFF
+ 5F3D1FFF5E3C1EFF5E3C1FFF5E3C1FFF5D3A19FF5F3C1AFF603D1BFF603D1BFF
+ 5E3B19FF5D3A18FF5E3B19FF603D1BFF5E3B19FF5E3B19FF5E3B19FF5E3B19FF
+ 5E3B19FF5E3B19FF5E3B19FF5E3B1AFF623B1FFF643B1AFF704212FF845112FF
+ 9B6512FFAF7515FFBC7E12FFC0810FFFC18210FFBD7E0CFFBC7B0EFFBE7E12FF
+ BE7E12FFB97B11FFBA7C12FFC08014FFBC7D0FFFBD7E10FFBF7E11FFBE7F11FF
+ BF7E11FFBE7F11FFBD7E10FFBC7D0FFFBA7B0DFFB87B0DFFBA7B0DFFB87B0DFF
+ B97C0EFFBA7D0FFFBB7E10FFBB7F0EFFBC7D0DFFBC7D0DFFBA7E0DFFB87E0DFF
+ B67E0FFFB57E0FFFB67F10FFB67E11FFB67E11FFB77F12FFB98013FFBA8213FF
+ BC8113FFBE8113FFBF8010FFBF7E12FFC17D18FFC17F19FFBD8018FFBA8017FF
+ BA8017FFBC811DFFBF8329FFBE8536FFB68344FFB9905FFFD6BB99FFF7E9D3FF
+ FAF6EBFFEFF3EEFFEEF2F3FFEFF4F5FFEFF4F3FFF1F3F4FFF2F0F6FFF4F0F6FF
+ F3EFF4FFF3F0F2FFF1F1F1FFF5F2EEFFFFF5EDFFEED8BFFFC7A776FFAD833CFF
+ B28223FFBA861CFFBC8419FFBE841AFFBC8218FFBB8215FFBC8113FFBD810FFF
+ BF820CFFBF8308FFBD8106FFBC8004FFBF8409FFBC830AFFB9800CFFB9800DFF
+ B9800DFFBB7F0DFFBE810DFFBF820EFFC18311FFC28412FFC18311FFBF810FFF
+ BC7E0CFFBB7D0BFFBD7F0DFFBF810FFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7E0AFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BC7F09FFBD800AFFBE810BFFBF820CFFBE8109FFBE8109FFBE8109FFBD8008FF
+ BC7F07FFBC7F07FFBC7F07FFBB7E06FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBC7F07FFBC7F07FFBC7F07FF4131B4FF
+ 4533BCFF4933C7FF4833CCFF4630CCFF442FCCFF4330CDFF4533CCFF402FC0FF
+ 3C31B0FF403CA5FF3E4196FF303982FF313D7FFF3C4588FF3A488AFF3C5293FF
+ 4460A1FF536EB1FF5572B7FF516EB3FF4E6BB0FF4F6FB1FF5575B6FF4566A5FF
+ 5175B1FF5B80BEFF5D83C3FF527ABBFF4E77BCFF4D77BEFF527BC4FF456DB5FF
+ 4A71B6FF4E75BAFF5073BCFF4B6EB7FF4265AFFF395BA7FF3555A1FF2A4994FF
+ 1D3980FF263B7FFF344683FF344076FF323867FF33355EFF363451FF3E3440FF
+ 463532FF4E3426FF563521FF5E391DFF613A1AFF603A1CFF5E381AFF613A1AFF
+ 653C1CFF6A401DFF6E411FFF6E411FFF683E1BFF643918FF5F3615FF673E1DFF
+ 653D1AFF633A19FF623A17FF623918FF633B18FF653C1BFF673F1CFF643B1AFF
+ 643C19FF643B1AFF643C19FF643B1AFF643C19FF643B1AFF623B1BFF5B381EFF
+ 613C20FF663F19FF623C12FF5F3B13FF603D1BFF5C3E23FF553928FF3D261EFF
+ 271B21FF141932FF203562FF365999FF3C63B1FF375FB2FF3C61B5FF3254A0FF
+ 2E4B95FF324C92FF374D8EFF304179FF2F3863FF343753FF3C3542FF453935FF
+ 4F3B2AFF553C22FF593B1EFF5B3C1DFF5E3C1EFF5F3C22FF603E21FF5B3A19FF
+ 5F3C1AFF613E1CFF613F1BFF5F3C1AFF5E3B19FF5F3C1BFF603C1EFF5E3A1CFF
+ 5E3B1AFF5E3B1AFF5E3B19FF5E3B1AFF5E3B1AFF5E3B1AFF603A1CFF653B1EFF
+ 6A3D17FF784611FF8D5912FFA77217FFB98017FFBD8110FFBB7C09FFC58614FF
+ C08010FFBD7D11FFBE8016FFBE8016FFB87C12FFB87D10FFBC8114FFBC7E12FF
+ BC7E12FFBD7F13FFBE8014FFBE8113FFBD8012FFBC7F11FFBC7F11FFB97C0EFF
+ B67B0DFFB77A0CFFB57A0DFFB67B0EFFB77C0FFFB97E11FFBA7F11FFBC7F11FF
+ BC800FFFBB7F0EFFB97F0EFFB67E0DFFB47E0CFFB47D0EFFB37C0DFFB57D10FF
+ B67E11FFB77F12FFBA8213FFBA8213FFBC8211FFBE8210FFBD8012FFC1811BFF
+ C0821EFFBF811BFFBA7F18FFB97E17FFB87E1FFFBA812CFFB6823CFFA67A45FF
+ B59571FFE4D1BCFFFCF6EBFFEDEEEAFFEAEFEDFFF4F9F7FFEDF2F0FFEEF3F1FF
+ F0F2F2FFF7F0F7FFF7EFF9FFF3EFF5FFEFEEF2FFEAECEDFFF0ECE7FFFEEEE1FF
+ D7BB9CFFB38D53FFAC7F2EFFB2801CFFB58012FFB77F14FFBB8117FFBB8215FF
+ B98112FFB97F0EFFBC810DFFC0830DFFC2850DFFBF8308FFBC8005FFC0850AFF
+ BD840BFFBA810DFFBA810EFFBA810EFFBC810DFFBF820CFFC0830DFFBD800CFF
+ BE800EFFBE800EFFBD7F0DFFBB7D0BFFBB7D0BFFBE800EFFC18410FFBD7F0DFF
+ BD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBC7F09FF
+ BC7F09FFBD7F09FFBC7F09FFBD7F09FFBC7F09FFBD7F09FFBC7F09FFBB7C09FF
+ BA7D07FFBB7D07FFBA7D07FFBD7F09FFBE810BFFC0820CFFC2850DFFBE8109FF
+ BE8109FFBD8008FFBC7F07FFBC7F07FFBB7E06FFBB7E06FFBA7D05FFBD8008FF
+ BD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FF
+ BD8008FFBD7F09FFBD8008FFBD7F09FFBD8008FFBD7F09FFBD8008FFBC7E08FF
+ BC7F07FFBC7E08FF4A3AC8FF4533C6FF442CC6FF432DC9FF4535C9FF4436CAFF
+ 4031C9FF3D2DC1FF4534C1FF3A2CA9FF352F94FF414499FF394292FF323E86FF
+ 40498CFF384583FF3C4E8DFF445D9DFF536DAFFF5774B7FF5271B6FF4C6DB2FF
+ 4C6FB1FF4F73B3FF4B70AEFF4E73B1FF557AB8FF597FBFFF5981C2FF547DC2FF
+ 4F79C0FF4D77BEFF4C73B8FF4E73B7FF5378BCFF5375BBFF4465AEFF395AA3FF
+ 32529DFF2A4A93FF3B589DFF304A8CFF2C3F7CFF2D3E76FF333E70FF313A66FF
+ 30355CFF343452FF3F3643FF483734FF543827FF5D3A20FF643D1DFF663D1CFF
+ 633C1CFF613A1AFF643B1AFF683D1CFF693E1DFF683D1CFF633A1AFF613818FF
+ 653A19FF673D1AFF6A401DFF693F1AFF673D1AFF663C17FF663C19FF663C17FF
+ 663C19FF673D18FF663C19FF663C17FF663C19FF663C17FF663C19FF663C17FF
+ 663C19FF643C19FF643C1FFF623B1BFF633B18FF673D18FF69421CFF68421FFF
+ 633D1DFF57391EFF462C1CFF25181AFF0B112EFF283F71FF3C60A6FF335DAAFF
+ 395DA9FF3B5DA9FF3A5AA6FF2F4F98FF2D4A8FFF2E4583FF2A3C71FF313B63FF
+ 3A3B55FF3E3641FF4B3B35FF513A2AFF563B21FF59391CFF5B391BFF5D3B1DFF
+ 5E3D23FF614124FF5A3B1CFF5D3D1AFF5E3E1AFF5E3F18FF603E1AFF603D1CFF
+ 5F3A20FF5E3820FF633A23FF653D24FF633F21FF603D1CFF5A381AFF593719FF
+ 5C391FFF643C20FF643110FF774112FF8D5718FF9F6A1AFFAB7818FFB47D14FF
+ B87F12FFBA7F12FFBE8016FFBE7F17FFBE7F17FFBC7F17FFBC8016FFBA8016FF
+ BA8016FFBA8016FFB87D10FFB97E11FFBA7F11FFBA7F11FFBA800FFFB87E0DFF
+ B67D0AFFB57C09FFB57C09FFB67F0CFFB97F0EFFB77F10FFB67E0FFFB57D0EFF
+ B77E11FFBB8012FFBB7E10FFBE8211FFC08412FFBF8410FFB9800CFFB67D0AFF
+ B67C0BFFB57D0EFFB57B11FFB87E15FFBA8017FFBA8017FFB87E14FFB77E11FF
+ B98110FFBB8415FFB47D15FFBA831BFFBC8219FFBF8319FFCA8A24FFC48729FF
+ B37B2CFFA57639FFAC8862FFDEC6B2FFF6ECE5FFEFECEEFFEEF1F5FFF0F4F5FF
+ F0F1EDFFF6F6F0FFEFEFE9FFFEFAF9FFFCF0F6FFF6EBF5FFEDE9F5FFE9E9F5FF
+ F0F2FAFFF1ECE9FFE7D2BCFFBC9B6EFFB1853EFFB28026FFB17D13FFB88112FF
+ BB8013FFBD7F13FFBC7F11FFBC800FFFBB7F0EFFBC7E0CFFBC7F0BFFBD800CFF
+ BE810DFFBF820CFFBF820CFFBE810BFFBB800CFFBA7F0BFFBA7F0BFFBD800AFF
+ BE810BFFBF820CFFC28511FFBD800CFFBC7F0BFFBF820EFFBF820EFFBC7F0BFF
+ BD800CFFC2850FFFB97C08FFBA7D07FFBC7F09FFBE810BFFBF820CFFBE810BFF
+ BD8109FFBC8008FFBC7F07FFBB7E06FFBC7D05FFBB7D07FFBF7F09FFBE7F0CFF
+ C07F0CFFBC7D0AFFBC7A09FFBB7C09FFBF7E0BFFBE800AFFC0800AFFBD8008FF
+ BD7E06FFBA7D05FFBA7D05FFBA7D07FFBC7F09FFBD800AFFBE810BFFBE810BFF
+ BD800AFFBD800AFFBB7E08FFBA7D07FFB97C06FFBA7D07FFBC7F09FFBE810BFF
+ BC7F09FFBB7E08FFBC7F09FFBE810BFFBF820EFFBE810BFFBB7E0AFFB97C06FF
+ BB7E0AFFBD800AFFBB7E0AFFBB7E08FFBB7E0AFF4834CDFF4833CFFF4B31D1FF
+ 4930CEFF4131C4FF3D31BFFF3C2FC1FF4030BEFF4732B6FF3C2B9EFF342B86FF
+ 3E3F8FFF3C4392FF313C86FF394285FF364080FF3C4D8CFF43599AFF4E68AAFF
+ 5370B3FF5170B5FF4B6EB2FF496FB0FF4B71B2FF5175B5FF5378B6FF567BB9FF
+ 577DBDFF577FC0FF5680C5FF5781C8FF5781C8FF4C71B5FF4C6FB1FF4F72B6FF
+ 4C6EB4FF3F60A9FF3859A2FF36569FFF314F96FF3B5699FF314A8AFF2D3F7AFF
+ 2F3F74FF333F6FFF323B66FF2E355CFF323452FF3D3645FF463735FF533726FF
+ 5D381CFF623B1BFF653C1BFF633B1EFF623A1DFF673C1BFF683E1BFF683D1CFF
+ 653C1CFF60391DFF60381BFF643918FF673B16FF6D401EFF6A401BFF6B3E1CFF
+ 673D18FF693C1AFF673D18FF693C1AFF683E19FF693C1AFF673D18FF683B19FF
+ 663C17FF683B19FF663C17FF693C1AFF673D1AFF633D1BFF643E1CFF663E1BFF
+ 653E18FF633B18FF603A17FF5F3916FF5A381AFF4F3420FF281C1CFF0E1634FF
+ 2B4379FF375DA5FF2E57A6FF395CA6FF3E5EA7FF405FAAFF3956A0FF385298FF
+ 334A88FF2B3C6FFF2C375DFF373951FF3D3540FF493835FF503727FF563720FF
+ 5C3C1FFF5F3D1FFF5D3B1DFF5A3A1DFF5D3D20FF5C3A1CFF5F3C1AFF603F18FF
+ 603F18FF623E18FF623D1BFF613A1EFF60381FFF5E351EFF5E361DFF5E371BFF
+ 5F391BFF5F391BFF603A1CFF60381FFF683A1BFF794217FF8B5116FF9E641CFF
+ AB751EFFB27E1AFFB68217FFBC8417FFBE841AFFBB7E16FFBC7F17FFBC7F17FF
+ BC8016FFBA8114FFBA8114FFBA8114FFB98013FFB67D10FFB77E11FFB88011FF
+ B88011FFB77F0EFFB67F0CFFB47D0AFFB37C09FFB67F0CFFB8810EFFB98110FF
+ B88011FFB67E0FFFB57C0FFFB67C12FFBA7F12FFBA7D0FFFBB7F0EFFBD810FFF
+ BE830FFFBD820EFFBB800CFFB97F0EFFB97E10FFBD8018FFBD821BFFBF831FFF
+ BE821EFFBC821BFFBB8318FFBD8617FFBD881AFFB48119FFB68119FFB87E14FF
+ BD8018FFC88724FFC0842BFFB27E37FFAB834FFFC4AA8CFFEBDBCFFFF8F2F3FF
+ EDEDF3FFEDF0F5FFF1F2F6FFEEEFEDFFF3F3EDFFF9F6F1FFF9F4F1FFF5EAEDFF
+ F9EEF8FFF4EFFEFFEFEFFBFFF6F6FCFFF6EFE6FFDBC3A5FFBB9460FFB68638FF
+ B98324FFB57E15FFBB8314FFBF8117FFC18017FFBF8012FFBE7F0FFFBD7E0EFF
+ BD7E0EFFBD7F0DFFBD7F0DFFBE800EFFBF810FFFBD800CFFBD800CFFBE810DFF
+ BE810DFFBE810BFFBE810BFFBD800AFFBD800AFFC18410FFBD800CFFBC7F0BFF
+ BE810DFFBE810DFFBC7F0BFFBD800AFFC1840EFFBD800AFFBD800AFFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8106FFBC8106FFBC8005FFBD7E04FFBD7E06FF
+ BE7E08FFC1800DFFC1800DFFC07E0DFFBE7C0BFFBD7B0AFFBE7C0BFFBF7E0BFF
+ C07F0CFFC0800AFFBF8008FFBE7F07FFBB7E06FFBC7F09FFBC7F09FFBD800AFF
+ BE810BFFBE810BFFBD800AFFBC7F09FFBB7E08FFBD800AFFBB7E08FFBA7D07FF
+ BB7E08FFBD800AFFBE810BFFBD800AFFBB7E08FFBC7F0BFFBE810DFFBF820EFF
+ BE810DFFBB7E0AFFBA7D09FFBB7E0AFFBD800CFFBF820EFFBF820EFFBF820EFF
+ 4830D0FF4B30D3FF4F2ED6FF4B2ED1FF432FC4FF3F2FBCFF3D2DB7FF422DB1FF
+ 3B2498FF32207EFF2A1F68FF383777FF44498EFF3C4289FF3A4087FF3D468AFF
+ 3C4C8EFF3F5596FF4761A3FF4D6AADFF4E6FB4FF4E71B5FF4C71B5FF4C72B3FF
+ 5276B6FF5478B8FF547ABAFF567CBCFF567EBFFF5680C5FF5781C8FF5680C7FF
+ 4A6EB4FF476AAEFF466AB0FF4367ADFF385BA4FF3656A1FF3857A2FF35529CFF
+ 385298FF2F4888FF2C3E79FF2F3F74FF344070FF343A67FF2E355CFF323452FF
+ 3B3645FF463637FF503626FF59361CFF60381BFF623B1BFF613A1EFF613A1EFF
+ 683F1FFF663D1CFF653C1CFF623B1BFF5F3A1EFF613A1EFF623919FF633916FF
+ 6A3F1EFF673F1CFF683D1CFF653D1AFF673C1BFF653D1AFF683D1CFF663E1BFF
+ 683D1CFF653D1AFF663B1AFF633B18FF653A19FF643C19FF673C1BFF663D1CFF
+ 5F3917FF623C1AFF663E1BFF643D17FF5F3714FF5B3512FF5E3816FF5E3C1FFF
+ 573C28FF2B1D1EFF181E3BFF354A81FF3659A2FF274FA1FF385AA6FF3E5DA8FF
+ 425FAAFF3D58A2FF3C559BFF374C8AFF2B3C6FFF2C365EFF373852FF403744FF
+ 483635FF4C3428FF54351EFF5C3C1FFF603F1EFF5F3C1BFF5A3918FF5C381AFF
+ 61391CFF643B1BFF653D1AFF653E18FF633F17FF633F17FF623D17FF613B18FF
+ 5D3616FF5D3518FF60351AFF62381BFF653B1EFF693D1EFF6B3E1CFF6F3F15FF
+ 8D551AFF9D631BFFAC731EFFB27D1CFFB68217FFB88412FFBD8715FFC1891AFF
+ BA7F12FFBB8013FFBC8114FFBD8214FFBD8312FFBC8211FFBB8012FFBA7F12FF
+ B87D10FFB97E11FFB97E11FFB97E10FFB97E10FFB87E0DFFB77D0CFFB67C0BFF
+ BA800FFFBB8012FFBC8113FFBB8013FFB87C12FFB77B11FFB77A12FFB97C14FF
+ B97B11FFBB7B0FFFBC7D0FFFBE7F0FFFBE8211FFBF8312FFBE8113FFBB8013FF
+ BB7D17FFBC7E1AFFBC801CFFBC801CFFBB8019FFBB8118FFBC8316FFBC8419FF
+ B6831BFFB6801BFFB97F16FFC2841EFFC7892BFFBC8433FFB6894CFFBE9B73FF
+ E6D1BBFFFBF0E8FFFEF9F8FFEEEDEFFFF1F0F2FFF2F4F5FFF1F1F1FFF2F3F1FF
+ FBFAF6FFF2F0EFFFEEE9EBFFF8F1F8FFF4F0FBFFF5F1F7FFFAF5F4FFF1E2D2FF
+ C5AA85FFB38B51FFB58434FFBE8627FFBB811AFFBF8319FFC2831BFFC18319FF
+ BF8012FFBF8010FFBE7F0FFFBD7E0EFFBD7F0DFFBD7F0DFFBE800EFFBF810FFF
+ BB7E0AFFBD800CFFBE810DFFC0830FFFC0830DFFBE810BFFBD800AFFBB7E08FF
+ BF820EFFBC7E0CFFBB7D0BFFBD7F0DFFBD800CFFBB7E0AFFBC7F09FFBF820CFF
+ C1840EFFBF820CFFBD8109FFBA7E06FFBA7E06FFBA7E06FFBB7F07FFBC8008FF
+ BC7F07FFBC7F07FFBC7E08FFBE800AFFC1820FFFC1820FFFBE7F0DFFBC7D0BFF
+ BC7D0BFFBC7D0BFFBD7E0BFFBD7E0BFFBD7F09FFBD8008FFBC7F07FFBC7F07FF
+ BE810BFFBE810DFFBF820EFFBE810DFFBE810DFFBC7F0BFFBB7E0AFFBA7D09FF
+ BF820EFFBD800CFFBC7F0BFFBC7F0BFFBE810DFFBF820EFFBD800CFFBB7E0AFF
+ BC7E0CFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBB7D0BFFBC7E0CFF
+ C28412FFC28412FFC28412FF4C2FD2FF492BD0FF4A28CDFF4B2BCAFF4832C0FF
+ 4432B5FF3C2AA7FF382495FF31187AFF2D1765FF24174FFF352E61FF4B4C86FF
+ 444988FF3D3F85FF434C90FF3B4B8DFF3B5192FF3F599BFF4865A8FF4E6FB4FF
+ 5275B9FF5176BAFF5075B9FF4D73B4FF5278B8FF577DBDFF557EBDFF557CC0FF
+ 527CC1FF4E78BFFF4872B9FF486CB2FF4466ACFF4266ACFF3F62ABFF3659A3FF
+ 3457A1FF3756A1FF34519BFF365096FF2D4587FF2A3C79FF2E3D75FF353E70FF
+ 343A67FF2E355CFF323452FF3C3647FF433536FF4E3325FF55331BFF5D3719FF
+ 60381BFF613A1EFF5F3A1EFF674020FF643E1CFF623B1BFF613B1DFF603B1FFF
+ 603B1FFF623919FF5F3615FF643B1AFF613B19FF633A1AFF613B19FF643B1BFF
+ 633D1BFF663D1DFF653F1DFF673E1EFF643E1CFF643B1BFF613B19FF633A1AFF
+ 623C1AFF663D1DFF653F1DFF5B3614FF5D3915FF603B15FF5F3A14FF5E3815FF
+ 5E3A16FF633E1CFF604023FF583D29FF2C1E1FFF212542FF3F5488FF3859A2FF
+ 264C9EFF3659A9FF3E5EAAFF405AA6FF38519BFF364D91FF324785FF2D3D72FF
+ 323B66FF3C3E5CFF423A4BFF46373BFF4F3830FF543623FF57361CFF5B391BFF
+ 603D1BFF5F3C1BFF5E3717FF67391AFF693A1BFF693C1BFF673D1AFF653E17FF
+ 653F15FF623F14FF613D15FF623C19FF633C1CFF683C1FFF693A1EFF693A1AFF
+ 6D3D19FF744519FF7F4C14FF9D631BFFAA6F19FFB37919FFB67F16FFB6800EFF
+ B57F0CFFB9820FFFBD8514FFB97E10FFBA7F11FFBC8211FFBD8411FFBD8411FF
+ BC8211FFBA7F11FFB97E11FFB87D10FFB87D10FFB97E11FFB97E11FFB97E10FF
+ B87D0FFFB87E0DFFB87E0DFFB97E10FFBB8013FFBC8114FFBB7F15FFB97C14FF
+ B87A14FFBA7C16FFBD7D17FFBE7C15FFBC7B12FFBB7B0FFFBD7E10FFBE8113FF
+ C08315FFBE8014FFBC7E14FFBA7C16FFBB7D19FFBA7D1BFFBA7D1BFFBA7E1AFF
+ BA7F18FFBB8117FFBB8219FFB7811CFFB8811EFFBF831FFFC88B2BFFC78B37FF
+ BA8643FFBF9969FFD5BB9DFFF4E7D9FFFDF7F2FFF9F6F2FFEEECEBFFF3F1F0FF
+ F7F7F7FFF3F5F6FFF1F5F6FFF0F2F2FFEFF1F1FFEDEFF0FFF2F1F5FFEFEBF0FF
+ F8F0F0FFFBEDE1FFDBC4AAFFB59365FFB08444FFB98532FFC28829FFC0821CFF
+ C08119FFC2821CFFC08119FFC18214FFC08111FFBF8010FFBE7F0FFFBD7F0DFF
+ BE800EFFBE800EFFBF810FFFBC7F0BFFBD800CFFBE810DFFBF820EFFBF820CFF
+ BE810BFFBD800AFFBC7F09FFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBD800AFFBF820CFFBE810BFFBC8008FFBB7F07FFBB7F07FF
+ BB7F07FFBC8008FFBC8008FFBD8008FFBC7F07FFBD7F09FFBF810BFFC28310FF
+ C28310FFBF800EFFBC7D0BFFBD7E0CFFBD7E0CFFBD7E0BFFBD7E0BFFBD7F09FF
+ BD7F09FFBD8008FFBD7F09FFBD800CFFBE810DFFBE810DFFBF820EFFBE810DFF
+ BD800CFFBC7F0BFFBB7E0AFFC18410FFBF820EFFBD800CFFBE810DFFBF820EFF
+ C0830FFFBE810DFFBC7F0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBB7D0BFFC18311FFC18311FFC18311FF4E2FD0FF4C2CCBFF
+ 4928C6FF482BBEFF442FAEFF3C2A9BFF331F89FF2F1775FF371A69FF371D59FF
+ 2F1B46FF382B51FF4E4976FF474A7DFF393C79FF3E4888FF3C4D8CFF384E8FFF
+ 3B5597FF4360A3FF4D6EB3FF5577BDFF567AC0FF537ABEFF5179BAFF597FC0FF
+ 5B81C1FF557EBDFF5279BDFF4E78BDFF4973BAFF416AB3FF466CB4FF4265AEFF
+ 4366AFFF4164AEFF385AA6FF3557A3FF3654A1FF304D98FF354E96FF2C4486FF
+ 293B78FF2D3C74FF343D6FFF333966FF2F335CFF313352FF3C3647FF433536FF
+ 4E3325FF55331BFF5D3719FF5F391BFF5F3A1EFF5F3A1EFF673F22FF643D1DFF
+ 61391CFF5E3A1CFF5E3C1FFF5E3C1FFF613A1AFF603716FF5D3616FF5C3616FF
+ 5D3518FF5D3717FF60381BFF613B1BFF643C1FFF643E1EFF653D20FF633D1DFF
+ 633B1EFF613B1BFF623A1DFF623C1CFF643C1FFF643E1EFF5F3C1AFF5C3A16FF
+ 5D3812FF5E3913FF613D19FF62401CFF63401EFF5E3E21FF543925FF30211FFF
+ 282B47FF46598CFF3B5BA4FF264B9FFF3658ABFF3E5DACFF3F59A5FF324A92FF
+ 2B4188FF2B3F80FF2E3C76FF364070FF3E4063FF3C364DFF483A45FF543F3DFF
+ 563B2DFF50311CFF563417FF623F1EFF65401EFF613817FF68391AFF6B391BFF
+ 6A3B1CFF693C1BFF673D18FF633F17FF614013FF603E13FF633F19FF67411FFF
+ 6C3F24FF69391DFF683612FF6D3A0FFF7D4A12FF8D5912FFAB701AFFB47715FF
+ BA7E14FFBA800FFFB57F0AFFB47E09FFB7800DFFBB8312FFB77F10FFB8800FFF
+ BB820FFFBC8310FFBE8210FFBD8110FFBC7E12FFBB7D11FFBA7C10FFBA7C10FF
+ BA7C10FFBA7C10FFBA7D0FFFBA7D0FFFBB7E10FFBB7E10FFB97B0FFFBB7D11FF
+ BD7F15FFBE7F17FFBD7D17FFBD7C19FFBF7E1BFFC1801DFFC27F1CFFC07E18FF
+ BD7B14FFBE7D14FFC07F16FFC07F16FFBD7F15FFBA7B13FFC0821CFFC0821EFF
+ C0811FFFC0811FFFBF831FFFC0851EFFC0861DFFBF861DFFB57F1AFFBA8320FF
+ C18424FFC1852CFFBD863DFFBB8D57FFCBAE8FFFEADACAFFF3EDE6FFF3F4F2FF
+ F2F1EDFFEDEDE7FFF2F2ECFFF7F8F6FFF1F4F8FFEEF3F6FFE8ECEDFFEFF4F5FF
+ EEF3F6FFEAEDF1FFF0ECEBFFFFF8EEFFFBE4CEFFC4A37CFFAD854AFFB5843AFF
+ BC862FFFC48828FFC2811EFFC07E18FFC0801AFFBE7F17FFC28315FFC18212FF
+ BF8010FFBE7F0FFFBE800EFFBE800EFFBE800EFFBF810FFFBF820EFFBE810DFF
+ BD800CFFBC7F0BFFBC7F09FFBD800AFFBE810BFFBF820CFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBC7E0CFFBD800CFFBD800CFFBC7F0BFFBA7D07FFBB7E08FF
+ BC7F09FFBD800AFFBE820AFFBD8109FFBD8109FFBC8008FFBD8008FFBC7F07FF
+ BD7F09FFBF810BFFC1820FFFC1820FFFBF800EFFBD7E0CFFBE7F0DFFBE7F0DFF
+ BD7E0BFFBD7E0BFFBD7F09FFBD7F09FFBE8109FFBE800AFFBB7E0AFFBC7E0CFF
+ BE800EFFBF810FFFBF810FFFBF810FFFBE800EFFBE800EFFC08210FFBF810FFF
+ BD7F0DFFBE800EFFC08210FFC18311FFBF810FFFBD7F0DFFBE7F0FFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BC7D0DFF4E31C4FF4C2FC0FF4A2DB9FF4127A9FF372191FF2E1B7CFF28156AFF
+ 2C135DFF381A55FF41234EFF3E253FFF3D2B42FF4D4564FF4D4C76FF3C4178FF
+ 414C8AFF3D4E8DFF384E8FFF385294FF3F5CA1FF4969B0FF5074BAFF537ABFFF
+ 537ABFFF5B82C6FF5F87C8FF5E84C5FF527ABBFF4D77BAFF4F79BEFF4E78BFFF
+ 4770B9FF486DB7FF4467B1FF4568B2FF4466B2FF3C5DACFF3859A8FF3655A4FF
+ 304D98FF375098FF2F4488FF283978FF2C3971FF313A6CFF313764FF2E325BFF
+ 333252FF3B3546FF443637FF503626FF57361CFF5F391BFF613B1BFF5F3A1EFF
+ 5F3A1EFF643D1DFF633C1CFF623B1BFF613B1DFF5E3C1FFF603B1FFF623B1BFF
+ 633A19FF5D3616FF5C3618FF5C3618FF5D3719FF5E381AFF603A1CFF623C1EFF
+ 633D1FFF633D1FFF633D1FFF633D1FFF633D1FFF633D1FFF633D1FFF633D1FFF
+ 613E1DFF62421FFF5E3E1AFF5E3A14FF5E3A14FF603E1AFF623F1DFF5F3C1BFF
+ 57371AFF533621FF382724FF303048FF475687FF3D5BA2FF294EA0FF3658ACFF
+ 3C5DADFF435DAAFF324994FF273D84FF283B7EFF2D3C7AFF344076FF393C68FF
+ 333050FF483D51FF54444BFF58423DFF523729FF55351EFF603E21FF644120FF
+ 633A19FF6A3919FF6D3A1AFF6A3B1CFF693B1CFF653C1BFF633E18FF5F3F16FF
+ 5E3E15FF5F3D19FF653F1DFF693D1EFF693917FF6A370CFF764009FF87540EFF
+ 9C6613FFB77A1AFFBF7E15FFC08111FFBE8210FFBD810FFFBB820FFFBA8213FF
+ BC8316FFB87F12FFB88011FFBA810EFFBA810DFFBC800EFFBE7F0FFFBE7D14FF
+ BE7D14FFBA7C10FFBA7C10FFB97B0FFFB97C0EFFBA7D0FFFBA7D0FFFBB7E10FF
+ BC7F11FFB87A0EFFBB7D11FFBD7E16FFBE7F17FFBE7D1AFFBF7E1BFFC1801EFF
+ C48321FFC5821FFFC3801DFFC07E18FFBF7D16FFBE7C15FFBE7D14FFBB7C14FF
+ BA7B13FFBE801AFFBD7F1BFFBC7E1AFFBD7F1BFFBD811DFFBE831CFFBE831CFF
+ BB811AFFB87F1CFFBE8627FFBE8229FFB37B2EFFB7854BFFC69F79FFDEC8B6FF
+ F9EEEAFFF0F0F0FFEEF3F2FFEDF1EBFFEFF0E7FFF2F3EAFFF3F4F0FFEDF0F4FF
+ E9ECF4FFE7EBF0FFEEF5F8FFE7F0F4FFEAEFEEFFF7F1EAFFFFF5E2FFF3D3B0FF
+ B68C57FFAD7F38FFBA8633FFBF8629FFC48523FFC27F1CFFBF7B16FFC28019FF
+ BC7E14FFC38416FFC28313FFC08111FFBF8010FFBE800EFFBE800EFFBE800EFF
+ BE800EFFC0830FFFBE810DFFBD800CFFBB7E0AFFBB7E08FFBD800AFFBE810BFF
+ C0830FFFBB7D0BFFBE800EFFBF810FFFBD7F0DFFBD7F0DFFBF810FFFBE810DFF
+ BB7E0AFFB87B05FFB97C06FFBC7F09FFBE810BFFBF830BFFBE820AFFBD8109FF
+ BC8008FFBE8109FFBC7F07FFBB7D07FFBC7E08FFBF800DFFC0810EFFBF800EFF
+ BE7F0DFFBF800EFFBE7F0DFFBE7F0DFFBD7E0BFFBD7E0BFFBE800AFFBE800AFF
+ BF810BFFBB7D0BFFBC7E0CFFBD7F0DFFBF810FFFC08210FFC08210FFC08210FF
+ BF810FFFBF810FFFBD7F0DFFBC7E0CFFBD7F0DFFC08210FFC18311FFC08210FF
+ BF810FFFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFFBB7C0CFF
+ BA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFF4B35ACFF452FA5FF3E269CFF341D8AFF
+ 2B1776FF281566FF2B165BFF321A50FF3D1E45FF4A2A42FF50333CFF443035FF
+ 4B4151FF50506EFF44487BFF444F8DFF3F508FFF3B4F90FF375193FF3B589DFF
+ 4163A9FF486BB4FF4971B9FF4B74B9FF557FC2FF5A84C5FF5A82C3FF5078B9FF
+ 4D77BAFF527CC1FF537DC4FF4C75BEFF4970BAFF4468B4FF4468B4FF4468B6FF
+ 3C60AEFF3B5CABFF3A59A8FF34509DFF3A519CFF304589FF283978FF2A3670FF
+ 2E366BFF2F3363FF2F315AFF333252FF3B3645FF443735FF513726FF5B391CFF
+ 623B1BFF633D1BFF623C1EFF5F3B1DFF613B19FF643B1AFF653C1BFF633C1CFF
+ 5F3A1EFF613B1DFF653C1BFF663E1BFF633C1CFF623C1CFF603A1AFF5F3919FF
+ 5F3919FF5F3919FF603A1AFF613B1BFF613B1BFF633D1DFF643E1EFF664020FF
+ 664020FF643E1EFF633D1DFF5F3C1BFF5E3E1BFF5D3D19FF603C16FF603C16FF
+ 5E3C18FF5B3B18FF593817FF553518FF563722FF44302BFF373247FF444E7DFF
+ 3E589BFF2E4EA1FF3557ABFF3C5BB0FF425DADFF344C98FF29408BFF283C83FF
+ 293A7DFF303E79FF333C6EFF2F315AFF423E5BFF4D4354FF59484CFF5D4742FF
+ 5C4133FF5A3B26FF583920FF603A1CFF673A18FF6B3B19FF693C1BFF673B1CFF
+ 633B1EFF603D1CFF5D3D1AFF5C3C19FF5F3C1AFF613B19FF663917FF6D3D13FF
+ 7A470FFF8A5613FF9D6817FFAE7518FFBF7D17FFC17E11FFC17F0FFFC08010FF
+ BF8214FFBE8316FFBB8118FFBB8019FFBA8017FFB98013FFB97F0EFFB87F0CFF
+ BA7E0DFFBD7E10FFC07D16FFC17E17FFBC7C10FFBA7D0FFFB97C0EFFB97C0EFF
+ B97C0EFFBB7F0EFFBC800FFFBD8012FFBA7C10FFBD7F13FFBF8018FFBF8018FF
+ BE7D1AFFBF7E1BFFC1801EFFC38220FFC4811EFFC4811EFFC2801AFFC07E17FF
+ BB7C14FFBA7B13FFBB7D13FFBC7D15FFBA7D15FFB97B15FFB77913FFB97B15FF
+ B97E17FFBB8019FFB97E17FFB77C18FFBB8121FFC68D32FFBE8637FFB38041FF
+ C49A70FFE3C4ADFFF4E4DEFFF7F3F8FFEDF1F6FFEBF3F3FFEEF4EFFFF0F5ECFF
+ F2F4EEFFF1F2F0FFECEFF3FFEAEDF5FFE9EBF5FFEBF1F8FFE3EEF2FFEFF4F2FF
+ F7EEE1FFECD4B8FFD6AE7EFFB2803EFFB17D2AFFBF892BFFC08522FFC2811EFF
+ C17D18FFBE7B14FFC4831AFFBE8113FFC48517FFC28313FFC18212FFBF8010FF
+ BE800EFFBE800EFFBE800EFFBE800EFFBE810DFFBE810DFFBD800CFFBD800CFF
+ BD800AFFBD800AFFBE810BFFBE810DFFBB7D0BFFBF8010FFC08111FFBE7F0FFF
+ BE800EFFC08210FFBF820EFFBB7E0AFFBB7E0AFFBC7F0BFFBC7F09FFBD800AFF
+ BD800AFFBD800AFFBC7F09FFBC7F09FFBE810BFFBB7E08FFB97C08FFB97C08FF
+ BB7D0BFFBD7F0DFFBE7F0FFFBE7F0FFFBF8010FFBE800EFFBD7F0DFFBC7F0BFF
+ BC7F0BFFBD800AFFBE810BFFBF820CFFBD7F0DFFBE7F0FFFBF8010FFC08111FF
+ C08111FFBF8010FFBE7F0FFFBE7F0FFFBC7D0DFFBB7C0CFFBA7B0BFFBC7D0DFF
+ C08111FFC28313FFC18212FFC08111FFBF8012FFBD7E10FFBB7C0EFFBB7C0EFF
+ BD7E10FFBD7E10FFBC7D0FFFB97A0CFFBB7C0EFFBB7C0EFFBB7C0EFF483896FF
+ 3B2A8BFF2D1A7BFF27126FFF2A1367FF301A62FF372057FF3D244AFF492A3FFF
+ 5A3A3FFF604439FF4C392CFF493E40FF504E64FF41457AFF3C488AFF415291FF
+ 3C5091FF375193FF38559AFF3C5EA4FF4066AEFF436BB3FF436DB4FF456FB4FF
+ 507ABDFF537DC0FF5077BBFF4F78BDFF557EC3FF527CC3FF4972BBFF4B72BDFF
+ 4569B5FF4468B6FF4367B5FF3D60B0FF3E5FAFFF3F5DAEFF3955A2FF3C539EFF
+ 33468AFF293877FF2A356FFF2F356AFF2E3360FF2E3059FF353351FF3D3643FF
+ 463734FF543925FF5F3B1DFF643E1CFF663E1BFF623C1CFF603A1AFF603815FF
+ 633C16FF673D1AFF653C1BFF603A1CFF603A1AFF683E1BFF6A401BFF6A4422FF
+ 674220FF663F1FFF633E1CFF623B1BFF5F3A18FF603919FF5F3A18FF613A1AFF
+ 623D1BFF663F1FFF674220FF684121FF65401EFF633C1CFF603B19FF543410FF
+ 593A13FF5F3E17FF5F3E17FF593915FF573714FF583716FF593A1BFF5A3A23FF
+ 4F3830FF3E3444FF434972FF3E5495FF2F4E9DFF3455ABFF3A5BB1FF3C59AAFF
+ 304C99FF29438FFF273E89FF263A81FF2B3D7EFF2F3D77FF2E3769FF393B63FF
+ 423E5BFF53495AFF64545BFF604B49FF50372DFF4A3020FF57381FFF633A19FF
+ 683C17FF673C1BFF633C1CFF623C1EFF603B1FFF5D3B1DFF5E3B1AFF633F1BFF
+ 623B14FF683C0DFF75470DFF8D5A14FFA26D1CFFB17C21FFBD821FFFBE7C13FF
+ BF7A0DFFBC790CFFBD7C10FFC07F16FFBE801AFFBA7D1BFFB77A18FFBB8019FF
+ B97F15FFB87E0DFFB67D0AFFB87C0BFFBC7D0FFFC07D16FFC27E19FFBC7C10FF
+ B97C0EFFB97C0EFFB87C0BFFB97D0CFFBB7F0EFFBC800FFFBE8211FFBD8012FF
+ BF8115FFC08218FFC08119FFBE7E18FFBE7D1AFFC07F1CFFC2811EFFC27F1CFF
+ C3811BFFC3811BFFBE7F17FFBB7C14FFBA7C12FFBC7E14FFBD8117FFBE8218FF
+ BC7F17FFBB7E16FFBA7F18FFBD821BFFBF841DFFBD811DFFBA7F1CFFBC8223FF
+ C8913CFFC18D4AFFB98E5DFFD5B49AFFFAE5DDFFFFF6F9FFF1F0FAFFEBF1F8FF
+ E8F1F4FFEFF6F3FFF2F9F2FFF2F6F1FFF1F4F2FFF2F3F7FFF1F3FBFFEAECF7FF
+ E9EEF7FFE6EFF2FFF8FAF4FFF2E5CFFFCCAD86FFBA8B4EFFB37B2CFFB57C1FFF
+ C58A26FFC1831DFFBF8018FFBF7D14FFBE7D11FFC68719FFC08413FFC48515FF
+ C38414FFC18212FFBF8010FFBE800EFFBE800EFFBE800EFFBE800EFFBC7F0BFF
+ BD800CFFBE810DFFBF820EFFBF820CFFBE810BFFBD800AFFBC7F0BFFBB7D0BFF
+ C08111FFC18212FFBE7F0FFFBE800EFFC18311FFC08210FFBB7E0AFFC0830FFF
+ BF820EFFBC7F0BFFBB7E08FFBA7D07FFBA7D07FFBC7F09FFBC7F09FFBF820CFF
+ BB7E08FFB77A06FFB77A06FFB97B09FFBC7E0CFFBE7F0FFFBE7F0FFFBF8010FF
+ BE7F0FFFBD7F0DFFBC7E0CFFBC7F0BFFBD800CFFBE810BFFBF820EFFBF810FFF
+ C08111FFC08111FFC08111FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFF
+ B97A0AFFB97A0AFFBC7D0DFFBF8010FFC28313FFC28313FFC18212FFBF8012FF
+ BD7E10FFBB7C0EFFBB7C0EFFBD7E10FFBE7F11FFBC7D0FFFB97A0CFFBE7F11FF
+ BE7F11FFBE7F11FF302470FF261967FF271568FF2F186CFF2C1560FF290F4FFF
+ 3C204EFF563B55FF8B6D72FF8F7264FF957B5DFF8F7D60FF72695CFF535262FF
+ 434781FF444D96FF3A4A8CFF3C518FFF3C5698FF3B589DFF3859A2FF375EA8FF
+ 3F68B1FF446FB8FF406CB3FF456FB4FF4E78BBFF507ABDFF4E77BCFF537CC1FF
+ 547EC5FF4A73BCFF4970BBFF4268B6FF3C61B1FF3B60B0FF395BAEFF3657A7FF
+ 3856A7FF3F5AAAFF445BA6FF34478BFF2F3E7DFF333E77FF32396BFF323562FF
+ 33325CFF302E4CFF3E3641FF493933FF573A25FF633D1DFF6B4320FF6C421DFF
+ 623C1AFF5D3715FF6C421DFF6B421BFF6C401BFF693F1AFF643E1CFF653F1DFF
+ 6B3F1AFF6C411AFF68401DFF633D1AFF623918FF613B18FF663D1CFF66401DFF
+ 673E1DFF633D1AFF643B1AFF633D1AFF663D1CFF653F1CFF663D1CFF623C19FF
+ 613817FF5C3814FF5B3B17FF583912FF593811FF5A3912FF5A3A16FF593B18FF
+ 593817FF573517FF5A391FFF4C3123FF3B2D38FF3C3E61FF394C89FF2A4895FF
+ 2B4A9FFF3B5CB2FF2E4EA1FF274695FF2C4A99FF34509DFF324B95FF2F458CFF
+ 304184FF2E3C77FF2F386AFF393D66FF444260FF4F485DFF60525DFF645356FF
+ 56423DFF4A3020FF5E3A1CFF5F3812FF623C19FF623D1BFF593517FF5D391BFF
+ 653F21FF623C1AFF5C340AFF6C440FFF7A4E0EFF895B0DFFA37119FFB47E1FFF
+ B97F1FFFBF811DFFC47F18FFC68015FFC48015FFC18017FFBE7E18FFBB7C1AFF
+ B87B1BFFB77B1BFFC38824FFC1891EFFBB8312FFB47B07FFB67A08FFBF8012FF
+ C27F18FFBE7B14FFBD7D11FFBB7E10FFB97D0CFFB87C0BFFB87C0BFFBA7E0CFF
+ BC800EFFBD8110FFBC800FFFBE8113FFBF8115FFBE8016FFBB7C14FFBA7A14FF
+ BB7B15FFBD7D17FFBD7D17FFC08119FFBF8018FFB97A12FFB87911FFB97D13FF
+ BA7E14FFB67B0EFFBE8316FFBD8319FFBD8319FFBC831AFFBC821BFFBE831FFF
+ BD821FFFBC7F21FFBA8126FFAD792CFFB88B52FFD2AF8DFFE5CFC3FFF5E8EAFF
+ F7F1FCFFEBEBF7FFECF2F9FFEBF2F5FFEBF3F2FFEAF3F0FFEBF1F0FFEEF0F0FF
+ EFEEF0FFEFEDF3FFEEEEFAFFE6E8F2FFEAEEEFFFFEFCF1FFE1CCB0FFB69060FF
+ C28B46FFC3872EFFBD811DFFBD8117FFBD7F13FFBF7F13FFC07F13FFC07F12FF
+ BC7F0BFFB87D09FFBE800EFFBC7D0DFFBB7C0CFFBC7D0DFFBF810FFFC08210FF
+ BF810FFFBD7F0DFFBE810DFFBD800CFFBD800CFFBD800CFFBC7F09FFBC7F09FF
+ BB7E08FFBB7E0AFFBC7E0CFFBF8010FFBE7F0FFFB87909FFB87909FFBD7F0DFF
+ BE800EFFBB7D0BFFB97B09FFBA7D09FFBC7F0BFFBD800CFFBD800AFFBC7F09FF
+ BA7D07FFB97C06FFBD800AFFBD800AFFBD800CFFBD800CFFBD7F0DFFBD7F0DFF
+ BD7E0EFFBD7E0EFFC18212FFBF8010FFBD7F0DFFBE800EFFC0830FFFBF820EFF
+ BD800AFFB97C08FFBB7D0BFFBB7C0CFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFFBF8010FFC08111FF
+ C08111FFC08111FFC28315FFC28315FFC38416FFC28315FFC18214FFBF8012FF
+ BD7E10FFBB7C0EFFBB7C0EFFBF8012FFC08113FF291B62FF23155CFF2A165FFF
+ 341C62FF331857FF3A1D4EFF644866FF987D87FFA48780FFA48870FFAB916DFF
+ AF9B78FF9A8E7CFF6C6873FF45487FFF3C458EFF3E4E90FF3F5492FF3E589AFF
+ 3B5A9FFF3659A2FF365DA7FF3A64AFFF406AB5FF436EB7FF436FB6FF4B75BAFF
+ 4D77BAFF4A73B8FF5079BEFF527CC3FF4972BBFF446BB6FF3F65B3FF3C61B1FF
+ 3B60B0FF395BAEFF3355A8FF3856A7FF3F5BA8FF3E55A0FF324589FF2F3E7CFF
+ 353E77FF333869FF313460FF32325AFF322E4BFF443C47FF4D3D36FF593C27FF
+ 613B1BFF673D18FF693F1AFF673F1CFF68401DFF673E17FF683E14FF673C15FF
+ 653B16FF633B18FF633B18FF683D16FF693E17FF613712FF5F3714FF623A17FF
+ 663E1BFF6B4320FF6D4522FF6C4421FF6B4320FF68401DFF68401DFF673F1CFF
+ 663E1BFF653D1AFF663E1BFF673F1CFF653F1CFF5F3F1BFF5E3E1AFF613D17FF
+ 603F18FF5F3F1BFF5D3F1CFF5E3D1CFF5D3C1BFF633F21FF563827FF47363AFF
+ 44425FFF3D4C84FF2D4892FF2D4DA0FF3D60B6FF2D4FA2FF284B9BFF3051A0FF
+ 3958A7FF3854A1FF344F99FF354B93FF304386FF32427DFF364175FF3A406BFF
+ 424365FF504A61FF594F5FFF574954FF574441FF5B3C25FF5C3918FF5F3C1BFF
+ 613E1DFF5C3918FF603A1AFF663D1CFF653A13FF6B410CFF855A17FF996D1AFF
+ A67617FFB37F1AFFB78018FFB67814FFB87714FFC07C17FFC07D16FFC07E17FF
+ BF8018FFBD7F1BFFBB7E1EFFBB7E20FFBB7F1FFFBF8420FFBE861BFFB98110FF
+ B57C08FFB87C0AFFC08111FFC28118FFBE7C15FFBD7F15FFBA7F11FFBD8012FF
+ BC8211FFBE8211FFBA800FFFBA7E0DFFB97F0EFFBA7E0DFFBA7F11FFBE8113FF
+ BC8114FFBD7F15FFBB7E16FFBF7F19FFBF811BFFB97A12FFBB7E16FFBB7E16FF
+ B87B13FFBA7E14FFBD8319FFBF851BFFBD8417FFBC8316FFBA8215FFBA8217FF
+ B78017FFB97E1AFFB87E1EFFBA7D1FFFB67D22FFC08836FFAF7E3AFFB79266FF
+ D6BEA8FFEADBD9FFF0E8F3FFEFECFBFFEBEBF7FFEAEDF5FFE8EFF2FFE7F1F1FF
+ E7F1F1FFE9F0F3FFEBEFF0FFF0EDEFFFF1EBF0FFEEEAF5FFF0EDF6FFFEFBF7FF
+ EFE5D3FFCBB189FFB88E53FFBA8132FFC08022FFC2841AFFBF8214FFBC7F11FF
+ BD7E10FFC07F12FFC18210FFC0830DFFBD830CFFBF810FFFBD7E0EFFBC7D0DFF
+ BD7E0EFFC08210FFC18311FFC08210FFBE800EFFBE810DFFBE810DFFBE810DFF
+ BD800CFFBD800AFFBC7F09FFBC7F09FFBC7F0BFFBE800EFFC18212FFBF8010FF
+ BB7C0CFFBB7C0CFFBF8010FFC08210FFBD7F0DFFBB7D0BFFBB7D0BFFBC7F0BFF
+ BC7F0BFFBC7F09FFBC7F09FFBB7E08FFBB7E08FFBD800AFFBD800AFFBD800CFF
+ BD800CFFBD7F0DFFBD7F0DFFBD7E0EFFBD7E0EFFBD7E0EFFBA7B0BFFB87909FF
+ B87A08FFBB7D0BFFBF820EFFC28511FFC38612FFB97B09FFB97A0AFFBB7C0CFF
+ BC7D0DFFBE7F0FFFC08111FFC18212FFC18212FFBD7E0EFFBD7E0EFFBE7F0FFF
+ BE7F0FFFBF8010FFBF8010FFC08111FFC08111FFC18214FFC18214FFC18214FF
+ C18214FFC08113FFBF8012FFBE7F11FFBD7E10FFBB7C0EFFBF8012FFC08113FF
+ 240E5DFF2E1964FF30175BFF270E46FF3A1E49FF6A4D67FF967B84FFAF928DFF
+ AC8F81FFA98C77FFAD8F72FFB9A185FFB2A390FF807980FF4B4D7DFF40498CFF
+ 415291FF425795FF405A9CFF3D5CA1FF375AA4FF345CA7FF3561AEFF3A67B1FF
+ 426FB8FF426EB5FF4872B7FF4973B8FF466FB4FF4C75BAFF4F79C0FF4972BBFF
+ 4068B3FF3F66B4FF3D64B3FF3B62B1FF355AACFF3153A6FF3452A3FF3A56A3FF
+ 354C97FF304386FF30407BFF343E74FF323867FF31335CFF323158FF33304AFF
+ 413943FF4B3B34FF60432EFF684222FF683E19FF673D18FF643C19FF68401DFF
+ 673E17FF693F15FF673E17FF663F19FF653F1CFF68421FFF6E451EFF71461FFF
+ 693F1AFF663F19FF663F19FF67401AFF68411BFF69421CFF67401AFF663F19FF
+ 653E18FF643D17FF633C16FF633C16FF633C16FF643D17FF653E18FF643E1BFF
+ 664420FF644420FF67431DFF64401AFF5F3C1AFF5A3918FF5B3816FF5B3816FF
+ 603A1AFF573720FF4A3534FF484156FF3E4A7AFF2E4589FF2C4B9AFF3B5FB3FF
+ 3D64B3FF3A61AFFF3C62B0FF4266B4FF3F5FABFF3C59A4FF3B55A1FF334B93FF
+ 354A8EFF344683FF35427AFF3C4473FF44476DFF4A4B67FF524F65FF615660FF
+ 62493FFF5D3E29FF56371EFF59391CFF5D3A19FF633D1AFF693E17FF673A07FF
+ 7A4C0CFF996A19FFAE7F1DFFB68519FFBE8619FFBF8319FFC2811FFFCA8627FF
+ BC7B18FFBB7D17FFBB7D17FFBD7F19FFBC801CFFBD8121FFBE8123FFBD8323FF
+ BB801CFFBA8215FFB8810EFFB58008FFB9800CFFBF8312FFC08218FFBB7E16FF
+ BD8018FFB97F15FFBD8117FFC1881BFFC3881BFFB98112FFB87D0FFFB77F10FF
+ B67B0DFFB67E0FFFBA7F11FFBA8114FFBC8016FFBC8218FFC0831BFFC0861DFF
+ B97C14FFB97F16FFBA8017FFB97F16FFBB8118FFBF871CFFC1891EFFC1891EFF
+ BA8215FFB78116FFB78017FFB6801BFFB97F1FFFB87F22FFBD8128FFBA8230FF
+ C49148FFB58A51FFC1A583FFE5D3C8FFF3ECF1FFEDEAF9FFEAEAF8FFECEDF7FF
+ E8EBF0FFE8EDF0FFE5EEF1FFE7F0F3FFE9EFF4FFEBEEF2FFF2EDEEFFF2EBEEFF
+ F4ECF3FFFDF4F7FFFFFDF1FFDAC5A9FFB69563FFBC8E47FFB87D27FFC2811EFF
+ C48418FFC08111FFBB7E10FFBA7D0FFFBF8010FFC28511FFC3870FFFC3870FFF
+ BF810FFFBE7F0FFFBD7E0EFFBE7F0FFFC08210FFC28412FFC18311FFBF810FFF
+ BF820EFFBF820EFFBF820EFFBE810DFFBE810BFFBD800AFFBD800AFFBD800CFF
+ BF8010FFC18214FFC08113FFBE7F11FFBE7F0FFFC18212FFC28313FFC08111FF
+ BC7E0CFFBC7E0CFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBC7F0BFF
+ BA7F0BFFBA7F0BFFBA7E0CFFBA7E0CFFBA7E0DFFBA7E0DFFBA7D0FFFBA7D0FFF
+ B77A0CFFB87C0BFFB87C0BFFB97D0BFFB97D0BFFBC810DFFC08511FFC28713FF
+ C08210FFBF810FFFBF810FFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFFBF810FFFBF810FFFBF810FFF
+ C08111FFC08111FFBF8010FFBF8010FFBF8010FFBF8010FFBF8010FFC08111FF
+ BB7C0CFFBF8010FFC08111FF331666FF351861FF30154DFF3B1E45FF6A4B60FF
+ A48588FFB2968BFFA38874FFA98B78FFAB8C77FFA8866FFFAF9079FFAD9987FF
+ 807879FF4E4E76FF424D87FF44548FFF435896FF415B9DFF3E5DA2FF3A5DA7FF
+ 365DABFF3662AFFF3765B2FF3E6BB5FF3B68B1FF436FB6FF4872B7FF466FB4FF
+ 4A73B8FF4C76BDFF4770B9FF4068B3FF4067B5FF4067B6FF3B62B1FF3459ABFF
+ 2E51A1FF2D4E9DFF304F9AFF2D458DFF2E4184FF2F3F7AFF323D71FF313764FF
+ 30325AFF303054FF34314BFF3A343FFF4C3E38FF745944FF876443FF825A37FF
+ 7B542EFF704A28FF724C2AFF704923FF704720FF6D4620FF69441EFF674220FF
+ 674220FF6A431DFF6C431CFF6A431DFF65401AFF643C19FF613C16FF633B18FF
+ 623D17FF663E1BFF65401AFF68401DFF67421CFF69411EFF68431DFF6A421FFF
+ 66411BFF673F1CFF643E1BFF613E1CFF63411DFF67421CFF643F19FF5D3A18FF
+ 593817FF5C3917FF603C18FF653D1AFF5D381EFF4F352EFF4B4050FF434A75FF
+ 324785FF284792FF2F54A4FF416BB8FF406AB5FF4169B4FF486CB8FF4265AFFF
+ 3C5BA6FF405CA9FF36509CFF344B96FF31488CFF364889FF3B4983FF3E4878FF
+ 3E446DFF45496CFF58556BFF68595DFF5F4A42FF553B2DFF523723FF59381EFF
+ 613B19FF683D12FF6D3E06FF8E5E16FFAA7820FFBA8621FFBC8719FFBE8619FF
+ C0831BFFC38023FFC9882CFFBA7D1FFFB87F1CFFB9811CFFB9811CFFBA811EFF
+ BC8222FFBE8425FFBF8525FFBC811DFFBA8118FFB98110FFB8810EFFBA8211FF
+ BC8415FFBB8118FFB97D19FFBC801CFFB87D16FFBB8019FFC2881FFFC2881FFF
+ BA8016FFB77E11FFBB8215FFB47B0EFFB57C0FFFB77E11FFB87F12FFBA8016FF
+ BC8218FFBE841BFFBF851CFFBC831AFFBC831AFFBB811AFFB88119FFBA8019FF
+ BA831BFFBB841BFFB9851BFFBB851AFFB78319FFB7821AFFB98423FFBD8427FF
+ BD842EFFC48A38FFC68F46FFC19255FFC09D71FFD7BFA9FFF3E7E1FFF7F3FEFF
+ EBEBFBFFE9E9F5FFEFF0FAFFECEDF1FFEAEEEFFFE7EDF2FFE8EEF3FFE8EEF5FF
+ ECEFF4FFF5F0F2FFF8F0F1FFFBF0F2FFFAECE6FFEED9C4FFC0A47BFFAE8547FF
+ BA8737FFBB8122FFC1821AFFC38317FFC18214FFBC7F11FFBC7F11FFBF8312FF
+ C38612FFC3870FFFC2860EFFC08210FFBF8010FFBD7E0EFFBF8010FFC18311FF
+ C28412FFC18311FFC08210FFC0830FFFC0830FFFBF820EFFBF820EFFBE810BFF
+ BE810BFFBE810BFFBD800CFFBF8010FFBF8012FFBF8012FFBF8012FFBF8010FF
+ C08111FFC18212FFC08111FFBE800EFFBD7F0DFFBB7D0BFFBA7D09FFBA7D09FF
+ BB7E0AFFBD800CFFBE810DFFBA7F0BFFBA7F0BFFBA7E0CFFBA7E0CFFBA7E0DFF
+ BA7E0DFFBA7D0FFFBA7D0FFFB87B0DFFBD8012FFC18514FFC28615FFBF8311FF
+ BB7F0DFFB97E0AFFB97E0AFFC28412FFC18311FFC08210FFBF810FFFBE800EFF
+ BD7F0DFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBE7F0FFF
+ BF8010FFC18212FFC28313FFBB7C0CFFBF8010FFC08111FF422067FF33134EFF
+ 42234AFF785869FFA88784FFB3927EFFAB8C6DFFA78869FFA98972FFB59383FF
+ B79081FFB29080FFAA927EFF80746EFF514F6CFF414B7BFF45538DFF425795FF
+ 415B9DFF3E5FA4FF3B60AAFF3862AFFF3664B2FF3565B3FF3664B1FF3663ADFF
+ 406CB3FF4773BAFF4771B6FF4872B7FF4A74BBFF456EB7FF3A64AFFF3C66B1FF
+ 3C66B3FF3960AEFF3358A8FF3053A3FF2E4F9EFF2F4E99FF274086FF2E4283FF
+ 2F4079FF2F3A6CFF2F3661FF303359FF313052FF35324BFF383440FF4F4341FF
+ 8C7462FFAA8A6DFFA88262FFA17C5AFF947052FF957251FF9A7652FF98734DFF
+ 926E4AFF8A6745FF826042FF7F5C3BFF7F5936FF7D5734FF7A5431FF785430FF
+ 785230FF74502CFF714B29FF6D4925FF6C4624FF6A4622FF6D4725FF6A4622FF
+ 684220FF65411DFF643E1CFF633F1BFF643E1CFF643F1DFF5A3715FF5F3A18FF
+ 653E18FF653E18FF613C1AFF5F3C1BFF643F1DFF68431DFF6E431CFF643D1DFF
+ 553829FF50434BFF4B5176FF394D86FF28468DFF254C97FF2F5AA3FF325FA8FF
+ 3D67AEFF5177BFFF4F70B9FF4161AAFF4360ABFF38529EFF354F9BFF334C96FF
+ 344A91FF374B8CFF37457FFF313E72FF374170FF484C6FFF5B576AFF5F545EFF
+ 5B4D4FFF594540FF593C2DFF583619FF653B11FF774A11FF9A6820FFAF7C26FF
+ BB8526FFBD8722FFC18825FFC28626FFBD7E26FFBC7F29FFBB832AFFB88426FF
+ B78424FFB88322FFB88322FFBB8324FFBC8326FFBD8427FFBE8424FFBB831EFF
+ BB8219FFBB8316FFBC8419FFBC821BFFBA7F1CFFB97C1EFFBD8022FFB97C1EFF
+ B97C1EFFBE8222FFBE8320FFBB801CFFBB811AFFBF861DFFB57D12FFB57D12FF
+ B67E13FFB77F14FFB98017FFBA8118FFBA8019FFBA8019FFBD861EFFBB841CFF
+ BA821DFFB7811CFFB87F1CFFB57E1BFFB6801BFFB5811CFFBD8820FFB7831EFF
+ B78221FFB98527FFBC832EFFBC8334FFC58B40FFC89354FFBB9363FFD0B495FF
+ EEDBCCFFFAF1EEFFF3F2FCFFEBECFAFFECECF8FFF1F3FBFFF1F2F6FFF0F2F3FF
+ ECEFF4FFEAEDF2FFEBEDF5FFEFEFF5FFF8F3F5FFFFF5F5FFFFF6F0FFEEDAC9FF
+ C2A382FFB18B55FFB18238FFB27D23FFBD821FFFB87C12FFC28118FFC18115FF
+ BF8115FFBE8316FFC08615FFC18513FFC0830DFFBE800AFFC08210FFBF8010FF
+ BD7E0EFFBF8010FFC18311FFC28412FFC18311FFC08210FFC0830FFFC0830FFF
+ BF820EFFBF820EFFBE810BFFBE810BFFBE810BFFBD800CFFBD7E0EFFBC7D0FFF
+ BD7E10FFBE7F11FFBF8012FFBF8012FFBF8010FFC08111FFBE7F0FFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBB7E0AFFBC7F0BFFBD800CFFBE810DFFBB800CFFBB800CFF
+ BB7F0DFFBB7F0DFFBB7F0EFFBB7F0EFFBB7E10FFBB7E10FFBE8113FFC28517FF
+ C68A19FFC68A19FFC18513FFBC800EFFB97E0AFFB87D09FFB97C08FFBA7D09FF
+ BC7F0BFFBE810DFFC0830FFFC28511FFC38612FFC48713FFBE810DFFBE810DFF
+ BD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBE800EFFBE800EFF
+ BD7F0DFFBC7E0CFFBD7F0DFFBF810FFFC18311FFC28412FFBB7D0BFFBF810FFF
+ C08210FF3A1A49FF442348FF664657FF92716EFFA47E6CFF956F51FF8A673FFF
+ 8E6D46FF97765CFFAC8975FFB9917FFFB4917DFFA88F75FF837569FF59556EFF
+ 484E7BFF46538BFF415694FF415B9DFF3F60A5FF3E62AEFF3A64B1FF3764B5FF
+ 3666B4FF3664B2FF3261ABFF3D6AB3FF4874BBFF4771B6FF4670B5FF4771B8FF
+ 436DB4FF3762ABFF3963AEFF3862AFFF345EABFF3459A9FF3559A7FF3355A1FF
+ 31519AFF264083FF2F4482FF2D3E76FF2B3668FF2F3560FF303457FF313050FF
+ 35324BFF343140FF473F3FFF917A6AFFB5987DFFB69476FFB59473FFAD8D70FF
+ B39376FFBC9B7AFFBC9977FFB89574FFB29072FFAC8C6FFFA9896CFFAC8968FF
+ AD8866FFA07B59FFA17E5CFFA57F5FFFA27F5DFF9D7757FF916E4CFF8A6444FF
+ 83603EFF866040FF7F5C3AFF7A5434FF714E2CFF714B2BFF714E2CFF785232FF
+ 795635FF694625FF6B4624FF6E4721FF6C451FFF66411FFF623F1DFF643F1DFF
+ 67401AFF693D14FF633916FF563623FF524144FF4E5170FF3F5186FF2E4B8EFF
+ 2A4F99FF2D59A0FF3564A8FF4A75B8FF6E95D9FF6B8ED2FF4E6CB3FF4461ABFF
+ 36509CFF3A54A1FF354F9CFF324B95FF30468DFF2E4283FF2F3F7AFF354378FF
+ 3E4975FF44496AFF56566EFF635D70FF665961FF5F4944FF583825FF66401DFF
+ 855924FFAB7A36FFB98636FFBB8530FFB98128FFBD852CFFBE852FFFB8802EFF
+ B8822FFFBA8835FFB98832FFB8862CFFB88527FFB88426FFBB8429FFBE842BFF
+ BE842BFFC3872DFFBE8326FFBD821FFFBD8421FFBE8522FFBC8223FFB98025FF
+ BB7F26FFBE812BFFBD8128FFBD7E26FFBA7E24FFBC7F22FFBC8222FFC08522FF
+ C08823FFBA8019FFB78018FFB87E17FFB78018FFBA8019FFB9821AFFBB811AFF
+ B88119FFB9831EFFB6801BFFB67F1CFFB88120FFB88021FFB5801FFFB68120FF
+ B98423FFBF8B27FFB78423FFB58123FFB8822BFFB77F2EFFB67C34FFC08442FF
+ C4905BFFC19E7CFFE1CCB7FFFCF0E6FFF8F3F2FFEFEEF7FFECEEF8FFEFF0FAFF
+ F2F4FCFFF3F4F8FFF4F3F7FFF1F0F4FFF0EEF4FFF0EEF4FFF4F0F6FFF9F3F8FF
+ FFF6F6FFFFF8ECFFE0C7ADFFAD895BFFB58747FFBF8B38FFB7801FFFC28821FF
+ B77D13FFBE7F17FFBE7F17FFBD8018FFBF8319FFC08517FFBF8514FFBE810DFF
+ BC7D0AFFBF810FFFBE7F0FFFBD7E0EFFBE7F0FFFC08210FFC28412FFC18311FF
+ BF810FFFBF820EFFBF820EFFBF820EFFBE810DFFBE810BFFBD800AFFBD800AFF
+ BD800CFFBC7D0DFFBA7B0DFFBC7D0FFFBF8012FFC08113FFBE7F11FFBE7F0FFF
+ C08111FFBE7F0FFFBD7E0EFFBD7F0DFFBC7E0CFFBC7F0BFFBD800CFFBD800CFF
+ BE810DFFBC810DFFBC810DFFBC800EFFBC800EFFBC800FFFBC800FFFBC7F11FF
+ BC7F11FFC48719FFC38618FFC28517FFBF8312FFBD810FFFBC800EFFBD820EFF
+ BF8410FFBA7D09FFBB7E0AFFBC7F0BFFBD800CFFBF820EFFC0830FFFC18410FF
+ C28511FFBE810DFFBE810DFFBD800CFFBD800CFFBD800CFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBF810FFFC08210FF
+ C08210FFBB7D0BFFBF810FFFC08210FF3C232DFF52393DFF6D5047FF775643FF
+ 794F38FF77492AFF704720FF69451DFF735133FF7E5C3FFF8C6648FF8F6C4BFF
+ 856B47FF6D5D4CFF584F69FF505282FF47548CFF425794FF425C9EFF4061A6FF
+ 3D64AFFF3A66B3FF3564B5FF3364B2FF3969B7FF3564AEFF3D6AB3FF4773BAFF
+ 456FB4FF426CB1FF456EB3FF426CB3FF3C67B0FF3B65B0FF3761AEFF315BA8FF
+ 345AA8FF365AA8FF3355A1FF2E4E97FF284285FF324784FF2E3E73FF273363FF
+ 2F355EFF333558FF313050FF33334BFF302F3FFF3E393BFF897669FFAD937BFF
+ AE9075FFB29477FFAD8F76FFB6997EFFB69679FFB59677FFB49477FFB19378FF
+ B09279FFB09378FFB49576FFB79675FFAE8D6CFFB39271FFBA9678FFB99877FF
+ B89476FFB1906FFFAF8B6DFFAB8A69FFAD896BFFA78665FFA48062FF9E7D5CFF
+ 9E7A5CFF9D7C5BFFA27E60FFA48160FF926F4EFF926C4AFF926843FF8D633EFF
+ 86603EFF805B39FF7D5735FF7C552FFF7B4E23FF794D28FF6B4932FF5F4B4AFF
+ 51526EFF3E4F80FF314D8EFF2F559DFF3865A8FF416FAFFF5782C1FF86ACECFF
+ 7FA1E3FF5572B5FF4662A9FF36519BFF3953A0FF37519EFF324C99FF2F4892FF
+ 31488CFF374C8AFF394B86FF394A7DFF364671FF465276FF555877FF615B72FF
+ 685760FF654B44FF745235FF92693CFFC19359FFCE9A57FFC8914CFFBA853CFF
+ B8833AFFB48236FFB18231FFB28534FFB98B3DFFB78A39FFB68834FFB7872FFF
+ B8862CFFBB852EFFBF8631FFC28634FFC68834FFC0832DFFBD8128FFC0842AFF
+ C2862DFFBE822EFFBC8131FFBF8435FFC28535FFC58937FFC48632FFBA7F29FF
+ BB7F26FFBF8629FFC28829FFBC8524FFBC8320FFB8821DFFB9811CFFB9831EFF
+ BD8520FFBD8722FFBD8520FFBA841FFFBA8320FFB5811DFFB47E1FFFB88223FF
+ B98325FFB68224FFB78325FFBC8929FFBD8A2AFFB58224FFB48026FFB8822FFF
+ B87F34FFB77E39FFC3874BFFC89668FFD4B69DFFF0E0D4FFFFF8F1FFF7F2F1FF
+ F0EFF3FFF1F4F9FFF1F3FBFFF0F2FAFFF0F0F6FFF2F1F5FFF6F0F5FFF6F0F5FF
+ F6F0F5FFF6EFF6FFF5EEF5FFFAF0F0FFF1E1D0FFC6AC88FFAD844DFFB9863DFF
+ C28C2EFFC18A21FFC18B20FFBB8318FFBA7C16FFBA7C18FFBA7C16FFBC7F17FF
+ BD8417FFBF8416FFC08111FFBE7F0DFFBF8010FFBD7E0EFFBC7D0DFFBD7E0EFF
+ C08210FFC18311FFC08210FFBE800EFFBE810DFFBE810DFFBE810DFFBD800CFF
+ BD800AFFBC7F09FFBC7F09FFBC7F0BFFBD7E10FFBB7B0FFFBD7E10FFC28315FF
+ C38416FFC08113FFBF8010FFC28313FFBD7E0EFFBD7E0EFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBD820EFFBB820EFFBB820FFFBB820FFF
+ BB8110FFBB8012FFBB8013FFBB8013FFC2871AFFBF8416FFBB8012FFB87E0DFF
+ B9800DFFBA810EFFBB820EFFBE830FFFBF820CFFBF820CFFBE810BFFBD800AFF
+ BD800AFFBC7F09FFBB7E08FFBB7E08FFBE810BFFBE810BFFBD800AFFBD800AFF
+ BC7F09FFBC7F09FFBB7E08FFBB7E08FFBC7F0BFFBD800CFFBE810DFFBE810DFF
+ BF820EFFBE810DFFBE810DFFBE810DFFBB7E0AFFBF820EFFC0830FFF5E402FFF
+ 573724FF57351DFF623D21FF6C3F24FF693A1EFF643918FF633D1AFF583618FF
+ 4E2F10FF51310EFF543712FF4E3612FF473524FF4C3E50FF514D77FF4A578BFF
+ 435895FF435E9EFF4363A5FF4066AEFF3C66B1FF3863B2FF3462B0FF416FBCFF
+ 3B68B2FF406BB4FF4771B8FF426CB3FF3F69B0FF436BB3FF416AB3FF456FBAFF
+ 426CB9FF3B62B0FF335AA8FF3458A6FF3759A5FF31519AFF2A478CFF2E4485FF
+ 364883FF2F3D71FF293160FF30345DFF343659FF313050FF33334BFF373745FF
+ 423B3EFF8C796CFFAF957DFFAE9075FFAF9174FFA68B71FFAF947AFFB39376FF
+ B29374FFAF8F72FFAB8D70FFA98C71FFA88B70FFAC8A6CFFAC8B6AFFB49274FF
+ B59376FFB59376FFB29073FFAF8D70FFAE8C6FFFB18F72FFB49275FFB39174FF
+ B49275FFB69477FFB79578FFB79578FFB49275FFB08E71FFAE8C6FFFB39173FF
+ B28F6EFFB28C69FFB28A67FFB0886BFFAE876BFFA88466FFA78260FF9F794FFF
+ 9E7953FF906E56FF7B635DFF605A6DFF434C77FF324987FF32549AFF3863A6FF
+ 3B69A9FF4F7BBBFF81A9EAFF7DA0E2FF4D6FB1FF4462A9FF3A57A1FF304E9BFF
+ 32509DFF304E9DFF304C99FF36519BFF3E579DFF3A5294FF344986FF394E85FF
+ 394A7BFF3C4571FF4F5072FF676075FF6F5F66FF796056FF8F7057FFB18A64FF
+ C2986BFFC89966FFBF905AFFBB8C54FFB38A4CFFAB8747FFAD8A48FFB18948FF
+ B28843FFB3863DFFB38538FFB68535FFB98636FFBD873AFFC0883BFFC0873CFF
+ B98035FFB77D31FFBB8233FFBE8438FFBD8337FFBD8439FFC1873FFFC2883DFF
+ C98F44FFC68C40FFBC8132FFB97F2DFFC18833FFC08731FFB77F26FFBB8429FF
+ B98325FFBA8223FFBC8425FFBF8827FFC18A29FFC08928FFBF8728FFBD8728FF
+ B88224FFB88126FFBB8429FFBC852AFFB98227FFBA8328FFBF892BFFBB8729FF
+ B48022FFB58026FFBB8433FFBA843DFFB98445FFC7915CFFCDA17CFFDECAB9FF
+ F4EBE7FFFFF8F8FFF5F0F1FFF4F0F5FFF5F5FBFFF1F3FBFFEFF1F9FFECECF2FF
+ F0EFF3FFF5F2F4FFF8F3F5FFF9F2F5FFF6EFF2FFF2EBF0FFF7EBE5FFD8C0A2FF
+ B08C5CFFB28242FFB57E2DFFB77D1DFFC38B20FFB98416FFB88015FFB97B15FF
+ B87A16FFB97815FFB97B15FFBA8016FFBE8316FFC28315FFC18212FFBE7F11FF
+ BC7D0FFFBB7C0EFFBC7D0DFFBF8010FFC08111FFBF810FFFBD7F0DFFBE800EFF
+ BD800CFFBD800CFFBD800CFFBC7F0BFFBC7F0BFFBB7E0AFFBB7D0BFFBF8010FF
+ BC7D0FFFBE7F0FFFC58616FFC68717FFC28313FFC18212FFC58616FFBC7D0DFF
+ BD7E0EFFBE7F0FFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBA7E0DFFBC8310FF
+ BA8310FFBC8310FFBC8211FFBC8113FFBC8113FFBC8114FFBC8114FFBF8417FF
+ BD8215FFBA7F11FFBA7F11FFBA800FFFB97F0EFFB57C09FFB47806FFBB7E0AFF
+ BC7E08FFBD7E0BFFBD7E0BFFBE7F0CFFBE7F0CFFBE810DFFBE810DFFBE810DFF
+ BE810DFFBD800CFFBD800CFFBC7F0BFFB97E0AFFB97E0AFFBB7E0AFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFBC800FFFBB7F0EFFBA7E0DFFB97D0CFF
+ BD8110FFBE8211FF613212FF633615FF673A19FF683C1DFF663B20FF633A21FF
+ 5D371FFF59351DFF503118FF54371CFF4E3214FF4B3113FF4D371EFF433023FF
+ 47353CFF5A516BFF434D7CFF374E86FF435D99FF4B67A7FF4365A7FF4066AEFF
+ 3F66B1FF335DAAFF446EBBFF426CB9FF4169B4FF436AB4FF476EB8FF4A71BBFF
+ 4972BBFF476FBAFF426BBAFF3F65B7FF3A5FAFFF3B5FADFF3F5FABFF3F5AA4FF
+ 375096FF314789FF32417FFF344179FF343D6FFF323764FF2E3058FF2C2E51FF
+ 2D2E50FF33324CFF33313DFF574D4DFF866F5FFFA2856AFFA98A6BFFA8896AFF
+ A78A6FFFAB8E73FFB49274FFB69372FFB49170FFAF8E6DFFA98A6BFFAA8968FF
+ B28C69FFB58F6CFFB28D71FFAF8D75FFB29078FFB4927AFFB18F77FFAD8B73FF
+ AD8B73FFB08E76FFB18F77FFB18F77FFB18F77FFB29078FFB18F77FFAF8D75FF
+ B18F77FFB4927AFFAF9077FFB09275FFB39370FFB28F6EFFB88F79FFBC9482FF
+ B4947DFFAA8F74FFA78F6BFFAD936FFFAB8D72FFAE9183FF907B83FF524D6CFF
+ 32407BFF2D4A94FF325BA4FF426FB8FF4C78BFFF557FC4FF618ACFFF557CC1FF
+ 3E65AAFF3D63ABFF3C61ABFF395DA9FF3357A5FF3152A1FF3857A6FF3D5CABFF
+ 3856A3FF314C96FF30478BFF3B4D8AFF455187FF4A507DFF4D4F72FF55526BFF
+ 675D6DFF77696DFF86706AFFB09384FFC8A48CFFC4A180FFDEBC98FFC9AC85FF
+ AF9872FFA68D65FFB29062FFB8905CFFBB8D57FFBA8B4EFFB98949FFB98A46FF
+ BA8D49FFBC924DFFBD9151FFB48547FFBD8A4CFFD19C5DFFD59D5CFFC18A45FF
+ B7813AFFBC8841FFB67F3AFFBA8340FFC9924DFFCA924BFFBD853EFFC48D44FF
+ CB9247FFB88031FFB67E2DFFBC8432FFBD842FFFB77E28FFBB8128FFC38930FF
+ C1872EFFB77D24FFB87F2AFFC18833FFC0852FFFBD802AFFC1852CFFC1852BFF
+ BF8329FFC48B2EFFC1892AFFC58D2EFFB78025FFB98532FFC89751FFBB8E55FF
+ BD966AFFE1C6ABFFF6ECE5FFEDECF0FFF3EFF5FFF7F3F9FFF8F4FAFFF7F2FBFF
+ F3F0F9FFEFEEF7FFEDEDF3FFEDEEF2FFEAECECFFF3F4F2FFF5F1F0FFF6F1EEFF
+ FBF2EFFFF2DECCFFC29B6EFFBC8A48FFB37C31FFB37A24FFB77D1DFFBF861DFF
+ C0861CFFB87D10FFC6871FFFBD7E16FFC4821BFFC98A22FFC2841AFFBF8115FF
+ C28315FFBE7F11FFBF7E15FFC3851BFFC08218FFBE8014FFC18317FFBC7F11FF
+ B87C0BFFBE8210FFBA7E0CFFBC800EFFBD810FFFBB7F0DFFB97D0BFFB97D0BFF
+ BC800FFFC18212FFC48614FFC18210FFBE7F0DFFBE7F0DFFC18210FFC38313FF
+ C38313FFC28114FFC08113FFC18115FFC48418FFC58519FFC5841BFFC38219FF
+ C18017FFBD7F13FFBA8213FFB7810FFFB67E0DFFB47C0BFFB37B0CFFB27A0BFF
+ B37B0CFFB37B0CFFC28719FFC08517FFBF8115FFBC7E12FFBA7D0FFFBB7E10FF
+ BC7F11FFBF8010FFBC7A09FFC07D0AFFC07C0BFFC07C0BFFBD7B0AFFBE7C0BFF
+ BF800EFFC38412FFBA7C0AFFB97B09FFB97D0CFFBE8211FFBF8312FFB87E0DFF
+ B67C0BFFB97D0CFFBC7C0CFFBC7C0CFFBC7D0FFFBE7F11FFBE8014FFBF8319FF
+ C2851DFFC3861EFFB77A12FFBB7E16FFBB7F15FF8D5722FF86521DFF794816FF
+ 6E4011FF633811FF5D3413FF5B3418FF5A351BFF543117FF5A3C1FFF573B1CFF
+ 4F371BFF4D3521FF422C20FF4B3635FF5F5566FF49527EFF3A4E88FF425A96FF
+ 4965A5FF4666A8FF4266ACFF4166B0FF375FAAFF3C63B1FF3D65B0FF3F67B2FF
+ 426AB5FF456CB7FF446CB7FF436BB6FF3F69B6FF3F67B9FF3C62B4FF395EAEFF
+ 3C5DACFF415DAAFF4059A3FF384D91FF324485FF35407CFF364076FF373B6EFF
+ 333663FF2E3058FF2C2E51FF2E2F51FF34334DFF2F2B37FF433735FF624A38FF
+ 7D5F44FF91704FFF987756FF937558FF8F7154FF906F4EFF977452FFA07B59FF
+ A3805EFFA48362FFA78462FFAC855EFFAC855FFFAD896BFFB29177FFB6947CFF
+ B19076FFAF8D75FFB29177FFB18F77FFAC8B71FFAB8971FFAE8D73FFB08E76FF
+ AE8D73FFAD8B73FFAE8D73FFAF8D75FFAC8D74FFB3957CFFB4987AFFB39572FF
+ AF8D6FFFB28875FFB18A7BFFAB8B78FFA0896FFFA89572FFA99671FFAB8B6EFF
+ B2917EFF9C807FFF62556DFF3D467FFF324D97FF2B529DFF3866B3FF4572BCFF
+ 5782CBFF6B95DCFF5E88CFFF426CB3FF3A64ABFF3D66AFFF3A62ADFF345AA8FF
+ 3055A5FF3557AAFF3A5CAFFF3959ACFF3553A2FF3A519DFF3C4F93FF3C4B89FF
+ 3C487EFF424A79FF4A4F76FF545577FF5D5A74FF675D6EFF928289FFF8E2DDFF
+ DFC7BBFFC7B19FFFEAD7C2FFE7D9C6FFD6C8B2FFD6BDA3FFCBAC8DFFC09B79FF
+ BF9871FFC8A175FFC9A575FFBE9D6CFFB09261FFB99A6DFFB69469FFB79069FF
+ BE946AFFC09368FFBB8F60FFB48C57FFB58C55FFD5A973FFC69A64FFC0935AFF
+ B5884FFFAD7E46FFBD8F55FFCA9B5EFFBC8B4DFFCD9D5DFFCC9A58FFC28E4BFF
+ B37F39FFB17D36FFBE8841FFC28D44FFBE8940FFBD883FFFBF8A41FFC28A3DFF
+ BF8637FFBA7F30FFB77C2CFFBC8433FFC68E3CFFC48D38FFC7913CFFC08C39FF
+ B9883CFFB28748FFA78452FFC2A683FFF1E2CFFFF1EFEEFFEBEEF6FFEFF1F9FF
+ F2F1FAFFF7F2FBFFF4F1FAFFF3F0F9FFEEF0F8FFEFF2F7FFEEF3F6FFE9EEEDFF
+ EFF3EEFFF6F3EEFFF7F1EAFFEEE4DAFFD9C2A8FFC0925CFFC08940FFBB8433FF
+ B8822BFFB88021FFBE8621FFC38A21FFBE841AFFC0841AFFBD7E16FFC1821AFF
+ C5861EFFC1821AFFC18319FFC18317FFBA7C10FFB6770FFFBE8119FFC08218FF
+ B97D13FFBC7E12FFB87D0FFFB97D0CFFBE8413FFBD810FFFBC8310FFBF8311FF
+ BB820FFFBB7F0EFFB97F0EFFBE8113FFC08315FFBB7F0EFFBD7F0DFFBC7E0CFF
+ BD7F0DFFBE7F0FFFBE7F0FFFBD7E10FFBC7C10FFBA7C10FFBC7E14FFBE8016FF
+ C18319FFC2831BFFC2831BFFC2821CFFC18319FFBC8211FFBB820EFFBA810EFF
+ B87F0CFFB77E0BFFB77D0CFFB87E0DFFB87E0DFFBF8312FFBE8211FFBD8012FF
+ BD8012FFBE7F11FFBC7F11FFBD8012FFBF8010FFC48414FFC78514FFC68413FF
+ C38110FFC07E0DFFBC7D0BFFBE7E0EFFBF810FFFBF810FFFBA7E0CFFBB7F0EFF
+ BF8312FFBD8312FFB87E0DFFB67C0BFFBA7E0DFFBF7F0FFFBE7E0EFFBD7E0EFF
+ BC7F11FFBD7F13FFBC8016FFBC8219FFBD831AFFB47A11FFB87E15FFBA7E14FF
+ A36E1EFF9E6B1BFF946317FF875912FF794D0EFF6D410CFF62380BFF5D320BFF
+ 613916FF66421EFF5E3E1BFF543819FF4E361EFF422D1EFF493432FF574D5EFF
+ 4F5786FF3B4D8CFF3E5496FF4762A5FF4565ACFF4066AEFF3E65AFFF3964ADFF
+ 345EA9FF3963AEFF3F69B4FF436EB7FF456DB8FF416BB6FF3F69B6FF3E67B6FF
+ 3D65B7FF3A60B2FF375CACFF3B5CABFF3E5CA9FF3E57A1FF374C90FF304283FF
+ 343F7BFF353F75FF333A6CFF2F3461FF2E3058FF2D2F52FF2F3052FF36334DFF
+ 3E3A46FF423634FF4E3624FF5C3E23FF6B4A29FF71502FFF69492CFF624225FF
+ 5F3D1FFF664322FF714E2CFF7D5A38FF866544FF8D6A48FF936C45FF936C45FF
+ 9C7957FFA58665FFA48566FF977857FF9A7B5CFFAD8E6DFFB59677FFAE8F6EFF
+ A48566FFA88968FFA98A6BFFA88968FFB09172FFB99A79FFB69778FFAC8D6EFF
+ A98B6EFFB09172FFB49470FFB49170FFB48B75FFB28A77FFAC8C75FFA78D6FFF
+ A58F6CFFA88E6AFFA88564FFB5907AFFA68A83FF716579FF48518AFF36509CFF
+ 284E9CFF315FADFF3E6AB7FF517EC8FF6A94DFFF638ED7FF4B74BDFF416AB3FF
+ 4169B4FF3D65B0FF385EACFF3359A7FF3659A9FF3B5EAEFF3E5FAFFF3F5CADFF
+ 455CACFF40529FFF38478CFF364282FF3B4680FF424A7FFF484C7CFF4C4C74FF
+ 524E71FF625973FFDED1DFFFFFF2F8FFE9DDDDFFF8EFEBFFFFFAF3FFFFFAF3FF
+ FFF5EDFFF7E8DFFFEAD6CBFFE1CABBFFDAC3B3FFD2BEACFFC9B8A5FFC0B29FFF
+ D4C5B5FFD8C7BAFFD5BFB4FFC8AFA5FFC9AFA3FFD2B8AAFFD1BAAAFFCAB49BFF
+ D3BA9AFFC3A883FFB89B76FFB0936CFFB1926BFFBEA077FFC1A178FFAC8C61FF
+ AE8D60FFBA976BFFC4A072FFC7A073FFC6A070FFC69E6EFFB99161FFAB834FFF
+ B1864DFFB18546FFBA894BFFC28F50FFBE8B4CFFB78446FFB98648FFBD8D4DFF
+ AB7B39FFB1823EFFC09350FFC59C5EFFB4915FFFB2956EFFD7C1A8FFFBF2E5FF
+ F0F2F2FFE9F2F6FFECF2F7FFEEF1F9FFF1F0F9FFEFF1F9FFF0F1FBFFEDF3FAFF
+ F1F7FEFFF0F6FBFFECF1F2FFF2F6F1FFFDFAF2FFFDF3E9FFE2D2C5FFBFA587FF
+ BD955BFFC19046FFC29141FFBC8B35FFB58224FFB78521FFBD8820FFBE871EFF
+ BA8118FFB77D16FFBA8019FFBD831CFFBC821BFFBE851CFFBD851AFFB87E14FF
+ B1770EFFBD831AFFC0841AFFB77D13FFB87D10FFB98112FFBD8312FFBF8716FF
+ BE8512FFBC8512FFBE8413FFBB8312FFBC8113FFBA8213FFBE8316FFBD8417FF
+ B57C0FFFB77E11FFBA8114FFBA8114FFB98013FFB77E11FFB87D10FFB87C12FF
+ B97D13FFB97C14FFBB7E16FFBC7F17FFBD8018FFBE8119FFBF821AFFC18317FF
+ C0830FFFC1850AFFC0830BFFBF820AFFBF820AFFC0820CFFC0820CFFC1830DFF
+ BC7F09FFBD800AFFBE810DFFBF820EFFC18210FFBF810FFFBF810FFFBC800EFF
+ C18815FFC28916FFC38814FFC08511FFBB800CFFB97E0AFFBA7E0CFFBB800CFF
+ C18612FFBE830FFFBD820EFFBF8410FFBE840DFFB97F08FFB87E07FFBD800AFF
+ C1830DFFC0820CFFBE810BFFBB800CFFBB7F0DFFB97F0EFFB8800FFFB98112FF
+ B57D0EFFB77F0EFFB97F0EFFA87110FFA87312FFA77515FFA47218FF996917FF
+ 8A5A12FF7C4A0EFF71420CFF704010FF693F12FF5C370BFF55340DFF533719FF
+ 4C351FFF4D392EFF4F4551FF565B88FF3D4D8FFF3B5094FF415DA4FF4465AEFF
+ 4065AFFF3D66AFFF3A67B0FF3562ACFF3B68B2FF426FB8FF4873BCFF4771BCFF
+ 456FBCFF416CBBFF416CBDFF3F67B9FF3B62B1FF395CACFF395AA9FF3C5AA7FF
+ 3B56A0FF364D91FF324485FF32407BFF343E74FF31386AFF2E3360FF2D2F57FF
+ 2E3053FF313052FF37344DFF3C3843FF413632FF4B3321FF513318FF583716FF
+ 5C3B1AFF5B3B1EFF5A3A1DFF5B391BFF5B3817FF5A3715FF5D3A19FF603E20FF
+ 664322FF6C451FFF69451DFF6F4D29FF765934FF755734FF6A4D28FF6E502DFF
+ 81643FFF8A6C49FF836641FF856744FF886B46FF886A47FF8B6E49FF9B7D5AFF
+ AC8F6AFFA78966FF967855FF8D6C4BFF987855FFA68460FFB08B69FFB38A71FF
+ B38A73FFB18E74FFAE9172FFA98D6AFFA98C67FFA98361FFB79278FFAD9284FF
+ 7C6F7DFF50578EFF37519EFF2F54A4FF315EAFFF3964B3FF4772C1FF5A86D3FF
+ 5B85D0FF4D77C2FF4A72BDFF4169B4FF3D65B0FF385FAAFF345AA8FF375BA9FF
+ 3B5EAEFF4162B2FF4462B3FF4860B4FF4156A8FF394A99FF35468FFF38488BFF
+ 3C4888FF3D4882FF3F457AFF474B7BFF43436BFF716E8EFFD1CEE4FFFDFAFFFF
+ EFEFF5FFF0F2F3FFFBFBFBFFF3F1F1FFF8F3F4FFFBF3F3FFFAEEEEFFF4E8E6FF
+ F2E9E6FFF5F0EDFFFBF7F6FFF5F1F0FFFDF7F8FFF9EEF0FFE9DCDEFFE8DBDDFF
+ F4E9EBFFF3EBECFFE9E0DCFFDDD3C2FFD7CAB4FFD6C8B2FFD9CBB5FFDFCFB8FF
+ E5D5BEFFDCCBB1FFC5B198FFBAA48BFFC2AD92FFCCB399FFCDB599FFD0B59BFF
+ D1B69BFFCDAF96FFC6A98AFFB5956AFFB29062FFB08A5AFFBB9363FFC59C6FFF
+ B98F64FFAE845AFFB38C60FFB48D60FFAB8555FFBB9767FFCAA97CFFBFA47FFF
+ C9B499FFE8DBCDFFF7F3EEFFEDF2F3FFE8F1F5FFE9EFF4FFEAEEF3FFECEFF4FF
+ EDF0F8FFEDF3FAFFEDF5FCFFECF6FDFFEAF3F7FFE8F0F0FFF1F2EEFFF9F3E8FF
+ EADDCDFFC2AF9AFFA08462FFBD9259FFBA8943FFBE8D41FFB58533FFAF7D23FF
+ B48123FFB68120FFBA8320FFBD8421FFBB801DFFBC811EFFC18623FFC28724FF
+ C18622FFC18720FFC18720FFBB8019FFC1861FFFBF851CFFB87E14FFBA8016FF
+ C0871AFFC1891AFFBE8617FFBE8615FFBE8615FFBD8516FFBC8415FFBB8215FF
+ BB8215FFBC8316FFBD8319FFB98116FFBC831AFFBE851CFFBE861BFFBB8318FF
+ B98116FFBA8016FFBC8218FFBC8218FFBB8117FFBA8016FFBB7F15FFBB7F15FF
+ BA7E14FFBA7E14FFBD8012FFC1810BFFC38208FFC38208FFC28309FFC28309FF
+ C3840CFFC3840CFFC2840EFFBE800AFFBD800AFFBD800CFFBE810DFFBE810DFF
+ BE800EFFBC800EFFBA810EFFB77F0EFFB88210FFB98310FFB9820FFFB67F0CFF
+ B67F0CFFB9800DFFBB820FFFBF8613FFBB820EFFBB7F0DFFBE830FFFBD820EFF
+ B97E0AFFBB7E0AFFBE810BFFC1840CFFC08409FFBF820AFFBD8109FFBA8009FF
+ BA7F0BFFB9800DFFB9800DFFBA810EFFBB820EFFBD820EFFB3770DFFB2780EFF
+ B1790EFFAF7810FFAB7413FFA36E14FF9F6718FF9B631CFF844E0DFF7A480CFF
+ 683D04FF5D3804FF59390EFF513816FF513B22FF4B3F3FFF595B84FF445092FF
+ 3A4E95FF3D58A2FF4062AEFF3E65B0FF3B66AFFF3C69B2FF3868B0FF3C6CB4FF
+ 4171B9FF4572BBFF4670BBFF456FBCFF436EBFFF4570C1FF436BBDFF3E65B4FF
+ 395CACFF3859A8FF3B59A6FF3C57A1FF384E95FF364889FF33417CFF313D73FF
+ 303769FF2C315EFF2D2F57FF2E3052FF313050FF36334CFF37313CFF3F332FFF
+ 4D3322FF553518FF5A3716FF5E3B1AFF5F3F22FF634326FF664426FF63401FFF
+ 5D3A19FF593615FF583618FF5C3918FF613A14FF5E3A12FF56350EFF5A3D16FF
+ 5E411CFF5D4019FF5D401BFF5F421BFF593C17FF51340DFF563914FF5E411AFF
+ 624520FF63461FFF6E512CFF7D6039FF7B5E39FF71512DFF6F4D29FF7B5733FF
+ 87633DFF926C49FF956D51FF987054FF9B7759FF9F7F5CFFA98966FFA78561FF
+ A17752FFA78161FF9C816DFF70656FFF4C538AFF3750A0FF3559ADFF3460B4FF
+ 3864B7FF3F6BBEFF4875C6FF4A75C4FF4571BEFF4771BCFF3F67B2FF3A63ACFF
+ 355CA6FF365AA6FF385CA8FF3B5FADFF3F63B1FF4465B5FF405BB2FF4058B0FF
+ 3C55ABFF3951A3FF374E9AFF364992FF36468BFF374587FF3D4884FF414B81FF
+ 303867FF646C91FFC1C6DFFFEEF3FFFFF3F7FCFFEAEFEEFFF7FAF8FFF5F6F4FF
+ F7F3F2FFF8F4F3FFFCF7F8FFFCF9FBFFF6F8F9FFF1F5F6FFF2F6F7FFFAF9FBFF
+ FAF5F6FFF3EEEDFFF4EFEEFFFAF5F6FFF5F4F6FFECECECFFF4F1ECFFF0EDE5FF
+ F2ECE5FFF5EFE8FFF9F2E9FFFEF7EEFFFDF4EBFFF0E7DEFFF0E5DDFFEBE1D7FF
+ E4D5CCFFD8CABEFFD8C7BEFFE1D1C5FFECDBD2FFF2E2D2FFE7D3BAFFE5D0B1FF
+ D1B799FFCFB297FFE0C2A9FFD1B29DFFC0A28FFFD3B5A2FFECCFBAFFCDB298FF
+ C7AC91FFC9B397FFC2AF9AFFD5C8BAFFF1EAE7FFF4F3F5FFE8EFF2FFE5EEF1FF
+ E5ECEFFFE6EBEEFFE9ECF0FFEBF0F3FFEDF3F8FFEEF7FBFFE7F2F6FFE3ECEFFF
+ E9EFEEFFF6F7EEFFF8F1E2FFDED0BAFFB8A286FFA98861FFCC9E68FFC28E4CFF
+ C28E47FFBA8639FFB7812EFFBE8831FFBB8227FFBB8023FFC5882BFFBF8024FF
+ BE7F23FFC48628FFC78729FFC18122FFC28223FFCC8D2BFFC88B29FFC28724FF
+ BC811DFFB87E17FFBB811AFFC38A21FFC1891EFFB88015FFBF871AFFBE8619FF
+ BD8417FFBC8316FFBC8218FFBC8218FFBC8218FFBC8219FFBE841DFFBD861EFF
+ C0861FFFBD841BFFBA8118FFB98017FFBD8319FFC0861CFFC0841AFFBF8417FF
+ BE8315FFBF8214FFBE8211FFBD8110FFBD8110FFBF810FFFBF7F09FFC17F08FF
+ C08109FFC1820AFFC2830BFFC0820CFFC1830DFFC0830FFFC18410FFBD820EFF
+ BB7F0DFFB97D0BFFB77E0BFFB87E0DFFB8800FFFB98110FFB47D0EFFB47F10FF
+ B68112FFB98213FFB78011FFB78011FFBA8114FFBC8316FFBB8013FFB87D0FFF
+ B97B0FFFBC7F11FFBC7F11FFB97C0EFFBC7D0FFFC08010FFC1810BFFC38208FF
+ C28009FFBF8008FFBE800AFFBE800AFFBF820EFFBF820EFFC28511FFC18410FF
+ C28310FFBB7910FFBA790DFFB8790BFFB6790BFFB4790CFFB37811FFB37619FF
+ B2751FFFA86D1EFF9F681FFF8F5C16FF7B4F10FF68430BFF59380AFF503510FF
+ 453328FF5C5979FF4A5490FF3E5194FF38539DFF3C5EAAFF3E65B0FF3A65AEFF
+ 3B68B1FF3868B0FF386AB2FF3C6CB4FF3F6CB5FF416CB5FF416BB8FF3F6ABBFF
+ 406BBCFF466DBCFF3F65B3FF395DABFF385AA6FF3C5BA6FF3C57A1FF394F96FF
+ 35498AFF334280FF323E74FF2F3668FF2B315CFF2C2F55FF2E2F51FF31314FFF
+ 353349FF3C3740FF423632FF4E3521FF57371AFF5E3B1AFF603D1CFF5B3B1EFF
+ 59391CFF5D3B1DFF5E3B1AFF5D3A19FF5C3A1CFF5E3C1FFF623E20FF673F1CFF
+ 65401AFF5A3A16FF583B16FF5B3E19FF5F421DFF60431EFF5A3D18FF543712FF
+ 523510FF4A2D08FF563914FF5D401BFF593C17FF583B16FF5D401BFF61441FFF
+ 61411DFF623E1AFF653F1CFF68421FFF6B4523FF6A4225FF6C4427FF734D2DFF
+ 7B5836FF856240FF855F3CFF7B5029FF7B5532FF71573FFF53494FFF434A81FF
+ 3D56A6FF375AB0FF3661B8FF3A65BCFF3E6ABEFF416DC0FF3E6BBCFF3C67B6FF
+ 3D67B4FF3B63AEFF365DA7FF3459A3FF375CA6FF3B60AAFF3C60ACFF3D61ADFF
+ 3F62B2FF3758AEFF3B5BB4FF3D5EB4FF3C5BB0FF3754A5FF334D9AFF334893FF
+ 36488FFF39498CFF384786FF39467EFF2E3B69FF6B7593FFE1E9FAFFFBFEFFFF
+ F4F8F3FFF2F8F3FFF1F5F0FFF1F2F0FFF3F3F3FFF5F6FAFFF4F7FCFFECF2F9FF
+ E4ECF3FFE8F1F5FFEAEFF2FFEEF0F0FFF5F3F2FFF5F6F2FFF1F4F2FFEAEFF0FF
+ E8EDEEFFF4F7FBFFF3F5F6FFF1F2F6FFF0EFF1FFEFEEF0FFF3F3F3FFF9F6F8FF
+ F8F6F6FFFCF9FBFFFDF8F9FFF8F3F4FFF2EDECFFEFE9EAFFF1ECEBFFF8F0F1FF
+ FBF4F1FFFFF9EFFFFFFFF2FFFDEDE0FFF6E5D8FFFFEEE6FFF4E0DBFFE8D5D2FF
+ FDEAE7FFFFEFEAFFEDDCD3FFE7D6C9FFE6D6C9FFDFD3C9FFE5DFDAFFEFEEF2FF
+ EBEEF6FFE9EFF4FFE5EEF1FFE7ECEDFFE7EBECFFEBEDEDFFECF0F1FFEFF4F7FF
+ EFF6F9FFE9F2F5FFE3EBEBFFE8EFECFFF3F4EBFFF2EAD9FFD6C7ADFFB49F80FF
+ B69770FFC29869FFB48551FFBB8D53FFB8894BFFBB8A46FFC6944CFFBC873EFF
+ B98336FFBB8336FFBA8034FFB87C30FFB77C2DFFB67B2CFFB17627FFB77A2AFF
+ C48A38FFCA913CFFBD852CFFB67E25FFB57E23FFB68022FFBC8425FFBC8524FF
+ B47D1AFFBE8724FFBC8621FFBC841FFFBB831EFFBD821FFFBD821FFFBD821FFF
+ BA811EFFBE8424FFBD8421FFBB821FFFBB801CFFB97E1AFFB97F18FFBC8219FF
+ BE841BFFBD8117FFBE8316FFC08315FFC18514FFC48515FFC48614FFC48614FF
+ C58614FFBF7D0CFFC07F0CFFBF800EFFC0810FFFC18210FFC08210FFBF810FFF
+ BD8110FFC18514FFBF8312FFBA7F11FFB77C0EFFB57D0EFFB67E0FFFB98112FF
+ B98213FFBC8316FFBD8518FFC0871AFFBF8619FFBD8417FFBB8215FFBD8117FF
+ BF8319FFBA7E14FFB97B11FFBA7B13FFBE7F17FFBE7F17FFBB7C14FFBB7C14FF
+ C08014FFC1800DFFC27F0AFFC0800AFFC07F0CFFC07F0CFFC0810EFFC18210FF
+ C18311FFC58614FFC28311FFC28310FFBB7210FFBC740FFFBC780DFFBB7B0BFF
+ BA7C0AFFB77A0CFFB6770FFFB37412FFBE7F23FFB77A24FFAB7321FF9D691DFF
+ 8B5C18FF7C5013FF6E4713FF583D23FF5F566AFF555B8AFF445693FF365096FF
+ 3A5AA5FF3D64AFFF3D64AEFF3B66AFFF3B68B2FF3867B1FF3B68B1FF3C69B2FF
+ 416AB3FF4169B4FF3D65B7FF3C64B6FF4168B7FF3C62B0FF395DABFF3C5CA8FF
+ 3D5CA7FF3C589FFF334C92FF304485FF354482FF323E74FF2E3567FF2A305BFF
+ 2D2E54FF2E304FFF2F304CFF343246FF3A323CFF40312EFF4D321EFF59371AFF
+ 603D1CFF623F1EFF5B3A20FF56351BFF583619FF5B3719FF5B391BFF5B391BFF
+ 5A381BFF5A381AFF5F3917FF603A17FF5C3B1AFF533415FF503112FF533415FF
+ 563718FF573819FF58391AFF5B3C1DFF563718FF5B3C1DFF5E3F20FF5B3C1DFF
+ 593A1BFF593A1BFF5B3C1DFF5E3D1CFF5F3917FF5C3613FF5B3713FF5C3715FF
+ 583214FF552F11FF573412FF5E3B19FF603A1AFF643E1CFF5F330EFF5D3714FF
+ 513B1FFF3D3536FF3D457AFF425BABFF3D60B6FF355FB8FF3561BAFF3966BDFF
+ 3C69C0FF3C6BBDFF3966B7FF3761AEFF3860ABFF3259A3FF3457A0FF3C5FA8FF
+ 4265AEFF4265AFFF3D61ADFF3B61AFFF355AAEFF365DB2FF3960B5FF395EB2FF
+ 3557AAFF31509FFF324B95FF32488FFF36498DFF2A3C7BFF3D4E87FF374674FF
+ 46516DFFBBC1CCFFFDFAF6FFFFFDF3FFF4F6F0FFF3F9F4FFF7FAF8FFF4F8F9FF
+ EFF2FAFFE8EEF9FFE6EFFCFFE6F2FEFFEAF7FFFFE6F1F5FFECF2F1FFF3F9F4FF
+ F5FCF5FFF0F7F2FFEAF5F3FFECF6F6FFF1F4FCFFF3F5FDFFF3F4FEFFF3F2FBFF
+ F2F1FAFFF1F1F7FFF0F2FAFFF2F5FAFFF1F3FBFFF3F6FBFFF3F6FBFFF2F5F9FF
+ F0F3F8FFF0F3F7FFF5F5FBFFF7F8FCFFEEF0F0FFF7F5F4FFFAF5F4FFFCF4F4FF
+ FEF5F8FFF9EFF5FFF4ECF3FFFAF2F9FFF1EAEFFFF6EEEFFFFCF3EFFFFEF6EFFF
+ FCF5F2FFF6F1F2FFECEEF6FFE9EBF5FFEEF4FBFFEFF4F7FFEFF1F2FFEFEFEFFF
+ F1EFEEFFF0F1EFFFF1F3F3FFF1F5F6FFF2F7F8FFE9EEEFFFE9EEECFFE9EAE1FF
+ E7E0D1FFD0C4ACFFB3A184FFB89F7FFFB49576FFAB8A69FFC19E7CFFC6A27CFF
+ CBA67AFFD3AD7DFFC29968FFBC915EFFB98C59FFC49863FFBF905CFFAF814BFF
+ AC7E48FFAF814BFFB78852FFC4945AFFC69452FFB9853FFFB6823BFFB9863DFF
+ B38234FFB27F2FFFB98433FFBA8633FFBE8833FFBB862FFFB9832CFFB8822BFF
+ BB822CFFBC832DFFBB822CFFB9802AFFBC842BFFBD8429FFBB8227FFBC8124FF
+ BC8223FFBE8222FFBD801EFFBC801CFFBF811BFFC0831BFFC4861AFFC7881AFF
+ C8871AFFC88818FFC68616FFC58515FFBE7E12FFBF7E15FFC18017FFC28118FF
+ C28118FFBF8117FFBF8117FFBC8114FFBC8114FFBB8013FFBA7F12FFB97E11FF
+ BA7F12FFBB8013FFBD8215FFBE8316FFC28517FFC48719FFC8891BFFC7881AFF
+ C48418FFC18115FFBE8016FFBF8117FFC08119FFBD7E16FFBE7E18FFC3831DFF
+ C2821CFFBE7E18FFBC7B18FFBE7F17FFBF8012FFC08010FFBF7F0FFFBF7E11FF
+ BF7E11FFBF8012FFC08113FFBF8214FFC28315FFBF8012FFBF8012FFBC7010FF
+ BA720DFFBA7409FFB97706FFB77805FFB67905FFB67707FFB6750CFFBA7812FF
+ B57412FFB27317FFB4781FFFB27A29FFAC772EFFA06C2AFF805932FF655759FF
+ 5D607FFF4C5A8EFF375090FF3959A0FF4164AEFF3F64AEFF3D64AEFF3E68B3FF
+ 3B68B2FF3B68B2FF406BB4FF456DB5FF446BB5FF3F66B5FF3B61B3FF3C62B0FF
+ 3B5FABFF3A5CA8FF3D5DA8FF3E5EA7FF3B579EFF30498FFF283E80FF344683FF
+ 323F77FF2C3666FF2A305BFF2D2E54FF2F2E4EFF312F4CFF333145FF38303AFF
+ 40312EFF4F3420FF5A381BFF5F3C1BFF603D1CFF5A391FFF57361CFF553316FF
+ 593517FF583618FF573518FF55341AFF583619FF623B1BFF663F1FFF603E21FF
+ 59381EFF56351BFF56351BFF59381EFF59381EFF59381EFF58371DFF57361CFF
+ 502F15FF4B2A10FF4F2E14FF55341AFF56351BFF523117FF512F12FF5B3515FF
+ 5B3513FF5C3917FF5F3E1DFF5C3A1DFF543215FF51300FFF553413FF583317FF
+ 643E20FF633916FF603C18FF503B1CFF39322FFF3A4474FF455DA9FF4568BEFF
+ 3660B9FF305CB5FF335FB8FF3967BFFF3E6CC0FF3C69BAFF3862AFFF3960AAFF
+ 3359A1FF36589EFF4062A8FF496BB1FF4568B1FF4063ADFF3B5FABFF385FAEFF
+ 365EB0FF345FB0FF355DAFFF345AA8FF33539FFF324B93FF2F468AFF304386FF
+ 314382FF2B3C75FF3F4C7AFF3F4764FF9A9CA6FFFFF8F1FFF8EFE1FFF8F4E9FF
+ F5F4EAFFF6F3EBFFF6F3EEFFF4F4F4FFF2F5FAFFEFF6FFFFEEF7FFFFEFF9FFFF
+ EBF2F5FFEBF1ECFFF4F7EEFFF5F9EEFFF0F5ECFFEDF4EFFFF1F7F6FFF1F2F6FF
+ F4F2F8FFF4F1FAFFF5F3F9FFF6F4FAFFF2F2F8FFEEF1F6FFEFF1F9FFF0F2FAFF
+ F1F4FCFFF1F7FEFFF1F7FEFFEEF4FBFFEAF2F9FFEBF3FAFFEDF5FCFFF4FAFFFF
+ EBEFF4FFF4F3F7FFF9F5FAFFF3EEF7FFF8F4FFFFFCFAFFFFEEEEFAFFF0EFF8FF
+ FCFBFFFFFBF9F8FFF7F4F0FFFAF6F5FFF5F2F4FFEBECF6FFF0F2FDFFF6F9FFFF
+ F5F8FCFFF4F6F7FFF3F4F2FFF3F1F0FFF5F2EEFFF4F2F1FFF3F3F3FFF5F9FAFF
+ F0F4F5FFF0F5F4FFEFF0ECFFF5F3E9FFEEE5D7FFD9CBB8FFDECDB8FFE2D0BFFF
+ DCCAB9FFF7E3D1FFF8E3CEFFF0DAC1FFEBD4BAFFCEB496FFC3A788FFC4A788FF
+ DBBC9BFFD3B493FFB79877FFB29372FFBD9E7DFFC6A786FFD0AE8AFFBC9569FF
+ B08756FFB18857FFB68E59FFAC834CFFA57D42FFB38849FFBC9251FFB38845FF
+ B28541FFAE823BFFB0823BFFB3823CFFB5823CFFB4813BFFB28038FFB98539FF
+ B78336FFB88235FFB98434FFBD8635FFBC8633FFB8822BFFB77F26FFBD8429FF
+ BE8528FFC28828FFC48926FFC38624FFC08420FFBD811DFFBB7F1BFFBB7E1EFF
+ BC7E20FFBD7F21FFBE8121FFBE8121FFBD8020FFBC7F1DFFBB7F1BFFB67A16FF
+ B77C15FFB87D16FFBC7F17FFBD8018FFBE8119FFBF821AFFBF8319FFBF7F13FF
+ C18214FFC58418FFC38317FFC28115FFBF7F13FFBF7E15FFC07F16FFC6851CFF
+ C3811AFFC3841CFFC78721FFC68620FFBF7F19FFBA7C16FFBC7F17FFBE8218FF
+ BF8115FFBE8014FFBD7F13FFBD7F13FFBD7F13FFBC8114FFBC8114FFBD8215FF
+ B87D10FFBA7C10FFBD7412FFBC740EFFB87508FFB67704FFB37902FFB57B04FF
+ B77B09FFBA7B0DFFBB7A11FFB97710FFB7750FFFB47311FFB47416FFB6771FFF
+ B97A2AFFA8773FFF7F6B5AFF646472FF556288FF3D548CFF375497FF3F5FAAFF
+ 3D5DA8FF4062AEFF3960AEFF365FAEFF426CB7FF4D74BEFF476BB1FF4164ADFF
+ 4468B4FF456BB9FF4064B0FF3F64AEFF4063ADFF4060ABFF3D5DA6FF37559CFF
+ 314B91FF2F4587FF344683FF334078FF2E3868FF2B315AFF2D2F52FF2E2E4CFF
+ 2F2E48FF332F42FF3F3640FF402F2CFF4F3420FF5D3B1EFF5E3818FF5C3616FF
+ 58371DFF56351BFF563417FF583619FF5B391CFF5E3C1FFF5C3A22FF5B3A20FF
+ 5F391BFF5D3719FF603D23FF5B3921FF57351DFF56341CFF58361EFF59371FFF
+ 59371FFF57351DFF59371FFF58361EFF57351DFF56341CFF56341CFF57351DFF
+ 58361EFF5B381EFF5F391BFF5B3817FF543516FF523417FF56341CFF58371DFF
+ 58391AFF573819FF59371FFF623F25FF603919FF573714FF533F20FF433D38FF
+ 3D446FFF4E64ABFF4466BAFF3C66BFFF325EB9FF3965BEFF3E6CC4FF3F6CC3FF
+ 416DC0FF345EABFF3057A1FF30549AFF35569BFF4160A5FF4766ABFF4262A9FF
+ 3C5CA7FF385BA5FF375CA6FF355CA6FF3860ABFF3D65B0FF4166B0FF3E5EA5FF
+ 395396FF354B8DFF324485FF31407EFF2C3872FF374170FF414562FF64626EFF
+ B8ACA8FFE5D6C6FFEADBC8FFE3D5BFFFE4D3BEFFECDDCAFFF4E7D9FFF7ECE4FF
+ F5F0EFFFF7F4F6FFF8F5F7FFF0ECEBFFEEE8E1FFF4EEE3FFFBF3E6FFFBF5E8FF
+ F7F5EBFFFAF6F1FFF6EFECFFFEF5F2FFFFF9F9FFFFF8F8FFFBF6F5FFF8F4F3FF
+ F8F6F6FFF9F8FAFFEDEEF2FFEDF0F4FFEFF4F7FFEEF4F9FFEAF2F9FFE6F0F7FF
+ E8F2F9FFEBF5FCFFE7EDF4FFECEFF4FFF3F2F6FFF7F3F8FFF6F5F9FFF4F4FAFF
+ EFF1FBFFEAEFF8FFF1F7FCFFF3F8F9FFF9FAF8FFFBFAF6FFFCF8F7FFF6F3F5FF
+ EEEDF6FFE9EAF4FFEDF0F8FFF3F6FAFFF7F9FAFFF5F6F4FFF3F1F0FFF2EFEBFF
+ F2F0EFFFF5F5F5FFF2F3F7FFF0F3F8FFF0F3F8FFF2F2F8FFF7F6F8FFFBF6F7FF
+ FAF3F0FFF4EEE9FFF1EDE8FFF8F5F0FFFDFAF2FFFBF5EEFFF9F2E9FFF8EFE5FF
+ F3EADDFFEDE2D4FFE8DBCBFFEDDFCDFFF7E9D7FFEEE0CEFFEADECCFFF1E5D3FF
+ ECDFCFFFF0E0CFFFF1DCC7FFE3CBB3FFD4BCA4FFE0C8ACFFD8BF9FFFBFA783FF
+ CBB189FFDDC198FFCEB184FFC7A97AFFC5A574FFBC9B6AFFAD8A58FFAD8A58FF
+ BB9664FFC09965FFD7AE77FFC79D62FFB68A4FFFB28649FFBB8F50FFBD9151FF
+ B18441FFA2732FFFA97931FFAF8036FFB9883CFFBC8B3DFFB58232FFAC7A28FF
+ B07E2CFFBD8837FFBB8433FFBA8231FFBB8332FFB8802EFFB27826FFB47B26FF
+ C18630FFC78D34FFC5892FFFC18629FFBF8224FFBE8121FFBF8222FFBF8220FF
+ BF8220FFC0821CFFBF8018FFC08216FFC38219FFC18317FFC28216FFBE8014FF
+ BD7F13FFBC7E12FFB87A0EFFC7891DFFC08216FFB97B0FFFC38519FFC08216FF
+ BA7F12FFC78E21FFBE861BFFC1891EFFC38B20FFC38B20FFC0881DFFBD851AFF
+ BA8217FFB98116FFBB8318FFB77F14FFB77F14FFBB730DFFBA760DFFB97909FF
+ B67B07FFB57D06FFB37D08FFB57C09FFB77B0AFFB57509FFB67509FFB87508FF
+ BB770CFFBC7A11FFBD7A17FFBC791CFFAA742DFF7E6543FF615D5CFF515D79FF
+ 3F5688FF3E5A9BFF4464ADFF3F5CA7FF3C5CA8FF375CACFF315AA9FF3D64B2FF
+ 4A6FB9FF4A6CB2FF4868AFFF4668B4FF4266B2FF4166B0FF3F64AEFF3E61ABFF
+ 3D5DA8FF3A5AA3FF345299FF2F498FFF2C4486FF304380FF2E3D75FF2A3666FF
+ 2A325AFF2E3053FF31314FFF32314BFF363245FF3D353CFF3D2C29FF4B301CFF
+ 59371AFF593313FF583212FF543319FF503118FF57341AFF583619FF5A381BFF
+ 5A391FFF583821FF59371FFF5D361AFF5C3618FF5D3A20FF58361EFF56341CFF
+ 56341CFF57351DFF58361EFF57351DFF55331BFF58361EFF57351DFF56341CFF
+ 55331BFF54321AFF55331BFF56341CFF59361CFF5B3719FF573517FF503215FF
+ 4F3217FF50311AFF52331CFF523419FF503318FF4F3019FF54341DFF542F13FF
+ 4F3011FF4D391AFF3C352CFF373C5DFF495B9AFF4362B1FF3C64BDFF345EB7FF
+ 3864BDFF3D6BC3FF3E6BC2FF3E6ABDFF345BA9FF30569EFF35569BFF385598FF
+ 3B589BFF3F5C9FFF3F5DA4FF3858A1FF31529BFF33559BFF37599FFF3C5FA8FF
+ 476AB3FF5272B9FF5471B6FF4B63A5FF405495FF38488AFF3C4B8AFF37427EFF
+ 384173FF3E4063FF4A455AFF71656BFF968479FFAA9276FFAF926BFFB8986FFF
+ C3A378FFCAAC83FFCAAE8BFFC6AF95FFC8B39EFFD3BFADFFCFBBA9FFD2BBA5FF
+ D7C2A7FFDEC7ADFFE4CFB4FFEDDBC4FFF8E7D2FFFBE8D3FFFBEAD5FFFEEDD8FF
+ FBECD9FFF6E8D6FFF1E4D4FFF0E7D9FFF4ECDFFFFAF3EAFFFAF7EFFFFCF9F4FF
+ F7F8F4FFF5F6F4FFF1F4F2FFECF1EFFFE9EEEDFFF7F7F7FFF8F4F3FFF5F0EDFF
+ F5EEEBFFF3EEEBFFF3F1F1FFF0F3F7FFF0F7FAFFF0F8F8FFF0F8F7FFF4F8F3FF
+ F4F5F1FFF5F4F0FFF4F2F2FFF3F1F7FFF2F1FAFFEAEEF3FFE9EEF1FFEBEFF0FF
+ EFF1F1FFF2F3F1FFF3F1F0FFF3F1F0FFF5F3F3FFEDECF0FFF0EEF4FFF3F0F9FF
+ F3F2FCFFF0EFF9FFEDECF6FFF0EDF6FFF2F2F8FFECF0F1FFEEF4F3FFEFF4F3FF
+ EEF3F2FFF3F5F5FFF8F9F7FFF6F4F3FFF0EDE9FFF4F0EBFFF6F3EBFFFFFCF7FF
+ F9F6F1FFFAF7F2FFFFFFF9FFF9F8F4FFFCF9F5FFFFF9F6FFFFF8F4FFFCF4EDFF
+ FFFFF7FFFFFBEEFFF5EBDAFFFAEFDBFFFFF2DCFFFEF1D7FFF4E6CAFFEFDFC2FF
+ E8D6B9FFDECAABFFE0CBACFFE7D2B3FFE7D0B0FFD8BC99FFCFB28DFFC8A982FF
+ C9AA83FFCFAF86FFCEAE83FFC7A679FFC19F71FFBB9767FFB79462FFB99460FF
+ BF9B65FFC49F67FFC19B61FFBD975DFFBE965BFFB6894CFFB8894CFFC39456FF
+ BC8D4FFFA77737FFAE7C3AFFBE8A47FFB8843DFFBE8B42FFC28E42FFC48F3FFF
+ C18A39FFBC8534FFBB8331FFBE8634FFC48B35FFC58C31FFBF8728FFBA8021FF
+ B97F20FFBC8222FFBF8623FFBE8522FFBE831FFFCB902CFFC98F28FFBE841DFF
+ B77D14FFBB8117FFBF851BFFBD8319FFBB8318FFB37C14FFB57F1AFFBA821DFF
+ BA831BFFB9821AFFB88118FFBA831AFFBC851CFFBE851CFFB88118FFB88118FF
+ B8740BFFB8770BFFB77B0AFFB77E0BFFB57E0BFFB37D0BFFB37B0CFFB3780BFF
+ B87A0EFFB9780BFFB97706FFBC7906FFBC7B08FFBD7B0AFFB9780CFFA6701BFF
+ 836738FF635B4EFF515C70FF405785FF405B9BFF4865AFFF435DA9FF3D5BA8FF
+ 3C5EB1FF3157A9FF365CAAFF4065AFFF4665AAFF4867ACFF4767B2FF4163AFFF
+ 4669B2FF4164ADFF3B5CA5FF35569FFF32529BFF304E95FF2E4B90FF30488AFF
+ 314481FF2F3E76FF2C3868FF2B335BFF2F3153FF30314DFF333049FF373142FF
+ 41363EFF402D28FF4D2F1CFF593418FF573111FF573111FF55341AFF52331AFF
+ 59361CFF59361CFF57361CFF57351DFF55351EFF54351CFF5A3519FF5A3618FF
+ 59371AFF56351BFF55341AFF56351BFF57361CFF57361CFF55341AFF533218FF
+ 55341AFF55341AFF543319FF543319FF543319FF543319FF55341AFF563619FF
+ 5B391CFF563619FF503416FF4E3319FF4F321DFF50331EFF51331AFF4D3218FF
+ 482D18FF4A2D18FF4A2810FF4C2E13FF4B361AFF3A2E22FF34354AFF445384FF
+ 3E5BA5FF3C63B8FF3560B7FF3965BEFF3E6CC4FF3C69C0FF3D68B9FF3259A7FF
+ 305298FF345496FF365292FF344F8FFF375194FF3A549AFF324F99FF294690FF
+ 324F94FF395399FF3D5A9FFF4966ABFF5B75BBFF617BBEFF5269ADFF3E5195FF
+ 334388FF364689FF344080FF303873FF3F4373FF4E4C70FF544E67FF766463FF
+ 95734FFFA4783BFFAE7D37FFB78539FFB78636FFB38236FFAE813EFFAD8348FF
+ B48A55FFB58C5BFFBE9360FFC09562FFBC915EFFB88F5EFFBF9669FFC8A476FF
+ CFAE7DFFCBAC79FFC9AB7AFFC8AC7DFFC1A779FFBAA177FFBBA47EFFC1AB88FF
+ EDD9BAFFF4E3C8FFFBECD2FFFDF0DAFFFFF7E4FFFFFFEEFFFFFFEDFFFFF8E7FF
+ F2E7D9FFF9ECDCFFFFF3E1FFFFF7E5FFFFF4E6FFF7F1E6FFF2EFEAFFEFF3EEFF
+ E9F0EDFFEDF4EFFFF1F8F1FFF5F7F1FFF5F5EFFFF6F2F1FFF6F3F5FFF7F5FBFF
+ EBF0F3FFE3EAEDFFE2EAEAFFE8F0EFFFECF2F1FFECF1F0FFEFEFEFFFF1EFEFFF
+ F7F2F4FFF3EDF2FFF5EDF7FFFBF3FEFFF5F1FDFFEAE7F6FFE4E3F3FFE6E8F3FF
+ EFF4F7FFECF2F1FFE9EEEDFFEAEEEFFFF4F6F7FFFCFBFDFFFAF9FBFFF6F4F4FF
+ F3F1F1FFF1EFEEFFF7F7F7FFF1F1F1FFF0F2F3FFF4F8F9FFEAEDF1FFE9EDF2FF
+ E8EAF4FFEEF3FCFFEBF1F8FFF1F6F9FFF0F5F6FFECF1EFFFF3F7F2FFEEF1E8FF
+ F9FAF0FFF7F7EBFFF8F6EBFFF8F5E7FFF2EFE1FFF5EFE2FFF6F0E3FFF4EDDEFF
+ F5E8DAFFF2E3D3FFF2E2D2FFF5E5D4FFF6E4D3FFEFDECBFFEEDBC6FFF0DEC7FF
+ E8D4BBFFDDC9B0FFD6C1A6FFD7C2A6FFD9C4A8FFD4BFA0FFC8B394FFC1AA8AFF
+ CBAF8DFFC9AB88FFD4B490FFC3A37FFFA2815AFFAD8B60FFC3A074FFB89466FF
+ AE8957FFB9925EFFC09962FFBC945AFFB0864BFFA57C3EFFA67A3DFFAA7E3EFF
+ C49551FFBE9049FFB7873FFFB18139FFB18036FFB38335FFB58434FFB88634FF
+ C28F39FFB9872FFFB78329FFB88328FFBA8426FFC18B2CFFC08B2AFFB88120FF
+ BB8324FFC1892AFFC78D2EFFC68C2CFFC38727FFBF8421FFC18623FFC48926FF
+ C18422FFBD821FFFBD821FFFB67509FFB6760AFFB57908FFB27A09FFB27B0CFF
+ AF7A0CFFB1790EFFB1770DFFBA7C10FFB8790BFFB67704FFB67802FFB97B05FF
+ BB7D0BFFB87A0EFFA8731CFF8A6B36FF685E4CFF596073FF455988FF3C5698FF
+ 4360ABFF4660ACFF4763B0FF4163B6FF365CAEFF355CAAFF375DA5FF3A599EFF
+ 405DA2FF4361AEFF3F61ADFF4669B2FF3E62A8FF3657A0FF2E4F98FF2C4C95FF
+ 2E4C93FF314D94FF344E90FF344987FF34437BFF2F3B6BFF2E345DFF2F3153FF
+ 2E2F4BFF2F2D43FF312C3BFF43393FFF422F2AFF4E301DFF5B361AFF5B3414FF
+ 5C3618FF5B3921FF593A21FF5A361EFF59361CFF56341CFF52321BFF51321DFF
+ 52321BFF59341AFF593517FF583618FF563718FF57371AFF58391AFF58381BFF
+ 573819FF563619FF543516FF523215FF533415FF533316FF543516FF563619FF
+ 573819FF58381BFF59391CFF5F3D20FF5A3A1DFF53391BFF52371DFF533522FF
+ 533522FF51361CFF4D341AFF4B331DFF492E19FF4A2B16FF51321BFF51381EFF
+ 3C2D1DFF36313AFF40496EFF3A5598FF3F64B8FF3B64B9FF3E69C0FF426FC6FF
+ 3E6CC0FF3C67B8FF335AA5FF315297FF334F90FF324B89FF334A88FF334B8DFF
+ 30498FFF28438DFF233D89FF2E4590FF334991FF364C94FF3E579DFF556EB4FF
+ 657EC4FF5972B8FF4359A0FF3D5099FF374990FF37468BFF303A7AFF424B84FF
+ 616697FF5A5E87FF675D6EFF8F7156FFA3773CFFAD7C30FFB78228FFBC841FFF
+ BC821BFFBC8425FFBF8932FFAE7929FFB17C33FFBA853CFFBD883FFFB8823BFF
+ AF7B35FFB17D3BFFB88743FFB0833AFFAA8035FFA87F36FFAB833BFFA87F3AFF
+ 9D7736FF9E793BFFA38146FFA98751FFB39461FFBB9D6EFFBCA175FFCAAE85FF
+ D8BE96FFD9BF9AFFCEB692FFC7AE8CFFCEB595FFDABF9DFFDAC1A1FFCFBA9EFF
+ C7B9A3FFCDC6B7FFD4D5CBFFDFE6DFFFE7EEE9FFF2F9F2FFF8FCF6FFF9F9F3FF
+ F5F3F2FFF5F2F4FFF4F3F7FFF2F5F9FFE6EDF0FFE4EDF0FFE8F2F2FFE8F0F0FF
+ E9EFEEFFEFF0EEFFF1EDECFFFEF5F2FFEDE0DEFFE5D6D4FFF3E3E4FFFFF1F5FF
+ FDF3F9FFF7EFF9FFF6F2F7FFF3F4F0FFF1F4EBFFF0EFEBFFEFEDECFFF5F0F1FF
+ F8F3F4FFF8F3F4FFF5F0F1FFF3EEEFFFEFEAEBFFF3F1F1FFEFEFEFFFF0F2F3FF
+ F4F7FCFFEAECF4FFEAECF6FFE9EDF8FFEFF5FFFFE8EFF8FFEAF2F9FFEBF4F8FF
+ ECF4F4FFF1F9F8FFEAF1EEFFEDF4F1FFF0F7F2FFF4FAF5FFF1F7F2FFEDF3EEFF
+ F0F5F3FFF5F8F6FFF3F6F4FFF4F2F1FFF2EFEBFFF4EFEEFFF9F4F1FFFAF3F0FF
+ F4EEE9FFF5EFEAFFFEF6EFFFFFF7F0FFFBF3ECFFFBF2E9FFFAF1E8FFF9F0E6FF
+ F5ECE2FFF1E7DDFFF0E4D8FFF6E9DBFFFAEBDBFFFFF6E6FFF9E9D8FFDCCBB8FF
+ D6C3AEFFD7C2ACFFC6B097FFD5BFA3FFE0C8AAFFE7CEAEFFE1C6A4FFCEB28FFF
+ BB9E79FFAF926DFFAC8E65FFBD9C6FFFC5A375FFCAA978FFC8A573FFBE9967FF
+ B48E58FFAE884EFFAE864BFFA87F40FFA97F3EFFB08641FFBC9049FFBF9248FF
+ B98B3EFFB28437FFB28234FFAE7A2DFFB78232FFC08839FFC08938FFBC8432FF
+ B9812FFFBE8530FFC48B36FFBF8631FFBB822DFFB9812FFFB5740BFFB57509FF
+ B27408FFAE7508FFAD750AFFAE750CFFB0760FFFB2780FFFB1750BFFB07507FF
+ B37705FFB47B08FFB47D0EFFB27B12FFAE7716FF9F701FFF7B5A28FF625442FF
+ 5A6175FF485E8EFF375295FF3C59A4FF455FABFF4A69B4FF3E63B3FF3962B1FF
+ 3A64B1FF3860A8FF34559AFF36559AFF3B5BA7FF395AA9FF3C5FA8FF3A5DA1FF
+ 36589EFF33559BFF32529BFF325097FF314D94FF314B8DFF344987FF32437BFF
+ 303C6CFF2F355EFF303254FF312F4CFF302D43FF332C3BFF42363CFF402C27FF
+ 4F301BFF5A3519FF5C3515FF5E381AFF5E3C24FF5C3D24FF5B371FFF59361CFF
+ 55331BFF51311AFF50311CFF50311AFF563319FF593517FF583618FF583918FF
+ 593A1BFF5A3B1AFF5A3B1CFF593A19FF58391AFF573817FF513213FF523312FF
+ 543516FF563716FF593A1BFF5B3C1BFF5C3D1EFF5C3D1EFF5E3C1FFF5A3A1DFF
+ 55391BFF53381DFF553621FF553522FF50341CFF4C3319FF4E381FFF4A321CFF
+ 4D2F1CFF563722FF53381EFF412C17FF392D29FF373C51FF354F8BFF4166B6FF
+ 426ABDFF426EC2FF4674C8FF426EC1FF3E67B6FF365BA5FF38589AFF304B8BFF
+ 304582FF374A87FF344889FF273D84FF1F3882FF213886FF293C8DFF2A3E8CFF
+ 293D8AFF2F4691FF4861ABFF607BC5FF5F7CC6FF516EB9FF4660ACFF374E99FF
+ 3C4F98FF304387FF3C4D8CFF6577B4FF6072ADFF525980FF726466FF856849FF
+ 946F35FFA47928FFB1801AFFB88112FFBC8316FFC1871EFFB97F1FFFB57C21FF
+ B67C23FFBA8027FFB77F26FFB47E27FFB7812EFFC08934FFB88224FFB88120FF
+ B98324FFBB8729FFBA852AFFB28028FFB1802AFFB48432FFAA7A2CFFAF8036FF
+ AE8138FFA67C37FFAC813EFFB68C49FFB38B4AFFA78042FFAC854EFFB8905BFF
+ C69E69FFC7A270FFB9996EFFB09777FFB9AB95FFC9C3B6FFE3E6DDFFE8EEE9FF
+ F2F8F3FFF7FBF6FFF7F8F4FFF3F4F2FFF2F1F3FFF1F2F6FFF6F8F9FFEDF0F4FF
+ EDF4F7FFECF5F8FFE4EDF0FFEAF0EFFFF4F3EFFFF4EDE4FFE6D6C9FFD0B9A9FF
+ C5AA96FFD5BAA6FFEFD5C4FFFDE6D6FFFEEDE0FFFFF4E4FFFAF0DEFFFAF3E0FF
+ FCF3E5FFFCF2E8FFF9EEE6FFF7EBE5FFF9EDE9FFFCF0ECFFF9EEEAFFF3E8E4FF
+ F7EEEAFFF5EEEBFFF6F2F1FFF9F6F8FFF2EEF4FFF4F0F6FFF3F0F2FFF6F4F4FF
+ EFF0EEFFF7F8F6FFFAFBF7FFF4F5F1FFF5F7F1FFEBEFE9FFF2F6F0FFF3FAF3FF
+ EEF4EFFFE6ECE7FFE6EBE9FFEAF0EFFFEDF2F1FFEBEFF0FFEEF2F3FFEBEDEEFF
+ EBECF0FFEFF1F2FFF2F4F5FFF2F4F5FFF5F7F8FFFDFCFEFFF1F0F2FFF5F4F6FF
+ FBF8FAFFFBF8FAFFFAF7F9FFFAF7F9FFFDFAFCFFFFFDFDFFEFEFEFFFF6F6F6FF
+ FDFBFBFFFFFDFCFFFFFDFCFFFBF6F3FFF4EEE9FFF2EAE3FFF9F0E7FFFEF4EAFF
+ FFF8EBFFFFF5E9FFFAEDDFFFEFDFD2FFE4D4C7FFDFCFBFFFC9B8A5FFD9C6B1FF
+ EBD6C0FFEEDAC1FFE5CFB6FFD2BCA0FFC3AB8DFFBDA484FFB59976FFB89B76FF
+ BA9C73FFC9A97EFFD3B285FFBB996BFFA78557FFB79260FFB58B56FFBB8E55FF
+ BB8C54FFB3854BFFAC7D40FFAA7B3EFFB38244FFBD8A4CFFB58244FFB07F41FF
+ AE7F42FFB6750CFFB57509FFB17307FFAF7407FFAD7309FFAE750CFFB1760FFF
+ B27710FFB0760CFFB37A0DFFB67E11FFB17D13FFA87514FF996911FF8C5A0EFF
+ 7C5013FF5D3C0FFF4D3D2DFF545972FF4B6094FF385298FF3654A1FF405DA8FF
+ 4565B0FF375EADFF3762B1FF3F6BB8FF3E68AFFF385A9CFF36579CFF3758A7FF
+ 3154A4FF32559EFF36599DFF3A5CA2FF3D5FA5FF3D5DA6FF38569DFF2F4B92FF
+ 2A4486FF2E4381FF2E3F77FF2E3A6AFF2F355EFF323456FF34334DFF343246FF
+ 383140FF3D3137FF3C2823FF4B2C17FF5A3416FF5A3215FF5B3517FF5C3820FF
+ 583821FF59351DFF58351BFF55331BFF52321BFF50301DFF51321DFF57331BFF
+ 583619FF593719FF583918FF5A3B1CFF5A3B1AFF593A1BFF593A19FF593A1BFF
+ 5B3C1BFF523314FF543514FF563718FF583918FF5A3B1CFF5B3C1BFF5C3D1EFF
+ 5C3D1EFF573517FF543516FF513415FF503416FF53321EFF52311EFF4E2F18FF
+ 482F15FF4B361BFF49331AFF4F311EFF553522FF54361BFF452C12FF3B2B1AFF
+ 302F38FF31497DFF4269B4FF466FBEFF4771C4FF4B77CAFF4370C1FF3F66B4FF
+ 385BA4FF3E5B9EFF324987FF2D407DFF344683FF344687FF273C80FF223985FF
+ 2B4292FF2D4097FF2C3F96FF273C8EFF273E8CFF33509BFF4766B1FF4D6EBDFF
+ 496DBBFF4868B4FF35549FFF38549BFF314A90FF324C8FFF5F7ABDFF7190D5FF
+ 6479B6FF5D5E84FF6A5D65FF786147FF8F7033FFA77B20FFB27E13FFB57D0EFF
+ B97C0EFFBF811BFFB97C1AFFB87B19FFBC811EFFBD821FFFB77E1BFFB37C1BFF
+ B77E1BFFBA7D15FFBE8016FFBF8319FFC1841CFFBF841DFFBE831FFFBB821FFF
+ BA8020FFBB8324FFBC8628FFB88328FFB07C22FFAF7D25FFB6842CFFB5842EFF
+ B07E2CFFA47226FFAF7B34FFBF8B45FFC49454FFBA905BFFB29269FFBBA58CFF
+ C9BEB0FFF1EEE9FFEFF2F0FFF0F5F3FFF0F5F3FFEFF1F1FFEEF0F0FFEFF2F6FF
+ F4F5F9FFF6F3F5FFF2F1F5FFF3F6FBFFEEF4F9FFE6EDF0FFEEF3F2FFF4F2EAFF
+ EAE0CFFFBBA48AFFB49574FFB38C65FFBC9569FFC7A276FFCAA97CFFC9AC80FF
+ C9B086FFD7C093FFDAC49AFFE0C9A3FFE3CAAAFFDFC4A9FFD8BFA5FFDCC1ACFF
+ E3C8B3FFEED6BEFFE5D0BAFFECDAC3FFEEDDC8FFF4E4D3FFF9ECDEFFF8E9E0FF
+ FFF2E9FFFFF6EAFFFFF1E4FFF4E7D7FFFFF2E2FFFFF9E8FFFCF4E3FFFFFAE9FF
+ FCF7E8FFEFECDEFFF9F7ECFFFAF9EFFFF5F6EDFFF8FAF4FFFCFDF9FFF6F7F5FF
+ EEF0F0FFF4F6F6FFF0F4F5FFEEF0F1FFE9EDEEFFEAEEEFFFECF0F1FFEEF2F3FF
+ EFF2F6FFEBEEF2FFEDF0F5FFEFEFF5FFECECF2FFEBEBF1FFECECF2FFECECF2FF
+ E7EAEFFFECF2F7FFEDF3F8FFE2E8EDFFE1E7ECFFEEF2F7FFEFF2F6FFEAEDF1FF
+ F5F7F8FFF7F6F8FFF7F5F5FFF5F3F3FFF9F4F5FFFEF9F8FFFFFBFAFFFFFAF9FF
+ FDF8F5FFF2ECE7FFF4EEE9FFF8F2EBFFFCF4EDFFFEF5ECFFF9EFE5FFEFE5DBFF
+ EADED2FFF7E7DAFFF4E4D3FFEAD9C6FFF5E4CFFFFFF4DFFFF2DDC7FFDDC8B2FF
+ EFD7BFFFEDD3B5FFEBCEAFFFE1C2A1FFD3B390FFC7A783FFC7A67FFFD2AE88FF
+ DCB892FFCAA57FFFC5A17BFFC3A17DFFB8770BFFB7770BFFB5770BFFB3780AFF
+ B3780BFFB2790CFFB5790FFFB37910FFB57B12FFB47D15FFB17A17FFA47016FF
+ 8E5D11FF78490CFF68390DFF5C320FFF502C0EFF412F24FF4D516EFF495D96FF
+ 36519BFF3655A4FF3F5CA7FF4161ACFF355FACFF3361AEFF3867B1FF3965ACFF
+ 3A5D9FFF3D5FA5FF3C5FAFFF3459A9FF3659A2FF395CA0FF3C5EA4FF3E60A6FF
+ 3E5EA7FF38569DFF2F4B92FF2A4486FF2D4280FF2D3E76FF2C3A6AFF2F375FFF
+ 333655FF36354FFF363448FF393241FF3E3238FF3D2924FF4D2E19FF5C3618FF
+ 5B3316FF5A3416FF5A361EFF54341DFF58341CFF57331BFF55331CFF53331CFF
+ 52321FFF53341FFF59351DFF59371AFF583619FF573819FF59391CFF58391AFF
+ 563619FF573819FF59391CFF5C3D1EFF553518FF563718FF57371AFF58391AFF
+ 58381BFF573819FF563619FF583618FF563214FF533113FF513310FF503314FF
+ 54311DFF54301EFF4F3017FF492E13FF473216FF493419FF513320FF573623FF
+ 57341AFF4E3112FF452E14FF2E2928FF2C4371FF4267B1FF4970BEFF4772C3FF
+ 4C78CBFF446FC0FF3D63B1FF385AA0FF365293FF2B407DFF243671FF2C3C77FF
+ 324284FF33468AFF3A4E9BFF445AACFF4156B2FF3D53B2FF374FA7FF2E4A9EFF
+ 2C4D9DFF3056A4FF3860B2FF3C67B6FF4B72C0FF4067B1FF3E60A6FF36579CFF
+ 2B4C91FF3F63A9FF618BD6FF6A8EDCFF566AB8FF575B95FF5E5766FF766348FF
+ 977533FFAC8023FFB8801BFFBC7F17FFBB7D19FFBB7C1AFFBF801EFFC68824FF
+ C68921FFBF851CFFBB8219FFBD831AFFB77A12FFBF8117FFC08218FFBB7D13FF
+ B97C14FFBE8119FFBC8219FFB67B14FFB57B14FFB77D16FFB67F17FFB47D15FF
+ B47E19FFB9831EFFBE8823FFC08926FFC08528FFBB7C24FFB87928FFBD8338FF
+ C18E50FFCAA174FFDDC2A7FFF0E0D3FFFAF5F2FFF3F5F6FFEFF4F7FFEDF2F5FF
+ ECF1F2FFEBF0F3FFEAF0F5FFEEF1F6FFF8F1F6FFF9EFF5FFF7F5FBFFF0F3F8FF
+ E8EDF0FFF1F4F2FFECE6DBFFCFC0A6FFA78A63FFB38B56FFBA8A4AFFBB8740FF
+ B38236FFAA7C2FFFA47A2FFFA27C2EFFAD8637FFAE8739FFB28940FFB78C49FF
+ B6894CFFB2864BFFB48650FFB98D57FFBB925BFFB38E56FFBD9963FFBF9F6AFF
+ C8A877FFD2B386FFD5B78EFFE4C4A0FFF3D2B1FFEBCAA9FFD9BA9BFFDDC0A1FF
+ E3C7A8FFE2C8AAFFE7D2B3FFE2CFB4FFDAC9AFFFF4E6D0FFFFF6E4FFFDF3E2FF
+ FAF1E4FFF9F0E6FFF7F0E7FFFAF4EDFFF4F2EAFFF8F9F0FFFAF8F0FFF0F1E8FF
+ EDEDE7FFF2F2ECFFF4F3EFFFF2F0EFFFF5F3F2FFF7F5F5FFF4F4F4FFF1F1F1FF
+ F2F1F3FFF6F5F7FFF6F5F9FFEFF0F4FFE3E8E9FFE9EEEFFFEBF0F1FFEDF2F3FF
+ F3F7F8FFF6FAFBFFF2F6F7FFF2F4F5FFF9FBFCFFF7F6F8FFF3F2F4FFF1F0F2FF
+ F5F2F4FFF7F4F6FFF7F4F6FFF5F4F6FFFBFFFFFFF4FAF9FFEFF5F4FFF0F5F4FF
+ F4F9F8FFFAFCFCFFFAFCFCFFFBFBFBFFF8F9F7FFF7F5F4FFF3F0ECFFF8F5F1FF
+ FFFFFBFFFCF7F4FFF4EFECFFFCF7F4FFFFFAF5FFFFF7F0FFFAF1E8FFF2E8DEFF
+ EFE3D7FFF3E6D8FFFBEEE0FFFFF5E5FFF3E4D4FFEEE1D1FFEEE1D3FFB8760DFF
+ B8770EFFB87A10FFB87B13FFB67B14FFB47915FFB17717FFAE7518FFAB7419FF
+ A5731BFF9B6A1AFF875B14FF72470EFF5F370DFF583014FF57301AFF563319FF
+ 473126FF4B4E6AFF4A5C91FF385298FF3A57A2FF435EA8FF4262ABFF3C64AFFF
+ 3460ADFF305FA9FF305CA3FF345B9FFF4164ADFF456ABCFF3F64B6FF3F64AEFF
+ 3E62A8FF3A5EA4FF395AA3FF3657A0FF33539AFF2F4E93FF2F4A8DFF304583FF
+ 30417AFF2E3C6DFF303762FF333557FF34324FFF333046FF362F3EFF45373BFF
+ 433028FF51341FFF5F3A1EFF5D351CFF5C341BFF58361EFF54341DFF54321AFF
+ 55331BFF55331BFF54341DFF54351EFF54351EFF55361DFF58361EFF543319FF
+ 563619FF57371AFF553518FF533316FF543417FF58381BFF5B3B1EFF57371AFF
+ 57371AFF58381BFF57371AFF563619FF533316FF513114FF4F2F12FF543417FF
+ 533316FF513316FF53351AFF573420FF573420FF54321AFF4F3217FF493115FF
+ 4E351BFF573823FF5B3922FF5C381AFF593817FF503416FF362822FF343F65FF
+ 4C67A7FF5070BBFF4A70C2FF4D76CBFF446CBEFF3F62ACFF3D599AFF31457FFF
+ 273871FF1F2D68FF223072FF2C3E85FF3C509DFF4C66B3FF5773C7FF4C6BC6FF
+ 4A6BC8FF4B69C0FF4464B7FF3A5DADFF375EADFF3B68B9FF4574C5FF416FBDFF
+ 4873BCFF446BAFFF4268A9FF2C5195FF21478FFF436CBBFF5C83D8FF6B8AE7FF
+ 576CBDFF485583FF53525BFF736144FF8D6E31FFA27322FFAD7516FFB97B17FF
+ BB7912FFBC7A13FFBE7D14FFB97B0FFFB3780BFFB77C0FFFBE8316FFBC7E12FF
+ C4861CFFC1821AFFB4770FFFB4770FFFBC8218FFBF8417FFB67B0EFFC0841AFF
+ BE841AFFBE861BFFBC861BFFB88419FFB98318FFBE861BFFC68A20FFCB8922FF
+ BD7918FFB4761CFFBE8639FFCF9F65FFE0BA90FFF4D9C4FFFFF3EAFFFAF4F5FF
+ F4F4FAFFF1F4FCFFF0F6FDFFF0F4F9FFEBF1F6FFE7EDF2FFE7EAEFFFFBF4F9FF
+ F9F1F8FFF7F4FDFFEEF0F8FFE9ECF0FFF6F3EEFFE7D9C6FFBCA27DFFB28D55FF
+ C08F49FFC48E3BFFBF862BFFB87F22FFB78122FFBC882AFFC28E30FFB88524FF
+ B3801FFFB47E20FFB88329FFBA8230FFB77F2EFFB77F30FFB98434FFB17E2EFF
+ A77628FFAC7C2EFFA87A2DFFA67930FFA87C35FFA87D3AFFB68A4BFFBA8D50FF
+ B68A4FFFA97C43FFAC8148FFB18851FFAE8750FFAE8A54FFA27F4DFFAF8F5EFF
+ D5B689FFE3C89CFFD0B68EFFBEA480FFBCA381FFD0B797FFE5D0B1FFD6C6A9FF
+ E5D7BBFFEEE0C4FFE6DABEFFE4D7BDFFEEE2CAFFF5E8D2FFF1E6D2FFF9EDDBFF
+ FDF3E2FFFDF4E6FFF9F0E2FFF8F0E3FFFDF4EAFFFFF6ECFFFBF4EBFFF2EFE7FF
+ F6F4ECFFFDFBF3FFF8F6EEFFF1EDE8FFFAF6F1FFFFFDF8FFF6F2EDFFEFEAE7FF
+ F1ECE9FFF3EFEEFFF5F0F1FFF3F0F2FFF3F0F2FFF1F0F4FFF0F1F5FFE3E8EBFF
+ E2EBEEFFE7F0F3FFEAF3F6FFECF3F6FFEAF1F4FFE7EEF1FFE5EBF0FFEAF0F5FF
+ EDF3F8FFF5F9FEFFF5F9FEFFEFF2FAFFF1F4FCFFF6F9FFFFF5F8FFFFEFF3F8FF
+ F1F4F8FFF5F7F8FFF6F8F8FFF7F7F7FFF6F7F5FFF8F6F5FFF9F8F4FFFCFAF9FF
+ F9F7F6FFF7F8F6FFB7740DFFB7750FFFB87715FFB47618FFB0741BFFA76C1CFF
+ 9D661BFF96611EFF875618FF7D5017FF6E4713FF613F11FF573811FF513415FF
+ 4E3319FF503219FF59371AFF4A3022FF3E3D4DFF4F5D87FF445A94FF334D8FFF
+ 465DA1FF4B65ABFF4565B0FF3E65B0FF3966B0FF3865AEFF3A64ABFF3960ABFF
+ 375CB0FF365BAFFF365CAAFF365BA5FF3C61ABFF3F62ABFF3457A0FF305298FF
+ 2F4E93FF2B4689FF304485FF334280FF353F75FF333968FF313258FF2F2F4DFF
+ 332F48FF3C3242FF463839FF422F22FF4F351DFF5D3E25FF5A3422FF512B19FF
+ 512E1AFF52331AFF593B20FF583A1FFF59381EFF58381BFF553917FF533816FF
+ 50341CFF4F321DFF53361BFF543619FF543619FF55371AFF56381BFF57391CFF
+ 583A1DFF583A1DFF523417FF543619FF56381BFF57391CFF56381BFF543619FF
+ 513316FF4E3116FF4B3218FF4C311CFF4E3122FF523324FF563424FF593622FF
+ 58371DFF58381BFF52331AFF57381FFF5B3921FF59371AFF593817FF5C3A1CFF
+ 55351EFF432A26FF3B3148FF474D7CFF566BAFFF5171C4FF456DC6FF486DC1FF
+ 4360A3FF2F437AFF2F3667FF23275AFF202667FF2A3783FF374CA1FF4B67BEFF
+ 5D7FD3FF6088DBFF5485D5FF6091DFFF618BD8FF5C83CEFF5F86D1FF5077C5FF
+ 3A67B8FF3E6DBEFF4272C0FF4B7BC3FF527CBFFF5076B7FF4465AAFF2F4F98FF
+ 3351A2FF4D6DC0FF658ADAFF678CD6FF5171B2FF435A88FF545B6FFF635A4DFF
+ 80612EFFAB7C2BFFAD730CFFC58312FFC38110FFBC7A09FFBD7E10FFBB7B0FFF
+ B97A0CFFC08111FFBD7F0DFFB87C0BFFB5750FFFB47715FFB9811CFFBC851CFF
+ B88210FFB47C0BFFBD7F13FFBE8119FFBA831BFFB4841BFFB7891EFFBD8D23FF
+ C48B22FFC5841BFFCF8A1BFFC18017FFB57F28FFAF823EFFAF8E60FFCEB89CFF
+ F7E7DBFFFFFAF7FFF5EFF4FFF3F0F9FFF2F3FDFFF3F5FFFFF3F4FEFFF0F2FAFF
+ EBEEF2FFEAEBEFFFEAE8EEFFEEEDF7FFE9EDF8FFEDF3FAFFFAFAFAFFEEE5D8FF
+ D4BB99FFC9A36DFFBF8E44FFC28C35FFBF8728FFBD8421FFBD8421FFBE8320FF
+ BF7F20FFBD7D1EFFBA7F1CFFB9801DFFBC811EFFBB8121FFBC8223FFBE8425FF
+ BF8427FFBF8427FFBA8124FFBA8124FFB98023FFB57F21FFB27B20FFB37C21FF
+ B58026FFBA852BFFB37E23FFB17E22FFB07D21FFB38024FFB78329FFB8862CFF
+ B7852DFFB4832DFFAD7B28FFAC7D29FFAD7D2BFFAD7E2DFFAE7E30FFB07F33FF
+ B18034FFAD8037FFAF8544FFB79052FFBF9A5CFFC19C60FFC2A065FFCBA973FF
+ D6B681FFDBBB8AFFD3B788FFD4B98DFFE1C89EFFF2DCB3FFF3DEB8FFE7D1ADFF
+ E1CDAAFFE6D2B3FFF2DFCAFFF7E6D3FFFFF2E0FFFFF7E5FFFEE9D4FFE9D4BFFF
+ E7D1BFFFF0DCCBFFFFECDDFFFBEBDEFFFBEFE5FFFFF6EFFFFEF6F6FFF7F2F3FF
+ F4F0F5FFF4F2F8FFF1F1F7FFEDF0F5FFECEFF3FFEDF0F4FFEFF4F5FFF0F5F6FF
+ EEF3F4FFEBF0F3FFE8EDF0FFEEF3F6FFF3F9FEFFEEF4F9FFE5EBF2FFEAEFF8FF
+ EFF4FDFFEAEDF5FFECF0F1FFEBEDEDFFECEEEEFFF1F3F3FFF2F4F4FFEFF1F1FF
+ EEF0F0FFF1F4F2FFF0F2F2FFEEF0F0FFF4F6F6FFB97924FFB27420FFA76A1AFF
+ 995F13FF8E5510FF834D0EFF7A470FFF734313FF673C11FF603913FF5A3715FF
+ 523516FF4F3419FF4E351BFF4C361DFF50371DFF573518FF492F1EFF3D3742FF
+ 4F5879FF4B5F8FFF3A4F8CFF42589AFF4760A6FF4663AEFF3F63AFFF3A64AFFF
+ 3A67B1FF3E69B2FF4067B5FF3F64B8FF3E63B7FF4368B8FF3D64AFFF4065AFFF
+ 4167AFFF3B5EA7FF395BA1FF355499FF2D488BFF304386FF334281FF353D78FF
+ 333869FF30325BFF302F4FFF342F4AFF3C3242FF463937FF433021FF4B341AFF
+ 573A1FFF56301EFF532C1DFF57321CFF58371DFF57391EFF56381BFF58371DFF
+ 573819FF543A12FF533914FF4E341CFF4E331FFF54361DFF56381BFF57391CFF
+ 583A1DFF57391CFF56381BFF543619FF533518FF503215FF503215FF513316FF
+ 513316FF513316FF503215FF4F3114FF4E3116FF4A3117FF49311BFF4B3121FF
+ 4F3223FF523421FF54351EFF553518FF553518FF502F15FF523018FF53351AFF
+ 533719FF523614FF553413FF5A3618FF573626FF55444FFF4D496DFF4B5692FF
+ 475EAAFF3D5BACFF3C59A4FF3C4E89FF313B6AFF272951FF1F1F4DFF252A67FF
+ 404C94FF5B6FBDFF738AD8FF7E98DEFF7698D4FF779ED5FF6A92C6FF5375ABFF
+ 506DA6FF6884C1FF6C8ACBFF5C7EC4FF557CC6FF4F79C4FF527DC6FF557EC3FF
+ 567DC1FF4E71B5FF36569FFF2E4A97FF3958A3FF567DC1FF6590D3FF5D88D1FF
+ 4D71B7FF4B659BFF505B77FF655B51FF856A3EFF9C722BFFAB761FFFAA7116FF
+ AC7213FFB57B1CFFBB801DFFBB8118FFBD8417FFBE8518FFC1871DFFC1801EFF
+ B67617FFB37713FFB87F16FFBC8516FFBD8516FFBF8117FFBD7F19FFB57D18FF
+ AC7C13FFAE8015FFB5851CFFBF8420FFC2801AFFC68316FFC5851FFFAA7826FF
+ 997539FFB39B77FFE3D3C2FFFAF0E9FFF4EEEFFFF1EAF1FFEFECF5FFEFEDF9FF
+ EFEFFBFFF1F2FCFFF2F5FAFFF4F6F7FFF4F6F7FFEBEDF5FFECEEF8FFE9F0F9FF
+ F2F6FBFFF8F5F0FFE1D3BDFFC5A378FFB98B4BFFC28A38FFC58929FFC0861FFF
+ BD841BFFBC821BFFBE801CFFC27D1CFFC17C1BFFBF811DFFBD821BFFBD821BFF
+ BD821BFFBE831CFFBE831CFFBE831CFFBF841DFFBF841DFFBE831CFFBD821BFF
+ BB8019FFBA7F18FFBA7F18FFBD821BFFBF841DFFB98116FFB88013FFB88015FF
+ BA8217FFBE861BFFC0881DFFC0871EFFBE851CFFBC831AFFBC821BFFBC821BFF
+ BD831CFFBD821EFFBD821EFFBD821EFFBB821FFFB17A1FFFB47E27FFB57F28FF
+ B07A25FFAD7B28FFB07F2FFFB28234FFAE8137FFAA7F36FFA67D38FFAA8241FF
+ AF8B4BFFAF8C4DFFA9874BFFAB894DFFB08E58FFB69568FFBC9971FFC8A57DFF
+ D2AF84FFCBA87DFFC09D71FFC59F75FFD1AD85FFD9B891FFDCBE9BFFE8CEB0FF
+ F9E2C8FFFFEED9FFFEF0DEFFFCEFE1FFFCF0E6FFFDF1EBFFFCF1EDFFFDF3ECFF
+ FFF5EEFFFFF9F0FFFFF8EFFFF9F4EBFFF6F0E9FFF5F1ECFFF1EEE9FFF9F6F2FF
+ FCFAF9FFF4F2F2FFEFECEEFFF0ECF1FFEEEBEDFFF7F4F0FFF4F1ECFFF5F2EDFF
+ F7F6F2FFF4F4F4FFEEF0F1FFECF0F1FFF1F5F6FFE9ECF0FFE6EAEBFFEEF0F1FF
+ 935E25FF8E5920FF824E19FF774511FF6D3D0DFF67370DFF62350FFF5F3413FF
+ 5C3515FF593418FF57341AFF52331AFF4E3319FF4C321AFF4B3119FF4D3218FF
+ 563417FF492D1CFF373035FF484F6AFF51618FFF3F558FFF3C5294FF415AA2FF
+ 4463AEFF3E62AEFF3B64ADFF3B66AFFF416AB3FF426AB5FF4066B8FF3E63B5FF
+ 4C72C0FF4367B3FF4065AFFF4066AEFF3D60A9FF3C5EA4FF38579CFF2E498CFF
+ 314487FF334281FF333E78FF34396AFF31335CFF313050FF34314BFF3B3443FF
+ 453939FF423225FF4A3418FF523516FF542E16FF593019FF60381FFF5C3A1DFF
+ 563619FF543619FF56351BFF563718FF563914FF543815FF53341DFF50321FFF
+ 57381FFF583A1FFF5A3C21FF5A3C21FF583A1FFF55371CFF513318FF4F3116FF
+ 503217FF503217FF4F3116FF4F3116FF4F3116FF503217FF513318FF523417FF
+ 4E3013FF4F3315FF4B3617FF4C3819FF4D371BFF50351AFF513316FF513213FF
+ 4E3112FF4B3113FF483219FF49341EFF4A3216FF50330CFF6A450DFF725227FF
+ 655354FF433E5DFF363A6BFF36417BFF303D7BFF29356FFF2A2F5CFF25264CFF
+ 18183CFF2C2B55FF4E5489FF6E76B1FF717BB1FF69729EFF626885FF595F72FF
+ 3B404FFF323845FF1D1E32FF151630FF2D2F51FF454B76FF576498FF6A7DBAFF
+ 5E7BBEFF5A7DC6FF5B82CCFF6089D2FF5E86CEFF456CB1FF2B4E90FF204382FF
+ 395E98FF547BB9FF638DD4FF5781CCFF466BB5FF3E5B98FF435279FF4E4E5EFF
+ 6D5D57FF80644CFF936D4AFF9D7241FF9B6C2EFF9F6E22FFA6771CFFA77717FF
+ A27115FFB27B20FFC38024FFC27A1CFFBE7715FFC17F18FFC2841EFFBD831CFF
+ BD801EFFBE811FFFB97F18FFB37C13FFB37F14FFB9841CFFBD8023FFBC7B1FFF
+ BC7A1BFFC0842BFFAA7C35FFA88553FFD3BDA1FFFFEFE2FFFEF5F1FFF1EAEDFF
+ F7F1F6FFF2EFF8FFEFEEF7FFECEEF6FFECF0F5FFEEF1F5FFF2F4F4FFF3F5F5FF
+ F0F3F8FFEBEDF5FFEBEFF4FFF9FAF8FFF9F1E4FFD7C2A6FFB28F5DFFA77932FF
+ BD842EFFC08522FFBC821BFFBB8118FFBA7F18FFBC7E18FFC07C17FFBF7B16FF
+ BF821AFFBD831AFFBC8219FFBC8219FFBB8118FFBB8118FFBB8118FFBA8017FF
+ BE841BFFBC8219FFBB8118FFBA8017FFBB8118FFBB8118FFBA8017FFB97F16FF
+ B87E15FFB77D13FFB77D14FFB97F15FFBC8218FFBD8319FFBD8319FFBC8218FF
+ BE841AFFBE841BFFBD831AFFBC8219FFBB8118FFBA8017FFB97F15FFB97F15FF
+ BE8218FFBC7F17FFB97C14FFB47912FFB67A16FFB87D19FFB47B18FFAD7615FF
+ B27C1DFFAE791EFFAD791FFFAB7921FFA97921FFA87923FFAC7D27FFB1812FFF
+ A6752BFFA7752DFFAE7D33FFB68438FFB38135FFAC7A2EFFB37F33FFBD8A41FF
+ A87830FFA87B37FFB08645FFBE965BFFC8A56DFFCDAD78FFD5B584FFD9BC90FF
+ EECFB0FFEACCB1FFE8CAAFFFEACCB1FFEFD2B7FFF4D9BEFFF8E0C4FFFAE3C9FF
+ E5CFB6FFDBC6B1FFEAD6C4FFFFF5E4FFFFFDF0FFFFF4E9FFFEEDE4FFF9E9DDFF
+ FAEADDFFFBEEE0FFFEF4EAFFFFF8F4FFFBF7F6FFF1F0F4FFEDEFF7FFF0F3FBFF
+ ECEEF8FFEAECF4FFF6F5F9FF623710FF613712FF623813FF613916FF613817FF
+ 5E3619FF5C3519FF5A351BFF5E3A22FF5B3921FF5A3820FF56371EFF53361BFF
+ 4F3419FF4E3318FF4F3217FF55341AFF4B2F1EFF372B2BFF434458FF56628AFF
+ 485C93FF374E92FF3D58A2FF4464B0FF3E62AEFF3A63ACFF3B64ADFF3D66AFFF
+ 3C64AFFF395EAEFF3659A9FF476BB9FF3E62AEFF3B60AAFF395FA7FF3457A0FF
+ 34569CFF345398FF2F498FFF2F4488FF314281FF333E78FF333A6CFF33355EFF
+ 343353FF35324CFF393344FF41383BFF423428FF49371AFF4F3412FF522D11FF
+ 5C3418FF613A1EFF59371AFF523419FF513419FF523419FF553617FF553813FF
+ 563815FF56341DFF543320FF583920FF593B20FF593B20FF583A1FFF57391EFF
+ 54361BFF523419FF503217FF523419FF523419FF53351AFF53351AFF54361BFF
+ 54361BFF55371CFF57361CFF543215FF513415FF4E3815FF4C3916FF4C3819FF
+ 4E361AFF513318FF513114FF523614FF4D3517FF47351EFF45331CFF4A3214FF
+ 5E3E0DFF835C0EFF916E2EFF6A5851FF413C57FF31335CFF2C3365FF20285DFF
+ 171E4FFF1C1D43FF1D1B39FF292640FF3A3653FF515274FF57577BFF3E3E5CFF
+ 28263AFF292227FF2F231FFF26150CFF36231BFF33221FFF241519FF1C0E1AFF
+ 180F24FF232040FF353A67FF5C6BA3FF5E76B8FF6182CBFF638AD4FF648ED5FF
+ 547EBFFF3B619BFF24487EFF28477AFF3B5992FF5073B5FF547BC5FF466FBEFF
+ 3F65B3FF3F5FA1FF3D5289FF474F77FF5B5872FF7A6C78FF8A746FFF896E59FF
+ 977C57FFA68B58FFA08447FF9A7737FFA4762FFFB97B27FFC88022FFCA801AFF
+ CB841CFFC28622FFB7801FFFB47B1EFFB77E21FFBC811DFFBA8118FFBD841BFF
+ BD8520FFBA7F22FFB37620FFB97D29FFB78239FFBC9158FFD6B790FFFAE5D0FF
+ FFF6EEFFF9F1F1FFF5F0F2FFF6F2F7FFF3F1F7FFEFEFF5FFEBEFF4FFEBF0F3FF
+ ECF2F1FFEFF4F2FFF0F5F3FFF1F4F8FFEBECF0FFEFEFEFFFFCF7EEFFF4E6CFFF
+ CFB68EFFB08B4FFFAC7B2FFFB98227FFBD821FFFBC811AFFBA8017FFB97E17FF
+ BB7E16FFC07E15FFBF7E15FFBD8215FFBA8114FFBA8114FFBA8114FFB98013FF
+ B98013FFB98013FFB98013FFBC8316FFBA8114FFB98013FFBA8114FFBC8316FF
+ BB8215FFB87F12FFB47B0EFFB87E15FFB87E15FFBA7D15FFB97F16FFBC8016FF
+ BB8117FFBD8117FFBB8215FFBE8316FFBC8316FFBD8215FFBA8114FFBB8013FF
+ B87F12FFB97E10FFBB7F0EFFC18210FFC2800FFFBE7F0DFFBF800EFFC18111FF
+ C38414FFC28313FFBE8113FFBD7F13FFBC8114FFBA8016FFB97F16FFB87E15FF
+ B98017FFBB8118FFB97F18FFBE8222FFBA8021FFBD8121FFC08522FFBE811FFF
+ B97D19FFBA7E1AFFC08321FFB97F1FFFB1781BFFAB761CFFAB7822FFAC7C2AFF
+ AD7F31FFB2883BFFB98F4AFFAF8147FFAD7E48FFAB7B47FFAC7E48FFB18550FF
+ B98F5AFFC19964FFC49F6BFFAE8A5AFF9F7D4FFFB08E63FFD7B78EFFECCCA8FF
+ EDCDAAFFE4C5A4FFDDBE9DFFCFB091FFD7BB9DFFE7CDB5FFF5DFCDFFF6E6D9FF
+ F1E5DFFFEFE8E5FFF4EFEEFFF2ECEDFFF7F0EDFFFFF9F3FF4D2C12FF4E3015FF
+ 523419FF56381DFF583920FF583920FF56371EFF54351CFF57381FFF56381DFF
+ 55371AFF543718FF553917FF573D19FF593F1BFF5C401EFF563619FF4E331FFF
+ 3C2A23FF3E3A45FF565D7EFF4F6295FF385295FF3957A4FF4565B1FF4064B0FF
+ 3D65ADFF3D67AEFF3D66AFFF3B63AEFF395DABFF3559A7FF3B5FABFF375BA7FF
+ 395EA8FF355BA3FF2C4F98FF2C4E94FF335198FF354F95FF2F4488FF314281FF
+ 333E78FF343B6DFF363861FF343557FF34324FFF373346FF3E383DFF3F352BFF
+ 48371CFF503715FF533113FF593517FF5A371DFF4F3017FF4E321AFF4C321AFF
+ 4F341AFF533518FF573714FF5A3715FF5B341EFF593420FF5A3820FF57391EFF
+ 55371CFF54361BFF53351AFF53351AFF54361BFF55371CFF4F3116FF513318FF
+ 54361BFF56381DFF56381DFF55371CFF54361BFF55341AFF57331BFF56341CFF
+ 52381AFF4E381CFF4E361EFF51341FFF55321EFF55331BFF513517FF50381AFF
+ 4B351CFF463014FF54360DFF724D0FFF9C6E0FFFA17A2CFF6A574AFF49445FFF
+ 3D416AFF303B6DFF1C2B63FF162455FF1F284AFF28293EFF433D48FF3C3336FF
+ 392E31FF382A2EFF2A1F22FF281B1DFF2E211FFF35241BFF371E0EFF432716FF
+ 42281AFF39221AFF301B19FF281419FF23121FFF201731FF3E4068FF505D91FF
+ 627BBBFF6485CAFF5C83C7FF5980BEFF4D72A6FF3E5C8BFF374B7BFF344578FF
+ 3F558FFF506CADFF5273BCFF5279C4FF557CC7FF5073BCFF4966A9FF485D9AFF
+ 536094FF5E648FFF717592FFA1A5B8FFC0C5CEFFBBBAB6FFB6A892FFAA895CFF
+ AF7A31FFC17F20FFC88314FFC78514FFBE8621FFB48123FFAB7A24FFB07D27FF
+ B77E21FFBA7F1CFFBC821BFFBF8722FFB78423FFAE7C24FFBC8A42FFB78A51FF
+ D0AD82FFF6DEC2FFFFF2E5FFFBF2EFFFF6F0F1FFF3EEF0FFEDE9EEFFECEBEFFF
+ EAEDF1FFECF1F4FFECF4F4FFEEF7F4FFF1F8F3FFF3F9F4FFF0F3F7FFF2F1F3FF
+ F9F3ECFFF6EBD7FFDCC6A2FFBA9B64FFAE843DFFB6832DFFB88021FFBC811DFF
+ BD821BFFBD7F19FFBC7F17FFBE8016FFC18115FFC18214FFB97F0EFFB97F0EFF
+ BA800FFFBA800FFFBA800FFFBB8110FFBB8110FFBB8110FFBC8211FFBA800FFF
+ BA800FFFBB8110FFBD8312FFBD8312FFB97F0EFFB57A0CFFBB7F15FFBC7F17FF
+ BE8016FFBC8016FFBE8016FFBC8016FFBF8115FFBD8214FFBC7F11FFBA7F11FF
+ BC800FFFBA800FFFBC800EFFBA810EFFBC800EFFBC800EFFBA7B08FFBE7D0AFF
+ BF7E0BFFC07F0CFFBE7D0AFFBA7B08FFBB7C09FFBE7F0CFFBC7D0AFFBD7E0BFF
+ BE7F0CFFBD7E0BFFBE7F0CFFBF800DFFC1800DFFBC7D0BFFBF8010FFBE7F11FF
+ C08010FFC38412FFC58312FFC2800FFFC1800DFFC38110FFC78717FFC08315FF
+ BC8016FFBB8219FFB57F1AFFAD7817FFA87616FFAA771BFFAC731DFFB17620FF
+ B47824FFB57C26FFB77E29FFB7802BFFB7812CFFB3812EFFC0903EFFAD7E2DFF
+ A87A2DFFAF8238FFAF833CFFAE813DFFAB803DFFA5793AFFAD7E41FFB58650FF
+ C29766FFCEA97DFFD0B08CFFCEB293FFD0B99FFFD6C2A9FFDDC8B2FFE9D2B8FF
+ F8DCBDFF4F331BFF50351BFF50341CFF51361CFF52361EFF55371EFF56381FFF
+ 573A1FFF533719FF533617FF523614FF523613FF533813FF563C14FF593F17FF
+ 5B401BFF543619FF523421FF432D21FF3B3032FF4E526BFF556492FF3D5799FF
+ 3858A4FF4160AFFF4163AFFF4268B0FF426BB0FF416BB2FF3F68B1FF4064B0FF
+ 4062AEFF375BA7FF365AA6FF3B60AAFF385EA6FF2D5197FF2D4F95FF37559CFF
+ 3C569CFF304589FF304283FF323D79FF333B70FF363965FF35375AFF363451FF
+ 353347FF3D3841FF3C322BFF43351EFF4F3A1AFF523617FF553518FF52341BFF
+ 4A2D18FF4B321EFF4B331DFF50351BFF523617FF583815FF5B3816FF5D341DFF
+ 5B3320FF58361EFF54361BFF523419FF503217FF503217FF523419FF55371CFF
+ 57391EFF4C2E13FF4E3015FF513318FF53351AFF54361BFF523419FF4F3116FF
+ 4D2F14FF57361CFF57361CFF53361BFF53351CFF53341FFF543520FF583521FF
+ 583521FF503219FF4F3419FF4B3015FF4E300DFF633F0FFF855B1AFFA4721AFF
+ 9B712EFF5B4E46FF454966FF434C77FF384677FF223267FF1D2D5CFF2A3355FF
+ 343549FF413A3DFF372A22FF322114FF382413FF3B2414FF3F2818FF422C1AFF
+ 422A14FF533316FF512D0FFF432208FF3C1E05FF3E1F08FF3E200DFF3A1F11FF
+ 311C1AFF1E1421FF373957FF5B6B9AFF6882BEFF5E80C2FF5379BAFF496EACFF
+ 3F5D96FF475589FF354072FF324179FF405592FF4865A8FF4F75BDFF5983CEFF
+ 5A88D5FF5F8BD8FF537BC6FF4C6DB6FF415EA3FF4B62A0FF8094CDFFAFC4F7FF
+ C1CDF1FFB5B0B9FF9D856FFF9E7235FFB57B22FFBD7D11FFBC7D0DFFB6801BFF
+ AF7E22FFB88935FFB98734FFBA8229FFB97E21FFBC8222FFC38C29FFC0912FFF
+ B78B37FFBE9459FFC19E73FFE0C3A8FFF6E4D3FFF6EAE4FFF6F0F1FFF8F3F5FF
+ EDE7ECFFEEEBEDFFEEEDEFFFEDF0F4FFECF3F6FFEDF5F5FFEBF6F3FFEBF6EEFF
+ ECF3EEFFEFF4F3FFFBF8F4FFFEF3E5FFE5D1B2FFBA9C6BFFA37E3AFFAA7B29FF
+ B68224FFB9801DFFBD821BFFBF811BFFC0801AFFBF8018FFC08014FFC18212FF
+ C08412FFB87F0CFFB87F0CFFB9800DFFB9800DFFBA810EFFBA810EFFBA810EFF
+ BB820FFFB9800DFFB9800DFFBA810EFFBB820FFFBC8310FFBC8310FFBA810EFF
+ B87E0DFFBD7F13FFBE8016FFBF8117FFBE8014FFBD7F13FFBC7E12FFBD8012FF
+ BE8211FFBA7E0DFFBA7E0CFFBB7F0DFFBB800CFFBC810DFFBC810DFFBD820EFF
+ BF820EFFBA7C0AFFBC7D0BFFBF800EFFC28310FFBF800EFFBC7D0AFFBE7F0CFF
+ C2840EFFC98913FFC5850FFFC3830DFFC4840EFFC8860FFFC98710FFCB8912FF
+ CC8914FFBD7E0BFFBD7E0BFFBF800DFFC3830DFFC2820CFFC17F08FFC07E07FF
+ BF7D06FFC2820CFFBF800DFFC28412FFC78A1CFFC38A1DFFBD851AFFB68119FF
+ BA831BFFBC7C16FFC07E18FFC3811BFFC3831DFFC3831DFFC1831DFFC2841EFF
+ C1861FFFC28723FFBB821FFFB98221FFB47E20FFAC751AFFAE761DFFB68029FF
+ B9802BFFB67A28FFB4792AFFB57C31FFB3803AFFAE8040FFA97F44FFAB854FFF
+ B28D59FFA8834FFFB18B55FFBE9459FF533719FF533718FF513517FF513516FF
+ 513517FF543718FF56391AFF583B1CFF573B19FF593A19FF583A17FF573A15FF
+ 563914FF553811FF553811FF523613FF523419FF533621FF492F1EFF36261FFF
+ 444353FF56628AFF445D9DFF3858A3FF3B5BA7FF3F62ACFF4569AFFF456CB1FF
+ 416BB2FF4067B1FF4467B1FF4568B2FF3A5EAAFF375BA7FF3A5FA9FF395FA7FF
+ 31559BFF33559BFF3959A0FF3B589DFF2E4589FF304283FF323D79FF333B70FF
+ 353A67FF35385EFF353553FF353349FF3F3845FF372D2DFF3F311FFF4B3A1FFF
+ 4E391AFF4D3519FF4C341EFF49311DFF4C3422FF4D351FFF51361BFF553917FF
+ 5B3915FF5D3816FF5D341DFF5B3320FF56341CFF53341BFF513219FF503118FF
+ 503118FF513219FF52331AFF53341BFF4F3017FF503118FF513219FF52331AFF
+ 513219FF503118FF4F3017FF4E3013FF543917FF533715FF533316FF543117FF
+ 543117FF57331BFF56371EFF593922FF53321FFF4F2D16FF512D0FFF633B11FF
+ 7D521FFF93642CFF9C6931FF86613FFF51515DFF3C4D74FF425280FF3C4B7CFF
+ 293768FF242F5BFF2C3255FF34354AFF352E35FF2D211BFF2F1D0CFF382107FF
+ 3F2203FF492905FF58350DFF5E390DFF61370AFF623809FF633B0BFF623C0CFF
+ 623A0AFF5E3606FF563204FF4B2B07FF371F0BFF302626FF444860FF5E719EFF
+ 5E7CBDFF4F75C3FF3E67BCFF385CAAFF495896FF434A81FF35417BFF314382FF
+ 304A8CFF36599DFF456FB6FF4E7EC6FF5D91D8FF5A8DD6FF598AD4FF4A74BFFF
+ 385BA5FF4562ACFF6880C8FF8794CCFF88859FFF7E6B63FF916D3DFFAD7D2FFF
+ B37919FFB1770EFFB27B1AFFAE791EFFC39139FFC28D36FFBF852CFFBA7E24FF
+ BC8026FFC18B2DFFBF9231FFB48E3CFFB89766FFCEB398FFEBD7C6FFF4E7DFFF
+ F0EAEBFFF3EFF4FFF5F1F6FFF0ECF1FFF3F0F2FFF2F1F3FFEFF2F6FFEDF4F7FF
+ EBF3F3FFE7F2F0FFE6F0EAFFE6EEE7FFF2F5F3FFF8F3EAFFF1E1CAFFCDB188FF
+ A98446FFAA7C2EFFB68325FFB47E19FFB97F18FFBC811AFFC1811BFFC2801AFF
+ BF7E15FFBE7F11FFBF820EFFBE840DFFBA810DFFBA810DFFBA810DFFBA810DFF
+ B9800CFFB9800CFFB9800CFFB87F0BFFB77E0AFFB9800CFFBA810DFFBB820EFF
+ BB820EFFBB820EFFBC830FFFBD8411FFBB7E10FFBF8012FFC08113FFBF8012FF
+ BC7D0FFFBA7B0BFFBB7C0CFFBD7F0DFFBC7E0CFFBC7F0BFFBD800CFFBD800CFF
+ BE810DFFBE810BFFBE810BFFBC810DFFB87B0DFFB3780BFFB4790CFFBA7F11FF
+ BE8014FFBB7E10FFBC7D0FFFBE7F0FFFC28212FFB97909FFB67705FFBC7D0BFF
+ C07E0DFFBD7B0AFFBE7D0AFFC18210FFC18416FFC08518FFC08518FFC18416FF
+ BF8214FFBF8010FFBE7F0FFFBE800EFFBA7B0BFFB57908FFB4790BFFB77D13FF
+ B98017FFB78018FFB8831BFFC08823FFBC7B18FFC07C19FFBF7B16FFBD7B15FF
+ BD7B14FFBF7E15FFC5841BFFC9881FFFB87A10FFB87911FFBF7F19FFC0821CFF
+ B97B17FFBA7B19FFC48321FFC48321FFC17F19FFBD7B15FFB97815FFB87B1BFF
+ B67B1EFFB17920FFB47E27FFBA842FFFB27C27FFB27C25FFBA8229FF563718FF
+ 563716FF563718FF553615FF543516FF523314FF513213FF503112FF593A19FF
+ 5A3B1AFF5B3C1BFF5C3D1CFF5B3C1BFF593A19FF563716FF523516FF4F2F18FF
+ 543520FF4E321AFF362112FF403842FF586182FF4A609AFF3A57A1FF3757A2FF
+ 3C5FA9FF4468AEFF436AAFFF3D65ADFF3A62AAFF3F62ABFF4465AEFF3F62ACFF
+ 365BA5FF375DA5FF375DA5FF34589EFF37599FFF3959A0FF37539AFF2E448BFF
+ 304184FF303D7BFF323C72FF353B6AFF363860FF333554FF33334BFF3D3748FF
+ 32292CFF392A21FF483722FF4F391DFF4D3517FF4F361CFF50371DFF50371DFF
+ 54381AFF573A15FF5B3B12FF5D3A12FF5D3816FF5B351DFF59341EFF54321BFF
+ 52331AFF52331AFF513219FF513219FF503118FF4F3017FF4F3017FF56371EFF
+ 55361DFF54351CFF53341BFF52331AFF52331AFF52331AFF533518FF533914FF
+ 503611FF523013FF522D13FF532E12FF553316FF55381DFF583A21FF573724FF
+ 4E2C15FF542E0EFF6E4720FF8A6336FF936C45FF8A614AFF6C5756FF596480FF
+ 405A88FF445A8AFF415487FF303E6FFF28315DFF2D3056FF37334CFF32272FFF
+ 302014FF3E260AFF58380DFF6F4712FF835718FF92631FFF96631DFF9B6724FF
+ 9B6724FF9B6A26FF9C6B25FF9B6A20FF99681EFF95661CFF8B611CFF79551FFF
+ 432B07FF32281EFF505466FF6273A4FF5A78BFFF496ECAFF4467C1FF475CA0FF
+ 4B5A98FF3E5091FF294084FF1E377FFF214188FF365B9FFF4670B3FF4C79BCFF
+ 5081C5FF5F91D9FF6291DBFF4A71BFFF3354A3FF324D9DFF415196FF5F6594FF
+ 615D70FF7E6E5EFF987C53FF987133FF9E6E26FFAA782CFFAF7A2AFFBA852EFF
+ BA852BFFBA7E24FFB4781FFFB57723FFB77E29FFB4822AFFA37C32FFAE946CFF
+ D0BEADFFF2E5DDFFFAF2F2FFF9F5FAFFEFEDF3FFEEEDF1FFFEFBFDFFF0EEEEFF
+ EFEEF0FFECEFF3FFECF1F4FFEBF2F5FFEBF3F3FFEBF4F1FFEDF4EDFFF7F8EFFF
+ F5EBDAFFE1CAAAFFBC9967FFAF8239FFC48F38FFCB9530FFB57F14FFB87E15FF
+ BC7F17FFC0801AFFC17F19FFBE7C13FFBB7C0CFFBC7F09FFBC820BFFBD8410FF
+ BC830FFFBB820FFFBA810DFFB9800DFFB87F0BFFB77E0BFFB67D09FFB67D0AFF
+ B87F0BFFBB820FFFBB820EFFBA810EFFBA810DFFBD8411FFC28614FFBB7D0BFF
+ BD7E0EFFBE800EFFBD7F0DFFB97B09FFB77907FFB97B09FFBB7E0AFFBE810DFF
+ BE810DFFBE810DFFBE810DFFBD800CFFBD800AFFBD800CFFBD7F0DFFC48719FF
+ B87D10FFB4790CFFBA7F12FFC18317FFBD7F13FFB8790BFFB57608FFC18212FF
+ B77808FFB87808FFC38412FFC58515FFBD7E0CFFB97A08FFBD7E0EFFBB8013FF
+ BB8117FFBC8218FFBD8215FFBC8114FFBF8214FFC28517FFC48817FFC08315FF
+ BB7E10FFB77C0FFFB77D13FFB67D14FFB47B12FFB47D15FFBB811AFFBF7E1BFF
+ C3801DFFC4821CFFC3811BFFBF7D16FFBC7B12FFBC7C10FFBE7E12FFC38317FF
+ B8780CFFB9770EFFBF7D14FFBE7B14FFBF7C15FFC07C17FFBF7B12FFC48212FF
+ C17F0EFFC2800FFFC58515FFC68719FFC28216FFBE8014FFC18319FFC7891FFF
+ BD7F13FFC58519FF5A381BFF573517FF533114FF533113FF553316FF563417FF
+ 553316FF543215FF58351BFF59361CFF56341CFF56341CFF54321AFF523019FF
+ 4F2D16FF4C2B17FF4C2B17FF4B2C15FF4B2D12FF4E3521FF403636FF3F435BFF
+ 4C5F92FF4560A3FF3956A0FF3A5BA4FF3E62A8FF3E65AAFF3A62AAFF375FA7FF
+ 3A5DA6FF3E5FA8FF3C5FA9FF4669B3FF395CA5FF30539CFF3E62A8FF4062A8FF
+ 3858A1FF425EA5FF344A91FF344588FF323F7DFF343E74FF383E6DFF373C63FF
+ 343658FF32304DFF373045FF3A2F39FF3B2A27FF463220FF563E20FF563B16FF
+ 523510FF593A13FF533008FF522F03FF5E3905FF633E0AFF5D390BFF5B3713FF
+ 5B381EFF53331CFF503019FF54351CFF513219FF52331AFF593A21FF56371EFF
+ 4F3017FF503118FF53341BFF56371EFF57381FFF54351CFF4F3017FF4D2E15FF
+ 52331AFF57391CFF503612FF4E320FFF502F15FF57331BFF5B3A20FF5A3C1FFF
+ 52381AFF493115FF51361CFF513419FF5A3B1AFF6E5230FF846E52FF8A7A6AFF
+ 746874FF535371FF3C5079FF385685FF4A6296FF3F548BFF23326AFF262E63FF
+ 3C3B65FF433A55FF2E1A1FFF4F311EFF775023FF966624FFA8721FFFAF7516FF
+ B17511FFB17511FFB2771AFFB2761CFFB37619FFB27517FFB37614FFB27612FF
+ B17612FFAA7514FFA4751AFF997227FF745724FF4C3E28FF505062FF6E7CADFF
+ 6981D3FF4D6BC4FF5370BBFF5573BAFF4A69B8FF3B5CACFF2D4E9EFF20408CFF
+ 2A4588FF3F5B98FF6481BAFF6989C4FF6287C5FF5B82C6FF5981C9FF4E73BDFF
+ 4A69B4FF5773BAFF4D67AAFF53689FFF7E8CB0FFB3B5C7FFB9ABADFFBFA293FF
+ A67D5CFFA06F37FFB38030FFB67F24FFBD8427FFBC8026FFBB7B2DFFB5762CFF
+ B4772DFFBF8F55FFCEB698FFEBE2D5FFFEF7F4FFF0EDEFFFECECF2FFF2F5FAFF
+ F5F4F8FFF1F0F2FFF2F0F0FFF4F3F5FFF0F3F7FFEFF3F8FFF1F7FCFFF4FBFEFF
+ F0F6F5FFEDEFE9FFFAF4E7FFCCBDA3FFAD8F66FFA98042FFBB8838FFC68C2DFF
+ B77E15FFB98013FFB97F15FFBD8018FFBF7F19FFBF7D16FFBD7C10FFBA7B0BFF
+ BB7E08FFBA8009FFBC800EFFBA7E0CFFB87C0BFFB87C0AFFB97D0CFFBA7E0CFF
+ B87C0BFFB67A08FFB97D0CFFBE8210FFC38716FFC18513FFBC800FFFB87C0AFF
+ BA7E0DFFBD810FFFBB7E0AFFBE800AFFBF810BFFBE800AFFBD7F09FFBC7E08FF
+ BD7F09FFBF800DFFBB7C09FFBE7F0CFFC18210FFC18210FFBE7F0DFFBD7E0BFF
+ BE7F0DFFBF800EFFBF800EFFBF800EFFBF800EFFBF800EFFBF800EFFBF800EFF
+ BF800EFFBF800EFFBC7D0BFFBD7E0CFFBF7D0CFFBE7F0CFFBF800EFFC0810EFF
+ C0810EFFBF810FFFB87D0FFFB87D10FFB87D10FFBA7D0FFFBA7D0FFFBC7D0DFF
+ BC7D0DFFBC7E0CFFBC7D0DFFBC7D0DFFBB7F0EFFBB7E10FFBA7F12FFBA7F12FF
+ B97F15FFB97F16FFC0821CFFC48622FFC78923FFC48620FFBF8018FFBA7C12FF
+ BA7C10FFBC7E12FFBB7D11FFBA7C10FFBB7B0FFFBE7E12FFC18017FFC4831AFF
+ C5831CFFC4831AFFBC7D0DFFBC7E0CFFBD7F0DFFBD800CFFBE800EFFBE810DFF
+ BF820EFFBF820EFFC28511FFC28511FFC28511FF5B381EFF59371AFF563319FF
+ 563417FF59371AFF5A381BFF58371DFF57361CFF59371FFF59371FFF593720FF
+ 593622FF583422FF573321FF563222FF553121FF52311EFF503019FF4F2F12FF
+ 4E351BFF41342CFF40404EFF4E5B87FF4A629EFF3F5CA1FF3E5EA7FF3D61A7FF
+ 3C63A8FF3962A7FF365EA6FF365DA2FF385BA4FF395CA6FF4568B2FF4063ACFF
+ 3659A2FF3A5EA4FF3A5CA2FF3858A1FF425DA7FF374D95FF35488CFF324180FF
+ 323D76FF363D6EFF373B64FF343659FF31314FFF3B3651FF403545FF412F30FF
+ 48301EFF553813FF573605FF5C3501FF683F08FF6E4207FF76490CFF865818FF
+ 84581BFF714817FF633E18FF583A1FFF4E321AFF54341DFF583920FF55361DFF
+ 55361DFF5C3D24FF593A21FF52331AFF53341BFF52331AFF55361DFF583920FF
+ 56371EFF513219FF4E2F16FF503118FF53351AFF5B3B1EFF58381BFF56341CFF
+ 54341DFF52361EFF4D341AFF463014FF412B0FFF50381CFF482F15FF574026FF
+ 7F6D5CFF9D9491FF9C9FAEFF8E9AC2FF869BCFFF4D669EFF37548DFF344E8AFF
+ 324A86FF2C3E79FF384173FF424064FF3F303EFF56392BFF774D23FF98641DFF
+ AF7417FFB87A10FFB77806FFB57604FFB37404FFB4780EFFB3760EFFB7760DFF
+ B8760DFFB7760AFFB67508FFB57606FFB37706FFAB7304FFAB7712FF9F711DFF
+ 7F5D22FF5C4836FF534D5EFF5E6597FF687BBFFF5C79BEFF5B7EC8FF5078CAFF
+ 4B74C9FF4972C7FF3C5FAFFF263F85FF182A69FF34457EFF5469A0FF6884C0FF
+ 6283C2FF577ABCFF5C81C5FF6385C7FF5B7CC1FF6487D1FF6A8BD4FF81A0DFFF
+ A9BEF1FFBEC1E7FFC7B7C8FFAA887BFFA77A4EFFAC7A2EFFB37D1FFFB67E1FFF
+ B77D24FFBF8036FFBB7B3AFFC08144FFD9A979FFE0CBB5FFEEEBE3FFFAF8F7FF
+ EDEEF2FFEAEEF3FFF0F3F8FFF1F2F6FFF1F0F2FFF5F3F3FFF5F4F6FFF1F4F8FF
+ EFF3F8FFF1F5FAFFF2F7FAFFF0F4F5FFF3F0EBFFFFFEECFFDAC4A1FFB99664FF
+ B48541FFC28933FFC48824FFB3770DFFB57A0CFFB67C12FFB87E15FFBE7F17FF
+ C07E17FFBE7D11FFBC7D0DFFBA7F0BFFBC810DFFBD8110FFBC800FFFBB7E10FF
+ BB7F0EFFBD8012FFBD8110FFBA7D0FFFB87C0BFFB97C0EFFBC800FFFBF8214FF
+ BF8312FFBC7F11FFBA7E0DFFBC7F11FFC18311FFB97C06FFBC7F07FFBE8109FF
+ BD8008FFBB7E06FFBA7D05FFBC7E08FFBD7F09FFBB7C09FFBE7F0CFFC0810FFF
+ C0810FFFBE7F0DFFBC7D0BFFBD7E0CFFBE7F0CFFBF7F09FFBF8008FFBF7F09FF
+ BF7F09FFBF7F09FFBF7F09FFBF7F09FFBF7F09FFC2820CFFBF810BFFBF810BFF
+ BE7F0CFFBD7E0BFFBC7F0BFFBB7E0AFFBB7E0AFFBA7E0DFFBA7E0DFFBC7D0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7E0BFFBC7F0BFFBC7F0BFFBC7F0BFFBD7F0DFF
+ BD7F0DFFBE7F0FFFBC800FFFBD8110FFBB8012FFBA7E14FFBE8218FFC1851BFF
+ C08518FFBA7F12FFB77C0EFFB87D0FFFBA800FFFBB8110FFBA7F11FFB97E10FF
+ BA7F11FFBF8115FFC18317FFC08218FFBF8115FFB87E0DFFB87F0CFFB9800DFF
+ BB7F0DFFBC810DFFBC810DFFBD820EFFBD820EFFBC7F0BFFBA7F0BFFBA7F0BFF
+ 573920FF55381DFF54351CFF53351AFF54361BFF55371CFF54361BFF53351AFF
+ 53341BFF53341BFF52321BFF52311DFF54301EFF54301EFF543020FF553121FF
+ 563522FF54351CFF533415FF4F3419FF413023FF413A41FF4D5677FF506297FF
+ 4A64A6FF4363AAFF4064AAFF3D64A9FF3B64A9FF3963A8FF365EA6FF355BA3FF
+ 3659A3FF3E61ABFF4063ACFF3B5EA7FF395DA3FF3C5EA4FF3E5EA7FF3F5CA6FF
+ 3A529AFF394C90FF354483FF333E78FF363D6FFF343A65FF33375AFF313352FF
+ 363452FF3D3448FF433033FF4F311EFF633F11FF714506FF804E06FF935D10FF
+ 996112FFA1691AFFA56F22FF93621EFF734613FF613C16FF593C21FF50361EFF
+ 4D2E17FF52321BFF4F2F18FF503019FF573720FF55351EFF4F2F18FF51311AFF
+ 503019FF54341DFF583821FF573720FF53331CFF4F2F18FF4F2F18FF523019FF
+ 5E3421FF5B3321FF52331EFF4B331DFF47311FFF432F1DFF462E1AFF462E16FF
+ 523A1EFF483219FF5E4D44FF908892FFA5AACBFF8EA1D4FF7697D6FF7B9DE3FF
+ 6B86D0FF4A62AAFF354E96FF365092FF3E528BFF4B557DFF4D495CFF483226FF
+ 855D2DFFA16B1EFFBB7912FFC6800AFFC37E05FFB97903FFAD7407FFAA730BFF
+ B1780FFFB2780EFFB6780EFFB7760DFFB7750EFFB7760DFFB6760AFFB67707FF
+ B57701FFB57802FFB4790BFFA57214FF835A1CFF614425FF554344FF504E6BFF
+ 7889BCFF708FD4FF5E87D6FF4D7CD0FF4F7ED4FF4D77CAFF3F5CA7FF314488FF
+ 172462FF222D69FF394C89FF48619FFF4564A1FF5678B4FF7A9CD2FF89AAE2FF
+ 81A3E5FF84A4EBFF7EA1E3FF88A5DEFFA0ABD7FFA6A0B3FF8F7264FF996F40FF
+ AC7B2DFFB47E20FFB17B1DFFBA812CFFC58A45FFB3793EFFB77E4AFFDFB78DFF
+ F5E6D3FFF4F4EEFFF5F7F7FFEBF0F3FFEBEFF4FFEDF2F5FFEFF1F2FFF0F0F0FF
+ F6F6F6FFF3F5F6FFF1F4F9FFF0F3FBFFEEF1F9FFEFF2F7FFF3F2F4FFFAF3EAFF
+ E7D3BAFFBFA276FFAF874DFFBB883FFFCB9138FFCC8E2AFFBA7E14FFBC8114FF
+ B47A10FFB77D14FFBD7E16FFBE8016FFBF7F13FFBE7F0FFFBC800EFFBC800EFF
+ C18214FFC08113FFBF7F13FFC18214FFC28216FFC18214FFBE7E12FFBB7C0EFF
+ BC7C10FFBD7E10FFBD7D11FFBD7E10FFBE7E12FFBF8012FFC08014FFC18212FF
+ B87C04FFBA7F04FFBC8106FFBB8005FFB97D05FFB87C04FFB97C06FFBB7E08FF
+ BA7D09FFBC7F0BFFBD7F0DFFBE800EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0BFF
+ BE7F05FFC08004FFBE8004FFBE8004FFBE7F05FFBE7F05FFBC7F07FFBC7F07FF
+ BF820AFFBE820AFFBD8109FFBC7F09FFBB7E08FFB97F08FFB87E07FFB87E07FF
+ BC7F09FFBD7F09FFBD7F09FFBD8008FFBD8008FFBD8008FFBF8008FFBD8008FF
+ BD8008FFBD8008FFBE8109FFBE8109FFBF810BFFBE810BFFBF820CFFBD820EFF
+ B77C08FFBA7F0BFFBE830FFFBD830CFFBA8009FFB87E07FFB88009FFBB830CFF
+ BD850EFFB9830EFFB8810EFFB9820FFFBB8312FFBB8314FFB98114FFB88011FF
+ B87D0FFFB87E0DFFB97F0EFFB77F0EFFB88011FFB88011FFB98112FFB88112FF
+ BB8314FFBB8314FFBB8314FF53381EFF52371DFF52341BFF513419FF4F3217FF
+ 4E3214FF4D3113FF4C3012FF53351AFF523419FF513219FF503118FF523019FF
+ 522F1BFF522F1BFF522E1CFF54331FFF54351CFF553617FF513517FF44301EFF
+ 413835FF4C4E66FF53608CFF5469A6FF4968ADFF4367ADFF3D66ABFF3E67ACFF
+ 3F69AEFF3B65ACFF355DA5FF355AA4FF3558A2FF395CA5FF3C5FA8FF3B5FA5FF
+ 4266ACFF4565AEFF3B58A2FF3D559DFF3A4E95FF364688FF34407AFF333C6EFF
+ 333A65FF31375CFF2F3455FF2E304FFF383249FF473136FF5C3B27FF80541EFF
+ 986417FFA86D17FFB6791CFFB6771BFFB2761DFFA66E1DFF895512FF67390AFF
+ 5A3412FF55381DFF4C3319FF492A13FF4E2E17FF4B2B14FF4C2C15FF54341DFF
+ 53331CFF4E2E17FF503019FF4F2F18FF52321BFF55351EFF54341DFF52321BFF
+ 503019FF51311AFF57321EFF5B2F1EFF5B301FFF52331CFF483219FF402F1CFF
+ 3F2D1CFF48301EFF4B331DFF50351AFF523B25FF715E5BFF9D94A8FFA7ABDBFF
+ 8B9DDCFF708ED5FF6C8CD7FF7D93E1FF6777C3FF576AADFF5B6BA0FF5C6688FF
+ 5E5E6AFF655548FF6A4A1FFFA17026FFB57915FFC48009FFC78203FFC17E03FF
+ B97A07FFB17710FFAE7714FFB57C13FFB87D10FFBA7C12FFB97A12FFB97913FF
+ B97913FFB97A12FFBB7C0EFFBF7F09FFBA7B01FFB67700FFB17608FFA9741DFF
+ 956727FF6E4A22FF412D22FF434157FF5C6D98FF708FC6FF6991D2FF5986D0FF
+ 4D79C6FF4B6DB9FF516AB4FF5868ADFF374789FF203271FF1F356FFF254073FF
+ 3F5987FF687FA5FF8397BAFF8C98C0FF8894BCFF7C8EB3FF7987A4FF868795FF
+ 8A7D75FF876541FF9F7032FFB57F2AFFB98122FFB87F24FFCA9241FFD49E5DFF
+ B17F4BFFAE8457FFE2C5A6FFFEF5E7FFF3F4F0FFEEF2F3FFEDF2F5FFECF2F7FF
+ EDF2F5FFEEF0F1FFF0F0F0FFF5F5F5FFF0F2F3FFF0F3F8FFF1F3FBFFEDF0F5FF
+ F1F0F4FFF6F1F2FFFAEEE2FFCEB391FFAB8654FFA57737FFB68033FFC5892FFF
+ C58723FFB97A12FFBC7F17FFB67C13FFB87E15FFBC7F17FFBF8117FFBE8014FF
+ BF8012FFBC800FFFBB7E10FFC08113FFBF7F13FFBF7F13FFC18115FFC28216FF
+ C28216FFBE7E12FFBB7B0FFFC08014FFBD7D11FFBB7B0FFFBB7B0FFFBD7D11FF
+ C08014FFC08014FFBF8010FFBA7D07FFBB8005FFBD8207FFBC8008FFBA7E06FF
+ B97D05FFBB7E08FFBD800AFFBA7D09FFBB7E0AFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BB7D0BFFBB7C0CFFBA7D09FFBC7F07FFBE8004FFBC8004FFBC8004FFBC8005FF
+ BC8005FFBB7F07FFBB7F07FFB77E05FFB77E05FFB87E07FFB77F08FFB87F0BFF
+ B87F0BFFB9800CFFBB810AFFBD8008FFBF8006FFBF8006FFBF8006FFBF8006FF
+ BD8106FFBD8106FFBD8008FFBD8008FFBC8008FFBD8109FFBD8109FFBE820AFF
+ BE820AFFBD830CFFBD830CFFB87B05FFBB7E08FFBD800AFFBD8109FFBB7F07FF
+ B98007FFBA8108FFBB840BFFBB830CFFB8820DFFB7800DFFB8820FFFBB8314FF
+ BA8314FFB88013FFB77F10FFB87E0DFFBA7E0DFFB97F0EFFB97E10FFB88011FF
+ B77F12FFB88013FFB68015FFBE861BFFBE8619FFBE8619FF52341BFF52341BFF
+ 52351AFF513517FF503415FF4F3314FF4E3311FF4E3311FF593D1BFF593D1BFF
+ 573A1BFF56381BFF563619FF55341AFF54321AFF54321BFF512E1AFF51311AFF
+ 55371AFF503618FF49321CFF44342DFF494453FF525B7DFF50649BFF4764A7FF
+ 4064AAFF3961A9FF3C65AAFF3F69AEFF3C66ADFF345DA6FF375DA5FF3558A1FF
+ 3B5EA7FF3E61AAFF3A5EA4FF4064AAFF4464ADFF37549EFF3D569EFF3C5097FF
+ 38488AFF35407CFF323D71FF313A66FF2F365DFF2F3657FF2E3556FF38364CFF
+ 4B353AFF68442CFF956628FFB27923FFB97B17FFBB7B15FFB87B1BFFA76C16FF
+ 935C11FF78460CFF5F320DFF583017FF523419FF472C11FF53351CFF56361FFF
+ 52321BFF51311AFF56361FFF54341DFF4E2E17FF503019FF4E2E17FF503019FF
+ 503019FF503019FF503019FF51311AFF54341DFF59371FFF5D351CFF5C371BFF
+ 543917FF4A3515FF402F15FF3F2C17FF462D19FF4E311CFF4E3015FF5F402BFF
+ 785956FF8C7486FF9284AEFF8B88C0FF7A84C0FF707EC0FF6D79C1FF6B74B4FF
+ 7578A4FF7D7B8EFF7D7167FF7D6541FF8A662AFF976A19FFAD7718FFB47A10FF
+ B67D0AFFB47B08FFB27709FFB1770DFFB27714FFB57816FFB97B11FFBB7C0EFF
+ BB7B0FFFB97A12FFB97815FFB87A16FFB87A14FFBA7B13FFB77A0CFFB97D0BFF
+ B77B09FFB0770AFFAF7817FFAD7926FF9C6D29FF7F5929FF4D351FFF534949FF
+ 5F6675FF7186A5FF7CA0D0FF729BD9FF5A82CAFF4B71BFFF4E6FBEFF5372BDFF
+ 4C68A9FF4F679DFF7285ABFF8E99B4FF858B98FF777073FF8C746EFF896C5DFF
+ 8D7660FF8F7956FF9A7C4BFF9E7837FFA67323FFB87F22FFBF8220FFBC801CFF
+ BC7F22FFD49C4BFFDBAB6BFFB89361FFBCA480FFF1E4CEFFF9F5EAFFEDEEECFF
+ EAEEEFFFEFF4F7FFEEF4F9FFEEF3F6FFEFF1F2FFF0F0F0FFF2F2F2FFECEEEFFF
+ EEF1F5FFEFF2F7FFF0EFF3FFF5F2F4FFF6EFECFFF1E1D0FFD7B78EFFB68A4FFF
+ AD7A34FFB27A2BFFB67A20FFB77A1AFFB77915FFC0821EFFBA7E1AFFB97F18FF
+ BB8117FFBD8215FFBE8113FFBD8012FFBC7C10FFBB7B0FFFBF7F13FFBE7F11FF
+ BD7E10FFBE7F11FFC08113FFBF8012FFBC7D0FFFBA7B0DFFC28315FFBE7F11FF
+ BB7C0EFFBA7B0DFFBD7E10FFBF8012FFBD7E10FFBB7C0CFFBA7F0BFFBC830AFF
+ BD840BFFBC820BFFBA8009FFBA8009FFBB800CFFBD820EFFB87D09FFB97E0AFF
+ B97E0AFFBA7F0BFFBA7F0BFFBA7F0BFFB97D0BFFB87D09FFBB810AFFBB810AFF
+ BB810AFFBB810AFFBB810AFFBB810AFFB9800CFFB9800CFFB57C08FFB57C08FF
+ B67D09FFB57F0AFFB67F0CFFB67F0CFFB7800DFFB9800CFFBC8008FFBD8105FF
+ BD8106FFBD8106FFBD8008FFBC8008FFBC8008FFBA8009FFBA8009FFBA8009FF
+ BB810AFFBB810AFFBA820BFFBA820BFFBB820EFFBB820EFFBD7E0EFFBF7F0FFF
+ BF7F0FFFBD7F0DFFBC7E0CFFBB7D0BFFBC7E0CFFBC800EFFBA7E0DFFB87E0DFF
+ B87D0FFFB98112FFBD8117FFBC8218FFBA8017FFBA7F12FFBD7E0CFFBD7E0BFF
+ BD800CFFBD7F0DFFBC800FFFBA7F11FFB98013FFB88013FFB87F12FFB87F12FF
+ BA7F11FF523019FF52331AFF57361CFF56381BFF56391AFF563A18FF573B19FF
+ 583C19FF573B19FF573B19FF573B19FF56391AFF563619FF543417FF513016FF
+ 502E16FF4F2D16FF502E17FF53361BFF50351AFF4B341AFF463324FF443941FF
+ 4F526EFF48598CFF415D9EFF3B5EA7FF345CA4FF3760A5FF3B65AAFF3561A8FF
+ 2F58A1FF395FA7FF3C5FA8FF4467B0FF4164ADFF365AA0FF385CA2FF3D5DA6FF
+ 37549EFF3B549CFF3A5097FF38498CFF35437EFF333E72FF313A66FF2F365DFF
+ 2D3658FF2A3555FF35364BFF463237FF69442AFF9C6B27FFBB8122FFBC7E14FF
+ B4780EFFB57B1CFF95600FFF774705FF653708FF592C11FF58301DFF59381EFF
+ 503416FF583920FF593922FF53331CFF4F2F18FF53331CFF503019FF492912FF
+ 4A2A13FF4F2F18FF4F2F18FF4F2F18FF4E2E17FF4F2F18FF52321BFF55351EFF
+ 5A3820FF553316FF563514FF523613FF4E3513FF4A3216FF4A3117FF4F341AFF
+ 57361CFF583212FF714828FF845840FF825B4DFF7E5D61FF7F6575FF73657DFF
+ 645979FF655A7BFF6E617BFF806F72FF8D7561FF927241FF966D28FFA3731BFF
+ B27916FFB57B11FFB67B0DFFB27A0BFFAE7609FFAB750AFFAE750CFFB17511FF
+ B67610FFB6760AFFB77609FFB7760DFFB5760EFFB5750FFFB67610FFB6770FFF
+ B6780EFFB27408FFB3780BFFB5790FFFB2780FFFAD720EFFAA7010FFB07518FF
+ B07B2AFF9F7435FF7C5E2FFF5D4C2BFF5F5C4DFF758088FF7C92AEFF7694C5FF
+ 7696D7FF6F92DBFF789BE4FF7194D3FF7C9BCEFFAEC4E8FFCFDDF3FFCBCEDCFF
+ CBBFBBFF9E775BFF9F6E40FFA67842FF9F722EFFA97927FFAF7B1DFFB67B17FF
+ BC8219FFC1831DFFB97C1AFFB8791DFFC48C3BFFC69656FFBC9B6EFFCFC3ABFF
+ F2F0E5FFF2EFEAFFE9EAE8FFEAEEEFFFF0F5F8FFEFF3F8FFEDF2F5FFF1F3F4FF
+ F1F1F1FFF0F0F0FFEBEDEDFFEFF0F4FFEFF0F4FFF0EFF1FFFBF6F5FFF1E9E2FF
+ DBC8B3FFD7B083FFC09050FFBF8A41FFC08837FFBA7E25FFBC7E20FFBF7F21FF
+ C48727FFBD821FFFBB811AFFBA8016FFB98112FFBB8012FFBD7F13FFBD7B14FF
+ BB7912FFBF7F13FFBD7E0EFFBB7C0EFFBB7C0CFFBD7E10FFBD7E0EFFBC7D0FFF
+ BA7B0BFFC28315FFBF8010FFBC7D0FFFBB7C0CFFBD7E10FFBD7E0EFFBC7D0FFF
+ BA7B0BFFBB7F0DFFBD820EFFBE830FFFBE830FFFBC810DFFBB800CFFBC810DFF
+ BE830FFFBA7F0BFFB97E0AFFB97E0AFFBA7F0BFFBC810DFFBB810AFFBA7F0BFF
+ B87D09FFBC810DFFBA810DFFBC800EFFBA810DFFBC800EFFBA810EFFBA810EFF
+ BA810EFFBA810EFFBA810EFFB9800DFFB87F0CFFB77E0BFFB57E0BFFB67C0BFF
+ B87D09FFBD8106FFBF8105FFBF8006FFBD8106FFBD8008FFBC8008FFBC7F09FF
+ BA8009FFBA7F0BFFB87F0BFFB9800CFFB9800CFFB8810EFFB8820DFFB9820FFF
+ BB820FFFBE8113FFBF8012FFBF8012FFBD7E0EFFBC7D0DFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBB7D0BFFB97D0BFFBA7E0DFFBD8110FFC08315FFC08315FFBE8014FF
+ BD7E10FFBF7E0BFFBF7F09FFBE7F0CFFBD800CFFBC800EFFBC800FFFBB8012FF
+ B98112FFB47C0DFFB67B0DFFB87C0BFF592F1CFF59321CFF5E351FFF5D371FFF
+ 5B361CFF5A3519FF593719FF5A3918FF543214FF533415FF553617FF563619FF
+ 55341AFF523018FF4C2C15FF4C2A13FF512F18FF512F18FF52341BFF4B3317FF
+ 4B3317FF44301EFF3F3132FF4C495FFF465485FF415B9DFF3D60A9FF355EA7FF
+ 365FA4FF3963A8FF325FA8FF2B569FFF385EA6FF4061AAFF4366AFFF3E61AAFF
+ 375AA3FF385BA4FF3C5CA5FF3956A0FF38519BFF384E95FF38498CFF364381FF
+ 343F73FF313A66FF2E375DFF2B3557FF263353FF30354AFF443035FF643F25FF
+ 97641EFFB77D1DFFBA8017FFB27C17FFA2711BFF7B510CFF603905FF57310FFF
+ 532A1BFF562F21FF5D3A20FF5C3D1EFF513219FF53321EFF4D2C18FF4B2A16FF
+ 51301CFF4F2E1AFF4A2915FF4C2B17FF502F1BFF502F1BFF502F1BFF502F1BFF
+ 51301CFF51301CFF52311DFF52321BFF4C2F14FF4E3214FF523117FF553218FF
+ 563417FF583618FF583A17FF613D17FF663B10FF865420FFA36928FFA66B25FF
+ 9F6A27FF9C6B33FF8F6540FF855D40FF8D603EFF96693EFF997039FF9D722FFF
+ A27524FFA9771DFFB17717FFB67610FFBD7B12FFBC7B0FFFB6780CFFB3780BFF
+ B07809FFB3780AFFB6790BFFB9790DFFB67509FFB6740BFFB5740BFFB4760CFF
+ B7760DFFB8770BFFBA7808FFBB7909FFB67508FFB3750BFFB17511FFB37713FF
+ B47310FFB27007FFB87004FFB77407FFAD760EFFA77717FF99701BFF84621CFF
+ 6F5729FF655744FF76757EFF939EBEFF96ADDDFF8DAEE6FF88AFE6FF8DB6E7FF
+ A2C8F2FFB0D0F4FFAAC3E3FFB2B5C3FF9D7F66FFBC8C5CFFC59155FFAB762DFF
+ B87F29FFBA8021FFB67C1CFFBA8322FFBC8628FFBC8326FFBC7F22FFB67D28FF
+ AE7C3AFFC5A57AFFE8DED4FFEAECEDFFF0EEEEFFEDEBEBFFF0F1F5FFF2F6FBFF
+ ECF0F5FFECEFF3FFF2F4F4FFF1F2F0FFF1F2F0FFECEEEEFFF0F2F3FFEEF0F1FF
+ F2F0EFFFFEFAF5FFEAE0D6FFC2AD92FFC39B67FFBF8B45FFCB9449FFCD9341FF
+ BE812BFFBD7F25FFBD7E24FFBD7E22FFBE8222FFBB811AFFB77F12FFB77F10FF
+ BA7F11FFBE8014FFC07E18FFBF7D17FFC18214FFBE800EFFBB7C0CFFBA7C0AFF
+ BB7C0CFFBD7F0DFFBD7E0EFFBC7E0CFFBD7E0EFFBC7E0CFFBC7D0DFFBD7F0DFF
+ BE7F0FFFBD7F0DFFBC7D0DFFBB7C0CFFBA7E0DFFBC800FFFBD810FFFBD810FFF
+ BB7F0DFFBA7E0CFFBB7F0DFFBD810FFFBB800CFFBA7F0BFFB97F08FFBB810AFF
+ BD830CFFBD840BFFBB810AFFB87E07FFBB7F0DFFBB7F0DFFBD7E0EFFBB7F0DFF
+ BD7E0EFFBD7F0DFFBD7F0DFFBD7F0DFFBF810FFFBE800EFFBF800DFFBE7F0CFF
+ BD7E0BFFBC7F0BFFBC7D0BFFBC7E08FFC18006FFC18105FFC18006FFBF8006FF
+ BF8008FFBD7F09FFBC7F0BFFBA7F0BFFBA7E0CFFBA7E0CFFB9800DFFB9800DFF
+ BA800FFFBA810EFFBB8110FFBB8110FFBB8012FFBA7F11FFB87E0DFFB77E0BFF
+ B77E0AFFB97F08FFBA8009FFBD8109FFBC8106FFBD8106FFBE8207FFC08409FF
+ C4850DFFC4850DFFC0800AFFBD7D07FFBD7F09FFBD7F09FFBD800CFFBD800CFF
+ BC810DFFBC800EFFBB820FFFBB8110FFB97F0EFFB9800DFFBB7F0DFF5B301FFF
+ 5D3320FF5F3522FF5D341EFF573119FF532E14FF502E11FF502E11FF553316FF
+ 573518FF59391CFF5B3A20FF5B3921FF58361FFF52321BFF523019FF57341AFF
+ 503118FF4B331DFF462F19FF4B3015FF452D17FF3F2B26FF4D4556FF4A5785FF
+ 4861A1FF4668AEFF3C64ACFF3A63A8FF3C66ABFF3762ABFF2F58A1FF395CA5FF
+ 3D5EA7FF3A5DA7FF385BA5FF3C5FA9FF4263ACFF4161AAFF3C5AA1FF364F99FF
+ 354D95FF354A8EFF334483FF313E76FF2F3969FF2E365EFF2C3459FF30395EFF
+ 3A3B55FF46353EFF5D3D26FF8A5D1AFFAA751AFFB37C1BFFAF7C20FF865A13FF
+ 653F09FF57340CFF5C391FFF5B3426FF573022FF56351BFF573819FF4C2D14FF
+ 503019FF4D2C18FF4E2E17FF583723FF593922FF573622FF5B3B24FF51301CFF
+ 51311AFF52311DFF53331CFF52311DFF51311AFF4E2D19FF4C2D16FF52371DFF
+ 53351CFF58341CFF59331BFF593418FF563514FF553511FF59380BFF6C420DFF
+ 8B5613FFAD6E16FFBC7916FFBA7811FFB27515FFAA7225FFAB732CFFB4782CFF
+ BC7D2CFFB67B25FFAE771CFFB17A19FFB87D1AFFB67812FFB27009FFBC7912FF
+ BB7910FFB9780FFFB7790DFFB87A0EFFB97C0EFFBC7D0FFFBD7C0FFFB8760DFF
+ B9770EFFB8760FFFB7790FFFB9790DFFBB7A0DFFBE7C0BFFBE7C0BFFBA790DFF
+ BE7C15FFBA7B19FFB57614FFBA7714FFC27E15FFC67C0CFFBD7400FFB37500FF
+ B67D0AFFB57D10FFAF791AFFA17024FF89622BFF7D6143FF7E6F66FF818089FF
+ 8B95A7FF91A1B8FF8398AEFF879AAFFFA5B7C8FFA1AFC1FF8A8685FF795733FF
+ B8864AFFCE974EFFAB721DFFBE8123FFBB801DFFAD7516FFB47E20FFBC872DFF
+ C38D36FFC58C36FFAF7B2EFFA0763BFFD3B896FFFFFDF8FFEEF1F6FFF2F0F0FF
+ F1EFEEFFF7F6F8FFF7F7FDFFE9EDF2FFE9EEF1FFF0F5F4FFEFF2F0FFF2F3F1FF
+ F0F0F0FFF1F2F6FFEFEEF2FFF5F0EFFFFFFBF3FFEDDCC7FFBA9B74FFB38545FF
+ B47C2DFFC78D3BFFC58B32FFB7791FFFBC7D21FFC08125FFC18424FFBF831FFF
+ BA8017FFB67E0FFFB57D0CFFBA800FFFBF8214FFC08218FFC28118FFC48515FF
+ C08210FFBB7D0BFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFB97B09FF
+ BA7C0AFFBC7E0CFFBE800EFFBE800EFFBE800EFFBD7F0DFFBC7E0CFFB97D0CFF
+ BA7E0DFFBC800EFFBB7F0DFFB97D0BFFB87C0AFFBA7F0BFFBB800CFFBC810DFF
+ BB810AFFBA8009FFBB810AFFBE850CFFBE850CFFBB8209FFB87E07FFBB7E0AFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7D0BFFBC7D0AFFBC7D0BFF
+ BD7E0BFFBD7E0BFFBE7F0CFFC1800DFFC0810EFFC2810EFFC2820CFFC18006FF
+ C18006FFBF8006FFBF8008FFBF8008FFBD7F09FFBC7F09FFBC7F0BFFBA7F0BFF
+ BA7F0BFFBB7F0DFFB9800DFFBC800EFFBA810EFFBD810FFFBB820FFFB87F0CFF
+ B77E0BFFB57C08FFB57C08FFB67E07FFB98007FFBA8106FFBD8207FFBF8508FF
+ BF8406FFBF8307FFC38608FFC4860AFFC28408FFC08004FFBA7B01FFBD7F09FF
+ BC7F0BFFBD7F0DFFBD7F0DFFBC800EFFBC800EFFBB820FFFBB820FFFB97F0EFF
+ B9800DFFBB7F0DFF553121FF55311FFF54301EFF522F1BFF512E1AFF502E17FF
+ 4F2D15FF4F2D15FF512F17FF523018FF54321AFF56341CFF57351DFF56341CFF
+ 55331BFF563319FF613E1CFF55371AFF3F2C1DFF372619FF482910FF502E16FF
+ 4E3329FF403440FF515A85FF465E9AFF4865A8FF4367ADFF3E66AEFF4068B0FF
+ 4167AFFF3E62A8FF4465AEFF3D60AAFF365AA6FF375BA7FF3D5FABFF4060ABFF
+ 3E5CA3FF3A579CFF334F96FF375197FF365096FF324A8CFF2F417CFF2C3A6EFF
+ 2E3763FF32365FFF32315BFF3A3457FF423648FF533D31FF765419FFA77B28FF
+ A8721FFF9E6821FF6F4413FF623C19FF583716FF523215FF552F17FF522E16FF
+ 4B2F11FF482E10FF503219FF4F3118FF50311AFF53351CFF573821FF583A21FF
+ 563720FF53351CFF53341DFF503219FF4C2D16FF4A2C13FF492A13FF4C2E15FF
+ 4F3019FF53341BFF58361EFF54321AFF56321AFF58361EFF57391EFF533719FF
+ 513713FF583B0EFF6D470DFF946319FFB4791CFFBD7B14FFBA790DFFBA7C12FF
+ B57B1CFFB0771CFFB5761CFFB7751CFFB5761AFFB57719FFB57818FFB77816FF
+ B97816FFB97815FFBB7815FFBB7913FFB87812FFB87911FFB87911FFB7790FFF
+ B7790FFFB9780FFFB8760FFFBB7912FFBB7D13FFBB7D13FFB87A10FFB8780CFF
+ B7770BFFB8780CFFB9780FFFB97A12FFBB7A17FFBB7A18FFB87715FFB97613FF
+ BB7714FFBD7A13FFBA7C12FFB5790FFFB57915FFB87D20FFB67D28FFAC782CFF
+ A57632FFA2783DFF946F3DFF937348FF927451FF8E7250FF8F7354FF947859FF
+ 967A58FF9A774BFFAC7E3EFFB57E2DFFB67C1DFFB47A13FFB47B12FFB78018FF
+ BC8425FFC1882DFFBA7E25FFB67C2AFFCB984FFFB68F51FFBCA27AFFF7EAD4FF
+ FFFCF7FFF1F1F1FFF2F2ECFFF3F3EDFFF7F2F3FFF4F3F7FFEEF1F9FFE7F0F4FF
+ E4EFEDFFE4EDEAFFE9EDE8FFF8F6F6FFF0ECF7FFEEE6F1FFFEF1F3FFFBE6D7FF
+ D6B58EFFB4884BFFC38B3AFFC08326FFB97C1CFFBB7E1CFFBE801CFFBA7C18FF
+ B77913FFB77A12FFB67B0EFFB87D0FFFBA800FFFBC8310FFBE8210FFBD810FFF
+ BB7F0DFFBA7E0CFFBF810FFFBE800EFFBD7F0DFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BE800EFFBF810FFFBF810FFFBF810FFFBF810FFFBE800EFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC7F09FFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F09FFBA7D09FFBC7F09FFBD800AFFBC7F09FFBB7D07FFBA7D07FF
+ BF810BFFC2840EFFBD8008FFBD8008FFBD8008FFBD8008FFBD8008FFBC8008FF
+ BC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBA8009FFBC7F09FFBA8009FF
+ BC7F09FFBA8009FFB87E07FFB87F06FFB87F06FFB87F06FFB87F06FFBA7F04FF
+ BA7F04FFBA7F04FFC0850AFFC08609FFC0850AFFC08408FFC08409FFBF8308FF
+ BE8207FFBE8109FFBD7F0DFFBD8110FFBC800FFFBB7F0EFFBE8211FFC28615FF
+ C08413FFBA7E0DFFBA7D0FFFBA7E0DFFBA7E0DFF563522FF543320FF53321EFF
+ 52321BFF52321BFF51331AFF513219FF503118FF4C2D14FF4F3017FF52331AFF
+ 55361DFF56361FFF54341DFF52321BFF523018FF5C3918FF543619FF423124FF
+ 422F22FF513016FF563214FF51301CFF412D2CFF454864FF4B5C8DFF4864A0FF
+ 3E61A5FF4168B2FF436CB5FF3D65ADFF3C62AAFF3F62ACFF3D60AAFF395DABFF
+ 355BA9FF385AA6FF3959A4FF3B59A0FF3C599EFF38559AFF375499FF345196FF
+ 314B8EFF2E4381FF2C3B73FF2F3766FF33355EFF36315EFF3A3257FF3B3148FF
+ 4B3833FF6F521FFFA0772EFF99651EFF885216FF683B19FF5C371DFF563619FF
+ 553518FF5B3418FF573216FF4B3015FF442E12FF51361CFF52341BFF52341BFF
+ 53351CFF54361DFF53351CFF51331AFF4F3118FF53351CFF51331AFF4F3118FF
+ 4D2F16FF4D2F16FF4E3017FF51331AFF54351CFF553119FF512D15FF4F2D15FF
+ 52331AFF51351DFF51361BFF553B17FF614314FF744E0EFF966716FFB47A1BFF
+ BC7B12FFB9780BFFBB7B0FFFBA7D15FFB57915FFB77718FFB97718FFB97718FF
+ B97718FFB97718FFB97816FFB97816FFB97815FFB97815FFB97815FFB87812FF
+ B87812FFB87812FFB77711FFB77810FFB77810FFB6770FFFB97A12FFBB7D13FF
+ BA7C12FFB87A10FFB6780EFFB6780EFFB6780EFFB77810FFB97A12FFBA7A14FF
+ BA7916FFB87715FFB87617FFB97619FFBB791AFFB77915FFB57713FFB8781AFF
+ BB7C22FFBB7C24FFB67923FFB47A21FFB57F28FFB47C2AFFB47E31FFB27B36FF
+ AC7635FFAB7637FFAC793AFFAD7B39FFAC7A32FFB98231FFBA8126FFBA8017FF
+ B57D0EFFB47C0FFFB47D14FFB87E1EFFBB7F25FFC4842FFFBB8135FFAC8040FF
+ AE8D5FFFDDCCB1FFFEF8EBFFEDEAE5FFEBE9E8FFEDEDE7FFEFEFE9FFF4F0EFFF
+ F2F1F3FFEFF3F8FFECF2F7FFE9F3F3FFEAF3F0FFEBEFEAFFECECECFFF3EBF5FF
+ FBEDF8FFF5E1E0FFDABBA6FFBD9561FFB78539FFC08528FFC4841EFFC2821CFF
+ C3841CFFC08119FFBC7E14FFBF8115FFC5881AFFBF8214FFBE8211FFBD810FFF
+ BB7F0DFFBB800CFFBB800CFFBB810AFFBB810AFFBE800EFFBD7F0DFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BC7E0CFFBE800EFFBF810FFFC18311FFC28511FFBC7F09FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBB7E08FFBB7E08FFBD800AFFBF820CFFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBB7F07FFBB7F07FFBB7F07FF
+ BB7F07FFBB7F07FFBB7F07FFBB7F07FFBB7F07FFBF830BFFBF830BFFBF830BFF
+ BE820AFFBE820AFFBD8109FFBD8109FFBC7F09FFB67A09FFB97C0EFFB97C0EFF
+ B87B0DFFBB7E10FFBF8214FFBC7F11FFB6790BFFBA7D0FFFBA7D0FFFBA7D0FFF
+ 52331CFF50311AFF4E3017FF4F3217FF523618FF503717FF503415FF4C3313FF
+ 4B3113FF4B3113FF4B3016FF4B2F17FF492E19FF4A2F1BFF4B2F1EFF4D2F1EFF
+ 573420FF54331FFF4C3222FF4B331DFF543312FF56330BFF55300AFF482D13FF
+ 453C3FFF535B78FF496195FF385B9DFF426AB2FF436DB8FF3663ADFF3761ACFF
+ 385DA7FF3B5EA8FF395DABFF345AA8FF3557A3FF3656A1FF3C59A3FF415DA4FF
+ 3B589DFF38559AFF334F96FF314B8EFF314684FF303F77FF303867FF31325EFF
+ 37325FFF393058FF392E48FF453332FF6A4D21FF997031FF8A5718FF6F3A07FF
+ 613516FF57321CFF53341BFF57361CFF5E361DFF5B361CFF4E3319FF482F15FF
+ 4A2F15FF4E3017FF51331AFF52341BFF52341BFF52341BFF53351CFF54361DFF
+ 52341BFF52341BFF51331AFF503219FF503219FF51331AFF52341BFF54351CFF
+ 57361CFF553119FF4F2F18FF4F3019FF4C2F1AFF4C2F14FF533611FF63400EFF
+ 815813FF9E6C19FFB67B18FFBB7B0FFFB8770AFFBA7A0EFFB97B17FFB77816FF
+ B87715FFB87715FFB87715FFB87715FFB87715FFB87714FFB87714FFB87714FF
+ B97815FFB97913FFB87812FFB87812FFB87812FFB77711FFB77810FFB77810FF
+ B6770FFFB97A12FFBA7B13FFBA7B13FFB7790FFFB6780EFFB6780EFFB7790FFF
+ B6770FFFB87911FFBA7A14FFB97815FFB87715FFB87617FFBA771AFFBD7B1CFF
+ B77516FFB87617FFBC781FFFBD7A23FFBA7924FFB6771FFFB67A20FFB87F24FF
+ B87E25FFB57E29FFB27A2BFFAC7629FFAC752AFFAD792CFFAE7B2BFFAE7A27FF
+ B77F26FFB97F20FFB87E17FFB67E13FFB57D12FFB67D14FFB97C1AFFBA7D20FF
+ BE8230FFB17D36FFA27B44FFC3A984FFFDF0DAFFFFFCF1FFEEEBE6FFF7F5F4FF
+ F1EFEEFFF2F0EFFFF2F3F1FFF1F3F3FFEEF1F5FFEDF0F4FFEBEFF0FFEAEFEEFF
+ EBF1ECFFE9ECEAFFF7F0F3FFFEEEEFFFE7CBC0FFC49E7EFFB28748FFB58330FF
+ B6791BFFBF7F19FFC3831DFFC2831BFFBC7D15FFB97B11FFC18317FFCC8F21FF
+ C48719FFC18514FFBD810FFFB97D0BFFB87D09FFB97E0AFFBB810AFFBD830CFF
+ BC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFF
+ C08210FFBF810FFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE810DFF
+ BC7F09FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BF820CFFBD800AFFBB7E08FFBB7E08FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BE810BFFBE810BFFBD800AFFBD800AFFBD800AFFBC7F09FFBC7F09FFBC7F0BFF
+ B97D0CFFBD8012FFBF8214FFBE8113FFC08315FFC28517FFBF8214FFB97C0EFF
+ BA7D0FFFBA7D0FFFBA7D0FFF4A2E16FF482D13FF472C12FF492E13FF4C3116FF
+ 4D3217FF4B3015FF482D12FF4D3217FF4D3218FF4D3218FF4C3018FF4A2F1AFF
+ 4B301CFF4B301CFF50301DFF532D1BFF542D17FF522D11FF53310DFF573609FF
+ 613C08FF6C4409FF6A4513FF5E472DFF615B60FF4E6089FF3B5C9BFF3E65AAFF
+ 3D67B2FF3363B1FF3563B1FF385CA8FF3A5DA7FF375BA7FF345AA8FF365AA6FF
+ 3C5CA7FF415EA8FF4561A8FF3B589DFF365398FF304C93FF2E498CFF324785FF
+ 324179FF32396AFF31325EFF36315EFF3A3257FF3A2E4AFF423134FF614522FF
+ 8D6530FF7D4B16FF623105FF5B3219FF51301DFF50311AFF53341BFF5C361EFF
+ 5C361EFF53341DFF4D331BFF492E14FF4E3017FF51331AFF51331AFF4F3118FF
+ 4F3118FF52341BFF54361DFF4F3118FF503219FF503219FF51331AFF51331AFF
+ 51331AFF51331AFF52331AFF57361CFF54321AFF50311CFF4F2F1CFF4C2D18FF
+ 4D2C12FF58340EFF68410AFF926319FFA67218FFB67C15FFB87B0DFFB7770BFF
+ B9780FFFBA7917FFB97718FFB87715FFB87714FFB87812FFB87812FFB87812FF
+ B87812FFB87812FFB87812FFB97913FFB97913FFB87812FFB87812FFB87812FF
+ B77711FFB77810FFB77810FFB6770FFFB87911FFBA7B13FFB97A12FFB7790FFF
+ B6780EFFB7790FFFB97B11FFB6770FFFB77810FFB97913FFB97913FFB87714FF
+ B97816FFBB791AFFBE7C1DFFB67415FFB97619FFBD7920FFBE7922FFBA7720FF
+ B7781EFFB97A1EFFBB7E20FFB47A1BFFB57A1DFFB37920FFB07721FFB17822FF
+ B17C22FFB17D1FFFB37D1EFFB77A1CFFB87B1BFFB77C18FFB87F16FFBA8217FF
+ BC8219FFBF811DFFBD8023FFC38A3BFFAB7C3EFFB09065FFE8D6B9FFFFF8E9FF
+ F6F3EBFFFCF9F4FFF6F2F1FFF3F1F1FFF2F1F3FFEEF3F1FFEEF3F1FFF0F2F3FF
+ F0EFF3FFEEEDF1FFEBEDEEFFE7ECEAFFF1F3EDFFF8F0E9FFE8D2C6FFCDA991FF
+ C4976BFFBF9046FFB38024FFB07512FFBA7B13FFBE7F17FFBD7F15FFB7790FFF
+ B5770BFFBC7E12FFC48719FFC38716FFC18514FFBD810FFFB97D0BFFB87D09FF
+ BA7F0BFFBD830CFFBF8410FFBA7C0AFFBA7C0AFFBA7C0AFFB97B09FFB97B09FF
+ BA7C0AFFBA7C0AFFBA7C0AFFC38513FFC18311FFBE800EFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBC7F0BFFBC7F09FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFC1840EFFBE810BFFBA7D07FFBA7D07FFBC7F09FF
+ BD800AFFBC7F09FFBA7D07FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC7F09FFBD800CFFBD800CFFBD7F0DFFBD800CFFBD7F0DFF
+ BD800CFFBD7F0DFFBD800CFFBE800EFFBD800CFFBC7E0CFFBC7F0BFFBB7D0BFF
+ BC7F0BFFBC7E0CFFBD7F0DFFBB7F0EFFC08315FFC38618FFC18416FFC28517FF
+ C48719FFC18416FFBB7E10FFBA7D0FFFBA7D0FFFBA7D0FFF432B15FF432B15FF
+ 452A15FF472C18FF4A2F1BFF4B2F1EFF482C1BFF482A19FF4B2D1CFF4F2F1CFF
+ 51311EFF53341FFF54351EFF53351CFF53351AFF563319FF542B12FF5C2D0DFF
+ 643404FF6A3E03FF6E490BFF7D5913FF956614FF9C6C1EFF8A642AFF725D47FF
+ 566078FF466199FF375A9EFF355DA8FF3967B5FF3866B4FF4067B2FF3F62ACFF
+ 385CA8FF375DABFF3D61ADFF4164AEFF4161AAFF405EA5FF38549BFF324E95FF
+ 2A4791FF2C468CFF324687FF34437BFF333A6BFF32335FFF37305BFF3D3258FF
+ 3E324EFF423239FF583D23FF7C562CFF704318FF61340FFF57321EFF502F20FF
+ 4C2E1BFF4F3019FF59331BFF5B341EFF553621FF523520FF54351EFF55371EFF
+ 55371EFF52341BFF4D2F16FF492B12FF4A2C13FF4B2D14FF4C2E15FF4D2F16FF
+ 4E3017FF4F3118FF503219FF503219FF4F3118FF4F3118FF4C2E13FF4B2D14FF
+ 4C2E1BFF4E301FFF502F1CFF563115FF693F14FF7C4F12FF9F6C1CFFAE7617FF
+ B67C12FFB87B0DFFB8780CFFB97710FFBB7716FFB97718FFB87812FFB87911FF
+ B87911FFB87911FFB87911FFB87911FFB87911FFB87911FFB97A12FFB97A12FF
+ B87911FFB87911FFB87812FFB77711FFB77711FFB77711FFB6770FFFB87911FF
+ B97A12FFB87911FFB7790FFFB6780EFFB87A0EFFBA7C10FFB6780EFFB87911FF
+ B97913FFB87812FFB77613FFB87715FFBC7A1BFFBF7D1EFFB87415FFBC7819FF
+ BF791EFFBF7820FFBB771EFFBB781CFFBD7C1AFFBB7D19FFB37811FFB47814FF
+ B77A18FFB97D1DFFB97D1DFFB67D1AFFB47D14FFB57C13FFB97B15FFBB7D19FF
+ B8801BFFBA831BFFBE841BFFC1841CFFC3831DFFBD7F25FFC8944DFFB9925EFF
+ C8B394FFFAF0DFFFFBF9EFFFECEBE7FFF2EFEAFFDAD6D5FFEDE9EEFFEAEBEFFF
+ E9F0EDFFEBF2EDFFF2F2F2FFF7F1F6FFF8F1F8FFF6F2F7FFECF0EBFFF6F6EAFF
+ EFE3D1FFCBAE93FFB2855AFFBD874AFFC18F37FFAE7A15FFB67B14FFBC7D15FF
+ BC7D15FFB97B11FFB7790FFFB6780CFFB87A0EFFB97C0EFFBE8211FFBD8110FF
+ BC800EFFBB7F0DFFBB800CFFBC810DFFBD820EFFBE830FFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBD7F0DFFBF810FFFC18311FFC28511FFBC7F09FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFC1840EFFBE810BFF
+ BA7D07FFBA7D07FFBC7F09FFBD800AFFBC7F09FFBA7D07FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC7F09FFBE800EFFBE800EFF
+ BE7F0FFFBE800EFFBE7F0FFFBE800EFFBE7F0FFFBE800EFFBD7E0EFFBD7F0DFF
+ BC7D0DFFBB7D0BFFBB7C0CFFBC7E0CFFBD7E0EFFBE7F0FFFB77A0CFFBD8012FF
+ BF8214FFBD8012FFBC7F11FFBE8113FFBC7F11FFB77A0CFFBA7D0FFFBA7D0FFF
+ BA7D0FFF442C18FF462E1AFF492F1EFF4B3121FF4D3021FF4C2F21FF4D2D20FF
+ 4F2E1FFF4E2A1AFF4E2915FF4E2810FF4E2A0CFF532E0CFF59360EFF613E12FF
+ 6A4316FF734319FF7F4815FF8D520CFF945D0CFF8F6617FF986F1AFFAC7814FF
+ B17A17FFAD7827FF846234FF636167FF50638EFF375695FF335AA5FF3F68B7FF
+ 3D66B5FF4C71BBFF456AB4FF3C63AEFF3C62B0FF4165B1FF4265AFFF3E5EA7FF
+ 39579EFF38549BFF334F96FF2C4993FF2D468EFF304687FF32437CFF323B6DFF
+ 333460FF38325BFF3C3256FF3E324EFF45363EFF523827FF6D4A29FF663C19FF
+ 62381BFF533121FF4B2E20FF492E1AFF4B2F17FF553119FF57331BFF543320FF
+ 513320FF54351EFF54361DFF53351CFF503219FF4D2F16FF4C2E15FF4C2E15FF
+ 4D2F16FF4B2D14FF4C2E15FF4D2F16FF4E3017FF4F3118FF4F3118FF4F3118FF
+ 4F3118FF4D2F16FF4C3018FF4F311EFF50321FFF53311AFF5C3515FF744616FF
+ 8E5A17FFAC731EFFB47916FFB87C12FFB97B0FFFB87A10FFBA7812FFBB7716FF
+ BB7716FFB77810FFB7790DFFB7790DFFB7790DFFB7790DFFB7790FFFB7790FFF
+ B77810FFB97A12FFB97A12FFB87911FFB87911FFB87812FFB77711FFB77711FF
+ B77711FFB6770FFFB87911FFB97A12FFB87911FFB6780EFFB6780EFFB97B0FFF
+ BB7D11FFB87A10FFB97B11FFB97A12FFB87812FFB67610FFB77613FFBB7A18FF
+ BE7D1BFFB97613FFBC7916FFBD791AFFBC771AFFBD781BFFC07C1DFFBD7D17FF
+ BA7B13FFB97B11FFB77B11FFBC7C16FFBF811DFFBE801AFFB97C14FFB57A0CFF
+ B4790BFFBF8117FFBE801AFFBB831EFFBC841FFFBF851CFFC0831BFFC07F1DFF
+ B47B26FFB28649FFD3B68FFFE7D9C6FFF6F3EBFFF6F7F3FFE0E3E1FFDDDCD8FF
+ D8D6D5FFEDEBF1FFECECF2FFEAF1EEFFEBF2EDFFF1F1F1FFF6F0F5FFF8EFF9FF
+ F8F1F6FFFFFEF6FFF8F2DFFFE3CEAEFFBF9B6DFFAD773BFFB37829FFB9821FFF
+ B57F14FFBE8218FFC08218FFBE8016FFBB7D11FFBA7C10FFBC7F11FFBA7D0FFF
+ B6790BFFBA7E0DFFBA7E0DFFBB7F0DFFBB7F0DFFBC810DFFBC810DFFBC810DFF
+ BC810DFFBB7D0BFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFF
+ BB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFFBE800EFF
+ BE810DFFBC7F09FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBF820CFFBD800AFFBB7E08FFBB7E08FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FFBC8008FF
+ BC7F09FFBD7F0DFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFFBF8010FF
+ C08111FFBA7D0FFFBF8214FFC18416FFBD8012FFBB7E10FFBD8012FFBD8012FF
+ BA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFF432B19FF472F1DFF4D3322FF4F3223FF
+ 4F3021FF4F2C1EFF522E1CFF57301AFF572E15FF592D0EFF5B3009FF603405FF
+ 693D07FF744B0CFF815714FF8D5F18FF9C661FFFA76A1AFFB37112FFB47610FF
+ A97816FFA97814FFB1790AFFB47807FFB87A14FF996A26FF736454FF58617CFF
+ 415A92FF3E5EA9FF4667B6FF4364B3FF4B6EB8FF466BB5FF4168B3FF4066B4FF
+ 4266B2FF4164AEFF3E5EA7FF3B59A0FF3B58A2FF37549EFF324F9AFF314A92FF
+ 32488AFF32427DFF323A6FFF323562FF3B365DFF382F50FF39304AFF463843FF
+ 51392DFF614229FF593216FF5B351DFF4F3021FF492E20FF472E1AFF4A3117FF
+ 533218FF563319FF51301CFF4F2F1CFF50311AFF4E3017FF4D2F16FF4E3017FF
+ 503219FF52341BFF53351CFF53351CFF4D2F16FF4D2F16FF4D2F16FF4E3017FF
+ 4F3118FF503219FF52341BFF52341BFF53381EFF52361EFF523421FF52331EFF
+ 563115FF63390FFF825016FFA0671CFFB5781BFFB87A14FFB87B13FFB87B13FF
+ B87A14FFBA7916FFBB7815FFBB7913FFB7790DFFB77A0CFFB77A0CFFB77A0CFF
+ B77A0CFFB7790DFFB7790DFFB7790FFFB97B11FFB97B11FFB87911FFB87911FF
+ B87911FFB77810FFB77711FFB77711FFB67610FFB77711FFB87911FFB77810FF
+ B6780EFFB6780EFFB97B0FFFBC7E12FFB97B0FFFBA7C12FFB97B11FFB77810FF
+ B67610FFB77613FFBA7916FFBE7E18FFB97B11FFBA7C12FFB97913FFB87714FF
+ BE7B18FFC2801AFFBF7E15FFB8780CFFBD7D11FFB97B0FFFBD7B14FFC1811BFF
+ C1811BFFBB7C14FFB97B0FFFBA7D0FFFBD7F15FFBC7F17FFB9811CFFBB831EFF
+ C0821CFFBF811DFFBB7C20FFAC782CFFB18D5DFFECD9BEFFFBF6EDFFEAECECFF
+ ECEEEEFFE3E5E5FFDCDEDEFFEDEDEDFFF2F0F6FFEFF0F4FFEDF2F0FFECF2EDFF
+ F0EFF1FFF2EEF4FFF5EBF7FFF7EEF1FFFFFEF1FFEDDEBEFFCBAB7AFFB48848FF
+ B87D2EFFB97B1DFFB77F12FFBC8413FFB97E11FFBF8115FFBE8014FFBB7D11FF
+ BA7C10FFBD8012FFBC7F11FFB97D0CFFBB7F0EFFBB7F0EFFBA7E0CFFBA7E0CFF
+ BA7F0BFFBA7F0BFFB97E0AFFB97E0AFFBD7F0DFFBE800EFFBF810FFFC08210FF
+ C08210FFBF810FFFBE800EFFBD7F0DFFBF810FFFC08210FFC08210FFC08210FF
+ BF810FFFBC7E0CFFBA7C0AFFB87B07FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BB7E08FFBB7E08FFBD800AFFBF820CFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBF810FFFBE800EFFBC7E0CFFBB7D0BFF
+ BC7E0CFFBE800EFFC08210FFC28313FFBE8113FFC38618FFC38618FFBE8113FF
+ BB7E10FFBE8113FFC08315FFBE8113FFBA7D0FFFBA7D0FFFBA7D0FFF442810FF
+ 4C2E15FF53341BFF55341AFF523013FF522C0CFF562E0BFF5E340AFF613506FF
+ 6D3F09FF7D4E10FF8E5D17FF9A691DFFA1711FFFA4731DFFA9761AFFB17619FF
+ B87714FFBD7B0BFFBB7C09FFB47B0EFFB37C0DFFBA7D09FFBC7C06FFB67201FF
+ A7711AFF826742FF626066FF4D6190FF4666ADFF4766B1FF4462AFFF4063ADFF
+ 4166B0FF4269B4FF4269B7FF4067B2FF4063ADFF4161AAFF4260A7FF415EA8FF
+ 3D5AA4FF37549FFF334E98FF34498DFF32417FFF323970FF323562FF3C3960FF
+ 332E4BFF352E43FF473A42FF4F3A32FF5C3E2BFF4D2B14FF523019FF4B2E1FFF
+ 472E1EFF47301AFF4C3418FF523516FF533316FF4E2D19FF4A2A17FF54351EFF
+ 51331AFF4E3017FF4E3017FF503219FF52341BFF52341BFF503219FF4F3118FF
+ 4F3118FF4F3118FF4F3118FF503219FF52341BFF54361DFF55371EFF51351DFF
+ 4F331BFF50311AFF523215FF5B340EFF6E420DFF955E19FFB67A26FFB9791AFF
+ BA7A14FFB77913FFB87A14FFB97B17FFBB7A17FFBC7A14FFBC7A11FFB97A0CFF
+ B77B0AFFB77B0AFFB77B0AFFB77A0CFFB77A0CFFB7790DFFB7790DFFB97B11FF
+ B97B11FFB87911FFB87911FFB87911FFB77810FFB77711FFB77711FFB67610FF
+ B77711FFB87911FFB77810FFB6780EFFB6780EFFB97B0FFFBD7F13FFBB7D11FF
+ BB7D11FFBA7C12FFB7790FFFB5760EFFB67610FFB97913FFBD7E16FFBA7D0FFF
+ B87E0DFFB87A10FFB77810FFBC7D15FFC2831BFFBF7F13FFB67709FFBB7C0EFF
+ B8780CFFBA7811FFC17F19FFC3811BFFC07E18FFC07F16FFC58519FFB7790FFF
+ B57B12FFB77C18FFBA7F1CFFBF811DFFBD8020FFB67C2AFFA47838FFD2B894FF
+ F9EFDEFFFCFDFBFFDEE3E6FFE4E8E9FFF1F3F4FFE9EDEEFFF0F2F3FFECEAF0FF
+ ECEBEFFFEEEFEDFFEDF0EEFFEFF0F4FFF3F0F9FFF9F1FCFFFFF5F5FFFEEBD6FF
+ DCC195FFB28845FFA6721FFFBE8022FFC7861DFFBA810EFFB87F0BFFB17504FF
+ B97C0EFFBC7E12FFB87B0DFFB6790BFFB97C0EFFBC800FFFBB7F0EFFBE8211FF
+ BC800FFFBA7E0CFFB87C0AFFB77C08FFB77C08FFB77C08FFB77C08FFBE800EFF
+ BF810FFFC08210FFC18311FFC18311FFC08210FFBF810FFFBE800EFFB87A08FF
+ BA7C0AFFBE800EFFC08210FFC18311FFC08210FFBE800EFFBC7E0CFFBC7F0BFF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBA7D07FF
+ BC7F09FFBD800AFFBC7F09FFBA7D07FFBA7D07FFBE810BFFC1840EFFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F0BFFBC7F0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFC08210FF
+ BE800EFFBD7F0DFFBC7E0CFFBC7E0CFFBE800EFFC18311FFC38513FFBA7E0DFF
+ BF8214FFBE8113FFB87B0DFFB5780AFFB87B0DFFBB7E10FFBB7E10FFBA7D0FFF
+ BA7D0FFFBA7D0FFF542E0BFF542F09FF573107FF5C3606FF654008FF714A0CFF
+ 7D540FFF855B0EFF996A18FF9E6E16FFA47415FFAA7717FFAD7817FFAE7714FF
+ AE7611FFAF750CFFB27507FFB67806FFB97A07FFB87A04FFB67705FFB57705FF
+ B77805FFBD7A05FFBD7702FFB47612FF8F682AFF6A5D4DFF4A5D80FF3A5A9BFF
+ 415EA8FF4E6DB8FF4164ADFF3E63ADFF3B62ADFF3960AEFF3960ABFF3D62ACFF
+ 4465AEFF4767B0FF4766B1FF4160ABFF3553A0FF304B95FF34498DFF364885FF
+ 333D73FF2C315EFF343458FF34314BFF343141FF3F353BFF4B3831FF4E3424FF
+ 4F2F1CFF4E2F1AFF4C301FFF48301CFF493119FF4D3517FF543815FF563716FF
+ 503118FF4C2B17FF4E2F18FF4F3118FF4F3118FF4F3118FF4F3118FF4E3017FF
+ 4D2F16FF4D2F16FF4F3118FF4F3118FF503219FF503219FF51331AFF52341BFF
+ 52341BFF52331CFF4B2C17FF55361FFF583A1FFF57330FFF623908FF835311FF
+ A56D1CFFB8791DFFBB7716FFBB7815FFB97816FFB77816FFB57816FFB77913FF
+ BC7A11FFBC7B0EFFB87909FFB67A08FFB67A08FFB67A08FFB77B0AFFB77B0AFF
+ B77A0CFFB77A0CFFB7790DFFB97B0FFFBB7D13FFBD7F15FFBD7E16FFBB7C14FF
+ B97A12FFB77810FFBC7C16FFBC7C16FFBB7C14FFBB7C14FFBA7C12FFB97B11FF
+ B97B0FFFB97B0FFFBA7D0FFFB97C0EFFB97B0FFFB87A10FFB7790FFFB77810FF
+ B6770FFFB6780EFFBA800FFFB67F0CFFB4790CFFB1750BFFB0740AFFB2760CFF
+ B77A0CFFB97D0CFFB97C0EFFB97B0FFFBA7A14FFBA7916FFBC7916FFBD7A17FF
+ BD7B14FFBB7D13FFC58820FFB67B14FFB97E1AFFB57816FFBA7A1BFFCB8F36FF
+ A7752DFFBF9C6AFFFDEED4FFEFEDE5FFE9ECF0FFE7EBF0FFE7E9EAFFE7E9E9FF
+ E9ECF0FFEDF0F4FFF2F1F5FFFAF8F8FFEEEAE9FFEEECECFFF0EFF8FFEAE9F3FF
+ F5F0F9FFFFFBF5FFDCC09EFFB28A4FFFAB7522FFBF8220FFBE7D14FFB57606FF
+ B87D09FFBD820EFFB67A09FFB77B0AFFB87B0DFFB97D0CFFBB7F0EFFBD8110FF
+ BE8211FFBF8312FFBF8311FFBF8311FFBF8311FFBE8210FFBE8210FFBD810FFF
+ BC810DFFBC810DFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBA7D09FFBA7D09FFBC7F0BFFBD800CFFBD800CFFBC7F0BFF
+ BA7D09FFBA7D09FFBE810DFFBC7F0BFFBA7D09FFBB7E0AFFBE810DFFBF820EFF
+ BD800CFFBB7E0AFFBA7D07FFBB7E08FFBD800AFFBF820CFFBF820CFFBD800AFF
+ BB7E08FFBA7D07FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFB97C08FFBA7D09FFBB7E0AFFBC7F0BFFBC7F0BFFBB7E0AFF
+ BA7D09FFB97C08FFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFF
+ BD800CFFBD800CFFBC7F0BFFBD800CFFBE810DFFBF820EFFBF820EFFBE810DFF
+ BD800CFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBD800CFF
+ BE810DFFBF810FFFBD8110FFBA7D0FFFB77A0CFFB77A0CFFBA7D0FFFBC7F11FF
+ BC7F11FFBA7D0FFFBC7F11FFBC7F11FFB47709FF70430AFF75490EFF7E5213FF
+ 895C18FF94691AFF9D7019FFA27619FFA77914FFA5750BFFAA760BFFAD780AFF
+ B0790AFFB2790CFFB4790CFFB6780CFFB6790BFFB47905FFB67C05FFB57C09FF
+ B87A08FFB97805FFBA7704FFB77707FFBB7908FFBF7903FFBA790DFF9C6B1BFF
+ 79623CFF566477FF45649BFF4061A6FF4265AFFF3B61A9FF3961A9FF3A62ADFF
+ 3B62B0FF3E65B0FF4166B0FF4666B1FF4767B0FF4160ABFF3D5CA7FF33519EFF
+ 2E4894FF2F458CFF334483FF323B74FF2D325FFF363759FF37344DFF373443FF
+ 3F383DFF493631FF4A3024FF4B2D1CFF4D2E19FF4A2F1BFF48301AFF483117FF
+ 4E3515FF533813FF533714FF4F3116FF4C2C15FF503219FF4F3118FF4F3118FF
+ 4E3017FF4E3017FF4E3017FF4E3017FF4E3017FF4E3017FF4F3118FF4F3118FF
+ 4F3118FF503219FF51331AFF51331AFF51321BFF482914FF533119FF573413FF
+ 5B3407FF734809FF986719FFB4781EFFB97816FFBC7815FFBC7815FFB97718FF
+ B77719FFB57816FFB77913FFBC7B0EFFBC7D0BFFB97B09FFB77B09FFB77B0AFF
+ B77B0AFFB77B0AFFB67A09FFB6790BFFB6790BFFB7790DFFB87A0EFFBA7C12FF
+ BC7E14FFBC7D15FFBA7B13FFB87911FFB77810FFB97913FFB97913FFB97913FF
+ B87911FFB87A10FFB7790FFFB7790DFFB6780CFFB87B0DFFB87B0DFFB87A0EFF
+ B87A0EFFB87A10FFB87A10FFB87911FFB67A10FFB87E0DFFB67E0DFFB67D10FF
+ B67C12FFB87B13FFB77B11FFB77C0EFFB77D0CFFBA7D0FFFBA7C10FFBA7A14FF
+ BA7916FFBA7916FFBC7916FFBD7B14FFBB7D13FFB98017FFB37912FFBB801DFF
+ BD8022FFB87A20FFB47C2DFFA57B40FFD8BE99FFFCF5E6FFEBF0EFFFE8ECF1FF
+ E7EBF0FFECECECFFECECECFFE7EBF0FFE6EAEFFFF3F3F3FFFBF7F6FFF3EEEDFF
+ F2EDEEFFEFEEF8FFEEEDF7FFF2EDEFFFF1E1D0FFAF8B5DFFA37027FFAD7010FF
+ C18013FFBE7F0DFFBB7E0AFFBF8410FFBD820EFFB87C0AFFB87C0BFFB97D0CFF
+ BA7E0DFFBB7F0EFFBD8110FFBE8211FFBE8211FFBE8210FFBE8210FFBD810FFF
+ BD810FFFBD810FFFBD810FFFBC810DFFBC810DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7D09FFBB7E0AFFBC7F0BFF
+ BD800CFFBD800CFFBC7F0BFFBB7E0AFFBA7D09FFBF820EFFBD800CFFBB7E0AFF
+ BC7F0BFFBE810DFFBF820EFFBD800CFFBB7E0AFFBA7D07FFBB7E08FFBD800AFF
+ BF820CFFBF820CFFBD800AFFBB7E08FFBA7D07FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBD800CFFBD800CFFBF820EFF
+ BF820EFFBF820EFFBF820EFFBD800CFFBD800CFFBD800CFFBD800CFFBD800CFF
+ BD800CFFBD800CFFBD800CFFBD800CFFBD800CFFBC7F0BFFBC7F0BFFBD800CFF
+ BE810DFFBE810DFFBD800CFFBC7F0BFFBC7F0BFFBD800CFFBC7F0BFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBC7F0BFFBD800CFFBE800EFFBD8110FFBB7E10FFB97C0EFF
+ BA7D0FFFBC7F11FFBD8012FFBC7F11FFBB7E10FFBE8113FFBD8012FFB77A0CFF
+ 9F6817FFA26C19FFA8721BFFAB761BFFAE7918FFAE7813FFAC760BFFAA7506FF
+ B37B0AFFB27B08FFB37908FFB47807FFB67709FFB7770BFFB9790DFFB87A0EFF
+ B17B09FFAF7D0DFFAE7C12FFB27910FFB97609FFBA7506FFB6750CFFB7770BFF
+ BE7B08FFBB7B0BFFA7700FFF84672AFF64696AFF506E97FF4167A7FF365FA8FF
+ 365EA6FF3860A8FF3A62ADFF3C66B1FF4169B4FF436AB4FF4669B3FF4768B1FF
+ 3E5DA8FF3D5CA7FF3755A2FF324C98FF31478FFF334385FF343C77FF313565FF
+ 36385BFF37374FFF3B3945FF413A3DFF463532FF462D23FF4A2C1BFF4E2F1AFF
+ 492E19FF492F17FF4A3117FF4E3515FF533911FF523712FF4F3116FF4C2D16FF
+ 52341BFF51331AFF4F3118FF4D2F16FF4D2F16FF4D2F16FF4E3017FF4F3118FF
+ 4E3017FF4E3017FF4E3017FF4E3017FF4F3118FF4F3118FF4F3118FF4F3118FF
+ 4B2B14FF523013FF593309FF663E04FF895B0EFFAE791FFFBB7F1BFFB5730CFF
+ BC7813FFBB7716FFB97619FFB77719FFB77816FFB97A12FFBB7C0CFFBC7D0AFF
+ BB7C0CFFB97D0CFFB87B0DFFB77A0CFFB77A0CFFB6790BFFB5770BFFB5770BFF
+ B6780CFFB7790DFFB97B11FFBA7C12FFBA7C12FFB97B11FFB7790FFFB6770FFF
+ B67610FFB67610FFB67610FFB6770FFFB5770DFFB5770DFFB5770BFFB5780AFF
+ B6790BFFB6790BFFB77A0CFFB87B0DFFB97B0FFFBA7C10FFBA7C12FFB87C12FF
+ B57A0DFFB67D10FFBB8118FFBE831CFFBE831CFFBB8118FFB77E11FFB57D0EFF
+ B97E10FFB97E11FFB87B13FFB87A14FFB87A14FFBA7A14FFBA7C12FFB87D10FF
+ B27B12FFAF7914FFBA7E1EFFC1852BFFB17928FFA47432FFB59467FFF6E5CBFF
+ F9F6F1FFE9EFF4FFE6EAEFFFE8EBEFFFEFEFEFFFF1F1F1FFE9EDF2FFE5EAEDFF
+ EEEFEDFFF4F1EDFFF7EFEFFFF7F0F3FFF5F2FBFFFFFDFFFFFEF4EDFFE1CCADFF
+ AB7F42FFB67B25FFC8841BFFD08B16FFC1820FFFBE830FFFC08511FFB57C09FF
+ BA7E0CFFBA7E0CFFBB7F0DFFBB7F0DFFBC800EFFBC800EFFBD810FFFBD810FFF
+ BB7F0DFFBB7F0DFFBB7F0DFFBC800EFFBC800EFFBC800EFFBC800EFFBC800EFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7F0BFFBC7F0BFFBD800CFFBE810DFFBE810DFFBD800CFFBC7F0BFFBC7F0BFF
+ BF820EFFBE810DFFBD800CFFBD800CFFBF820EFFBF820EFFBE810DFFBD800CFF
+ BA7D07FFBB7E08FFBD800AFFBE810BFFBE810BFFBD800AFFBB7E08FFBA7D07FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BD800CFFBE810DFFBE810DFFBF820EFFBF820EFFBE810DFFBE810DFFBD800CFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BB7E08FFBC7F09FFBD800AFFBD800AFFBD800AFFBD800AFFBC7F09FFBB7E08FF
+ BE810BFFBD800AFFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBC7F09FFBD800CFF
+ BD8110FFBC7F11FFBB7E10FFBC7F11FFBD8012FFBD8012FFBC7F11FFBA7D0FFF
+ BF8214FFBE8113FFBA7D0FFFB17511FFB0750EFFAF750CFFAF7309FFAF7309FF
+ AF7407FFB27507FFB27605FFB87C0BFFB97A0AFFB87909FFB8790BFFB8770BFF
+ B9780CFFB9770EFFB5790FFFAF7B10FFAB7D12FFAC7B17FFAF7914FFB8770BFF
+ B87409FFB4750DFFB5760EFFB97706FFBB7C0AFFB07508FF916A1CFF6F6A55FF
+ 5C7389FF476EA5FF3562ABFF3963AAFF3A64ABFF3C65AEFF3D67B2FF426AB5FF
+ 436AB4FF4669B3FF4667B0FF4160ABFF4361AEFF3F5DACFF3753A0FF344B96FF
+ 354689FF353F7BFF353A6BFF35365CFF383751FF3C3A46FF423C3DFF463532FF
+ 462D23FF492D1CFF51321DFF4C3018FF4D3218FF51331AFF533719FF543A12FF
+ 543914FF513419FF4F3019FF54361DFF52341BFF4F3118FF4D2F16FF4C2E15FF
+ 4D2F16FF4F3118FF503219FF4D2F16FF4D2F16FF4D2F16FF4D2F16FF4D2F16FF
+ 4E3017FF4E3017FF4F3017FF523117FF583311FF643B0AFF7C4F0CFF9F6C16FF
+ B77E1BFFB97C14FFB27108FFBB7913FFBB7716FFB77719FFB77719FFB77915FF
+ B97B11FFBB7D0BFFBB7D0BFFBA7D0FFFBA7C10FFB97B0FFFB87A0EFFB7790DFF
+ B6780CFFB5770BFFB5770BFFB5770BFFB6780CFFB7790FFFB87A10FFB87A10FF
+ B7790FFFB6780EFFB5760EFFB67610FFB67512FFB67610FFB6770FFFB6770FFF
+ B5770BFFB5770BFFB5780AFFB87B0DFFB87B0DFFB87B0DFFB97C0EFFB97B0FFF
+ B97B0FFFBA7C12FFBA7C12FFB4790CFFB67C12FFBD7F19FFBF831FFFC28420FF
+ BD821BFFBA7F12FFB77C0EFFB97E10FFB97E11FFB97C14FFB87A14FFB87A14FF
+ B87C12FFBA7C10FFB67E0FFFB57F14FFB07C17FFB57D1EFFB7802BFFA97630FF
+ AF8752FFD6BF9FFFFCF3E5FFEDEFEFFFE5EBF0FFE5E9EEFFE7EAEEFFEEEDEFFF
+ F1F0F2FFEBF0F3FFEAEFF2FFE9EAE8FFECE9E5FFF3EDEEFFF5EEF1FFF8F1F8FF
+ FFFEFEFFFFF0DDFFD0B387FFAF7E34FFBE7F1DFFC98415FFC9840FFFBB7C0AFF
+ BC800FFFBE8512FFB67D0AFFBC800EFFBC800EFFBC800EFFBC800EFFBC800EFF
+ BC800EFFBC800EFFBC800EFFB97D0BFFB97D0BFFBA7E0CFFBA7E0CFFBB7F0DFF
+ BC800EFFBC800EFFBC800EFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBE800EFFBE800EFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD800CFFBD800CFFBE810DFFBE810DFFBE810DFF
+ BE810DFFBD800CFFBD800CFFBF820EFFBF820EFFBE810DFFBE810DFFBF820EFF
+ BF820EFFBF820EFFBE810DFFBB7E08FFBC7F09FFBD800AFFBE810BFFBE810BFF
+ BD800AFFBC7F09FFBB7E08FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBA7D09FFBA7D09FFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBA7D09FFBA7D09FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFF
+ BC7F09FFBC7F0BFFBC7F09FFBF820EFFBE810BFFBD800CFFBB7E08FFBB7E0AFF
+ BB7E08FFBB7E0AFFBC7F0BFFBB7F0EFFBB7E10FFBC7F11FFBD8012FFBD8012FF
+ BC7F11FFBA7D0FFFB87B0DFFBD8012FFBD8012FFBB7E10FFB77806FFB57604FF
+ B37303FFB37303FFB47307FFB8770BFFBB7A11FFBE7C15FFB8760FFFB8760FFF
+ B97710FFB97710FFB97710FFB9780FFFB8770EFFB3770DFFAB7B12FFA97C15FF
+ AD7B17FFB17914FFB7770BFFB67509FFB2750DFFB3760EFFB27305FFB87909FF
+ B87808FF9F6D13FF7E673AFF6B7071FF5074A2FF3D6EB4FF426CB1FF406AB1FF
+ 3E67B0FF3C66B1FF4068B3FF4168B2FF4265AFFF4162ABFF4060ABFF4363AFFF
+ 4160AFFF3A56A3FF354C97FF354689FF343E7AFF34386BFF31335CFF343452FF
+ 3A3A46FF433C3FFF463735FF473028FF4C301FFF543520FF503019FF52331AFF
+ 55351EFF56381DFF563B16FF563B16FF53361BFF53341DFF55371EFF53351CFF
+ 503219FF4D2F16FF4C2E15FF4D2F16FF4F3118FF503219FF4D2F16FF4D2F16FF
+ 4D2F16FF4D2F16FF4D2F16FF4D2F16FF4D2F16FF4E3015FF553413FF5D370DFF
+ 75490EFF946317FFAE781AFFB67B14FFBA7A0EFFBA7A0EFFB97A12FFB77915FF
+ B77816FFB77816FFB77913FFB97B0FFFBB7C0CFFBB7C0CFFBB7D11FFBA7C12FF
+ BA7C12FFB97B11FFB7790FFFB6780EFFB6780EFFB5770DFFB6780EFFB6780EFF
+ B7790DFFB7790DFFB7790DFFB7790DFFB6780CFFB6780EFFB77711FFB77613FF
+ B77711FFB87911FFB87911FFB87A0EFFB87A0EFFB87B0DFFBA7E0DFFBA7E0DFF
+ BA7E0DFFB97D0CFFB97C0EFFB97C0EFFB87A0EFFB87A0EFFB7790DFFB77B11FF
+ BC7C16FFBD7F1BFFBF7F19FFBC7F17FFBC7E12FFBA7D0FFFBA7E0DFFBA7D0FFF
+ BA7C12FFBA7B13FFBA7B13FFBA7C10FFBA7D0FFFB67E0DFFB68113FFB6831BFF
+ B88426FFAE7A2DFFA57A41FFCAAB84FFF8E9D6FFF5F2EAFFE7E9E9FFE6EBEEFF
+ E8EBEFFFE9EAEEFFE8E9EDFFE8EAEBFFEAEEEFFFEFF1F1FFECEDEBFFE9E7E6FF
+ F1ECEEFFF2EBEEFFF4EBEEFFFFF3EAFFECD3B3FFBC975DFFB6842CFFBC8114FF
+ C27E0DFFC27E0DFFBD7D11FFBD8215FFBF8716FFBB8411FFBA810DFFBC810DFF
+ BC810DFFBB800CFFBB800CFFBB800CFFBB800CFFBA7F0BFFB97D0BFFB97D0BFF
+ B97D0BFFBA7E0CFFBA7E0CFFBB7F0DFFBB7F0DFFBC800EFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE800EFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFFBF810FFF
+ BF810FFFBF810FFFBE800EFFBE800EFFBF810FFFBF820EFFBB7E08FFBC7F09FF
+ BD800AFFBD800AFFBD800AFFBD800AFFBC7F09FFBB7E08FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7E0AFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBD800CFF
+ BC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBD7F0DFFBD800CFFBF810FFFBE810DFF
+ BD7F0DFFBB7E0AFFBB7D0BFFBB7E0AFFBB7D0BFFBC7E0CFFB97D0CFFBA7D0FFF
+ BC7F11FFBC7F11FFBB7E10FFB97C0EFFB87B0DFFB77A0CFFBA7D0FFFBA7D0FFF
+ BC7F11FFBC7C06FFBC7C06FFBB7A07FFB87907FFBA770AFFB7760AFFB6740BFF
+ B5720BFFB7740DFFB8750EFFB8760FFFB97710FFB9780FFFB9790DFFB8790BFF
+ B3780BFFAB790FFFAB7B12FFB27B12FFB37A0DFFB47709FFB37608FFB2760CFF
+ B1770DFFAD7107FFB67709FFBE7A09FFAC710EFF8E6625FF786D59FF577499FF
+ 4474B6FF4973B8FF456FB6FF3E69B2FF3C66B1FF3E66B1FF3E65AFFF3D60AAFF
+ 3B5CA5FF3B5BA7FF3F5EADFF3D5BACFF3853A3FF344B96FF344489FF323C78FF
+ 2E3469FF303360FF343353FF393947FF433C3FFF483839FF49312BFF4E3122FF
+ 563521FF512F18FF56311BFF5A3521FF59371FFF573B18FF563A17FF54371CFF
+ 55361FFF55371EFF54361DFF51331AFF4F3118FF4E3017FF4E3017FF4E3017FF
+ 4F3118FF4E3017FF4E3017FF4E3017FF4D2F16FF4D2F16FF4D2F16FF4C2E15FF
+ 4D2F12FF54330CFF663E0DFF855815FFA6721FFFB87C1CFFB87A10FFBB7B0FFF
+ C28216FFB77A12FFB57A13FFB57915FFB57A13FFB97B11FFB97B0FFFBB7C0CFF
+ BB7C0EFFBA7C12FFBA7B13FFB97913FFB97A12FFB87911FFB7790FFFB7790FFF
+ B7790FFFB6780EFFB6780EFFB7790DFFB7790DFFB7790DFFB7790DFFB6780CFF
+ B6780EFFB87812FFB87714FFB87812FFB97A12FFB97A12FFBA7C10FFBA7C10FF
+ BA7D0FFFBC800FFFBC800FFFBB7F0EFFBA7E0DFFB97C0EFFB87B0DFFB87A0EFF
+ B87A0EFFBB7C0EFFBB7B0FFFBB7912FFBC7A14FFBC7A13FFBC7B12FFBC7D0FFF
+ BA7E0DFFBB7C0CFFB97C0EFFB97B11FFBA7B13FFBB7D13FFBB7D11FFBC800FFF
+ BA800FFFB37E0FFFB7841CFFBE8A30FFAD7F38FFB99567FFE4CDB3FFFFFBF1FF
+ F1EFEEFFE9EBEBFFEAEEEFFFEEEFF3FFEAEBEFFFE5E5EBFFE4E5E9FFE9E9E9FF
+ EDEEECFFF2F0EFFFECEDEBFFF1F0F2FFF6F1F3FFFDF0EEFFF8E1D1FFD7B58AFF
+ BB914AFFBD8B27FFC08714FFC18210FFC58215FFC3811BFFBE801AFFB88011FF
+ B47F0AFFB87F0BFFBA7F0BFFBA7F0BFFBA7F0BFFBA7F0BFFBA7F0BFFBA7F0BFF
+ BA7F0BFFBA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBB7F0DFFBB7F0DFF
+ BB7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBE800EFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BE800EFFBD7F0DFFBE800EFFBF810FFFBF810FFFBD7F0DFFBD7F0DFFBE800EFF
+ BF820EFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBF810FFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBE800EFFBE800EFF
+ BF810FFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBF8010FFBE7F0FFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBE7F0FFF
+ BF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFF
+ BD7E0EFFBA7D0FFFBC7F11FFBD8012FFBC7F11FFBA7D0FFFB87B0DFFB87B0DFF
+ B87B0DFFB87B0DFFB97C0EFFBD8012FFB37402FFB47503FFB67705FFB67707FF
+ B77707FFB57608FFB37406FFB27305FFB67709FFB67709FFB67606FFB77707FF
+ B77806FFB87906FFBA7B08FFB87C0AFFAD780AFFB17A0BFFB97C06FFB97C04FF
+ B47905FFB17805FFB27709FFB2790CFFAE740BFFB17309FFBF7809FFBA750EFF
+ A46919FF896C47FF5E708DFF446FAEFF4B75B8FF4670B7FF406BB4FF3E68B3FF
+ 4068B3FF3D64AEFF395CA6FF34559EFF3757A3FF3A59A8FF3A58A9FF3752A2FF
+ 364D98FF38488DFF353E7DFF30356CFF343567FF343458FF393848FF433C41FF
+ 4B383BFF4D322EFF503122FF55321EFF502B15FF562F19FF5A3220FF59341EFF
+ 563716FF533715FF53351CFF523520FF55361FFF54361DFF53351CFF51331AFF
+ 4F3118FF4E3017FF4D2F16FF4D2F16FF4F3118FF4F3118FF4E3017FF4E3017FF
+ 4D2F16FF4D2F16FF4C2E15FF4F3011FF58360BFF734D13FF97671FFFAF7620FF
+ B97B17FFBC7B0FFFBD7D11FFBD7F13FFB57B12FFB57B12FFB57B12FFB57B11FF
+ B97B0FFFB97C0EFFB97C0EFFB97B0FFFB97A12FFB97913FFB97815FFB97913FF
+ B97913FFB87911FFB87911FFB87911FFB7790FFFB7790FFFB7790DFFB7790DFF
+ B77A0CFFB77A0CFFB77A0CFFB7790DFFB77711FFB77613FFB87812FFB87911FF
+ B97A12FFB97B0FFFBA7C10FFBA7D0FFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFF
+ BA7E0DFFBA7E0DFFBA7D0FFFBC7D0FFFBD7D0DFFBD7D0DFFBC7B0FFFBB7910FF
+ BB7910FFBB7A0EFFBC7C0CFFBB7D0BFFBA7B09FFB97A0AFFBA7910FFBC7A13FF
+ BD7B14FFBE7D14FFBF8012FFBC8211FFB47E0CFFB17E16FFB6842CFFB58B4AFF
+ E3C6A1FFFDEBDAFFF8F3F0FFF1F3F4FFEFEFEFFFEFEFEFFFEEEDEFFFEAEAF0FF
+ E6E8F0FFE6E9EEFFEDECE8FFF0EDE8FFF1EFEEFFECEEEEFFEDF1F2FFF8F6F6FF
+ FFF4EEFFE7C8B1FFBB915CFFBB8A3AFFAD7C10FFB47F0AFFB77D0CFFB97A12FF
+ BD791AFFBA7917FFB17A0BFFAE7904FFB67D09FFB87E07FFB97F08FFB97F08FF
+ B97E0AFFB97E0AFFB97E0AFFB97E0AFFBC810DFFBB800CFFBB7F0DFFBB7F0DFF
+ BB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBB7D0BFFBD7F0DFFBF810FFFBE800EFF
+ BC7E0CFFBB7D0BFFBD7F0DFFBF820EFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBF810FFFBF810FFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBF810FFFBF810FFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7E0EFFC08113FFC08113FFBE7F11FFBE7F11FF
+ BE7F11FFBE7F11FFC08113FFC08113FFBD7E10FFBC7D0FFFBB7C0EFFBB7C0EFF
+ BB7C0EFFBC7D0FFFBD7E10FFBE7F11FFBE8113FFC08315FFC08315FFBE8113FF
+ BA7D0FFFB97C0EFFBA7D0FFFBC7F11FFB97C0EFFBA7D0FFFC08315FFB57608FF
+ B47507FFB47507FFB47507FFB47507FFB47507FFB57608FFB57606FFB77808FF
+ B57705FFB37503FFB27402FFB47502FFB67905FFBB7D07FFBA7F0BFFAE7605FF
+ B27906FFB97D02FFBA7C00FFB17902FFAF7805FFB07807FFB2790CFFB2780FFF
+ B07208FFBC7708FFBE770FFFAE6E16FF956D39FF6D7078FF506D9AFF4F73B3FF
+ 456EB7FF3E6BB4FF406CB3FF436BB3FF3F66ABFF375AA3FF2E519BFF3757A3FF
+ 3A5AA6FF3B59A8FF3954A4FF3A519FFF3A4D98FF364486FF323A75FF35386FFF
+ 333460FF38364CFF423A44FF4A393CFF4D332DFF4E301FFF523019FF4F2812FF
+ 532C16FF56301EFF55321EFF523417FF4E3515FF4C3319FF50341CFF55351EFF
+ 55361DFF53351CFF52341BFF50311AFF4F3019FF4D2F16FF4D2E15FF513318FF
+ 513318FF4F3118FF4F3019FF4E2F18FF4E2F16FF4E3013FF53320BFF653E07FF
+ 8B5D16FFA97522FFB3781BFFB77711FFBD7C10FFBC7C10FFB4760CFFB77B11FF
+ B57B11FFB57B11FFB77C0FFFB97C0EFFB97C0EFFB97B0FFFB97B11FFB97A12FF
+ B97913FFB97913FFB97913FFB97A12FFB97B11FFB97B11FFB97B11FFB87A0EFF
+ B87A0EFFB87A0EFFB77A0CFFB77A0CFFB87B0DFFB87B0DFFB87A0EFFB6770FFF
+ B67610FFB6770FFFB77810FFB87A10FFB87A0EFFB97C0EFFB97C0EFFB87C0BFF
+ B97D0CFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBC7F11FFBE7F0FFFBE7F0CFF
+ BE7F0CFFBC7D0FFFBB7B0FFFBB7B0FFFBA7A0EFFBB7A0DFFBB7B0BFFB97909FF
+ B9780BFFBA7A0EFFB97B11FFBB7C14FFBD7F15FFBE8014FFBD8215FFB77D13FF
+ A97314FFA1742AFFB3905EFFFFEDD4FFFFFDF5FFE8E6E6FFF4F6F7FFF0F0F0FF
+ EEECECFFE9E8EAFFE9E9EFFFEBEDF5FFF0F1F5FFF3F2EEFFF1F1EBFFEAEDEBFF
+ E8EDECFFEAECECFFFAF1EDFFFFECDCFFD1AC86FF996A26FFA97618FFB08010FF
+ BC8A14FFBF8819FFBC7E18FFBC7A1BFFBC7D1BFFB68015FFB5810FFFB57C09FF
+ B77C08FFB77C08FFB87D09FFB87D09FFB97E0AFFB97D0BFFB97E0AFFBD810FFF
+ BD810FFFBC800EFFBC800EFFBB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFFBE800EFF
+ BE810DFFBD7F0DFFBD800CFFBC7E0CFFBB7E0AFFBB7D0BFFBB7E0AFFBC7E0CFF
+ BC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBD7F0DFF
+ BC7F0BFFBA7C0AFFBA7D09FFBA7C0AFFBA7D09FFBC7E0CFFBD800CFFBB7D0BFF
+ BD800CFFBF810FFFBE810DFFBB7D0BFFBA7D09FFBC7E0CFFBE810DFFBD800CFF
+ BC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBD800AFFBC7F0BFF
+ BC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F0BFFBC7E0CFF
+ BB7D0BFFBA7C0AFFB97B09FFB97B09FFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7E0EFFC18214FF
+ C18214FFBF8012FFBE7F11FFBE7F11FFBF8012FFC18214FFC18214FFBC7D0FFF
+ BB7C0EFFBB7C0EFFBB7C0EFFBB7C0EFFBD7E10FFBE7F11FFBF8012FFC28517FF
+ C38716FFC28517FFBF8312FFBC7F11FFBB7F0EFFBD8012FFC08413FFBB7E10FF
+ BB7F0EFFC38618FFB4760CFFB4760CFFB4760CFFB4760CFFB4760AFFB4760AFF
+ B4760AFFB4760AFFB6780CFFB47709FFB27507FFB37706FFB77808FFB67A09FF
+ B67707FFB27605FFB67C0BFFB47B08FFB47B02FFB27900FFAE7803FFAD7907FF
+ AF7A0CFFB37B10FFB67B0EFFB97A0CFFB87605FFB7790FFFB07A23FF956E30FF
+ 7A694EFF6D7380FF506DA6FF3D67B4FF3A6BB1FF4472B2FF4E75B3FF486DABFF
+ 395CA5FF2D519DFF30529EFF3B5AA5FF3E57A1FF4259A7FF3851A7FF2A4498FF
+ 2E448BFF2A3B7AFF313B77FF313568FF343557FF3F394AFF483A3BFF4B3529FF
+ 4F331BFF55341AFF583319FF543018FF502D19FF4E2F1AFF4D331BFF4C351BFF
+ 493418FF4A3117FF56341CFF58341CFF54351CFF52341BFF4F321DFF4E311CFF
+ 4F2F18FF502E16FF583619FF4D2D10FF4B2C13FF553420FF563521FF512F17FF
+ 54320EFF653F09FF966517FFAC7316FFB67A1AFFB57713FFB4750DFFBA7910FF
+ BC7E14FFBB7D13FFB7790FFFB67B0EFFB67B0EFFB97C0EFFB97C0EFFBA7D0FFF
+ BA7D0FFFBB7D11FFB7790FFFB77810FFB7790FFFB7790FFFB6780CFFB6790BFF
+ B6790BFFB67A09FFB47807FFB67A09FFB77B0AFFB6790BFFB47709FFB37509FF
+ B4760AFFB6780CFFB7790DFFB87A0EFFB87A0EFFB97B0FFFB97B0FFFBA7D0FFF
+ BA7D0FFFBB7E10FFB87B0DFFB87B0DFFB87B0DFFB77A0CFFB77A0CFFB87B0DFF
+ B87B0DFFB87C0BFFBB7E0AFFB77D06FFB27A09FFB37C0DFFB57F14FFB98116FF
+ BD7F15FFBE7D11FFBC780DFFC18013FFBC7C10FFB4790CFFB87E14FFB98116FF
+ B47A11FFB1760FFFC08021FFA97021FFA9824EFFECD4B8FFFFFBF3FFF4EFF0FF
+ F8F5F7FFF4F3F5FFEBEAECFFE9E8EAFFE8E7EBFFEAE9EDFFF0EDEFFFF3F1F1FF
+ F3F1F0FFEEF1EFFFEAF5F2FFE7EEEBFFF8F1EEFFFFF8ECFFEEC9A7FFB5894CFF
+ B08028FFB8871BFFAE7D09FFB4810DFFBA8215FFBA8017FFB77C15FFB57D18FF
+ B9821FFFC08B23FFC18618FFC18311FFBD7F0DFFBD7F0DFFBF810FFFC08210FF
+ BD7E0EFFBA7C0AFFC38414FFC08111FFBD7E0EFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BC7D0DFFBA7C0AFFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FF
+ BC7F0BFFBC7F09FFBA7D09FFBA7D07FFB97C08FFB97C06FFBA7D09FFBB7E08FF
+ BD800CFFBE810BFFBE810DFFBE810BFFBD800CFFBC7F09FFBA7D09FFB97C06FF
+ B87B07FFB87B05FFBC7F0BFFBB7E08FFBB7E0AFFBB7E08FFBB7E0AFFBD800AFF
+ BE810DFFBF820EFFBA7D09FFBC7F0BFFBE800EFFBE810DFFBC7E0CFFBC7F0BFF
+ BF810FFFC18410FFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFF
+ BC7E0CFFBC7E0CFFBF810FFFBF810FFFBE800EFFBE800EFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBA7C0AFFBC7E0CFFBD7F0DFFBC7E0CFFB97B09FFB97B09FF
+ BB7D0BFFBE800EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFC08111FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBC7D0DFFB87A08FFB97A0AFFBE800EFFBD7E0EFFB77907FF
+ B67707FFB97B09FFBD7E0EFFBD7F0DFFBD7E0EFFB4750DFFB4750DFFB4750DFF
+ B4750DFFB4760CFFB4760CFFB4760CFFB4760CFFB5770BFFB4760AFFB37608FF
+ B37608FFB5780AFFB5780AFFB47709FFB37608FFB77A0CFFB67A09FFB27905FF
+ AF7A02FFAE7805FFAD7809FFAF790EFFB27A0FFFB97C0EFFBA7B09FFB57603FF
+ B3780AFFAB781AFF966E23FF896A35FF7A7164FF5E72A1FF476EB8FF4371B8FF
+ 4575B5FF4F77B2FF4E73B1FF4167AFFF365CAAFF3054A0FF3959A4FF3B549CFF
+ 3E55A3FF3250A9FF2A489FFF314E98FF324A8CFF334385FF323B74FF333760FF
+ 3B394FFF453A3CFF4A3728FF4D331BFF543417FF563417FF553119FF502F1BFF
+ 4D2F1CFF4C311CFF49331AFF483317FF4A3216FF57331BFF5A341CFF56341CFF
+ 52341BFF4F321DFF50311CFF512F18FF522E16FF593418FF523013FF512F17FF
+ 54331FFF55331CFF553014FF5E3B10FF774C0DFFA77015FFB77810FFBA7B13FF
+ B87911FFB6780EFFB7790FFFB97B11FFBA7C12FFB87A0EFFB87A0EFFB87B0DFF
+ B97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB6780EFFB6780EFFB6780CFF
+ B6790BFFB77A0CFFB77B0AFFB77B09FFB77B09FFB67A08FFB87C0AFFB97D0CFF
+ B87C0BFFB6780CFFB5770BFFB7790FFFB87A0EFFB87A0EFFB87B0DFFB97C0EFF
+ B97C0EFFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFFB87B0DFFB87B0DFFB97C0EFF
+ B97C0EFFB97C0EFFB97C0EFFB87B0DFFB87C0BFFBB7E0AFFB87E07FFB37D0AFF
+ B27E0CFFB27F11FFB57F14FFBA7D15FFBD7B14FFBF7D14FFC28115FFBF8115FF
+ B98013FFBA8217FFBA8217FFB87F16FFBB7F1FFFBD7D29FFAD7736FFCAAA87FF
+ F6E7D7FFFAF5F4FFF0F0F6FFF1F0F2FFF2EFF1FFECEBEDFFEBEAEEFFEBEAEEFF
+ EFECEEFFF6F1F0FFF7F2F1FFF4F2F2FFEEF0F0FFE3EEECFFF5F9F3FFFFF3EAFF
+ FFE2C9FFDFB481FFB78638FFAF7E18FFB4810DFFB47E0BFFB6800DFFB98112FF
+ B87F12FFB47C11FFB27B12FFB47D1AFFBA811EFFBB8013FFC08111FFC18212FF
+ C08111FFBE7F0FFFBD7E0EFFBD7E0EFFBD7E0EFFC38414FFC08111FFBD7E0EFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBD7E0EFFBB7D0BFFBC7F0BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBD800AFFBD800AFFBC7F09FF
+ BB7E08FFBC7F09FFBC7F09FFBE810BFFBE810BFFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBE810BFFBD800AFFBC7F09FF
+ BB7E08FFBB7E08FFBC7F09FFBC7F09FFBD800AFFBE800EFFC08210FFC18311FF
+ BF810FFFBC7E0CFFB97B09FFB97B09FFBA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE800EFFBE800EFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBF810FFFBD7F0DFFBA7C0AFFBB7D0BFF
+ BF810FFFBF810FFFBB7D0BFFB97B09FFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFF
+ B4750DFFB4750DFFB4750DFFB4750DFFB4760CFFB4760CFFB4760CFFB4760CFF
+ B37509FFB4760AFFB5780AFFB5780AFFB37608FFB37608FFB47709FFB5780AFF
+ B4790CFFB3780AFFB37A07FFB17A07FFB0790AFFB0780BFFB0770EFFB2780FFF
+ BB7B0FFFBB7908FFB97700FFB67905FFAF780FFF9C6F14FF8E6B22FF7C6D4DFF
+ 677292FF5272B3FF4975BCFF4273B9FF4772B5FF4A74B7FF456EB7FF3D64B2FF
+ 3057A5FF365AA6FF3B58A3FF3E5CABFF3A5BB1FF3559ADFF3D5DA8FF3F5CA1FF
+ 3C5299FF374685FF343C6BFF363955FF403A3FFF45362DFF4B341EFF4F3217FF
+ 543319FF56321AFF53321EFF50301DFF4D301BFF492F17FF483117FF4C3116FF
+ 57331BFF59331BFF55331BFF52341BFF51321BFF50311CFF512F18FF522E16FF
+ 563417FF563417FF55331BFF56341CFF563117FF5A3411FF704716FF8E5F1BFF
+ B37A1DFFB97A12FFB87911FFB97A12FFB87A10FFB6780EFFB6780EFFB87A10FF
+ B97B0FFFB97B0FFFB97C0EFFB97C0EFFB87B0DFFB87B0DFFB87B0DFFB87B0DFF
+ B5770DFFB5770DFFB5770BFFB6790BFFB77A0CFFB87C0BFFB87C0AFFB87C0AFF
+ B77B09FFB97D0BFFBA7E0DFFB97D0CFFB87A0EFFB87A0EFFB97B11FFBA7C10FF
+ BA7C10FFBA7D0FFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB87B0DFFB87B0DFF
+ B87B0DFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBA7D0FFFB97C0EFFB87C0BFF
+ BA7D09FFB97E0AFFB87F0BFFB67F0CFFB47E0CFFB57C0FFFB87C12FFBB7C14FF
+ BA7B13FFB77810FFB87E14FFB77F14FFB47C11FFB57D12FFB77D14FFB97F20FF
+ AD7429FFB58751FFF3D8BDFFFFF9EFFFEFEDEDFFF0F3F8FFEFEEF2FFEEEDEFFF
+ EEEDEFFFEEEDEFFFF1EEF0FFF3F1F1FFF8F3F2FFF8F3F2FFF3F1F1FFEFEFEFFF
+ F1F3F3FFFFFFF9FFF6E4CDFFD1B186FFBA904BFFAF7B21FFB17A11FFB8810EFF
+ BA810EFFB97F0EFFBA7E0DFFB97C0EFFB67B0DFFB37B0EFFB17A12FFB47A13FF
+ B87A0EFFBF8010FFC38414FFC28313FFBE7F0FFFBB7C0CFFBC7D0DFFBF8010FF
+ C38414FFC18212FFBE7F0FFFBD7E0EFFBE7F0FFFBF8010FFBE7F0FFFBC7E0CFF
+ BC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ C0830DFFBF820CFFBE810BFFBD800AFFBD800AFFBD800AFFBE810BFFBE810BFF
+ B87B05FFB97C06FFB97C06FFBA7D07FFBC7F09FFBD800AFFBD800AFFBE810BFF
+ C0830DFFBF820CFFBD800AFFBC7F09FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ B87A08FFBB7D0BFFBD7F0DFFBE800EFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBF810FFFBE800EFFBC7E0CFFBA7C0AFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBE800EFFBF810FFFC08210FF
+ BE800EFFBC7E0CFFBD7F0DFFC08210FFC18311FFBE800EFFBD7F0DFFBF810FFF
+ BD7F0DFFBD7F0DFFBD7F0DFFB4750DFFB4750DFFB4750DFFB4750DFFB4760CFF
+ B4760CFFB4760CFFB4760CFFB27408FFB4760AFFB6790BFFB5780AFFB37608FF
+ B27507FFB47709FFB6790BFFB3780BFFB3780BFFB37908FFB47A09FFB27A0BFF
+ B0780DFFB1760FFFB3750FFFBC7A11FFBC7708FFBC7801FFBA7B03FFB37908FF
+ A6730BFF9A7017FF866D3BFF686874FF596EA2FF4E73B7FF3E6CB9FF3E6BB5FF
+ 4370BAFF426FB9FF3C66B3FF335DAAFF395FADFF4163AFFF4869B8FF466BBFFF
+ 436BBEFF436AB4FF4566AFFF4360ABFF3D5296FF354377FF333B59FF3B3742FF
+ 423630FF473321FF4D3119FF513219FF55331CFF56331FFF52311DFF4E2F1AFF
+ 4A2E16FF493016FF4D3218FF56311BFF59331BFF55341AFF53351AFF53331CFF
+ 51311AFF523019FF532E18FF563319FF57361CFF59371FFF57341AFF583210FF
+ 673C11FF85571DFFA37125FFBA8021FFB97A12FFB5760EFFB97A12FFBA7C12FF
+ B6780EFFB5770DFFB97B11FFBA7C10FFB97B0FFFB97C0EFFB87B0DFFB87B0DFF
+ B77A0CFFB77A0CFFB6790BFFB4760AFFB4760CFFB5770BFFB6790BFFB77A0CFF
+ B87C0BFFB97D0BFFB97D0BFFB77B09FFB87C0AFFB87C0BFFB97D0CFFB87A0EFF
+ B97B0FFFB97B11FFBA7C10FFBB7E10FFBA7D0FFFBA7D0FFFB97C0EFFB97C0EFF
+ B87B0DFFB87B0DFFB77A0CFFB77A0CFFB97C0EFFBB7E10FFBD8012FFBD8012FF
+ BB7E10FFB97C0EFFB77B0AFFBA7C0AFFBC7F0BFFBC820BFFB9810AFFB67D09FF
+ B57B0AFFB67A10FFB97C14FFB47912FFAE730CFFB67C13FFB37B10FFB1790EFF
+ B87E15FFB57A13FFB0781FFFA27434FFC8A57DFFFFEED9FFFFFAF3FFEAE9EDFF
+ EBEEF6FFEFEFF5FFEFEEF2FFEEEDEFFFEFEEF0FFF3F1F1FFF7F3F2FFF8F3F0FF
+ F7F2F1FFF1EEF0FFEFECEEFFFFFBFAFFFFF5E7FFD6BE9AFFA8864AFFA87B24FF
+ AF7914FFB27A0BFFC08412FFC08111FFBD7E0EFFBC7C0CFFBB7D0BFFBA7E0CFF
+ B87E0DFFB37B10FFB2780EFFB77A0CFFBD7E0EFFC18212FFC28313FFBF8010FF
+ BD7E0EFFBC7D0DFFBD7E0EFFC38414FFC08111FFBE7F0FFFBD7E0EFFBE7F0FFF
+ BF8010FFBE7F0FFFBD7F0DFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFC0830DFFBF820CFFBE810BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBD800AFFB87B05FFB97C06FFB97C06FFBA7D07FFBC7F09FF
+ BD800AFFBD800AFFBE810BFFBF820CFFBE810BFFBC7F09FFBB7E08FFBB7E08FF
+ BB7E08FFBC7F09FFBC7F0BFFB67806FFB87A08FFBB7D0BFFBD7F0DFFBE800EFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBE800EFFBE800EFFBC7E0CFFBC7E0CFFBC7E0CFFBF810FFFC28412FF
+ C18311FFBD7F0DFFB97B09FFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBD7F0DFFBC7E0CFFBD7F0DFFBF810FFFBF810FFF
+ BF810FFFBF810FFFC08210FFBD7F0DFFBD7F0DFFBD7F0DFFB4750DFFB4750DFF
+ B4750DFFB4750DFFB4760CFFB4760CFFB4760CFFB4760CFFB27408FFB4760AFF
+ B6790BFFB5780AFFB37608FFB27507FFB47709FFB6790BFFB3780BFFB3780AFF
+ B57908FFB47A09FFB4790BFFB1770DFFB3750FFFB57411FFBB7811FFBB7607FF
+ BD7902FFC07D03FFBA7D05FFB37A07FFAB7810FF96722CFF706256FF646B8CFF
+ 5372B1FF406BBAFF396ABAFF3E6FBFFF406EBBFF3C68B5FF3B64B3FF3D64B3FF
+ 4267B7FF456CBBFF4671C2FF4572C3FF446EBBFF4269B7FF4568B8FF3F5AA4FF
+ 344881FF2F3B5FFF353545FF3E3532FF463324FF4A321CFF50311AFF55331CFF
+ 56331FFF54311DFF4F2E1AFF4C2D16FF4B3016FF4F3118FF53311AFF56321AFF
+ 55341AFF53351AFF53341BFF52321BFF53311AFF523019FF533119FF59381EFF
+ 5A391FFF5B3515FF62380EFF794A14FF9A6620FFB37C27FFBC7F1DFFB77810FF
+ B3740CFFB87911FFBB7D13FFB87A10FFB7790FFFBA7C12FFB97B0FFFB97B0FFF
+ B87B0DFFB87B0DFFB77A0CFFB77A0CFFB6790BFFB6790BFFB4760AFFB4760AFF
+ B5770BFFB6790BFFB77A0CFFB87C0BFFB97D0CFFB97D0CFFB67A09FFB67A09FF
+ B67A09FFB67A09FFB87A0EFFB87A0EFFB87A0EFFB87A0EFFBB7E10FFBA7D0FFF
+ BA7D0FFFB97C0EFFB97C0EFFB87B0DFFB87B0DFFB77A0CFFB77A0CFFB97C0EFF
+ BB7E10FFBD8012FFBD8012FFBB7E10FFB97C0EFFB77A0CFFB97A0AFFBC7F0BFF
+ BD800AFFBC8008FFB97C06FFB67A08FFB67B0EFFB67C13FFB67C15FFB27811FF
+ BA8017FFB47A11FFB87E15FFC28720FFBA7D1DFFAF7A2AFFBC9666FFEED7BDFF
+ FFF4E8FFF7F3F2FFEAEDF2FFE4E7EFFFECEFF4FFEAEBEFFFEAECEDFFEEEDEFFF
+ F3F1F1FFF6F2F1FFF6F1EEFFF3EFEEFFEDECEEFFEFEAECFFFFF5F3FFE8CFBBFF
+ B49560FF9C7725FFB18219FFB9820FFFB57705FFBF7F0FFFC38013FFC07D10FF
+ BE7C0BFFBF7E0BFFC0810EFFBE8210FFB77F0EFFB47C0DFFBA7E0DFFBB7C0CFF
+ BC7D0DFFBF8010FFC18212FFC18212FFBD7E0EFFB97A0AFFC28313FFBF8010FF
+ BD7E0EFFBC7D0DFFBE7F0FFFBF8010FFBE7F0FFFBD7F0DFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBE810DFFBD800CFF
+ BC7F0BFFBA7D09FFBA7D09FFBA7D09FFBA7D09FFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBC7F0BFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBE810DFFBF820EFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFB87A08FFB67806FFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBF810FFFC28412FFC18311FFBD7F0DFFB97B09FFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE800EFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBC7E0CFFBE800EFFBE800EFFBE800EFFBC7E0CFFBC7E0CFF
+ BC7E0CFFB4750DFFB4750DFFB4750DFFB4750DFFB4760CFFB4760CFFB4760CFF
+ B4760CFFB37509FFB4760AFFB5780AFFB5780AFFB37608FFB37608FFB47709FF
+ B5780AFFB4790BFFB37908FFB57907FFB57907FFB37908FFB3780BFFB3750FFF
+ B67512FFBA7710FFB77407FFBC7904FFC27F05FFBF7E04FFBC7E08FFB87E0DFF
+ A37420FF806441FF716B76FF5D72A6FF476FBAFF3E6EC0FF3D71C4FF4273BFFF
+ 4370BAFF466FBEFF3F67B9FF3F67B9FF3B66B5FF3D6BB9FF4070BEFF3E6CBAFF
+ 416CBDFF4469BDFF3F5FABFF354D87FF2E3B61FF313345FF3B3334FF453529FF
+ 4B3321FF4F311EFF52311DFF57321EFF55301CFF523019FF4E2E17FF4E2F18FF
+ 4E2F18FF53311AFF533119FF543319FF553518FF55341AFF52331AFF53311AFF
+ 502F1BFF52321BFF56371EFF5A381BFF5C3613FF704212FF8F5A1BFFAD7222FF
+ BB7E20FFB97B17FFB77810FFB4750DFFB77810FFBA7C12FFB97B11FFB87A10FF
+ B97B11FFB87A0EFFB87A0EFFB77A0CFFB77A0CFFB77A0CFFB77A0CFFB77A0CFF
+ B6790BFFB5770BFFB5770BFFB5770BFFB6790BFFB77A0CFFB87C0BFFB87C0BFF
+ B87C0BFFB67A09FFB57908FFB47807FFB6790BFFB87B0DFFB97B0FFFB97B0FFF
+ B87A0EFFBA7D0FFFBA7D0FFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB87B0DFF
+ B87B0DFFB87B0DFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBA7D0FFFB97C0EFF
+ B87B0DFFB97A0CFFBA7C0AFFBC7E08FFBC7F07FFBA7E06FFB87D09FFB77C0EFF
+ B67C12FFB57C13FFB37912FFBA8017FFB2780FFFB87D19FFBE8425FFB27A21FF
+ B68743FFE9CFABFFFFFFF3FFFEF8F3FFF0EFF1FFEFF3F8FFE3E6EEFFE6EAEFFF
+ E5E8EDFFEAEBEFFFECEEEFFFF2F0F0FFF5F1F0FFF3F0ECFFF0EEEDFFEBECF0FF
+ F2ECEDFFFFEAE4FFCDAB8DFF9F7C38FF9F7514FFB68511FFBF860BFFBA7B08FF
+ C48212FFC47F12FFC27D10FFC27E0DFFC3800DFFC48310FFC28511FFBB820FFF
+ B97F0EFFBD8110FFBC7D0DFFBA7B0BFFBD7E0EFFC18212FFC18212FFBC7D0DFF
+ B77808FFC08111FFBE7F0FFFBB7C0CFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BD7F0DFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBA7D09FFBA7D09FFB97C08FFBA7D09FFBA7D09FF
+ BB7E0AFFBD800CFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFFBA7D09FFBA7D09FF
+ B97C08FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFBD800CFFBF820EFF
+ C0830FFFBE800EFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBB7D0BFF
+ BA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBF810FFFBE800EFFBC7E0CFF
+ BA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBF810FFFBE800EFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBA7C0AFFBC7E0CFFBB7D0BFFB97B09FFB97B09FFBC7E0CFFBD7F0DFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFB4750DFFB4750DFFB4750DFFB4750DFF
+ B4760CFFB4760CFFB4760CFFB4760CFFB5770BFFB4760AFFB37608FFB37608FF
+ B5780AFFB5780AFFB47709FFB37608FFB57B0AFFB47B08FFB47A03FFB37902FF
+ B37804FFB47807FFB6780EFFB77711FFB97711FFB37209FFB87907FFBE7E08FF
+ BD7A05FFBE7E08FFBD7D0DFFA97013FF956B30FF826D5EFF666F94FF4F70B5FF
+ 406FC1FF3D71C4FF4576C0FF4A77C0FF4D77C4FF426DBEFF426DBEFF3B68B9FF
+ 3D6EBAFF4373C1FF3D6CBDFF406CBFFF4068BBFF4060ABFF385189FF2F3C62FF
+ 2F3143FF383134FF44342DFF4A3526FF4D3120FF51301DFF542F1BFF542F19FF
+ 55301AFF53311AFF4F3019FF4E2F18FF503019FF533119FF543319FF573518FF
+ 573518FF543319FF51311AFF50311CFF52331EFF54341DFF563416FF60380EFF
+ 7E4E14FFA46B20FFBA7B1FFFBD7B15FFB77810FFB87911FFB87911FFB77810FF
+ B7790FFFB97B11FFB87A10FFB4760CFFB6780CFFB6780CFFB6790BFFB77A0CFF
+ B77A0CFFB77A0CFFB77A0CFFB77A0CFFB6790BFFB6790BFFB6790BFFB6790BFF
+ B77A0CFFB77A0CFFB77A0CFFB77A0CFFB77A0CFFB6790BFFB5780AFFB77A0CFF
+ BA7D0FFFBC7F11FFBB7E10FFBA7D0FFFB87B0DFFB87B0DFFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFBA7D0FFFBA7D0FFFB87B0DFFB87B0DFFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFB87B0DFFB87B0DFFB77A0CFFB87909FFB97A07FFBA7C06FF
+ BB7E08FFBA7F0BFFB87D0FFFB57C0FFFB47A10FFB4780EFFBD7F15FFB57711FF
+ B67C1DFFAF7823FFA7742BFFC8A26CFFFFF2DDFFFFFFFCFFF6F6F6FFE9ECF0FF
+ F0F4F9FFEBEFF4FFE4E8EDFFEAEEF3FFEAEDF1FFEEF0F1FFF4F2F2FFF3F1F0FF
+ F1EFEEFFF1EFEFFFEEEFF3FFF8F0F0FFF7D8C9FFBE966CFFA57C2DFFAD7F14FF
+ B58007FFC08507FFC3820FFFC78213FFC37E11FFC37E0FFFC57F0DFFC4810EFF
+ C3820FFFC0830FFFBA810EFFB87F0CFFBD8110FFBE7F0FFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFB97A0AFFBE7F0FFFBC7D0DFFBA7B0BFFBA7B0BFF
+ BC7D0DFFBD7E0EFFBD7E0EFFBC7E0CFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBC7F0BFFBD800CFFBE810DFFBC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFF
+ BB7E0AFFBA7D09FFBA7D09FFBA7D09FFBD800CFFBC7F0BFFBC7F0BFFBB7E0AFF
+ BB7E0AFFBC7F0BFFBD800CFFBE810DFFBD7F0DFFBA7C0AFFB87A08FFB97B09FF
+ BC7E0CFFC08210FFC18311FFC18311FFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBC7E0CFFBE800EFFBD7F0DFFB87A08FF
+ B87A08FFBC7E0CFFBD7F0DFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFB4750DFF
+ B4750DFFB4750DFFB4750DFFB4760CFFB4760CFFB4760CFFB4760CFFB6780CFF
+ B4760AFFB27507FFB37608FFB5780AFFB6790BFFB47709FFB27507FFB67C0BFF
+ B47B08FFB47A03FFB27900FFB27801FFB47806FFB6780CFFB87911FFB57810FF
+ B1720AFFB5780AFFBB7C0CFFB87907FFBC7A09FFBD7B0BFFAC6E0AFFA46F1FFF
+ 8F6F46FF6E6D7DFF576EA6FF446EBBFF3C6EC0FF4575BDFF4D7BC2FF507AC5FF
+ 4671C0FF4875C6FF4372C3FF4778C4FF4B7CC8FF3F6FC1FF3F6DC1FF3D65B8FF
+ 4161AAFF3C548AFF303E62FF2E3042FF373035FF433431FF4A362BFF4A3022FF
+ 4D2F1EFF502D19FF532E18FF56311BFF55331CFF51301CFF4E2F1AFF4F3019FF
+ 513219FF543319FF573518FF573518FF543319FF52321BFF50311CFF50321FFF
+ 53331CFF553211FF63390AFF8A5614FFB17521FFC4801BFFBE790CFFB6750CFF
+ BA7B13FFBB7C14FFB6770FFFB5770DFFB97B11FFB7790FFFB17309FFB5770BFF
+ B5770BFFB6790BFFB6790BFFB77A0CFFB77A0CFFB87B0DFFB87B0DFFB77A0CFF
+ B77A0CFFB77A0CFFB77A0CFFB6790BFFB6790BFFB6790BFFB6790BFFB97C0EFF
+ B87B0DFFB77A0CFFB97C0EFFBC7F11FFBE8113FFBD8012FFBC7F11FFB77A0CFF
+ B87B0DFFB87B0DFFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFFBB7E10FFB87B0DFF
+ B87B0DFFB87B0DFFB77A0CFFB77A0CFFB87B0DFFB87B0DFFB87B0DFFB7790DFF
+ B5780AFFB77806FFB97A07FFBC7F0BFFBC800EFFB97E10FFB77C0FFFBD8012FF
+ BC7F11FFC6861AFFBE801CFFB9802AFFA5742AFFA2783DFFDABF9AFFFFFAF0FF
+ EBEDEEFFECEFF3FFE5E8ECFFEEF1F5FFF5FAFDFFE7EBF0FFF4F8FDFFECEFF3FF
+ F0F2F3FFF3F3F3FFF4F2F1FFF2F0EFFFF0F0F0FFF3F2F4FFFFF6EEFFE5C3A6FF
+ BB8D57FFB98B33FFC19121FFBB8207FFC18509FFC48310FFBC7A0AFFC07E0EFF
+ C17F0FFFC4810EFFC4810EFFBF7F0FFFBB7F0EFFB77E0BFFB47D0AFFBB7F0EFF
+ C08111FFC18212FFBE7F0FFFB97A0AFFB77808FFB97A0AFFBD7E0EFFBD7E0EFF
+ BB7C0CFFB97A0AFFB97A0AFFBB7C0CFFBD7E0EFFBC7D0DFFBB7C0CFFBC7E0CFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBD800CFF
+ BD800CFFBC7F0BFFBC7F0BFFBD800CFFBE810DFFC0830FFFC0830FFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBF820EFF
+ BE810DFFBD800CFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFFC58715FF
+ C08210FFBB7D0BFFB97B09FFBB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFB97B09FFBA7C0AFF
+ BC7E0CFFBD7F0DFFBC7E0CFFB97B09FFB97B09FFBB7D0BFFBE800EFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ C18311FFBF810FFFB97B09FFB97B09FFBD7F0DFFBE800EFFBA7C0AFFBB7D0BFF
+ BB7D0BFFBB7D0BFFB1720AFFB2730BFFB4750DFFB5760EFFB4760CFFB3750BFF
+ B2740AFFB17309FFB4760AFFB4760AFFB47709FFB47709FFB47709FFB47709FF
+ B47709FFB47709FFB6790BFFB27605FFB27703FFB77D06FFB87E07FFB47806FF
+ B3780AFFB77B11FFB1770EFFB1770EFFB2780EFFB2790CFFB77A0CFFBA7B0DFF
+ BB7A0EFFBA7811FFB47814FF986D2AFF776963FF667399FF5376B8FF406EBBFF
+ 4270B7FF4978BCFF4974BDFF4F7BC8FF4F7ECFFF4B7ACBFF4576C2FF4171BFFF
+ 3B6ABEFF3664B8FF3358A8FF39569BFF3C4F82FF2E385AFF212133FF2F272EFF
+ 483B39FF524039FF432D22FF472A1CFF4E2D1AFF57321EFF57321CFF512E1AFF
+ 50301DFF533522FF4D301BFF4F3118FF523117FF523215FF543215FF533316FF
+ 51321BFF4F321DFF4F311EFF56361FFF5D3714FF714510FF956017FFAF7014FF
+ BA7508FFC27A0AFFBB7A0EFFB87911FFB77810FFB77810FFB7790FFFB7790FFF
+ B5770DFFB4760CFFB7790DFFB7790DFFB87B0DFFB87B0DFFB97C0EFFB87B0DFF
+ B87B0DFFB77A0CFFB77A0CFFB87B0DFFBA7D0FFFBB7E10FFBB7E10FFB97C0EFF
+ B77A0CFFB6790BFFB5780AFFB6790BFFB77A0CFFB87B0DFFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFB47709FFB77A0CFFB97C0EFFB97C0EFFB77A0CFFB77A0CFF
+ B97C0EFFBB7E10FFC28517FFBF8214FFBC7F11FFBC7F11FFBD8012FFBD8012FF
+ BB7E10FFB97C0EFFB57A0DFFB77A0CFFB77A0CFFB87C0BFFBA7E0DFFB97F0EFF
+ BA7F11FFBB7E10FFB57606FFC38313FFBE7D11FFCA8D2DFFBD893CFF996F34FF
+ C0A279FFFFF6DFFFF6F3EFFFEFF3F8FFF0F3F7FFF0F2F3FFEDEFF0FFE9EDEEFF
+ E9ECF0FFEAEDF1FFE6E9EDFFEAEDF1FFF3F5F6FFFAFAFAFFEAEBE9FFEAE8E7FF
+ F4F3EFFFF0E2D0FFBE9B70FFA97A36FFB98628FFBD881AFFBB800CFFC58711FF
+ BE7E0EFFC07F12FFC0810FFFC0810FFFC2800FFFBF7F0FFFBE7E12FFB97E11FF
+ B67E0DFFB57D0CFFBA7E0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFB87909FFC28313FFC38414FFBA7B0BFFBA7B0BFFC38414FF
+ C28313FFB87909FFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBA7C0AFFBC7E0CFFBF810FFFBE800EFFBB7D0BFFB87A08FF
+ B97B09FFBA7C0AFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFB97B09FFB97B09FFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFBE800EFFBE800EFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFB97B09FFBB7D0BFFBE800EFFBD7F0DFFBB7D0BFFBB7D0BFF
+ BD7F0DFFC08210FFBD7F0DFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFF
+ BA7C0AFFB97B09FFBB7D0BFFBB7D0BFFBB7D0BFFB1720AFFB2730BFFB3740CFF
+ B3740CFFB4760CFFB3750BFFB3750BFFB3750BFFB4760AFFB4760AFFB47709FF
+ B47709FFB47709FFB47709FFB47709FFB4760AFFB6780EFFB3750BFFB37608FF
+ B77B09FFB77B09FFB27906FFB27709FFB47B0EFFB3790FFFB27A0FFFB07A0FFF
+ B07B0DFFB27A0DFFB57A0DFFB7790FFFB9790DFFBB7C0AFFA4721AFF80684CFF
+ 6D6E82FF5873ACFF4C75BEFF4B7ABEFF4F7EC2FF4775BCFF4E7BC5FF4E7ECCFF
+ 4B7CCCFF497AC6FF4777C5FF406FC5FF3D69BDFF4165B3FF385294FF2F3E6FFF
+ 242A4DFF201F33FF352D37FF4E4346FF594A48FF45312CFF462D23FF4B2C1DFF
+ 52311DFF55331CFF522F1BFF4D2D1AFF4C2E1BFF4A2D18FF4E2F18FF513219FF
+ 543319FF553518FF543417FF50311AFF4D301BFF492B18FF523018FF5C350FFF
+ 76470FFFA06819FFB87917FFC27A0AFFC37D08FFBA790DFFB87911FFB87911FF
+ B77810FFB7790FFFB7790FFFB87A10FFB97B11FFBA7C10FFB97B0FFFB77A0CFF
+ B6790BFFB6790BFFB77A0CFFB87B0DFFB97C0EFFB97C0EFFB97C0EFFB97C0EFF
+ BA7D0FFFBA7D0FFFBB7E10FFBC7F11FFBC7F11FFB77A0CFFB87B0DFFB87B0DFF
+ B87B0DFFB87B0DFFB87B0DFFB87B0DFFB87B0DFFB77A0CFFB97C0EFFBA7D0FFF
+ B97C0EFFB77A0CFFB6790BFFB77A0CFFB97C0EFFBF8214FFBC7F11FFBA7D0FFF
+ BA7D0FFFBB7E10FFBB7E10FFB97C0EFFB6790BFFB57A0DFFB67B0EFFB67B0EFF
+ B77C0FFFB87D10FFB87D10FFB97E10FFBB7F0EFFB77806FFBD7C0FFFC2801AFF
+ BD822CFFAC7F3CFFB89769FFE9D4B9FFFFFEF4FFEDEFF0FFEAF0F7FFEDF0F4FF
+ EEF0F0FFECEEEEFFECEEEEFFEDEFF0FFEEF1F5FFF5F8FCFFEAEDF1FFE5E9EAFF
+ EDEFEFFFEDEEECFFFBF8F3FFF6F0E5FFCDBB9EFFBB955BFFAB7828FFBA8524FF
+ BD8518FFB97C0EFFC28313FFBB7B0FFFBC7F11FFBC800EFFBE800EFFBE800EFF
+ BE7F11FFBC7E14FFB97D13FFB67E11FFB67F10FFBA7E0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBA7B0BFFC08111FFC18212FF
+ BC7D0DFFBC7D0DFFC18212FFC08111FFBA7B0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBD7F0DFFBF810FFF
+ BE800EFFBC7E0CFFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBE800EFFBE800EFF
+ BD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBE800EFFBE800EFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFFBC7E0CFFBE800EFF
+ BE800EFFBC7E0CFFBC7E0CFFBE800EFFC08210FFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFB97B09FFBB7D0BFFBB7D0BFFBB7D0BFF
+ B2730BFFB1720AFFB1720AFFB2730BFFB2740AFFB4760CFFB5770DFFB5770DFF
+ B4760AFFB4760AFFB47709FFB47709FFB47709FFB47709FFB47709FFB4760AFF
+ B97711FFB77411FFB4750DFFB5790FFFB4790BFFB27709FFB27709FFB2790CFF
+ B67D10FFB27D0FFFB07D0FFFAF7C0EFFB07B0DFFB1790CFFB4780EFFB7780AFF
+ BE7D03FFAA740FFF886736FF6E6464FF566996FF4D72B6FF4D7ABEFF4B7CC2FF
+ 4576BAFF4B7CC2FF4B7CCAFF4B7CCCFF4C7CCAFF4C7BCCFF4273C9FF3F6BBFFF
+ 4868B4FF324889FF1F2D5EFF1E2447FF2A2740FF3D3847FF4F4752FF574C54FF
+ 483A3CFF44312EFF472B20FF4E2E1BFF52311DFF502F1BFF4B2A1AFF472918FF
+ 472C17FF4B2F17FF513219FF55341AFF563619FF523419FF4D3119FF4C2F1AFF
+ 492B18FF502D13FF60360CFF7F4E10FFA9701BFFBF8018FFC47E0CFFC17B06FF
+ B9780CFFB87911FFB97A12FFB87911FFB6780EFFB7790FFFBB7D13FFBF8117FF
+ BD7F13FFBB7D11FFB77A0CFFB5780AFFB47709FFB5780AFFB87B0DFFB97C0EFF
+ BA7E0DFFB97D0CFFB97D0CFFB87B0DFFBA7D0FFFBC7E12FFBF8115FFC18317FF
+ B97B0FFFB97B0FFFB97B0FFFB87B0DFFB87B0DFFB87C0BFFB87C0BFFB87C0BFF
+ B97C0EFFBA7D0FFFBB7E10FFB97C0EFFB77A0CFFB6790BFFB6790BFFB77A0CFF
+ BB7E10FFBA7D0FFFB87B0DFFB87B0DFFB97C0EFFB87B0DFFB6790BFFB3780AFF
+ B57D0EFFB57C0FFFB67C12FFB67C13FFB57B12FFB57B11FFB87D10FFBB7E10FF
+ BE7E0EFFBA7C12FFC18427FFA87428FF9D7642FFD6BF9FFFFFF7E9FFF2F0EFFF
+ E7EBF0FFE6ECF1FFECEEEFFFEEEFEDFFEDEEECFFEEEEEEFFEFF1F1FFF3F5F6FF
+ EBEDEEFFEEF2F3FFF1F4F8FFF4F6F6FFF2EFEAFFFFF7EAFFFDEFD9FFD7BB92FF
+ B58C43FFAA771BFFBB821FFFBC8219FFB87A10FFBD7F15FFB67A10FFBA7F12FF
+ B97F0EFFB9800DFFBB7F0EFFBB7D11FFBB7C14FFB87E15FFB57F14FFB58012FF
+ B87D0FFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBD7F0DFFBF810FFFBF810FFFBD7F0DFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFB97B09FFB97B09FF
+ BA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BF810FFFBF810FFFBE800EFFBD7F0DFFBC7E0CFFBA7C0AFFBA7C0AFFB97B09FF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBE800EFFBF810FFF
+ BA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFB87A08FF
+ BB7D0BFFBB7D0BFFBB7D0BFFB2730BFFB1720AFFB07109FFB07109FFB2740AFF
+ B4760CFFB6780EFFB7790FFFB4760AFFB4760AFFB47709FFB47709FFB47709FF
+ B47709FFB47709FFB4760CFFBA7613FFB87413FFB47612FFB27710FFB1770DFF
+ B0770AFFB17609FFB27709FFB77C0EFFB47D0EFFB27D0EFFAF7D0DFFAF7D0DFF
+ B07B0CFFB37A0DFFB77B09FFB97B00FFB1770DFF956A2BFF735F4EFF525B80FF
+ 4765A6FF446FB8FF3E71BAFF477BBEFF4A7FC2FF497DC9FF487BCBFF4C7BCCFF
+ 4A7BCBFF4072C5FF3968BAFF3858A4FF253B7DFF1B285CFF272E55FF3A3A58FF
+ 424056FF454357FF4A4455FF4A424DFF443739FF432C24FF46291AFF4E2F1AFF
+ 51301CFF4D2C1CFF472918FF492E19FF4C3018FF503019FF52331AFF523419FF
+ 513419FF4E321AFF4B301BFF52331EFF553014FF663A0BFF875513FFAF761BFF
+ C08218FFC17E09FFBA7702FFB8780CFFB97A12FFBB7C14FFB97A12FFB5770DFF
+ B7790FFFBD7F15FFC4861CFFBD7F13FFBB7D11FFB87B0DFFB6790BFFB5780AFF
+ B5780AFFB6790BFFB77A0CFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97B0FFF
+ BB7D11FFBD7F13FFBE8014FFB97B0FFFB97B0FFFB87A0EFFB87B0DFFB87B0DFF
+ B97D0CFFBA7E0DFFBA7E0DFFBA7D0FFFBA7D0FFFBA7D0FFFB97C0EFFB87B0DFF
+ B87B0DFFB87B0DFFB87B0DFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFF
+ B87B0DFFB77A0CFFB3780AFFB47D0EFFB67E11FFB77E15FFB67C15FFB47A13FF
+ B47A11FFB97B0FFFBB7D11FFBF8117FFBD8121FFBF8738FFA07437FFAC8F68FF
+ F0E1CEFFFEFBF6FFE0E5E8FFE5EBF0FFE8EDF0FFEBEDEDFFECEDEBFFECEDEBFF
+ EDEEECFFEFF1F1FFF2F4F4FFF1F3F3FFF0F2F3FFE4E8E9FFF0F1EFFFFBF6EDFF
+ F6E8D5FFE3C9A5FFC39E64FFB1832FFFAD7613FFBB811AFFBE8119FFB97A12FF
+ BA7E14FFB57B11FFB98013FFB77F10FFB67E0DFFBA7D0FFFBA7C10FFBB7D13FF
+ B87E15FFB68015FFB78214FFB87D0FFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBE7F0FFFBB7C0CFFBC7D0DFFC18212FFC18212FF
+ BC7D0DFFBB7C0CFFBE7F0FFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBD7F0DFFBF810FFFBF810FFFBE800EFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBD7F0DFF
+ BD7F0DFFBE800EFFBE800EFFB97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBA7C0AFFB97B09FFBB7D0BFFBB7D0BFFBB7D0BFFB2730BFFB1720AFF
+ B07109FFB07109FFB2740AFFB4760CFFB6780EFFB7790FFFB4760AFFB4760AFF
+ B47709FFB47709FFB47709FFB47709FFB47709FFB4760AFFB97510FFB97613FF
+ B57713FFB0760FFFB0760FFFB1770EFFB4760AFFB57608FFB87909FFB67A09FF
+ B27C0AFFB07C0AFFB17D0BFFB17D0BFFB47C0DFFB77E0BFFB37700FFB47B0EFF
+ A6732AFF816346FF595A76FF4760A0FF3F6BB8FF396EBEFF4980C5FF4A84C6FF
+ 4780CBFF467BCBFF4879C9FF4375C7FF376CBDFF3060B2FF264A98FF1E377DFF
+ 212F69FF333B6AFF43466CFF3F4261FF383C59FF3B3F58FF49485CFF453D47FF
+ 402F2CFF412A1BFF4A2C19FF51301CFF51311EFF4C2E1BFF4C321AFF4B3119FF
+ 4E2F18FF4E2F18FF4E3116FF4E3319FF4D331BFF4E331EFF573622FF593212FF
+ 6E3F0CFF905C15FFAF7619FFBD8215FFBF800DFFB97A07FFB9790DFFBA7B13FF
+ BC7D15FFB97A12FFB6780EFFB7790FFFBD7F15FFC3851BFFBA7C10FFBA7C10FF
+ B97C0EFFB87B0DFFB77A0CFFB6790BFFB5780AFFB5780AFFB77B0AFFB77B09FF
+ B87C0BFFB97D0CFFB97B0FFFB87A0EFFB7790FFFB7790FFFB87A10FFB87A10FF
+ B7790DFFB77A0CFFB87B0DFFBA7E0DFFBC800EFFBD8110FFB87B0DFFB87B0DFF
+ B87B0DFFB97C0EFFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFB97C0EFFBA7D0FFF
+ BC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFFB67B0DFFB47D0EFFB47F11FF
+ B67F17FFB77C18FFB57915FFB67812FFBA7C12FFBC7D15FFB47818FFBB8532FF
+ B68A4BFFB08F62FFDBC7AEFFFFFEF4FFF4F6F6FFE9F0F3FFE7EEF1FFEBEFF0FF
+ EFF0EEFFEEEFEBFFECEDEBFFEAEDEBFFEDF0EEFFEFF2F0FFF4F5F3FFF3F6F4FF
+ E2E4E4FFF3F2EEFFFFF6E8FFD2BD9EFFA98450FFA3732BFFB38020FFB37A11FF
+ BE8119FFC08119FFBB7C14FFBA7E14FFB57D12FFB98114FFB67E13FFB77E11FF
+ BA7C10FFBA7C10FFBA7D0FFFBA7F12FFB88015FFBA8215FFBA7D0FFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBF8010FFBA7B0BFF
+ BB7C0CFFC28313FFC28313FFBB7C0CFFBA7B0BFFBF8010FFBD7E0EFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBD7E0EFF
+ BD7E0EFFBE7F0FFFBF8010FFBF8010FFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFF
+ BB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFFBA7B0BFFBA7B0BFF
+ BA7B0BFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBE800EFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFB97B09FFBA7C0AFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBA7C0AFFBB7D0BFFBB7D0BFF
+ BB7D0BFFB2730BFFB1720AFFB1720AFFB2730BFFB2740AFFB4760CFFB5770DFF
+ B5770DFFB4760AFFB4760AFFB47709FFB47709FFB47709FFB47709FFB47709FF
+ B4760AFFB7760DFFB77810FFB37811FFAF750EFFAF750EFFB2780FFFB6780EFF
+ B67508FFB97707FFB77806FFB37A07FFB27B08FFB27C09FFB37D0AFFB47C0BFF
+ B67D0AFFB07703FFB57C13FFB07928FF946D47FF69637AFF5469A7FF4572C3FF
+ 3E78CAFF4683C7FF4A86C8FF4984CCFF447ECAFF4277C8FF3D72C3FF3169BAFF
+ 2C5FAFFF274C9EFF27418DFF2A3B7AFF384377FF424875FF393F68FF313A60FF
+ 384163FF464A66FF464654FF463A3AFF452F24FF492E1AFF50311CFF50321FFF
+ 4D321EFF4D331BFF4C321AFF4C2F1AFF4C2D16FF4D2F16FF4D3218FF4C341CFF
+ 503520FF56341DFF5B3211FF754511FF99641BFFB07918FFBB8012FFBE8210FF
+ BD7F0DFFB97B0FFFBB7C14FFBC7D15FFBA7B13FFB7790FFFB7790FFFBB7D13FF
+ BF8117FFB97B0FFFB97B0FFFB97C0EFFB97C0EFFB87B0DFFB77A0CFFB6790BFF
+ B57908FFB57908FFB67A08FFB87C0BFFB97D0CFFB97B0FFFB7790DFFB5770DFF
+ B3750BFFBA7C12FFB97B11FFB87A0EFFB77A0CFFB87B0DFFBA7E0DFFBC800EFF
+ BE8210FFB97C0EFFB87B0DFFB77A0CFFB97C0EFFBB7E10FFBC7F11FFBC7F11FF
+ BB7E10FFB97C0EFFBB7E10FFBE8113FFBE8113FFBD8012FFBB7E10FFBA7D0FFF
+ B87D0FFFB17C0DFFB27F11FFB78018FFB77C18FFB77915FFB87812FFBD7B14FF
+ BC7E1AFFAD751CFFB4833DFFB38F5FFFCAB296FFFBEFE3FFFFFFFBFFE5E9EAFF
+ EBF2F5FFEAEFF0FFECF1F0FFF1F2F0FFF0F1EDFFECEFEDFFEAEDEBFFEBEEECFF
+ EDF0EEFFEBECE8FFF7F8F4FFF1F2F0FFFFFFF9FFFFF9E6FFC5A881FFA57535FF
+ B77E28FFB97E1AFFB67D10FFBE8016FFBE8016FFBC7E12FFBA7F11FFB67E11FF
+ B68113FFB87F16FFB87E15FFBA7C12FFBB7C0EFFBC7E0CFFB97F0EFFB98013FF
+ BA8114FFBA7D0FFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBF8010FFBB7C0CFFBC7D0DFFC18212FFC18212FFBC7D0DFFBB7C0CFF
+ BF8010FFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFFBF8010FFBF8010FFBD7E0EFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFB97A0AFFB97A0AFFBA7B0BFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFF
+ BD7E0EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFF
+ BE800EFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BD7F0DFFB97B09FFBA7C0AFFBA7C0AFFBC7E0CFFBD7F0DFFBE800EFFBF810FFF
+ BF810FFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBE800EFFBD7F0DFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFB1720AFFB2730BFFB3740CFFB3740CFF
+ B4760CFFB3750BFFB3750BFFB3750BFFB4760AFFB4760AFFB47709FFB47709FF
+ B47709FFB47709FFB47709FFB47709FFB57608FFB6790BFFB37A0DFFAC760BFF
+ AD760DFFB37910FFBA7910FFB97609FFBC7708FFBC7807FFB87906FFB57A06FF
+ B37A07FFB37A07FFB37908FFB3780AFFB47C0FFFB07A15FFAF7621FF9B7144FF
+ 786D81FF5F71B0FF4A77CEFF3F7BD4FF3F80C5FF4787C8FF4987CEFF4480CCFF
+ 4178C9FF3D73C6FF326DBCFF2E66B3FF335BAEFF3553A2FF35488CFF37457FFF
+ 3D487AFF36406FFF2C3A6AFF37456FFF404A6CFF494D60FF50474AFF4C3931FF
+ 4D3120FF4F3019FF4E311CFF4C311CFF4C321AFF4B3119FF4C2F1AFF4D2E19FF
+ 4C3018FF4B3218FF4B331BFF4F341FFF55331CFF5E3514FF814F1AFFA66F24FF
+ B47A1AFFB57D0EFFB87E0DFFB87E0DFFBC7E14FFBC7D15FFBC7D15FFBA7B13FF
+ B87A10FFB7790FFFB7790FFFB87A10FFB97B0FFFB97B0FFFB87B0DFFB77A0CFF
+ B77A0CFFB77A0CFFB87B0DFFB87C0BFFB67A09FFB77B09FFB77B0AFFB87C0BFF
+ B87A0EFFB87A0EFFB87A10FFB87A10FFBE8016FFBC7E14FFBA7C10FFB87B0DFF
+ B77A0CFFB87C0BFFBA7E0CFFBB7F0DFFBB7E10FFB97C0EFFB87B0DFFB97C0EFF
+ BB7E10FFBC7F11FFBB7E10FFB97C0EFFB77A0CFFBA7D0FFFBE8113FFBF8214FF
+ BD8012FFBA7D0FFFBA7D0FFFB87D0FFFAF7B09FFB17F0FFFB78017FFB87E17FF
+ B87A14FFBB7913FFBE7C15FFBC7F1FFFB47F2EFFAE8547FFB89C79FFE5D5C5FF
+ FFF9F6FFF0F2F3FFE4EAE9FFE7EDECFFE8EEEDFFECF1F0FFF3F4F2FFF3F4F2FF
+ EFF1F1FFEAEFEEFFECEFEDFFEEEFEDFFF4F3EFFFF4F3EFFFE9EAE6FFFBF7ECFF
+ F8E7CDFFC8A776FFBC8437FFC98728FFBE8016FFBC7E12FFBD7D11FFBC7D0FFF
+ BD7E0EFFBB7F0DFFB47E0CFFB27D0FFFBA7F1BFFB97D19FFBD7C13FFBC7C0CFF
+ BC7E08FFBA8009FFBA7F11FFB98013FFBA7D0FFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBC7D0DFFBD7E0EFFBF8010FF
+ BF8010FFBD7E0EFFBC7D0DFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFFBC7D0DFF
+ BE7F0FFFBF8010FFBD7E0EFFBB7C0CFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFF
+ BB7C0CFFBB7C0CFFBB7C0CFFBB7C0CFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BD7F0DFFBE800EFFBE800EFFBE800EFFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBE800EFFBE800EFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBC7E0CFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBC7E0CFFBA7C0AFFB87A08FFBC7E0CFFBB7D0BFFB97B09FFB97B09FF
+ B97B09FFBB7D0BFFBD7F0DFFBE800EFFBB7D0BFFBB7D0BFFBB7D0BFFB1720AFF
+ B2730BFFB4750DFFB5760EFFB4760CFFB3750BFFB2740AFFB17309FFB4760AFF
+ B4760AFFB47709FFB47709FFB47709FFB47709FFB47709FFB47709FFB47505FF
+ B67A09FFB27A0BFFAE7609FFAE760BFFB47A10FFBB7B0FFFBA770AFFBD7809FF
+ BD7809FFB87907FFB77907FFB47807FFB17706FFB37706FFB07507FFBC831AFF
+ B17815FFAA6F19FF9A6F3EFF7A6F83FF6274B3FF4877CDFF3A78D2FF3A7BC5FF
+ 4485C9FF4886D2FF4481D1FF407BCBFF3D78C8FF3573C1FF346DBCFF3A66BAFF
+ 3D5FB2FF37509AFF344889FF394984FF31427AFF2A3B73FF334477FF3A4773FF
+ 474F6DFF524D5CFF4E4041FF493328FF4B301CFF4C2F1AFF4B2F17FF4A3018FF
+ 4A3018FF4D3119FF4E321AFF4C3319FF4A321AFF49311DFF4C311CFF59371AFF
+ 663C12FF8E5B1DFFB17927FFB77C18FFAF7708FFB07809FFB07809FFBC8016FF
+ BD7E16FFBC7D15FFBA7B13FFB97B11FFB7790FFFB5770DFFB3750BFFBA7C10FF
+ B97B0FFFB6790BFFB5780AFFB5780AFFB77A0CFFB97C0EFFBB7E10FFB87C0BFF
+ B77B0AFFB77B0AFFB77A0CFFB87A0EFFBA7C10FFBD7F15FFBE8016FFC2841AFF
+ C08218FFBC7E12FFB97B0FFFB6790BFFB67A09FFB77B0AFFB87C0BFFBE8113FF
+ BB7E10FFB97B0FFFB97B0FFFBB7D11FFBB7D11FFB97B0FFFB7790DFFB5780AFF
+ B97C0EFFBD8012FFBE8211FFBC7F11FFB97C0EFFB97C0EFFB87D0FFFB07A08FF
+ B57E0FFFB98116FFB97F16FFB87C12FFB97B11FFBB7E16FFB98023FFBD8A44FF
+ A98353FFC0A993FFFBF1EAFFFDFCFEFFEBF0F3FFF8FEFDFFEEF5F2FFE7ECEAFF
+ EBF0EEFFF1F4F2FFF5F6F4FFF1F3F3FFECF1F0FFEBF0EFFFEDF0EEFFECE9E5FF
+ F9F3EEFFFAF4E9FFF2E4CEFFC4AA82FF9A7133FFAE711BFFC4811AFFBF7F13FF
+ BD8012FFBA7B0DFFB97A0CFFBB7D0BFFB97E0AFFB37C09FFB0780BFFBC811AFF
+ BC7E18FFBD7C13FFBB7C0CFFBB7D07FFBB7E08FFB97F0EFFBB8012FFBA7E0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBE7F11FFBE7F11FFBD7E10FFBC7D0DFFBB7C0CFF
+ BB7D0BFFBB7C0CFFBB7D0BFFBB7C0CFFBB7D0BFFBB7C0CFFBB7D0BFFBA7B0BFF
+ B97B09FFB87909FFBB7D0BFFBE7F0FFFBF810FFFBC7D0DFFBA7B0BFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBA7B0BFFB97A0AFFB97A0AFFBA7C0AFF
+ BB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBE800EFFBF810FFFBF810FFFBC7E0CFF
+ BC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBC7E0CFFBC7F0BFFBB7D0BFF
+ BB7E0AFFBB7D0BFFBB7E0AFFBB7D0BFFBB7E0AFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFF
+ BB7D0BFFB97B09FFB97B09FFBB7D0BFFBB7D0BFFB97B09FFB67806FFBD7F0DFF
+ BB7D0BFFB97B09FFB77907FFB87A08FFBB7D0BFFBE800EFFC08210FFBB7D0BFF
+ BB7D0BFFBB7D0BFFB07109FFB2730BFFB4750DFFB3740CFFB2740AFFB2740AFF
+ B3750BFFB5770DFFB17307FFB27408FFB47709FFB6790BFFB77A0CFFB77A0CFF
+ B77A0CFFB77A0CFFB37608FFB37608FFB17609FFB2770AFFB2770AFFB3780BFF
+ B5770BFFB7770BFFB7780AFFB8790BFFB8790BFFB6790BFFB77A0CFFB77A0CFF
+ B77A0CFFB87A0EFFB5770DFFB87C18FFAF751CFF936B3AFF736D80FF5972B0FF
+ 4476C8FF3E7ED6FF4886D2FF4886D2FF4482D6FF3F7FD3FF3D7EC9FF3E7CC8FF
+ 3C76C8FF376DC2FF4071C7FF406ABDFF3054A2FF26438DFF304A8DFF395193FF
+ 3B4E91FF3D4F8EFF3A4882FF3A4474FF47486AFF544E61FF503F42FF42291FFF
+ 4A2B16FF5B3C23FF4E2F18FF4C3018FF492F11FF4D3414FF513A20FF4C351FFF
+ 482F1FFF533621FF4F2D09FF795019FFA17022FFB07819FFB4770FFFB77C0EFF
+ B77F10FFB47B0EFFB2760CFFB4750DFFB5760EFFB77810FFB97B11FFBA7C12FF
+ BB7D13FFBC7E14FFB97B0FFFBA7C10FFBA7D0FFFBA7D0FFFB97C0EFFB77A0CFF
+ B47709FFB37608FFC18416FFBD8012FFB77A0CFFB5770BFFB6780CFFB87A0EFF
+ B87A0EFFB87A0EFFB6780CFFBC7E12FFBD7F13FFB97B0FFFB97B0FFFBD8012FF
+ BC7F11FFB6790BFFB67B0DFFB67B0EFFB67A10FFB97C14FFBC7F17FFBC7E18FF
+ BA7B13FFB7790FFFB7790DFFB87B0DFFBB7C0CFFBC7E0CFFBC7D0DFFBB7C0CFF
+ B97A0CFFB8790BFFBA7B0BFFBE7F11FFB6780EFFB2770AFFBA8211FFB88210FF
+ B07C11FFAF7F27FFAE8148FFCDA98BFFF0DBD3FFF8F0F1FFE9EDEEFFE6EEEDFF
+ E8F2ECFFE4EFE7FFE5ECE7FFE3E8E6FFEBEDEDFFF2F2F2FFECEFEDFFEBF0EEFF
+ ECF2F1FFEAECECFFEDE8E9FFFFFBF5FFFFF2DCFFD6B88FFFA77F3EFFA2701DFF
+ B3791AFFBE7F17FFBC7E12FFBB7F0EFFB97D0CFFB77B0AFFB77B0AFFB77B09FF
+ B77D0CFFB87D0FFFB87D10FFB97B0FFFB97C0EFFB97D0CFFBB7D0BFFBB7F0DFF
+ BC800FFFBD8110FFBB7F0EFFBB7F0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7E10FFBB7E10FFB77A0CFFBD8012FFBD8012FFB77A0CFFB6780CFFBC7E12FF
+ C18317FFC18416FFB57907FFB97E0AFFBC800EFFBC810DFFBA7E0CFFB87D09FF
+ B87C0AFFB97E0AFFB97D0BFFBA7F0BFFBB7F0DFFBC810DFFBC800EFFBB800CFF
+ BA7E0CFFB97D0BFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBC7D0DFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFF
+ BD7E0EFFBA7B0BFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BE7F0FFFBE7F0FFFC08111FFC08111FFBF8010FFBD7E0EFFBB7C0CFFBC7D0DFF
+ C08111FFC38513FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FF
+ BC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FFBC7F0BFFBC7F09FF
+ BC7F0BFFBC7F0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFB87A08FFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BA7C0AFFB87A08FFBF810FFFBD7F0DFFBC7E0CFFBC7E0CFFBE800EFFBF810FFF
+ BE800EFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FFB2730BFFB4750DFF
+ B3740CFFB2740AFFB2740AFFB3750BFFB5770DFFB17307FFB37509FFB47709FF
+ B6790BFFB77A0CFFB77A0CFFB77A0CFFB77A0CFFB37509FFB37509FFB4760AFF
+ B4760AFFB4760AFFB5770BFFB5770BFFB5770BFFB6780CFFB6780CFFB6780CFF
+ B6780CFFB7790DFFB7790DFFB7790DFFB7790DFFB6750CFFB87A14FFAE7518FF
+ 956F39FF777281FF5E76B2FF4677C7FF3D7AD0FF3E7CC8FF4683CDFF4783D5FF
+ 4885D5FF4A88CEFF4987CEFF467ED0FF3E73CAFF3D70C6FF3D6CC0FF305BACFF
+ 284E9CFF34539EFF3C57A1FF395199FF3B4F96FF3C4E8FFF3D4B85FF474D7CFF
+ 4F4E6EFF504653FF4B3835FF482E1EFF4C2D16FF502F1BFF56381FFF553A18FF
+ 4F3614FF4D371BFF4A321AFF492E1AFF523419FF5F3B0BFF855B16FFA9741DFF
+ B47A13FFB5770DFFB87B0DFFB87D0FFFB57C0FFFB77B11FFB97A12FFB87911FF
+ B87911FFB87A10FFB7790FFFB7790FFFB7790FFFB6780CFFB6780CFFB87B0DFF
+ B97C0EFFB97C0EFFB97C0EFFB87B0DFFB77A0CFFBC7E12FFBA7C10FFB7790DFF
+ B7790DFFB97B0FFFBA7C10FFB97B0FFFB87A0EFFB4760AFFB6780CFFB6780CFF
+ B4760AFFB4760AFFB6780CFFB6780CFFB4760AFFB57A0CFFB57A0CFFB67A10FF
+ B97C14FFBB7D17FFBB7D17FFBA7A14FFB77810FFBB7D11FFBC7F11FFBF8010FF
+ BF8010FFBF8010FFBE7F0FFFBD7D11FFBC7C10FFC18013FFBA790DFFB8780CFF
+ BE8113FFBA810EFFAC7708FFA97814FFAC8132FFAE875AFFDDBFACFFF9E7E6FF
+ F6F0F5FFF2F6F7FFEBF3F2FFE4EEE8FFEAF1ECFFEBF2EFFFEBF0EFFFEEEEEEFF
+ ECECECFFEDEEECFFF1F4F2FFF1F6F7FFEFF1F2FFF4ECEDFFFDEAE2FFE6C4A6FF
+ BC935CFFB07D2DFFB27A1BFFB47916FFB97F16FFB97E10FFBB7F0EFFBB7F0EFF
+ BA7E0DFFB97D0CFFB87C0BFFB77B0AFFB77B0AFFBA7E0DFFBA7E0DFFB97D0CFF
+ B97D0CFFB97D0CFFBB7F0EFFBC800FFFBD8110FFBB7F0DFFBB7F0DFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBB7E10FFBB7E10FFB97C0EFFBC7F11FFBC7E12FF
+ B7790DFFB7790DFFBD7F13FFC08218FFC08216FFB87C0AFFBA7F0BFFBB800CFF
+ BB800CFFBA7F0BFFB97E0AFFB97E0AFFBA7F0BFFB97E0AFFBA7F0BFFBB800CFF
+ BC810DFFBC810DFFBB800CFFBA7F0BFFB97E0AFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBE7F0FFFBC7D0DFFBA7B0BFF
+ BB7C0CFFBD7E0EFFBE7F0FFFBD7E0EFFBB7C0CFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBF8010FFC08111FFC08111FF
+ BE7F0FFFBC7D0DFFBC7D0DFFBE7F0FFFC18311FFBC7F0BFFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBE800EFFC08210FF
+ C28412FFC28412FFC08210FFBE800EFFBD7F0DFFBF810FFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBE800EFFBF810FFFBE800EFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ B07109FFB2730BFFB4750DFFB3740CFFB2740AFFB2740AFFB3750BFFB5770DFF
+ B27408FFB37509FFB47709FFB6790BFFB77A0CFFB77A0CFFB77A0CFFB6790BFF
+ B37509FFB4760AFFB4760AFFB4760AFFB5770BFFB5770BFFB6780CFFB6780CFF
+ B7790DFFB7790DFFB7790DFFB7790DFFB6780CFFB6780CFFB6780CFFB6780CFF
+ B5770DFFB47912FFAD7615FF9A7237FF81767EFF697AB2FF4F77C9FF3E77CDFF
+ 4680CBFF4A87C9FF4984C9FF4F86C9FF5086C7FF4A7EC4FF4179C8FF3D74C9FF
+ 3A70C5FF3E6FC5FF3763B6FF345DACFF4061B0FF4260ADFF3A57A2FF3A539DFF
+ 3A5097FF405291FF445185FF4B5077FF555065FF574B51FF4D3A33FF422818FF
+ 4E2E1BFF5B3C23FF593E1CFF4F3614FF4F3517FF4F3419FF503217FF5B3711FF
+ 774F14FF956719FFAF791BFFB57B12FFB6760AFFB97A0AFFBA7E0DFFB77D0CFF
+ BB7D13FFBA7B13FFB97A12FFB87911FFB7790FFFB6780EFFB5770DFFB5770DFF
+ B6780CFFB7790DFFB87B0DFFB87B0DFFB97C0EFFB97C0EFFB87B0DFFB87B0DFF
+ B87A0EFFB7790DFFB87A0EFFB97B0FFFBB7D11FFBB7D11FFB97B0FFFB87A0EFF
+ B5770BFFB37509FFB27408FFB4760AFFB4760AFFB27408FFB37509FFB5780AFF
+ B47A09FFB47B08FFB57A0CFFB87D10FFBA7D15FFB97C14FFB97A12FFB77810FF
+ BB7D11FFBB7E10FFBC7F11FFBD8012FFBD7F13FFBD7F13FFBE7C15FFBD7B14FF
+ C2831BFFB8770EFFBB7A0EFFC48316FFBC7F11FFB17914FFAE7F29FFAD8747FF
+ C5A784FFF7E2D3FFFFF5F6FFF3EDF2FFF7F9FAFFEFF3F4FFE1E6E7FFEDF2F3FF
+ EEF1F5FFF3F4F8FFF2EFF1FFEDE8E9FFEEECECFFF4F3F5FFF3F3F9FFF4F0F5FF
+ FFF6F7FFEDD3C5FFB8916AFF9D6C2EFFB37C27FFBF8323FFB67A1AFFBB8019FF
+ B87D10FFBB7F0EFFBC800FFFBC800FFFBB7F0EFFB97D0CFFB67A09FFB47807FF
+ BA7E0DFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFBA7E0DFFBC800FFFBC800FFF
+ BB7F0DFFBB7F0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBB7E10FFBB7E10FF
+ BB7E10FFBC7F11FFBA7C10FFB7790DFFB97B0FFFBE8014FFC08218FFBE8014FF
+ BC800EFFBB800CFFB97E0AFFB97E0AFFBB800CFFBB800CFFBB800CFFBB800CFF
+ B97E0AFFBA7F0BFFBB800CFFBB800CFFBB800CFFBB800CFFBA7F0BFFB97E0AFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BF8010FFC08111FFC18212FFBF8010FFBC7D0DFFBB7C0CFFBC7D0DFFBE800EFF
+ BC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFF
+ BE800EFFBD7F0DFFBB7D0BFFBC7E0CFFBE800EFFBF810FFFBD7F0DFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFB07109FFB2730BFFB4750DFFB3740CFFB2740AFF
+ B2740AFFB3750BFFB5770DFFB37509FFB37509FFB5780AFFB6790BFFB77A0CFF
+ B77A0CFFB6790BFFB6790BFFB4760AFFB4760AFFB4760AFFB5770BFFB5770BFF
+ B6780CFFB6780CFFB6780CFFB7790DFFB7790DFFB7790DFFB7790DFFB6780CFF
+ B6780CFFB6780CFFB4790CFFB77B11FFB27910FFAD7510FF9C722FFF877673FF
+ 747DA9FF5A79C8FF4474CCFF4D87CFFF4D8AC8FF518AC2FF6598D0FF6B97D2FF
+ 517FBFFF4074C0FF3E76C8FF3A70C7FF3E70C8FF3B6ABEFF3C66B9FF456BBDFF
+ 4366B6FF3C5BAAFF3957A4FF344F99FF384F93FF3C4E89FF444E7DFF525472FF
+ 5A5465FF56484CFF4C3932FF4B2E1FFF54351EFF503618FF4D3315FF52371CFF
+ 543619FF5A3814FF694110FF8F631CFFA6741CFFB57C19FFB77B11FFB7770BFF
+ B97A0CFFB97D0BFFB97D0BFFB87A10FFB87911FFB87911FFB87911FFB87A10FF
+ B87A10FFB7790FFFB7790FFFBB7D11FFBA7C10FFBA7D0FFFB97C0EFFB77A0CFF
+ B6790BFFB5780AFFB47709FFB87A0EFFB97B0FFFB97B0FFFBA7C10FFBA7C10FF
+ BA7C10FFB97B0FFFB87A0EFFB97B0FFFB5770BFFB6780CFFBC7E12FFBC7E12FF
+ B6780CFFB5770BFFB97C0EFFB47B08FFB47B07FFB57B0AFFB77C0EFFB87C12FF
+ B87B13FFB87911FFB7790FFFB7790DFFB87A0EFFB87A0EFFB97B0FFFB97B11FF
+ B97A12FFB97815FFB97815FFBC7E1AFFBD7D17FFBF7B10FFC07C11FFC2801AFF
+ BD832AFFB88B47FFB89769FFEAD5BFFFFFF8F0FFFFF8F8FFF0EBEDFFF7F4F6FF
+ EDEEF2FFE1E4E9FFEEF0F8FFEEEDF6FFF7F3F9FFF6F1F2FFEFEBEAFFF0EBECFF
+ F2EFF1FFF1EFF5FFFAF0F6FFFFFCF7FFDCBDA6FFA57845FF9F681FFFBA7E24FF
+ C38422FFBB7E1CFFBE821EFFBA7F12FFBC800FFFBC800FFFBC800FFFBB7F0EFF
+ B97D0CFFB77B0AFFB67A09FFBB7F0EFFBA7E0DFFBA7E0DFFB97D0CFFB97D0CFF
+ BA7E0DFFBB7F0EFFBC800FFFBB7F0DFFBB7F0DFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBB7E10FFBB7E10FFBD8012FFBB7E10FFB87A0EFFB87A0EFFBB7D11FF
+ BE8014FFBE8016FFBC7E12FFBF8311FFBC810DFFB87D09FFB87D09FFBB800CFF
+ BD820EFFBD820EFFBB800CFFBA7F0BFFBA7F0BFFBA7F0BFFBB800CFFBB800CFF
+ BA7F0BFFBA7F0BFFBA7E0CFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBC7D0DFFBC7D0DFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBF8010FFC08111FFC18212FFC08111FFBD7E0EFF
+ BB7C0CFFBB7C0CFFBC7E0CFFBC7F0BFFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FFBC7F09FF
+ BC7F09FFBC7F09FFBC7F0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFB87A08FFB97B09FFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFB97B09FFB87A08FFBE800EFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BE800EFFBD7F0DFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FFB2730BFF
+ B4750DFFB3740CFFB2740AFFB2740AFFB3750BFFB5770DFFB37509FFB4760AFF
+ B5780AFFB6790BFFB77A0CFFB6790BFFB6790BFFB5780AFFB4760AFFB4760AFF
+ B5770BFFB5770BFFB6780CFFB6780CFFB7790DFFB7790DFFB7790DFFB7790DFF
+ B7790DFFB7790DFFB6780CFFB6780CFFB6780CFFB4790CFFB77F12FFB07A0FFF
+ AE750CFFA07225FF8A715DFF7B7997FF6379C1FF4D76CBFF4F84CDFF508CC7FF
+ 5E96C5FF8EBDE9FF9CC1F3FF6E93CFFF4A7DC3FF457ECDFF3D73CAFF3E72CCFF
+ 3B6CC2FF3C6ABEFF446EC1FF4267BBFF385CB0FF395BAEFF3051A0FF304D97FF
+ 344D8DFF3D4F84FF495179FF4D506CFF524F5FFF5B5053FF503A2FFF4F3322FF
+ 442C16FF483018FF533A20FF563716FF5F3A0EFF774B0EFFA27220FFB07B1AFF
+ B97E17FFB97B11FFB6770FFFB7790DFFB97D0CFFB77E0BFFB97B11FFB97A12FF
+ B87911FFB87911FFB87A10FFB7790FFFB7790FFFB7790FFFBB7D11FFBB7D11FF
+ B97C0EFFB87B0DFFB77A0CFFB6790BFFB5780AFFB5780AFFBC7E12FFBC7E12FF
+ BA7C10FFB97B0FFFB7790DFFB7790DFFB7790DFFB87A0EFFB97B0FFFB7790DFF
+ BA7C10FFC18317FFC18317FFBA7C10FFB7790DFFB97C0EFFB37A06FFB57D06FF
+ B67D0AFFB77D0CFFB77C0FFFB67A10FFB67A10FFB77B11FFB57A0DFFB57A0DFF
+ B57A0DFFB67A10FFB67812FFB77915FFB87819FFB8781AFFB5781AFFBB7E1CFF
+ BD7910FFC07812FFC47E23FFB77C34FFB78D5EFFCDB49AFFFDF3E9FFF9F5F4FF
+ F3F1F1FFF2EFF1FFF6F1F3FFF0ECF2FFE8E7F1FFEDEBF7FFF2EBF8FFF6EFF6FF
+ F6F1F0FFF2EFEBFFF1EDECFFF1EEF0FFF8F1F8FFFFF6F7FFFFEADAFFCBA680FF
+ AD7937FFB57925FFBF7E1CFFBE7C15FFBA7E1AFFBC811AFFBC8114FFBD8110FF
+ BB7F0EFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFB97D0CFFBC800FFFBB7F0EFF
+ BA7E0DFFB97D0CFFB97D0CFFBA7E0DFFBA7E0DFFBB7F0EFFBA7E0CFFBA7E0CFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7D0FFFBA7D0FFFBE8113FFBA7D0FFF
+ B87A0EFFBA7C10FFBD7F13FFBE8014FFBD7F15FFBC7E12FFBF8312FFBC800EFF
+ B87C0AFFB87C0AFFBB7F0DFFBD810FFFBD810FFFBB7F0DFFBB7F0DFFBA7E0CFF
+ BA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBB7F0DFFBB7C0CFFBC7D0DFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBF8010FFBF8010FF
+ BE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBE7F0FFFC08111FF
+ C18212FFBF8010FFBC7D0DFFBA7B0BFFBA7B0BFFBB7D0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBE800EFFBE800EFF
+ BF810FFFBF810FFFBF810FFFBF810FFFBE800EFFBE800EFFBD7F0DFFBC7E0CFF
+ BA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBC7E0CFFBB7D0BFFBC7E0CFFBC7E0CFF
+ BC7E0CFFB07109FFB2730BFFB4750DFFB3740CFFB2740AFFB2740AFFB3750BFF
+ B5770DFFB4760AFFB5770BFFB6790BFFB6790BFFB6790BFFB6790BFFB5780AFF
+ B47709FFB5770BFFB5770BFFB5770BFFB6780CFFB6780CFFB7790DFFB7790DFF
+ B7790DFFB5770BFFB5770BFFB6780CFFB6780CFFB7790DFFB7790DFFB87A0EFF
+ B67B0EFFB58012FFB07B0DFFB2770AFFA6701DFF8C6B44FF81737EFF6F7AB4FF
+ 5778C8FF5489D2FF528FCDFF6198C5FF99C8EEFFB1D0FDFF7B9AD1FF4F7FBFFF
+ 467FCAFF4077CCFF3E73CDFF3B6DC5FF3D6CC2FF436FC3FF3D66BBFF365DB2FF
+ 3A5FB4FF375CAEFF3253A2FF345097FF3A528EFF3F4E7FFF3F486DFF474B67FF
+ 5D5867FF5C4A4BFF533C34FF412E21FF453120FF4F3622FF513211FF633B07FF
+ 82550CFFAE7A1CFFB77E15FFB97D13FFB97A12FFB67814FFB57A13FFB57D0EFF
+ B47C0DFFBB7F15FFBC7D15FFBB7C14FFB97A12FFB7790FFFB5770DFFB4760CFF
+ B3750BFFB87A0EFFB7790DFFB77A0CFFB77A0CFFB77A0CFFB87B0DFFB97C0EFF
+ BA7D0FFFBD7F13FFBD7F13FFBC7E12FFB97B0FFFB6780CFFB5770BFFB6780CFF
+ B87A0EFFB5770BFFB6780CFFB97B0FFFBE8014FFBE8014FFB97B0FFFB6780CFF
+ B5780AFFB47B07FFB67E07FFB77E0BFFB77D0CFFB67B0DFFB67B0EFFB77B11FF
+ B97D13FFB97E11FFB97E11FFB87C12FFB97C14FFBA7C16FFBB7C1AFFBC7C1EFF
+ BB7C20FFB77C1FFFB57919FFBA7611FFC27D1CFFBD7A2BFFAB743BFFBB9779FF
+ E8D6CBFFFAF6F5FFE3E7E8FFE8EAEBFFF5F4F6FFF9F3F8FFF5EEF5FFF0ECF7FF
+ EDE9F5FFF6EEF9FFF2ECF1FFF3F0ECFFF0F0EAFFEEECEBFFF8F3F4FFFFF4F6FF
+ FCE9E1FFDDBDA0FFBA905BFFB77F30FFC58526FFBC7B12FFB8780CFFBB7E16FF
+ B67C12FFBC8113FFBD8110FFBB7F0EFFB97D0CFFB97D0CFFB97D0CFFBB7F0EFF
+ BC800FFFBC800FFFBC800FFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFBA7E0DFF
+ BA7E0DFFBA7E0CFFBA7E0CFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7D0FFF
+ BA7D0FFFBD8012FFBA7D0FFFB97B0FFFBC7E12FFBD7F13FFBB7D11FFBB7D13FF
+ BC7E12FFBC800FFFBB7F0DFFB97D0BFFB97D0BFFBB7F0DFFBB7F0DFFBB7F0DFF
+ BB7F0DFFBB7F0DFFBB7F0DFFBA7E0CFFB97D0BFFB97D0BFFBA7E0CFFBB7F0DFF
+ BB7F0DFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBB7C0CFF
+ BA7B0BFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBC7D0DFF
+ BD7E0EFFC08111FFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFF
+ BB7C0CFFBE7F0FFFBF8010FFBF8010FFBE7F0FFFBB7C0CFFBA7B0BFFBB7C0CFF
+ BD7F0DFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBB7D0BFFBA7C0AFFBB7D0BFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FFB2730BFFB4750DFFB3740CFF
+ B2740AFFB2740AFFB3750BFFB5770DFFB4760AFFB5770BFFB6790BFFB6790BFF
+ B6790BFFB6790BFFB5780AFFB47709FFB5770BFFB5770BFFB6780CFFB6780CFF
+ B7790DFFB7790DFFB7790DFFB7790DFFB37509FFB4760AFFB5770BFFB6780CFF
+ B7790DFFB87A0EFFB97B0FFFB87D10FFB17C0EFFB1790CFFB97A0CFFAD7215FF
+ 92682DFF877061FF777AA0FF5F79BFFF598AD8FF5391D8FF5790C3FF8BBCE4FF
+ ADCAF6FF7E9CCDFF5684BEFF467FC4FF4379CCFF4076CDFF3D70C6FF3F70C6FF
+ 4472C6FF3C68BCFF325DB4FF3760B5FF3C63B8FF375CAEFF3858A3FF3C579AFF
+ 3B4F88FF364674FF3D486EFF50536FFF5D5360FF58494DFF47393AFF41312BFF
+ 453021FF4C2F10FF6A410AFF916010FFB47D15FFB97D0CFFB87A0EFFB97913FF
+ B67A1AFFB47A1AFFB07C12FFB07A0FFFBA7D15FFBB7C14FFBA7B13FFB97A12FF
+ B7790FFFB5770DFFB4760CFFB4760CFFB87A0EFFB87A0EFFB77A0CFFB6790BFF
+ B77A0CFFB87B0DFFB97C0EFFBA7D0FFFB87A0EFFBA7C10FFBC7E12FFBB7D11FF
+ B97B0FFFB7790DFFB7790DFFB87A0EFFB5770BFFB87A0EFFB97B0FFFB7790DFF
+ B7790DFFB97B0FFFB87A0EFFB5780AFFB77B09FFB97E0AFFBB7F0DFFBA7E0DFF
+ B67B0DFFB67B0EFFB87D10FFBA7F12FFB97E11FFB87D10FFB67C12FFB67C13FF
+ B77B17FFB97C1CFFBB7C20FFBC7D23FFBF8427FFB37618FFBB7A18FFBE7E26FF
+ B37735FFB9895FFFDDC0B1FFFCF0F0FFEDF0F4FFDEE7EBFFE6EAEBFFF3F2F4FF
+ F6F0F5FFF4EDF4FFF3EDF8FFF0EAF5FFF3EBF2FFEDE8E9FFEEF0EAFFEBF0E7FF
+ E9EDE8FFFBF8F4FFF2E4DEFFCBB29EFFB38D5DFFB5853DFFBE8425FFC08216FF
+ BC7B0EFFC08111FFC18618FFB57D0EFFB97F0EFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBC800FFFBC800FFFBD8110FFBD8110FFBC800FFFBB7F0EFFB97D0CFF
+ B97D0CFFB97D0CFFBA7E0DFFBA7E0DFFB97D0BFFB97D0BFFB97D0CFFB97D0CFF
+ B97D0CFFB97D0CFFB97C0EFFB97C0EFFBC7F11FFBA7D0FFFBB7D11FFBE8014FF
+ BD7F13FFB97B0FFFB97B11FFBE8014FFB87C0BFFBA7E0CFFBB7F0DFFBB7F0DFF
+ BA7E0CFFB97D0BFFB97D0BFFBA7E0CFFBC800EFFBB7F0DFFBA7E0CFFB97D0BFF
+ B97D0BFFBA7E0CFFBB7F0DFFBC800EFFBA7B0BFFBB7C0CFFBD7E0EFFBF8010FF
+ BF8010FFBD7E0EFFBB7C0CFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFBD7E0EFF
+ BB7C0CFFBA7B0BFFBC7D0DFFBE7F0FFFC08111FFC08111FFBF8010FFBE7F0FFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFFBC7D0DFF
+ BA7B0BFFBA7B0BFFBC7D0DFFBF810FFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFB97B09FFB97B09FF
+ B97B09FFB97B09FFBA7C0AFFBA7C0AFFBD7F0DFFBB7D0BFFB97B09FFBA7C0AFF
+ BC7E0CFFBD7F0DFFBC7E0CFFBA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FF
+ B2730BFFB4750DFFB3740CFFB2740AFFB2740AFFB3750BFFB5770DFFB5770BFF
+ B5770BFFB6790BFFB6790BFFB6790BFFB5780AFFB47709FFB47709FFB5770BFF
+ B5770BFFB6780CFFB6780CFFB7790DFFB7790DFFB7790DFFB87A0EFFB27408FF
+ B37509FFB4760AFFB6780CFFB7790DFFB97B0FFFBA7C10FFB97E11FFAD780AFF
+ B0790AFFBF7C0FFFB57411FF9A691BFF8F7148FF817C8BFF677BB2FF5280CEFF
+ 518CDCFF518DC8FF87B9E7FFB0D0FBFF8EABD8FF6492C8FF4F85C6FF467BCBFF
+ 4379CEFF4074C7FF4375C8FF4675C9FF3B69BDFF325EB2FF3561B5FF3C65BAFF
+ 3B61B3FF395DABFF3C5AA1FF3A5391FF344980FF354776FF434C72FF55526CFF
+ 595162FF4B424FFF3D3235FF3D2A22FF4C2E11FF73480FFFA06C19FFB67D10FF
+ BA7B08FFB9780BFFB97913FFB87B1DFFB47B1EFFAC7B15FFAD790FFFB37910FF
+ B77810FFB77810FFB87911FFB87A10FFB87A10FFB87A10FFB97B11FFBD7F13FF
+ BB7D11FFB97C0EFFB77A0CFFB6790BFFB5780AFFB6790BFFB6790BFFB37509FF
+ B7790DFFBC7E12FFBE8014FFBB7D11FFB97B0FFFB87A0EFFB87A0EFFB97B0FFF
+ BD7F13FFBB7D11FFB4760AFFB4760AFFBB7D11FFBD7F13FFB97C0EFFB87C0BFF
+ BA7E0CFFBB7E10FFBB7E10FFB77C0FFFB67B0EFFB97E11FFBC8114FFB57A0DFF
+ B37A0DFFB2780EFFB2780FFFB37713FFB47818FFB8791DFFB87B1EFFC6892CFF
+ B3781BFFB87C22FFAF7A2AFFA4753FFFD2AE90FFFFF0E9FFFFFAFFFFEDF0F8FF
+ E8F1F5FFEAEFF0FFEBEDEEFFECE8EEFFEEE7EEFFF0ECF2FFF6EFF6FFEBE4E7FF
+ E8E3E4FFEDF1EBFFE9F1EAFFE7EDE8FFFAF8F0FFDECEBEFF977857FF9A6F30FF
+ B6832DFFBF851EFFB67A09FFBB7F0EFFCC901FFFC98F1EFFBB8110FFB87C0BFF
+ B97D0CFFBB7F0EFFBD8110FFBE8211FFBD8110FFBC800FFFBC800FFFBD8110FF
+ BC800FFFBB7F0EFFB97D0CFFB97D0CFFB97D0CFFB97D0CFFBA7E0DFFB97D0BFF
+ B97D0BFFB97D0CFFB97D0CFFB97D0CFFB97D0CFFB97C0EFFB97C0EFFBC7F11FF
+ BA7D0FFFBC7E12FFBF8115FFBD7F13FFB7790DFFB87A10FFBF8115FFB57908FF
+ B97D0BFFBC800EFFBC800EFFBA7E0CFFB87C0AFFB87C0AFFB97D0BFFBC800EFF
+ BB7F0DFFBA7E0CFFB97D0BFFB97D0BFFBA7E0CFFBB7F0DFFBC800EFFBA7B0BFF
+ BB7C0CFFBD7E0EFFBF8010FFBF8010FFBD7E0EFFBB7C0CFFBA7B0BFFBA7B0BFF
+ BD7E0EFFBE7F0FFFBD7E0EFFBB7C0CFFBA7B0BFFBC7D0DFFBE7F0FFFC08111FF
+ C08111FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBA7B0BFFB97A0AFFBA7B0BFFBD7E0EFFC18212FFBC7E0CFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBE800EFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBE800EFFBD7F0DFF
+ BB7D0BFFB97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBB7D0BFFBA7C0AFFBC7E0CFF
+ BC7E0CFFBC7E0CFFAF7008FFB07109FFB1720AFFB3740CFFB3750BFFB3750BFF
+ B2740AFFB2740AFFB4760AFFB4760AFFB5780AFFB5780AFFB6790BFFB6790BFF
+ B6790BFFB77A0CFFB87A0EFFB7790DFFB6780CFFB6780CFFB87A0EFFBA7C10FF
+ BC7E12FFBE8014FFB5770BFFB6780CFFB7790DFFB97B0FFFB97B0FFFB7790DFF
+ B6780CFFB3780BFFB07B0DFFB07809FFBF770BFFC37C14FFB17A19FF94712FFF
+ 807365FF6F7B9DFF5880CBFF4D85DEFF5492D9FF6097D0FF99BEEAFFB1D3FEFF
+ 77A6DAFF4C81C0FF477BC7FF4C7ED0FF4A7CCEFF4272C4FF3E6DBFFF3F6EC0FF
+ 3F6BBEFF3965B8FF3F69BCFF335BADFF3258A6FF3657A0FF375394FF3C5692FF
+ 41568DFF3E4E7DFF4D5076FF4A4866FF535167FF59535EFF483734FF482A11FF
+ 784D14FFAD7722FFB97C0EFFC17F08FFBC7A09FFB5740BFFB27416FFB2791CFF
+ AD7C16FFA8750DFFB37910FFB87911FFB87911FFB97A12FFBA7C12FFBA7C12FF
+ BB7D13FFBB7D13FFC08216FFBD7F13FFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFF
+ B87B0DFFB6790BFFB6780CFFBB7D11FFBB7D11FFB6780CFFB7790DFFBE8014FF
+ C08216FFBC7E12FFC98B1FFFC88A1EFFC4861AFFC08216FFBB7D11FFB7790DFF
+ B4760AFFB27408FFB47709FFBA7D0FFFBB7D13FFB7790FFFB67A10FFBA7E14FF
+ BA7E14FFB4790CFFBD8417FFB88011FFB2790CFFAF770CFFB27811FFB37A17FF
+ B5781AFFB4771AFFBB7C20FFB4781EFFAF7D2AFFA37936FFAD8D62FFF1D9C5FF
+ FFFEFEFFE2DFE8FFE9EDF2FFE8EFF2FFEBF0F1FFEFF1F2FFF3EFF5FFF1EDF3FF
+ F0EDEFFFF1ECEDFFF9F3F4FFEEE9EAFFEFF6F3FFE4EFECFFE8EFECFFF6F1E8FF
+ D3BDA4FFAC8558FFB18034FFB67E1FFFB67E13FFB88011FFB97F15FFB67D10FF
+ B57D0CFFB9800DFFB97D0CFFB97D0CFFBA7E0DFFBB7F0EFFBC800FFFBD8110FF
+ BE8211FFBE8211FFBA7E0DFFB97D0CFFB87C0BFFB87C0BFFB87C0BFFB97D0CFF
+ BA7E0DFFBA7E0DFFB97D0BFFB97D0BFFB87C0BFFB87C0BFFB77B0AFFB77B0AFF
+ B77A0CFFB6790BFFB87B0DFFBB7E10FFBD7F13FFBD7F13FFBB7D11FFBA7C10FF
+ BC7E14FFBE8014FFBB7E10FFB97D0CFFB87C0BFFBA7E0DFFBC800FFFBB7F0EFF
+ B87C0BFFB57908FFBC800FFFBC800FFFBD8110FFBD8110FFBD8110FFBB7F0EFF
+ B97D0CFFB87C0BFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBC7D0DFFBF8010FFC18212FFC08111FFBE7F0FFFBB7C0CFF
+ BB7C0CFFBC7D0DFFBD7E0EFFBC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFF
+ BD7E0EFFBE7F0FFFB97A0AFFBB7C0CFFBE7F0FFFBF8010FFBF8010FFBE7F0FFF
+ BB7C0CFFB97A0AFFBB7D0BFFBD7F0DFFBE800EFFBF810FFFBE800EFFBC7E0CFF
+ BA7C0AFFB87A08FFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFF
+ B97B09FFB97B09FFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BE800EFFBE800EFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBE800EFFBD7F0DFF
+ BC7E0CFFBB7D0BFFB97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BA7C0AFFB97B09FFBA7C0AFFBA7C0AFFBA7C0AFFB1720AFFB2730BFFB3740CFF
+ B4750DFFB4760CFFB3750BFFB2740AFFB2740AFFB5770BFFB5770BFFB5780AFF
+ B6790BFFB6790BFFB77A0CFFB77A0CFFB77A0CFFB5770BFFB6780CFFB7790DFF
+ B87A0EFFB97B0FFFBA7C10FFBA7C10FFBA7C10FFB87A0EFFB87A0EFFB7790DFF
+ B7790DFFB7790DFFB7790DFFB87A0EFFB67B0EFFB37B0EFFB3780AFFBF770BFF
+ C47D0EFFB57A0CFF9B731BFF86714BFF757782FF5D79BAFF4E7ED6FF508BDAFF
+ 5690D2FF7FABDAFFA2C9F5FF87B6EAFF5B8ECCFF4F82CBFF4D7ECCFF4778C8FF
+ 3F70C0FF3C6BBCFF3E6DBEFF416EBFFF416EBFFF3B65B8FF3058AAFF2E54A2FF
+ 31549EFF335297FF3B5798FF3F5896FF3E5289FF414B7BFF444970FF515473FF
+ 5D5B6EFF55474BFF503723FF744B1AFFA06C1FFFBE8119FFC3800DFFC07C0BFF
+ BD7C10FFB97A18FFB47A1AFFAF7C14FFB07C12FFB47A11FFB87911FFB87911FF
+ B87911FFB87A10FFB7790FFFB7790FFFB7790FFFBB7D11FFB87A0EFFB6790BFF
+ B77A0CFFBA7D0FFFBC7F11FFBD8012FFBD8012FFB4760AFFB6780CFFB7790DFF
+ B7790DFFB97B0FFFBE8014FFC18317FFC18317FFC08216FFBF8115FFBE8014FF
+ BD7F13FFBC7E12FFBB7D11FFBA7C10FFBA7C10FFB7790DFFBA7C12FFBB7C14FF
+ BA7B13FFB97C14FFBB7E16FFBA7E14FFB67D10FFB77F10FFB57E0FFFB57D10FF
+ B47E13FFB78018FFBA811EFFBD8324FFBF8427FFB37619FFAE7722FFB3883FFF
+ BD9F68FFD2BE9FFFF6ECE2FFFFFEFFFFEFEEF7FFEBEEF2FFEBF0F1FFECF0F1FF
+ EFF0F4FFF0EEF4FFEFEEF2FFF0EEEDFFF1EEEAFFF6F0F1FFEFEDEDFFE3EBEBFF
+ E4EFEDFFF9FCFAFFF6EDDFFFCEB290FFB3864DFFB8822DFFBB801CFFB98017FF
+ BC831AFFBB831EFFB67F17FFB97E10FFBB7F0DFFB97D0CFFBA7E0DFFBA7E0DFF
+ BB7F0EFFBC800FFFBC800FFFBD8110FFBD8110FFB97D0CFFB97D0CFFB87C0BFF
+ B87C0BFFB87C0BFFB97D0CFFBB7F0EFFBC800FFFBB7F0DFFBB7F0DFFBB7F0EFF
+ BA7E0DFFBA7E0DFFB97D0CFFB97C0EFFB97C0EFFB97C0EFFBA7D0FFFBC7E12FF
+ BB7D11FFB97B0FFFB97B0FFFBC7E14FFBE8014FFBD8012FFBB7F0EFFB87C0BFF
+ B87C0BFFBA7E0DFFBB7F0EFFB97D0CFFB87C0BFFBB7F0EFFBC800FFFBD8110FF
+ BD8110FFBC800FFFBB7F0EFFBA7E0DFFB97D0CFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBA7B0BFFBC7D0DFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBD7E0EFFC08111FFBF8010FFBD7E0EFF
+ BC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFFBB7C0CFFBC7D0DFFBC7D0DFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBF810FFFBE800EFFBC7E0CFF
+ BA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BE800EFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFF
+ B3740CFFB4750DFFB4750DFFB5760EFFB5770DFFB4760CFFB3750BFFB2740AFF
+ B6780CFFB6780CFFB6790BFFB77A0CFFB77A0CFFB87B0DFFB87B0DFFB87B0DFF
+ B37509FFB5770BFFB7790DFFB97B0FFFBA7C10FFB97B0FFFB87A0EFFB7790DFF
+ BB7D11FFBA7C10FFB87A0EFFB7790DFFB7790DFFB87A0EFFBA7C10FFB97E11FF
+ B77C0FFFB6790BFFC0780CFFC37D0CFFB67C05FFA1730EFF8E6F30FF7B7062FF
+ 6574A2FF587CC8FF4F86D7FF4E89D1FF6395C9FF86B4E3FF8EBDF5FF6999D9FF
+ 5486CEFF4C7DC9FF4575C3FF4373C1FF4171BFFF3E6EBCFF416FBDFF4573C1FF
+ 406BBCFF375EADFF2E54A2FF2E519BFF305097FF38559AFF3D599AFF3F5492FF
+ 3C4981FF434A7BFF4B5279FF5B5C76FF605662FF5E483DFF734E28FF9A6826FF
+ BC8124FFBF7E12FFC07B0EFFC27E13FFBF7D17FFB57711FFB27A0FFFB67E11FF
+ B77A12FFB87911FFB87911FFB77810FFB6780EFFB5770DFFB5770DFFB4760CFF
+ BF8115FFBC7E12FFB87B0DFFB77A0CFFB77A0CFFB97C0EFFB97C0EFFB97C0EFF
+ BD7F13FFBB7D11FFB97B0FFFBA7C10FFBA7C10FFB87A0EFFB97B0FFFBB7D11FF
+ B97B0FFFB97B0FFFBA7C10FFBB7D11FFBC7E12FFBD7F13FFBD7F13FFBE8014FF
+ BD7C13FFBB7912FFBB7C14FFBE7E18FFBC7E18FFBA7D15FFB87E14FFB98013FF
+ B27A0BFFB47D0EFFB77F12FFB88217FFB9821AFFBA8320FFBD8427FFC1882DFF
+ B57A24FFA9782AFFAE8C50FFD1BD94FFF1E7D5FFF6F5F1FFF2F3F7FFF1F4F9FF
+ EEF0F1FFEEF0F0FFECF0F1FFECEFF3FFEEEEF4FFEDEFF0FFF0EFEBFFF1EEE9FF
+ F0EEEEFFF7F9FAFFE9EFF4FFF3F8FBFFFFFEFAFFDFCEBBFFB89569FFB58440FF
+ BF8329FFC0821CFFBC811DFFBF8623FFBD8526FFBA811EFFBB7F15FFBD8012FF
+ BA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBC800FFF
+ B97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFBA7E0DFFBB7F0EFFBC800FFF
+ BE8210FFBD810FFFBD8110FFBD8110FFBC800FFFBC800FFFBB7E10FFBB7E10FF
+ B97C0EFFBA7D0FFFBA7C10FFB97B0FFFB87A0EFFB97B0FFFBB7D13FFBE8014FF
+ BF8214FFBC7F11FFB97C0EFFB87B0DFFB97C0EFFBA7D0FFFBB7E10FFBA7D0FFF
+ BB7E10FFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ B97A0AFFB97A0AFFBA7B0BFFBC7D0DFFBD7E0EFFBE7F0FFFBD7E0EFFBD7E0EFF
+ BF8010FFBE7F0FFFBD7E0EFFBB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBC7E0CFFBE800EFFBF810FFF
+ B97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBA7C0AFFBA7C0AFFB4750DFFB5760EFFB6770FFFB6770FFFB6780EFF
+ B5770DFFB4760CFFB3750BFFB6780CFFB7790DFFB77A0CFFB77A0CFFB87B0DFF
+ B87B0DFFB97C0EFFB97C0EFFB4760AFFB5770BFFB6780CFFB87A0EFFB87A0EFF
+ B87A0EFFB7790DFFB7790DFFBB7D11FFBA7C10FFB97B0FFFB97B0FFFB97B0FFF
+ B97B0FFFBA7C10FFBB7D11FFB97B0FFFB9790DFFBF7A0BFFBF7D0CFFB77D06FF
+ A7760AFF9B711EFF886E46FF737184FF687FB7FF5282CAFF4C87CFFF548DC1FF
+ 679CCEFF7EADEAFF6C9BDFFF5786D0FF4A7BC7FF4677C3FF4C7DC9FF4B7BC9FF
+ 4171BFFF3E6CBAFF406EBCFF4D78C7FF426BBAFF375DABFF3054A0FF30519AFF
+ 33539AFF36549BFF395396FF3C4C8EFF404C86FF3F4C7AFF4D5376FF5D5A70FF
+ 615256FF70523FFF91683BFFA8762AFFB27819FFBB7913FFBD7B12FFBB7811FF
+ B3750BFFB2770AFFB37B0CFFB77B11FFB97A12FFB87911FFB87911FFB87A10FF
+ B7790FFFB7790FFFB7790FFFC18317FFBE8014FFBA7D0FFFB77A0CFFB5780AFF
+ B6790BFFB77A0CFFB87B0DFFC4861AFFBD7F13FFBB7D11FFBD7F13FFBA7C10FF
+ B4760AFFB37509FFB87A0EFFB97B0FFFB97B0FFFB97B0FFFBA7C10FFBA7C10FF
+ BA7C10FFBA7C10FFBA7C10FFBD7C13FFB97710FFB97A12FFBF8018FFBD7F19FF
+ B87B13FFB57C0FFFBA8213FFB57E0FFFB37E0FFFB47F11FFB37F15FFB57F1AFF
+ B57E1DFFB57C21FFB07924FFC48F3FFFAC813EFFB19768FFDDD1B5FFF7F6ECFF
+ EFF3F4FFE8ECF1FFECEFF4FFEFF1F2FFEFF1F1FFEFF1F2FFECEFF3FFEBEEF2FF
+ ECEEEFFFEFEFE9FFEFEFE9FFE5E7E7FFEFF3F4FFE6E9EEFFF8F6F6FFF7EBE1FF
+ C2A88AFFA97D47FFAD772AFFC28525FFC1811BFFBC7F1DFFBD8324FFBC8326FF
+ BA8020FFBD7E16FFC08014FFBB7E10FFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBC800FFFBC800FFFBA7E0DFFB97D0CFFB97D0CFF
+ B97D0CFFB97D0CFFBA7E0DFFBE8210FFBD810FFFBD8110FFBD8110FFBC800FFF
+ BC800FFFBB7E10FFBB7E10FFBA7D0FFFB97C0EFFB87A0EFFB7790DFFB7790DFF
+ B97B0FFFBB7D13FFBD7F13FFBD7F13FFBD8012FFBB7E10FFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBA7D0FFFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FF
+ BA7D0FFFBA7D0FFFBA7D0FFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBB7C0CFFBC7D0DFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFFBC7D0DFF
+ BE7F0FFFC08111FFC18212FFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFB87A08FFBA7C0AFFBC7E0CFFBE800EFFBF810FFF
+ BE800EFFBD7F0DFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ BC7E0CFFBB7D0BFFB97B09FFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFB4750DFFB5760EFF
+ B6770FFFB77810FFB7790FFFB6780EFFB5770DFFB4760CFFB6780CFFB7790DFF
+ B77A0CFFB77A0CFFB87B0DFFB87B0DFFB97C0EFFB97C0EFFB7790DFFB6780CFF
+ B6780CFFB5770BFFB6780CFFB7790DFFB87A0EFFB97B0FFFB97B0FFFBA7C10FF
+ BB7D11FFBC7E12FFBC7E12FFBB7D11FFBA7C10FFB97B0FFFBC7A11FFBB7A0EFF
+ BB7B0BFFBA7E0CFFB57E0BFFAF7A0CFFAB7615FF9C722FFF816D5CFF797E97FF
+ 577CB4FF4F86C9FF5790C7FF548CC3FF6496D8FF6999E1FF5B8CD6FF4B7DC9FF
+ 4677C5FF4E7FCDFF4F80CEFF4273C1FF3B6BB9FF3F6DBBFF547FCEFF4E77C6FF
+ 4268B6FF375BA7FF3355A1FF33539EFF33539EFF38559FFF3E539EFF3E5194FF
+ 374B82FF40507BFF52587BFF565369FF5E4F53FF775C48FF8B6634FFA2722AFF
+ B37920FFB67814FFB7750FFFB8780CFFB6790BFFB3780AFFB97B11FFB97A12FF
+ BA7B13FFBA7B13FFBA7C12FFBB7D13FFBB7D13FFBB7D13FFB97B0FFFB87A0EFF
+ B77A0CFFB6790BFFB6790BFFB87B0DFFBB7E10FFBE8113FFBE8014FFB97B0FFF
+ B87A0EFFBC7E12FFBB7D11FFB7790DFFB87A0EFFBD7F13FFB97B0FFFB97B0FFF
+ B97B0FFFB97B0FFFB87A0EFFB87A0EFFB87A0EFFB87A0EFFBB7B0FFFB7760DFF
+ B7790FFFBD7F15FFBB7E16FFB67A10FFB37A0DFFB88011FFBC8516FFB68112FF
+ B27C11FFB17C14FFB57E1DFFB57F21FFB27923FFA97424FFBC9049FFB18F59FF
+ CBB794FFF2EAD9FFF5F8F6FFEDF3F8FFEFF3F8FFECEFF4FFF0F2F3FFF0F2F3FF
+ EFF0F4FFEBEEF2FFE9EEEFFFEAEFEEFFEFEEEAFFEDEEEAFFECF2F1FFEDF3F2FF
+ F0EEEEFFFFF8F2FFF4DDC7FFC6A377FFBE8D47FFBD852CFFC38521FFBF8018FF
+ B87B19FFBA7E1EFFBB7E20FFB97C1AFFBC7C16FFC07F16FFBA7D0FFFBA7E0DFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFC08413FFBF8312FF
+ BD8110FFBA7E0DFFB87C0BFFB87C0BFFB77B0AFFB77B0AFFBC800EFFBB7F0DFF
+ BB7F0EFFBB7F0EFFBA7E0DFFBA7E0DFFB97C0EFFB97C0EFFBA7D0FFFB97C0EFF
+ B7790DFFB7790DFFB87A0EFFBA7C10FFBB7D13FFBB7D11FFBA7C10FFBB7E10FF
+ BE8113FFBF8214FFBE8113FFBB7E10FFB97C0EFFB87B0DFFBA7D0FFFBA7D0FFF
+ BA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFBB7E10FFBB7C0CFFBC7D0DFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBB7C0CFFBB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFF
+ BA7B0BFFBA7B0BFFBC7D0DFFBE7F0FFFC08111FFC18212FFBA7B0BFFBB7C0CFF
+ BD7E0EFFBF8010FFBF8010FFBD7E0EFFBB7C0CFFBA7B0BFFB87909FFBA7B0BFF
+ BC7D0DFFBE7F0FFFBF8010FFBE7F0FFFBD7E0EFFBB7C0CFFBE7F0FFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBA7B0BFFB97A0AFFBB7D0BFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFB2730BFFB3740CFFB5760EFFB6770FFFB7790FFFB6780EFFB6780EFF
+ B6780EFFB6780CFFB6780CFFB6790BFFB77A0CFFB77A0CFFB87B0DFFB87B0DFF
+ B87B0DFFB97B0FFFB87A0EFFB6780CFFB5770BFFB5770BFFB6780CFFB87A0EFF
+ BA7C10FFB87A0EFFB97B0FFFBB7D11FFBC7E12FFBC7E12FFBB7D11FFB97B0FFF
+ BA7A0EFFBE7A11FFBB7A0EFFB77B09FFB57E0BFFB37E10FFB27C11FFB97B0FFF
+ AC761FFF8E6A3AFF7D7470FF5A749CFF5183BFFF5893CBFF4D89C5FF5486CEFF
+ 6694E1FF6092DEFF4D81CDFF4576C4FF487CC9FF4C7DCBFF4576C4FF3F70BEFF
+ 4272C0FF4E7CCAFF4F7AC9FF486FBDFF3C62B0FF375BA9FF3256A4FF3256A4FF
+ 3E5DACFF3E59AAFF3D55A1FF385191FF3D5289FF465586FF484E77FF4A4663FF
+ 56484EFF725840FF916C38FFAB7A2EFFB37A1FFFB67814FFBC7B12FFBB7E10FF
+ B87B0DFFB97B11FFBA7B13FFBA7B13FFBB7C14FFBC7E14FFBD7F15FFBD7F15FF
+ BE8016FFB97B0FFFB97B0FFFB97C0EFFB87B0DFFB77A0CFFB6790BFFB87B0DFF
+ BA7D0FFFBE8014FFBB7D11FFBA7C10FFBA7C10FFBA7C10FFB87A0EFFB87A0EFF
+ BB7D11FFB6780CFFB7790DFFB7790DFFB87A0EFFB97B0FFFB97B0FFFBA7C10FF
+ BA7C10FFB97A0CFFB8790BFFB7790DFFBA7C10FFB97E11FFB77C0FFFB47C0DFF
+ B57E0FFFBF8819FFB88315FFB27E14FFB37D18FFB78122FFBD852CFFBD8533FF
+ B58239FFA27D3FFFB89E70FFE8D8C1FFFFFBF4FFF1F4F8FFEAF1FAFFF0F6FDFF
+ EBEEF3FFF2F3F7FFF0F1F5FFEDF0F4FFEBEFF0FFE9EFEEFFE9EEECFFEFEDECFF
+ EDEEECFFDDE8E5FFE4EEE8FFFAF4EFFFF6E3D4FFC8A884FFAA7E43FFB5812EFF
+ BE8621FFC1851BFFBC7E14FFB67812FFB97B17FFBA7C18FFBA7A14FFBC7A13FF
+ BF7F13FFB97C0EFFB97D0CFFB97D0CFFB97D0CFFBA7E0DFFBA7E0DFFBA7E0DFF
+ BA7E0DFFC18514FFC08413FFBD8110FFBB7F0EFFB97D0CFFB87C0BFFB77B0AFF
+ B77B0AFFBA7E0CFFBA7E0CFFBA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87B0DFF
+ B87B0DFFB97C0EFFB87B0DFFB87A0EFFB97B0FFFBB7D11FFBC7E12FFBB7D13FF
+ BA7C10FFB7790DFFBA7D0FFFBE8113FFC08315FFBE8113FFBB7E10FFB87B0DFF
+ B6790BFFBA7D0FFFB97C0EFFB97C0EFFB87B0DFFB97C0EFFBA7D0FFFBB7E10FF
+ BB7E10FFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBB7C0CFF
+ BA7B0BFFBD7E0EFFBE7F0FFFBF8010FFBC7D0DFFB97A0AFFB87909FFBA7B0BFF
+ BC7D0DFFBF8010FFBE7F0FFFBD7E0EFFBB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFF
+ BC7D0DFFB97A0AFFBB7C0CFFBE7F0FFFC08111FFC08111FFBE7F0FFFBB7C0CFF
+ B97A0AFFBE7F0FFFBD7E0EFFBB7C0CFFBA7B0BFFBA7B0BFFBC7D0DFFBE7F0FFF
+ BF8010FFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFFBB7C0CFF
+ BB7C0CFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFF
+ BE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFB07109FFB1720AFFB3740CFFB5760EFF
+ B6780EFFB7790FFFB7790FFFB7790FFFB5770BFFB5770BFFB5780AFFB6790BFF
+ B6790BFFB77A0CFFB77A0CFFB77A0CFFB97B0FFFB97B0FFFB87A0EFFB87A0EFF
+ B87A0EFFB87A0EFFB87A0EFFB87A0EFFB97B0FFFB97B0FFFBA7C10FFBA7C10FF
+ BA7C10FFBA7C10FFB97B0FFFBB7B0FFFBF7B12FFBB7A0EFFB27C07FFAD7B09FF
+ AC7B15FFB37B16FFBF7B0AFFB9760FFFA27125FF806C49FF5F7287FF507DB0FF
+ 4F8AC2FF4F8CCCFF5182D0FF5B8ADCFF5B8FDCFF4A80CDFF4275C5FF457ACAFF
+ 4C7FCFFF497CCCFF4376C6FF4374C4FF4775C3FF507BCAFF4B74C3FF4067B6FF
+ 375EADFF3055A5FF3055A7FF3E60B4FF3C5CB5FF3655AAFF35559CFF375695FF
+ 37508EFF394C85FF3D4678FF414060FF584C4CFF796040FF9A7335FFAD7B29FF
+ B57B1CFFB77A12FFB77C0FFFB97E10FFBA7C12FFBA7B13FFBA7B13FFBA7B13FF
+ BA7C12FFBB7D13FFBB7D13FFBB7D13FFBA7C10FFBC7E12FFBD8012FFBB7E10FF
+ B77A0CFFB47709FFB37608FFB47709FFBE8014FFBF8115FFBD7F13FFB97B0FFF
+ B7790DFFB97B0FFFB97B0FFFB7790DFFB7790DFFB7790DFFB87A0EFFB87A0EFF
+ B97B0FFFBA7C10FFBA7C10FFBB7E10FFB97A0AFFBB7C0CFFBD7E10FFBA7D0FFF
+ B87D0FFFBA7F11FFB77F10FFB47D0EFFBC8516FFBA8517FFB78319FFB67F1CFF
+ B78025FFBD8631FFC99041FFC79652FFAC8D56FFD4C19CFFFDF0E2FFFDF7F8FF
+ EEEDF6FFEAEEF9FFEFF2FAFFEBEEF3FFF2F1FAFFF1F1F7FFEDF0F5FFEAEFF0FF
+ E9EEECFFEBEEECFFEFEDEDFFEBEDEDFFDDEEE5FFECF8ECFFFFFCEFFFE2C9AFFF
+ AB8251FF9D6C22FFAF7A19FFBF8718FFBD8312FFBA7D0FFFBA7910FFBD7C13FF
+ C07F13FFBD7C0FFFBB7B0FFFBC7D0FFFB77B0AFFB87C0BFFB87C0BFFB97D0CFF
+ BA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBF8312FFBE8211FFBC800FFFBB7F0EFF
+ BA7E0DFFB97D0CFFBA7E0DFFBA7E0DFFBB7F0DFFBA7E0CFFBA7E0DFFBA7E0DFF
+ B97D0CFFB97D0CFFB87B0DFFB87B0DFFB97C0EFFB87B0DFFB97B0FFFBB7D11FF
+ BE8014FFBE8014FFBB7D13FFB87A0EFFB7790DFFBA7D0FFFBE8113FFBE8113FF
+ BB7E10FFB87B0DFFB77A0CFFB77A0CFFB97C0EFFB97C0EFFB87B0DFFB87B0DFF
+ B87B0DFFB97C0EFFBB7E10FFBC7F11FFBA7B0BFFBB7C0CFFBD7E0EFFBF8010FF
+ BF8010FFBD7E0EFFBB7C0CFFBA7B0BFFBB7C0CFFBF8010FFC18212FFBE7F0FFF
+ B97A0AFFB77808FFBC7D0DFFC18212FFC08111FFBF8010FFBD7E0EFFBC7D0DFF
+ BB7C0CFFBA7B0BFFBA7B0BFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFF
+ BE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBF8010FFBE7F0FFFBC7D0DFFBA7B0BFF
+ BA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BC7D0DFFBD7E0EFFC08111FFC18212FFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBC7E0CFFBC7E0CFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFAE6E08FF
+ B07109FFB2720CFFB4750DFFB6770FFFB77810FFB77810FFB7790FFFB4760CFF
+ B4760AFFB5770BFFB5770BFFB6780CFFB6790BFFB6780CFFB7790DFFB7790DFF
+ B97B0FFFBA7C10FFBB7D11FFBB7D11FFB97B0FFFB87A0EFFB7790DFFBB7D11FF
+ BA7C10FFB87A0EFFB7790DFFB7790DFFB87A0EFFBA7C10FFBB7D13FFBD7A13FF
+ B87A10FFAD7907FFA97909FFA97812FFB37814FFBF7809FFBA7409FFB57C21FF
+ 8D6B30FF79786EFF627D97FF547FB0FF578CCFFF5183D5FF4C7FD5FF5086D3FF
+ 477EC9FF4278C5FF487DCDFF5285D5FF5283D1FF4B7AC4FF4572BCFF4671C0FF
+ 517CCDFF4D77CAFF3F69BCFF375DAFFF2D52A4FF2E50A4FF3A5CB5FF3B5DB7FF
+ 3155A9FF34549FFF345496FF304B8EFF364C8DFF3D4C8AFF3E4675FF414054FF
+ 5D5147FF83673EFFA17736FFAE7823FFAF730FFFB37706FFBB7F0DFFB97D13FF
+ B87B13FFB87B13FFB77B11FFB87A10FFB87A10FFB7790FFFB7790FFFB3740CFF
+ B57810FFB87B13FFB97D13FFB77B11FFB7790DFFB77A0CFFB87B0DFFB5780AFF
+ BA7C10FFBA7C10FFB6780CFFB7790DFFC08014FFC28216FFBE7E12FFBC7C10FF
+ BC7C10FFBC7C10FFBB7C0EFFBB7B0FFFB87B0DFFB87A0EFFB87B0DFFB97A0AFF
+ BF8010FFC08113FFBA7D0FFFB97E10FFBD8214FFBD8214FFB57D0EFFB88011FF
+ BC8419FFBC841FFFB77F20FFB07A23FFB68131FFC7914AFFCB9F64FFCCB68DFF
+ F4E9D3FFFFFEF7FFF4EFF1FFEDECF5FFF0F3FBFFEFF3F8FFF0F4F9FFF1F3FBFF
+ F1F0F9FFEFEFF5FFECEDF1FFEBEDEDFFECECECFFECEBEFFFEBEDEEFFEDF7F1FF
+ F1F5E9FFF9E8D3FFCCAB84FFAB7B3BFFB27B26FFB47D14FFB57F0DFFB98112FF
+ B67B0DFFBA7A0EFFC18013FFC48212FFBE7F0DFFBA7B0BFFB87C0BFFB67A09FF
+ B77B0AFFB77B0AFFB87C0BFFBA7E0DFFBB7F0EFFBB7F0EFFBC800FFFBC800FFF
+ BC800FFFBB7F0EFFBA7E0DFFBA7E0DFFBB7F0EFFBC800FFFBD8110FFBC800FFF
+ BC800FFFBB7F0EFFBB7F0EFFBA7E0DFFBA7E0DFFBA7D0FFFB97C0EFFB97C0EFF
+ B97C0EFFBA7C10FFBD7F13FFC08216FFC08216FFBB7D11FFB7790DFFB87B0DFF
+ BA7D0FFFBC7F11FFBB7E10FFB87B0DFFB77A0CFFB77A0CFFB97C0EFFB97C0EFF
+ B87B0DFFB77A0CFFB77A0CFFB87B0DFFB97C0EFFBB7E10FFBC7F11FFBA7B0BFF
+ BB7C0CFFBD7E0EFFBF8010FFBF8010FFBD7E0EFFBB7C0CFFBA7B0BFFB87909FF
+ BE7F0FFFC28313FFBF8010FFB97A0AFFB87909FFBE7F0FFFC68717FFBD7E0EFF
+ BC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBB7C0CFF
+ BD7E0EFFBE7F0FFFBF8010FFBE7F0FFFBC7D0DFFBA7B0BFFB87909FFBC7D0DFF
+ BB7C0CFFB97A0AFFB97A0AFFBB7C0CFFBF8010FFC38414FFC68717FFBE800EFF
+ BE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBE800EFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBD7F0DFF
+ BC7E0CFFBA7C0AFFB97B09FFB97B09FFBA7C0AFFBC7E0CFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFB1730FFFB47610FFB77915FFB77913FFB57711FFB3750FFF
+ B3750FFFB4770FFFB77A12FFB5790FFFB5790FFFB67A10FFB77B11FFB77C0FFF
+ B3770DFFAF7407FFB3780BFFB4790CFFB57A0DFFB67B0EFFB67B0EFFB57A0DFF
+ B4790CFFB3780BFFB4790CFFB57A0DFFB57A0DFFB57A0DFFB67B0EFFB67B0EFF
+ B77C0FFFB77B11FFB87E15FFB57C13FFAF7B11FFAD790EFFAD780AFFAF750BFF
+ B5730DFFB57110FFAF7113FFA57424FF8C7139FF797562FF7180A0FF6083C5FF
+ 4B7DD5FF4982DDFF4B84CFFF4078BFFF4276C2FF4C80CDFF4B7EC7FF6491D5FF
+ 769BD9FF4B6EAEFF4468B4FF4A71C6FF3B66C3FF3B67C0FF3F62B2FF3655A4FF
+ 3A58B1FF3353ACFF385DAFFF3C5EAAFF334F96FF2B4286FF37488BFF3C4C8EFF
+ 3B4A88FF425084FF3A4466FF4D4D5BFF625144FF836038FFAA7933FFB77B1BFF
+ BA7702FFC38208FFB57B11FFB27B13FFB47B12FFB57B11FFB77C0FFFB97E11FF
+ BC8016FFBE801AFFBD7E1CFFB67919FFB07214FFAE7111FFB07410FFB67A10FF
+ B97C0EFFBA7E0DFFBB7C0EFFBC7D0FFFBD7D11FFBE7E12FFBE7D14FFBD7B12FF
+ BD790EFFBC780DFFBD780BFFC07B0EFFC07D10FFBF7D0DFFBB7A0DFFB87909FF
+ B87B0DFFBA7D0FFFB97B0FFFBA7C10FFBC7E14FFBC8016FFBC8016FFBA7F12FF
+ BA7D0FFFB97C0EFFB7790DFFB77A12FFCC8F2DFFBE842BFFB27D2DFFBB8842FF
+ B48548FFB39064FFDFD3C1FFE0DFDBFFEEECECFFF5F2F4FFF5F7F8FFF4F8F9FF
+ EFF4F5FFE8EDF0FFF1F4F9FFEDEBF1FFF0EBF4FFF3ECF3FFEFE8EFFFEEEAF0FF
+ EAEAF0FFE3E3E9FFEFEAECFFFFF7EEFFF2D3B4FFBC935CFFAE7929FFB67E1FFF
+ B88119FFB57E15FFB57E16FFB77D16FFBD7B14FFBE7D11FFBF7D0CFFBC7D0BFF
+ B77E0BFFB57D0CFFBC800FFFBA7D0FFFB87B0DFFB77A0CFFB87B0DFFBA7D0FFF
+ BC7F11FFBE8113FFB87B0DFFB77A0CFFB6790BFFB97C0EFFBD8012FFC08315FF
+ BF8214FFBE8113FFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBB7E10FFBB7E10FF
+ BA7D0FFFB97C0EFFB97C0EFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BA7E0DFFB97D0CFFBA7E0DFFB97D0CFFB97D0CFFBB7F0EFFBE8211FFBF8312FF
+ BD8110FFBB7F0EFFB97D0CFFBA7E0DFFBB7F0EFFBC800FFFBC800FFFBB7F0EFF
+ BA7E0DFFB97D0CFFBA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFF
+ B77B0AFFB67A09FFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BC7D0DFFBB7C0CFFBE7F0FFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BC7D0DFFBB7C0CFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBD7F0DFFBB7D0BFFB97B09FFBA7C0AFFBC7E0CFFBC7E0CFF
+ BB7D0BFFB97B09FFBA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFF
+ B97D0CFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFB1730FFFB47612FFB77915FF
+ B77915FFB57713FFB37511FFB3750FFFB47610FFB57810FFB4770FFFB3760EFF
+ B4770FFFB5790FFFB5790FFFB3770DFFB1750BFFB4790CFFB57A0DFFB67B0EFF
+ B77C0FFFB77C0FFFB67B0EFFB57A0DFFB4790CFFB67B0EFFB67B0EFFB77C0FFF
+ B77C0FFFB87D10FFB87D10FFB87D10FFB77D13FFB27910FFB07911FFAE7911FF
+ B07910FFB37D0BFFB67D10FFBC7B19FFBD7A1DFFB57614FFB1781BFFA17724FF
+ 907647FF7D7984FF6C7EB3FF547FCEFF4B82D7FF4C83CCFF548BD0FF4A7ECAFF
+ 3E6FBDFF4C7DC7FF89B5F5FFA3C5FBFF6D8AC3FF4665B0FF456ABFFF3963C3FF
+ 365FBBFF395AA9FF3855A0FF3854ABFF3553AAFF385CA8FF3D5FA5FF395298FF
+ 314487FF364486FF3C4B8AFF3E508DFF3E518AFF3B4D7CFF374061FF4D4752FF
+ 695445FF7E5A2CFF9C6B21FFBB821FFFC4861AFFB77C15FFB67B14FFB47A10FF
+ B57A0CFFB77C0EFFBB8013FFC0831BFFC38521FFC38324FFBF7F21FFBB7B1CFF
+ B67917FFB87A14FFB87C12FFB77B11FFB57A0DFFBB7E10FFBB7E10FFBB7E10FF
+ BA7C10FFBA7C12FFBC7B12FFBD7A13FFBE7C13FFC37F16FFC48017FFC48015FF
+ C18014FFBF7E12FFBE7F11FFBD8012FFBE8014FFBC8016FFBB7E16FFBA7E14FF
+ BB7D13FFBB7D13FFBC7E12FFBD7F13FFC08014FFC28216FFBD7E16FFC38626FF
+ B67B25FFB07B32FFAF8042FFAC8450FFC6AB89FFEDE7E0FFE9EDF2FFF0F1F5FF
+ F0EFF1FFEDEFEFFFEFF1F1FFECF2F1FFE9EEEFFFF2F5F9FFECEAF0FFEFE7F1FF
+ F4EBF5FFF3EAF4FFF2EDF6FFEEF1F6FFEDECF0FFF5E7E9FFE0C6B8FFC7A177FF
+ B98947FFB58026FFB47A13FFB07910FFB07B13FFB37D18FFB67B17FFBB7C14FF
+ BE7D11FFBF7D0CFFBB7D0BFFB77E0BFFB57D0CFFB97E10FFBA7D0FFFB97C0EFF
+ B87B0DFFB97C0EFFBA7D0FFFBC7F11FFBD8012FFBD8012FFBB7E10FFBB7E10FF
+ BD8012FFC08315FFC28517FFC28517FFC08315FFBB7E10FFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFB77A0CFFB87B0DFFBA7D0FFF
+ BB7E10FFBC7F11FFBC7F11FFBB7E10FFBB7E10FFB97D0CFFBA7E0DFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFBA7E0DFFB97D0CFFB97D0CFF
+ BB7F0EFFBE8211FFBF8312FFBD8110FFBA7E0DFFB87C0BFFB97D0CFFBA7E0DFF
+ BB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFB87C0BFFBA7E0DFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBB7F0EFFB97D0CFFB87C0BFFB77B0AFFBB7C0CFFBB7C0CFFBB7C0CFF
+ BA7B0BFFBA7B0BFFBB7C0CFFBB7C0CFFBB7C0CFFBD7E0EFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBB7C0CFF
+ BA7B0BFFBA7B0BFFBB7C0CFFBB7C0CFFBB7C0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFF
+ BB7D0BFFBD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFBA7E0DFFB97D0CFFB97D0CFF
+ B87C0BFFB87C0BFFB97D0CFFB97D0CFFBA7E0DFFB87C0BFFB87C0BFFB87C0BFF
+ B27410FFB47612FFB67814FFB67814FFB47612FFB37511FFB3750FFFB57711FF
+ B4770FFFB3760EFFB1740CFFB2750DFFB3770DFFB5790FFFB5790FFFB4780EFF
+ B57A0DFFB67B0EFFB77C0FFFB77C0FFFB77C0FFFB77C0FFFB67B0EFFB57A0DFF
+ B87D10FFB87D10FFB87D10FFB87D10FFB97E11FFB97E11FFBA7F12FFBA7E14FF
+ B2780FFFB27811FFB07911FFB27C11FFB67F10FFBA8114FFC1801EFFC28021FF
+ BA7C18FFB37919FFA8791EFF977435FF817063FF767A93FF6582BBFF5681CAFF
+ 4D7FC7FF4F84CDFF487BCBFF3F72C2FF4476C2FF6895D8FF95B6EEFF97B4EDFF
+ 5171BAFF4365B9FF3B62BEFF2E54ACFF305099FF3A569DFF3350A1FF3454A7FF
+ 395DA9FF3E60A6FF3C5699FF34478AFF2E3E80FF374887FF435798FF3F5694FF
+ 435993FF2E406FFF393E5FFF544D5AFF635043FF755936FF937038FFAA7B31FF
+ BA7A1CFFC17A12FFBA7A0AFFB97B09FFB77D0CFFB97F15FFBD801EFFBF8222FF
+ B77516FFB77411FFB7780AFFB77907FFB77B0AFFB57A0DFFB27612FFB17511FF
+ BA7F12FFB97F0EFFB57D0EFFB47B0EFFB47A11FFB67B14FFB87C18FFB97C1AFF
+ C18220FFBF801EFFBC7E1AFFBD7C19FFBD7D17FFBE7F17FFBD8018FFBC7F17FF
+ BA7F18FFBA8017FFBD7F15FFBE7F11FFBE7F11FFBF8012FFBE8014FFBE8016FF
+ BD7E16FFB77711FFB57818FFAC711BFFA8742DFF9E7439FFA68558FFDBC6ABFF
+ FAF7F2FFF3F8FBFFF3F6FAFFF0F2F3FFEEEDEFFFEDEFEFFFECF1F0FFECF0F1FF
+ F1F4F8FFE8E7F0FFEAE6F1FFF2ECF7FFF0EBF4FFF2EEF4FFF3F2F6FFF4F0EFFF
+ FEEFE6FFC4A98FFFA7804CFFB28339FFB78221FFB47C0FFFB67E11FFB68015FF
+ B47D15FFB67C15FFBB7D13FFBD7C0FFFBF7D0DFFBC7E0CFFB77D0CFFB57D0EFF
+ B77C0EFFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFFBB7E10FFBB7E10FFBC7F11FF
+ B97C0EFFB87B0DFFB87B0DFFB97C0EFFBB7E10FFBC7F11FFBB7E10FFBA7D0FFF
+ BC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FF
+ B6790BFFB77A0CFFB97C0EFFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBC7F11FF
+ B97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFF
+ BB7F0EFFBA7E0DFFBA7E0DFFBB7F0EFFBE8211FFBE8211FFBC800FFFBA7E0DFF
+ B87C0BFFB97D0CFFB97D0CFFBA7E0DFFBA7E0DFFB97D0CFFB97D0CFFB87C0BFF
+ BB7F0EFFBB7F0EFFBC800FFFBC800FFFBC800FFFBB7F0EFFB97D0CFFB97D0CFF
+ BC7D0DFFBB7C0CFFB97A0AFFB87909FFB87909FFB97A0AFFBB7C0CFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBF8010FFBE7F0FFFBD7E0EFFBB7C0CFFBA7B0BFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBB7C0CFFB97A0AFFB87909FFB87909FFB97A0AFFBB7C0CFFBC7D0DFF
+ BF810FFFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFF
+ BD7F0DFFBC7E0CFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBD7F0DFFBB7D0BFF
+ BA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFB97D0CFFBA7E0DFF
+ B87C0BFFB87C0BFFB87C0BFFB27410FFB47612FFB57713FFB57713FFB37511FF
+ B27410FFB3750FFFB57711FFB4770FFFB3760EFFB2750DFFB2750DFFB4780EFF
+ B67A10FFB87C12FFB87C12FFB77C0FFFB77C0FFFB77C0FFFB77C0FFFB77C0FFF
+ B77C0FFFB77C0FFFB77C0FFFB77C0FFFB77C0FFFB77C0FFFB87D10FFB87D10FF
+ B97E11FFB97E11FFB97D13FFB67B14FFB57B14FFB37C13FFB37D12FFB67D10FF
+ BA7E14FFBD7C19FFBE7D1AFFBC7E1AFFB47915FFB07A1BFFA17528FF8C6B44FF
+ 817573FF7483A4FF5E80BBFF5683C7FF4B7CCAFF4979CBFF487ACCFF3C70BDFF
+ 3867ABFF6587C2FF9BB9F2FF718FD6FF4C6DBDFF3E62BAFF25499DFF2A448AFF
+ 3B5597FF2F4C97FF3554A3FF3D62ACFF4365ABFF405B9EFF36498CFF273779FF
+ 304283FF485EA0FF455FA1FF4662A3FF354C8AFF2A3B6EFF424B71FF646377FF
+ 635B5CFF5D5244FF806540FFA66F2CFFB5731AFFB47612FFB37A0DFFB57D0EFF
+ B67D10FFB87A16FFB97816FFB97514FFBA7710FFBB7C0AFFBB7E08FFBB800CFF
+ BB8012FFB97D19FFBA7D1BFFB57B11FFB77C0EFFB47B0EFFB3790FFFB37912FF
+ B47915FFB57A17FFB67B18FFBC811EFFB97C1AFFB47814FFB37811FFB77A12FF
+ B97D13FFB97D13FFB67C12FFB37814FFB57B14FFBE8014FFC48414FFC48414FF
+ C18013FFBA7C12FFB67911FFBC7E18FFB77816FFBF8123FFBA812CFFAE7D39FF
+ A7804CFFBDA280FFF6E8D5FFF3F3EDFFF0F5F8FFF4F7FBFFF5F6FAFFF4F3F7FF
+ F2F1F3FFEFF1F1FFEDF2F1FFEDF0F4FFE6E8F0FFE8E8F4FFEEECF8FFEBE8F1FF
+ EDE9EEFFF4EFF0FFFCF3EAFFFBE7D5FFBFA27DFFA87F41FFB0812DFFAE7911FF
+ B47C0BFFBF8716FFB67F10FFB67E13FFB77D14FFBA7C10FFBD7C0FFFBF7D0DFF
+ BC7D0DFFB67E0FFFB67E0FFFB67B0DFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBB7E10FFB77A0CFFB77A0CFFB77A0CFFB77A0CFFB77A0CFF
+ B77A0CFFB77A0CFFB77A0CFFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBB7E10FFB87B0DFFB87B0DFFBA7D0FFFBB7E10FFBC7F11FF
+ BC7F11FFBB7E10FFBB7E10FFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBA7E0DFFB97D0CFFBB7F0EFFBA7E0DFFBA7E0DFFBC800FFFBE8211FF
+ BE8211FFBC800FFFB97D0CFFBA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBA7E0DFFBA7E0DFFBB7F0EFFBB7F0EFFBC800FFFBD8110FFBC800FFF
+ BC800FFFBB7F0EFFBA7E0DFFBC7D0DFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFF
+ BB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBF8010FFC08111FFBF8010FF
+ BD7E0EFFBB7C0CFFBA7B0BFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBB7C0CFFBA7B0BFFBA7B0BFF
+ BB7C0CFFBC7D0DFFBC7D0DFFBE800EFFBE800EFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBB7D0BFFBA7C0AFFB97B09FFBA7C0AFFBC7E0CFF
+ BD7F0DFFBC7E0CFFBA7C0AFFBA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87C0BFF
+ B97D0CFFB97D0CFFBA7E0DFFB87C0BFFB87C0BFFB87C0BFFB27410FFB37511FF
+ B57713FFB47612FFB27410FFB1730FFFB3750FFFB57711FFB57810FFB57810FF
+ B57810FFB57810FFB5790FFFB77B11FFBA7E14FFBC8016FFB77B11FFB77B11FF
+ B77B11FFB77B11FFB77B11FFB77B11FFB77B11FFB77B11FFB5790FFFB5790FFF
+ B5790FFFB67A10FFB67A10FFB77B11FFB77B11FFB77B11FFB97B15FFB67B14FF
+ B47C0FFFB17C0EFFB47A10FFB67911FFB97913FFBA7A14FFB97E17FFB37912FF
+ B77C15FFB0791EFF9D6E2AFF8E7351FF80808CFF6B82AFFF6189CAFF5A8AD8FF
+ 5080D2FF4476C8FF4376C6FF4474BCFF5B80BAFF7F9DD6FF95B2F7FF5B79C6FF
+ 4362B7FF264594FF283E7FFF39518DFF2E4B90FF3657A0FF4469B3FF496CB5FF
+ 425FA4FF384E90FF243677FF283A7BFF4A60A2FF506AB0FF4767B0FF3757A0FF
+ 243E84FF2C4381FF526396FF5D6991FF515976FF5F585FFF815D45FF956531FF
+ 9E6D23FFA97618FFB47E13FFB87F0CFFB9780BFFB7730AFFC47E19FFC17E17FF
+ BD7D11FFB97C0EFFB57B0AFFB37B0CFFB77A12FFB87A14FFB67610FFB77711FF
+ B87812FFB87812FFB87714FFB87714FFB57713FFB47610FFBD7F19FFB77D14FF
+ B2780EFFB1790AFFB37B0AFFB57E0BFFB77F08FFB47C0BFFB07911FFB27A15FF
+ BC7E12FFC28212FFC48212FFBF7E11FFB97A12FFB37713FFB77A18FFB27515FF
+ C4872AFFBE8736FFA97D3EFFB29267FFD8C6AFFFFFFAEFFFE9EDE8FFEAEFF0FF
+ F0F3F8FFF5F5FBFFF6F4FAFFF2F1F5FFF1F1F1FFF0F2F2FFEEF3F6FFE7EDF4FF
+ E9EDF8FFE8EAF5FFE6E3ECFFEEE9EBFFFCF3EFFFFFF8E6FFDAC3A3FFB1905EFF
+ A87D34FFB18024FFAE7609FFB47C05FFBC8611FFAF7906FFB57D10FFB67C12FF
+ BA7C10FFBC7D0FFFBD7D0DFFBC7D0DFFB77F10FFB77E11FFB67B0DFFB97C0EFF
+ BA7D0FFFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBC7F11FFBC7F11FF
+ BC7F11FFBC7F11FFBB7E10FFBA7D0FFFBB7E10FFBB7E10FFB97C0EFFB97C0EFF
+ B97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFBB7E10FFBB7E10FF
+ BC7F11FFBC7F11FFBB7E10FFBA7D0FFFB87B0DFFB87B0DFFB97D0CFFBA7E0DFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFBC800FFFBB7F0EFF
+ BA7E0DFFBC800FFFBE8211FFBE8211FFBB7F0EFFB97D0CFFBD8110FFBD8110FF
+ BC800FFFBC800FFFBC800FFFBC800FFFBD8110FFBD8110FFBA7E0DFFBB7F0EFF
+ BC800FFFBC800FFFBD8110FFBC800FFFBB7F0EFFBB7F0EFFBC7D0DFFBD7E0EFF
+ BE7F0FFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBE7F0FFFBE7F0FFF
+ BF8010FFBF8010FFBF8010FFBE7F0FFFBC7D0DFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFF
+ BE7F0FFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBD7F0DFFBD7F0DFF
+ BE800EFFBE800EFFBD7F0DFFBC7E0CFFBA7C0AFFB97B09FFB97B09FFB77907FF
+ B67806FFB87A08FFBA7C0AFFBB7D0BFFBB7D0BFFB97B09FFBA7E0DFFB97D0CFF
+ B97D0CFFB87C0BFFB87C0BFFB97D0CFFB97D0CFFBA7E0DFFB87C0BFFB87C0BFF
+ B87C0BFFB27410FFB37511FFB47612FFB37511FFB1730FFFB0720EFFB3750FFF
+ B57711FFB4770FFFB57810FFB67911FFB67911FFB67A10FFB77B11FFB97D13FF
+ BB7F15FFB77B11FFB77B11FFB67A10FFB5790FFFB5790FFFB67A10FFB77B11FF
+ B77B11FFB4780EFFB4780EFFB5790FFFB5790FFFB67A10FFB67A10FFB67A10FF
+ B67911FFB57713FFB37811FFB17A0BFFB17A0BFFB37910FFB67812FFBC7A13FF
+ B97C14FFB77D16FFB27811FFBC7B12FFBB7A17FFAB731AFF967137FF837C79FF
+ 7A8AAFFF6487C7FF5A88D6FF5584D6FF4D7DCFFF4E83D3FF5284CCFF6186C2FF
+ 7E9FD7FF9EBBFEFF607AC6FF4461B2FF2F4995FF2A3C7BFF334781FF2E4A8BFF
+ 3C5EA4FF486FBAFF4F73BFFF4664ABFF3C5699FF263A7BFF1F3374FF445C9EFF
+ 5774B9FF4D6DB9FF3A5EACFF2C4D9DFF21418DFF2F4C91FF5770B0FF657CB4FF
+ 57638BFF655B6BFF746055FF816641FF906F30FFA47824FFB17D19FFB87A10FF
+ B9750AFFBE7A11FFBB7811FFB77810FFB2760CFFAE740AFFAF7609FFB4790CFF
+ B67A10FFB67814FFB77915FFBA7916FFBB7B15FFBC7A14FFBA7811FFB8760FFF
+ B4760CFFBE8016FFBA7F12FFB87D0FFFB77D0CFFB87F0CFFBA810DFFBB840BFF
+ B9820FFFB77F1AFFB57C19FFBA7C12FFBC7B0EFFBE7C0CFFBD7C0FFFBC7C16FF
+ BA7D1BFFB67919FFAE7114FFB97E28FFB27F36FFA57D48FFC1A886FFE8DFD1FF
+ F8F7F3FFECF2EDFFEBF1F0FFEDF0F5FFF0EFF8FFF0EDF6FFEDECF0FFEFEFEFFF
+ F2F4F4FFF1F6F7FFEAF3F7FFE8EEF9FFE3E7F2FFE6E4EAFFF5EDEDFFFFF3E7FF
+ FFEBD0FFBA9D71FFA37E40FFA77A29FFBA8726FFBE8615FFBE850CFFBC840DFF
+ B37C09FFB57D0EFFB57C0FFFBA7D0FFFBC7D0FFFBD7D0DFFBD7E0EFFB77F10FF
+ B77E11FFB77C0EFFB97C0EFFB97C0EFFBA7D0FFFBA7D0FFFBB7E10FFBB7E10FF
+ BC7F11FFB97C0EFFBA7D0FFFBB7E10FFBA7D0FFFB97C0EFFB87B0DFFB97C0EFF
+ BA7D0FFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFFB97C0EFF
+ B97C0EFFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBB7E10FFB97C0EFFB77A0CFF
+ B6790BFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFF
+ B97D0CFFBD8110FFBB7F0EFFBB7F0EFFBC800FFFBD8110FFBD8110FFBB7F0EFF
+ B87C0BFFBD8110FFBD8110FFBC800FFFBC800FFFBC800FFFBC800FFFBD8110FF
+ BD8110FFB97D0CFFB97D0CFFBB7F0EFFBC800FFFBC800FFFBC800FFFBB7F0EFF
+ BB7F0EFFBC7D0DFFBE7F0FFFC08111FFC18212FFC18212FFC08111FFBE7F0FFF
+ BC7D0DFFC08111FFBF8010FFBF8010FFBE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFF
+ BD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBE7F0FFFC08111FFC18212FFC18212FFC08111FFBE7F0FFF
+ BC7D0DFFBC7E0CFFBD7F0DFFBE800EFFBF810FFFBE800EFFBC7E0CFFB97B09FF
+ B87A08FFB87A08FFB77907FFB67806FFB77907FFBA7C0AFFBC7E0CFFBB7D0BFF
+ B97B09FFBA7E0DFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFB97D0CFF
+ BA7E0DFFB97D0CFFB97D0CFFB97D0CFFB27410FFB37511FFB37511FFB27410FF
+ B0720EFFB0720EFFB2740EFFB57711FFB0730BFFB3760EFFB57810FFB67911FF
+ B4780EFFB4780EFFB5790FFFB77B11FFB77B11FFB67A10FFB5790FFFB4780EFF
+ B4780EFFB5790FFFB67A10FFB77B11FFB5790FFFB67A10FFB67A10FFB67A10FF
+ B77B11FFB77B11FFB87C12FFB87B13FFB57713FFB37811FFB17A0BFFB27B0CFF
+ B37811FFB77915FFBD7C13FFBA7E14FFB47F17FFB17A12FFB9780FFFBE7D11FF
+ B67911FF986F26FF83796FFF8695B6FF6486C2FF517DCAFF5582D3FF5788D8FF
+ 5186D6FF497DC4FF5D87C2FF93B6EEFF8AA8E9FF566FB7FF465DABFF3E539EFF
+ 2F3E7CFF293A73FF2E4A8AFF4367ADFF4A71BFFF5479C9FF4969B4FF4360A5FF
+ 2B4385FF162F6FFF3B5597FF5B78BDFF5373BFFF476ABAFF3F64B6FF2E53A5FF
+ 264796FF3E5EA7FF5B78BDFF5D79B6FF5871A3FF5A6B8CFF60646FFF6F6456FF
+ 856A3EFF9B722DFFAC771DFFB67812FFBB7A11FFBE7D11FFBF7D16FFBD7D17FF
+ B97B15FFB77D14FFB98112FFBC8316FFB88119FFB77F1AFFB98017FFBB7F15FF
+ BC7E12FFBC7D0FFFBC7B0EFFBB7A0DFFBD7C0FFFBE7F11FFBE7F11FFBD8012FF
+ BC7F11FFBD8110FFBF8312FFBE8315FFBB831EFFB9801DFFBA7D15FFB97B11FF
+ BB7B0FFFBE7D14FFC0801AFFBE811FFFC5882BFFB97E28FFB47E31FFB18546FF
+ BE9E73FFE4D3B9FFF7F4EFFFF0F5F6FFF0F5F3FFEDF2F0FFECEFF4FFF0EFF8FF
+ EFECF5FFEDE9EFFFF0EEEEFFF2F4F4FFECF1F2FFE8F1F5FFE4EEF8FFE3EAF3FF
+ EDECF0FFFBF1EAFFEEDAC8FFD1B592FFAC8A55FFB18742FFB6852FFFBD8623FF
+ C38918FFC18710FFBC830FFFBA8310FFB57D0EFFB77C0FFFB97C0EFFBC7D0FFF
+ BD7E0EFFBB7F0EFFB97E10FFB88011FFB97E10FFBA7D0FFFB97C0EFFB87B0DFF
+ B97C0EFFBA7D0FFFBC7F11FFBD8012FFB5780AFFB77A0CFFB87B0DFFB87B0DFF
+ B6790BFFB5780AFFB77A0CFFB97C0EFFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFF
+ BA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFBB7E10FFBB7E10FFBC7F11FFBC7F11FF
+ BB7E10FFBA7D0FFFB87B0DFFB77A0CFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFBD8110FFBC800FFFBB7F0EFFBC800FFF
+ BD8110FFBD8110FFBA7E0DFFB77B0AFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFF
+ B97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFB77B0AFFB87C0BFFB97D0CFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFC28313FFC08111FFBE7F0FFFBD7E0EFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBF8010FFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBE800EFFBE800EFFBE800EFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBA7C0AFFB97B09FFBA7C0AFFB97B09FFB87A08FFBA7C0AFF
+ BD7F0DFFBE800EFFBE800EFFBC7E0CFFBA7E0DFFB97D0CFFB97D0CFFB87C0BFF
+ B87C0BFFB97D0CFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFB27410FF
+ B37511FFB37511FFB1730FFFAF710DFFB0720EFFB2740EFFB57711FFAD7008FF
+ B0730BFFB4770FFFB57810FFB3770DFFB1750BFFB2760CFFB3770DFFB67A10FF
+ B5790FFFB4780EFFB3770DFFB3770DFFB4780EFFB5790FFFB67A10FFB77B11FF
+ B77B11FFB87C12FFB87C12FFB97D13FFB97D13FFB97D13FFBA7C16FFB97A18FF
+ B67A16FFB47C0FFFB37B0EFFB47814FFB67715FFB97B11FFB67C12FFB4801BFF
+ AE7A16FFB4750DFFBC7B0FFFBB7C0CFF996E1FFF80776DFF8A9DC0FF698BC6FF
+ 5883CCFF5785D2FF5182D0FF4B83D0FF4D83CAFF6490CDFF95BAF4FF718FD0FF
+ 4963A9FF445AA8FF4B5BA7FF35407EFF23316BFF2E4989FF496DB3FF4871C0FF
+ 557DCFFF486CB8FF4666AFFF2E4B8EFF102C6DFF324F92FF5A78BFFF5477C1FF
+ 557ACAFF4D75C7FF436BBDFF355AAAFF204490FF34559EFF6185CBFF5E8BCFFF
+ 527BB9FF4B6698FF4F5A78FF615A5DFF79634AFF916D37FFA27426FFAD7719FF
+ B77B17FFBE7E18FFBC7C16FFB87812FFB2750DFFB07508FFAD7508FFBD8820FF
+ B9861EFFBA831AFFB98114FFBA800FFFBE7F0FFFBE7F0FFFBF8010FFB7780AFF
+ B97B0FFFBC7E14FFBC7E14FFBD7C13FFBD7C13FFBF7F13FFC08218FFBC811DFF
+ BA821DFFBB801CFFBC811AFFBE801AFFC0801AFFBF811DFFBD8020FFC68A31FF
+ B98132FFA67634FFAA8551FFCEB797FFF2E9DBFFF2F4F5FFE1E7ECFFECF3F0FF
+ EBF0EEFFEDF0F5FFF3F2FCFFF3F0F9FFEFEBF1FFEFEDEDFFF1F4F2FFE4E9EAFF
+ E2EEF0FFE4EFF7FFE9EFF6FFF9F5F4FFFEF1E3FFD9BFA1FF9F7C50FFAD8446FF
+ CA9B51FFC8933CFFB37A17FFB27709FFBA7E0CFFBA7E0CFFBA800FFFB57D0EFF
+ B77C0FFFB97C0EFFBC7D0FFFBD7E0EFFBB7F0EFFBA7F11FFBA7F11FFBC7F11FF
+ BA7D0FFFB87B0DFFB77A0CFFB87B0DFFBA7D0FFFBC7F11FFBE8113FFB97C0EFF
+ BB7E10FFBD8012FFBD8012FFBB7E10FFBA7D0FFFBC7F11FFBF8214FFBC7F11FF
+ BC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFB97C0EFF
+ BA7D0FFFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBA7D0FFFB97C0EFFB97D0CFF
+ BA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFBE8211FF
+ BC800FFFBB7F0EFFBC800FFFBD8110FFBD8110FFBA7E0DFFB77B0AFFB97D0CFF
+ B87C0BFFB77B0AFFB67A09FFB67A09FFB77B0AFFB87C0BFFB97D0CFFB67A09FF
+ B77B0AFFB97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBA7E0DFFBA7E0DFFBE7F0FFF
+ BD7E0EFFBB7C0CFFBA7B0BFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFC38414FF
+ C18212FFBE7F0FFFBC7D0DFFBB7C0CFFBD7E0EFFBF8010FFC18212FFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBE7F0FFF
+ BD7E0EFFBB7C0CFFBA7B0BFFBA7B0BFFBB7C0CFFBD7E0EFFBE7F0FFFC18311FF
+ C08210FFBD7F0DFFBB7D0BFFBA7C0AFFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BB7D0BFFBA7C0AFFBC7E0CFFBF810FFFC18311FFC08210FFBF810FFFBA7E0DFF
+ B97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFB97D0CFFBA7E0DFFBB7F0EFF
+ BB7F0EFFBB7F0EFFAF710DFFB0720EFFB1730FFFB1730FFFAE700CFFAE700CFF
+ AF710BFFB1730DFFAE7109FFAF720AFFB1740CFFB3760EFFB4780EFFB4780EFF
+ B4780EFFB3770DFFB67911FFB1740CFFB0730BFFB57810FFB77A12FFB57810FF
+ B57810FFB77A12FFB87B13FFB3760EFFB4770FFFB97C14FFB97C14FFB57810FF
+ B57810FFBA7C16FFB47717FFB27714FFB1790EFFB27A0FFFB57816FFB77816FF
+ B5770DFFAE740AFFAB7A18FFA87616FFB67B18FFB57810FFB97E10FF9B7429FF
+ 71706CFF869EC8FF7B9DD8FF4D78BBFF5381C8FF6195DCFF528BD6FF4C82C9FF
+ 6693D0FF93B7F3FF6886C7FF465FA5FF4B5FADFF414E9AFF2E3777FF202B69FF
+ 334D8FFF5174BDFF4772C3FF517DD0FF537CCBFF4C71BBFF3B5DA3FF1D3E83FF
+ 1E3F84FF4365ABFF476CB6FF557CCAFF5A85D4FF5884D1FF5078C3FF365EA6FF
+ 274C90FF254F92FF5489CCFF5C93D8FF507DC6FF4E6FB4FF5F72ABFF555A7BFF
+ 534A47FF7C6341FF967232FFAC7B25FFB9801DFFBC7D15FFB7760DFFB4730AFF
+ B5760EFFB47A13FFAE7A15FFAC7B15FFAC770FFFB37D12FFBF8718FFBA7F11FF
+ B17609FFB77B11FFB77D14FFB47A13FFB37814FFB57915FFBB7B15FFBD7B14FF
+ BA780FFFB6750CFFB3760EFFBB811AFFBC8320FFB9801DFFB97E1BFFB47715FF
+ B57516FFBA7D20FFC48B36FFAB7931FFA7824AFFCFB590FFF7E9D6FFFBF8F3FF
+ EEF3F6FFE9F2F6FFE9EFEEFFE9EEECFFE9ECF1FFEDECF5FFF1EEF7FFF3EFF5FF
+ F0EEEEFFE8EBE9FFEAEFF0FFEFF8FBFFE3EDF4FFECF1F4FFFFF9F0FFD6C4ADFF
+ A07F58FF976D38FFAD7D3BFFB48033FFB27923FFB37717FFBF8018FFBF8214FF
+ BA7D0FFFBD8214FFB77C0FFFB77C0FFFBA7D0FFFBD7E10FFBE7F0FFFBD810FFF
+ BC8211FFBC8211FFB77A0CFFBF8214FFC18416FFBD8012FFBA7D0FFFBC7F11FF
+ BC7F11FFB97C0EFFBA7D0FFFBE8113FFBD8012FFB87B0DFFB87B0DFFBD8012FF
+ BE8113FFBA7D0FFFB87B0DFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBA7D0FFF
+ B97C0EFFB87B0DFFBB7E10FFBA7D0FFFB87B0DFFB6790BFFB6790BFFB87B0DFF
+ BA7D0FFFBB7E10FFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFF
+ B97D0CFFB87C0BFFB87C0BFFBA7E0DFFBB7F0EFFBC800FFFBC800FFFBB7F0EFF
+ B97D0CFFB87C0BFFBF8312FFBC800FFFB87C0BFFB57908FFB57908FFB67A09FF
+ B97D0CFFBB7F0EFFC48817FFBF8312FFB87C0BFFB67A09FFB77B0AFFBA7E0DFF
+ BD8110FFBE8211FFBC7D0DFFBB7C0CFFB97A0AFFB87909FFB87909FFB97A0AFF
+ BB7C0CFFBC7D0DFFC08111FFC08111FFBE7F0FFFBD7E0EFFBC7D0DFFBC7D0DFF
+ BD7E0EFFBD7E0EFFBB7C0CFFBC7D0DFFBF8010FFC18212FFC28313FFC38414FF
+ C28313FFC18212FFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BC7D0DFFBB7C0CFFBF810FFFBE800EFFBD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBB7D0BFFBD7F0DFFBE800EFFBD7F0DFFBA7C0AFFBA7C0AFF
+ BC7E0CFFBF810FFFBF8312FFBA7E0DFFBB7F0EFFC28615FFC38716FFBD8110FF
+ B87C0BFFB87C0BFFB77B0AFFBC800FFFBC800FFFAB6D09FFAF710DFFB37511FF
+ B47612FFB37511FFB0720EFFAF710BFFAF710BFFAF720AFFB0730BFFB1740CFF
+ B3760EFFB4780EFFB5790FFFB5790FFFB5790FFFB97C14FFB4770FFFB2750DFF
+ B67911FFB87B13FFB57810FFB4770FFFB57810FFB87B13FFB67911FFB77A12FF
+ B97C14FFB97C14FFB77A12FFB77A12FFB77C15FFB47719FFB37717FFB27910FF
+ B37A11FFB67919FFB57816FFB6780EFFAF750BFFA87819FFA7781CFFAE7617FF
+ B07511FFB1790EFF937027FF74777BFF8BA7D6FF779CD4FF5C87C6FF5C8ACAFF
+ 5D90D6FF548BD6FF4B80C9FF5985C4FF82A7E3FF7595D6FF4760A8FF3F53A1FF
+ 364290FF272C71FF192363FF2E488BFF4267B1FF4773C6FF5482D6FF5785D3FF
+ 507AC5FF4267B1FF244790FF193C85FF2E539DFF4D75C0FF527ECBFF5482CFFF
+ 5A89D3FF5F8CD5FF537DC2FF3B63A4FF2B5797FF205496FF447CC3FF5385D7FF
+ 4977CBFF4A6FC1FF4862A5FF455179FF54535CFF78694FFF8E6F3AFFA0762BFF
+ AE791FFFB67A1AFFBD7C19FFC07F1CFFC0821CFFB0760FFFB47D15FFB57B11FF
+ B77C0FFFBD8012FFBA7D0FFFB97E11FFC2881EFFB47D15FFB17A17FFB27B1AFF
+ B57C19FFB97D19FFBD7D17FFBE7C13FFBD7C10FFBC7E14FFBC821BFFBA811EFF
+ B47C1DFFB47B1EFFB87D20FFC08326FFC28731FFBF893CFFAB8041FFBEA175FF
+ EADBC1FFFDF8EFFFF9FBFBFFF0F6FBFFE9EFF4FFE7EDECFFE7ECEBFFE7EAEEFF
+ ECEBF4FFF1EEF7FFF5F1F7FFF2F2F2FFEEF0F0FFE7EFEFFFE1EBEBFFE1E8EBFF
+ F4F5F1FFFEF1E1FFD4BB9BFFAC8755FFAE7F41FFB8843DFFBE8635FFB87C23FF
+ B47717FFBA7C18FFBC7D15FFBA7E14FFC1851BFFBC8016FFBC8016FFBD7F13FF
+ BE7F0FFFBD7E0EFFBC7E0CFFB97D0BFFB77D0CFFBA7D0FFFBF8214FFC08315FF
+ BB7E10FFB87B0DFFB97C0EFFB87B0DFFB47709FFBA7D0FFFBD8012FFBC7F11FF
+ B87B0DFFB87B0DFFBC7F11FFBD8012FFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFF
+ BA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFBA7D0FFFB97C0EFFBA7D0FFFBC7F11FF
+ BE8113FFBE8113FFBC7F11FFBA7D0FFFB97C0EFFBC800FFFBB7F0EFFBB7F0EFF
+ BA7E0DFFBA7E0DFFB97D0CFFB97D0CFFB97D0CFFBB7F0EFFBB7F0EFFBB7F0EFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFFBA7E0DFF
+ BB7F0EFFBA7E0DFFB97D0CFFB87C0BFFB77B0AFFBA7E0DFFB87C0BFFB87C0BFF
+ B97D0CFFBC800FFFBE8211FFBD8110FFBC800FFFBB7C0CFFBB7C0CFFBA7B0BFF
+ BA7B0BFFBA7B0BFFBA7B0BFFBB7C0CFFBB7C0CFFBE7F0FFFBD7E0EFFBC7D0DFF
+ BB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBF8010FFBF8010FFBF8010FF
+ BF8010FFBF8010FFBF8010FFBF8010FFC08111FFBB7C0CFFBC7D0DFFBD7E0EFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBF810FFFBE800EFFBD7F0DFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBA7C0AFFBC7E0CFFBE800EFF
+ BE800EFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFFBC800FFFBB7F0EFFBB7F0EFF
+ BB7F0EFFBD8110FFBF8312FFBD8110FFB97D0CFFB97D0CFFBB7F0EFFBB7F0EFF
+ B1730FFFB1730FFFB1730FFFAF710DFFAE700CFFAF710DFFB47610FFB87A14FF
+ B0730BFFB1740CFFB1740CFFB2750DFFB4780EFFB67A10FFB77B11FFB87C12FF
+ BB7E16FFB67911FFB4770FFFB87B13FFB97C14FFB57810FFB3760EFFB4770FFF
+ B87B13FFBA7D15FFB97C14FFB77A12FFB77A12FFB97C14FFB97C14FFB57A13FF
+ B5781AFFB47818FFB57A13FFB57A13FFB57919FFB67917FFB87A10FFB2780FFF
+ A77418FFAA7A22FFA97419FFAC7716FFA97511FF8A6A29FF777D88FF8BAADDFF
+ 7DA4DBFF74A0DBFF6D99D8FF5C8BCFFF5488D4FF4E81CAFF527EBEFF739AD8FF
+ 7A9DDDFF4460A7FF324896FF323F8EFF272D74FF1F286CFF39529AFF4367B3FF
+ 4672C5FF5383D5FF5A89DAFF5C88D5FF527CC7FF325BA4FF19408BFF1C448FFF
+ 4F79C6FF507ECBFF4C7ECAFF5184CDFF6396DCFF689ADCFF5682C1FF3F6AA9FF
+ 234D8EFF2E589DFF416EB8FF4E7ECCFF4C7BCCFF416BB8FF36599DFF395082FF
+ 4B546FFF605B5AFF776246FF8F6A36FFA47329FFB1771EFFB97816FFBC7710FF
+ BE780DFFC58013FFC77F10FFC27A0AFFC57E0CFFC4800FFFC38215FFC4881EFF
+ B37C14FFB17D19FFB37E1DFFB67F1CFFBA8019FFBC8016FFC28114FFC38215FF
+ BA7C10FFB67C13FFB07918FFA97517FFAC771DFFBA812BFFC78C36FFC48C3DFF
+ A77735FFA68351FFD0BC9DFFFAF2E5FFF9F9F9FFF1F5FAFFF3F8FBFFEDF2F3FF
+ EFF4F3FFEDF2F1FFEDEEF2FFEDEDF3FFEFEDF3FFF0EFF3FFEDEFF0FFEAEFEEFF
+ EDF5F5FFDEE6E5FFEAEDEBFFFFFDF2FFF5E1C8FFC8A87FFFB08447FFB48138FF
+ BD8536FFC38733FFBD8127FFB87B1DFFB97C1AFFB97B17FFB87D16FFBE831CFF
+ BB8118FFBD8117FFBE8014FFBC800FFFBD7E0EFFBB7D0BFFB87C0AFFB87C0AFF
+ BA7E0DFFBC7F11FFBB7E10FFB97C0EFFB97C0EFFBA7D0FFFB87B0DFFB47709FF
+ BA7D0FFFBB7E10FFBA7D0FFFB77A0CFFB77A0CFFBA7D0FFFBB7E10FFBA7D0FFF
+ BC7F11FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBB7E10FFBC7F11FF
+ BB7E10FFBD8012FFBF8214FFC08315FFC08315FFBF8214FFBD8012FFBB7E10FF
+ BD8110FFBC800FFFBA7E0DFFB97D0CFFB87C0BFFB97D0CFFBA7E0DFFBB7F0EFF
+ BE8211FFBD8110FFBA7E0DFFB87C0BFFB87C0BFFB87C0BFFBA7E0DFFBB7F0EFF
+ B97D0CFFBA7E0DFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB87C0BFFB77B0AFF
+ B97D0CFFB87C0BFFB77B0AFFB97D0CFFBC800FFFBD8110FFBC800FFFBA7E0DFF
+ BB7C0CFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBB7C0CFF
+ BB7C0CFFBA7B0BFFBA7B0BFFB97A0AFFBA7B0BFFBA7B0BFFBC7D0DFFBC7D0DFF
+ C38414FFC18212FFBE7F0FFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFF
+ BB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BE800EFFBE800EFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFF
+ B97B09FFBC7E0CFFBE800EFFBF810FFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFF
+ B97D0CFFBC800FFFBB7F0EFFB67A09FFB87C0BFFC08413FFC08413FFBB7F0EFF
+ BC800FFFBA7E0DFFBA7E0DFFB27410FFB27410FFB0720EFFAE700CFFAD6F0BFF
+ B0720EFFB67812FFBB7D17FFB2750DFFB1740CFFB1740CFFB2750DFFB4780EFF
+ B67A10FFB97D13FFBA7E14FFBB7E16FFB67911FFB4770FFFB97C14FFBA7D15FF
+ B77A12FFB4770FFFB57810FFB57810FFBA7D15FFBA7D15FFB57810FFB4770FFF
+ B97C14FFB97C14FFB27612FFB67A1AFFB67A1AFFB87A16FFB67A16FFB37919FF
+ B37A17FFB97B11FFB47912FFAE791EFFB8862EFFB47F24FFB98626FFB68021FF
+ 947236FF888E99FF96B4E5FF8CB2E8FF87B2EBFF7EAAE7FF608DD0FF5082CEFF
+ 5485D1FF5984C7FF6A93D2FF769CDDFF4464ABFF2F4694FF344392FF2D337CFF
+ 222C72FF465FA9FF466DB8FF4370C1FF497ACAFF5686D4FF6694E1FF6693DDFF
+ 4670BBFF254B99FF1A418FFF416AB9FF4D7BC9FF4D7FCBFF457AC3FF538ACFFF
+ 6B9FE1FF6A9BD9FF5A85C4FF4D70B2FF2A4D91FF234A8EFF3764A8FF3F6FB7FF
+ 4475C1FF4472C0FF3A61ABFF3F5C99FF4D5E89FF616171FF736559FF886942FF
+ 9C6F32FFAE7627FFBD7C20FFBB7714FFC47B13FFC0770BFFBD7204FFC27907FF
+ C67F0DFFC07E0EFFB5770BFFB47A13FFB27E1AFFB5801FFFB5801FFFB77F1AFF
+ B97F16FFC08014FFC38215FFB7790DFFB37910FFB07918FFAD781DFFB07A23FF
+ BB8532FFC48C3DFFBC8943FFA37C45FFB99F77FFE1D5C3FFF5F4F0FFEBEFF4FF
+ E5EBF2FFEFF3F4FFF2F4F4FFF1F5F6FFEFF3F4FFEFF0F4FFEFEDF3FFEEEDF1FF
+ EFEEF2FFEBEFF0FFEAF0EFFFEDF5F5FFE4EAE9FFF9F6F1FFFFF7E5FFE3C8A6FF
+ BF9864FFB4833DFFB07826FFB97E28FFBE8228FFBF8427FFBF8323FFBB7F1FFF
+ B77C19FFB67A16FFB87D16FFB67C13FFB67C12FFB97E11FFBB7F0EFFBE7F0FFF
+ BE800EFFBD820EFFBD810FFFB87C0BFFB77A0CFFB77A0CFFB87B0DFFBC7F11FF
+ BF8214FFBE8113FFBB7E10FFBA7D0FFFBA7D0FFFB97C0EFFB87B0DFFB87B0DFF
+ B97C0EFFBA7D0FFFBA7D0FFFBB7E10FFBC7F11FFBD8012FFBE8113FFBE8113FF
+ BD8012FFBC7F11FFBB7E10FFC08315FFBF8214FFBD8012FFBB7E10FFBB7E10FF
+ BD8012FFBF8214FFC08315FFBE8211FFBC800FFFBA7E0DFFB87C0BFFB77B0AFF
+ B87C0BFFBA7E0DFFBC800FFFBD8110FFBC800FFFBB7F0EFFB97D0CFFB97D0CFF
+ B97D0CFFB97D0CFFBA7E0DFFBD8110FFBB7F0EFFB97D0CFFB77B0AFFB77B0AFF
+ B97D0CFFBB7F0EFFBC800FFFC18514FFBD8110FFB77B0AFFB57908FFB67A09FF
+ B87C0BFFB97D0CFFB97D0CFFBB7C0CFFBC7D0DFFBE7F0FFFBF8010FFBF8010FF
+ BE7F0FFFBC7D0DFFBB7C0CFFBB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFF
+ BC7D0DFFBD7E0EFFBE7F0FFFC18212FFC08111FFBE7F0FFFBC7D0DFFBB7C0CFF
+ BA7B0BFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBD7F0DFFB97B09FFBB7D0BFFBE800EFFBF810FFFBF810FFF
+ BD7F0DFFBB7D0BFFBA7C0AFFB97D0CFFBB7F0EFFBA7E0DFFB77B0AFFB87C0BFF
+ BD8110FFBD8110FFBB7F0EFFBE8211FFB97D0CFFB97D0CFFA96B07FFAE700CFF
+ B47612FFB77915FFB67814FFB47612FFB2740EFFB2740EFFB2750DFFB2750DFF
+ B2750DFFB2750DFFB3770DFFB67A10FFB87C12FFBA7E14FFB77A12FFB3750FFF
+ B3750FFFB97B15FFBB7D17FFB87A14FFB67812FFB77913FFB2740EFFB77913FF
+ B77913FFB2740EFFB2740EFFB77913FFB77913FFB07410FFB77B1BFFB77B1BFF
+ B97A18FFB97A18FFB17A19FFB07916FFB77A12FFB87A14FFB0771CFFB7812AFF
+ B27C1DFFB88322FFB57C1FFF997438FF93929BFF9DB6E2FF8CB1E5FF83AEE7FF
+ 86AFEDFF6A94D9FF4E7ECCFF5585D3FF5E88CFFF5B85C8FF78A0E1FF5377BDFF
+ 34509DFF354695FF2B317CFF1E2A72FF4E69B3FF4E75C0FF4674C1FF4373C1FF
+ 4D7FCBFF6798E2FF74A1EBFF5982CBFF3559A5FF234793FF294F9DFF4973C0FF
+ 5687D3FF487DC6FF477EC3FF6399DAFF74A7E6FF709CDCFF6587CDFF4765ACFF
+ 2F508FFF20457FFF234983FF4972B0FF5F8BD2FF4E79C8FF4570C1FF496DB9FF
+ 5068A4FF525E82FF5E575EFF715C47FF8F693FFFAA7A3AFFB17928FFB87B1EFF
+ B97815FFB7750CFFBD780BFFC68211FFC58313FFBC7C10FFB67B14FFB67D1AFF
+ B47E1FFFB37D1FFFB47A1BFFB47818FFBA7916FFBB7C14FFB87C12FFB97F16FF
+ BB821FFFBC8326FFB9832CFFB68130FFB48138FFAC8043FFC2A277FFE7D4B9FF
+ F9F4EBFFF0F3F7FFE8EEF5FFE5EBF0FFEAECECFFF3F4F2FFE8ECEDFFE8EBEFFF
+ EDECF0FFEEEDF1FFF0EFF1FFF0F2F3FFF1F6F7FFF1F9F9FFEAF2F2FFEDF0EEFF
+ FEF5EBFFF0DCC3FFC8A67BFFBB9051FFC18C3BFFB57A1DFFB57B1BFFB87F1CFF
+ BC8320FFBC8320FFB77E1BFFB47B18FFB77C18FFB67C15FFB47A11FFB57B11FF
+ B87D10FFBB7F0EFFBE7F0FFFBF810FFFC0830FFFC18311FFBB7F0EFFB97C0EFF
+ B87B0DFFBB7E10FFBF8214FFC18416FFC08315FFC08315FFBB7E10FFB97C0EFF
+ B87B0DFFB87B0DFFB87B0DFFB87B0DFFB97C0EFFBB7E10FFB97C0EFFBB7E10FF
+ BF8214FFC18416FFC18416FFBF8214FFBB7E10FFB97C0EFFBE8113FFBD8012FF
+ BB7E10FFB97C0EFFB97C0EFFBB7E10FFBD8012FFBE8113FFBE8211FFBC800FFF
+ BA7E0DFFB87C0BFFB77B0AFFB87C0BFFBA7E0DFFBC800FFFBA7E0DFFBB7F0EFF
+ BB7F0EFFBC800FFFBB7F0EFFBA7E0DFFB97D0CFFB87C0BFFBC800FFFBB7F0EFF
+ B97D0CFFB87C0BFFB87C0BFFBA7E0DFFBC800FFFBD8110FFC18514FFBD8110FF
+ B87C0BFFB67A09FFB67A09FFB77B0AFFB87C0BFFB77B0AFFBC7D0DFFBD7E0EFF
+ BE7F0FFFBF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7D0DFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBE7F0FFFBF8010FFC08111FFBB7C0CFFBC7D0DFF
+ BD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBD7E0EFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBA7C0AFFBB7D0BFF
+ BD7F0DFFBF810FFFBF810FFFBE800EFFBB7D0BFFB97B09FFBC800FFFBA7E0DFF
+ BA7E0DFFBD8110FFBC800FFFB87C0BFFB77B0AFFBA7E0DFFBE8211FFB97D0CFF
+ B97D0CFFAB6D09FFAF710DFFB37511FFB57713FFB47612FFB27410FFB1730DFF
+ B2740EFFB2750DFFB2750DFFB2750DFFB3760EFFB3770DFFB5790FFFB67A10FF
+ B77B11FFB57711FFB1730DFFB2740EFFB97B15FFBB7D17FFB87A14FFB67812FF
+ B77913FFB2740EFFB47610FFB57711FFB3750FFFB47610FFB77913FFB77913FF
+ B37713FFB67B18FFB87B1BFFBC7A1BFFB87819FFAD7817FFAD7915FFB77913FF
+ BB7A17FFB4761CFFB1781DFFAC7514FFB07714FFB17416FFA07439FF958F90FF
+ 9BAED4FF7DA0D2FF729DD6FF7FA8E7FF6B94D9FF4D7ACBFF527ED1FF557DC8FF
+ 4C75BAFF77A1E4FF678ED3FF3E5CA9FF364C9AFF2F3A84FF26347CFF617EC8FF
+ 638CD5FF507FC9FF4576C0FF487BC4FF6092DAFF749FE8FF658DD5FF4767B2FF
+ 2F4E99FF1D3D89FF3E62AEFF5B85D0FF5789D1FF5084C7FF5F93D5FF74A5E3FF
+ 79A5E5FF769AE0FF6484CBFF5270B1FF36528FFF1D3A73FF2B4B86FF4B71B2FF
+ 5681CAFF4E7DCFFF517FD3FF527ACCFF4E6BAEFF495886FF494B63FF5A4C50FF
+ 6E5644FF87643CFF926A30FF9C6F2BFFA47121FFA86E15FFB27513FFBE7E18FF
+ BC7F17FFB67B14FFB57C19FFB47D1CFFB37B1CFFB37919FFB47916FFB67814FF
+ B67911FFB47A11FFB97F18FFBB801CFFBC8223FFB88027FFA87323FFA0702EFF
+ A37E4AFFDBC4A4FFFBF1E0FFFCFCFCFFE9EFF6FFEAF2F9FFECF3F6FFEEECEBFF
+ F1F0ECFFE9ECF0FFEAEDF2FFEFEEF2FFF1EEF0FFEFEFEFFFEEF0F0FFEBF3F3FF
+ EBF5F5FFF2FAFAFFF8F9F5FFF4E9DBFFD3B99BFFB08857FFB5843EFFC48C33FF
+ BB7F1BFFBC831AFFB87F16FFB67F17FFB57E16FFB07813FFB37B16FFB9811CFF
+ B88119FFB88015FFB98013FFBA7F11FFBA800FFFBD7F0DFFBD7F0DFFBC7F0BFF
+ BC7E0CFFC18514FFBD8012FFBC7F11FFBE8113FFBF8214FFBD8012FFBD8012FF
+ BF8214FFBC7F11FFB97C0EFFB87B0DFFBA7D0FFFBA7D0FFFB87B0DFFB97C0EFF
+ BC7F11FFB97C0EFFBB7E10FFBE8113FFC18416FFC18416FFBE8113FFBB7E10FF
+ B97C0EFFB87B0DFFB97C0EFFBB7E10FFBD8012FFBD8012FFBB7E10FFB97C0EFF
+ B87B0DFFBD8110FFBC800FFFBA7E0DFFB97D0CFFB87C0BFFB97D0CFFBA7E0DFF
+ BB7F0EFFB87C0BFFB97D0CFFBB7F0EFFBC800FFFBD8110FFBB7F0EFFBA7E0DFF
+ B87C0BFFB77B0AFFB97D0CFFBC800FFFBE8211FFBE8211FFBD8110FFBA7E0DFF
+ B97D0CFFB97D0CFFB97D0CFFB97D0CFFBB7F0EFFBD8110FFBC800FFFB97D0CFF
+ B67A09FFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFF
+ BD7E0EFFBE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBD7E0EFFBE7F0FFFBF8010FF
+ C08111FFB97A0AFFBA7B0BFFBC7D0DFFBE7F0FFFBF8010FFBE7F0FFFBD7E0EFF
+ BC7D0DFFBD7E0EFFBD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFF
+ BD7E0EFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBE800EFF
+ BE800EFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBF810FFFBE800EFFBC7E0CFF
+ B97B09FFBD8110FFBA7E0DFFBB7F0EFFC08413FFBE8211FFB77B0AFFB67A09FF
+ BB7F0EFFBC800FFFBA7E0DFFBA7E0DFFB1730FFFB1730FFFB0720EFFAE700CFF
+ AC6E0AFFAE700CFFB2740EFFB57711FFB2750DFFB2750DFFB3760EFFB3760EFF
+ B4780EFFB3770DFFB3770DFFB2760CFFB67812FFB2740EFFB3750FFFB87A14FF
+ BB7D17FFB77913FFB3750FFFB47610FFB57711FFB3750FFFB47610FFB77913FF
+ B97B15FFB87A14FFB97B15FFB97E17FFB67B17FFB87B19FFBE791CFFB77719FF
+ AC7716FFA97713FFB57A13FFBB7A17FFC17F26FFB7781CFFB97F18FFB87E15FF
+ BA7819FFAC793BFF93837DFF8C9AB7FF7595C6FF6993CEFF7399DAFF6088D0FF
+ 4C76C9FF4B74C9FF486FBDFF4B73BBFF6994D7FF6E97DCFF4062AEFF374F9BFF
+ 37458DFF2E3E83FF6686CDFF638DD4FF5586CCFF4A7DC3FF4679BFFF5283C7FF
+ 6B95DAFF7496DCFF5D79C0FF3E569EFF27408AFF2F4C96FF496FB7FF618BD0FF
+ 5F8FD1FF6291CFFF6F9CD9FF77A3E0FF7AA6E5FF6A94D5FF5F7FC8FF5269B4FF
+ 394C95FF253A7EFF2D4A87FF4266A2FF5985C4FF5A8BD1FF5C8CDAFF5782D3FF
+ 4B6CBBFF4058A0FF3B4D8AFF434C78FF4B4A5EFF5C5252FF786556FF907452FF
+ 99733DFF9F712AFFA9731EFFA87011FFB47B18FFB37B16FFB37C14FFB47D15FF
+ B57E15FFB77F12FFB87D0FFFB67B0DFFB1780FFFB77D16FFB57915FFB67B18FF
+ B77E23FFA46F1FFFA07536FFBB9B70FFF1E1CAFFF7F1EAFFECF0F5FFDEE7F0FF
+ E8F0F7FFF2F7F8FFF5F2EEFFF0EDE9FFF0F1F5FFEFF2F7FFF6F2F7FFF4F2F2FF
+ EDEDEDFFE6EBEAFFE1EBEBFFDFEBEDFFF4FCFCFFF6F6F0FFE6D6C6FFC2A382FF
+ AC804AFFB07C30FFBE8425FFC4881EFFC28A1BFFB98213FFB68113FFB37F15FF
+ AE7911FFB37E16FFB8831BFFB78017FFBB8318FFBC8316FFBC8113FFBA800FFF
+ BD7F0DFFBB7D0BFFBA7B08FFB97B09FFC08413FFBD8012FFBC7F11FFBE8113FF
+ BC7F11FFB97C0EFFBA7D0FFFBF8214FFBE8113FFB97C0EFFB87B0DFFBB7E10FF
+ BB7E10FFB87B0DFFB97C0EFFBE8113FFBB7E10FFBC7F11FFBC7F11FFBD8012FF
+ BD8012FFBC7F11FFBC7F11FFBB7E10FFB87B0DFFBA7D0FFFBC7F11FFBD8012FF
+ BD8012FFBC7F11FFBA7D0FFFB87B0DFFBC800FFFBB7F0EFFBB7F0EFFBA7E0DFF
+ BA7E0DFFB97D0CFFB97D0CFFB97D0CFFB87C0BFFB87C0BFFB97D0CFFBA7E0DFF
+ BB7F0EFFBC800FFFBC800FFFBC800FFFB67A09FFB87C0BFFBC800FFFBF8312FF
+ BF8312FFBE8211FFBB7F0EFFB97D0CFFBA7E0DFFBA7E0DFFBA7E0DFFBD8110FF
+ BE8211FFBD8110FFB97D0CFFB67A09FFBE7F0FFFBD7E0EFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBD7E0EFFBD7E0EFFBE7F0FFFBE7F0FFFBE7F0FFFBC7D0DFFBC7D0DFF
+ BB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBD7F0DFFBE800EFFBF810FFFBD7F0DFFBC7E0CFFBB7D0BFFBC7E0CFF
+ BE800EFFBE800EFFBC7E0CFFBA7C0AFFBC800FFFBD8110FFBD8110FFBD8110FF
+ BA7E0DFFB97D0CFFBB7F0EFFBF8312FFB97D0CFFBB7F0EFFBB7F0EFFAE700CFF
+ AE720EFFB27410FFAF730FFFAF710DFFAC700CFFAF710DFFAF740DFFB1730DFF
+ B0760DFFB3760EFFB2780FFFB4770FFFB0760CFFB1750BFFB0730BFFB77913FF
+ B3750FFFB3750FFFB87A14FFBA7C16FFB57711FFB1730DFFB0720CFFB87A14FF
+ B3750FFFB57711FFBB7D17FFBD7F19FFBA7C16FFBB7D17FFC1831DFFB67B14FF
+ B97B17FFBD791AFFB97718FFAD7613FFAB7712FFB47814FFBB7A18FFB77719FF
+ AC6C0DFFB57A13FFB4770FFFB36F10FFA76D25FF856647FF7C7474FF909BAFFF
+ 869BBBFF8294BDFF6C80B0FF647AAEFF5774B1FF456AB4FF527CC7FF5784C8FF
+ 6C95DAFF3E5EAAFF334B97FF36448CFF2B3777FF6275AEFF5772A5FF6688BDFF
+ 5C83BAFF4C76B9FF4975BCFF618BD2FF7A9EE4FF6B88CBFF475FA1FF384E90FF
+ 253C80FF375497FF6084C4FF6994D3FF628ECDFF6491D4FF6C9BDFFF6699D8FF
+ 6A97DAFF5D80CAFF4E68B5FF4C60ADFF4457A0FF2D4789FF1C3E7AFF4B74B3FF
+ 4978BCFF4978C9FF4775CDFF446DC9FF3F66C2FF3D61B9FF4361AEFF475B94FF
+ 556288FF787F93FFA09B9DFFAE9C8BFFAE916CFFAA8247FFA47327FFAE791EFF
+ B07A15FFB27C11FFB67E11FFBA8314FFBC8415FFBB8012FFB97E11FFB77C15FF
+ BE811FFFB57818FFB47B20FFBB8433FFA57835FFAB8A5CFFD9C4A8FFFFFFF4FF
+ F3F5F5FFE4EAEFFFDFE7EEFFE9EEF1FFF4F6F6FFF6F5F1FFECEAE9FFECEDF1FF
+ EEEEF4FFF5F2F4FFF4F2F2FFEEEEEEFFE7EBECFFE1EAEDFFE2EBEEFFEBF0EFFF
+ EDE6DDFFDAC3ADFFC29E76FFB8894BFFB67F2EFFBC8222FFCD9329FFC38B1CFF
+ BA8314FFB98416FFBB851AFFB47F17FFB68119FFB98219FFB17A11FFBB8318FF
+ BB8215FFBC8113FFBA800FFFBB7F0EFFBB7D0BFFBA7C0AFFB97B09FFBB7F0EFF
+ B87B0DFFBA7D0FFFBD8012FFBB7E10FFB77A0CFFBB7E10FFC38618FFBF8214FF
+ BA7D0FFFB97B0FFFBC7E12FFBC7E12FFB97B0FFFBA7C10FFBF8115FFBE8113FF
+ BD8012FFBB7E10FFB97C0EFFB97C0EFFBB7E10FFBD8012FFBE8113FFBE8113FF
+ BD8110FFBB7E10FFB97D0CFFB97D0CFFBB7F0EFFBD8110FFBE8211FFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0DFFB97D0CFFB87C0BFFB97D0CFF
+ B87C0BFFB87C0BFFB87C0BFFB97D0CFFBB7F0EFFBE8211FFBF8312FFBB7F0EFF
+ BA7E0DFFBA7E0DFFBA7E0DFFBB7F0EFFBC800FFFBD8110FFBE8211FFC48817FF
+ C08413FFBC800FFFB97D0CFFB97D0CFFB97D0CFFB87C0BFFB77B0AFFBE7F0FFF
+ BD7F0DFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBE7F0FFF
+ BD7E0EFFBB7C0CFFBA7B0BFFB97A0AFFB97A0AFFBA7B0BFFBA7B0BFFC08111FF
+ BE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBC7D0DFFBE7F0FFFBF8010FFBE7F0FFF
+ BD7E0EFFBC7D0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE7F0FFFBC7D0DFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBE800EFFBF810FFFBF810FFF
+ BC7E0CFFBA7C0AFFBA7C0AFFBD7F0DFFBE800EFFBD7F0DFFBB7C0CFFBA7E0DFF
+ BF8214FFBF8312FFB87C0BFFB67A09FFBC800FFFC18513FFC28614FFB77B09FF
+ BC800EFFBC800FFFAC6F0DFFAC710EFFAF7210FFAF7411FFB17412FFAF7410FF
+ AF730FFFAE740DFFAE730CFFAE740DFFB0750EFFAD740BFFAD730AFFAE750CFF
+ B47A11FFB87E15FFB2740EFFB3750FFFB0720CFFB67812FFBF811BFFB77913FF
+ AF710BFFB57711FFBB7D17FFBA7C16FFB97B15FFB77913FFB77913FFB77913FF
+ B77913FFB87A14FFB3760EFFB47610FFB77613FFB67814FFB47814FFB27713FF
+ B47612FFB37511FFB97A18FFB77816FFB57713FFB77915FFBD7C1AFFB87921FF
+ A67226FF91692FFF836A42FF827059FF7D6A63FF705D5AFF6B5F53FF676B76FF
+ 4E6EAFFF406EC2FF4772BBFF5C83C8FF425EABFF2A3E8BFF3A4890FF373C73FF
+ 251F3EFF262031FF181F30FF314362FF566FADFF597AC9FF537ECFFF6A94DFFF
+ 6E96D1FF5978AFFF465A94FF42528DFF364883FF3E5894FF5D82BCFF6C97DAFF
+ 5F8FE1FF5588DEFF5C8DDBFF5988D2FF5C83CDFF5778C1FF4D6BB2FF4E6BB5FF
+ 4A6AB5FF3B5DA9FF2C51A1FF3358ACFF4065BAFF4A6FC4FF486EC6FF436BC3FF
+ 4673CAFF5580D1FF6587CDFF5F7DB4FF738FB8FFABC0DCFFC5CCE0FFD1C8CBFF
+ B1977FFF8A632FFFAA7B29FFB27E19FFB67E11FFB8800FFFBA8211FFBD8214FF
+ BB7D17FFBA7916FFBB7815FFC58324FFBD802AFFB58135FFB88C51FFB5976EFF
+ CBBBA4FFF5F0E7FFF3F8F7FFEFF6F9FFEEF3F4FFEBF1F0FFEDF0EEFFEEEFEDFF
+ EEEEEEFFEEEDEFFFEEEDF1FFE8E7EBFFE7E6E8FFEAEAEAFFE8EBEFFFE9EDF2FF
+ E6ECF3FFE7EAEEFFF1ECE9FFDFCFBFFFBF9E7DFFAD824FFFB4813BFFB37C27FF
+ B47B1EFFC78E2BFFBA7F18FFC1861FFFC68B24FFC38821FFBB8019FFB57A13FF
+ B67C13FFB97F16FFBB8117FFB57A0DFFB2770AFFB77C0EFFBA7F11FFBA7D0FFF
+ BA7D0FFFBE8211FFBB8012FFB97E10FFB77C0EFFB87D0FFFBB8012FFBC8113FF
+ BA7F12FFB87D10FFBC8114FFB87D10FFB77B11FFB97D13FFB77B11FFB3770DFF
+ B67A10FFBE8218FFBC7E12FFBA7D0FFFB97C0EFFBA7D0FFFBD8012FFC08315FF
+ C18514FFC18514FFB97D0CFFBA7E0CFFBB7F0EFFBB7F0DFFBB7F0DFFBB7F0DFF
+ BA7E0CFFB97D0BFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBD7F0DFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BA7C0AFFB97B09FFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFC18311FFBF810FFFBE800EFFBD7F0DFFBD7F0DFFBE800EFF
+ BF810FFFC18311FFB77B09FFB97E0AFFBB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFF
+ BB7F0DFFBE8210FFBC800FFFBA7E0DFFBA7D0FFFBC7F11FFBE8113FFBE8113FF
+ BB7E10FFB87B0DFFB87B0DFFBA7D0FFFBC7F11FFBC7F11FFBA7D0FFFBA7D0FFF
+ BC7F11FFBE8113FFB97C0EFFB97C0EFFBA7D0FFFBB7E10FFBB7E10FFBB7E10FF
+ BA7D0FFFBA7D0FFFBB7E10FFBB7F0EFFBB7F0EFFBB7F0EFFBA7E0CFFBA7E0CFF
+ B97E0AFFB97E0AFFBB800CFFBA7F0BFFB87C0AFFB77B09FFB77B0AFFB87C0BFF
+ BA7E0DFFBB7E10FFBF8115FFBE8014FFBC7F11FFBA7E0DFFB97D0CFFBA7E0CFF
+ BB800CFFBC810DFFBF8410FFB77C08FFB77B09FFAD720FFFAE7310FFAF7411FF
+ B07512FFB07512FFAF7411FFAE730FFFAD720EFFAB710AFFAE740DFFB17710FF
+ B37912FFB37A11FFB27910FFB1780FFFB1780FFFB1730DFFB57711FFB2740EFF
+ B47610FFBB7D17FFB77913FFB1730DFFB67812FFBB7D17FFBA7C16FFB87A14FF
+ B77913FFB77913FFB77913FFB77913FFB87A14FFB57810FFB57810FFB67812FF
+ B67812FFB67812FFB67812FFB57713FFB57713FFB67814FFB77915FFB87917FF
+ B77816FFB77816FFB87917FFB9791AFFB37920FFA3742AFFA0753CFF9C6F49FF
+ 936944FF8E6B39FF7B6D5AFF536BA1FF456FC2FF517BC2FF6083C7FF4960ACFF
+ 33438FFF3E488EFF3D3C6EFF372433FF3B2422FF271B17FF2E2E3CFF465183FF
+ 5874BBFF5780CFFF5D8ED8FF6695D3FF5C83BAFF586EA8FF44528DFF2B3973FF
+ 2F427BFF435F95FF4C71ABFF5881C6FF6D9AE4FF5E8AD7FF5F8BD8FF648FD8FF
+ 658FD6FF618BD0FF638DD4FF5883CCFF456CBAFF476CBCFF3C5FAFFF395AAAFF
+ 3E5FAFFF4466B9FF4D73C5FF5781D4FF6089D8FF688BD4FF799BD7FF8CB1DDFF
+ ADCBEEFFC3D2F3FFD8D7E7FFB6A396FF836034FFA6782AFFB27C17FFB57B11FF
+ B97C0EFFB87D0FFFB97D13FFB77A1AFFB9791BFFD59132FFBB7A1EFFB17627FF
+ AC7C3CFFAA875BFFCCB79CFFEDE6DDFFEBEFF0FFE9F2F6FFE8F1F4FFEAF0EFFF
+ EBEFEAFFECEDE9FFECEDEBFFEBECF0FFEBEBF1FFF2F1F5FFF0EDEFFFE7E6E8FF
+ E8EAEBFFF0F3F7FFEFF3F8FFEDF0F5FFF8F6F6FFF4E8DEFFCDB59DFFBE976BFF
+ C6975AFFC38D40FFAF7620FFA86F12FFAE7414FFB87B19FFBC7E1AFFBF811DFF
+ BF811BFFBD7F19FFBB7E16FFB97C14FFB87C12FFBA7E14FFB67A10FFB57A0DFF
+ B97E11FFBA7F12FFB67B0EFFB57A0CFFB77C0EFFBB8012FFB97E10FFB87D0FFF
+ B87D0FFFBB8012FFBB8012FFBA7F12FFB87D10FFB5790FFFB4780EFFB87C12FF
+ BD8117FFBD8018FFBA7D15FFBC7F17FFC2861CFFC18317FFBE8113FFBB7E10FF
+ B97C0EFFBA7D0FFFBB7E10FFBA7E0DFFB87C0BFFB77B09FFB97D0BFFBB7F0DFF
+ BD810FFFBD820EFFBB800CFFB97E0AFFB77C08FFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBA7C0AFFBA7C0AFFBB7D0BFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBE800EFFBD7F0DFFB97E0AFFBB800CFFBC810DFF
+ BB800CFFB97D0BFFB87C0AFFBA7E0CFFBB7F0DFFBB7F0EFFBB7F0EFFBB7E10FF
+ BC7F11FFBD8012FFBD8012FFBB7E10FFB97C0EFFBD8012FFBF8214FFC08315FF
+ C08315FFBE8113FFBD8012FFBF8214FFC18416FFBC7F11FFBC7F11FFBC7F11FF
+ BC7F11FFBB7E10FFB97C0EFFB77A0CFFB6790BFFBB7E10FFBB7E10FFBB7F0EFF
+ BB7F0EFFBA7E0CFFBA7E0CFFB97E0AFFB97E0AFFB97E0AFFB97E0AFFB97D0BFF
+ BA7E0CFFBA7E0DFFB97D0CFFB97C0EFFB97C0EFFBC7E12FFBC7E12FFBC7F11FF
+ BB7F0EFFBB7F0DFFBA7E0CFFB97E0AFFB97F08FFC18612FFBA7F0BFFBA7E0CFF
+ AF7411FFAF7411FFB07512FFB07512FFB07512FFB07512FFAF7410FFAE730FFF
+ B07511FFB17612FFB27811FFB47A13FFB57B14FFB57B14FFB27910FFAF760DFF
+ B0720CFFB77913FFB57711FFB2740EFFB57711FFB67812FFB47610FFB67812FF
+ BA7C16FFB97B15FFB87A14FFB77913FFB67812FFB77913FFB77913FFB87A14FF
+ B77A12FFB77A12FFB67812FFB67812FFB67812FFB67812FFB77915FFB77915FF
+ B47612FFB77915FFBA7B19FFB87917FFB57614FFB67715FFBC7C1DFFBD8225FF
+ AE7825FFA97630FFA7733EFFA4723EFF9C7132FF806B4BFF576791FF4D70BAFF
+ 4D70B2FF516EB1FF41559CFF354489FF3D4686FF3C3B67FF3C2835FF442722FF
+ 422520FF322027FF333554FF576DA1FF5B85C8FF5086CDFF548AD1FF4A79BDFF
+ 4D6DAFFF394F90FF2B3A79FF303E78FF2F4071FF273B64FF405473FF637DA2FF
+ 5677B6FF5B84CDFF6796E0FF659AE3FF5D98DEFF609BE0FF669CDBFF6094D0FF
+ 507EB8FF4A73B1FF486EAFFF4062A8FF304F9AFF3856A3FF5973BFFF6F89CFFF
+ 748CCEFF7C97CAFF87A6C7FFA8C0D6FFB6C0D1FFBCB6B7FFA2896FFF8C642FFF
+ B17D2AFFBD811DFFC2801AFFC27F18FFBE7F17FFBB7F1BFFBC7F22FFBF8026FF
+ C68529FFB0701BFFAA732AFFAC7F46FFB79773FFE4D3BEFFFFFCF5FFEEF2F3FF
+ E9EFF4FFE7F0F3FFEAF0EFFFECEFEDFFEEEFEDFFEFEFEFFFEEEFF3FFEEEFF3FF
+ F4F1F3FFF5F2F4FFECEBEDFFE9EAEEFFF0F3F7FFF0F2F3FFF1EFEFFFFFF9F0FF
+ D9C5B3FFB49673FFB98F5AFFD39F5CFFC99140FFC0842AFFC08424FFB67B17FF
+ B77915FFB67812FFB67812FFB97B15FFBD7F19FFBD8018FFBA7D15FFB67A10FF
+ BB7F15FFBB8013FFBD8215FFBF8417FFBE8315FFB97E10FFB77C0EFFB97E10FF
+ BB8110FFB97F0EFFB87E0DFFB97F0EFFBA7F11FFBB8012FFBA7F11FFB87D0FFF
+ B87D10FFBA7F12FFBF8417FFC3881BFFC1851BFFBB7F15FFB97D13FFBB7F15FF
+ BC7E12FFBA7D0FFFB87B0DFFB87B0DFFBA7D0FFFBB7E10FFBB7F0EFFB97D0CFF
+ B67A08FFB87C0AFFBC800EFFBF8311FFBF8410FFBC810DFFB87D09FFB67B07FF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BA7C0AFFBC7E0CFFBD7F0DFFBF810FFFBF810FFFBD7F0DFFBC7E0CFFBA7C0AFF
+ BB800CFFBC810DFFBD820EFFBC810DFFB97D0BFFB77B09FFB87C0AFFBA7E0CFF
+ BA7E0DFFBB7F0EFFBD8012FFBD8012FFBC7F11FFBB7E10FFBB7E10FFBB7E10FF
+ BA7D0FFFBB7E10FFBD8012FFBC7F11FFB97C0EFFB87B0DFFBA7D0FFFBB7E10FF
+ BB7E10FFBB7E10FFBC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFFB87B0DFF
+ BC7F11FFBB7E10FFBB7F0EFFBA7E0DFFBA7E0CFFB97D0BFFB97E0AFFB97E0AFF
+ B77C08FFB97E0AFFBA7E0CFFBC800EFFBC800FFFBA7E0DFFB97C0EFFB77A0CFF
+ B87B0DFFBA7D0FFFBB7E10FFBC800FFFBC800EFFBA7E0CFFB87C0AFFB77C08FF
+ BF8311FFB97D0BFFB97D0BFFAE7310FFAF7411FFAF7411FFB07512FFB17613FF
+ B17613FFB17612FFB17612FFB97E1AFFB57A16FFB17710FFB0760FFFB27811FF
+ B47A13FFB47B12FFB37A11FFB0720CFFB87A14FFB87A14FFB1730DFFB0720CFF
+ B57711FFB77913FFB77913FFB97B15FFB87A14FFB77913FFB67812FFB67812FF
+ B77913FFB77913FFB87A14FFBA7D15FFB97C14FFB77913FFB67812FFB67812FF
+ B77913FFB97B17FFBA7C18FFB57713FFB87A16FFB97A18FFB97A18FFB87917FF
+ B97A18FFBC7C1DFFBE8022FFB1781BFFB17927FFB47934FFB07635FFA77229FF
+ 896C40FF616784FF526EAEFF4A68A9FF4662A3FF405397FF3F4A8EFF404884FF
+ 3C3A64FF3E2D38FF452821FF4E2A22FF391C18FF32272FFF5C6580FF6787B8FF
+ 5B89C9FF588CD8FF4475C3FF365EA6FF365698FF3C5293FF40538CFF313F6FFF
+ 1C2747FF272F3CFF414A58FF52638AFF486298FF476DA7FF4F80BEFF5791D3FF
+ 609CDEFF68A3E1FF6CA5DDFF74A8DDFF6392C8FF5480BDFF456AAEFF2E4E97FF
+ 2C458FFF36488FFF364584FF6773A9FF667197FF616E7CFF737B7AFF80766FFF
+ 8E7660FF956E41FFA87431FFBA7E24FFC68320FFC78322FFC48321FFBD801EFF
+ BA7E1EFFB97D23FFBB7F26FFBE7E29FFB77E2FFFA77435FFAF8959FFDCC1A6FF
+ F5E8DAFFF1EDECFFEEF1F5FFEFF3F8FFEDF4F7FFEEF4F3FFEFF4F2FFF1F3F3FF
+ F1F3F4FFF1F2F6FFF1F2F6FFEFECEEFFF3F1F1FFF3F2F6FFEDEEF2FFE9EAEEFF
+ EEECECFFF1E9E2FFF3E3D2FFBCA383FFB28E60FFBB8C4EFFBE883BFFB0751FFF
+ BA7D1FFFC48725FFB2740EFFB57711FFB57810FFB57711FFB87B13FFBB7E16FF
+ BC8016FFBA7E14FFB77C0FFFB77C0FFFBA7F12FFBC8114FFBD8214FFBA7F11FF
+ B87D0FFFB87D0FFFBB8110FFBA800FFFB97F0EFFB97F0EFFB97F0EFFBA7F11FF
+ BA7F11FFBA7F11FFB97E10FFB97E11FFBC8114FFC08518FFC2871AFFBF8319FF
+ BA7E14FFB77B11FFB77C0FFFBB7E10FFB97C0EFFB87B0DFFB97C0EFFBB7E10FF
+ BD8012FFBC800FFFBB7F0EFFB87C0AFFB97D0BFFBB7F0DFFBD810FFFBD820EFF
+ BB800CFFB97E0AFFB87D09FFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFF
+ BD7F0DFFBF810FFFC18311FFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBE800EFFBE800EFFBA7C0AFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBA7C0AFFBA7F0BFFBC810DFFBD820EFFBB800CFFB97D0BFF
+ B87C0AFFB97D0BFFBB7F0DFFB97D0CFFBC800FFFBE8113FFBD8012FFBB7E10FF
+ B97C0EFFBB7E10FFBD8012FFB87B0DFFBA7D0FFFBB7E10FFB97C0EFFB77A0CFF
+ B5780AFFB6790BFFB87B0DFFB5780AFFB77A0CFFB97C0EFFBB7E10FFBC7F11FF
+ BD8012FFBD8012FFBD8012FFBC7F11FFBC7F11FFBB7F0EFFBA7E0DFFB97D0BFF
+ B97D0BFFBA7F0BFFBA7F0BFFB97E0AFFB97E0AFFBB7F0DFFBB7F0DFFBB7F0EFF
+ BB7F0EFFB97C0EFFB97C0EFFB87B0DFFB97D0CFFBA7E0DFFBA7E0DFFBA7E0CFF
+ B97D0BFFB87C0AFFB77B09FFBA7E0DFFB57907FFB57907FFAC7010FFAD7111FF
+ AE7212FFAF7313FFB17613FFB27714FFB47916FFB57A17FFBA7F1BFFB67B17FF
+ B27811FFB0760FFFB27811FFB47A13FFB47A13FFB27811FFB1730DFFB67812FF
+ B87A14FFB2740EFFAE700AFFB47610FFB97B15FFB77913FFB87A14FFB77913FF
+ B67812FFB67812FFB67812FFB67812FFB87A14FFB87A14FFBA7D15FFB97C14FF
+ B87A14FFB77913FFB77913FFB87A14FFB97B17FFBA7C18FFB87A16FFB77915FF
+ B77816FFB97A18FFBC7D1BFFBD7E1CFFBB7B1CFFB87917FFB57915FFBB7F1FFF
+ BE7D2CFFB67628FFAE721EFF96703AFF6B697CFF556AA1FF536FAFFF506CADFF
+ 4F62A6FF4E5A9CFF474F8AFF3E3D65FF3C2D35FF41251EFF4D2A1DFF492717FF
+ 513925FF706861FF727E96FF6B87BDFF648EDBFF4678CBFF3968B2FF406CACFF
+ 496CABFF47649DFF3E5085FF354066FF363A45FF373638FF333039FF383B4AFF
+ 43546EFF56739AFF5C83BAFF5585C7FF598DD3FF689FE4FF84BDFAFF7AB1EEFF
+ 72A4E6FF628ED5FF4D6FBBFF435BA7FF404F97FF3E447FFF433E65FF675A6AFF
+ 786A5EFF8B7355FF966D46FFAC7641FFAE6E27FFAF6A13FFBD7916FFC07E18FF
+ BD7E22FFBA7E24FFB37C21FFAD791BFFAE771CFFAE761DFFCC9443FFC08C46FF
+ A67C47FFC1A17EFFFEEAD8FFFFF8F1FFE6E3E5FFEAEDF2FFF1F4F9FFF0F5F8FF
+ F1F6F5FFF0F5F4FFF1F3F4FFF0F1F5FFEFEFF5FFEFEFF5FFEEECECFFEDEBEBFF
+ F1F2F6FFEFEFF5FFE9E8ECFFF6F1EEFFF4E7D9FFD8C2A6FFBE9B6FFFC69A5DFF
+ C39047FFB57C27FFAF7214FFC0811FFFC88822FFB97A12FFB67911FFB87C12FF
+ BB7E16FFBB7F15FFB97D13FFB87D10FFB97E11FFBA7F12FFB2770AFFB57A0CFF
+ B67B0DFFB57A0CFFB3780AFFB57B0AFFB87E0DFFBB8110FFB97F0EFFBA810EFF
+ BA810EFFBA810EFFB97F0EFFB97F0EFFB97F0EFFBA800FFFB3780AFFB77C0EFF
+ BB8013FFBB8013FFBA7F12FFBA7F12FFBB8013FFBC8114FFC28517FFC08315FF
+ BD8012FFBD8012FFBD8012FFBC7F11FFB97D0CFFB67A09FFBB7F0DFFBA7E0CFF
+ BA7E0CFFBA7E0CFFBA7F0BFFBA7F0BFFBA7F0BFFBB800CFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBE800EFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFC08210FFC18311FFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBC7E0CFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFB87D09FFBA7F0BFF
+ BB800CFFBB800CFFBA7E0CFFB97D0BFFBB7F0DFFBD810FFFBA7E0DFFBC800FFF
+ BE8113FFBC7F11FFBA7D0FFFB97C0EFFBB7E10FFBE8113FFBD8012FFBE8113FF
+ BF8214FFBE8113FFBB7E10FFBA7D0FFFBB7E10FFBD8012FFB5780AFFB77A0CFF
+ B97C0EFFBB7E10FFBC7F11FFBD8012FFBD8012FFBD8012FFBD8012FFBC7F11FF
+ BA7E0DFFB97D0CFFB97D0BFFB97D0BFFBA7F0BFFBB800CFFBC810DFFBB800CFF
+ BA7E0CFFB97D0BFFB97D0CFFBA7E0DFFBB7E10FFBC7F11FFBA7E0DFFB97D0BFF
+ B87C0AFFB87C0AFFB87C0BFFB97D0CFFBA7E0DFFBB7F0EFFB87B0DFFB67A09FF
+ B67A09FFAC7010FFAC7010FFAD7111FFAE7212FFAF7411FFB17613FFB37815FF
+ B47916FFB27713FFB37814FFB37814FFB57B14FFB57B14FFB37912FFB0760FFF
+ AE740DFFB47610FFB3750FFFB67812FFB47610FFB0720CFFB47610FFB97B15FF
+ B67812FFB77913FFB67812FFB57711FFB57711FFB57711FFB67812FFB87A14FF
+ B87A14FFB97C14FFB87B13FFB87A14FFB77913FFB77913FFB87A14FFB87A16FF
+ B97B17FFB97B17FFB67814FFB57614FFB97A18FFBD7E1CFFBE7F1DFFBA7A1BFF
+ B47612FFB67C13FFBE801AFFC17E22FFB8751EFFB3741AFF9E7237FF746C73FF
+ 596998FF4F6AAAFF526FB4FF5269ADFF4C5C9EFF434D89FF3A3A62FF362B35FF
+ 39241CFF442719FF523018FF775629FF896F4AFF7B706CFF707A98FF6483C8FF
+ 517DD0FF497EC7FF4C81C4FF4D7EBCFF4970AEFF4764A1FF4D5E8FFF454C65FF
+ 343035FF5E4C41FF483526FF332A21FF43464AFF646F8AFF6B82AFFF6484BFFF
+ 5F8AC9FF5B8ECCFF6499D8FF679BDEFF5C89D3FF4E71C1FF4563B2FF4960ABFF
+ 5966A4FF5B5A86FF62596EFF6B5B54FF876C51FF91643FFFA36836FFB06D28FF
+ BD7A25FFB9791AFFBA7D1DFFB67E25FFB47E29FFB37F25FFB07D21FFB27B20FF
+ AF7922FFB78239FFAC7E44FFBA986DFFE7CFB7FFFFF7EFFFFAF5F7FFEBEBF1FF
+ EDEFF7FFEDF0F4FFEDF1F2FFEDF1F2FFEDF1F2FFEEEFF3FFECECF2FFEBEAF3FF
+ EAEAF0FFF0F0F0FFE8E7E9FFE9ECF1FFEFEFF5FFF4F0F5FFFFF7F0FFF0DBC6FF
+ C2A37CFFB0884EFFB6843CFFB17A25FFAF7417FFB77A18FFBE801AFFC07E17FF
+ BA7B13FFB97B11FFBA7F12FFBC8016FFBB8013FFB87D10FFB77C0FFFB87D10FF
+ BB8013FFB77C0EFFBA7F11FFBA7F11FFB87D0FFFB87E0DFFBD8312FFC18716FF
+ C28817FFB87F0CFFBA810EFFBB820FFFBA810EFFB97F0EFFB87E0DFFB97F0EFF
+ BB8110FFB67B0DFFB97E10FFBA7F12FFB77C0FFFB57A0DFFB77C0FFFB87D10FF
+ B87D10FFBF8214FFBE8113FFBD8012FFBD8012FFBF8214FFBF8214FFBC800FFF
+ B97D0CFFBC800EFFBB7F0DFFB97D0BFFB87C0AFFB87D09FFB97E0AFFBB800CFF
+ BC810DFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFF
+ BA7C0AFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBE800EFFBF810FFF
+ BF810FFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFB97B09FFB97B09FFBA7C0AFFBC7E0CFF
+ BD7F0DFFB77C08FFB97E0AFFBB800CFFBB800CFFBA7E0CFFBA7E0CFFBC800EFF
+ BE8210FFBC800FFFBC800FFFBC7F11FFBB7E10FFBA7D0FFFBA7D0FFFBC7F11FF
+ BD8012FFBB7E10FFBC7F11FFBE8113FFBD8012FFBA7D0FFFB97C0EFFBB7E10FF
+ BC7F11FFBB7E10FFBB7E10FFBC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFF
+ B87B0DFFBE8113FFBC7F11FFBA7E0DFFB87C0BFFB87C0AFFB97D0BFFBA7F0BFF
+ BB800CFFBD820EFFBC810DFFBA7E0CFFB97D0BFFB97D0CFFBA7E0DFFBC7F11FF
+ BD8110FFBB7F0DFFBA7E0CFFB87C0AFFB77B09FFB87C0BFFB97C0EFFBC7F11FF
+ BD8012FFBB7D11FFBA7D0FFFBA7D0FFFAF7313FFAE7212FFAD7111FFAD7111FF
+ AD7111FFAF7313FFB07512FFB17613FFAE7310FFB07511FFB37814FFB47915FF
+ B27713FFB07511FFAF750EFFAE740DFFB77913FFAF710BFFB2740EFFB77913FF
+ B3750FFFB47610FFB87A14FFB57711FFB67812FFB57711FFB57711FFB57711FF
+ B57711FFB67812FFB87A14FFB97B15FFB77A12FFB77A12FFB87A14FFB87A14FF
+ B87A14FFB87A14FFB77915FFB77915FFB57713FFB57713FFB57614FFB77816FF
+ B97A18FFBB7C1AFFBB7B1CFFB87C18FFBA8118FFB77E15FFBA7819FFBA771BFF
+ B7761AFF9E7233FF786C6CFF5F6B95FF4763A4FF5070BBFF4E69B3FF405599FF
+ 374482FF2E345FFF2C2532FF31231DFF35221AFF45290BFF875C1DFF9E7330FF
+ 8C6B44FF7E7071FF6574A5FF5B83CBFF5187CEFF4C8AD0FF518ED2FF5087CCFF
+ 4C76C1FF4E6EB0FF475B8BFF424155FF755948FF8F643DFF845E2EFF6A4A1FFF
+ 563C24FF524445FF696D86FF889BC6FF6587BCFF638CCAFF5680C5FF4C76C3FF
+ 567BCFFF557ACEFF4A71BFFF4C72BAFF506AB0FF394D84FF4D5876FF8F8D99FF
+ A48B8FFF9E7769FF966741FFA06E32FFAC7B2BFFAD7D25FFAE7D27FFB07F29FF
+ B58329FFBA852AFFBF862BFFBB8331FF9C6C2AFFA78151FFD9BFA1FFFFF1E4FF
+ F9F3F4FFEBEAF4FFEEEFF9FFEEF0F8FFEBECF0FFECEEEFFFEDEFF0FFEEF0F1FF
+ ECEFF3FFEBEEF3FFECEBF4FFEBEBF1FFEFF1F2FFEBEDEEFFE5E7EFFFECEBF4FF
+ FBF6F8FFF7E8DFFFD4BA9CFFB38E5CFFB2833FFFB57F2CFFB67D20FFBE831FFF
+ C48620FFC0831BFFBF7D16FFBB7D13FFBB7D11FFB87D0FFFB77C0FFFB77C0EFF
+ B97E10FFB97E10FFB97E10FFB87D0FFFBB8012FFBE8315FFBE8413FFBC8211FF
+ BE8413FFC38918FFC48A19FFC08615FFB87F0CFFBA810EFFBB820FFFBB820FFF
+ B87F0CFFB87F0CFFB97F0EFFBB8110FFB97E10FFBE8315FFBE8315FFB87D0FFF
+ B4790CFFB57A0DFFB57A0DFFB2770AFFB87B0DFFB77A0CFFB87B0DFFBB7E10FF
+ BF8214FFC18416FFBF8312FFBD8110FFBB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFF
+ BA7F0BFFBA7F0BFFBB800CFFBB800CFFBA7C0AFFBB7D0BFFBD7F0DFFBF810FFF
+ BF810FFFBD7F0DFFBB7D0BFFBA7C0AFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFB87D09FFBA7F0BFFBC810DFFBB800CFF
+ B97D0BFFB97D0BFFBA7E0CFFBC800EFFBE8211FFBC800FFFBA7D0FFFBA7D0FFF
+ BB7E10FFBC7F11FFBC7F11FFBC7F11FFB77A0CFFB97C0EFFBB7E10FFBA7D0FFF
+ B87B0DFFB87B0DFFB97C0EFFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBC7F11FF
+ BB7E10FFB97C0EFFB77A0CFFB6790BFFBE8113FFBC7F11FFBA7E0DFFB87C0BFF
+ B87C0AFFB97D0BFFBA7F0BFFBC810DFFBC810DFFBB800CFFBB7F0DFFBB7F0DFF
+ BB7F0EFFBB7F0EFFBB7E10FFBC800FFFBA7F0BFFBA7F0BFFBA7E0CFFBA7E0CFF
+ BB7F0EFFBB7E10FFBC7E12FFBD7F13FFBB7D13FFBB7D11FFBB7E10FFB27616FF
+ B07414FFAE7212FFAD7111FFAC7010FFAC7010FFAD720FFFAD720FFFB07512FF
+ B17613FFB17612FFAE730FFFAB700CFFAC710DFFB0760FFFB37912FFBA7C16FF
+ AD6F09FFB0720CFFB97B15FFB67812FFB47610FFB77913FFB47610FFB57711FF
+ B57711FFB47610FFB47610FFB57711FFB67812FFB87A14FFB97B15FFB57810FF
+ B67911FFB87A14FFB97B15FFB97B15FFB87A14FFB67814FFB57713FFB0720EFF
+ B47612FFB67715FFB67715FFB57614FFB67715FFBC7C1DFFC08321FFBA861CFF
+ B17A11FFB37412FFBB781BFFB8791DFFA07030FF7C6C60FF686F90FF536FB0FF
+ 5B7ECEFF5573C0FF3D559DFF314183FF292F5CFF25212DFF2B211AFF43342BFF
+ 432806FF8D5C10FFAB761CFF9B6B29FF86694AFF5E6176FF5B78ABFF5887C4FF
+ 518CD1FF5D9BE2FF5E99E8FF5084D7FF4D75C7FF5270B1FF61698EFF7B5E59FF
+ A0714BFFA37234FF9D6A24FF9A6A2AFF886232FF67523DFF4F4A4CFF7A8397FF
+ 8194B9FF738CBEFF617DBAFF6080C7FF587FC9FF4F80C4FF5B8FD2FF5079C2FF
+ 4668AAFF6884B3FFB4C4E8FFD0CDEDFFD2C1CFFFB89D8FFFA48058FFA07732FF
+ A57821FFA8761CFFAE791EFFB68022FFBF862BFFC38832FFBB863DFFAA814AFF
+ C3A37FFFEBD8C3FFFFF5F1FFF2F1FAFFE9ECFAFFEBECFAFFE9EAF4FFEBECF0FF
+ EEEDEFFFEEF0F1FFF0F1F5FFEFF2F7FFEFF2F7FFF0EFF8FFF0F0F6FFEDEEF2FF
+ F1F4F8FFE7E9F1FFEBE9EFFFFBF3F3FFE3D0C1FFB89874FFAE8449FFAC782BFF
+ B47B1EFFC08521FFC2881FFFB97F16FFBB7E16FFBF8018FFB87A10FFBA7F12FF
+ B4790BFFB07507FFB3780AFFBA7F11FFBD8214FFBA7F11FFB57A0CFFB4790BFF
+ B77C0EFFB77D0CFFB67C0BFFB97F0EFFBD8312FFBA800FFFB37908FFB87F0CFF
+ BA810EFFBC8310FFBB820FFFB87F0CFFB77E0BFFB97F0EFFBB8110FFB3780AFF
+ BA7F11FFBD8214FFB97E10FFB77C0FFFBA7F12FFBA7F12FFB77C0FFFBA7D0FFF
+ B97C0EFFB97C0EFFBB7E10FFBD8012FFBC7F11FFB97D0CFFB67A09FFB97D0BFF
+ BA7E0CFFBB7F0DFFBC800EFFBC810DFFBB800CFFBA7F0BFFB97E0AFFBA7C0AFF
+ BB7D0BFFBD7F0DFFBF810FFFBF810FFFBD7F0DFFBB7D0BFFBA7C0AFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFBE800EFFBC7E0CFFBB7D0BFFBE800EFF
+ BE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBA7C0AFF
+ BB7D0BFFBD7F0DFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFFBB800CFF
+ BC810DFFBD820EFFBC810DFFB97D0BFFB77B09FFB87C0AFFBA7E0CFFBF8312FF
+ BC800FFFB97C0EFFB97C0EFFBB7E10FFBD8012FFBD8012FFBB7E10FFBB7E10FF
+ BD8012FFBF8214FFBF8214FFBE8113FFBD8012FFBF8214FFC18416FFB97C0EFF
+ B97C0EFFBA7D0FFFBB7E10FFBB7E10FFBB7E10FFBA7D0FFFBA7D0FFFBE8113FF
+ BC7F11FFBA7E0DFFB87C0BFFB77B09FFB87C0AFFBA7F0BFFBC810DFFBA7F0BFF
+ BB800CFFBC800EFFBD810FFFBD8110FFBC800FFFBB7E10FFBA7E0DFFB87D09FF
+ B97F08FFBB7F0DFFBD810FFFBE8113FFBD8012FFBC7E14FFBB7D13FFB87A10FF
+ B97B0FFFB97B0FFFAA6D0FFFA76A0CFFA96C0EFFAF7214FFAF7313FFAB6F0FFF
+ AA6E0EFFAD7111FFB17613FFAE7310FFAB700DFFAC710EFFAF7410FFB17612FF
+ B17612FFB07511FFB2740EFFB1730DFFB2740EFFB57711FFB97B15FFBB7D17FF
+ B97B15FFB67812FFBD7F19FFBB7D17FFB97B15FFB77913FFB57711FFB47610FF
+ B3750FFFB3750FFFB97C14FFBA7D15FFB87A14FFB57711FFB67812FFBA7C16FF
+ B87A16FFB27410FFB67814FFB27410FFB37412FFB87917FFBA7B19FFB87917FF
+ BA7A1BFFBD821FFFAE7B13FFAF7C14FFB27616FFB7791BFFBF8024FFAD7C38FF
+ 8A735DFF72758AFF546CAEFF6084D8FF6889D8FF3D58A2FF405093FF333968FF
+ 292531FF31261EFF3A2A1DFF5A3D16FF9C6A17FFB87E17FFA06B10FF8A6626FF
+ 6E6557FF475669FF53739EFF517DBAFF5287D0FF5D95E7FF669DF8FF598BE3FF
+ 4A71BCFF5768A0FF685772FF744F47FF8F622FFFA77424FFAB7411FFAE7918FF
+ A57827FF846227FF705A37FF766A5EFF807A85FF6C708DFF6676A1FF7595C6FF
+ 6CA0CFFF6A9FD2FF78A0DAFF799CD4FF88ACDCFF9DBCE9FFA9BAEBFFCED2F5FF
+ D7CDD3FF9E866AFF8F6A26FFB78428FFCE902CFFC27E19FFB2710FFFC2842AFF
+ C98F44FFB08144FFA28154FFE2CCB0FFFFF3E7FFEEE9EAFFE8EAF5FFEDF1FFFF
+ ECEFFDFFEAECF6FFEFF0F4FFF0EFF1FFEDEFF0FFEBEEF2FFECEFF4FFEEF0F8FF
+ F2F1FAFFF3F2FBFFF0F3F8FFE8EBF0FFDDE0E5FFF4F1F3FFF0E5DDFFCBB59CFF
+ C09C6EFFBE914EFFB07924FFB37A17FFBC811AFFC0861DFFBC8219FFBF851CFF
+ C1831DFFB77A12FFB97E10FFBD8312FFBB8110FFB47A09FFB37908FFB77D0CFF
+ B87D0FFFB3780AFFB4790BFFB87D0FFFBB8012FFBB8012FFB77C0EFFB57A0CFF
+ B77C0EFFBA800FFFBB820FFFBD8411FFBD8312FFBB8110FFB77D0CFFB67C0BFF
+ B77C0EFFB97E10FFC3881AFFBE8315FFB97E11FFB97E11FFBB8013FFBD8215FF
+ BC8114FFBC8114FFC28517FFC08315FFBC7F11FFB97C0EFFB87B0DFFBA7D0FFF
+ BD8110FFBF8312FFBD810FFFBC800EFFBB7F0DFFBA7E0CFFBA7F0BFFBB800CFF
+ BC810DFFBD820EFFBC7E0CFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFFBF810FFF
+ C18311FFC28412FFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBB7D0BFFBC7E0CFF
+ BE800EFFBF810FFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBF8410FFBC810DFFBA7F0BFFBB800CFFBC800EFFBD810FFF
+ BB7F0DFFB87C0AFFBC800FFFC38716FFC5881AFFBF8214FFBC7F11FFBD8012FF
+ BC7F11FFB97C0EFFBE8113FFBB7E10FFBA7D0FFFBD8012FFC28517FFC48719FF
+ BF8214FFBA7D0FFFB97C0EFFBA7D0FFFBD8012FFBE8113FFBE8113FFBD8012FF
+ BA7D0FFFB97C0EFFBB7E10FFBC7F11FFBD8110FFBE8211FFBF8311FFBE8210FF
+ BC810DFFBB800CFFBC810DFFBB800CFFBA7E0CFFB97D0BFFB97D0CFFBA7E0DFF
+ BB7E10FFBC800FFFBB800CFFBB810AFFBB7F0DFFBB7F0DFFBB7E10FFBB7E10FF
+ BB7D13FFBB7D13FFBD7F15FFC38519FFC38519FFAA6D0FFFA86B0DFFA96C0EFF
+ AE7113FFAF7313FFAB6F0FFFAA6E0EFFAD7111FFB17613FFAF7411FFAD720FFF
+ AD720FFFAF7410FFB17612FFB07511FFAE730FFFB2740EFFB1730DFFB2740EFF
+ B57711FFB97B15FFBA7C16FFB97B15FFB67812FFBC7E18FFBB7D17FFB97B15FF
+ B87A14FFB77913FFB77913FFB77913FFB77913FFB67911FFB77A12FFB67812FF
+ B3750FFFB57711FFB97B15FFB77915FFB27410FFB67814FFB47612FFB57614FF
+ BA7B19FFBB7C1AFFB77816FFB67617FFB67B18FFA97812FFAF7E18FFB97D1DFF
+ BD7F21FFBF8024FFA9752EFF8C6D4CFF756F7AFF677CB9FF5E82D6FF5E81D1FF
+ 405DA8FF435396FF2E3262FF27202DFF403325FF372207FF684813FFA77218FF
+ B4780EFFAC730AFFB0822EFF998252FF6D6655FF4C5461FF5E7498FF658AC2FF
+ 5C8CD4FF598FE4FF5A90E7FF5180D2FF4F6BB2FF55578DFF5B4960FF6A4F3AFF
+ 8E692DFFA97A1EFFB17D13FFAF7A12FFA9761AFFA67930FF8E6632FF815F42FF
+ 6A554DFF635F65FF758494FF8CADC0FFA4CCE8FF9EBCE5FF9DBAE7FF9FC3EBFF
+ A6C8F3FFA6C1F4FFBDCBF5FFB9B9C5FF82725BFF93702EFFA87318FFBE7A17FF
+ C97F19FFC17C1BFFBC7C27FFBE8742FFB8905CFFBEA583FFECDECBFFFFF7F0FF
+ ECEBEFFFE6E9F7FFEAEEFFFFE7EAF8FFE6E8F2FFF0F1F5FFF0F2F3FFEFF3F4FF
+ EEF2F3FFEEF1F6FFEDEFF7FFF1EEF7FFEEEDF6FFEEF0F8FFF1F4F9FFFBFAFCFF
+ F9F0ECFFD1BFAEFFAD916FFFAC834CFFAD7C32FFBC852AFFB87D19FFB87F16FF
+ BA8217FFB67D14FFB87F16FFBE831CFFBC7F17FFBB8012FFBC8211FFBA800FFF
+ B67C0BFFB57B0AFFB77D0CFFB77C0EFFB67B0DFFC3881AFFC08517FFBE8315FF
+ BC8113FFBC8113FFBC8113FFBC8114FFBC8113FFBA800FFFBA800FFFBA800FFF
+ B77D0CFFB47A09FFB4790BFFB67B0DFFB97E10FFB77C0EFFBB8013FFBC8114FF
+ B87D10FFB57A0DFFB77C0FFFBC8016FFC08518FFBA7D0FFFBB7E10FFBC7F11FF
+ BD8012FFBD8012FFBC7F11FFBC800FFFBB7F0EFFBB7F0DFFBB7F0DFFBA7E0CFF
+ BA7E0CFFBA7F0BFFBA7F0BFFBB800CFFBB800CFFBB7D0BFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBB7D0BFFBC7E0CFFBE800EFFBF810FFFBE800EFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBE800EFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBE830FFFBC810DFFBA7F0BFF
+ BB800CFFBC800EFFBD810FFFBB7F0DFFB97D0BFFBA7E0DFFC08413FFC28517FF
+ BE8113FFBC7F11FFBD8012FFBE8113FFBB7E10FFBF8214FFBC7F11FFBB7E10FF
+ BD8012FFC08315FFC18416FFBF8214FFBB7E10FFB97C0EFFBA7D0FFFBD8012FF
+ BE8113FFBE8113FFBD8012FFBA7D0FFFB97C0EFFBC7F11FFBC7F11FFBD8110FF
+ BD8110FFBD810FFFBD810FFFBC810DFFBC810DFFBC810DFFBB800CFFBA7E0CFF
+ B97D0BFFB97D0CFFBA7E0DFFBB7E10FFBC800FFFBB800CFFBB800CFFBB7F0DFF
+ BB7F0DFFBB7F0EFFBB7E10FFBB7D11FFBB7D11FFB97B11FFB7790DFFB77A0CFF
+ AB6E11FFA96C0FFFAA6D0FFFAE7113FFAE7113FFAC6F11FFAB6F0FFFAD7111FF
+ B07414FFAF7313FFAE7310FFAF7411FFB07512FFB07512FFAF7411FFAD720EFF
+ B2740EFFB2740EFFB2740EFFB57711FFB77913FFB97B15FFB87A14FFB77913FF
+ BB7D17FFBA7C16FFB97B15FFB87A14FFB87A14FFB97B15FFBA7C16FFBB7D17FF
+ B3760EFFB57810FFB47610FFB1730DFFB3750FFFB87A14FFB77915FFB1730FFF
+ B57713FFB57713FFB77816FFBB7C1AFFBA7B19FFB57614FFB27213FFAF7411FF
+ A5710CFFAE7A15FFB87B19FFB9791AFFB67519FFA36B1EFF906838FF7C6E68FF
+ 6D7DB2FF5F80D0FF5E81D1FF4966B1FF4A569CFF343464FF281C28FF432E18FF
+ 573805FF896116FFB2791CFFB47610FFB57B12FFC08B2AFFB28738FF8F6F34FF
+ 6E5737FF665E57FF667389FF6788B6FF608FD3FF568BDCFF4F7FD7FF4B71C9FF
+ 455CAAFF444F88FF4D4D65FF6F6359FF92784AFF9E762EFFA8761EFFBF8526FF
+ C4852BFFAF701FFFA66D28FF996A34FF84653EFF857459FF8D8D7BFF969E9DFF
+ ABB9D0FFAABDDEFFA6C1DCFF9DB9D7FF97ACD2FF9FADCAFF999A9EFF77694DFF
+ 967334FFB27E2BFFC27F23FFC47B1FFFBE7922FFB77C2DFFB38341FFAD8D5CFF
+ E3D2B8FFF7F1E6FFFBF7F6FFEAEAF0FFE8EBF9FFE9EEFDFFE6EAF5FFE6E9F1FF
+ EFF2F6FFF0F4F5FFF0F5F4FFF0F4F5FFEFF2F6FFECEFF4FFEDEBF1FFE9E8F1FF
+ F5F7FFFFF2F1F5FFFBF4F1FFE5D5C8FFBCA486FFB69466FFB58949FFAB7625FF
+ C38A2DFFBA7F1BFFB67D14FFB78017FFB47D14FFB47B12FFB97F16FFBC8218FF
+ BD8214FFBA800FFFB97F0EFFBA800FFFB97E10FFB77C0EFFB77C0EFFB97E10FF
+ C4891CFFBD8215FFB67B0EFFB4790CFFB67B0EFFB87D10FFB67A10FFB4790CFF
+ C18618FFBF8416FFBC8113FFB77C0EFFB3780AFFB2770AFFB4790CFFB67B0EFF
+ B67B0EFFBE8218FFC0841AFFB97D13FFB3770DFFB77B11FFBD8018FFBE8218FF
+ B7790DFFB87B0DFFBA7D0FFFBC7F11FFBC7F11FFBC7F11FFBC800FFFBB7F0EFF
+ B97D0BFFB97D0BFFBA7E0CFFBA7E0CFFBA7F0BFFBA7F0BFFB97E0AFFB97E0AFF
+ BB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBE800EFFBD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BC810DFFBB800CFFBA7F0BFFBB800CFFBC800EFFBD810FFFBC800EFFBB7F0DFF
+ B97D0CFFBD8110FFBF8214FFBD8012FFBC7F11FFBE8113FFBE8113FFBD8012FF
+ BF8214FFBE8113FFBD8012FFBC7F11FFBD8012FFBE8113FFBD8012FFBD8012FF
+ B97C0EFFBB7E10FFBC7F11FFBE8113FFBE8113FFBC7F11FFBB7E10FFB97C0EFF
+ BD8012FFBD8012FFBC800FFFBC800FFFBB7F0DFFBC800EFFBC810DFFBD820EFF
+ BB800CFFBB800CFFBA7E0CFFB97D0BFFB97D0CFFBA7E0DFFBB7E10FFBB7F0EFF
+ BB7F0DFFBB7F0DFFBB7F0DFFBB7F0DFFBB7F0EFFBB7E10FFBB7E10FFBB7E10FF
+ C08216FFB5780AFFB5780AFFAC6F12FFAB6E11FFAC6F11FFAD7012FFAD7012FF
+ AC6F11FFAC7010FFAD7111FFAC7010FFAD7111FFAE7310FFB07512FFB17613FF
+ B17613FFB07512FFAE730FFFB27410FFB2740EFFB3750FFFB47610FFB67812FF
+ B77913FFB77913FFB77913FFBA7C16FFB97B15FFB87A14FFB77913FFB77913FF
+ B87A14FFB87A14FFB97B15FFB3760EFFB57810FFB47610FFB2740EFFB47610FF
+ B97B15FFB87A16FFB37511FFB57713FFB57713FFB77816FFB97A18FFB87917FF
+ B57614FFB37314FFB07311FFAC770FFFB17A12FFB47612FFB37210FFB37013FF
+ A86C1AFF9E6F31FF8D7765FF6B77A7FF6081D1FF5B80D0FF415FACFF404E96FF
+ 3C396BFF2E202CFF42270CFF835C17FFA27115FFB47719FFBB7A18FFC07F1CFF
+ BC7E1AFFB07616FFAA751EFFA1732CFF7B5B2AFF675D4BFF6D7985FF6888B1FF
+ 5F89CAFF537DD0FF446EC7FF365DB2FF3A5AA5FF435790FF515977FF625D5CFF
+ 776145FF926A35FFA7732CFFBF8030FFBD7A25FFC27F2AFFB97C2CFFA37129FF
+ 9B7338FF967547FF816C4DFF94877FFF958F90FF92928CFF868581FF7B777CFF
+ 7D7575FF83755FFF866D41FF9C742CFFB78330FFC88633FFC88333FFBE8034FF
+ AE7B35FFB18B51FFC0A87EFFF5EDDCFFF6F5F1FFF2F1F3FFE8EBF0FFEEF0FAFF
+ EEF2FDFFEBEDF7FFECEFF7FFEDF2F5FFEEF2F3FFEEF3F2FFEDF2F1FFECF0F1FF
+ EBECF0FFE9EAEEFFEAE8EEFFE7E6EFFFF3EEF0FFFBEFE5FFC8B299FFA07E53FF
+ AC8345FFB9873BFFBF8A30FFC28828FFB77C18FFB37C14FFBB841BFFBA831AFF
+ B47B12FFB57B11FFBA8114FFBF8416FFB97F0EFFB97F0EFFBD8312FFBC8113FF
+ B77C0EFFB77C0EFFBC8113FFC3881BFFBF8417FFBA7F12FFB97D13FFBA7E14FF
+ BB7F15FFBA7D15FFB97D13FFC08518FFBF8416FFBD8215FFBA7F12FFB87D10FF
+ B77C0FFFB87D10FFB87C12FFBD8117FFC2861CFFC0831BFFB97C14FFB77A12FF
+ BD8018FFBE801AFFB87B13FFBB7D11FFB97C0EFFB87B0DFFB6790BFFB77A0CFF
+ B97C0EFFBC800FFFBD8110FFB77B09FFB87C0AFFBA7E0CFFBB7F0DFFBB800CFF
+ BA7F0BFFB87D09FFB77C08FFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBE800EFF
+ BD7F0DFFBB7D0BFFBA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBA7F0BFFBA7F0BFFBA7F0BFFBB800CFFBC800EFF
+ BD810FFFBD810FFFBD810FFFBA7E0DFFBC800FFFBC7F11FFBC7F11FFBC7F11FF
+ BD8012FFBD8012FFBD8012FFC08315FFBF8214FFBE8113FFBC7F11FFBB7E10FF
+ BB7E10FFBC7F11FFBE8113FFBA7D0FFFBB7E10FFBC7F11FFBD8012FFBD8012FF
+ BC7F11FFBB7E10FFBA7D0FFFBE8113FFBD8012FFBC800FFFBA7E0DFFBA7E0CFF
+ BB7F0DFFBC810DFFBD820EFFBB800CFFBA7F0BFFBA7E0CFFBA7E0CFFBA7E0DFF
+ BA7E0DFFBA7D0FFFBB7E10FFBB7F0EFFBB7F0DFFBB7F0DFFBB7F0DFFBB7F0EFF
+ BB7F0EFFBB7F0EFFBB7F0EFFC5881AFFB97D0CFFB97D0CFFAD7013FFAE7114FF
+ AD7013FFAC6F12FFAC6F11FFAD7012FFAD7012FFAC6F11FFA96D0DFFAB6F0FFF
+ AE7212FFB07414FFB17613FFB27714FFB27714FFB27713FFB27410FFB3750FFF
+ B3750FFFB47610FFB47610FFB57711FFB67812FFB77913FFB97B15FFB87A14FF
+ B77913FFB57711FFB47610FFB47610FFB47610FFB57711FFB57810FFB77A12FF
+ B67812FFB47610FFB67812FFBB7D17FFBA7C18FFB57713FFB57713FFB67814FF
+ B67715FFB67715FFB67715FFB77816FFB87819FFB57816FFB97F18FFB87F16FF
+ B67512FFB77312FFBC771AFFB4741FFFAB762DFF96795AFF757CA7FF607FCEFF
+ 5076C8FF3255A5FF323F8DFF3A376FFF372634FF4D3011FF9B6E1DFFAD760EFF
+ B07011FFBA7518FFC17C1FFFB87312FFB47007FFBF7D14FFBC7E18FFA4721AFF
+ 896829FF736646FF677074FF6D85A9FF6783C3FF466CBAFF4B7CC8FF4B7CC8FF
+ 5274C0FF455D9FFF454F7EFF6C6982FF8F7D7CFF907059FF9C6F44FFA56E31FF
+ B27426FFBE7E26FFBE8026FFBE822EFFB9813AFFAB7539FFA5733FFFA67642FF
+ A5793AFFA07435FF9D6D39FF996A34FFA17333FFB6883BFFBB8931FFB68127FF
+ BF8435FFD19651FFBF8E50FF9D763FFFB29869FFEBDEBEFFF9F8EEFFEFF3F4FF
+ EBEDEEFFEBECF0FFF3F3F9FFF1F4F9FFECEFF7FFEDF1F6FFEBF0F3FFEAEFF0FF
+ EAEFEEFFE8EDECFFEAECECFFEAECEDFFEAEBEFFFEDEBF1FFF3EFF5FFFFF7F7FF
+ F6E2D0FFBE9E7AFFAC8148FFBE8D43FFC38D36FFD09839FFBF8623FFB57D18FF
+ B17914FFB88119FFBC831AFFB57D12FFB57C0FFFBD8516FFBE8315FFB97E10FF
+ B97E10FFBE8315FFBD8215FFB87D10FFB87D10FFBC8114FFB87C12FFBA7E14FF
+ BC8016FFBB7E16FFB97C14FFB87B13FFBA7C16FFBC7F17FFB67A10FFB77C0FFF
+ B77B11FFB97D13FFBB7F15FFBC8016FFBC8016FFBC7F17FFBB7E16FFBD8018FF
+ BC7E18FFB77913FFB87A14FFBC7E18FFBC7E1AFFB87B13FFBC7E12FFBB7E10FF
+ B97C0EFFB77A0CFFB77A0CFFB77A0CFFB97D0CFFBA7E0DFFB77B09FFB87C0AFF
+ BA7E0CFFBB7F0DFFBB800CFFBA7F0BFFB87D09FFB77C08FFBD7F0DFFBD7F0DFF
+ BE800EFFBE800EFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFB97B09FFBA7C0AFF
+ BC7E0CFFBE800EFFBE800EFFBE800EFFBD7F0DFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBA7F0BFFBA7F0BFF
+ BB800CFFBB800CFFBC800EFFBC800EFFBD810FFFBD810FFFBD8110FFBB7F0EFF
+ BB7E10FFBB7E10FFBB7E10FFBA7D0FFFBA7D0FFFBA7D0FFFBF8214FFBF8214FF
+ BD8012FFBB7E10FFBA7D0FFFBA7D0FFFBC7F11FFBD8012FFBB7E10FFBB7E10FF
+ BC7F11FFBC7F11FFBC7F11FFBC7F11FFBB7E10FFBB7E10FFBF8214FFBD8012FF
+ BB7F0EFFBA7E0DFFB97D0BFFBA7E0CFFBB800CFFBB800CFFBA7F0BFFBA7F0BFF
+ BA7E0CFFBB7F0DFFBB7F0EFFBA7E0DFFBA7D0FFFBA7D0FFFBA7D0FFFBA7E0DFF
+ BA7E0DFFBA7E0DFFBA7E0CFFBA7E0CFFBA7E0CFFBA7E0CFFBC800FFFB67A08FF
+ B67A08FFAE7114FFB07316FFAF7215FFAB6E11FFAB6E10FFAD7012FFAE7113FF
+ AC6F11FFA96D0DFFAC7010FFAE7212FFB07414FFB07512FFB07512FFB27714FF
+ B37814FFB27410FFB3750FFFB47610FFB3750FFFB3750FFFB3750FFFB57711FF
+ B77913FFB87A14FFB77913FFB57711FFB47610FFB3750FFFB3750FFFB3750FFF
+ B3750FFFB77A12FFB87B13FFB77913FFB57711FFB77913FFBB7D17FFBA7C18FF
+ B57713FFB67814FFB87A16FFB87917FFB67715FFB77816FFBB7C1AFFBD7D1EFF
+ BB7C1AFFB67C13FFB67C13FFB67512FFB77614FFBE791CFFB3741AFFA86E1CFF
+ 8F6C44FF757CA3FF5977C8FF4670C3FF385DB1FF344699FF3D3C7AFF3A293EFF
+ 58371DFFA27121FFB77D14FFB57314FFB57013FFBA7419FFB87312FFB57108FF
+ BC7A0AFFC17F0EFFB5790FFFA87519FF916E2CFF786647FF6C6C6CFF6D7898FF
+ 607FB4FF497CBBFF487FC8FF567FCEFF4E6CB9FF5C72B3FF9DABDBFFC8CCE9FF
+ BAB2BDFFA28882FFA1795CFFA36F33FFB97F2DFFC88B2BFFC0811FFFBC7A27FF
+ BD7B2DFFBF7D2FFFBA7A26FFBD7D1FFFC27F22FFC68131FFC17E2FFFBE7E29FF
+ CC9336FFC38C2BFFBB862BFFBD863BFFC28F51FFB78C59FFAF8F64FFD1BE9DFF
+ FFFBE8FFF2F7F5FFE9F2F6FFEAEDF1FFEDEFF0FFF5F2F4FFF1F0F2FFEBEEF2FF
+ EAEEF3FFE9F0F3FFE7EEF1FFE8EEEDFFE8EDECFFEAECECFFEBEDEDFFEDEFF0FF
+ F0EFF3FFFAF4F9FFF8E9E6FFD8BDA3FFAF8959FFBA8741FFC68D37FFBB7F1FFF
+ BB7F1BFFC38824FFB9811CFFAF7712FFB07911FFB77F14FFB57D0EFFB67E0DFF
+ C38A17FFBB8012FFBA7F11FFBA7F11FFBD8214FFBD8215FFBA7F12FFB97E11FF
+ BA7F12FFAE7208FFB4780EFFB87B13FFB97C14FFB67812FFB57711FFB87A14FF
+ BC7E18FFB97C14FFB77B11FFB67A10FFB67A10FFB67A10FFB77A12FFB57810FF
+ B4770FFFB3750FFFB57711FFB77913FFB77913FFB67814FFB67814FFB97B17FF
+ BC7E18FFB87A0EFFBA7D0FFFBC7F11FFBD8012FFBC7F11FFB97C0EFFB67A09FF
+ B47807FFB97D0BFFB97D0BFFBA7E0CFFBA7E0CFFBA7F0BFFBA7F0BFFB97E0AFF
+ B97E0AFFBD7F0DFFBD7F0DFFBE800EFFBF810FFFBF810FFFBF810FFFBE800EFF
+ BE800EFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFFBE800EFF
+ BE800EFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBA7F0BFFBB800CFFBC810DFFBC810DFFBB7F0DFFBB7F0DFFBC800EFF
+ BD810FFFBE8211FFBA7E0DFFB87B0DFFBA7D0FFFBB7E10FFB97C0EFFB97C0EFF
+ BA7D0FFFBE8113FFBD8012FFBB7E10FFBB7E10FFBC7F11FFBC7F11FFBC7F11FF
+ BB7E10FFBB7E10FFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBB7E10FF
+ BB7E10FFBE8113FFBD8012FFBC800FFFBB7F0EFFBA7E0CFFB97D0BFFB97E0AFF
+ B97E0AFFB97E0AFFBA7F0BFFBB7F0DFFBB7F0DFFBB7F0EFFBB7F0EFFBA7D0FFF
+ B97C0EFFBA7D0FFFBA7D0FFFBA7D0FFFBA7E0DFFBA7E0CFFBA7E0CFFBA7E0CFF
+ BA7F0BFFB77B09FFB67A08FFB67A08FFAF7215FFB17417FFB07316FFAB6E11FF
+ AA6D10FFAE7114FFAF7214FFAC6F11FFAD7012FFAF7214FFB07414FFAF7313FF
+ AD720FFFAD720FFFB07512FFB27713FFB27410FFB47610FFB47610FFB3750FFF
+ B1730DFFB2740EFFB57711FFB77913FFB77913FFB67812FFB57711FFB57711FF
+ B47610FFB57711FFB67812FFB77913FFB67911FFB87B13FFB67812FFB3750FFF
+ B57711FFB97B15FFB87A16FFB27410FFB77915FFBB7D19FFBC7D1BFFBA7B19FF
+ BB7C1AFFBF801EFFBF7F20FFBB7C1AFFB3750FFFB77913FFB67715FFB77718FF
+ BB781CFFAF7016FFA86E15FF906E40FF70769BFF5878CBFF4977CFFF3F68C4FF
+ 3C51ACFF4C4E94FF43344FFF583825FFA3722EFFB97C1FFFBC791CFFBA7617FF
+ BA7518FFB47415FFAD7411FFAE7611FFB67C12FFB5770BFFB8760FFFB87A20FF
+ 9F6F2DFF7C5D36FF71685BFF738394FF5784B7FF588DD0FF688FD4FF6887C6FF
+ 7996C9FFACC5EFFFBCD6FBFFABBDDCFFB3B4CEFFAB9CA0FF967254FF9D6E30FF
+ B47F25FFB37919FFB07420FFB37828FFB27924FFAF781DFFB87F1CFFBC7F21FF
+ C38031FFC27F34FFB67726FFBB8227FFAD7915FFB38022FFB68236FFB08144FF
+ B99265FFDBBFA1FFF9E9D9FFFDF8F5FFEAF3F7FFE5F0F8FFECF1F4FFF1F1F1FF
+ F3EFEEFFF1EDECFFECEEEFFFEBF0F3FFE9F2F6FFE8F1F4FFECF2F1FFEDF2F0FF
+ EFF2F0FFF1F2F0FFEFF1F2FFF3F0F2FFF7EEF1FFF3E0D9FFD5B493FFBC8F56FF
+ B98130FFB37616FFB97A12FFC18319FFC18720FFBD8520FFB37B16FFB0760FFF
+ B77E11FFB87E0DFFB77E0AFFBE8511FFB77D0CFFBA7F11FFBB8013FFBA7F12FF
+ BA7F12FFBC8114FFBB7F15FFB87C12FFBB7E16FFBC7F17FFBD7F19FFBE801AFF
+ BF811DFFC0821EFFC28420FFC48622FFC2851DFFBD8018FFB77A12FFB57810FF
+ B57810FFB77913FFB87A14FFB87A14FFBD7F1BFFB77915FFB77915FFBC7E1AFF
+ BC7D1BFFB67715FFB67715FFBB7D17FFB6780CFFB87B0DFFBC7F11FFBE8113FF
+ BD8012FFBB7E10FFB87C0BFFB57908FFBB7F0DFFBB7F0DFFBA7E0CFFBA7E0CFF
+ BA7F0BFFBA7F0BFFBB800CFFBB800CFFB97B09FFBA7C0AFFBC7E0CFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBD7F0DFFC08210FFBF810FFFBE800EFFBC7E0CFF
+ BB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBE800EFFBB800CFFBC810DFFBE830FFFBD820EFF
+ BA7E0CFFB97D0BFFBB7F0DFFBC800EFFBD8110FFB77B0AFFB5780AFFB97C0EFF
+ BB7E10FFBA7D0FFFB97C0EFFBC7F11FFBD8012FFBA7D0FFFB97C0EFFBB7E10FF
+ BE8113FFBF8214FFBD8012FFB97C0EFFBC7F11FFBC7F11FFBB7E10FFBB7E10FF
+ BB7E10FFBB7E10FFBC7F11FFBC7F11FFBC7F11FFBC7F11FFBC800FFFBC800FFF
+ BB7F0DFFB97D0BFFB87D09FFB77C08FFB97E0AFFBA7F0BFFBB7F0DFFBC800EFF
+ BC800FFFBB7F0EFFBA7D0FFFB97C0EFFB97B0FFFB97B0FFFB97C0EFFB97D0CFF
+ B97D0BFFB97D0BFFB97E0AFFB97F08FFB97E0AFFB97E0AFFB97D0BFFAF7215FF
+ B27518FFB07316FFAA6D10FFAA6D10FFAE7114FFAF7214FFAC6F11FFB17416FF
+ B27517FFB27616FFAF7313FFAC7010FFAB700DFFAD720FFFB17412FFB07410FF
+ B27710FFB47612FFB1760FFFB1730FFFAF740DFFB47612FFB57A13FFB67814FF
+ B47912FFB57713FFB47912FFB77915FFB67B14FFBA7C18FFB97E17FFB67812FF
+ B57A13FFB57711FFB0750EFFB37511FFB57915FFB57713FFAD710DFFB77915FF
+ BB7F1BFFC0811FFFBC7F1DFFBE7F1DFFBF8220FFBF7F20FFB97A18FFB97B17FF
+ BF811DFFC0811FFFBC7F1FFFBD7D1FFFB6781AFFB97D23FFAD8550FF7A788BFF
+ 7189C5FF5C84CFFF3E69BAFF3751A5FF5661A5FF4D4868FF523C31FF9C6F36FF
+ AC731EFFB6781EFFC08022FFBF7F20FFB47818FFB07918FFB67F1CFFAE750CFF
+ C08014FFC57D11FFBC740FFFB2711CFFA06C29FF8A6938FF756C58FF798D9EFF
+ 81A1C5FF90A9D5FF8EA7D3FF98B6DFFFA7CAF2FFA3C9F3FF9DBCE3FF9EADCEFF
+ A9A5B1FF93775FFF926630FFB5812EFFC2892CFFBA812CFFB17823FFAD781DFF
+ B27F1FFFC08B2AFFBC8328FFC08131FFC68638FFBF7F2AFFBE8326FFB27D1CFF
+ A9751BFFA67531FFB08554FFC4A382FFE5CFBDFFF6EAE4FFE9E8EAFFE4ECF3FF
+ E4EEF5FFEEF2F3FFF1F2F0FFF1EEEAFFEEEDE9FFEFF1F1FFEEF5F8FFEBF4F7FF
+ ECF5F8FFEFF7F7FFF2F7F6FFF4F6F6FFF2F4F4FFF0F2F3FFF6F1F0FFF7E5DAFF
+ DEC1A6FFB58D5DFFB1803AFFB77E23FFB87911FFC7871BFFC4861AFFBD831AFF
+ C18720FFBA8019FFB57C13FFBD8215FFBB8110FFB37A06FFB47B07FFB57B0AFF
+ BB8012FFBC8114FFB97E11FFB97E11FFBD8215FFBC8016FFB67A10FFC0841AFF
+ BB7E16FFB77A12FFB87B13FFBD7F19FFC1831DFFC28420FFC1831DFFC1841CFF
+ BB7F15FFB57810FFB57810FFBA7C16FFC3851FFFC98B25FFCD8F29FFD2942EFF
+ C0821CFFB97B15FFC2841EFFC68822FFBD7F1BFFB57713FFB57711FFB97B0FFF
+ B97C0EFFB97C0EFFB97C0EFFBA7D0FFFBB7E10FFBC800FFFBD8110FFBD8110FF
+ BC800EFFBB7F0EFFBA7E0CFFBA7E0CFFBB7F0DFFBC800EFFBD810FFFB67905FF
+ B87B07FFBA7D09FFBC7F0BFFBD800CFFBD7F0DFFBD7F0DFFBC7E0CFFC48614FF
+ C28412FFBF810FFFBC7E0CFFB97B09FFB87A08FFB87909FFB87A08FFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBB7F0DFF
+ BD820EFFBF8311FFBD810FFFBA7E0CFFB87C0AFFBA7E0CFFBC800EFFBB7F0EFF
+ B47807FFB27507FFB87B0DFFBB7E10FFBA7D0FFFBB7E10FFBE8113FFBC7F11FF
+ B97D0CFFB77A0CFFBB7F0EFFC08315FFC18514FFBD8012FFB87C0BFFBC7F11FF
+ BC800FFFBB7E10FFBB7F0EFFBB7E10FFBB7F0EFFBC7F11FFBC800FFFBB7F0EFF
+ BC800FFFBD8110FFBD810FFFBB7F0DFFB97D0BFFB77C08FFB67B07FFB97E0AFF
+ BA7F0BFFBB7F0DFFBC800EFFBC800EFFBB7F0EFFBA7E0DFFB97D0CFFB97C0EFF
+ B97C0EFFB97D0CFFB97D0BFFB97D0BFFB97E0AFFB97F08FFB97F08FFBA8009FF
+ B77D06FFB77C08FFAD6E14FFAF7016FFB17218FFAF7016FFAC6D11FFAA6B0FFF
+ AC6D11FFAE6F13FFAD6F11FFAD6F11FFAD6F11FFAC6F0FFFAC6F0FFFAC6F0FFF
+ AB6E0EFFAB6E0CFFB07311FFAF7410FFB07311FFAF7410FFB27513FFB37814FF
+ B67917FFB77C18FFB47715FFB27713FFB17412FFB07511FFB27513FFB37814FF
+ B77A18FFB87D19FFB07410FFB37814FFB87C18FFB97E1AFFB87B19FFB57A17FF
+ B57816FFB57A17FFB97C1AFFBA7F1CFFBC7F1DFFB97E1BFFB77A18FFB37815FF
+ B57816FFB67919FFB9791BFFBA7A1CFFB87B1BFFB67B17FFB67B14FFB87C18FF
+ B97E21FFA97B3BFF836D5BFF8E90A2FF7C95C1FF5F83BFFF7699D9FF9AB5EEFF
+ 8D9AC0FF736C6FFF805D2BFF9B6A1CFFAD7724FFAE761DFFB57E1DFFBD821EFF
+ B57B14FFBE8119FFBA7910FFC9871EFFC9811BFFBB7412FFB97619FFB37620FF
+ AB7324FFA37839FF88714BFF887F71FFA0A1A5FFAAB9CCFF9DBBDEFF9CC2ECFF
+ A3CAF6FFABCBEEFFAFBDCFFF87817AFF7B5F3CFF9A6E31FFB77F30FFC2832BFF
+ C08028FFBB7D23FFAE7617FFBE8829FFC79238FFC18833FFC58937FFBF822CFF
+ B37314FFC18422FFC18629FFBB8538FFB48450FFBC9676FFDAC1B1FFF8EDE5FF
+ F7F7F1FFE5E9E4FFECEEEEFFF0F0F0FFF3F4F2FFF3F7F2FFF4F8F3FFF1F7F2FF
+ EEF4F3FFE9F3F3FFECF5F8FFE6EFF2FFEBF1F6FFF1F6F9FFF1F4F8FFE8EBEFFF
+ E8EBEFFFFFFCF2FFF4D4ABFFC09356FFA17228FFB07D27FFB7801FFFB77D14FF
+ BD8215FFBE8113FFBB8013FFB97D13FFBB7F15FFC2861CFFC18619FFBB8012FF
+ B97F0EFFBD8312FFBE8315FFC28418FFC38519FFBF8115FFB97B0FFFB7790DFF
+ BB7D11FFBF8115FFC18317FFBD7F15FFB97B11FFB97B11FFBB7D13FFBE8016FF
+ BE8016FFBE8016FFBB7D11FFBB7D11FFBB7D13FFBB7C14FFBC7C16FFBE7E18FF
+ C0801AFFC2831BFFBA7C12FFBD7F13FFBF8115FFBE8014FFBB7D13FFB87911FF
+ B67610FFB6770FFFC38317FFBA7B0DFFB97A0CFFBA7B0DFFB8790BFFBC7D0FFF
+ C08113FFBB7C0EFFBE7F11FFBE7F0FFFBD7E10FFBD7E0EFFBD7E0EFFBC7D0DFF
+ BC7D0DFFBC7E0CFFBB7E0AFFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7D0BFFBD7F0DFFBE7F0FFFC08111FFC18212FFC08111FF
+ BF8012FFBF8010FFC08210FFBD7F0DFFB97B09FFB97B09FFBA7C0AFFBC7E0CFF
+ BB7D0BFFB97B09FFC08210FFBE800EFFBC7E0CFFBA7C0AFFB97B09FFBB7D0BFF
+ BD7F0DFFBE800EFFBB7D0BFFBB7D0BFFBB7C0CFFBC7D0DFFBD7E0EFFBD7E0EFF
+ BE7F0FFFBE7F0FFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBB7C0CFFBB7D0BFFBB7C0CFFBB7D0BFFBB7C0CFFBB7D0BFF
+ BB7C0CFFBB7D0BFFBC7D0DFFBC7E0CFFBC7D0DFFBC7E0CFFBC7D0DFFBC7E0CFF
+ BC7D0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7F0BFFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBF820EFFC0830FFFC38612FFC48713FFC48713FFC38513FF
+ C08210FFBF820EFFBC7F0BFFBC7F0BFFBC7F09FFBB7E08FFBB7E08FFBA7D07FF
+ BA7E06FFBA7E06FFBB7F07FFBB7F07FFBB7E08FFAD6E14FFAE6F15FFB07117FF
+ AF7016FFAC6D11FFAB6C10FFAD6E12FFAE6F13FFAC6E10FFAC6E10FFAD6F11FF
+ AE7012FFAF7212FFB17414FFB27515FFB27515FFB47916FFB37815FFB27714FF
+ B07512FFB07512FFB07512FFB17613FFB17613FFAF7411FFB07512FFB27714FF
+ B47916FFB57A17FFB67B18FFB67B18FFB67B18FFB77C19FFB97E1BFFBB801DFF
+ BA7F1CFFB87D1AFFB67B18FFB77C19FFB87D1AFFAE7310FFB27714FFB67B18FF
+ B77C19FFB57A17FFB27714FFB07512FFB07313FFB8771BFFB7781CFFB47A1AFF
+ B37B16FFB57B12FFB67B14FFB77C1FFFAE7B32FF8F6D42FF9D9185FFA0AEC1FF
+ 9DB9E2FFA8C9FAFFB5D5FFFFB1C8EEFFB5B7BFFF937348FF99671FFFA67225FF
+ B17B26FFB37D1EFFB78018FFB5790FFFB7770BFFB8770BFFBE7A11FFC37E17FF
+ C17D1AFFBE7A19FFBF7D1EFFC48223FFBD8128FFA4722AFF96703AFF907959FF
+ 8B8376FF7E868DFF7F8FA0FF8A9AABFF8F9AA2FF858077FF7B6748FF85602CFF
+ A2712BFFB67B2BFFBD7E24FFB9781CFFAD7010FFBE8424FFB47E20FFAD7621FF
+ AD7524FFC48A38FFCF933AFFC18220FFC08323FFC78C36FFB47F3CFFBA9066FF
+ DDBDAAFFF1E1DBFFF5F0EFFFEFF5F0FFF0F6F1FFF1EFEEFFF1EDECFFEBECEAFF
+ E7EBE6FFE5EBE6FFE5ECE7FFE6EFECFFE7EFEEFFE8F2F2FFEEF5F8FFEBEFF4FF
+ ECEFF4FFF1F2F6FFFFFEFFFFFFFFFFFFF2E3D0FFDCB47AFFC08B3BFFB17C25FF
+ BD892BFFBB8520FFB57D12FFB57C0FFFB4790BFFBA7D0FFFB97B0FFFBB7D13FF
+ BE8016FFBB8013FFB87D10FFB37B0CFFB47C0DFFBC7E12FFBF8115FFC18317FF
+ BE8014FFB97B0FFFB87A0EFFBC7E12FFC08216FFC18317FFBD7F13FFBA7C10FF
+ B97B0FFFBB7D11FFBD7F13FFBE8014FFBD8012FFB97D0CFFB87C0BFFB87A0EFF
+ B97B11FFBB7B15FFBD7D17FFBF8018FFC08218FFB7790DFFBA7E0DFFBC800FFF
+ BB7F0EFFB97C0EFFB87A0EFFB97A12FFBA7B13FFC48418FFBE7F11FFBE7F11FF
+ BF8012FFBC7D0FFFC08113FFC58618FFC18214FFBC7D0FFFBB7C0EFFBB7C0EFF
+ BA7B0DFFB97A0CFFB8790BFFB8790BFFB77808FFBB7E08FFBB7F07FFBB7F07FF
+ BB7F07FFBB7E08FFBB7E08FFBB7E0AFFBB7E0AFFBB7D0BFFBC7E0CFFBD7E0EFF
+ BF8010FFBF8012FFBF8012FFBE7F11FFBE7F0FFFBF8010FFBD7F0DFFBB7D0BFF
+ BA7C0AFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBA7C0AFFB97B09FF
+ B97B09FFBA7C0AFFBD7F0DFFC08210FFC28412FFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBE800EFFBE800EFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBE800EFFBE800EFFBF820EFFBF820EFFBE810DFF
+ BD800CFFBC7F0BFFBA7D09FFBA7D09FFB97C08FFBB7E0AFFBC7F0BFFBD800CFF
+ BE810DFFBE810DFFBD800CFFBC7F0BFFBB7E0AFFBC7F09FFBC7F09FFBC7F09FF
+ BB7E08FFBB7E08FFBA7D07FFBA7D07FFBA7D07FFBB7E08FFBB7E08FFBB7E08FF
+ AB6D13FFAC6E14FFAD6F15FFAD6F15FFAC6E14FFAC6E14FFAD7013FFAE7114FF
+ AD7012FFAE7113FFAF7214FFB07315FFB17515FFB27616FFB37717FFB47818FF
+ B57A17FFB47916FFB37815FFB17613FFB07512FFB07512FFB07512FFB07512FF
+ B07512FFB27714FFB67B18FFB87D1AFFB97E1BFFB67B18FFB37815FFB17613FF
+ BA7F1CFFBB801DFFBA7F1CFFB87D1AFFB67B18FFB57A17FFB77C19FFB87D1AFF
+ B87D1AFFBB801DFFBE8320FFBE8320FFBB801DFFB87D1AFFB57A17FFB47818FF
+ B7791BFFB77A1DFFB37B1CFFAF7B17FFB17A12FFB37912FFB77B1BFFAF7A29FF
+ A27D45FF9E8B70FFABAEB2FFC0D1EBFFC2DCFFFFB9D6FDFFB4CAEDFFC4C6CEFF
+ B28E68FF9E6827FFA56E25FFB67E2CFFB57C1FFFBA8019FFB97E11FFB97A0AFF
+ BA7A0AFFB37205FFBE7D11FFC8851EFFC07D1AFFC1801EFFC68725FFBD8022FF
+ BD832AFFAF7A2AFFA27532FF99723BFF917043FF90734EFF947653FF94734CFF
+ 9B7343FFA2743AFFAF7B34FFB77F2DFFBB7F25FFBF8220FFC1831DFFB87D16FF
+ B9801DFFBA8426FFC38C37FFB98130FFB27727FFB37723FFB87A20FFC78D34FF
+ B68033FFAB7E41FFC8A583FFF6DFCFFFFEF2F0FFEFECEEFFE9EEEDFFECF3F0FF
+ F7F7F7FFF6F4F4FFF0F1EFFFEAEEE9FFE8EEE9FFE9EFEAFFEBF2EDFFEDF4F1FF
+ E6EEEEFFEEF5F8FFEAEEF3FFE8EBEFFFECEAEAFFFCF6F1FFF2E9DCFFBAA586FF
+ B78B4CFFB17B28FFB47F25FFC18B2CFFBD861EFFB57D12FFB57C0FFFB4790BFF
+ B87A0EFFBB7D11FFBB7D13FFBA7C12FFB87C12FFB97E11FFB47C0DFFB07809FF
+ B97B0FFFBC7E12FFBE8014FFBC7E12FFB97B0FFFB97B0FFFBD7F13FFC08216FF
+ BF8115FFBD7F13FFBA7C10FFB97B0FFFBB7D11FFBD7F13FFBD7F13FFBD8012FF
+ B77B0AFFB77B0AFFB7790DFFB87A10FFBA7B13FFBB7C14FFBD7E16FFBE8014FF
+ B6790BFFB77B0AFFB97D0CFFB87C0BFFB87B0DFFB87A0EFFBB7C14FFBE8016FF
+ BD7D11FFB97A0CFFBC7D0FFFBD7E10FFB8790BFFBB7C0EFFC18214FFC08113FF
+ BD7E10FFBC7D0FFFBB7C0EFFBA7B0DFFB97A0CFFB8790BFFB7780AFFB77808FF
+ BB7E08FFBB7F07FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E0AFFBB7E0AFF
+ BB7D0BFFBB7D0BFFBC7D0DFFBD7E0EFFBE7F0FFFBD7E0EFFBD7E10FFBD7E0EFF
+ BE7F0FFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFF
+ BB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFC08210FFC28412FF
+ BD7E0EFFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BF810FFFBF810FFFBF810FFFBF810FFFBF810FFFBF810FFFBF810FFFBF810FFF
+ B97C08FFBA7D09FFBB7E0AFFBC7F0BFFBD800CFFBE810DFFBF820EFFBF820EFF
+ BA7D09FFBA7D09FFBA7D09FFBB7E0AFFBB7E0AFFBA7D09FFBA7D09FFBA7D09FF
+ BC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFFBA7D09FFBA7D09FFBA7D09FF
+ BA7D09FFBA7D09FFBA7D09FFAB6D13FFAB6D13FFAC6E14FFAC6E14FFAD6F15FF
+ AD6F15FFAE7114FFAE7114FFB27517FFB27517FFB17416FFB17416FFB17515FF
+ B07414FFB07414FFB07414FFB17515FFB17613FFB17613FFB17613FFB17613FF
+ B27714FFB27714FFB27714FFB57A17FFB77C19FFB97E1BFFBA7F1CFFB97E1BFF
+ B57A17FFB07512FFAD720FFFB57A17FFB57A17FFB57A17FFB57A17FFB47916FF
+ B47916FFB47916FFB57A17FFB77C19FFB87D1AFFB87D1AFFB77C19FFB77C19FF
+ B77C19FFB87D1AFFB97E1BFFB97D1DFFB77D1EFFB27C1DFFB07B1AFFAF7914FF
+ B27B13FFB77B17FFB37C21FF9E722BFF876938FF918370FFB5B5B5FFC9D2DFFF
+ C9D7E9FFC5CFE0FFCCC6C1FFB68E64FFA26B28FFA36A1FFFAD7523FFB07819FF
+ B77D16FFB97E11FFBD8110FFBE7F0FFFB67508FFBC7A11FFC5831CFFC07F1CFF
+ BB7C1AFFBB7E1EFFB97C1EFFBA7D20FFBA7E25FFBC802CFFBC8131FFB77D31FF
+ B47A32FFB27731FFB0752FFFB0752DFFB97F33FFBF8533FFBB8128FFB47A1BFF
+ B77C19FFBD831CFFBF851EFFC28B28FFBC8628FFC58E39FFC08837FFB87D2DFF
+ B57A2AFFAF7523FFB37E2EFFA97C39FFC29D6BFFECD4B8FFFFF5E9FFFBF5F6FF
+ F4F5F9FFF2F7F8FFEAEFF0FFF6F8F9FFF8F7F9FFF5F7F7FFF5F8F6FFF2F8F3FF
+ F2F9F2FFF2F9F2FFF2F7F5FFE4E9EAFFE4EBEEFFF0F4F9FFF5F7F8FFFCF6F1FF
+ FAEDDFFFD3BFA6FFA7875CFFA77630FFA9731CFFB17A1FFFBA8322FFB98017FF
+ B87F12FFBE8315FFBC8113FFB97B0FFFBD7F13FFBE8016FFB87C12FFBA7E14FF
+ BD8319FFBA8114FFB37A0DFFB67B0EFFBA7C10FFBC7E12FFBB7D11FFB97B0FFF
+ B97B0FFFBB7D11FFBE8014FFBE8014FFBC7E12FFBB7D11FFBA7C10FFBB7D11FF
+ BC7E12FFBC7E12FFBD8012FFBB7F0EFFBA7E0DFFBA7D0FFFBA7C10FFBA7C12FF
+ BB7D13FFBB7D13FFBB7D11FFB97D0CFFB97D0CFFB97D0BFFB87C0AFFB77B0AFF
+ B97C0EFFBD7F15FFC18319FFB8780CFFB67709FFBB7C0EFFBC7D0FFFB67709FF
+ B8790BFFBF8012FFBF8012FFBF8012FFBE7F11FFBE7F11FFBE7F11FFBE7F11FF
+ BD7E10FFBD7E10FFBD7E0EFFBB7E08FFBB7F07FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E0AFFBB7E0AFFBB7D0BFFBB7D0BFFBB7C0CFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0FFFBB7C0CFFBC7E0CFFBE800EFFC08210FFBE800EFFBC7E0CFF
+ BB7D0BFFBD7F0DFFBF810FFFBF810FFFBE800EFFBC7E0CFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBC7E0CFFBD7F0DFFBE7F0FFFBE7F0FFFBD7E0EFFBD7E0EFFBC7D0DFF
+ BB7C0CFFBB7C0CFFBB7C0CFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBC7D0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFB87B07FFB97C08FFBA7D09FFBB7E0AFFBD800CFF
+ BF820EFFC0830FFFC18410FFBD800CFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFF
+ BC7F0BFFBC7F0BFFBD7F0DFFBC7E0CFFBC7E0CFFBC7D0DFFBB7D0BFFBB7C0CFF
+ BA7C0AFFBA7B0BFFBA7C0AFFBA7B0BFFBA7C0AFFBA7B0BFFAB6C14FFAB6C14FF
+ AB6D13FFAC6E14FFAD6F15FFAE7016FFAE7114FFAE7114FFB07316FFB07316FF
+ B07315FFB07315FFAF7214FFAF7214FFAF7214FFAF7313FFB17515FFB17515FF
+ B17515FFB27616FFB27616FFB27616FFB27616FFB27616FFB57919FFB67A1AFF
+ B67A1AFFB77B1BFFB67A1AFFB57919FFB37717FFB27616FFB07512FFB17613FF
+ B47916FFB67B18FFB87D1AFFB87D1AFFB67B18FFB57A17FFB27714FFB37815FF
+ B67B18FFBA7F1CFFBD821FFFBF8421FFBF8421FFBF8421FFBC801CFFBB801DFF
+ B67F1EFFB37C19FFB37B16FFB57C13FFBA7E14FFBB8019FFB67F24FF9D6E24FF
+ 97723EFFA58B67FFAE9E87FFB3A696FFA99F8EFFA38E6FFFA5783FFFA76E23FF
+ A8701EFFA87017FFAF7515FFB47A11FFAE7208FFB87A0EFFBD7D11FFBD7B14FF
+ B97613FFBA7917FFBE7E1FFFB6781AFFB17417FFB87C22FFAF731FFFB27624FF
+ B97925FFBD7D25FFC37F26FFC17D24FFBB7821FFB87722FFAC6E1AFFB17823FF
+ B57F2AFFB7822BFFB58226FFB27E20FFB68120FFBC8726FFC18C2BFFB68022FF
+ BD842EFFC18735FFC48939FFC3893DFFB47F36FFAF7F3DFFA9854FFFD6BC97FF
+ FFF0DFFFFDF7F2FFE9E8ECFFEBEEF6FFF3F7FCFFE9EEF1FFF0F1F5FFF0F1F5FF
+ F0F2F3FFEEF3F2FFF0F4EFFFF1F5EFFFF2F6F0FFF2F6F1FFEBF0F1FFE4EBEEFF
+ F6FAFFFFF2F2F2FFFEF5E8FFF1DDC4FFAC8F68FF9C743AFFAE7A2DFFB1781DFF
+ B3791AFFB77C18FFB67D14FFBA8114FFBF8416FFBC8113FFB67B0EFFB97E11FF
+ B97D13FFB77A12FFB87E15FFBE851CFFBC8419FFB67C12FFB87D10FFBB7E10FF
+ BC7F11FFBB7E10FFBA7D0FFFB87B0DFFB97C0EFFBA7D0FFFBC7F11FFBC7F11FF
+ BB7E10FFBB7E10FFBA7D0FFFBA7D0FFFBC7F11FFBC7F11FFC08413FFBF8312FF
+ BF8214FFBD7F13FFBC7E12FFBB7D11FFB97B0FFFB97C0EFFBE8211FFBE8210FF
+ BD810FFFBA7E0CFFB87C0BFFBA7D0FFFBE8014FFC18317FFBC7D0FFFBA7B0DFF
+ BF8012FFC18214FFBA7B0DFFBD7E10FFC38416FFC28315FFBD7E10FFBD7E10FF
+ BD7E10FFBE7F11FFBF8012FFBF8012FFC08113FFC08111FFBB7E0AFFBB7E08FF
+ BB7E08FFBB7E08FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7E0CFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBA7B0BFFBB7C0CFFBB7C0CFFBB7C0CFFBB7D0BFFBD7F0DFF
+ C08210FFBF810FFFBD7F0DFFBB7D0BFFBD7F0DFFBF810FFFBE800EFFBD7F0DFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBE800EFFBE800EFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFC18311FFC08210FF
+ BF810FFFBD7F0DFFBB7D0BFFBA7C0AFFB97B09FFB87A08FFBC7E0CFFBC7E0CFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7D0DFFBC7D0DFF
+ BC7D0FFFBB7C0CFFBB7C0EFFBA7B0BFFBA7B0DFFBA7B0BFFBA7B0DFFBA7B0BFF
+ BA7B0DFFAD6E16FFAC6D15FFAB6D13FFAC6E14FFAD6F15FFAE7016FFAD6F15FF
+ AC6F12FFAB6E11FFAC6F12FFAD7012FFAE7113FFAF7214FFB07315FFB17416FF
+ B27517FFB37717FFB37717FFB37717FFB37717FFB27616FFB07414FFAF7313FF
+ AE7212FFB07414FFB17515FFB27616FFB37717FFB57919FFB77B1BFFB97D1DFF
+ BA7E1EFFB27714FFB37815FFB67B18FFBA7F1CFFBD821FFFBD821FFFBB801DFF
+ B87D1AFFB97E1BFFBB801DFFBF8421FFC38825FFC58A27FFC28724FFBC811EFF
+ B87D19FFBB8019FFBC811AFFBA7F1CFFB57C19FFB27A15FFB57B12FFBC7E12FF
+ BF8115FFBC7E18FFB57C1FFFAD792DFFA17536FF9A723EFF967446FF937447FF
+ 936F39FFA27127FFB17A25FFBC852AFFB67E1FFFBA7F1BFFBA7F18FFAF720AFF
+ B6770FFFB67610FFBD7C1AFFB87617FFB57517FFBC7D21FFB6791CFFAF7417FF
+ B87E25FFBD8331FFBA7D2DFFB47420FFB47219FFC07B1EFFC27E1FFFBD7B1CFF
+ BB7B1DFFB6791CFFB67C23FFB58026FFBB872DFFBE8B2FFFB88426FFB78122FF
+ BE8829FFB68021FFBA8124FFC78D34FFC38A35FFBC8132FFB77D35FFB48142FF
+ C39964FFBDA178FFE2D1B6FFFBF5EAFFF0F0F0FFDFE3E8FFDEE4EBFFE8ECF1FF
+ ECEFF4FFEFF2F7FFEDF0F5FFEAEDF1FFE8EDECFFEBEFEAFFEEF2ECFFF4F7EEFF
+ F5F9F4FFEFF4F5FFEEF4F9FFFAFEFFFFF1EFEEFFFFF7E7FFFFE6C4FFC39E6AFF
+ BE9049FFBA832EFFBC7F21FFB87D1AFFBA7F18FFBA8016FFBA8114FFB97E10FF
+ B4790BFFB67B0EFFB57A0DFFB4770FFFB2780FFFB67D14FFBA8118FFB87F16FF
+ B47A11FFB87D10FFBB7E10FFBC7F11FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFF
+ B97C0EFFBA7D0FFFBB7E10FFBC7F11FFBB7E10FFBA7D0FFFB97C0EFFBB7E10FF
+ BC800FFFC18513FFC18513FFC08413FFBF8214FFBD8012FFBB7E10FFB97C0EFF
+ B87C0BFFBF8311FFBF8311FFBE8210FFBB7F0DFFB87C0BFFB97D0CFFBC7F11FF
+ BF8214FFBB7C0EFFB8790BFFBC7D0FFFBE7F11FFB97A0CFFBC7D0FFFC08113FF
+ BD7E10FFBA7B0DFFBA7B0DFFBA7B0DFFBB7C0EFFBC7D0FFFBC7D0FFFBD7E10FF
+ BD7E0EFFBB7E0AFFBB7E08FFBB7E08FFBB7E08FFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7B0BFFBA7B0BFFBB7C0CFF
+ BB7C0CFFBA7C0AFFBC7E0CFFBE800EFFBE800EFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BE800EFFB97B09FFBA7C0AFFBA7C0AFFBB7D0BFFBD7F0DFFBE800EFFBF810FFF
+ C08210FFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBF810FFFBF810FFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFF
+ B97B09FFB87A08FFB97B09FFB97B09FFB97B09FFB97B09FFB97B09FFB97B09FF
+ B87A08FFBC7D0FFFBC7D0FFFBC7D0FFFBB7C0EFFBB7C0EFFBA7B0DFFBA7B0DFF
+ BA7B0DFFB97A0CFFB97A0CFFB97A0CFFAD7118FFAB6F16FFA96D14FFAA6E15FF
+ AB6F16FFAC7016FFAA6E14FFA86C12FFAA6F12FFAA6F12FFAB7013FFAD7215FF
+ AE7415FFAF7516FFB07617FFB17718FFB27616FFB27616FFB37717FFB37717FF
+ B37717FFB17515FFB07414FFAF7313FFAF7313FFB07414FFB17515FFB37717FF
+ B47818FFB67A1AFFB77B1BFFB87C1CFFB57A17FFB57A17FFB57A17FFB87D1AFF
+ BB801DFFBC811EFFBB801DFFB87D1AFFBA7F1CFFB87D1AFFB77C19FFB77C19FF
+ B77C19FFB57A17FFB07512FFAE720EFFBA7E14FFBC7E14FFBA7C18FFB57816FF
+ B37614FFB37811FFBA7C10FFBD8012FFBD7D11FFC3831DFFC3842AFFBB7E2EFF
+ B1772CFFA7712AFFA7752DFFB18032FFAE791FFFB57E1DFFC78E2BFFC28723FF
+ B97F18FFBD821BFFBA7C18FFBA7B19FFB37315FFBB7A1EFFBE7C23FFBA7B21FF
+ B97B21FFB67B1EFFB67C1DFFB67D20FFBE832DFFBD812FFFB57723FFB2751FFF
+ BC8026FFBF8427FFBD8225FFC2872AFFB67D20FFB87F22FFB47B1EFFB67E1FFF
+ BB8324FFB77D1EFFB27818FFB87E1EFFC08626FFBD8324FFBF8329FFBB7F2BFF
+ C08536FFB9823DFFAE7F47FFBB986CFFE0CAAEFFF3EBDAFFFAF9F5FFECF3F6FF
+ EAF3F7FFE8F0F7FFEDF0F5FFF6F9FEFFF2F4FCFFF0F3F8FFEEF1F5FFECF0F1FF
+ EFF3EEFFF2F4EEFFF5F7F1FFF5F9F4FFEEF5F8FFF4FCFFFFF1F7FEFFF2F0EFFF
+ F0E2CFFFD6BA91FFBE9354FFBA8535FFC0842AFFBE811FFFBA7F18FFBD8018FF
+ BE8218FFBB8013FFB87D0FFFB87D0FFFBB8215FFB57C0FFFB2780FFFB57B12FF
+ B87E17FFB87E17FFB57B14FFB47A11FFB77C0FFFBA7E0DFFBB7F0EFFBC800FFF
+ BD8110FFBC800FFFBB7F0EFFBB7F0EFFB97D0CFFBB7F0EFFBC800FFFBC800FFF
+ BA7E0DFFB97D0CFFBA7E0DFFBC800FFFBD810FFFBE8210FFBE8210FFBE8211FF
+ BD8110FFBB7F0EFFB97D0CFFB87C0BFFBC800EFFBC800EFFBC800EFFBA7E0CFF
+ B77B09FFB77B0AFFBA7E0DFFBC800FFFBA7B0BFFB57606FFB87909FFBA7B0BFF
+ B77808FFB97A0AFFBC7D0DFFB67707FFBD7E0EFFBD7E0EFFBC7D0DFFBC7D0DFF
+ BB7C0CFFBB7C0CFFBA7B0BFFBA7B0BFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBE800EFFBD7F0DFFBC7E0CFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFFBA7C0AFFBA7C0AFFBB7D0BFFBC7E0CFF
+ BE800EFFBE800EFFBD7F0DFFBB7D0BFFB97B09FFB97B09FFBA7C0AFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFB97B09FFBA7C0AFFBA7C0AFFBC7E0CFF
+ BD7F0DFFBE800EFFBF810FFFBF810FFFB97B09FFBA7C0AFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBA7C0AFFB97B09FFBC7D0FFFBC7D0FFFBC7D0FFFBB7C0EFF
+ BB7C0EFFBA7B0DFFBA7B0DFFBA7B0DFFB97A0CFFB97A0CFFB97A0CFFAE7219FF
+ AB6F16FFA96D14FFAA6E15FFAB6F16FFAC7017FFAA6E14FFA76B11FFAF7319FF
+ AF7417FFAF7417FFAF7417FFAE7415FFAE7415FFAE7415FFAE7415FFAC6F11FF
+ AE7212FFB07414FFB27616FFB47818FFB47818FFB47818FFB47818FFB37717FF
+ B37717FFB47818FFB47818FFB47818FFB37717FFB17515FFB07414FFB67B18FF
+ B47916FFB27714FFB37815FFB57A17FFB77C19FFB67B18FFB57A17FFBB801DFF
+ B57A17FFAF7411FFAE7310FFB27714FFB87D1AFFBD821FFFC08420FFB97B11FF
+ B97B11FFB97815FFB47513FFB27311FFB37511FFB67911FFB97D13FFB7790FFF
+ BB7B15FFBD7A1DFFC27F28FFC2802DFFB17221FFAA6E1CFFB77E28FFB67C1CFF
+ AC710DFFBC821BFFB97F18FFAA6E0AFFB57915FFC08021FFBE7E20FFB7751CFF
+ B97921FFC5852DFFC3842CFFB4791CFFB77D1EFFBA8320FFAF7815FFB27819FF
+ BD8127FFBD8127FFB97F26FFB98128FFB27A21FFAE741BFFB47B20FFB17619FF
+ BC7F21FFBB7F1FFFBC8020FFC28626FFBD8121FFB27818FFB47A1AFFB77B1BFF
+ BB7E20FFBE8026FFBC7E2AFFC1873CFFB78243FFA87C4DFFB99A79FFE9DAC7FF
+ F7F5EBFFEFF4F3FFE2EBEFFFEDF6FAFFF1F7FCFFECEFF4FFF2F2F8FFEDEFF7FF
+ EEF1F6FFEFF3F8FFF1F5F6FFF3F6F4FFF2F3EFFFEFF0ECFFE9EEECFFE9EFF4FF
+ F3FBFFFFECF0F5FFFFFEF9FFE6D7BDFFAC8E5FFFB68743FFB47E27FFBE8222FF
+ BC7E18FFB97C14FFBA7E14FFBC8114FFBA7F12FFBD8214FFC4891BFFC48B1EFF
+ BA8114FFB67C12FFBB8118FFBD831CFFB97F18FFB57A16FFB77C15FFB57A0DFF
+ B87C0BFFBA7E0DFFBC800FFFBE8211FFBF8312FFBE8211FFBD8110FFB87C0BFF
+ BB7F0EFFBD8110FFBC800FFFBA7E0DFFB87C0BFFBA7E0DFFBC800FFFB87C0BFF
+ B97D0BFFBB7F0DFFBC800EFFBC800FFFBB7F0EFFB97D0CFFB87C0BFFB77B09FF
+ B87C0AFFB97D0BFFB87C0AFFB67A08FFB67A08FFB87C0BFFBA7E0DFFC08111FF
+ BA7B0BFFBB7C0CFFBE7F0FFFBC7D0DFFBE7F0FFFBF8010FFB87909FFC48515FF
+ C38414FFC28313FFC08111FFBE7F0FFFBD7E0EFFBB7C0CFFBB7D0BFFBB7D0BFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBF810FFF
+ BE800EFFBC7E0CFFBB7D0BFFBA7C0AFFBB7D0BFFBB7D0BFFBC7E0CFFBA7C0AFF
+ B97B09FFB97B09FFBB7D0BFFBE800EFFBF810FFFBC7E0CFFB97B09FFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFFBE800EFFBE800EFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBD7F0DFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BE800EFFC08210FFC28412FFC28412FFC08210FFBE800EFFBC7D0DFFBC7D0DFF
+ BC7D0DFFBC7D0FFFBB7C0CFFBB7C0EFFBA7B0BFFBA7B0DFFBA7B0BFFB97A0CFF
+ B97A0AFFB97A0CFFAC6F19FFA56812FFA46711FFA86B15FFAA6E15FFA66A11FF
+ A3670EFFA5690FFFAE7218FFAD7117FFAD7215FFB07518FFB3781BFFB3781BFF
+ B07518FFAD7314FFA6690BFFB27517FFB47719FFB27517FFB5781AFFB17416FF
+ B07315FFBA7D1FFFB17416FFB07315FFB17416FFB47719FFB87B1DFFB97C1EFF
+ B6791BFFB37717FFB67B18FFB77C19FFB87D1AFFB87D1AFFB77C19FFB57A17FF
+ B37815FFB27714FFBA7F1CFFBC811EFFB87D1AFFB47916FFB67B18FFBB801DFF
+ BA7F1CFFB47814FFB77913FFBA7A14FFBB7A18FFBA7819FFB77516FFB47415FF
+ B57915FFB77C18FFB57C19FFB47A1BFFB67621FFB77827FFB87A2CFFB97B2FFF
+ B67B2CFFB47A28FFB97E21FFB87B1BFFBF8220FFC38624FFBC7D1BFFB57516FF
+ B77719FFB7761AFFB4751BFFBC7C24FFBF7F27FFB6791CFFAF7515FFB47C17FF
+ BA861CFFC08A1FFFB37B10FFBA8017FFB77F1AFFAE7716FFAA7318FFB0761DFF
+ B57920FFB5761EFFC28125FFBB781BFFBA7819FFC48321FFC78A28FFC18727FF
+ B57F20FFB17B1CFFB97D1DFFBA7C1EFFBF8127FFB77B29FFB37A35FFB6854DFF
+ BB946DFFCDB49AFFFFF7EAFFF2F1EDFFE6EEEEFFE5EEF2FFE8F1F5FFF0F5F8FF
+ F4F6F7FFF6F5F9FFEDEDF3FFE7EAEFFFE5E8EDFFE8ECEDFFF0F3F1FFF3F6F4FF
+ F1F4F2FFEBEFF0FFE7EDF2FFE4EAF1FFEBEEF2FFF0EBE2FFE3D1B4FFD3B280FF
+ C2924AFFAD751CFFB77B17FFBE8016FFC18319FFC2841AFFC08518FFBF8417FF
+ BE8316FFBE8316FFCB9225FFBE8518FFB67C12FFB97F16FFBC811AFFB97E17FF
+ B77B17FFB87D16FFB77C0FFFBA7D0FFFBA7D0FFFB87B0DFFB6790BFFB77A0CFF
+ BC7F11FFC08315FFBD8012FFBD8012FFBC7F11FFB97C0EFFB6790BFFB5780AFF
+ B77A0CFFBA7E0DFFBA7E0DFFBB7F0EFFBC800EFFBC800EFFBC800EFFBB7F0DFF
+ B97D0BFFB87C0AFFBA7E0DFFBB7F0EFFBB7F0EFFB87C0BFFB67A08FFB67A08FF
+ B97D0BFFBC800EFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBA7C0AFFC08210FFBE800EFFBB7D0BFFB97B09FFB97B09FFBD7F0DFF
+ C18311FFC48614FFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBA7D09FFBB7E0AFFBD800CFFBC7F0BFFBA7D09FFB97C08FF
+ BB7E0AFFBC7F0BFFB77907FFB97B09FFBB7D0BFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BC7E0CFFBB7D0BFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFF
+ B97B09FFB97B09FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBC7F0BFFBB7E0AFFBB7E0AFFBA7D09FFBA7D09FFBB7E0AFF
+ BB7E0AFFBC7F0BFFBA7C0AFFBB7D0BFFB97B09FFB77907FFBB7D0BFFC08210FF
+ BE800EFFB87A08FFBC7E0CFFBB7D0BFFBB7D0BFFBD7F0DFFBF810FFFBF810FFF
+ BC7E0CFFB97B09FFBA7B0BFFBC7D0DFFBF8010FFC08111FFC08111FFBD7E0EFF
+ B97A0AFFB77808FFC08111FFC08111FFC08111FFC08111FFBF8010FFBF8010FF
+ BE7F0FFFBE7F0FFFB97A0AFFBA7C0AFFBB7C0CFFBC7E0CFFBC7D0DFFBB7D0BFF
+ BA7B0BFFB97B09FFB77808FFB77907FFB77808FFAB6E18FFA66913FFA56812FF
+ A96C16FFAC7017FFAA6E15FFA86C13FFAA6E15FFA66A10FFA5690FFFA4680EFF
+ A56A0DFFA86D10FFAB7013FFAD7215FFAE7316FFAB6E10FFB37618FFB27517FF
+ AF7214FFB37618FFB27517FFB27517FFBB7E20FFB37618FFB37618FFB27517FF
+ B37618FFB47719FFB5781AFFB47719FFB37717FFB87C1CFFB87D1AFFB87D1AFF
+ B87D1AFFB87D1AFFB97E1BFFBA7F1CFFBA7F1CFFBD821FFFBA7F1CFFB77C19FF
+ B67B18FFB57A17FFB47916FFB37815FFB37815FFB27513FFB37614FFB87617FF
+ BA7617FFB97516FFB97718FFBB7C1AFFBC7F1DFFB57B1CFFB37A1FFFB57925FF
+ B87B2BFFBD7F31FFBD8135FFBD8135FFBD8030FFBC7D25FFBB7C20FFC18325FF
+ C38626FFB9791AFFB37314FFB9791AFFBB7D1FFFB6771BFFB97A20FFB87A20FF
+ B37619FFB17717FFB67E19FFB7821AFFB88217FFBC8516FFBE8619FFBB841BFF
+ B37C19FFAE781AFFB2781FFFB67A21FFB97A22FFC8862DFFC27F23FFBD7A1DFF
+ C08022FFC18426FFBE8425FFB68022FFB57F21FFC5882AFFC18226FFB97924FF
+ AB7125FFB07B3CFFB58A59FFC0A180FFE3D2BFFFF9F3ECFFEDEFEFFFE4EBEEFF
+ E2EBEEFFE8EDF0FFECF0F1FFF1F1F1FFF0EFF1FFEFEFF5FFEAEDF2FFE9ECF0FF
+ EDEFF0FFF2F4F4FFF2F7F6FFF0F5F4FFEDF2F3FFE7EBF0FFF1F4F8FFF6F2F1FF
+ E3D9C8FFC9B18DFFB39058FFB18034FFB87F22FFB97E17FFBB7D11FFB97B0FFF
+ B87A10FFB77B11FFB77C0FFFB77C0FFFB77C0FFFBA8114FFB77E11FFB67D10FF
+ B87E14FFBA8017FFBC7E18FFBC7E18FFBE801AFFBC7E12FFBC7F11FFBA7D0FFF
+ B97C0EFFB97C0EFFBC7F11FFC18416FFC48719FFB87B0DFFBA7D0FFFBC7F11FF
+ BB7E10FFB97C0EFFB87B0DFFB97C0EFFBB7E10FFBA7D0FFFBB7F0EFFBC800FFF
+ BD810FFFBC800EFFB97D0BFFB67A08FFB47806FFB67A09FFB87C0BFFBB7F0EFF
+ BB7F0EFFB97D0CFFB87C0AFFB97D0BFFBB7F0DFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBF810FFFBD7F0DFFBB7D0BFF
+ BA7C0AFFBA7C0AFFBD7F0DFFC08210FFC28412FFC08210FFBF810FFFBE800EFF
+ BD7F0DFFBB7D0BFFBA7C0AFFB87A08FFB87A08FFBA7D09FFBB7E0AFFBD800CFF
+ BC7F0BFFBA7D09FFB97C08FFBB7E0AFFBC7F0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFBA7C0AFFB97B09FFB87A08FFBB7D0BFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFB97B09FFB97B09FFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFFB87A08FFBF810FFFC28412FF
+ BD7F0DFFB97B09FFBB7D0BFFBE800EFFBE800EFFBD7F0DFFBB7D0BFFBA7C0AFF
+ BA7C0AFFBC7E0CFFBD7F0DFFBC7E0CFFBA7C0AFFBD7E0EFFBD7E0EFFBE7F0FFF
+ BE7F0FFFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBD7E0EFFBC7D0DFFBB7C0CFF
+ BB7C0CFFBA7B0BFFBA7B0BFFBA7B0BFFBA7B0BFFBC7E0CFFBD7F0DFFBE800EFF
+ BE800EFFBE800EFFBE800EFFBD7F0DFFBC7E0CFFB87A08FFB87A08FFB87A08FF
+ A86D17FFA46913FFA46913FFA86D17FFAB701AFFAB701AFFAB7118FFAD731AFF
+ A76D14FFA86F14FFA97015FFAA7116FFAB7217FFAC7318FFAE7518FFB2771AFF
+ AD7012FFB17416FFB17416FFB17416FFB6791BFFB5781AFFB37618FFB6791BFF
+ B47719FFB47719FFB47719FFB37618FFB17416FFB17416FFB27517FFB37717FF
+ B67A1AFFB57A17FFB57A17FFB57A17FFB67B18FFB97E1BFFBC811EFFBE8320FF
+ BA7F1CFFB57A17FFB47916FFB77C19FFB57A17FFB07512FFB17613FFB77B1BFF
+ B87E1FFFB87D20FFB97A1EFFB87518FFB87312FFBB7412FFBC7813FFBC7A14FF
+ B17210FFAE7113FFAD7118FFAE721EFFB27525FFB47628FFB37527FFB37423FF
+ BD7D28FFBB7C22FFC18226FFC28525FFB67917FFB17511FFB97D19FFBE821EFF
+ B67919FFB5781AFFB37619FFB27518FFB3791AFFB77D1EFFB57B1BFFAE7714FF
+ BA851DFFB6841AFFB4801BFFB4801CFFB27C1EFFB17A1FFFB57B22FFBA8027FF
+ BE812BFFBB7B26FFB97A22FFB97D24FFBA7E25FFB57C21FFB2781FFFB2791EFF
+ C18427FFBD7E26FFB37626FFAF7833FFBF905AFFC8A47CFFD9C1A9FFFFF5E9FF
+ F7F4F0FFECF0F1FFE8EDF0FFE7ECEFFFEBEDEEFFEDEFEFFFEFF0EEFFEFEFEFFF
+ F0F1F5FFF0F0F6FFF0F1F5FFF1F3F4FFF2F4F4FFF1F6F5FFF1F4F8FFF1F4F8FF
+ EFF0F4FFFDFAF6FFF0E7DAFFD5C2A7FFC4A677FFB38B4AFFAC7B2BFFB88223FF
+ C2881FFFC08315FFB97B0FFFB7790FFFB77B11FFB77D13FFB77D13FFB57B11FF
+ B47B0EFFB98013FFBD8215FFBB8013FFB87C12FFBA7B13FFBA7A14FFBA7B13FF
+ BC7E14FFBA7C10FFB7790DFFB7790DFFBA7C10FFBE8014FFC18317FFC38519FF
+ B5770BFFB97B0FFFBC7E12FFBE8014FFBD7F13FFBC7E12FFBC7E12FFBD7F13FF
+ B87A0EFFBA7D0FFFBB7F0EFFBC800FFFBC800EFFBA7E0CFFB87C0AFFB67A08FF
+ B37706FFB77A0CFFBB7E10FFBE8113FFBD8012FFBB7F0EFFB97D0BFFB87C0AFF
+ BB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBB7D0BFFBC7E0CFFBD7F0DFFBE800EFFBF810FFF
+ BF8010FFBF8010FFBE7F0FFFBD7E0EFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFF
+ BA7D09FFBB7E0AFFBD800CFFBC7F0BFFBA7D07FFB97C06FFBB7E08FFBC7F0BFF
+ BE800EFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFB97B09FFB97B09FF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BA7D09FFBB7E0AFFBD800CFFBE810DFFBE810DFFBD800CFFBB7E0AFFBA7D09FF
+ BA7C0AFFC38513FFC68816FFBF810FFFB97B09FFBA7C0AFFBD7F0DFFBE800EFF
+ BE800EFFBB7D0BFFB87A08FFB77907FFB97B09FFBB7D0BFFBC7E0CFFBB7D0BFF
+ BE7F0FFFBD7E10FFBC7D0FFFBC7D0FFFBC7D0FFFBD7E10FFBF8012FFBF8012FF
+ BD7E10FFBC7D0FFFBA7B0DFFB97A0CFFB8790BFFB97A0CFFBA7B0DFFBA7B0BFF
+ BB7D0BFFBC7F0BFFBD800CFFBD800CFFBD800CFFBD800CFFBC7F0BFFBB7E0AFF
+ B97C08FFB97C08FFB97C08FFA76C16FFA66B15FFA66B15FFA86D17FFA96E18FF
+ AA6F19FFAC7219FFAD731AFFAA7017FFB0761DFFB67D22FFB87F24FFB57C21FF
+ B1781DFFAE7518FFAE7518FFAD7013FFB07315FFB27517FFB6791BFFBB7E20FF
+ B97C1EFFB37618FFB07315FFB07315FFB37618FFB5781AFFB5781AFFB27517FF
+ B17416FFB27517FFB47719FFB17515FFB17613FFB17613FFB27714FFB37815FF
+ B57A17FFB87D1AFFB97E1BFFB27714FFB17613FFB37815FFB67B18FFB57A17FF
+ B47916FFB87D1AFFBC8222FFB37A1DFFB67A20FFB7781CFFB77516FFB97413FF
+ C07A15FFC37E17FFC17E17FFBE7C16FFB97B17FFB6781AFFB77A1DFFB97A22FF
+ B97924FFB77522FFB57320FFBD7C27FFB7771FFFBC7D21FFBF8220FFB87D16FF
+ B47A11FFB97F16FFBA8017FFB37814FFB37717FFB47719FFB5781BFFB87A20FF
+ B77B21FFB7791FFFB2771AFFB47D1AFFAE7A15FFAF7B17FFB7801DFFB7801FFF
+ B37B1CFFB37A1DFFB98025FFB57920FFB77B22FFBB7F26FFBD8128FFBE7F27FF
+ BA7C22FFB6771DFFB4751BFFB97B21FFB67A26FFB97F37FFC18F53FFD1AA7EFF
+ E0C4A6FFEFDFCEFFFFFBF4FFF4F4F4FFEFF2F6FFEFF0F4FFEFF0F4FFF1F0F2FF
+ F2F2F2FFF1F4F2FFF1F4F2FFEFF0F4FFF1F2F6FFF4F3F5FFF4F3F5FFF0F2F3FF
+ EDF1F2FFEEF3F6FFF3F4F8FFF8F4F3FFFBF1E7FFDDC9B0FFC1A37AFFC39B60FF
+ BC8D43FFB27F29FFBE8928FFC58B21FFC18416FFB97B0FFFB67A10FFB97F16FF
+ BC8219FFBA8017FFB67C12FFB57C0FFFBB8314FFBD8214FFBA7D0FFFB97B0FFF
+ BE7D14FFBE7B14FFB8760FFFBB7A11FFB7790DFFB5770DFFB6780CFFB97B11FF
+ BB7D11FFBB7D13FFB97B0FFFB87A10FFBB7D11FFBE8016FFBE8014FFBD7F15FF
+ BC7E12FFBD7F15FFBF8115FFB97B11FFBA7C10FFBA7D0FFFBB7F0EFFBC800EFF
+ BD810FFFBD810FFFBE8211FFB77A0CFFB97B0FFFBC7E12FFBE8014FFBD7F13FF
+ BB7E10FFB87C0BFFB77B09FFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBD7F0DFFBD7F0DFF
+ BD7F0DFFBD7F0DFFBD7F0DFFBB7C0CFFBB7C0CFFBC7D0DFFBD7E0EFFBE800EFF
+ BF810FFFC08210FFC08210FFBA7D09FFBB7E0AFFBD800CFFBC7F0BFFBA7D07FF
+ B97C06FFBB7E08FFBC7F09FFBB7E0AFFBA7C0AFFB97B09FFB97B09FFBA7C0AFF
+ BB7D0BFFBD7F0DFFBF810FFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BB7D0BFFB97B09FFB97B09FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBA7D09FFBB7E0AFFBE810DFFBF820EFFBF820EFF
+ BE810DFFBB7E0AFFBA7D09FFBF810FFFC28412FFC18311FFBC7E0CFFBB7D0BFF
+ BD7F0DFFBC7E0CFFB87A08FFBD7F0DFFBA7C0AFFB87A08FFB87A08FFBA7C0AFF
+ BB7D0BFFBB7D0BFFBA7C0AFFBD7E10FFBD7E10FFBC7D0FFFBC7D0FFFBD7E10FF
+ BE7F11FFBF8012FFC08113FFC08113FFBF8012FFBD7E10FFBB7C0EFFBB7C0EFF
+ BB7C0EFFBD7E10FFBE7F0FFFB77907FFB87A08FFB97B09FFB97B09FFB97B09FF
+ B97B09FFB87A08FFB77907FFB87A08FFB87A08FFB87A08FFA96D19FFA96D19FF
+ A86C18FFA66A16FFA66B15FFA76C16FFA96E18FFA96E18FFA66C13FFAB7118FF
+ B1781DFFB47B20FFB1781DFFAD7419FFAB7217FFAA7114FFB37619FFB07316FF
+ B27518FFB5781BFFB87B1EFFB97C1FFFB77A1DFFB27518FFAC6F12FFB07316FF
+ B5781BFFB77A1DFFB5781BFFB37619FFB4771AFFB5781AFFB17515FFB27714FF
+ B37815FFB57A17FFB57A17FFB57A17FFB47916FFB47916FFB07512FFB57A17FF
+ B87D1AFFB57A17FFB57A17FFB97E1BFFBE8320FFBF8421FFB47A1BFFB97C1EFF
+ B87B1BFFB57614FFBA7714FFC17D18FFC58019FFC27E15FFBF7D14FFBD7C13FF
+ BA7B13FFBA7C16FFBC7D1BFFBE7C1DFFBD781BFFBB741CFFBC7C24FFB17319FF
+ B47719FFBC811DFFBA8118FFB88015FFB77F14FFB1790EFFB17710FFB47916FF
+ B87B1EFFBB7D23FFBA7B23FFB97924FFBA7825FFBB7C24FFB87B1DFFB57A17FF
+ B77C19FFBF831FFFC08420FFB97D19FFB57A17FFB77C19FFB67A1AFFBB7D1FFF
+ BF8123FFC38324FFC68223FFC68120FFC67F1EFFC37D20FFC0802BFFB88033FF
+ BE894AFFC69A6BFFCFB091FFE7D3C1FFF4EDE4FFEAEBE9FFECF0F1FFEDF0F5FF
+ F1EFF5FFF3EFF4FFF4F1F3FFF3F3F3FFF0F7F4FFF1F8F5FFEDEEF2FFF1F0F4FF
+ F5F2F4FFF2F1F3FFEDEFF0FFE9ECF0FFEAEEF3FFF2F1F3FFFCF4EDFFF2DFCAFF
+ CBAC85FFB0854CFFB48339FFB47E29FFB37C21FFC38C29FFBD8417FFB87D0FFF
+ B3780BFFB47A10FFBB8118FFBC831AFFB87F16FFB1790EFFB57C0FFFB67E0FFF
+ B57A0CFFB5780AFFBF7E11FFCA861BFFCB831DFFC17C15FFBC7A13FFB97B11FF
+ B97A12FFBA7C12FFBC7D15FFBB7D13FFB77810FFB3750BFFBE7F17FFBF8117FF
+ BF8018FFBD7F15FFBA7B13FFBA7C12FFBC7D15FFBE8016FFC2831BFFC08218FF
+ BD8012FFBB7F0EFFBA7E0CFFBC800EFFBF8312FFC18514FFBF8115FFBE8016FF
+ BD7F15FFBB7D13FFBA7C10FFB97C0EFFB77B0AFFB67A08FFBC7F0BFFBC7F0BFF
+ BC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBC7F0BFF
+ BD800CFFBD800CFFBD800CFFBC7F0BFFBB7E0AFFBB7D0BFFBB7C0CFFBB7C0EFF
+ BC7D0DFFBD7E0EFFBE7F0FFFBF8010FFC08210FFC08210FFBA7D09FFBB7E0AFF
+ BD800AFFBC7F09FFBA7D07FFB97C06FFBB7F07FFBC7F09FFBB7E0AFFBA7C0AFF
+ B97B09FFB97B09FFBA7C0AFFBB7D0BFFBD7F0DFFBF810FFFBB7D0BFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFB97B09FFB97B09FFBB7E0AFFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFB97C06FFBB7E08FF
+ BD800AFFBF820CFFBF820CFFBD800AFFBB7E08FFB97C08FFBD7F0DFFBF810FFF
+ BE800EFFBA7C0AFFB97B09FFBC7E0CFFBB7D0BFFB67806FFBA7C0AFFB97B09FF
+ B97B09FFBA7C0AFFBC7E0CFFBC7E0CFFBA7C0AFFB77907FFBB7C0EFFBB7C0EFF
+ BD7E10FFBE7F11FFBE7F11FFBE7F11FFBE7F11FFBE7F11FFBF8012FFBE7F11FF
+ BD7E10FFBC7D0FFFBB7C0EFFBC7D0FFFBC7D0FFFBD7E10FFB77808FFB87909FF
+ B97A0AFFB97A0AFFB97A0AFFB97A0AFFB87909FFB77808FFB77808FFB77808FF
+ B77808FFAA6E1AFFAD711DFFAB6F1BFFA66A16FFA46913FFA66B15FFA86D17FF
+ A86D17FFA56B12FFA66C13FFA86F14FFAA7116FFAB7217FFAD7419FFB0771CFF
+ B37A1FFFB87D20FFB37619FFB17417FFB27518FFB27518FFB77A1DFFBB7E21FF
+ B77A1DFFAE7114FFB17417FFB4771AFFB6791CFFB6791CFFB6791CFFB6791CFF
+ B6791BFFB67A1AFFB77C19FFB97E1BFFBA7F1CFFBA7F1CFFB97E1BFFB77C19FF
+ B57A17FFB47916FFBA7F1CFFBA7F1CFFB57A17FFB47916FFBA7F1CFFBD821FFF
+ BA7D1BFFBC7E1AFFBF811DFFBB7F1BFFB57915FFB77915FFC07F1CFFC17E1BFF
+ BA7812FFBE7C15FFBB7D13FFB87E14FFBC8219FFC2841EFFC68523FFC78324FF
+ C57F24FFBB7B23FFAF7018FFB27517FFBC811EFFBC821BFFBB8318FFB88015FF
+ B1780FFFB47915FFB67B18FFBA7D1FFFBD7F25FFBD7D25FFB97921FFBB7B23FF
+ C08127FFC18325FFBF8220FFBF8220FFC48622FFC38422FFBE801CFFB87917FF
+ B67715FFB87917FFB9791AFFBA7819FFB77614FFBB7716FFC27D1CFFC68120FF
+ C48125FFC48836FFB8843DFFB3844EFFB9946EFFC8B09CFFE7DCD4FFF5F6F4FF
+ E0E7EAFFE4EAEFFFE7EBF0FFF0ECF2FFF3ECF3FFF0ECF1FFEDEFF0FFEAF3F0FF
+ EAF5F3FFEBEEF2FFF1F0F4FFF4F1F3FFF0F0F0FFEBEDEEFFE7EAEEFFE8ECF1FF
+ F0EEEEFFFCF0E4FFDFC5A7FFC09562FFB5813AFFBE832DFFBD8121FFB47A1AFF
+ B47A13FFBA8114FFB87D0FFFB47B0EFFB97F16FFBF851EFFC18720FFBB811AFF
+ B47C11FFBB8215FFB87D0FFFB57908FFB87909FFC28010FFCA8518FFC98018FF
+ C17913FFC28019FFC08119FFC08119FFC08119FFC08119FFBD7E16FFB97A12FF
+ B6770FFFC1821AFFC1821AFFC08119FFBC7D15FFB97A12FFB87911FFBA7B13FF
+ BD7E16FFC88921FFC5871DFFC08216FFBC7F11FFB97D0CFFBA7E0CFFBB7F0EFF
+ BD8012FFC5871DFFC1821AFFBC7D15FFB97A12FFB87A10FFB77A0CFFB77B0AFF
+ B67A08FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBC7F0BFFBB7E0AFFBB7E0AFF
+ BA7C0AFFBF8010FFBF8012FFBE7F0FFFBD7E0EFFBC7D0DFFBB7C0CFFBA7C0AFF
+ BA7C0AFFBA7D09FFBB7E0AFFBD800AFFBC7F09FFBA7D07FFB97C06FFBB7F07FF
+ BC7F09FFBE810DFFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7C0AFF
+ BA7C0AFFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFFBC7E0CFFBB7D0BFFB97B09FF
+ B97C08FFBB7E0AFFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFB97C06FFBA7D07FFBC7F09FFBD800AFFBD800AFFBC7F09FFBA7D07FF
+ B97C06FFB77907FFBD7F0DFFBF810FFFBA7C0AFFB77907FFBA7C0AFFBC7E0CFF
+ BA7C0AFFBA7C0AFFB97B09FFBA7C0AFFBC7E0CFFBE800EFFBD7F0DFFBA7C0AFF
+ B77907FFBA7B0DFFBB7C0EFFBC7D0FFFBD7E10FFBE7F11FFBD7E10FFBC7D0FFF
+ BB7C0EFFBB7C0EFFBB7C0EFFBB7C0EFFBA7B0DFFBA7B0DFFB97A0CFFB97A0CFF
+ B97A0CFFBB7C0EFFBC7D0FFFBD7D11FFBD7E10FFBD7D11FFBD7E10FFBC7C10FF
+ BB7C0EFFB7770BFFB7780AFFB7770BFFAA711CFFAD741FFFAC731EFFA66D18FF
+ A26913FFA66D17FFA9701AFFA86F19FFA76F16FFA66E15FFA66E15FFA87017FF
+ AC751AFFB0791EFFB37C21FFB77E23FFB77C1FFFB37619FFB4771AFFB6791CFF
+ B27518FFB6791CFFBB7E21FFB6791CFFB6791CFFB5781BFFB37619FFB37619FF
+ B5781BFFB77A1DFFB87B1EFFB87B1DFFB87C1CFFB87D1AFFB97E1BFFB97E1BFF
+ B97E1BFFB97E1BFFB97E1BFFB87D1AFFB77C19FFB77C19FFB57A17FFB47916FF
+ B67B18FFB97E1BFFB97E1BFFBB7D17FFB7760AFFBE7D11FFBA7D15FFB47915FF
+ B67C1CFFBE8528FFC08528FFB77C1FFFAB7111FFA9730EFFA8740FFFAC7813FF
+ B27B18FFB77D1EFFB97A20FFB87820FFB97925FFB3731EFFB67A21FFBD8225FF
+ B87E1EFFB67E19FFB9811CFFB77F1AFFBC811EFFB87C1CFFB87B1BFFBC7E20FF
+ C08022FFBC7C1DFFBA7B19FFBC7D1BFFBF8220FFC08321FFBE811FFFBC7F1FFF
+ BD7F21FFBF7F21FFBC7B1FFFB97619FFBC791CFFBC791CFFB87518FFB27214FF
+ B17416FFB97E21FFBC8328FFB8822BFFBE883BFFBE8C4AFFAA8051FFB59578FF
+ D8C6BBFFF0ECEBFFEFF8FCFFE1EDF3FFE0EAF1FFE9ECF4FFF2EDF6FFF5EDF4FF
+ F2ECF1FFECEEEFFFE5F2F0FFE7F4F2FFECF1F4FFF1F0F4FFF3F1F1FFF2F0F0FF
+ ECEEEFFFE8EBEFFFE8EBF0FFF1EDECFFE3D3C2FFC09F78FFB98647FFCB8D39FF
+ D08C2BFFCA881FFFBD7F19FFAB7108FFBD8214FFBA7F11FFB77E11FFBB8118FF
+ C0861FFFC28821FFBD831CFFB77E15FFBB8215FFB87E0DFFB87C0AFFBE7F0DFF
+ C47F10FFC37B0FFFC1770DFFBE750DFFC4811AFFC2821CFFC2821CFFC0801AFF
+ BE7E18FFBC7C16FFBC7C16FFBC7C16FFBF7F19FFC0801AFFC0801AFFBD7D17FF
+ BA7A14FFB87812FFB97913FFBA7A14FFC1811BFFC08119FFBE8016FFBC7F11FF
+ BB7F0EFFBA7E0DFFBA7D0FFFBA7D0FFFC5871DFFC1821AFFBC7C16FFB97913FF
+ B97B11FFB97B0FFFB87B0DFFB77B09FFBB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBB7E0AFFBB7E0AFFBD800CFFBD800CFFBC7F0BFFBB7E0AFF
+ BA7D09FFBA7D09FFBA7D09FFBA7C0AFFC08111FFBF8012FFBE7F11FFBD7E10FF
+ BB7C0CFFBA7B0BFFB87A08FFB87A08FFBA7D09FFBB7E0AFFBD800AFFBC7F09FF
+ BA7E06FFB97D05FFBB7F07FFBC7F09FFBC7F0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BB7D0BFFBA7C0AFFB97B09FFB87A08FFBB7D0BFFBC7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBB7D0BFFB97B09FFB97C08FFBB7E0AFFBB7E08FFBB7E08FFBB7E08FF
+ BB7E08FFBB7E08FFBB7E08FFBB7E08FFB97C06FFB97C06FFBA7D07FFBA7D07FF
+ BA7D07FFBA7D07FFB97C06FFB97C06FFB87A08FFBB7D0BFFBC7E0CFFBA7C0AFF
+ BB7D0BFFBF810FFFC08210FFBD7F0DFFBC7E0CFFBB7D0BFFBA7C0AFFBB7D0BFF
+ BD7F0DFFBD7F0DFFBC7E0CFFBA7C0AFFBC7D0FFFBC7D0FFFBB7C0EFFBA7B0DFF
+ BA7B0DFFBA7B0DFFBB7C0EFFBB7C0EFFBA7B0DFFBB7C0EFFBD7E10FFBD7E10FF
+ BD7E10FFBB7C0EFFB97A0CFFB8790BFFBC7C10FFBD7D11FFBE7D14FFBE7E12FF
+ BE7D14FFBE7E12FFBD7C13FFBC7C10FFBA7910FFBA7A0EFFBA7910FFAB711FFF
+ AF7523FFAE7422FFA76D1BFFA46B16FFA86F1AFFAC731EFFAB721CFFA66D17FF
+ A56D14FFA66E15FFAA7219FFAF771EFFB0791EFFAE771CFFAE751AFFB0741AFF
+ AE7218FFB77B21FFBD8127FFB77B21FFB67A20FFB67A20FFAE7316FFBC8026FF
+ B77B21FFB0741AFFAE7218FFB0741AFFB4781EFFB67A20FFB97C1FFFB67A1AFF
+ B57A17FFB47916FFB47916FFB47818FFB67A1AFFB87B1DFFB77D1EFFB3791AFF
+ AD7314FFAB7112FFB27819FFB67C1DFFB77A1CFFB87C1CFFBF811DFFBA790DFF
+ C38013FFBF8018FFB57A16FFB57C1FFFBC852AFFB9802AFFAE761DFFB0791EFF
+ AF791AFFAD7A19FFB07E1AFFB3801FFFB68021FFB97E21FFB97B21FFB97924FF
+ B77722FFBC8026FFBF8427FFB67C1CFFB57A17FFBE8320FFC38825FFC38727FF
+ BA7D1DFFB47717FFB97C1CFFBE8121FFBB7E1EFFB57816FFB37713FFB77B17FF
+ B97D19FFB57A17FFB17515FFB6771BFFBE7F25FFC07D26FFBB7821FFC58128FF
+ C58428FFC08224FFBC7F21FFBC8326FFC08B30FFC18D33FFBB8734FFBF8B3FFF
+ C7985BFFAC8860FFBBA38DFFF0E4DEFFF8FAFBFFE7F0F4FFDDE9EFFFE8F0F7FF
+ EEF1F9FFF7F2FBFFF8F1F8FFF3EFF4FFEEF0F1FFE8F3F1FFEAF5F3FFF1F2F6FF
+ F2F1F5FFF1F1F1FFF0F0F0FFEBEFF0FFECEDF1FFEFECEEFFF8EDE5FFC4A98EFF
+ A8804CFFB78134FFD29234FFC27F18FFB9770EFFC0821CFFBC811AFFB87D10FF
+ B57A0CFFB4790CFFB57B11FFB97F16FFBA7F18FFB77D14FFB3790FFFAF7609FF
+ B07605FFB77B09FFC08210FFC28010FFBD780BFFBE760AFFC17B10FFC28017FF
+ BF8117FFBE7F17FFBA7B13FFB77810FFB87911FFBC7D15FFC08119FFBB7D13FF
+ BD7F15FFC08218FFBF8117FFBC7E14FFB97A12FFB87911FFB87911FFB5760EFF
+ B7790FFFB97B0FFFBC7F11FFBD8110FFBC800FFFBC7F11FFBB7D11FFC3851BFF
+ BF8018FFBB7C14FFBA7B13FFBB7D13FFBB7E10FFB97D0CFFB77B09FFB87C0AFF
+ BA7C0AFFBA7C0AFFBA7C0AFFBA7D09FFBA7D09FFBA7D09FFBA7D07FFBE810DFF
+ BD800CFFBB7E0AFFBA7D09FFB97C08FFBA7D09FFBA7D09FFBB7D0BFFBC7D0DFF
+ BC7D0DFFBC7D0DFFBB7C0CFFBB7C0CFFBB7D0BFFBA7C0AFFBA7C0AFFBA7D09FF
+ BB7E0AFFBD800CFFBC7F09FFBA7D07FFB97C06FFBB7E08FFBC7F09FFB77907FF
+ B97A0AFFBB7C0CFFBC7E0CFFBD800CFFBD800CFFBC7F0BFFBB7E0AFFBB7C0CFF
+ BC7D0FFFBC7D0FFFBC7D0DFFBC7E0CFFBB7E0AFFB97B09FFB97B09FFBB7D0BFF
+ BB7D0BFFBB7D0BFFBB7E0AFFBB7E08FFBB7E08FFBB7F07FFBB7F07FFB97D05FF
+ B97C06FFB87B05FFB87B05FFB87B05FFB87B05FFB97C06FFB97C06FFBD800CFF
+ BA7C0AFFB67806FFB77907FFC18311FFC98B19FFC58715FFBB7E0AFFC0830FFF
+ BD7F0DFFBA7C0AFFB97A0AFFBB7C0CFFBD7E0EFFBD7E0EFFBD7E0EFFC08010FF
+ BE7E0EFFBA7A0AFFB77907FFB67707FFB87909FFBA7B0DFFBC7D0FFFBD7D11FF
+ BD7F13FFC18214FFC38416FFC28315FFC08113FFBD7E10FFBB7C0EFFB97A0CFF
+ BA7A0EFFBB7B0FFFBC7C10FFBC7C10FFBB7B0FFFBA7A0EFFB9790DFFBC7B12FF
+ BC7C10FFBC7C10FFA66D1EFFAD7425FFB2792AFFAF7627FFA97120FFA66E1DFF
+ AC7220FFB27826FFAD741FFFAE751FFFB27721FFB1771EFFAF751CFFAE741BFF
+ AF751CFFB1771EFFB17620FFAF731FFFAC711BFFAD721CFFB0761DFFB37920FF
+ B2781FFFB1781DFFB2781FFFAF751CFFAE741BFFB37920FFBC812BFFBE832DFF
+ B87C28FFB3771EFFB87B1BFFB87B19FFBF8220FFBE8222FFB5781BFFB2761CFF
+ B77B22FFB37822FFB27622FFB37723FFB47923FFB47923FFB47A21FFB57920FF
+ B4781EFFB6791BFFBE7E18FFBC7D15FFB87A16FFB67919FFB6791CFFB7791FFF
+ B77722FFB67621FFBE8229FFB77B21FFB57C1FFFBC8524FFBF8825FFB8811EFF
+ B37B16FFB27916FFB17718FFB67C1DFFB47719FFB57919FFBE8320FFBC801CFF
+ B47814FFB67A16FFB77A18FFBB7E1EFFBD8020FFBD7F21FFC08125FFC08326FF
+ BA7C22FFB17417FFB37614FFB17511FFB07511FFB47916FFB87B1DFFB97B21FF
+ B87823FFB87824FFC2822DFFBF8127FFB77D1EFFB77D1DFFBF8827FFC48E30FF
+ BA852BFFAA7421FFB67F34FFB4864CFFC1A380FFEEE0CEFFF9F4F1FFEAECEDFF
+ F3F5F6FFEFF3F4FFEAEDF1FFEDF0F5FFF0F3F8FFF4F5F9FFF6F5F7FFF3F3F3FF
+ EDF0EEFFEDEDEDFFF1ECEEFFF3F0F2FFEBF0EEFFEDF4F1FFE8EDF0FFF4F3F5FF
+ FEF1EFFFDBC1B1FFBA9367FFB58440FFAD761BFFB87D16FFB97B15FFB77B17FF
+ C18426FFBA7E1EFFBD8117FFB97C0EFFBE8113FFBD8215FFB57A0DFFB57A0DFF
+ B97E11FFB3780BFFB67B0DFFBE8113FFBD8110FFB67A09FFB67709FFBE7F11FF
+ C58417FFC48517FFB97A0AFFB97A0AFFB97A0CFFB9790DFFBB7B0FFFBC7B12FF
+ BE7E12FFBF8012FFBF8010FFBC7D0DFFBA7C0AFFBB7D0BFFBE7F0FFFC08113FF
+ BF7F13FFBF7F13FFBF8012FFBE7F0FFFBF8010FFC18212FFC38414FFC38414FF
+ C18214FFBE7F11FFB7770BFFBC7C10FFBE7E12FFB97A0CFFB97A0AFFBE7F0FFF
+ BE800EFFB87C0AFFB97C0EFFB97C0EFFBA7D0FFFBA7E0DFFB97D0BFFB87D09FF
+ B97C06FFB87C04FFB77A04FFB97C06FFBC7E08FFBE800AFFBF800DFFC0810EFF
+ C0810FFFC0810FFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7D0BFFBB7E0AFF
+ BB7E0AFFBB7E0AFFBE800EFFBC7E0CFFBA7C0AFFB87B07FFB87B07FFBA7D09FF
+ BC7F0BFFBE800EFFC08113FFB7780AFFB97A0CFFBE7F0FFFBA7D07FFB87D02FF
+ BB8005FFB97C06FFB27206FFBD7B14FFC5831CFFC6851CFFC48614FFC2850FFF
+ BC7F0BFFB57705FFCE8D24FFC5831CFFBB7B0FFFB77808FFB87B07FFBB7F07FF
+ BA7F04FFB87D02FFBB8005FFBA7E06FFBA7D07FFB97C06FFB97C06FFBA7D07FF
+ BA7D07FFBB7E08FFBA7D09FFBB7D0BFFBB7C0CFFBC7D0DFFBC7D0DFFBB7D0BFF
+ BB7E0AFFBA7D07FFBB7E08FFB87B07FFB87909FFBC7C10FFBD7D11FFBB7B0FFF
+ BD7E10FFC28212FFBC7A0AFFBD7B0AFFBE7E08FFBD8008FFBD800AFFBE810DFF
+ BD8110FFBD7F13FFC08218FFB97D13FFBA7C10FFBE8113FFC08413FFBB7F0EFF
+ BA7B0BFFBB7C0CFFB77907FFB77907FFB87A08FFB87909FFB97A0AFFBA7B0DFF
+ BA7B0DFFBB7C0EFFBA7A0EFFBA7B0DFFBA7B0DFFA66E1DFFAD7524FFB67B2BFF
+ B77C2CFFB27826FFAD7321FFAF731FFFB17620FFB0751FFFB2781FFFB5791FFF
+ B5791FFFB3781BFFB3781BFFB6791CFFB67A20FFB3771EFFB0751FFFAE741BFF
+ AE741BFFB0771CFFB1781DFFB1781BFFB1781BFFB77E21FFB47B1EFFB37A1FFF
+ B77E23FFBD832AFFBE842BFFBA7F29FFB77B21FFB47717FFB57713FFBB7E1EFF
+ BD8022FFBB7D23FFC1842EFFCC903CFFCF9341FFB67B2BFFB67B2BFFB87E2CFF
+ BD8331FFC38733FFC18630FFBC7F29FFB6791CFFB77A18FFB47612FFB0710FFF
+ B57516FFBC7E20FFC18226FFC08127FFBC7D23FFB7791FFFB2741AFFAE7316FF
+ B3791AFFB77D1DFFB67D1AFFB37A17FFB17815FFBF8526FFBD8324FFB87C1CFF
+ B37717FFB77A18FFB77A18FFBA7C18FFBD7F1BFFB97A18FFBD7E1CFFBC7F1FFF
+ BA7C1EFFBA7D20FFBD8023FFB97D23FFB3771DFFB37616FFB77A18FFBB801DFF
+ BF8421FFC28527FFC18329FFB97C26FFB2751FFFBB7F26FFB87D20FFB27B1AFF
+ B27B18FFB88120FFBD8427FFB9802AFFB1792AFFA9752FFFB8905BFFD4BDA3FF
+ F3EAE0FFF1F1F1FFE6E9EDFFF1F1F1FFF1F1F1FFECEEEFFFECEFF3FFEEF1F5FF
+ F1F4F8FFF5F5F5FFF4F4F4FFF1F1F1FFF2F0F0FFF7F2F4FFEFEDEDFFE5ECE9FF
+ F0F7F4FFF9FDFEFFFDF5F5FFF0DACFFFD2AE90FFB18349FFBB8635FFBC8222FF
+ C2881FFFBC811DFFB87C1CFFC18629FFC18525FFBA7E14FFB97C0EFFBA7D0FFF
+ BB7E10FFBA7D0FFFBC7F11FFBE8113FFBB7E10FFBC7F11FFBD8012FFBC7F11FF
+ B87B0DFFB87B0DFFBC7F11FFC08315FFC18514FFBB7D0BFFBB7E0AFFBA7B0BFF
+ BA7B0BFFBB7B0FFFBC7C10FFBE7F11FFBF8010FFBA7C0AFFB97C08FFB87B05FF
+ BA7D07FFBE800EFFC18212FFC28315FFC18214FFBB7D0BFFBA7D09FFB97B09FF
+ BB7D0BFFBD7E0EFFBE7F0FFFBD7E10FFBA7B0DFFB97A0CFFBA7B0DFFBA7B0BFF
+ B97A0AFFBB7D0BFFBF810FFFC0830FFFBC800EFFC5881AFFC08517FFBE8113FF
+ BA7E0DFFB77B09FFB77C08FFBB7E0AFFBC7F09FFBD800AFFBD800AFFBF810BFF
+ BF810BFFBE7F0CFFBD7E0BFFBE7D0AFFBB7C09FFBD7E0CFFBC7E0CFFBC7E0CFF
+ BC7E0CFFBC7E0CFFBB7D0BFFBB7E0AFFBB7E0AFFBD7F0DFFBC7E0CFFBA7D09FF
+ B97C08FFB97C08FFBA7D09FFBC7F0BFFBD7F0DFFBA7B0BFFB97A0CFFC48418FF
+ CA8B1DFFBF820CFFB97E03FFBB8005FFBC7F09FFC48418FFC98721FFC98721FF
+ C28118FFBE800EFFBD800AFFBC7F0BFFB97A0AFFC6841DFFC17F19FFBA7910FF
+ B87909FFB97C08FFBB7F07FFBA7F04FFB97E03FFBB7F07FFBB7E08FFBB7E0AFF
+ BC7F0BFFBC7F0BFFBB7E08FFBB7E08FFBB7E08FFBA7D09FFBB7D0BFFBB7C0CFF
+ BC7D0FFFBC7D0DFFBB7D0BFFBB7E08FFBA7E06FFBF830BFFBC7F09FFBC7D0FFF
+ C18115FFC17F18FFBF7E15FFBF7F13FFC48316FFBD7B0BFFBF7B0AFFBD7E06FF
+ BC8005FFBD8106FFBD800AFFBB7F0EFFBB7D13FFBE8119FFB87B13FFB5790FFF
+ B87D0FFFBB7F0EFFB77B09FFB87909FFB97A0AFFBC7E0CFFBC7E0CFFBB7D0BFF
+ BA7B0BFFBA7B0BFFB97A0CFFB8790BFFB8790BFFB8790BFFB8790BFFB8790BFF
+ A46A11FFA86E15FFAF731AFFAF731AFFAC7016FFAA6E14FFAB6E11FFAC6F11FF
+ AA6D0FFFAC7010FFAF7210FFAF7210FFAD710DFFAD710DFFB1730FFFB17412FF
+ B67919FFB5781AFFB57919FFB47818FFB27714FFB27714FFB47915FFB57A16FF
+ B57A16FFB37814FFB17613FFB37815FFB67A1AFFB67A1AFFB47719FFB17515FF
+ B67715FFB57713FFB87B1BFFB87B1DFFB2741AFFB57822FFBE822EFFC18533FF
+ B77C2CFFB87D2DFFBC8230FFC08634FFC48834FFC18630FFBD802AFFBA7D20FF
+ B77A18FFB67812FFB47612FFB77915FFBB7E1CFFBF8222FFBF8222FFBD7F21FF
+ BA7D1FFFB77A1CFFB07518FFAE7316FFB2771AFFB87C22FFB87C22FFB4781EFF
+ C4882FFFBE8228FFBC7F22FFB77A1DFFB37517FFB77A1AFFC0811FFFC38422FF
+ B97B17FFBD7F1BFFBA7D1BFFB67917FFB47818FFBA7E1EFFBB8122FFBA8021FF
+ BF8024FFC28426FFBE8222FFB77B1BFFB97D1DFFC18426FFBF8329FFB97D23FF
+ C08528FFBC8222FFB6801BFFB37D18FFB27A1BFFB2791EFFB57B29FFB67F36FF
+ AB7D43FFC8A87FFFF1E3D1FFF6F4F3FFE8ECF1FFE6ECF3FFEDEFF0FFF1EFEEFF
+ ECECECFFECEEEFFFECEFF3FFEFF2F6FFF2F4F5FFF3F5F6FFF0F3F7FFF0F3F7FF
+ EAECEDFFECEEEFFFF2F7F6FFF6F8F8FFF3EEEDFFDBCAC1FFBD9F86FFC0976AFF
+ B27F39FFC58F38FFC3892AFFC18422FFBB7D1FFFB47618FFBB7E1CFFBB8118FF
+ BE8014FFBD8012FFB87B0DFFB77A0CFFBD8012FFBF8214FFBC7F11FFBD8012FF
+ C08315FFBC7F11FFBA7D0FFFBC7F11FFBD8012FFBD8012FFBE8113FFC08413FF
+ BD7F0DFFBD800CFFBC7D0DFFBB7C0CFFBC7C10FFBD7D11FFBE7F11FFBE7F0FFF
+ C18311FFBE810DFFBB7E08FFBA7D07FFBB7D0BFFBC7D0DFFBA7B0DFFB97A0CFF
+ BB7D0BFFB87B07FFB77907FFB87A08FFBA7B0BFFBC7D0DFFBB7C0EFFBA7B0DFF
+ C18214FFBB7C0EFFB87909FFBA7B0BFFBE800EFFBE800EFFBE810DFFBC810DFF
+ C58917FFC08714FFBE8210FFBA7E0CFFB77B0AFFB77B0AFFBB7C0CFFBC7D0DFF
+ BE7F0FFFBE800EFFBF800EFFBF800DFFBE800AFFBC7F07FFBC7D05FFB97B05FF
+ C08010FFBE7F11FFBE7F11FFBD7E10FFBC7D0DFFBC7D0DFFBB7D0BFFBB7D0BFF
+ BB7E0AFFBB7E0AFFBB7E08FFBB7E08FFBB7F07FFBB7F07FFBB7F07FFBB7E08FF
+ BA7D09FFB97B09FFC48418FFCA8A1EFFBF8010FFB97C08FFBB7E08FFBC7F0BFF
+ C68719FFC9881FFFC58519FFBD7E0EFFB97C08FFBB7E08FFBE7F0FFFBD7E10FF
+ BC7D0FFFBB7C0EFFB97B09FFB97C08FFBA7D07FFBA7E06FFBA7D07FFBA7D09FF
+ BB7D0BFFBC7D0DFFBE7F0FFFBF8010FFBF810FFFBE810DFFBC7F09FFBB7E08FF
+ BA7D09FFBB7D0BFFBB7C0CFFBC7D0FFFBC7D0DFFBB7D0BFFBB7E08FFBA7E06FF
+ B57901FFB87B05FFC28315FFCD8D21FFCD8B24FFC38219FFB9790DFFB77609FF
+ BD7B0BFFBF7B0AFFBD7E06FFBB7F04FFBC8005FFBB7E08FFB97D0CFFB97B11FF
+ C3861EFFBB7E16FFB67A10FFB67B0DFFB87C0BFFB67A08FFB97A0AFFBC7D0FFF
+ BE7E12FFBE7D14FFBD7C13FFBC7C10FFBC7C10FFBB7C0EFFBA7B0DFFBA7B0DFF
+ B8790BFFB8790BFFB8790BFFAF7417FFAF7417FFAF7215FFAD7013FFAC6F11FF
+ AD7012FFB17414FFB47715FFAC6F0DFFAE720EFFB2740EFFB3750FFFB2750DFF
+ B2750DFFB6770FFFB77913FFB87A16FFB77A18FFB87C18FFB57915FFB27710FF
+ B1760FFFB47A11FFB67C13FFBB8118FFB97F16FFB77C15FFB77C15FFB77B17FF
+ B87C18FFB77A18FFB57816FFBB7D19FFBA7C18FFBF8222FFBF8224FFB5771DFF
+ B2751FFFB57925FFB37725FFB07525FFB67B2BFFBB812FFFB97F2DFFB67A26FF
+ B37822FFB87B25FFBF8225FFBC7F1DFFC0821CFFC0821CFFBD7F19FFB67A16FF
+ B47814FFB77A18FFBA7D1BFFC88C2CFFC58929FFBA7F22FFB2771AFFB4781FFF
+ BD8128FFBF822CFFB97C26FFBF822CFFBA7E25FFBE7F27FFBD8023FFB6771BFF
+ BA7D1DFFC68627FFC68725FFB97B17FFBD7F1BFFB97D19FFB37713FFB07512FF
+ B77C19FFBC8222FFBE8425FFB8791DFFC18226FFC18426FFBB7F1FFFBC8020FF
+ C28626FFBB8023FFAE7415FFBA8021FFB77E1BFFB57F1AFFB57F1AFFB37B1CFF
+ B57B22FFC08535FFCA934EFFBF9560FFDDC19EFFFFFBEEFFF8FAFBFFE2E9F2FF
+ EBF2FBFFEFF1F2FFF0EEEDFFECECECFFEBEDEDFFEDEEF2FFEDF0F4FFF1F3F4FF
+ F1F5F6FFF2F5FAFFF2F7FAFFF7FAFEFFEAEEEFFFE9EDEEFFF1F1F1FFFFF3F1FF
+ DEC8BCFFAD8C6BFFB98D58FFAB7A2CFFC28B30FFBA7D1FFFB47618FFB6771BFF
+ B57719FFBE801AFFBF8417FFC4861AFFC38618FFB97C0EFFB5780AFFBE8113FF
+ BE8113FFB87B0DFFBB7E10FFC38618FFBC7F11FFB97C0EFFBF8214FFC18416FF
+ BD8012FFBC7F11FFBF8312FFBF810FFFBE810DFFBD7E0EFFBC7D0DFFBC7C10FF
+ BD7D11FFBE7F11FFBE7F0FFFBD7F0DFFBA7D09FFB87B05FFB97C06FFBB7D0BFF
+ BD7E0EFFBD7E10FFBC7D0FFFBE800EFFBB7E0AFFB97B09FFB97B09FFBB7C0CFF
+ BD7E0EFFBE7F11FFBD7E10FFCB8C1EFFC08113FFB97A0AFFBC7D0DFFBE800EFF
+ BB7D0BFFB87B07FFB87D09FFB97E0AFFB77E0AFFBA7E0CFFBA7E0CFFB97D0CFF
+ B87C0BFFB97A0CFFB8790BFFBB7C0EFFBB7C0CFFBD7D0DFFBE7F0CFFBE800AFF
+ BE8207FFBF8006FFBD8008FFC18111FFC08014FFBF7F13FFBE7E12FFBD7E10FF
+ BC7D0DFFBB7C0CFFBB7D0BFFBA7D09FFBB7E08FFBB7E08FFBC8008FFBC8106FF
+ BB8005FFBB8005FFBA7F04FFC0830DFFB77A06FFB9790DFFBE7E12FFBA7B0DFF
+ B87A08FFBB7E0AFFB97C08FFB7780AFFBC7D0FFFBD7E10FFB97B09FFB87B05FF
+ BD800AFFC18214FFC08113FFB57606FFB67905FFB87B07FFBA7D07FFBA7E06FF
+ BA7E06FFBA7D09FFBA7C0AFFBC7D0DFFBD7E10FFC08014FFC18214FFC18212FF
+ C0830FFFBD800CFFBC7F09FFBA7D09FFBB7D0BFFBB7C0CFFBC7D0FFFBC7D0DFF
+ BB7D0BFFBB7E08FFBA7E06FFBB7F07FFB97C06FFBB7C0EFFC08014FFC07E17FF
+ BB7A11FFB9790DFFBC7B0EFFBD7B0BFFBF7B0AFFBD7E06FFBB7F04FFBB7F04FF
+ BA7D07FFB87C0BFFB7790FFFCB8E26FFC1841CFFBA7E14FFB97E10FFBA7E0DFF
+ B97D0BFFBD7E0EFFC18214FFBB7912FFBC7A14FFBC7A13FFBD7C13FFBE7D14FF
+ BE7E12FFBF8012FFBF8012FFBD7E10FFBD7E10FFBD7D11FF}
+ Color = clBtnShadow
+ ParentColor = False
+ Scale = 1.000000000000000000
+ ScrollBars.Color = clBtnShadow
+ ScrollBars.ShowHandleGrip = True
+ ScrollBars.Style = rbsDefault
+ SizeGrip = sgAuto
+ TabOrder = 0
+ end
+ object RadioGroup1: TRadioGroup
+ Left = 394
+ Top = 20
+ Width = 109
+ Height = 185
+ Anchors = [akTop, akRight]
+ Caption = 'Operation'
+ ItemIndex = 0
+ Items.Strings = (
+ 'Opaque'
+ 'Add'
+ 'Sub'
+ 'Modulate'
+ 'Min'
+ 'Max'
+ 'Difference'
+ 'Exclusion'
+ 'Pattern')
+ TabOrder = 1
+ OnClick = RadioGroup1Click
+ end
+end
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,132 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ GR32, GR32_Image, GR32_Layers, GR32_Blend, StdCtrls, ExtCtrls;
+
+type
+ TForm1 = class(TForm)
+ ImgView: TImgView32;
+ RadioGroup1: TRadioGroup;
+ procedure FormCreate(Sender: TObject);
+ procedure RadioGroup1Click(Sender: TObject);
+ protected
+ procedure PC_Add(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Sub(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Modulate(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Min(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Max(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Difference(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Exclusion(F: TColor32; var B: TColor32; M: TColor32);
+ procedure PC_Pattern(F: TColor32; var B: TColor32; M: TColor32);
+ public
+ PatCount: Integer;
+ L: TBitmapLayer;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.DFM}
+
+procedure TForm1.FormCreate(Sender: TObject);
+var
+ I, J: Integer;
+begin
+ L := TBitmapLayer.Create(ImgView.Layers);
+ L.Bitmap.SetSize(200, 200);
+ L.Bitmap.DrawMode := dmCustom;
+ L.Location := FloatRect(20, 20, 220, 220);
+ for J := 0 to 199 do
+ for I := 0 to 199 do
+ L.Bitmap[I, J] := Gray32(Round(((Sin(I / 10) + Sin(J / 10)) * 0.25 + 0.5) * 255));
+ L.Bitmap.OnPixelCombine := nil; // none by default
+end;
+
+procedure TForm1.PC_Add(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorAdd(F, B);
+end;
+
+procedure TForm1.PC_Max(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorMax(F, B);
+end;
+
+procedure TForm1.PC_Min(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorMin(F, B);
+end;
+
+procedure TForm1.PC_Modulate(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorModulate(F, B);
+end;
+
+procedure TForm1.PC_Pattern(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ PatCount := 1 - PatCount;
+ if PatCount = 0 then B := F;
+end;
+
+procedure TForm1.PC_Sub(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorSub(F, B);
+end;
+
+procedure TForm1.PC_Difference(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorDifference(F, B);
+end;
+
+procedure TForm1.PC_Exclusion(F: TColor32; var B: TColor32; M: TColor32);
+begin
+ B := ColorExclusion(F, B);
+end;
+
+procedure TForm1.RadioGroup1Click(Sender: TObject);
+begin
+ case RadioGroup1.ItemIndex of
+ 0: L.Bitmap.OnPixelCombine := nil;
+ 1: L.Bitmap.OnPixelCombine := PC_Add;
+ 2: L.Bitmap.OnPixelCombine := PC_Sub;
+ 3: L.Bitmap.OnPixelCombine := PC_Modulate;
+ 4: L.Bitmap.OnPixelCombine := PC_Min;
+ 5: L.Bitmap.OnPixelCombine := PC_Max;
+ 6: L.Bitmap.OnPixelCombine := PC_Difference;
+ 7: L.Bitmap.OnPixelCombine := PC_Exclusion;
+ 8: L.Bitmap.OnPixelCombine := PC_Pattern;
+ end;
+ L.Bitmap.Changed;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,49 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="PixelCombine_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj PixelCombine_Ex.obj"/>
+ <RESFILES value="PixelCombine_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="Vcl50.lib GR32_CB5.lib"/>
+ <PACKAGES value="Vcl50.bpi Vclx50.bpi bcbsmp50.bpi Vcldb50.bpi vclado50.bpi ibsmp50.bpi
+ VCLBDE50.bpi vcldbx50.bpi Qrpt50.bpi TeeUI50.bpi TeeDB50.bpi Tee50.bpi
+ Dss50.bpi TeeQR50.bpi VCLIB50.bpi Vclmid50.bpi vclie50.bpi Inetdb50.bpi
+ Inet50.bpi NMFast50.bpi webmid50.bpi bcbie50.bpi dclocx50.bpi
+ bcb2kaxserver50.bpi GR32_CB5.bpi TB2K_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="PixelCombine_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("PixelCombine_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, Form1);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TForm1), &Form1);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program PixelCombine_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelCombine_Ex/PixelCombine_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/MainUnit.dfm
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/MainUnit.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/MainUnit.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,9260 @@
+object MainForm: TMainForm
+ Left = 272
+ Top = 282
+ BorderStyle = bsToolWindow
+ Caption = 'PixelF Example'
+ ClientHeight = 258
+ ClientWidth = 459
+ Color = clBtnFace
+ Constraints.MaxHeight = 285
+ Constraints.MaxWidth = 467
+ Constraints.MinHeight = 285
+ Constraints.MinWidth = 467
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poScreenCenter
+ OnClose = FormClose
+ OnCreate = FormCreate
+ DesignSize = (
+ 459
+ 258)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Image32: TImage32
+ Left = 8
+ Top = 8
+ Width = 300
+ Height = 244
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ AutoSize = True
+ Bitmap.DrawMode = dmBlend
+ Bitmap.Data = {
+ 2C010000F4000000C2D7D4FFACC1BEFFA7BCB9FFBACFCCFFBDD2CFFFAABFBCFF
+ A2B7B4FFAABFBCFFB6CBC8FF97ACA9FF9EB3B0FFB9CECBFFBACFCCFFB5CAC7FF
+ B0C5C2FFA1B6B3FFAEC3C0FFACC1BEFFB1C6C3FFB6CBC8FFB1C6C3FFA3B8B5FF
+ 9DB2AFFF9FB4B1FF9BB0ADFF9CB1AEFF90A5A2FF8BA09DFF738885FF687D7AFF
+ 7E9390FF79908CFF778E8AFF748D89FF768F8BFF7B9490FF819894FF7F9692FF
+ 7D9490FF7D9490FF859A97FF7E9390FF7C918EFF819693FF8A9D9AFF8DA09DFF
+ 92A5A2FF97AAA7FF889B98FF94A7A4FF94A7A4FF869996FF849794FF9BAEABFF
+ B8CBC8FFC6D9D6FFB7CAC7FFA7BAB7FFA6B9B6FFADC0BDFFAABDBAFFAEC1BEFF
+ B9CCC9FFBACFCCFFA4B9B6FFB4CBC7FFB9CECBFFBACFCCFFC3D8D5FFC1D6D3FF
+ B8CBC8FFB7CAC7FFB8C9C6FFAFC0BDFF9EAFACFFA4B5B2FFAAB8B6FF7F8D8BFF
+ 374543FF818F8DFF7D8C88FF94A39FFF97A6A2FF8E9D99FF91A09CFF95A4A0FF
+ 94A39FFF97A6A2FF8B9A96FF8B9A96FF8A9995FF8A9995FF8A9995FF899894FF
+ 879692FF869591FF80928BFF8A9F97FF99ADA8FFA0B6B1FFD1E7E5FFC3DBD9FF
+ B7CFCFFFB1CBCBFFB7D1D1FFB0CACAFFBCD2D0FFB9D0CCFFADC2BFFFBFD5D0FF
+ D4E6DFFFC1D6CEFFC5DCD8FFC7E0DCFFD3ECE8FFD9F2EEFFC9E4E0FFB4CFCBFF
+ B2CDC9FFBFDAD6FFC3E1DCFFC7E5E0FFC2E2DDFFB8D8D3FFB2D2CDFFB2D2CDFF
+ ABCDC7FFA2C4BEFF82A09BFFACCAC5FFB5D3CEFFA8C6C1FFADCBC6FFAAC8C3FF
+ A2BDB9FFA9C4C0FFC9E2DEFFD5EEEAFFDCF3EFFFD5ECE8FFD0E7E3FFD0E7E3FF
+ CAE1DDFFBFD8D4FFB1D1CCFFABCBC6FFA5C3BEFF99B2AEFF7A8F8CFF556663FF
+ 3E4B49FF384341FF676D6CFF6A706FFFA5ABAAFFB1B9B8FF9AA2A1FF879290FF
+ 7B8886FF9BA9A7FF83928EFF7D8E8AFF7F908CFF8A9B97FF94A5A1FF93A4A0FF
+ 8A9B97FF82938FFF99AAA6FFA5B6B2FFA9BAB6FF9EAFABFF94A5A1FF93A4A0FF
+ 97A8A4FF97A8A4FF93A1A0FF879594FF99A9A8FFA0B0AFFF8E9E9DFFA5B5B4FF
+ C4D6D5FFBACCCBFFBED3D1FFB1C6C4FFA6BBB9FFA2B7B5FF98AEACFF879D9BFF
+ 768C8AFF6F8481FF4C5957FF4C5754FF5D6B67FF677571FF5C6A66FF677571FF
+ 7C8B87FF7B8A86FF768783FF7D8E8AFF81928EFF7F908CFF7D918CFF80948FFF
+ 839792FF829691FF859391FF8B9997FF8B9997FF849290FF82908EFF889694FF
+ 8B9997FF899795FF889694FF889694FF889694FF889694FF879593FF869492FF
+ 849290FF83918FFF84938FFF83928EFF84928EFF85938FFF869490FF85938FFF
+ 848F8CFF808B88FF767F7CFF4E5754FF818A87FF7C8582FF7C8380FF828986FF
+ 828986FF77807DFF8B9491FF8C9794FF8E9C98FF95A39FFF9CAAA6FFA4B2AEFF
+ A8B7B3FFACBBB7FFA1B2AEFFA1B2AEFFA2B3AFFFA3B4B0FFA3B7B2FFA4B8B3FF
+ A5B9B4FFA5B9B4FFAEC2BDFFA8BCB7FFA7BBB6FFADC1BCFFB0C4BFFFAABEB9FF
+ A1B5B0FF9DB1ACFF9CB0ABFFA2B6B1FFA5B9B4FFA3B7B2FFA2B6B1FFA2B6B1FF
+ 9DB1ACFF97ACA4FF93AAA2FF96AEA4FFA6BEB4FFBED6CCFFC7DED6FFBBD2CAFF
+ ADC4BCFFA8BFB7FF9DB3AEFF9EB4AFFF9EB3B0FF9DB2AFFF99AEABFF93A8A5FF
+ 8DA2A0FF8C9F9CFF80918EFF7B8A86FF798884FF6A7975FF4F5E5AFF4A5955FF
+ 566561FF5B6A66FF5D6C68FF5F6E6AFF5F6E6AFF5E6D69FFB5CAC7FF9DB2AFFF
+ 93A8A5FFA2B7B4FFAFC4C1FFAABFBCFFA4B9B6FFA5BAB7FFBCD1CEFFA1B6B3FF
+ 96ABA8FFA0B5B2FFACC1BEFFB5CAC7FFB8CDCAFFB2C7C4FFAEC3C0FFADC2BFFF
+ B0C5C2FFB3C8C5FFADC2BFFFA2B7B4FF9DB2AFFFA0B5B2FF9CB1AEFF9DB2AFFF
+ 91A6A3FF8A9F9CFF6F8481FF627774FF768B88FF728784FF6B827EFF67807CFF
+ 68817DFF6F8884FF7B928EFF849B97FF8AA19DFF8EA5A1FF8BA09DFF879C99FF
+ 859A97FF849996FF839693FF829592FF8B9E9BFF96A9A6FF95A8A5FF889B98FF
+ 869996FF8EA19EFF8C9F9CFF8B9E9BFFA7BAB7FFCEE1DEFFB9CCC9FFA7BAB7FF
+ A5B8B5FFABBEBBFFA9BCB9FFAEC1BEFFB7CAC7FFB5CAC7FFAABFBCFFB8CFCBFF
+ BACFCCFFB8CDCAFFC0D5D2FFC0D5D2FFBBCECBFFBDD0CDFFC1D2CFFFB8C9C6FF
+ A6B7B4FFA7B8B5FFABB9B7FF82908EFF2E3C3AFF667472FF758480FF879692FF
+ 8A9995FF859490FF889793FF879692FF869591FF8E9D99FF8F9E9AFF92A19DFF
+ 94A39FFF93A29EFF8F9E9AFF8A9995FF899894FF899894FF82948DFF8A9C95FF
+ 92A6A1FF95ABA6FFCBE1DFFFC8E0DEFFBFD7D7FFB0CACAFF8EA8A8FF7D9797FF
+ 8FA5A3FFA4BBB7FFA5BAB7FFAFC3BEFFBFD1CAFFBCD1C9FFB4CBC7FFB9D2CEFF
+ C8E1DDFFD3ECE8FFCCE5E1FFBCD7D3FFC0DBD7FFCFEAE6FFBEDCD7FFC7E5E0FF
+ CAE8E3FFC4E4DFFFBEDED9FFB7D7D2FFA9CBC5FF9DBDB8FF7E9C97FFAFCDC8FF
+ BCDAD5FFAFCDC8FFB9D7D2FFC0DED9FFB5D0CCFFACC7C3FFC9E2DEFFD6EFEBFF
+ DCF3EFFFD2E9E5FFCCE3DFFFCFE6E2FFD2E9E5FFCDE6E2FFC1DFDAFFB4D4CFFF
+ A9C7C2FF9FB8B4FF879C99FF657673FF475452FF384341FF696F6EFF6A706FFF
+ 858B8AFF959D9CFF98A3A1FF929D9BFF83908EFF8A9896FF97A6A2FF91A29EFF
+ 8C9D99FF8A9B97FF8D9E9AFF92A39FFF93A4A0FF91A29EFF8A9B97FF9EAFABFF
+ ACBDB9FFA5B6B2FF98A9A5FF93A4A0FF95A6A2FF96A7A3FF8D9B99FF82908FFF
+ 93A3A2FF9CACABFF90A09FFFA6B6B5FFBFD1D0FFB3C5C4FFBCD1CFFFB8CDCBFF
+ B1C6C4FFA9BEBCFF9CB2B0FF8AA09EFF758B89FF687D7AFF3E4C48FF485350FF
+ 596763FF62706CFF5E6C68FF65736FFF73827EFF788783FF778884FF7C8D89FF
+ 7F908CFF7D8E8AFF7C908BFF7F938EFF80948FFF7E928DFF82908EFF889694FF
+ 899795FF849290FF83918FFF899795FF8D9B99FF8B9997FF899795FF899795FF
+ 8A9896FF8A9896FF8B9997FF8A9896FF8A9896FF8A9896FF859490FF84938FFF
+ 83918DFF84928EFF85938FFF84928EFF848F8CFF818C89FF79827FFF505956FF
+ 838C89FF7F8885FF7F8683FF858C89FF868D8AFF7C8582FF87908DFF8A9592FF
+ 909E9AFF98A6A2FF9FADA9FFA4B2AEFFA5B4B0FFA5B4B0FFA2B3AFFFA4B5B1FF
+ A7B8B4FFA8B9B5FFA5B9B4FFA2B6B1FF9EB2ADFF9BAFAAFFA6BAB5FFA6BAB5FF
+ A9BDB8FFAFC3BEFFAEC2BDFFA7BBB6FFA3B7B2FFA4B8B3FFA1B5B0FFA4B8B3FF
+ A4B8B3FFA0B4AFFF9FB3AEFFA2B6B1FFA2B6B1FF9EB3ABFF97AEA6FF98B0A6FF
+ A6BEB4FFBED6CCFFC6DDD5FFBAD1C9FFAAC1B9FFA4BBB3FF9EB4AFFF9EB4AFFF
+ 9FB4B1FF9EB3B0FF9AAFACFF94A9A6FF8EA3A1FF8C9F9CFF81928FFF7C8B87FF
+ 778682FF657470FF485753FF43524EFF53625EFF5A6965FF5E6D69FF606F6BFF
+ 62716DFF61706CFFB9CECBFFA3B8B5FF94A9A6FF9AAFACFFA7BCB9FFA7BCB9FF
+ 98ADAAFF8BA09DFFA3B8B5FFA0B5B2FF94A9A6FF95AAA7FFADC2BFFFBDD2CFFF
+ B9CECBFFB4C9C6FFB4C9C6FFB2C7C4FFB1C6C3FFB0C5C2FFA8BDBAFF9EB3B0FF
+ 9AAFACFF9BB0ADFF9AAFACFF9BB0ADFF8EA3A0FF859A97FF697E7BFF5C716EFF
+ 718683FF6E8380FF728985FF6D8480FF69807CFF6A817DFF738A86FF7E9591FF
+ 879C99FF8BA09DFF869B98FF889D9AFF899E9BFF859A97FF7D928FFF7B908DFF
+ 8B9E9BFF9DB0ADFFA0B3B0FF8C9F9CFF879A97FF90A3A0FF8A9D9AFF809390FF
+ 98ABA8FFC1D4D1FFBBCECBFFA9BCB9FFA6B9B6FFAEC1BEFFB0C3C0FFB6C9C6FF
+ BACDCAFFB1C6C3FFABC0BDFFB6CDC9FFB4C9C6FFADC2BFFFB4C9C6FFB6CBC8FF
+ B7CAC7FFBED1CEFFB4C5C2FFB1C2BFFFA4B5B2FFA5B6B3FFAFBDBBFF96A4A2FF
+ 414F4DFF677573FF788783FF83928EFF869591FF879692FF8B9A96FF84938FFF
+ 83928EFF92A19DFF909F9BFF94A39FFF97A6A2FF96A5A1FF91A09CFF8D9C98FF
+ 8B9A96FF8C9B97FF80928BFF869891FF8EA29DFF90A6A1FFC8DEDCFFD0E8E6FF
+ C5DDDDFFA6C0C0FF758F8FFF5A7474FF6B817FFF93AAA6FFA1B6B3FFA2B6B1FF
+ B0C2BBFFBCD1C9FFB1C6C3FFB6CDC9FFC3DAD6FFCAE3DFFFC4DDD9FFBAD3CFFF
+ BDD8D4FFCBE6E2FFC0DBD7FFC6E4DFFFCBE9E4FFC9E7E2FFC3E3DEFFBDDDD8FF
+ B2D2CDFFA8C8C3FF7D9B96FFADCBC6FFBFDAD6FFB3CECAFFBDD8D4FFCAE5E1FF
+ BED7D3FFA8C1BDFFC7DEDAFFD6EDE9FFDDF4F0FFD5ECE8FFD0E5E2FFD4E9E6FF
+ D9EEEBFFD5EEEAFFCCEAE5FFBBDBD6FFAECCC7FFA9C2BEFF9BB0ADFF7F908DFF
+ 5C6967FF46514FFF515756FF717776FF798180FF848C8BFF879290FF7E8987FF
+ 828F8DFF849290FF8D9C98FF96A7A3FF9BACA8FF94A5A1FF8D9E9AFF8C9D99FF
+ 869793FF7D8E8AFF7F908CFF96A7A3FFAABBB7FFA9BAB6FF9BACA8FF91A29EFF
+ 90A19DFF92A39FFF99A7A5FF8C9A98FF93A19FFF95A3A1FF899A97FF9DAEABFF
+ B1C4C1FFA7BAB7FFAABDBAFFB0C3C0FFABC0BDFF9DB2AFFF8FA6A2FF839A96FF
+ 718884FF617673FF4C5A56FF5E6966FF63716DFF63716DFF667470FF667470FF
+ 6B7A76FF798884FF7B8C88FF7E8F8BFF7F908CFF7E8F8BFF7E928DFF839792FF
+ 829691FF7D918CFF818F8DFF869492FF879593FF849290FF83918FFF879593FF
+ 8B9997FF8A9896FF889694FF899795FF899795FF8A9896FF8B9997FF8C9A98FF
+ 8D9B99FF8D9B99FF8B9A96FF889793FF879591FF869490FF879591FF879591FF
+ 889390FF86918EFF828B88FF565F5CFF87908DFF838C89FF828986FF868D8AFF
+ 868D8AFF7E8784FF828B88FF87928FFF909E9AFF9BA9A5FFA1AFABFFA3B1ADFF
+ A0AFABFF9EADA9FF9EAFABFFA2B3AFFFA8B9B5FFACBDB9FFA9BDB8FFA3B7B2FF
+ 9CB0ABFF97ABA6FF9EB2ADFFA2B6B1FFA9BDB8FFAEC2BDFFAABEB9FFA3B7B2FF
+ A4B8B3FFAABEB9FFA5B9B4FFA9BDB8FFAABEB9FFA7BBB6FFA7BBB6FFAABEB9FF
+ A8BCB7FFA4B9B1FF9DB4ACFF9AB2A8FFA6BEB4FFBCD4CAFFC6DDD5FFBAD1C9FF
+ A8BFB7FF9FB6AEFF9EB4AFFF9FB5B0FFA0B5B2FF9EB3B0FF9AAFACFF95AAA7FF
+ 8FA4A2FF8DA09DFF81928FFF7C8B87FF768581FF61706CFF42514DFF3D4C48FF
+ 4E5D59FF576662FF556460FF596864FF5F6E6AFF63726EFFC6DBD8FFBACFCCFF
+ ADC2BFFFAABFBCFFB0C5C2FFAFC4C1FF9AAFACFF839895FF8A9F9CFF9FB4B1FF
+ 95AAA7FF8BA09DFFA5BAB7FFB8CDCAFFB4C9C6FFB5CAC7FFB9CECBFFB7CCC9FF
+ B4C9C6FFAEC3C0FFA4B9B6FF9BB0ADFF96ABA8FF95AAA7FF97ACA9FF97ACA9FF
+ 889D9AFF7E9390FF627774FF576C69FF718683FF718683FF79908CFF778E8AFF
+ 728985FF6D8480FF708783FF788F8BFF7E9390FF7E9390FF879C99FF889D9AFF
+ 8A9F9CFF889D9AFF7F9491FF7C918EFF889B98FF97AAA7FF9AADAAFF99ACA9FF
+ 96A9A6FF91A4A1FF8DA09DFF94A7A4FFA8BBB8FFBCCFCCFFC8DBD8FFB6C9C6FF
+ B2C5C2FFB8CBC8FFB8CBC8FFBACDCAFFB3C6C3FFA0B5B2FFA7BCB9FFB1C8C4FF
+ ACC1BEFFA1B6B3FFA5BAB7FFA9BEBBFFAFC2BFFFBBCECBFFA7B8B5FFA7B8B5FF
+ A0B1AEFF9FB0ADFFACBAB8FFA6B4B2FF5D6B69FF7A8886FF7F8E8AFF859490FF
+ 889793FF8F9E9AFF93A29EFF899894FF899894FF9EADA9FF92A19DFF91A09CFF
+ 909F9BFF909F9BFF909F9BFF8F9E9AFF8D9C98FF8B9A96FF7D8F88FF82948DFF
+ 8DA19CFF8FA5A0FFC7DCDAFFD7EDEBFFCBE3E3FF9FB9B9FF7B9595FF617979FF
+ 637977FF829995FF99ACA9FF9BAFAAFFA8BAB3FFB7CCC4FFAABFBCFFB0C7C3FF
+ BBD2CEFFC2D9D5FFBCD3CFFFB3CCC8FFB8D1CDFFC2DDD9FFC7E2DEFFC7E2DEFF
+ C6E1DDFFC2E0DBFFC1DFDAFFC1E1DCFFC2E2DDFFC2E2DDFF91AFAAFFAECCC7FF
+ BFDAD6FFB9D4D0FFBAD5D1FFBED9D5FFB8D1CDFFABC4C0FFBED5D1FFCDE4E0FF
+ D7EEEAFFD4EBE7FFD3E8E5FFD6EBE8FFD6EBE8FFCFE6E2FFCEE9E5FFC1DFDAFF
+ B7D2CEFFB3CCC8FFADC2BFFF98A9A6FF788583FF606B69FF394140FF6E7675FF
+ 727A79FF7D8584FF7D8886FF6E7977FF7C8987FF798684FF6F7E7AFF839490FF
+ 92A39FFF8D9E9AFF859692FF849591FF7F908CFF758682FF82938FFF93A4A0FF
+ A3B4B0FFA5B6B2FF9CADA9FF95A6A2FF94A5A1FF97A8A4FFA1AFADFF96A4A2FF
+ 95A3A1FF909E9CFF879895FF9CADAAFFB6C7C4FFB5C8C5FFB7CAC7FFC2D5D2FF
+ BCD1CEFFA4B9B6FF8EA5A1FF829995FF6D8480FF5A6D6AFF3D4B47FF535E5BFF
+ 515F5BFF4F5D59FF5E6C68FF62706CFF677672FF808F8BFF778884FF7A8B87FF
+ 7B8C88FF7A8B87FF7D918CFF839792FF829691FF7C908BFF83918FFF859391FF
+ 879593FF859391FF83918FFF849290FF869492FF879593FF879593FF879593FF
+ 879593FF879593FF879593FF889694FF899795FF8A9896FF8C9B97FF889793FF
+ 85938FFF83918DFF84928EFF85938FFF86918EFF85908DFF87908DFF58615EFF
+ 88918EFF848D8AFF818885FF838A87FF838A87FF7D8683FF828B88FF87928FFF
+ 8F9D99FF99A7A3FF9FADA9FFA0AEAAFF9DACA8FF9BAAA6FF97A8A4FF9CADA9FF
+ A3B4B0FFA9BAB6FFA9BDB8FFA7BBB6FFA2B6B1FF9FB3AEFF9DB1ACFF9FB3AEFF
+ A5B9B4FFAABEB9FFA7BBB6FFA0B4AFFFA1B5B0FFA7BBB6FF9EB2ADFFA5B9B4FF
+ AABEB9FFAABEB9FFAABEB9FFA9BDB8FFA4B8B3FF9DB2AAFF9EB5ADFF9BB3A9FF
+ A5BDB3FFBBD3C9FFC5DCD4FFB9D0C8FFA7BEB6FF9EB5ADFF9FB5B0FF9FB5B0FF
+ A0B5B2FF9FB4B1FF9BB0ADFF95AAA7FF8FA4A2FF8DA09DFF80918EFF7C8B87FF
+ 778682FF63726EFF43524EFF3D4C48FF4C5B57FF53625EFF54635FFF596864FF
+ 606F6BFF64736FFFC5DAD7FFC1D6D3FFB6CBC8FFAEC3C0FFB0C5C2FFB3C8C5FF
+ AABFBCFF9CB1AEFF8FA4A1FFA8BDBAFF98ADAAFF7B908DFF899E9BFFA2B7B4FF
+ ADC2BFFFB8CDCAFFB4C9C6FFB5CAC7FFB4C9C6FFAEC3C0FFA5BAB7FF9EB3B0FF
+ 99AEABFF95AAA7FF9AAFACFF99AEABFF889D9AFF7A8F8CFF5C716EFF526764FF
+ 6F8481FF728784FF6F8481FF758A87FF778C89FF738885FF738885FF7A8F8CFF
+ 7E9390FF7D928FFF8DA29FFF8A9F9CFF8A9F9CFF8A9F9CFF869B98FF809592FF
+ 819693FF869B98FF91A4A1FF95A8A5FF99ACA9FF9AADAAFF9BAEABFFA6B9B6FF
+ BACDCAFFC9DCD9FFCFE2DFFFBFD2CFFFBCCFCCFFBFD2CFFFBBCECBFFB8CBC8FF
+ A9BCB9FF8DA29FFFA7BCB9FFB2C9C5FFADC2BFFFA0B5B2FFA1B6B3FFA4B9B6FF
+ AEC1BEFFBCCFCCFFB0C1BEFFADBEBBFFA4B5B2FF99AAA7FF9BA9A7FF9EACAAFF
+ 616F6DFF7A8886FF7E8D89FF84938FFF879692FF8E9D99FF93A29EFF8A9995FF
+ 8C9B97FFA1B0ACFF9EADA9FF96A5A1FF8D9C98FF8B9A96FF8E9D99FF909F9BFF
+ 8C9B97FF869591FF82928BFF7D8F88FF879B96FF879D98FFB8CDCBFFD2E8E6FF
+ D7EFEFFFB2CACAFF89A1A1FF768E8EFF657B79FF687F7BFF7F928FFF8FA39EFF
+ 9DAFA8FFA8BAB3FF9AADAAFFA1B6B3FFB0C5C2FFB9D0CCFFBAD1CDFFB8D1CDFF
+ C1DAD6FFCBE4E0FFCEE7E3FFC8E3DFFFC4DFDBFFC0DED9FFC1DFDAFFC5E3DEFF
+ CBE9E4FFD0EEE9FFB7D2CEFFB7D2CEFFC2DBD7FFC9E2DEFFBFD8D4FFB5CECAFF
+ BAD1CDFFC0D7D3FFC2D7D4FFCCE1DEFFD0E5E2FFCCE1DEFFD0E3E0FFD7EAE7FF
+ D7EAE7FFCDE2DFFFCEE7E3FFC8E3DFFFC4DDD9FFC0D7D3FFB7CCC9FFA8B9B6FF
+ 8D9B99FF7A8583FF3B4644FF5B6362FF5C6463FF7A8281FF899492FF7D8886FF
+ 7F8C8AFF687573FF667571FF74837FFF7B8A86FF758480FF72817DFF7B8A86FF
+ 859490FF879692FF869591FF899894FF909F9BFF95A4A0FF97A6A2FF98A7A3FF
+ 9BAAA6FF9FAEAAFFA3B1AFFF9EACAAFF96A4A2FF859391FF768482FF798A87FF
+ 869794FF899A97FF91A4A1FFA5B8B5FFABC0BDFF9FB4B1FF92A7A4FF869B98FF
+ 6F8481FF576A67FF495753FF5A6562FF53615DFF4F5D59FF5E6C68FF5E6C68FF
+ 5D6C68FF707F7BFF6E7F7BFF72837FFF758682FF758682FF778B86FF7D918CFF
+ 7E928DFF7A8E89FF7F8D8BFF808E8CFF83918FFF859391FF849290FF83918FFF
+ 859391FF899795FF889694FF879593FF869492FF859391FF849290FF849290FF
+ 859391FF869492FF869591FF83928EFF7F8D89FF7D8B87FF7E8C88FF7E8C88FF
+ 808B88FF7E8986FF828B88FF505956FF808986FF7F8885FF7F8683FF818885FF
+ 848B88FF828B88FF848D8AFF87928FFF8D9B97FF95A39FFF9BA9A5FF9EACA8FF
+ 9EADA9FF9EADA9FF97A8A4FF9AABA7FF9FB0ACFFA4B5B1FFA5B9B4FFA6BAB5FF
+ A6BAB5FFA6BAB5FFA1B5B0FF9EB2ADFFA0B4AFFFA5B9B4FFA5B9B4FFA0B4AFFF
+ 9DB1ACFF9FB3AEFF98ACA7FF9CB0ABFF9CB0ABFF99ADA8FF99ADA8FF9BAFAAFF
+ 9AAEA9FF96ABA3FF9DB4ACFF9AB2A8FFA5BDB3FFBAD2C8FFC4DBD3FFB8CFC7FF
+ A7BEB6FF9FB6AEFF9EB4AFFF9FB5B0FF9FB4B1FF9EB3B0FF9AAFACFF94A9A6FF
+ 8EA3A1FF8DA09DFF7F908DFF7B8A86FF798884FF687773FF4B5A56FF43524EFF
+ 4D5C58FF505F5BFF5B6A66FF5F6E6AFF63726EFF63726EFFBCD1CEFFB5CAC7FF
+ A8BDBAFF9CB1AEFF98ADAAFF9DB2AFFFA2B7B4FFA2B7B4FF91A6A3FFA9BEBBFF
+ A4B9B6FF8A9F9CFF889D9AFF99AEABFFA1B6B3FFA1B6B3FFA8BDBAFFAFC4C1FF
+ B3C8C5FFB0C5C2FFAABFBCFFA6BBB8FF9FB4B1FF99AEABFF9FB4B1FF9FB4B1FF
+ 8EA3A0FF7E9390FF5C716EFF4F6461FF6A7F7CFF6D827FFF6B807DFF778C89FF
+ 7D908DFF718683FF6C7F7CFF708582FF788D8AFF798E8BFF839895FF7F9491FF
+ 809592FF889D9AFF8DA29FFF8CA19EFF8A9F9CFF8A9F9CFF98ABA8FF8DA09DFF
+ 8FA29FFF9CAFACFF9CAFACFF96A9A6FFA5B8B5FFBFD2CFFFB9CCC9FFAFC2BFFF
+ B1C4C1FFB8CBC8FFBACDCAFFBED1CEFFB3C6C3FF98ADAAFFAABFBCFFB8CFCBFF
+ B6CBC8FFA9BEBBFFA7BCB9FFA8BDBAFFB1C4C1FFC0D3D0FFB7C8C5FFABBCB9FF
+ A1B2AFFF95A6A3FF909E9CFF95A3A1FF5E6C6AFF758381FF7F8E8AFF899894FF
+ 8A9995FF8C9B97FF91A09CFF8C9B97FF8E9D99FF9EADA9FFAAB9B5FFA0AFABFF
+ 95A4A0FF91A09CFF91A09CFF8F9E9AFF899894FF83928EFF899992FF7C8C85FF
+ 849591FF7E928DFFA0B5B3FFC0D6D4FFE1F6F7FFCEE6E6FF91A9A9FF89A1A1FF
+ 6A807EFF576C69FF6B7E7BFF859692FF91A19AFF97A9A2FF92A5A2FF9CB1AEFF
+ ACC1BEFFB6CBC8FFBACFCCFFBDD4D0FFC4DBD7FFC9E2DEFFCEE7E3FFCBE4E0FF
+ CAE3DFFFCBE6E2FFCBE6E2FFC5E3DEFFC5E3DEFFCBE6E2FFCBE6E2FFB6CFCBFF
+ BCD5D1FFCDE6E2FFC0D9D5FFB2C9C5FFBAD1CDFFC6DDD9FFCADFDCFFD1E6E3FF
+ D0E5E2FFCADDDAFFCADDDAFFD6E9E6FFDCEFECFFD8EDEAFFD2E9E5FFD0E9E5FF
+ CFE6E2FFC8DDDAFFC0D3D0FFB3C4C1FF9FADABFF8C9997FF45504EFF45504EFF
+ 5C6765FF879290FF8D9896FF838E8CFF869391FF798684FF6D7C78FF707F7BFF
+ 73827EFF72817DFF6F7E7AFF6D7C78FF6E7D79FF6F7E7AFF73827EFF6E7D79FF
+ 6F7E7AFF778682FF808F8BFF859490FF8B9A96FF91A09CFF909E9CFF94A2A0FF
+ 8F9D9BFF849290FF7E8C8AFF7E8C8AFF7D8E8BFF7D8E8BFF7A8B88FF8C9F9CFF
+ 9DB0ADFF9DB2AFFF94A9A6FF819693FF627774FF485B58FF4A5854FF505B58FF
+ 4A5854FF4C5A56FF5A6864FF616F6BFF63726EFF6B7A76FF6F807CFF768783FF
+ 7A8B87FF7A8B87FF798D88FF7E928DFF819590FF80948FFF798785FF7A8886FF
+ 7E8C8AFF849290FF859391FF849290FF869492FF8C9A98FF8A9896FF889694FF
+ 869492FF849290FF83918FFF83918FFF849290FF859391FF879692FF84938FFF
+ 818F8BFF808E8AFF808E8AFF7F8D89FF808B88FF7E8986FF767F7CFF434C49FF
+ 747D7AFF79827FFF7C8380FF818885FF888F8CFF8B9491FF858E8BFF87928FFF
+ 8B9995FF92A09CFF99A7A3FF9EACA8FFA0AFABFFA1B0ACFF9EAFABFF9EAFABFF
+ A0B1ADFFA1B2AEFFA1B5B0FFA2B6B1FFA4B8B3FFA4B8B3FFA4B8B3FFA0B4AFFF
+ A0B4AFFFA4B8B3FFA4B8B3FF9FB3AEFF9CB0ABFF9DB1ACFFA1B5B0FF9FB3AEFF
+ 97ABA6FF8EA29DFF8DA19CFF94A8A3FF9AAEA9FF9CB1A9FF9CB3ABFF9BB3A9FF
+ A7BFB5FFBBD3C9FFC1D8D0FFB4CBC3FFA6BDB5FFA1B8B0FF9DB3AEFF9EB4AFFF
+ 9EB3B0FF9DB2AFFF99AEABFF93A8A5FF8DA2A0FF8B9E9BFF80918EFF7A8985FF
+ 778682FF6A7975FF52615DFF4C5B57FF52615DFF505F5BFF53625EFF576662FF
+ 5B6A66FF5D6C68FFB7CCC9FFADC2BFFFA1B6B3FF98ADAAFF93A8A5FF91A6A3FF
+ 95AAA7FF99AEABFF92A7A4FFA0B5B2FFABC0BDFFA1B6B3FF97ACA9FFA0B5B2FF
+ A0B5B2FF8DA29FFFA3B8B5FFAEC3C0FFB6CBC8FFB4C9C6FFAFC4C1FFAABFBCFF
+ A0B5B2FF96ABA8FF9CB1AEFFA0B5B2FF94A9A6FF879C99FF647976FF526764FF
+ 697E7BFF687D7AFF718481FF7E918EFF7F908DFF687B78FF5B6C69FF5F726FFF
+ 6F827FFF788B88FF7F928FFF7B8E8BFF7C918EFF859A97FF8EA3A0FF90A5A2FF
+ 90A5A2FF93A8A5FF9CAFACFF95A8A5FF91A4A1FF90A3A0FF8C9F9CFF8C9F9CFF
+ 9AADAAFFACBFBCFFAABDBAFFA3B6B3FFA8BBB8FFAFC2BFFFB5C8C5FFC1D4D1FF
+ C0D3D0FFAABFBCFFA5BAB7FFB7CECAFFB9CECBFFAEC3C0FFAABFBCFFA7BCB9FF
+ ADC0BDFFBBCECBFFB4C5C2FFA0B1AEFF99AAA7FF99AAA7FF98A6A4FF9DABA9FF
+ 63716FFF748280FF81908CFF909F9BFF909F9BFF899894FF8C9B97FF8B9A96FF
+ 8C9B97FF96A5A1FFA3B2AEFFA2B1ADFF9FAEAAFF9AA9A5FF94A39FFF8E9D99FF
+ 899894FF879692FF8F9F98FF7D8D86FF899A96FF80948FFF90A5A3FFA7BDBBFF
+ D6EBECFFD5EAEBFF99AEAFFF95AAABFF718684FF576C69FF687B78FF7A8B87FF
+ 809089FF899B94FF8FA29FFF9DB0ADFFACBFBCFFB2C7C4FFB5CAC7FFB8CDCAFF
+ BBD0CDFFBDD4D0FFCEE5E1FFC9E2DEFFCBE4E0FFD1EAE6FFD0E9E5FFC7E2DEFF
+ C5E0DCFFC7E2DEFFD0E9E5FFB4CBC7FFB7CECAFFC8DFDBFFBFD6D2FFB6CBC8FF
+ B7CCC9FFB0C5C2FFB3C6C3FFC3D6D3FFCCDFDCFFC6D7D4FFC0D1CEFFC7D8D5FF
+ D0E1DEFFD1E4E1FFD4E9E6FFD3EAE6FFCFE6E2FFCADFDCFFC8DBD8FFC2D3D0FF
+ B1BFBDFF9DABA9FF667371FF3A4745FF657270FF96A3A1FF8A9795FF83908EFF
+ 8B9896FF919E9CFF7D8C88FF758480FF758480FF7E8D89FF7C8B87FF6C7B77FF
+ 5F6E6AFF5E6D69FF62716DFF5E6D69FF606F6BFF687773FF6C7B77FF6C7B77FF
+ 6F7E7AFF768581FF717F7BFF788682FF788682FF818F8BFF9AA9A5FFAFBEBAFF
+ B5C4C0FFB7C8C4FFACBDB9FFAFC3BEFFB6CAC5FFB7CBC6FFACC0BBFF93A7A2FF
+ 728883FF5D716CFF465450FF35403DFF2A3834FF2E3C38FF3B4945FF566460FF
+ 6C7B77FF71807CFF71827EFF7B8C88FF82938FFF7E8F8BFF788C87FF7A8E89FF
+ 7F938EFF819590FF7C8A88FF7B8987FF7F8D8BFF859391FF859391FF808E8CFF
+ 82908EFF889694FF859391FF83918FFF818F8DFF7F8D8BFF7F8D8BFF808E8CFF
+ 82908EFF849290FF859490FF83928EFF82908CFF818F8BFF818F8BFF7F8D89FF
+ 7E8986FF7B8683FF717A77FF3D4643FF6E7774FF757E7BFF7A817EFF7E8582FF
+ 878E8BFF8C9592FF848D8AFF86918EFF8B9995FF93A19DFF9AA8A4FF9FADA9FF
+ A1B0ACFFA2B1ADFFA0B1ADFFA1B2AEFFA1B2AEFFA1B2AEFFA0B4AFFFA0B4AFFF
+ A1B5B0FFA1B5B0FFA3B7B2FFA4B8B3FFA7BBB6FFA9BDB8FFA4B8B3FF9EB2ADFF
+ 9EB2ADFFA4B8B3FFA8BCB7FFA6BAB5FF9FB3AEFF96AAA5FF94A8A3FF9AAEA9FF
+ 9FB3AEFF9FB4ACFF9CB3ABFF9FB7ADFFACC4BAFFBCD4CAFFBDD4CCFFAEC5BDFF
+ A2B9B1FFA1B8B0FF9BB1ACFF9CB2ADFF9DB2AFFF9CB1AEFF98ADAAFF92A7A4FF
+ 8CA19FFF8A9D9AFF849592FF788783FF71807CFF667571FF54635FFF52615DFF
+ 586763FF54635FFF4B5A56FF4F5E5AFF54635FFF586763FFB3C8C5FFABC0BDFF
+ A7BCB9FFABC0BDFFAABFBCFFA2B7B4FF9DB2AFFFA0B5B2FFA2B7B4FF9DB2AFFF
+ A3B8B5FF9EB3B0FF94A9A6FFA6BBB8FFAFC4C1FF98ADAAFFA5BAB7FFB2C7C4FF
+ BCD1CEFFB9CECBFFB2C7C4FFAABFBCFF9CB1AEFF8EA3A0FF94A9A6FF9CB1AEFF
+ 96ABA8FF8DA29FFF6B807DFF586D6AFF6B807DFF6A7D7AFF6F807DFF7C8D8AFF
+ 7A8886FF5D6E6BFF4B5C59FF586966FF728380FF809390FF8DA09DFF889B98FF
+ 849996FF879C99FF879C99FF859A97FF869B98FF8A9F9CFF91A4A1FFA3B6B3FF
+ 9DB0ADFF829592FF829592FFA1B4B1FFB3C6C3FFAEC1BEFFB8CBC8FFAFC2BFFF
+ AEC1BEFFAEC1BEFFAEC1BEFFBBCECBFFBCCFCCFFA8BDBAFF9BB0ADFFB0C7C3FF
+ B6CBC8FFACC1BEFFA6BBB8FFA1B6B3FFA5B8B5FFB2C5C2FFB8C9C6FF9DAEABFF
+ 99AAA7FFA2B3B0FFA5B3B1FFA7B5B3FF667472FF6E7C7AFF7E8D89FF92A19DFF
+ 909F9BFF82918DFF83928EFF859490FF859490FF899894FF92A19DFF9BAAA6FF
+ A3B2AEFFA0AFABFF96A5A1FF8D9C98FF8B9A96FF8D9C98FF90A099FF809089FF
+ 95A4A0FF8D9E9AFF8FA1A0FF97ACAAFFC4D9DAFFC8DDDEFF9BB0B1FF95AAABFF
+ 728785FF5D706DFF6B7C79FF6E7F7BFF6E7E77FF7E8E87FF869794FF93A6A3FF
+ A6B7B4FFADC0BDFFB2C5C2FFB4C9C6FFB8CDCAFFB9CECBFFCFE4E1FFC9E0DCFF
+ C9E0DCFFCDE6E2FFCEE7E3FFC9E2DEFFCAE3DFFFD1EAE6FFD4EBE7FFB7CECAFF
+ B8CFCBFFC6DBD8FFC1D6D3FFBFD4D1FFB5CAC7FF9BAEABFF869996FFA7B8B5FF
+ BECFCCFFBCCDCAFFAFC0BDFFAFBDBBFFB5C3C1FFB6C7C4FFD4E7E4FFD1E6E3FF
+ CCE1DEFFCBDEDBFFCEE1DEFFCFE0DDFFBDCECBFFAAB8B6FF9AA8A6FF374442FF
+ 586563FF93A09EFF95A2A0FF99A6A4FF919E9CFF8C9997FF92A09CFF7A8985FF
+ 707F7BFF7B8A86FF81908CFF798884FF778682FF808F8BFF64736FFF64736FFF
+ 697874FF6E7D79FF6A7975FF606F6BFF606F6BFF677672FF75837FFF6F7D79FF
+ 5D6B67FF5E6C68FF7D8B87FF93A29EFF96A5A1FF98A7A3FF9EAFABFF9CADA9FF
+ A3B4B0FFB1C5C0FFBDD1CCFFBBCFCAFFB3C9C4FFB1C5C0FFA6B4B0FF76817EFF
+ 4C5A56FF33413DFF25332FFF3B4945FF566561FF53625EFF6C7D79FF788985FF
+ 7F908CFF798A86FF6F837EFF6F837EFF748883FF788C87FF849290FF818F8DFF
+ 82908EFF879593FF83918FFF7B8987FF7A8886FF7F8D8BFF7D8B89FF7C8A88FF
+ 7A8886FF798785FF7A8886FF7D8B89FF808E8CFF818F8DFF7B8A86FF7A8985FF
+ 798783FF798783FF798783FF778581FF747F7CFF707B78FF757E7BFF3F4845FF
+ 6E7774FF747D7AFF777E7BFF7A817EFF828986FF88918EFF818A87FF85908DFF
+ 8C9A96FF95A39FFF9CAAA6FFA1AFABFFA2B1ADFFA2B1ADFF9EAFABFF9FB0ACFF
+ A1B2AEFFA3B4B0FFA2B6B1FFA2B6B1FFA1B5B0FFA1B5B0FFA1B5B0FFA6BAB5FF
+ ADC1BCFFADC1BCFFA4B8B3FF9CB0ABFFA1B5B0FFACC0BBFFA1B5B0FFA5B9B4FF
+ A5B9B4FFA1B5B0FF9FB3AEFF9FB3AEFF9BAFAAFF95AAA2FF9EB5ADFFA2BAB0FF
+ B0C8BEFFBED6CCFFBBD2CAFFAAC1B9FF9FB6AEFFA0B7AFFF9BB1ACFF9BB1ACFF
+ 9CB1AEFF9BB0ADFF97ACA9FF91A6A3FF8BA09EFF899C99FF879895FF778682FF
+ 6C7B77FF62716DFF54635FFF566561FF5C6B67FF576662FF576662FF586763FF
+ 596864FF586763FFB9CECBFFB7CCC9FFBED3D0FFAFC4C1FFB2C7C4FFC0D5D2FF
+ B1C6C3FFABC0BDFFA1B6B3FFA3B8B5FFAABFBCFFA7BCB9FF9DB2AFFFA4B9B6FF
+ AABFBCFFA0B5B2FFAFC4C1FFBACFCCFFBACFCCFFADC2BFFFA6BBB8FFA7BCB9FF
+ A0B5B2FF94A9A6FF98ADAAFF95AAA7FF99AEABFF96ABA8FF879C99FF516663FF
+ 6A7F7CFF607370FF6A7876FF5A6866FF5B6866FF5A6866FF4F5D5BFF546562FF
+ 71827FFF879895FF829592FF899C99FF829794FF819693FF8BA09DFF889D9AFF
+ 809793FF859A97FF809390FF92A5A2FF98ABA8FF92A5A2FF90A3A0FF92A5A2FF
+ A5B8B5FFC5D8D5FFB6C9C6FFB6C9C6FFB0C3C0FFA8BBB8FFA8BBB8FFB2C5C2FF
+ BCCFCCFFBDD2CFFFA3B8B5FFB2C9C5FFB4C9C6FFADC2BFFFAEC3C0FFAABFBCFF
+ A8BBB8FFAEC1BEFFB1C2BFFF9CADAAFF9AABA8FF93A4A1FF9BA9A7FF9DABA9FF
+ 808E8CFF748280FF869591FF8B9A96FF8C9B97FF899894FF889793FF8A9995FF
+ 8A9995FF879692FF95A4A0FF8C9B97FF8E9D99FF9DACA8FFA5B4B0FFA0AFABFF
+ 9CABA7FF9EADA9FF9CAAA4FFA5B5AEFFA7B6B2FF9DAEAAFF9EB0AFFFB1C6C4FF
+ C2D7D8FFC7DCDDFF9CB1B2FF8FA4A5FF6D8280FF607370FF6F807DFF6A7975FF
+ 62706AFF73837CFF778583FF71827FFF808E8CFF9CADAAFFB4C5C2FFB7CAC7FF
+ B6C9C6FFB8CBC8FFCCDFDCFFBED3D0FFBFD4D1FFCEE5E1FFD5ECE8FFCEE5E1FF
+ CAE1DDFFCFE6E2FFD8EFEBFFC3D8D5FFBCD1CEFFC5D8D5FFC3D6D3FFC0D3D0FF
+ B7CAC7FFA8B9B6FF97A8A5FF8A9896FF899795FF9BA9A7FFA4B2B0FF9BA8A6FF
+ 93A09EFF94A2A0FF9DAEABFFA9BCB9FFB1C4C1FFB4C5C2FFBECFCCFFCADBD8FF
+ C2D3D0FFAEBFBCFFA1B2AFFF6F7D7BFF263432FF657371FF8A9795FF8D9A98FF
+ 889391FF94A19FFFA5B3AFFF82908CFF717F7BFF6E7C78FF63716DFF62706CFF
+ 72807CFF7E8C88FF7E8C88FF778581FF677571FF62706CFF667470FF5E6C68FF
+ 5A6864FF667470FF6A7670FF68746EFF5F6B65FF596761FF707E78FF919F99FF
+ 9AAAA3FF91A19AFF96A69FFFA3B5AEFFB4C6BFFFBBCDC6FFB5CAC2FFB0C5BDFF
+ B0C5BDFFB5C7C0FFCAD8D4FFC6D1CEFFB6C4C0FF93A19DFF5D6B67FF33413DFF
+ 31403CFF475652FF4C5D59FF62736FFF758682FF758682FF718580FF758984FF
+ 798D88FF788C87FF7C8A88FF7B8987FF778583FF758381FF7A8886FF808E8CFF
+ 7D8B89FF768482FF6D7B79FF72807EFF798785FF7A8886FF707E7CFF677573FF
+ 6A7876FF748280FF74837FFF7A8985FF808E8AFF7D8B87FF73817DFF6D7B77FF
+ 6F7A77FF737E7BFF707976FF29322FFF646D6AFF6A7370FF707774FF7A817EFF
+ 848B88FF868F8CFF8F9895FF818C89FF889692FF9AA8A4FF9EACA8FFA3B1ADFF
+ A7B6B2FFA5B4B0FFA5B6B2FFA4B5B1FFA3B4B0FFA4B5B1FFA4B8B3FFA5B9B4FF
+ A5B9B4FFA4B8B3FFA5B9B4FF91A5A0FFA1B5B0FFBACEC9FFADC1BCFFA0B4AFFF
+ A1B5B0FF9CB0ABFF9CB0ABFF9FB3AEFFA3B7B2FFA3B7B2FF9FB3AEFF99ADA8FF
+ 93A7A2FF90A59DFF91A8A0FF9CB4AAFFB8D0C6FFB8D0C6FFB6CDC5FFB7CEC6FF
+ A3BAB2FFA1B8B0FFA0B6B1FF9EB4AFFF99AEABFF93A8A5FF8DA29FFF869B98FF
+ 819694FF819491FF768784FF7B8A86FF6C7B77FF687773FF5E6D69FF303F3BFF
+ 5E6D69FF4B5A56FF586763FF5A6965FF5C6B67FF5C6B67FFB5CAC7FFACC1BEFF
+ B1C6C3FFA4B9B6FFA5BAB7FFAEC3C0FF9EB3B0FF9DB2AFFFA1B6B3FFA2B7B4FF
+ AABFBCFFABC0BDFFA6BBB8FFADC2BFFFB1C6C3FFA5BAB7FFAEC3C0FFBACFCCFF
+ BCD1CEFFB0C5C2FFA7BCB9FFA7BCB9FFA2B7B4FF98ADAAFF98ADAAFF96ABA8FF
+ 9AAFACFF9BB0ADFF8FA4A1FF5F7471FF748986FF6D807DFF6A7876FF5B6866FF
+ 586361FF566361FF525F5DFF5D6B69FF73817FFF798A87FF90A19EFF93A6A3FF
+ 8BA09DFF869B98FF8BA09DFF879C99FF819894FF889F9BFF8EA19EFF99ACA9FF
+ 99ACA9FF94A7A4FF95A8A5FF96A9A6FFA4B7B4FFBFD2CFFFC9DCD9FFC9DCD9FF
+ C4D7D4FFBDD0CDFFB9CCC9FFB9CCC9FFB3C6C3FFAABFBCFFADC2BFFFB9D0CCFF
+ B8CDCAFFB0C5C2FFB2C7C4FFAFC4C1FFACBFBCFFB1C4C1FFB5C6C3FF9CADAAFF
+ 95A6A3FF8D9E9BFF98A6A4FF9DABA9FF7E8C8AFF707E7CFF899894FF8E9D99FF
+ 909F9BFF8D9C98FF8C9B97FF8E9D99FF8C9B97FF889793FF96A5A1FF91A09CFF
+ 909F9BFF96A5A1FF9CABA7FF9DACA8FFA0AFABFFA4B3AFFF9EACA6FFA6B4AEFF
+ A4B3AFFF9DACA8FFA4B4B3FFB8CAC9FFC4D8D9FFC2D7D8FF95AAABFF8CA0A1FF
+ 708281FF647572FF6F7D7BFF687773FF62706AFF717F79FF74817FFF6E7C7AFF
+ 717F7DFF849290FF9CAAA8FFABBCB9FFB4C5C2FFB8CBC8FFD0E3E0FFC4D7D4FF
+ BDD0CDFFBFD4D1FFC3D8D5FFC2D9D5FFC3DAD6FFC7DCD9FFCBE0DDFFBFD2CFFF
+ C3D6D3FFCFE2DFFFCCDFDCFFC1D4D1FFB0C1BEFF98A9A6FF9DABA9FF95A3A1FF
+ 94A2A0FF9BA8A6FF9BA8A6FF94A19FFF929F9DFF98A5A3FF9DABA9FF9BA9A7FF
+ 90A19EFF8D9E9BFF9CADAAFFB6C7C4FFC4D5D2FFC4D5D2FFBCCDCAFF99AAA7FF
+ 344240FF697775FF83908EFF818E8CFF7B8684FF86918FFFA4B2AEFF8A9894FF
+ 879591FF8D9B97FF798783FF64726EFF6C7A76FF7B8985FF899793FF84928EFF
+ 74827EFF6C7A76FF6C7A76FF5F6D69FF55635FFF5C6A66FF6B7771FF616D67FF
+ 505C56FF4E5A54FF687670FF8E9C96FF9BA9A3FF91A19AFF94A49DFFA2B2ABFF
+ AFC1BAFFB6C8C1FFB3C5BEFFADC2BAFFACC1B9FFB1C3BCFF9DABA7FFAAB5B2FF
+ BECCC8FFD9E7E3FFE3F1EDFFC5D3CFFF859490FF4F5E5AFF4E5F5BFF536460FF
+ 5E6F6BFF6B7C78FF728681FF748883FF718580FF6F837EFF677573FF6D7B79FF
+ 72807EFF768482FF7A8886FF798785FF6D7B79FF5F6D6BFF73817FFF73817FFF
+ 748280FF73817FFF6C7A78FF63716FFF63716FFF677573FF73827EFF768581FF
+ 798783FF768480FF6F7D79FF6B7975FF6E7976FF707B78FF4C5552FF212A27FF
+ 6D7673FF79827FFF727976FF6E7572FF737A77FF78817EFF8A9390FF86918EFF
+ 92A09CFF9FADA9FF9EACA8FFA2B0ACFFA8B7B3FFA5B4B0FFA2B3AFFFA2B3AFFF
+ A1B2AEFFA1B2AEFF9EB2ADFF9EB2ADFF9FB3AEFFA0B4AFFFA9BDB8FF9CB0ABFF
+ 9EB2ADFFA6BAB5FFA0B4AFFF9BAFAAFFA2B6B1FFA8BCB7FF9FB3AEFFA2B6B1FF
+ A5B9B4FFA7BBB6FFA6BAB5FFA2B6B1FF9EB2ADFF9BB0A8FF95ACA4FFA0B8AEFF
+ BBD3C9FFB9D1C7FFB5CCC4FFB5CCC4FFA2B9B1FFA1B8B0FF99AFAAFF9BB1ACFF
+ 9DB2AFFF9BB0ADFF95AAA7FF8BA09DFF809593FF7B8E8BFF829390FF7F8E8AFF
+ 6D7C78FF697874FF5A6965FF2F3E3AFF5B6A66FF51605CFF53625EFF576662FF
+ 5B6A66FF5C6B67FFAEC3C0FF9FB4B1FFA4B9B6FFA0B5B2FFA3B8B5FFA9BEBBFF
+ 9DB2AFFFA5BAB7FFACC1BEFFA8BDBAFFAEC3C0FFB1C6C3FFADC2BFFFB0C5C2FF
+ ADC2BFFF9CB1AEFFAEC3C0FFBACFCCFFBFD4D1FFB4C9C6FFA9BEBBFFA4B9B6FF
+ 9DB2AFFF95AAA7FF98ADAAFF98ADAAFF9BB0ADFF9EB3B0FF96ABA8FF6B807DFF
+ 728784FF718481FF667371FF5A6563FF575F5EFF55605EFF5A6563FF6D7A78FF
+ 7B8987FF728380FF879895FF8DA09DFF879C99FF829794FF859C98FF839A96FF
+ 849B97FF8FA6A2FF96A9A6FF9BAEABFF96A9A6FF92A5A2FF97AAA7FF98ABA8FF
+ A3B6B3FFBBCECBFFBDD0CDFFBED1CEFFBBCECBFFB7CAC7FFB7CAC7FFB9CCC9FF
+ B3C6C3FFA8BDBAFFABC0BDFFB4CBC7FFB0C5C2FFA9BEBBFFAEC3C0FFAEC3C0FF
+ ABBEBBFFAEC1BEFFB5C6C3FF98A9A6FF8D9E9BFF869794FF93A19FFF9BA9A7FF
+ 7E8C8AFF707E7CFF84938FFF8A9995FF8C9B97FF8A9995FF8A9995FF8B9A96FF
+ 879692FF81908CFF889793FF8E9D99FF91A09CFF909F9BFF91A09CFF96A5A1FF
+ 99A8A4FF98A7A3FF93A19BFF97A59FFF93A29EFF92A19DFFA3B3B2FFBED0CFFF
+ C5D9DAFFBCD0D1FF90A4A5FF899D9EFF768887FF6C7D7AFF717F7DFF6A7975FF
+ 67756FFF72807AFF7A8785FF778482FF727F7DFF73817FFF818F8DFF93A19FFF
+ 9CAAA8FF9AABA8FFBFD0CDFFBBCECBFFB5C8C5FFB2C5C2FFB7CAC7FFBED3D0FF
+ C0D5D2FFBCD1CEFFAFC2BFFFA8B9B6FFB4C5C2FFC7D8D5FFC8D9D6FFBFD0CDFF
+ B0BEBCFF9AA8A6FF98A5A3FF9CA9A7FF9EABA9FF9CA7A5FF95A09EFF949F9DFF
+ 9BA6A4FFA3AEACFF94A19FFF8F9C9AFF8A9896FF8F9D9BFF9CADAAFFAEBFBCFF
+ BACDCAFFC0D3D0FFC2D5D2FFB9CCC9FF4A5B58FF5B6967FF768381FF7B8886FF
+ 6D7876FF737E7CFF939E9BFF798481FF7C8784FF8D9895FF838E8BFF6F7A77FF
+ 6E7976FF75807DFF8A9592FF87928FFF798481FF707B78FF6E7976FF5F6A67FF
+ 515C59FF545F5CFF626C66FF545E58FF44504AFF4A5650FF6C7872FF8F9D97FF
+ 9AA8A2FF92A09AFF8B9B94FF96A69FFFA3B3ACFFA7B9B2FFA6B8B1FFA2B4ADFF
+ A2B4ADFFA6B6AFFFB9C7C3FFB4BFBCFFA5B3AFFFA5B3AFFFC0CECAFFE1EFEBFF
+ E2F1EDFFD1E0DCFF96A7A3FF71827EFF4B5C58FF445551FF526661FF637772FF
+ 6D817CFF718580FF717F7DFF6C7A78FF63716FFF5D6B69FF616F6DFF6A7876FF
+ 6E7C7AFF6B7977FF616F6DFF5E6C6AFF606E6CFF667472FF687674FF657371FF
+ 647270FF667472FF697874FF6B7A76FF6F7D79FF6F7D79FF6B7975FF64726EFF
+ 5E6966FF5A6562FF444D4AFF1D2623FF5A6360FF6D7673FF707774FF787F7CFF
+ 7C8380FF7D8683FF87908DFF8B9693FF9BA9A5FFA2B0ACFF9CAAA6FFA2B0ACFF
+ A9B8B4FFA3B2AEFFA0B1ADFFA3B4B0FFA4B5B1FFA2B3AFFF9CB0ABFF9BAFAAFF
+ 9EB2ADFFA2B6B1FFA8BCB7FFACC0BBFFA3B7B2FF9AAEA9FF99ADA8FF97ABA6FF
+ 98ACA7FFA2B6B1FF9BAFAAFF9DB1ACFFA0B4AFFFA3B7B2FFA5B9B4FFA4B8B3FF
+ A2B6B1FFA0B5ADFF9BB2AAFFA5BDB3FFC0D8CEFFBAD2C8FFB3CAC2FFB2C9C1FF
+ 9FB6AEFFA0B7AFFF9AB0ABFF9CB2ADFF9DB2AFFF9CB1AEFF95AAA7FF8A9F9CFF
+ 7F9492FF7A8D8AFF81928FFF798884FF697874FF6A7975FF556460FF293834FF
+ 4C5B57FF4B5A56FF505F5BFF53625EFF586763FF5A6965FFB4C9C6FF9FB4B1FF
+ A3B8B5FFA2B7B4FFA5BAB7FFA6BBB8FF9BB0ADFFA8BDBAFF96ABA8FF92A7A4FF
+ 9DB2AFFFACC1BEFFB3C8C5FFBCD1CEFFBBD0CDFFABC0BDFFA8BDBAFFB6CBC8FF
+ BED3D0FFB7CCC9FFA9BEBBFF9EB3B0FF94A9A6FF8CA19EFF95AAA7FF97ACA9FF
+ 9AAFACFF9FB4B1FF97ACA9FF708582FF607572FF657673FF5F6A68FF5A6261FF
+ 596160FF5A6261FF636B6AFF7C8785FF869391FF788684FF7F908DFF889B98FF
+ 879A97FF819693FF839A96FF809793FF819894FF8EA5A1FF8FA4A1FF95A8A5FF
+ 91A4A1FF91A4A1FF95A8A5FF94A7A4FFA0B3B0FFBCCFCCFFADC0BDFFADC0BDFF
+ A8BBB8FFA3B6B3FFA5B8B5FFAFC2BFFFB6C9C6FFB5CAC7FFA7BCB9FFAEC5C1FF
+ A8BDBAFFA2B7B4FFABC0BDFFADC2BFFFAABDBAFFACBFBCFFAEBFBCFF95A6A3FF
+ 8C9D9AFF839491FF8E9C9AFF96A4A2FF7E8C8AFF758381FF81908CFF869591FF
+ 899894FF899894FF8A9995FF8A9995FF859490FF7D8C88FF7A8985FF8C9B97FF
+ 98A7A3FF95A4A0FF91A09CFF93A29EFF8F9E9AFF879692FF89958FFF8C9892FF
+ 879591FF8A9995FFA6B6B5FFCBDBDAFFCFE1E2FFBDD1D2FF8FA3A4FF8C9E9FFF
+ 829291FF788986FF778583FF74827EFF74807AFF79857FFF798684FF7D8A88FF
+ 7B8886FF758280FF7A8785FF859391FF869492FF7D8B89FF95A3A1FF9FB0ADFF
+ A3B4B1FF9FB2AFFFA8BBB8FFB7CAC7FFB7CAC7FFABBEBBFFA0B1AEFF93A4A1FF
+ 99AAA7FFA7B8B5FFA9BAB7FFACBAB8FFA8B6B4FF9CAAA8FF869391FF929F9DFF
+ 9DA8A6FF9AA5A3FF99A4A2FF9EA9A7FFA5B0AEFFA8B3B1FFADB8B6FFABB6B4FF
+ ADBAB8FFB3C1BFFFB3C4C1FFB4C5C2FFB9CCC9FFC3D6D3FFC6D9D6FFCBDEDBFF
+ 809390FF445552FF73817FFF84918FFF646F6DFF5D6866FF86918EFF6C7774FF
+ 67726FFF747F7CFF798481FF7A8582FF75807DFF697471FF77827FFF788380FF
+ 6C7774FF646F6CFF65706DFF5B6663FF4F5A57FF525D5AFF545E58FF4B554FFF
+ 46524CFF56625CFF77837DFF939F99FF98A6A0FF92A09AFF8A9892FF90A099FF
+ 9AAAA3FF9FAFA8FF9DAFA8FF9BADA6FF9BADA6FF9DADA6FF95A39FFFA4AFACFF
+ ABB9B5FFACBAB6FFB2C0BCFFC3D1CDFFD0DFDBFFD4E3DFFFDFF0ECFFD6E7E3FF
+ B5C6C2FF7D8E8AFF495D58FF3B4F4AFF4F635EFF667A75FF4F5D5BFF576563FF
+ 5F6D6BFF657371FF6C7A78FF707E7CFF697775FF606E6CFF515F5DFF515F5DFF
+ 586664FF62706EFF667472FF647270FF62706EFF647270FF5C6B67FF5F6E6AFF
+ 667470FF6A7874FF677571FF5B6965FF4C5754FF3F4A47FF323B38FF151E1BFF
+ 3F4845FF58615EFF616865FF747B78FF7A817EFF7A8380FF808986FF86918EFF
+ 94A29EFF9AA8A4FF98A6A2FFA4B2AEFFABBAB6FFA2B1ADFF9FB0ACFFA3B4B0FF
+ A6B7B3FFA2B3AFFF99ADA8FF95A9A4FF98ACA7FF9DB1ACFFA0B4AFFFB8CCC7FF
+ B2C6C1FFA3B7B2FFA7BBB6FF9FB3AEFF91A5A0FF95A9A4FF9CB0ABFF9CB0ABFF
+ 9DB1ACFF9FB3AEFFA2B6B1FFA3B7B2FFA3B7B2FFA1B6AEFF9FB6AEFFAAC2B8FF
+ C4DCD2FFBCD4CAFFB1C8C0FFAEC5BDFF9DB4ACFF9FB6AEFFA0B6B1FF9DB3AEFF
+ 99AEABFF93A8A5FF8CA19EFF859A97FF809593FF7F928FFF7B8C89FF73827EFF
+ 6A7975FF71807CFF54635FFF2B3A36FF404F4BFF455450FF4E5D59FF52615DFF
+ 556460FF566561FFC2D7D4FFABC0BDFFAABFBCFFA3B8B5FF9FB4B1FF9BB0ADFF
+ 8BA09DFF95AAA7FFA0B5B2FF96ABA8FF9CB1AEFFA9BEBBFFADC2BFFFB0C5C2FF
+ ABC0BDFF9BB0ADFF9CB1AEFFA9BEBBFFB5CAC7FFB4C9C6FFAABFBCFF9EB3B0FF
+ 92A7A4FF8BA09DFF8FA4A1FF94A9A6FF96ABA8FF9DB2AFFF97ACA9FF768B88FF
+ 4F6461FF596A67FF5C6463FF5C6261FF616766FF606867FF666E6DFF7B8684FF
+ 869391FF7A8886FF80918EFF8C9F9CFF8DA09DFF889D9AFF889F9BFF819894FF
+ 7B9490FF879E9AFF8CA19EFF94A7A4FF94A7A4FF95A8A5FF94A7A4FF8EA19EFF
+ 9CAFACFFBCCFCCFFB9CCC9FFBBCECBFFB5C8C5FFAABDBAFFA5B8B5FFABBEBBFF
+ B4C7C4FFB6CBC8FFB1C6C3FFB7CECAFFB0C5C2FFA9BEBBFFB0C5C2FFB1C6C3FF
+ ADC0BDFFAFC2BFFFADBEBBFF9AABA8FF96A7A4FF899A97FF8A9896FF8D9B99FF
+ 788684FF768482FF859490FF899894FF8C9B97FF8C9B97FF8F9E9AFF909F9BFF
+ 8A9995FF81908CFF7F8E8AFF93A29EFF9FAEAAFF9BAAA6FF94A39FFF94A39FFF
+ 909F9BFF879692FF8C9892FF8F9B95FF8A9894FF8D9C98FFADBDBCFFD6E6E5FF
+ DAECEDFFC6D8D9FF90A2A3FF8A9C9DFF879796FF81928FFF7B8987FF7C8A86FF
+ 7F8B85FF7B8781FF707B79FF7A8583FF7D8886FF788583FF7D8A88FF899694FF
+ 8B9896FF82908EFF7B8987FF889996FF8D9E9BFF899A97FF91A29FFFA0B3B0FF
+ A1B4B1FF94A7A4FF9DAEABFF8F9D9BFF8D9B99FF92A09EFF8F9D9BFF929F9DFF
+ 96A3A1FF909D9BFF7A8583FF86918FFF959D9CFF9BA3A2FFA2AAA9FFA8B0AFFF
+ A8B0AFFFA3ABAAFFB9C1C0FFB1BCBAFFAAB5B3FFA0ADABFF95A3A1FF91A29FFF
+ 9FB2AFFFB0C5C2FFCADFDCFFCFE4E1FFC0D3D0FF3E4F4CFF7C8A88FF99A6A4FF
+ 677270FF545F5DFF7C8784FF76817EFF747F7CFF6F7A77FF6D7875FF788380FF
+ 77827FFF616C69FF687370FF6B7673FF616C69FF596461FF5F6A67FF5C6764FF
+ 55605DFF586360FF59635DFF515C54FF525D55FF636E66FF79867EFF8C9991FF
+ 96A39BFF98A79FFF92A199FF96A59DFF9AABA2FF9FB0A7FFA1B2A9FFA1B2A9FF
+ 9EB1A8FF9FAFA8FFABB9B5FFA0ABA8FF98A6A2FF9EACA8FFA5B3AFFFAAB8B4FF
+ B3C2BEFFBFCECAFFD4E5E1FFDDEEEAFFE1F2EEFFE1F2EEFFDEF2EDFFC2D6D1FF
+ 7A8E89FF344843FF475553FF4B5957FF4C5A58FF4C5A58FF505E5CFF566462FF
+ 566462FF52605EFF475553FF4B5957FF52605EFF576563FF515F5DFF455351FF
+ 404E4CFF42504EFF44534FFF44534FFF475551FF4A5854FF4A5854FF42504CFF
+ 35403DFF2A3532FF1C2522FF151E1BFF363F3CFF555E5BFF5D6461FF707774FF
+ 737A77FF717A77FF707976FF6F7A77FF7D8B87FF8C9A96FF95A39FFFA8B6B2FF
+ B1C0BCFFA9B8B4FFA3B4B0FFA8B9B5FFA9BAB6FFA4B5B1FF97ABA6FF8FA39EFF
+ 8DA19CFF8FA39EFF92A6A1FFB1C5C0FFB3C7C2FFA9BDB8FFB2C6C1FFADC1BCFF
+ 9BAFAAFF99ADA8FFA4B8B3FFA1B5B0FF9FB3AEFFA0B4AFFFA2B6B1FFA4B8B3FF
+ A4B8B3FFA2B7AFFF9EB5ADFFACC4BAFFC8E0D6FFBFD7CDFFB0C7BFFFABC2BAFF
+ 9AB1A9FF9EB5ADFF96ACA7FF94AAA5FF92A7A4FF8EA3A0FF8A9F9CFF869B98FF
+ 839896FF839693FF81928FFF778682FF6D7C78FF71807CFF4D5C58FF32413DFF
+ 404F4BFF4E5D59FF4B5A56FF4F5E5AFF52615DFF54635FFFC0D5D2FFAEC3C0FF
+ AEC3C0FFA4B9B6FFA0B5B2FF9FB4B1FF8FA4A1FF94A9A6FFB2C7C4FFA2B7B4FF
+ A2B7B4FFA9BEBBFFA4B9B6FFA0B5B2FF9AAFACFF8CA19EFF96ABA8FF9EB3B0FF
+ A7BCB9FFACC1BEFFA9BEBBFFA2B7B4FF9AAFACFF95AAA7FF8BA09DFF91A6A3FF
+ 90A5A2FF9AAFACFF97ACA9FF809592FF495E5BFF5C6D6AFF636B6AFF636867FF
+ 676D6CFF6A706FFF676F6EFF737E7CFF7F8A88FF768482FF748280FF7E918EFF
+ 839693FF839895FF8AA19DFF879E9AFF819A96FF8BA29EFF8FA4A1FF97AAA7FF
+ 99ACA9FF9BAEABFF98ABA8FF8C9F9CFF97AAA7FFB8CBC8FFBFD2CFFFC4D7D4FF
+ C3D6D3FFBBCECBFFB5C8C5FFB4C7C4FFB3C6C3FFAFC4C1FFB6CBC8FFBED5D1FF
+ B8CDCAFFAEC3C0FFB1C6C3FFAEC3C0FFA9BCB9FFABBEBBFFB1C2BFFFA2B3B0FF
+ A2B3B0FF92A3A0FF8B9997FF889694FF717F7DFF707E7CFF84938FFF879692FF
+ 889793FF899894FF8E9D99FF91A09CFF8C9B97FF83928EFF889793FF92A19DFF
+ 97A6A2FF93A29EFF8E9D99FF8E9D99FF909F9BFF919F9BFF909C96FF96A29CFF
+ 909E9AFF8E9D99FFADBBBAFFD5E5E4FFDAECEDFFC6D8D9FF8D9FA0FF849697FF
+ 869695FF829390FF7B8886FF808E8AFF85918BFF78847EFF788381FF7B8684FF
+ 7B8684FF788381FF7B8684FF828F8DFF8A9795FF8C9997FF849290FF8C9A98FF
+ 899795FF7D8E8BFF7F908DFF8E9F9CFF91A4A1FF8C9D9AFF8F9D9BFF83918FFF
+ 869492FF8D9B99FF8A9795FF8B9896FF8F9C9AFF8B9896FF7B8684FF7F8A88FF
+ 8B9392FF979F9EFFA0A8A7FFA1A9A8FF9EA4A3FF989E9DFFA1A9A8FF9FA7A6FF
+ 96A19FFF889593FF7D8B89FF798C89FF809592FF899E9BFFA9C0BCFFADC4C0FF
+ B9CECBFF3B4E4BFF7B8C89FFA1AFADFF7B8684FF697472FF616C69FF737E7BFF
+ 848F8CFF7B8683FF67726FFF6B7673FF727D7AFF67726FFF697471FF6F7A77FF
+ 67726FFF5F6A67FF67726FFF687370FF636E6BFF65716BFF6A746EFF5C675FFF
+ 566159FF626D65FF727F77FF818E86FF919E96FF9FACA4FF96A59DFF96A59DFF
+ 97A89FFF9BACA3FF9EAFA6FFA0B1A8FF9DB0A7FF9DAEA5FF9BA9A5FF939E9BFF
+ 94A29EFFA5B3AFFFABB9B5FFA1AFABFF9CABA7FFA3B2AEFFB1C2BEFFD4E5E1FF
+ EBFCF8FFE2F3EFFFD1E5E0FFD3E7E2FFDAEEE9FFDCF0EBFFA8B6B4FF9AA8A6FF
+ 7F8D8BFF657371FF5B6967FF63716FFF6F7D7BFF758381FF667472FF697775FF
+ 6E7C7AFF6E7C7AFF647270FF576563FF53615FFF556361FF5B6A66FF566561FF
+ 52605CFF515F5BFF52605CFF53615DFF535E5BFF505B58FF323B38FF19221FFF
+ 0A1310FF262F2CFF404744FF666D6AFF656C69FF58615EFF5B6461FF55605DFF
+ 667470FF83918DFF95A39FFFA6B4B0FFB1C0BCFFAFBEBAFFACBDB9FFB0C1BDFF
+ B2C3BFFFADBEBAFFA1B5B0FF96AAA5FF8FA39EFF8DA19CFF869A95FF96AAA5FF
+ 9BAFAAFF9BAFAAFFA6BAB5FFACC0BBFFA6BAB5FFA3B7B2FFA7BBB6FFA2B6B1FF
+ 9CB0ABFF9BAFAAFF9DB1ACFFA0B4AFFF9FB3AEFF9DB2AAFF99B0A8FFABC3B9FF
+ CAE2D8FFC1D9CFFFB1C8C0FFA9C0B8FF98AFA7FF9DB4ACFF869C97FF8AA09BFF
+ 8FA4A1FF92A7A4FF91A6A3FF8BA09DFF849997FF819491FF849592FF7A8985FF
+ 6B7A76FF62716DFF374642FF31403CFF3D4C48FF505F5BFF465551FF4A5955FF
+ 4E5D59FF51605CFFB5CAC7FFACC1BEFFB1C6C3FFA4B9B6FFA5BAB7FFADC2BFFF
+ 9EB3B0FF9DB2AFFFA3B8B5FF94A9A6FF98ADAAFFA5BAB7FFA7BCB9FFABC0BDFF
+ B0C5C2FFABC0BDFFA0B5B2FF9FB4B1FFA0B5B2FFA4B9B6FFA6BBB8FFA5BAB7FF
+ A2B7B4FFA1B6B3FF8DA29FFF91A6A3FF8A9F9CFF92A7A4FF92A7A4FF859A97FF
+ 465B58FF627370FF717978FF686D6CFF6B706FFF737978FF707877FF747F7DFF
+ 7D8886FF788684FF707E7CFF778A87FF7A8D8AFF7C918EFF889F9BFF89A09CFF
+ 859E9AFF8EA5A1FF8FA4A1FF92A5A2FF93A6A3FF9AADAAFF9CAFACFF8FA29FFF
+ 94A7A4FFB1C4C1FFB6C9C6FFB8CBC8FFB7CAC7FFB8CBC8FFBBCECBFFBDD0CDFF
+ B4C7C4FFA7BCB9FFACC1BEFFB8CFCBFFB6CBC8FFADC2BFFFADC2BFFFA9BEBBFF
+ A5B8B5FFA8BBB8FFB3C4C1FFA5B6B3FFA6B7B4FF98A9A6FF93A19FFF8E9C9AFF
+ 72807EFF6C7A78FF82918DFF83928EFF83928EFF84938FFF8B9A96FF91A09CFF
+ 8D9C98FF859490FF879692FF889793FF8C9B97FF909F9BFF8F9E9AFF8B9A96FF
+ 8E9D99FF95A39FFF8F9B95FF9AA6A0FF94A29EFF8E9D99FFA7B5B4FFD0E0DFFF
+ D9EBECFFC8DADBFF8D9FA0FF809293FF839392FF81928FFF7B8886FF84928EFF
+ 8A9690FF77817BFF848C8BFF808887FF7E8685FF7A8583FF778280FF75807EFF
+ 7A8785FF83908EFF879492FF899795FF879593FF808E8CFF7E8F8CFF879895FF
+ 8C9D9AFF8A9B98FF808E8CFF788684FF828F8DFF8E9B99FF8B9896FF8D9A98FF
+ 939E9CFF8F9A98FF868E8DFF808887FF828A89FF8E9695FF969C9BFF929897FF
+ 909695FF959B9AFF9BA1A0FF9FA7A6FF9FAAA8FF99A6A4FF99A7A5FF96A9A6FF
+ 899E9BFF778E8AFF768D89FF809793FF748986FF405350FF6B7C79FF919F9DFF
+ 8F9A98FF899492FF737C79FF78817EFF8B9491FF919A97FF7D8683FF737C79FF
+ 79827FFF7B8481FF727B78FF7D8683FF78817EFF737C79FF7C8582FF7F8885FF
+ 78817EFF77817BFF6B756FFF566159FF4D5850FF5D6860FF737E76FF818C84FF
+ 8F9C94FF9EABA3FF95A49CFF93A29AFF92A39AFF95A69DFF9AABA2FF9CADA4FF
+ 9BACA3FF99AAA1FF97A5A1FF99A4A1FF96A4A0FF95A39FFF92A09CFF93A19DFF
+ 9CABA7FFA7B6B2FF9BACA8FFB1C2BEFFD4E5E1FFF1FFFEFFEFFFFEFFE1F5F0FF
+ D8ECE7FFD9EDE8FFEAF8F6FFEAF8F6FFE2F0EEFFD3E1DFFFC5D3D1FFBBC9C7FF
+ B0BEBCFFA7B5B3FFB0BEBCFFACBAB8FFAAB8B6FFAAB8B6FFA8B6B4FFA2B0AEFF
+ A1AFADFFA5B3B1FFA2B1ADFF9EADA9FF9AA8A4FF96A4A0FF96A4A0FF96A4A0FF
+ 99A4A1FF99A4A1FF767F7CFF565F5CFF1C2522FF17201DFF171E1BFF39403DFF
+ 404744FF3D4643FF4E5754FF47524FFF5F6D69FF869490FF94A29EFF9AA8A4FF
+ A4B3AFFFAAB9B5FFA4B5B1FFA8B9B5FFAEBFBBFFB0C1BDFFACC0BBFFA4B8B3FF
+ 9CB0ABFF97ABA6FF92A6A1FF8CA09BFF90A49FFF96AAA5FF9AAEA9FFA3B7B2FF
+ A8BCB7FFA0B4AFFFA7BBB6FFA0B4AFFF98ACA7FF96AAA5FF99ADA8FF9DB1ACFF
+ 9CB0ABFF9AAFA7FF93AAA2FFA8C0B6FFCAE2D8FFC3DBD1FFB1C8C0FFA9C0B8FF
+ 97AEA6FF9DB4ACFF8AA09BFF8EA49FFF92A7A4FF93A8A5FF90A5A2FF889D9AFF
+ 809593FF7C8F8CFF7A8B88FF798884FF6C7B77FF5B6A66FF293834FF303F3BFF
+ 32413DFF41504CFF41504CFF44534FFF495854FF4B5A56FFB2C7C4FFAEC3C0FF
+ B3C8C5FFA2B7B4FFA2B7B4FFADC2BFFF9CB1AEFF95AAA7FFB8CDCAFFA7BCB9FF
+ A5BAB7FFABC0BDFFA5BAB7FFA4B9B6FFA8BDBAFFA5BAB7FFB0C5C2FFA7BCB9FF
+ 9FB4B1FF9FB4B1FFA3B8B5FFA5BAB7FFA5BAB7FFA5BAB7FF93A8A5FF93A8A5FF
+ 869B98FF8BA09DFF8BA09DFF849996FF445754FF637471FF7A8583FF6A706FFF
+ 6B7170FF78807FFF798482FF7C8785FF818E8CFF818F8DFF869794FF899C99FF
+ 829794FF809592FF89A09CFF879E9AFF819894FF869D99FF889D9AFF889B98FF
+ 889B98FF95A8A5FF9EB1AEFF93A6A3FF95A8A5FFADC0BDFFB8CBC8FFB1C4C1FF
+ AABDBAFFACBFBCFFB8CBC8FFBED1CEFFB2C5C2FFA1B4B1FFA2B7B4FFB3C8C5FF
+ B6C9C6FFAFC2BFFFB0C3C0FFADC0BDFFA9BCB9FFB1C2BFFFB0C1BEFFA1B2AFFF
+ A3B4B1FF9AABA8FF9BA9A7FF98A6A4FF788684FF6E7C7AFF879692FF879692FF
+ 869591FF879692FF8F9E9AFF96A5A1FF94A39FFF8C9B97FF83928EFF82918DFF
+ 8B9A96FF9AA9A5FF9CABA7FF93A29EFF909F9BFF98A6A2FF929C96FFA0AAA4FF
+ 9CA7A4FF93A19DFFAAB8B6FFD1E3E2FFDEF3F1FFD1E6E4FF8EA2A3FF7D9290FF
+ 819392FF829291FF7B8987FF899694FF919A97FF78817EFF7E8685FF778280FF
+ 7B8382FF7E8987FF798482FF6F7A78FF707D7BFF7B8886FF74817FFF798684FF
+ 7D8B89FF818F8DFF849290FF859693FF889694FF889694FF859391FF7C8A88FF
+ 84918FFF8C9997FF869391FF869391FF8D9896FF8A9593FF8A9593FF7D8886FF
+ 7C8483FF868E8DFF88908FFF828A89FF88908FFF979F9EFF959D9CFF99A1A0FF
+ 939E9CFF8E9B99FF98A6A4FFA0B1AEFF8C9F9CFF6D827FFF627774FF718683FF
+ 3A4F4CFF4D605DFF5B6C69FF7A8886FF93A09EFF96A3A1FFB1BCB9FF949F9CFF
+ 949F9CFFA7B2AFFF9EA9A6FF899491FF848F8CFF899491FF737E7BFF818C89FF
+ 818C89FF7F8A87FF8C9592FF8F9895FF868F8CFF838C89FF5D6761FF47524AFF
+ 434D47FF5D6860FF7A847EFF87928AFF8F9B95FF99A69EFF9AA8A2FF96A59DFF
+ 94A29CFF96A79EFF9CAAA4FF9FB0A7FF9EACA6FF9CAAA4FF9AA8A4FFA2ADAAFF
+ A0AEAAFF9BA9A5FFA0AEAAFFA8B6B2FF9FAEAAFF8F9E9AFF94A39FFF92A39FFF
+ B4C3BFFFE5F6F2FFF1FFFEFFDFF0ECFFD9EAE6FFEAFBF7FFD8EBE8FFDDF0EDFF
+ DEF0EFFFD9ECE9FFD6E8E7FFD6E9E6FFD3E5E4FFCFE2DFFFD3E3E2FFC6D7D4FF
+ BBCBCAFFBACBC8FFBCCCCBFFBBCCC9FFBBCBCAFFBDCECBFFB7CAC7FFB8CCC7FF
+ BACBC7FFB8C9C5FFB3C4C0FFADBEBAFFA9B8B4FFA5B4B0FFC6D4D0FFD0DEDAFF
+ A1ACA9FF717C79FF232C29FF1A2320FF2D3633FF4C5552FF4B5653FF46524CFF
+ 63716DFF8E9C96FF94A29EFF8B9B94FF93A29EFF9EB0A9FF8D9E9AFF93A59EFF
+ 9DAEAAFFA6BBB3FFACC0BBFFA8BFB7FFA1B7B2FF9BB1ACFFACC2BDFF97ADA8FF
+ 9DB1ACFFA5B9B4FF9EB2ADFFA3B7B2FFA7BBB6FF98ACA7FFADC1BCFFA4B8B3FF
+ 9CB0ABFF99ADA8FF9DB1ACFFA1B5B0FFA1B5B0FFA0B4AFFF8FA69EFFA5BCB4FF
+ CAE1D9FFC4DBD3FFB2C8C3FFA8BEB9FF97ADA8FF9CB2ADFF9DB3AEFF9AAFACFF
+ 95AAA7FF8FA4A1FF889D9AFF819693FF7B908EFF788D8BFF728380FF7A8886FF
+ 768482FF657470FF2E3C3AFF374642FF2C3B37FF34423EFF404E4AFF43514DFF
+ 465450FF46544EFFC2D7D4FFB8CDCAFFA7BCB9FF9AAFACFF9CB1AEFFA7BCB9FF
+ ACC1BEFFA9BEBBFFBACFCCFFB8CDCAFFA8BDBAFFA1B6B3FFAEC3C0FFB1C6C3FF
+ A6BBB8FFA1B6B3FFA5BCB8FFA1B8B4FF9CB3AFFF9AB1ADFF9FB6B2FFA7BEBAFF
+ ABC0BDFFAABFBCFF9DB0ADFF99ACA9FFA1B4B1FF98ABA8FF8A9D9AFF708380FF
+ 586966FF6E7F7CFF707D7BFF6B7876FF6F7C7AFF7B8886FF818F8DFF7D8B89FF
+ 7A8886FF798A87FF80918EFF889B98FF8A9F9CFF869B98FF859A97FF89A09CFF
+ 8BA29EFF89A09CFF859B96FF92A6A1FF92A6A1FF869A95FF889C97FF9CB0ABFF
+ A8BCB7FFA6BAB5FFAEC2BDFFB9CDC8FFAFC3BEFFA5B9B4FFB8CCC7FFC5D9D4FF
+ B6CAC5FFA2B6B1FFA6B7B4FFAEBFBCFFB1C2BFFFADBEBBFFACBDBAFFB3C4C1FF
+ B5C6C3FFB4C2C0FFAFBDBBFFADBBB9FFA0AEACFF95A3A1FF9AA8A6FF9FADABFF
+ 8A9896FF6B7977FF7F908CFF859692FF899A96FF8A9B97FF8E9F9BFF94A5A1FF
+ 95A6A2FF92A39FFF7F908CFF839490FF8B9C98FF91A29EFF8E9F9BFF889995FF
+ 8A9B97FF93A19DFF99A09BFF909691FF909794FF8F9A97FF95A4A0FFDEF3F0FF
+ DAF1EDFFD8F1EDFFB9D4D1FF708886FF748A88FF879998FF7A8A89FF818D8DFF
+ 929A9AFF8C9494FF7B8684FF73807EFF747F7DFF788583FF7A8785FF74817FFF
+ 717E7CFF74817FFF758280FF7B8886FF859290FF8B9896FF889593FF82908EFF
+ 879492FF909D9BFF889593FF84918FFF7F8C8AFF7D8A88FF7F8C8AFF84918FFF
+ 899694FF8C9997FF94A19FFF919E9CFF8A9593FF808B89FF7D8886FF808B89FF
+ 808B89FF7D8886FF949F9DFF879290FF86918FFF929F9DFF93A09EFF859391FF
+ 859693FF93A4A1FF819491FFA0B3B0FFA1B4B1FF728582FF526360FF7B8C89FF
+ 839491FF8FA09DFFAEBFBCFFA9BAB7FFA4B5B2FFA2B3B0FFA4B2B0FF9FADABFF
+ 94A2A0FF8A9896FF889593FF7D8A88FF758280FF788583FF838E8CFF899492FF
+ 8A9593FF899491FF7D8885FF4D5953FF35403DFF626E68FF697471FF929E98FF
+ 9CA7A4FFA1ADA7FF9AA5A2FF9CA8A2FF9DA8A5FF9CAAA4FF9EA9A6FF9CAAA4FF
+ A0ABA8FF9FADA9FFA2B0ACFF9DABA7FF98A6A2FF95A39FFF96A4A0FF9BA9A5FF
+ A2B0ACFFA6B4B0FF9DABA7FF97A6A2FFA4B2AEFFC5D4D0FFE7F6F2FFF1FFFCFF
+ E5F4F0FFD5E6E3FFD4EAE8FFD9F1EFFFD7EFEFFFD1E9E7FFD9F1F1FFE6FEFCFF
+ E0F8F8FFCEE6E4FFDBF0F1FFDAF0EEFFD4E9EAFFCCE2E0FFC7DCDDFFC7DDDBFF
+ C6DBDCFFC4DAD8FFC1DAD6FFBDD6D2FFBCD5D1FFBED7D3FFC2D9D5FFC0D7D3FF
+ BED3D0FFBDD2CFFFB8CBC8FFC6D9D6FFC7D8D5FFD0E1DEFFB4C2C0FF3E4C4AFF
+ 041210FF42504CFF54605AFF637068FF697771FF92A199FF95A59EFF84958CFF
+ 98A8A1FF8DA097FF8B9D96FF8BA097FF8BA098FF89A197FF92A9A1FF9CB5ABFF
+ 9DB5ADFF95ADA5FF99B0ABFF9EB5B0FF9FB5B0FF9BB1ACFF9DB3AEFFA5BBB6FF
+ A7BDB8FFA2B8B3FFA0B4AFFFA3B7B2FFA5B6B2FFA1B2AEFFA0B1ADFFA4B5B1FF
+ A3B4B0FFA0B1ADFF9DB2AFFFA3BAB6FFC9E0DCFFB5CCC8FFB2C9C5FF9BB2AEFF
+ 8FA6A2FF8EA5A1FF94ABA7FF90A6A4FF899F9DFF839997FF849A98FF859B99FF
+ 7E9492FF748987FF788887FF7E8E8DFF6E7C7BFF6C7A78FF394545FF1D2A28FF
+ 44524EFF202B28FF39453FFF3C4842FF414B45FF414C44FFBCD1CEFFB7CCC9FF
+ B0C5C2FFABC0BDFFA7BCB9FFA5BAB7FFA4B9B6FFA3B8B5FFB6CBC8FFBACFCCFF
+ AEC3C0FFA3B8B5FFAABFBCFFADC2BFFFAABFBCFFADC4C0FFAAC1BDFFA4BDB9FF
+ 9FB6B2FF9BB2AEFF9EB5B1FFA5BCB8FFADC2BFFFAFC4C1FFA9BCB9FFA0B3B0FF
+ A3B6B3FF9BAEABFF95A6A3FF7D8E8BFF61726FFF728380FF758381FF717F7DFF
+ 73817FFF7D8B89FF81928FFF7F908DFF7E8F8CFF81928FFF7B8E8BFF839693FF
+ 859A97FF829794FF829794FF889D9AFF8BA29EFF89A09CFF869A95FF91A5A0FF
+ 93A7A2FF8CA09BFF8CA09BFF9AAEA9FFA8BCB7FFAEC2BDFFACC0BBFFB8CCC7FF
+ B2C6C1FFA9BDB8FFB4C8C3FFB7CBC6FFABBFBAFFA3B7B2FFA6B4B2FFAFBDBBFF
+ B3C1BFFFB0BEBCFFAFBDBBFFB3C1BFFFB3C1BFFFAFBDBBFFAFBDBBFFB3C1BFFF
+ ACBAB8FFA1AFADFF9FADABFF9FADABFF8F9D9BFF788684FF758682FF7D8E8AFF
+ 82938FFF859692FF899A96FF91A29EFF94A5A1FF92A39FFF91A29EFF90A19DFF
+ 91A29EFF91A29EFF8B9C98FF859692FF899A96FF94A29EFF9AA09BFF939792FF
+ 909593FF8A9592FF8C9D99FFD0E6E1FFD4EDE9FFD8F3EFFFD5F0ECFF8CA7A3FF
+ 647C7AFF798E8CFF778688FF849092FF8F9699FF838B8BFF818B8BFF798684FF
+ 788583FF7E8B89FF818E8CFF7D8A88FF7C8987FF7E8B89FF788583FF798684FF
+ 7E8B89FF818E8CFF7F8C8AFF7B8886FF7F8C8AFF879492FF879492FF859290FF
+ 828F8DFF818E8CFF83908EFF869391FF8A9795FF8C9997FFA2AFADFF9FACAAFF
+ 96A3A1FF899694FF828F8DFF828F8DFF83908EFF808D8BFF8C9795FF848F8DFF
+ 83908EFF8B9896FF8C9997FF84918FFF83918FFF8A9896FF9EAFACFFB8C9C6FF
+ B3C4C1FF829390FF546764FF7D908DFF859895FF91A4A1FFADC0BDFFA8BBB8FF
+ A3B6B3FFA1B4B1FFA3B4B1FFA1B2AFFF9CADAAFF97A8A5FFA0AEACFF95A3A1FF
+ 8C9997FF8B9896FF8F9C9AFF929F9DFF929D9BFF909B99FF6C7774FF4F5A57FF
+ 4C5754FF76817EFF6F7A77FF86918EFF909B98FF98A3A0FF95A09DFF9AA5A2FF
+ 9FAAA7FF9EA9A6FF9AA5A2FF98A3A0FF9CA7A4FFA2ADAAFFA2B0ACFFA0AEAAFF
+ 9DABA7FF9AA8A4FF99A7A3FF9AA8A4FF9EACA8FFA2B0ACFF9DABA7FFA0AEAAFF
+ A5B3AFFFB5C3BFFFD3E1DDFFEEFCF8FFF0FEFAFFE1F2EFFFC4DCDAFFD2EEEEFF
+ DDF9F9FFD6F2F2FFCDE9E9FFCDE9E9FFD1EBEBFFCFE9E9FFCFE9E9FFD0EAEAFF
+ D4ECECFFD5EDEDFFD7EFEFFFD8F0F0FFD4ECECFFCEE9E6FFC1DCD9FFC2E0DBFF
+ C8E6E1FFCDEBE6FFCEE9E5FFC6E1DDFFBED7D3FFB8D1CDFFBFD6D2FFBDD4D0FF
+ CADFDCFFE0F3F0FFD9EAE7FF9CADAAFF485956FF11201CFF4D5B55FF616E66FF
+ 67766EFF87968EFF9FB0A7FF93A49BFF92A59CFF9EB1A8FF93A89FFF96ABA2FF
+ 93ABA1FF90A89EFF93ACA2FF9CB5ABFF9CB7ADFF97B2A8FF9BB2ADFF9FB6B1FF
+ 9EB5B0FF98AFAAFF99AFAAFFA1B7B2FFA6BCB7FFA5BBB6FF9DB1ACFFA1B5B0FF
+ A4B5B1FFA2B3AFFFA2B3AFFFA5B6B2FFA6B5B1FFA0B1ADFF9DB2AFFFA7BDBBFF
+ CDE3E1FFB8CECCFFB6CCCAFFA3B9B7FF97ADABFF91A7A5FF95ABA9FF95ABA9FF
+ 90A6A4FF889E9CFF859B99FF859B99FF829896FF7E9391FF7B8D8EFF728183FF
+ 606E6DFF6B7978FF3B4948FF162321FF3A4844FF2A3532FF3D4943FF434D47FF
+ 48534BFF4A554DFFBACFCCFFB5CAC7FFB4C9C6FFB4C9C6FFAABFBCFF9EB3B0FF
+ 9FB4B1FFAABFBCFFA2B7B4FFB1C6C3FFB0C5C2FFA6BBB8FFA7BCB9FFA6BBB8FF
+ A7BCB9FFB0C7C3FFAFC6C2FFA8C1BDFFA3BAB6FF9CB3AFFF9BB2AEFF9FB6B2FF
+ A9BEBBFFB1C6C3FFA8BBB8FF9AADAAFF9DB0ADFF9BAEABFFA0B1AEFF91A29FFF
+ 768784FF849592FF7C8A88FF788684FF788684FF7D8B89FF80918EFF80918EFF
+ 81928FFF849592FF7E918EFF849794FF849996FF839895FF859A97FF8BA09DFF
+ 8EA5A1FF8EA5A1FF8EA29DFF96AAA5FF9AAEA9FF96AAA5FF8EA29DFF91A5A0FF
+ A0B4AFFFAEC2BDFFAABEB9FFB5C9C4FFB5C9C4FFB4C8C3FFB9CDC8FFB4C8C3FF
+ ADC1BCFFB4C8C3FFA7B5B3FFAFBDBBFFB3C1BFFFB2C0BEFFAFBDBBFFAFBDBBFF
+ ADBBB9FFAAB8B6FFACBAB8FFB3C1BFFFB4C2C0FFABB9B7FFA3B1AFFF9EACAAFF
+ 93A19FFF869492FF6D7E7AFF768783FF7D8E8AFF80918DFF859692FF8E9F9BFF
+ 94A5A1FF95A6A2FF8FA09CFF8B9C98FF899A96FF889995FF859692FF849591FF
+ 8D9E9AFF9BA9A5FFA1A7A2FF999D98FF949B98FF8C9794FF899A96FFBFD5D0FF
+ D3EAE6FFDDF8F4FFD7F2EEFFA9C4C0FF576F6DFF748987FF758486FF869294FF
+ 8C9598FF889090FF828C8CFF7B8886FF788583FF7B8886FF7C8987FF7A8785FF
+ 798684FF7B8886FF7B8886FF778482FF758280FF788583FF778482FF758280FF
+ 778482FF7C8987FF84918FFF83908EFF83908EFF828F8DFF83908EFF859290FF
+ 879492FF899694FF98A5A3FF9BA8A6FF96A3A1FF8B9896FF83908EFF83908EFF
+ 859290FF869391FF889391FF8A9593FF8A9795FF8B9896FF8B9896FF899694FF
+ 869492FF849290FF95A6A3FFAFC0BDFFB0C1BEFF8A9B98FF546764FF7F928FFF
+ 849794FF8DA09DFFA5B8B5FFA5B8B5FFA5B8B5FFA4B7B4FFA2B3B0FF9DAEABFF
+ 98A9A6FF94A5A2FFA1AFADFF98A6A4FF8F9C9AFF8B9896FF8C9997FF8E9B99FF
+ 8C9795FF879290FF6B7673FF515C59FF586360FF808B88FF7B8683FF899491FF
+ 919C99FF949F9CFF909B98FF98A3A0FFA0ABA8FF9EA9A6FF97A29FFF949F9CFF
+ 9AA5A2FFA1ACA9FF96A4A0FF99A7A3FF9BA9A5FF9AA8A4FF97A5A1FF96A4A0FF
+ 99A7A3FF9CAAA6FF9AA8A4FFA5B3AFFFA5B3AFFFA0AEAAFFB4C2BEFFDBE9E5FF
+ F2FFFCFFEEFFFCFFD8EEECFFD3EDEDFFD3EDEDFFD7F1F1FFDCF6F6FFDBF5F5FF
+ D2ECECFFCAE4E4FFD0EAEAFFD2ECECFFD7EFEFFFDAF2F2FFDAF2F2FFD6EEEEFF
+ D1E9E9FFCBE6E3FFCDE8E5FFCBE9E4FFCBE6E2FFC8E3DFFFC4DFDBFFC1DCD8FF
+ C3DCD8FFC3DCD8FFCAE1DDFFBFD6D2FFD3E8E5FFE1F6F3FFE5F8F5FFEBFEFBFF
+ 9DAEABFF0F1E1AFF36443EFF5C6B63FF798880FF83928AFF9AABA2FF9DAEA5FF
+ 8A9D94FF9CAFA6FF95AAA1FF98ADA4FF95ADA3FF90A89EFF8EA79DFF92ABA1FF
+ 96AFA5FF96AFA5FF94ABA6FF98AFAAFF97AEA9FF91A8A3FF90A6A1FF96ACA7FF
+ 9FB3AEFFA3B7B2FF9AAEA9FFA0B4AFFFA5B6B2FFA4B5B1FFA7B6B2FFA9B8B4FF
+ A8B7B3FFA1B2AEFF91A4A1FFA0B5B2FFC7DCD9FFB0C5C2FFB1C6C3FFA5BAB7FF
+ 9AAFACFF8FA4A1FF889D9AFF8A9F9CFF869B98FF7C918EFF748986FF738885FF
+ 748986FF738885FF788A89FF617372FF546463FF6C7C7BFF445552FF152321FF
+ 31403CFF32403CFF283630FF303C36FF37443CFF3C4941FFBCD1CEFFB3C8C5FF
+ AFC4C1FFAEC3C0FFA1B6B3FF93A8A5FF9FB4B1FFB6CBC8FF95AAA7FFABC0BDFF
+ B3C8C5FFAEC3C0FFAEC3C0FFAABFBCFFA8BDBAFFB0C7C3FFB1C8C4FFABC4C0FF
+ A7BEBAFFA1B8B4FF9AB1ADFF99B0ACFFA1B6B3FFAABFBCFFA5B8B5FF97AAA7FF
+ 9BAEABFF9BAEABFFA2B3B0FF95A6A3FF7C8D8AFF8B9C99FF7F8D8BFF7C8A88FF
+ 7A8886FF7A8886FF7A8B88FF7B8C89FF7D8E8BFF80918EFF829592FF839693FF
+ 829794FF839895FF859A97FF899E9BFF8BA29EFF8DA4A0FF8B9F9AFF91A5A0FF
+ 98ACA7FF99ADA8FF91A5A0FF8FA39EFF9FB3AEFFB3C7C2FFA6BAB5FFACC0BBFF
+ AFC3BEFFB8CCC7FFC0D4CFFFB7CBC6FFB2C6C1FFC0D4CFFFAEBCBAFFB1BFBDFF
+ B3C1BFFFB1BFBDFFADBBB9FFACBAB8FFABB9B7FFAAB8B6FFA5B3B1FFABB9B7FF
+ AEBCBAFFABB9B7FFA4B2B0FF9DABA9FF95A3A1FF8E9C9AFF6A7B77FF748581FF
+ 7D8E8AFF7F908CFF82938FFF8A9B97FF92A39FFF96A7A3FF8D9E9AFF889995FF
+ 859692FF859692FF849591FF859692FF8E9F9BFF9CAAA6FFA2A8A3FF9CA09BFF
+ 99A09DFF909B98FF889995FFA8BEB9FFCAE1DDFFDCF5F1FFCEE7E3FFC5DEDAFF
+ 5F7573FF798E8CFF728183FF818D8FFF889194FF8C9696FF828E8EFF7D8A88FF
+ 788583FF768381FF758280FF73807EFF717E7CFF707D7BFF7B8886FF74817FFF
+ 717E7CFF758280FF788583FF758280FF73807EFF74817FFF808D8BFF808D8BFF
+ 7F8C8AFF7D8A88FF7C8987FF7E8B89FF828F8DFF869391FF8C9997FF93A09EFF
+ 94A19FFF8B9896FF818E8CFF7F8C8AFF808D8BFF808D8BFF85908EFF8E9997FF
+ 8F9C9AFF8B9896FF8A9795FF8D9A98FF889694FF7E8C8AFF7D8E8BFF9CADAAFF
+ AABBB8FF99AAA7FF5B6E6BFF879A97FF859895FF899C99FF8FA29FFF96A9A6FF
+ 9FB2AFFFA3B6B3FFA2B3B0FF9AABA8FF92A3A0FF8D9E9BFF8F9D9BFF8A9896FF
+ 84918FFF7F8C8AFF818E8CFF84918FFF838E8CFF7D8886FF76817EFF4D5855FF
+ 4D5855FF727D7AFF7F8A87FF8F9A97FF97A29FFF919C99FF919C99FF97A29FFF
+ 9DA8A5FF9DA8A5FF99A4A1FF97A29FFF9AA5A2FF9EA9A6FF97A5A1FF9CAAA6FF
+ A0AEAAFF9EACA8FF97A5A1FF92A09CFF919F9BFF92A09CFF97A5A1FFA2B0ACFF
+ A2B0ACFF98A6A2FF9BA9A5FFB9C7C3FFE0EEEAFFF1FFFFFFEAFFFEFFD7F1F1FF
+ CDE7E7FFD5EFEFFFE0FAFAFFDFF9F9FFD6F0F0FFD0EAEAFFD1EBEBFFD1EBEBFF
+ D2EAEAFFCCE4E4FFC1D9D9FFB9D1D1FFBBD3D3FFC1D9D7FFC9E4E0FFCBE9E4FF
+ CEE9E5FFCBE6E2FFC9E4E0FFCCE7E3FFD2EBE7FFD2EBE7FFD9F0ECFFD6EDE9FF
+ E1F6F3FFD6EBE8FFD4E7E4FFEFFFFFFFD4E5E2FF667773FF1E2E27FF3E4D45FF
+ 7F8E86FF889990FF8E9F96FFA1B2A9FF90A39AFF97AAA1FF95AAA1FF99AEA5FF
+ 97AFA5FF92AAA0FF8BA49AFF8CA59BFF92ABA1FF98B0A8FF90A7A2FF94ABA6FF
+ 96ADA8FF93AAA5FF91A7A2FF92A8A3FF9AAEA9FF9FB3AEFF9CB0ABFFA2B6B1FF
+ A8B9B5FFA7B8B4FFA9B8B4FFABBAB6FFA8B7B3FFA0B1ADFF95A8A5FFA5BAB7FF
+ CCE1DEFFB3C8C5FFB7CCC9FFB1C6C3FFA7BCB9FF9BB0ADFF92A7A4FF91A6A3FF
+ 8A9F9CFF7E9390FF778C89FF768B88FF758A87FF728784FF758786FF5F7170FF
+ 526463FF667675FF445552FF162724FF233430FF283733FF2B3B34FF32403AFF
+ 3A4842FF3F4E46FFBDD2CFFFB2C7C4FFADC2BFFFAABFBCFF9BB0ADFF8DA29FFF
+ 98ADAAFFB0C5C2FF9FB4B1FFB1C6C3FFB4C9C6FFB0C5C2FFB4C9C6FFB4C9C6FF
+ B3C8C5FFBBD2CEFFB5CCC8FFAEC7C3FFACC3BFFFA9C0BCFFA1B8B4FF99B0ACFF
+ 9CB1AEFFA5BAB7FFAABDBAFF9EB1AEFFA1B4B1FF9CAFACFF9BACA9FF899A97FF
+ 6D7E7BFF7D8E8BFF7F8D8BFF808E8CFF7E8C8AFF7B8987FF778885FF788986FF
+ 7A8B88FF7A8B88FF849794FF829592FF809592FF829794FF849996FF859A97FF
+ 859C98FF869D99FF7E928DFF849893FF8FA39EFF95A9A4FF94A8A3FF96AAA5FF
+ A5B9B4FFB8CCC7FFA7BBB6FFA6BAB5FFA5B9B4FFB2C6C1FFBED2CDFFB3C7C2FF
+ A9BDB8FFB4C8C3FFB7C5C3FFB5C3C1FFB2C0BEFFAFBDBBFFAAB8B6FFA9B7B5FF
+ ABB9B7FFAFBDBBFFA4B2B0FFA2B0AEFFA3B1AFFFA7B5B3FFA7B5B3FFA0AEACFF
+ 98A6A4FF94A2A0FF6A7975FF768581FF7F8E8AFF7E8D89FF7D8C88FF84938FFF
+ 8D9C98FF93A29EFF9BAAA6FF96A5A1FF92A19DFF91A09CFF8D9C98FF899894FF
+ 8B9A96FF919F9BFF9FA5A0FF999F9AFF9AA19EFF949F9CFF8C9B97FF94A8A3FF
+ C0D5D2FFD2EBE7FFD1EAE6FFD0E9E5FF607674FF708281FF6A797BFF7C888AFF
+ 7F888BFF828C8CFF838F8FFF818E8CFF7D8A88FF7A8785FF798684FF798684FF
+ 768381FF73807EFF798684FF73807EFF73807EFF798684FF7D8A88FF7A8785FF
+ 758280FF73807EFF808D8BFF808D8BFF7E8B89FF7A8785FF788583FF7A8785FF
+ 808D8BFF869391FF8A9795FF93A09EFF97A4A2FF909D9BFF859290FF7F8C8AFF
+ 7C8987FF798684FF7E8987FF8A9593FF8C9997FF859290FF859290FF8A9795FF
+ 849290FF778583FF798A87FF98A9A6FFABBCB9FFA8B9B6FF607370FF93A6A3FF
+ 91A4A1FF96A9A6FF8B9E9BFF91A4A1FF9AADAAFF9FB2AFFFA0B1AEFF9BACA9FF
+ 95A6A3FF92A3A0FF8E9C9AFF8E9C9AFF8A9795FF84918FFF859290FF8A9795FF
+ 899492FF818C8AFF737E7BFF495451FF4D5855FF6A7572FF7A8582FF848F8CFF
+ 939E9BFF8E9996FF97A29FFF97A29FFF99A4A1FF9CA7A4FF9EA9A6FF9EA9A6FF
+ 9CA7A4FF9AA5A2FFA2B0ACFFA6B4B0FFA8B6B2FFA5B3AFFF9DABA7FF96A4A0FF
+ 92A09CFF919F9BFF99A7A3FF9DABA7FFA2B0ACFF9FADA9FF95A39FFF9DABA7FF
+ C4D2CEFFECFDFAFFE7FDFBFFE3FBF9FFE1F9F7FFDCF4F2FFD0E8E6FFC9E1DFFF
+ D2EAE8FFE0F8F6FFD4ECEAFFD2EAE8FFCBE3E1FFBBD3D1FFA4BCBAFF98B0AEFF
+ A3BBB9FFB7CFCDFFAAC5C1FFBCD7D3FFD1ECE8FFDDF8F4FFE7FFFCFFEAFFFFFF
+ E6FDF9FFDCF3EFFFE2F9F5FFECFFFFFFE7FCF9FFD5EAE7FFD2E7E4FFE0F5F2FF
+ DEF1EEFFCBDCD8FF475750FF1B2B24FF596962FF8F9F98FF92A29BFF9CAEA7FF
+ 9BADA6FFA0B2ABFF9BB0A8FF9EB3ABFF9EB5ADFF9CB3ABFF96ADA5FF95ACA4FF
+ 9CB3ABFFA4BBB3FF96ACA7FF99AFAAFF9EB4AFFFA0B6B1FF9EB4AFFF9BB1ACFF
+ 9DB1ACFFA0B4AFFFA0B1ADFFA6B7B3FFABBAB6FFAAB9B5FFAAB9B5FFABBAB6FF
+ A8B7B3FFA0B1ADFF97AAA7FFA1B6B3FFC4D9D6FFAABFBCFFAFC4C1FFA9BEBBFF
+ A1B6B3FF98ADAAFF96ABA8FF8FA4A1FF839895FF778C89FF738885FF738885FF
+ 6D827FFF657A77FF6A7F7DFF5E7371FF4D625FFF4A5D5AFF324542FF1C2F2CFF
+ 253934FF293A36FF2A3B37FF32423BFF394942FF3D4D46FFB9CECBFFB4C9C6FF
+ B1C6C3FFAEC3C0FFA2B7B4FF93A8A5FF93A8A5FF9CB1AEFFA9BEBBFFB4C9C6FF
+ ADC2BFFFA4B9B6FFAABFBCFFB0C5C2FFB7CCC9FFC2D9D5FFB9D0CCFFAEC7C3FF
+ ADC4C0FFAEC5C1FFA8BFBBFF9DB4B0FF9EB3B0FFA5BAB7FFA4B7B4FF99ACA9FF
+ 9EB1AEFF9AADAAFF9AABA8FF879895FF6A7B78FF798A87FF7D8B89FF82908EFF
+ 83918FFF808E8CFF7B8C89FF7C8D8AFF7C8D8AFF798A87FF8A9D9AFF869996FF
+ 859A97FF8A9F9CFF8CA19EFF899E9BFF879E9AFF889F9BFF869A95FF8A9E99FF
+ 8FA39EFF91A5A0FF93A7A2FF98ACA7FF9FB3AEFFA5B9B4FFAEC2BDFFABBFBAFF
+ A5B9B4FFAFC3BEFFBCD0CBFFB2C6C1FFA3B7B2FFA5B9B4FFBCCAC8FFB6C4C2FF
+ B1BFBDFFADBBB9FFA9B7B5FFA6B4B2FFABB9B7FFB2C0BEFFA9B7B5FF9FADABFF
+ 9CAAA8FFA4B2B0FFA8B6B4FFA0AEACFF99A7A5FF98A6A4FF677672FF74837FFF
+ 7D8C88FF7A8985FF758480FF7A8985FF859490FF8C9B97FF94A39FFF91A09CFF
+ 91A09CFF93A29EFF91A09CFF8C9B97FF8A9995FF8D9B97FF9FA6A1FF9BA19CFF
+ 9EA5A2FF9DA8A5FF96A5A1FF8CA09BFFC1D6D3FFD7EEEAFFCDE4E0FFC0D7D3FF
+ 5E7371FF596B6AFF606F71FF7B888AFF7A8688FF788282FF7C8888FF7E8B89FF
+ 7D8A88FF7C8987FF7E8B89FF818E8CFF7F8C8AFF7A8785FF788583FF74817FFF
+ 768381FF7D8A88FF818E8CFF7C8987FF778482FF758280FF808D8BFF818E8CFF
+ 808D8BFF7D8A88FF798684FF7A8785FF808D8BFF869391FF7B8886FF84918FFF
+ 8A9795FF889593FF84918FFF84918FFF84918FFF818E8CFF7E8987FF879290FF
+ 899694FF859290FF859290FF889593FF83918FFF798785FF70817EFF899A97FF
+ 9AABA8FFA1B2AFFF526562FF93A6A3FF9BAEABFFA6B9B6FFA7BAB7FFA5B8B5FF
+ A2B5B2FF9EB1AEFF9CADAAFF96A7A4FF91A29FFF8E9F9CFF98A6A4FF9CAAA8FF
+ 99A6A4FF919E9CFF909D9BFF95A2A0FF939E9CFF899492FF697471FF4E5956FF
+ 636E6BFF76817EFF7B8683FF75807DFF8E9996FF919C99FF9AA5A2FF98A3A0FF
+ 98A3A0FF9CA7A4FFA2ADAAFFA3AEABFF9EA9A6FF98A3A0FF94A29EFF96A4A0FF
+ 99A7A3FF9CAAA6FF9EACA8FF9FADA9FF9FADA9FF9EACA8FF9EACA8FF9CAAA6FF
+ A2B0ACFFA8B6B2FF9CAAA6FF95A39FFFAFBDB9FFD6E5E1FFEDFFFFFFEAFFFFFF
+ EBFFFFFFDFF7F5FFD4ECEAFFD0E8E6FFD4ECEAFFDAF2F0FFE3FBF9FFDEF6F4FF
+ D5EDEBFFBFD7D5FF9FB7B5FF89A19FFF90A8A6FFA5BDBBFF9AB5B1FFA9C4C0FF
+ B9D4D0FFC5E0DCFFD7F0ECFFE7FFFCFFEBFFFEFFE4FBF7FFDDF4F0FFE8FFFBFF
+ DEF3F0FFD8EDEAFFE2F7F4FFD5EAE7FFCEE3E0FFE8FCF7FFADBEBAFF36463FFF
+ 384841FF899992FF9AACA5FF8C9E97FF8EA099FF9EB0A9FF9AAFA7FF9CB1A9FF
+ 9EB5ADFFA0B7AFFF9CB3ABFF99B0A8FF9EB5ADFFA7BEB6FF98AEA9FF98AEA9FF
+ 9CB2ADFFA3B9B4FFA3B9B4FF9EB4AFFF9CB0ABFF9CB0ABFF9FB0ACFFA4B5B1FF
+ A9B8B4FFA7B6B2FFA8B7B3FFAAB9B5FFA8B7B3FFA1B2AEFF9AADAAFF99AEABFF
+ B6CBC8FFA0B5B2FFA7BCB9FF9FB4B1FF9DB2AFFF9DB2AFFF90A5A2FF899E9BFF
+ 7B908DFF708582FF6E8380FF6D827FFF647976FF596E6BFF5D726FFF5A6F6CFF
+ 4C615EFF3C514EFF394E4BFF435855FF536762FF5B6F6AFF6D817CFF738480FF
+ 788A83FF7A8C85FFB5CAC7FFB4C9C6FFB3C8C5FFB0C5C2FFABC0BDFFA3B8B5FF
+ 9AAFACFF94A9A6FFA1B6B3FFAEC3C0FFAABFBCFFA0B5B2FFA3B8B5FFA8BDBAFF
+ AFC4C1FFBCD3CFFFB7CECAFFA8C1BDFFA4BBB7FFA8BFBBFFA7BEBAFFA0B7B3FF
+ A1B6B3FFA9BEBBFF9EB1AEFF91A4A1FF96A9A6FF99ACA9FFA2B3B0FF92A3A0FF
+ 728380FF7C8D8AFF748280FF7E8C8AFF859391FF83918FFF7F908DFF81928FFF
+ 7F908DFF798A87FF8A9D9AFF859895FF859A97FF8EA3A0FF91A6A3FF8DA29FFF
+ 889F9BFF89A09CFF91A5A0FF94A8A3FF91A5A0FF8DA19CFF92A6A1FF9CB0ABFF
+ 9BAFAAFF91A5A0FFA3B7B2FFA6BAB5FFA4B8B3FFABBFBAFFBBCFCAFFB7CBC6FF
+ AABEB9FFA9BDB8FFB9C7C5FFB3C1BFFFAFBDBBFFAEBCBAFFAAB8B6FFA5B3B1FF
+ A8B6B4FFB0BEBCFFADBBB9FF9FADABFF9AA8A6FFA2B0AEFFA3B1AFFF99A7A5FF
+ 94A2A0FF99A7A5FF667571FF758480FF7E8D89FF798884FF72817DFF768581FF
+ 82918DFF8B9A96FF8B9A96FF899894FF8B9A96FF91A09CFF92A19DFF8D9C98FF
+ 8B9A96FF8D9B97FF9DA49FFF969D98FF98A19EFF9BA9A5FF9BAAA6FF869A95FF
+ C5DAD7FFDDF4F0FFC9E0DCFFC0D7D3FF8CA19FFF6D7F7EFF677678FF798688FF
+ 788486FF768282FF758181FF7B8886FF7D8A88FF7D8A88FF808D8BFF859290FF
+ 828F8DFF7A8785FF7A8785FF778482FF778482FF7C8987FF7D8A88FF798684FF
+ 778482FF788583FF798684FF7E8B89FF828F8DFF818E8CFF7D8A88FF7A8785FF
+ 7C8987FF7F8C8AFF74817FFF798684FF7A8785FF788583FF7B8886FF83908EFF
+ 879492FF869391FF7F8A88FF838E8CFF84918FFF859290FF859290FF859290FF
+ 818F8DFF7E8C8AFF748582FF899A97FF98A9A6FFA2B3B0FF485B58FF8B9E9BFF
+ 93A6A3FF9EB1AEFFA8BBB8FFA5B8B5FFA3B6B3FFA1B4B1FFA0B1AEFF99AAA7FF
+ 8E9F9CFF869794FF96A4A2FF9CAAA8FF9BA8A6FF929F9DFF919E9CFF96A3A1FF
+ 95A09EFF899492FF687370FF4C5754FF66716EFF75807DFF7C8784FF727D7AFF
+ 909B98FF939E9BFF97A29FFF98A3A0FF9BA6A3FF9EA9A6FFA1ACA9FFA0ABA8FF
+ 9DA8A5FF9AA5A2FF8B9995FF899793FF889692FF8E9C98FF97A5A1FF9EACA8FF
+ A0AEAAFF9FADA9FF9FADA9FF9CAAA6FF9EACA8FFA4B2AEFFA2B0ACFF9EACA8FF
+ A5B3AFFFB2C1BDFFE3F6F3FFE8FFFBFFEBFFFDFFE6FDF9FFE6FDF9FFE8FFFBFF
+ E0F7F3FFD4EBE7FFE4FDF9FFE0F9F5FFDEF7F3FFD4EDE9FFB6D1CDFF99B4B0FF
+ 93AEAAFF9CB7B3FFB4CDC9FFB4CDC9FFADC6C2FFAAC3BFFFBED5D1FFDAF1EDFF
+ E8FFFBFFE6FDF9FFD9F0ECFFDCF3EFFFD6EDE9FFD9F0ECFFE2F9F5FFD5ECE8FF
+ CAE1DDFFD6ECE7FFE8F9F5FF889A93FF475952FF72847DFF94A69FFF7C8E87FF
+ 7A8F87FF8FA49CFF93A8A0FF93A8A0FF97ACA4FF9DB2AAFF9CB1A9FF96ABA3FF
+ 99AEA6FFA0B5ADFF9AB0ABFF94AAA5FF96AAA5FF9FB3AEFFA3B7B2FF9EB2ADFF
+ 9BACA8FF9AABA7FF9BAAA6FFA0AFABFFA2B1ADFFA1B0ACFFA4B2AEFFA9B7B3FF
+ AAB8B4FFA6B5B1FFA6B7B3FF9BAFAAFFB5C9C4FFAABEB9FFB7CBC6FFB1C5C0FF
+ B8CCC7FFC6DAD5FFB3C7C2FFB0C4BFFFA7BBB6FF9DB1ACFF97ABA6FF95A9A4FF
+ 8EA29DFF839994FF768C87FF778E89FF738A85FF6A817CFF748B86FF839A95FF
+ 8AA09BFF97ADA8FF95ABA6FF9AAEA9FF9EB2ADFF9FB3AEFFB3C8C5FFB3C8C5FF
+ AFC4C1FFACC1BEFFAEC3C0FFB0C5C2FFA8BDBAFF9CB1AEFF97ACA9FFACC1BEFF
+ B2C7C4FFABC0BDFFAABFBCFFA8BDBAFFAABFBCFFB5CCC8FFB2C9C5FF9FB8B4FF
+ 99B0ACFF9FB6B2FFA2B9B5FF9EB5B1FFA1B6B3FFABC0BDFFA8BBB8FF95A8A5FF
+ 96A9A6FF9BAEABFFA8B9B6FF98A9A6FF71827FFF748582FF6B7977FF798785FF
+ 83918FFF83918FFF81928FFF829390FF80918EFF798A87FF7F928FFF7A8D8AFF
+ 7B908DFF879C99FF8CA19EFF879C99FF819894FF829995FF8A9E99FF8EA29DFF
+ 8B9F9AFF879B96FF95A9A4FFA9BDB8FFA6BAB5FF94A8A3FF889C97FF95A9A4FF
+ 99ADA8FFA2B6B1FFB5C9C4FFBACEC9FFB3C7C2FFB3C7C2FFB5C3C1FFB0BEBCFF
+ AEBCBAFFAFBDBBFFABB9B7FFA4B2B0FFA5B3B1FFADBBB9FFADBBB9FF9EACAAFF
+ 9AA8A6FFA0AEACFF9CAAA8FF8F9D9BFF8D9B99FF97A5A3FF687773FF778682FF
+ 81908CFF7B8A86FF73827EFF778682FF84938FFF8E9D99FF98A7A3FF94A39FFF
+ 93A29EFF96A5A1FF94A39FFF8D9C98FF889793FF899793FF919B95FF8A918CFF
+ 8B9491FF909E9AFF94A39FFF7D8E8AFFC3D6D3FFDCF1EEFFD9EEEBFFE1F6F3FF
+ DAEFEDFFA2B4B3FF7C8B8DFF738284FF727F81FF778383FF798585FF808D8BFF
+ 83908EFF828F8DFF859290FF899694FF84918FFF7A8785FF7D8A88FF798684FF
+ 778482FF798684FF778482FF74817FFF758280FF798684FF717E7CFF798684FF
+ 818E8CFF83908EFF7E8B89FF788583FF768381FF778482FF879492FF84918FFF
+ 7C8987FF74817FFF74817FFF7A8785FF7E8B89FF7C8987FF7A8583FF7A8583FF
+ 7A8785FF7F8C8AFF7F8C8AFF7C8987FF7A8886FF7B8987FF94A5A2FFA6B7B4FF
+ B3C4C1FFBBCCC9FF506360FF889B98FF849794FF889B98FF849794FF899C99FF
+ 94A7A4FFA1B4B1FFABBCB9FFA6B7B4FF97A8A5FF899A97FF8C9A98FF95A3A1FF
+ 96A3A1FF8D9A98FF8D9A98FF94A19FFF949F9DFF889391FF6A7572FF3F4A47FF
+ 4F5A57FF5E6966FF76817EFF737E7BFF919C99FF8C9794FF939E9BFF98A3A0FF
+ 9EA9A6FFA0ABA8FF9EA9A6FF9CA7A4FF9BA6A3FF9CA7A4FFA0AEAAFF97A5A1FF
+ 8E9C98FF8D9B97FF92A09CFF95A39FFF92A09CFF8E9C98FF9DABA7FF9BA9A5FF
+ 98A6A2FF9AA8A4FFA2B0ACFFA8B6B2FFA2B0ACFF96A5A1FFB7CAC7FFDBF0EDFF
+ EDFFFFFFEDFFFFFFE3F8F5FFE0F7F3FFE1F8F4FFDDF4F0FFCFE6E2FFCFE8E4FF
+ D9F2EEFFE3FCF8FFD5F0ECFFBAD5D1FFABC6C2FFACC7C3FFD3ECE8FFCFE8E4FF
+ C3DCD8FFBBD4D0FFCAE1DDFFE1F8F4FFE8FFFBFFE0F7F3FFE0F7F3FFDDF4F0FF
+ DDF4F0FFDBF2EEFFD6EDE9FFD9F0ECFFD8EFEBFFCCE3DFFFD6EAE5FFCBDDD6FF
+ 6C7E77FF5B6D66FF869891FF7B8D86FF7A8F87FF8CA199FF91A69EFF8FA49CFF
+ 93A8A0FF9BB0A8FF9BB0A8FF95AAA2FF94A9A1FF9AAFA7FFA3B7B2FF96ACA7FF
+ 95A9A4FF9EB2ADFFA5B9B4FFA1B5B0FF9EAFABFF9DAEAAFF95A4A0FF99A8A4FF
+ 9CABA7FF9CABA7FFA1AFABFFA8B6B2FFABB9B5FFA8B7B3FF93A4A0FF819590FF
+ 9DB1ACFF9CB0ABFFB0C4BFFFAEC2BDFFBDD1CCFFD5E9E4FFD1E5E0FFD4E8E3FF
+ D0E4DFFFC5D9D4FFBCD0CBFFB8CCC7FFB4C8C3FFAFC3BEFFABC1BCFFACC3BEFF
+ B0C7C2FFADC4BFFFB4CBC6FFB0C7C2FFA1B8B3FFACC3BEFFADC3BEFFB0C6C1FF
+ B3C9C4FFB3CAC5FFC2D7D4FFC1D6D3FFB9CECBFFADC2BFFFA6BBB8FFA6BBB8FF
+ A4B9B6FFA0B5B2FFA0B5B2FFABC0BDFFB7CCC9FFB6CBC8FFA8BDBAFF9FB4B1FF
+ A8BDBAFFB7CECAFFA7BEBAFF9FB8B4FF9FB6B2FFA1B8B4FFA2B9B5FFA2B9B5FF
+ A6BBB8FFACC1BEFFA3B6B3FF9BAEABFF9EB1AEFFA3B6B3FFA3B4B1FF9EAFACFF
+ 869794FF61726FFF6D7B79FF7C8A88FF859391FF808E8CFF7C8D8AFF839491FF
+ 879895FF839491FF8FA29FFF899C99FF839895FF859A97FF8CA19EFF91A6A3FF
+ 90A7A3FF8DA4A0FF80948FFF829691FF90A49FFF8EA29DFF869A95FF9EB2ADFF
+ B4C8C3FFA9BDB8FF9AAEA9FF93A7A2FF9CB0ABFFADC1BCFFACC0BBFF9EB2ADFF
+ A3B7B2FFB7CBC6FFBBC9C7FFABB9B7FFA7B5B3FFB2C0BEFFB2C0BEFFA3B1AFFF
+ 9EACAAFFA6B4B2FFABB9B7FFA9B7B5FFA5B3B1FF9EACAAFF97A5A3FF94A2A0FF
+ 94A2A0FF96A4A2FF62706CFF62706CFF808E8AFF74827EFF798783FF8E9C98FF
+ 788682FF7E8C88FF8C9A96FF93A19DFF94A29EFF909E9AFF8E9C98FF909E9AFF
+ 8E9C98FF899793FF99A39DFF939D97FF8E9996FF8C9A96FF8A9995FF8E9F9BFF
+ A0B3B0FFB5C8C5FFD9ECE9FFEEFFFEFFE3F5F4FFD7E9E8FFADBCBEFF879698FF
+ 8A999BFF717F7EFF798585FF788583FF7A8785FF808D8BFF879492FF889593FF
+ 83908EFF7D8A88FF798684FF7E8B89FF818E8CFF7C8987FF73807EFF6F7C7AFF
+ 727F7DFF778482FF798684FF758280FF788583FF818E8CFF83908EFF7C8987FF
+ 74817FFF717E7CFF828F8DFF7C8987FF74817FFF6D7A78FF6C7977FF707D7BFF
+ 768381FF7A8785FF7E8987FF76817FFF73807EFF7D8A88FF83908EFF818E8CFF
+ 7E8C8AFF818F8DFF849592FF8D9E9BFFA9BAB7FFB9CAC7FF94A7A4FF5E716EFF
+ 9DB0ADFF97AAA7FF95A8A5FF91A4A1FF91A4A1FF98ABA8FFA4B5B2FFA7B8B5FF
+ A0B1AEFF97A8A5FF95A3A1FF92A09EFF95A2A0FF9AA7A5FF98A5A3FF8F9C9AFF
+ 8A9593FF889391FF6D7875FF46514EFF414C49FF5F6A67FF6F7A77FF75807DFF
+ 838E8BFF919C99FF919C99FF97A29FFF9DA8A5FF9FAAA7FF9DA8A5FF9BA6A3FF
+ 9EA9A6FFA1ACA9FFA1AFABFF9EACA8FF9AA8A4FF98A6A2FF97A5A1FF96A4A0FF
+ 93A19DFF919F9BFF9CAAA6FF9DABA7FF9DABA7FF9AA8A4FF97A5A1FF98A6A2FF
+ 9EACA8FFA2B1ADFF93A4A1FFB1C4C1FFD8EBE8FFEDFFFDFFEBFEFBFFE0F5F2FF
+ DCF1EEFFDDF4F0FFD9F0ECFFCEE5E1FFD3ECE8FFD4EDE9FFE0FBF7FFC9E4E0FF
+ A1BCB8FFC9E4E0FFD1EAE6FFD4EBE7FFD8EFEBFFDDF4F0FFE2F9F5FFE4FBF7FF
+ E1F8F4FFDFF6F2FFD9F0ECFFD4EBE7FFD8EFEBFFD8EFEBFFCFE8E4FFD3ECE8FF
+ D6EFEBFFCDE4E0FFCBDFDAFFCDE1DCFFA5B9B4FF445853FF728681FF80948FFF
+ 70847FFF849893FF849893FF899D98FF90A19DFF92A39FFF92A39FFF97A8A4FF
+ A2B3AFFFA9BDB8FFA2B6B1FF9EB2ADFF9CB0ABFF9DB1ACFF9DAEAAFF99AAA6FF
+ 9BAAA6FF9FAEAAFF9DACA8FF9CABA7FF99A7A3FF96A4A0FF9CA7A4FFA5B0ADFF
+ ABB6B3FFAAB8B4FF93A39CFF74867FFF7C8E87FF788A83FF7F918AFF8B9D96FF
+ 80928BFF97A9A2FFABBDB6FFBBCDC6FFCFE1DAFFD9EBE4FFD5E7E0FFCCDED7FF
+ C4D6CFFFBFD4CCFFBFD6CEFFB6CEC6FFBBD3CBFFBED6CEFFB5CCC7FFB5CCC7FF
+ BCD3CEFFB9D0CBFFBBD2CDFFBBD2CDFFBAD1CCFFB7D1CBFFBDD2CFFFBED3D0FF
+ B9CECBFFAFC4C1FFA7BCB9FFA3B8B5FF9DB2AFFF96ABA8FFA4B9B6FFADC2BFFF
+ B8CDCAFFB8CDCAFFADC2BFFFA4B9B6FFABC0BDFFB8CFCBFFA3BAB6FF9BB4B0FF
+ 99B0ACFF9BB2AEFF9DB4B0FF9DB4B0FFA3B8B5FFAABFBCFFA7BAB7FF9EB1AEFF
+ 9BAEABFF9AADAAFF9DAEABFFA0B1AEFF8C9D9AFF667774FF697775FF748280FF
+ 7C8A88FF7D8B89FF7B8C89FF7F908DFF839491FF849592FF8FA29FFF8A9D9AFF
+ 839895FF849996FF899E9BFF8FA4A1FF91A8A4FF91A8A4FF93A7A2FF899D98FF
+ 8CA09BFF90A49FFF8A9E99FF91A5A0FFA8BCB7FFB8CCC7FFB1C5C0FF98ACA7FF
+ 8DA19CFF9BAFAAFFA4B8B3FF9EB2ADFF9CB0ABFFA3B7B2FFBAC8C6FFB6C4C2FF
+ B2C0BEFFAEBCBAFFA9B7B5FFA7B5B3FFA9B7B5FFADBBB9FFAFBDBBFFADBBB9FF
+ A8B6B4FFA0AEACFF97A5A3FF92A09EFF919F9DFF92A09EFF6E7C78FF5E6C68FF
+ 788682FF72807CFF778581FF8A9894FF768480FF818F8BFF879591FF8F9D99FF
+ 97A5A1FF98A6A2FF93A19DFF8E9C98FF8D9B97FF929D9AFF909C96FF8E9A94FF
+ 8E9996FF909E9AFF919F9BFF94A39FFFA1B2AFFFB0C3C0FFBDD0CDFFDBEEEBFF
+ D7E9E8FFD4E6E5FFBFCED0FF9CABADFF94A3A5FF7F8F8EFF818F8EFF808D8BFF
+ 808D8BFF828F8DFF859290FF869391FF84918FFF828F8DFF7C8987FF7F8C8AFF
+ 808D8BFF7C8987FF758280FF727F7DFF73807EFF768381FF74817FFF717E7CFF
+ 717E7CFF768381FF7D8A88FF7D8A88FF73807EFF687573FF758280FF758280FF
+ 758280FF758280FF758280FF758280FF74817FFF74817FFF7F8A88FF778280FF
+ 74817FFF7C8987FF828F8DFF828F8DFF808E8CFF82908EFF859693FF8A9B98FF
+ A5B6B3FFB0C1BEFF9FB2AFFF718481FF8EA19EFF91A4A1FF97AAA7FF8FA29FFF
+ 8A9D9AFF90A3A0FF9DAEABFFA1B2AFFF9AABA8FF91A29FFF8F9D9BFF8C9A98FF
+ 909D9BFF97A4A2FF96A3A1FF869391FF747F7DFF687371FF606B68FF3A4542FF
+ 36413EFF55605DFF687370FF707B78FF808B88FF8D9895FF919C99FF929D9AFF
+ 949F9CFF97A29FFF9AA5A2FF9CA7A4FF9CA7A4FF9BA6A3FFA3B1ADFFA0AEAAFF
+ 9CAAA6FF9AA8A4FF99A7A3FF97A5A1FF94A29EFF919F9BFF94A29EFF95A39FFF
+ 97A5A1FF97A5A1FF96A4A0FF96A4A0FF98A6A2FF9AA8A4FF909E9CFF9FB0ADFF
+ BBCCC9FFD6E9E6FFEAFDFAFFEFFFFFFFE9FCF9FFDFF4F1FFE6FDF9FFCEE5E1FF
+ DEF7F3FFDFF8F4FFD2EDE9FFCAE5E1FFBBD6D2FFCDE8E4FFD9F0ECFFDAF1EDFF
+ DDF4F0FFE1F8F4FFE4FBF7FFE3FAF6FFDFF6F2FFDBF2EEFFD9F0ECFFD2E9E5FF
+ D7EEEAFFD6EFEBFFCEE7E3FFCFE8E4FFD0E9E5FFC5DEDAFFC4DAD5FFC4D8D3FF
+ A3B7B2FF617570FF768A85FF839792FF728681FF849893FF7F938EFF819590FF
+ 869793FF889995FF8C9D99FF92A39FFF9BACA8FFA1B2AEFF91A29EFF91A5A0FF
+ 98ACA7FF9DB1ACFF9DAEAAFF99AAA6FF9DACA8FFA3B2AEFF99A8A4FF9AA9A5FF
+ 98A6A2FF8F9D99FF8B9693FF8C9794FF929D9AFF96A4A0FF9BABA4FF7C8E87FF
+ 80928BFF7E9089FF869891FF8FA19AFF83958EFF93A59EFF80928BFF91A39CFF
+ AABCB5FFC2D4CDFFD1E3DCFFD6E8E1FFD4E6DFFFD0E5DDFFCDE4DCFFC4DCD4FF
+ C7DED6FFC4DCD4FFBDD4CFFFC3DAD5FFCCE3DEFFC7DED9FFBDD4CFFFBDD4CFFF
+ BAD4CEFFBAD4CEFFB9CECBFFBDD2CFFFBCD1CEFFB5CAC7FFAFC4C1FFA9BEBBFF
+ A1B6B3FF98ADAAFFA5BAB7FFABC0BDFFB4C9C6FFB8CDCAFFB1C6C3FFAABFBCFF
+ AEC3C0FFB7CECAFFAFC6C2FFA4BDB9FF9FB6B2FF9CB3AFFF9AB1ADFF98AFABFF
+ 9DB2AFFFA3B8B5FFA9BCB9FFA3B6B3FF9EB1AEFF96A9A6FF9AABA8FFA7B8B5FF
+ 99AAA7FF738481FF6A7876FF6E7C7AFF778583FF7F8D8BFF7F908DFF7E8F8CFF
+ 829390FF899A97FF8B9E9BFF889B98FF839895FF829794FF859A97FF8A9F9CFF
+ 8EA5A1FF91A8A4FFA3B7B2FF93A7A2FF899D98FF91A5A0FF91A5A0FF839792FF
+ 97ABA6FFC5D9D4FFB9CDC8FF9DB1ACFF8B9F9AFF93A7A2FFA0B4AFFFA2B6B1FF
+ A3B7B2FFA9BDB8FFB0BEBCFFBAC8C6FFBBC9C7FFB0BEBCFFA9B7B5FFACBAB8FF
+ ADBBB9FFA9B7B5FFAEBCBAFFACBAB8FFA7B5B3FFA0AEACFF98A6A4FF93A19FFF
+ 92A09EFF92A09EFF6E7C78FF4A5552FF606B68FF67726FFF6F7A77FF7E8986FF
+ 6E7976FF7E8986FF7A8582FF7F8A87FF8C9794FF949F9CFF8D9895FF808B88FF
+ 818C89FF8C9794FF8B9791FF8B9791FF8F9A97FF919F9BFF93A19DFF94A39FFF
+ 9DABA9FFA5B6B3FFADBEBBFFD2E3E0FFCEE0DFFFCFE1E0FFCEE0E1FFAFC1C2FF
+ 9CAEAFFF95A5A4FF8C9A99FF8D9A98FF8B9896FF889593FF859290FF84918FFF
+ 859290FF879492FF7F8C8AFF7F8C8AFF7D8A88FF7B8886FF788583FF768381FF
+ 74817FFF74817FFF788583FF788583FF758280FF768381FF808D8BFF889593FF
+ 7D8A88FF6A7775FF707D7BFF717E7CFF727F7DFF74817FFF758280FF768381FF
+ 768381FF768381FF808B89FF798482FF758280FF7C8987FF828F8DFF83908EFF
+ 82908EFF83918FFF96A7A4FF99AAA7FFB2C3C0FFB4C5C2FFBDD0CDFF9BAEABFF
+ 899C99FFA0B3B0FF98ABA8FF8FA29FFF889B98FF8A9D9AFF96A7A4FF9BACA9FF
+ 98A9A6FF92A3A0FF8D9B99FF889694FF8A9795FF94A19FFF96A3A1FF899694FF
+ 76817FFF687371FF57625FFF323D3AFF2D3835FF4A5552FF5B6663FF646F6CFF
+ 747F7CFF808B88FF929D9AFF8F9A97FF8D9895FF929D9AFF99A4A1FF9DA8A5FF
+ 9BA6A3FF98A3A0FF9FADA9FF9EACA8FF9CAAA6FF9CAAA6FF9CAAA6FF9BA9A5FF
+ 98A6A2FF95A39FFF909E9AFF919F9BFF92A09CFF95A39FFF97A5A1FF98A6A2FF
+ 96A4A0FF94A29EFF9BA9A5FF97A6A2FF99A8A4FFA6B7B3FFBECFCBFFD2E6E1FF
+ E0F4EFFFE2F8F3FFECFFFEFFD6EDE8FFEAFFFEFFE6FFFAFFC1DDD7FFC7E3DDFF
+ CFEEE7FFCFEBE5FFE0F7F3FFE2F7F4FFE4F9F6FFE6FBF8FFE7FCF9FFE4F9F6FF
+ DDF4F0FFD8EFEBFFD9F0ECFFD2E9E5FFD4EDE9FFD8F1EDFFD0E9E5FFCCE7E3FF
+ CAE5E1FFC1DAD6FFC2D7D4FFBCD1CEFFA3B8B5FF839895FF6E8380FF829794FF
+ 758885FF7D908DFF829390FF829390FF81928FFF829390FF879593FF8D9B99FF
+ 93A19FFF95A6A3FF9CADA9FF99AAA6FF96A7A3FF93A4A0FF8E9D99FF8C9B97FF
+ 95A4A0FFA1B0ACFF9AA8A4FF9DABA7FF9EA9A6FF949F9CFF85908DFF7F8A87FF
+ 89928FFF919C99FF96A69FFF7F918AFF81938CFF82948DFF8A9C95FF90A29BFF
+ 869891FF90A29BFF889A93FF889A93FF8D9F98FF99ABA4FFADBFB8FFC1D3CCFF
+ D1E3DCFFD9EBE4FFD5EAE1FFD0E8DEFFD3E8DFFFCAE2D8FFC1D8D0FFC9E0D8FF
+ CDE3DEFFBFD5D0FFC3DAD5FFC2D9D4FFC0D9D5FFC0D9D5FFB7CCC9FFBCD1CEFF
+ BDD2CFFFB9CECBFFB6CBC8FFB3C8C5FFACC1BEFFA5BAB7FFA2B7B4FFA5BAB7FF
+ ADC2BFFFB3C8C5FFB2C7C4FFADC2BFFFB1C6C3FFB7CECAFFB2C9C5FFA7C0BCFF
+ A0B7B3FF9CB3AFFF99B0ACFF97AEAAFF9DB2AFFFA4B9B6FF9FB2AFFFA2B5B2FF
+ A2B5B2FF97AAA7FF95A6A3FFA3B4B1FF9BACA9FF788986FF6B7977FF697775FF
+ 717F7DFF7F8D8BFF7F908DFF7A8B88FF7D8E8BFF879895FF839693FF849794FF
+ 829794FF819693FF809592FF829794FF869D99FF89A09CFFA0B4AFFF9AAEA9FF
+ 8DA19CFF92A6A1FF95A9A4FF819590FF8DA19CFFC2D6D1FFB5C9C4FFA9BDB8FF
+ A0B4AFFF9FB3AEFF9EB2ADFF9DB1ACFFA5B9B4FFB1C5C0FFA8B6B4FFB1BFBDFF
+ B9C7C5FFBAC8C6FFB6C4C2FFB0BEBCFFA7B5B3FF9FADABFFA6B4B2FFA6B4B2FF
+ A4B2B0FF9FADABFF99A7A5FF96A4A2FF95A3A1FF97A5A3FF6E7976FF35403DFF
+ 4B5653FF616C69FF6B7673FF76817EFF67726FFF798481FF737E7BFF6F7A77FF
+ 788380FF85908DFF808B88FF717C79FF717C79FF7F8A87FF89958FFF8A9690FF
+ 8A9894FF8C9A96FF8E9C98FF919F9BFF94A2A0FF98A6A4FFB0BEBCFFD4E5E2FF
+ D4E4E3FFCFE1E0FFD4E6E7FFB5C7C8FF97A9AAFF9FAFAEFF94A2A1FF97A4A2FF
+ 97A4A2FF919E9CFF889593FF84918FFF869391FF899694FF828F8DFF7E8B89FF
+ 7A8785FF798684FF7A8785FF798684FF758280FF717E7CFF7A8785FF818E8CFF
+ 808D8BFF7B8886FF83908EFF909D9BFF889593FF758280FF7A8785FF758280FF
+ 6F7C7AFF6A7775FF6C7977FF727F7DFF7A8785FF808D8BFF818C8AFF7C8785FF
+ 788583FF7C8987FF828F8DFF859290FF83918FFF82908EFFA3B4B1FFAABBB8FF
+ C1D2CFFFB9CAC7FFD3E6E3FFBCCFCCFF859895FFB5C8C5FF9CAFACFF96A9A6FF
+ 90A3A0FF8DA09DFF91A29FFF95A6A3FF98A9A6FF99AAA7FF98A6A4FF8F9D9BFF
+ 8B9896FF8D9A98FF8D9A98FF869391FF7E8987FF7A8583FF646F6CFF3F4A47FF
+ 37423FFF4D5855FF5B6663FF636E6BFF717C79FF7A8582FF919C99FF909B98FF
+ 8F9A97FF939E9BFF98A3A0FF9CA7A4FF9CA7A4FF9BA6A3FF98A6A2FF98A6A2FF
+ 99A7A3FF9CAAA6FF9FADA9FF9FADA9FF9CAAA6FF9AA8A4FF95A39FFF93A19DFF
+ 919F9BFF94A29EFF99A7A3FF9CAAA6FF99A7A3FF96A4A0FF9AA8A4FF96A4A0FF
+ 909E9AFF8C9B97FF909F9BFF9FB0ACFFB3C7C2FFC4D8D3FFE6FCF7FFE4FBF6FF
+ EAFFFEFFDFF9F3FFBEDAD4FFC4E0DAFFD2F1EAFFD3EFE9FFE6FBF8FFE8FBF8FF
+ E9FCF9FFE9FEFBFFE9FEFBFFE5FAF7FFDEF5F1FFD8EFEBFFDAF1EDFFCEE7E3FF
+ D3ECE8FFDAF3EFFFD2EDE9FFCEE9E5FFCBE6E2FFBFDAD6FFC0D7D3FFC0D5D2FF
+ A8BDBAFF9AAFACFF5C716EFF809592FF7D908DFF758885FF859693FF879895FF
+ 879895FF859693FF849290FF859391FF8B9997FF909E9CFF9CADA9FF97A8A4FF
+ 91A29EFF8D9E9AFF889793FF82918DFF84938FFF8B9A96FF98A6A2FF9AA8A4FF
+ 9CA7A4FF97A29FFF8C9794FF85908DFF8D9693FF949F9CFF84948DFF7A8C85FF
+ 7D8F88FF82948DFF889A93FF8A9C95FF899B94FF91A39CFF99ABA4FF91A39CFF
+ 879992FF84968FFF8B9D96FF9CAEA7FFAEC0B9FFBACDC4FFCCDFD6FFCEE3DAFF
+ D8EBE2FFD4E9E0FFD0E5DDFFDAF1E9FFDDF3EEFFCCE2DDFFCEE4DFFFCCE3DEFF
+ CAE1DDFFC7E0DCFFB6CBC8FFB9CECBFFB8CDCAFFB3C8C5FFB0C5C2FFB0C5C2FF
+ ADC2BFFFA8BDBAFF9FB4B1FFA2B7B4FFA9BEBBFFB0C5C2FFB1C6C3FFB0C5C2FF
+ B5CAC7FFBBD2CEFFA9C0BCFF9FB8B4FF9BB2AEFF9AB1ADFF9AB1ADFF9BB2AEFF
+ A3B8B5FFABC0BDFF94A7A4FF9FB2AFFFA7BAB7FF9DB0ADFF91A29FFF94A5A2FF
+ 8A9B98FF6C7D7AFF697775FF667472FF6C7A78FF798785FF7A8B88FF748582FF
+ 768784FF7F908DFF7C8F8CFF7E918EFF7F9491FF7F9491FF7E9390FF7E9390FF
+ 7E9591FF7F9692FF91A5A0FF9BAFAAFF95A9A4FF92A6A1FF95A9A4FF889C97FF
+ 8DA19CFFB1C5C0FFBFD3CEFFBBCFCAFFB5C9C4FFAEC2BDFFA6BAB5FFA1B5B0FF
+ A1B5B0FFA4B8B3FFB3C1BFFFAAB8B6FFAEBCBAFFBFCDCBFFC3D1CFFFB3C1BFFF
+ A5B3B1FFA2B0AEFFA4B2B0FFA4B2B0FFA3B1AFFF9FADABFF9AA8A6FF97A5A3FF
+ 96A4A2FF97A5A3FF7D8885FF35403DFF4E5956FF6F7A77FF76817EFF7A8582FF
+ 6A7572FF788380FF7B8683FF6F7A77FF6F7A77FF7B8683FF7C8784FF717C79FF
+ 707B78FF798481FF82908AFF82908AFF82908CFF83918DFF889692FF8E9C98FF
+ 929F9DFF92A09EFFA9B7B5FFCCDDDAFFDAEAE9FFD7E7E6FFD8EAEBFFB4C6C7FF
+ 879B9CFF92A4A3FF95A3A2FF9BA8A6FF9DAAA8FF98A5A3FF8D9A98FF869391FF
+ 869391FF899694FF84918FFF7F8C8AFF7A8785FF798684FF7B8886FF7B8886FF
+ 768381FF717E7CFF74817FFF818E8CFF83908EFF7B8886FF7E8B89FF8A9795FF
+ 899694FF7C8987FF828F8DFF7B8886FF717E7CFF6A7775FF6A7775FF717E7CFF
+ 7B8886FF83908EFF828D8BFF808B89FF7C8987FF7E8B89FF84918FFF879492FF
+ 849290FF7F8D8BFF95A6A3FFA7B8B5FFBACBC8FFAEBFBCFFCADDDAFFB9CCC9FF
+ 718481FFB6C9C6FFA2B5B2FFA2B5B2FF9DB0ADFF93A6A3FF8B9C99FF899A97FF
+ 90A19EFF97A8A5FF9EACAAFF97A5A3FF919E9CFF8B9896FF818E8CFF778482FF
+ 76817FFF788381FF77827FFF535E5BFF485350FF5A6562FF65706DFF6E7976FF
+ 7A8582FF808B88FF8C9794FF8F9A97FF939E9BFF95A09DFF949F9CFF96A19EFF
+ 99A4A1FF9CA7A4FF96A4A0FF96A4A0FF98A6A2FF9CAAA6FF9FADA9FF9EACA8FF
+ 9BA9A5FF97A5A1FF9AA8A4FF96A4A0FF92A09CFF92A09CFF97A5A1FF9BA9A5FF
+ 9BA9A5FF9AA8A4FF8E9996FF909E9AFF93A19DFF93A29EFF909F9BFF8C9D99FF
+ 8B9F9AFF8CA09BFFC5DBD6FFE9FFFBFFE5FFF9FFD1EBE5FFC9E5DFFFC8E4DEFF
+ CFEEE7FFE1FDF7FFE6FBF8FFE8FBF8FFE8FBF8FFEAFDFAFFE9FEFBFFE7FCF9FF
+ E1F8F4FFDDF4F0FFD4EDE9FFC7E0DCFFCCE5E1FFD5F0ECFFD1ECE8FFCDE8E4FF
+ C7E5E0FFC0DBD7FFB9D0CCFFC2D9D5FFAAC1BDFF9FB6B2FF495E5BFF7B908DFF
+ 899C99FF768986FF7F908DFF869794FF8D9B99FF8A9896FF84918FFF83908EFF
+ 899694FF909E9CFF8B9C98FF8A9B97FF909F9BFF97A6A2FF96A5A1FF8A9995FF
+ 808E8AFF7B8985FF95A09DFF909B98FF8F9A97FF939E9BFF949D9AFF8D9693FF
+ 8C9592FF8D9895FF788680FF7D8E85FF809188FF86978EFF85968DFF83948BFF
+ 8C9D94FF92A39AFF84958CFF899A91FF8E9F96FF8E9F96FF8C9D94FF8C9D94FF
+ 92A39AFF97A89FFFA1B2A9FFA3B7ABFFB2C3BAFFB5C8BFFFBBCEC5FFD2E7DEFF
+ E6FBF3FFE1F8F0FFD8EEE9FFD5ECE7FFD2E9E5FFCFE6E2FFB3C8C5FFB5CAC7FF
+ B1C6C3FFA9BEBBFFA4B9B6FFA5BAB7FFA2B7B4FF9EB3B0FFA0B5B2FFA2B7B4FF
+ A8BDBAFFADC2BFFFADC2BFFFADC2BFFFB5CAC7FFBED5D1FFB2C9C5FFA7C0BCFF
+ A2B9B5FF9FB6B2FF9DB4B0FF9BB2AEFFA0B5B2FFA6BBB8FF96A9A6FF9FB2AFFF
+ AEC1BEFFAABDBAFF99AAA7FF8D9E9BFF7C8D8AFF61726FFF687674FF687674FF
+ 6E7C7AFF768482FF788986FF778885FF788986FF7B8C89FF7B8E8BFF7B8E8BFF
+ 7B908DFF7D928FFF7F9491FF809592FF809793FF7F9692FF899D98FF97ABA6FF
+ 99ADA8FF93A7A2FF91A5A0FF8EA29DFF93A7A2FFA2B6B1FFC6DAD5FFC0D4CFFF
+ B7CBC6FFB4C8C3FFB9CDC8FFBCD0CBFFB3C7C2FFA7BBB6FFC4D2D0FFAEBCBAFF
+ A9B7B5FFBBC9C7FFC2D0CEFFB5C3C1FFACBAB8FFB1BFBDFFA9B7B5FFA9B7B5FF
+ A7B5B3FFA3B1AFFF9CAAA8FF97A5A3FF95A3A1FF96A3A1FF8E9996FF3F4A47FF
+ 5A6562FF7D8885FF7D8885FF7F8A87FF6E7976FF75807DFF7D8885FF727D7AFF
+ 6E7976FF76817EFF7A8582FF75807DFF737E7BFF76817EFF7E8C86FF7E8C86FF
+ 7D8B87FF7F8D89FF879591FF93A19DFF96A3A1FF94A19FFF96A4A2FFB2C0BEFF
+ D3E3E2FFDCECEBFFDCEEEFFFB9CDCEFF849899FF849695FF95A3A2FF9AA7A5FF
+ 9DAAA8FF98A5A3FF8F9C9AFF899694FF889593FF8A9795FF869391FF828F8DFF
+ 7E8B89FF7D8A88FF7E8B89FF7D8A88FF798684FF758280FF758280FF808D8BFF
+ 84918FFF7F8C8AFF808D8BFF879492FF8A9795FF869391FF808D8BFF7D8A88FF
+ 788583FF74817FFF74817FFF768381FF7A8785FF7D8A88FF828D8BFF848F8DFF
+ 828F8DFF828F8DFF869391FF899694FF83918FFF7A8886FF7F908DFF9DAEABFF
+ AABBB8FFA4B5B2FFBACDCAFFA8BBB8FF607370FFAABDBAFFA7BAB7FFA8BBB8FF
+ A3B6B3FF96A9A6FF889996FF81928FFF849592FF8B9C99FF909E9CFF909E9CFF
+ 93A09EFF919E9CFF869391FF798684FF778280FF7A8583FF77827FFF55605DFF
+ 4B5653FF5A6562FF66716EFF717C79FF7F8A87FF848F8CFF87928FFF8D9895FF
+ 939E9BFF95A09DFF929D9AFF909B98FF939E9BFF97A29FFF97A5A1FF98A6A2FF
+ 9BA9A5FF9EACA8FFA0AEAAFF9DABA7FF97A5A1FF92A09CFF9AA8A4FF96A4A0FF
+ 92A09CFF919F9BFF93A19DFF96A4A0FF98A6A2FF99A7A3FF99A4A1FF929D9AFF
+ 8D9895FF909E9AFF99A7A3FF99A8A4FF8C9D99FF7F938EFFA1B7B2FFD7EEE9FF
+ D2E9E4FFC5DFD9FFCEEAE4FFC9E5DFFFD4F3ECFFE8FFFEFFE7FAF7FFE8F9F6FF
+ E5F8F5FFE7FAF7FFE8FBF8FFE7FCF9FFE4FBF7FFE1F8F4FFD3ECE8FFC2DBD7FF
+ C4DFDBFFD1ECE8FFCEE9E5FFC9E4E0FFC4E2DDFFBFDAD6FFB1CAC6FFBED5D1FF
+ AAC1BDFFA3BAB6FF495E5BFF6F8481FF8EA19EFF7D908DFF768784FF7E8F8CFF
+ 899795FF8A9896FF879492FF859290FF8A9795FF8F9C9AFF9BAAA6FF93A4A0FF
+ 93A29EFF93A29EFF91A09CFF8A9995FF899793FF8A9894FF949F9CFF8A9592FF
+ 889390FF929D9AFF99A29FFF909996FF868F8CFF818D87FF788680FF84958CFF
+ 809188FF889990FF85968DFF7E8F86FF8D9E95FF8E9F96FF87988FFF8E9F96FF
+ 93A49BFF92A39AFF8C9D94FF8B9C93FF91A299FF98A9A0FF90A196FF8A9B90FF
+ 8FA097FF94A59CFF99AAA1FFB3C6BDFFD9EBE4FFE8FDF5FFE1F5F0FFDCF2EDFF
+ D8EDEAFFD3EAE6FFB1C6C3FFB3C8C5FFAFC4C1FFA8BDBAFFA3B8B5FFA3B8B5FF
+ A0B5B2FF9BB0ADFFA0B5B2FFA2B7B4FFA5BAB7FFA7BCB9FFA3B8B5FFA2B7B4FF
+ ADC2BFFFB9D0CCFFB0C7C3FFA6BFBBFFA1B8B4FF9EB5B1FF9AB1ADFF96ADA9FF
+ 99AEABFF9EB3B0FF95A8A5FF95A8A5FFA4B7B4FFAEC1BEFFA3B4B1FF8E9F9CFF
+ 768784FF5C6D6AFF5E6C6AFF657371FF6A7876FF6E7C7AFF728380FF788986FF
+ 798A87FF758683FF7F928FFF7C8F8CFF778C89FF7B908DFF829794FF899E9BFF
+ 8BA29EFF8BA29EFF93A7A2FF91A5A0FF96AAA5FF96AAA5FF8B9F9AFF8CA09BFF
+ 98ACA7FF9DB1ACFFBACEC9FFBACEC9FFB6CAC5FFB1C5C0FFB7CBC6FFC2D6D1FF
+ C2D6D1FFBACEC9FFC1CFCDFFB5C3C1FFB0BEBCFFB6C4C2FFBBC9C7FFB7C5C3FF
+ B4C2C0FFB4C2C0FFACBAB8FFADBBB9FFABB9B7FFA7B5B3FFA1AFADFF9CAAA8FF
+ 9AA8A6FF9BA8A6FF95A09DFF454E4BFF626B68FF858E8BFF808986FF858E8BFF
+ 79827FFF7B8481FF77807DFF767F7CFF767F7CFF78817EFF7A8380FF7B8481FF
+ 7A8380FF77827FFF83918BFF83938CFF83918DFF83918DFF8D9B97FF98A6A2FF
+ 98A5A3FF919E9CFF909D9BFF97A5A3FFC1D1D0FFD6E6E5FFDBEDEEFFC7DBDCFF
+ 93A7A8FF879C9AFF96A4A3FF98A5A3FF97A4A2FF93A09EFF8D9A98FF8A9795FF
+ 8B9896FF8D9A98FF899694FF879492FF859290FF83908EFF828F8DFF808D8BFF
+ 7D8A88FF7C8987FF808D8BFF818E8CFF828F8DFF859290FF899694FF8C9997FF
+ 8E9B99FF8F9C9AFF7F8C8AFF7E8B89FF7D8A88FF7C8987FF7B8886FF7C8987FF
+ 7C8987FF7C8987FF838E8CFF879290FF869391FF859290FF889593FF8A9795FF
+ 818F8DFF758381FF758683FF9DAEABFFA2B3B0FFABBCB9FFB9CCC9FFA3B6B3FF
+ 617471FFA1B4B1FFA5B8B5FFA4B7B4FF9FB2AFFF96A9A6FF8E9F9CFF879895FF
+ 859693FF869794FF879593FF879593FF8D9A98FF919E9CFF8D9A98FF83908EFF
+ 7E8987FF7E8987FF727D7AFF515C59FF46514EFF55605DFF616C69FF6E7976FF
+ 7D8885FF808B88FF899491FF8D9895FF929D9AFF95A09DFF96A19EFF949F9CFF
+ 919C99FF909B98FF94A29EFF96A4A0FF9AA8A4FFA0AEAAFFA3B1ADFFA1AFABFF
+ 9CAAA6FF97A5A1FF97A5A1FF97A5A1FF96A4A0FF95A39FFF93A19DFF93A19DFF
+ 95A39FFF97A5A1FFA2AEA8FF97A39DFF8D9993FF8A9892FF92A09AFF98A8A1FF
+ 95A7A0FF90A59DFF8CA39BFFB5CDC5FFBAD2CAFFC0DBD2FFBDDAD1FFBDDAD1FF
+ DBFAF1FFE6FFFCFFE8FBF8FFE7F8F5FFE4F5F2FFE2F5F2FFE4F7F4FFE4F9F6FF
+ E4FBF7FFE3FAF6FFD9F2EEFFC5DEDAFFC4DFDBFFD1ECE8FFCDEBE6FFC7E5E0FF
+ C4E2DDFFC0DBD7FFB5CDCBFFB8D0CEFFACC2C0FFB1C7C5FF5B706EFF5D7270FF
+ 829493FF809291FF7B8B8AFF7E8E8DFF859392FF8A9897FF8E9A9AFF8C9898FF
+ 8A9494FF84918FFF8D9C98FF8C9B97FF8B9A96FF879692FF7E8D89FF7A8985FF
+ 84928EFF919F9BFF8F9A97FF848F8CFF87908DFF969F9CFF9BA4A1FF8E9794FF
+ 7F8885FF77837DFF798781FF84958CFF788980FF83948BFF86978EFF819289FF
+ 91A299FF889990FF9BACA3FF98A9A0FF92A39AFF8C9D94FF899A91FF8D9E95FF
+ 96A79EFF9EAFA6FFA7B7ACFF99A99EFF9BABA0FF9FAFA4FF9AA9A1FFA9BAB1FF
+ D0E2DBFFECFFF9FFE2F6F1FFDDF3EEFFD9EEEBFFD5EAE8FFB0C5C2FFB3C8C5FF
+ B3C8C5FFAEC3C0FFABC0BDFFABC0BDFFA8BDBAFFA3B8B5FF9DB2AFFF9FB4B1FF
+ A1B6B3FF9FB4B1FF98ADAAFF96ABA8FFA2B7B4FFB1C8C4FF91AAA6FF8CA5A1FF
+ 8DA4A0FF90A7A3FF91A8A4FF92A9A5FF97ACA9FF9EB3B0FF889B98FF7F928FFF
+ 8EA19EFFA4B7B4FFA2B3B0FF8D9E9BFF71827FFF576865FF4D5B59FF586664FF
+ 5E6C6AFF5E6C6AFF637471FF70817EFF71827FFF697A77FF879895FF7D908DFF
+ 778A87FF7B8E8BFF869996FF92A5A2FF97ACA9FF98ADAAFFA1B5B0FF8CA09BFF
+ 94A5A1FF99ADA8FF889C97FF889C97FF9BAFAAFFA0B4AFFFA9BDB8FFB7CBC6FF
+ B9CDC8FFA9BDB8FF9FB3AEFFA7BBB6FFB6CAC5FFBED2CDFFAEBFBCFFB5C6C3FF
+ B9C7C5FFB4C5C2FFB6C4C2FFB7C8C5FFB5C3C1FFAABBB8FFAAB8B6FFAABBB8FF
+ ACBAB8FFA8B9B6FFA6B4B2FFA1B2AFFFA2B0AEFFA3B1AFFF96A19EFF45504DFF
+ 646F6CFF86918EFF808B88FF8C9794FF848F8CFF86918EFF6F7A77FF788380FF
+ 7F8A87FF7D8885FF7C8784FF7F8A87FF808B88FF7D8885FF8C9A94FF8D9D96FF
+ 8C9A96FF8B9995FF92A09CFF9AA8A4FF95A2A0FF8A9795FF9AA7A5FF8C9997FF
+ B5C3C1FFCBDBDAFFD5E7E6FFD4E6E5FFA6BBB9FF97A9A8FF97A5A3FF96A3A1FF
+ 929F9DFF8D9A98FF8A9795FF8B9896FF8E9B99FF919E9CFF8C9997FF8C9997FF
+ 8A9795FF889593FF879290FF828F8DFF838E8CFF818E8CFF859290FF7D8A88FF
+ 7C8987FF859290FF8D9A98FF8E9B99FF8E9B99FF8F9C9AFF83908EFF808D8BFF
+ 7D8A88FF7B8886FF7B8886FF7D8A88FF818E8CFF83908EFF838E8CFF899492FF
+ 8B9694FF889593FF8A9795FF8B9896FF7F8D8BFF717F7DFF738481FF9FB0ADFF
+ A0B1AEFFB3C6C3FFBFD2CFFFA3B8B5FF677978FF99AEABFFA0B3B0FF9CAFACFF
+ 97AAA7FF95A8A5FF95A8A5FF94A5A2FF8FA09DFF8A9B98FF8F9D9BFF899795FF
+ 869492FF899694FF879492FF7E8B89FF768381FF73807EFF76817EFF54625EFF
+ 4A5552FF55635FFF626D6AFF6E7C78FF7E8986FF7E8C88FF909B98FF8E9C98FF
+ 929D9AFF96A4A0FF9CA7A4FF99A7A3FF939E9BFF8B9995FF8D9B97FF909E9AFF
+ 98A6A2FFA0AEAAFFA7B5B1FFA8B6B2FFA4B2AEFFA0AEAAFF95A39FFF99A7A3FF
+ 9CAAA6FF9BA9A5FF96A4A0FF93A19DFF94A29EFF96A4A0FF8F9B95FF97A39DFF
+ 9DA9A3FF9AA6A0FF919F99FF8D9B95FF8F9F98FF93A59EFF889D95FF9AB1A9FF
+ ABC3BBFFC0D8D0FFA9C4BBFFAEC9C0FFDFFCF3FFD7F2E9FFE7FCF9FFE5F8F5FF
+ E1F4F1FFDFF2EFFFDFF4F1FFE2F7F4FFE3FAF6FFE3FAF6FFE3FCF8FFCCE5E1FF
+ C9E4E0FFD5F0ECFFD2EDE9FFCAE8E3FFC9E4E0FFC4DFDBFFBED6D4FFB7CFCDFF
+ AFC5C3FFC0D6D4FF6E8381FF4D6260FF718382FF7D8F8EFF899998FF859594FF
+ 869493FF8C9A99FF95A1A1FF929E9EFF859191FF788583FF4B5955FF5F6E6AFF
+ 7A8884FF84938FFF7C8A86FF707E7AFF717F7BFF7C8A86FF838E8BFF7B8683FF
+ 828B88FF929B98FF969F9CFF868F8CFF77807DFF717D77FF76847EFF7E8F86FF
+ 6C7D74FF7B8C83FF87988FFF86978EFF96A79EFF85968DFF8D9E95FF8C9D94FF
+ 8B9C93FF8D9E95FF90A198FF91A299FF90A198FF8E9F96FF9DACA4FF90A095FF
+ 96A79EFFA1B2A9FF98A9A0FF9CADA4FFC0D2CBFFE0F5EDFFE1F5F0FFDEF2EDFF
+ D9EEEBFFD6EBE8FFB8CFCBFFB1C8C4FFACC3BFFFACC3BFFFADC4C0FFA9C0BCFF
+ A4BBB7FFA1B8B4FF9EB5B1FF95ACA8FF93AAA6FF98AFABFF98AFABFF96ADA9FF
+ 9FB6B2FFADC4C0FFB5CECAFF93ACA8FF839A96FF8FA6A2FF9CB3AFFF9BB2AEFF
+ A4B9B6FFB5CAC7FF91A4A1FF8A9D9AFF849794FF91A4A1FF9FB0ADFF899A97FF
+ 6C7D7AFF667774FF3D4C48FF364541FF4D5C58FF5B6A66FF64736FFF677672FF
+ 5E6D69FF6E7D79FF7F8E8AFF94A5A1FF93A4A0FF7B8C88FF7E8F8BFF9CADA9FF
+ A2B3AFFF8D9E9AFF92A39FFFA3B4B0FFA2B1ADFF92A39FFF93A4A0FF96A7A3FF
+ 9AABA7FFA5B6B2FFB4C8C3FFC4D8D3FFC9DFDAFFBBD1CCFFA6BCB7FF9FB5B0FF
+ A6BCB7FFAFC5C0FFAFC2BFFFA8BBB8FFA3B4B1FFA2B5B2FFACBDBAFFB3C6C3FF
+ BACBC8FFBACDCAFFAFC0BDFFA9BCB9FFA9BAB7FFA5B8B5FFA1B2AFFF99ACA9FF
+ 9DAEABFFA4B5B2FF96A5A1FF4D5B57FF515F5BFF82908CFF869490FF8B9995FF
+ 96A4A0FF84928EFF8D9B97FF899793FF85938FFF889692FF8E9C98FF909E9AFF
+ 8B9995FF869490FF919F9BFF8F9D99FF8F9D99FF93A19DFF99A7A3FF9AA8A4FF
+ 94A29EFF8E9C98FF919F9BFF98A6A2FFA9B7B3FFCCDAD8FFD6E4E2FFD3E1DFFF
+ C3D1CFFF889694FF919F9DFF9AA8A6FF98A6A4FF8B9997FF859391FF8B9997FF
+ 909D9BFF8D9A98FF939E9CFF8F9A98FF8D9896FF8B9694FF88908FFF818C8AFF
+ 858D8CFF8A9593FF7C8987FF7D8A88FF83908EFF899694FF8B9896FF8B9896FF
+ 929F9DFF9CA9A7FF7E8B89FF84918FFF879492FF84918FFF7D8A88FF7A8785FF
+ 808D8BFF879492FF818C89FF909996FF8F9895FF8A9592FF95A09DFF93A19DFF
+ 849290FF7E8C8AFF7F908DFF95A6A3FFB1C3C2FFB2C7C5FFBDD2D0FF9CB2B0FF
+ 3C5051FF92A8A6FF9BB0ADFF94A9A6FF8EA3A0FF8BA09DFF869B98FF819491FF
+ 7F928FFF829592FF839491FF859693FF879895FF8B9997FF8E9C9AFF8B9997FF
+ 7C8A88FF6D7B79FF6B7975FF64736FFF3D4B47FF586763FF667470FF6F7E7AFF
+ 6E7C78FF72817DFF82908CFF82918DFF899793FF909F9BFF96A4A0FF95A4A0FF
+ 96A4A0FF97A5A1FF97A5A1FF93A19DFF8F9D99FF8C9A96FF8C9A96FF909E9AFF
+ 95A39FFF98A6A2FF97A5A1FF95A39FFF93A19DFF92A09CFF92A09CFF94A29EFF
+ 96A4A0FF98A6A2FF939F99FF9BA7A1FFA2AEA8FF9FADA7FF97A59FFF909E98FF
+ 8D9D96FF8C9E97FF93A59EFF899E96FF93A8A0FFAFC4BCFFC0D7CFFFC6DDD5FF
+ D3EAE2FFE4FBF3FFE2F9F5FFDAF1EDFFDAF1EDFFE0F7F3FFDCF3EFFFD3EAE6FF
+ D6EFEBFFE3FCF8FFDDF6F2FFDAF3EFFFD5EEEAFFD3ECE8FFD6EFEBFFD5F0ECFF
+ CBE4E0FFBDD6D2FFBDD6D2FFB1C8C4FFBBD0CDFFACC1BEFF879C99FF536865FF
+ 657875FF758885FF899A97FF81928FFF7F908DFF81928FFF758381FF5A6866FF
+ 4A5856FF4B5856FF576561FF5A6862FF65716BFF697771FF67736DFF636F69FF
+ 6F7B75FF818D87FF84908AFF6C7872FF69756FFF828E88FF8D9993FF7E8A84FF
+ 74807AFF78847EFF7C8A84FF7B8B84FF7A8A83FF7C8C85FF86968FFF91A19AFF
+ 92A29BFF8C9C95FF899992FF8C9C95FF8C9C95FF8C9C95FF92A29BFF97A7A0FF
+ 8F9F98FF82928BFF94A69FFF9BB0A7FF8BA098FF8CA199FFA1B6AEFF9AAFA7FF
+ A4B9B1FFD8EFE7FFE0F7EFFFDBF2EAFFD4EAE5FFD0E6E1FFB8CFCBFFB5CCC8FF
+ B2C9C5FFADC4C0FFA5BCB8FF9DB4B0FF98AFABFF97AEAAFFA1B8B4FF9CB3AFFF
+ 9CB3AFFFA1B8B4FFA0B7B3FF9CB3AFFFA1B8B4FFAAC1BDFFA1BAB6FFAEC7C3FF
+ ACC3BFFF9AB1ADFF9BB2AEFFACC3BFFFAEC3C0FF9EB3B0FFAEC1BEFF9EB1AEFF
+ 859895FF7B8E8BFF7B8C89FF6B7C79FF61726FFF6C7D7AFF5B6A66FF42514DFF
+ 4A5955FF505F5BFF4F5E5AFF4B5A56FF52615DFF7A8985FF697874FF84938FFF
+ 909F9BFF81908CFF7A8985FF889793FF95A4A0FF94A39FFF98A7A3FFA9B8B4FF
+ A9B8B4FFA1B0ACFF9FB0ACFF9DAEAAFF99AAA6FF9EAFABFFA5B9B4FFBBCFCAFF
+ CBE1DCFFC8DED9FFB8CEC9FFABC1BCFFA5BCB7FFA4BBB6FFBACDCAFFB5C8C5FF
+ AEC1BEFFAABDBAFFAABDBAFFAABDBAFFAABDBAFFA9BCB9FFA8BBB8FFA4B7B4FF
+ A1B4B1FF9FB2AFFF99ACA9FF93A6A3FF95A8A5FF9BAEABFF99A8A4FF53625EFF
+ 53625EFF7E8D89FF808F8BFF83928EFF8D9C98FF7C8B87FF879692FF889793FF
+ 889793FF889793FF889793FF899894FF8D9C98FF909F9BFF93A19DFF909E9AFF
+ 8F9D99FF92A09CFF98A6A2FF9BA9A5FF98A6A2FF94A29EFF94A29EFF98A6A2FF
+ A4B2AEFFCEDCD8FFE1EFEBFFD8E6E2FFCDDBD7FFABB9B5FF95A3A1FF96A4A2FF
+ 92A09EFF8B9997FF899795FF8D9B99FF919E9CFF909D9BFF929D9BFF8F9A98FF
+ 909897FF8F9796FF8A9291FF848C8BFF868E8DFF899492FF848F8DFF83908EFF
+ 889593FF8D9A98FF8D9A98FF8D9A98FF93A09EFF9CA9A7FF818E8CFF828F8DFF
+ 84918FFF84918FFF83908EFF84918FFF869391FF889692FF88918EFF929C96FF
+ 8D9693FF89928FFF939E9BFF93A19DFF889593FF83918FFF869794FF97AAA7FF
+ B0C2C1FFB1C6C4FFBACFD0FF9AAFB0FF3A4F50FF879D9BFF8CA2A0FF879E9AFF
+ 869B98FF869B98FF839895FF7C918EFF7C8F8CFF7E918EFF8A9B98FF889996FF
+ 839491FF81928FFF899795FF8D9B99FF889694FF7F8D8BFF6E7D79FF697874FF
+ 43524EFF5D6C68FF687773FF72817DFF71807CFF788783FF8C9B97FF899894FF
+ 889793FF8D9C98FF91A09CFF92A19DFF91A09CFF909F9BFF919F9BFF8E9C98FF
+ 8A9894FF879591FF879591FF8B9995FF8F9D99FF92A09CFF94A29EFF93A19DFF
+ 909E9AFF8E9C98FF8D9B97FF8D9B97FF8E9C98FF8F9D99FF8F9B95FF94A09AFF
+ 97A59FFF98A6A0FF97A59FFF96A49EFF98A8A1FF9BABA4FF92A49DFF9DAFA8FF
+ A2B4ADFFA4B6AFFFB1C6BEFFCCE1D9FFDFF4ECFFE2F9F1FFDFF6F2FFD5EEEAFF
+ D5EEEAFFDAF3EFFFD7F0ECFFCFE8E4FFD3ECE8FFDEF7F3FFDAF3EFFFDDF6F2FF
+ DDF6F2FFD8F1EDFFD4EDE9FFD1EAE6FFCAE3DFFFC2DBD7FFC0D7D3FFB0C7C3FF
+ B2C7C4FFA6BBB8FF8EA3A0FF4A5F5CFF6D807DFF7A8D8AFF778885FF6D7E7BFF
+ 677875FF667774FF5B6967FF455351FF3A4846FF3C4B47FF485652FF4C5852FF
+ 505C56FF56625CFF5D6963FF66726CFF737F79FF7D8983FF79857FFF6B7771FF
+ 6D7973FF84908AFF909C96FF85918BFF77837DFF72807AFF7D8B85FF7E8E87FF
+ 808E88FF83938CFF8F9D97FF99A9A2FF9BA9A3FF95A59EFF93A19BFF97A7A0FF
+ 9BA9A3FF99A9A2FF9AA8A2FF97A7A0FF8D9B95FF7E8E87FF91A69EFF9CB3ABFF
+ 91A69EFF8AA199FF9AAFA7FF8EA59DFF93A8A0FFBAD1C9FFDBF0E8FFD7EEE6FF
+ D7ECE4FFD2E9E1FFA7BEBAFFABC2BEFFAEC5C1FFAAC1BDFFA2B9B5FF9DB4B0FF
+ 9DB4B0FF9EB5B1FFA2B9B5FF9FB6B2FF9DB4B0FF9DB4B0FF9BB2AEFF9BB2AEFF
+ A0B7B3FFA7BEBAFF8FA8A4FFAFC8C4FFB7CECAFF9DB4B0FF95ACA8FFAAC1BDFF
+ AEC3C0FF9CB1AEFFAFC2BFFFA8BBB8FF95A8A5FF869996FF7C8D8AFF657673FF
+ 5A6B68FF657673FF44534FFF313F3BFF4E5C58FF72807CFF7A8884FF606E6AFF
+ 414F4BFF4E5C58FF596763FF74827EFF8E9C98FF8F9D99FF7F8D89FF798783FF
+ 8A9894FF9FADA9FF8B9A96FF99A8A4FF9BAAA6FF98A7A3FF9EAFABFF9FB0ACFF
+ 9CADA9FFA2B3AFFF95A9A4FFACC0BBFFC1D7D2FFC6DCD7FFBED4CFFFB2C8C3FF
+ A5BCB7FF9CB3AEFFB2C5C2FFB2C5C2FFB2C5C2FFAFC2BFFFABBEBBFFA9BCB9FF
+ AABDBAFFABBEBBFFA7BAB7FFA2B5B2FF9FB2AFFF9DB0ADFF97AAA7FF90A3A0FF
+ 8FA29FFF94A7A4FF9FAEAAFF5F6E6AFF5C6B67FF7F8E8AFF81908CFF859490FF
+ 8F9E9AFF81908CFF869591FF8B9A96FF8F9E9AFF8B9A96FF83928EFF82918DFF
+ 8B9A96FF94A39FFF94A29EFF909E9AFF8C9A96FF8D9B97FF93A19DFF97A5A1FF
+ 98A6A2FF97A5A1FF96A4A0FF9BA9A5FF9BA9A5FFC6D4D0FFE8F6F2FFDFEDE9FF
+ DCEAE6FFD5E3DFFFA6B4B2FF98A9A6FF919F9DFF909E9CFF919F9DFF909E9CFF
+ 919E9CFF93A09EFF919C9AFF8F9A98FF8F9A98FF919C9AFF8F9796FF88908FFF
+ 878F8EFF889391FF889391FF879492FF8B9896FF909D9BFF8F9C9AFF8E9B99FF
+ 94A19FFF9DAAA8FF859290FF818E8CFF7F8C8AFF808D8BFF84918FFF879492FF
+ 879492FF869490FF8D9693FF939D97FF8B9491FF88918EFF929D9AFF93A19DFF
+ 8B9896FF899795FF92A3A0FFA2B5B2FFB4C6C5FFB4C9C7FFB8CDCEFF99AEAFFF
+ 405556FF829896FF819795FF7E9591FF809592FF839895FF829794FF7C918EFF
+ 7B8E8BFF7D908DFF849592FF829390FF7D8E8BFF7B8C89FF83918FFF899795FF
+ 859391FF7C8A88FF6B7975FF687672FF43514DFF5C6A66FF65736FFF6E7C78FF
+ 6E7C78FF788682FF919F9BFF8E9C98FF8A9894FF8A9894FF8E9C98FF919F9BFF
+ 919F9BFF8F9D99FF95A39FFF93A19DFF8F9D99FF8D9B97FF8D9B97FF8F9D99FF
+ 92A09CFF95A39FFF94A29EFF92A09CFF909E9AFF8E9C98FF8C9A96FF8A9894FF
+ 8A9894FF8A9894FF8F9B95FF909C96FF909E98FF92A09AFF96A49EFF9AA8A2FF
+ 9EAEA7FFA1B1AAFF96A8A1FF9EB0A9FF9EB0A9FF97A9A2FF9DB2AAFFB6CBC3FF
+ D1E6DEFFDDF4ECFFDCF3EFFFD3ECE8FFD2EBE7FFD7F0ECFFD4EDE9FFCEE7E3FF
+ D0E9E5FFD9F2EEFFD5EEEAFFDEF7F3FFE2FBF7FFDAF3EFFFCFE8E4FFC9E2DEFF
+ C6DFDBFFC4DDD9FFC2D9D5FFB4CBC7FFACC1BEFFA1B6B3FF9AAFACFF384D4AFF
+ 728582FF7B8E8BFF738481FF6B7C79FF687976FF697A77FF616F6DFF4F5D5BFF
+ 43514FFF43524EFF495753FF4C5A54FF495751FF47554FFF53615BFF67756FFF
+ 707E78FF6C7A74FF6F7D77FF6D7B75FF74827CFF85938DFF919F99FF8B9993FF
+ 7A8882FF6D7B75FF7B8983FF7F8D87FF85918BFF899791FF96A29CFF9FADA7FF
+ A2AEA8FF9BA9A3FF95A19BFF98A6A0FF9EAAA4FF9CAAA4FF9EAAA4FF9CAAA4FF
+ 99A59FFF909E98FF91A39CFFA2B7AFFF9BADA6FF8EA39BFF97A9A2FF8DA29AFF
+ 8C9E97FFA1B6AEFFD9EBE4FFD9EEE6FFDCEEE7FFD6EBE3FF9EB5B1FFA4BBB7FF
+ A8BFBBFFA5BCB8FFA2B9B5FFA2B9B5FFA1B8B4FFA0B7B3FFA5BCB8FFA3BAB6FF
+ 9DB4B0FF96ADA9FF94ABA7FF9BB2AEFFA4BBB7FFABC2BEFF9BB4B0FF9EB7B3FF
+ 9EB5B1FF96ADA9FF8CA39FFF8BA29EFF97ACA9FFA4B9B6FF9DB0ADFFA1B4B1FF
+ 9BAEABFF94A7A4FF8D9E9BFF728380FF5C6D6AFF606E6CFF4B5955FF273531FF
+ 323D3AFF515F5BFF747F7CFF72807CFF525D5AFF4A5854FF57625FFF667470FF
+ 848F8CFF93A19DFF899491FF768480FF848F8CFF9DABA7FF8A9995FF91A09CFF
+ 8C9B97FF8A9995FF94A5A1FF99AAA6FF9BACA8FFA6B7B3FF97ABA6FFA7BBB6FF
+ B6CCC7FFBDD3CEFFBCD2CDFFB7CDC8FFADC4BFFFA5BCB7FFA7BAB7FFABBEBBFF
+ AEC1BEFFABBEBBFFA7BAB7FFA7BAB7FFACBFBCFFB2C5C2FFAEC1BEFFA8BBB8FF
+ A3B6B3FF9FB2AFFF98ABA8FF90A3A0FF8DA09DFF8FA29FFF9AA9A5FF667571FF
+ 61706CFF7D8C88FF81908CFF879692FF91A09CFF889793FF899894FF8F9E9AFF
+ 94A39FFF8F9E9AFF859490FF81908CFF869591FF8D9C98FF93A19DFF8E9C98FF
+ 899793FF879591FF8B9995FF909E9AFF93A19DFF94A29EFF95A39FFFA1AFABFF
+ 93A19DFFB2C0BCFFDFEDE9FFE5F3EFFFE9F7F3FFEAF9F5FFBCCAC8FFA4B5B2FF
+ 95A3A1FF97A5A3FF9AA8A6FF94A2A0FF929F9DFF94A19FFF929D9BFF8F9A98FF
+ 919C9AFF949F9DFF939B9AFF8C9493FF88908FFF889391FF889391FF879492FF
+ 8B9896FF8F9C9AFF8E9B99FF8D9A98FF93A09EFF9CA9A7FF8B9896FF859290FF
+ 7E8B89FF7A8785FF7B8886FF7E8B89FF808D8BFF818F8BFF8D9693FF929C96FF
+ 8C9592FF8A9390FF949F9CFF93A19DFF8C9997FF8E9C9AFFA0B1AEFFB2C5C2FF
+ BCCECDFFB8CDCBFFB2C7C8FF97ACADFF4F6465FF8BA19FFF839997FF7F9692FF
+ 809592FF839895FF839895FF7E9390FF809390FF839693FF7A8B88FF7C8D8AFF
+ 7E8F8CFF80918EFF869492FF859391FF798785FF6B7977FF687672FF667470FF
+ 404E4AFF586662FF606E6AFF697773FF6B7975FF75837FFF879591FF8C9A96FF
+ 8E9C98FF8B9995FF8A9894FF8E9C98FF919F9BFF919F9BFF99A7A3FF97A5A1FF
+ 95A39FFF93A19DFF93A19DFF95A39FFF97A5A1FF98A6A2FF95A39FFF94A29EFF
+ 94A29EFF92A09CFF919F9BFF8F9D99FF8E9C98FF8D9B97FF939F99FF919D97FF
+ 8E9C96FF909E98FF94A29CFF98A6A0FF9AAAA3FF9AAAA3FFA0B2ABFF92A49DFF
+ 90A29BFF9BADA6FF99AEA6FF9BB0A8FFBBD0C8FFE2F9F1FFDDF4F0FFD6EFEBFF
+ D4EDE9FFD7F0ECFFD6EFEBFFD1EAE6FFD2EBE7FFD8F1EDFFD3ECE8FFDDF6F2FF
+ E0F9F5FFD8F1EDFFCCE5E1FFC6DFDBFFC3DCD8FFC1DAD6FFC0D7D3FFBAD1CDFF
+ AFC4C1FFA4B9B6FFA5BAB7FF283D3AFF6E817EFF778A87FF728380FF728380FF
+ 778885FF7F908DFF7D8B89FF6C7A78FF5D6B69FF566561FF6A7874FF717F79FF
+ 6A7872FF5B6963FF606E68FF72807AFF73817BFF65736DFF6D7B75FF72807AFF
+ 798781FF84928CFF8E9C96FF8E9C96FF7E8C86FF6C7A74FF78847EFF7E8A84FF
+ 84908AFF8A9690FF939F99FF9DA9A3FF9DA9A3FF99A59FFF97A39DFF9AA6A0FF
+ 9BA7A1FF9AA6A0FF9AA6A0FF9CA8A2FF9FABA5FFA1ADA7FF91A19AFFA5B7B0FF
+ A4B4ADFF95A7A0FF9AAAA3FF98AAA3FF97A7A0FF9DAFA8FFCCDCD5FFD0E2DBFF
+ D8E8E1FFD5E7E0FFA7BEBAFFA9C0BCFFA5BCB8FF9EB5B1FF9DB4B0FF9DB4B0FF
+ 96ADA9FF8CA39FFFA2B9B5FFA7BEBAFFA4BBB7FF9CB3AFFF9BB2AEFFA5BCB8FF
+ ACC3BFFFACC3BFFFB0C9C5FF9CB5B1FF93AAA6FF94ABA7FF8DA4A0FF829995FF
+ 8BA09DFF9FB4B1FFA1B4B1FF9FB2AFFF91A4A1FF879A97FF869794FF748582FF
+ 627370FF63716FFF4C5754FF303B38FF2C3532FF2F3A37FF525B58FF6E7976FF
+ 5F6865FF535E5BFF5B6461FF5B6663FF717A77FF889390FF8D9693FF7E8986FF
+ 828B88FF909B98FF9CAAA6FF9EADA9FF96A5A1FF91A09CFF96A7A3FF95A6A2FF
+ 94A5A1FF9EAFABFF9FB3AEFFABBFBAFFB7CDC8FFBDD3CEFFC0D6D1FFC0D6D1FF
+ B9D0CBFFB1C8C3FFACBFBCFFAEC1BEFFADC0BDFFA6B9B6FF9DB0ADFF9BAEABFF
+ A1B4B1FFA8BBB8FFB2C5C2FFAABDBAFFA3B6B3FF9FB2AFFF97AAA7FF8DA09DFF
+ 879A97FF889B98FF8E9D99FF677672FF606F6BFF74837FFF7A8985FF808F8BFF
+ 899894FF84938FFF879692FF8C9B97FF91A09CFF91A09CFF8D9C98FF889793FF
+ 869591FF869591FF94A29EFF909E9AFF8A9894FF889692FF899793FF8C9A96FF
+ 8F9D99FF919F9BFF919F9BFFA5B3AFFF909E9AFF99A7A3FFC7D5D1FFE1EFEBFF
+ EEFCF8FFE8F7F3FFC8D6D4FFACBDBAFF98A9A6FF97A8A5FF9DABA9FF99A7A5FF
+ 95A3A1FF96A4A2FF919E9CFF8E9B99FF919C9AFF96A19FFF949F9DFF8D9896FF
+ 8B9392FF899492FF85908EFF84918FFF889593FF8D9A98FF8C9997FF8A9795FF
+ 909D9BFF99A6A4FF95A2A0FF8F9C9AFF869391FF7B8886FF73807EFF73807EFF
+ 788583FF7D8B87FF89928FFF909A94FF8E9794FF8F9895FF96A19EFF909E9AFF
+ 8B9896FF919F9DFFA8B9B6FFBCCFCCFFC0D2D1FFB8CDCBFFA9BEBFFF94A9AAFF
+ 607576FF96ACAAFF8BA19FFF859C98FF829794FF829794FF809592FF7E9390FF
+ 829592FF879A97FF788986FF7C8D8AFF80918EFF849592FF8A9896FF889694FF
+ 798785FF697775FF6B7975FF677571FF404E4AFF586662FF616F6BFF6A7874FF
+ 6C7A76FF75837FFF7B8985FF8A9894FF94A29EFF8E9C98FF879591FF889692FF
+ 8D9B97FF8F9D99FF919F9BFF909E9AFF8F9D99FF8F9D99FF909E9AFF919F9BFF
+ 92A09CFF93A19DFF93A19DFF94A29EFF95A39FFF96A4A0FF97A5A1FF96A4A0FF
+ 94A29EFF93A19DFF939F99FF929E98FF8F9D97FF919F99FF93A19BFF95A39DFF
+ 93A39CFF92A29BFF9FB1AAFF91A39CFF93A59EFFA0B2ABFF9EB3ABFF9EB3ABFF
+ C0D5CDFFECFFFBFFE1F8F4FFDBF4F0FFD9F2EEFFDBF4F0FFDAF3EFFFD7F0ECFF
+ D7F0ECFFD8F1EDFFD8F1EDFFDDF6F2FFDDF6F2FFD6EFEBFFD0E9E5FFCBE4E0FF
+ C5DEDAFFBED7D3FFB6CDC9FFBCD3CFFFB3C8C5FFA9BEBBFFADC2BFFF293E3BFF
+ 687B78FF768986FF6C7D7AFF6E7F7CFF748582FF7D8E8BFF818F8DFF788684FF
+ 6D7B79FF677672FF85938FFF94A29CFF909E98FF7B8983FF75837DFF818F89FF
+ 7F8D87FF6F7D77FF6A7872FF707E78FF75837DFF7C8A84FF87958FFF8D9B95FF
+ 82908AFF72807AFF79857FFF818B85FF87918BFF8B958FFF929C96FF9AA49EFF
+ 9AA49EFF96A09AFFA0AAA4FFA1ABA5FFA2ACA6FFA3ADA7FFA0AAA4FF9DA7A1FF
+ 9CA6A0FF9BA7A1FF94A29CFFA5B5AEFFA8B6B0FF9BABA4FF9CAAA4FFA1B1AAFF
+ A3B1ABFFA2B2ABFFADBBB5FFB5C5BEFFC1CFC9FFC5D5CEFFA3BAB6FFA4BBB7FF
+ 9EB5B1FF96ADA9FF96ADA9FF9BB2AEFF96ADA9FF89A09CFF95ACA8FFA3BAB6FF
+ A9C0BCFFA2B9B5FFA1B8B4FFAAC1BDFFA9C0BCFF9FB6B2FFA6BFBBFFA1BAB6FF
+ 9BB2AEFF97AEAAFF9AB1ADFFA1B8B4FFA0B5B2FF9AAFACFFA4B7B4FFA2B5B2FF
+ 94A7A4FF8C9F9CFF8E9F9CFF7C8D8AFF637471FF5B6967FF37423FFF424B48FF
+ 565F5CFF4E5754FF545D5AFF646D6AFF545D5AFF4B5451FF5E6764FF5B6461FF
+ 656E6BFF7B8481FF8B9491FF8C9592FF89928FFF889390FF97A5A1FF9DACA8FF
+ 9CABA7FF9DACA8FF9FB0ACFF97A8A4FF91A29EFF9CADA9FF9BAFAAFFA8BCB7FF
+ B5CBC6FFBCD2CDFFC0D6D1FFBFD5D0FFB7CEC9FFAEC5C0FFACBFBCFFACBFBCFF
+ A9BCB9FFA1B4B1FF98ABA8FF95A8A5FF9AADAAFFA1B4B1FFABBEBBFFA3B6B3FF
+ 9CAFACFF98ABA8FF91A4A1FF879A97FF7F928FFF7E918EFF879692FF6C7B77FF
+ 64736FFF707F7BFF778682FF7D8C88FF81908CFF7F8E8AFF808F8BFF84938FFF
+ 8A9995FF91A09CFF94A39FFF92A19DFF8D9C98FF889793FF94A29EFF92A09CFF
+ 8F9D99FF8D9B97FF8D9B97FF8F9D99FF919F9BFF92A09CFF8E9C98FFA4B2AEFF
+ 919F9BFF8D9B97FFA9B7B3FFCDDBD7FFEAF8F4FFE1F0ECFFCCDDDAFFB5C6C3FF
+ 9EAFACFF97A8A5FF9CAAA8FF9DABA9FF9AA8A6FF97A5A3FF94A19FFF909D9BFF
+ 929D9BFF96A19FFF96A19FFF909B99FF8E9695FF8B9694FF859290FF859290FF
+ 899694FF8C9997FF8B9896FF889593FF8D9A98FF96A3A1FF9CA9A7FF97A4A2FF
+ 8D9A98FF808D8BFF758280FF717E7CFF74817FFF788682FF848D8AFF8F9993FF
+ 919A97FF929B98FF949F9CFF8B9995FF8A9795FF98A6A4FFACBDBAFFC0D3D0FF
+ BED0CFFFB6CBC9FFA3B8B9FF94A9AAFF6D8283FF98AEACFF8EA4A2FF869D99FF
+ 819693FF7E9390FF7C918EFF7A8F8CFF7F928FFF859895FF7B8C89FF7A8B88FF
+ 798A87FF798A87FF818F8DFF849290FF7D8B89FF73817FFF6C7A76FF64726EFF
+ 3A4844FF52605CFF5E6C68FF697773FF687672FF707E7AFF788682FF8A9894FF
+ 94A29EFF8D9B97FF83918DFF84928EFF889692FF899793FF899793FF8A9894FF
+ 8B9995FF8C9A96FF8E9C98FF8F9D99FF909E9AFF919F9BFF8F9D99FF92A09CFF
+ 95A39FFF98A6A2FF9AA8A4FF99A7A3FF98A6A2FF96A4A0FF929E98FF939F99FF
+ 919F99FF92A09AFF92A09AFF92A09AFF92A29BFF92A29BFF8C9E97FF93A59EFF
+ 98AAA3FF96A8A1FF97ACA4FFABC0B8FFCFE4DCFFE9FFF8FFE3FAF6FFDFF8F4FF
+ DDF6F2FFDDF6F2FFDDF6F2FFDCF5F1FFDAF3EFFFD8F1EDFFDDF6F2FFDEF7F3FF
+ DBF4F0FFD7F0ECFFD5EEEAFFD2EBE7FFC9E2DEFFBFD8D4FFACC3BFFFB7CECAFF
+ B2C7C4FFA9BEBBFFB0C5C2FF405552FF657875FF778A87FF748582FF71827FFF
+ 6F807DFF738481FF7B8987FF7F8D8BFF7F8D8BFF7E8D89FF82908CFF94A29CFF
+ 97A59FFF87958FFF7F8D87FF889690FF899791FF7F8D87FF707E78FF717F79FF
+ 73817BFF798781FF83918BFF899791FF83918BFF7A8882FF808A84FF86908AFF
+ 8B958FFF8D9791FF929C96FF99A39DFF9BA59FFF98A29CFF96A09AFF98A29CFF
+ A1ABA5FFACB6B0FFAEB8B2FFA7B1ABFFA0AAA4FF9EA8A2FF9BA7A1FFA3B1ABFF
+ A8B6B0FFA1AFA9FF9CAAA4FFA0AEA8FFA3B1ABFF9FADA7FF96A49EFF9DABA5FF
+ A5B3ADFFA9B7B1FF94ABA7FF9BB2AEFF9AB1ADFF93AAA6FF96ADA9FFA2B9B5FF
+ A5BCB8FF9EB5B1FF94ABA7FFA4BBB7FFA7BEBAFF9BB2AEFF9AB1ADFFA6BDB9FF
+ A6BDB9FF9AB1ADFF9BB4B0FFA1BAB6FFA0B7B3FF9AB1ADFFA3BAB6FFB0C7C3FF
+ A8BDBAFF92A7A4FF92A5A2FF9BAEABFF99ACA9FF98ABA8FF9CADAAFF879895FF
+ 657673FF576563FF49524FFF545B58FF686F6CFF59605DFF4E5552FF555C59FF
+ 535A57FF5F6663FF585F5CFF5D6461FF646B68FF6E7572FF818885FF939A97FF
+ 959C99FF8A9390FF909E9AFF98A7A3FF9AA9A5FF9DACA8FF9EAFABFF95A6A2FF
+ 93A4A0FFA2B3AFFF98ACA7FFA5B9B4FFAFC5C0FFB3C9C4FFB4CAC5FFB4CAC5FF
+ B0C7C2FFAAC1BCFFA6B9B6FFA7BAB7FFA5B8B5FFA0B3B0FF9AADAAFF97AAA7FF
+ 99ACA9FF9CAFACFFA1B4B1FF98ABA8FF92A5A2FF90A3A0FF8C9F9CFF829592FF
+ 7B8E8BFF798C89FF7C8B87FF6C7B77FF657470FF6D7C78FF778682FF7D8C88FF
+ 808F8BFF808F8BFF7D8C88FF81908CFF889793FF8F9E9AFF93A29EFF93A29EFF
+ 91A09CFF8F9E9AFF8C9A96FF8E9C98FF909E9AFF919F9BFF919F9BFF92A09CFF
+ 92A09CFF93A19DFF8D9B97FF9BA9A5FF95A39FFF93A19DFF93A19DFFAFBDB9FF
+ DFEDE9FFE1F0ECFFD9EAE7FFC6D9D6FFACBFBCFF9AADAAFF9AABA8FF9EAFACFF
+ 9CAAA8FF94A2A0FF95A3A1FF909E9CFF8F9C9AFF94A19FFF97A2A0FF929D9BFF
+ 8E9997FF8E9997FF8D9A98FF8C9997FF8E9B99FF909D9BFF8C9997FF889593FF
+ 8B9896FF93A09EFF98A5A3FF93A09EFF8B9896FF83908EFF7D8A88FF788583FF
+ 73807EFF6F7D79FF838C89FF8F9993FF929B98FF929B98FF8E9996FF84928EFF
+ 8A9795FFA0AEACFFB4C5C2FFC4D7D4FFBBCDCCFFB8CDCBFFA9BEBFFF9CB1B2FF
+ 778C8DFF91A7A5FF8BA19FFF849B97FF809592FF7F9491FF7C918EFF788D8AFF
+ 7C8F8CFF819491FF80918EFF7D8E8BFF778885FF748582FF7B8987FF818F8DFF
+ 7D8B89FF758381FF6D7B77FF636E6BFF36413EFF4F5A57FF5F6A67FF6B7673FF
+ 687370FF6C7774FF7A8582FF87928FFF8C9794FF85908DFF838E8BFF8A9592FF
+ 8D9895FF889390FF869490FF889692FF8A9894FF8D9B97FF8F9D99FF919F9BFF
+ 92A09CFF92A09CFF909E9AFF93A19DFF98A6A2FF9CAAA6FF9DABA7FF9CAAA6FF
+ 9AA8A4FF98A6A2FF98A49EFF99A59FFF96A49EFF92A09AFF8E9C96FF8E9C96FF
+ 92A29BFF96A69FFF8A9C95FF8D9F98FF90A29BFF8FA19AFF90A59DFFA3B8B0FF
+ C6DBD3FFE1F8F0FFE3FAF6FFDFF8F4FFDDF6F2FFDCF5F1FFDDF6F2FFDDF6F2FF
+ DAF3EFFFD5EEEAFFDAF3EFFFDBF4F0FFDAF3EFFFD5EEEAFFD3ECE8FFD1EAE6FF
+ C9E2DEFFBFD8D4FFB0C7C3FFB7CECAFFAEC3C0FFA4B9B6FFAFC4C1FF5D726FFF
+ 607370FF738683FF7D8E8BFF788986FF738481FF748582FF7E8C8AFF889694FF
+ 8D9B99FF8D9C98FF82918DFF8E9E97FF92A29BFF889891FF85958EFF8E9E97FF
+ 93A39CFF8F9F98FF879790FF81918AFF7F8F88FF83938CFF889891FF86968FFF
+ 809089FF7C8A84FF848E88FF8C938EFF909792FF919893FF959C97FF9CA39EFF
+ A0A7A2FF9FA6A1FF929994FF909792FF979E99FFA6ADA8FFAFB6B1FFADB4AFFF
+ A9B0ABFFA7B1ABFF9EAAA4FFA0ACA6FFA9B5AFFFABB7B1FFA2AEA8FFA1ADA7FF
+ A3AFA9FF9EAAA4FF95A19BFF97A39DFF9AA6A0FF9CA8A2FF91A8A4FF9DB4B0FF
+ A0B7B3FF97AEAAFF97AEAAFFA5BCB8FFAEC5C1FFACC3BFFFA3BAB6FFAFC6C2FF
+ A9C0BCFF94ABA7FF92A9A5FFA4BBB7FFACC3BFFFA4BBB7FFA7C0BCFFA3BCB8FF
+ 9FB6B2FF9EB5B1FFA0B7B3FF9EB5B1FF91A6A3FF829794FF839693FF8EA19EFF
+ 8EA19EFF8EA19EFF94A5A2FF859693FF6C7D7AFF647270FF464F4CFF474E4BFF
+ 5E6562FF5F6663FF59605DFF555C59FF49504DFF565D5AFF474E4BFF585F5CFF
+ 5F6663FF5F6663FF707774FF8C9390FF959C99FF89928FFFA0AEAAFFA4B3AFFF
+ 9FAEAAFF9BAAA6FF97A8A4FF8E9F9BFF91A29EFFA6B7B3FFA1B5B0FFA9BDB8FF
+ ADC3BEFFACC2BDFFABC1BCFFAFC5C0FFB1C8C3FFB1C8C3FFAABDBAFFAABDBAFF
+ A8BBB8FFA3B6B3FF9CAFACFF96A9A6FF91A4A1FF90A3A0FF99ACA9FF91A4A1FF
+ 8C9F9CFF8C9F9CFF8A9D9AFF829592FF7B8E8BFF798C89FF6B7A76FF62716DFF
+ 5D6C68FF657470FF72817DFF7A8985FF7D8C88FF7F8E8AFF808F8BFF859490FF
+ 8B9A96FF8F9E9AFF8F9E9AFF8F9E9AFF909F9BFF92A19DFF84928EFF889692FF
+ 8D9B97FF919F9BFF92A09CFF92A09CFF92A09CFF92A09CFF8E9C98FF94A29EFF
+ 99A7A3FF9DABA7FF899793FF99A7A3FFD6E4E0FFE7F6F2FFEAFBF8FFDAEDEAFF
+ BDD0CDFFA1B4B1FF9BACA9FFA0B1AEFF9DABA9FF8F9D9BFF97A5A3FF919F9DFF
+ 8F9C9AFF93A09EFF97A2A0FF939E9CFF8F9A98FF8F9A98FF95A2A0FF93A09EFF
+ 94A19FFF94A19FFF8E9B99FF889593FF8A9795FF919E9CFF909D9BFF8A9795FF
+ 84918FFF828F8DFF83908EFF7D8A88FF717E7CFF667470FF838C89FF909A94FF
+ 939C99FF8F9895FF899491FF7E8C88FF8A9795FFA7B5B3FFBCCDCAFFC8DBD8FF
+ BACCCBFFBCD1CFFFB2C7C8FFA7BCBDFF7F9495FF8AA09EFF889E9CFF839A96FF
+ 819693FF829794FF7F9491FF7A8F8CFF7C8F8CFF7F928FFF899A97FF879895FF
+ 81928FFF7E8F8CFF83918FFF859391FF7E8C8AFF74817FFF76817EFF687370FF
+ 384340FF525D5AFF646F6CFF727D7AFF6D7875FF6F7A77FF798481FF808B88FF
+ 808B88FF7B8683FF828D8AFF919C99FF949F9CFF8B9693FF818F8BFF83918DFF
+ 879591FF8A9894FF8D9B97FF8F9D99FF909E9AFF909E9AFF94A29EFF97A5A1FF
+ 9CAAA6FFA0AEAAFFA1AFABFFA0AEAAFF9DABA7FF9AA8A4FFA2AEA8FFA2AEA8FF
+ 9CAAA4FF93A19BFF8A9892FF899791FF90A099FF98A8A1FF9DAFA8FF879992FF
+ 859790FF96A8A1FF96ABA3FF92A79FFFB3C8C0FFE2F9F1FFE1F8F4FFDEF7F3FF
+ DBF4F0FFDAF3EFFFDBF4F0FFDCF5F1FFD8F1EDFFD2EBE7FFD2EBE7FFD7F0ECFF
+ D7F0ECFFD2EBE7FFCEE7E3FFCBE4E0FFC5DEDAFFBED7D3FFBAD1CDFFBAD1CDFF
+ ABC0BDFF9FB4B1FFABC0BDFF708582FF596C69FF6C7F7CFF788986FF768784FF
+ 738481FF768784FF818F8DFF899795FF8B9997FF879692FF94A39FFF98A8A1FF
+ 98A8A1FF92A29BFF93A39CFF9BABA4FFA0B0A9FFA0B0A9FFA1B1AAFF96A69FFF
+ 90A099FF93A39CFF91A19AFF86968FFF7C8C85FF7A8882FF848E88FF8C938EFF
+ 909792FF909792FF949B96FF9DA49FFFA2A9A4FFA2A9A4FFA0A7A2FF959C97FF
+ 909792FF989F9AFFA1A8A3FFA3AAA5FFA4ABA6FFA6B0AAFF9EAAA4FF9CA8A2FF
+ A9B5AFFFB2BEB8FFA8B4AEFFA3AFA9FFA4B0AAFF9EAAA4FF96A29CFF97A39DFF
+ 9BA7A1FFA1ADA7FF9AB1ADFFA7BEBAFFAAC1BDFF9CB3AFFF8EA5A1FF8EA5A1FF
+ 98AFABFF9EB5B1FFA9C0BCFFA8BFBBFFA0B7B3FF99B0ACFF9EB5B1FFA9C0BCFF
+ A8BFBBFF9EB5B1FFA4BDB9FFA2BBB7FF95ACA8FF869D99FF8EA5A1FF9FB6B2FF
+ 98ADAAFF809592FF8A9D9AFF859895FF7C8F8CFF798C89FF829390FF81928FFF
+ 697A77FF4D5B59FF323B38FF363D3AFF525956FF5A615EFF59605DFF545B58FF
+ 474E4BFF545B58FF5D6461FF4D5451FF4A514EFF585F5CFF636A67FF676E6BFF
+ 737A77FF838C89FF99A7A3FF8D9C98FF8F9E9AFF9CABA7FF9AABA7FF8A9B97FF
+ 859692FF8D9E9AFF839792FFA2B6B1FFB9CFCAFFB8CEC9FFB0C6C1FFAEC4BFFF
+ AAC1BCFFA2B9B4FF9AADAAFFA1B4B1FFA3B6B3FF9CAFACFF92A5A2FF8EA19EFF
+ 8FA29FFF91A4A1FF9FB2AFFF98ABA8FF8C9F9CFF849794FF839693FF819491FF
+ 748784FF647774FF6F7E7AFF556460FF5A6965FF6B7A76FF687773FF73827EFF
+ 84938FFF7F8E8AFF808F8BFF859490FF8C9B97FF909F9BFF91A09CFF91A09CFF
+ 92A19DFF92A19DFF9BA9A5FF93A19DFF909E9AFF95A39FFF96A4A0FF909E9AFF
+ 8E9C98FF919F9BFF919F9BFF93A19DFF92A09CFF95A39FFF98A6A2FF9AA8A4FF
+ BAC8C4FFEBFAF6FFE3F6F3FFD3E8E5FFD2E5E2FFC9DCD9FFB0C3C0FF9DB0ADFF
+ 98A9A6FF8FA09DFF9EACAAFF99A7A5FF94A2A0FF92A09EFF93A09EFF919E9CFF
+ 8C9997FF879492FF8E9B99FF8C9997FF8E9B99FF929F9DFF909D9BFF889593FF
+ 84918FFF859290FF94A19FFF95A2A0FF909D9BFF859290FF818E8CFF818E8CFF
+ 7A8785FF707E7AFF808986FF97A19BFF969F9CFF838C89FF7A8582FF7F8D89FF
+ 94A19FFFAEBCBAFFC7D8D5FFBDD0CDFFC4D6D5FFC3D8D6FFAFC4C5FF9BB0B1FF
+ 8BA0A1FF7A908EFF8DA3A1FF829995FF7C918EFF7E9390FF7D928FFF768B88FF
+ 768986FF788B88FF7F908DFF889996FF8A9B98FF81928FFF7B8987FF798785FF
+ 758381FF707D7BFF747F7CFF5B6461FF323B38FF656E6BFF68716EFF6F7875FF
+ 757E7BFF6D7673FF6D7673FF757E7BFF7B8481FF7C8582FF7F8885FF858E8BFF
+ 8C9592FF8E9996FF8C9A96FF8D9B97FF8F9D99FF93A19DFF97A5A1FF9AA8A4FF
+ 9AA8A4FF9AA8A4FF97A5A1FF98A6A2FF9AA8A4FF9BA9A5FF9CAAA6FF9CAAA6FF
+ 9CAAA6FF9BA9A5FF939F99FF97A39DFF98A6A0FF96A49EFF92A09AFF92A09AFF
+ 96A69FFF9CACA5FF96A8A1FF9DAFA8FF98AAA3FF91A39CFF95AAA2FF9EB3ABFF
+ B1C6BEFFCBE2DAFFDBF2EEFFDBF4F0FFD9F2EEFFD4EDE9FFD5EEEAFFD8F1EDFF
+ D3ECE8FFC8E1DDFFD0E9E5FFD5EEEAFFD2EBE7FFC9E2DEFFC7E0DCFFCCE5E1FF
+ C8E1DDFFBCD5D1FFB4CBC7FFB8CFCBFFB7CCC9FFAFC4C1FF9AAFACFF778C89FF
+ 6D807DFF819491FF869794FF7F908DFF7C8D8AFF7E8F8CFF83918FFF82908EFF
+ 859391FF899894FF94A5A1FF98AAA3FF9DAFA8FF9CAEA7FF96A8A1FF94A69FFF
+ 9CAEA7FFA7B9B2FFA4B6AFFF9AACA5FF92A49DFF8A9C95FF8B9D96FF96A8A1FF
+ 899B94FF66766FFF727E78FF7E8882FF89938DFF8F9993FF919B95FF929C96FF
+ 97A19BFF9CA6A0FF9EA8A2FF9DA7A1FF9CA6A0FF9AA49EFF9AA49EFF9BA59FFF
+ 9DA7A1FF9EA8A2FF9AA6A0FF9FABA5FFA3AFA9FFA4B0AAFFA4B0AAFFA3AFA9FF
+ 9FABA5FF9AA6A0FF929E98FF8C9892FF8C9892FF95A19BFFA9C0BCFFB3CAC6FF
+ B4CBC7FFA6BDB9FF98AFABFF95ACA8FF99B0ACFF9BB2AEFFA5BCB8FFACC3BFFF
+ A9C0BCFF9FB6B2FF9BB2AEFFA1B8B4FFA3BAB6FF9DB4B0FF8DA6A2FF9DB6B2FF
+ A6BDB9FF99B0ACFF8EA5A1FF92A9A5FF9AAFACFF9CB1AEFF8EA19EFF859895FF
+ 758885FF6A7D7AFF71827FFF768784FF697A77FF576563FF3A4340FF3A413EFF
+ 565D5AFF5E6562FF575E5BFF4D5451FF434A47FF5A615EFF666D6AFF555C59FF
+ 4B524FFF4F5653FF525956FF555C59FF656C69FF77807DFF84928EFF93A29EFF
+ 9AA9A5FF93A29EFF8FA09CFF96A7A3FF96A7A3FF8FA09CFF7B8F8AFF8B9F9AFF
+ A0B6B1FFB1C7C2FFB0C6C1FFA4BAB5FF98AFAAFF94ABA6FF99ACA9FFA0B3B0FF
+ A5B8B5FFA2B5B2FF9AADAAFF94A7A4FF92A5A2FF92A5A2FF9CAFACFF99ACA9FF
+ 90A3A0FF869996FF7F928FFF7B8E8BFF708380FF657875FF576662FF404F4BFF
+ 4C5B57FF657470FF697874FF71807CFF7F8E8AFF7E8D89FF889793FF8C9B97FF
+ 909F9BFF91A09CFF909F9BFF8E9D99FF8E9D99FF8E9D99FF94A29EFF8E9C98FF
+ 8D9B97FF93A19DFF95A39FFF92A09CFF92A09CFF95A39FFF94A29EFF95A39FFF
+ 92A09CFF93A19DFF95A39FFF94A29EFFAEBCB8FFD9E8E4FFE5F8F5FFD5EAE7FF
+ D1E4E1FFCCDFDCFFBBCECBFFABBEBBFFA3B4B1FF98A9A6FF9CAAA8FF97A5A3FF
+ 92A09EFF909E9CFF919E9CFF8F9C9AFF899694FF84918FFF869391FF859290FF
+ 889593FF8E9B99FF8F9C9AFF899694FF869391FF879492FF879492FF8E9B99FF
+ 909D9BFF879492FF808D8BFF7E8B89FF7A8785FF75837FFF838C89FF97A19BFF
+ 97A09DFF8A9390FF87928FFF8D9B97FF9EABA9FFB3C1BFFFC1D2CFFFBBCECBFF
+ BFD1D0FFBACFCDFFAABFC0FFA2B7B8FF99AEAFFF869C9AFF97ADABFF8BA29EFF
+ 829794FF7E9390FF798E8BFF718683FF6F827FFF708380FF7E8F8CFF859693FF
+ 889996FF829390FF808E8CFF7F8D8BFF7B8987FF768381FF747F7CFF59625FFF
+ 323B38FF5D6663FF5F6865FF69726FFF767F7CFF757E7BFF767F7CFF79827FFF
+ 7C8582FF7D8683FF7F8885FF848D8AFF89928FFF899491FF95A09DFF93A19DFF
+ 93A19DFF94A29EFF94A29EFF93A19DFF92A09CFF909E9AFF96A4A0FF96A4A0FF
+ 96A4A0FF96A4A0FF95A39FFF95A39FFF95A39FFF95A39FFF96A29CFF9BA7A1FF
+ 9DABA5FF9DABA5FF98A6A0FF96A49EFF97A7A0FF9AAAA3FF91A39CFF9BADA6FF
+ 99ABA4FF96A8A1FF98ADA5FF9AAFA7FFA8BDB5FFBFD6CEFFD2E9E5FFD2EBE7FF
+ CEE7E3FFC9E2DEFFCBE4E0FFD2EBE7FFD5EEEAFFD1EAE6FFCFE8E4FFD0E9E5FF
+ CDE6E2FFC9E2DEFFC8E1DDFFC9E2DEFFC5DEDAFFBED7D3FFB6CDC9FFB4CBC7FF
+ ACC1BEFFA7BCB9FF9BB0ADFF7D928FFF718481FF7F928FFF8E9F9CFF879895FF
+ 849592FF879895FF8B9997FF889694FF869492FF879692FF90A19DFF97A9A2FF
+ A0B2ABFFA2B4ADFF9CAEA7FF94A69FFF92A49DFF94A69FFF91A39CFF94A69FFF
+ 9BADA6FF98AAA3FF8EA099FF92A49DFF92A49DFF84948DFF75817BFF7A8680FF
+ 848E88FF89958FFF909A94FF94A09AFF9BA59FFF9DA9A3FFA2ACA6FF9FABA5FF
+ A0AAA4FF9EAAA4FFA1ABA5FFA1ADA7FFA5AFA9FFA4B0AAFFA4B0AAFFA5B1ABFF
+ A7B3ADFFABB7B1FFAEBAB4FFABB7B1FFA0ACA6FF95A19BFF909C96FF8A9690FF
+ 8A9690FF919D97FFA7BEBAFFACC3BFFFADC4C0FFA4BBB7FF9BB2AEFF96ADA9FF
+ 94ABA7FF91A8A4FF9DB4B0FFAAC1BDFFAEC5C1FFA2B9B5FF98AFABFF9BB2AEFF
+ A0B7B3FFA0B7B3FF8FA8A4FF94ADA9FF9AB1ADFF9BB2AEFF98AFABFF96ADA9FF
+ 99AEABFF9BB0ADFF99ACA9FF92A5A2FF829592FF738683FF758683FF7A8B88FF
+ 748582FF687674FF414C49FF3B4441FF545D5AFF606966FF565F5CFF464F4CFF
+ 414A47FF626B68FF6A7370FF5C6562FF515A57FF4D5653FF4A5350FF4A5350FF
+ 555E5BFF626D6AFF6A7874FF82918DFF93A29EFF92A19DFF91A29EFF9AABA7FF
+ 9CADA9FF94A5A1FF8A9E99FF899D98FF96ACA7FFB0C6C1FFB7CDC8FFA9BFBAFF
+ 9EB5B0FF9FB6B1FF9BAEABFFA0B3B0FFA3B6B3FFA1B4B1FF97AAA7FF8C9F9CFF
+ 849794FF819491FF839693FF839693FF7D908DFF708380FF647774FF5D706DFF
+ 556865FF4D605DFF41504CFF2E3D39FF3D4C48FF606F6BFF6D7C78FF72817DFF
+ 7C8B87FF808F8BFF889793FF8A9995FF8C9B97FF8C9B97FF8A9995FF899894FF
+ 8B9A96FF8D9C98FF92A09CFF8D9B97FF8C9A96FF909E9AFF93A19DFF92A09CFF
+ 92A09CFF94A29EFF9AA8A4FF9AA8A4FF95A39FFF96A4A0FF98A6A2FF93A19DFF
+ A4B2AEFFC6D5D1FFDDF0EDFFD1E6E3FFCADFDCFFC6DBD8FFBDD2CFFFAEC3C0FF
+ A1B4B1FF98ABA8FF98A9A6FF93A4A1FF909E9CFF8E9C9AFF8E9C9AFF8C9A98FF
+ 869492FF818F8DFF818E8CFF808D8BFF859290FF8C9997FF8C9997FF879492FF
+ 83908EFF84918FFF7D8A88FF889593FF909D9BFF8A9795FF808D8BFF7A8785FF
+ 788583FF768480FF818A87FF909A94FF919A97FF8D9693FF96A19EFF9FADA9FF
+ ADBAB8FFBECCCAFFC8D9D6FFC5D8D5FFC3D5D4FFB2C7C5FFA1B6B7FFA3B8B9FF
+ 9CB1B2FF839997FF8EA4A2FF869D99FF809592FF7D928FFF7A8F8CFF758A87FF
+ 758885FF768986FF7A8B88FF7D8E8BFF7E8F8CFF7C8D8AFF7D8B89FF7C8A88FF
+ 768482FF707D7BFF6F7A77FF57605DFF3F4845FF616A67FF616A67FF68716EFF
+ 757E7BFF78817EFF767F7CFF757E7BFF757E7BFF78817EFF7E8784FF838C89FF
+ 868F8CFF86918EFF939E9BFF92A09CFF93A19DFF93A19DFF92A09CFF919F9BFF
+ 919F9BFF909E9AFF9CAAA6FF9AA8A4FF98A6A2FF96A4A0FF95A39FFF96A4A0FF
+ 96A4A0FF97A5A1FF9BA7A1FFA0ACA6FFA3B1ABFFA3B1ABFF9EACA6FF9AA8A2FF
+ 97A7A0FF98A8A1FF92A49DFF9AACA5FF98AAA3FF95A7A0FF96ABA3FF98ADA5FF
+ A8BDB5FFC3DAD2FFD1E8E4FFCFE8E4FFCAE3DFFFC3DCD8FFC3DCD8FFCBE4E0FF
+ D5EEEAFFD9F2EEFFCFE8E4FFC9E2DEFFC7E0DCFFC9E2DEFFC8E1DDFFC2DBD7FF
+ BED7D3FFBED7D3FFBFD6D2FFB5CCC8FFA7BCB9FFA5BAB7FFA1B6B3FF899E9BFF
+ 7A8D8AFF839693FF8C9D9AFF859693FF849592FF8C9D9AFF94A2A0FF92A09EFF
+ 8E9C9AFF8C9B97FF8FA09CFF95A7A0FF9BADA6FF9CAEA7FF98AAA3FF92A49DFF
+ 8D9F98FF8A9C95FF8A9C95FF8B9D96FF98AAA3FF9AACA5FF8D9F98FF889A93FF
+ 899B94FF84948DFF7C8A84FF7B8983FF7F8B85FF83918BFF8D9993FF92A09AFF
+ 97A39DFF96A49EFF99A59FFF96A49EFF98A49EFF97A59FFF9BA7A1FF9CAAA4FF
+ A2AEA8FFA1AFA9FFA0AEA8FF9BA9A3FF98A6A0FF9FADA7FFA8B6B0FFAAB8B2FF
+ A1AFA9FF98A6A0FF93A19BFF909E98FF8F9D97FF94A29CFF9BB2AEFF9DB4B0FF
+ 9EB5B1FF9EB5B1FF9CB3AFFF99B0ACFF94ABA7FF90A7A3FF97AEAAFFA4BBB7FF
+ A8BFBBFF9CB3AFFF94ABA7FF99B0ACFFA1B8B4FFA3BAB6FF99B2AEFF8FA8A4FF
+ 8EA5A1FF95ACA8FF98AFABFF90A7A3FF8CA19EFF8EA3A0FF8A9D9AFF8B9E9BFF
+ 849794FF778A87FF738481FF71827FFF667774FF596765FF46514EFF343F3CFF
+ 4C5552FF5C6764FF5C6562FF4B5653FF4A5350FF6C7774FF6F7875FF646F6CFF
+ 5D6663FF586360FF58615EFF525D5AFF525B58FF4F5A57FF566460FF5C6B67FF
+ 71807CFF8B9A96FF93A4A0FF8E9F9BFF8FA09CFF98A9A5FF99ADA8FF96AAA5FF
+ 9AB0ABFFA9BFBAFFB2C8C3FFB0C6C1FFAEC5C0FFB2C9C4FF9DB0ADFF9BAEABFF
+ 98ABA8FF92A5A2FF869996FF768986FF6B7E7BFF687B78FF5B6E6BFF5D706DFF
+ 5A6D6AFF526562FF4C5F5CFF4A5D5AFF455855FF3F524FFF404F4BFF303F3BFF
+ 3A4945FF5B6A66FF707F7BFF758480FF7C8B87FF869591FF859490FF879692FF
+ 899894FF899894FF8A9995FF8D9C98FF91A09CFF95A4A0FF95A39FFF919F9BFF
+ 8E9C98FF8E9C98FF8F9D99FF8F9D99FF8E9C98FF8E9C98FF97A5A1FF98A6A2FF
+ 93A19DFF94A29EFF98A6A2FF93A19DFF9CAAA6FFB7C6C2FFD1E4E1FFCFE4E1FF
+ CBE0DDFFC6DBD8FFBDD2CFFFA8BDBAFF98ABA8FF96A9A6FF97A8A5FF92A3A0FF
+ 8F9D9BFF8D9B99FF8E9C9AFF8C9A98FF879593FF82908EFF83908EFF828F8DFF
+ 869391FF8B9896FF8A9795FF83908EFF7E8B89FF7E8B89FF7B8886FF84918FFF
+ 8C9997FF8B9896FF84918FFF7C8987FF778482FF75837FFF7E8784FF86908AFF
+ 848D8AFF87908DFF99A4A1FFA7B5B1FFB4C1BFFFC4D2D0FFC5D6D3FFC8DBD8FF
+ C6D8D7FFAEC3C1FF9DB2B3FFA5BABBFF9DB2B3FF7B918FFF819795FF7F9692FF
+ 7F9491FF7F9491FF7E9390FF7B908DFF7A8D8AFF7A8D8AFF7B8C89FF7A8B88FF
+ 788986FF778885FF798785FF768482FF6E7C7AFF677472FF65706DFF535C59FF
+ 4F5855FF67706DFF67706DFF656E6BFF6B7471FF6C7572FF6A7370FF666F6CFF
+ 67706DFF707976FF7B8481FF828B88FF87908DFF8A9390FF899491FF8A9894FF
+ 8F9D99FF92A09CFF94A29EFF97A5A1FF99A7A3FF9BA9A5FF9FADA9FF9DABA7FF
+ 9AA8A4FF97A5A1FF97A5A1FF98A6A2FF9AA8A4FF9CAAA6FFA1ADA7FFA4B0AAFF
+ A5B3ADFFA4B2ACFF9FADA7FF9BA9A3FF98A8A1FF98A8A1FF99ABA4FF9CAEA7FF
+ 94A69FFF8FA19AFF91A69EFF97ACA4FFB0C5BDFFD4EBE3FFDBF2EEFFD7F0ECFF
+ D1EAE6FFC8E1DDFFC4DDD9FFC8E1DDFFD1EAE6FFD8F1EDFFD0E9E5FFC5DEDAFF
+ C2DBD7FFC8E1DDFFC6DFDBFFBAD3CFFFB5CECAFFB9D2CEFFC0D7D3FFB3CAC6FF
+ A4B9B6FFA2B7B4FFA0B5B2FF899E9BFF7A8D8AFF839693FF8A9B98FF829390FF
+ 7E8F8CFF859693FF8E9C9AFF8C9A98FF889694FF859490FF8FA09CFF8FA19AFF
+ 8C9E97FF869891FF859790FF899B94FF8C9E97FF8C9E97FF98AAA3FF8B9D96FF
+ 90A29BFF99ABA4FF91A39CFF879992FF7D8F88FF6E8079FF74847DFF73837CFF
+ 74847DFF7B8B84FF86968FFF8E9E97FF90A099FF8F9F98FF9BABA4FF9BABA4FF
+ 9CACA5FF9EAEA7FFA2B2ABFFA6B6AFFFABBBB4FFADBDB6FFACBCB5FFA2B2ABFF
+ 9CAAA4FF9EAEA7FFA6B4AEFFA8B8B1FFA8B6B0FFA6B6AFFF919F99FF8F9F98FF
+ 919F99FF92A29BFFA2B9B5FFA0B7B3FFA0B7B3FFA4BBB7FFA6BDB9FFA4BBB7FF
+ 9FB6B2FF9CB3AFFF9CB3AFFFA2B9B5FF9FB6B2FF94ABA7FF90A7A3FF99B0ACFF
+ 9FB6B2FF9DB4B0FF95AEAAFF90A9A5FF94ABA7FF96ADA9FF8CA39FFF7E9591FF
+ 829794FF91A6A3FF899C99FF8FA29FFF8B9E9BFF7E918EFF768784FF70817EFF
+ 627370FF53615FFF42504CFF2A3834FF3F4A47FF566460FF626D6AFF596763FF
+ 56615EFF73817DFF7A8582FF707E7AFF66716EFF5E6C68FF616C69FF5E6C68FF
+ 56615EFF485652FF485753FF475652FF51605CFF677672FF788985FF82938FFF
+ 8A9B97FF92A39FFF8DA19CFF99ADA8FF9FB5B0FF9FB5B0FFA2B8B3FFACC2BDFF
+ B0C7C2FFAEC5C0FF97AAA7FF8DA09DFF859895FF819491FF798C89FF6D807DFF
+ 667976FF667976FF536663FF546764FF526562FF516461FF556865FF5A6D6AFF
+ 576A67FF4F625FFF4E5D59FF42514DFF3E4D49FF52615DFF6B7A76FF74837FFF
+ 7B8A86FF879692FF879692FF899894FF8B9A96FF8C9B97FF8D9C98FF91A09CFF
+ 97A6A2FF9CABA7FF96A4A0FF93A19DFF8F9D99FF8C9A96FF8C9A96FF8E9C98FF
+ 8E9C98FF8C9A96FF8C9A96FF909E9AFF8E9C98FF909E9AFF96A4A0FF92A09CFF
+ 98A6A2FFADBCB8FFC6DBD8FFD4EBE7FFD4EBE7FFCBE2DEFFC1D6D3FFA2B7B4FF
+ 8EA19EFF95A8A5FF95A8A5FF90A3A0FF8D9E9BFF8C9D9AFF909E9CFF8F9D9BFF
+ 8A9896FF859391FF869391FF84918FFF859290FF8A9795FF889593FF828F8DFF
+ 7E8B89FF7F8C8AFF7A8785FF7C8987FF828F8DFF879492FF889593FF84918FFF
+ 7E8B89FF7A8884FF818A87FF838D87FF7C8582FF7E8784FF8F9A97FF9BA9A5FF
+ A9B6B4FFBCCAC8FFB0C1BEFFBACDCAFFBFD1D0FFADC2C0FFA2B7B8FFACC1C2FF
+ 9FB4B5FF778D8BFF7D9391FF819894FF849996FF849996FF809592FF7B908DFF
+ 778A87FF728582FF7E8F8CFF7B8C89FF798A87FF7B8C89FF7E8C8AFF798785FF
+ 717F7DFF6C7977FF68716EFF555C59FF5E6562FF666D6AFF656C69FF606764FF
+ 636A67FF656C69FF646B68FF5F6663FF636A67FF717875FF7E8582FF848B88FF
+ 888F8CFF8B9491FF899491FF8C9A96FF919F9BFF94A29EFF95A39FFF97A5A1FF
+ 9BA9A5FF9EACA8FF9AA8A4FF98A6A2FF96A4A0FF95A39FFF95A39FFF98A6A2FF
+ 9BA9A5FF9DABA7FFA5B1ABFFA5B1ABFFA2B0AAFF9FADA7FF9CAAA4FF9AA8A2FF
+ 99A9A2FF9AAAA3FF9AACA5FF9BADA6FF95A7A0FF91A39CFF91A69EFF94A9A1FF
+ ADC2BAFFD4EBE3FFDEF5F1FFDAF3EFFFD6EFEBFFD0E9E5FFC9E2DEFFC7E0DCFF
+ CCE5E1FFD2EBE7FFD0E9E5FFC5DEDAFFC0D9D5FFC5DEDAFFC2DBD7FFB5CECAFF
+ AFC8C4FFB3CCC8FFB3CAC6FFABC2BEFFA0B5B2FF9DB2AFFF96ABA8FF7D928FFF
+ 708380FF7C8F8CFF8A9B98FF80918EFF788986FF7A8B88FF7E8C8AFF7B8987FF
+ 788684FF778682FF8C9D99FF8A9F97FF849991FF7B9088FF7B9088FF849991FF
+ 8BA098FF8BA098FF899E96FF7D928AFF81968EFF8BA098FF859A92FF7E938BFF
+ 788D85FF6D827AFF7D8F88FF7E9089FF81938CFF879992FF8FA19AFF95A7A0FF
+ 97A9A2FF96A8A1FF8B9D96FF8B9D96FF8D9F98FF90A29BFF95A7A0FF9AACA5FF
+ 9FB1AAFFA2B4ADFFB2C4BDFFACBEB7FFABBBB4FFADBFB8FFAEBEB7FFA6B8B1FF
+ A6B6AFFFA7B9B2FFB4C4BDFFB5C7C0FFB9C9C2FFB8CAC3FFB4CBC7FFADC4C0FF
+ A9C0BCFFAAC1BDFFAAC1BDFFA5BCB8FFA1B8B4FFA0B7B3FFA3BAB6FFA5BCB8FF
+ 9EB5B1FF92A9A5FF90A7A3FF97AEAAFF98AFABFF91A8A4FF98B1ADFF8CA5A1FF
+ 889F9BFF8DA4A0FF91A8A4FF8CA39FFF8A9F9CFF8DA29FFF94A7A4FF97AAA7FF
+ 90A3A0FF809390FF788986FF738481FF687976FF5A6B68FF394844FF25332FFF
+ 394743FF53615DFF64726EFF667470FF5F6D69FF768480FF83918DFF7D8B87FF
+ 6E7C78FF62706CFF63716DFF6A7874FF64726EFF576561FF4D5C58FF556460FF
+ 4F5E5AFF465551FF596A66FF839490FF95A6A2FF8D9E9AFF849893FF9DB1ACFF
+ ABC1BCFFA9BFBAFFA7BDB8FFAEC4BFFFAEC5C0FFA7BEB9FF91A4A1FF839693FF
+ 7A8D8AFF7D908DFF7D908DFF788B88FF788B88FF7E918EFF778A87FF758885FF
+ 6F827FFF6A7D7AFF6A7D7AFF6A7D7AFF627572FF586B68FF5E6D69FF566561FF
+ 44534FFF455450FF606F6BFF71807CFF788783FF84938FFF879692FF889793FF
+ 899894FF899894FF889793FF8A9995FF8E9D99FF91A09CFF93A19DFF93A19DFF
+ 8F9D99FF8A9894FF8B9995FF919F9BFF919F9BFF8E9C98FF8B9995FF93A19DFF
+ 94A29EFF95A39FFF9AA8A4FF96A4A0FF9BA9A5FFAEBDB9FFB8CDCAFFD2E9E5FF
+ D6EDE9FFCDE4E0FFC4D9D6FF9EB3B0FF849794FF90A3A0FF93A6A3FF8FA29FFF
+ 8D9E9BFF8D9E9BFF92A09EFF92A09EFF8E9C9AFF899795FF859290FF828F8DFF
+ 83908EFF879492FF869391FF828F8DFF828F8DFF859290FF768381FF74817FFF
+ 788583FF828F8DFF889593FF879492FF859290FF85938FFF88918EFF89938DFF
+ 7F8885FF7C8582FF838E8BFF889692FF94A19FFFAAB8B6FFA8B9B6FFB3C6C3FF
+ BDCFCEFFB1C6C4FFA5BABBFFA7BCBDFF91A6A7FF667C7AFF728886FF7B928EFF
+ 839895FF839895FF819693FF809592FF7E918EFF788B88FF798A87FF778885FF
+ 788986FF7D8E8BFF808E8CFF7B8987FF768482FF768381FF7D8683FF616865FF
+ 6D7471FF636A67FF646B68FF616865FF676E6BFF6D7471FF646B68FF616865FF
+ 676E6BFF777E7BFF818885FF818885FF848B88FF89928FFF919C99FF94A29EFF
+ 97A5A1FF97A5A1FF94A29EFF92A09CFF94A29EFF97A5A1FF9AA8A4FF9AA8A4FF
+ 99A7A3FF98A6A2FF99A7A3FF9BA9A5FF9EACA8FF9FADA9FFA3AFA9FFA2AEA8FF
+ 9EACA6FF9CAAA4FF9AA8A2FF9AA8A2FF9AAAA3FF9BABA4FF95A7A0FF9AACA5FF
+ 99ABA4FF99ABA4FF95AAA2FF8EA39BFFA0B5ADFFC3DAD2FFD7EEEAFFD2EBE7FF
+ D0E9E5FFD0E9E5FFCCE5E1FFC6DFDBFFC5DEDAFFC9E2DEFFCCE5E1FFC5DEDAFF
+ C1DAD6FFC0D9D5FFBDD6D2FFB5CECAFFAEC7C3FFADC6C2FFABC2BEFFA9C0BCFF
+ A3B8B5FFA1B6B3FF98ADAAFF7B908DFF6E817EFF7A8D8AFF81928FFF7A8B88FF
+ 778885FF798A87FF7E8C8AFF7F8D8BFF82908EFF849591FF798A86FF7F948CFF
+ 81968EFF7B9088FF7A8F87FF82978FFF869B93FF839890FF8EA39BFF8EA39BFF
+ 98ADA5FF99AEA6FF8EA39BFF93A8A0FFA3B8B0FFA7BCB4FFB9CEC6FFBACFC7FF
+ B9CEC6FFB3C8C0FFAABFB7FFA5BAB2FFA7BCB4FFAABFB7FFBACFC7FFBBD0C8FF
+ BDD2CAFFC1D6CEFFC6DBD3FFCCE1D9FFD1E6DEFFD4E9E1FFD2E7DFFFD2E7DFFF
+ DEF0E9FFEAFFF7FFEEFFF9FFE2F7EFFFDEF0E9FFDEF3EBFFE4F6EFFFE8FDF5FF
+ EDFFF8FFEAFFF7FFC0D7D3FFB5CCC8FFABC2BEFFA7BEBAFFA2B9B5FF9AB1ADFF
+ 98AFABFF9BB2AEFFA2B9B5FFA6BDB9FFA3BAB6FF98AFABFF94ABA7FF98AFABFF
+ 94ABA7FF8BA29EFF95AEAAFF859E9AFF7C938FFF869D99FF98AFABFF9EB5B1FF
+ 92A7A4FF849996FF819491FF849794FF7C8F8CFF6E817EFF677875FF647572FF
+ 596A67FF4A5B58FF2F3E3AFF253430FF3E4D49FF53625EFF63726EFF697874FF
+ 62716DFF73827EFF788783FF7E8D89FF798884FF6E7D79FF6E7D79FF798884FF
+ 7A8985FF707F7BFF677672FF71807CFF697874FF586763FF647571FF8C9D99FF
+ 9FB0ACFF98A9A5FF8EA29DFF9EB2ADFFADC3BEFFB3C9C4FFB1C7C2FFAEC4BFFF
+ ABC2BDFFA9C0BBFF99ACA9FF899C99FF809390FF869996FF8B9E9BFF889B98FF
+ 8A9D9AFF91A4A1FF91A4A1FF91A4A1FF8A9D9AFF7D908DFF738683FF6C7F7CFF
+ 637673FF5B6E6BFF667571FF677672FF4A5955FF3A4945FF586763FF73827EFF
+ 798884FF81908CFF869591FF889793FF899894FF879692FF859490FF859490FF
+ 879692FF899894FF96A4A0FF97A5A1FF919F9BFF8A9894FF8A9894FF919F9BFF
+ 919F9BFF8C9A96FF8C9A96FF98A6A2FF9AA8A4FF97A5A1FF99A7A3FF94A29EFF
+ 99A7A3FFABBAB6FFACC1BEFFCCE3DFFFD1E8E4FFCDE4E0FFCCE1DEFFA4B9B6FF
+ 819693FF8CA19EFF90A3A0FF8DA09DFF8B9C99FF8D9E9BFF90A19EFF91A29FFF
+ 909E9CFF8C9A98FF899694FF84918FFF828F8DFF83908EFF828F8DFF7F8C8AFF
+ 808D8BFF84918FFF768381FF73807EFF768381FF7E8B89FF818E8CFF7F8C8AFF
+ 83908EFF8A9894FF8A9390FF8E9892FF87908DFF818A87FF7F8A87FF7B8985FF
+ 879492FFA0AEACFFA7B8B5FFAEC1BEFFBACCCBFFB4C9C7FFA6BBBCFF9EB3B4FF
+ 819697FF556B69FF6D8381FF788F8BFF7F9491FF7E9390FF7E9390FF829794FF
+ 859895FF819491FF7A8B88FF788986FF7C8D8AFF829390FF83918FFF7B8987FF
+ 788684FF7D8A88FF88918EFF676E6BFF79807DFF646B68FF69706DFF666D6AFF
+ 6B726FFF717875FF616865FF606764FF6A716EFF7C8380FF828986FF7D8481FF
+ 7F8683FF87908DFF8F9A97FF92A09CFF97A5A1FF96A4A0FF92A09CFF919F9BFF
+ 94A29EFF97A5A1FF9DABA7FF9DABA7FF9DABA7FF9DABA7FF9DABA7FF9DABA7FF
+ 9DABA7FF9EACA8FF9EAAA4FF9EAAA4FF9CAAA4FF9CAAA4FF9DABA5FF9DABA5FF
+ 9CACA5FF9BABA4FF96A8A1FF9AACA5FF9AACA5FF9CAEA7FF97ACA4FF8CA199FF
+ 9CB1A9FFC0D7CFFFD5ECE8FFCCE5E1FFCAE3DFFFCCE5E1FFCBE4E0FFC3DCD8FF
+ BFD8D4FFC0D9D5FFC4DDD9FFC5DEDAFFC1DAD6FFBBD4D0FFB9D2CEFFB8D1CDFF
+ B3CCC8FFACC5C1FFA9C0BCFFA8BFBBFFA5BAB7FFA8BDBAFFA2B7B4FF849996FF
+ 738683FF7C8F8CFF8A9B98FF899A97FF8C9D9AFF92A3A0FF96A4A2FF96A4A2FF
+ 9CAAA8FFA2B3AFFFAFC0BCFFBFD4CCFFC9DED6FFC7DCD4FFC8DDD5FFD3E8E0FF
+ DAEFE7FFD8EDE5FFC4D9D1FFBFD4CCFFBBD0C8FFAEC3BBFFA4B9B1FFBACFC7FF
+ D6EBE3FFDBF0E8FFD7EEE6FFDAF1E9FFD6EDE5FFC3DAD2FFADC4BCFFA3BAB2FF
+ A9C0B8FFB4CBC3FFC1D8D0FFC2D9D1FFC4DBD3FFC8DFD7FFCDE4DCFFD3EAE2FF
+ D8EFE7FFDCF3EBFFBFD6CEFFBCD3CBFFC7DCD4FFD9F0E8FFE4F9F1FFDBF2EAFF
+ D8EDE5FFD8EFE7FFDEF3EBFFE4FBF3FFE9FEF6FFE2F9F1FFC5DCD8FFB7CECAFF
+ ABC2BEFFA5BCB8FF9DB4B0FF94ABA7FF93AAA6FF99B0ACFF99B0ACFFA4BBB7FF
+ A7BEBAFF9FB6B2FF9AB1ADFF9AB1ADFF96ADA9FF8DA4A0FF809793FF879E9AFF
+ 8CA39FFF8FA4A1FF8FA4A1FF90A5A2FF8FA4A1FF8EA19EFF778A87FF7E8F8CFF
+ 7B8C89FF71827FFF6C7D7AFF687674FF596765FF465452FF2A3935FF293834FF
+ 455450FF556460FF61706CFF687773FF61706CFF707F7BFF64736FFF798884FF
+ 859490FF7F8E8AFF7E8D89FF879894FF8D9C98FF869591FF83928EFF81908CFF
+ 81908CFF84938FFF899A96FF93A4A0FF9FB0ACFFA8B9B5FF95A9A4FF94A8A3FF
+ 9CB2ADFFABC1BCFFAAC0BBFFA0B6B1FF9FB6B1FFAAC0BBFFA9BCB9FF96A9A6FF
+ 8C9F9CFF92A5A2FF96A9A6FF90A3A0FF8EA19EFF93A6A3FF8A9D9AFF8FA29FFF
+ 8FA29FFF839693FF768986FF708380FF6E817EFF6E7F7CFF6A7876FF71807CFF
+ 505F5BFF374642FF566561FF778682FF7D8C88FF81908CFF8B9A96FF8B9C98FF
+ 8D9E9AFF8D9E9AFF8B9C98FF8A9B97FF8B9C98FF8D9E9AFF9CABA7FF9CABA7FF
+ 95A4A0FF8A9995FF889793FF8D9C98FF8C9B97FF859490FF859490FF91A29EFF
+ 95A4A0FF8E9F9BFF8B9C98FF859692FF8A9B97FF9DAEAAFFABC0BDFFCEE3E0FF
+ D2E9E5FFD2E9E5FFD8EFEBFFB2C9C5FF89A09CFF92A9A5FF8BA29EFF889D9AFF
+ 869B98FF8A9D9AFF8EA19EFF92A3A0FF8FA09DFF8D9B99FF8F9C9AFF889593FF
+ 83908EFF818E8CFF7E8B89FF7A8785FF7B8886FF7F8C8AFF7A8785FF788583FF
+ 7B8886FF7D8A88FF798684FF74817FFF7C8987FF899793FF868F8CFF909792FF
+ 8E9592FF87908DFF838C89FF7A8582FF84918FFF9FADABFF9EACAAFFA3B4B1FF
+ B1C3C2FFB3C8C6FFA8BDBEFF9DB2B3FF809596FF586E6CFF7A908EFF829794FF
+ 849996FF7C918EFF788D8AFF7C918EFF7F928FFF7C8F8CFF859693FF849592FF
+ 899A97FF8D9E9BFF889996FF7D8E8BFF7D8B89FF82908EFF7C8785FF5C6562FF
+ 77807DFF626B68FF6A7370FF646D6AFF636A67FF656C69FF59605DFF5B625FFF
+ 666F6CFF79827FFF7E8784FF77817BFF7A8380FF838E8BFF848F8CFF899793FF
+ 909E9AFF93A19DFF93A19DFF94A29EFF9AA8A4FFA0AEAAFF99A7A3FF99A7A3FF
+ 9AA8A4FF99A7A3FF99A7A3FF97A5A1FF96A4A0FF97A29FFF9AA6A0FF9BA7A1FF
+ 9EAAA4FFA1ADA7FFA3AFA9FFA0AEA8FF9EACA6FF9AAAA3FF9EAEA7FF9CAEA7FF
+ 99ABA4FF99ABA4FF96A8A1FF8DA29AFFA3B8B0FFCCE2DDFFD9F0ECFFCDE6E2FF
+ CAE1DDFFCBE4E0FFCBE2DEFFC1DAD6FFBCD3CFFFBAD3CFFFC0D7D3FFC4DDD9FF
+ C3DAD6FFB8D1CDFFB9D0CCFFBCD5D1FFBAD1CDFFAEC5C1FFA4B9B6FFA5B9B4FF
+ A2B5B2FFA9BDB8FFAABBB8FF8D9E9AFF758683FF7A8B87FFA9B7B5FFABBAB6FF
+ AFBDBBFFB2C1BDFFAEBBB9FFA7B5B1FFA9B6B4FFAFBEBAFFA2B4ADFFB5CAC1FF
+ C2D7CFFFC1D6CEFFC6DBD3FFD8EDE5FFE7FCF4FFEAFFF7FFDAEFE7FFC4D9D1FF
+ A8BDB5FF8FA49CFF8FA49CFFAEC5BDFFC7DCD4FFBBD1CCFFB8CEC9FFBDD4CFFF
+ BBD2CDFFA9C0BBFF92A9A4FF8DA49FFF9FB6B1FFB4CBC6FFAEC5C0FFAFC6C1FF
+ B1C8C3FFB5CCC7FFBAD1CCFFC0D7D2FFC6DDD8FFC9E0DBFFD6EDE5FFC6DDD5FF
+ C2D9D1FFCFE6DEFFD9F0E8FFD4EBE3FFD0E7DFFFD2E9E1FFCCE3DBFFD4EBE3FF
+ D7EEE6FFD0E7DFFFBAD1CDFFC1D8D4FFC0D7D3FFB1C8C4FF9FB6B2FF95ACA8FF
+ 91A8A4FF8EA5A1FF8DA4A0FF9DB4B0FFA7BEBAFFA4BBB7FF9CB3AFFF95ACA8FF
+ 8AA19DFF7F9692FF6C817EFF7E9390FF849996FF798C89FF718481FF798C89FF
+ 809390FF81928FFF768784FF859391FF849290FF879593FF6B7977FF63706EFF
+ 7C8987FF5F6C6AFF35433FFF33413DFF54625EFF5F6D69FF5E6C68FF6C7A76FF
+ 72817DFF81908CFF6E7F7BFF778884FF80918DFF82938FFF7E8F8BFF798D88FF
+ 7E8F8BFF82938FFF91A09CFF97A6A2FF93A4A0FF899A96FF879894FF8FA09CFF
+ 98A9A5FF9BACA8FF99ADA8FF9CB0ABFF9FB3AEFF9FB3AEFF9EB4AFFFA0B6B1FF
+ A2B8B3FFA2B8B3FF96A9A6FF94A6A5FF8EA09FFF889A99FF889A99FF889A99FF
+ 859796FF7F9190FF7D8F8EFF849695FF899B9AFF879998FF7C8E8DFF708281FF
+ 687A79FF677875FF64716FFF64716FFF5D6A68FF556260FF5A6866FF6A7876FF
+ 728380FF728380FF839491FF8A9D9AFF8BA09DFF849996FF819894FF879E9AFF
+ 8BA29EFF8A9F9CFF98ABA8FF9CADAAFF9EB1AEFFA1B4B1FFA4B7B4FFA9BCB9FF
+ ADC2BFFFB2C7C4FFB4C9C6FFAFC6C2FFBDD2CFFFCBE2DEFFCAE1DDFFC3DAD6FF
+ B1C8C4FF98AFABFFA4B7B4FFBDD0CDFFD5EAE7FFDBF2EEFFD0E9E5FFC5E0DCFF
+ C6E1DDFFC9E7E2FFB8D6D1FFA5C0BCFF90A9A5FF859C98FF849996FF889B98FF
+ 8C9D9AFF8E9F9CFF919F9DFF859391FF859391FF889694FF83918FFF849290FF
+ 808E8CFF717F7DFF7A8886FF788684FF7A8886FF7F8D8BFF7C8A88FF778583FF
+ 7B8987FF869490FF868D8AFF888E89FF868B89FF909794FFA0A7A4FF969F9CFF
+ 808B89FF7A8785FF899795FF859693FF9EB0AFFFB3C8C6FFACC1C2FFA3B8B9FF
+ 899E9FFF5B716FFF8CA19FFF889B98FF7E918EFF7A8D8AFF809390FF879A97FF
+ 849794FF7B8E8BFF849794FF819491FF7F928FFF7D908DFF7D908DFF7E918EFF
+ 80918EFF80918EFF7D8E8BFF495755FF6A7775FF657270FF6A7573FF5D6866FF
+ 5F6865FF606966FF58625CFF5E6862FF69756FFF76827CFF7A8882FF78877FFF
+ 74847DFF73837CFF83918DFF8B9693FF929D9AFF96A19EFF98A3A0FF98A3A0FF
+ 99A4A1FF9AA5A2FF9FAAA7FF9EA9A6FF9EA9A6FF9DA8A5FF9CA7A4FF9BA6A3FF
+ 9AA5A2FF9AA5A2FFA0A7A4FF9FA6A3FF9FA6A3FF9DA6A3FF9EA7A4FF9DA8A5FF
+ 9EA9A6FF9DABA7FF96A4A0FF96A5A1FF9EADA9FF93A4A0FF95A6A2FF97A8A4FF
+ 91A5A0FFB1C5C0FFCEE3E0FFC7DEDAFFC3D8D5FFC3DAD6FFC8DDDAFFC7DEDAFF
+ C1D6D3FFB7CECAFFB6CBC8FFB2C9C5FFB4C9C6FFB8CFCBFFB9CECBFFB2C9C5FF
+ ADC2BFFFAEC1BEFFBAC9C5FFBAC8C2FFB3C1BDFFB4C2BCFFBAC5C2FFADB9B3FF
+ A3AEABFFABB7B1FF9EA9A6FF9AA6A0FF95A09DFF94A09AFF95A09DFF94A09AFF
+ 919C99FF8D9993FF9DAEA5FF99ADA1FFADC0B7FFC2D5CCFFC2D5CCFFCBDED5FF
+ E1F6EDFFEFFFFBFFDFF6EEFFC1D8D0FF8DA39EFF7F9590FFA2B8B3FFB6CDC8FF
+ BBD1CCFFC8DFDBFFBBD4D0FFBDD6D2FFBDD6D2FFB9D2CEFFB4CDC9FFB4CDC9FF
+ B9D2CEFFBED7D3FFB1CAC6FFB1CAC6FFB3CCC8FFB7D0CCFFBBD4D0FFBDD6D2FF
+ BED7D3FFBDD6D2FFC0D7D2FFC5DCD7FFCBE2DDFFD0E7E2FFD2E9E4FFD4EBE6FF
+ D6EDE8FFD9F0EBFFD3EAE5FFD3EAE5FFD2E9E4FFD2E9E4FFA3BAB6FFB2C9C5FF
+ BDD4D0FFB8CFCBFFAAC1BDFF9DB4B0FF91A8A4FF89A09CFFA5BCB8FFA1B8B4FF
+ 9AB1ADFF9BB2AEFFA3BAB6FFA7BEBAFF98AFABFF849B97FF778A87FF7E918EFF
+ 7F928FFF778A87FF70817EFF6E7F7CFF6B7C79FF677875FF6C7A78FF798785FF
+ 7F8C8AFF899694FF758280FF687573FF747F7DFF525D5BFF36413EFF333E3BFF
+ 54625EFF64726EFF65736FFF6E7C78FF687773FF6D7C78FF6D7E7AFF72837FFF
+ 788985FF7B8C88FF7A8E89FF7B8F8AFF7D918CFF7F938EFF879894FF93A29EFF
+ 96A7A3FF91A29EFF8D9E9AFF8FA09CFF90A19DFF8E9F9BFF8FA39EFF97ABA6FF
+ 9FB3AEFF9FB3AEFF9CB2ADFF9BB1ACFF9AB0ABFF98AEA9FF99ACA9FF96A8A7FF
+ 94A6A5FF94A6A5FF92A4A3FF8B9D9CFF839594FF7E908FFF859796FF809291FF
+ 788A89FF718382FF6D7F7EFF6E807FFF718382FF778786FF8B9896FF8C9997FF
+ 869391FF788684FF707E7CFF717F7DFF70817EFF6E7F7CFF859895FF8FA29FFF
+ 93A8A5FF98AFABFFACC3BFFFBCD5D1FFB5CCC8FF9DB4B0FFD5EAE7FFD9ECE9FF
+ D9EEEBFFDBF0EDFFDCF1EEFFDFF4F1FFE3FAF6FFE7FEFAFFE5FEFAFFDFF8F4FF
+ E6FFFBFFEAFFFFFFE5FFFCFFE6FFFDFFE6FFFDFFDDF6F2FFB8CBC8FFBED1CEFF
+ CCDFDCFFD6EDE9FFD7F0ECFFD1ECE8FFD0EEE9FFD3F3EEFFCCECE7FFC0DED9FF
+ ADC8C4FF9CB5B1FF90A7A3FF8A9F9CFF8FA09DFF93A4A1FF919F9DFF859391FF
+ 859391FF879593FF82908EFF83918FFF818F8DFF73817FFF748280FF717F7DFF
+ 748280FF7B8987FF7E8C8AFF7D8B89FF82908EFF8B9995FF929996FF909691FF
+ 8A8F8DFF919895FF9FA6A3FF959E9BFF889391FF8C9997FF8D9B99FF7B8C89FF
+ 859796FF9DB2B0FFA8BDBEFFAABFC0FF8A9FA0FF546A68FF8CA19FFF8A9D9AFF
+ 829592FF7A8D8AFF7A8D8AFF7C8F8CFF778A87FF6E817EFF768986FF778A87FF
+ 798C89FF7C8F8CFF7F928FFF809390FF7E918EFF7D908DFF7B8D8CFF425251FF
+ 616F6DFF616F6DFF616E6CFF5C6765FF636C69FF5C6562FF5B655FFF636D67FF
+ 6E7A74FF77857FFF7A8981FF77887FFF73867DFF73867DFF8A9894FF919C99FF
+ 97A29FFF9BA6A3FF9DA8A5FF9DA8A5FF9DA8A5FF9EA9A6FF9DA8A5FF9DA8A5FF
+ 9DA8A5FF9DA8A5FF9EA9A6FF9EA9A6FF9EA9A6FF9EA9A6FF9EA5A2FF9EA5A2FF
+ 9EA5A2FF9FA6A3FF9DA6A3FF9DA6A3FF9BA6A3FF9BA6A3FF96A4A0FF99A7A3FF
+ 9AA9A5FF909F9BFF93A4A0FF8D9E9AFF839792FFACC0BBFFC0D3D0FFC6DBD8FF
+ C8DDDAFFC2D7D4FFBFD4D1FFC1D6D3FFBCD1CEFFB2C7C4FFC1D6D3FFB7CCC9FF
+ AEC3C0FFA9BEBBFFA5BAB7FFA4B9B6FFA9BEBBFFB5C6C2FFACB8B2FFADB7B1FF
+ A4AEA8FFA1ABA5FFA2ACA6FF939D97FF88928CFF8F9993FF8D9791FF8F9993FF
+ 939D97FF98A29CFF99A39DFF97A19BFF919B95FF8A978FFF96A59DFF94A59AFF
+ A2B6AAFFB2C6BAFFB5C8BFFFC5D8CFFFDDF2E9FFE9FEF5FFE7FEF6FFBDD4CCFF
+ 94AAA5FF95ABA6FFADC4BFFFB4CBC6FFB3CAC6FFBDD4D0FFCFE7E5FFC8E3E0FF
+ C4DCDAFFBBD6D3FFBBD3D1FFBCD7D4FFC3DBD9FFC6E1DEFFC1D9D7FFBAD5D2FF
+ B6CECCFFB1CCC9FFB4CCCAFFB6D1CEFFBED6D4FFC1DAD6FFC6DDD8FFCBE2DDFF
+ D0E7E2FFD4EBE6FFD5ECE7FFD6EDE8FFD8EFEAFFDAF1ECFFD7EEE9FFD5ECE7FF
+ D1E8E3FFCEE5E0FFA1B8B4FFABC2BEFFB1C8C4FFABC2BEFFA2B9B5FF9CB3AFFF
+ 99B0ACFF96ADA9FFA4BBB7FF9CB3AFFF92A9A5FF93AAA6FF9FB6B2FFA8BFBBFF
+ A2B9B5FF95ACA8FF90A3A0FF889B98FF819491FF7D908DFF798A87FF70817EFF
+ 6B7C79FF6B7C79FF717F7DFF798785FF7F8C8AFF8B9896FF7E8B89FF707D7BFF
+ 707B79FF545F5DFF394441FF343F3CFF54625EFF667470FF6A7874FF72807CFF
+ 677672FF677672FF70817DFF70817DFF71827EFF768783FF7B8F8AFF80948FFF
+ 819590FF80948FFF849591FF8D9E9AFF93A4A0FF91A29EFF8D9E9AFF8B9C98FF
+ 8A9B97FF889995FF8EA29DFF9DB1ACFFA9BDB8FFABBFBAFFA9BDB8FFA8BCB7FF
+ A7BBB6FFA3B7B2FF9CAFACFF8DA09DFF819491FF7F928FFF7E918EFF7C8F8CFF
+ 819491FF8B9E9BFF7C8F8CFF7F928FFF879A97FF94A7A4FFA4B7B4FFB2C5C2FF
+ BBCECBFFC1D2CFFFC4D2D0FFCBD9D7FFCDDBD9FFC9D7D5FFC6D4D2FFC8D9D6FF
+ CDDEDBFFCFE0DDFFD5E8E5FFE2F5F2FFE6F9F6FFDDF2EFFFDCF1EEFFE3FAF6FF
+ E1F6F3FFD4E9E6FFD5E8E5FFD7EAE7FFD8EDEAFFD9EEEBFFDAEFECFFDCF1EEFF
+ DFF6F2FFE3FAF6FFE9FFFEFFE3FCF8FFE8FFFDFFE7FFFCFFDCF7F3FFE0FBF7FF
+ E8FFFFFFEAFFFFFFD5E8E5FFC4D7D4FFBFD2CFFFCDE4E0FFD8F1EDFFD5F0ECFF
+ D3F1ECFFD8F6F1FFD7F5F0FFD2F0EBFFC6E1DDFFB1CAC6FF9CB3AFFF8EA3A0FF
+ 8FA09DFF91A29FFF919F9DFF869492FF879593FF889694FF818F8DFF818F8DFF
+ 82908EFF778583FF73817FFF6F7D7BFF707E7CFF768482FF7D8B89FF808E8CFF
+ 83918FFF899793FF969F9CFF929994FF8A918EFF919A97FF9FA8A5FF9AA5A2FF
+ 9BA8A6FFAFBDBBFF9CADAAFF8B9E9BFF8EA09FFF9CB1AFFFA7BCBDFFA8C0C0FF
+ 8EA6A6FF667C7AFF829795FF869996FF849794FF7E918EFF7A8D8AFF7A8D8AFF
+ 778A87FF718481FF6F827FFF718481FF768986FF7C8F8CFF819491FF809390FF
+ 7B8E8BFF768986FF80908FFF445453FF5F6D6BFF687573FF5E6967FF5C6765FF
+ 69726FFF5B625FFF575E59FF626C66FF707C76FF788680FF7A8981FF7A8B82FF
+ 7B8E85FF7E9188FF889692FF8C9A96FF92A09CFF95A39FFF96A4A0FF96A4A0FF
+ 96A4A0FF97A5A1FF93A19DFF93A19DFF94A29EFF95A39FFF96A4A0FF97A5A1FF
+ 98A6A2FF9AA5A2FF9CA3A0FF9DA4A1FF9EA5A2FF9DA6A3FF9DA6A3FF9CA5A2FF
+ 98A3A0FF97A29FFF96A4A0FF9AA8A4FF96A5A1FF8C9B97FF94A5A1FF859692FF
+ 7A8B87FFADC1BCFFBBCFCAFFC9DDD8FFCFE3DEFFC4D8D3FFB9CDC8FFB6CAC5FF
+ B1C5C0FFAABEB9FFB4C8C3FFABBFBAFFA1B5B0FF99ADA8FF92A6A1FF92A6A1FF
+ 9CB0ABFFABBCB8FFA1ADA7FFA4AEA8FF9BA59FFF959F99FF949E98FF86908AFF
+ 7B857FFF828C86FF848E88FF89938DFF8F9993FF939D97FF929C96FF8F9993FF
+ 8C9690FF88958DFF8C9B93FF8E9F94FF9DAEA3FFA9BAAFFFAFC2B9FFC6D9D0FF
+ DAEFE6FFDCF1E8FFE5FAF2FFBBD0C8FFA5BBB6FFADC3BEFFAAC1BCFFA2B9B4FF
+ A9C0BCFFB4CBC7FFC1D8D4FFC1DAD6FFC6DDD9FFC9E2DEFFD0E7E3FFD0E9E5FF
+ D0E7E3FFCCE5E1FFD1E8E4FFCBE4E0FFC7DEDAFFBFD8D4FFBFD6D2FFBED7D3FF
+ C4DBD7FFC6DDD9FFC1D8D3FFC5DCD7FFCBE2DDFFD0E7E2FFD2E9E4FFD4EBE6FF
+ D7EEE9FFD9F0EBFFE0F7F2FFDEF5F0FFDBF2EDFFD8EFEAFFA5BCB8FFACC3BFFF
+ AEC5C1FFA6BDB9FF9EB5B1FF9CB3AFFF9CB3AFFF9AB1ADFF8FA6A2FF97AEAAFF
+ 9EB5B1FF9DB4B0FF9AB1ADFF9CB3AFFFA5BCB8FFACC3BFFFA5B8B5FF94A7A4FF
+ 899C99FF899C99FF869794FF7B8C89FF7D8E8BFF899A97FF758381FF768482FF
+ 778482FF788583FF6E7B79FF616E6CFF5F6A68FF576260FF3F4A47FF394441FF
+ 576561FF65736FFF697773FF74827EFF707F7BFF758480FF788985FF738480FF
+ 71827EFF758682FF7D918CFF849893FF849893FF819590FF869793FF8A9B97FF
+ 8C9D99FF8A9B97FF869793FF869793FF8A9B97FF8D9E9AFF819590FF92A6A1FF
+ 9EB2ADFF9DB1ACFF99ADA8FF9BAFAAFF9BAFAAFF98ACA7FF97AAA7FF889B98FF
+ 819491FF889B98FF8FA29FFF94A7A4FFA3B6B3FFB6C9C6FFBBCECBFFC2D5D2FF
+ CCDFDCFFD6E9E6FFDDF0EDFFE0F3F0FFE0F3F0FFDFF2EFFFDBECE9FFDDEEEBFF
+ DEEFECFFDEEFECFFDFF0EDFFE1F2EFFFE2F3F0FFE1F2EFFFD8EBE8FFD0E3E0FF
+ CADDDAFFC9DCD9FFCADDDAFFCFE2DFFFDAEDEAFFE5F8F5FFE2F5F2FFE5F8F5FF
+ E6FBF8FFE8FDFAFFE9FEFBFFECFFFEFFECFFFFFFECFFFFFFE3FCF8FFDFF8F4FF
+ E5FEFAFFE6FFFBFFDAF5F1FFDCF7F3FFE5FFFCFFE5FEFAFFEBFEFBFFCADDDAFF
+ B7CCC9FFC5DCD8FFD3EAE6FFCDE6E2FFC8E3DFFFCEECE7FFCFEDE8FFD4EFEBFF
+ D0E9E5FFBFD8D4FFADC2BFFF9DB2AFFF94A7A4FF90A19EFF93A19FFF899795FF
+ 8A9896FF8A9896FF808E8CFF808E8CFF82908EFF798785FF778583FF72807EFF
+ 707E7CFF73817FFF798785FF7D8B89FF7E8C8AFF808E8AFF87928FFF828C86FF
+ 79827FFF7E8986FF8C9794FF8C9A96FF96A4A2FFAFC0BDFFB0C3C0FFB0C5C2FF
+ B2C7C5FFACC2C0FFA0B8B8FF99B1B1FF8FA7A7FF839997FF6C817FFF788B88FF
+ 7F928FFF7E918EFF7C8F8CFF7E918EFF809390FF7F928FFF788B88FF788B88FF
+ 798C89FF7D908DFF809390FF7E918EFF778A87FF708380FF7B8B8AFF4C5A59FF
+ 616E6CFF737E7CFF596462FF58605FFF69706DFF545B58FF4B524DFF5D645FFF
+ 6F7973FF77837DFF7C8981FF829189FF8A9B92FF8FA097FF869490FF8A9894FF
+ 8F9D99FF919F9BFF919F9BFF919F9BFF919F9BFF93A19DFF919F9BFF919F9BFF
+ 92A09CFF93A19DFF94A29EFF94A29EFF95A39FFF97A29FFF9AA3A0FF9CA5A2FF
+ 9EA7A4FF9FA8A5FF9EA7A4FF9AA5A2FF97A29FFF93A19DFF95A39FFF9AA8A4FF
+ 96A5A1FF8F9E9AFF9AABA7FF8A9B97FF7E8F8BFFB9CAC6FFC2D3CFFFC1D2CEFF
+ C2D3CFFFBECFCBFFAFC0BCFF9EAFABFF98A9A5FF9BACA8FF99AAA6FF99AAA6FF
+ 9AABA7FF9AABA7FF92A39FFF8C9D99FF90A19DFF9BAAA6FF9BA7A1FFA2ACA6FF
+ 9AA49EFF939D97FF949E98FF8A948EFF828C86FF89938DFF8C9690FF8E9892FF
+ 8D9791FF89938DFF858F89FF838D87FF87918BFF89968EFF86958DFF8B9C91FF
+ 9AABA0FFA5B6ABFFAFC2B9FFCDE0D7FFE1F4EBFFD9EEE5FFD7ECE4FFC0D5CDFF
+ BFD5D0FFBDD3CEFFA0B7B2FF96ADA8FFA4BBB7FFA6BDB9FFAEC5C1FFB3CAC6FF
+ BCD1CEFFC3DAD6FFCBE0DDFFCEE5E1FFD0E5E2FFD0E7E3FFCCE1DEFFCFE6E2FF
+ D4E9E6FFD3EAE6FFD1E6E3FFCBE2DEFFC7DCD9FFC4DBD7FFCAE1DCFFCDE4DFFF
+ D0E7E2FFD1E8E3FFD2E9E4FFD2E9E4FFD5ECE7FFD7EEE9FFE3FAF5FFE4FBF6FF
+ E5FCF7FFE6FDF8FF9FB6B2FFACC3BFFFB7CECAFFB6CDC9FFAEC5C1FFA3BAB6FF
+ 95ACA8FF8AA19DFF8CA39FFF9BB2AEFFAAC1BDFFACC3BFFFA1B8B4FF9BB2AEFF
+ A2B9B5FFAEC5C1FFA3B6B3FF96A9A6FF92A5A2FF96A9A6FF8E9F9CFF7D8E8BFF
+ 7F908DFF8FA09DFF83918FFF82908EFF859290FF7F8C8AFF74817FFF657270FF
+ 5F6A68FF6B7674FF3E4946FF3D4845FF5F6D69FF6C7A76FF6A7874FF73817DFF
+ 71807CFF7A8985FF7C8D89FF778884FF748581FF768783FF7B8F8AFF80948FFF
+ 819590FF7F938EFF7F938EFF829691FF869A95FF879B96FF859994FF849893FF
+ 889C97FF8DA19CFF829691FF92A6A1FF9AAEA9FF96AAA5FF97ABA6FFA2B6B1FF
+ ABBCB8FFA9BAB6FFAFC0BDFFB0C1BEFFBCCDCAFFCFE0DDFFD8E9E6FFD7E8E5FF
+ DAEBE8FFE2F3F0FFEEFFFCFFEFFFFDFFEEFFFCFFE9FAF7FFE3F4F1FFDFF0EDFF
+ DFF0EDFFDFF2EFFFE3F6F3FFDAEDEAFFCFE2DFFFC8DBD8FFBDD0CDFFA8BBB8FF
+ 8EA19EFF7B8E8BFF80918EFF5B6C69FF566764FF869794FFB8C9C6FFCADBD8FF
+ D2E3E0FFDEEFECFFE0F3F0FFE3F6F3FFE4F9F6FFE5FAF7FFE5FAF7FFE5FAF7FF
+ E7FEFAFFE9FFFCFFE6FFFBFFDFF8F4FFE4FDF9FFE7FFFCFFDEF9F5FFE3FEFAFF
+ E8FFFFFFE8FFFDFFEDFFFFFFCEE1DEFFB7CCC9FFC0D7D3FFC9E0DCFFC0D9D5FF
+ BDD8D4FFC6E1DDFFCCE7E3FFD1ECE8FFD3ECE8FFCBE4E0FFC3D8D5FFB7CCC9FF
+ A5B8B5FF94A7A4FF93A4A1FF8B9C99FF8E9F9CFF8C9D9AFF80918EFF7E8F8CFF
+ 80918EFF798A87FF778885FF738481FF6F807DFF6F807DFF748582FF7A8B88FF
+ 7B8C89FF7B8A86FF92A09CFF8E9A94FF818C89FF818F8BFF919F9BFF98A7A3FF
+ A0B1AEFFB3C6C3FFBED1CEFFC6DBD8FFC0D6D4FFAAC2C0FF98B0B0FF89A3A3FF
+ 859F9FFF8BA3A1FF607573FF708380FF7C8F8CFF7D908DFF7A8D8AFF7C8F8CFF
+ 809390FF829592FF859895FF809390FF7D908DFF7D908DFF7F928FFF7E918EFF
+ 798C89FF758683FF748281FF586464FF616E6CFF778280FF575F5EFF515756FF
+ 5D6461FF4C514FFF474D48FF5A615CFF6F7671FF76807AFF7B8880FF86958DFF
+ 91A098FF97A69EFF8F9D99FF92A09CFF95A39FFF97A5A1FF96A4A0FF95A39FFF
+ 96A4A0FF97A5A1FF98A6A2FF98A6A2FF98A6A2FF98A6A2FF98A6A2FF98A6A2FF
+ 98A6A2FF98A6A2FF99A4A1FF9BA6A3FF9DA8A5FF9EA9A6FF9DA8A5FF9BA6A3FF
+ 98A3A0FF94A29EFF94A29EFF94A39FFF96A5A1FF94A39FFF9EAFABFF95A6A2FF
+ 8B9C98FFBDCECAFFC1D0CCFFAAB9B5FFA3B2AEFFAEBDB9FFA6B5B1FF8C9B97FF
+ 859490FF93A29EFF909F9BFF95A4A0FF9EADA9FFA2B1ADFF9BAAA6FF909F9BFF
+ 8D9C98FF92A09CFF919D97FF9BA59FFF949E98FF8B958FFF8C9690FF858F89FF
+ 7F8983FF86908AFF8E9892FF8F9993FF8E9892FF89938DFF838D87FF828C86FF
+ 858F89FF88958DFF87968EFF86978CFF8FA095FF97A89DFFA7B8AFFFCBDED5FF
+ E7FAF1FFE5F8EFFFD7ECE4FFD2E7DFFFD6ECE7FFCCE2DDFFB3C9C4FFB1C7C2FF
+ AABFBCFF8BA09DFFA2B7B4FFA3B8B5FFA4B7B4FFA1B6B3FFA6B9B6FFACC1BEFF
+ BBCECBFFC2D7D4FFC6D9D6FFCCE1DEFFD8EBE8FFDCF1EEFFDEF1EEFFD7ECE9FF
+ D5E8E5FFD1E6E3FFD4EBE6FFD4EBE6FFD3EAE5FFD1E8E3FFCFE6E1FFCFE6E1FF
+ D2E9E4FFD5ECE7FFDDF4EFFFE0F7F2FFE5FCF7FFEAFFFCFFA7BEBAFFB1C8C4FF
+ B7CECAFFB4CBC7FFADC4C0FFA5BCB8FF9BB2AEFF91A8A4FF98AFABFF9AB1ADFF
+ A1B8B4FFA8BFBBFFA6BDB9FF9DB4B0FF97AEAAFF96ADA9FF9CAFACFF98ABA8FF
+ 9CAFACFFA2B5B2FF98A9A6FF829390FF7B8C89FF839491FF859391FF869492FF
+ 929F9DFF8E9B99FF889593FF74817FFF636E6CFF7C8785FF3A4542FF3F4A47FF
+ 667470FF75837FFF6F7D79FF72807CFF6C7B77FF72817DFF788985FF788985FF
+ 788985FF778884FF768A85FF778B86FF7A8E89FF7C908BFF788C87FF7D918CFF
+ 879B96FF8FA39EFF8DA19CFF879B96FF869A95FF8A9E99FF889C97FF96AAA5FF
+ 9EB2ADFF9FB3AEFFADC1BCFFC8DCD7FFDBECE8FFDBECE8FFE2F3F0FFE4F5F2FF
+ E6F7F4FFE6F7F4FFE3F4F1FFE0F1EEFFDEEFECFFDEEFECFFCFE0DDFFD5E6E3FF
+ DFF0EDFFE5F6F3FFE7F8F5FFE4F5F2FFDFF0EDFFD9ECE9FFDEF3F0FFD2E9E5FF
+ CCE1DEFFCCE1DEFFC4D9D6FFABBEBBFF859895FF6B7E7BFF6D7E7BFF536461FF
+ 60716EFF9EAFACFFD0DEDCFFD5E3E1FFD5E3E1FFE1EFEDFFEFFFFDFFEFFFFFFF
+ EDFFFFFFEDFFFFFFEDFFFFFFECFFFEFFECFFFFFFECFFFFFFE0F9F5FFD6EFEBFF
+ D5EEEAFFD5EEEAFFCDE8E4FFD6F1EDFFE4FFFBFFE6FFFBFFE8FDFAFFCCE1DEFF
+ B8CDCAFFBAD1CDFFBFD6D2FFBBD4D0FFBCD5D1FFC2DDD9FFC8E3DFFFCDE8E4FF
+ D0E9E5FFCEE5E1FFCCE3DFFFC6DBD8FFB2C5C2FF99ACA9FF95A6A3FF91A29FFF
+ 96A7A4FF93A4A1FF839491FF7E8F8CFF80918EFF798A87FF748582FF758683FF
+ 728380FF70817EFF748582FF7D8E8BFF81928FFF80918DFF97A6A2FF95A59EFF
+ 869591FF879692FFA2B1ADFFB8C9C5FFC0D3D0FFC7DCD9FFC5DAD7FFC8DFDBFF
+ B3CBC9FF9DB5B3FF96B0B0FF8EA8A8FF849E9EFF88A09EFF6B807EFF7A8D8AFF
+ 849794FF829592FF7D908DFF7C8F8CFF7D908DFF7E918EFF899C99FF829592FF
+ 7B8E8BFF7B8E8BFF7F928FFF829592FF7F928FFF7C8D8AFF758382FF6D7979FF
+ 646F6DFF7A8281FF606665FF555B5AFF595E5CFF4E5351FF4F5550FF626863FF
+ 717873FF777E79FF7C877FFF88958DFF909F97FF91A098FF93A19DFF96A4A0FF
+ 98A6A2FF98A6A2FF96A4A0FF95A39FFF96A4A0FF98A6A2FF97A5A1FF97A5A1FF
+ 97A5A1FF97A5A1FF97A5A1FF97A5A1FF97A5A1FF96A4A0FF9AA5A2FF9BA6A3FF
+ 9CA7A4FF9DA8A5FF9CA7A4FF99A7A3FF97A5A1FF96A4A0FF92A19DFF8B9A96FF
+ 95A4A0FF93A29EFF95A6A2FF96A7A3FF90A19DFFABBAB6FFB3C1BDFF96A4A0FF
+ 909B98FFA1AFABFFA7B2AFFF92A09CFF8F9A97FF9CAAA6FF99A4A1FF98A6A2FF
+ 9DA8A5FF9CAAA6FF97A29FFF8B9995FF8A9592FF8E9996FF8F9993FF99A39DFF
+ 929C96FF858F89FF828C86FF7D8781FF77817BFF7C8680FF848E88FF88928CFF
+ 8C9690FF8E9892FF8D9791FF8B958FFF89938DFF87948CFF8A9991FF7F9085FF
+ 7F9085FF84958AFF91A299FFB7C8BFFFD9ECE3FFE3F6EDFFE2F4EDFFE3F8F0FF
+ E3F7F2FFDAF0EBFFD9EFEAFFDCF2EDFFBACFCCFF839895FF819491FF839693FF
+ 899A97FF8B9E9BFF92A3A0FF94A7A4FF9BACA9FF9BAEABFF9DAEABFFA1B4B1FF
+ ABBCB9FFAEC1BEFFB4C5C2FFB7CAC7FFC1D2CFFFC5D8D5FFBAD0CBFFB9D0CBFF
+ B9D0CBFFBAD1CCFFBDD4CFFFC5DCD7FFD0E7E2FFD7EEE9FFDEF5F0FFE0F7F2FF
+ E4FBF6FFE7FEF9FFA9C0BCFFAEC5C1FFB0C7C3FFACC3BFFFA9C0BCFFA9C0BCFF
+ A7BEBAFFA4BBB7FF9EB5B1FF97AEAAFF96ADA9FF9DB4B0FF9FB6B2FF98AFABFF
+ 8FA6A2FF8CA39FFF98ABA8FF96A9A6FF99ACA9FF9EB1AEFF9CADAAFF90A19EFF
+ 889996FF889996FF6D7B79FF6B7977FF7C8987FF7D8A88FF83908EFF727F7DFF
+ 596462FF798482FF414C49FF414C49FF65736FFF75837FFF73817DFF788682FF
+ 71807CFF74837FFF72837FFF798A86FF7F908CFF7C8D89FF738782FF728681FF
+ 788C87FF80948FFF7B918CFF7D938EFF869C97FF8EA49FFF8DA19CFF869A95FF
+ 859994FF8B9F9AFF849591FF8FA09CFF92A39FFF90A19DFFA3B4B0FFC3D4D0FF
+ D6E5E1FFD3E2DEFFD9EAE6FFD9EAE6FFCCDDD9FFB5C6C2FFABBCB8FFB2C3BFFF
+ B8C9C5FFB6C7C3FFB9CAC6FFBECFCBFFCBDCD8FFDDEEEAFFE9FAF6FFE5F6F2FF
+ D4E5E1FFC1D5D0FFCDE4E0FFC2DBD7FFC2D9D5FFCDE4E0FFD2E9E5FFC8DDDAFF
+ B8CBC8FFACBFBCFFA1B2AFFF9BACA9FFA9B7B5FFC4D2D0FFD1DEDCFFCCD9D7FF
+ CCD9D7FFD6E3E1FFDEEFECFFDFF2EFFFE1F6F3FFE3F8F5FFE3F8F5FFE3F8F5FF
+ E4FBF7FFE5FCF8FFE3FCF8FFDCF5F1FFDCF5F1FFD6EFEBFFC6E1DDFFCBE6E2FF
+ DCF7F3FFE3FCF8FFE2F9F5FFCBE0DDFFB5CAC7FFAEC5C1FFB4CBC7FFB7D0CCFF
+ BAD3CFFFBDD6D2FFC5DEDAFFCBE4E0FFCCE3DFFFC7DEDAFFC9E0DCFFC9E0DCFF
+ B9CECBFFA5B8B5FF97A8A5FF95A6A3FF9DAEABFF9AABA8FF879895FF7E8F8CFF
+ 7F908DFF788986FF758683FF7A8B88FF7A8B88FF758683FF778885FF81928FFF
+ 899A97FF899A96FF839490FF84968FFF71827EFF6C7D79FF93A4A0FFBACEC9FF
+ C3D6D3FFBDD2CFFFC6DBD8FFC8DFDBFFADC5C3FF97AFADFF98B2B2FF92ACACFF
+ 859F9FFF8BA3A1FF6F8482FF7C8F8CFF849794FF819491FF7B8E8BFF7A8D8AFF
+ 7B8E8BFF7A8D8AFF889B98FF809390FF798C89FF7A8D8AFF7F928FFF829592FF
+ 7F928FFF7C8D8AFF788685FF7C8888FF586361FF6F7776FF656B6AFF5C6261FF
+ 565B59FF545755FF5C605BFF6A706BFF757C77FF777E79FF7D8880FF8A978FFF
+ 8F9E96FF8C9B93FF909F9BFF92A19DFF93A29EFF93A29EFF91A09CFF8F9E9AFF
+ 909F9BFF92A19DFF909F9BFF909F9BFF91A09CFF92A19DFF93A29EFF93A29EFF
+ 94A39FFF94A39FFF96A4A0FF97A5A1FF97A5A1FF97A5A1FF97A5A1FF97A6A2FF
+ 97A6A2FF97A6A2FF92A19DFF81908CFF91A09CFF8C9B97FF7E8F8BFF899A96FF
+ 859692FF82918DFF98A49EFF8C9892FF8C9690FF97A39DFFA4AEA8FFA2AEA8FF
+ A2ACA6FFA2AEA8FF9EA8A2FF98A49EFF97A19BFF95A19BFF949E98FF8B9791FF
+ 8B958FFF8E9892FF919B95FF9DA7A1FF959F99FF858F89FF818B85FF7D8781FF
+ 78827CFF7C8680FF838D87FF858F89FF88928CFF8C9690FF909A94FF909A94FF
+ 8E9892FF8A978FFF8F9E96FF7F8F84FF7E8E83FF839388FF84958CFF97A89FFF
+ B2C3BAFFBCCFC6FFD9EBE4FFE5FAF2FFE3F7F2FFDDF1ECFFE8FCF7FFE9FDF8FF
+ CCE1DEFFB4C7C4FF95A6A2FF8D9E9AFF899894FF889995FF91A09CFF91A29EFF
+ 8E9D99FF859692FF6C7B77FF70817DFF798884FF7D8E8AFF869591FF91A29EFF
+ A3B2AEFFADBEBAFFB3C9C4FFB1C8C3FFAFC6C1FFB0C7C2FFB5CCC7FFC2D9D4FF
+ D1E8E3FFDBF2EDFFE0F7F2FFDFF6F1FFDEF5F0FFDDF4EFFF95ACA8FFA2B9B5FF
+ B0C7C3FFB6CDC9FFB7CECAFFB4CBC7FFABC2BEFFA1B8B4FF9DB4B0FF99B0ACFF
+ 99B0ACFF9CB3AFFF99B0ACFF92A9A5FF94ABA7FF9BB2AEFF94A7A4FF8DA09DFF
+ 8A9D9AFF8EA19EFF97A8A5FF9BACA9FF9BACA9FF99AAA7FF707E7CFF677573FF
+ 74817FFF778482FF899694FF808D8BFF65706EFF8B9694FF4C5754FF434E4BFF
+ 5F6D69FF6E7C78FF73817DFF818F8BFF7E8D89FF83928EFF70817DFF7C8D89FF
+ 859692FF82938FFF758984FF718580FF7A8E89FF869A95FF879D98FF839994FF
+ 849A95FF879D98FF869A95FF829691FF879B96FF93A7A2FF97A8A4FF9BACA8FF
+ 93A4A0FF879894FF8FA09CFFA8B7B3FFAFBEBAFFA5B4B0FF96A5A1FFA0B1ADFF
+ 9DAEAAFF8A9B97FF879894FF97A8A4FF9FB0ACFF98A9A5FFAABBB7FFA4B5B1FF
+ A7B8B4FFBCCDC9FFD8E9E5FFE6F7F3FFDFF0ECFFD0E4DFFFDBF2EEFFCBE4E0FF
+ C1DAD6FFC5DEDAFFCCE3DFFFCBE2DEFFCEE1DEFFD1E4E1FFCCDDDAFFBFD0CDFF
+ B3C1BFFFB4C2C0FFC5D2D0FFD5E2E0FFD9E4E2FFD0DDDBFFD3E4E1FFD6E9E6FF
+ DBF0EDFFE0F5F2FFE3F8F5FFE6FBF8FFE9FFFCFFECFFFFFFE0F9F5FFE0F9F5FF
+ E6FFFBFFDDF6F2FFC3DEDAFFBFDAD6FFCDE8E4FFD4EDE9FFE2F9F5FFCBE2DEFF
+ AFC6C2FFA3BAB6FFA9C0BCFFB4CBC7FFB8CFCBFFB3CCC8FFC6DDD9FFCDE4E0FF
+ CCE3DFFFC5DCD8FFC7DEDAFFCDE4E0FFC4DBD7FFB4C9C6FF96A9A6FF98A9A6FF
+ A1B2AFFF9EAFACFF899A97FF7F908DFF7E8F8CFF778885FF798A87FF80918EFF
+ 81928FFF7A8B88FF798A87FF839491FF8B9C99FF8D9E9AFF93A4A0FF90A59DFF
+ 748883FF667A75FF8EA29DFFBAD0CBFFBFD4D1FFAFC4C1FFBCD3CFFFC8DFDBFF
+ B1C9C7FF97AFADFF92ACACFF88A2A2FF809A9AFF91A9A7FF617674FF6E817EFF
+ 758885FF748784FF728582FF748784FF768986FF758885FF879A97FF809390FF
+ 798C89FF7A8D8AFF7F928FFF809390FF7A8D8AFF758683FF748281FF7B8787FF
+ 444F4DFF5B6362FF606665FF5A605FFF4D5250FF4E514FFF616560FF6E746FFF
+ 767D78FF787F7AFF7F8A82FF8E9B93FF91A098FF8A9B92FF91A09CFF92A19DFF
+ 93A29EFF92A19DFF909F9BFF8E9D99FF8F9E9AFF91A09CFF909F9BFF91A09CFF
+ 92A19DFF94A39FFF96A5A1FF98A7A3FF99A8A4FF9AA9A5FF94A39FFF94A39FFF
+ 94A29EFF93A29EFF94A39FFF95A4A0FF97A6A2FF98A7A3FF92A19DFF7A8985FF
+ 8D9C98FF84938FFF6B7C78FF7B8C88FF778884FF606F6BFF7B8781FF858F89FF
+ 89938DFF8B958FFF97A19BFFA6B0AAFFA6B0AAFF9BA59FFF9EA8A2FF99A39DFF
+ 98A29CFF9BA59FFF9BA59FFF96A09AFF939D97FF949E98FF919B95FF9EA8A2FF
+ 97A19BFF87918BFF838D87FF808A84FF7C8680FF808A84FF8D9791FF88928CFF
+ 838D87FF848E88FF89938DFF8F9993FF929C96FF929D95FF93A098FF839388FF
+ 87978CFF8F9F94FF86958DFF819289FF8B9C93FF91A299FFC4D6CFFFDEF0E9FF
+ E0F1EDFFD6EAE5FFDBEFEAFFD7EBE6FFD7ECE9FFEFFFFFFFEAF9F5FFC7D6D2FF
+ 9CABA7FF869591FF899894FF92A19DFF95A4A0FF91A09CFF7C8B87FF84938FFF
+ 8E9D99FF97A6A2FFA1B0ACFFAFBEBAFFC0CFCBFFCBDCD8FFDAF0EBFFD4EBE6FF
+ CBE2DDFFC4DBD6FFC2D9D4FFC9E0DBFFD5ECE7FFDEF5F0FFDBF2EDFFD7EEE9FF
+ D3EAE5FFCFE6E1FFAFC6C2FF9BB2AEFF9AB1ADFFAFC6C2FFB5CCC8FFA6BDB9FF
+ A2B9B5FFAEC5C1FF9BB2AEFF9DB4B0FF92A9A5FF869D99FF91A8A4FFA6BDB9FF
+ A0B7B3FF889F9BFF91A4A1FF90A3A0FF8B9E9BFF899C99FF93A4A1FF9BACA9FF
+ 95A6A3FF899A97FF8B9997FF82908EFF7B8886FF7B8886FF7D8A88FF7E8B89FF
+ 7F8A88FF7F8A88FF495451FF56615EFF606E6AFF667470FF717F7BFF7D8B87FF
+ 7B8A86FF71807CFF7B8C88FF7C8D89FF7E8F8BFF80918DFF7F938EFF7F938EFF
+ 7E928DFF7E928DFF8FA5A0FF90A7A2FF8CA39EFF859C97FF879D98FF8DA39EFF
+ 8EA29DFF879B96FF90A19DFF7E8F8BFF73827EFF7C8B87FF91A09CFFA0AEAAFF
+ 9FADA9FF97A6A2FF9FAFA8FFA1B1AAFF9FAFA8FF97A7A0FF90A099FF93A39CFF
+ A1B1AAFFAEBEB7FFA5B5AEFFABBBB4FFA6B6AFFFA2B2ABFFBBCBC4FFDFEFE8FF
+ E3F3ECFFCBDCD8FFCCE3DFFFC7E0DCFFB8D1CDFFC4DDD9FFC7DEDAFFB5CCC8FF
+ B8CBC8FFADC0BDFFBCCDCAFFB4C5C2FFBAC8C6FFBAC8C6FFB5C2C0FFBFCCCAFF
+ D7E2E0FFDDEAE8FFD4E5E2FFD0E3E0FFCDE2DFFFD0E5E2FFD7ECE9FFE1F6F3FF
+ E8FFFBFFECFFFFFFE6FFFBFFE4FDF9FFE0F9F5FFD4EDE9FFBFDAD6FFB5D0CCFF
+ C3DEDAFFDAF5F1FFDDF6F2FFD6EDE9FFBBD2CEFFA7BEBAFFA6BDB9FFA6BDB9FF
+ A8BFBBFFB4CBC7FFC5DAD7FFC8DFDBFFCAE1DDFFC7DEDAFFC3DAD6FFC5DCD8FF
+ CEE5E1FFD6EDE9FFC0D3D0FFA2B5B2FF8C9F9CFF97AAA7FFB0C3C0FFB6C9C6FF
+ A4B7B4FF90A3A0FF90A3A0FF8A9D9AFF859895FF879A97FF8EA19EFF91A4A1FF
+ 8C9F9CFF879B96FF8EA29DFFA0B7AFFF889E99FF90A6A1FFA1B7B2FFA8BEB9FF
+ C5DAD7FFC7DEDAFFBCD3CFFFBCD3CFFFAFC7C5FF99B1AFFF89A1A1FF859D9DFF
+ 849C9CFF829896FF6C817FFF526562FF637673FF768986FF677A77FF6D807DFF
+ 7D908DFF708380FF748784FF7A8D8AFF7B8E8BFF778A87FF768986FF798C89FF
+ 748784FF6E7F7CFF687675FF697575FF646F6DFF676F6EFF6F7574FF616766FF
+ 505553FF4F5452FF727873FF727873FF707772FF767D78FF87928AFF98A59DFF
+ 99A8A0FF8FA097FF8E9D99FF8FA09CFF90A19DFF8FA09CFF8C9D99FF889995FF
+ 869793FF869793FF8B9C98FF869793FF859692FF8A9B97FF91A29EFF91A29EFF
+ 879894FF7E8F8BFF82938FFF80918DFF83928EFF82938FFF7D8E8AFF778884FF
+ 788985FF7D8E8AFF738480FF6C7D79FF6F7E7AFF6B7A76FF62716DFF63726EFF
+ 5F6E6AFF505E5AFF7E8882FF8A928BFF8A928BFF8F9790FFA2AAA3FFA8B0A9FF
+ A2AAA3FFA3ABA4FFA5ADA6FFA4ACA5FFA4ACA5FFA5ADA6FFA6AEA7FFA3ABA4FF
+ 9CA49DFF969E97FF919B95FF9CA6A0FFA2ACA6FF97A19BFF838D87FF78827CFF
+ 7E8882FF88928CFF8E9892FF828C86FF808A84FF88928CFF8B958FFF87918BFF
+ 8E9892FF9BA69EFF8E9B93FF87958AFF818F84FF809085FF899890FF91A098FF
+ 92A39AFF91A299FFA3B3ACFFDEF0E9FFDBECE8FFD8E9E5FFBACEC9FFABBFBAFF
+ DCEFECFFDAEDEAFFE6F5F1FFEAF8F2FFE1EFE9FFC5D3CDFFA4B2ACFF8E9C96FF
+ 85938DFF818F89FF8F9D97FFA0AEA8FFAFBDB7FFBAC8C2FFCDDBD5FFE1EFE9FF
+ E3F1EBFFD8E8E1FFE0F6F1FFDCF3EEFFD9F0EBFFDBF2EDFFE1F8F3FFE3FAF5FF
+ DCF3EEFFD4EBE6FFCBE2DDFFCFE6E1FFCEE5E0FFC9E0DBFFC0D7D3FFACC3BFFF
+ A2B9B5FFA9C0BCFFAAC1BDFFA0B7B3FF9EB5B1FFA7BEBAFF98AFABFFA0B7B3FF
+ 9CB3AFFF90A7A3FF93AAA6FF9EB5B1FF96ADA9FF819894FF8EA19EFF8A9D9AFF
+ 819491FF7A8D8AFF7F908DFF899A97FF8C9D9AFF879895FF7B8987FF73817FFF
+ 6B7876FF6A7775FF6E7B79FF73807EFF778280FF798482FF4D5855FF5C6764FF
+ 64726EFF65736FFF6A7874FF75837FFF798884FF768581FF758682FF788985FF
+ 7C8D89FF81928EFF839792FF879B96FF889C97FF879D98FF738A85FF7B928DFF
+ 829994FF859C97FF899F9AFF8AA09BFF849893FF788C87FF7C8D89FF72837FFF
+ 707F7BFF7C8B87FF8E9C98FF98A6A2FF99A7A3FF97A5A1FFA5B3ADFFA5B5AEFF
+ A2B2ABFF9AAAA3FF91A19AFF90A099FF9AAAA3FFA4B4ADFFA1B1AAFFA6B6AFFF
+ A1B1AAFF9CACA5FFAFBFB8FFD2E2DBFFE5F5EEFFE2F4EDFFD5EAE7FFCBE4E0FF
+ B7CECAFFBCD3CFFFBCD3CFFFB4C9C6FFC2D5D2FFBFD2CFFFC9DAD7FFBCCDCAFF
+ BCCAC8FFBAC8C6FFAFBCBAFFB4C1BFFFCBD8D6FFD9E6E4FFD4E5E2FFD0E3E0FF
+ CDE2DFFFCFE4E1FFD5EAE7FFDDF2EFFFE4FBF7FFE9FFFCFFE9FFFEFFE7FFFCFF
+ E5FEFAFFDCF5F1FFC9E4E0FFBED9D5FFC6E1DDFFD5F0ECFFDCF5F1FFD5EEEAFF
+ BED5D1FFAAC1BDFFAAC1BDFFA7BEBAFFA7BCB9FFB0C5C2FFC5DAD7FFC8DDDAFF
+ CADFDCFFC7DEDAFFC2D9D5FFBDD6D2FFBED7D3FFC1DAD6FFC7DCD9FFC0D3D0FF
+ B1C4C1FFADC0BDFFBCCFCCFFCCDFDCFFC6D9D6FFB4C7C4FFA1B4B1FF9AADAAFF
+ 93A6A3FF91A4A1FF95A8A5FF9AADAAFF9BAEABFF9BAFAAFFB1C7C2FFC4DBD3FF
+ B1C7C2FFB9CFCAFFC5DBD6FFBFD5D0FFCBE0DDFFC6DDD9FFCAE1DDFFBBD2CEFF
+ AEC4C2FFA6BEBCFF9DB2B3FF88A0A0FF7A8F90FF748A88FF748987FF4C5F5CFF
+ 576A67FF768986FF708380FF6F827FFF7A8D8AFF748784FF728582FF7A8D8AFF
+ 7E918EFF7C8F8CFF7B8E8BFF7A8D8AFF728582FF687B78FF778786FF717F7EFF
+ 5E6B69FF586361FF616968FF606665FF5C6360FF666D6AFF6C726DFF6F7671FF
+ 727974FF747E78FF7E8B83FF8B9A92FF8FA097FF899C93FF849591FF879894FF
+ 8A9B97FF8C9D99FF8C9D99FF8D9E9AFF8FA09CFF91A29EFF92A39FFF8B9C98FF
+ 82938FFF798A86FF748581FF72837FFF738480FF748581FF5E6F6BFF5E726DFF
+ 697A76FF738480FF788985FF7A8B87FF81928EFF899A96FFADBEBAFFA8B9B5FF
+ B1C0BCFFB4C3BFFFACBBB7FFA0AFABFF879692FF65736DFF77817BFF919992FF
+ 99A19AFF959D96FF9BA39CFF9EA69FFF9AA29BFF9BA39CFFA2AAA3FFA2AAA3FF
+ A4ACA5FFA6AEA7FFA5ADA6FF9FA7A0FF969E97FF8E968FFF8B958FFF8E9892FF
+ 8F9993FF8A948EFF818B85FF7C8680FF7D8781FF808A84FF8B958FFF838D87FF
+ 838D87FF8D9791FF8F9993FF89938DFF8B958FFF95A098FF97A49CFF95A398FF
+ 919F94FF8E9C91FF8B9A92FF8E9D95FF94A39BFF98A9A0FF95A59EFFD0E0D9FF
+ CFE0DCFFCCDDD9FFB2C3BFFFA3B7B2FFD4E7E4FFD7E8E4FFE2F1EDFFEBF9F3FF
+ EDFBF5FFE3F1EBFFDAE8E2FFD9E7E1FFDDEBE5FFDFEDE7FFD1DFD9FFD6E4DEFF
+ E1EFE9FFECFAF4FFEEFCF6FFE5F3EDFFDAE8E2FFD2E2DBFFB5CBC6FFB6CDC8FF
+ B6CDC8FFB9D0CBFFC4DBD6FFD2E9E4FFD3EAE5FFCDE4DFFFCBE2DDFFCFE6E1FF
+ CEE5E0FFC8DFDAFFC6DDD9FFBAD1CDFFAFC6C2FFACC3BFFFA9C0BCFFA4BBB7FF
+ A0B7B3FFA1B8B4FF9FB6B2FFA9C0BCFFAAC1BDFF9DB4B0FF96ADA9FF95ACA8FF
+ 889F9BFF768D89FF90A3A0FF8C9F9CFF829592FF7A8D8AFF7C8D8AFF839491FF
+ 869794FF849592FF8C9A98FF82908EFF778482FF717E7CFF717E7CFF74817FFF
+ 778280FF76817FFF4F5A57FF5F6A67FF677571FF64726EFF667470FF73817DFF
+ 7D8C88FF808F8BFF778884FF7A8B87FF7E8F8BFF839490FF869A95FF8A9E99FF
+ 8CA09BFF8BA19CFF778E89FF7C9690FF829C96FF859F99FF889F9AFF879D98FF
+ 7F938EFF748883FF60716DFF61726EFF6D7C78FF7E8D89FF8C9A96FF92A09CFF
+ 98A3A0FF9AA8A4FF9FADA7FFA0AEA8FF9EACA6FF97A59FFF8F9D97FF8D9B95FF
+ 93A19BFF99A7A1FF9EACA6FFA2B0AAFFA1AFA9FF9DABA5FFA3B1ABFFB8C6C0FF
+ D1DFD9FFDFEFE8FFE2F5F2FFDCF3EFFFC7DCD9FFC8DDDAFFC6DBD8FFC1D4D1FF
+ D1E4E1FFD2E5E2FFCFE0DDFFBCCDCAFFB8C9C6FFB6C7C4FFA7B5B3FFA7B5B3FF
+ C1CFCDFFD8E6E4FFD6E7E4FFD2E5E2FFCFE4E1FFCFE4E1FFD2E7E4FFD8EDEAFF
+ DDF4F0FFE2F9F5FFE9FFFEFFE8FFFDFFE6FFFBFFE0F9F5FFD1ECE8FFC6E1DDFF
+ C6E1DDFFCDE8E4FFD8F3EFFFD3EEEAFFBFD8D4FFB0C7C3FFAFC6C2FFA9BEBBFF
+ A5B8B5FFABBEBBFFB9CCC9FFBBD0CDFFC0D5D2FFC1D8D4FFC0D7D3FFB9D2CEFF
+ B3CCC8FFAFC8C4FFB4C9C6FFBDD2CFFFB5CAC7FFA1B6B3FF9EB3B0FFADC2BFFF
+ B1C6C3FFA6BBB8FFA5BAB7FFA4B9B6FFA4B9B6FFA7BCB9FFACC1BEFFB2C7C4FF
+ B8CDCAFFBCD2CDFFBFD3CEFFCCE1D9FFC1D5D0FFCBDFDAFFD8ECE7FFCDE3DEFF
+ CDE2DFFFC9DEDBFFBACFCCFF99AEABFF849997FF879D9BFF8B9FA0FF809596FF
+ 7E9293FF869B99FF788A89FF475A57FF4B5E5BFF738683FF778A87FF6E817EFF
+ 738683FF738683FF768986FF7B8E8BFF7D908DFF7B8E8BFF7A8D8AFF7B8E8BFF
+ 788B88FF738683FF708281FF6D7D7CFF606E6CFF5E6B69FF6A7573FF6B7372FF
+ 69726FFF747D7AFF7A817CFF7C8680FF7D8781FF79857FFF78877FFF7D8E85FF
+ 7F9289FF7F9289FF889995FF899A96FF879894FF839490FF7E8F8BFF7B8C88FF
+ 7B8C88FF7C8D89FF71827EFF748581FF768783FF758682FF778884FF81928EFF
+ 93A4A0FFA1B2AEFFA9BDB8FFAAC0BBFFB5C9C4FFC0D4CFFFC6DAD5FFC7DBD6FF
+ CBDFDAFFD1E5E0FFCFE0DCFFC8D9D5FFD0DFDBFFD8E7E3FFD3E2DEFFC2D1CDFF
+ 9BAAA6FF6E7C76FF6B7771FF97A29AFFA8B3ABFF9AA59DFF95A098FF97A29AFF
+ 98A39BFF9AA59DFF9CA79FFF9EA9A1FFA0ABA3FFA2ADA5FFA0ABA3FF98A39BFF
+ 8E9991FF869189FF8B958FFF858F89FF808A84FF808A84FF848E88FF858F89FF
+ 808A84FF79837DFF828C86FF7E8882FF838D87FF8D9791FF8F9993FF87918BFF
+ 858F89FF8A958DFF939E96FF97A298FF95A398FF8E9C91FF86938BFF84938BFF
+ 8E9D95FF99A8A0FF99A9A2FFD0E0D9FFD9E8E4FFD8E9E5FFC1D2CEFFB2C3BFFF
+ D6E7E4FFD5E6E2FFD0DFDBFFD4E4DDFFD4E4DDFFD0E0D9FFD0E0D9FFD6E6DFFF
+ DBEBE4FFDCECE5FFDEEEE7FFD2E2DBFFD1E1DAFFDAEAE3FFD7E7E0FFC6D6CFFF
+ BECEC7FFC1D3CCFFABC1BCFFB0C7C2FFADC4BFFFA6BDB8FFB0C7C2FFC4DBD6FF
+ CAE1DCFFC3DAD5FFC9E0DBFFCEE5E0FFCDE4DFFFC7DED9FFB8CFCBFFBAD1CDFF
+ B8CFCBFFB4CBC7FFB3CAC6FFB1C8C4FFAAC1BDFFA1B8B4FF9EB5B1FFA5BCB8FF
+ A8BFBBFFA2B9B5FF9DB4B0FF99B0ACFF8EA5A1FF819894FF7E918EFF7A8D8AFF
+ 768986FF778A87FF7F908DFF849592FF829390FF7C8D8AFF8A9896FF83918FFF
+ 788583FF6D7A78FF697674FF697674FF677270FF626D6BFF5F6A67FF6C7774FF
+ 707E7AFF6C7A76FF6C7A76FF778581FF7E8D89FF7D8C88FF778884FF788985FF
+ 7A8B87FF7C8D89FF7D918CFF7F938EFF80948FFF7F9590FF869D98FF7F9993FF
+ 76908AFF6F8983FF6D847FFF6B827DFF697F7AFF677B76FF4C5D59FF556662FF
+ 6B7A76FF83928EFF909E9AFF93A19DFF9BA6A3FFA5B0ADFF9BA9A3FF9DABA5FF
+ 9DABA5FF9AA8A2FF96A49EFF94A29CFF96A49EFF99A7A1FF9FADA7FFA1AFA9FF
+ A4B2ACFFA3B1ABFF9EACA6FF9DABA5FFA8B6B0FFB5C5BEFFD9EAE6FFDFF2EFFF
+ D5E8E5FFDBEEEBFFD6E9E6FFCBDEDBFFD3E6E3FFCDE0DDFFC8D9D6FFB4C5C2FF
+ B3C4C1FFB5C6C3FFA5B6B3FFA4B5B2FFC0D1CEFFDAEBE8FFD7EAE7FFD6E9E6FF
+ D2E7E4FFD0E5E2FFD0E5E2FFD3E8E5FFD7EEEAFFDCF3EFFFE5FEFAFFE3FCF8FF
+ E0F9F5FFDBF4F0FFD2EDE9FFCAE5E1FFC7E2DEFFC7E2DEFFD6F1EDFFD3EEEAFF
+ C3DCD8FFB4CDC9FFB4C9C6FFAABFBCFFA1B4B1FFA4B7B4FFA8BBB8FFAEC1BEFF
+ B6CBC8FFC0D7D3FFC6DDD9FFC2DBD7FFBAD5D1FFB6CFCBFFB2C9C5FFBCD1CEFF
+ BBD0CDFFACC1BEFFA3B8B5FFA8BDBAFFAFC4C1FFAFC4C1FFB6CBC8FFBCD1CEFF
+ C3D8D5FFC7DCD9FFC9DEDBFFCADFDCFFCEE3E0FFD1E7E2FFC3D7D2FFC5DAD2FF
+ BDD1CCFFC5D9D4FFD2E6E1FFCADED9FFC5D8D5FFC7DCD9FFD4E7E4FFB8CBC8FF
+ 9EB0AFFF90A2A1FF7F9192FF697B7CFF5D6F70FF5F7170FF6D7F7EFF4B5E5BFF
+ 506360FF6F827FFF758885FF6D807DFF6D807DFF6B7E7BFF708380FF6E817EFF
+ 697C79FF637673FF627572FF697C79FF718481FF768986FF687A79FF637574FF
+ 576865FF556361FF5E6B69FF5E6967FF5D6865FF687370FF6D7771FF6A7670FF
+ 67736DFF63716BFF63746BFF677A71FF6A7F76FF6D8279FF687C77FF6C7D79FF
+ 70817DFF748581FF788985FF7E8F8BFF859692FF8A9B97FF9CADA9FFA4B5B1FF
+ ACBDB9FFAFC0BCFFAFC0BCFFB3C4C0FFBDCECAFFC3D7D2FFBFD5D0FFBED4CFFF
+ C2D8D3FFC9DFDAFFCADED9FFC5D9D4FFC2D6D1FFC4D8D3FFC9DAD6FFBDCECAFF
+ BFCECAFFC2D1CDFFBECDC9FFB6C5C1FF9BAAA6FF77857FFF606D65FF949F97FF
+ A8B3ABFF96A199FF8F9A92FF97A29AFF9CA79FFF9EA9A1FF9BA69EFF9CA79FFF
+ 9EA9A1FF9EA9A1FF9BA69EFF95A098FF8E9991FF89948CFF8D9791FF848E88FF
+ 7C8680FF7D8781FF848E88FF858F89FF7D8781FF747E78FF79837DFF77817BFF
+ 7D8781FF86908AFF88928CFF838D87FF818B85FF848F87FF88938BFF8D988EFF
+ 8D9B90FF88968BFF818E86FF828F87FF8A9991FF95A49CFFA1AFA9FFCCDCD5FF
+ D9E8E4FFDFEEEAFFCDDEDAFFBDCECAFFCBDCD9FFC1D2CEFFDAEAE3FFD8E8E1FF
+ D0E0D9FFC8D8D1FFC7D7D0FFCADAD3FFC9D9D2FFC4D4CDFFC2D2CBFFB8C8C1FF
+ B6C6BFFFBFCFC8FFC6D6CFFFC3D3CCFFBFCFC8FFBDCFC8FFB9CFCAFFBFD6D1FF
+ B8CFCAFFAAC1BCFFAEC5C0FFC4DBD6FFCDE4DFFFC6DDD8FFC7DED9FFCBE2DDFF
+ CBE2DDFFC6DDD8FFADC4C0FFB3CAC6FFB5CCC8FFB1C8C4FFB1C8C4FFB4CBC7FF
+ AFC6C2FFA5BCB8FF95ACA8FF97AEAAFF99B0ACFF9DB4B0FFA3BAB6FFA5BCB8FF
+ A0B7B3FF9AB1ADFF859895FF7B8E8BFF748784FF7A8D8AFF889996FF8D9E9BFF
+ 899A97FF839491FF8C9A98FF8A9896FF828F8DFF768381FF727F7DFF707D7BFF
+ 6A7573FF5F6A68FF606B68FF687370FF6A7874FF667470FF697773FF717F7BFF
+ 6F7E7AFF677672FF788985FF7A8B87FF7C8D89FF7F908CFF80948FFF849893FF
+ 879B96FF869C97FF90AAA4FF829E98FF748E88FF69837DFF657C77FF647B76FF
+ 677D78FF6B7F7AFF495A56FF50615DFF697874FF889692FF9AA5A2FF9BA6A3FF
+ A3ACA9FFADB8B5FFA4B2ACFFA5B4ACFFA6B5ADFFA6B5ADFFA4B3ABFFA2B1A9FF
+ A1B0A8FFA1B0A8FFA4B3ABFFA1B0A8FFA1B0A8FFA3B2AAFF9DACA4FF93A29AFF
+ 93A29AFF99A7A1FFB8C7C3FFC5D6D3FFC4D5D2FFCFE0DDFFCFE0DDFFC4D5D2FF
+ CADBD8FFBECFCCFFBED1CEFFAFC2BFFFB2C5C2FFB7CAC7FFABBEBBFFACBFBCFF
+ C6D9D6FFDCEFECFFDAEDEAFFDAEDEAFFD6EBE8FFD3E8E5FFCFE4E1FFD0E5E2FF
+ D3EAE6FFD7EEEAFFE2FBF7FFE0F9F5FFDBF4F0FFD5EEEAFFD0EBE7FFCFEAE6FF
+ CDE8E4FFCBE6E2FFD3F1ECFFD4EFEBFFC5DEDAFFB7D0CCFFB6CBC8FFABC0BDFF
+ A0B3B0FFA3B4B1FFA4B5B2FFA9BCB9FFB4C9C6FFC0D7D3FFCBE2DEFFCCE5E1FF
+ C8E3DFFFC4DFDBFFBBD2CEFFB9CECBFFBCD1CEFFC4D9D6FFC3D8D5FFBED3D0FF
+ C3D8D5FFCFE4E1FFD1E6E3FFD4E9E6FFD5EAE7FFD1E6E3FFCADFDCFFC5DAD7FF
+ C6DBD8FFC8DED9FFD0E4DFFFCBDDD6FFC8D9D5FFCBDCD8FFD0E1DDFFBFD0CCFF
+ ADBEBBFFB5C8C5FFD3E4E1FFDFF0EDFFE4F4F3FFD7E7E6FFB8C7C9FF91A0A2FF
+ 6C7B7DFF546463FF5D6F6EFF576A67FF5E716EFF6A7D7AFF6C7F7CFF6A7D7AFF
+ 687B78FF627572FF738683FF6F827FFF687B78FF627572FF5F726FFF627572FF
+ 6C7F7CFF748784FF7B908EFF6F8482FF556A67FF495C59FF50615EFF556361FF
+ 5F6D69FF72807CFF79857FFF707E78FF6C7C75FF6F817AFF788D84FF829A90FF
+ 8BA399FF90A89EFFA5B9B4FFA8BCB7FFADC1BCFFB2C6C1FFB7CBC6FFBED2CDFF
+ C7DBD6FFCCE0DBFFC5D9D4FFC8DCD7FFCCE0DBFFCDE1DCFFCCE0DBFFCADED9FF
+ C7DBD6FFC6DAD5FFC2D9D4FFC0D7D2FFC2D9D4FFC8DFDAFFC9DFDAFFC3D9D4FF
+ BED4CFFFC1D5D0FFC0D1CDFFB5C6C2FFB4C3BFFFB2C1BDFFABBAB6FFABBAB6FF
+ A2B0ACFF8A9892FF606D65FF8D9B90FF9CAA9FFF8B998EFF89978CFF95A398FF
+ 99A79CFF9AA89DFF9AA89DFF9AA89DFF99A79CFF97A59AFF94A297FF919F94FF
+ 8F9D92FF8F9C94FF909A94FF89938DFF828C86FF808A84FF808A84FF7E8882FF
+ 77817BFF707A74FF76807AFF757F79FF79837DFF7F8983FF828C86FF828C86FF
+ 828C86FF859088FF89948CFF8A958BFF8B968CFF8A958BFF86938BFF88958DFF
+ 8E9B93FF91A098FF97A59FFFAFBDB7FFB6C5C1FFBAC9C5FFB4C3BFFFACBBB7FF
+ ADBEBBFFA1B2AEFFA3B5AEFF9FB2A9FF98ABA2FF94A79EFF98ABA2FFA0B3AAFF
+ A0B3AAFF9AADA4FF9FB2A9FFA3B6ADFFA7BAB1FFAFC2B9FFBFD2C9FFCCDFD6FF
+ C6D9D0FFB5CAC2FFB6CCC7FFBCD3CEFFB8CFCAFFACC3BEFFB0C7C2FFC6DDD8FF
+ D4EBE6FFD3EAE5FFC4DBD6FFC9E0DBFFCAE1DCFFC5DCD7FFB1C8C4FFB1C8C4FF
+ AEC5C1FFA7BEBAFFA5BCB8FFA8BFBBFFA8BFBBFFA6BDB9FF9EB5B1FF98AFABFF
+ 96ADA9FF99B0ACFF9CB3AFFF9BB2AEFF99B0ACFF99B0ACFF9CAFACFF8A9D9AFF
+ 788B88FF758885FF7A8B88FF7B8C89FF798A87FF788986FF818F8DFF818F8DFF
+ 798684FF6A7775FF626F6DFF5E6B69FF545F5DFF444F4DFF56615EFF616C69FF
+ 667470FF697773FF73817DFF7F8D89FF7D8C88FF73827EFF697A76FF6B7C78FF
+ 6F807CFF748581FF798D88FF80948FFF859994FF879D98FF79938DFF6E8A84FF
+ 68827CFF647E78FF637A75FF5E7570FF5E746FFF607671FF566763FF52635FFF
+ 64726EFF85938FFF9DA8A5FFA0ABA8FFA4ADAAFFACB6B0FFAAB6B0FFA8B7AFFF
+ A8B7AFFFA8B7AFFFA8B7AFFFA7B6AEFFA3B2AAFFA0AFA7FFA9B8B0FFA1B0A8FF
+ 9AA9A1FF9BAAA2FF9DACA4FF9CABA3FF9BAAA2FF9CAAA4FF9FADA9FFACBAB8FF
+ A9B7B5FFB5C3C1FFBCCAC8FFBACBC8FFC5D6D3FFBBCCC9FFBACDCAFFB1C4C1FF
+ B6C9C6FFB7CCC9FFB0C5C2FFB8CFCBFFCFE4E1FFDAEFECFFDBEEEBFFDCEFECFF
+ D9EEEBFFD4E9E6FFCEE3E0FFCDE2DFFFCFE6E2FFD3EAE6FFDDF6F2FFDDF6F2FF
+ DAF3EFFFD4EDE9FFD3EEEAFFD7F2EEFFD8F3EFFFD6F1EDFFD5F3EEFFD3F1ECFF
+ C3DEDAFFB7D0CCFFB5CCC8FFABC0BDFFA2B3B0FFA4B5B2FFA4B5B2FFA7BAB7FF
+ AFC2BFFFB4CBC7FFBAD3CFFFBDD8D4FFBFDDD8FFC3DEDAFFBED5D1FFB0C5C2FF
+ AFC4C1FFC0D5D2FFC4D9D6FFB7CCC9FFB5CAC7FFC0D5D2FFC6DBD8FFC4D9D6FF
+ BFD4D1FFB7CCC9FFB0C5C2FFAEC3C0FFB2C7C4FFB6CCC7FFBDD1CCFFB6C8C1FF
+ BFD0CCFFC3D4D0FFC1D2CEFFA9BAB6FF8B9C99FF9BACA9FF96A7A4FFBAC8C6FF
+ DEECEBFFEDFBFAFFE9F6F8FFDAE7E9FFC1CDCFFFA8B6B5FFA4B4B3FFABBEBBFF
+ B0C3C0FFAFC2BFFFAFC2BFFFB1C4C1FFB0C3C0FFAEC1BEFFA2B5B2FFA1B4B1FF
+ A0B3B0FF9EB1AEFF97AAA7FF90A3A0FF91A4A1FF95AAA7FF97ADABFF94AAA8FF
+ 889F9BFF859A97FF91A4A1FF95A6A3FF9CABA7FFADBCB8FFB7C5BFFFADBDB6FF
+ A7B9B2FFACC1B9FFB5CDC3FFBBD4CAFFC0D9CFFFC5DED4FFC1D7D2FFC4D8D3FF
+ C4D8D3FFC3D7D2FFC0D4CFFFC0D4CFFFC2D6D1FFC4D8D3FFC3D7D2FFC1D5D0FF
+ C0D4CFFFC4D8D3FFC9DDD8FFCCE0DBFFCADED9FFC6DCD7FFC0D7D2FFBAD4CEFF
+ BCD3CEFFC1D8D3FFC2D8D3FFBDD3CEFFB8CEC9FFB8CEC9FFB7CBC6FFB4C5C1FF
+ B8C7C3FFB5C4C0FFAAB9B5FFA8B7B3FFA2B0ACFF8F9D97FF6E7D75FF90A095FF
+ 9CAA9FFF8E9E93FF919F94FF97A79CFF9AA89DFF98A89DFF9AA89DFF98A89DFF
+ 98A69BFF92A297FF909E93FF8D9D92FF919F94FF93A196FF97A19BFF949E98FF
+ 909A94FF8A948EFF848E88FF7E8882FF79837DFF77817BFF79837DFF7A847EFF
+ 7C8680FF7F8983FF818B85FF848E88FF86908AFF87928AFF88938BFF889389FF
+ 889389FF8A958BFF8A978FFF8C9991FF8B9890FF8B9890FF94A29CFF99A7A1FF
+ 98A7A3FF95A4A0FF95A4A0FF99A8A4FF9BACA9FF98A9A5FF9AACA5FF97AAA1FF
+ 90A39AFF8C9F96FF90A39AFF96A9A0FF95A89FFF8EA198FF92A59CFF97AAA1FF
+ 93A69DFF8EA198FF9DB0A7FFBBCEC5FFC9DCD3FFC4D9D0FFB7CDC8FFB9D0CBFF
+ B7CEC9FFB1C8C3FFB2C9C4FFBFD6D1FFCDE4DFFFD4EBE6FFC4DBD6FFCAE1DCFF
+ CCE3DEFFC8DFDAFFB7CECAFFB2C9C5FFAEC5C1FFAAC1BDFFA4BBB7FF9FB6B2FF
+ 9EB5B1FFA0B7B3FFA6BDB9FF9EB5B1FF9AB1ADFF98AFABFF8FA6A2FF849B97FF
+ 829995FF89A09CFF8FA29FFF819491FF758885FF6F827FFF6D7E7BFF697A77FF
+ 6D7E7BFF758683FF798785FF7A8886FF73807EFF63706EFF5E6B69FF5E6B69FF
+ 56615FFF46514FFF485350FF56615EFF5E6C68FF62706CFF697773FF768480FF
+ 788783FF73827EFF788985FF798A86FF7B8C88FF7E8F8BFF819590FF879B96FF
+ 8B9F9AFF8CA29DFFA3BFB9FF9AB9B2FF9AB6B0FF9EB8B2FF9DB4AFFF91A8A3FF
+ 8AA09BFF899F9AFF697A76FF566763FF5B6965FF7B8985FF9AA5A2FFA1AAA7FF
+ 9DA6A3FF9FA9A3FFA4B0AAFFA3B0A8FFA2AFA7FFA5B2AAFFA8B5ADFFA9B6AEFF
+ A5B2AAFFA1AEA6FFABB8B0FFA5B2AAFF9DAAA2FF9BA8A0FFA1AEA6FFA8B5ADFF
+ A8B5ADFFA3AFA9FFA0ABA8FFA8B5B3FF9FACAAFFA8B6B4FFB3C1BFFFBBC9C7FF
+ C9DAD7FFBECFCCFFB1C4C1FFAEC1BEFFAFC4C1FFAEC5C1FFADC4C0FFC0D9D5FF
+ D8EFEBFFD8EFEBFFD8EDEAFFDBEEEBFFD9EEEBFFD3E8E5FFCCE1DEFFC9DEDBFF
+ CBE2DEFFD0E7E3FFD3ECE8FFD8F1EDFFD9F2EEFFD6EFEBFFD6F1EDFFDEF9F5FF
+ E1FCF8FFDFFAF6FFD6F4EFFFD4F2EDFFC3DEDAFFB5CECAFFB4CBC7FFABC0BDFF
+ A4B5B2FFA7B8B5FFA9BAB7FFA8BBB8FFA9BCB9FFA6BDB9FFA5BEBAFFA9C4C0FF
+ B1CFCAFFB9D7D2FFC4DDD9FFB8CFCBFFB0C7C3FFB5CCC8FFB6CDC9FFAFC6C2FF
+ A8BFBBFFA8BFBBFFA6BDB9FFA6BDB9FFA6BDB9FFA5BCB8FFA4BBB7FFA3BAB6FF
+ A3BAB6FFA5BBB6FFA1B5B0FF97A9A2FFA9B8B4FFABBAB6FFA7B6B2FF8F9E9AFF
+ 717F7DFF8C9A98FF879593FF929F9DFFA9B5B5FFC7D3D3FFDFEBEDFFE7F3F5FF
+ E3ECEFFFD9E5E5FFC0D0CFFFC2D5D2FFC0D3D0FFC1D4D1FFC4D7D4FFC1D4D1FF
+ C3D6D3FFD1E4E1FFCCDFDCFFCBDEDBFFCCDFDCFFCDE0DDFFC5D8D5FFBBCECBFF
+ BACDCAFFBFD4D1FFB0C8C6FFB9D1CFFFBED5D1FFC7DCD9FFD4E7E4FFD1E2DFFF
+ CCDDD9FFD5E6E2FFD2E2DBFFCBDDD6FFCADCD5FFCCE1D9FFC9E1D7FFC1DAD0FF
+ BDD8CEFFC1DCD2FFBBD1CCFFC0D4CFFFC5D9D4FFC8DCD7FFCADED9FFCCE0DBFF
+ CFE3DEFFD2E6E1FFD2E6E1FFCFE3DEFFCDE1DCFFCDE1DCFFCEE2DDFFCDE1DCFF
+ C9DDD8FFC3D9D4FFC7DED9FFBFD9D3FFBCD6D0FFBED8D2FFC0D7D2FFBAD1CCFF
+ B6CCC7FFB6CCC7FFB1C5C0FFAEC2BDFFB6C7C3FFB4C5C1FFAAB9B5FFA5B4B0FF
+ 9BA9A5FF86948EFF76857DFF91A297FF9CACA1FF97A89DFF9AAA9FFF98A99EFF
+ 96A69BFF98A99EFF97A79CFF96A79CFF97A79CFF92A398FF8E9E93FF8A9B90FF
+ 8B9B90FF8D9D92FF939F99FF949E98FF919B95FF8B958FFF848E88FF7F8983FF
+ 7C8680FF7B857FFF7C8680FF7E8882FF808A84FF808A84FF818B85FF838D87FF
+ 838D87FF828D85FF7D8880FF808B81FF859086FF89948AFF8D9890FF8D9890FF
+ 8A978FFF89968EFF9AA8A2FF9BA9A3FF9CABA7FF93A29EFF8F9E9AFF95A4A0FF
+ 98A6A4FF9CADA9FFA1B3ACFF9DB2A9FF96ABA2FF8FA49BFF8EA39AFF8FA49BFF
+ 8A9F96FF82978EFF9AAFA6FF9AAFA6FF93A89FFF8A9F96FF8BA097FF9EB3AAFF
+ BACFC6FFCEE3DAFFBFD5D0FFBBD2CDFFBAD1CCFFBAD1CCFFB7CEC9FFB7CEC9FF
+ C2D9D4FFD0E7E2FFC6DDD8FFCDE4DFFFCFE6E1FFCCE3DEFFB8CDCAFFB3CAC6FF
+ B4C9C6FFB6CDC9FFB0C5C2FFA0B7B3FF98ADAAFF99B0ACFF9CB1AEFF97AEAAFF
+ 98ADAAFF95ACA8FF889D9AFF788F8BFF7C918EFF8A9F9CFF829592FF839693FF
+ 899C99FF90A3A0FF91A29FFF90A19EFF9BACA9FFABBCB9FFBACBC8FFC0CECCFF
+ BCCAC8FFB3C1BFFFB7C5C3FFC3D1CFFFC3D0CEFFB7C4C2FFB7C5C1FFC6D4D0FF
+ CCDBD7FFC5D4D0FFC1D0CCFFC5D4D0FFC8D7D3FFC3D4D0FFC9DAD6FFC8D9D5FF
+ C6D7D3FFC4D5D1FFC2D6D1FFC2D6D1FFC3D7D2FFC2D8D3FFB1CBC5FFA9C3BDFF
+ A5BFB9FFA7BEB9FFA0B6B1FF90A6A1FF869A95FF839792FF758682FF5B6A66FF
+ 54625EFF75807DFF96A19EFF9DA6A3FF959E9BFF929B98FF9FABA5FF9DAAA2FF
+ 9EABA3FFA3B0A8FFAAB7AFFFAEBBB3FFACB9B1FFA9B6AEFFA7B4ACFFA8B5ADFF
+ A5B2AAFFA0ADA5FFA4B1A9FFABB8B0FFA6B3ABFF9BA7A1FFA5B0ADFFAEB9B7FF
+ A0ADABFFA8B5B3FFB4C2C0FFBCCAC8FFC9D7D5FFB9CAC7FFA7B8B5FFA5B8B5FF
+ A6BBB8FFA2B9B5FFA7BEBAFFC6DDD9FFDDF4F0FFD8EFEBFFD6EBE8FFDAEDEAFF
+ D7ECE9FFD2E7E4FFCADFDCFFC6DBD8FFC8DFDBFFCDE4E0FFCBE2DEFFD3ECE8FF
+ DAF1EDFFD7F0ECFFDAF3EFFFE2FBF7FFE6FFFBFFE1FCF8FFD8F6F1FFD4F2EDFF
+ C2DDD9FFB3CCC8FFB2C9C5FFABC0BDFFA3B6B3FFA8BBB8FFB0C3C0FFB0C3C0FF
+ AABFBCFFA3BAB6FF9EB7B3FFA2BDB9FFAFCDC8FFBED9D5FFBBD4D0FFB7CECAFF
+ ACC3BFFFA5BCB8FFA8BFBBFFACC3BFFFA8BFBBFF9FB6B2FF9EB5B1FFA4BBB7FF
+ ACC3BFFFB2C9C5FFB1C8C4FFA9C0BCFF9EB5B1FF97ACA9FFA4B8B3FF93A4A0FF
+ A1B0ACFF9BAAA6FF93A29EFF7E8C88FF657270FF8B9896FF8D9896FF7C8785FF
+ 838E8CFFAEB9B7FFD6E0E0FFE1EBEBFFDEE8E8FFDCE8E8FFD5E6E3FFCADDDAFF
+ C1D4D1FFC9DCD9FFD1E4E1FFC7DAD7FFCDE0DDFFE9FCF9FFC8DBD8FFC4D7D4FF
+ C4D7D4FFC4D7D4FFBED1CEFFB8CBC8FFBED1CEFFC8DDDAFFC9E1DFFFCBE3E1FF
+ C6DDD9FFC4DBD7FFCADFDCFFC4D7D4FFC0D3D0FFCBDFDAFFC6DAD5FFC8DCD7FF
+ CEE2DDFFD0E6E1FFC7DFD7FFB8D0C8FFB2CDC4FFB6D1C8FFC7DDD8FFC9DFDAFF
+ CDE1DCFFCAE0DBFFC8DCD7FFC2D8D3FFC2D6D1FFC0D6D1FFB4C8C3FFB7CDC8FF
+ C2D6D1FFC7DDD8FFCCE0DBFFC9DFDAFFC8DCD7FFC4DAD5FFC4DBD6FFBDD4CFFF
+ BAD1CCFFBDD4CFFFBFD6D1FFBDD3CEFFBAD0CBFFBAD0CBFFB4C8C3FFAFC3BEFF
+ B5C6C2FFB5C6C2FFABBCB8FFA8B7B3FF9BAAA6FF84938FFF6C7B73FF87978CFF
+ 96A59DFF98A89DFF99A8A0FF93A398FF8D9C94FF95A59AFF95A49CFF97A79CFF
+ 98A79FFF95A59AFF8E9D95FF88988DFF86958DFF87968EFF86928CFF87918BFF
+ 848E88FF808A84FF7C8680FF78827CFF757F79FF747E78FF7B857FFF7E8882FF
+ 818B85FF808A84FF808A84FF808A84FF7D8781FF79847CFF747F77FF7B867CFF
+ 869187FF8D988EFF919C94FF929D95FF919E96FF929F97FF9BA8A0FF9EACA6FF
+ AAB8B2FF9EAEA7FF93A39CFF92A29BFF8E9D99FF96A5A1FF9FB1AAFFA0B3AAFF
+ 9EB1A8FF9AADA4FF9CAFA6FF9FB2A9FF9DB0A7FF96A9A0FF92A59CFF98ABA2FF
+ A3B6ADFFA4B7AEFF92A59CFF81948BFF8DA097FFA4B9B0FFBBD2CAFFB4CCC4FF
+ B6CEC6FFBED6CEFFBBD3CBFFB6CEC6FFC1D8D3FFD4EBE6FFC8DFDAFFCFE6E1FF
+ D3EAE5FFD0E7E2FFBBCDCCFFB3C8C6FFB2C4C3FFB1C6C4FFB1C3C2FFA8BDBBFF
+ A7B9B8FFA6BBB9FFA3B5B4FFA5BAB8FFABBDBCFFADC2C0FFB3C5C4FFB7CCCAFF
+ C1D3D2FFC7D9D8FFD0E3E0FFD3E6E3FFD6E9E6FFD7EAE7FFD8EBE8FFD9ECE9FF
+ DCEFECFFDEF1EEFFDFF2EFFFDEEFECFFD6E7E4FFDAEBE8FFE6F7F4FFE0F1EEFF
+ DAEBE8FFE3F4F1FFDFF0EDFFDEEFECFFDDEEEBFFDDEEEBFFE1F2EFFFE3F4F1FF
+ E0F1EEFFD7EAE7FFDBEEEBFFD8EBE8FFD6E9E6FFD5E8E5FFD6E9E6FFD5E8E5FF
+ D3E6E3FFD1E4E1FFCADED9FFB9CDC8FFBBCFCAFFB5C9C4FF97A8A4FF8D9E9AFF
+ 91A29EFF889793FF7A8985FF818F8BFF7E8C88FF6A7572FF939E9BFFA3AEABFF
+ A9B2AFFF929B98FF929E98FF939F99FF96A29CFF9DA9A3FFA4B0AAFFA8B4AEFF
+ A6B2ACFFA4B0AAFF98A49EFF9FABA5FFA7B3ADFFA7B3ADFFA1ADA7FF9BA7A1FF
+ 9DA9A3FFA3AFA9FFA9B4B1FFAFBAB7FFB1BFBBFFAFBDB9FFABB9B5FFAFBEBAFF
+ BECDC9FFC9DAD6FFB8C9C5FFA1B2AEFFA0B4AFFFA7BBB6FFA8BCB7FFBED4CFFF
+ D8EEE9FFD2E8E3FFD4E9E6FFD7ECE9FFDAEFECFFDAEFECFFD7ECE9FFD1E6E3FF
+ CCE1DEFFC9DEDBFF9FB4B1FFB6CDC9FFDBF0EDFFD6EDE9FFD7EEEAFFE8FFFBFF
+ E6FDF9FFECFFFFFFE5FEFAFFD2EBE7FFCDE6E2FFACC3BFFFBBD2CEFFB0C7C3FF
+ A3B8B5FFA4B9B6FFABC0BDFFACC1BEFFABC2BEFFA6BDB9FFA0B7B3FF9DB6B2FF
+ A2BBB7FFA7C0BCFFB1C8C4FFB4C9C6FFB6CBC8FFB3C8C5FFACC1BEFFA7BCB9FF
+ A4B9B6FFA4B9B6FFADC2BFFFA9BEBBFFA3B8B5FFA1B6B3FFA7BCB9FFAEC3C0FF
+ AABFBCFFA1B6B3FFA1B4B1FF8B9C99FF899795FF889694FF879492FF76817FFF
+ 6A7370FF8E9794FF8A918EFF8B928FFF848D8AFF818A87FF97A19BFFC1CBC5FF
+ DEEAE4FFE5F3EFFFDDF0EDFFCFE4E2FFC5DAD8FFC4D9D7FFC4D9D7FFC3D8D6FF
+ C6DBD9FFCBE0DEFFC2D7D5FFC5DAD8FFD1E6E4FFCADFDDFFCADFDDFFCADFDDFF
+ BDD2D0FFD0E5E3FFC8DEDCFFCAE0DEFFCBE1DFFFCAE0DEFFC7DDDBFFC8DDDBFF
+ CADFDDFFCCE1DEFFCDE2DFFFD0E5E2FFD0E5E2FFCBE2DEFFC8DFDBFFCAE1DDFF
+ CDE4E0FFCEE5E1FFD5ECE8FFD4EBE7FFD0E5E2FFC8DFDBFFC9DEDBFFCBE2DEFF
+ CADFDCFFC3DAD6FFB4C9C6FFBCD3CFFFC4D9D6FFC2D9D5FFC0D5D2FFC0D7D3FF
+ C2D7D4FFC0D5D2FFBED3D0FFB7CCC9FFB2C7C4FFB6CBC8FFBDD2CFFFC0D3D0FF
+ B9CCC9FFB1C4C1FFA7BAB7FFAEC1BEFFB3C6C3FFB0C3C0FFABBEBBFFA8B9B6FF
+ A0B1AEFF99A8A4FF64726CFF909D95FF8F9B95FF89968EFF8A9690FF8B9890FF
+ 95A19BFF8E9B93FF8D9993FF96A39BFF9EAAA4FF9CA9A1FF929E98FF89968EFF
+ 88948EFF8A9690FF78827CFF7E8882FF808A84FF79837DFF727C76FF717B75FF
+ 717B75FF6F7973FF6A746EFF757F79FF78827CFF717B75FF707A74FF79837DFF
+ 7E8882FF7A857DFF808881FF818A80FF868F85FF8F988EFF97A298FF9AA59BFF
+ 97A298FF909E93FF919F94FF94A39BFF9EADA5FFA3B2AAFF9DACA4FF91A098FF
+ 8E9F96FF93A49BFF9CACA5FFA2B2ABFFA5B5AEFFA3B3ACFFA1B1AAFFA1B1AAFF
+ 9EAEA7FF98A8A1FF9BABA4FF9EAEA7FFA1B1AAFF9EAEA7FF99A9A2FF96A69FFF
+ 97A7A0FF97AAA1FFADC2B9FFBDD5CBFFBDD5CBFFB4CCC2FFBAD2C8FFC3DBD1FF
+ C9E0D8FFD2E9E1FFD2E9E1FFD0E7DFFFD3E9E4FFD7EDE8FFC8DAD9FFC7D9D8FF
+ CBDDDCFFD3E5E4FFD8EAE9FFD8EAE9FFD9EBEAFFDCEEEDFFE0F2F1FFE1F3F2FF
+ E1F3F2FFE1F3F2FFE1F3F2FFE2F4F3FFE4F6F5FFE6F8F7FFDCEFECFFDCEFECFF
+ DCEFECFFDDF0EDFFDEF1EEFFDEF1EEFFDEF1EEFFDEF1EEFFE3F6F3FFE5F8F5FF
+ E0F3F0FFE1F4F1FFE7FAF7FFDFF2EFFFDBEEEBFFE7FAF7FFE4F7F4FFE4F7F4FF
+ E4F7F4FFE3F6F3FFE4F7F4FFE6F9F6FFE4F7F4FFE1F4F1FFE3F6F3FFE0F3F0FF
+ DDF0EDFFDCEFECFFDCEFECFFDCEFECFFDAEDEAFFD8EBE8FFDDEEEAFFCFE0DCFF
+ D2E3DFFFCFE0DCFFBDCCC8FFBBCAC6FFBAC9C5FFA7B6B2FF93A19DFF98A6A2FF
+ 97A29FFF7E8986FF9AA5A2FF9EA9A6FFA5AEABFF99A29FFF99A59FFF99A59FFF
+ 9CA8A2FFA1ADA7FFA5B1ABFFA7B3ADFFA4B0AAFFA0ACA6FF99A59FFF9CA8A2FF
+ A3AFA9FFA8B4AEFFA1ADA7FF97A39DFF97A39DFFA0ACA6FFA0ABA8FFA8B3B0FF
+ AEBCB8FFB1BFBBFFB1BFBBFFB4C2BEFFBBCAC6FFC3D2CEFFC7D8D4FFAABBB7FF
+ A4B5B1FFADBEBAFFB5C9C4FFCFE3DEFFDFF3EEFFD2E6E1FFCEE3E0FFD2E7E4FF
+ D7ECE9FFD9EEEBFFD6EBE8FFCFE4E1FFC8DDDAFFC4D9D6FFA6BBB8FFB8CDCAFF
+ D5EAE7FFCEE3E0FFCEE3E0FFE1F6F3FFE2F7F4FFEDFFFFFFEAFFFDFFD7EEEAFF
+ D0E7E3FFAAC1BDFFB8CFCBFFAFC6C2FFA3BAB6FFA4BBB7FFB2C9C5FFAEC5C1FF
+ AAC1BDFFA6BDB9FFA3BAB6FFA1B8B4FF9FB6B2FF9EB5B1FFA3B8B5FFAABFBCFF
+ B2C7C4FFB5CAC7FFB2C7C4FFACC1BEFFA7BCB9FFA4B9B6FFA5BAB7FFA5BAB7FF
+ A3B8B5FFA1B6B3FFA5BAB7FFA9BEBBFFA6BBB8FF9EB3B0FF9EB0AFFF889A99FF
+ 8A9896FF879593FF838E8CFF6E7977FF646B68FF888F8CFF838984FF898F8AFF
+ 8C938EFF888F8AFF848F87FF96A199FFBDCAC2FFDFEDE7FFE6F9F6FFD5EAE8FF
+ C5DAD8FFC0D5D3FFC5DAD8FFC9DEDCFFC6DBD9FFC0D5D3FFCBE0DEFFBED3D1FF
+ C8DDDBFFC8DDDBFFCEE3E1FFD7ECEAFFCADFDDFFCBE0DEFFC5DBD9FFC9DFDDFF
+ CFE5E3FFD3E9E7FFD3E9E7FFD0E6E4FFCDE3E1FFCAE0DEFFCAE0DEFFCCE2E0FF
+ CCE2E0FFC7DDDBFFC4DAD8FFC8DEDCFFCEE4E2FFD4EAE8FFD6EDE9FFD6EDE9FF
+ CFE6E2FFC7DEDAFFC5DCD8FFCAE1DDFFCEE5E1FFCDE4E0FFC9E0DCFFCFE6E2FF
+ D0E7E3FFC9E0DCFFC3DAD6FFBFD6D2FFB9D0CCFFB4C9C6FFB9CCC9FFC1D4D1FF
+ C6D9D6FFC2D5D2FFB9CCC9FFB5C8C5FFBACDCAFFC1D4D1FFB6C9C6FFB5C8C5FF
+ B0C3C0FFABBEBBFFAABDBAFFA9BCB9FFA0B3B0FF97A8A4FF545F5CFF828C86FF
+ 86908AFF848E88FF89938DFF8D9791FF98A29CFF929C96FF89938DFF8A948EFF
+ 8C9690FF8C9690FF8A948EFF87918BFF858F89FF848E88FF848E88FF858F89FF
+ 828C86FF7C8680FF79837DFF79837DFF757F79FF6E7872FF707A74FF79837DFF
+ 7E8882FF7E8882FF7E8882FF808A84FF808A84FF7F8A82FF848C85FF838C82FF
+ 868F85FF90998FFF99A49AFF9DA89EFF98A399FF919C92FF98A69BFF9CAA9FFF
+ 9EAEA3FF9FAFA4FF9DADA2FF9AAA9FFF96A79CFF94A59AFF9DABA5FFA1AFA9FF
+ A3B1ABFFA1AFA9FFA1AFA9FFA2B0AAFF9DABA5FF97A59FFF99A7A1FF9AA8A2FF
+ 9CAAA4FF9DABA5FF9BA9A3FF96A49EFF8F9D97FF8A9B92FF97ACA3FFAFC7BBFF
+ B7CFC3FFB0C8BCFFB5CDC3FFBDD5CBFFC6DED4FFD3EBE1FFD1E8E0FFCFE6DEFF
+ D1E7E2FFD5EBE6FFD8EBE8FFD8EBE8FFDDF0EDFFE5F8F5FFE9FCF9FFE9FCF9FF
+ EAFDFAFFEEFFFEFFEDFFFDFFECFFFCFFEBFEFBFFEAFDFAFFEAFDFAFFE8FBF8FF
+ E5F8F5FFE3F6F3FFEEFFFEFFEDFFFDFFECFFFCFFECFFFCFFEBFEFBFFEBFEFBFF
+ E9FCF9FFE9FCF9FFE4F7F4FFEBFEFBFFE9FCF9FFE8FBF8FFEAFDFAFFE2F5F2FF
+ E0F3F0FFEEFFFEFFE6F9F6FFE7FAF7FFE8FBF8FFE7FAF7FFE6F9F6FFE5F8F5FF
+ E6F9F6FFE7FAF7FFE8FBF8FFE5F8F5FFE3F6F3FFE2F5F2FFE3F6F3FFE2F5F2FF
+ E0F3F0FFDEF1EEFFE6F7F3FFDFF0ECFFE1F2EEFFDEEFEBFFD8E7E3FFDAE9E5FF
+ D0DFDBFFB5C4C0FFAEBCB8FFACBAB6FFA9B4B1FF8F9A97FF9FAAA7FF95A09DFF
+ A0A9A6FFA1AAA7FF9CA8A2FF9DA9A3FF9FABA5FFA2AEA8FFA5B1ABFFA6B2ACFF
+ A5B1ABFFA2AEA8FFA3AFA9FFA0ACA6FFA6B2ACFFAEBAB4FFA7B3ADFF98A49EFF
+ 98A49EFFA5B1ABFFA1ACA9FFA5B0ADFFA7B5B1FFABB9B5FFAFBDB9FFB5C3BFFF
+ BBCAC6FFC0CFCBFFCBDCD8FFB9CAC6FFB7C8C4FFC0D1CDFFC6DAD5FFD5E9E4FF
+ DDF1ECFFD2E6E1FFC9DEDBFFCEE3E0FFD5EAE7FFD9EEEBFFD8EDEAFFD1E6E3FF
+ C7DCD9FFC1D6D3FFB7CCC9FFC0D5D2FFD5EAE7FFCADFDCFFC9DEDBFFDCF1EEFF
+ E1F6F3FFEDFFFFFFEBFFFEFFD9F0ECFFD1E8E4FFA8BFBBFFB5CCC8FFAEC5C1FF
+ A4BBB7FFA5BCB8FFB3CAC6FFADC4C0FFA7BEBAFFA5BCB8FFA6BDB9FFA4BBB7FF
+ 9EB5B1FF98AFABFF9AAFACFFA0B5B2FFA6BBB8FFA9BEBBFFA8BDBAFFA5BAB7FF
+ A2B7B4FFA0B5B2FF9DB2AFFFA1B6B3FFA2B7B4FF9FB4B1FF9FB4B1FFA1B6B3FF
+ 9EB3B0FF99AEABFF9BADACFF8A9C9BFF8E9C9AFF879593FF7F8A88FF687371FF
+ 5D6461FF808784FF838984FF848A85FF888F8AFF868D88FF758078FF737E76FF
+ 96A39BFFC1CFC9FFE9FAF6FFE6F9F6FFDCEFECFFCDE0DDFFC6D9D6FFC6D9D6FF
+ BFD2CFFFB3C6C3FFB0C3C0FFA0B3B0FFBACDCAFFC3D6D3FFC1D4D1FFCFE2DFFF
+ C6D9D6FFB6CBC8FFD1E8E4FFCEE5E1FFCBE2DEFFC8DFDBFFC8DFDBFFC7DEDAFF
+ C6DDD9FFC4DBD7FFC5DCD8FFCAE1DDFFD0E7E3FFD1E8E4FFCFE6E2FFCFE6E2FF
+ D4EBE7FFDAF1EDFFD5EAE7FFD6EBE8FFCFE4E1FFC3D8D5FFBDD2CFFFC2D7D4FF
+ CBE0DDFFCFE4E1FFD1E6E3FFD4E9E6FFD3E8E5FFD0E5E2FFCEE3E0FFCCE1DEFF
+ C5DAD7FFBDD2CFFFCADDDAFFC4D7D4FFBED1CEFFBCCFCCFFBDD0CDFFBCCFCCFF
+ B7CAC7FFB3C6C3FFBACDCAFFB5C8C5FFAEC1BEFFA9BCB9FFA9BCB9FFA6B9B6FF
+ 95A8A5FF869793FF4D5855FF7D8781FF838D87FF858F89FF8B958FFF8F9993FF
+ 9AA49EFF929C96FF838D87FF7D8781FF77817BFF79837DFF808A84FF858F89FF
+ 848E88FF808A84FF88928CFF858F89FF7F8983FF79837DFF79837DFF79837DFF
+ 737D77FF69736DFF6E7872FF717B75FF79837DFF818B85FF818B85FF7B857FFF
+ 78827CFF79847CFF868E87FF828B81FF848D83FF8F988EFF9CA79DFFA2ADA3FF
+ 9BA69CFF929D93FF9CAA9FFFA1AFA4FF9EAEA3FF99A99EFF9CACA1FFA2B2A7FF
+ 9DAEA3FF93A499FF9BA9A3FF9EACA6FF9EACA6FF9DABA5FFA0AEA8FFA3B1ABFF
+ 9EACA6FF96A49EFF94A29CFF92A09AFF92A09AFF97A59FFF9DABA5FF9EACA6FF
+ 9AA8A2FF93A49BFF8CA198FFA9C1B5FFB6CEC2FFB1C9BDFFB3CBC1FFB9D1C7FF
+ C3DBD1FFD2EAE0FFCCE3DBFFCAE1D9FFCBE1DCFFD0E6E1FFDEF1EEFFDCEFECFF
+ DEF1EEFFE2F5F2FFE2F5F2FFDEF1EEFFE0F3F0FFE5F8F5FFE2F5F2FFE1F4F1FF
+ E2F5F2FFE4F7F4FFE7FAF7FFE7FAF7FFE4F7F4FFE0F3F0FFE4F7F4FFE6F9F6FF
+ E7FAF7FFE6F9F6FFE2F5F2FFE1F4F1FFE2F5F2FFE4F7F4FFE2F5F2FFEAFDFAFF
+ E7FAF7FFE5F8F5FFE9FCF9FFE3F6F3FFE0F3F0FFE9FCF9FFE4F7F4FFE5F8F5FF
+ E6F9F6FFE6F9F6FFE1F4F1FFDCEFECFFDEF1EEFFE3F6F3FFDEF1EEFFDEF1EEFF
+ DFF2EFFFE1F4F1FFE3F6F3FFE1F4F1FFDDF0EDFFD9ECE9FFDEEFEBFFE1F2EEFF
+ E1F2EEFFDCEDE9FFDBEAE6FFDCEBE7FFCBDAD6FFB0BFBBFFBECCC8FFB2C0BCFF
+ A8B3B0FF8F9A97FF9CA7A4FF8C9794FF9AA3A0FFA5AEABFF9CA8A2FF9CA8A2FF
+ 9CA8A2FF9EAAA4FFA1ADA7FFA5B1ABFFA8B4AEFFA9B5AFFFAEBAB4FFA4B0AAFF
+ A5B1ABFFADB9B3FFA7B3ADFF98A49EFF9BA7A1FFACB8B2FFACB7B4FFA8B3B0FF
+ A1AFABFFA1AFABFFA7B5B1FFB2C0BCFFBBCAC6FFC2D1CDFFBFD0CCFFC1D2CEFF
+ C9DAD6FFCFE0DCFFCDE1DCFFD1E5E0FFD5E9E4FFD4E8E3FFCCE1DEFFD0E5E2FF
+ D8EDEAFFDEF3F0FFDEF3F0FFD8EDEAFFCDE2DFFFC5DAD7FFC1D6D3FFC4D9D6FF
+ D3E8E5FFC6DBD8FFC4D9D6FFD6EBE8FFD9EEEBFFE7FCF9FFE8FFFBFFDAF1EDFF
+ D4EBE7FFA8BFBBFFB4CBC7FFAEC5C1FFA3BAB6FFA2B9B5FFABC2BEFFA8BFBBFF
+ A6BDB9FFA5BCB8FFA5BCB8FFA3BAB6FF9FB6B2FF9BB2AEFFA4B9B6FFA2B7B4FF
+ 9FB4B1FF9CB1AEFF9AAFACFF9BB0ADFF9DB2AFFF9FB4B1FF9BB0ADFFA0B5B2FF
+ A1B6B3FF9AAFACFF95AAA7FF95AAA7FF96ABA8FF94A9A6FF97A9A8FF8B9D9CFF
+ 919F9DFF889694FF7E8987FF677270FF5C6360FF7E8582FF898F8AFF838984FF
+ 7D847FFF7B827DFF747F77FF737E76FF808D85FF92A09AFFC8D7D3FFE1F2EFFF
+ F0FFFEFFE3F4F1FFD3E4E1FFCEDFDCFFC7D8D5FFBDCECBFFA1B2AFFF99AAA7FF
+ C7D8D5FFD6E7E4FFC9DAD7FFD8E9E6FFD6E7E4FFC2D5D2FFD8EDEAFFD4EBE7FF
+ D1E8E4FFCFE6E2FFCDE4E0FFC9E0DCFFC3DAD6FFBED5D1FFBDD4D0FFC5DCD8FF
+ D1E8E4FFD9F0ECFFD7EEEAFFD1E8E4FFCFE6E2FFD3EAE6FFD2E7E4FFD7ECE9FF
+ D3E8E5FFC6DBD8FFBCD1CEFFBED3D0FFC7DCD9FFCDE2DFFFCEE3E0FFD1E6E3FF
+ D2E7E4FFD2E7E4FFD6EBE8FFD8EDEAFFD3E8E5FFC9DEDBFFCFE2DFFFC6D9D6FF
+ BFD2CFFFC4D7D4FFD2E5E2FFDAEDEAFFD5E8E5FFCDE0DDFFBACDCAFFB9CCC9FF
+ B6C9C6FFB3C6C3FFAFC2BFFFA2B5B2FF899C99FF748581FF515C59FF818B85FF
+ 87918BFF86908AFF8A948EFF8A948EFF919B95FF87918BFF808A84FF78827CFF
+ 717B75FF727C76FF7B857FFF848E88FF86908AFF858F89FF858F89FF848E88FF
+ 7F8983FF78827CFF77817BFF78827CFF747E78FF6D7771FF6D7771FF6A746EFF
+ 707A74FF7D8781FF7D8781FF737D77FF6F7973FF747F77FF828A83FF7D867CFF
+ 7E877DFF8C958BFF9DA89EFFA5B0A6FF9EA99FFF949F95FF97A59AFFA3B1A6FF
+ A3B3A8FF9AAA9FFF9BABA0FFA4B4A9FFA0B1A6FF92A398FF99A7A1FF9BA9A3FF
+ 9BA9A3FF9CAAA4FFA2B0AAFFA7B5AFFFA3B1ABFF9BA9A3FFA0AEA8FF9CAAA4FF
+ 99A7A1FF9AA8A2FF9EACA6FFA3B1ABFFA5B3ADFFA4B5ACFF98ADA4FFB3CBBFFF
+ BED6CAFFB7CFC3FFB8D0C6FFBDD5CBFFC4DCD2FFD0E8DEFFD0E7DFFFCCE3DBFF
+ CDE3DEFFD2E8E3FFE0F1EEFFDFF0EDFFE1F2EFFFE5F6F3FFE5F6F3FFE3F4F1FF
+ E7F8F5FFEEFFFCFFE2F3F0FFE3F4F1FFE5F6F3FFE7F8F5FFE9FAF7FFE9FAF7FF
+ E7F8F5FFE5F6F3FFE1F4F1FFE5F8F5FFE8FBF8FFE6F9F6FFE2F5F2FFE0F3F0FF
+ E3F6F3FFE6F9F6FFE2F5F2FFE7FAF7FFDFF2EFFFDAEDEAFFE0F3F0FFDCEFECFF
+ D2E5E2FFD3E6E3FFE0F3F0FFDEF1EEFFDEF1EEFFDEF1EEFFD5E8E5FFC9DCD9FF
+ C7DAD7FFCCDFDCFFCCDFDCFFCEE1DEFFD2E5E2FFD6E9E6FFD8EBE8FFD6E9E6FF
+ D0E3E0FFCBDEDBFFC8D9D5FFD3E4E0FFD5E6E2FFD3E4E0FFD8E7E3FFD6E5E1FF
+ C4D3CFFFB4C3BFFFC7D5D1FFB1BFBBFF9FAAA7FF87928FFF98A3A0FF8A9592FF
+ 97A09DFFA1AAA7FF9FABA5FF9DA9A3FF9BA7A1FF9AA6A0FF9BA7A1FF9FABA5FF
+ A5B1ABFFAAB6B0FFADB9B3FFA1ADA7FF9DA9A3FFA1ADA7FF9DA9A3FF94A09AFF
+ 9BA7A1FFACB8B2FFB0BBB8FFABB6B3FFA3B1ADFFA2B0ACFFA8B6B2FFB1BFBBFF
+ B7C6C2FFBCCBC7FFB7C8C4FFB8C9C5FFB7C8C4FFBDCECAFFC9DDD8FFD2E6E1FF
+ D5E9E4FFD9EDE8FFD4E9E6FFD7ECE9FFDDF2EFFFE3F8F5FFE5FAF7FFE1F6F3FF
+ D7ECE9FFCFE4E1FFC2D7D4FFC1D6D3FFCDE2DFFFC2D7D4FFC1D6D3FFCDE2DFFF
+ CBE0DDFFD7ECE9FFE2F9F5FFD8EFEBFFD5ECE8FFA8BFBBFFB3CAC6FFADC4C0FF
+ A2B9B5FFA0B7B3FFA4BBB7FFA6BDB9FFA7BEBAFFA5BCB8FFA0B7B3FF9DB4B0FF
+ 9CB3AFFF9DB4B0FFAABFBCFFA7BCB9FFA2B7B4FF9EB3B0FF9DB2AFFF9EB3B0FF
+ A0B5B2FFA1B6B3FF9DB2AFFFA1B6B3FF9FB4B1FF95AAA7FF8DA29FFF8CA19EFF
+ 8EA3A0FF8FA4A1FF8EA09FFF859796FF8D9B99FF82908EFF798482FF66716FFF
+ 5C6360FF7D8481FF848A85FF878D88FF818883FF787F7AFF758078FF7C877FFF
+ 7B8880FF76827CFF919F9BFFB3C1BFFFD3E1DFFFDCEAE8FFDFEDEBFFE0EEECFF
+ D4E2E0FFC1CFCDFFA0AEACFF92A09EFFB8C6C4FFC6D4D2FFC2D0CEFFDDEBE9FF
+ DFEDEBFFC8D9D6FFC3D6D3FFC9DEDBFFD4E9E6FFDEF3F0FFE1F6F3FFDDF2EFFF
+ D4E9E6FFCDE2DFFFC5DAD7FFC6DBD8FFCBE0DDFFD1E6E3FFCEE3E0FFC4D9D6FF
+ C1D6D3FFC4D9D6FFCADFDCFFD3E8E5FFD5EAE7FFCCE1DEFFC2D7D4FFC3D8D5FF
+ CADFDCFFCFE4E1FFD4E9E6FFD6EBE8FFD5EAE7FFD4E9E6FFD6EBE8FFD7ECE9FF
+ D0E5E2FFC6DBD8FFCBDEDBFFCFE2DFFFD1E4E1FFCBDEDBFFC1D4D1FFBCCFCCFF
+ BFD2CFFFC5D8D5FFC4D7D4FFC5D8D5FFC2D5D2FFB9CCC9FFAEC1BEFF9EB1AEFF
+ 879A97FF758682FF525D5AFF828C86FF86908AFF838D87FF848E88FF818B85FF
+ 858F89FF7A847EFF7B857FFF79837DFF76807AFF76807AFF7A847EFF808A84FF
+ 858F89FF88928CFF818B85FF858F89FF848E88FF7D8781FF78827CFF79837DFF
+ 7B857FFF79837DFF76807AFF6F7973FF707A74FF7A847EFF7B857FFF737D77FF
+ 727C76FF78837BFF79817AFF757E74FF788177FF889187FF9BA69CFFA5B0A6FF
+ A0ABA1FF96A197FF92A095FFA5B3A8FFACBCB1FFA3B3A8FF9EAEA3FFA4B4A9FF
+ A1B2A7FF96A79CFF98A6A0FF9AA8A2FF9CAAA4FF9DABA5FFA4B2ACFFAAB8B2FF
+ A9B7B1FFA3B1ABFFAFBDB7FFB0BEB8FFAFBDB7FFABB9B3FFA4B2ACFFA0AEA8FF
+ 9FADA7FF9FB0A7FFA8BDB4FFBED6CAFFC3DBCFFFBCD4C8FFC1D9CFFFC7DFD5FF
+ C9E1D7FFD1E9DFFFD9F0E8FFD4EBE3FFD4EAE5FFD9EFEAFFDBECE9FFDCEDEAFF
+ E1F2EFFFE5F6F3FFE2F3F0FFDCEDEAFFDEEFECFFE3F4F1FFE1F2EFFFE4F5F2FF
+ E6F7F4FFE6F7F4FFE3F4F1FFE2F3F0FFE3F4F1FFE4F5F2FFE5F8F5FFE3F6F3FF
+ E1F4F1FFE0F3F0FFE0F3F0FFDFF2EFFFDDF0EDFFDBEEEBFFE0F3F0FFE4F7F4FF
+ D8EBE8FFCEE1DEFFD2E5E2FFCCDFDCFFBDD0CDFFB8CBC8FFD1E4E1FFCBDEDBFF
+ CBDEDBFFCCDFDCFFC4D7D4FFB3C6C3FFACBFBCFFAEC1BEFFC0D3D0FFC0D3D0FF
+ C2D5D2FFC4D7D4FFC6D9D6FFC4D7D4FFC0D3D0FFBCCFCCFFAEBFBBFFB8C9C5FF
+ BACBC7FFC0D1CDFFD1E0DCFFCBDAD6FFBBCAC6FFB8C7C3FFC4D2CEFFAFBDB9FF
+ 9CA7A4FF848F8CFF9AA5A2FF8F9A97FF98A19EFF9BA4A1FFA1ADA7FFA1ADA7FF
+ 9EAAA4FF9BA7A1FF99A59FFF9AA6A0FF9DA9A3FFA1ADA7FFA9B5AFFFA2AEA8FF
+ 9CA8A2FF9AA6A0FF98A49EFF99A59FFFA2AEA8FFADB9B3FFA7B2AFFFA8B3B0FF
+ A7B5B1FFABB9B5FFAFBDB9FFB1BFBBFFB0BFBBFFB0BFBBFFB7C8C4FFABBCB8FF
+ 97A8A4FFA1B2AEFFC6DAD5FFDDF1ECFFDCF0EBFFDDF1ECFFDBF0EDFFDBF0EDFF
+ DDF2EFFFE3F8F5FFE7FCF9FFE6FBF8FFDFF4F1FFD9EEEBFFCBE0DDFFC6DBD8FF
+ D2E7E4FFCADFDCFFC8DDDAFFD0E5E2FFC9DEDBFFD3E8E5FFDEF5F1FFD6EDE9FF
+ D3EAE6FFA4BBB7FFAEC5C1FFACC3BFFFA3BAB6FFA0B7B3FFA3BAB6FFA6BDB9FF
+ A7BEBAFFA2B9B5FF9BB2AEFF96ADA9FF97AEAAFF9AB1ADFF9CB1AEFF9CB1AEFF
+ 9EB3B0FFA1B6B3FFA3B8B5FFA2B7B4FF9EB3B0FF9AAFACFF9CB1AEFFA0B5B2FF
+ 9DB2AFFF93A8A5FF8BA09DFF8A9F9CFF8A9F9CFF899E9BFF869897FF7D8F8EFF
+ 83918FFF788684FF737E7CFF646F6DFF5B625FFF79807DFF787E79FF888E89FF
+ 8C938EFF7E8580FF747F77FF7A857DFF7A877FFF74807AFF747F7CFF818E8CFF
+ 98A3A1FFADBAB8FFC5D0CEFFC9D6D4FFB5C0BEFF96A3A1FF9DA8A6FF7E8B89FF
+ 899492FF8D9A98FFA2ADABFFCAD7D5FFCCD7D5FFB7C5C3FFAABBB8FFAABFBCFF
+ B2C5C2FFB7CCC9FFC2D5D2FFCCE1DEFFDBEEEBFFE2F7F4FFDDF0EDFFCFE4E1FF
+ C9DCD9FFC8DDDAFFC7DAD7FFBED3D0FFBED1CEFFC1D6D3FFBBD0CDFFC6DBD8FF
+ CDE2DFFFC9DEDBFFC3D8D5FFC4D9D6FFC9DEDBFFCCE1DEFFCFE4E1FFD4E9E6FF
+ D5EAE7FFD4E9E6FFD4E9E6FFD5EAE7FFD0E5E2FFC9DEDBFFC5D8D5FFC4D7D4FF
+ C2D5D2FFBFD2CFFFBBCECBFFB7CAC7FFB3C6C3FFB1C4C1FFCADDDAFFC6D9D6FF
+ BACDCAFFAABDBAFF9DB0ADFF93A6A3FF859895FF7A8B87FF56615EFF858F89FF
+ 89938DFF86908AFF87918BFF838D87FF88928CFF7D8781FF78827CFF7B857FFF
+ 7D8781FF7D8781FF7B857FFF7B857FFF7F8983FF828C86FF78827CFF7F8983FF
+ 808A84FF79837DFF747E78FF76807AFF7A847EFF7C8680FF79837DFF747E78FF
+ 727C76FF757F79FF77817BFF76807AFF757F79FF78837BFF737B74FF717A70FF
+ 767F75FF868F85FF98A399FFA2ADA3FF9FAAA0FF97A298FF94A297FFA5B3A8FF
+ AFBFB4FFAABAAFFFA4B4A9FFA4B4A9FFA2B3A8FF9DAEA3FF98A6A0FF9DABA5FF
+ A1AFA9FFA1AFA9FFA4B2ACFFAAB8B2FFABB9B3FFA9B7B1FFA5B3ADFFADBBB5FF
+ B5C3BDFFB5C3BDFFADBBB5FFA4B2ACFF9EACA6FF9BACA3FFA9BEB5FFBED6CAFF
+ C5DDD1FFC1D9CDFFC8E0D6FFCEE6DCFFCDE5DBFFD1E9DFFFD7EEE6FFD1E8E0FF
+ D0E6E1FFD6ECE7FFBACBC7FFC0D1CDFFCADBD7FFD0E1DDFFCADBD7FFBDCECAFF
+ B7C8C4FFB9CAC6FFCBDCD8FFD1E2DEFFD7E8E4FFD7E8E4FFD4E5E1FFD5E6E2FF
+ DDEEEAFFE4F5F1FFDEF1EEFFCFE2DFFFC2D5D2FFC2D5D2FFCADDDAFFCADDDAFF
+ BCCFCCFFAEC1BEFFD5E8E5FFDEF1EEFFD4E7E4FFC7DAD7FFC6D9D6FFBFD2CFFF
+ B1C4C1FFADC0BDFFC2D5D2FFBBCECBFFBDD0CDFFC7DAD7FFC4D7D4FFB5C8C5FF
+ ACBFBCFFADC0BDFFC0D3D0FFBCCFCCFFB7CAC7FFB4C7C4FFB3C6C3FFB3C6C3FF
+ B2C5C2FFB1C4C1FFA8B9B5FFA8B9B5FFA0B1ADFFADBEBAFFC7D6D2FFBBCAC6FF
+ A6B5B1FFACBBB7FFAFBDB9FFA5B3AFFF9CA7A4FF86918EFFA0ABA8FF99A4A1FF
+ 9FA8A5FF9CA5A2FF9CA8A2FF9FABA5FFA2AEA8FFA1ADA7FF9DA9A3FF9AA6A0FF
+ 99A59FFF9AA6A0FF9FABA5FFA2AEA8FF9FABA5FF98A49EFF98A49EFFA1ADA7FF
+ A9B5AFFFAAB6B0FFA0ABA8FFA4AFACFFA7B5B1FFABB9B5FFAEBCB8FFAEBCB8FF
+ ADBCB8FFAEBDB9FFAFC0BCFFADBEBAFF9EAFABFFA8B9B5FFCFE3DEFFE1F5F0FF
+ DDF1ECFFE3F7F2FFDDF2EFFFDAEFECFFD9EEEBFFDCF1EEFFE2F7F4FFE4F9F6FF
+ E1F6F3FFDDF2EFFFDAEFECFFD2E7E4FFDBF0EDFFD4E9E6FFD3E8E5FFD8EDEAFF
+ CFE4E1FFD8EDEAFFDDF4F0FFD6EDE9FFCFE6E2FF9CB3AFFFA6BDB9FFA9C0BCFF
+ A5BCB8FFA5BCB8FFA3BAB6FFA2B9B5FF9FB6B2FF9CB3AFFF98AFABFF97AEAAFF
+ 97AEAAFF98AFABFF91A6A3FF92A7A4FF96ABA8FF9BB0ADFF9FB4B1FF9EB3B0FF
+ 99AEABFF94A9A6FF96ABA8FF9BB0ADFF9BB0ADFF95AAA7FF90A5A2FF8EA3A0FF
+ 899E9BFF849996FF859796FF798B8AFF7D8B89FF717F7DFF6F7A78FF65706EFF
+ 5B625FFF777E7BFF7B817CFF818782FF848B86FF7F8681FF78837BFF77827AFF
+ 77847CFF79857FFF747F7CFF717C79FF77807DFF828D8AFF939C99FF929D9AFF
+ 858E8BFF747F7CFF969F9CFF848F8CFF848D8AFF7A8582FF939C99FFB8C3C0FF
+ BCC5C2FFB7C5C1FFA3B2AEFF9DB1ACFF9AABA7FF92A6A1FF97A8A4FFA5B9B4FF
+ C0D1CDFFD2E6E1FFE2F3EFFFCFE3DEFFC8D9D5FFCDE1DCFFD3E4E0FFCBDFDAFF
+ C8D9D5FFC9DDD8FFBED1CEFFC7DAD7FFCDE0DDFFC9DCD9FFC5D8D5FFC6D9D6FF
+ C9DCD9FFC9DCD9FFC7DAD7FFCFE2DFFFD5E8E5FFD5E8E5FFD5E8E5FFD7EAE7FF
+ D6E9E6FFD3E6E3FFC3D6D3FFBCCFCCFFBBCECBFFC7DAD7FFDAEDEAFFE2F5F2FF
+ DBEEEBFFD0E3E0FFC3D6D3FFB8CBC8FFA7BAB7FF97AAA7FF91A4A1FF8DA09DFF
+ 819491FF768783FF5C6764FF8A948EFF8E9892FF8A948EFF8B958FFF89938DFF
+ 8F9993FF858F89FF79837DFF7E8882FF838D87FF848E88FF818B85FF7C8680FF
+ 78827CFF77817BFF757F79FF78827CFF76807AFF717B75FF707A74FF747E78FF
+ 77817BFF757F79FF77817BFF77817BFF747E78FF717B75FF737D77FF78827CFF
+ 77817BFF727D75FF717972FF727B71FF788177FF879086FF95A096FF9EA99FFF
+ 9CA79DFF97A298FF99A79CFFA0AEA3FFA5B5AAFFA7B7ACFFA5B5AAFFA1B1A6FF
+ 9EAFA4FF9EAFA4FF9AA8A2FFA2B0AAFFA7B5AFFFA3B1ABFFA1AFA9FFA4B2ACFF
+ A8B6B0FFA9B7B1FF9EACA6FFA3B1ABFFA9B7B1FFADBBB5FFADBBB5FFAAB8B2FF
+ A6B4AEFFA2B3AAFFA2B7AEFFBED6CAFFCCE4D8FFCAE2D6FFCDE5DBFFCDE5DBFF
+ CAE2D8FFCEE6DCFFD3EAE2FFCCE3DBFFCAE0DBFFD1E7E2FF8D9E9AFF98A9A5FF
+ A9BAB6FFB5C6C2FFB1C2BEFFA3B4B0FF99AAA6FF98A9A5FF95A6A2FF9FB0ACFF
+ AABBB7FFAEBFBBFFAFC0BCFFB5C6C2FFC3D4D0FFD0E1DDFFEDFFFDFFD3E6E3FF
+ BCCFCCFFBDD0CDFFCCDFDCFFCDE0DDFFB5C8C5FF9CAFACFFC8DBD8FFD7EAE7FF
+ D2E5E2FFC3D6D3FFBFD2CFFFB8CBC8FFAFC2BFFFAFC2BFFFBFD2CFFFB9CCC9FF
+ BFD2CFFFD1E4E1FFD7EAE7FFCCDFDCFFC4D7D4FFC5D8D5FFC6D9D6FFBED1CEFF
+ B2C5C2FFAABDBAFFA7BAB7FFA9BCB9FFACBFBCFFADC0BDFFB5C6C2FFA9BAB6FF
+ 97A8A4FFA6B7B3FFC3D2CEFFB0BFBBFF94A39FFF9BAAA6FF97A5A1FF99A7A3FF
+ 9AA5A2FF889390FFA4AFACFFA1ACA9FFA7B0ADFFA0A9A6FF939F99FF9AA6A0FF
+ A3AFA9FFA7B3ADFFA4B0AAFF9FABA5FF9BA7A1FF99A59FFF919D97FF9BA7A1FF
+ 9CA8A2FF929E98FF94A09AFFA2AEA8FFA7B3ADFFA1ADA7FFA0ABA8FFA3AEABFF
+ A3B1ADFFA4B2AEFFA5B3AFFFA9B7B3FFAFBEBAFFB4C3BFFFA2B3AFFFB9CAC6FF
+ BECFCBFFC6D7D3FFDBEFEAFFDCF0EBFFD7EBE6FFE7FBF6FFDDF2EFFFD7ECE9FF
+ D3E8E5FFD5EAE7FFDCF1EEFFE0F5F2FFE0F5F2FFDDF2EFFFE0F5F2FFD5EAE7FF
+ DDF2EFFFD6EBE8FFD5EAE7FFDAEFECFFD0E5E2FFDAEFECFFDFF6F2FFD6EDE9FF
+ CCE3DFFF95ACA8FF9FB6B2FFA6BDB9FFA8BFBBFFAAC1BDFFA0B7B3FF9BB2AEFF
+ 96ADA9FF95ACA8FF99B0ACFF9CB3AFFF9CB3AFFF9AB1ADFF99AEABFF96ABA8FF
+ 94A9A6FF95AAA7FF98ADAAFF9BB0ADFF9BB0ADFF99AEABFF90A5A2FF96ABA8FF
+ 9AAFACFF98ADAAFF96ABA8FF93A8A5FF8A9F9CFF819693FF899B9AFF7B8D8CFF
+ 7C8A88FF6F7D7BFF707B79FF687371FF5E6562FF777E7BFF888E89FF787E79FF
+ 717873FF7B827DFF7F8A82FF79847CFF748179FF78857DFF7B857FFF78817EFF
+ 78817EFF77807DFF717A77FF6D7673FF747D7AFF7F8885FF7B8481FF87908DFF
+ 909996FF7D8683FF858E8BFF9FA8A5FFA5AEABFFB8C3C0FFA3B2AEFFA7B8B4FF
+ A9BAB6FFA3B4B0FF99AAA6FF96A7A3FF9DAEAAFFA6B7B3FFCEDFDBFFC1D2CEFF
+ C1D2CEFFD4E5E1FFDFF0ECFFD8E9E5FFCDDEDAFFCADBD7FFD1E2DFFFD5E8E5FF
+ D7EAE7FFD0E3E0FFCBDEDBFFCCDFDCFFCCDFDCFFCBDEDBFFCADDDAFFD3E6E3FF
+ D9ECE9FFD6E9E6FFD3E6E3FFD2E5E2FFD2E5E2FFCFE2DFFFDAEDEAFFDDF0EDFF
+ DEF1EEFFD8EBE8FFCCDFDCFFC0D3D0FFB8CBC8FFB6C9C6FFBCCFCCFFAFC2BFFF
+ 9EB1AEFF95A8A5FF97AAA7FF94A7A4FF829592FF70817DFF5D6865FF8A948EFF
+ 8C9690FF87918BFF88928CFF86908AFF8C9690FF838D87FF7E8882FF828C86FF
+ 88928CFF8A948EFF88928CFF808A84FF76807AFF6F7973FF7C8680FF7A847EFF
+ 757F79FF707A74FF747E78FF7A847EFF79837DFF747E78FF77817BFF7C8680FF
+ 7A847EFF737D77FF76807AFF7E8882FF7B857FFF707B73FF727A73FF747D73FF
+ 7C857BFF889187FF939E94FF9AA59BFF9AA59BFF96A197FF9DABA0FF99A79CFF
+ 98A89DFF9FAFA4FFA1B1A6FF9DADA2FF99AA9FFF9AABA0FF9CAAA4FFA6B4AEFF
+ ABB9B3FFA5B3ADFF9EACA6FF9FADA7FFA4B2ACFFA6B4AEFFAEBCB6FFA8B6B0FF
+ A1AFA9FFA0AEA8FFA3B1ABFFA7B5AFFFA7B5AFFFA5B6ADFF9DB2A9FFC0D8CCFF
+ D5EDE1FFD3EBDFFFD1E9DFFFCAE2D8FFC5DDD3FFC9E1D7FFD7EEE6FFD0E7DFFF
+ CEE4DFFFD5EBE6FF8E9E97FFA4B4ADFFB3C3BCFFAEBEB7FFA0B0A9FF99A9A2FF
+ 97A7A0FF95A59EFF8A9A93FF91A19AFF9BABA4FF9FAFA8FF9BABA4FF9BABA4FF
+ AABAB3FFBACBC7FFD5E8E5FFE3F6F3FFDAEDEAFFC9DCD9FFCEE1DEFFCFE2DFFF
+ BCCFCCFFABBEBBFFAFC2BFFFC2D5D2FFCEE1DEFFC7DAD7FFBDD0CDFFB9CCC9FF
+ B5C8C5FFAEC1BEFFBCCFCCFFB9CCC9FFB9CCC9FFBCCFCCFFBFD2CFFFBCCFCCFF
+ B3C6C3FFABBEBBFFA9BCB9FFA7BAB7FFAABDBAFFB0C3C0FFB2C5C2FFAFC2BFFF
+ ABBEBBFFA9BCB9FFB0C1BDFFAEBFBBFFB1C2BEFF9AABA7FFA8B7B3FFAEBDB9FF
+ 869591FF8F9E9AFF98A6A2FF909E9AFF919C99FF8D9895FF8B9693FF9AA5A2FF
+ A6AFACFF9BA4A1FF939F99FF96A29CFF9AA6A0FF9AA6A0FF94A09AFF929E98FF
+ 9EAAA4FFAEBAB4FFA2AEA8FFA7B3ADFFA1ADA7FF94A09AFF97A39DFFA7B3ADFF
+ AAB6B0FF9FABA5FFA9B4B1FFADB8B5FFAEBCB8FFACBAB6FFA8B6B2FFA8B6B2FF
+ ADBCB8FFB2C1BDFFA0B1ADFFA6B7B3FFB5C6C2FFCBDCD8FFDAEEE9FFE1F5F0FF
+ DFF3EEFFDCF0EBFFD3E8E5FFD7ECE9FFDAEFECFFDAEFECFFD8EDEAFFD7ECE9FF
+ D9EEEBFFDBF0EDFFDCF1EEFFDEF3F0FFDDF2EFFFDAEFECFFD6EBE8FFD5EAE7FF
+ D8EDEAFFDBF0EDFFDDF4F0FFDBF2EEFFC7DEDAFF8AA19DFF9CB3AFFF9EB5B1FF
+ A6BDB9FFB0C7C3FFA8BFBBFF9EB5B1FF9AB1ADFF9FB6B2FF9CB3AFFF94ABA7FF
+ 99B0ACFFA6BDB9FF9EB3B0FF9CB1AEFF99AEABFF99AEABFF9AAFACFF98ADAAFF
+ 96ABA8FF93A8A5FF8EA3A0FF8FA4A1FF8FA4A1FF8FA4A1FF8DA29FFF8A9F9CFF
+ 889D9AFF869B98FF8A9C9BFF819392FF768482FF707E7CFF6F7A78FF5F6A68FF
+ 626966FF787F7CFF7D837EFF808681FF7E8580FF7A817CFF77827AFF79847CFF
+ 76837BFF727F77FF77817BFF787F7AFF7D847FFF828984FF7E8580FF777E79FF
+ 7B827DFF858C87FF7F8681FF878E89FF888F8AFF848B86FF8D948FFFA0A7A2FF
+ A8AFAAFFA0AAA4FFA4B2ACFF9DADA6FF9BABA4FF9FAFA8FF9FAFA8FF99A9A2FF
+ 93A39CFF92A29BFFAEBEB7FFABBBB4FFABBBB4FFB5C5BEFFC5D5CEFFD0E0D9FF
+ D2E2DBFFCDDEDAFFB8C9C6FFCEDFDCFFDBECE9FFD6E7E4FFD5E6E3FFDCEDEAFF
+ D6E7E4FFC6D7D4FFC7D8D5FFC5D6D3FFD7E8E5FFDCEDEAFFC9DAD7FFC6D7D4FF
+ C3D4D1FFACBDBAFFBFD2CFFFBDD0CDFFC2D5D2FFCADDDAFFC5D8D5FFB6C9C6FF
+ B2C5C2FFB8CBC8FFB2C5C2FFADC0BDFFA5B8B5FF9DB0ADFF94A7A4FF8A9D9AFF
+ 809390FF7B8C88FF646F6CFF89938DFF838D87FF7C8680FF7E8882FF7F8983FF
+ 8B958FFF86908AFF87918BFF8B958FFF8B958FFF848E88FF7F8983FF7F8983FF
+ 7E8882FF7B857FFF818B85FF7B857FFF737D77FF717B75FF737D77FF76807AFF
+ 76807AFF757F79FF828C86FF808A84FF828C86FF86908AFF848E88FF7D8781FF
+ 79837DFF79847CFF727A73FF737C72FF7D867CFF8E978DFF98A399FF9AA59BFF
+ 99A49AFF99A49AFF9AA89DFF9BA99EFF98A89DFFA2B2A7FFB0C0B5FFA9B9AEFF
+ 9DAEA3FFA4B5AAFF9EACA6FFA7B5AFFFAFBDB7FFB0BEB8FFAAB8B2FFA7B5AFFF
+ A9B7B1FFADBBB5FFA8B6B0FFABB9B3FFABB9B3FFA8B6B0FFA6B4AEFFA6B4AEFF
+ A2B0AAFF99AAA1FF99AEA5FFA6BEB2FFC5DDD1FFD5EDE1FFCDE5DBFFCAE2D8FF
+ CDE5DBFFC9E1D7FFD3EAE2FFCAE1D9FFC8DED9FFCFE5E0FF8F9F98FFA1B1AAFF
+ ADBDB6FFA5B5AEFF95A59EFF8C9C95FF899992FF889891FF92A29BFF8F9F98FF
+ 90A099FF94A49DFF96A69FFF95A59EFF99A9A2FF9FAFA8FFC6D7D4FFD9ECE9FF
+ D5E8E5FFC2D5D2FFC0D3D0FFC1D4D1FFB9CCC9FFB4C7C4FFB7CAC7FFC0D3D0FF
+ C1D4D1FFBACDCAFFB7CAC7FFBACDCAFFB7CAC7FFAEC1BEFFB5C8C5FFB2C5C2FF
+ B0C3C0FFB2C5C2FFB4C7C4FFB1C4C1FFA9BCB9FFA2B5B2FFAABDBAFFA8BBB8FF
+ A8BBB8FFABBEBBFFACBFBCFFAABDBAFFA7BAB7FFA5B8B5FFA5B6B2FFABBCB8FF
+ AEBFBBFFA2B3AFFFADBCB8FFB1C0BCFF95A4A0FF889793FF98A6A2FF8E9C98FF
+ 8E9996FF8B9693FF899491FF97A29FFFA0A9A6FF939C99FF86928CFF939F99FF
+ 99A59FFF94A09AFF94A09AFF9BA7A1FF9EAAA4FF9BA7A1FF96A29CFF97A39DFF
+ 929E98FF8C9892FF929E98FF9EAAA4FF9EAAA4FF95A19BFF9FAAA7FFA2ADAAFF
+ A3B1ADFFA2B0ACFFA1AFABFFA4B2AEFFABBAB6FFB2C1BDFF9EAFABFFA5B6B2FF
+ B6C7C3FFCBDCD8FFD3E7E2FFD2E6E1FFD1E5E0FFD5E9E4FFD4E9E6FFD7ECE9FF
+ DAEFECFFD9EEEBFFD7ECE9FFD6EBE8FFD8EDEAFFDAEFECFFD5EAE7FFD6EBE8FF
+ D6EBE8FFD3E8E5FFCFE4E1FFCEE3E0FFD1E6E3FFD4E9E6FFDAF1EDFFD8EFEBFF
+ C0D7D3FF8BA29EFF9FB6B2FFA0B7B3FFA6BDB9FFABC2BEFFA5BCB8FF99B0ACFF
+ 94ABA7FF99B0ACFF99B0ACFF92A9A5FF95ACA8FF9FB6B2FF9DB2AFFF99AEABFF
+ 94A9A6FF92A7A4FF92A7A4FF93A8A5FF92A7A4FF91A6A3FF8BA09DFF8BA09DFF
+ 8A9F9CFF889D9AFF859A97FF819693FF7D928FFF7B908DFF728483FF6F8180FF
+ 6A7876FF687674FF677270FF576260FF5C6360FF747B78FF797F7AFF7C827DFF
+ 7B827DFF787F7AFF768179FF7A857DFF78857DFF748179FF77817BFF7A817CFF
+ 7E8580FF828984FF7E8580FF777E79FF79807BFF818883FF868D88FF8D948FFF
+ 8D948FFF878E89FF8E9590FFA0A7A2FFABB2ADFFA8B2ACFFA5B3ADFF99A9A2FF
+ 94A29CFF98A8A1FF9FADA7FF9DADA6FF98A6A0FF93A39CFFA0AEA8FF9FAFA8FF
+ A1AFA9FFA6B6AFFFAEBCB6FFB5C5BEFFBBC9C3FFBCCCC5FFB7C8C5FFC9DAD7FF
+ D0E1DEFFC6D7D4FFC4D5D2FFD0E1DEFFD4E5E2FFCDDEDBFFCCDDDAFFCBDCD9FF
+ D1E2DFFFD0E1DEFFC8D9D6FFC9DAD7FFC6D7D4FFB9CAC7FFB2C5C2FFB3C6C3FF
+ BACDCAFFC4D7D4FFC2D5D2FFB5C8C5FFAEC1BEFFB0C3C0FFA5B8B5FFA3B6B3FF
+ A0B3B0FF9CAFACFF96A9A6FF8DA09DFF839693FF7D8E8AFF5C6764FF88928CFF
+ 86908AFF7C8680FF7D8781FF808A84FF8C9690FF858F89FF848E88FF88928CFF
+ 87918BFF818B85FF7D8781FF7F8983FF818B85FF808A84FF7E8882FF7B857FFF
+ 79837DFF78827CFF79837DFF78827CFF77817BFF76807AFF7A847EFF838D87FF
+ 858F89FF808A84FF808A84FF858F89FF828C86FF79847CFF757D76FF767F75FF
+ 7F887EFF90998FFF99A49AFF9BA69CFF9BA69CFF9CA79DFFA1AFA4FFA2B0A5FF
+ 9BABA0FFA2B2A7FFAFBFB4FFAABAAFFFA2B3A8FFA9BAAFFFA1AFA9FFA7B5AFFF
+ AEBCB6FFB0BEB8FFAEBCB6FFACBAB4FFADBBB5FFB0BEB8FFACBAB4FFA5B3ADFF
+ A6B4AEFFADBBB5FFACBAB4FFA2B0AAFF9FADA7FFA2B3AAFF99AEA5FFA3BBAFFF
+ BFD7CBFFD0E8DCFFC9E1D7FFC8E0D6FFCBE3D9FFC6DED4FFCFE6DEFFC6DDD5FF
+ C3D9D4FFC7DDD8FF92A09AFF9FADA7FFA8B6B0FFA0AEA8FF919F99FF899791FF
+ 87958FFF87958FFF93A19BFF8A9892FF87958FFF909E98FF9BA9A3FF9EACA6FF
+ 9BA9A3FF98A8A1FFAEBFBCFFCDE0DDFFD6E9E6FFC7DAD7FFBFD2CFFFBCCFCCFF
+ BACDCAFFBED1CEFFCADDDAFFC8DBD8FFBDD0CDFFB3C6C3FFB6C9C6FFBFD2CFFF
+ BCCFCCFFB1C4C1FFAEC1BEFFABBEBBFFA9BCB9FFA9BCB9FFABBEBBFFAABDBAFF
+ A4B7B4FF9FB2AFFFA8BBB8FFA7BAB7FFA5B8B5FFA6B9B6FFA7BAB7FFA6B9B6FF
+ A4B7B4FFA1B4B1FF9AABA7FFA7B8B4FFA8B9B5FFAABBB7FFABBAB6FFACBBB7FF
+ A1B0ACFF778682FFA0AEAAFF93A19DFF919C99FF8F9A97FF8E9996FF98A3A0FF
+ 9CA5A2FF8D9693FF84908AFF929E98FF94A09AFF8A9690FF8D9993FF9EAAA4FF
+ 9FABA5FF909C96FF98A49EFF939F99FF8F9B95FF939F99FF9CA8A2FFA1ADA7FF
+ 9DA9A3FF97A39DFF9CA7A4FF9FAAA7FF9EACA8FF9DABA7FF9CAAA6FF9EACA8FF
+ A4B3AFFFAAB9B5FFA1B2AEFFA6B7B3FFBACBC7FFD3E4E0FFD6EAE5FFCDE1DCFF
+ CEE2DDFFD9EDE8FFD7ECE9FFD9EEEBFFDAEFECFFD9EEEBFFD7ECE9FFD6EBE8FF
+ D7ECE9FFD8EDEAFFD7ECE9FFD7ECE9FFD7ECE9FFD5EAE7FFD3E8E5FFD2E7E4FF
+ D3E8E5FFD5EAE7FFDAF1EDFFD7EEEAFFB5CCC8FF8DA4A0FFA3BAB6FFA5BCB8FF
+ A7BEBAFFA7BEBAFFA4BBB7FF97AEAAFF91A8A4FF95ACA8FF98AFABFF94ABA7FF
+ 94ABA7FF9AB1ADFFA1B6B3FF9BB0ADFF94A9A6FF90A5A2FF90A5A2FF91A6A3FF
+ 93A8A5FF93A8A5FF899E9BFF899E9BFF879C99FF849996FF7F9491FF798E8BFF
+ 748986FF718683FF657776FF677978FF677573FF667472FF636E6CFF525D5BFF
+ 59605DFF747B78FF757B76FF797F7AFF79807BFF777E79FF768179FF7A857DFF
+ 79867EFF76837BFF78827CFF79837DFF7D8781FF808A84FF7B857FFF747E78FF
+ 737D77FF78827CFF848E88FF8C9690FF8D9791FF87918BFF8B958FFF9CA6A0FF
+ AAB4AEFFAEB8B2FFABB7B1FF99A7A1FF919D97FF93A19BFF9FABA5FF9FADA7FF
+ 9DA9A3FF97A59FFF97A39DFF98A6A0FF9FABA5FFA1AFA9FFA8B4AEFFAEBCB6FF
+ BBC7C1FFC1CFC9FFB7C5C3FFC4D5D2FFC8D9D6FFBECFCCFFBCCDCAFFC7D8D5FF
+ CDDEDBFFC8D9D6FFCEDFDCFFD4E5E2FFCDDEDBFFC5D6D3FFCADBD8FFCBDCD9FF
+ C7D8D5FFC8D9D6FFA9BCB9FFA8BBB8FFADC0BDFFB7CAC7FFBBCECBFFB6C9C6FF
+ ADC0BDFFA8BBB8FF9EB1AEFF9EB1AEFF9DB0ADFF9CAFACFF97AAA7FF8EA19EFF
+ 829592FF7C8D89FF525D5AFF89938DFF8D9791FF818B85FF7F8983FF858F89FF
+ 919B95FF858F89FF88928CFF8B958FFF8A948EFF838D87FF7F8983FF818B85FF
+ 838D87FF828C86FF79837DFF7C8680FF7F8983FF808A84FF7D8781FF7A847EFF
+ 79837DFF78827CFF747E78FF848E88FF87918BFF7B857FFF7C8680FF8A948EFF
+ 8A948EFF7B867EFF767E77FF778076FF80897FFF8F988EFF97A298FF99A49AFF
+ 9AA59BFF9CA79DFFA9B7ACFFA8B6ABFF9FAFA4FFA2B2A7FFAEBEB3FFACBCB1FF
+ A5B6ABFFACBDB2FFA6B4AEFFA8B6B0FFABB9B3FFAEBCB6FFAEBCB6FFADBBB5FF
+ ABB9B3FFAAB8B2FFB0BEB8FFA3B1ABFFA5B3ADFFB3C1BBFFB3C1BBFFA3B1ABFF
+ A1AFA9FFADBEB5FF9BB0A7FFA1B9ADFFBAD2C6FFCAE2D6FFC6DED4FFC8E0D6FF
+ CBE3D9FFC4DCD2FFCEE5DDFFC7DED6FFC2D8D3FFC2D8D3FF8D9B95FF96A49EFF
+ 9CAAA4FF98A6A0FF8F9D97FF899791FF899791FF8C9A94FF8E9C96FF899791FF
+ 899791FF94A29CFF9DABA5FF9EACA6FF9DABA5FF9CACA5FF9BACA8FFC1D4D1FF
+ D7EAE7FFD2E5E2FFCCDFDCFFC3D6D3FFBDD0CDFFC0D3D0FFC4D7D4FFBFD2CFFF
+ B1C4C1FFA4B7B4FFA6B9B6FFAFC2BFFFADC0BDFFA3B6B3FFA6B9B6FFA4B7B4FF
+ A2B5B2FFA2B5B2FFA3B6B3FFA2B5B2FF9EB1AEFF9BAEABFFA1B4B1FFA3B6B3FF
+ A4B7B4FFA4B7B4FFA6B9B6FFA7BAB7FFA3B6B3FF9DB0ADFF98A9A5FFA7B8B4FF
+ A1B2AEFFABBCB8FFA3B2AEFFA1B0ACFFA5B4B0FF6A7975FF9FADA9FF909E9AFF
+ 8E9996FF8F9A97FF8F9A97FF96A19EFF98A19EFF8A9390FF929E98FF95A19BFF
+ 909C96FF86928CFF87938DFF94A09AFF9CA8A2FF9AA6A0FFA3AFA9FF99A59FFF
+ 95A19BFF9EAAA4FFA8B4AEFFA7B3ADFFA0ACA6FF9DA9A3FFA3AEABFFA6B1AEFF
+ A5B3AFFFA4B2AEFFA2B0ACFFA0AEAAFFA1B0ACFFA3B2AEFFA2B3AFFFA4B5B1FF
+ B8C9C5FFD5E6E2FFDDF1ECFFD3E7E2FFD4E8E3FFE1F5F0FFDCF1EEFFDCF1EEFF
+ DBF0EDFFDAEFECFFD9EEEBFFD8EDEAFFD8EDEAFFD9EEEBFFDAEFECFFDAEFECFF
+ DAEFECFFD9EEEBFFD8EDEAFFD7ECE9FFD8EDEAFFD8EDEAFFDCF3EFFFD8EFEBFF
+ A8BFBBFF8CA39FFFA2B9B5FFA7BEBAFFA8BFBBFFA4BBB7FFA6BDB9FF9AB1ADFF
+ 93AAA6FF97AEAAFF9BB2AEFF9AB1ADFF98AFABFF99B0ACFF9CB1AEFF97ACA9FF
+ 91A6A3FF8DA29FFF8DA29FFF8DA29FFF8DA29FFF8CA19EFF899E9BFF889D9AFF
+ 869B98FF829794FF7D928FFF788D8AFF728784FF6F8481FF697B7AFF6C7E7DFF
+ 6C7A78FF667472FF5F6A68FF4B5654FF555C59FF737A77FF767C77FF7A807BFF
+ 7A817CFF777E79FF768179FF7B867EFF7A877FFF77847CFF76807AFF79837DFF
+ 7C8680FF7C8680FF78827CFF727C76FF707A74FF707A74FF7A847EFF848E88FF
+ 89938DFF87918BFF8A948EFF98A29CFFA6B0AAFFADB7B1FFAEBAB4FFA0ACA6FF
+ 95A19BFF96A29CFF9CA8A2FF9EAAA4FF9DA9A3FF9DA9A3FF9BA7A1FF9CA8A2FF
+ 9EAAA4FF9FABA5FFA3AFA9FFAAB6B0FFB4C0BAFFB9C7C1FFB0BFBBFFBBCCC9FF
+ C1D2CFFFBFD0CDFFC0D1CEFFC6D7D4FFC1D2CFFFB4C5C2FFC5D6D3FFD8E9E6FF
+ D2E3E0FFC7D8D5FFCFE0DDFFCCDDDAFFC5D6D3FFD1E2DFFFB0C3C0FFA7BAB7FF
+ 9FB2AFFFA4B7B4FFB2C5C2FFBACDCAFFB3C6C3FFA7BAB7FFA5B8B5FFA4B7B4FF
+ A1B4B1FF9DB0ADFF96A9A6FF8B9E9BFF7F928FFF798A86FF4B5653FF89938DFF
+ 929C96FF86908AFF848E88FF8A948EFF959F99FF87918BFF8D9791FF929C96FF
+ 919B95FF8A948EFF858F89FF848E88FF838D87FF808A84FF78827CFF7C8680FF
+ 818B85FF808A84FF7C8680FF79837DFF7A847EFF7C8680FF77817BFF808A84FF
+ 818B85FF7C8680FF7E8882FF86908AFF86908AFF7F8A82FF777F78FF788177FF
+ 7F887EFF8C958BFF929D93FF939E94FF95A096FF99A49AFFA8B6ABFFAAB8ADFF
+ A0B0A5FFA1B1A6FFADBDB2FFABBBB0FFA3B4A9FFA8B9AEFFA9B7B1FFA8B6B0FF
+ A7B5AFFFA9B7B1FFABB9B3FFAAB8B2FFA5B3ADFFA1AFA9FFAEBCB6FFA9B7B1FF
+ ACBAB4FFB3C1BBFFB3C1BBFFAAB8B2FFABB9B3FFB2C3BAFFA0B5ACFFA3BBAFFF
+ B9D1C5FFC8E0D4FFC7DFD5FFC9E1D7FFCCE4DAFFC5DDD3FFCFE6DEFFCBE2DAFF
+ C6DCD7FFC3D9D4FF88978FFF8C9B93FF909F97FF909F97FF8B9A92FF86958DFF
+ 87968EFF8B9A92FF8D9C94FF8F9E96FF94A39BFF98A79FFF95A49CFF909F97FF
+ 93A29AFF9AAAA3FF93A4A0FFB3C6C3FFC6D9D6FFC7DAD7FFC8DBD8FFC2D5D2FF
+ BACDCAFFBCCFCCFFBACDCAFFBDD0CDFFB7CAC7FFABBEBBFFA9BCB9FFAFC2BFFF
+ AFC2BFFFA8BBB8FFA6B9B6FFA4B7B4FFA1B4B1FF9FB2AFFF9DB0ADFF9AADAAFF
+ 96A9A6FF92A5A2FF9AADAAFFA0B3B0FFA4B7B4FFA5B8B5FFA8BBB8FFABBEBBFF
+ A6B9B6FF9DB0ADFF9CADA9FFA7B8B4FF9FB0ACFFA7B8B4FF9EADA9FF9DACA8FF
+ A9B8B4FF758480FF8F9D99FF808E8AFF818C89FF889390FF8A9592FF919C99FF
+ 97A09DFF8D9693FF9FABA5FF97A39DFF929E98FF929E98FF8E9A94FF8A9690FF
+ 95A19BFFA5B1ABFFA4B0AAFF99A59FFF95A19BFF9CA8A2FFA3AFA9FFA1ADA7FF
+ 9BA7A1FF98A49EFFA3AEABFFA8B3B0FFABB9B5FFAFBDB9FFB0BEBAFFAEBCB8FF
+ ACBBB7FFACBBB7FFA6B7B3FFA4B5B1FFB3C4C0FFD0E1DDFFDDF1ECFFD9EDE8FF
+ D8ECE7FFDEF2EDFFDFF4F1FFDEF3F0FFDCF1EEFFDBF0EDFFDAEFECFFDBF0EDFF
+ DBF0EDFFDBF0EDFFD6EBE8FFD6EBE8FFD5EAE7FFD5EAE7FFD6EBE8FFD5EAE7FF
+ D4E9E6FFD4E9E6FFDAF1EDFFD7EEEAFF97AEAAFF89A09CFF9CB3AFFFA2B9B5FF
+ A4BBB7FF9EB5B1FFA5BCB8FF9BB2AEFF95ACA8FF97AEAAFF9BB2AEFF9CB3AFFF
+ 99B0ACFF98AFABFF91A6A3FF8EA3A0FF8A9F9CFF879C99FF869B98FF849996FF
+ 819693FF7E9390FF859A97FF849996FF839895FF809592FF7C918EFF778C89FF
+ 728784FF708582FF6E807FFF6F8180FF6C7A78FF63716FFF596462FF46514FFF
+ 535A57FF757C79FF787E79FF7C827DFF7B827DFF787F7AFF77827AFF7B867EFF
+ 79867EFF76837BFF738078FF76837BFF78857DFF76837BFF738078FF707D75FF
+ 6D7A72FF6B7870FF6E7B73FF79867EFF849189FF88958DFF8D9A92FF97A49CFF
+ A3B0A8FFAAB7AFFFB3BEB6FFAAB5ADFFA2ADA5FF9FAAA2FF9DA8A0FF9AA59DFF
+ 9DA8A0FFA2ADA5FFA8B3ABFFA3AEA6FF9BA69EFF97A29AFF97A29AFF98A39BFF
+ 9AA59DFF98A49EFFA5B3AFFFA9B7B5FFADBBB9FFB1BFBDFFBBC9C7FFC1CFCDFF
+ B7C5C3FFA7B5B3FFB5C3C1FFD4E2E0FFDAE8E6FFD3E1DFFFD6E4E2FFCCDAD8FF
+ C3D1CFFFCFE0DDFFC1D4D1FFB0C3C0FF9BAEABFF96A9A6FFA8BBB8FFBDD0CDFF
+ BBCECBFFADC0BDFFAEC1BEFFAABDBAFFA4B7B4FF9DB0ADFF96A9A6FF8C9F9CFF
+ 829592FF7E8F8BFF45504DFF838D87FF8F9993FF88928CFF86908AFF89938DFF
+ 929C96FF858F89FF88928CFF8E9892FF919B95FF8C9690FF87918BFF858F89FF
+ 828C86FF7D8781FF7A847EFF7C8680FF7D8781FF7B857FFF78827CFF78827CFF
+ 7C8680FF808A84FF818B85FF7A847EFF7A847EFF818B85FF828C86FF7C8680FF
+ 7D8781FF859088FF7C847DFF7D867CFF838C82FF8D968CFF909B91FF909B91FF
+ 939E94FF98A399FFA1AFA4FFA7B5AAFF9FAFA4FF9FAFA4FFAABAAFFFA9B9AEFF
+ 9FB0A5FFA0B1A6FFA8B6B0FFA5B3ADFFA3B1ABFFA6B4AEFFAAB8B2FFABB9B3FF
+ A6B4AEFFA2B0AAFFA6B4AEFFB0BEB8FFB2C0BAFFABB9B3FFA9B7B1FFAFBDB7FF
+ B1BFB9FFABBCB3FFA6BBB2FFA8C0B4FFBDD5C9FFCBE3D7FFC9E1D7FFCBE3D9FF
+ CEE6DCFFC6DED4FFC8DFD7FFC8DFD7FFC5DBD6FFC1D7D2FF91A098FF909F97FF
+ 93A29AFF95A49CFF909F97FF8A9991FF899890FF8C9B93FF8B9A92FF8F9E96FF
+ 96A59DFF99A8A0FF94A39BFF8F9E96FF96A59DFFA1B1AAFF94A5A1FFA5B8B5FF
+ AABDBAFFA9BCB9FFB0C3C0FFB1C4C1FFAFC2BFFFB4C7C4FFADC0BDFFB7CAC7FF
+ BACDCAFFB2C5C2FFAEC1BEFFB3C6C3FFB4C7C4FFAFC2BFFFAEC1BEFFADC0BDFF
+ ABBEBBFFA8BBB8FFA3B6B3FF9DB0ADFF98ABA8FF94A7A4FF97AAA7FFA0B3B0FF
+ A4B7B4FFA2B5B2FFA6B9B6FFACBFBCFFA8BBB8FF9EB1AEFFA2B3AFFFA8B9B5FF
+ A3B4B0FFA3B4B0FFA0AFABFFA2B1ADFFA9B8B4FF94A39FFF899793FF7C8A86FF
+ 818C89FF8A9592FF8C9794FF949F9CFF9FA8A5FF9DA6A3FFA1ADA7FF95A19BFF
+ 95A19BFF9FABA5FF99A59FFF8B9791FF919D97FFA5B1ABFFA0ACA6FF9CA8A2FF
+ 97A39DFF96A29CFF99A59FFF9BA7A1FF99A59FFF97A39DFF9DA8A5FFA2ADAAFF
+ A8B6B2FFB1BFBBFFB6C4C0FFB9C7C3FFB8C7C3FFB8C7C3FFB4C5C1FFB4C5C1FF
+ BECFCBFFD1E2DEFFDDF1ECFFE0F4EFFFDEF2EDFFDCF0EBFFE0F5F2FFDDF2EFFF
+ DAEFECFFD9EEEBFFDBF0EDFFDCF1EEFFDDF2EFFFDCF1EEFFD6EBE8FFD5EAE7FF
+ D4E9E6FFD6EBE8FFD7ECE9FFD7ECE9FFD5EAE7FFD3E8E5FFD5ECE8FFD5ECE8FF
+ 8BA29EFF89A09CFF97AEAAFF9CB3AFFF9EB5B1FF95ACA8FF9EB5B1FF99B0ACFF
+ 95ACA8FF94ABA7FF97AEAAFF98AFABFF97AEAAFF94ABA7FF91A6A3FF8EA3A0FF
+ 8BA09DFF899E9BFF889D9AFF849996FF809592FF7C918EFF7F9491FF7F9491FF
+ 7E9390FF7C918EFF798E8BFF748986FF708582FF6E8380FF738584FF728483FF
+ 6D7B79FF647270FF5C6765FF4C5755FF5B625FFF7C8380FF767C77FF7A807BFF
+ 7A817CFF777E79FF768179FF7A857DFF78857DFF75827AFF738078FF74837BFF
+ 76837BFF718078FF717E76FF718078FF727F77FF6C7B73FF6E7B73FF75847CFF
+ 839088FF8A9991FF94A199FF99A8A0FFA4B1A9FFA9B6AEFFB3BEB6FFAEB9B1FF
+ A9B4ACFFA5B0A8FF9EA9A1FF98A39BFF99A49CFF9FAAA2FFACB7AFFFA6B1A9FF
+ 9EA9A1FF99A49CFF99A49CFF99A49CFF97A29AFF939F99FF9AA8A4FF97A5A3FF
+ 94A2A0FF98A6A4FFA5B3B1FFB1BFBDFFB0BEBCFFA7B5B3FFA3B1AFFFC1CFCDFF
+ D5E3E1FFD8E6E4FFD4E2E0FFCBD9D7FFC5D3D1FFC7D8D5FFCDDEDBFFBED1CEFF
+ A5B8B5FF94A7A4FFA0B3B0FFB8CBC8FFBCCFCCFFB1C4C1FFAFC2BFFFABBEBBFF
+ A5B8B5FF9FB2AFFF99ACA9FF92A5A2FF8A9D9AFF879894FF434E4BFF79837DFF
+ 858F89FF87918BFF88928CFF848E88FF8B958FFF828C86FF7B857FFF838D87FF
+ 87918BFF858F89FF838D87FF838D87FF818B85FF7E8882FF7C8680FF7B857FFF
+ 78827CFF76807AFF757F79FF78827CFF7E8882FF828C86FF88928CFF79837DFF
+ 77817BFF848E88FF848E88FF78827CFF7A847EFF89948CFF868E87FF868F85FF
+ 8B948AFF929B91FF929D93FF919C92FF949F95FF9AA59BFF9DABA0FFA5B3A8FF
+ 9EAEA3FF9CACA1FFA8B8ADFFA8B8ADFF9EAFA4FF9CADA2FFA5B3ADFFA3B1ABFF
+ A3B1ABFFA7B5AFFFACBAB4FFAEBCB6FFADBBB5FFAAB8B2FFA0AEA8FFB1BFB9FF
+ B3C1BBFFA4B2ACFF9FADA7FFACBAB4FFAEBCB6FFA2B3AAFFA8BDB4FFACC4B8FF
+ C2DACEFFCEE6DAFFC9E1D7FFC9E1D7FFCCE4DAFFC6DED4FFBCD3CBFFC1D8D0FF
+ C1D7D2FFBCD2CDFF9CA9A1FF99A69EFF9BA8A0FF9FACA4FF9CA9A1FF94A199FF
+ 909D95FF94A199FF909D95FF8C9991FF8C9991FF929F97FF96A39BFF97A49CFF
+ 9BA8A0FF9EACA6FF92A39FFF9CAFACFF9AADAAFF97AAA7FFA0B3B0FFA3B6B3FF
+ A3B6B3FFABBEBBFF94A7A4FFA0B3B0FFA5B8B5FF9FB2AFFF9CAFACFF9FB2AFFF
+ 9DB0ADFF95A8A5FFA8BBB8FFAABDBAFFACBFBCFFACBFBCFFA9BCB9FFA5B8B5FF
+ A1B4B1FF9EB1AEFF9BAEABFFA2B5B2FFA2B5B2FF9CAFACFF9FB2AFFFA9BCB9FF
+ A8BBB8FF9FB2AFFFA9BAB6FFA8B9B5FFA9BAB6FF9FB0ACFFA3B2AEFFA4B3AFFF
+ 9DACA8FFACBBB7FF97A5A1FF8A9894FF8E9996FF95A09DFF909B98FF95A09DFF
+ A3ACA9FFA5AEABFF9FABA5FF96A29CFF939F99FF98A49EFF98A49EFF94A09AFF
+ 98A49EFFA2AEA8FF9FABA5FFA2AEA8FF9CA8A2FF929E98FF919D97FF9CA8A2FF
+ A1ADA7FF9DA9A3FFA1ACA9FFA3AEABFFA4B2AEFFA8B6B2FFADBBB7FFB0BEBAFF
+ B0BFBBFFB0BFBBFFBACBC7FFC4D5D1FFCDDEDAFFD3E4E0FFDAEEE9FFE3F7F2FF
+ E4F8F3FFDFF3EEFFDEF3F0FFDAEFECFFD7ECE9FFD6EBE8FFD9EEEBFFDCF1EEFF
+ DCF1EEFFDCF1EEFFDAEFECFFD8EDEAFFD8EDEAFFDAEFECFFDCF1EEFFDDF2EFFF
+ DAEFECFFD6EBE8FFD2E9E5FFD9F0ECFF8BA29EFF95ACA8FF9DB4B0FF9DB4B0FF
+ 9CB3AFFF91A8A4FF99B0ACFF99B0ACFF97AEAAFF94ABA7FF93AAA6FF95ACA8FF
+ 95ACA8FF94ABA7FF9BB0ADFF97ACA9FF92A7A4FF8EA3A0FF8CA19EFF8A9F9CFF
+ 869B98FF849996FF7F9491FF7F9491FF7D928FFF7B908DFF778C89FF728784FF
+ 6E8380FF6B807DFF748685FF728483FF6D7B79FF677573FF616C6AFF515C5AFF
+ 5C6360FF7B827FFF717772FF757B76FF757C77FF747B76FF747F77FF79847CFF
+ 78857DFF75827AFF73827AFF75867DFF75847CFF6F8077FF707F77FF75867DFF
+ 77867EFF72837AFF74837BFF76877EFF7F8E86FF899A91FF93A29AFF99AAA1FF
+ A1B0A8FFA5B4ACFFB0BDB5FFACB7AFFFA8B3ABFFA7B2AAFFA3AEA6FF9BA69EFF
+ 97A29AFF98A39BFFA7B2AAFFA7B2AAFFA6B1A9FFA3AEA6FFA1ACA4FFA1ACA4FF
+ A3AEA6FFA4B0AAFF99A7A3FF97A5A3FF93A19FFF92A09EFF98A6A4FFA4B2B0FF
+ ABB9B7FFACBAB8FF99A7A5FFA9B7B5FFC4D2D0FFD0DEDCFFCCDAD8FFCCDAD8FF
+ CBD9D7FFBFD0CDFFC8D9D6FFC8DBD8FFB8CBC8FF9EB1AEFF9AADAAFFACBFBCFF
+ B5C8C5FFAFC2BFFFADC0BDFFABBEBBFFA7BAB7FFA3B6B3FF9EB1AEFF97AAA7FF
+ 8EA19EFF899A96FF495451FF747E78FF7F8983FF89938DFF8D9791FF838D87FF
+ 87918BFF838D87FF79837DFF7E8882FF808A84FF7C8680FF7B857FFF7F8983FF
+ 818B85FF808A84FF7E8882FF7A847EFF76807AFF747E78FF77817BFF7B857FFF
+ 7F8983FF818B85FF87918BFF7E8882FF7C8680FF828C86FF828C86FF7E8882FF
+ 818B85FF8A958DFF8C948DFF8C958BFF8F988EFF949D93FF919C92FF8F9A90FF
+ 929D93FF99A49AFF9EACA1FFA6B4A9FF9EAEA3FF99A99EFFA5B5AAFFA9B9AEFF
+ A2B3A8FFA0B1A6FFA5B3ADFFA5B3ADFFA5B3ADFFA7B5AFFFA9B7B1FFAAB8B2FF
+ AAB8B2FFA9B7B1FFA5B3ADFFB0BEB8FFB1BFB9FFA7B5AFFFA1AFA9FFA5B3ADFF
+ A7B5AFFFA3B4ABFFA5BAB1FFADC5B9FFC4DCD0FFCFE7DBFFC6DED4FFC3DBD1FF
+ C7DFD5FFC2DAD0FFBAD1C9FFC2D9D1FFC4DAD5FFBFD5D0FF9AA79FFF96A39BFF
+ 98A59DFF9EABA3FF9EABA3FF95A29AFF919E96FF95A29AFF9BA8A0FF8B9890FF
+ 808D85FF85928AFF8F9C94FF909D95FF8A978FFF83918BFF8FA09CFF99ACA9FF
+ 9CADAAFF99ACA9FFA2B3B0FFA0B3B0FF9FB0ADFFA4B7B4FF9EAFACFFA4B7B4FF
+ A8B9B6FF9FB2AFFF9FB0ADFF9FB2AFFF9BACA9FF8DA09DFF95A6A3FF98ABA8FF
+ A1B2AFFFA4B7B4FFA8B9B6FFA5B8B5FFA5B6B3FFA2B5B2FFA2B3B0FFA5B8B5FF
+ A2B3B0FF96A9A6FF9AABA8FFA5B8B5FFA9BAB7FFA1B2AFFFAEBFBBFFA9BAB6FF
+ AFC0BCFF9CADA9FFA3B2AEFFA2B1ADFF8E9D99FFB4C3BFFFA4B2AEFF95A39FFF
+ 97A29FFF99A4A1FF8D9895FF8C9794FF9AA3A0FF9FA8A5FFA2AEA8FF9AA6A0FF
+ 8E9A94FF87938DFF8D9993FF9BA7A1FFA3AFA9FFA2AEA8FF9BA7A1FFA4B0AAFF
+ 9FABA5FF8E9A94FF8C9892FF9CA8A2FFA6B2ACFFA2AEA8FFADB9B3FFAAB6B0FF
+ A3B1ADFFA0AEAAFF9FADA9FF9FADA9FF9EADA9FF9EADA9FFB3C4C0FFC5D6D2FF
+ D0E1DDFFCEDFDBFFD0E4DFFFDEF2EDFFE4F8F3FFDFF2EFFFDBF0EDFFD7ECE9FF
+ D3E8E5FFD4E9E6FFD7ECE9FFDBF0EDFFDBF0EDFFDBF0EDFFD9EEEBFFD8EDEAFF
+ D7ECE9FFDAEFECFFDDF2EFFFDDF2EFFFDAEFECFFD6EBE8FFD2E9E5FFDDF6F2FF
+ 91A8A4FFA0B9B5FFA7BEBAFFA1BAB6FF9FB6B2FF8FA8A4FF98AFABFF98B1ADFF
+ 9AB1ADFF94ADA9FF93AAA6FF92ABA7FF96ADA9FF95ACA8FF9EB5B1FF99AEABFF
+ 91A6A3FF8BA09DFF899E9BFF889D9AFF889D9AFF879C99FF829794FF829794FF
+ 809592FF7D928FFF788D8AFF738885FF708380FF6D807DFF6F8180FF6F7F7EFF
+ 687674FF64716FFF5B6866FF4B5654FF505956FF6E7572FF6A716CFF6F7671FF
+ 717873FF707772FF727D75FF78837BFF7A857DFF76837BFF75847CFF77887FFF
+ 76857DFF6F8077FF728179FF798A81FF7D8C84FF77887FFF7A8981FF788980FF
+ 7C8B83FF84958CFF909F97FF96A79EFF9DACA4FFA2B1A9FFAFBCB4FFA7B4ACFF
+ A4AEA8FFA4B1A9FFA6B0AAFF9DAAA2FF96A09AFF909D95FFA2ACA6FFA5B2AAFF
+ AAB4AEFFA2AFA7FF9BA59FFF95A29AFF9AA49EFF9EAAA4FF9FADA9FFA2B0ACFF
+ A3B0AEFF9EADA9FF9CA9A7FF9FAEAAFFA8B6B4FFAEBDB9FF96A4A2FF98A7A3FF
+ B3C1BFFFC6D5D1FFC3D1CFFFCDDCD8FFD1DFDDFFBBCCC9FFBECFCCFFCCDFDCFF
+ C9DAD7FFA9BCB9FF9AABA8FFA2B5B2FFAFC0BDFFACBFBCFFAFC0BDFFACBFBCFF
+ ACBDBAFFA8BBB8FFA4B5B2FF98ABA8FF8E9F9CFF879692FF515C59FF757F79FF
+ 7D8781FF8E9892FF949E98FF858F89FF88928CFF87918BFF808A84FF838D87FF
+ 808A84FF79837DFF77817BFF7C877FFF818B85FF828D85FF7E8882FF79847CFF
+ 757F79FF768179FF7A847EFF7F8A82FF808A84FF7F8A82FF838D87FF859088FF
+ 838D87FF7E8981FF7F8983FF869189FF8A948EFF89948CFF8E978DFF8D968CFF
+ 8F988EFF929B91FF8E998FFF8B968CFF8E998FFF95A096FFA2B0A5FFAAB8ADFF
+ 9EAEA3FF97A79CFFA3B3A8FFABBBB0FFA6B7ACFFA6B7ACFFA9B7B1FFA9B7B1FF
+ A8B6B0FFA6B4AEFFA3B1ABFFA1AFA9FFA0AEA8FFA0AEA8FFB0BEB8FFAFBDB7FF
+ B0BEB8FFAFBDB7FFA8B6B0FFA1AFA9FFA3B1ABFFAABAB3FFA2B7AEFFABC3B9FF
+ C5DDD3FFCFE7DDFFC2DAD0FFBED6CCFFC1D8D0FFBDD4CCFFBFD6CEFFC9E0D8FF
+ CDE3DEFFC7DDD8FF8C9690FF97A19BFF9CA6A0FF97A19BFF939D97FF96A09AFF
+ 96A09AFF929C96FF939D97FF8E9892FF89938DFF86908AFF838D87FF858F89FF
+ 919B95FF9CA8A2FF9AA9A5FF98A9A5FF9AA9A5FF97A8A4FF99A8A4FF98A9A5FF
+ 9DACA8FF9EAFABFFA9B8B4FF91A29EFF9BAAA6FFA8B9B5FFA4B3AFFFA6B7B3FF
+ A9B8B4FF93A4A0FF909F9BFF9AABA7FFA1B0ACFF9CADA9FFA3B2AEFFB0C1BDFF
+ B6C5C1FFAEBFBBFF9DACA8FFA1B2AEFFA6B5B1FFA2B3AFFFA4B3AFFFA6B7B3FF
+ A9B8B4FFA4B5B1FFAABBB7FFA9BAB6FF9FB0ACFF93A4A0FF99A8A4FFA3B2AEFF
+ 9EADA9FF8E9D99FF909E9AFF93A19DFF909B98FF919C99FF98A3A0FF939E9BFF
+ 919A97FF9CA5A2FFA3ADA7FFA5AFA9FF9AA49EFF88928CFF8A948EFF9DA7A1FF
+ A6B0AAFF9FA9A3FF9DA7A1FF99A39DFF959F99FF959F99FF9AA49EFFA1ABA5FF
+ A6B0AAFFA9B3ADFF9CA8A2FFA6B3ABFFA4B2ACFF9AA8A2FF94A29CFF98A6A0FF
+ 98A8A1FF93A39CFFA2B3AFFFCEDFDBFFDAEBE8FFD4E5E2FFE0F3F0FFE2F5F2FF
+ D7EAE7FFDAEDEAFFDEF3F0FFDBF0EDFFDBF0EDFFDFF4F1FFDFF4F1FFDAEFECFF
+ D9EEEBFFDCF1EEFFDBF0EDFFD4E9E6FFD2E7E4FFD8EDEAFFDDF2EFFFDAEFECFF
+ D5EAE7FFD2E9E5FFC9E1DFFFDEF9F6FF9BB3B1FFADC8C5FFB1C9C7FFA7C2BFFF
+ ABC3C1FFA0BBB8FFA4BCBAFF9AB5B2FF94ACAAFF8CA7A4FF879F9DFF829D9AFF
+ 8BA3A1FF95ADABFF99B2AEFF97AEAAFF8AA19DFF7A918DFF738A86FF788F8BFF
+ 819693FF849996FF839693FF839693FF819491FF7C8F8CFF758885FF708380FF
+ 71827FFF71827FFF667675FF738180FF667472FF606D6BFF5C6967FF535E5CFF
+ 5C6764FF6B7471FF6C7670FF6C7670FF707A74FF76807AFF79817AFF777F78FF
+ 7A827BFF7E8981FF76827CFF73817BFF75817BFF73817BFF75817BFF74827CFF
+ 77837DFF76847EFF79857FFF76847EFF7C8882FF86948EFF95A19BFF9AA8A2FF
+ 9EAAA4FF9DABA5FFA0ACA6FFA3B1ABFFA9B4B1FFA6B4AEFFA8B3B0FFA3B1ABFF
+ 9AA5A2FF8D9B95FF909B98FF99A7A1FFA3AEABFF9EACA6FF99A4A1FF94A29CFF
+ 95A09DFF96A29CFF95A09DFF99A59FFF9EA9A6FF9DABA5FF9EA9A6FFA1AFA9FF
+ AAB8B4FFB2C0BAFFB6C5C1FF9EAEA7FFACBBB7FFC7D7D0FFBFD0CCFFBACCC5FF
+ C5D6D2FFC8D9D5FFC4D5D1FFC2D3CFFFCAD9D5FFC3D4D0FFB1C0BCFFA7B8B4FF
+ ACBBB7FFA5B6B2FFAEBDB9FFABBCB8FFB2C1BDFFACBDB9FFA0AFABFF9BACA8FF
+ 9AA9A5FF8C9B97FF6C7774FF6D7875FF8C9794FF838E8BFF9AA5A2FF8B9693FF
+ 85918BFF838F89FF79867EFF7D8A82FF818E86FF808D85FF7D8A82FF7C8A7FFF
+ 7F8C84FF839186FF818C84FF778278FF737E76FF7A857BFF828D85FF838E84FF
+ 808B83FF7E897FFF79847CFF7E897FFF838E86FF859086FF869189FF89948AFF
+ 919C94FF97A298FF969F95FF919A90FF929B91FF959E94FF8E998FFF889389FF
+ 8E998FFF9CA79DFF9DABA0FFA2B0A5FFA4B4A9FFA5B5AAFFA2B2A7FFA1B1A6FF
+ A1B2A7FFA4B5AAFF9EACA6FFA6B4AEFFABB9B3FFA9B7B1FFA8B6B0FFA6B4AEFF
+ 9FADA7FF96A49EFFA1AFA9FFA9B7B1FF9EACA6FFA4B2ACFF95A39DFFA6B4AEFF
+ A1AFA9FFA5B5AEFFA2B9B1FFA3BBB3FFB8D0C8FFC8E0D8FFC4DCD4FFC1D9D1FF
+ C4DBD6FFC1D8D3FFBFD6D1FFC4DBD6FFCAE1DCFFCBE2DDFF858F89FF8F9993FF
+ 949E98FF8E9892FF88928CFF88928CFF88928CFF858F89FF8B958FFF8B958FFF
+ 8E9892FF919B95FF8E9892FF89938DFF8C9690FF909C96FF96A4A0FF99A8A4FF
+ 9CABA7FF9AA9A5FF95A4A0FF94A39FFF99A8A4FF9EADA9FFA7B6B2FF93A29EFF
+ 98A7A3FFA3B2AEFF9EADA9FFA2B1ADFFA7B6B2FF9AA9A5FF99A8A4FFA1B0ACFF
+ A2B1ADFF9CABA7FFA0AFABFFABBAB6FFADBCB8FFA5B4B0FFA7B6B2FFABBAB6FF
+ ABBAB6FFA6B5B1FFA4B3AFFFA4B3AFFFA2B1ADFF9EADA9FF9CADA9FFA6B7B3FF
+ A9BAB6FFA2B3AFFFA0AFABFFA1B0ACFF98A7A3FF899894FF96A4A0FF93A19DFF
+ 8A9592FF889390FF929D9AFF949F9CFF9AA3A0FFAAB3B0FFA8B2ACFFA6B0AAFF
+ 9BA59FFF8C9690FF8C9690FF98A29CFF9EA8A2FF9BA59FFFA7B1ABFF9FA9A3FF
+ 96A09AFF96A09AFF9CA6A0FFA2ACA6FFA2ACA6FF9FA9A3FF9AA79FFF9FACA4FF
+ 9AA9A1FF909F97FF8F9D97FF9AA8A2FF9FAFA8FF9DADA6FFA6B7B3FFCEDFDBFF
+ DAEBE8FFD5E6E3FFDEF1EEFFE1F4F1FFD8EAE9FFDAECEBFFDAEFECFFD7ECE9FF
+ D8EDEAFFDDF2EFFFDDF2EFFFD9EEEBFFD9EEEBFFDCF1EEFFDAEFECFFD4E9E6FF
+ D2E7E4FFD9EEEBFFDEF3F0FFDBF0EDFFD6EBE8FFD3EAE6FFCFE7E5FFDAF5F2FF
+ A3BEBBFFA0BBB8FFA9C4C1FFA6C1BEFFA7C2BFFFA1BCB9FF9CB7B4FF96B1AEFF
+ 90ABA8FF8BA6A3FF86A19EFF839E9BFF89A4A1FF92ADAAFF92ABA7FF90A9A5FF
+ 889F9BFF7C938FFF778E8AFF7A918DFF7C918EFF798E8BFF809390FF809390FF
+ 7F928FFF7B8E8BFF788986FF768784FF768784FF778885FF6B7978FF717F7EFF
+ 64716FFF5B6866FF596664FF4F5C5AFF57625FFF65706DFF66706AFF67716BFF
+ 6B756FFF727C76FF767E77FF757D76FF79817AFF7F8780FF78827CFF75817BFF
+ 75817BFF75817BFF75817BFF76827CFF77837DFF78847EFF7A8680FF78847EFF
+ 7A8680FF85918BFF939F99FF9EAAA4FFA4B0AAFFA6B2ACFF9EACA8FFA2B0ACFF
+ A4B2AEFFA5B3AFFFA8B6B2FFA8B6B2FFA0AEAAFF95A39FFF93A19DFF98A6A2FF
+ 9DABA7FF9EACA8FF99A7A3FF94A29EFF95A39FFF99A7A3FF99A39DFF9DA7A1FF
+ 9EAAA4FF9EAAA4FF9CA8A2FF9FABA5FFA4B2ACFFABB9B3FFBACAC3FFA5B5AEFF
+ A9B9B2FFC1D1CAFFC8DAD3FFC5D7D0FFC7D9D2FFC9DBD4FFCBDAD6FFC6D5D1FF
+ CAD9D5FFC7D6D2FFB7C6C2FFB0BFBBFFB0BFBBFFA7B6B2FFA8B7B3FFA7B6B2FF
+ ACBBB7FFA9B8B4FF9CABA7FF9BAAA6FF99A8A4FF8B9A96FF879290FF576260FF
+ 899491FF798481FF7D8885FF8B9693FF88948EFF8F9B95FF85928AFF839088FF
+ 818E86FF818E86FF839186FF87958AFF8B998EFF8D9B90FF879288FF7D887EFF
+ 788379FF7D887EFF838E84FF828D83FF7E897FFF7C877DFF7C877DFF7F8A80FF
+ 828D83FF859086FF89948AFF8F9A90FF95A096FF99A49AFF98A197FF939C92FF
+ 939C92FF969F95FF8E998FFF869187FF8B968CFF98A399FF9AA89DFFA1AFA4FF
+ A4B4A9FFA3B3A8FF9EAEA3FF9CACA1FFA0B1A6FFA6B7ACFFAAB8B2FFACBAB4FF
+ ACBAB4FFA7B5AFFF9DABA5FF97A59FFF97A59FFF9AA8A2FFA5B3ADFFACBAB4FF
+ A1AFA9FFA8B6B0FF9BA9A3FFABB9B3FFA2B0AAFFA3B3ACFF9AB0ABFFA1B8B3FF
+ BCD3CEFFCDE4DFFFC5DCD7FFC1D8D3FFC8DFDAFFC9E0DBFFC4DBD6FFC7DED9FF
+ CCE3DEFFCFE6E1FF858F89FF909A94FF959F99FF8F9993FF858F89FF818B85FF
+ 828C86FF838D87FF89938DFF89938DFF8C9690FF919B95FF909A94FF8B958FFF
+ 8A948EFF8B9791FF93A19DFF9AA9A5FFA0AFABFF9DACA8FF94A39FFF909F9BFF
+ 95A4A0FF9CABA7FFA5B4B0FF96A5A1FF98A7A3FF9EADA9FF99A8A4FF9DACA8FF
+ A5B4B0FFA2B1ADFFA5B4B0FFA7B6B2FFA2B1ADFF9BAAA6FF9DACA8FFA5B4B0FF
+ A3B2AEFF9AA9A5FFAAB9B5FFADBCB8FFABBAB6FFA5B4B0FFA2B1ADFFA1B0ACFF
+ 9CABA7FF96A5A1FF96A7A3FFA7B8B4FFB2C3BFFFADBEBAFFA8B7B3FFA5B4B0FF
+ A0AFABFF99A8A4FF9AA8A4FF95A39FFF8A9592FF889390FF949F9CFF97A29FFF
+ 9BA4A1FFAAB3B0FFA7B1ABFFA0AAA4FF97A19BFF919B95FF929C96FF96A09AFF
+ 9AA49EFF9CA6A0FFAFB9B3FFA4AEA8FF99A39DFF97A19BFF9DA7A1FFA0AAA4FF
+ 9CA6A0FF96A09AFFA0ADA5FFA0ADA5FF95A49CFF8B9A92FF8F9D97FFA0AEA8FF
+ AABAB3FFA9B9B2FFABBCB8FFCDDEDAFFDBECE9FFD7E8E5FFDCEFECFFE0F3F0FF
+ DBEDECFFDCEEEDFFD6EBE8FFD4E9E6FFD5EAE7FFDAEFECFFDAEFECFFD7ECE9FF
+ D7ECE9FFDAEFECFFD8EDEAFFD2E7E4FFD2E7E4FFD9EEEBFFDDF2EFFFDBF0EDFF
+ D7ECE9FFD5ECE8FFD5EDEBFFD4EFECFFB1CCC9FF8FAAA7FFA3BEBBFFA5C0BDFF
+ A3BEBBFF9FBAB7FFA5C0BDFF9EB9B6FF95B0ADFF8EA9A6FF85A09DFF7D9895FF
+ 7E9996FF839E9BFF87A09CFF87A09CFF849B97FF7F9692FF7E9591FF7F9692FF
+ 7A8F8CFF728784FF7E918EFF7F928FFF7F928FFF7C8F8CFF798A87FF778885FF
+ 778885FF788986FF707E7DFF6E7A7AFF636E6CFF586361FF576260FF515C5AFF
+ 525B58FF636C69FF636A65FF636A65FF686F6AFF6F7671FF737A73FF737A73FF
+ 787F78FF7E867FFF78827CFF78827CFF77817BFF77817BFF78827CFF79837DFF
+ 7A847EFF7B857FFF7C8680FF7A847EFF7C8680FF848E88FF949E98FFA3ADA7FF
+ ACB6B0FFAEBAB4FFA4B2AEFFA5B3AFFFA4B2AEFFA4B2AEFFA8B6B2FFACBAB6FF
+ A5B3AFFF9BA9A5FF98A6A2FF96A4A0FF99A7A3FF9FADA9FF9CAAA6FF94A29EFF
+ 96A4A0FF9FADA9FF9DA7A1FFA0AAA4FF9FABA5FF9DA9A3FF9AA6A0FF9BA7A1FF
+ 9EACA6FFA2B0AAFFBBCBC4FFADBDB6FFA5B5AEFFB8C8C1FFD0E2DBFFCEE0D9FF
+ C4D6CFFFC8DAD3FFCCDBD7FFC2D1CDFFC4D3CFFFC4D3CFFFBAC9C5FFB6C5C1FF
+ B3C2BEFFA6B5B1FFA3B2AEFFA1B0ACFFA6B5B1FFA3B2AEFF98A7A3FF98A7A3FF
+ 96A5A1FF889793FF8B9694FF424D4BFF899491FF85908DFF788380FF8A9592FF
+ 74807AFF77837DFF86938BFF818E86FF7D8A82FF7E8B83FF839186FF849287FF
+ 818F84FF7D8B80FF8E998FFF859086FF7F8A80FF838E84FF879288FF848F85FF
+ 7F8A80FF7D887EFF818C82FF828D83FF859086FF889389FF8D988EFF939E94FF
+ 99A49AFF9DA89EFF9CA59BFF969F95FF959E94FF97A096FF8E998FFF859086FF
+ 879288FF919C92FF95A398FF9CAA9FFFA1B1A6FF9FAFA4FF99A99EFF97A79CFF
+ 9BACA1FFA1B2A7FFB7C5BFFFB5C3BDFFB7C5BFFFB6C4BEFFA8B6B0FF99A7A1FF
+ 9CAAA4FFA9B7B1FFA2B0AAFFA6B4AEFF98A6A0FF9FADA7FF95A39DFFA5B3ADFF
+ 9AA8A2FF98A8A1FF97ABA6FFA2B8B3FFC1D7D2FFD2E8E3FFC7DDD8FFC1D7D2FF
+ C9DFDAFFCDE3DEFFC8DED9FFC8DED9FFC8DED9FFCAE0DBFF88928CFF919B95FF
+ 98A29CFF939D97FF88928CFF818B85FF838D87FF86908AFF8D9791FF86908AFF
+ 828C86FF848E88FF87918BFF89938DFF8E9892FF939F99FF95A39FFF9AA9A5FF
+ 9FAEAAFF9DACA8FF98A7A3FF94A39FFF95A4A0FF98A7A3FFA1B0ACFF9AA9A5FF
+ 9BAAA6FF9FAEAAFF9CABA7FF9DACA8FFA3B2AEFFA7B6B2FFAAB9B5FFA8B7B3FF
+ A2B1ADFF9BAAA6FF9DACA8FFA3B2AEFFA1B0ACFF99A8A4FFA3B2AEFFA6B5B1FF
+ A6B5B1FFA2B1ADFFA1B0ACFFA2B1ADFF9DACA8FF96A5A1FF98A9A5FFA3B4B0FF
+ AABBB7FFA6B7B3FFA4B3AFFFA7B6B2FFACBBB7FFAEBDB9FF9AA8A4FF99A7A3FF
+ 929D9AFF949F9CFF9FAAA7FF99A4A1FF919A97FF969F9CFF9DA7A1FF959F99FF
+ 919B95FF949E98FF98A29CFF99A39DFF9CA6A0FFA2ACA6FFA8B2ACFFA2ACA6FF
+ 9BA59FFF99A39DFF9AA49EFF9BA59FFF99A39DFF96A09AFFA5B2AAFFA2AFA7FF
+ 95A49CFF8A9991FF909E98FFA2B0AAFFABBBB4FFA9B9B2FFB0C1BDFFCADBD7FF
+ DBECE9FFDBECE9FFDBEEEBFFE0F3F0FFE0F2F1FFDFF1F0FFD6EBE8FFD3E8E5FF
+ D4E9E6FFD8EDEAFFD8EDEAFFD3E8E5FFD2E7E4FFD5EAE7FFD4E9E6FFD0E5E2FF
+ D1E6E3FFD7ECE9FFDBF0EDFFD9EEEBFFD6EBE8FFD5ECE8FFD8F0EEFFCDE8E5FF
+ B8D3D0FF849F9CFFA1BCB9FFA4BFBCFF9DB8B5FF9AB5B2FFA8C3C0FFA0BBB8FF
+ 98B3B0FF91ACA9FF87A29FFF7D9895FF799491FF7C9794FF829B97FF829B97FF
+ 819894FF809793FF849B97FF869D99FF7F9491FF748986FF7C8F8CFF7F928FFF
+ 809390FF7D908DFF7A8B88FF748582FF71827FFF717F7DFF768282FF6A7676FF
+ 626D6BFF56615FFF56615FFF525D5BFF4C5552FF616A67FF646B66FF646B66FF
+ 676E69FF6E7570FF717871FF707770FF757C75FF7C837CFF7B827DFF78827CFF
+ 78827CFF78827CFF78827CFF79837DFF7A847EFF7B857FFF7C8680FF7D8781FF
+ 7F8983FF86908AFF959F99FFA6B0AAFFAFB9B3FFB0BAB4FFB0BBB8FFACBAB6FF
+ A7B5B1FFA4B2AEFFA7B5B1FFABB9B5FFA7B5B1FF9EACA8FF99A7A3FF93A19DFF
+ 96A4A0FFA0AEAAFFA0AEAAFF96A4A0FF95A39FFF9EACA8FF9FA9A3FFA1ABA5FF
+ A0ACA6FF9EAAA4FF9BA7A1FF9AA6A0FF9BA9A3FF9EACA6FFB7C7C0FFB4C4BDFF
+ A6B6AFFFB1C1BAFFCEE0D9FFCDDFD8FFBFD1CAFFC7D9D2FFC5D4D0FFB9C8C4FF
+ B9C8C4FFBCCBC7FFB7C6C2FFB7C6C2FFB3C2BEFFA4B3AFFFA5B4B0FFA0AFABFF
+ A4B3AFFFA1B0ACFF97A6A2FF97A6A2FF95A4A0FF869591FF919C9AFF56615FFF
+ 7A8582FF86918EFF86918EFF8A9592FF76827CFF85918BFF88958DFF88958DFF
+ 8B9890FF8F9C94FF919F94FF8E9C91FF87958AFF818F84FF909B91FF889389FF
+ 848F85FF889389FF8B968CFF879288FF828D83FF808B81FF838E84FF889389FF
+ 8E998FFF8F9A90FF8E998FFF909B91FF98A399FF9EA99FFF9EA79DFF98A197FF
+ 969F95FF98A197FF8F9A90FF848F85FF838E84FF8C978DFF909E93FF96A499FF
+ 9AAA9FFF9DADA2FF9BABA0FF98A89DFF96A79CFF96A79CFFAEBCB6FFABB9B3FF
+ B2C0BAFFBBC9C3FFB2C0BAFF9EACA6FF9BA9A3FFA8B6B0FFA2B0AAFFA1AFA9FF
+ 8F9D97FF94A29CFF8B9993FF9EACA6FF93A19BFF91A19AFF9AAEA9FFA3B9B4FF
+ C3D7D2FFD3E9E4FFCBDFDAFFC3D9D4FFCADED9FFC9DFDAFFCBDFDAFFC4DAD5FF
+ C1D5D0FFBED4CFFF848E88FF8B958FFF919B95FF8F9993FF87918BFF808A84FF
+ 818B85FF86908AFF8A948EFF7F8983FF79837DFF7B857FFF838D87FF89938DFF
+ 929C96FF97A39DFF97A5A1FF96A5A1FF97A6A2FF98A7A3FF98A7A3FF97A6A2FF
+ 94A39FFF91A09CFF9AA9A5FF9CABA7FF9DACA8FFA0AFABFFA1B0ACFF9CABA7FF
+ 9CABA7FFA4B3AFFFA7B6B2FFA5B4B0FFA2B1ADFF9FAEAAFFA2B1ADFFA6B5B1FF
+ A5B4B0FFA1B0ACFFA2B1ADFFA5B4B0FFA5B4B0FFA4B3AFFFA6B5B1FFA7B6B2FF
+ A2B1ADFF9AA9A5FF97A8A4FF9AABA7FF9BACA8FF9AABA7FF9EADA9FFA4B3AFFF
+ A9B8B4FFA9B8B4FF9BA9A5FF9AA8A4FF939E9BFF97A29FFFA2ADAAFF99A4A1FF
+ 8B9491FF8A9390FF949E98FF8E9892FF8E9892FF96A09AFF9CA6A0FF9CA6A0FF
+ 9EA8A2FFA2ACA6FF99A39DFF9BA59FFF9DA7A1FF9AA49EFF96A09AFF959F99FF
+ 98A29CFF9CA6A0FFA0ADA5FF9FACA4FF95A49CFF8C9B93FF93A19BFFA3B1ABFF
+ AABAB3FFA6B6AFFFB0C1BDFFC3D4D0FFD8E9E6FFDEEFECFFDAEDEAFFE0F3F0FF
+ E5F7F6FFE2F4F3FFD9EEEBFFD6EBE8FFD5EAE7FFD8EDEAFFD6EBE8FFD0E5E2FF
+ CEE3E0FFD0E5E2FFD1E6E3FFCEE3E0FFD0E5E2FFD6EBE8FFD8EDEAFFD5EAE7FF
+ D4E9E6FFD4EBE7FFD8F0EEFFCAE2E0FFB4CCCAFF839B99FFA4BCBAFFA6BEBCFF
+ 9CB4B2FF96AEACFF9EB6B4FF97AFADFF92AAA8FF90A8A6FF8DA5A3FF879F9DFF
+ 869E9CFF89A19FFF8AA39FFF88A19DFF859C98FF829995FF859C98FF879E9AFF
+ 819693FF778C89FF758885FF798C89FF7D908DFF7D908DFF7A8B88FF738481FF
+ 6E7F7CFF6D7B79FF778383FF677171FF65706EFF56615FFF5A6261FF58605FFF
+ 4B524FFF666D6AFF6C736EFF6A716CFF6D736EFF717772FF737771FF727670FF
+ 767A74FF7B827BFF7B827DFF7B827DFF7A817CFF7A817CFF7B827DFF7C837EFF
+ 7D847FFF7D847FFF7E8580FF828984FF858C87FF8B928DFF99A09BFFAAB1ACFF
+ AFB6B1FFAAB4AEFFB0BBB8FFAEBCB8FFA9B7B3FFA4B2AEFFA6B4B0FFAAB8B4FF
+ AAB8B4FFA5B3AFFF98A6A2FF92A09CFF95A39FFFA0AEAAFFA2B0ACFF9AA8A4FF
+ 96A4A0FF99A7A3FFA0AAA4FFA1ABA5FF9FABA5FF9EAAA4FF9DA9A3FF9CA8A2FF
+ 9CAAA4FF9DABA5FFB1C1BAFFB7C7C0FFADBDB6FFB0C0B9FFC6D8D1FFC7D9D2FF
+ BED0C9FFC7D9D2FFC0CFCBFFB4C3BFFFB5C4C0FFB7C6C2FFB3C2BEFFB6C5C1FF
+ B6C5C1FFAAB9B5FFACBBB7FFA6B5B1FFA7B6B2FFA3B2AEFF99A8A4FF99A8A4FF
+ 96A5A1FF869591FF8F9A98FF6B7674FF323D3AFF3A4542FF545F5CFF56615EFF
+ 6D7973FFA0ACA6FF85928AFF8A978FFF8E9B93FF8F9C94FF8D9B90FF8A988DFF
+ 8A988DFF8A988DFF889389FF828D83FF808B81FF869187FF89948AFF869187FF
+ 828D83FF828D83FF838E84FF8D988EFF97A298FF95A096FF8D988EFF8A958BFF
+ 929D93FF9BA69CFF9DA69CFF969F95FF959E94FF98A197FF919C92FF859086FF
+ 828D83FF89948AFF909E93FF94A297FF99A99EFFA0B0A5FFA3B3A8FFA0B0A5FF
+ 96A79CFF8FA095FF9EACA6FF96A49EFF9AA8A2FFA6B4AEFFA2B0AAFF92A09AFF
+ 8D9B95FF96A49EFFA9B7B1FFA6B4AEFF909E98FF93A19BFF8A9892FF9EACA6FF
+ 97A59FFF97A7A0FF9EAFABFFA3B7B2FFC0D1CDFFD3E7E2FFD2E3DFFFCCE0DBFF
+ D1E2DEFFCBDFDAFFCFE0DCFFC8DCD7FFC3D4D0FFBED2CDFF87918BFF89938DFF
+ 8D9791FF909A94FF8B958FFF848E88FF848E88FF88928CFF818B85FF79837DFF
+ 76807AFF7E8882FF89938DFF8F9993FF919B95FF929E98FF96A4A0FF92A19DFF
+ 8F9E9AFF91A09CFF95A4A0FF96A5A1FF92A19DFF8D9C98FF96A5A1FF9DACA8FF
+ 9CABA7FF9FAEAAFFA6B5B1FF9DACA8FF95A4A0FF9FAEAAFFA1B0ACFFA3B2AEFF
+ A4B3AFFFA4B3AFFFA6B5B1FFA7B6B2FFA8B7B3FFA8B7B3FFA8B7B3FFAAB9B5FF
+ A9B8B4FFA9B8B4FFABBAB6FFADBCB8FFA6B5B1FF9CABA7FF9BACA8FF9BACA8FF
+ 9CADA9FFA0B1ADFFA6B5B1FFA6B5B1FFA1B0ACFF9CABA7FF9EACA8FF97A5A1FF
+ 8B9693FF8C9794FF9BA6A3FF97A29FFF8E9794FF8F9895FF909A94FF919B95FF
+ 939D97FF97A19BFF9BA59FFF9DA7A1FF9CA6A0FF99A39DFF8E9892FF96A09AFF
+ 9DA7A1FF9BA59FFF949E98FF929C96FF99A39DFFA1ABA5FF9FACA4FFA3B0A8FF
+ 9EADA5FF98A79FFF9DABA5FFABB9B3FFB0C0B9FFACBCB5FFA9BAB6FFB7C8C4FF
+ D3E4E1FFDFF0EDFFD7EAE7FFDFF2EFFFE8FAF9FFE2F4F3FFDCF1EEFFD8EDEAFF
+ D7ECE9FFD9EEEBFFD6EBE8FFCFE4E1FFCDE2DFFFCFE4E1FFD1E6E3FFCFE4E1FF
+ D1E6E3FFD6EBE8FFD7ECE9FFD4E9E6FFD2E7E4FFD4EBE7FFDAF0EEFFC9E1DFFF
+ 9FB7B5FF879F9DFFA5BDBBFFA4BCBAFF9BB3B1FF95ADABFF9CB4B2FF94ACAAFF
+ 8EA6A4FF8DA5A3FF8CA4A2FF88A09EFF879F9DFF89A19FFF92ABA7FF8FA8A4FF
+ 8AA19DFF839A96FF819894FF829995FF7E9390FF768B88FF708380FF738683FF
+ 778A87FF788B88FF778885FF748582FF71827FFF73817FFF748080FF616B6BFF
+ 687371FF596462FF5B6362FF5B6362FF49504DFF6B726FFF747B76FF717873FF
+ 727873FF747A75FF757973FF727670FF767A74FF7D817BFF7C827DFF7B827DFF
+ 7B827DFF7B827DFF7B827DFF7C837EFF7D847FFF7E8580FF7F8681FF858C87FF
+ 888F8AFF8B928DFF989F9AFFAAB1ACFFAFB6B1FFA7B1ABFFA8B3B0FFAAB8B4FF
+ A9B7B3FFA5B3AFFFA4B2AEFFA9B7B3FFAEBCB8FFAFBDB9FF9AA8A4FF98A6A2FF
+ 98A6A2FF9CAAA6FF9FADA9FF9FADA9FF9BA9A5FF96A4A0FFA0AAA4FFA1ABA5FF
+ 9FABA5FF9EAAA4FF9DA9A3FF9DA9A3FF9BA9A3FF9BA9A3FFA9B9B2FFB2C2BBFF
+ B0C0B9FFB1C1BAFFBBCDC6FFC3D5CEFFC3D5CEFFC7D9D2FFC1D0CCFFB8C7C3FF
+ BAC9C5FFB9C8C4FFB0BFBBFFB2C1BDFFB9C8C4FFB5C4C0FFB3C2BEFFACBBB7FF
+ ABBAB6FFA7B6B2FF9EADA9FF9EADA9FF9BAAA6FF8A9995FF8A9593FF76817FFF
+ 0C1714FF091411FF222D2AFF1F2A27FF404C46FF7D8983FF929F97FF929F97FF
+ 8F9C94FF87948CFF7E8C81FF7C8A7FFF808E83FF869489FF7D887EFF79847AFF
+ 7A857BFF818C82FF859086FF838E84FF818C82FF818C82FF818C82FF8D988EFF
+ 98A399FF97A298FF8D988EFF889389FF8B968CFF929D93FF99A298FF939C92FF
+ 929B91FF98A197FF939E94FF889389FF848F85FF89948AFF92A095FF96A499FF
+ 9DADA2FFA5B5AAFFA8B8ADFFA3B3A8FF98A99EFF90A196FFA4B2ACFF9AA8A2FF
+ 95A39DFF97A59FFF95A39DFF8D9B95FF8C9A94FF92A09AFFA8B6B0FFA6B4AEFF
+ 919F99FF93A19BFF889690FF9CAAA4FF97A59FFF9AA8A2FF9CABA7FF9FB0ACFF
+ BBCAC6FFCFE0DCFFD1E0DCFFCEDFDBFFD4E3DFFFCDDEDAFFD2E1DDFFCDDEDAFF
+ CBDAD6FFC7D8D4FF909A94FF8C9690FF8E9892FF939D97FF939D97FF8B958FFF
+ 88928CFF8B958FFF818B85FF79837DFF77817BFF818B85FF8D9791FF929C96FF
+ 929C96FF8F9B95FF96A4A0FF93A29EFF92A19DFF92A19DFF94A39FFF95A4A0FF
+ 95A4A0FF94A39FFF9CABA7FFA5B4B0FF9EADA9FFA0AFABFFACBBB7FFA2B1ADFF
+ 95A4A0FFA0AFABFF9EADA9FFA2B1ADFFA8B7B3FFAAB9B5FFA7B6B2FFA4B3AFFF
+ A5B4B0FFA9B8B4FFA6B5B1FFA8B7B3FFA8B7B3FFA9B8B4FFADBCB8FFAFBEBAFF
+ A8B7B3FF9DACA8FFA1B2AEFFA0B1ADFFA3B4B0FFA8B9B5FFACBBB7FFA8B7B3FF
+ A1B0ACFF9CABA7FF9EACA8FF94A29EFF848F8CFF85908DFF95A09DFF95A09DFF
+ 8E9794FF919A97FF8B958FFF949E98FF97A19BFF96A09AFF99A39DFFA0AAA4FF
+ 9BA59FFF919B95FF8F9993FF96A09AFF9CA6A0FF9BA59FFF96A09AFF949E98FF
+ 98A29CFF9DA7A1FFA3B0A8FFAAB7AFFFA7B6AEFF9EADA5FF9FADA7FFAAB8B2FF
+ AFBFB8FFADBDB6FF9EAFABFFA9BAB6FFCBDCD9FFDDEEEBFFD4E7E4FFDCEFECFF
+ E8FAF9FFE0F2F1FFDDF2EFFFD9EEEBFFD8EDEAFFDAEFECFFD8EDEAFFD1E6E3FF
+ CFE4E1FFD1E6E3FFD4E9E6FFD2E7E4FFD4E9E6FFD9EEEBFFD9EEEBFFD4E9E6FF
+ D3E8E5FFD5ECE8FFDDF3F1FFCCE4E2FF849C9AFF8BA3A1FFA3BBB9FFA1B9B7FF
+ 9EB6B4FF98B0AEFF9DB5B3FF93ABA9FF8BA3A1FF89A19FFF879F9DFF839B99FF
+ 829A98FF849C9AFF8CA5A1FF8DA6A2FF8AA19DFF829995FF7E9591FF7E9591FF
+ 7C918EFF778C89FF758885FF758885FF748784FF718481FF71827FFF728380FF
+ 758683FF7A8886FF6D7979FF5A6464FF6B7674FF5B6664FF5C6463FF5C6463FF
+ 464D4AFF707774FF787F7AFF747B76FF757B76FF767C77FF777B75FF747872FF
+ 787C76FF7E827CFF7D837EFF7C827DFF7C827DFF7C827DFF7C827DFF7D837EFF
+ 7E847FFF7F8580FF818782FF878D88FF888E89FF888E89FF959B96FFAAB0ABFF
+ B1B7B2FFABB2ADFFA2ADAAFFA8B6B2FFACBAB6FFA6B4B0FFA1AFABFFA5B3AFFF
+ ADBBB7FFB2C0BCFFA1AFABFFA3B1ADFF9DABA7FF95A39FFF9AA8A4FFA5B3AFFF
+ A3B1ADFF98A6A2FFA1ABA5FFA0AAA4FF9EAAA4FF9DA9A3FF9CA8A2FF9BA7A1FF
+ 97A59FFF96A49EFF9EAEA7FFA1B1AAFFA8B8B1FFACBCB5FFADBFB8FFBED0C9FF
+ C9DBD4FFC1D3CCFFC4D3CFFFC0CFCBFFC2D1CDFFBCCBC7FFAAB9B5FFABBAB6FF
+ B8C7C3FFBBCAC6FFB7C6C2FFAEBDB9FFAEBDB9FFAAB9B5FFA2B1ADFFA4B3AFFF
+ A1B0ACFF909F9BFF8F9A98FF7D8886FF394441FF384340FF343F3CFF2C3734FF
+ 28342EFF4B5751FF8A978FFF8A978FFF88958DFF86938BFF849287FF839186FF
+ 859388FF869489FF7A857BFF788379FF7A857BFF828D83FF869187FF848F85FF
+ 828D83FF848F85FF808B81FF889389FF919C92FF949F95FF919C92FF8C978DFF
+ 889389FF879288FF949D93FF8E978DFF8F988EFF97A096FF95A096FF8B968CFF
+ 889389FF8C978DFF8D9B90FF96A499FF9FAFA4FFA2B2A7FF9FAFA4FF99A99EFF
+ 96A79CFF96A79CFFA6B4AEFFA5B3ADFFA2B0AAFF9BA9A3FF94A29CFF919F99FF
+ 93A19BFF96A49EFF9CAAA4FFA0AEA8FF909E98FF93A19BFF85938DFF97A59FFF
+ 919F99FF95A39DFF95A39FFF9AA9A5FFB5C3BFFFC6D5D1FFC1CFCBFFBDCCC8FF
+ C4D2CEFFC3D2CEFFCBD9D5FFCBDAD6FFCCDAD6FFCAD9D5FF939D97FF8C9690FF
+ 8C9690FF929C96FF949E98FF8C9690FF86908AFF87918BFF89938DFF7D8781FF
+ 77817BFF7E8882FF8B958FFF929C96FF949E98FF939F99FF98A6A2FF98A7A3FF
+ 99A8A4FF97A6A2FF95A4A0FF96A5A1FF9AA9A5FF9FAEAAFFA5B4B0FFADBCB8FF
+ A3B2AEFFA2B1ADFFB2C1BDFFA8B7B3FF99A8A4FFA6B5B1FF9DACA8FFA3B2AEFF
+ ABBAB6FFADBCB8FFA7B6B2FFA0AFABFFA1B0ACFFA7B6B2FF9FAEAAFFA1B0ACFF
+ A2B1ADFFA5B4B0FFABBAB6FFAFBEBAFFA8B7B3FF9EADA9FF9FB0ACFF9FB0ACFF
+ A1B2AEFFA4B5B1FFA6B5B1FFA3B2AEFFA2B1ADFFA3B2AEFF9CAAA6FF92A09CFF
+ 838E8BFF86918EFF97A29FFF95A09DFF8A9390FF89928FFF86908AFF949E98FF
+ 99A39DFF949E98FF98A29CFFA3ADA7FF9EA8A2FF8E9892FF96A09AFF98A29CFF
+ 9BA59FFF9BA59FFF99A39DFF97A19BFF97A19BFF98A29CFFA2AFA7FFA9B6AEFF
+ A5B4ACFF99A8A0FF94A29CFF9CAAA4FFA1B1AAFFA0B0A9FF97A8A4FFA0B1ADFF
+ C5D6D3FFDBECE9FFD1E4E1FFD9ECE9FFE7F9F8FFDDEFEEFFDCF1EEFFD8EDEAFF
+ D8EDEAFFDBF0EDFFD9EEEBFFD4E9E6FFD2E7E4FFD4E9E6FFD7ECE9FFD5EAE7FF
+ D7ECE9FFDBF0EDFFDAEFECFFD5EAE7FFD4E9E6FFD7ECE9FFE0F6F4FFCFE7E5FF
+ 718987FF8DA5A3FFA1B9B7FF9FB7B5FFA1B9B7FF9BB3B1FF92AAA8FF89A19FFF
+ 829A98FF839B99FF869E9CFF869E9CFF88A09EFF8BA3A1FF819A96FF859E9AFF
+ 869D99FF809793FF7C938FFF7D9490FF7E9390FF7B908DFF809390FF7C8F8CFF
+ 758885FF6D807DFF6B7C79FF6E7F7CFF758683FF7D8B89FF677373FF555F5FFF
+ 6C7775FF5C6765FF5A6563FF5C6463FF434C49FF727976FF787F7AFF757C77FF
+ 747B76FF777D78FF767D76FF737A73FF797D77FF7E857EFF7D837EFF7D837EFF
+ 7C827DFF7C827DFF7C827DFF7D837EFF7F8580FF7F8580FF828883FF878D88FF
+ 868C87FF838984FF919792FFAAB0ABFFB4BAB5FFAFB6B1FFA2ADAAFFABB9B5FF
+ B0BEBAFFA8B6B2FF9EACA8FF9FADA9FFA8B6B2FFAEBCB8FFA8B6B2FFABB9B5FF
+ A0AEAAFF909E9AFF95A39FFFA9B7B3FFAAB8B4FF9BA9A5FFA2ACA6FFA0AAA4FF
+ 9DA9A3FF9CA8A2FF9AA6A0FF98A49EFF93A19BFF919F99FF94A49DFF90A099FF
+ 9DADA6FFA4B4ADFFA2B4ADFFBBCDC6FFCBDDD6FFB9CBC4FFC6D5D1FFC4D3CFFF
+ C7D6D2FFBCCBC7FFA4B3AFFFA3B2AEFFB4C3BFFFBCCBC7FFB7C6C2FFAFBEBAFF
+ AEBDB9FFABBAB6FFA5B4B0FFA8B7B3FFA5B4B0FF94A39FFF7F8A88FF636E6CFF
+ 586360FF5E6966FF414C49FF424D4AFF1F2B25FF2C3832FF4A574FFF505D55FF
+ 5C6961FF6C7971FF7B897EFF818F84FF7E8C81FF79877CFF7E897FFF7C877DFF
+ 7F8A80FF879288FF8A958BFF889389FF879288FF89948AFF808B81FF828D83FF
+ 889389FF909B91FF95A096FF929D93FF889389FF7F8A80FF90998FFF8B948AFF
+ 8D968CFF97A096FF96A197FF8E998FFF8A958BFF8E998FFF869489FF94A297FF
+ 9EAEA3FF9CACA1FF92A297FF8C9C91FF91A297FF99AA9FFF93A19BFF9FADA7FF
+ A6B4AEFF9DABA5FF92A09AFF8E9C96FF8F9D97FF8E9C96FF95A39DFF9DABA5FF
+ 92A09AFF97A59FFF889690FF96A49EFF8F9D97FF93A19BFF8F9D99FF98A6A2FF
+ B1BFBBFFBDCBC7FFAFBDB9FFA7B5B1FFAFBDB9FFB3C1BDFFC1CFCBFFC4D2CEFF
+ C6D4D0FFC4D2CEFFABB5AFFF9BA59FFF8F9993FF8E9892FF8E9892FF8A948EFF
+ 89938DFF8D9791FF858F89FF86908AFF8A948EFF919B95FF949E98FF939D97FF
+ 939D97FF929E98FF9EACA8FF9EADA9FF9FAEAAFF94A39FFF8B9A96FF99A8A4FF
+ A2B1ADFF94A39FFFAFBEBAFFAEBDB9FFAAB9B5FFA5B4B0FFA4B3AFFFA5B4B0FF
+ A4B3AFFFA1B0ACFFA4B3AFFFA8B7B3FFACBBB7FFACBBB7FFA8B7B3FFA3B2AEFF
+ 9FAEAAFF9EADA9FFA0AFABFF9CABA7FF99A8A4FF9DACA8FFA5B4B0FFA9B8B4FF
+ A7B6B2FFA3B2AEFF93A4A0FF9CADA9FFA3B4B0FFA4B5B1FFA6B5B1FFA6B5B1FF
+ A1B0ACFF9AA9A5FFA1AFABFF889692FF909B98FF848F8CFF889390FF95A09DFF
+ 87908DFF949D9AFF8D9791FF8B958FFF919B95FF9BA59FFF9BA59FFF949E98FF
+ 96A09AFFA1ABA5FF99A39DFF96A09AFF959F99FF97A19BFF9AA49EFF9BA59FFF
+ 96A09AFF929C96FF929F97FF94A199FF98A79FFF9CABA3FF99A7A1FF94A29CFF
+ 95A59EFF9CACA5FFB1C2BEFFA8B9B5FFC3D4D1FFD0E1DEFFD7EAE7FFE7FAF7FF
+ DEF0EFFFDAECEBFFDBF0EDFFD7ECE9FFD3E8E5FFD4E9E6FFD7ECE9FFD7ECE9FF
+ D1E6E3FFCCE1DEFFD9EEEBFFD1E6E3FFD0E5E2FFD7ECE9FFDBF0EDFFD6EBE8FF
+ D4E9E6FFD6EBE8FFD1E7E5FFDEF4F2FF849A98FF95ABA9FFABC1BFFFA3B9B7FF
+ A2B8B6FF97ADABFF9AB0AEFF8EA4A2FF859B99FF869C9AFF8BA19FFF8EA4A2FF
+ 90A6A4FF94AAA8FF92ABA7FF7D9692FF809793FF829995FF748B87FF788F8BFF
+ 889D9AFF839895FF7C8F8CFF7D908DFF778A87FF6E817EFF738481FF7B8C89FF
+ 738481FF61726FFF5E6C6BFF626E6EFF5F6C6AFF5F6C6AFF5D6A68FF4F5A58FF
+ 4E5956FF666F6CFF76807AFF76807AFF76807AFF787F7AFF788079FF79817AFF
+ 7C837CFF7C847DFF7B827DFF79807BFF787F7AFF7B827DFF7E8580FF7F8681FF
+ 7B827DFF767D78FF7B827DFF838A85FF89908BFF878E89FF979E99FFA9B0ABFF
+ B5BCB7FFAFB9B3FFACB7B4FFA5B3AFFFA9B7B3FFB2C0BCFFADBBB7FF9FADA9FF
+ 9DABA7FFA6B4B0FFA0AEAAFFA3B1ADFFA1AFABFF99A7A3FF96A4A0FF9BA9A5FF
+ A1AFABFFA4B2AEFF99A39DFFA5AFA9FFA8B4AEFF9FABA5FF94A09AFF939F99FF
+ 95A39DFF99A7A1FF96A69FFF9AAAA3FF9CACA5FF9BABA4FF9FB1AAFFACBEB7FF
+ B8CAC3FFBDCFC8FFBCCBC7FFC2D1CDFFC7D6D2FFC4D3CFFFB6C5C1FFA9B8B4FF
+ AAB9B5FFB3C2BEFFBAC9C5FFB5C4C0FFAEBDB9FFA8B7B3FFA4B3AFFFA0AFABFF
+ 9BAAA6FF98A7A3FF808B89FF626D6BFF66716EFF87928FFF75807DFF4F5A57FF
+ 5C6862FF5A6660FF5F6C64FF546159FF47544CFF435048FF47554AFF4C5A4FFF
+ 4E5C51FF4C5A4FFF606B61FF747F75FF828D83FF838E84FF838E84FF89948AFF
+ 879288FF808B81FF7A857BFF89948AFF8F9A90FF869187FF848F85FF8E998FFF
+ 909B91FF89948AFF8E978DFF8E978DFF8F988EFF949D93FF97A298FF96A197FF
+ 8F9A90FF89948AFF95A398FF8C9A8FFF8C9C91FF95A59AFF8F9F94FF819186FF
+ 88998EFF9DAEA3FF8A9892FF9DABA5FFA4B2ACFF9AA8A2FF96A49EFF9AA8A2FF
+ 93A19BFF82908AFF8C9A94FFA2B0AAFFA2B0AAFF919F99FF8A9892FF899791FF
+ 919F99FFA1AFA9FF8C9A96FF95A39FFF96A4A0FFA3B1ADFF8E9C98FF85938FFF
+ 9CAAA6FF808E8AFF9EACA8FFAAB8B4FFAEBCB8FFA8B6B2FFA4AEA8FF97A19BFF
+ 8E9892FF8F9993FF919B95FF909A94FF909A94FF939D97FF909A94FF919B95FF
+ 949E98FF99A39DFF9BA59FFF9BA59FFF9BA59FFF9AA6A0FF97A5A1FF9BAAA6FF
+ A6B5B1FFA2B1ADFF94A39FFF9AA9A5FFA6B5B1FFA3B2AEFFABBAB6FFAAB9B5FF
+ A8B7B3FFA6B5B1FFA6B5B1FFA7B6B2FFA8B7B3FFA7B6B2FF98A7A3FF9CABA7FF
+ A1B0ACFFA5B4B0FFA5B4B0FFA4B3AFFFA2B1ADFFA2B1ADFF9DACA8FF9BAAA6FF
+ 9BAAA6FF9EADA9FFA4B3AFFFA7B6B2FFA5B4B0FFA2B1ADFF9FB0ACFFA3B4B0FF
+ A5B6B2FFA4B5B1FFA8B7B3FFACBBB7FFAAB9B5FFA4B3AFFFA3B1ADFF8B9995FF
+ 909B98FF86918EFF899491FF949F9CFF87908DFF929B98FF959F99FF97A19BFF
+ A0AAA4FFA8B2ACFFA7B1ABFF9FA9A3FF99A39DFF98A29CFF9FA9A3FF98A29CFF
+ 929C96FF919B95FF96A09AFF9CA6A0FF9EA8A2FF9EA8A2FF99A69EFF96A39BFF
+ 96A59DFF9DACA4FFA0AEA8FF9FADA7FF9EAEA7FFA1B1AAFFB0C1BDFFAFC0BCFF
+ D1E2DFFFDAEBE8FFD8EBE8FFE2F5F2FFDCEEEDFFDCEEEDFFDCF1EEFFD8EDEAFF
+ D5EAE7FFD6EBE8FFD9EEEBFFD9EEEBFFD4E9E6FFCFE4E1FFD8EDEAFFD2E7E4FF
+ D0E5E2FFD6EBE8FFD9EEEBFFD4E9E6FFD2E7E4FFD4E9E6FFE0F6F4FFE0F6F4FF
+ 798F8DFF869C9AFFA1B7B5FFA1B7B5FFA1B7B5FF94AAA8FFA4BAB8FF97ADABFF
+ 8BA19FFF879D9BFF869C9AFF879D9BFF8CA2A0FF92A8A6FF8AA39FFF7A938FFF
+ 758C88FF728985FF6A817DFF6C837FFF778C89FF7B908DFF738683FF758885FF
+ 718481FF6B7E7BFF738481FF7D8E8BFF788986FF697A77FF647473FF657372FF
+ 5C6A68FF576563FF505E5CFF404D4BFF3E4C48FF53615DFF737F79FF6F7B75FF
+ 6B7771FF6E7872FF758078FF7B867EFF7E8981FF7E8981FF777E79FF757F79FF
+ 787F7AFF7A847EFF808782FF818B85FF838A85FF808A84FF808782FF7E8882FF
+ 848B86FF88928CFF939A95FF9DA7A1FFAAB1ACFFA8B2ACFFAAB5B2FFA4B2AEFF
+ A8B6B2FFB0BEBAFFACBAB6FFA0AEAAFF9EACA8FFA6B4B0FFA5B3AFFFA8B6B2FF
+ A6B4B0FF9EACA8FF9AA8A4FF9DABA7FFA1AFABFFA2B0ACFFA8B2ACFFA8B2ACFF
+ A2AEA8FF9DA9A3FF9EAAA4FFA0ACA6FF9AA8A2FF93A19BFF9AAAA3FF9EAEA7FF
+ 9FAFA8FF9DADA6FFA0B2ABFFAEC0B9FFBACCC5FFBFD1CAFFB6C5C1FFBBCAC6FF
+ C3D2CEFFC4D3CFFFBAC9C5FFADBCB8FFAAB9B5FFAFBEBAFFB2C1BDFFAFBEBAFF
+ ABBAB6FFA8B7B3FFA5B4B0FFA0AFABFF9AA9A5FF95A4A0FF97A2A0FF6C7775FF
+ 586360FF899491FF8A9592FF7C8784FF79857FFF6C7872FF78857DFF748179FF
+ 6F7C74FF6C7971FF6F7D72FF748277FF79877CFF7D8B80FF747F75FF5D685EFF
+ 485349FF4F5A50FF6F7A70FF889389FF848F85FF727D73FF7B867CFF7D887EFF
+ 808B81FF838E84FF859086FF89948AFF8D988EFF919C92FF949D93FF939C92FF
+ 919A90FF90998FFF8F9A90FF939E94FF99A49AFF9DA89EFF859388FF818F84FF
+ 849489FF8E9E93FF8D9D92FF7F8F84FF78897EFF7B8C81FF92A09AFFA1AFA9FF
+ A1AFA9FF8F9D97FF86948EFF8D9B95FF919F99FF8A9892FF85938DFF9DABA5FF
+ A5B3ADFFA0AEA8FFA1AFA9FF9CAAA4FF97A59FFF9CAAA4FF98A6A2FF869591FF
+ 697773FF606F6BFF4E5C58FF485753FF5D6B67FF41504CFF35433FFF43524EFF
+ 566460FF5C6B67FF9CA6A0FF97A19BFF959F99FF9AA49EFF9DA7A1FF99A39DFF
+ 949E98FF929C96FF98A29CFF99A39DFF99A39DFF9AA49EFF9AA49EFF9BA59FFF
+ 9CA6A0FF9AA6A0FF9EACA8FF96A5A1FF9FAEAAFFA7B6B2FF9FAEAAFF9FAEAAFF
+ A7B6B2FFA8B7B3FFA1B0ACFFA1B0ACFFA1B0ACFFA2B1ADFFA3B2AEFFA5B4B0FF
+ A7B6B2FFA9B8B4FF97A6A2FF9AA9A5FF9EADA9FFA3B2AEFFA7B6B2FFA8B7B3FF
+ A8B7B3FFA7B6B2FF9CABA7FF9DACA8FFA0AFABFFA3B2AEFFA5B4B0FFA6B5B1FF
+ A5B4B0FFA4B3AFFFA2B3AFFFA1B2AEFF9DAEAAFF9AABA7FFA0AFABFFA7B6B2FF
+ A8B7B3FFA4B3AFFFA6B4B0FF92A09CFF919C99FF8A9592FF8D9895FF929D9AFF
+ 89928FFF909996FF96A09AFF9EA8A2FFA3ADA7FFA3ADA7FFA0AAA4FF9DA7A1FF
+ 96A09AFF8F9993FFA2ACA6FF9CA6A0FF959F99FF939D97FF98A29CFF9DA7A1FF
+ 9FA9A3FF9FA9A3FF929F97FF8B9890FF87968EFF8E9D95FF96A49EFF97A59FFF
+ 95A59EFF96A69FFFA6B7B3FFAEBFBBFFD8E9E6FFE1F2EFFFD7EAE7FFDDF0EDFF
+ D9EBEAFFDEF0EFFFDCF1EEFFD9EEEBFFD6EBE8FFD8EDEAFFDBF0EDFFDBF0EDFF
+ D7ECE9FFD3E8E5FFD9EEEBFFD4E9E6FFD2E7E4FFD5EAE7FFD6EBE8FFD2E7E4FF
+ D1E6E3FFD2E7E4FFDCF1EFFFDBF0EEFF758A88FF899E9CFFAEC3C1FFB0C5C3FF
+ AABFBDFF96ABA9FF9EB3B1FF96ABA9FF8FA4A2FF8EA3A1FF8DA2A0FF8CA19FFF
+ 8EA3A1FF92A8A6FF88A19DFF869F9BFF7E9591FF7B928EFF7F9692FF7B928EFF
+ 7C918EFF889D9AFF6C7F7CFF6D807DFF687B78FF617471FF677875FF6E7F7CFF
+ 687976FF5C6D6AFF5C6C6BFF5B6B6AFF51625FFF495A57FF435451FF374543FF
+ 364541FF4A5955FF586660FF505E58FF4A5852FF4F5B55FF59665EFF637068FF
+ 67746CFF66736BFF68726CFF67736DFF6B756FFF69756FFF6B756FFF6B7771FF
+ 707A74FF717D77FF7B857FFF76827CFF7F8983FF8D9993FF949E98FFA7B3ADFF
+ B9C3BDFFBCC8C2FFACBAB6FFA9B7B3FFACBAB6FFB3C1BDFFB1BFBBFFA7B5B1FF
+ A5B3AFFFABB9B5FFAAB8B4FFADBBB7FFAAB8B4FFA3B1ADFF9EACA8FFA0AEAAFF
+ A1AFABFF9FADA9FFA6B0AAFFA8B2ACFFA4B0AAFFA0ACA6FF9FABA5FFA0ACA6FF
+ 9AA8A2FF93A19BFF9EAEA7FFA2B2ABFFA2B2ABFFA0B0A9FFA2B4ADFFAFC1BAFF
+ BACCC5FFBFD1CAFFB7C6C2FFBAC9C5FFC2D1CDFFC8D7D3FFC5D4D0FFBAC9C5FF
+ B3C2BEFFB3C2BEFFABBAB6FFAAB9B5FFA8B7B3FFA7B6B2FFA5B4B0FF9FAEAAFF
+ 98A7A3FF92A19DFF9EA9A7FF75807EFF4F5A57FF8C9794FF929D9AFF9DA8A5FF
+ 919D97FF87938DFF7B8880FF7D8A82FF7E8B83FF7E8B83FF7E8C81FF818F84FF
+ 87958AFF8D9B90FF939E94FF929D93FF89948AFF717C72FF566157FF4F5A50FF
+ 657066FF818C82FF788379FF747F75FF7A857BFF889389FF909B91FF8D988EFF
+ 8D988EFF939E94FF9DA69CFF9EA79DFF9CA59BFF959E94FF8C978DFF8B968CFF
+ 919C92FF97A298FF869489FF869489FF86968BFF8D9D92FF93A398FF91A196FF
+ 85968BFF7B8C81FF889690FF9DABA5FFA7B5AFFF9BA9A3FF909E98FF8F9D97FF
+ 8B9993FF82908AFF96A49EFFA9B7B1FFADBBB5FFA4B2ACFF98A6A0FF7A8882FF
+ 596761FF4B5953FF3D4C48FF334440FF1E2D29FF11221EFF0E1D19FF2F403CFF
+ 768581FF8C9D99FF596864FF42534FFF3A4945FF435450FF9BA59FFF9CA6A0FF
+ A0AAA4FFA6B0AAFFA7B1ABFFA0AAA4FF96A09AFF8F9993FF9FA9A3FFA0AAA4FF
+ 9EA8A2FF99A39DFF98A29CFF9AA49EFF9AA49EFF96A29CFFAFBDB9FF93A29EFF
+ 8E9D99FF9BAAA6FF9DACA8FF9BAAA6FF9FAEAAFF9EADA9FF96A5A1FF95A4A0FF
+ 98A7A3FF9CABA7FF9DACA8FF9DACA8FFA0AFABFFA5B4B0FFA3B2AEFFA2B1ADFF
+ A3B2AEFFA7B6B2FFACBBB7FFAEBDB9FFACBBB7FFA9B8B4FF9DACA8FFA1B0ACFF
+ A5B4B0FFA8B7B3FFA8B7B3FFA7B6B2FFA7B6B2FFA8B7B3FF9FB0ACFF9DAEAAFF
+ 97A8A4FF93A4A0FF9AA9A5FFA2B1ADFFA3B2AEFF9EADA9FFAAB8B4FF9AA8A4FF
+ 939E9BFF909B98FF919C99FF929D9AFF8D9693FF8F9895FF909A94FF9DA7A1FF
+ A0AAA4FF949E98FF8D9791FF929C96FF96A09AFF959F99FF9BA59FFF98A29CFF
+ 959F99FF96A09AFF98A29CFF96A09AFF919B95FF8C9690FF9EABA3FF98A59DFF
+ 93A29AFF97A69EFF9BA9A3FF9AA8A2FF9AAAA3FF9DADA6FF98A9A5FFA4B5B1FF
+ D3E4E1FFE0F1EEFFD7EAE7FFDCEFECFFD7E9E8FFDBEDECFFDAEFECFFD8EDEAFF
+ D7ECE9FFD8EDEAFFDAEFECFFDAEFECFFD8EDEAFFD5EAE7FFDAEFECFFD7ECE9FF
+ D5EAE7FFD5EAE7FFD4E9E6FFD2E7E4FFD1E6E3FFD1E6E3FFD1E6E4FFCEE3E1FF
+ 667B79FF7A8F8DFFA0B5B3FFA5BAB8FFA2B7B5FF90A5A3FF8FA4A2FF8A9F9DFF
+ 899E9CFF8EA3A1FF8FA4A2FF899E9CFF849997FF819795FF7F9692FF859E9AFF
+ 7C938FFF768D89FF7D9490FF6C837FFF5C716EFF677C79FF657875FF657875FF
+ 607370FF5B6E6BFF60716EFF667774FF627370FF596A67FF546665FF566B69FF
+ 506562FF4D625FFF516461FF4A5D5AFF4B5F5AFF5C706BFF6F817AFF6B7D76FF
+ 697972FF6B7B74FF72837AFF788980FF7C8B83FF7D8C84FF75837DFF77857FFF
+ 78847EFF72807AFF6F7B75FF6B7973FF707C76FF72807AFF6D7973FF707E78FF
+ 77837DFF7F8D87FF78847EFF9EACA6FFB7C3BDFFB4C2BCFFACBAB6FFA9B7B3FF
+ ABB9B5FFB1BFBBFFB0BEBAFFAAB8B4FFA8B6B2FFACBAB6FFAAB8B4FFADBBB7FF
+ ABB9B5FFA5B3AFFFA2B0ACFFA3B1ADFFA3B1ADFF9FADA9FF919B95FFA2ACA6FF
+ ADB9B3FFA7B3ADFF9BA7A1FF95A19BFF96A49EFF99A7A1FF9FAFA8FFA3B3ACFF
+ A3B3ACFFA1B1AAFFA3B5AEFFAEC0B9FFB9CBC4FFBDCFC8FFB9C8C4FFB7C6C2FF
+ BBCAC6FFC4D3CFFFC7D6D2FFC0CFCBFFB9C8C4FFB6C5C1FFACBBB7FFAAB9B5FF
+ A8B7B3FFA6B5B1FFA3B2AEFF9EADA9FF97A6A2FF92A19DFF8C9795FF7A8583FF
+ 505B58FF8C9794FF86918EFF9BA6A3FF919D97FF98A49EFF8A978FFF8B9890FF
+ 8C9991FF8D9A92FF8D9B90FF8D9B90FF8E9C91FF8F9D92FF949F95FF8A958BFF
+ 828D83FF7C877DFF6F7A70FF616C62FF657066FF737E74FF768177FF7A857BFF
+ 828D83FF8D988EFF95A096FF939E94FF8B968CFF838E84FF858E84FF8A9389FF
+ 919A90FF939C92FF8F9A90FF8C978DFF8A958BFF8A958BFF93A196FF92A095FF
+ 89998EFF839388FF88988DFF95A59AFF96A79CFF8E9F94FF86948EFF99A7A1FF
+ A6B4AEFFA3B1ABFF9DABA5FF9AA8A2FF919F99FF83918BFF7B8983FF82908AFF
+ 77857FFF66746EFF5B6963FF47554FFF36443EFF34443DFF647571FF798D88FF
+ 91A29EFF9AAEA9FF9EAFABFFAFC3BEFFD5E6E2FFE6FAF5FFE7F8F4FFCADED9FF
+ B6C7C3FFB6CAC5FF9FA9A3FF9FA9A3FF9FA9A3FF9EA8A2FF9FA9A3FF9FA9A3FF
+ 9CA6A0FF99A39DFFA5AFA9FFA8B2ACFFA5AFA9FF9DA7A1FF9BA59FFF9EA8A2FF
+ 9DA7A1FF96A29CFFB2C0BCFF95A4A0FF8E9D99FF94A39FFF8A9995FF859490FF
+ 91A09CFF9CABA7FF95A4A0FF93A29EFF97A6A2FF9CABA7FF9BAAA6FF97A6A2FF
+ 99A8A4FFA1B0ACFFA7B6B2FFA3B2AEFFA1B0ACFFA4B3AFFFABBAB6FFAEBDB9FF
+ ABBAB6FFA7B6B2FF9EADA9FFA1B0ACFFA5B4B0FFA7B6B2FFA6B5B1FFA6B5B1FF
+ A6B5B1FFA7B6B2FFA3B4B0FFA2B3AFFF9EAFABFF9AABA7FF9FAEAAFFA5B4B0FF
+ A4B3AFFF9FAEAAFFACBAB6FFA1AFABFF949F9CFF95A09DFF96A19EFF919C99FF
+ 929B98FF8F9895FF86908AFF99A39DFFA1ABA5FF959F99FF8A948EFF919B95FF
+ 9DA7A1FFA3ADA7FF97A19BFF939D97FF8F9993FF8F9993FF919B95FF8F9993FF
+ 89938DFF838D87FFA2AFA7FF9FACA4FF9CABA3FF9CABA3FF99A7A1FF94A29CFF
+ 96A69FFF9DADA6FF95A6A2FFA0B1ADFFCFE0DDFFDFF0EDFFDAEDEAFFDFF2EFFF
+ D5E7E6FFD4E6E5FFD7ECE9FFD6EBE8FFD6EBE8FFD6EBE8FFD8EDEAFFD7ECE9FF
+ D5EAE7FFD3E8E5FFDAEFECFFDAEFECFFD8EDEAFFD4E9E6FFD2E7E4FFD2E7E4FF
+ D2E7E4FFD2E7E4FFD1E6E4FFCCE1DFFF5E7371FF687D7BFF879C9AFF8EA3A1FF
+ 95AAA8FF8DA2A0FF94A9A7FF8EA3A1FF8CA19FFF90A5A3FF91A6A4FF8BA09EFF
+ 859A98FF829896FF758C88FF7E9793FF7B928EFF7D9490FF8CA39FFF829995FF
+ 788D8AFF869B98FF91A4A1FF91A4A1FF90A3A0FF92A5A2FF9AABA8FFA2B3B0FF
+ A3B4B1FF9EB1AEFFA0B5B3FFA7BDBBFFA6BDB9FFA7BEBAFFAEC3C0FFA9BEBBFF
+ A8BEB9FFB5CBC6FFA4B9B1FFA7BCB4FFABBDB6FFAABCB5FFA7BAB1FFA6B9B0FF
+ ABBCB3FFAEBFB6FFA5B5AEFFA6B6AFFFA8B6B0FFA3B3ACFFA0AEA8FF9EAEA7FF
+ A2B0AAFFA6B6AFFF96A49EFFA0B0A9FF9DABA5FF91A19AFF697771FF99A9A2FF
+ AFBDB7FFA3B1ABFFA5B3AFFFA3B1ADFFA4B2AEFFA7B5B1FFA8B6B2FFA4B2AEFF
+ A2B0ACFFA3B1ADFFA8B6B2FFAAB8B4FFA8B6B2FFA3B1ADFFA3B1ADFFA6B4B0FF
+ A6B4B0FFA2B0ACFF89938DFF9BA59FFFA8B4AEFFA8B4AEFFA0ACA6FF9CA8A2FF
+ 98A6A0FF98A6A0FF9CACA5FFA1B1AAFFA3B3ACFFA2B2ABFFA3B5AEFFADBFB8FF
+ B6C8C1FFB8CAC3FFB8C7C3FFB1C0BCFFAFBEBAFFB6C5C1FFBBCAC6FFB9C8C4FF
+ B4C3BFFFB3C2BEFFB4C3BFFFAFBEBAFFA9B8B4FFA4B3AFFFA0AFABFF9CABA7FF
+ 97A6A2FF93A29EFF85908EFF7E8987FF515C59FF848F8CFF808B88FF96A19EFF
+ 8A9690FF95A19BFF95A29AFF919E96FF909D95FF93A098FF97A59AFF97A59AFF
+ 92A095FF8C9A8FFF8C978DFF778278FF6F7A70FF7D887EFF89948AFF808B81FF
+ 6D786EFF616C62FF727D73FF808B81FF818C82FF768177FF778278FF808B81FF
+ 758076FF5F6A60FF50594FFF555E54FF5F685EFF6B746AFF737E74FF758076FF
+ 717C72FF6C776DFF707E73FF758378FF6B7B70FF5D6D62FF5F6F64FF718176FF
+ 7E8F84FF7F9085FF85938DFF83918BFF788680FF687670FF5F6D67FF5B6963FF
+ 505E58FF414F49FF35433DFF3C4A44FF3A4842FF43514BFF616F69FF83918BFF
+ ABB9B3FFD0E0D9FFC2D6D1FFC6DCD7FFCFE3DEFFD0E6E1FFDCF0EBFFDDF3EEFF
+ CFE3DEFFC5DBD6FFC6DAD5FFD5EBE6FFE1F5F0FFDAF0EBFFA1ABA5FF9EA8A2FF
+ 959F99FF8D9791FF8E9892FF99A39DFFA4AEA8FFA8B2ACFF9FA9A3FFA5AFA9FF
+ A4AEA8FF9CA6A0FF9BA59FFFA1ABA5FFA0AAA4FF97A39DFFA2B0ACFF9BAAA6FF
+ A1B0ACFF9CABA7FF7F8E8AFF74837FFF8D9C98FFA8B7B3FFA0AFABFF9DACA8FF
+ 9FAEAAFFA4B3AFFF9FAEAAFF95A4A0FF95A4A0FF9EADA9FFA3B2AEFF9CABA7FF
+ 98A7A3FF9DACA8FFA7B6B2FFAEBDB9FFABBAB6FFA6B5B1FFA0AFABFFA0AFABFF
+ A0AFABFFA1B0ACFFA3B2AEFFA4B3AFFFA5B4B0FFA5B4B0FFA4B5B1FFA7B8B4FF
+ A5B6B2FFA0B1ADFFA0AFABFFA3B2AEFFA3B2AEFFA0AFABFFABB9B5FFA4B2AEFF
+ 929D9AFF98A3A0FF99A4A1FF8F9A97FF959E9BFF8D9693FF7A847EFF8D9791FF
+ 9DA7A1FF9BA59FFF919B95FF919B95FF9BA59FFFA4AEA8FFA1ABA5FF9AA49EFF
+ 919B95FF8E9892FF909A94FF939D97FF949E98FF939D97FF96A39BFF96A39BFF
+ 96A59DFF96A59DFF919F99FF8B9993FF8D9D96FF95A59EFF9CADA9FFA4B5B1FF
+ D1E2DFFFE2F3F0FFDFF2EFFFE2F5F2FFD4E6E5FFCFE1E0FFD5EAE7FFD5EAE7FF
+ D5EAE7FFD5EAE7FFD5EAE7FFD4E9E6FFD2E7E4FFD1E6E3FFD7ECE9FFDAEFECFF
+ D8EDEAFFD2E7E4FFCFE4E1FFD1E6E3FFD2E7E4FFD1E6E3FFCCE1DFFFD4E9E7FF
+ 768B89FF899E9CFFA7BCBAFFA7BCBAFFA8BDBBFF9DB2B0FFA4B9B7FFA3B8B6FF
+ A5BAB8FFA9BEBCFFAABFBDFFAABFBDFFB2C7C5FFBCD1CFFFB2C9C5FFB2CBC7FF
+ B2C9C5FFB7CECAFFC1D8D4FFC1D8D4FFC3D8D5FFCEE3E0FFCFE2DFFFCDE0DDFF
+ CBDEDBFFCCDFDCFFD3E4E1FFD7E8E5FFD9EAE7FFD6E9E6FFB8CECCFFBDD8D5FF
+ BDD6D2FFBAD3CFFFBED7D3FFB9D2CEFFB5CCC7FFBDD4CFFFB8D0C8FFBFD6CEFF
+ C4DBD3FFC1D8D0FFBBD0C7FFB6CBC2FFB7CCC3FFBDD0C7FFBACCC5FFBCCEC7FF
+ C1D1CAFFC0D2CBFFC3D3CCFFC4D6CFFFCADAD3FFCBDDD6FFCCDCD5FFD5E7E0FF
+ CFDFD8FFBCCEC7FF76867FFF9FB1AAFFB3C3BCFFA7B7B0FFA7B5B1FFA6B4B0FF
+ A5B3AFFFA6B4B0FFA7B5B1FFA6B4B0FFA3B1ADFFA1AFABFFA7B5B1FFA8B6B2FF
+ A5B3AFFFA1AFABFFA3B1ADFFA8B6B2FFA9B7B3FFA5B3AFFF97A19BFF99A39DFF
+ 9AA6A0FFA2AEA8FFADB9B3FFB1BDB7FFA2B0AAFF92A09AFF97A7A0FF9EAEA7FF
+ A3B3ACFFA3B3ACFFA5B7B0FFADBFB8FFB3C5BEFFB4C6BFFFBDCCC8FFB3C2BEFF
+ ACBBB7FFAFBEBAFFB3C2BEFFB3C2BEFFB2C1BDFFB2C1BDFFB7C6C2FFB1C0BCFF
+ AAB9B5FFA4B3AFFFA0AFABFF9CABA7FF97A6A2FF94A39FFF939E9CFF848F8DFF
+ 4F5A57FF747F7CFF889390FF9CA7A4FF8C9892FF8A9690FF909D95FF8B9890FF
+ 8A978FFF8F9C94FF96A499FF98A69BFF919F94FF89978CFF889389FF8C978DFF
+ 8F9A90FF8A958BFF79847AFF687369FF646F65FF6A756BFF545F55FF636E64FF
+ 5B665CFF3F4A40FF39443AFF4A554BFF465147FF2F3A30FF2F382EFF2A3329FF
+ 262F25FF262F25FF263127FF242F25FF1E291FFF172218FF1C2A1FFF29372CFF
+ 2F3F34FF2C3C31FF314136FF425247FF536459FF5B6C61FF4D5B55FF505E58FF
+ 55635DFF616F69FF74827CFF84928CFF84928CFF7B8983FF82908AFF87958FFF
+ 83918BFF84928CFF909E98FF98A6A0FFA8B6B0FFC0D0C9FFCDE1DCFFC9DFDAFF
+ C5DBD6FFB2C8C3FFBBD1CCFFCBE1DCFFC8DED9FFDBF1ECFFB6CCC7FFC8DED9FF
+ CFE5E0FFC6DCD7FFA0AAA4FF9FA9A3FF97A19BFF8D9791FF8E9892FF9AA49EFF
+ A5AFA9FFA7B1ABFF959F99FF9FA9A3FFA2ACA6FF9CA6A0FF9EA8A2FFA7B1ABFF
+ A7B1ABFF9DA9A3FF97A5A1FF9BAAA6FFACBBB7FFAAB9B5FF8F9E9AFF879692FF
+ 9DACA8FFB0BFBBFFADBCB8FFA8B7B3FFA9B8B4FFACBBB7FFA2B1ADFF92A19DFF
+ 91A09CFF9AA9A5FFA7B6B2FF9EADA9FF99A8A4FF9EADA9FFABBAB6FFB3C2BEFF
+ B0BFBBFFABBAB6FFA7B6B2FFA2B1ADFF9FAEAAFF9FAEAAFFA4B3AFFFA7B6B2FF
+ A7B6B2FFA6B5B1FFA4B5B1FFA9BAB6FFA8B9B5FF9FB0ACFF9AA9A5FF9BAAA6FF
+ 9FAEAAFF9FAEAAFFA7B5B1FFA4B2AEFF8D9895FF97A29FFF98A3A0FF8A9592FF
+ 969F9CFF8A9390FF7D8781FF858F89FF909A94FF959F99FF929C96FF8F9993FF
+ 96A09AFFA0AAA4FFA7B1ABFFA0AAA4FF97A19BFF939D97FF949E98FF97A19BFF
+ 97A19BFF96A09AFF95A29AFF93A098FF94A39BFF99A8A0FF9AA8A2FF97A59FFF
+ 97A7A0FF9BABA4FF9CADA9FFA6B7B3FFD4E5E2FFE5F6F3FFE0F3F0FFE3F6F3FF
+ D6E8E7FFD2E4E3FFD6EBE8FFD6EBE8FFD7ECE9FFD6EBE8FFD4E9E6FFD2E7E4FF
+ D1E6E3FFD0E5E2FFD2E7E4FFD7ECE9FFD6EBE8FFCEE3E0FFCADFDCFFCEE3E0FF
+ D1E6E3FFD0E5E2FFCCDEDDFFD8EAE9FF819392FF99ABAAFFB9CBCAFFB5C7C6FF
+ AFC1C0FF9FB1B0FF9DAFAEFFACBEBDFFBFD1D0FFC4D6D5FFBCCECDFFBACCCBFF
+ CADCDBFFDDF2F0FFE5FCF8FFDBF4F0FFE1F8F4FFE4FBF7FFDBF2EEFFD4EBE7FF
+ D3E8E5FFCEE3E0FFDBEEEBFFD7EAE7FFD2E5E2FFD1E4E1FFD3E4E1FFD2E3E0FF
+ D2E3E0FFD0E3E0FFC7DFDDFFCBE8E5FFC7E2DEFFC1DCD8FFC4DFDBFFBFDAD6FF
+ BBD5CFFFC0DAD4FFC6E1D8FFCBE3DBFFCCE4DCFFCAE2DAFFC6DED4FFC3DBD1FF
+ C4DCD2FFC9DED5FFBED3CBFFBDD2CAFFC0D2CBFFC1D6CEFFC7D9D2FFC6DBD3FF
+ C8DAD3FFC5DAD2FFCDDFD8FFCEE3DBFFCFE1DAFFCFE4DCFF788A83FF90A59DFF
+ A3B5AEFFA7B9B2FFADBCB8FFADBBB7FFAAB8B4FFA9B7B3FFABB9B5FFABB9B5FF
+ A8B6B2FFA4B2AEFFABB9B5FFA9B7B3FFA5B3AFFFA0AEAAFFA3B1ADFFA9B7B3FF
+ ABB9B5FFA7B5B1FFA2ACA6FF9DA7A1FF97A39DFF9DA9A3FFADB9B3FFB5C1BBFF
+ A8B6B0FF97A59FFF93A39CFF9CACA5FFA4B4ADFFA6B6AFFFA9BBB4FFAFC1BAFF
+ B3C5BEFFB2C4BDFFC1D0CCFFB7C6C2FFB0BFBBFFB0BFBBFFB2C1BDFFB0BFBBFF
+ AFBEBAFFB1C0BCFFB2C1BDFFAFBEBAFFAAB9B5FFA5B4B0FFA2B1ADFF9DACA8FF
+ 98A7A3FF94A39FFF99A4A2FF879290FF515C59FF646F6CFF8A9592FF98A3A0FF
+ 909C96FF8A9690FF93A098FF929F97FF93A098FF96A39BFF9AA89DFF9AA89DFF
+ 97A59AFF93A196FF808B81FF7D887EFF747F75FF6A756BFF667167FF69746AFF
+ 69746AFF657066FF7B867CFF889389FF859086FF737E74FF6F7A70FF7B867CFF
+ 7C877DFF707B71FF7C857BFF767F75FF6C756BFF626B61FF576258FF505B51FF
+ 4B564CFF49544AFF536156FF616F64FF6E7E73FF77877CFF7D8D82FF86968BFF
+ 92A398FF9BACA1FFA4B2ACFFA7B5AFFFABB9B3FFB1BFB9FFB7C5BFFFB6C4BEFF
+ AAB8B2FF9CAAA4FF8D9B95FF93A19BFF94A29CFF9CAAA4FFA6B4AEFF9DABA5FF
+ 94A29CFF9BABA4FF8FA5A0FFADC4BFFFCDE4DFFFC1D8D3FFC1D8D3FFC2D9D4FF
+ B4CBC6FFD2E9E4FFD1E8E3FFC6DDD8FFB9D0CBFFB4CBC6FF9DA7A1FFA3ADA7FF
+ A3ADA7FF9CA6A0FF9AA49EFF9FA9A3FFA0AAA4FF9BA59FFF949E98FFA0AAA4FF
+ A6B0AAFFA1ADA7FFA8B2ACFFB1BDB7FFB2BEB8FFA9B5AFFF98A6A2FF99A8A4FF
+ A8B7B3FFB1C0BCFFA9B8B4FFA9B8B4FFB0BFBBFFADBCB8FFB5C4C0FFAEBDB9FF
+ AEBDB9FFAFBEBAFFA2B1ADFF8F9E9AFF8C9B97FF95A4A0FFB3C2BEFFA9B8B4FF
+ A2B1ADFFA6B5B1FFB2C1BDFFBAC9C5FFB7C6C2FFB0BFBBFFAFBEBAFFA7B6B2FF
+ A1B0ACFFA1B0ACFFA8B7B3FFADBCB8FFADBCB8FFAAB9B5FFA8B9B5FFADBEBAFF
+ ACBDB9FFA0B1ADFF98A7A3FF99A8A4FF9FAEAAFFA4B3AFFFA3B1ADFFA2B0ACFF
+ 8A9592FF95A09DFF96A19EFF87928FFF959E9BFF87908DFF8F9993FF87918BFF
+ 87918BFF8E9892FF919B95FF8F9993FF97A19BFFA4AEA8FF9EA8A2FF9AA49EFF
+ 959F99FF949E98FF939D97FF909A94FF88928CFF828C86FF84908AFF808D85FF
+ 828E88FF8B9993FF93A19BFF94A29CFF93A19BFF92A29BFF96A5A1FFA2B3AFFF
+ D4E5E2FFE5F6F3FFE1F2EFFFE2F5F2FFD9ECE9FFD9ECE9FFD7ECE9FFD8EDEAFF
+ D8EDEAFFD7ECE9FFD4E9E6FFD1E6E3FFD0E5E2FFD0E5E2FFCEE3E0FFD5EAE7FF
+ D4E9E6FFCBE0DDFFC7DCD9FFCCE1DEFFD0E5E2FFCEE3E0FFD8EBE8FFD5E6E3FF
+ 667675FF6D7E7BFF889897FF8B9C99FF91A1A0FF889996FF869695FFA4B5B2FF
+ C5D5D4FFC9DAD7FFB2C2C1FFA1B2AFFFADBDBCFFC2D5D2FFB5CAC7FFB1C8C4FF
+ CFE4E1FFEBFFFDFFE9FEFBFFEBFFFDFFEFFFFFFFE4F7F4FFE0F3F0FFDBEEEBFF
+ DAEBE8FFDAEBE8FFDBECE9FFDBECE9FFDCEDEAFFDDF0EDFFD4EDE9FFD7F5F0FF
+ D2EDE9FFC9E4E0FFCEE9E5FFCDE8E4FFCAE6E0FFD0ECE6FFCDE8DFFFCBE6DDFF
+ CAE2DAFFC8E0D8FFC9E1D9FFCBE4DAFFCCE4DCFFCEE5DDFFCEE3DBFFCBE0D8FF
+ C8DCD7FFC6DDD5FFC7DDD8FFC4DBD3FFBED4CFFFB8CFC7FFCCE2DDFFC5DCD4FF
+ CDE1DCFFE3F8F0FF819590FF8B9D96FF9BACA8FFAEBFBBFFAEBDB9FFADBBB7FF
+ AAB8B4FFA8B6B2FFA9B7B3FFABB9B5FFA7B5B1FFA2B0ACFFAFBDB9FFACBAB6FF
+ A6B4B0FFA0AEAAFFA2B0ACFFAAB8B4FFACBAB6FFA8B6B2FF9FABA5FFA0ACA6FF
+ 9FABA5FF9DA9A3FFA2AEA8FFA9B5AFFFA7B5AFFFA2B0AAFF91A19AFF9BABA4FF
+ A5B5AEFFA9B9B2FFADBDB6FFB1C3BCFFB5C5BEFFB3C3BCFFBECDC9FFB5C4C0FF
+ AEBDB9FFAEBDB9FFADBCB8FFA9B8B4FFA7B6B2FFA9B8B4FFACBBB7FFAAB9B5FF
+ A9B8B4FFA7B6B2FFA5B4B0FF9FAEAAFF98A7A3FF92A19DFF8F9D99FF86918EFF
+ 586360FF5A6562FF828D8AFF87928FFF8F9B95FF939F99FF89968EFF8C9991FF
+ 8F9C94FF8F9C94FF8D9A92FF8B998EFF8C978FFF8C978DFF88938BFF8C978DFF
+ 838E86FF6B766CFF5C675FFF5F6A60FF67726AFF687369FF68736BFF758076FF
+ 808B83FF848F85FF859088FF879288FF87928AFF859086FF7D867CFF818A80FF
+ 858E84FF848D83FF7F8A80FF7F8A80FF828D83FF869187FF869489FF8B998EFF
+ 92A297FF97A79CFF97A79CFF94A499FF97A89DFF9DAEA3FFA1B0A8FF9EADA5FF
+ 9AA8A2FF97A69EFF99A7A1FF9CABA3FF9DABA5FF9CABA3FFABB9B3FFA2B1A9FF
+ 92A09AFF92A199FF9EACA6FF9CABA3FF99A7A1FFA2B2ABFF8DA29AFFA2BAB2FF
+ C2D8D3FFBBD2CDFFCCE2DDFFCFE6E1FFB3C9C4FFC7DED9FFC4DAD5FFBFD6D1FF
+ C5DBD6FFCAE1DCFF9DA49FFFA6ADA8FFAEB5B0FFAEB5B0FFA3ADA7FF9AA49EFF
+ 959F99FF949E98FFA5B1ABFFA3AFA9FFA6B2ACFFACBAB4FFB3BFB9FFADBBB5FF
+ A6B4AEFFA1AFA9FF9BA9A5FF99A7A3FFA4B2AEFFACBAB6FFA6B4B0FFA8B6B2FF
+ ACBAB6FFA5B3AFFFB0BEBAFFADBBB7FFACBAB6FFABB9B5FFA4B2AEFF9BA9A5FF
+ 99A7A3FF9DABA7FFA2B1ADFFB3C2BEFFA2B1ADFF9CABA7FFB7C6C2FFB3C2BEFF
+ A5B4B0FFB8C7C3FFA8B7B3FFA3B2AEFF9FAEAAFFA2B1ADFFA9B8B4FFAFBEBAFF
+ B0BFBBFFAEBDB9FFA6B7B3FFA0B1ADFF9FB0ACFFA0B1ADFF9EADA9FF97A6A2FF
+ 9AA9A5FFA4B3AFFF9FADA9FF9EACA8FF96A19EFF87928FFF818C89FF87928FFF
+ 8C9592FF89928FFF8E9A94FF8C9892FF8E9A94FF94A09AFF929E98FF8C9892FF
+ 8E9A94FF96A29CFF95A19BFF9AA6A0FF939F99FF84908AFF818D87FF8E9A94FF
+ 96A29CFF94A09AFF97A19BFF94A09AFF8E9996FF8B9693FF939E9BFF99A7A3FF
+ 95A39FFF899894FF92A19DFF8C9B97FFD8E7E3FFDCEDE9FFE0F1EDFFD9EAE6FF
+ D9EAE6FFD6E9E6FFD8EDEAFFDEF3F0FFE2F7F4FFDDF2EFFFD3E8E5FFCEE3E0FF
+ D2E7E4FFD8EDEAFFD2E7E4FFD2E7E4FFD0E5E2FFCFE4E1FFCEE3E0FFCEE3E0FF
+ CDE2DFFFCFE2DFFFCEDFDCFFCCDBD7FFA0AEACFF5B6A66FF859391FF8F9E9AFF
+ 808E8CFFA9B8B4FFA3B1AFFFA6B5B1FFAEBCBAFFB4C3BFFFAFBDBBFFA5B4B0FF
+ A4B2B0FFAAB9B5FFA1B2AEFFA1B2AEFFA8B9B5FFB6C7C3FFC5D6D2FFD4E5E1FF
+ E5F6F2FFF1FFFEFFEAFBF7FFE6F7F3FFE2F1EDFFDEEDE9FFDDECE8FFE1F0ECFF
+ E6F5F1FFE6FAF5FFDDF4EFFFE1FDF7FFE2FCF6FFD9F3EDFFD7F1EBFFDCF6F0FF
+ DAF4EEFFD1EBE5FFDBF5EFFFD5EFE9FFD7F1EBFFD8F2ECFFD1EBE5FFD1ECE3FF
+ CEE8E2FFC3DAD5FFC8DED9FFCDE1DCFFCCE1DEFFC7DED9FFC4DBD7FFC1D8D3FF
+ B7D0CCFFAEC8C2FFB3CAC6FFCDE4DFFFCBE0DDFFD2E6E1FF9EAFACFF798884FF
+ A0AEACFFB0BFBBFFAEBCB8FFA9B7B3FFA8B6B2FFAAB8B4FFA9B7B3FFA5B3AFFF
+ A4B2AEFFA8B6B2FFABB9B5FFA5B3AFFFA8B6B2FFA8B6B2FFA3B1ADFFA9B7B3FF
+ ACBAB6FF9EACA8FF9AA8A2FF9FADA7FF8F9D97FF9DABA5FFA6B4AEFF97A59FFF
+ A2B0AAFFAEBCB6FFABB9B3FFA1AFA9FF8E9C96FFA5B3ADFFAAB8B2FFA4B4ADFF
+ BCCAC4FFADBDB6FFB4C3BFFFAEBDB9FFAAB9B5FFABBAB6FFADBCB8FFADBCB8FF
+ ACBBB7FFADBCB8FFACBBB7FFADBCB8FFACBBB7FFA8B7B3FFA3B2AEFF9DACA8FF
+ 98A7A3FF96A5A1FF92A19DFF82908AFF697771FF56645EFF808E88FF7E8C86FF
+ 87938DFF919D97FF848E88FF8E9892FF97A19BFF98A29CFF909A94FF88938BFF
+ 89908BFF89948CFF939D97FF859088FF7B857FFF6E7971FF5C6660FF5F6A62FF
+ 6C7670FF6E7971FF747E78FF79847CFF7E8882FF818C84FF818B85FF808B83FF
+ 808A84FF818C84FF8E978DFF90998FFF939C92FF99A298FF9DA89EFF9EA99FFF
+ 9BA69CFF97A298FF95A398FF97A59AFF99A99EFF9CACA1FF9DADA2FF9CACA1FF
+ 99AA9FFF98A99EFFA0B0A5FF97A79CFF99A8A0FFA6B6ABFFA9B8B0FF9FAFA4FF
+ 9CABA3FFA2B2A7FF9FAEA6FF9FAFA4FF9EADA5FF9DADA2FF9CABA3FF9CACA1FF
+ 9FAEA6FFA0B1A8FF97ACA3FFA3BBB1FFC8DDD5FFC9E0D8FFC6DBD3FFC3DAD2FF
+ B9CEC6FFC1D8D0FFC6DAD5FFBAD0CBFFBBCECBFFC3D8D5FF9CA39EFFA1A8A3FF
+ A6ADA8FFA7AEA9FFA1ABA5FF9DA7A1FF9CA6A0FF9CA6A0FF9FABA5FFA5B1ABFF
+ A5B3ADFFA5B3ADFFAFBDB7FFBAC8C2FFB0C0B9FF9CACA5FFA9B7B3FFA5B3AFFF
+ ADBBB7FFB1BFBBFFA6B4B0FFA4B2AEFFA3B1ADFF99A7A3FFB5C3BFFFB4C2BEFF
+ B4C2BEFFB3C1BDFFADBBB7FFA6B4B0FFA7B5B1FFADBBB7FFA4B3AFFFB3C2BEFF
+ A4B3AFFF9DACA8FFB3C2BEFFAEBDB9FF9FAEAAFFAFBEBAFFB6C5C1FFB0BFBBFF
+ AAB9B5FFAAB9B5FFAEBDB9FFB0BFBBFFAFBEBAFFACBBB7FFABBCB8FFA4B5B1FF
+ A2B3AFFFA2B3AFFF9FAEAAFF95A4A0FF91A09CFF94A39FFFA3B1ADFFA0AEAAFF
+ 98A3A0FF899491FF85908DFF8A9592FF909996FF8F9895FF9BA7A1FF97A39DFF
+ 97A39DFF9AA6A0FF98A49EFF919D97FF909C96FF95A19BFF8E9A94FF96A29CFF
+ 94A09AFF8A9690FF8A9690FF96A29CFF9DA9A3FF9AA6A0FF9FA8A5FFA2ABA8FF
+ 9FAAA7FF9AA5A2FF99A4A1FF9BA6A3FF94A29EFF8C9A96FF869591FF879692FF
+ C1D0CCFFDFEEEAFFE0F1EDFFD7E8E4FFD6E7E3FFD0E4DFFFDBEEEBFFD9EEEBFF
+ D9EEEBFFD8EDEAFFD7ECE9FFD7ECE9FFD7ECE9FFD8EDEAFFD7ECE9FFD6EBE8FF
+ D4E9E6FFD2E7E4FFD0E5E2FFCFE4E1FFCFE4E1FFD1E4E1FFCBDAD6FFCFDDD9FF
+ AAB8B4FF4C5A56FF808E8AFF97A5A1FF919F9BFFA8B6B2FF9DABA7FF9AA8A4FF
+ 9FADA9FFAAB8B4FFA8B6B2FF9CAAA6FF9AA8A4FFA1AFABFF9FAEAAFF9CABA7FF
+ 9BAAA6FF9EADA9FFA3B2AEFFAFBEBAFFC7D6D2FFDCEBE7FFEFFEFAFFEFFEFAFF
+ EEFDF9FFEDFCF8FFEBFAF6FFE9F8F4FFE8F7F3FFE5F6F2FFDEF4EFFFE0FAF4FF
+ E2F9F4FFDAF4EEFFD8EFEAFFD6F0EAFFD9F0EBFFD5EFE9FFDDF4EFFFD6F0EAFF
+ D6EDE8FFD9F3EDFFDCF3EEFFD1EBE5FFCEE5E0FFD1E8E3FFCADFDCFFCDE2DFFF
+ CDE2DFFFC9E0DCFFC4DDD9FFC0D9D5FFB2CDC9FFA5C0BCFFB5CECAFFCCE5E1FF
+ CCE1DEFFD2E5E2FFA0B1AEFF768482FF9DAAA8FFAAB7B5FFAAB8B4FFA6B4B0FF
+ A5B3AFFFA7B5B1FFA5B3AFFFA1AFABFFA1AFABFFA4B2AEFFADBBB7FFA7B5B1FF
+ A9B7B3FFA9B7B3FFA4B2AEFFABB9B5FFAFBDB9FFA3B1ADFF9DABA5FFA2B0AAFF
+ 93A19BFFA0AEA8FFA8B6B0FF99A7A1FFA1AFA9FFABB9B3FFA7B5AFFF9FADA7FF
+ 92A09AFFA5B3ADFFA7B5AFFFA4B2ACFFBBC9C3FFB0BEB8FFB4C3BFFFB4C3BFFF
+ B0BFBBFFACBBB7FFAAB9B5FFACBBB7FFADBCB8FFACBBB7FFA5B4B0FFA7B6B2FF
+ A9B8B4FFA9B8B4FFA5B4B0FF9FAEAAFF99A8A4FF96A5A1FF8E9E97FF7F8F88FF
+ 697771FF57655FFF82908AFF808E88FF85918BFF8A9690FF86908AFF8D9791FF
+ 939D97FF929C96FF8E9590FF8A918CFF8D948FFF929994FF8A948EFF808A84FF
+ 7E8882FF76807AFF66706AFF646E68FF6A746EFF66706AFF727C76FF757F79FF
+ 79837DFF7C8680FF7E8882FF828C86FF87918BFF8B968EFF8C948DFF90998FFF
+ 969F95FF9DA69CFF9FAAA0FF9FAAA0FF9DA89EFF9AA59BFF95A398FF9AA89DFF
+ 9FAFA4FFA5B5AAFFA8B8ADFFA5B5AAFFA0B1A6FF9DAEA3FFA8B8ADFF9EAEA3FF
+ 94A499FF97A79CFFA5B5AAFFAFBFB4FFA9B9AEFF9DADA2FFA4B4A9FFA4B4A9FF
+ A4B4A9FFA3B3A8FFA2B2A7FFA2B2A7FFA3B3A8FFA3B4A9FF96A9A0FFA2B7AEFF
+ C4D9D0FFC7DCD3FFC2D7CFFFC3D8D0FFB8CDC5FFC3D8D0FFC0D4CFFFB7CBC6FF
+ B7CAC7FFC2D5D2FF9AA19CFF9BA29DFF9DA49FFF9FA6A1FF9EA8A2FFA0AAA4FF
+ A2ACA6FFA3ADA7FF9BA7A1FFA5B1ABFF9EACA6FF94A29CFFA2B0AAFFBDCBC5FF
+ B9C9C2FFA0B0A9FFABB9B5FFA7B5B1FFAFBDB9FFB3C1BDFFAAB8B4FFA8B6B2FF
+ A6B4B0FF9BA9A5FFB3C1BDFFB3C1BDFFB5C3BFFFB4C2BEFFADBBB7FFA6B4B0FF
+ A8B6B2FFAFBDB9FFA1B0ACFFAEBDB9FFA3B2AEFF9FAEAAFFB0BFBBFFA9B8B4FF
+ 9CABA7FFA7B6B2FFB9C8C4FFB4C3BFFFAEBDB9FFACBBB7FFAEBDB9FFAEBDB9FF
+ ACBBB7FFA9B8B4FFAEBFBBFFA7B8B4FFA4B5B1FFA5B6B2FFA5B4B0FF9CABA7FF
+ 92A19DFF8D9C98FFA0AEAAFF9DABA7FF96A19EFF8A9592FF86918EFF8A9592FF
+ 909996FF909996FFA1ADA7FF9DA9A3FF9BA7A1FF9DA9A3FF9CA8A2FF97A39DFF
+ 94A09AFF94A09AFF8C9892FF94A09AFF95A19BFF8E9A94FF8F9B95FF97A39DFF
+ 9CA8A2FF99A59FFF9EA7A4FFA5AEABFFA6B1AEFFA2ADAAFF9DA8A5FF9AA5A2FF
+ 95A39FFF92A09CFF84938FFF899894FFA1B0ACFFD9E8E4FFDBECE8FFD6E7E3FF
+ D8E9E5FFD3E7E2FFD9ECE9FFD1E6E3FFCDE2DFFFD1E6E3FFD8EDEAFFDDF2EFFF
+ DAEFECFFD6EBE8FFDAEFECFFD8EDEAFFD5EAE7FFD1E6E3FFCFE4E1FFCEE3E0FF
+ CEE3E0FFD0E3E0FFD1E0DCFFD7E5E1FFBECCC8FF3A4844FF6F7D79FF8A9894FF
+ 8A9894FF8C9A96FF9AA8A4FF8E9C98FF919F9BFFA3B1ADFFA6B4B0FF98A6A2FF
+ 95A39FFF9FADA9FF9CABA7FF9BAAA6FF99A8A4FF95A4A0FF92A19DFF98A7A3FF
+ ACBBB7FFC1D0CCFFD9E8E4FFDEEDE9FFE7F6F2FFEDFCF8FFEDFCF8FFE8F7F3FF
+ E1F0ECFFD9EAE6FFCCE2DDFFCCE3DEFFCFE5E0FFCEE5E0FFCAE0DBFFC4DBD6FF
+ CAE0DBFFD3EAE5FFD3E9E4FFD7EEE9FFD1E7E2FFD4EBE6FFE1F7F2FFD5ECE7FF
+ CEE4DFFFE2F8F3FFDBEEEBFFDAEFECFFD9EEEBFFD5ECE8FFD2EBE7FFCDE6E2FF
+ BDD8D4FFADC8C4FFB9D2CEFFCBE4E0FFCFE4E1FFD4E7E4FFAABBB8FF7A8886FF
+ A1AEACFFAAB7B5FFAEBCB8FFAAB8B4FFA9B7B3FFABB9B5FFA9B7B3FFA4B2AEFF
+ A3B1ADFFA6B4B0FFACBAB6FFA6B4B0FFA7B5B1FFA6B4B0FFA1AFABFFAAB8B4FF
+ B0BEBAFFA6B4B0FF9BA9A3FFA2B0AAFF93A19BFF9FADA7FFA8B6B0FF98A6A0FF
+ 9EACA6FFA4B2ACFFA1AFA9FF9CAAA4FF97A59FFFA5B3ADFFA2B0AAFFA3B1ABFF
+ B8C6C0FFB3C1BBFFB4C3BFFFBBCAC6FFB9C8C4FFADBCB8FFA6B5B1FFA9B8B4FF
+ ACBBB7FFAAB9B5FFA4B3AFFFA6B5B1FFA8B7B3FFA8B7B3FFA5B4B0FF9EADA9FF
+ 96A5A1FF91A09CFF8B9B94FF7D8D86FF687670FF56645EFF83918BFF818F89FF
+ 828E88FF828E88FF87918BFF8C9690FF8F9993FF8D9791FF8A918CFF8A918CFF
+ 909792FF979E99FF818B85FF7C8680FF828C86FF818B85FF717B75FF69736DFF
+ 66706AFF5B655FFF6B756FFF6E7872FF717B75FF757F79FF7A847EFF828C86FF
+ 8C9690FF939E96FF8B938CFF90998FFF98A197FF9DA69CFF9EA99FFF9EA99FFF
+ 9DA89EFF9CA79DFF9BA99EFF9EACA1FFA1B1A6FFA6B6ABFFA9B9AEFFA9B9AEFF
+ A7B8ADFFA6B7ACFFA7B7ACFFA6B6ABFF9AAA9FFF90A095FF9AAA9FFFAEBEB3FF
+ AFBFB4FFA2B2A7FFA5B5AAFFA5B5AAFFA6B6ABFFA7B7ACFFA7B7ACFFA6B6ABFF
+ A6B6ABFFA4B5AAFF97AAA1FFA1B6ADFFC1D6CDFFC3D8CFFFC0D5CDFFC3D8D0FF
+ B9CEC6FFC4D9D1FFC2D6D1FFBCD0CBFFBDD0CDFFC8DBD8FF989F9AFF989F9AFF
+ 99A09BFF9CA39EFF9EA8A2FFA1ABA5FFA1ABA5FFA0AAA4FFA5B1ABFFA8B4AEFF
+ 9DABA5FF909E98FF9BA9A3FFB5C3BDFFBCCCC5FFB2C2BBFFAEBCB8FFA9B7B3FF
+ B0BEBAFFB6C4C0FFAEBCB8FFADBBB7FFABB9B5FF9FADA9FFAFBDB9FFB0BEBAFF
+ B5C3BFFFB5C3BFFFADBBB7FFA3B1ADFFA1AFABFFA5B3AFFF9BAAA6FFA6B5B1FF
+ A2B1ADFFA1B0ACFFADBCB8FFA8B7B3FF9EADA9FFA5B4B0FFAFBEBAFFABBAB6FF
+ A8B7B3FFA8B7B3FFA9B8B4FFAAB9B5FFA9B8B4FFA7B6B2FFACBDB9FFA5B6B2FF
+ A1B2AEFFA4B5B1FFABBAB6FFA9B8B4FFA0AFABFF99A8A4FF9DABA7FF9BA9A5FF
+ 97A29FFF919C99FF8E9996FF8E9996FF919A97FF909996FF9CA8A2FF99A59FFF
+ 98A49EFF9AA6A0FF9BA7A1FF99A59FFF95A19BFF939F99FF929E98FF97A39DFF
+ 96A29CFF8F9B95FF8C9892FF909C96FF929E98FF909C96FF929B98FF97A09DFF
+ 99A4A1FF9AA5A2FF99A4A1FF9AA5A2FF99A7A3FF99A7A3FF8E9D99FF93A29EFF
+ 889793FFCEDDD9FFD4E5E1FFD5E6E2FFDCEDE9FFDAEEE9FFD4E7E4FFCCE1DEFF
+ C8DDDAFFCBE0DDFFD4E9E6FFD9EEEBFFD7ECE9FFD3E8E5FFD8EDEAFFD6EBE8FF
+ D2E7E4FFCFE4E1FFCCE1DEFFCADFDCFFC9DEDBFFCBDEDBFFD3E2DEFFD7E5E1FF
+ CEDCD8FF32403CFF5C6A66FF73817DFF788682FF75837FFF94A29EFF82908CFF
+ 83918DFF9AA8A4FFA2B0ACFF96A4A0FF92A09CFF9DABA7FF97A6A2FF98A7A3FF
+ 9CABA7FF9FAEAAFF9DACA8FF9BAAA6FFA2B1ADFFACBBB7FFC6D5D1FFD1E0DCFF
+ E0EFEBFFEEFDF9FFF3FFFEFFF2FFFDFFEBFAF6FFE4F5F1FFC3D7D2FFBDD3CEFF
+ BED2CDFFBAD0CBFFAFC3BEFF9FB5B0FFA5B9B4FFB2C8C3FFBCD0CBFFD3E9E4FF
+ CBDFDAFFC1D7D2FFD9EDE8FFD5EBE6FFD2E6E1FFEAFEF9FFE9FCF9FFE6FBF8FF
+ E2F7F4FFDDF4F0FFDCF5F1FFDBF4F0FFCDE8E4FFBFDAD6FFB7D0CCFFC3DCD8FF
+ CBE0DDFFD0E3E0FFB0C1BEFF7C8A88FFA5B2B0FFAAB7B5FFAEBCB8FFABB9B5FF
+ AAB8B4FFADBBB7FFABB9B5FFA6B4B0FFA4B2AEFFA7B5B1FFA7B5B1FFA1AFABFF
+ A3B1ADFFA1AFABFF9BA9A5FFA5B3AFFFADBBB7FFA5B3AFFF9AA8A2FFA3B1ABFF
+ 95A39DFFA1AFA9FFABB9B3FF9DABA5FFA1AFA9FFA4B2ACFF9CAAA4FF9AA8A2FF
+ 9EACA6FFA5B3ADFF9EACA6FFA3B1ABFFB5C3BDFFB5C3BDFFB4C3BFFFC0CFCBFF
+ C0CFCBFFAFBEBAFFA4B3AFFFA7B6B2FFABBAB6FFA8B7B3FFAAB9B5FFA9B8B4FF
+ A7B6B2FFA4B3AFFFA0AFABFF99A8A4FF91A09CFF8C9B97FF8C9C95FF7E8E87FF
+ 67756FFF53615BFF818F89FF818F89FF818D87FF7E8A84FF89938DFF8C9690FF
+ 8E9892FF8C9690FF8A918CFF8A918CFF8F9691FF959C97FF7F8983FF7C8680FF
+ 858F89FF86908AFF77817BFF6C7670FF636D67FF545E58FF656F69FF69736DFF
+ 6E7872FF747E78FF7B857FFF838D87FF8D9791FF949F97FF8D958EFF90998FFF
+ 959E94FF97A096FF96A197FF97A298FF99A49AFF9CA79DFFA3B1A6FFA2B0A5FF
+ 9EAEA3FF9FAFA4FFA1B1A6FFA5B5AAFFA9BAAFFFACBDB2FFA0B0A5FFA8B8ADFF
+ A7B7ACFF9AAA9FFF93A398FF9BABA0FFA8B8ADFFAEBEB3FFA0B0A5FFA0B0A5FF
+ A2B2A7FFA5B5AAFFA7B7ACFFA7B7ACFFA5B5AAFFA2B3A8FF9EB1A8FFA6BBB2FF
+ C4D9D0FFC6DBD2FFC3D8D0FFC6DBD3FFBCD1C9FFC7DCD4FFC5D9D4FFC0D4CFFF
+ C3D6D3FFCCDFDCFF949B96FF969D98FF9AA19CFF9FA6A1FFA0AAA4FF9FA9A3FF
+ 9BA59FFF98A29CFFAAB6B0FFAAB6B0FFA6B4AEFFA4B2ACFFA6B4AEFFAEBCB6FF
+ B7C7C0FFBDCDC6FFB9C7C3FFB1BFBBFFB5C3BFFFB7C5C1FFAFBDB9FFACBAB6FF
+ A8B6B2FF9BA9A5FFABB9B5FFAEBCB8FFB5C3BFFFBBC9C5FFB7C5C1FFABB9B5FF
+ A5B3AFFFA5B3AFFF9DACA8FFA4B3AFFFA5B4B0FFA6B5B1FFAAB9B5FFA5B4B0FF
+ 9FAEAAFFA1B0ACFFABBAB6FFA9B8B4FFA8B7B3FFA8B7B3FFA9B8B4FFAAB9B5FF
+ AAB9B5FFA9B8B4FFAABBB7FFA3B4B0FF9CADA9FF9EAFABFFA9B8B4FFAFBEBAFF
+ ACBBB7FFA5B4B0FF9BA9A5FF9AA8A4FF9BA6A3FF9BA6A3FF98A3A0FF939E9BFF
+ 919A97FF909996FF98A49EFF99A59FFF99A59FFF98A49EFF98A49EFF97A39DFF
+ 939F99FF8F9B95FF99A59FFF9AA6A0FF96A29CFF8E9A94FF89958FFF8B9791FF
+ 8D9993FF8E9A94FF8D9693FF8B9491FF899491FF8D9895FF939E9BFF98A3A0FF
+ 99A7A3FF9BA9A5FF92A19DFF96A5A1FF7F8E8AFFBFCECAFFD1E2DEFFD6E7E3FF
+ D7E8E4FFD5E9E4FFD3E6E3FFCFE4E1FFCDE2DFFFCDE2DFFFCFE4E1FFD1E6E3FF
+ D3E8E5FFD4E9E6FFD6EBE8FFD5EAE7FFD2E7E4FFCFE4E1FFCBE0DDFFC9DEDBFF
+ C7DCD9FFC8DBD8FFCEDDD9FFCFDDD9FFD8E6E2FF374541FF54625EFF6D7B77FF
+ 768480FF7B8985FF899793FF788682FF788682FF8E9C98FF98A6A2FF919F9BFF
+ 8F9D99FF98A6A2FF95A4A0FF93A29EFF96A5A1FF9EADA9FFA0AFABFF9DACA8FF
+ 9AA9A5FF9BAAA6FFA9B8B4FFB4C3BFFFC4D3CFFFD3E2DEFFDDECE8FFDFEEEAFF
+ DCEBE7FFD9E8E4FFCEDFDBFFC4D8D3FFBFD0CCFFB3C7C2FF9FB0ACFF879B96FF
+ 879894FF90A49FFFA2B3AFFFC8DCD7FFC2D3CFFFACC0BBFFC3D4D0FFCFE3DEFF
+ D3E4E0FFE3F7F2FFE6F9F6FFE1F6F3FFDBF0EDFFD6EDE9FFD6EFEBFFDAF3EFFF
+ D3EEEAFFCBE6E2FFB9D2CEFFBDD6D2FFC6DBD8FFC9DCD9FFB3C4C1FF778583FF
+ A1AEACFFA3B0AEFFA7B5B1FFA4B2AEFFA5B3AFFFA8B6B2FFA7B5B1FFA2B0ACFF
+ A0AEAAFFA3B1ADFFA5B3AFFFA0AEAAFFA3B1ADFFA0AEAAFF99A7A3FFA2B0ACFF
+ ABB9B5FFA5B3AFFF9CAAA4FFA6B4AEFF98A6A0FFA3B1ABFFAFBDB7FFA5B3ADFF
+ A9B7B1FFA9B7B1FF9AA8A2FF98A6A0FFA6B4AEFFA4B2ACFF9BA9A3FFA5B3ADFF
+ B1BFB9FFB6C4BEFFB3C2BEFFC0CFCBFFC2D1CDFFB3C2BEFFA6B5B1FFA5B4B0FF
+ A7B6B2FFA6B5B1FFADBCB8FFA8B7B3FFA1B0ACFF9CABA7FF99A8A4FF96A5A1FF
+ 92A19DFF8E9D99FF8E9E97FF82928BFF697771FF515F59FF7D8B85FF808E88FF
+ 838F89FF808C86FF8A948EFF8E9892FF919B95FF8F9993FF8D948FFF8A918CFF
+ 8A918CFF8C938EFF848E88FF7E8882FF848E88FF848E88FF757F79FF6C7670FF
+ 636D67FF545E58FF656F69FF6B756FFF747E78FF7C8680FF828C86FF88928CFF
+ 8D9791FF919C94FF909891FF90998FFF8F988EFF8E978DFF8C978DFF909B91FF
+ 949F95FF98A399FFA3B1A6FFA3B1A6FFA1B1A6FFA1B1A6FFA2B2A7FFA4B4A9FF
+ A6B7ACFFA7B8ADFFA3B3A8FFA2B2A7FFA4B4A9FFA4B4A9FF9AAA9FFF92A297FF
+ 9BABA0FFACBCB1FF9EAEA3FF9DADA2FF9FAFA4FFA3B3A8FFA7B7ACFFA8B8ADFF
+ A6B6ABFFA2B3A8FFA6B9B0FFADC2B9FFC9DED5FFCBE0D7FFC9DED6FFCBE0D8FF
+ C0D5CDFFC9DED6FFBFD3CEFFBCD0CBFFBDD0CDFFC3D6D3FF8D948FFF939A95FF
+ 9BA29DFFA1A8A3FFA1ABA5FF9EA8A2FF99A39DFF959F99FF9EAAA4FFA4B0AAFF
+ ACBAB4FFB3C1BBFFAFBDB7FFA9B7B1FFAABAB3FFB1C1BAFFB8C6C2FFAEBCB8FF
+ B1BFBBFFB4C2BEFFAFBDB9FFB0BEBAFFB0BEBAFFA4B2AEFFA3B1ADFFA4B2AEFF
+ ACBAB6FFB7C5C1FFBBC9C5FFB4C2BEFFABB9B5FFA8B6B2FFA7B6B2FFA9B8B4FF
+ ACBBB7FFACBBB7FFA7B6B2FFA2B1ADFF9FAEAAFF9CABA7FFB1C0BCFFB0BFBBFF
+ AFBEBAFFAEBDB9FFADBCB8FFACBBB7FFABBAB6FFABBAB6FFAABBB7FFA3B4B0FF
+ 9AABA7FF97A8A4FFA1B0ACFFACBBB7FFACBBB7FFA7B6B2FF95A39FFF93A19DFF
+ 96A19EFF99A4A1FF95A09DFF8D9895FF89928FFF89928FFF97A39DFF9DA9A3FF
+ 9FABA5FF9AA6A0FF95A19BFF939F99FF8F9B95FF8B9791FF9AA6A0FF99A59FFF
+ 96A29CFF919D97FF8C9892FF8C9892FF8F9B95FF929E98FF939C99FF8C9592FF
+ 87928FFF8B9693FF919C99FF949F9CFF95A39FFF99A7A3FF8D9C98FF8F9E9AFF
+ 82918DFFABBAB6FFCDDEDAFFD6E7E3FFCCDDD9FFC8DCD7FFD5E8E5FFD4E9E6FF
+ D3E8E5FFD0E5E2FFCDE2DFFFCDE2DFFFD1E6E3FFD6EBE8FFD4E9E6FFD4E9E6FF
+ D3E8E5FFD2E7E4FFCFE4E1FFCBE0DDFFC7DCD9FFC6D9D6FFD3E2DEFFD5E3DFFF
+ E1EFEBFF3F4D49FF4B5955FF798783FF7E8C88FF85938FFF889692FF7D8B87FF
+ 7D8B87FF8A9894FF93A19DFF92A09CFF919F9BFF95A39FFF9EADA9FF96A5A1FF
+ 92A19DFF96A5A1FF9AA9A5FF99A8A4FF97A6A2FF98A7A3FF91A09CFF98A7A3FF
+ A4B3AFFFAFBEBAFFB6C5C1FFB9C8C4FFB8C7C3FFB6C5C1FFCAD9D5FFC6D5D1FF
+ C0CFCBFFB6C5C1FFA5B4B0FF96A5A1FF93A29EFF98A7A3FF96A5A1FFB8C7C3FF
+ B7C6C2FFA4B3AFFFAEBDB9FFC0CFCBFFCCDBD7FFDAEBE7FFDCEFECFFD9EEEBFF
+ D5EAE7FFCFE6E2FFCFE8E4FFD6EFEBFFD6F1EDFFD3EEEAFFCAE3DFFFC5DEDAFF
+ CDE2DFFFCADDDAFFBACBC8FF768482FFA2AFADFFA0ADABFFA4B2AEFFA2B0ACFF
+ A4B2AEFFA8B6B2FFA8B6B2FFA3B1ADFFA2B0ACFFA4B2AEFFA5B3AFFFA2B0ACFF
+ A6B4B0FFA3B1ADFF9BA9A5FFA2B0ACFFABB9B5FFA5B3AFFF96A49EFFA1AFA9FF
+ 92A09AFF9BA9A3FFA8B6B0FFA2B0AAFFA7B5AFFFA4B2ACFF9CAAA4FF98A6A0FF
+ ACBAB4FFA4B2ACFF9AA8A2FFA9B7B1FFAEBCB6FFB5C3BDFFB3C2BEFFB9C8C4FF
+ BECDC9FFB8C7C3FFACBBB7FFA4B3AFFFA3B2AEFFA5B4B0FFA8B7B3FFA1B0ACFF
+ 99A8A4FF95A4A0FF96A5A1FF97A6A2FF96A5A1FF94A39FFF8F9F98FF879790FF
+ 707E78FF53615BFF7B8983FF7F8D87FF84908AFF838F89FF8B958FFF8F9993FF
+ 929C96FF919B95FF8F9691FF89908BFF868D88FF858C87FF88928CFF7F8983FF
+ 808A84FF7F8983FF727C76FF6C7670FF68726CFF5B655FFF68726CFF707A74FF
+ 7B857FFF848E88FF89938DFF8C9690FF8D9791FF8E9991FF929A93FF8E978DFF
+ 8A9389FF899288FF8B968CFF909B91FF949F95FF95A096FF9FADA2FFA3B1A6FF
+ A6B6ABFFAABAAFFFABBBB0FFA9B9AEFFA4B5AAFFA1B2A7FFABBBB0FF9BABA0FF
+ 97A79CFFA3B3A8FFA7B7ACFF9DADA2FF98A89DFF9EAEA3FFA3B3A8FFA1B1A6FF
+ A0B0A5FFA3B3A8FFA8B8ADFFAABAAFFFA7B7ACFFA3B4A9FFA6B9B0FFACC1B8FF
+ C9DED5FFCCE1D8FFCBE0D8FFCEE3DBFFC1D6CEFFC8DDD5FFBED2CDFFBBCFCAFF
+ BACDCAFFBBCECBFF838A85FF8D948FFF99A09BFFA0A7A2FF9FA9A3FF9DA7A1FF
+ 9CA6A0FF9CA6A0FF99A59FFFA7B3ADFFB0BEB8FFB0BEB8FFAEBCB6FFAEBCB6FF
+ ABBBB4FFA6B6AFFFB5C3BFFFAAB8B4FFACBAB6FFB0BEBAFFAFBDB9FFB4C2BEFF
+ B8C6C2FFAEBCB8FFA2B0ACFF9DABA7FFA0AEAAFFADBBB7FFB7C5C1FFB5C3BFFF
+ ADBBB7FFA7B5B1FFAEBDB9FFACBBB7FFB1C0BCFFB1C0BCFFA6B5B1FFA3B2AEFF
+ A4B3AFFF9FAEAAFFAFBEBAFFAFBEBAFFAFBEBAFFAEBDB9FFACBBB7FFAAB9B5FF
+ A9B8B4FFA8B7B3FFAABBB7FFA6B7B3FF9DAEAAFF97A8A4FF9EADA9FFA9B8B4FF
+ ABBAB6FFA6B5B1FF97A5A1FF92A09CFF929D9AFF949F9CFF919C99FF889390FF
+ 868F8CFF89928FFF909C96FF9BA7A1FFA0ACA6FF99A59FFF909C96FF8E9A94FF
+ 8E9A94FF8C9892FF96A29CFF95A19BFF95A19BFF939F99FF8F9B95FF8C9892FF
+ 8C9892FF8F9B95FF969F9CFF929B98FF8F9A97FF939E9BFF929D9AFF8E9996FF
+ 8F9D99FF97A5A1FF92A19DFF8A9995FF899894FF8D9C98FFC1D2CEFFD4E5E1FF
+ C9DAD6FFC9DDD8FFD4E7E4FFD2E7E4FFD0E5E2FFCDE2DFFFC9DEDBFFCADFDCFF
+ CEE3E0FFD2E7E4FFCEE3E0FFD0E5E2FFD2E7E4FFD2E7E4FFD0E5E2FFCADFDCFF
+ C4D9D6FFC2D5D2FFCDDCD8FFD7E5E1FFDCEAE6FF35433FFF384642FF8F9D99FF
+ 8D9B97FF8A9894FF8B9995FF899793FF889692FF899793FF8E9C98FF92A09CFF
+ 92A09CFF909E9AFF9FAEAAFF98A7A3FF94A39FFF96A5A1FF98A7A3FF98A7A3FF
+ 9BAAA6FFA0AFABFF9AA9A5FF9FAEAAFFA6B5B1FFADBCB8FFB0BFBBFFB1C0BCFF
+ AEBDB9FFACBBB7FFB6C4C0FFBAC8C4FFB9C7C3FFB1BFBBFFABB9B5FFAAB8B4FF
+ A9B7B3FFA6B4B0FF9BA9A5FFA5B3AFFFAAB8B4FFA7B5B1FFA2B0ACFFA8B6B2FF
+ BECCC8FFD5E4E0FFD4E5E2FFD4E9E6FFD4E9E6FFCEE5E1FFCCE5E1FFD2EBE7FF
+ D6F1EDFFD7F2EEFFD4EDE9FFC8E1DDFFD0E5E2FFC9DCD9FFC0D1CEFF778583FF
+ A5B2B0FFA1AEACFFA2B0ACFFA1AFABFFA4B2AEFFA9B7B3FFAAB8B4FFA6B4B0FF
+ A5B3AFFFA7B5B1FFA3B1ADFFA2B0ACFFA8B6B2FFA5B3AFFF9BA9A5FFA1AFABFF
+ A8B6B2FFA1AFABFF96A49EFFA0AEA8FF8E9C96FF94A29CFFA2B0AAFF9EACA6FF
+ A3B1ABFF9FADA7FFA0AEA8FF99A7A1FFB0BEB8FFA4B2ACFF9AA8A2FFADBBB5FF
+ ACBAB4FFB3C1BBFFB2C1BDFFB1C0BCFFB7C6C2FFBDCCC8FFB4C3BFFFA3B2AEFF
+ 9EADA9FFA6B5B1FFA3B2AEFF9DACA8FF96A5A1FF94A39FFF97A6A2FF98A7A3FF
+ 96A5A1FF92A19DFF8B9B94FF8B9B94FF788680FF5A6862FF7E8C86FF808E88FF
+ 85918BFF84908AFF8D9791FF8F9993FF919B95FF909A94FF8E9590FF89908BFF
+ 868D88FF848B86FF86908AFF7C8680FF7B857FFF7A847EFF707A74FF6F7973FF
+ 6F7973FF646E68FF67716BFF6F7973FF7A847EFF838D87FF87918BFF89938DFF
+ 89938DFF8A958DFF919992FF8B948AFF889187FF8C958BFF939E94FF99A49AFF
+ 98A399FF95A096FFA1AFA4FFA3B1A6FFA3B3A8FFA6B6ABFFA8B8ADFFA8B8ADFF
+ A7B8ADFFA6B7ACFFA5B5AAFF9DADA2FF99A99EFFA0B0A5FFA7B7ACFFA7B7ACFF
+ A0B0A5FF9AAA9FFFACBCB1FFA6B6ABFFA2B2A7FFA2B2A7FFA6B6ABFFA7B7ACFF
+ A4B4A9FF9FB0A5FF9CAFA6FFA3B8AFFFC2D7CEFFC7DCD3FFC9DED6FFCCE1D9FF
+ BFD4CCFFC5DAD2FFC3D7D2FFC0D4CFFFBBCECBFFB8CBC8FF7C837EFF888F8AFF
+ 969D98FF9EA5A0FF9DA7A1FF9DA7A1FFA1ABA5FFA5AFA9FFA4B0AAFFB6C2BCFF
+ B7C5BFFFA9B7B1FFACBAB4FFBDCBC5FFBDCDC6FFADBDB6FFC0CECAFFB2C0BCFF
+ B0BEBAFFB0BEBAFFACBAB6FFAFBDB9FFB1BFBBFFA7B5B1FFABB9B5FFA1AFABFF
+ 9EACA8FFA9B7B3FFB5C3BFFFB6C4C0FFAEBCB8FFA8B6B2FFAEBDB9FFAAB9B5FF
+ B2C1BDFFB3C2BEFFA7B6B2FFA6B5B1FFABBAB6FFA5B4B0FFA5B4B0FFA6B5B1FF
+ A7B6B2FFA7B6B2FFA6B5B1FFA5B4B0FFA4B3AFFFA5B4B0FFA9BAB6FFA8B9B5FF
+ A2B3AFFF9BACA8FFA1B0ACFFABBAB6FFAEBDB9FFA8B7B3FFA3B1ADFF9BA9A5FF
+ 98A3A0FF99A4A1FF95A09DFF8D9895FF8E9794FF939C99FF84908AFF939F99FF
+ 9CA8A2FF95A19BFF8C9892FF8C9892FF8E9A94FF8E9A94FF919D97FF929E98FF
+ 94A09AFF94A09AFF8F9B95FF88948EFF84908AFF85918BFF929B98FF939C99FF
+ 96A19EFF99A4A1FF929D9AFF899491FF8B9995FF97A5A1FF9EADA9FF8B9A96FF
+ 8D9C98FF74837FFFB3C4C0FFD2E3DFFFCDDEDAFFD7EBE6FFD1E4E1FFCCE1DEFF
+ C8DDDAFFC6DBD8FFC5DAD7FFC7DCD9FFCADFDCFFCBE0DDFFC7DCD9FFCADFDCFF
+ CEE3E0FFD0E5E2FFCDE2DFFFC7DCD9FFC0D5D2FFBDD0CDFFB5C4C0FFC9D7D3FF
+ C9D7D3FF212F2BFF263430FFA4B2AEFFA2B0ACFF93A19DFF899793FF8D9B97FF
+ 8A9894FF83918DFF84928EFF8C9A96FF8C9A96FF85938FFF92A19DFF92A19DFF
+ 95A4A0FF9AA9A5FF99A8A4FF97A6A2FF9CABA7FFA3B2AEFF9BAAA6FF9FAEAAFF
+ A5B4B0FFA9B8B4FFABBAB6FFA9B8B4FFA6B5B1FFA3B2AEFFAFBAB7FFB7C2BFFF
+ B6C1BEFFABB6B3FFA8B3B0FFACB7B4FFA9B4B1FFA0ABA8FFA7B2AFFF9AA5A2FF
+ A4AFACFFB0BBB8FFA0ABA8FF98A3A0FFB4BFBCFFD3E1DDFFC9DAD7FFCDE2DFFF
+ D1E6E3FFCCE3DFFFC8E1DDFFCCE5E1FFD0EBE7FFD2EDE9FFCEE7E3FFBFD8D4FF
+ C6DBD8FFC0D3D0FFBBCCC9FF72807EFFA2AFADFF9EABA9FF9CAAA6FF9AA8A4FF
+ 9EACA8FFA4B2AEFFA6B4B0FFA2B0ACFFA1AFABFFA4B2AEFF9FADA9FF9FADA9FF
+ A6B4B0FFA3B1ADFF99A7A3FF9DABA7FFA3B1ADFF9CAAA6FF9FADA7FFA9B7B1FF
+ 95A39DFF98A6A0FFA5B3ADFFA2B0AAFFA7B5AFFFA2B0AAFFA3B1ABFF9AA8A2FF
+ B2C0BAFFA3B1ABFF9AA8A2FFB0BEB8FFABB9B3FFB1BFB9FFB1C0BCFFABBAB6FF
+ B2C1BDFFC0CFCBFFB9C8C4FFA3B2AEFF9CABA7FFA6B5B1FFA4B3AFFF9EADA9FF
+ 98A7A3FF96A5A1FF98A7A3FF97A6A2FF91A09CFF8B9A96FF889891FF8C9C95FF
+ 7E8C86FF606E68FF818F89FF818F89FF85918BFF838F89FF8E9892FF8F9993FF
+ 8F9993FF8E9892FF8D948FFF89908BFF878E89FF868D88FF838D87FF78827CFF
+ 77817BFF78827CFF707A74FF727C76FF747E78FF6A746EFF636D67FF6A746EFF
+ 747E78FF7C8680FF808A84FF828C86FF848E88FF859088FF8F9790FF8A9389FF
+ 889187FF919A90FF9CA79DFFA2ADA3FF9DA89EFF96A197FFA7B5AAFFA3B1A6FF
+ 9BABA0FF99A99EFF9BABA0FFA3B3A8FFABBCB1FFB1C2B7FF95A59AFFA4B4A9FF
+ A9B9AEFFA0B0A5FF9EAEA3FFA5B5AAFFA8B8ADFFA2B2A7FFB0C0B5FFA9B9AEFF
+ A2B2A7FFA0B0A5FFA2B2A7FFA2B2A7FF9EAEA3FF99AA9FFF91A49BFF99AEA5FF
+ BACFC6FFC2D7CEFFC6DBD3FFC9DED6FFBCD1C9FFC1D6CEFFC4D8D3FFC1D5D0FF
+ BACDCAFFB4C7C4FF8D948FFF959C97FF949B96FF979E99FFA4AEA8FFA9B3ADFF
+ ABB5AFFFB6C0BAFFAFBBB5FFB0BCB6FFB5C3BDFFBFCDC7FFC5D3CDFFC1CFC9FF
+ B8C8C1FFB3C3BCFFBBC9C5FFBECCC8FFB7C5C1FFAAB8B4FFA8B6B2FFAFBDB9FF
+ A9B7B3FF9BA9A5FFABB9B5FF94A29EFF96A4A0FFB3C1BDFFBAC8C4FFA4B2AEFF
+ 9BA9A5FFA8B6B2FFADBCB8FFABBAB6FFA8B7B3FFA5B4B0FFA4B3AFFFA5B4B0FF
+ A9B8B4FFACBBB7FF9CABA7FFA7B6B2FFB0BFBBFFAFBEBAFFA9B8B4FFA6B5B1FF
+ A8B7B3FFAAB9B5FFA8B9B5FFAFC0BCFFACBDB9FFA1B2AEFFA3B2AEFFAEBDB9FF
+ B0BFBBFFA9B8B4FFA4B2AEFF9EACA8FF98A3A0FF939E9BFF99A4A1FF9EA9A6FF
+ 9BA4A1FF919A97FF8C9892FF909C96FF96A29CFF98A49EFF929E98FF8C9892FF
+ 919D97FF9AA6A0FF909C96FF8F9B95FF8E9A94FF8C9892FF8A9690FF88948EFF
+ 87938DFF86928CFF8F9895FF8F9895FF8D9895FF8C9794FF8D9895FF8F9A97FF
+ 909E9AFF92A09CFFA8B7B3FFA4B3AFFFA0AFABFF899894FF9AABA7FFCDDEDAFF
+ D6E7E3FFD2E6E1FFD2E5E2FFD0E5E2FFD1E6E3FFD0E5E2FFCEE3E0FFCBE0DDFF
+ C8DDDAFFC6DBD8FFCBE0DDFFCADFDCFFCBE0DDFFCCE1DEFFCDE2DFFFC9DEDBFF
+ C1D6D3FFBDD0CDFFBDCCC8FFC4D2CEFFAAB8B4FF12201CFF2B3935FF818F8BFF
+ 8F9D99FF8B9995FF818F8BFF84928EFF889692FF8B9995FF8D9B97FF8D9B97FF
+ 8C9A96FF8B9995FF8C9B97FF8F9E9AFF93A29EFF96A5A1FF97A6A2FF98A7A3FF
+ 99A8A4FF9AA9A5FF9FAEAAFFA3B2AEFFA7B6B2FFA8B7B3FFA7B6B2FFA6B5B1FF
+ A7B6B2FFA9B8B4FFA3AEABFFA8B3B0FFADB8B5FFAEB9B6FFABB6B3FFA6B1AEFF
+ A5B0ADFFA5B0ADFF9DA8A5FFA1ACA9FFA3AEABFFA7B2AFFFA4AFACFF9AA5A2FF
+ ACB7B4FFD3E1DDFFD6E7E4FFD4E9E6FFD6EBE8FFD4EBE7FFD0E9E5FFD0E9E5FF
+ CFEAE6FFD1ECE8FFD4EDE9FFC4DDD9FFBED3D0FFC3D6D3FFBECFCCFF7A8886FF
+ 859290FFA0ADABFF9FADA9FFA1AFABFFA3B1ADFFA3B1ADFFA2B0ACFFA3B1ADFF
+ A6B4B0FFA8B6B2FFAAB8B4FFA3B1ADFFA0AEAAFFA2B0ACFFA0AEAAFF9AA8A4FF
+ 95A39FFF95A39FFFA5B3ADFFA1AFA9FF9FADA7FFA0AEA8FFA0AEA8FFA0AEA8FF
+ A3B1ABFFA7B5AFFFABB9B3FFAEBCB6FFACBAB4FFA5B3ADFFA3B1ABFFA7B5AFFF
+ ABB9B3FFABB9B3FFAFBEBAFFAFBEBAFFB5C4C0FFBCCBC7FFB8C7C3FFACBBB7FF
+ A6B5B1FFA8B7B3FFA0AFABFF9EADA9FF9BAAA6FF99A8A4FF96A5A1FF92A19DFF
+ 8D9C98FF889793FF889891FF899992FF8A9892FF44524CFF74827CFF7F8D87FF
+ 8B9791FF828E88FF848E88FF8D9791FF8F9993FF89938DFF89908BFF8F9691FF
+ 929994FF909792FF87918BFF818B85FF79837DFF757F79FF747E78FF727C76FF
+ 6F7973FF6B756FFF6C7670FF6C7670FF727C76FF79837DFF79837DFF76807AFF
+ 7D8781FF89948CFF878F88FF8C958BFF929B91FF949D93FF929D93FF949F95FF
+ 9AA59BFFA0ABA1FF96A499FF97A59AFF9EAEA3FF9DADA2FF97A79CFFA3B3A8FF
+ B2C3B8FFB1C2B7FFAABAAFFFA9B9AEFFA2B2A7FF9EAEA3FFA4B4A9FFACBCB1FF
+ A7B7ACFF9AAA9FFF9AAA9FFFA0B0A5FFA4B4A9FFA1B1A6FF9AAA9FFF98A89DFF
+ 9EAEA3FFA4B5AAFF99ACA3FF9FB4ABFFB4C9C0FFCADFD6FFD1E6DEFFC8DDD5FF
+ C0D5CDFFC0D5CDFFBDD1CCFFBBCFCAFFB8CBC8FFB8CBC8FF939A95FF9BA29DFF
+ 979E99FF969D98FF9FA9A3FFA5AFA9FFACB6B0FFBBC5BFFFAAB6B0FFA9B5AFFF
+ AAB8B2FFB3C1BBFFBBC9C3FFBAC8C2FFB3C3BCFFADBDB6FFB6C4C0FFC1CFCBFF
+ C4D2CEFFBBC9C5FFB5C3BFFFB6C4C0FFAEBCB8FFA1AFABFFA3B1ADFF98A6A2FF
+ 9AA8A4FFABB9B5FFB3C1BDFFAAB8B4FFA3B1ADFFA5B3AFFFA6B5B1FFA8B7B3FF
+ A9B8B4FFA4B3AFFF9EADA9FF9FAEAAFFA6B5B1FFAEBDB9FF9BAAA6FF9FAEAAFF
+ A3B2AEFFA4B3AFFFA5B4B0FFA6B5B1FFA8B7B3FFA8B7B3FFA7B8B4FFAEBFBBFF
+ ADBEBAFFA3B4B0FFA5B4B0FFAEBDB9FFB0BFBBFFA9B8B4FFA8B6B2FFA2B0ACFF
+ 99A4A1FF929D9AFF95A09DFF9CA7A4FF9EA7A4FF99A29FFF96A29CFF96A29CFF
+ 9AA6A0FF9CA8A2FF98A49EFF939F99FF95A19BFF9CA8A2FF919D97FF909C96FF
+ 8F9B95FF8D9993FF8B9791FF89958FFF88948EFF87938DFF8E9794FF8B9491FF
+ 87928FFF889390FF8D9895FF909B98FF8D9B97FF8B9995FF92A19DFFA2B1ADFF
+ B8C7C3FFA9B8B4FFABBCB8FFCBDCD8FFD2E3DFFFD7EBE6FFD4E7E4FFD1E6E3FF
+ CFE4E1FFCDE2DFFFCADFDCFFC6DBD8FFC3D8D5FFC1D6D3FFC5DAD7FFC4D9D6FF
+ C4D9D6FFC6DBD8FFC8DDDAFFC6DBD8FFC1D6D3FFBED1CEFFB5C4C0FFC4D2CEFF
+ 8D9B97FF0A1814FF2A3834FF72807CFF83918DFF808E8AFF808E8AFF818F8BFF
+ 85938FFF889692FF8B9995FF8E9C98FF8F9D99FF909E9AFF8A9995FF8D9C98FF
+ 909F9BFF93A29EFF95A4A0FF96A5A1FF97A6A2FF97A6A2FF99A8A4FF9DACA8FF
+ A2B1ADFFA6B5B1FFAAB9B5FFACBBB7FFAFBEBAFFB0BFBBFFAAB5B2FFAAB5B2FF
+ A9B4B1FFA4AFACFF9FAAA7FF9EA9A6FF9FAAA7FFA2ADAAFFA6B1AEFFA8B3B0FF
+ A7B2AFFFA8B3B0FFA5B0ADFF99A4A1FFA5B0ADFFC7D5D1FFD4E5E2FFD1E6E3FF
+ D3E8E5FFD1E8E4FFCDE6E2FFCDE6E2FFCCE7E3FFCEE9E5FFCFE8E4FFC6DFDBFF
+ C2D7D4FFC4D7D4FFBECFCCFF7C8A88FF84918FFF98A5A3FF9AA8A4FF9EACA8FF
+ A3B1ADFFA5B3AFFFA4B2AEFFA2B0ACFFA2B0ACFFA2B0ACFFA5B3AFFF9FADA9FF
+ 9CAAA6FF9EACA8FF9DABA7FF98A6A2FF94A29EFF94A29EFFA6B4AEFFA3B1ABFF
+ A1AFA9FFA1AFA9FFA1AFA9FFA2B0AAFFA5B3ADFFA8B6B0FFA5B3ADFFA9B7B1FF
+ A8B6B0FFA3B1ABFFA2B0AAFFA8B6B0FFADBBB5FFAEBCB6FFB2C1BDFFB2C1BDFF
+ B7C6C2FFBDCCC8FFB8C7C3FFACBBB7FFA6B5B1FFA7B6B2FFA4B3AFFFA0AFABFF
+ 9AA9A5FF96A5A1FF94A39FFF91A09CFF8D9C98FF8A9995FF83938CFF889891FF
+ 83918BFF45534DFF6B7973FF7E8C86FF86928CFF838F89FF88928CFF909A94FF
+ 939D97FF8D9791FF8C938EFF8E9590FF8D948FFF89908BFF87918BFF818B85FF
+ 7A847EFF78827CFF79837DFF76807AFF6F7973FF68726CFF76807AFF717B75FF
+ 6F7973FF6F7973FF6D7771FF6F7973FF7B857FFF8A958DFF8C948DFF8C958BFF
+ 8C958BFF8D968CFF8F9A90FF96A197FF9EA99FFFA3AEA4FF9DABA0FF9BA99EFF
+ A0B0A5FFA0B0A5FF99A99EFFA3B3A8FFACBDB2FFA6B7ACFFADBDB2FFAEBEB3FF
+ A8B8ADFF9CACA1FF9AAA9FFFA3B3A8FFACBCB1FFAEBEB3FF9EAEA3FFA2B2A7FF
+ A4B4A9FFA2B2A7FF9DADA2FF9BABA0FF9DADA2FFA0B1A6FF9DB0A7FFA2B7AEFF
+ B3C8BFFFC6DBD2FFCCE1D9FFC5DAD2FFC1D6CEFFC2D7CFFFBBCFCAFFB7CBC6FF
+ B1C4C1FFADC0BDFF919893FF9CA39EFF9BA29DFF99A09BFF9EA8A2FFA2ACA6FF
+ A8B2ACFFB9C3BDFFAAB6B0FFA7B3ADFFA5B3ADFFACBAB4FFB6C4BEFFB9C7C1FF
+ B1C1BAFFA9B9B2FFB0BEBAFFBECCC8FFC5D3CFFFBFCDC9FFB9C7C3FFBAC8C4FF
+ B8C6C2FFB2C0BCFFACBAB6FFAAB8B4FFAAB8B4FFB0BEBAFFB9C7C3FFBDCBC7FF
+ B8C6C2FFB1BFBBFFA3B2AEFFA9B8B4FFABBAB6FFA5B4B0FF9BAAA6FF99A8A4FF
+ A0AFABFFAAB9B5FFA1B0ACFF9EADA9FF9CABA7FF9EADA9FFA3B2AEFFA6B5B1FF
+ A6B5B1FFA4B3AFFFA6B7B3FFADBEBAFFADBEBAFFA6B7B3FFA8B7B3FFAFBEBAFF
+ AFBEBAFFA9B8B4FFABB9B5FFA5B3AFFF9CA7A4FF919C99FF929D9AFF9BA6A3FF
+ A3ACA9FFA3ACA9FF9CA8A2FF98A49EFF97A39DFF9AA6A0FF99A59FFF94A09AFF
+ 939F99FF97A39DFF919D97FF919D97FF8F9B95FF8D9993FF8B9791FF8A9690FF
+ 88948EFF88948EFF8C9592FF87908DFF828D8AFF85908DFF8D9895FF8F9A97FF
+ 899793FF83918DFF83928EFF92A19DFFB0BFBBFFAEBDB9FFB3C4C0FFC8D9D5FF
+ C8D9D5FFCFE3DEFFD0E3E0FFCDE2DFFFCBE0DDFFC8DDDAFFC5DAD7FFC4D9D6FF
+ C3D8D5FFC2D7D4FFBFD4D1FFBFD4D1FFBFD4D1FFC0D5D2FFC2D7D4FFC2D7D4FF
+ C0D5D2FFC0D3D0FFB2C1BDFFC9D7D3FF64726EFF071511FF34423EFF677571FF
+ 7B8985FF778581FF808E8AFF82908CFF84928EFF879591FF8A9894FF8D9B97FF
+ 8F9D99FF919F9BFF8F9E9AFF909F9BFF92A19DFF95A4A0FF98A7A3FF9AA9A5FF
+ 9AA9A5FF9AA9A5FF9FAEAAFF9FAEAAFFA1B0ACFFA4B3AFFFA7B6B2FFA9B8B4FF
+ A9B8B4FFA8B7B3FFAFBAB7FFAFBAB7FFAEB9B6FFABB6B3FFA7B2AFFFA4AFACFF
+ A4AFACFFA5B0ADFFABB6B3FFABB6B3FFA7B2AFFFA9B4B1FFA9B4B1FF9DA8A5FF
+ A3AEABFFBCCAC6FFD0E1DEFFCEE3E0FFCFE4E1FFCDE4E0FFC9E2DEFFC8E1DDFF
+ C8E3DFFFCAE5E1FFC9E2DEFFC9E2DEFFC8DDDAFFC4D7D4FFBCCDCAFF7E8C8AFF
+ 84918FFF919E9CFF99A7A3FF9FADA9FFA6B4B0FFA9B7B3FFA8B6B2FFA5B3AFFF
+ A2B0ACFFA1AFABFFA8B6B2FFA2B0ACFF9FADA9FFA2B0ACFFA2B0ACFF9DABA7FF
+ 9AA8A4FF9BA9A5FFA0AEA8FF9FADA7FF9DABA5FF9BA9A3FF9BA9A3FF9EACA6FF
+ A1AFA9FFA2B0AAFF9EACA6FFA3B1ABFFA4B2ACFFA1AFA9FFA1AFA9FFA9B7B1FF
+ AFBDB7FFB0BEB8FFB4C3BFFFB5C4C0FFB9C8C4FFBCCBC7FFB6C5C1FFACBBB7FF
+ A6B5B1FFA7B6B2FFA8B7B3FFA3B2AEFF9BAAA6FF95A4A0FF92A19DFF909F9BFF
+ 8E9D99FF8C9B97FF809089FF899992FF7C8A84FF4B5953FF62706AFF808E88FF
+ 818D87FF88948EFF858F89FF8C9690FF909A94FF8D9791FF8D948FFF8C938EFF
+ 89908BFF858C87FF858F89FF7E8882FF78827CFF78827CFF7A847EFF77817BFF
+ 6C7670FF626C66FF77817BFF737D77FF707A74FF6F7973FF6E7872FF727C76FF
+ 7F8983FF8C978FFF8B938CFF848D83FF7E877DFF80897FFF889389FF949F95FF
+ 9CA79DFF9FAAA0FFA0AEA3FF9CAA9FFF9FAFA4FFA0B0A5FF9BABA0FFA2B2A7FF
+ A5B6ABFF99AA9FFFA4B4A9FFADBDB2FFAEBEB3FFA1B1A6FF95A59AFF98A89DFF
+ A8B8ADFFB4C4B9FFA5B5AAFFA6B6ABFFA6B6ABFFA6B6ABFFA5B5AAFFA2B2A7FF
+ A0B0A5FF9EAFA4FFA2B5ACFFA6BBB2FFB4C9C0FFC1D6CDFFC5DAD2FFC2D7CFFF
+ C0D5CDFFC3D8D0FFBCD0CBFFB5C9C4FFADC0BDFFA7BAB7FF848B86FF949B96FF
+ 9AA19CFF9AA19CFF9EA8A2FF9EA8A2FFA2ACA6FFB1BBB5FFB3BFB9FFB1BDB7FF
+ ADBBB5FFB2C0BAFFBBC9C3FFBFCDC7FFB5C5BEFFA9B9B2FFADBBB7FFB3C1BDFF
+ B5C3BFFFB0BEBAFFB0BEBAFFB8C6C2FFBDCBC7FFBDCBC7FFAAB8B4FFA4B2AEFF
+ A2B0ACFFA9B7B3FFB0BEBAFFB2C0BCFFAEBCB8FFAAB8B4FFA7B6B2FFABBAB6FF
+ ADBCB8FFA9B8B4FFA1B0ACFF9CABA7FF9DACA8FFA1B0ACFFA8B7B3FFA4B3AFFF
+ A2B1ADFFA5B4B0FFA6B5B1FFA4B3AFFFA2B1ADFFA2B1ADFFA5B6B2FFABBCB8FF
+ ACBDB9FFA8B9B5FFABBAB6FFAFBEBAFFAEBDB9FFA9B8B4FFA8B6B2FFA5B3AFFF
+ 9EA9A6FF949F9CFF949F9CFF9EA9A6FFA8B1AEFFABB4B1FFA2AEA8FF9BA7A1FF
+ 96A29CFF99A59FFF99A59FFF95A19BFF929E98FF929E98FF909C96FF909C96FF
+ 8E9A94FF8C9892FF8B9791FF89958FFF87938DFF87938DFF87908DFF858E8BFF
+ 838E8BFF86918EFF8A9592FF8B9693FF85938FFF818F8BFF8A9995FF808F8BFF
+ 8C9B97FF95A4A0FFAEBFBBFFCCDDD9FFC7D8D4FFC7DBD6FFCADDDAFFC7DCD9FF
+ C5DAD7FFC4D9D6FFC4D9D6FFC6DBD8FFC7DCD9FFC9DEDBFFC1D6D3FFC0D5D2FF
+ BFD4D1FFBED3D0FFBFD4D1FFBFD4D1FFC0D5D2FFC2D5D2FFB8C7C3FFCDDBD7FF
+ 3E4C48FF111F1BFF4D5B57FF6E7C78FF7E8C88FF768480FF808E8AFF82908CFF
+ 85938FFF899793FF8B9995FF8C9A96FF8D9B97FF8D9B97FF8E9D99FF8E9D99FF
+ 8F9E9AFF92A19DFF96A5A1FF99A8A4FF99A8A4FF98A7A3FF9FAEAAFF9EADA9FF
+ 9DACA8FFA0AFABFFA3B2AEFFA4B3AFFFA3B2AEFFA1B0ACFFA6B4B0FFABB9B5FF
+ B3BEBBFFB4C2BEFFB5C0BDFFAEBCB8FFAAB5B2FFA4B2AEFFA8B3B0FFA6B4B0FF
+ A3AEABFFA5B3AFFFACB7B4FFA2B0ACFFA6B1AEFFB9C7C3FFCEDFDCFFCBE0DDFF
+ CDE2DFFFCBE2DEFFC6DFDBFFC5DEDAFFC4DFDBFFC6E1DDFFC5DEDAFFCAE3DFFF
+ CADFDCFFC2D5D2FFBACBC8FF82908EFF899694FF93A09EFF98A6A2FF9DABA7FF
+ A3B1ADFFA6B4B0FFA5B3AFFFA2B0ACFF9FADA9FF9EACA8FFA9B7B3FFA3B1ADFF
+ A0AEAAFFA3B1ADFFA4B2AEFFA1AFABFF9FADA9FFA1AFABFF9DABA5FF9EACA6FF
+ 9CAAA4FF98A6A0FF99A7A1FF9DABA5FFA0AEA8FFA0AEA8FF9DABA5FFA2B0AAFF
+ A4B2ACFFA1AFA9FFA2B0AAFFA9B7B1FFAEBCB6FFAFBDB7FFB0BFBBFFB3C2BEFF
+ B6C5C1FFB7C6C2FFB3C2BEFFACBBB7FFA8B7B3FFA8B7B3FFA8B7B3FFA4B3AFFF
+ 9EADA9FF99A8A4FF95A4A0FF91A09CFF8D9C98FF899894FF7F8F88FF8A9A93FF
+ 788680FF505E58FF5E6C66FF82908AFF7F8B85FF8D9993FF818B85FF848E88FF
+ 87918BFF87918BFF89908BFF89908BFF888F8AFF878E89FF838D87FF7A847EFF
+ 737D77FF727C76FF76807AFF737D77FF69736DFF5E6862FF66706AFF69736DFF
+ 6D7771FF727C76FF76807AFF7B857FFF838D87FF8B968EFF8B938CFF828B81FF
+ 7A8379FF7D867CFF89948AFF97A298FF9EA99FFF9EA99FFF9FADA2FF9AA89DFF
+ 9CACA1FF9FAFA4FF9EAEA3FFA5B5AAFFA4B5AAFF94A59AFF95A59AFFA4B4A9FF
+ AFBFB4FFA9B9AEFF9AAA9FFF93A398FF9AAA9FFFA4B4A9FFA1B1A6FFA0B0A5FF
+ A0B0A5FFA2B2A7FFA5B5AAFFA3B3A8FF9EAEA3FF98A99EFFA1B4ABFFA9BEB5FF
+ B6CBC2FFC0D5CCFFC2D7CFFFC0D5CDFFBED3CBFFBFD4CCFFBDD1CCFFB8CCC7FF
+ B0C3C0FFABBEBBFF7E8580FF8D948FFF909792FF8F9691FF949E98FF97A19BFF
+ 9FA9A3FFB1BBB5FFBAC6C0FFBBC7C1FFB9C7C1FFBAC8C2FFC0CEC8FFC3D1CBFF
+ B8C8C1FFAABAB3FFADBBB7FFACBAB6FFA9B7B3FFA9B7B3FFAEBCB8FFB5C3BFFF
+ B8C6C2FFB6C4C0FFB5C3BFFFA3B1ADFF9FADA9FFADBBB7FFB3C1BDFFA9B7B3FF
+ A4B2AEFFAAB8B4FFA8B7B3FFA9B8B4FFAAB9B5FFACBBB7FFABBAB6FFA8B7B3FF
+ A3B2AEFF9FAEAAFFA4B3AFFFA4B3AFFFA8B7B3FFADBCB8FFAAB9B5FFA2B1ADFF
+ A0AFABFFA4B3AFFFA5B6B2FFA8B9B5FFA9BAB6FFA8B9B5FFABBAB6FFADBCB8FF
+ ADBCB8FFAAB9B5FFA3B1ADFFA3B1ADFF9FAAA7FF99A4A1FF9AA5A2FFA3AEABFF
+ ACB5B2FFADB6B3FFAAB6B0FFA1ADA7FF9BA7A1FF9CA8A2FF9DA9A3FF99A59FFF
+ 95A19BFF95A19BFF8F9B95FF8F9B95FF8D9993FF8B9791FF89958FFF88948EFF
+ 86928CFF86928CFF828B88FF87908DFF899491FF899491FF86918EFF848F8CFF
+ 83918DFF85938FFF8F9E9AFF7B8A86FF7D8C88FF859490FFA7B8B4FFCEDFDBFF
+ CCDDD9FFCBDFDAFFCADDDAFFC7DCD9FFC6DBD8FFC5DAD7FFC5DAD7FFC7DCD9FF
+ C9DEDBFFCADFDCFFC6DBD8FFC5DAD7FFC3D8D5FFC1D6D3FFBFD4D1FFBED3D0FF
+ BFD4D1FFC2D5D2FFC0CFCBFFCAD8D4FF22302CFF283632FF677571FF7D8B87FF
+ 83918DFF798783FF798783FF7D8B87FF84928EFF8A9894FF8E9C98FF8F9D99FF
+ 8E9C98FF8D9B97FF879692FF869591FF859490FF889793FF8D9C98FF91A09CFF
+ 91A09CFF909F9BFF96A5A1FF97A6A2FF99A8A4FF9EADA9FFA3B2AEFFA8B7B3FF
+ ABBAB6FFACBBB7FFA2B1ADFFA5B4B0FFAAB8B4FFACBBB7FFADBBB7FFA8B7B3FF
+ A3B1ADFF9EADA9FFA4B2AEFFA3B2AEFF9FADA9FFA1B0ACFFAAB8B4FFA4B3AFFF
+ A6B4B0FFB5C4C0FFCCDDDAFFCADFDCFFCBE0DDFFC8DFDBFFC4DDD9FFC2DBD7FF
+ C1DCD8FFC3DEDAFFC4DDD9FFC9E2DEFFC9DEDBFFC0D3D0FFB9CAC7FF83918FFF
+ 8F9C9AFF9CA9A7FF97A5A1FF9AA8A4FF9EACA8FF9FADA9FF9EACA8FF9CAAA6FF
+ 9BA9A5FF9CAAA6FFA5B3AFFF9EACA8FF9CAAA6FF9FADA9FFA0AEAAFF9EACA8FF
+ 9DABA7FF9FADA9FFA2B0AAFFA5B3ADFFA3B1ABFF9DABA5FF9DABA5FFA4B2ACFF
+ A7B5AFFFA4B2ACFFA0AEA8FFA5B3ADFFA6B4AEFFA3B1ABFFA3B1ABFFA8B6B0FF
+ ACBAB4FFACBAB4FFAAB9B5FFAEBDB9FFB2C1BDFFB1C0BCFFAFBEBAFFADBCB8FF
+ ABBAB6FFAAB9B5FFA5B4B0FFA3B2AEFFA0AFABFF9EADA9FF9AA9A5FF94A39FFF
+ 8C9B97FF869591FF7E8E87FF879790FF74827CFF4F5D57FF5E6C66FF808E88FF
+ 7C8882FF8A9690FF88928CFF858F89FF838D87FF838D87FF868D88FF878E89FF
+ 888F8AFF8A918CFF848E88FF7B857FFF727C76FF707A74FF737D77FF727C76FF
+ 6C7670FF656F69FF606A64FF656F69FF6B756FFF707A74FF76807AFF7F8983FF
+ 86908AFF89948CFF919992FF8A9389FF858E84FF8A9389FF95A096FFA0ABA1FF
+ A4AFA5FFA4AFA5FFA0AEA3FF99A79CFF9BABA0FFA1B1A6FFA2B2A7FFACBCB1FF
+ ACBDB2FF9CADA2FF95A59AFF9FAFA4FFAABAAFFFAABAAFFF9FAFA4FF94A499FF
+ 93A398FF97A79CFF98A89DFF96A69BFF96A69BFF9AAA9FFF9FAFA4FF9FAFA4FF
+ 9AAA9FFF94A59AFF9CAFA6FFA9BEB5FFBACFC6FFC2D7CEFFC3D8D0FFBFD4CCFF
+ BCD1C9FFB9CEC6FFBBCFCAFFB8CCC7FFB4C7C4FFB2C5C2FF838A85FF8B928DFF
+ 858C87FF808782FF87918BFF919B95FF9FA9A3FFB5BFB9FFB9C5BFFFBECAC4FF
+ BBC9C3FFB7C5BFFFBAC8C2FFBFCDC7FFB7C7C0FFABBBB4FFAEBCB8FFACBAB6FF
+ ACBAB6FFB0BEBAFFB4C2BEFFB4C2BEFFAEBCB8FFA8B6B2FFC2D0CCFFAEBCB8FF
+ A9B7B3FFB8C6C2FFBCCAC6FFADBBB7FFA7B5B1FFAEBCB8FFA6B5B1FFA4B3AFFF
+ A4B3AFFFA9B8B4FFAEBDB9FFB0BFBBFFABBAB6FFA6B5B1FF9DACA8FF9CABA7FF
+ A3B2AEFFADBCB8FFACBBB7FFA3B2AEFFA2B1ADFFA9B8B4FFA5B6B2FFA5B6B2FF
+ A6B7B3FFA6B7B3FFA9B8B4FFAAB9B5FFABBAB6FFABBAB6FFA4B2AEFFA3B1ADFF
+ A0ABA8FF9BA6A3FF9FAAA7FFA7B2AFFFACB5B2FFA9B2AFFFA8B4AEFF9FABA5FF
+ 99A59FFF9AA6A0FF99A59FFF95A19BFF929E98FF939F99FF909C96FF8F9B95FF
+ 8E9A94FF8C9892FF8A9690FF88948EFF87938DFF86928CFF818A87FF88918EFF
+ 8B9693FF899491FF838E8BFF808B88FF82908CFF879591FF7F8E8AFF7B8A86FF
+ 869591FF84938FFF99AAA6FFC0D1CDFFC8D9D5FFCEE2DDFFCFE2DFFFCBE0DDFF
+ C9DEDBFFC7DCD9FFC6DBD8FFC5DAD7FFC4D9D6FFC4D9D6FFC9DEDBFFC9DEDBFF
+ C7DCD9FFC4D9D6FFC0D5D2FFBDD2CFFFBDD2CFFFC1D4D1FFC0CFCBFFBCCAC6FF
+ 182622FF475551FF778581FF869490FF82908CFF7C8A86FF75837FFF798783FF
+ 808E8AFF889692FF8E9C98FF919F9BFF92A09CFF92A09CFF899894FF869591FF
+ 84938FFF879692FF8D9C98FF91A09CFF91A09CFF8F9E9AFF99A8A4FF9CABA7FF
+ 9FAEAAFFA1B0ACFFA3B2AEFFA6B5B1FFABBAB6FFAFBEBAFFAEBDB9FFAAB9B5FF
+ A5B4B0FFA2B1ADFFA1B0ACFFA1B0ACFFA0AFABFFA0AFABFFA4B3AFFFA6B5B1FF
+ 9FAEAAFF9EADA9FFA5B4B0FFA2B1ADFFA1B0ACFFADBEBAFFC8DBD8FFC7DCD9FF
+ C8DDDAFFC6DDD9FFC1DAD6FFBFD8D4FFBED9D5FFBFDAD6FFC3DCD8FFC5DEDAFF
+ C6DBD8FFC1D4D1FFBACBC8FF808E8CFF8E9B99FFA1AEACFF9DABA7FFA0AEAAFF
+ A3B1ADFFA3B1ADFFA1AFABFFA0AEAAFF9FADA9FFA0AEAAFFA6B4B0FFA0AEAAFF
+ 9CAAA6FF9FADA9FFA1AFABFF9FADA9FF9FADA9FFA2B0ACFFA0AEA8FFA6B4AEFF
+ A3B1ABFF9CAAA4FF9CAAA4FFA5B3ADFFA8B6B0FFA3B1ABFFA3B1ABFFA8B6B0FF
+ A9B7B1FFA4B2ACFFA2B0AAFFA6B4AEFFA8B6B0FFA7B5AFFFA6B5B1FFADBCB8FF
+ B0BFBBFFADBCB8FFABBAB6FFADBCB8FFADBCB8FFABBAB6FFA3B2AEFFA2B1ADFF
+ A1B0ACFFA0AFABFF9DACA8FF96A5A1FF8D9C98FF869591FF7F8F88FF81918AFF
+ 73817BFF4A5852FF65736DFF7C8A84FF7A8680FF838F89FF929C96FF8A948EFF
+ 858F89FF848E88FF868D88FF858C87FF858C87FF89908BFF86908AFF7F8983FF
+ 78827CFF757F79FF757F79FF757F79FF727C76FF6F7973FF737D77FF757F79FF
+ 757F79FF747E78FF7A847EFF858F89FF8E9892FF909B93FF8F9790FF8E978DFF
+ 8F988EFF929B91FF97A298FF9DA89EFFA2ADA3FFA5B0A6FFA4B2A7FF9DABA0FF
+ 9EAEA3FFA2B2A7FFA3B3A8FFB0C0B5FFB4C5BAFFA7B8ADFFA4B4A9FFA3B3A8FF
+ A4B4A9FFA5B5AAFFA0B0A5FF99A99EFF98A89DFF9CACA1FF9AAA9FFF99A99EFF
+ 99A99EFF9DADA2FFA1B1A6FFA3B3A8FFA0B0A5FF9BACA1FF97AAA1FFA8BDB4FF
+ BCD1C8FFC4D9D0FFC3D8D0FFBFD4CCFFBACFC7FFB6CBC3FFB6CAC5FFB4C8C3FF
+ B2C5C2FFB2C5C2FF858C87FF8A918CFF838A85FF808782FF89938DFF929C96FF
+ 9DA7A1FFAEB8B2FFB3BFB9FFBAC6C0FFB6C4BEFFADBBB5FFADBBB5FFB6C4BEFF
+ B6C6BFFFAFBFB8FFAFBDB9FFAFBDB9FFB0BEBAFFB3C1BDFFB4C2BEFFB1BFBBFF
+ AEBCB8FFADBBB7FFB3C1BDFFAAB8B4FFA6B4B0FFABB9B5FFAEBCB8FFA8B6B2FF
+ A0AEAAFF9DABA7FFA7B6B2FFA4B3AFFFA2B1ADFFA2B1ADFFA5B4B0FFA9B8B4FF
+ ABBAB6FFACBBB7FFA2B1ADFF9AA9A5FF9DACA8FFA9B8B4FFADBCB8FFA6B5B1FF
+ A4B3AFFFAAB9B5FFA5B6B2FFA3B4B0FFA2B3AFFFA3B4B0FFA6B5B1FFA7B6B2FF
+ AAB9B5FFACBBB7FFACBAB6FFA7B5B1FFA0ABA8FF9AA5A2FF9FAAA7FFA7B2AFFF
+ A9B2AFFFA3ACA9FFA2AEA8FF9BA7A1FF96A29CFF95A19BFF939F99FF8E9A94FF
+ 8D9993FF909C96FF929E98FF929E98FF909C96FF8F9B95FF8D9993FF8B9791FF
+ 89958FFF89958FFF848D8AFF87908DFF87928FFF85908DFF818C89FF808B88FF
+ 82908CFF85938FFF788783FF7F8E8AFF8A9995FF7D8C88FF8A9B97FFB5C6C2FF
+ C0D1CDFFC6DAD5FFCDE0DDFFCBE0DDFFCADFDCFFC9DEDBFFC7DCD9FFC4D9D6FF
+ C2D7D4FFC1D6D3FFC5DAD7FFC6DBD8FFC7DCD9FFC4D9D6FFBFD4D1FFBBD0CDFF
+ BBD0CDFFBED1CEFFBDCCC8FFAFBDB9FF1F2D29FF667470FF7D8B87FF879591FF
+ 7B8985FF7F8D89FF7C8A86FF7D8B87FF808E8AFF83918DFF889692FF8D9B97FF
+ 919F9BFF93A19DFF8F9E9AFF8B9A96FF889793FF8B9A96FF92A19DFF97A6A2FF
+ 97A6A2FF94A39FFF9AA9A5FF9FAEAAFFA3B2AEFFA2B1ADFF9DACA8FF9DACA8FF
+ A4B3AFFFAAB9B5FFB2C3BFFFACBDB9FFA4B5B1FFA0B1ADFFA0B1ADFFA2B3AFFF
+ A3B4B0FFA3B4B0FFA1B2AEFFA5B6B2FF9DAEAAFF9AABA7FF9FB0ACFF9CADA9FF
+ 9DAEAAFFACBDB9FFC4D7D4FFC4D9D6FFC5DAD7FFC2D9D5FFBDD6D2FFBBD4D0FF
+ BAD5D1FFBBD6D2FFC1DAD6FFBFD8D4FFC2D7D4FFC5D8D5FFBDCECBFF7A8886FF
+ 869391FF9FACAAFF9EACA8FFA3B1ADFFA8B6B2FFAAB8B4FFA8B6B2FFA4B2AEFF
+ A2B0ACFFA0AEAAFFAAB8B4FFA3B1ADFF9FADA9FFA1AFABFFA2B0ACFFA0AEAAFF
+ A1AFABFFA4B2AEFF9DABA5FFA3B1ABFFA1AFA9FF98A6A0FF98A6A0FFA3B1ABFF
+ A5B3ADFF9FADA7FFA2B0AAFFA7B5AFFFA8B6B0FFA3B1ABFFA1AFA9FFA3B1ABFF
+ A5B3ADFFA3B1ABFFA8B7B3FFAFBEBAFFB1C0BCFFACBBB7FFAAB9B5FFADBCB8FF
+ AEBDB9FFAAB9B5FFA4B3AFFFA2B1ADFFA0AFABFF9FAEAAFF9CABA7FF97A6A2FF
+ 909F9BFF8A9995FF86968FFF7F8F88FF798781FF485650FF73817BFF7C8A84FF
+ 7E8A84FF7E8A84FF909A94FF87918BFF828C86FF848E88FF878E89FF838A85FF
+ 818883FF848B86FF818B85FF7F8983FF7D8781FF7B857FFF78827CFF76807AFF
+ 757F79FF757F79FF7C8680FF808A84FF818B85FF7F8983FF838D87FF8D9791FF
+ 929C96FF909B93FF8C948DFF919A90FF959E94FF949D93FF909B91FF939E94FF
+ 9DA89EFFA5B0A6FFA7B5AAFFA0AEA3FF9EAEA3FF9DADA2FF9CACA1FFA9B9AEFF
+ B1C2B7FFA8B9AEFFA8B8ADFFA2B2A7FFA0B0A5FFA3B3A8FFA2B2A7FF9EAEA3FF
+ 9FAFA4FFA4B4A9FFA2B2A7FFA1B1A6FFA1B1A6FFA2B2A7FFA4B4A9FFA5B5AAFF
+ A5B5AAFFA3B4A9FF95A89FFFA8BDB4FFBCD1C8FFC2D7CEFFC0D5CDFFBFD4CCFF
+ BBD0C8FFB6CBC3FFB6CAC5FFB2C6C1FFAFC2BFFFADC0BDFF818883FF89908BFF
+ 888F8AFF8B928DFF959F99FF98A29CFF98A29CFFA2ACA6FFAFBBB5FFB6C2BCFF
+ B1BFB9FFA4B2ACFFA2B0AAFFB0BEB8FFB7C7C0FFB5C5BEFFAFBDB9FFAEBCB8FF
+ AFBDB9FFAEBCB8FFACBAB6FFADBBB7FFB4C2BEFFBDCBC7FFB0BEBAFFB3C1BDFF
+ B0BEBAFFAAB8B4FFADBBB7FFB3C1BDFFAAB8B4FF9AA8A4FFACBBB7FFA9B8B4FF
+ A4B3AFFF9DACA8FF99A8A4FF9CABA7FFA5B4B0FFADBCB8FFAFBEBAFF9FAEAAFF
+ 9AA9A5FFA6B5B1FFAEBDB9FFA9B8B4FFA5B4B0FFA8B7B3FFA7B6B2FFA2B3AFFF
+ A2B1ADFFA3B2AEFFA5B4B0FFA5B4B0FFA9B8B4FFADBCB8FFB3C1BDFFABB9B5FF
+ A0ABA8FF98A3A0FF9DA8A5FFA6B1AEFFA4AFACFF9DA8A5FFA4B0AAFF9EAAA4FF
+ 9AA6A0FF98A49EFF95A19BFF8F9B95FF909C96FF94A09AFF95A19BFF94A09AFF
+ 939F99FF919D97FF8F9B95FF8D9993FF8C9892FF8B9791FF88918EFF868F8CFF
+ 818C89FF808B88FF818C89FF828D8AFF818F8BFF818F8BFF879591FF869591FF
+ 899793FF73827EFF879692FFBAC9C5FFC4D3CFFFC1D2CEFFC7DAD7FFC6DBD8FF
+ C7DCD9FFC8DDDAFFC8DDDAFFC6DBD8FFC4D9D6FFC2D7D4FFC0D5D2FFC3D8D5FF
+ C4D9D6FFC2D7D4FFBDD2CFFFB9CECBFFB9CECBFFBCCFCCFFBBCAC6FFA8B6B2FF
+ 2A3834FF7C8A86FF7E8C88FF85938FFF768480FF83918DFF889692FF85938FFF
+ 82908CFF808E8AFF82908CFF879591FF8C9A96FF909E9AFF8F9E9AFF8A9995FF
+ 879692FF8A9995FF91A09CFF96A5A1FF96A5A1FF94A39FFF8C9B97FF94A39FFF
+ 9CABA7FF9CABA7FF98A7A3FF9AA9A5FFA5B4B0FFB0BFBBFFAAB9B5FFA5B6B2FF
+ A5B4B0FFA4B5B1FFA9B8B4FFA7B8B4FFA6B5B1FFA1B2AEFF9FAEAAFFA3B4B0FF
+ 9EADA9FF97A8A4FF9EADA9FF9BACA8FFA1B0ACFFAEBFBBFFC2D5D2FFC3D6D3FF
+ C2D7D4FFBFD6D2FFBCD3CFFFBAD1CDFFB9D2CEFFBAD3CFFFC2D9D5FFBDD4D0FF
+ C1D6D3FFC9DCD9FFBFD0CDFF758381FF7D8B89FF99A7A5FF95A39FFF9BA9A5FF
+ A4B2AEFFA7B5B1FFA5B3AFFFA0AEAAFF9AA8A4FF97A5A1FFA6B4B0FF9FADA9FF
+ 9BA9A5FF9CAAA6FF9EACA8FF9CAAA6FF9CAAA6FF9FADA9FF9FADA7FFA7B5AFFF
+ A5B3ADFF9BA9A3FF9BA9A3FFA6B4AEFFA9B7B1FFA2B0AAFFA0AEA8FFA5B3ADFF
+ A6B4AEFFA1AFA9FF9FADA7FFA2B0AAFFA3B1ABFFA1AFA9FFABBAB6FFB2C1BDFF
+ B3C2BEFFACBBB7FFAAB9B5FFADBCB8FFAEBDB9FFAAB9B5FFA6B5B1FFA3B2AEFF
+ 9FAEAAFF9CABA7FF9AA9A5FF97A6A2FF92A19DFF8F9E9AFF8E9D99FF81918AFF
+ 818F89FF4A5852FF808E88FF808E88FF85918BFF7F8B85FF848E88FF7C8680FF
+ 7B857FFF818B85FF868D88FF818982FF7E8580FF818982FF79837DFF7C877FFF
+ 7F8983FF7E8981FF79837DFF758078FF747E78FF747F77FF707A74FF7A857DFF
+ 818B85FF848F87FF89938DFF8F9A92FF8C9690FF838E86FF90998FFF97A096FF
+ 9CA59BFF98A197FF90998FFF909B91FF9DA89EFFABB6ACFFAAB5ABFF9FADA2FF
+ 9DABA0FF97A79CFF92A297FF9EAEA3FFAABAAFFFA2B3A8FFA1B1A6FF9DADA2FF
+ A0B0A5FFA6B6ABFFA6B6ABFFA0B0A5FFA0B0A5FFA5B5AAFFA1B1A6FFA1B1A6FF
+ A1B1A6FFA0B0A5FF9FAFA4FF9FAFA4FFA0B0A5FFA1B2A7FF95A89FFFA9BEB5FF
+ BBD0C7FFBFD4CBFFBED3CBFFBED3CBFFBCD1C9FFB8CDC5FFB9CDC8FFB4C8C3FF
+ ADC0BDFFA9BCB9FF8B928FFF848B88FF7F8683FF848B88FF88918EFF8E9794FF
+ 959E9BFF9DA6A3FFBEC9C6FFBCC7C4FFA8B6B2FFAEBCB8FFADBBB7FFA2B0ACFF
+ AAB9B5FFA4B3AFFFABB9B5FFADBBB7FFADBBB7FFADBBB7FFB3C1BDFFB9C7C3FF
+ B8C6C2FFB2C0BCFFB0BEBAFFB1BFBBFFB0BEBAFFADBBB7FFAFBDB9FFB2C0BCFF
+ AEBCB8FFA6B4B0FFB1BFBBFFA8B6B2FFA3B1ADFFA2B0ACFF9EACA8FF99A7A3FF
+ 9EACA8FFA9B7B3FFAEBCB8FFA3B1ADFF9BA9A5FFA0AEAAFFADBBB7FFB4C2BEFF
+ AFBDB9FFA6B4B0FFAAB8B4FFA6B5B1FFA5B3AFFFA4B2AEFFA6B4B0FFA8B6B2FF
+ A8B6B2FFA7B5B1FFABB9B5FFAAB8B4FF95A39FFF9EACA8FF919F9BFFA6B4B0FF
+ 9CAAA6FFA1ACA9FF9BA6A3FF9BA6A3FF9BA6A3FF99A4A1FF98A3A0FF95A09DFF
+ 939E9BFF919C99FF8F9A97FF8F9A97FF8D9895FF8C9794FF8A9592FF899491FF
+ 889390FF87928FFF848F8CFF828D8AFF828D8AFF838E8BFF808B88FF7B8683FF
+ 7D8885FF838E8BFF7B8683FF7F8D89FF8A9592FF788682FF6F7D79FF9BA9A5FF
+ C5D3CFFFBDCCC8FFBED1CEFFBFD4D1FFC3D8D5FFC5DAD7FFC2D7D4FFBDD2CFFF
+ B8CDCAFFB6CBC8FFC3D8D5FFC3D8D5FFC2D7D4FFBED3D0FFBACFCCFFB9CECBFF
+ BACFCCFFBED1CEFFCDDCD8FF9DABA7FF1F2D29FF778581FF768480FF83918DFF
+ 808E8AFF798783FF7B8985FF7B8985FF7D8B87FF808E8AFF869490FF8A9894FF
+ 8E9C98FF8F9D99FF909F9BFF8E9D99FF8B9A96FF899894FF8B9A96FF909F9BFF
+ 96A5A1FF9AA9A5FF97A6A2FF9AA9A5FF9EADA9FF9FAEAAFF9FAEAAFFA0AFABFF
+ A2B1ADFFA4B3AFFFB2C1BDFFACBBB7FFA6B4B0FFA4B3AFFFA7B5B1FFA7B6B2FF
+ A6B4B0FFA2B1ADFF9FADA9FF9CABA7FF9BA9A5FF99A8A4FF9CAAA6FF9EADA9FF
+ A2B0ACFFA2B1ADFFC0D1CDFFCCE0DBFFC6DAD5FFB6CCC7FFB8CEC9FFBBD1CCFF
+ BAD0CBFFBED4CFFFC3D9D4FFBBD1CCFFC0D4CFFFC2D6D1FFB6CAC5FF7D8E8AFF
+ 899A96FF93A4A0FF8F9E9AFF92A09CFF97A5A1FF9EACA8FFA2B0ACFFA0AEAAFF
+ 98A6A2FF909E9AFF97A5A1FF9AA8A4FF9DABA7FF9FADA9FF9FADA9FF9EACA8FF
+ 9EACA8FF9EACA8FF9DABA7FF99A7A3FF9FADA9FFA0AEAAFF97A5A1FF9BA9A5FF
+ A5B3AFFFA4B2AEFF9DABA7FFA6B4B0FFAAB8B4FFA5B3AFFFA4B2AEFFA7B5B1FF
+ A5B3AFFFA0AEAAFFA9B7B3FFB2C0BCFFB5C3BFFFAEBCB8FFA9B7B3FFABB9B5FF
+ ACBAB6FFA9B7B3FFA7B5B1FFA8B6B2FFA8B6B2FFA4B2AEFF9EACA8FF98A6A2FF
+ 95A39FFF94A29EFF8E9D99FF8A9995FF889692FF404E4AFF7C8A86FF7A8884FF
+ 87938DFF8A9690FF89948CFF8B968EFF8C978FFF88938BFF848C85FF7E877DFF
+ 7B837CFF7B847AFF7D8880FF7D887EFF7C877FFF7C877DFF7B867EFF7B867CFF
+ 7B867EFF7B867CFF79847CFF818C82FF848F87FF818C82FF808B83FF869187FF
+ 8D9890FF8F9A90FF939C92FF9FA79DFFA8B0A6FF99A298FF8F988EFFA2ABA1FF
+ B3BCB2FFA7B2A8FFA5B0A6FF9FADA2FF9CAA9FFF9AA89DFF9AA89DFF9BABA0FF
+ 9DADA2FF9EAEA3FF9CAA9FFFA0AEA3FFA3B1A6FFA0AEA3FF9BA99EFF98A69BFF
+ 9BA99EFF9FADA2FFA5B3A8FF99A79CFF96A499FF9FADA2FFA2B0A5FF9EACA1FF
+ 9EACA1FFA3B3A8FF9BAFA3FFABC1B5FFBAD0C4FFBED4C8FFC0D5CCFFC2D7CEFF
+ BACFC6FFAEC3BAFFB5CAC2FFB5CAC2FFB5C9C4FFB4C8C3FF8D9491FF878E8BFF
+ 848B88FF89908DFF8D9693FF909996FF959E9BFF9AA3A0FFBBC6C3FFC2CDCAFF
+ AFBDB9FFACBAB6FFAAB8B4FFA8B6B2FFB1C0BCFFA5B4B0FFADBBB7FFB0BEBAFF
+ B0BEBAFFAFBDB9FFB1BFBBFFB4C2BEFFB0BEBAFFA9B7B3FFAFBDB9FFAFBDB9FF
+ ADBBB7FFA9B7B3FFABB9B5FFB0BEBAFFAEBCB8FFA9B7B3FFB1BFBBFFA9B7B3FF
+ A4B2AEFFA2B0ACFF9DABA7FF99A7A3FF9EACA8FFA7B5B1FFA3B1ADFF9EACA8FF
+ 9AA8A4FF9CAAA6FFA3B1ADFFA9B7B3FFAAB8B4FFA8B6B2FFABB9B5FFA9B7B3FF
+ A7B5B1FFA7B5B1FFA7B5B1FFA5B3AFFFA1AFABFF9DABA7FFA7B5B1FFA5B3AFFF
+ 98A6A2FF99A7A3FF92A09CFF9CAAA6FF9AA8A4FF9CAAA6FF99A4A1FF99A4A1FF
+ 97A29FFF95A09DFF939E9BFF929D9AFF909B98FF909B98FF8C9794FF8B9693FF
+ 8A9592FF899491FF87928FFF86918EFF85908DFF848F8CFF848F8CFF818C89FF
+ 7F8A87FF818C89FF7F8A87FF7B8683FF7C8784FF818C89FF838E8BFF848F8CFF
+ 899491FF7A8582FF727D7AFF9DA8A5FFC4CFCCFFBBC9C5FFC0D3D0FFC0D5D2FF
+ C3D8D5FFC3D8D5FFC2D7D4FFBED3D0FFBBD0CDFFB9CECBFFC0D5D2FFC3D8D5FF
+ C4D9D6FFC3D8D5FFC0D5D2FFBED3D0FFBDD2CFFFC0D3D0FFC0CFCBFF919F9BFF
+ 1E2C28FF74827EFF6F7D79FF7B8985FF7C8A86FF7B8985FF7D8B87FF7C8A86FF
+ 7D8B87FF808E8AFF84928EFF889692FF8B9995FF8D9B97FF91A09CFF909F9BFF
+ 8F9E9AFF8E9D99FF8F9E9AFF91A09CFF94A39FFF96A5A1FF97A6A2FF9AA9A5FF
+ 9DACA8FF9EADA9FF9EADA9FF9FAEAAFFA2B1ADFFA5B4B0FFACBAB6FFA9B7B3FF
+ A7B5B1FFA8B6B2FFABB9B5FFA9B7B3FFA4B2AEFF9EACA8FF9FADA9FF9DABA7FF
+ 9AA8A4FF99A7A3FF99A7A3FF9BA9A5FF9CAAA6FF9CABA7FFC5D6D2FFCDE1DCFF
+ C4D8D3FFB8CCC7FFBFD3CEFFC5D9D4FFC0D4CFFFBFD3CEFFC4D8D3FFBED2CDFF
+ C2D6D1FFC4D8D3FFB9CDC8FF80948FFF8FA39EFF9AABA7FF92A19DFF95A39FFF
+ 98A6A2FF9EACA8FFA2B0ACFFA1AFABFF9CAAA6FF97A5A1FF9AA8A4FF9BA9A5FF
+ 9CAAA6FF9CAAA6FF9DABA7FF9DABA7FF9EACA8FF9FADA9FF9EACA8FF99A7A3FF
+ 9FADA9FFA2B0ACFF9AA8A4FF9DABA7FFA3B1ADFF9EACA8FF9DABA7FFA4B2AEFF
+ A8B6B2FFA4B2AEFFA3B1ADFFA7B5B1FFA8B6B2FFA5B3AFFFA3B1ADFFADBBB7FF
+ B2C0BCFFAEBCB8FFABB9B5FFAFBDB9FFB1BFBBFFB0BEBAFFABB9B5FFA8B6B2FF
+ A3B1ADFFA1AFABFFA0AEAAFF9BA9A5FF95A39FFF909E9AFF879593FF889694FF
+ 8C9A96FF53615DFF6E7C78FF75837FFF828E88FF87938DFF89948CFF89948CFF
+ 89948CFF88938BFF879086FF848D83FF838C82FF828B81FF7E897FFF7D887EFF
+ 7C877DFF7B867CFF7B867CFF7A857BFF7A857BFF7A857BFF7F8A80FF818C82FF
+ 818C82FF7F8A80FF828D83FF89948AFF8C978DFF89948AFF939B91FF99A197FF
+ A1A99FFF9AA298FF8E978DFF9CA59BFFABB4AAFFA6AFA5FFACB7ADFFA4AFA5FF
+ 9CAA9FFF9CAA9FFFA1AFA4FFA5B3A8FFA2B2A7FF9FAFA4FF9BA99EFFA0AEA3FF
+ A5B3A8FFA5B3A8FFA2B0A5FFA0AEA3FFA2B0A5FFA6B4A9FFA6B4A9FF9DABA0FF
+ 97A59AFF9BA99EFFA3B1A6FFA7B5AAFFA9B7ACFFAABAAFFF9FB3A7FFAEC4B8FF
+ BBD1C5FFBAD0C4FFBACFC6FFBCD1C8FFB9CEC5FFB1C6BDFFB7CCC4FFB4C9C1FF
+ B1C5C0FFADC1BCFF8E9592FF8A918EFF8A918EFF909794FF929B98FF919A97FF
+ 929B98FF959E9BFFAFBAB7FFC8D3D0FFBBC9C5FFADBBB7FFA7B5B1FFAEBCB8FF
+ BAC9C5FFA6B5B1FFABB9B5FFAFBDB9FFB0BEBAFFAEBCB8FFAFBDB9FFB0BEBAFF
+ ACBAB6FFA5B3AFFFACBAB6FFADBBB7FFAAB8B4FFA6B4B0FFA9B7B3FFAEBCB8FF
+ AFBDB9FFACBAB6FFB1BFBBFFABB9B5FFA6B4B0FFA3B1ADFF9EACA8FF9AA8A4FF
+ 9DABA7FFA4B2AEFF9CAAA6FF9CAAA6FF9CAAA6FF9BA9A5FF9BA9A5FF9FADA9FF
+ A7B5B1FFACBAB6FFA7B5B1FFA6B4B0FFA6B4B0FFA7B5B1FFA7B5B1FFA3B1ADFF
+ 9CAAA6FF97A5A1FFA2B0ACFF9DABA7FF9DABA7FF92A09CFF95A39FFF8F9D99FF
+ 97A5A1FF99A7A3FF98A3A0FF96A19EFF939E9BFF909B98FF8E9996FF8D9895FF
+ 8D9895FF8E9996FF8B9693FF8B9693FF8A9592FF889390FF87928FFF86918EFF
+ 85908DFF848F8CFF85908DFF7F8A87FF7C8784FF7E8986FF7E8986FF7C8784FF
+ 7C8784FF7F8A87FF8A9592FF86918EFF889390FF7A8582FF717C79FF97A29FFF
+ BDC8C5FFB5C3BFFFB9CCC9FFB8CDCAFFBACFCCFFBBD0CDFFBBD0CDFFB9CECBFF
+ B6CBC8FFB4C9C6FFB9CECBFFBFD4D1FFC6DBD8FFC9DEDBFFC7DCD9FFC3D8D5FF
+ BFD4D1FFBFD2CFFFBDCCC8FF8A9894FF273531FF788682FF6E7C78FF75837FFF
+ 7B8985FF7D8B87FF808E8AFF808E8AFF808E8AFF818F8BFF83918DFF869490FF
+ 899793FF8B9995FF91A09CFF92A19DFF93A29EFF94A39FFF94A39FFF93A29EFF
+ 91A09CFF909F9BFF93A29EFF95A4A0FF99A8A4FF9BAAA6FF9EADA9FFA1B0ACFF
+ A6B5B1FFAAB9B5FFA5B3AFFFA5B3AFFFA7B5B1FFABB9B5FFAEBCB8FFAAB8B4FF
+ A1AFABFF99A7A3FF9DABA7FF9BA9A5FF99A7A3FF97A5A1FF95A39FFF96A4A0FF
+ 97A5A1FF97A6A2FFC5D6D2FFCADED9FFC0D4CFFFB6CAC5FFC2D6D1FFC8DCD7FF
+ C1D5D0FFBDD1CCFFC4D8D3FFBFD3CEFFC3D7D2FFC4D8D3FFBBCFCAFF869A95FF
+ 96AAA5FFA1B2AEFF99A8A4FF9AA8A4FF9AA8A4FF9DABA7FFA0AEAAFFA2B0ACFF
+ A1AFABFF9FADA9FF9DABA7FF9CAAA6FF9CAAA6FF9BA9A5FF9CAAA6FF9DABA7FF
+ 9EACA8FF9EACA8FF9FADA9FF98A6A2FF9EACA8FFA2B0ACFF9DABA7FF9FADA9FF
+ A2B0ACFF99A7A3FF9AA8A4FF9FADA9FFA1AFABFF9EACA8FF9EACA8FFA3B1ADFF
+ A6B4B0FFA6B4B0FFA1AFABFFAAB8B4FFB0BEBAFFAFBDB9FFADBBB7FFB0BEBAFF
+ B3C1BDFFB3C1BDFFAEBCB8FFA7B5B1FFA0AEAAFF9EACA8FFA0AEAAFF9DABA7FF
+ 94A29EFF8B9995FF82908EFF869492FF8E9C98FF6E7C78FF5A6864FF73817DFF
+ 7D8983FF838F89FF89948CFF88938BFF869189FF869189FF8A9389FF8B948AFF
+ 8B948AFF8A9389FF818C82FF808B81FF7E897FFF7B867CFF79847AFF788379FF
+ 788379FF778278FF7A857BFF7A857BFF79847AFF7A857BFF828D83FF8B968CFF
+ 8B968CFF859086FF9AA298FF979F95FF9EA69CFF9EA69CFF939C92FF99A298FF
+ A8B1A7FFABB4AAFFADB8AEFFA4AFA5FF99A79CFF9BA99EFFA3B1A6FFA8B6ABFF
+ A3B3A8FF9DADA2FF98A69BFF9EACA1FFA5B3A8FFA6B4A9FFA4B2A7FFA1AFA4FF
+ A1AFA4FFA2B0A5FFA4B2A7FF9FADA2FF97A59AFF94A297FF9BA99EFFA6B4A9FF
+ AAB8ADFFA5B5AAFFA5B9ADFFB6CCC0FFC1D7CBFFBDD3C7FFB7CCC3FFB9CEC5FF
+ BBD0C7FFB8CDC4FFB4C9C1FFB0C5BDFFAABEB9FFA5B9B4FF8D9491FF8A918EFF
+ 8C9390FF939A97FF949D9AFF909996FF8D9693FF8E9794FF9DA8A5FFC9D4D1FF
+ C7D5D1FFB3C1BDFFA6B4B0FFAFBDB9FFBDCCC8FFA6B5B1FFA8B6B2FFACBAB6FF
+ ACBAB6FFA9B7B3FFAAB8B4FFAEBCB8FFADBBB7FFA9B7B3FFA7B5B1FFAAB8B4FF
+ ABB9B5FFA9B7B3FFABB9B5FFB0BEBAFFB0BEBAFFADBBB7FFB1BFBBFFAEBCB8FF
+ AAB8B4FFA4B2AEFF9FADA9FF9CAAA6FF9EACA8FFA1AFABFFA2B0ACFFA1AFABFF
+ 9EACA8FF9BA9A5FF9AA8A4FF9EACA8FFA6B4B0FFACBAB6FFA2B0ACFFA1AFABFF
+ A1AFABFFA3B1ADFFA4B2AEFFA2B0ACFF9EACA8FF9AA8A4FF9EACA8FF98A6A2FF
+ A1AFABFF8F9D99FF97A5A1FF85938FFF95A39FFF97A5A1FF97A29FFF949F9CFF
+ 909B98FF8D9895FF8B9693FF8B9693FF8C9794FF8D9895FF8D9895FF8C9794FF
+ 8C9794FF8B9693FF8A9592FF899491FF889390FF87928FFF87928FFF808B88FF
+ 7C8784FF7E8986FF7F8A87FF7D8885FF7D8885FF7F8A87FF899491FF848F8CFF
+ 889390FF7B8683FF6C7774FF8B9693FFB3BEBBFFB2C0BCFFB1C4C1FFB1C6C3FF
+ B4C9C6FFB8CDCAFFBACFCCFFB7CCC9FFB2C7C4FFADC2BFFFAEC3C0FFB7CCC9FF
+ C3D8D5FFCADFDCFFCADFDCFFC4D9D6FFBED3D0FFBCCFCCFFCAD9D5FF8A9894FF
+ 364440FF818F8BFF768480FF798783FF7E8C88FF7E8C88FF85938FFF85938FFF
+ 85938FFF84928EFF83918DFF85938FFF899793FF8C9A96FF8C9B97FF8F9E9AFF
+ 93A29EFF96A5A1FF96A5A1FF94A39FFF909F9BFF8D9C98FF8D9C98FF909F9BFF
+ 94A39FFF98A7A3FF9CABA7FFA3B2AEFFAAB9B5FFB0BFBBFFA3B1ADFFA3B1ADFF
+ A5B3AFFFAAB8B4FFADBBB7FFA9B7B3FFA0AEAAFF97A5A1FF99A7A3FF99A7A3FF
+ 99A7A3FF96A4A0FF94A29EFF94A29EFF95A39FFF96A5A1FFBCCDC9FFC6DAD5FF
+ C0D4CFFFB6CAC5FFBED2CDFFC3D7D2FFBFD3CEFFBED2CDFFC2D6D1FFBFD3CEFF
+ C2D6D1FFC1D5D0FFB8CCC7FF869A95FF97ABA6FFA1B2AEFF9FAEAAFF9EACA8FF
+ 9DABA7FF9CAAA6FF9DABA7FF9FADA9FFA0AEAAFFA1AFABFF9EACA8FF9EACA8FF
+ 9EACA8FF9FADA9FFA0AEAAFFA0AEAAFF9FADA9FF9DABA7FFA0AEAAFF97A5A1FF
+ 9AA8A4FF9FADA9FF9CAAA6FFA1AFABFFA4B2AEFF9AA8A4FF98A6A2FF9AA8A4FF
+ 9AA8A4FF97A5A1FF97A5A1FF9AA8A4FF9EACA8FFA1AFABFFA2B0ACFFA9B7B3FF
+ AFBDB9FFB0BEBAFFADBBB7FFADBBB7FFAEBCB8FFB0BEBAFFADBBB7FFA7B5B1FF
+ A0AEAAFF9DABA7FF9DABA7FF99A7A3FF92A09CFF8C9A96FF859391FF879593FF
+ 8C9A96FF83918DFF4A5854FF75837FFF7B8781FF818D87FF8A958DFF87928AFF
+ 848F87FF859088FF8A9389FF8D968CFF8E978DFF8D968CFF879288FF859086FF
+ 818C82FF7C877DFF79847AFF768177FF747F75FF747F75FF747F75FF778278FF
+ 79847AFF7C877DFF848F85FF8E998FFF919C92FF8D988EFF9AA298FF8E968CFF
+ 929A90FF98A096FF8E978DFF90998FFFA1AAA0FFABB4AAFFACB7ADFFA6B1A7FF
+ 9EACA1FF9FADA2FFA5B3A8FFA8B6ABFFA5B5AAFFA2B2A7FF9EACA1FFA3B1A6FF
+ A9B7ACFFAAB8ADFFA7B5AAFFA2B0A5FF9EACA1FF9DABA0FFA2B0A5FFA7B5AAFF
+ A3B1A6FF98A69BFF98A69BFFA2B0A5FFA6B4A9FFA0B0A5FFA5B9ADFFB8CEC2FF
+ C5DBCFFFBFD5C9FFB4C9C0FFB4C9C0FFB7CCC3FFB6CBC2FFB4C9C1FFB1C6BEFF
+ AEC2BDFFAABEB9FF8A918EFF878E8BFF89908DFF909794FF919A97FF8D9693FF
+ 89928FFF89928FFF8F9A97FFC2CDCAFFCBD9D5FFBCCAC6FFABB9B5FFADBBB7FF
+ BAC9C5FFA7B6B2FFABB9B5FFADBBB7FFABB9B5FFA6B4B0FFA6B4B0FFABB9B5FF
+ ADBBB7FFACBAB6FFA3B1ADFFA9B7B3FFADBBB7FFADBBB7FFAEBCB8FFB2C0BCFF
+ B1BFBBFFAEBCB8FFB0BEBAFFB0BEBAFFADBBB7FFA7B5B1FFA1AFABFF9FADA9FF
+ A0AEAAFFA1AFABFFAAB8B4FFA4B2AEFF9CAAA6FF9AA8A4FF9CAAA6FFA0AEAAFF
+ A3B1ADFFA4B2AEFFA2B0ACFFA0AEAAFF9DABA7FF9DABA7FF9EACA8FF9FADA9FF
+ 9EACA8FF9CAAA6FF9DABA7FF96A4A0FFA1AFABFF92A09CFF98A6A2FF82908CFF
+ 919F9BFF96A4A0FF96A19EFF949F9CFF909B98FF8C9794FF8A9592FF8A9592FF
+ 8C9794FF8D9895FF8C9794FF8B9693FF8B9693FF8A9592FF899491FF889390FF
+ 889390FF889390FF899491FF828D8AFF7E8986FF7F8A87FF7F8A87FF7D8885FF
+ 7E8986FF828D8AFF848F8CFF808B88FF889390FF7E8986FF697471FF818C89FF
+ AAB5B2FFB2C0BCFFB0C3C0FFB1C6C3FFB7CCC9FFBED3D0FFC1D6D3FFBED3D0FF
+ B5CAC7FFAEC3C0FFA5BAB7FFB0C5C2FFBED3D0FFC7DCD9FFC8DDDAFFC2D7D4FF
+ BACFCCFFB8CBC8FFD0DFDBFF818F8BFF3C4A46FF83918DFF7D8B87FF808E8AFF
+ 83918DFF7E8C88FF8A9894FF8B9995FF8A9894FF879591FF85938FFF869490FF
+ 8B9995FF909E9AFF889793FF8C9B97FF91A09CFF95A4A0FF96A5A1FF94A39FFF
+ 909F9BFF8D9C98FF91A09CFF92A19DFF94A39FFF96A5A1FF99A8A4FFA0AFABFF
+ A8B7B3FFAEBDB9FFA4B2AEFFA2B0ACFFA3B1ADFFA6B4B0FFA8B6B2FFA6B4B0FF
+ 9EACA8FF97A5A1FF96A4A0FF98A6A2FF99A7A3FF97A5A1FF95A39FFF94A29EFF
+ 96A4A0FF98A7A3FFB0C1BDFFC4D8D3FFC6DAD5FFB9CDC8FFB8CCC7FFBACEC9FF
+ BCD0CBFFC5D9D4FFC1D5D0FFBFD3CEFFC0D4CFFFBBCFCAFFB1C5C0FF829691FF
+ 94A8A3FF9CADA9FFA2B1ADFFA1AFABFF9FADA9FF9CAAA6FF9BA9A5FF9BA9A5FF
+ 9DABA7FF9FADA9FF9EACA8FF9EACA8FF9FADA9FFA3B1ADFFA5B3AFFFA5B3AFFF
+ A0AEAAFF9CAAA6FFA2B0ACFF96A4A0FF96A4A0FF9AA8A4FF98A6A2FFA0AEAAFF
+ A7B5B1FFA0AEAAFF9CAAA6FF9BA9A5FF99A7A3FF96A4A0FF94A29EFF93A19DFF
+ 97A5A1FF9CAAA6FF9FADA9FFA4B2AEFFABB9B5FFAEBCB8FFACBAB6FFAAB8B4FF
+ ABB9B5FFAFBDB9FFA7B5B1FFA6B4B0FFA2B0ACFF9DABA7FF98A6A2FF93A19DFF
+ 919F9BFF8F9D99FF8C9A98FF889694FF869490FF8D9B97FF43514DFF7B8985FF
+ 7B8781FF838F89FF8A958DFF88938BFF869189FF859088FF889187FF8A9389FF
+ 8B948AFF8B948AFF8D988EFF8A958BFF848F85FF7E897FFF79847AFF758076FF
+ 737E74FF737E74FF768177FF7E897FFF848F85FF848F85FF879288FF8E998FFF
+ 939E94FF939E94FF8B9389FF7A8278FF7C847AFF858D83FF7E877DFF818A80FF
+ 949D93FFA1AAA0FFA8B3A9FFA8B3A9FFA6B4A9FFA5B3A8FFA5B3A8FFA6B4A9FF
+ A7B7ACFFA9B9AEFFA5B3A8FFAAB8ADFFAFBDB2FFB2C0B5FFAFBDB2FFAAB8ADFF
+ A5B3A8FFA3B1A6FFA1AFA4FFAEBCB1FFB2C0B5FFA6B4A9FF9FADA2FFA4B2A7FF
+ A9B7ACFFA6B6ABFF9EB2A6FFB4CABEFFC6DCD0FFC0D6CAFFB4C9C0FFB0C5BCFF
+ AFC4BBFFADC2B9FFB6CBC3FFB7CCC4FFB7CBC6FFB8CCC7FF868D8AFF828986FF
+ 838A87FF8A918EFF8B9491FF89928FFF87908DFF88918EFF909B98FFB7C2BFFF
+ C0CECAFFC1CFCBFFB6C4C0FFADBBB7FFB5C4C0FFA8B7B3FFAFBDB9FFB2C0BCFF
+ B0BEBAFFA9B7B3FFA5B3AFFFA8B6B2FFABB9B5FFAAB8B4FFA3B1ADFFAAB8B4FF
+ AEBCB8FFADBBB7FFADBBB7FFB1BFBBFFB2C0BCFFAFBDB9FFAFBDB9FFB2C0BCFF
+ B1BFBBFFA9B7B3FFA4B2AEFFA4B2AEFFA4B2AEFFA2B0ACFFACBAB6FFA2B0ACFF
+ 98A6A2FF97A5A1FF9CAAA6FFA0AEAAFF9EACA8FF9AA8A4FFA5B3AFFFA2B0ACFF
+ 9DABA7FF9BA9A5FF9CAAA6FF9CAAA6FF9BA9A5FF99A7A3FF9CAAA6FF96A4A0FF
+ 9CAAA6FF97A5A1FF96A4A0FF85938FFF8C9A96FF95A39FFF95A09DFF939E9BFF
+ 909B98FF8D9895FF8B9693FF8B9693FF8B9693FF8B9693FF889390FF889390FF
+ 87928FFF87928FFF86918EFF86918EFF85908DFF85908DFF889390FF838E8BFF
+ 818C89FF808B88FF7D8885FF7A8582FF7F8A87FF86918EFF828D8AFF7C8784FF
+ 87928FFF838E8BFF6F7A77FF818C89FFA9B4B1FFB4C2BEFFAEC1BEFFAFC4C1FF
+ B5CAC7FFBDD2CFFFC2D7D4FFC0D5D2FFB7CCC9FFAFC4C1FFA2B7B4FFACC1BEFF
+ BACFCCFFC4D9D6FFC5DAD7FFC0D5D2FFB9CECBFFB7CAC7FFCAD9D5FF707E7AFF
+ 3C4A46FF82908CFF7F8D89FF82908CFF889692FF83918DFF8D9B97FF8E9C98FF
+ 8D9B97FF8A9894FF869490FF879591FF8D9B97FF93A19DFF899894FF8C9B97FF
+ 8F9E9AFF93A29EFF94A39FFF92A19DFF909F9BFF8E9D99FF99A8A4FF99A8A4FF
+ 97A6A2FF96A5A1FF96A5A1FF9AA9A5FFA1B0ACFFA6B5B1FFA6B4B0FFA3B1ADFF
+ A1AFABFFA2B0ACFFA4B2AEFFA2B0ACFF9CAAA6FF96A4A0FF94A29EFF97A5A1FF
+ 9AA8A4FF99A7A3FF95A39FFF94A29EFF96A4A0FF99A8A4FFA5B6B2FFC2D6D1FF
+ CBDFDAFFBCD0CBFFB3C7C2FFB2C6C1FFBACEC9FFCBDFDAFFC1D5D0FFBFD3CEFF
+ BFD3CEFFB7CBC6FFACC0BBFF7F938EFF92A6A1FF98A9A5FF9FAEAAFFA1AFABFF
+ A0AEAAFF9EACA8FF9BA9A5FF9AA8A4FF9BA9A5FF9DABA7FF9EACA8FF9DABA7FF
+ 9DABA7FFA1AFABFFA6B4B0FFA7B5B1FFA3B1ADFF9EACA8FFA2B0ACFF97A5A1FF
+ 97A5A1FF98A6A2FF94A29EFF9CAAA6FFA6B4B0FFA2B0ACFFA3B1ADFF9FADA9FF
+ 9CAAA6FF9BA9A5FF96A4A0FF92A09CFF94A29EFF9AA8A4FF96A4A0FF9AA8A4FF
+ A3B1ADFFABB9B5FFABB9B5FFA7B5B1FFAAB8B4FFB0BEBAFFA3B1ADFFA4B2AEFF
+ A2B0ACFF9CAAA6FF95A39FFF919F9BFF919F9BFF92A09CFF8B9997FF889694FF
+ 83918DFF8F9D99FF465450FF7E8C88FF7A8680FF86928CFF88938BFF89948CFF
+ 89948CFF87928AFF868F85FF858E84FF879086FF899288FF8E998FFF8B968CFF
+ 859086FF7F8A80FF7A857BFF788379FF778278FF778278FF788379FF818C82FF
+ 869187FF828D83FF7F8A80FF818C82FF859086FF859086FF7E867CFF71796FFF
+ 757D73FF7F877DFF7B847AFF818A80FF949D93FF9DA69CFF9EA99FFFA2ADA3FF
+ A3B1A6FFA1AFA4FF9EACA1FF9DABA0FFA0B0A5FFA5B5AAFFA1AFA4FFA5B3A8FF
+ AAB8ADFFAFBDB2FFAFBDB2FFACBAAFFFA8B6ABFFA6B4A9FF9CAA9FFFA8B6ABFF
+ AFBDB2FFAAB8ADFFA2B0A5FFA3B1A6FFA8B6ABFFA9B9AEFFA1B5A9FFB8CEC2FF
+ CBE1D5FFC8DED2FFBCD1C8FFB6CBC2FFB2C7BEFFADC2B9FFAFC4BCFFB1C6BEFF
+ B4C8C3FFB7CBC6FF848B88FF7F8683FF7E8582FF848B88FF87908DFF87908DFF
+ 88918EFF8B9491FFA1ACA9FFACB7B4FFACBAB6FFC1CFCBFFC3D1CDFFB2C0BCFF
+ B3C2BEFFAAB9B5FFABB9B5FFB1BFBBFFB3C1BDFFAFBDB9FFABB9B5FFACBAB6FF
+ ACBAB6FFA9B7B3FFA6B4B0FFABB9B5FFACBAB6FFA7B5B1FFA6B4B0FFACBAB6FF
+ B2C0BCFFB3C1BDFFAEBCB8FFB4C2BEFFB3C1BDFFACBAB6FFA7B5B1FFA9B7B3FF
+ A8B6B2FFA4B2AEFFA8B6B2FFA0AEAAFF98A6A2FF98A6A2FF9DABA7FF9FADA9FF
+ 9CAAA6FF98A6A2FFA1AFABFF9FADA9FF9DABA7FF9DABA7FF9EACA8FF9EACA8FF
+ 9BA9A5FF99A7A3FF9BA9A5FF97A5A1FF93A19DFF9DABA7FF909E9AFF8A9894FF
+ 869490FF92A09CFF929D9AFF919C99FF8F9A97FF8E9996FF8C9794FF8A9592FF
+ 899491FF889390FF87928FFF87928FFF87928FFF86918EFF86918EFF86918EFF
+ 85908DFF85908DFF848F8CFF838E8BFF838E8BFF818C89FF7A8582FF76817EFF
+ 7D8885FF889390FF87928FFF7A8582FF838E8BFF899491FF7D8885FF8E9996FF
+ B0BBB8FFB6C4C0FFB1C4C1FFAFC4C1FFB1C6C3FFB7CCC9FFBED3D0FFBFD4D1FF
+ BACFCCFFB4C9C6FFA4B9B6FFAEC3C0FFBACFCCFFC3D8D5FFC5DAD7FFC1D6D3FF
+ BCD1CEFFBACDCAFFC9D8D4FF6B7975FF485652FF8A9894FF82908CFF83918DFF
+ 8E9C98FF8C9A96FF8D9B97FF8F9D99FF8E9C98FF8A9894FF85938FFF869490FF
+ 8D9B97FF94A29EFF8F9E9AFF909F9BFF91A09CFF91A09CFF91A09CFF91A09CFF
+ 909F9BFF909F9BFF9AA9A5FF99A8A4FF97A6A2FF94A39FFF94A39FFF98A7A3FF
+ A0AFABFFA6B5B1FFA5B3AFFFA3B1ADFFA1AFABFFA3B1ADFFA4B2AEFFA0AEAAFF
+ 98A6A2FF919F9BFF94A29EFF98A6A2FF9BA9A5FF99A7A3FF94A29EFF919F9BFF
+ 93A19DFF95A4A0FF9BACA8FFBACEC9FFC6DAD5FFB6CAC5FFABBFBAFFA9BDB8FF
+ B4C8C3FFC7DBD6FFC1D5D0FFC0D4CFFFC0D4CFFFB5C9C4FFABBFBAFF819590FF
+ 94A8A3FF9AABA7FF99A8A4FF9EACA8FFA1AFABFFA2B0ACFF9FADA9FF9DABA7FF
+ 9DABA7FF9EACA8FFA0AEAAFF9BA9A5FF98A6A2FF9AA8A4FFA0AEAAFFA5B3AFFF
+ A4B2AEFFA2B0ACFFA2B0ACFF9AA8A4FF9DABA7FF9CAAA6FF94A29EFF98A6A2FF
+ A1AFABFF9EACA8FFA4B2AEFF9FADA9FF9DABA7FF9DABA7FF99A7A3FF92A09CFF
+ 93A19DFF99A7A3FF93A19DFF96A4A0FF9FADA9FFA8B6B2FFA8B6B2FFA2B0ACFF
+ A4B2AEFFABB9B5FFA4B2AEFFA1AFABFF9CAAA6FF98A6A2FF96A4A0FF94A29EFF
+ 92A09CFF919F9BFF808E8CFF869492FF85938FFF8E9C98FF4D5B57FF7B8985FF
+ 75817BFF88948EFF859088FF8A958DFF8E9991FF8B968EFF868F85FF828B81FF
+ 858E84FF8A9389FF8B968CFF889389FF838E84FF7F8A80FF7D887EFF7D887EFF
+ 7E897FFF7F8A80FF7A857BFF7F8A80FF808B81FF7C877DFF7A857BFF7C877DFF
+ 7A857BFF768177FF7B8379FF767E74FF80887EFF8B9389FF8A9389FF949D93FF
+ A2ABA1FFA3ACA2FF9BA69CFF9DA89EFF9CAA9FFF9CAA9FFF9CAA9FFF9CAA9FFF
+ 9CACA1FF9FAFA4FF9DABA0FFA0AEA3FFA4B2A7FFA8B6ABFFA9B7ACFFA8B6ABFF
+ A4B2A7FFA1AFA4FFA2B0A5FFA1AFA4FFA2B0A5FFA4B2A7FFA2B0A5FF9FADA2FF
+ A1AFA4FFA5B5AAFFA6BAAEFFBBD1C5FFCDE3D7FFCAE0D4FFC0D5CCFFBCD1C8FF
+ B6CBC2FFAFC4BBFFA9BEB6FFAABFB7FFACC0BBFFAEC2BDFF848B88FF7D8481FF
+ 7C8380FF818885FF848D8AFF868F8CFF8A9390FF8F9895FFB1BCB9FFA6B1AEFF
+ 9CAAA6FFBECCC8FFCBD9D5FFB7C5C1FFB3C2BEFFACBBB7FFA3B1ADFFADBBB7FF
+ B4C2BEFFB4C2BEFFB1BFBBFFB1BFBBFFB0BEBAFFACBAB6FFA9B7B3FFACBAB6FF
+ A9B7B3FFA1AFABFFA0AEAAFFA8B6B2FFB1BFBBFFB6C4C0FFAEBCB8FFB5C3BFFF
+ B5C3BFFFADBBB7FFA9B7B3FFABB9B5FFABB9B5FFA6B4B0FFA5B3AFFFA0AEAAFF
+ 9CAAA6FF9BA9A5FF9EACA8FFA0AEAAFF9EACA8FF9CAAA6FF98A6A2FF99A7A3FF
+ 9BA9A5FF9FADA9FFA2B0ACFFA2B0ACFF9FADA9FF9CAAA6FF9AA8A4FF97A5A1FF
+ 8C9A96FFA0AEAAFF8C9A96FF8E9C98FF818F8BFF8F9D99FF8F9A97FF8F9A97FF
+ 8F9A97FF8D9895FF8B9693FF899491FF87928FFF85908DFF899491FF899491FF
+ 899491FF899491FF899491FF889390FF889390FF889390FF818C89FF828D8AFF
+ 848F8CFF808B88FF77827FFF727D7AFF7B8683FF899491FF8E9996FF7A8582FF
+ 818C89FF8C9794FF889390FF9BA6A3FFB7C2BFFFB8C6C2FFBBCECBFFB6CBC8FF
+ B4C9C6FFB8CDCAFFC0D5D2FFC4D9D6FFC2D7D4FFBED3D0FFA8BDBAFFB1C6C3FF
+ BCD1CEFFC4D9D6FFC5DAD7FFC2D7D4FFBFD4D1FFBED1CEFFD1E0DCFF72807CFF
+ 596763FF96A4A0FF889692FF85938FFF93A19DFF95A39FFF8C9A96FF8E9C98FF
+ 8E9C98FF899793FF84928EFF85938FFF8D9B97FF94A29EFF96A5A1FF95A4A0FF
+ 93A29EFF91A09CFF909F9BFF909F9BFF909F9BFF91A09CFF96A5A1FF95A4A0FF
+ 93A29EFF92A19DFF94A39FFF9AA9A5FFA4B3AFFFABBAB6FFA4B2AEFFA2B0ACFF
+ A2B0ACFFA4B2AEFFA5B3AFFFA0AEAAFF95A39FFF8D9B97FF95A39FFF99A7A3FF
+ 9CAAA6FF99A7A3FF92A09CFF8E9C98FF8F9D99FF91A09CFF92A39FFFB1C5C0FF
+ BDD1CCFFAEC2BDFFA4B8B3FFA3B7B2FFADC1BCFFBFD3CEFFC1D5D0FFC1D5D0FF
+ C1D5D0FFB6CAC5FFADC1BCFF849893FF98ACA7FF9EAFABFF94A39FFF9BA9A5FF
+ A2B0ACFFA5B3AFFFA3B1ADFFA0AEAAFFA0AEAAFFA1AFABFFA1AFABFF9AA8A4FF
+ 93A19DFF93A19DFF9AA8A4FFA2B0ACFFA6B4B0FFA6B4B0FFA1AFABFF9CAAA6FF
+ A2B0ACFFA1AFABFF94A29EFF95A39FFF9CAAA6FF99A7A3FFA0AEAAFF9BA9A5FF
+ 9AA8A4FF9CAAA6FF98A6A2FF909E9AFF909E9AFF97A5A1FF95A39FFF97A5A1FF
+ 9FADA9FFA7B5B1FFA5B3AFFF9CAAA6FF9CAAA6FFA3B1ADFFA6B4B0FF9EACA8FF
+ 96A4A0FF95A39FFF98A6A2FF98A6A2FF94A29EFF8E9C98FF748280FF849290FF
+ 889692FF8E9C98FF53615DFF778581FF707C76FF8A9690FF828D85FF8A958DFF
+ 929D95FF8F9A92FF879086FF828B81FF858E84FF8C958BFF879288FF859086FF
+ 828D83FF7F8A80FF7F8A80FF818C82FF848F85FF869187FF818C82FF828D83FF
+ 808B81FF7E897FFF818C82FF848F85FF7F8A80FF778278FF788076FF7A8278FF
+ 8A9288FF959D93FF97A096FFA2ABA1FFACB5ABFFA6AFA5FFA4AFA5FFA2ADA3FF
+ 9FADA2FFA1AFA4FFA5B3A8FFA7B5AAFFA4B4A9FFA2B2A7FFA5B3A8FFA5B3A8FF
+ A7B5AAFFA9B7ACFFA9B7ACFFA6B4A9FFA2B0A5FF9FADA2FFB3C1B6FFA5B3A8FF
+ 9DABA0FFA3B1A6FFA6B4A9FFA0AEA3FF9FADA2FFA2B2A7FFA2B6AAFFB5CBBFFF
+ C4DACEFFC1D7CBFFB9CEC5FFB6CBC2FFB1C6BDFFA9BEB5FFAEC3BBFFADC2BAFF
+ ACC0BBFFACC0BBFF3C4340FF6D7471FF868D8AFF757C79FF6E7774FF868F8CFF
+ 909996FF828B88FFABB6B3FFA6B1AEFFB2C0BCFFCBD9D5FFCBD9D5FFB6C4C0FF
+ AEBDB9FFBBCAC6FFA5B3AFFFACBAB6FFB1BFBBFFB1BFBBFFB3C1BDFFB6C4C0FF
+ B1BFBBFFA9B7B3FFA6B4B0FFAEBCB8FFB1BFBBFFABB9B5FFA5B3AFFFA7B5B1FF
+ ABB9B5FFACBAB6FFADBBB7FFB1BFBBFFB6C4C0FFB5C3BFFFA8B6B2FF9DABA7FF
+ A1AFABFFACBAB6FFA4B2AEFF9FADA9FF9DABA7FFA0AEAAFFA0AEAAFF9DABA7FF
+ 9DABA7FFA0AEAAFF99A7A3FF9BA9A5FF9EACA8FF9EACA8FF9DABA7FF9BA9A5FF
+ 9BA9A5FF9BA9A5FF9AA8A4FF9CAAA6FF919F9BFF93A19DFF9EACA8FF8A9894FF
+ 768480FF82908CFF8C9794FF87928FFF909B98FF95A09DFF8B9693FF899491FF
+ 8E9996FF8A9592FF87928FFF848F8CFF818C89FF828D8AFF85908DFF87928FFF
+ 85908DFF838E8BFF838E8BFF848F8CFF848F8CFF838E8BFF808B88FF7C8784FF
+ 77827FFF747F7CFF848F8CFF8A9592FF8A9592FF828D8AFF828D8AFF939E9BFF
+ ABB6B3FFB9C7C3FFBFD2CFFFB7CCC9FFB7CCC9FFBDD2CFFFC3D8D5FFC3D8D5FF
+ C4D9D6FFC7DCD9FFB1C6C3FFA8BDBAFFA9BEBBFFB8CDCAFFC6DBD8FFC7DCD9FF
+ C4D9D6FFC5D8D5FFD4E3DFFF586662FF5A6864FF899793FF94A29EFF8F9D99FF
+ 818F8BFF93A19DFF899793FF899793FF8F9D99FF93A19DFF8B9995FF818F8BFF
+ 869490FF94A29EFF8F9E9AFF909F9BFF91A09CFF92A19DFF94A39FFF95A4A0FF
+ 96A5A1FF97A6A2FF909F9BFF96A5A1FF9BAAA6FF98A7A3FF8F9E9AFF8C9B97FF
+ 97A6A2FFA5B4B0FFA8B6B2FFA0AEAAFF9CAAA6FFA2B0ACFFA7B5B1FFA0AEAAFF
+ 95A39FFF8E9C98FF8B9995FF8F9D99FF97A5A1FF9CAAA6FF96A4A0FF8D9B97FF
+ 8D9B97FF92A19DFF8B9C98FFA3B7B2FFB6CAC5FFB4C8C3FFACC0BBFFAEC2BDFF
+ B3C7C2FFB4C8C3FFC2D6D1FFC4D8D3FFC2D6D1FFB3C7C2FFB5C9C4FF788C87FF
+ A6BAB5FFA7B8B4FF9BAAA6FF98A6A2FF98A6A2FF9DABA7FFA0AEAAFF9DABA7FF
+ 9BA9A5FF9CAAA6FFA3B1ADFFA4B2AEFF9FADA9FF9BA9A5FF9FADA9FFA5B3AFFF
+ A1AFABFF96A4A0FF9CAAA6FF9AA8A4FF99A7A3FF9CAAA6FFA0AEAAFFA1AFABFF
+ 9FADA9FF9CAAA6FF9DABA7FF9CAAA6FF9DABA7FF9EACA8FF99A7A3FF92A09CFF
+ 93A19DFF98A6A2FF9CAAA6FF9AA8A4FF9AA8A4FF9DABA7FFA1AFABFFA1AFABFF
+ 9DABA7FF99A7A3FF9FADA9FF97A5A1FF919F9BFF93A19DFF95A39FFF92A09CFF
+ 8D9B97FF899793FF849290FF748280FF8A9894FF798783FF73817DFF697773FF
+ 7E8A84FF88948EFF848F87FF859088FF87928AFF89948CFF8A9389FF889187FF
+ 858E84FF848D83FF8B968CFF848F85FF7F8A80FF808B81FF7C877DFF758076FF
+ 768177FF7D887EFF869187FF859086FF859086FF859086FF879288FF8A958BFF
+ 8D988EFF8F9A90FF959D93FF979F95FF9AA298FF9CA49AFF9CA59BFFA0A99FFF
+ A5AEA4FFA8B1A7FFABB6ACFFABB6ACFFA7B5AAFFA3B1A6FF9FADA2FF9EACA1FF
+ 9EAEA3FFA1B1A6FFA3B1A6FFA7B5AAFFA9B7ACFFA9B7ACFFA9B7ACFFA9B7ACFF
+ A2B0A5FF99A79CFFA0AEA3FFA4B2A7FFA7B5AAFFA6B4A9FFA1AFA4FF9DABA0FF
+ 9DABA0FF9DADA2FFA2B6AAFFB4CABEFFC5DBCFFFC5DBCFFFBBD0C7FFB3C8BFFF
+ AFC4BBFFADC2B9FFAFC4BCFFAEC3BBFFACC0BBFFA9BDB8FF424946FF5A615EFF
+ 6C7370FF6E7572FF6F7875FF7E8784FF89928FFF8A9390FF99A4A1FFA5B0ADFF
+ A7B5B1FFA7B5B1FFB9C7C3FFCEDCD8FFC0CFCBFFA2B1ADFFB4C2BEFFB3C1BDFF
+ AFBDB9FFA9B7B3FFA4B2AEFFA4B2AEFFACBAB6FFB3C1BDFFA5B3AFFFAAB8B4FF
+ AAB8B4FFA5B3AFFFA3B1ADFFA6B4B0FFA8B6B2FFA7B5B1FFB0BEBAFFB1BFBBFF
+ B1BFBBFFADBBB7FFA9B7B3FFA7B5B1FFA8B6B2FFAAB8B4FF9BA9A5FF9CAAA6FF
+ 9FADA9FFA3B1ADFFA1AFABFF9DABA7FFA0AEAAFFA7B5B1FF9AA8A4FF9AA8A4FF
+ 9BA9A5FF9CAAA6FF9DABA7FF9CAAA6FF9AA8A4FF99A7A3FF9CAAA6FF9BA9A5FF
+ 94A29EFF95A39FFF9AA8A4FF8D9B97FF7D8B87FF7B8985FF8F9A97FF889390FF
+ 8A9592FF899491FF828D8AFF828D8AFF889390FF86918EFF8C9794FF889390FF
+ 86918EFF86918EFF899491FF8C9794FF8C9794FF8A9592FF848F8CFF85908DFF
+ 85908DFF848F8CFF838E8BFF808B88FF7E8986FF7D8885FF7B8683FF7F8A87FF
+ 7F8A87FF7C8784FF848F8CFF9CA7A4FFB7C2BFFFC6D4D0FFBFD2CFFFB9CECBFF
+ BACFCCFFBFD4D1FFC3D8D5FFC2D7D4FFC4D9D6FFC7DCD9FFB7CCC9FFADC2BFFF
+ ABC0BDFFB6CBC8FFC3D8D5FFC8DDDAFFC8DDDAFFCBDEDBFFD8E7E3FF495753FF
+ 677571FF717F7BFF808E8AFF879591FF85938FFF96A4A0FF8B9995FF869490FF
+ 879591FF8C9A96FF8A9894FF84928EFF889692FF93A19DFF8D9C98FF8D9C98FF
+ 8F9E9AFF91A09CFF93A29EFF95A4A0FF96A5A1FF97A6A2FF8F9E9AFF91A09CFF
+ 93A29EFF94A39FFF91A09CFF909F9BFF93A29EFF98A7A3FFA5B3AFFFA0AEAAFF
+ A0AEAAFFA6B4B0FFA8B6B2FFA0AEAAFF97A5A1FF93A19DFF8D9B97FF8C9A96FF
+ 909E9AFF96A4A0FF95A39FFF909E9AFF8E9C98FF909F9BFF82938FFF9DB1ACFF
+ B6CAC5FFB9CDC8FFB4C8C3FFB6CAC5FFB9CDC8FFB9CDC8FFBBCFCAFFBDD1CCFF
+ BDD1CCFFB0C4BFFFB4C8C3FF7A8E89FFA8BCB7FFA9BAB6FF9AA9A5FF97A5A1FF
+ 98A6A2FF9EACA8FFA1AFABFF9EACA8FF9BA9A5FF9CAAA6FF9EACA8FF9CAAA6FF
+ 97A5A1FF94A29EFF9AA8A4FFA5B3AFFFA6B4B0FFA1AFABFF9FADA9FF9DABA7FF
+ 9CAAA6FF9DABA7FFA0AEAAFFA1AFABFFA0AEAAFF9EACA8FFA2B0ACFFA1AFABFF
+ A2B0ACFFA2B0ACFF9AA8A4FF8E9C98FF889692FF899793FF99A7A3FF99A7A3FF
+ 9BA9A5FF9EACA8FFA1AFABFFA0AEAAFF9BA9A5FF96A4A0FF9DABA7FF96A4A0FF
+ 909E9AFF909E9AFF919F9BFF8E9C98FF889692FF84928EFF7F8D8BFF778583FF
+ 899793FF7E8C88FF6C7A76FF62706CFF77837DFF87938DFF869189FF88938BFF
+ 8A958DFF8C978FFF8E978DFF8D968CFF8A9389FF899288FF8B968CFF848F85FF
+ 808B81FF808B81FF7C877DFF768177FF788379FF7F8A80FF828D83FF828D83FF
+ 838E84FF859086FF879288FF8A958BFF8C978DFF8E998FFF90988EFF8F978DFF
+ 8D958BFF8D958BFF8F988EFF98A197FFA3ACA2FFABB4AAFFA7B2A8FFA8B3A9FF
+ A5B3A8FFA2B0A5FF9EACA1FF9CAA9FFF9BABA0FF9DADA2FFA3B1A6FFA5B3A8FF
+ A5B3A8FFA3B1A6FFA4B2A7FFA5B3A8FFA1AFA4FF9AA89DFF9DABA0FF9FADA2FF
+ A1AFA4FFA2B0A5FF9FADA2FF9DABA0FF9CAA9FFF9AAA9FFFA8BCB0FFB6CCC0FF
+ C4DACEFFC6DCD0FFC0D5CCFFB8CDC4FFAFC4BBFFA8BDB4FFACC1B9FFABC0B8FF
+ AABEB9FFA8BCB7FF656C69FF626966FF676E6BFF737A77FF757E7BFF737C79FF
+ 7A8380FF87908DFF8F9A97FFA0ABA8FF9AA8A4FF8C9A96FF9DABA7FFC0CECAFF
+ BCCBC7FF9BAAA6FFA8B6B2FF9DABA7FF9EACA8FFAFBDB9FFBBC9C5FFB4C2BEFF
+ A7B5B1FFA0AEAAFFA4B2AEFFA7B5B1FFA5B3AFFFA0AEAAFF9EACA8FFA2B0ACFF
+ A4B2AEFFA2B0ACFFAFBDB9FFB0BEBAFFABB9B5FFA3B1ADFFA5B3AFFFACBAB6FF
+ A9B7B3FF9EACA8FF93A19DFF98A6A2FFA0AEAAFFA4B2AEFF9FADA9FF99A7A3FF
+ 9DABA7FFA5B3AFFF9CAAA6FF99A7A3FF97A5A1FF99A7A3FF9DABA7FF9DABA7FF
+ 9AA8A4FF96A4A0FF9BA9A5FF95A39FFF96A4A0FF97A5A1FF95A39FFF95A39FFF
+ 8B9995FF768480FF99A4A1FF929D9AFF8B9693FF85908DFF838E8BFF85908DFF
+ 899491FF8A9592FF8F9A97FF8C9794FF899491FF889390FF8B9693FF8E9996FF
+ 8F9A97FF909B98FF87928FFF87928FFF86918EFF85908DFF85908DFF85908DFF
+ 86918EFF86918EFF848F8CFF87928FFF87928FFF86918EFF8F9A97FFA3AEABFF
+ B6C1BEFFBDCBC7FFBDD0CDFFB9CECBFFBCD1CEFFC1D6D3FFC2D7D4FFC0D5D2FF
+ C2D7D4FFC8DDDAFFBFD4D1FFB6CBC8FFB0C5C2FFB7CCC9FFC1D6D3FFC8DDDAFF
+ CCE1DEFFD2E5E2FFDDECE8FF44524EFF74827EFF6F7D79FF788682FF808E8AFF
+ 8F9D99FF99A7A3FF8C9A96FF82908CFF7F8D89FF85938FFF879591FF84928EFF
+ 889692FF92A09CFF8A9995FF8B9A96FF8C9B97FF8E9D99FF909F9BFF92A19DFF
+ 93A29EFF94A39FFF909F9BFF8E9D99FF8D9C98FF909F9BFF96A5A1FF98A7A3FF
+ 94A39FFF8E9D99FF9EACA8FF9BA9A5FF9EACA8FFA5B3AFFFA6B4B0FF9FADA9FF
+ 96A4A0FF93A19DFF919F9BFF8B9995FF8B9995FF919F9BFF94A29EFF92A09CFF
+ 8F9D99FF8F9E9AFF7D8E8AFF9AAEA9FFB7CBC6FFBFD3CEFFBED2CDFFC0D4CFFF
+ C1D5D0FFBFD3CEFFC3D7D2FFC3D7D2FFBFD3CEFFAFC3BEFFB0C4BFFF738782FF
+ 9FB3AEFF9EAFABFF99A8A4FF96A4A0FF98A6A2FF9EACA8FFA1AFABFF9EACA8FF
+ 9CAAA6FF9DABA7FF9DABA7FF99A7A3FF92A09CFF8E9C98FF95A39FFFA1AFABFF
+ A7B5B1FFA6B4B0FFA5B3AFFFA2B0ACFF9FADA9FF9EACA8FF9FADA9FFA1AFABFF
+ A1AFABFFA0AEAAFF98A6A2FF9AA8A4FFA0AEAAFFA6B4B0FFA3B1ADFF99A7A3FF
+ 92A09CFF92A09CFF96A4A0FF97A5A1FF9AA8A4FF9DABA7FFA0AEAAFF9FADA9FF
+ 9AA8A4FF97A5A1FF97A5A1FF93A19DFF8E9C98FF8D9B97FF8D9B97FF8D9B97FF
+ 889692FF83918DFF7F8D8BFF7F8D8BFF899793FF889692FF697773FF5F6D69FF
+ 737F79FF87938DFF87928AFF89948CFF8D9890FF8F9A92FF929B91FF919A90FF
+ 8F988EFF8E978DFF8A958BFF869187FF838E84FF818C82FF7C877DFF79847AFF
+ 7C877DFF838E84FF818C82FF828D83FF859086FF879288FF8A958BFF8C978DFF
+ 8D988EFF8E998FFF949C92FF90988EFF899187FF848C82FF848D83FF8D968CFF
+ 9CA59BFFA6AFA5FFADB8AEFFAFBAB0FFAEBCB1FFADBBB0FFAAB8ADFFA7B5AAFF
+ A5B5AAFFA6B6ABFFA9B7ACFFAAB8ADFFA8B6ABFFA5B3A8FFA6B4A9FFA9B7ACFF
+ A7B5AAFFA2B0A5FF9FADA2FF9FADA2FF9FADA2FFA1AFA4FFA2B0A5FFA1AFA4FF
+ 9EACA1FF9AAA9FFFACC0B4FFB6CCC0FFC1D7CBFFC4DACEFFC2D7CEFFBDD2C9FF
+ B3C8BFFFA9BEB5FFA9BEB6FFA9BEB6FFA8BCB7FFA7BBB6FF787F7CFF6F7673FF
+ 6F7673FF787F7CFF77807DFF707976FF737C79FF7F8885FF7E8986FF85908DFF
+ 8B9995FF8F9D99FF93A19DFF9EACA8FFB1C0BCFFC2D1CDFFA3B1ADFFA2B0ACFF
+ ABB9B5FFB3C1BDFFA9B7B3FF98A6A2FF9EACA8FFB1BFBBFFA3B1ADFFA8B6B2FF
+ A8B6B2FFA0AEAAFF9BA9A5FF9CAAA6FF9FADA9FF9FADA9FFA5B3AFFFADBBB7FF
+ AAB8B4FFA0AEAAFFA1AFABFFAAB8B4FFA3B1ADFF919F9BFF92A09CFF95A39FFF
+ 9BA9A5FFA1AFABFF9EACA8FF98A6A2FF96A4A0FF9AA8A4FF9DABA7FF98A6A2FF
+ 94A29EFF97A5A1FF9CAAA6FF9EACA8FF9AA8A4FF95A39FFF97A5A1FF8F9D99FF
+ 96A4A0FF99A7A3FF92A09CFF9CAAA6FF98A6A2FF788682FF98A3A0FF98A3A0FF
+ 8D9895FF848F8CFF899491FF8C9794FF8B9693FF8D9895FF8E9996FF8C9794FF
+ 899491FF87928FFF889390FF8A9592FF8D9895FF8E9996FF8B9693FF899491FF
+ 87928FFF85908DFF85908DFF86918EFF889390FF8A9592FF929D9AFF96A19EFF
+ 97A29FFF98A3A0FFA0ABA8FFACB7B4FFB2BDBAFFB0BEBAFFB8CBC8FFB6CBC8FF
+ BACFCCFFBFD4D1FFC0D5D2FFBED3D0FFC1D6D3FFC7DCD9FFC6DBD8FFBFD4D1FF
+ BACFCCFFBBD0CDFFC1D6D3FFC7DCD9FFCBE0DDFFD0E3E0FFD5E4E0FF53615DFF
+ 62706CFF84928EFF7D8B87FF73817DFF92A09CFF96A4A0FF8C9A96FF82908CFF
+ 7D8B87FF808E8AFF7F8D89FF7D8B87FF84928EFF919F9BFF8A9995FF8B9A96FF
+ 8B9A96FF8C9B97FF8D9C98FF8E9D99FF8F9E9AFF8F9E9AFF909F9BFF8E9D99FF
+ 8D9C98FF8F9E9AFF97A6A2FF9DACA8FF9AA9A5FF93A29EFF99A7A3FF94A29EFF
+ 96A4A0FFA0AEAAFFA5B3AFFF9EACA8FF94A29EFF8E9C98FF95A39FFF909E9AFF
+ 8F9D99FF92A09CFF92A09CFF8F9D99FF909E9AFF92A19DFF839490FF9FB3AEFF
+ BACEC9FFC2D6D1FFC1D5D0FFC4D8D3FFC5D9D4FFC2D6D1FFC6DAD5FFC5D9D4FF
+ BFD3CEFFAEC2BDFFB0C4BFFF718580FF9BAFAAFF99AAA6FF99A8A4FF96A4A0FF
+ 96A4A0FF9DABA7FFA0AEAAFF9EACA8FF9CAAA6FF9EACA8FFA2B0ACFF9DABA7FF
+ 95A39FFF92A09CFF95A39FFF9CAAA6FFA0AEAAFFA1AFABFFA8B6B2FFA6B4B0FF
+ A2B0ACFF9FADA9FF9FADA9FFA0AEAAFFA1AFABFFA2B0ACFF8E9C98FF909E9AFF
+ 98A6A2FFA2B0ACFFA4B2AEFF9EACA8FF9AA8A4FF9BA9A5FF95A39FFF96A4A0FF
+ 97A5A1FF9AA8A4FF9CAAA6FF9EACA8FF9EACA8FF9DABA7FF92A09CFF92A09CFF
+ 8F9D99FF8C9A96FF8D9B97FF8F9D99FF8C9A96FF879591FF859391FF879593FF
+ 879591FF919F9BFF6F7D79FF606E6AFF75817BFF85918BFF859088FF88938BFF
+ 8B968EFF8E9991FF929B91FF929B91FF90998FFF8F988EFF8A958BFF89948AFF
+ 869187FF828D83FF7D887EFF7B867CFF808B81FF869187FF848F85FF869187FF
+ 89948AFF8C978DFF8E998FFF8E998FFF8D988EFF8D988EFF9DA59BFF99A197FF
+ 929A90FF8B9389FF879086FF8C958BFF959E94FF9CA59BFFA1ACA2FFA4AFA5FF
+ A6B4A9FFA6B4A9FFA5B3A8FFA3B1A6FFA1B1A6FFA2B2A7FFA8B6ABFFABB9AEFF
+ AAB8ADFFA8B6ABFFAAB8ADFFADBBB0FFAAB8ADFFA4B2A7FFA6B4A9FFA4B2A7FF
+ A2B0A5FFA4B2A7FFA7B5AAFFA7B5AAFFA2B0A5FF9BABA0FFACC0B4FFB6CCC0FF
+ C0D6CAFFC0D6CAFFBDD2C9FFBBD0C7FFB6CBC2FFB1C6BDFFAABFB7FFA9BEB6FF
+ A8BCB7FFA7BBB6FF636A67FF686F6CFF6D7471FF707774FF707976FF747D7AFF
+ 7A8380FF7E8784FF848F8CFF85908DFF8D9B97FF909E9AFF7A8884FF616F6BFF
+ 657470FF7D8C88FF717F7BFF64726EFF6C7A76FF909E9AFFADBBB7FFB1BFBBFF
+ ABB9B5FFAAB8B4FFA1AFABFFAAB8B4FFADBBB7FFA4B2AEFF99A7A3FF97A5A1FF
+ 9BA9A5FF9DABA7FF93A19DFFA5B3AFFFACBAB6FFA5B3AFFFA3B1ADFFA8B6B2FF
+ A0AEAAFF909E9AFF93A19DFF909E9AFF94A29EFF9EACA8FFA3B1ADFF9FADA9FF
+ 9AA8A4FF98A6A2FF9EACA8FF98A6A2FF94A29EFF96A4A0FF9CAAA6FF9EACA8FF
+ 9AA8A4FF95A39FFF99A7A3FF919F9BFF98A6A2FF99A7A3FF919F9BFF9CAAA6FF
+ 9AA8A4FF7C8A86FF848F8CFF909B98FF87928FFF7F8A87FF899491FF8A9592FF
+ 838E8BFF87928FFF8C9794FF8A9592FF889390FF86918EFF86918EFF87928FFF
+ 8A9592FF8C9794FF8E9996FF8B9693FF87928FFF848F8CFF838E8BFF848F8CFF
+ 86918EFF87928FFF95A09DFF97A29FFF97A29FFF99A4A1FFA4AFACFFB3BEBBFF
+ BCC7C4FFBAC8C4FFB4C7C4FFB1C6C3FFB5CAC7FFBCD1CEFFBED3D0FFBCD1CEFF
+ BED3D0FFC3D8D5FFC6DBD8FFC5DAD7FFC2D7D4FFC0D5D2FFC1D6D3FFC3D8D5FF
+ C5DAD7FFC6D9D6FFCAD9D5FF74827EFF33413DFF8D9B97FF7D8B87FF5C6A66FF
+ 899793FF92A09CFF899793FF82908CFF7F8D89FF7E8C88FF778581FF72807CFF
+ 7D8B87FF8F9D99FF8C9B97FF8C9B97FF8B9A96FF8B9A96FF8B9A96FF8A9995FF
+ 8A9995FF8A9995FF8B9A96FF8E9D99FF8E9D99FF8C9B97FF91A09CFF9CABA7FF
+ 9FAEAAFF9CABA7FF9BA9A5FF93A19DFF92A09CFF9DABA7FFA6B4B0FFA2B0ACFF
+ 96A4A0FF8D9B97FF98A6A2FF97A5A1FF98A6A2FF98A6A2FF92A09CFF8C9A96FF
+ 909E9AFF97A6A2FF90A19DFFA8BCB7FFBDD1CCFFC1D5D0FFBFD3CEFFC2D6D1FF
+ C4D8D3FFC2D6D1FFBDD1CCFFBCD0CBFFB9CDC8FFACC0BBFFB2C6C1FF788C87FF
+ A4B8B3FFA2B3AFFF9AA9A5FF96A4A0FF94A29EFF99A7A3FF9CAAA6FF9BA9A5FF
+ 9BA9A5FF9EACA8FFA4B2AEFF9FADA9FF9BA9A5FF9AA8A4FF9AA8A4FF9AA8A4FF
+ 9BA9A5FF9DABA7FFA8B6B2FFA6B4B0FFA3B1ADFFA0AEAAFF9EACA8FF9EACA8FF
+ A0AEAAFFA2B0ACFF98A6A2FF95A39FFF96A4A0FF9BA9A5FF9AA8A4FF94A29EFF
+ 909E9AFF919F9BFF94A29EFF94A29EFF94A29EFF94A29EFF97A5A1FF9BA9A5FF
+ A0AEAAFFA4B2AEFF96A4A0FF98A6A2FF95A39FFF8F9D99FF8E9C98FF909E9AFF
+ 8E9C98FF879591FF899795FF879593FF83918DFF909E9AFF798783FF5F6D69FF
+ 7A8680FF7F8B85FF818C84FF848F87FF88938BFF8B968EFF8F988EFF8F988EFF
+ 8E978DFF8D968CFF8B968CFF8D988EFF8A958BFF838E84FF7D887EFF7D887EFF
+ 848F85FF89948AFF879288FF889389FF8A958BFF8C978DFF8D988EFF8C978DFF
+ 8B968CFF8A958BFF939B91FF959D93FF969E94FF969E94FF959E94FF969F95FF
+ 99A298FF9BA49AFF9EA99FFFA1ACA2FFA4B2A7FFA6B4A9FFA5B3A8FFA5B3A8FF
+ A4B4A9FFA5B5AAFF9FADA2FFA3B1A6FFA6B4A9FFA6B4A9FFA8B6ABFFAAB8ADFF
+ A5B3A8FF9DABA0FFAAB8ADFFA7B5AAFFA5B3A8FFA6B4A9FFA8B6ABFFA6B4A9FF
+ A1AFA4FF9AAA9FFFB2C6BAFFBDD3C7FFC4DACEFFBDD3C7FFB3C8BFFFAFC4BBFF
+ B2C7BEFFB4C9C0FFABC0B8FFAABFB7FFA8BCB7FFA6BAB5FF5A615EFF676E6BFF
+ 6D7471FF6B726FFF6D7673FF79827FFF7E8784FF79827FFF9CA7A4FFA7B2AFFF
+ AAB8B4FF9DABA7FF84928EFF667470FF495854FF374642FF42504CFF2A3834FF
+ 263430FF4C5A56FF808E8AFF9DABA7FF9EACA8FF97A5A1FF9BA9A5FFA5B3AFFF
+ A9B7B3FFA2B0ACFF99A7A3FF97A5A1FF98A6A2FF98A6A2FF869490FF9AA8A4FF
+ A9B7B3FFAAB8B4FFA7B5B1FFA6B4B0FFA1AFABFF98A6A2FF8F9D99FF8A9894FF
+ 8E9C98FF9BA9A5FFA7B5B1FFA8B6B2FFA3B1ADFFA0AEAAFF9EACA8FF9AA8A4FF
+ 96A4A0FF97A5A1FF9BA9A5FF9DABA7FF9BA9A5FF98A6A2FF9DABA7FF99A7A3FF
+ 9AA8A4FF99A7A3FF94A29EFF96A4A0FF93A19DFF84928EFF6C7774FF86918EFF
+ 828D8AFF788380FF86918EFF848F8CFF77827FFF7E8986FF848F8CFF85908DFF
+ 86918EFF86918EFF86918EFF86918EFF899491FF8B9693FF8E9996FF8C9794FF
+ 889390FF848F8CFF828D8AFF828D8AFF838E8BFF838E8BFF9AA5A2FF98A3A0FF
+ 929D9AFF8F9A97FF98A3A0FFACB7B4FFBCC7C4FFC1CFCBFFB6C9C6FFB0C5C2FF
+ B2C7C4FFB9CECBFFBDD2CFFFBBD0CDFFB9CECBFFBACFCCFFBFD4D1FFC3D8D5FF
+ C3D8D5FFBDD2CFFFBACFCCFFBBD0CDFFBBD0CDFFBBCECBFFC7D6D2FF9DABA7FF
+ 15231FFF7C8A86FF808E8AFF54625EFF7F8D89FF93A19DFF85938FFF818F8BFF
+ 7E8C88FF7C8A86FF72807CFF6C7A76FF788682FF8B9995FF8B9A96FF8B9A96FF
+ 8B9A96FF8A9995FF899894FF899894FF889793FF889793FF869591FF8D9C98FF
+ 8E9D99FF899894FF8C9B97FF98A7A3FF9FAEAAFF9EADA9FFA0AEAAFF98A6A2FF
+ 96A4A0FFA0AEAAFFA8B6B2FFA5B3AFFF9BA9A5FF94A29EFF99A7A3FF9AA8A4FF
+ 9DABA7FF9DABA7FF95A39FFF8E9C98FF93A19DFF9BAAA6FF9AABA7FFAEC2BDFF
+ BED2CDFFBED2CDFFBCD0CBFFC0D4CFFFC2D6D1FFC0D4CFFFC1D5D0FFBED2CDFF
+ B9CDC8FFABBFBAFFB1C5C0FF768A85FFA0B4AFFF9DAEAAFF9DACA8FF96A4A0FF
+ 92A09CFF94A29EFF97A5A1FF97A5A1FF99A7A3FF9DABA7FFA1AFABFF9DABA7FF
+ 9DABA7FFA0AEAAFF9FADA9FF9CAAA6FF9BA9A5FF9EACA8FFA4B2AEFFA4B2AEFF
+ A3B1ADFFA0AEAAFF9DABA7FF9DABA7FF9FADA9FFA1AFABFFA5B3AFFF9FADA9FF
+ 9BA9A5FF9CAAA6FF9BA9A5FF95A39FFF92A09CFF93A19DFF919F9BFF92A09CFF
+ 919F9BFF919F9BFF92A09CFF96A4A0FF9CAAA6FFA1AFABFF9AA8A4FF9FADA9FF
+ 9BA9A5FF909E9AFF8C9A96FF8E9C98FF8B9995FF82908CFF879593FF818F8DFF
+ 818F8BFF899793FF84928EFF566460FF7F8B85FF7A8680FF808B83FF828D85FF
+ 869189FF89948CFF8D968CFF8D968CFF8B948AFF8A9389FF8D988EFF919C92FF
+ 8F9A90FF848F85FF7C877DFF7F8A80FF869187FF8B968CFF879288FF879288FF
+ 89948AFF8A958BFF8A958BFF8B968CFF8A958BFF8A958BFF7F877DFF878F85FF
+ 91998FFF9AA298FF9FA89EFFA2ABA1FFA4ADA3FFA6AFA5FF9FAAA0FFA2ADA3FF
+ A3B1A6FFA4B2A7FFA4B2A7FFA4B2A7FFA3B3A8FFA5B5AAFF9BA99EFFA1AFA4FF
+ A5B3A8FFA6B4A9FFA9B7ACFFAAB8ADFFA4B2A7FF9CAA9FFFA3B1A6FFA2B0A5FF
+ A2B0A5FFA3B1A6FFA3B1A6FFA1AFA4FF9DABA0FF98A89DFFBCD0C4FFC5DBCFFF
+ CAE0D4FFBED4C8FFAEC3BAFFA8BDB4FFAABFB6FFAEC3BAFFABC0B8FFAABFB7FF
+ A8BCB7FFA6BAB5FF6A716EFF6B726FFF6A716EFF6B726FFF727B78FF7C8582FF
+ 7C8582FF757E7BFF909B98FFA9B4B1FFB9C7C3FFBAC8C4FFB8C6C2FFB4C2BEFF
+ 9DACA8FF82918DFF73817DFF6F7D79FF5F6D69FF45534FFF35433FFF43514DFF
+ 6E7C78FF93A19DFF93A19DFF98A6A2FF9BA9A5FF9AA8A4FF9BA9A5FF9BA9A5FF
+ 96A4A0FF8E9C98FF85938FFF92A09CFFA0AEAAFFA8B6B2FFA5B3AFFF9EACA8FF
+ 98A6A2FF95A39FFF879591FF85938FFF8B9995FF98A6A2FFA3B1ADFFA5B3AFFF
+ A4B2AEFFA5B3AFFF9DABA7FF9CAAA6FF9AA8A4FF99A7A3FF9AA8A4FF9BA9A5FF
+ 9CAAA6FF9CAAA6FF9AA8A4FF9BA9A5FF96A4A0FF96A4A0FF99A7A3FF93A19DFF
+ 8E9C98FF95A39FFF56615EFF7A8582FF788380FF6C7774FF7A8582FF75807DFF
+ 66716EFF717C79FF75807DFF798481FF7F8A87FF828D8AFF838E8BFF85908DFF
+ 889390FF8B9693FF8C9794FF8A9592FF889390FF85908DFF838E8BFF828D8AFF
+ 828D8AFF828D8AFF97A29FFF97A29FFF939E9BFF8F9A97FF95A09DFFA5B0ADFF
+ B5C0BDFFBAC8C4FFBED1CEFFB5CAC7FFB2C7C4FFB9CECBFFBED3D0FFBBD0CDFF
+ B4C9C6FFB0C5C2FFB4C9C6FFBACFCCFFBBD0CDFFB4C9C6FFAFC4C1FFB2C7C4FF
+ B4C9C6FFB3C6C3FFBDCCC8FFB5C3BFFF1A2824FF586662FF8C9A96FF5D6B67FF
+ 6D7B77FF889692FF83918DFF7C8A86FF788682FF788682FF72807CFF6D7B77FF
+ 778581FF879591FF889793FF889793FF899894FF899894FF8A9995FF8A9995FF
+ 8B9A96FF8B9A96FF879692FF909F9BFF91A09CFF8B9A96FF8F9E9AFF9BAAA6FF
+ 9FAEAAFF98A7A3FFA0AEAAFF9DABA7FF9EACA8FFA3B1ADFFA4B2AEFF9FADA9FF
+ 9DABA7FF9EACA8FF98A6A2FF98A6A2FF9AA8A4FF9DABA7FF9AA8A4FF95A39FFF
+ 97A5A1FF9CABA7FF9AABA7FFADC1BCFFBDD1CCFFBED2CDFFBCD0CBFFC0D4CFFF
+ C2D6D1FFBFD3CEFFC8DCD7FFC3D7D2FFBBCFCAFFABBFBAFFAEC2BDFF70847FFF
+ 97ABA6FF91A29EFFA0AFABFF97A5A1FF909E9AFF8F9D99FF919F9BFF92A09CFF
+ 96A4A0FF9CAAA6FFA2B0ACFF9DABA7FF9DABA7FFA1AFABFFA0AEAAFF9AA8A4FF
+ 9AA8A4FF9FADA9FF9FADA9FFA1AFABFFA2B0ACFFA0AEAAFF9DABA7FF9BA9A5FF
+ 9CAAA6FF9FADA9FFA8B6B2FFA1AFABFF9DABA7FF9FADA9FF9FADA9FF9AA8A4FF
+ 96A4A0FF96A4A0FF8D9B97FF8F9D99FF919F9BFF919F9BFF8F9D99FF8E9C98FF
+ 919F9BFF93A19DFF94A29EFF9BA9A5FF99A7A3FF8D9B97FF889692FF8D9B97FF
+ 8A9894FF818F8BFF83918FFF7C8A88FF889692FF85938FFF8F9D99FF4B5955FF
+ 88948EFF7D8983FF828D85FF848F87FF88938BFF8A958DFF8E978DFF8D968CFF
+ 8C958BFF8A9389FF8F9A90FF95A096FF939E94FF859086FF7C877DFF808B81FF
+ 879288FF8C978DFF889389FF889389FF89948AFF8B968CFF8D988EFF8F9A90FF
+ 919C92FF929D93FF7E867CFF858D83FF90988EFF9AA298FFA0A99FFFA5AEA4FF
+ A9B2A8FFADB6ACFF99A49AFF9AA59BFF99A79CFF97A59AFF95A398FF95A398FF
+ 94A499FF97A79CFF9DABA0FFA1AFA4FFA3B1A6FFA4B2A7FFA7B5AAFFAAB8ADFF
+ A6B4A9FF9FADA2FF99A79CFF9CAA9FFF9FADA2FFA0AEA3FF9EACA1FF9DABA0FF
+ 9CAA9FFF9BABA0FFBFD3C7FFC6DCD0FFCAE0D4FFC0D6CAFFB3C8BFFFADC2B9FF
+ AABFB6FFA9BEB5FFA9BEB6FFA8BDB5FFA6BAB5FFA5B9B4FF717875FF646B68FF
+ 5D6461FF686F6CFF787F7CFF7D8683FF7C8582FF79827FFF7F8885FF939E9BFF
+ ADB8B5FFB8C6C2FFBAC8C4FFB8C6C2FFB5C3BFFFB2C1BDFFA2B0ACFF9AA8A4FF
+ 8E9C98FF869490FF85938FFF808E8AFF6C7A76FF576561FF8D9B97FF8D9B97FF
+ 8D9B97FF92A09CFF9CAAA6FFA0AEAAFF95A39FFF869490FF8B9995FF8E9C98FF
+ 98A6A2FFA1AFABFF9FADA9FF93A19DFF8B9995FF8A9894FF82908CFF83918DFF
+ 8B9995FF95A39FFF9AA8A4FF9AA8A4FF9DABA7FFA2B0ACFF9CAAA6FF9DABA7FF
+ 9CAAA6FF9BA9A5FF99A7A3FF9AA8A4FF9CAAA6FF9FADA9FF92A09CFF98A6A2FF
+ 919F9BFF93A19DFF9FADA9FF93A19DFF8E9C98FFA6B4B0FF424D4AFF6C7774FF
+ 6A7572FF5B6663FF697471FF626D6AFF535E5BFF616C69FF67726FFF6E7976FF
+ 76817EFF7C8784FF7F8A87FF818C89FF85908DFF889390FF8A9592FF899491FF
+ 87928FFF86918EFF848F8CFF848F8CFF838E8BFF838E8BFF85908DFF8D9895FF
+ 949F9CFF97A29FFF9EA9A6FFABB6B3FFB5C0BDFFB7C5C1FFC6D9D6FFB9CECBFF
+ B4C9C6FFB9CECBFFBFD4D1FFBBD0CDFFB0C5C2FFA9BEBBFFACC1BEFFB3C8C5FF
+ B4C9C6FFABC0BDFFA6BBB8FFABC0BDFFAFC4C1FFB1C4C1FFAAB9B5FFB5C3BFFF
+ 273531FF374541FF94A29EFF667470FF586662FF72807CFF82908CFF778581FF
+ 717F7BFF74827EFF74827EFF72807CFF788682FF83918DFF859490FF869591FF
+ 879692FF899894FF8A9995FF8C9B97FF8D9C98FF8E9D99FF8D9C98FF95A4A0FF
+ 95A4A0FF909F9BFF96A5A1FFA1B0ACFF9FAEAAFF93A29EFF9BA9A5FF9EACA8FF
+ A3B1ADFFA4B2AEFF9DABA7FF97A5A1FF9AA8A4FFA3B1ADFF97A5A1FF93A19DFF
+ 94A29EFF9BA9A5FF9EACA8FF9CAAA6FF9BA9A5FF9BAAA6FF95A6A2FFA9BDB8FF
+ BDCECAFFBED2CDFFC0D1CDFFC2D6D1FFC5D6D2FFBFD3CEFFC4D5D1FFBDD1CCFF
+ B8C9C5FFA7BBB6FFAFC0BCFF718580FF9BACA8FF94A5A1FFA2B1ADFF98A6A2FF
+ 8E9C98FF8C9A96FF8D9B97FF8F9D99FF95A39FFF9CAAA6FFA6B4B0FFA0AEAAFF
+ 9EACA8FFA0AEAAFF9DABA7FF96A4A0FF96A4A0FF9DABA7FF9BA9A5FF9EACA8FF
+ A1AFABFFA0AEAAFF9CAAA6FF9AA8A4FF9BA9A5FF9DABA7FFA7B5B1FF9FADA9FF
+ 9BA9A5FF9BA9A5FF98A6A2FF909E9AFF899793FF879591FF899793FF8D9B97FF
+ 92A09CFF92A09CFF8D9B97FF899793FF879591FF879591FF899793FF93A19DFF
+ 93A19DFF889692FF869490FF8E9C98FF8D9B97FF85938FFF81908CFF7C8B87FF
+ 92A09CFF869490FF97A5A1FF45534FFF8F9B95FF84908AFF859088FF87928AFF
+ 8A958DFF8D9890FF909891FF8F988EFF8D958EFF8C958BFF919C92FF98A399FF
+ 95A096FF869187FF7C877DFF808B81FF889389FF8C978DFF8B968CFF8C978DFF
+ 8C978DFF8E998FFF929D93FF96A197FF9AA59BFF9DA89EFF8B948AFF8F988EFF
+ 959D93FF98A197FF9CA59BFFA1AAA0FFA7B0A6FFABB4AAFFAEB9AFFFAEB9AFFF
+ AAB8ADFFA6B4A9FFA2B0A5FFA1AFA4FFA2B0A5FFA4B2A7FF99A79CFF9CAA9FFF
+ 9CAA9FFF9BA99EFF9EACA1FFA3B1A6FFA2B0A5FF9DABA0FF94A297FF99A79CFF
+ 9EACA1FFA0AEA3FF9EACA1FF9DABA0FF9FADA2FFA0B0A5FFBCCFC6FFC0D8CEFF
+ C6DBD2FFC0D8CEFFBCD1C8FFB5CDC3FFAFC4BCFFA6BDB5FFA6BBB3FFA3BAB2FF
+ A4B8B3FFA2B8B3FF707573FF656A68FF6B706EFF666D6AFF737A77FF858C89FF
+ 7B827FFF79827FFF7D8683FF899491FFA6B1AEFFC0CBC8FFC5D0CDFFB9C7C3FF
+ B6C4C0FFBDCBC7FFB0BEBAFF9BA9A5FF97A5A1FFA1AFABFFA8B6B2FFADBBB7FF
+ A2B0ACFF899793FFB5C3BFFFA6B4B0FF909E9AFF82908CFF879591FF96A4A0FF
+ 9FADA9FF9FADA9FF909E9AFF9AA8A4FF99A7A3FF98A6A2FF9BA9A5FF909E9AFF
+ 85938FFF8A9894FF83918DFF768480FF8A9894FF9EACA8FF97A5A1FF9BA9A5FF
+ A6B4B0FF9EACA8FF9EACA8FF9DABA7FFA0AEAAFFA2B0ACFF9CAAA6FF94A29EFF
+ 99A7A3FFA4B2AEFF9EACA8FFA1AFABFF9EACA8FF96A4A0FF93A19DFF98A6A2FF
+ 9FADA9FFA1AFABFF4A5552FF3C4744FF67726FFF596461FF485350FF3C4744FF
+ 4E5956FF55605DFF535E5BFF5B6663FF697471FF77827FFF818C89FF85908DFF
+ 86918EFF86918EFF879591FF84928EFF808E8AFF7E8C88FF808E8AFF869490FF
+ 8D9B97FF92A09CFF8D9B97FF7D8B87FF8C9A96FF889692FF92A09CFFA8B6B2FF
+ A2B0ACFFB5C4C0FFB0C1BEFFBFD2CFFFB8CBC8FFBACDCAFFBCCFCCFFBACDCAFF
+ BBCECBFFA3B6B3FFA6B9B6FFA4B7B4FFA4B7B4FFA2B5B2FF9BAEABFF92A5A2FF
+ 90A3A0FF96A7A4FF9CABA7FFADBBB7FF3F4D49FF3F4D49FF8B9995FF798783FF
+ 5E6C68FF63716DFF7B8985FF788682FF74827EFF6F7D79FF6E7C78FF73817DFF
+ 7D8B87FF85938FFF82918DFF839490FF859692FF859692FF899A96FF8E9F9BFF
+ 8E9F9BFF899A96FF8FA09CFF8FA09CFF90A19DFF91A29EFF94A5A1FF9AABA7FF
+ A0B1ADFFA7B6B2FFA2B0ACFF9DABA7FFA4B2AEFFA5B3AFFF9CAAA6FF9EACA8FF
+ A4B2AEFF9FADA9FF9DABA7FF96A4A0FF93A19DFF96A4A0FF98A6A2FF93A19DFF
+ 8F9D99FF8D9B97FFA8B7B3FFADBEBAFFB8C7C3FFBCCDC9FFBFCECAFFBFD0CCFF
+ C4D3CFFFC6D7D3FFBECDC9FFC4D5D1FFC0CFCBFFAFC0BCFFBAC9C5FF788985FF
+ A6B5B1FF91A09CFF9EACA8FFA0AEAAFF9DABA7FF96A4A0FF93A19DFF96A4A0FF
+ 98A6A2FF96A4A0FF9CAAA6FF99A7A3FF99A7A3FF9CAAA6FF9CAAA6FF98A6A2FF
+ 99A7A3FF9DABA7FF9FADA9FF96A4A0FF9CAAA6FFA4B2AEFF9DABA7FF9BA9A5FF
+ 9FADA9FF9BA9A5FF93A19DFF96A4A0FF9AA8A4FF9BA9A5FF99A7A3FF94A29EFF
+ 8F9D99FF8C9A96FF93A19BFF92A09AFF95A39DFF95A39DFF86948EFF798781FF
+ 7F8D87FF919F99FF8D9B95FF7F8D87FF77857FFF7F8D87FF8B9993FF8D9B95FF
+ 87958FFF83918BFF809089FF889891FF8A9892FF96A49EFF8F9D97FF55635DFF
+ 77837DFF7F8B85FF8B958FFF88928CFF86908AFF88928CFF8D948FFF8E968FFF
+ 8C938EFF8A928BFF879288FF8C978DFF8C978DFF848F85FF818C82FF869187FF
+ 8E998FFF919C92FF8F9A90FF8F9A90FF909B91FF909B91FF929D93FF949F95FF
+ 96A197FF97A298FF95A096FF949F95FF9BA49AFF97A298FF929D93FF9FAAA0FF
+ B0BBB1FFAFBAB0FFAFBAB0FFA9B4AAFFA1ACA2FF9FAAA0FFA1ACA2FFA4AFA5FF
+ A5B0A6FFA2B0A5FFA5B3A8FFA4B2A7FFA2B0A5FFA3B1A6FFAAB8ADFFAEBCB1FF
+ A7B5AAFF9BA99EFF99A79CFFA3B1A6FF9BA99EFF8E9C91FF8E9C91FF909E93FF
+ 97A59AFFA4B3ABFFBACFC7FFBED6CEFFC2D9D1FFBCD4CCFFB7CEC6FFAFC7BFFF
+ A5BBB6FF9BB2ADFF9FB5B0FF9DB4AFFF9CB2ADFF9AB1ACFF686D6BFF666B69FF
+ 6F7472FF646967FF6B726FFF828986FF7E8582FF818885FF7E8784FF89928FFF
+ A1ACA9FFBDC8C5FFC6D1CEFFBFCAC7FFB9C7C3FFBDCBC7FFB5C3BFFFA1AFABFF
+ 9BA9A5FFA0AEAAFFA4B2AEFFABB9B5FFA6B4B0FF94A29EFFADBBB7FFABB9B5FF
+ A4B2AEFF9AA8A4FF94A29EFF92A09CFF8D9B97FF869490FF92A09CFF9DABA7FF
+ A5B3AFFFAAB8B4FFA6B4B0FF92A09CFF879591FF8E9C98FF96A4A0FF869490FF
+ 8F9D99FF99A7A3FF8F9D99FF919F9BFF9CAAA6FF96A4A0FF9DABA7FF9CAAA6FF
+ 9EACA8FFA2B0ACFF9FADA9FF98A6A2FF99A7A3FF9FADA9FF99A7A3FF9CAAA6FF
+ 9AA8A4FF93A19DFF919F9BFF96A4A0FF9CAAA6FF9DABA7FF4C5754FF27322FFF
+ 424D4AFF414C49FF4A5552FF4A5552FF505B58FF45504DFF56615EFF5F6A67FF
+ 6E7976FF7D8885FF87928FFF8B9693FF8A9592FF889390FF869490FF83918DFF
+ 808E8AFF7E8C88FF7F8D89FF83918DFF899793FF8C9A96FF919F9BFF818F8BFF
+ 8A9894FF889692FF9BA9A5FFB8C6C2FFB2C0BCFFBAC9C5FFC5D6D3FFC4D7D4FF
+ B5C8C5FFBFD2CFFFC3D6D3FFB5C8C5FFACBFBCFF93A6A3FF899C99FF879A97FF
+ 879A97FF859895FF798C89FF697C79FF5F726FFF5F706DFF576662FF9EACA8FF
+ 54625EFF3D4B47FF84928EFF8F9D99FF7E8C88FF6E7C78FF7A8884FF798783FF
+ 768480FF73817DFF73817DFF788682FF82908CFF889793FF81908CFF849591FF
+ 869793FF839490FF839490FF869793FF869793FF82938FFF899A96FF899A96FF
+ 899A96FF8A9B97FF8FA09CFF98A9A5FFA0B1ADFFA6B7B3FFA5B3AFFFA0AEAAFF
+ A6B4B0FFA7B5B1FF9CAAA6FF9DABA7FFA2B0ACFF9CAAA6FFA0AEAAFF9BA9A5FF
+ 99A7A3FF9CAAA6FF9DABA7FF98A6A2FF96A4A0FF97A5A1FFA6B5B1FFACBBB7FF
+ B5C4C0FFBCCBC7FFC1D0CCFFC3D2CEFFC4D3CFFFC5D4D0FFBFCECAFFC5D4D0FF
+ BECDC9FFADBCB8FFB1C0BCFF758480FFA2B1ADFF94A39FFF9AA8A4FF9BA9A5FF
+ 99A7A3FF95A39FFF95A39FFF99A7A3FF98A6A2FF94A29EFF9FADA9FF9FADA9FF
+ A2B0ACFFA3B1ADFF9EACA8FF97A5A1FF98A6A2FF9EACA8FFA2B0ACFF9AA8A4FF
+ A2B0ACFFAAB8B4FFA2B0ACFF9EACA8FF9FADA9FF99A7A3FF97A5A1FF93A19DFF
+ 909E9AFF909E9AFF93A19DFF93A19DFF909E9AFF8C9A96FF8E9C96FF889690FF
+ 818F89FF7A8882FF717F79FF6A7872FF6D7B75FF74827CFF82908AFF7F8D87FF
+ 7D8B85FF7F8D87FF83918BFF87958FFF87958FFF85938DFF8C9C95FF91A19AFF
+ 8D9B95FF95A39DFF8B9993FF53615BFF77837DFF818D87FF8B958FFF89938DFF
+ 87918BFF88928CFF8D948FFF8F9691FF8D948FFF8B938CFF8A958DFF8E998FFF
+ 8C978DFF859086FF838E84FF889389FF8E998FFF909B91FF8F9A90FF8F9A90FF
+ 8E998FFF8E998FFF8E998FFF8F9A90FF909B91FF919C92FF939E94FF919C92FF
+ 98A399FF99A49AFF95A096FFA0ABA1FFABB6ACFFA6B1A7FFA9B4AAFFA7B2A8FF
+ A5B0A6FFA4AFA5FFA4AFA5FFA3AEA4FFA1ACA2FF9FAAA0FFA0AEA3FFA0AEA3FF
+ 9EACA1FFA1AFA4FFAAB8ADFFB2C0B5FFADBBB0FFA4B2A7FF9CAA9FFFA0AEA3FF
+ 97A59AFF8D9B90FF8B998EFF859388FF869489FF92A199FFAFC4BCFFB6CDC8FF
+ BCD3CEFFBAD1CCFFB4CBC6FFACC3BEFFA0B7B2FF96ADA8FF98AFAAFF98AFAAFF
+ 97AEA9FF97AEA9FF616664FF696E6CFF747977FF606563FF616865FF7D8481FF
+ 7E8582FF808784FF77807DFF7D8683FF919C99FFAFBAB7FFBFCAC7FFBCC7C4FF
+ B4C2BEFFB4C2BEFFB7C5C1FFA5B3AFFF9DABA7FF9DABA7FF9BA9A5FFA3B1ADFF
+ A7B5B1FF9DABA7FF99A7A3FFA3B1ADFFAAB8B4FFA7B5B1FFA0AEAAFF99A7A3FF
+ 919F9BFF899793FF7D8B87FF818F8BFF909E9AFF9DABA7FF98A6A2FF879591FF
+ 85938FFF93A19DFF9BA9A5FF8E9C98FF909E9AFF94A29EFF8D9B97FF92A09CFF
+ 9DABA7FF9DABA7FF9BA9A5FF99A7A3FF9CAAA6FFA3B1ADFFA6B4B0FFA2B0ACFF
+ 9DABA7FF9CAAA6FF97A5A1FF9AA8A4FF99A7A3FF93A19DFF919F9BFF96A4A0FF
+ 99A7A3FF99A7A3FF55605DFF25302DFF384340FF3E4946FF57625FFF606B68FF
+ 646F6CFF535E5BFF66716EFF6E7976FF7B8683FF86918EFF8D9895FF8D9895FF
+ 899491FF85908DFF85938FFF83918DFF808E8AFF7E8C88FF7D8B87FF7F8D89FF
+ 818F8BFF83918DFF899793FF7D8B87FF7F8D89FF7D8B87FF95A39FFFB9C7C3FF
+ BAC8C4FFBAC9C5FFC0D1CEFFBFD2CFFFB3C6C3FFBBCECBFFB5C8C5FFA0B3B0FF
+ A0B3B0FF97AAA7FF6D807DFF637673FF586B68FF516461FF495C59FF3E514EFF
+ 394C49FF3B4C49FF354440FF889692FF576561FF394743FF7E8C88FF8D9B97FF
+ 7D8B87FF62706CFF75837FFF72807CFF6F7D79FF6E7C78FF717F7BFF768480FF
+ 7B8985FF7E8D89FF7B8A86FF81928EFF869793FF839490FF81928EFF849591FF
+ 869793FF859692FF889995FF879894FF869793FF889995FF8FA09CFF98A9A5FF
+ A2B3AFFFA7B8B4FFACBAB6FFA7B5B1FFADBBB7FFADBBB7FFA1AFABFFA0AEAAFF
+ A4B2AEFF9EACA8FFA1AFABFF9FADA9FFA0AEAAFFA3B1ADFFA2B0ACFF9EACA8FF
+ 9FADA9FFA4B2AEFFA6B5B1FFAAB9B5FFB0BFBBFFB9C8C4FFC0CFCBFFC4D3CFFF
+ C4D3CFFFC2D1CDFFC1D0CCFFC4D3CFFFBCCBC7FFAAB9B5FFA8B7B3FF73827EFF
+ 9BAAA6FF98A7A3FF94A29EFF96A4A0FF95A39FFF94A29EFF97A5A1FF9BA9A5FF
+ 97A5A1FF909E9AFF9FADA9FFA2B0ACFFA6B4B0FFA7B5B1FF9FADA9FF95A39FFF
+ 95A39FFF9AA8A4FF9BA9A5FF95A39FFFA0AEAAFFAAB8B4FFA3B1ADFF9EACA8FF
+ 9DABA7FF96A4A0FF9DABA7FF94A29EFF8A9894FF889692FF8C9A96FF8F9D99FF
+ 8D9B97FF899793FF93A19BFF899791FF788680FF6A7872FF67756FFF6B7973FF
+ 6C7A74FF687670FF6B7973FF798781FF808E88FF7E8C86FF808E88FF8B9993FF
+ 93A19BFF92A09AFF93A39CFF94A49DFF8D9B95FF919F99FF87958FFF515F59FF
+ 79857FFF85918BFF8B958FFF89938DFF89938DFF8A948EFF8E9590FF8F9691FF
+ 8F9691FF8D958EFF8D9890FF909B91FF8D988EFF879288FF859086FF8A958BFF
+ 8E998FFF8E998FFF8E998FFF8D988EFF8C978DFF8B968CFF8B968CFF8B968CFF
+ 8B968CFF8B968CFF939E94FF919C92FF99A49AFF9DA89EFF9BA69CFFA5B0A6FF
+ ACB7ADFFA1ACA2FFA3AEA4FFA6B1A7FFA9B4AAFFA9B4AAFFA6B1A7FFA2ADA3FF
+ 9FAAA0FF9DA89EFF9FADA2FF9FADA2FF9DABA0FF9FADA2FFA7B5AAFFB0BEB3FF
+ AEBCB1FFA6B4A9FF9EACA1FF9DABA0FF93A196FF8F9D92FF8F9D92FF839186FF
+ 808E83FF8E9D95FFA8BDB5FFB2C8C3FFBDD3CEFFBED4CFFFB9CFCAFFB2C8C3FF
+ A7BDB8FF9DB3AEFF97ADA8FF96ACA7FF96ACA7FF96ACA7FF5B605EFF696E6CFF
+ 767B79FF5E6361FF5E6562FF7D8481FF7C8380FF787F7CFF727B78FF727B78FF
+ 808B88FFA0ABA8FFB6C1BEFFB7C2BFFFAEBCB8FFABB9B5FFB0BEBAFFA2B0ACFF
+ 9EACA8FF9BA9A5FF94A29EFF9AA8A4FFA2B0ACFF9DABA7FF95A39FFF9DABA7FF
+ A2B0ACFFA1AFABFFA1AFABFFA2B0ACFFA1AFABFF9EACA8FF93A19DFF879591FF
+ 8F9D99FF9EACA8FF98A6A2FF8E9C98FF95A39FFFA1AFABFF9BA9A5FF96A4A0FF
+ 96A4A0FF98A6A2FF97A5A1FF9AA8A4FFA0AEAAFFA1AFABFF99A7A3FF97A5A1FF
+ 9AA8A4FFA3B1ADFFABB9B5FFAAB8B4FFA0AEAAFF98A6A2FF9BA9A5FF9EACA8FF
+ 9CAAA6FF96A4A0FF94A29EFF97A5A1FF98A6A2FF95A39FFF626D6AFF37423FFF
+ 4F5A57FF55605DFF67726FFF6F7A77FF7D8885FF7A8582FF808B88FF838E8BFF
+ 889390FF8C9794FF8C9794FF889390FF838E8BFF808B88FF83918DFF82908CFF
+ 7F8D89FF7D8B87FF7C8A86FF7B8985FF7A8884FF7B8985FF7B8985FF7B8985FF
+ 798783FF72807CFF83918DFFA5B3AFFFB6C4C0FFBAC9C5FFB3C4C1FFB8CBC8FF
+ AFC2BFFFB8CBC8FFB4C7C4FF9CAFACFF8C9F9CFF708380FF394C49FF2D403DFF
+ 253835FF293C39FF304340FF314441FF2D403DFF2E3F3CFF3B4A46FF667470FF
+ 43514DFF404E4AFF93A19DFF909E9AFF7C8A86FF717F7BFF768480FF6D7B77FF
+ 667470FF697773FF72807CFF788682FF768480FF72807CFF71807CFF7B8C88FF
+ 859692FF859692FF849591FF899A96FF8E9F9BFF90A19DFF8D9E9AFF8C9D99FF
+ 8B9C98FF8E9F9BFF95A6A2FF9CADA9FFA1B2AEFFA5B4B0FFABB9B5FFA6B4B0FF
+ ADBBB7FFAEBCB8FFA3B1ADFFA2B0ACFFA5B3AFFF9FADA9FFA1AFABFFA1AFABFF
+ A4B2AEFFA7B5B1FFA4B2AEFFA1AFABFFA5B3AFFFADBBB7FFACBBB7FFABBAB6FF
+ ACBBB7FFB3C2BEFFBBCAC6FFC1D0CCFFC2D1CDFFC1D0CCFFC3D2CEFFC2D1CDFF
+ BECDC9FFAFBEBAFFA5B4B0FF778682FF95A4A0FF9BAAA6FF8F9D99FF919F9BFF
+ 92A09CFF93A19DFF97A5A1FF9AA8A4FF93A19DFF8A9894FF9CAAA6FF9CAAA6FF
+ 9FADA9FFA2B0ACFF9DABA7FF94A29EFF919F9BFF93A19DFF95A39FFF8F9D99FF
+ 9AA8A4FFA5B3AFFFA0AEAAFF9EACA8FF9FADA9FF9AA8A4FF9BA9A5FF94A29EFF
+ 8C9A96FF879591FF889692FF899793FF889692FF879591FF899791FF818F89FF
+ 6D7B75FF5A6862FF596761FF64726CFF67756FFF5F6D67FF64726CFF798781FF
+ 83918BFF7E8C86FF818F89FF919F99FF9AA8A2FF96A49EFF8F9F98FF91A19AFF
+ 8A9892FF909E98FF87958FFF52605AFF7C8882FF89958FFF8A948EFF8A948EFF
+ 8A948EFF8B958FFF8F9691FF909792FF909792FF8F9790FF919C94FF919C92FF
+ 8E998FFF889389FF889389FF8D988EFF8F9A90FF8C978DFF8D988EFF8C978DFF
+ 8B968CFF8A958BFF8A958BFF8A958BFF8A958BFF8B968CFF909B91FF8C978DFF
+ 929D93FF98A399FF99A49AFFA5B0A6FFABB6ACFF9FAAA0FF9EA99FFFA4AFA5FF
+ A9B4AAFFA9B4AAFFA5B0A6FFA0ABA1FF9FAAA0FFA0ABA1FFA3B1A6FFA1AFA4FF
+ 9DABA0FF9BA99EFFA0AEA3FFA7B5AAFFA5B3A8FF9EACA1FF9BA99EFF96A499FF
+ 8D9B90FF8E9C91FF919F94FF859388FF839186FF94A39BFFA6BBB3FFB0C6C1FF
+ BBD1CCFFBCD2CDFFB8CEC9FFB3C9C4FFACC2BDFFA5BBB6FF99AFAAFF98AEA9FF
+ 96ACA7FF94AAA5FF505553FF606563FF707573FF5D6260FF636A67FF818885FF
+ 7B827FFF727976FF767F7CFF6F7875FF788380FF96A19EFFB0BBB8FFB5C0BDFF
+ ADBBB7FFA9B7B3FFA8B6B2FFA0AEAAFFA2B0ACFFA0AEAAFF94A29EFF96A4A0FF
+ 9DABA7FF99A7A3FFA2B0ACFFA2B0ACFF9FADA9FF9BA9A5FF9EACA8FFA3B1ADFF
+ A4B2AEFFA0AEAAFFB6C4C0FF9CAAA6FF9CAAA6FFA6B4B0FF99A7A3FF8F9D99FF
+ 8F9D99FF8A9894FF9EACA8FFA3B1ADFFA3B1ADFFA2B0ACFFA4B2AEFFA1AFABFF
+ 9BA9A5FF9BA9A5FF9CAAA6FF99A7A3FF98A6A2FF9EACA8FFA6B4B0FFA5B3AFFF
+ 98A6A2FF8B9995FF9DABA7FF9FADA9FF9EACA8FF98A6A2FF96A4A0FF96A4A0FF
+ 93A19DFF8D9B97FF727D7AFF46514EFF5F6A67FF636E6BFF737E7BFF788380FF
+ 8A9592FF8D9895FF939E9BFF929D9AFF909B98FF8D9895FF899491FF87928FFF
+ 848F8CFF838E8BFF83918DFF82908CFF808E8AFF7E8C88FF7C8A86FF7A8884FF
+ 798783FF788682FF74827EFF808E8AFF7C8A86FF74827EFF75837FFF8B9995FF
+ ADBBB7FFBCCBC7FFB6C7C4FFB7CAC7FFA6B9B6FFACBFBCFFB1C4C1FF9BAEABFF
+ 728582FF374A47FF2F423FFF263936FF253835FF314441FF3E514EFF3E514EFF
+ 354845FF2F403DFF1E2D29FF394743FF313F3BFF3A4844FF93A19DFF899793FF
+ 7E8C88FF808E8AFF7B8985FF6E7C78FF64726EFF6C7A76FF7D8B87FF879591FF
+ 82908CFF778581FF6C7B77FF798884FF84938FFF869591FF879692FF8D9C98FF
+ 93A29EFF95A4A0FF93A29EFF92A19DFF92A19DFF95A4A0FF9AA9A5FF9DACA8FF
+ 9DACA8FF9CABA7FFA2B0ACFF9EACA8FFA7B5B1FFA9B7B3FFA0AEAAFFA0AEAAFF
+ A4B2AEFF9EACA8FFA1AFABFFA1AFABFFA3B1ADFFA6B4B0FFA4B2AEFFA1AFABFF
+ A6B4B0FFAEBCB8FFB3C2BEFFAEBDB9FFABBAB6FFADBCB8FFB5C4C0FFBDCCC8FF
+ C1D0CCFFC2D1CDFFC2D1CDFFBFCECAFFBFCECAFFB7C6C2FFA8B7B3FF808F8BFF
+ 909F9BFF9BAAA6FF899793FF8D9B97FF909E9AFF919F9BFF94A29EFF96A4A0FF
+ 8F9D99FF869490FF9AA8A4FF97A5A1FF98A6A2FF9EACA8FF9EACA8FF98A6A2FF
+ 93A19DFF92A09CFF9BA9A5FF92A09CFF99A7A3FFA1AFABFF9BA9A5FF99A7A3FF
+ 9CAAA6FF98A6A2FF879591FF8A9894FF8C9A96FF8A9894FF869490FF84928EFF
+ 869490FF899793FF899791FF85938DFF74827CFF5E6C66FF586660FF62706AFF
+ 66746EFF616F69FF6C7A74FF7C8A84FF84928CFF7F8D87FF83918BFF92A09AFF
+ 95A39DFF8C9A94FF91A19AFF94A49DFF8E9C96FF95A39DFF8C9A94FF55635DFF
+ 7C8882FF87938DFF89938DFF8A948EFF8B958FFF8C9690FF8E9590FF8F9691FF
+ 909792FF919992FF929D95FF919C92FF8C978DFF889389FF8A958BFF909B91FF
+ 8F9A90FF8A958BFF8C978DFF8C978DFF8B968CFF8B968CFF8C978DFF8D988EFF
+ 8E998FFF8E998FFF8C978DFF859086FF89948AFF8D988EFF909B91FF9FAAA0FF
+ A9B4AAFFA0ABA1FF9AA59BFF9EA99FFFA1ACA2FF9FAAA0FF9BA69CFF9AA59BFF
+ 9CA79DFF9FAAA0FFA0AEA3FF9FADA2FF9BA99EFF97A59AFF99A79CFF9DABA0FF
+ 9BA99EFF95A398FF9BA99EFF99A79CFF8F9D92FF8B998EFF8B998EFF818F84FF
+ 808E83FF909F97FFA9BEB6FFB2C8C3FFB8CEC9FFB4CAC5FFACC2BDFFA7BDB8FF
+ A2B8B3FF9EB4AFFF97ADA8FF96ACA7FF94AAA5FF92A8A3FF464B49FF535856FF
+ 686D6BFF5E6361FF666D6AFF818885FF7B827FFF777E7BFF767F7CFF6B7471FF
+ 6E7976FF899491FFA3AEABFFAAB5B2FFA6B4B0FFA4B2AEFFA4B2AEFF9FADA9FF
+ A5B3AFFFA5B3AFFF98A6A2FF97A5A1FF9BA9A5FF95A39FFF9EACA8FF9EACA8FF
+ 9CAAA6FF9BA9A5FF9EACA8FFA4B2AEFFA3B1ADFF9EACA8FFACBAB6FF94A29EFF
+ 9AA8A4FFA4B2AEFF95A39FFF8E9C98FF889692FF6F7D79FF94A29EFFA3B1ADFF
+ A3B1ADFFA2B0ACFFACBAB6FFAAB8B4FFA0AEAAFFA2B0ACFFA0AEAAFF9CAAA6FF
+ 97A5A1FF97A5A1FF9CAAA6FF9CAAA6FF909E9AFF808E8AFF9BA9A5FF9DABA7FF
+ 9CAAA6FF98A6A2FF96A4A0FF95A39FFF8F9D99FF879591FF889390FF505B58FF
+ 606B68FF697471FF808B88FF85908DFF909B98FF8C9794FF98A3A0FF95A09DFF
+ 919C99FF8D9895FF8B9693FF8C9794FF8E9996FF909B98FF889692FF869490FF
+ 84928EFF82908CFF808E8AFF7F8D89FF7E8C88FF7E8C88FF778581FF84928EFF
+ 7D8B87FF7C8A86FF768480FF7C8A86FFA3B1ADFFB5C4C0FFACBDBAFFAABDBAFF
+ 92A5A2FF8B9E9BFF849794FF778A87FF748784FF5E716EFF6A7D7AFF566966FF
+ 405350FF324542FF2B3E3BFF273A37FF293C39FF2F403DFF2D3C38FF566460FF
+ 5F6D69FF43514DFF85938FFF7E8C88FF788682FF72807CFF75837FFF6A7874FF
+ 62706CFF6C7A76FF7F8D89FF8C9A96FF899793FF818F8BFF6F7E7AFF798884FF
+ 83928EFF84938FFF869591FF8A9995FF8D9C98FF8C9B97FF92A19DFF8F9E9AFF
+ 8E9D99FF91A09CFF96A5A1FF99A8A4FF98A7A3FF95A4A0FFA1AFABFF9EACA8FF
+ A8B6B2FFACBAB6FFA4B2AEFFA5B3AFFFAAB8B4FFA4B2AEFFA5B3AFFFA2B0ACFF
+ A2B0ACFFA5B3AFFFA5B3AFFFA3B1ADFFA6B4B0FFACBAB6FFB2C1BDFFAFBEBAFF
+ ACBBB7FFADBCB8FFB2C1BDFFBAC9C5FFC1D0CCFFC5D4D0FFC1D0CCFFB8C7C3FF
+ BBCAC6FFBAC9C5FFA9B8B4FF899894FF8A9995FF99A8A4FF818F8BFF889692FF
+ 8E9C98FF8F9D99FF909E9AFF919F9BFF8E9C98FF879591FF9AA8A4FF98A6A2FF
+ 9AA8A4FFA0AEAAFFA0AEAAFF9BA9A5FF99A7A3FF9AA8A4FF9FADA9FF94A29EFF
+ 97A5A1FF9AA8A4FF8F9D99FF8B9995FF8C9A96FF879591FF73817DFF7E8C88FF
+ 899793FF8D9B97FF8A9894FF889692FF8B9995FF8F9D99FF8E9C96FF8A9892FF
+ 7D8B85FF6B7973FF606E68FF5F6D67FF606E68FF606E68FF67756FFF73817BFF
+ 7B8983FF7F8D87FF899791FF96A49EFF98A6A0FF919F99FF98A8A1FF9BABA4FF
+ 96A49EFF9CAAA4FF909E98FF56645EFF7A8680FF838F89FF86908AFF88928CFF
+ 8B958FFF8B958FFF8D948FFF8D948FFF909792FF929A93FF929D95FF8F9A90FF
+ 8A958BFF879288FF8C978DFF929D93FF909B91FF889389FF8E998FFF8E998FFF
+ 8D988EFF8D988EFF8E998FFF8F9A90FF909B91FF919C92FF909B91FF8A958BFF
+ 8C978DFF8D988EFF8E998FFF9EA99FFFACB7ADFFA7B2A8FF9AA59BFF9AA59BFF
+ 98A399FF95A096FF939E94FF929D93FF949F95FF97A298FF96A499FF98A69BFF
+ 96A499FF93A196FF95A398FF99A79CFF97A59AFF919F94FFA3B1A6FFAAB8ADFF
+ A2B0A5FF94A297FF8E9C91FF849287FF829085FF8B9A92FFB1C6BEFFB8CEC9FF
+ BBD1CCFFB2C8C3FFA5BBB6FF9DB3AEFF98AEA9FF95ABA6FF91A7A2FF91A7A2FF
+ 90A6A1FF90A6A1FF454A48FF505553FF676C6AFF616664FF636A67FF777E7BFF
+ 757C79FF7D8481FF767F7CFF69726FFF67726FFF7D8885FF96A19EFF9FAAA7FF
+ 9EACA8FF9EACA8FFA0AEAAFF9CAAA6FFA3B1ADFFA4B2AEFF98A6A2FF95A39FFF
+ 97A5A1FF909E9AFF919F9BFF97A5A1FF99A7A3FF97A5A1FF99A7A3FF9FADA9FF
+ A2B0ACFFA2B0ACFF9DABA7FF8F9D99FFA0AEAAFFAAB8B4FF9DABA7FFA6B4B0FF
+ A8B6B2FF879591FF8C9A96FF9FADA9FF9BA9A5FF96A4A0FFA7B5B1FFABB9B5FF
+ A5B3AFFFADBBB7FFA0AEAAFF9DABA7FF97A5A1FF94A29EFF99A7A3FF9EACA8FF
+ 96A4A0FF899793FF98A6A2FF9BA9A5FF9BA9A5FF99A7A3FF99A7A3FF99A7A3FF
+ 919F9BFF889692FF929D9AFF596461FF687370FF717C79FF85908DFF889390FF
+ 919C99FF8F9A97FF97A29FFF95A09DFF929D9AFF919C99FF919C99FF949F9CFF
+ 98A3A0FF9AA5A2FF8E9C98FF8D9B97FF8A9894FF889692FF879591FF879591FF
+ 889692FF899793FF85938FFF8A9894FF7D8B87FF8D9B97FF8D9B97FF84928EFF
+ A1AFABFFABBAB6FFA1B2AFFF8B9E9BFF718481FF7F928FFF849794FF7D908DFF
+ 97AAA7FFA6B9B6FF96A9A6FF839693FF657875FF415451FF243734FF1D302DFF
+ 304340FF4A5B58FF83928EFF9DABA7FF98A6A2FF566460FF889692FF83918DFF
+ 7F8D89FF707E7AFF6B7975FF667470FF64726EFF697773FF74827EFF7D8B87FF
+ 82908CFF83918DFF758480FF7D8C88FF83928EFF859490FF889793FF8B9A96FF
+ 8A9995FF869591FF8F9E9AFF8A9995FF869591FF889793FF91A09CFF98A7A3FF
+ 9BAAA6FF9BAAA6FFA0AEAAFF9EACA8FFA8B6B2FFADBBB7FFA6B4B0FFA6B4B0FF
+ ABB9B5FFA4B2AEFFADBBB7FFA7B5B1FFA4B2AEFFA6B4B0FFA8B6B2FFA6B4B0FF
+ A7B5B1FFABB9B5FFAAB9B5FFACBBB7FFAEBDB9FFB1C0BCFFB5C4C0FFBBCAC6FF
+ C2D1CDFFC7D6D2FFBFCECAFFB0BFBBFFB2C1BDFFB5C4C0FFA5B4B0FF8D9C98FF
+ 84938FFF96A5A1FF778581FF83918DFF8C9A96FF8D9B97FF8C9A96FF8E9C98FF
+ 8F9D99FF8E9C98FF99A7A3FF9CAAA6FFA2B0ACFFA4B2AEFF9DABA7FF96A4A0FF
+ 9AA8A4FFA4B2AEFFA1AFABFF96A4A0FF9AA8A4FF9CAAA6FF8E9C98FF85938FFF
+ 83918DFF7B8985FF768480FF7F8D89FF8B9995FF93A19DFF94A29EFF93A19DFF
+ 93A19DFF94A29EFF8C9A94FF84928CFF7B8983FF74827CFF6A7872FF606E68FF
+ 5B6963FF5C6A64FF697771FF707E78FF7C8A84FF889690FF92A09AFF98A6A0FF
+ 9BA9A3FF9CAAA4FF99A9A2FF9BABA4FF94A29CFF99A7A1FF8D9B95FF53615BFF
+ 78847EFF828E88FF848E88FF87918BFF8A948EFF8A948EFF8B928DFF8C938EFF
+ 8F9691FF929A93FF909B93FF8D988EFF879288FF859086FF8D988EFF949F95FF
+ 909B91FF879288FF929D93FF919C92FF909B91FF8F9A90FF8E998FFF8F9A90FF
+ 8F9A90FF909B91FF929D93FF8F9A90FF929D93FF919C92FF8D988EFF9BA69CFF
+ ABB6ACFFA8B3A9FFA2ADA3FF9EA99FFF99A49AFF96A197FF949F95FF929D93FF
+ 909B91FF8E998FFF909E93FF93A196FF94A297FF92A095FF93A196FF96A499FF
+ 94A297FF8E9C91FF9CAA9FFFB3C1B6FFB3C1B6FFA0AEA3FF98A69BFF94A297FF
+ 909E93FF93A29AFFADBFB8FFB6CAC5FFBCD0CBFFB3C7C2FFA6BAB5FF9DB1ACFF
+ 97ABA6FF93A7A2FF93A7A2FF93A7A2FF92A6A1FF92A6A1FF4B504EFF545957FF
+ 6B706EFF646967FF5E6562FF6A716EFF6D7471FF7F8683FF7C8582FF6D7673FF
+ 697471FF7D8885FF949F9CFF9EA9A6FF9FADA9FFA1AFABFF9DABA7FF98A6A2FF
+ 9EACA8FF9FADA9FF94A29EFF919F9BFF93A19DFF8B9995FF93A19DFF9AA8A4FF
+ 9CAAA6FF93A19DFF8D9B97FF919F9BFF9BA9A5FFA1AFABFF95A39FFF8C9A96FF
+ 9FADA9FFA4B2AEFF95A39FFFABB9B5FFB9C7C3FF9AA8A4FF95A39FFFA6B4B0FF
+ 99A7A3FF8D9B97FF9DABA7FFA2B0ACFF9DABA7FFA9B7B3FF9DABA7FF9CAAA6FF
+ 98A6A2FF95A39FFF9DABA7FFA7B5B1FFA4B2AEFF9AA8A4FF98A6A2FF9BA9A5FF
+ 9DABA7FF9CAAA6FF9EACA8FF9EACA8FF97A5A1FF8D9B97FF8B9693FF5C6764FF
+ 747F7CFF788380FF808B88FF7C8784FF8D9895FF95A09DFF97A29FFF97A29FFF
+ 96A19EFF96A19EFF97A29FFF99A4A1FF9BA6A3FF9DA8A5FF94A29EFF92A09CFF
+ 8F9D99FF8C9A96FF8C9A96FF8D9B97FF909E9AFF92A09CFF9AA8A4FF94A29EFF
+ 82908CFFA0AEAAFFABB9B5FF99A7A3FFABB9B5FFAAB9B5FFABBCB9FF708380FF
+ 546764FF96A9A6FFCCDFDCFFC0D3D0FFB5C8C5FFABBEBBFFA7BAB7FFABBEBBFF
+ A7BAB7FF8EA19EFF6D807DFF617471FF768986FF96A7A4FFAAB9B5FF9DABA7FF
+ 82908CFF3D4B47FF7A8884FF7B8985FF7B8985FF717F7BFF697773FF6B7975FF
+ 6D7B77FF6B7975FF6B7975FF707E7AFF798783FF82908CFF798884FF7F8E8AFF
+ 84938FFF879692FF8C9B97FF91A09CFF8E9D99FF889793FF8E9D99FF879692FF
+ 808F8BFF83928EFF8E9D99FF9AA9A5FFA2B1ADFFA5B4B0FF99A7A3FF97A5A1FF
+ A1AFABFFA6B4B0FF9EACA8FF9EACA8FFA2B0ACFF9BA9A5FFB3C1BDFFABB9B5FF
+ A5B3AFFFA8B6B2FFABB9B5FFA9B7B3FFA9B7B3FFAAB8B4FFA1B0ACFFA8B7B3FF
+ B0BFBBFFB6C5C1FFB9C8C4FFBDCCC8FFC4D3CFFFC9D8D4FFBDCCC8FFAAB9B5FF
+ AAB9B5FFAFBEBAFF9FAEAAFF8D9C98FF808F8BFF94A39FFF707E7AFF7E8C88FF
+ 8A9894FF8B9995FF8A9894FF8D9B97FF92A09CFF94A29EFF95A39FFF9FADA9FF
+ A8B6B2FFA6B4B0FF97A5A1FF8E9C98FF98A6A2FFA9B7B3FFA6B4B0FF9EACA8FF
+ A3B1ADFFA7B5B1FF9AA8A4FF8F9D99FF8A9894FF818F8BFF85938FFF8A9894FF
+ 92A09CFF9AA8A4FF9EACA8FF9DABA7FF99A7A3FF95A39FFFA4B2ACFF97A59FFF
+ 919F99FF94A29CFF8F9D97FF818F89FF788680FF798781FF7D8B85FF818F89FF
+ 8B9993FF95A39DFF96A49EFF919F99FF92A09AFF98A6A0FF92A29BFF94A49DFF
+ 8D9B95FF92A09AFF87958FFF505E58FF78847EFF838F89FF838D87FF86908AFF
+ 8A948EFF8A948EFF8B928DFF8B928DFF8E9590FF929A93FF8F9A92FF8B968CFF
+ 859086FF848F85FF8D988EFF95A096FF919C92FF879288FF949F95FF939E94FF
+ 919C92FF8F9A90FF8E998FFF8D988EFF8D988EFF8D988EFF8C978DFF8A958BFF
+ 8F9A90FF8D988EFF869187FF919C92FF9FAAA0FF9DA89EFFABB6ACFFA6B1A7FF
+ A0ABA1FF9CA79DFF9AA59BFF96A197FF909B91FF8A958BFF909E93FF94A297FF
+ 95A398FF93A196FF93A196FF94A297FF909E93FF8A988DFF869489FFA9B7ACFF
+ B3C1B6FFA2B0A5FF9DABA0FF9EACA1FF9CAA9FFF9BAAA2FF9BADA6FFA7BBB6FF
+ B1C5C0FFADC1BCFFA2B6B1FF9AAEA9FF94A8A3FF90A49FFF98ACA7FF97ABA6FF
+ 95A9A4FF93A7A2FF525755FF545957FF575C5AFF6B706EFF5E6562FF4B524FFF
+ 303734FF666D6AFF78817EFF7F8885FF77827FFF7B8683FF99A4A1FF98A3A0FF
+ 95A39FFFA9B7B3FF94A29EFF9BA9A5FFA0AEAAFF9EACA8FF95A39FFF909E9AFF
+ 919F9BFF95A39FFF92A09CFF95A39FFF96A4A0FF92A09CFF8C9A96FF8D9B97FF
+ 94A29EFF9CAAA6FF94A29EFF919F9BFF8F9D99FF93A19DFF9CAAA6FFA5B3AFFF
+ AAB8B4FFADBBB7FF95A39FFF9FADA9FFAEBCB8FFB0BEBAFF74827EFFA9B7B3FF
+ 97A5A1FFA4B2AEFFA0AEAAFF9DABA7FF9FADA9FFA4B2AEFFA1AFABFF9CAAA6FF
+ 9FADA9FFA8B6B2FF9BA9A5FFABB9B5FF99A7A3FF9BA9A5FF99A7A3FF9FADA9FF
+ AAB8B4FF7B8985FF828D8AFF5C6764FF6C7774FF7B8683FF798481FF85908DFF
+ 899491FF8E9996FF9AA5A2FF9CA7A4FF9FAAA7FF9FAAA7FF99A4A1FF95A09DFF
+ 9AA5A2FFA2ADAAFF9EACA8FF9EACA8FF9CAAA6FF9BA9A5FF9BA9A5FF9BA9A5FF
+ 99A7A3FF95A39FFFA4B2AEFF9FADA9FF99A7A3FF8E9C98FF788682FF63716DFF
+ 5F6D69FF657470FF627370FF627572FFA2B5B2FFB5C8C5FFCCDFDCFFBDD0CDFF
+ B4C7C4FFA7BAB7FFACBFBCFFA8BBB8FFA4B7B4FFA5B8B5FFA8BBB8FFABBEBBFF
+ A9BCB9FFA8B9B6FF9FAEAAFF9CAAA6FF818F8BFF35433FFF7B8985FF808E8AFF
+ 7C8A86FF7A8884FF6D7B77FF768480FF7D8B87FF7A8884FF73817DFF707E7AFF
+ 768480FF7E8C88FF85938FFF7F8D89FF7E8C88FF818F8BFF7C8A86FF778581FF
+ 818F8BFF93A19DFF97A5A1FF8D9B97FF879591FF8B9995FF95A39FFF9EACA8FF
+ A4B2AEFFA8B6B2FFA5B3AFFFA9B7B3FFACBAB6FFAAB8B4FFA5B3AFFFA4B2AEFF
+ A8B6B2FFADBBB7FFAAB8B4FFAAB8B4FFA9B7B3FFA8B6B2FFAAB8B4FFACBAB6FF
+ ADBBB7FFABB9B5FFA4B3AFFFA8B7B3FFAEBDB9FFB4C3BFFFB8C7C3FFBCCBC7FF
+ BFCECAFFC0CFCBFFBECDC9FFB9C8C4FFB4C3BFFFB8C7C3FFA3B2AEFF94A39FFF
+ 657470FF92A19DFF768480FF798783FF808E8AFF84928EFF82908CFF818F8BFF
+ 8A9894FF96A4A0FF94A29EFF93A19DFF98A6A2FF9DABA7FF99A7A3FF909E9AFF
+ 909E9AFF98A6A2FF94A29EFF9AA8A4FF9DABA7FF9DABA7FF9CAAA6FF9BA9A5FF
+ 94A29EFF8C9A96FF9FADA9FF9AA8A4FF95A39FFF95A39FFF98A6A2FF9BA9A5FF
+ 9BA9A5FF99A7A3FF96A49EFF97A59FFF99A7A1FF99A7A1FF99A7A1FF97A59FFF
+ 94A29CFF93A19BFF94A29CFF95A39DFF99A7A1FF9EACA6FFA1AFA9FFA0AEA8FF
+ 9CAAA4FF98A6A0FF92A29BFF91A19AFF8F9D97FF86948EFF93A19BFF5D6B65FF
+ 66726CFF7F8B85FF7F8983FF838D87FF88928CFF8A948EFF8A918CFF8A918CFF
+ 8E9590FF919992FF869189FF8D988EFF859086FF7F8A80FF889389FF8D988EFF
+ 8C978DFF919C92FF848F85FF8D988EFF929D93FF8F9A90FF8D988EFF909B91FF
+ 929D93FF919C92FF848F85FF89948AFF8C978DFF8B968CFF8B968CFF929D93FF
+ 9BA69CFFA1ACA2FFA5B0A6FFA4AFA5FFA3AEA4FFA0ABA1FF9CA79DFF97A298FF
+ 939E94FF909B91FF869489FF909E93FF97A59AFF98A69BFF9BA99EFF9EACA1FF
+ 96A499FF8A988DFF8D9B90FF9DABA0FFADBBB0FFB8C6BBFFB1BFB4FF96A499FF
+ 93A196FFACBBB3FFB6C6BFFFABBCB8FFAABBB7FFAEBFBBFFA3B4B0FF8FA09CFF
+ 8C9D99FF97A8A4FF8E9F9BFF90A19DFF92A39FFF94A5A1FF5F6462FF505553FF
+ 444947FF5A5F5DFF606764FF545B58FF19201DFF242B28FF565F5CFF727B78FF
+ 75807DFF76817EFF939E9BFFA2ADAAFF9AA8A4FF9AA8A4FF97A5A1FF99A7A3FF
+ 9BA9A5FF9CAAA6FF9BA9A5FF97A5A1FF92A09CFF8F9D99FF93A19DFF96A4A0FF
+ 97A5A1FF92A09CFF8C9A96FF8B9995FF8F9D99FF95A39FFF97A5A1FF92A09CFF
+ 8E9C98FF8F9D99FF94A29EFF9BA9A5FFA0AEAAFFA1AFABFF9EACA8FFA2B0ACFF
+ ADBBB7FFAEBCB8FF84928EFF808E8AFFAAB8B4FFC6D4D0FFAAB8B4FFA3B1ADFF
+ A2B0ACFFA7B5B1FFA9B7B3FFA6B4B0FFA5B3AFFFA9B7B3FFABB9B5FFAAB8B4FF
+ 9EACA8FF9BA9A5FF99A7A3FF9FADA9FF9EACA8FF798783FF7C8784FF5D6865FF
+ 77827FFF899491FF7E8986FF7D8885FF808B88FF8D9895FF939E9BFF8D9895FF
+ 8B9693FF929D9AFF9DA8A5FFA1ACA9FF9EA9A6FF9AA5A2FF9FADA9FF8D9B97FF
+ 8F9D99FFA3B1ADFFA4B2AEFF919F9BFF8F9D99FFA1AFABFFA9B7B3FF919F9BFF
+ 6E7C78FF465450FF1E2C28FF05130FFF04120EFF0D1C18FF61726FFF768986FF
+ B7CAC7FFC2D5D2FFBDD0CDFFB7CAC7FFB2C5C2FFB0C3C0FFA3B6B3FFA1B4B1FF
+ A0B3B0FFA3B6B3FFA8BBB8FFA9BCB9FFA5B8B5FFA2B3B0FFA0AFABFF95A39FFF
+ 99A7A3FF42504CFF8D9B97FF7F8D89FF74827EFF687672FF687672FF6B7975FF
+ 6F7D79FF72807CFF73817DFF73817DFF74827EFF75837FFF778581FF74827EFF
+ 75837FFF778581FF788682FF768480FF798783FF7F8D89FF8F9D99FF899793FF
+ 85938FFF8A9894FF92A09CFF99A7A3FF9CAAA6FF9DABA7FF9CAAA6FFA2B0ACFF
+ A7B5B1FFA7B5B1FFA3B1ADFFA1AFABFFA3B1ADFFA6B4B0FFA8B6B2FFAAB8B4FF
+ AAB8B4FFA9B7B3FFABB9B5FFAEBCB8FFAEBCB8FFAAB8B4FFA7B6B2FFABBAB6FF
+ B1C0BCFFB6C5C1FFBBCAC6FFBECDC9FFC1D0CCFFC2D1CDFFBAC9C5FFB9C8C4FF
+ B4C3BFFFB5C4C0FFA5B4B0FF9CABA7FF72817DFF91A09CFF74827EFF788682FF
+ 818F8BFF899793FF889692FF84928EFF85938FFF8B9995FF92A09CFF92A09CFF
+ 99A7A3FFA1AFABFFA1AFABFF99A7A3FF97A5A1FF9AA8A4FF9BA9A5FFA0AEAAFF
+ A1AFABFF9FADA9FF9EACA8FF9FADA9FF9CAAA6FF96A4A0FF9CAAA6FF9AA8A4FF
+ 97A5A1FF97A5A1FF99A7A3FF9CAAA6FF9DABA7FF9DABA7FF9CAAA4FF9CAAA4FF
+ 9BA9A3FF9AA8A2FF98A6A0FF96A49EFF94A29CFF93A19BFF9CAAA4FF9DABA5FF
+ 9EACA6FFA0AEA8FFA0AEA8FF9DABA5FF97A59FFF92A09AFF93A39CFF92A29BFF
+ 919F99FF8A9892FF95A39DFF64726CFF69756FFF84908AFF838D87FF858F89FF
+ 87918BFF87918BFF888F8AFF878E89FF878E89FF889089FF838E86FF89948AFF
+ 808B81FF79847AFF818C82FF859086FF828D83FF879288FF7F8A80FF869187FF
+ 8B968CFF8B968CFF8C978DFF8F9A90FF909B91FF8D988EFF7C877DFF838E84FF
+ 879288FF879288FF8A958BFF939E94FF9EA99FFFA4AFA5FFA6B1A7FFA6B1A7FF
+ A5B0A6FFA4AFA5FFA1ACA2FF9EA99FFF9BA69CFF99A49AFF8E9C91FF93A196FF
+ 95A398FF94A297FF97A59AFF9CAA9FFF99A79CFF919F94FF8D9B90FF93A196FF
+ 99A79CFFA5B3A8FFA7B5AAFF95A398FF93A196FFA8B7AFFFC3D3CCFFB4C5C1FF
+ ACBDB9FFACBDB9FFA2B3AFFF90A19DFF8A9B97FF91A29EFF90A19DFF8D9E9AFF
+ 889995FF849591FF6C716FFF585D5BFF464B49FF5A5F5DFF6D7471FF757C79FF
+ 2F3633FF171E1BFF37403DFF656E6BFF707B78FF6F7A77FF85908DFFA8B3B0FF
+ A2B0ACFF94A29EFF9BA9A5FF97A5A1FF95A39FFF99A7A3FF9DABA7FF9CAAA6FF
+ 93A19DFF8B9995FF8F9D99FF92A09CFF93A19DFF919F9BFF8D9B97FF8B9995FF
+ 8D9B97FF909E9AFF98A6A2FF93A19DFF8E9C98FF8C9A96FF8F9D99FF94A29EFF
+ 98A6A2FF9AA8A4FF9FADA9FF9AA8A4FFABB9B5FFB3C1BDFF9FADA9FF4B5955FF
+ 7F8D89FF8C9A96FF9FADA9FF98A6A2FF96A4A0FF9CAAA6FFA2B0ACFFA2B0ACFF
+ A0AEAAFFA0AEAAFF9DABA7FF8B9995FF8E9C98FF8A9894FF8C9A96FF99A7A3FF
+ 8D9B97FF7E8C88FF87928FFF4E5956FF586360FF788380FF86918EFF8C9794FF
+ 808B88FF7D8885FFA6B1AEFF99A4A1FF8A9592FF838E8BFF848F8CFF87928FFF
+ 86918EFF838E8BFF52605CFF45534FFF4B5955FF5F6D69FF5E6C68FF4A5854FF
+ 475551FF55635FFF4A5854FF465450FF42504CFF3E4C48FF394743FF3B4945FF
+ 485652FF566561FF6B7C79FF829592FFB5C8C5FFC5D8D5FFB3C6C3FFBCCFCCFF
+ AFC2BFFFB1C4C1FF9DB0ADFF9CAFACFF9EB1AEFFA2B5B2FFA6B9B6FFA4B7B4FF
+ 9EB1AEFF99AAA7FF9FAEAAFF899793FFA8B6B2FF4C5A56FF909E9AFF7F8D89FF
+ 6F7D79FF606E6AFF62706CFF5F6D69FF5F6D69FF667470FF707E7AFF75837FFF
+ 717F7BFF6B7975FF727D7AFF75807DFF77827FFF77827FFF7C8784FF808B88FF
+ 7D8885FF76817EFF87928FFF848F8CFF848F8CFF889390FF909B98FF98A3A0FF
+ 9AA5A2FF9AA5A2FF96A4A0FF9BA9A5FFA1AFABFFA3B1ADFFA1AFABFF9FADA9FF
+ A0AEAAFFA2B0ACFFA3B1ADFFA7B5B1FFA9B7B3FFA9B7B3FFADBBB7FFB3C1BDFF
+ B1BFBBFFABB9B5FFADBCB8FFAFBEBAFFB4C3BFFFB9C8C4FFBECDC9FFC1D0CCFF
+ C3D2CEFFC3D2CEFFBBCAC6FFBDCCC8FFB6C5C1FFAEBDB9FFA3B2AEFFA2B1ADFF
+ 7D8C88FF83928EFF6E7C78FF72807CFF7D8B87FF899793FF8E9C98FF899793FF
+ 85938FFF85938FFF8D9B97FF8E9C98FF95A39FFF9FADA9FFA2B0ACFF9DABA7FF
+ 97A5A1FF95A39FFF9FADA9FFA2B0ACFFA2B0ACFF9EACA8FF9DABA7FF9FADA9FF
+ 9FADA9FF9BA9A5FF9CAAA6FF9CAAA6FF9BA9A5FF99A7A3FF98A6A2FF98A6A2FF
+ 9BA9A5FF9EACA8FF9DABA5FF9CAAA4FF9BA9A3FF9AA8A2FF99A7A1FF99A7A1FF
+ 99A7A1FF99A7A1FFA1AFA9FFA1AFA9FFA1AFA9FFA2B0AAFFA1AFA9FF9DABA5FF
+ 97A59FFF92A09AFF97A7A0FF93A39CFF92A09AFF8C9A94FF93A19BFF697771FF
+ 65716BFF838F89FF838D87FF828C86FF828C86FF838D87FF868D88FF868D88FF
+ 848B86FF828A83FF818C84FF879288FF7E897FFF778278FF818C82FF869187FF
+ 838E84FF879288FF808B81FF859086FF889389FF89948AFF8C978DFF8F9A90FF
+ 8B968CFF859086FF7A857BFF838E84FF89948AFF8A958BFF8E998FFF9AA59BFF
+ A5B0A6FFA9B4AAFFA8B3A9FFA9B4AAFFA9B4AAFFA8B3A9FFA7B2A8FFA6B1A7FF
+ A4AFA5FFA3AEA4FF99A79CFF99A79CFF96A499FF92A095FF95A398FF9BA99EFF
+ 9DABA0FF9AA89DFF96A499FF92A095FF8C9A8FFF95A398FF9FADA2FF95A398FF
+ 93A196FFA2B1A9FFCCDCD5FFB9CAC6FFAABBB7FFA5B6B2FF9FB0ACFF94A5A1FF
+ 8D9E9AFF8D9E9AFF8C9D99FF839490FF768783FF6F807CFF616664FF575C5AFF
+ 4A4F4DFF525755FF606764FF7C8380FF454C49FF252C29FF2C3532FF5B6461FF
+ 6A7572FF707B78FF76817EFF9FAAA7FFA3B1ADFF9EACA8FF9CAAA6FF98A6A2FF
+ 94A29EFF95A39FFF98A6A2FF98A6A2FF93A19DFF8E9C98FF889692FF8B9995FF
+ 8E9C98FF909E9AFF909E9AFF8F9D99FF909E9AFF909E9AFF97A5A1FF93A19DFF
+ 8E9C98FF8C9A96FF8D9B97FF919F9BFF96A4A0FF99A7A3FF9FADA9FF8E9C98FF
+ A6B4B0FFB2C0BCFFB1BFBBFF55635FFF5F6D69FF5E6C68FFA2B0ACFFA0AEAAFF
+ 9EACA8FF9FADA9FF9FADA9FF9CAAA6FF9AA8A4FF99A7A3FF889692FF6C7A76FF
+ 7C8A86FF768480FF73817DFF818F8BFF72807CFF768480FF818C89FF35403DFF
+ 313C39FF5A6562FF7A8582FF8C9794FF818C89FF7A8582FF7F8A87FF8C9794FF
+ 96A19EFF8D9895FF798481FF65706DFF55605DFF4D5855FF4A5854FF566460FF
+ 5F6D69FF5E6C68FF5B6965FF596763FF505E5AFF45534FFF596763FF63716DFF
+ 717F7BFF7C8A86FF7F8D89FF7F8D89FF82908CFF869591FF81928FFF7E918EFF
+ 98ABA8FFBED1CEFFB6C9C6FFC8DBD8FFAABDBAFFA9BCB9FF9FB2AFFF9EB1AEFF
+ 9DB0ADFFA0B3B0FFA3B6B3FFA0B3B0FF99ACA9FF94A5A2FF9BAAA6FF808E8AFF
+ 9FADA9FF55635FFF788682FF818F8BFF6E7C78FF697773FF63716DFF5D6B67FF
+ 596763FF5F6D69FF6A7874FF707E7AFF6E7C78FF697773FF6D7875FF77827FFF
+ 7B8683FF77827FFF7A8582FF828D8AFF818C89FF77827FFF7E8986FF7F8A87FF
+ 7F8A87FF818C89FF8A9592FF95A09DFF9BA6A3FF9AA5A2FF96A4A0FF99A7A3FF
+ 9DABA7FF9EACA8FF9DABA7FF9DABA7FFA0AEAAFFA2B0ACFF9CAAA6FFA1AFABFF
+ A4B2AEFFA5B3AFFFADBBB7FFB8C6C2FFB8C6C2FFAFBDB9FFB1C0BCFFB3C2BEFF
+ B6C5C1FFBBCAC6FFC0CFCBFFC3D2CEFFC3D2CEFFC2D1CDFFBFCECAFFC4D3CFFF
+ B8C7C3FFA5B4B0FF9DACA8FF9DACA8FF7F8E8AFF687773FF6B7975FF6A7874FF
+ 717F7BFF7F8D89FF899793FF8A9894FF889692FF899793FF909E9AFF909E9AFF
+ 94A29EFF9BA9A5FF9FADA9FF9CAAA6FF95A39FFF8F9D99FF9AA8A4FF9EACA8FF
+ 9FADA9FF9AA8A4FF97A5A1FF99A7A3FF98A6A2FF95A39FFF9CAAA6FF9EACA8FF
+ 9EACA8FF9BA9A5FF96A4A0FF94A29EFF97A5A1FF9AA8A4FF9AA8A2FF99A7A1FF
+ 99A7A1FF99A7A1FF9BA9A3FF9EACA6FFA1AFA9FFA3B1ABFF9EACA6FF9EACA6FF
+ 9FADA7FFA2B0AAFFA3B1ABFFA1AFA9FF9DABA5FF99A7A1FF99A9A2FF92A29BFF
+ 92A09AFF8D9B95FF8E9C96FF6C7A74FF5B6761FF7E8A84FF808A84FF7E8882FF
+ 7D8781FF808A84FF878E89FF89908BFF868D88FF838B84FF7C877FFF828D83FF
+ 79847AFF758076FF828D83FF8A958BFF889389FF8B968CFF89948AFF8B968CFF
+ 8B968CFF8A958BFF8D988EFF8E998FFF869187FF7C877DFF848F85FF8F9A90FF
+ 95A096FF939E94FF97A298FFA3AEA4FFADB8AEFFAFBAB0FFACB7ADFFACB7ADFF
+ ACB7ADFFACB7ADFFABB6ACFFAAB5ABFFA9B4AAFFA8B3A9FFA4B2A7FFA0AEA3FF
+ 9BA99EFF98A69BFF99A79CFF9CAA9FFF9EACA1FF9DABA0FFA3B1A6FF9CAA9FFF
+ 919F94FF95A398FF9FADA2FF98A69BFF94A297FFA0AFA7FFC9D9D2FFB6C7C3FF
+ A3B4B0FF9BACA8FF99AAA6FF96A7A3FF8FA09CFF8B9C98FF80918DFF778884FF
+ 6B7C78FF647571FF646967FF5F6462FF555A58FF545957FF59605DFF818885FF
+ 525956FF29302DFF262F2CFF4C5552FF626D6AFF7E8986FF727D7AFF929D9AFF
+ 97A5A1FFA3B1ADFF9CAAA6FF9BA9A5FF98A6A2FF94A29EFF909E9AFF909E9AFF
+ 92A09CFF95A39FFF8A9894FF8B9995FF8C9A96FF8F9D99FF919F9BFF919F9BFF
+ 8F9D99FF8D9B97FF96A4A0FF93A19DFF8F9D99FF8B9995FF8A9894FF8B9995FF
+ 8E9C98FF919F9BFF98A6A2FF8A9894FFA3B1ADFFA6B4B0FFA7B5B1FF8F9D99FF
+ 7B8985FF8E9C98FF84928EFF899793FF8A9894FF83918DFF798783FF73817DFF
+ 72807CFF73817DFF93A19DFF778581FF869490FF788682FF677571FF6A7874FF
+ 5A6864FF64726EFF596461FF212C29FF2C3734FF4D5855FF5F6A67FF707B78FF
+ 75807DFF808B88FF7A8582FF747F7CFF606B68FF444F4CFF394441FF4B5653FF
+ 6A7572FF808B88FF7C8A86FF899793FF919F9BFF909E9AFF909E9AFF909E9AFF
+ 84928EFF73817DFF697773FF717F7BFF7C8A86FF84928EFF8B9995FF95A39FFF
+ 9EACA8FFA3B2AEFF97A8A5FF7E918EFF8DA09DFFBED1CEFFBBCECBFFC3D6D3FF
+ A1B4B1FFA6B9B6FF9FB2AFFF9CAFACFF9BAEABFF9DB0ADFFA0B3B0FFA1B4B1FF
+ 9CAFACFF99AAA7FF94A39FFF82908CFF8E9C98FF6C7A76FF616F6BFF85938FFF
+ 6F7D79FF6F7D79FF697773FF63716DFF5D6B67FF5D6B67FF62706CFF677571FF
+ 6A7874FF6B7975FF646F6CFF717C79FF77827FFF707B78FF6F7A77FF77827FFF
+ 7B8683FF788380FF7D8885FF7E8986FF7B8683FF788380FF7F8A87FF8C9794FF
+ 95A09DFF95A09DFF97A5A1FF97A5A1FF95A39FFF94A29EFF94A29EFF98A6A2FF
+ 9EACA8FFA2B0ACFF95A39FFF9BA9A5FF9DABA7FF9DABA7FFAAB8B4FFBCCAC6FF
+ BFCDC9FFB7C5C1FFB6C5C1FFB6C5C1FFB7C6C2FFBCCBC7FFC2D1CDFFC4D3CFFF
+ C3D2CEFFC1D0CCFFBECDC9FFC3D2CEFFB6C5C1FF9DACA8FF97A6A2FF94A39FFF
+ 808F8BFF52615DFF72807CFF6B7975FF697773FF717F7BFF7C8A86FF83918DFF
+ 889692FF8D9B97FF98A6A2FF97A5A1FF96A4A0FF97A5A1FF99A7A3FF99A7A3FF
+ 92A09CFF8C9A96FF93A19DFF9AA8A4FF9DABA7FF99A7A3FF95A39FFF94A29EFF
+ 92A09CFF8F9D99FF97A5A1FF9AA8A4FF9CAAA6FF9AA8A4FF96A4A0FF95A39FFF
+ 98A6A2FF9BA9A5FF9AA8A2FF9AA8A2FF9AA8A2FF9AA8A2FF9DABA5FFA0AEA8FF
+ A4B2ACFFA6B4AEFF9EACA6FF9EACA6FF9FADA7FFA1AFA9FFA4B2ACFFA3B1ABFF
+ A0AEA8FF9DABA5FF98A8A1FF8F9F98FF92A09AFF8F9D97FF8C9A94FF76847EFF
+ 59655FFF828E88FF828C86FF808A84FF7E8882FF818B85FF878E89FF888F8AFF
+ 868D88FF828A83FF79847CFF7D887EFF747F75FF707B71FF7F8A80FF869187FF
+ 838E84FF869187FF889389FF8A958BFF89948AFF889389FF8A958BFF8C978DFF
+ 859086FF7C877DFF8E998FFF9BA69CFFA0ABA1FF9BA69CFF9CA79DFFA8B3A9FF
+ B0BBB1FFAEB9AFFFB0BBB1FFAFBAB0FFAEB9AFFFACB7ADFFAAB5ABFFA9B4AAFF
+ A8B3A9FFA8B3A9FFA9B7ACFFA5B3A8FFA2B0A5FFA1AFA4FFA1AFA4FF9FADA2FF
+ 9DABA0FF9CAA9FFFA4B2A7FFA3B1A6FF9BA99EFF9CAA9FFFA3B1A6FF9BA99EFF
+ 97A59AFFA3B2AAFFC3D3CCFFB7C6C2FFA5B4B0FF97A6A2FF93A29EFF92A19DFF
+ 8B9A96FF83928EFF798884FF758480FF71807CFF707F7BFF666B69FF5D6260FF
+ 555A58FF575C5AFF5F6663FF909794FF636A67FF2D3431FF1F2825FF3C4542FF
+ 586360FF8D9895FF77827FFF8F9A97FF8D9B97FF9BA9A5FF9DABA7FFA0AEAAFF
+ 9FADA9FF98A6A2FF8E9C98FF8B9995FF919F9BFF99A7A3FF94A29EFF919F9BFF
+ 8F9D99FF909E9AFF92A09CFF919F9BFF8C9A96FF879591FF95A39FFF94A29EFF
+ 919F9BFF8B9995FF85938FFF818F8BFF818F8BFF82908CFF7E8C88FF8A9894FF
+ A1AFABFF9BA9A5FF8E9C98FF9BA9A5FF75837FFF92A09CFF889692FF94A29EFF
+ 9CAAA6FF98A6A2FF909E9AFF909E9AFF95A39FFF98A6A2FFA1AFABFF8E9C98FF
+ 919F9BFF84928EFF6E7C78FF677571FF5F6D69FF5E6C68FF3B4643FF101B18FF
+ 222D2AFF3F4A47FF4E5956FF616C69FF65706DFF687370FF4B5653FF515C59FF
+ 535E5BFF56615EFF646F6CFF77827FFF7F8A87FF7B8683FF879591FF7B8985FF
+ 7D8B87FF8F9D99FF95A39FFF899793FF7F8D89FF808E8AFF899793FF8E9C98FF
+ 909E9AFF8C9A96FF899793FF8A9894FF8B9995FF889793FFA0B1AEFF8B9E9BFF
+ A4B7B4FFC3D6D3FFB9CCC9FFB2C5C2FF9DB0ADFFA8BBB8FF98ABA8FF96A9A6FF
+ 95A8A5FF99ACA9FF9FB2AFFFA1B4B1FF9FB2AFFF9EAFACFF8D9C98FF899793FF
+ 869490FF889692FF596763FF818F8BFF73817DFF687672FF6B7975FF677571FF
+ 616F6BFF5E6C68FF5E6C68FF616F6BFF65736FFF687672FF606B68FF6A7572FF
+ 707B78FF6D7875FF6A7572FF6E7976FF76817EFF7A8582FF7C8784FF7F8A87FF
+ 7B8683FF737E7BFF76817EFF848F8CFF8C9794FF8B9693FF96A4A0FF93A19DFF
+ 8E9C98FF8B9995FF8C9A96FF919F9BFF98A6A2FF9DABA7FF93A19DFF98A6A2FF
+ 96A4A0FF94A29EFFA3B1ADFFBDCBC7FFC5D3CFFFBDCBC7FFBAC9C5FFB9C8C4FF
+ BAC9C5FFBECDC9FFC4D3CFFFC6D5D1FFC4D3CFFFC0CFCBFFB9C8C4FFBCCBC7FF
+ B1C0BCFF99A8A4FF96A5A1FF8E9D99FF879692FF4B5A56FF7D8B87FF72807CFF
+ 697773FF6B7975FF717F7BFF798783FF82908CFF8B9995FF909E9AFF93A19DFF
+ 92A09CFF8F9D99FF8F9D99FF909E9AFF8C9A96FF869490FF8F9D99FF98A6A2FF
+ 9EACA8FF9BA9A5FF97A5A1FF96A4A0FF95A39FFF93A19DFF93A19DFF96A4A0FF
+ 98A6A2FF99A7A3FF99A7A3FF9BA9A5FF9DABA7FF9FADA9FF9EACA6FF9DABA5FF
+ 9DABA5FF9DABA5FF9EACA6FF9FADA7FFA0AEA8FFA1AFA9FFA3B1ABFFA2B0AAFF
+ A1AFA9FFA2B0AAFFA2B0AAFFA1AFA9FF9DABA5FF9AA8A2FF97A7A0FF8C9C95FF
+ 92A09AFF93A19BFF8E9C96FF83918BFF5D6963FF8C9892FF87918BFF858F89FF
+ 848E88FF848E88FF858C87FF848B86FF818883FF7E867FFF808B83FF838E84FF
+ 778278FF727D73FF7F8A80FF859086FF808B81FF818C82FF7E897FFF828D83FF
+ 838E84FF838E84FF859086FF8A958BFF889389FF838E84FF8E998FFF9DA89EFF
+ A2ADA3FF9AA59BFF9AA59BFFA8B3A9FFAEB9AFFFAAB5ABFFB2BDB3FFB0BBB1FF
+ AEB9AFFFABB6ACFFA9B4AAFFA7B2A8FFA7B2A8FFA6B1A7FFA8B6ABFFA4B2A7FF
+ A4B2A7FFA8B6ABFFA8B6ABFFA2B0A5FF9CAA9FFF9BA99EFF9BA99EFFA0AEA3FF
+ 9DABA0FF9EACA1FFA4B2A7FF9DABA0FF9AA89DFFA4B3ABFFC3D1CBFFBECDC9FF
+ AFBEBAFF99A8A4FF8B9A96FF879692FF7F8E8AFF758480FF778682FF7B8A86FF
+ 81908CFF859490FF5C615FFF515654FF4D5250FF4D5250FF4D5451FF848B88FF
+ 666D6AFF383F3CFF222B28FF363F3CFF4D5855FF8C9794FF7A8582FF9DA8A5FF
+ 96A4A0FF9AA8A4FFA0AEAAFFA4B2AEFFA6B4B0FFA0AEAAFF95A39FFF8F9D99FF
+ 92A09CFF97A5A1FF9AA8A4FF95A39FFF919F9BFF919F9BFF94A29EFF93A19DFF
+ 8D9B97FF879591FF92A09CFF93A19DFF92A09CFF8D9B97FF869490FF7F8D89FF
+ 7D8B87FF7D8B87FF6E7C78FF8E9C98FF93A19DFF95A39FFF909E9AFF8B9995FF
+ 63716DFF62706CFF808E8AFF8C9A96FF96A4A0FF94A29EFF93A19DFF98A6A2FF
+ 9DABA7FF9EACA8FF98A6A2FF919F9BFF83918DFF7F8D89FF707E7AFF677571FF
+ 697773FF53615DFF242F2CFF010C09FF121D1AFF27322FFF36413EFF525D5AFF
+ 57625FFF535E5BFF606B68FF67726FFF687370FF67726FFF727D7AFF86918EFF
+ 8F9A97FF8B9693FF97A5A1FF82908CFF798783FF84928EFF8F9D99FF8C9A96FF
+ 889692FF899793FF818F8BFF8D9B97FF98A6A2FF9CAAA6FFA0AEAAFFA4B2AEFF
+ A2B0ACFF9BAAA6FF9DAEABFF96A9A6FFB9CCC9FFBACDCAFFB6C9C6FFAEC1BEFF
+ A5B8B5FFA1B4B1FF93A6A3FF92A5A2FF93A6A3FF98ABA8FF9DB0ADFF9DB0ADFF
+ 98ABA8FF94A5A2FF889793FF8A9894FF7F8D89FF8E9C98FF596763FF6F7D79FF
+ 7F8D89FF616F6BFF687672FF65736FFF606E6AFF5E6C68FF5F6D69FF606E6AFF
+ 5F6D69FF5E6C68FF636E6BFF666F6CFF6B7471FF707976FF717A77FF707976FF
+ 747D7AFF7B8481FF7A8380FF818A87FF7F8885FF77807DFF7A8380FF89928FFF
+ 919A97FF8C9794FF95A39FFF919F9BFF8D9B97FF8A9894FF8B9995FF909E9AFF
+ 94A29EFF97A5A1FF96A4A0FF98A6A2FF919F9BFF8B9995FF9BA9A5FFBAC8C4FF
+ C6D4D0FFBFCDC9FFC0CFCBFFBDCCC8FFBDCCC8FFC1D0CCFFC7D6D2FFCAD9D5FF
+ C6D5D1FFC1D0CCFFB9C8C4FFB8C7C3FFB0BFBBFF9BAAA6FF98A7A3FF899894FF
+ 8D9C98FF4A5955FF7F8D89FF75837FFF6E7C78FF6E7C78FF717F7BFF768480FF
+ 7F8D89FF889692FF84928EFF8D9B97FF92A09CFF8F9D99FF8E9C98FF909E9AFF
+ 8E9C98FF889692FF8D9B97FF96A4A0FF9BA9A5FF98A6A2FF96A4A0FF99A7A3FF
+ 9DABA7FF9EACA8FF9AA8A4FF99A7A3FF99A7A3FF9BA9A5FF9EACA8FF9FADA9FF
+ 9EACA8FF9DABA7FF9CAAA4FF9DABA5FF9EACA6FF9FADA7FF9FADA7FF9FADA7FF
+ 9FADA7FF9EACA6FFA5B3ADFFA4B2ACFFA2B0AAFFA1AFA9FFA1AFA9FF9FADA7FF
+ 9BA9A3FF97A59FFF9AAAA3FF8D9D96FF94A29CFF96A49EFF8C9A94FF889690FF
+ 58645EFF8B9791FF858F89FF86908AFF86908AFF848E88FF838A85FF808782FF
+ 7F8681FF7F8780FF848F87FF859086FF79847AFF737E74FF818C82FF879288FF
+ 818C82FF808B81FF7B867CFF818C82FF838E84FF818C82FF828D83FF889389FF
+ 8B968CFF8A958BFF869187FF97A298FF9EA99FFF96A197FF98A399FFA8B3A9FF
+ AFBAB0FFA9B4AAFFB1BCB2FFAFBAB0FFACB7ADFFAAB5ABFFA8B3A9FFA7B2A8FF
+ A7B2A8FFA7B2A8FFA2B0A5FF9EACA1FFA0AEA3FFA8B6ABFFA9B7ACFFA3B1A6FF
+ 9EACA1FF9EACA1FF9BA99EFF9FADA2FF9AA89DFF9AA89DFFA2B0A5FF9DABA0FF
+ 98A69BFF9EADA5FFC2D0CAFFC7D6D2FFBDCCC8FFA0AFABFF889793FF7F8E8AFF
+ 778682FF6D7C78FF7A8985FF83928EFF8F9E9AFF96A5A1FF6F7472FF676E6BFF
+ 666B69FF575E5BFF444B48FF7A817EFF717875FF585F5CFF2B3431FF39423FFF
+ 45504DFF838E8BFF77827FFFACB7B4FFA8B3B0FFA1AFABFFA2B0ACFFA6B5B1FF
+ AAB8B4FFA6B5B1FF9DABA7FF94A39FFF92A09CFF92A19DFF9AA8A4FF93A29EFF
+ 8F9D99FF8F9E9AFF95A39FFF96A5A1FF92A09CFF8B9A96FF8F9D99FF91A09CFF
+ 94A29EFF909F9BFF8A9894FF83928EFF818F8BFF808F8BFF798783FF94A39FFF
+ 7C8A86FF8D9C98FFA9B7B3FF93A29EFF7E8C88FF5F6D69FF8D9B97FF94A29EFF
+ 96A4A0FF909E9AFF8E9C98FF909E9AFF8D9B97FF879591FF8D9B97FF8B9995FF
+ 707B78FF727D7AFF697471FF5D6865FF636E6BFF3C4744FF05100DFF000502FF
+ 182320FF1B2623FF121D1AFF303B38FF4D5855FF606B68FF66716EFF7C8784FF
+ 899491FF7F8A87FF77827FFF7E8986FF87928FFF899491FFA0ABA8FF96A4A0FF
+ 82908CFF73817DFF7F8D89FF96A4A0FF95A39FFF83918DFF8E9C98FF96A4A0FF
+ 99A7A3FF97A5A1FF9AA8A4FFA3B1ADFFA7B5B1FFA3B2AEFF99AAA7FF98ABA8FF
+ BDD0CDFFA8BBB8FFB6C9C6FFB9CCC9FFB2C5C2FF94A7A4FF92A5A2FF94A5A2FF
+ 96A7A4FF9AABA8FF9DAEABFF98A9A6FF8E9F9CFF869794FF859490FF85938FFF
+ 788682FF83918DFF576561FF5B6965FF8C9A96FF63716DFF64726EFF606E6AFF
+ 5E6966FF606B68FF646F6CFF636E6BFF5D6865FF56615EFF646D6AFF5D6663FF
+ 606966FF6E7774FF737C79FF6F7875FF6E7774FF747D7AFF747D7AFF7F8885FF
+ 828B88FF7E8784FF838C89FF939C99FF9BA4A1FF949F9CFF96A4A0FF93A19DFF
+ 909E9AFF8F9D99FF909E9AFF92A09CFF94A29EFF95A39FFF99A7A3FF9AA8A4FF
+ 8F9D99FF85938FFF96A4A0FFB7C5C1FFC6D4D0FFBFCDC9FFC3D2CEFFBECFCBFF
+ BFCECAFFC4D3CFFFCAD9D5FFCCDBD7FFC8D7D3FFC3D2CEFFBDCCC8FFBAC9C5FF
+ B3C2BEFFA0AFABFF9BAAA6FF859490FF8F9E9AFF4B5955FF798783FF73817DFF
+ 717F7BFF73817DFF768480FF788682FF808E8AFF899793FF82908CFF909E9AFF
+ 9BA9A5FF9BA9A5FF9AA8A4FF9CAAA6FF9BA9A5FF95A39FFF8A9894FF92A09CFF
+ 97A5A1FF94A29EFF93A19DFF9AA8A4FFA3B1ADFFA7B5B1FFA4B2AEFFA1AFABFF
+ 9EACA8FF9EACA8FFA0AEAAFF9FADA9FF9BA9A5FF96A4A0FF97A59FFF99A7A1FF
+ 9CAAA4FF9FADA7FFA1AFA9FFA2B0AAFFA1AFA9FFA1AFA9FFA4B2ACFFA2B0AAFF
+ A0AEA8FFA0AEA8FFA1AFA9FF9FADA7FF9CAAA4FF99A7A1FFA0AEA8FF919F99FF
+ 95A39DFF96A49EFF87958FFF84928CFF4E5A54FF818D87FF7E8882FF828C86FF
+ 858F89FF848E88FF808A84FF7D8781FF818883FF818B85FF7B867EFF7D887EFF
+ 717C74FF6D786EFF7D8880FF848F85FF7E8981FF7E897FFF818C84FF879288FF
+ 89948CFF848F85FF828D85FF879288FF8C978FFF8E998FFF7F8A80FF929D93FF
+ 9AA59BFF939E94FF97A298FFAAB5ABFFB2BDB3FFADB8AEFFAFBAB0FFAEB9AFFF
+ ABB6ACFFA9B4AAFFA8B3A9FFA8B3A9FFA9B4AAFFA7B5AAFF9DABA0FF98A69BFF
+ 9BA99EFFA5B3A8FFA8B6ABFFA3B1A6FF9FADA2FFA2B0A5FFA3B1A6FFA2B0A5FF
+ 98A69BFF97A59AFFA0AEA3FF9DABA0FF94A297FF96A59DFFBECEC7FFCCDBD7FF
+ C7D6D2FFA7B6B2FF899894FF7E8D89FF768581FF6C7B77FF7B8A86FF879692FF
+ 95A4A0FF9BAAA6FF7C8380FF6B7471FF69706DFF6B7471FF4D5653FF505956FF
+ 79827FFF717A77FF3B4441FF303936FF4F5855FF78817EFF838C89FF949D9AFF
+ AEB7B4FFB2BDBAFFA7B6B2FFA0B1ADFFA1B0ACFFA1B2AEFF9DACA8FF8FA09CFF
+ 8C9B97FF8C9D99FF96A5A1FF91A29EFF909F9BFF8E9F9BFF93A29EFF94A5A1FF
+ 96A5A1FF92A39FFF8F9E9AFF889995FF8B9A96FF8FA09CFF8F9E9AFF82938FFF
+ 7E8D89FF7D8E8AFF798884FF80918DFF8D9C98FF81928EFF9CABA7FF7B8C88FF
+ 798884FF83928EFF859490FF899894FF8F9D99FF919F9BFF8F9D99FF8B9995FF
+ 889390FF85908DFF838E8BFF798481FF78817EFF5F6865FF747D7AFF79827FFF
+ 606966FF1B2421FF08110EFF060F0CFF0B1411FF1D2623FF38413EFF535C59FF
+ 6A7370FF78817EFF737C79FF7B8481FF848D8AFF87908DFF858E8BFF838C89FF
+ 858E8BFF86918EFFA5B0ADFF95A09DFF87928FFF85908DFF838E8BFF808B88FF
+ 85908DFF8F9A97FF97A29FFF9AA5A2FF9FAAA7FFA3AEABFFA4AFACFFA3AEABFF
+ A0ABA8FF9CAAA6FF92A3A0FFAFC2BFFFB1C4C1FFA2B5B2FFAEBFBCFFBBCCC9FF
+ ACBDBAFF98A9A6FF91A29FFF8D9B99FF919F9DFF93A19FFF8F9D9BFF94A2A0FF
+ 929F9DFF808D8BFF8C9B97FF808F8BFF8C9A96FF808E8AFF687672FF293733FF
+ 6E7976FF747F7CFF687370FF5D6865FF636C69FF5A6360FF616A67FF717A77FF
+ 646D6AFF646D6AFF69726FFF626D6AFF636E6BFF697471FF6B7673FF6A7572FF
+ 707B78FF798481FF707B78FF76817EFF7F8A87FF848F8CFF828D8AFF85908DFF
+ 97A29FFFABB6B3FF94A29EFF9AA8A4FF919F9BFF7F8D89FF808E8AFF909E9AFF
+ 93A19DFF879591FF94A29EFF99A7A3FF92A09CFF869490FF93A19DFFB2C0BCFF
+ C1CFCBFFBAC9C5FFC4D5D1FFC0D4CFFFC0D1CDFFBFD0CCFFC1D2CEFFC5D6D2FF
+ CADBD7FFCEDFDBFFCDDCD8FFBFCECAFFB5C3BFFFADBBB7FF8F9D99FF8B9995FF
+ 899793FF4D5B57FF6C7A76FF72807CFF778581FF778581FF74827EFF768480FF
+ 82908CFF8E9C98FF96A4A0FF98A6A2FF9FADA9FFA6B4B0FFA6B4B0FFA0AEAAFF
+ 99A7A3FF97A5A1FF9DABA5FF9AA8A2FF99A7A1FF9BA9A3FF9AA8A2FF97A59FFF
+ 9AA8A2FF9FADA7FF9DABA5FFA0AEA8FF9EACA6FF9BA9A3FF9FADA7FFA5B3ADFF
+ A1AFA9FF97A59FFF9AA8A2FF96A49EFF93A19BFF96A49EFF9CAAA4FFA2B0AAFF
+ A3B1ABFFA3B1ABFFA0AEA8FFA0AEA8FFA0AEA8FF9FADA7FF9FADA7FF9FADA7FF
+ 9FADA7FF9FADA7FF99A7A1FF9DA9A3FF97A39DFF8C9892FF88948EFF828E88FF
+ 414D47FF808C86FF85918BFF84908AFF838F89FF84908AFF84908AFF838F89FF
+ 818B85FF7D8781FF7E8882FF7C877FFF757F79FF6D7870FF6E7872FF78837BFF
+ 7E8882FF7E8981FF7A847EFF7C877FFF7F8983FF808B83FF818B85FF848F87FF
+ 88928CFF8B968EFF8C9A8FFF919F94FF94A297FF94A297FF99A79CFFA2B0A5FF
+ A8B6ABFFA8B6ABFFA6B4A9FFAAB8ADFFADBBB0FFACBAAFFFA8B6ABFFA4B2A7FF
+ A2B0A5FFA3B1A6FFAEBCB1FF9AAA9FFF93A398FFA0B0A5FFA9B9AEFFA2B2A7FF
+ 9BABA0FF9CACA1FF9BABA0FFA2B2A7FFA5B5AAFFA2B2A7FFA0B0A5FFA0B0A5FF
+ 9CACA1FF96A59DFFB2C2BBFFCCDCD5FFCEDED7FFB8C8C1FFA3B3ACFF91A19AFF
+ 85958EFF879790FF778780FF8C9C95FF9EAEA7FFA0B0A9FF757E7BFF707976FF
+ 69726FFF6C7572FF565F5CFF545D5AFF727B78FF6C7572FF3D4643FF28312EFF
+ 3E4744FF6B7471FF818A87FF949D9AFFABB4B1FFB0BBB8FFA0AFABFF9AABA7FF
+ 9DAEAAFFA3B4B0FFA3B4B0FF9AABA7FF95A6A2FF95A6A2FF97A8A4FF95A6A2FF
+ 93A4A0FF93A4A0FF94A5A1FF95A6A2FF95A6A2FF95A6A2FF8A9B97FF879894FF
+ 889995FF8E9F9BFF8D9E9AFF849591FF80918DFF81928EFF71827EFF82938FFF
+ 8D9E9AFF849591FF8A9B97FF839490FF8A9B97FF92A39FFF82918DFF83928EFF
+ 85938FFF84928EFF82908CFF7F8D89FF808B88FF7F8A87FF87908DFF7D8683FF
+ 737C79FF5D6663FF7B827FFF707774FF484F4CFF070E0BFF141D1AFF1F2825FF
+ 363F3CFF525B58FF656E6BFF6E7774FF707976FF717A77FF79827FFF7C8582FF
+ 808986FF858E8BFF87908DFF87908DFF858E8BFF828B88FF9EA9A6FF96A19EFF
+ 86918EFF788380FF737E7BFF77827FFF7F8A87FF838E8BFF8E9996FF919C99FF
+ 97A29FFF9EA9A6FFA4AFACFFA8B3B0FFAAB5B2FFA9B7B3FF9EAFACFFB8CBC8FF
+ B8CBC8FFA6B9B6FFAEBFBCFFB6C7C4FFA6B7B4FF92A3A0FF98A6A4FF92A09EFF
+ 96A3A1FF94A19FFF8C9997FF909D9BFF929D9BFF83908EFF8B9995FF808F8BFF
+ 8A9894FF7F8D89FF697773FF283632FF697471FF6F7A77FF6E7774FF646D6AFF
+ 68716EFF5D6663FF636A67FF727976FF686F6CFF68716EFF69726FFF646F6CFF
+ 66716EFF6C7774FF6D7875FF6B7673FF6F7A77FF77827FFF747F7CFF76817EFF
+ 7A8582FF7C8784FF7B8683FF7E8986FF8F9A97FFA1ACA9FF84928EFF8F9D99FF
+ 919F9BFF869490FF818F8BFF879591FF899793FF84928EFF94A29EFF9BA9A5FF
+ 99A7A3FF8F9D99FF94A29EFFA9B7B3FFBDCBC7FFC3D2CEFFC1D2CEFFBFD3CEFF
+ BFD3CEFFBFD3CEFFC2D3CFFFC4D5D1FFC5D6D2FFC6D7D3FFC7D6D2FFBBCAC6FF
+ B1BFBBFFABB9B5FF919F9BFF8D9B97FF8F9A97FF57625FFF677571FF687672FF
+ 6E7C78FF75837FFF768480FF778581FF83918DFF919F9BFF8F9D99FF93A19DFF
+ 99A7A3FF9FADA9FFA1AFABFF9DABA7FF99A7A3FF97A5A1FF93A19BFF92A09AFF
+ 95A39DFF98A6A0FF97A59FFF96A49EFF9BA9A3FFA3B1ABFF9DABA5FFA0AEA8FF
+ 9FADA7FF9BA9A3FF9DABA5FFA3B1ABFFA2B0AAFF9DABA5FFA1AFA9FF9FADA7FF
+ 9CAAA4FF9BA9A3FF9DABA5FFA0AEA8FFA1AFA9FFA1AFA9FFA3B1ABFFA3B1ABFF
+ A1AFA9FFA0AEA8FF9EACA6FF9CAAA4FF9BA9A3FF9AA8A2FF9AA6A0FF9CA8A2FF
+ 98A49EFF8F9B95FF8C9892FF838F89FF48544EFF838F89FF808C86FF7E8A84FF
+ 7D8983FF7D8983FF7E8A84FF7C8882FF78847EFF75817BFF7A847EFF7A847EFF
+ 77817BFF727C76FF747E78FF7B857FFF808A84FF7F8983FF7B857FFF7D8781FF
+ 808A84FF818B85FF828C86FF848E88FF89938DFF8C978FFF8F9C94FF94A297FF
+ 96A499FF96A499FF9AA89DFFA2B0A5FFA7B5AAFFA6B4A9FFA5B3A8FFA8B6ABFF
+ ACBAAFFFADBBB0FFAAB8ADFFA7B5AAFFA7B5AAFFA8B6ABFFABBBB0FF9FAFA4FF
+ 98A89DFF9EAEA3FFA5B5AAFFA4B4A9FFA0B0A5FF9EAEA3FF9AAA9FFF9DADA2FF
+ 9EAEA3FF9FAFA4FFA1B1A6FFA2B2A7FF9BABA0FF91A196FFACBCB5FFCADAD3FF
+ D2E2DBFFC1D1CAFFAFBFB8FF9BABA4FF8B9B94FF8A9A93FF7B8B84FF8E9E97FF
+ 9FAFA8FFA2B2ABFF717A77FF79827FFF707976FF727B78FF68716EFF5F6865FF
+ 6E7774FF6A7370FF4F5855FF2B3431FF303936FF5D6663FF828B88FF9AA3A0FF
+ AFB8B5FFB6C1BEFFA9B8B4FFA4B5B1FFA6B7B3FFABBCB8FFABBCB8FFA1B2AEFF
+ 96A7A3FF91A29EFF98A9A5FF99AAA6FF99AAA6FF97A8A4FF96A7A3FF96A7A3FF
+ 97A8A4FF99AAA6FF8D9E9AFF8A9B97FF8B9C98FF8D9E9AFF8A9B97FF839490FF
+ 80918DFF81928EFF7B8C88FF8D9E9AFF95A6A2FF8FA09CFF778884FF839490FF
+ 8D9E9AFF8FA09CFF859490FF82918DFF7F8D89FF7B8985FF798783FF788682FF
+ 7B8683FF7B8683FF7D8683FF7C8582FF727B78FF5E6764FF7F8683FF686F6CFF
+ 474E4BFF29302DFF515A57FF535C59FF5C6562FF6A7370FF737C79FF727B78FF
+ 717A77FF737C79FF7F8885FF7D8683FF7E8784FF848D8AFF8B9491FF8C9592FF
+ 868F8CFF808986FF99A4A1FFA0ABA8FF939E9BFF747F7CFF66716EFF727D7AFF
+ 7C8784FF7A8582FF7E8986FF818C89FF86918EFF8C9794FF95A09DFF9CA7A4FF
+ A3AEABFFA4B2AEFFA8B9B6FFC1D4D1FFBFD2CFFFAABDBAFFADBEBBFFB0C1BEFF
+ A0B1AEFF8E9F9CFF9AA8A6FF95A3A1FF97A4A2FF909D9BFF83908EFF879492FF
+ 8E9997FF84918FFF879591FF7F8E8AFF889692FF7C8A86FF6C7A76FF273531FF
+ 616C69FF67726FFF6E7774FF68716EFF6E7774FF616A67FF636A67FF707774FF
+ 69706DFF6C7572FF6C7572FF6A7572FF6D7875FF717C79FF717C79FF6F7A77FF
+ 727D7AFF788380FF7B8683FF77827FFF75807DFF747F7CFF737E7BFF76817EFF
+ 838E8BFF919C99FF889692FF919F9BFF98A6A2FF93A19DFF889692FF818F8BFF
+ 85938FFF8D9B97FF909E9AFF97A5A1FF9BA9A5FF96A4A0FF92A09CFF9CAAA6FF
+ B5C3BFFFCAD9D5FFB9CAC6FFB9CDC8FFBDD1CCFFC1D5D0FFC5D6D2FFC5D6D2FF
+ C4D5D1FFC3D4D0FFC6D5D1FFBCCBC7FFAFBDB9FFA8B6B2FF92A09CFF8D9B97FF
+ 8E9996FF5E6966FF677571FF606E6AFF65736FFF73817DFF788682FF768480FF
+ 808E8AFF919F9BFF899793FF8D9B97FF92A09CFF96A4A0FF99A7A3FF99A7A3FF
+ 98A6A2FF96A4A0FF909E98FF919F99FF96A49EFF99A7A1FF97A59FFF94A29CFF
+ 9AA8A2FFA4B2ACFF9FADA7FFA3B1ABFFA2B0AAFF9DABA5FF9BA9A3FF9EACA6FF
+ 9FADA7FF9EACA6FFA1AFA9FFA1AFA9FFA0AEA8FF9EACA6FF9DABA5FF9DABA5FF
+ 9FADA7FFA2B0AAFFA6B4AEFFA5B3ADFFA2B0AAFF9FADA7FF9CAAA4FF99A7A1FF
+ 97A59FFF96A49EFF98A49EFF99A59FFF9AA6A0FF939F99FF919D97FF828E88FF
+ 525E58FF84908AFF7B8781FF7A8680FF78847EFF78847EFF79857FFF77837DFF
+ 74807AFF717D77FF757F79FF78827CFF78827CFF757F79FF76807AFF7C8680FF
+ 7F8983FF7E8882FF7A847EFF7D8781FF7F8983FF818B85FF828C86FF848E88FF
+ 88928CFF8C978FFF909D95FF94A297FF96A499FF96A499FF9AA89DFFA2B0A5FF
+ A6B4A9FFA4B2A7FFA1AFA4FFA4B2A7FFA8B6ABFFAAB8ADFFA9B7ACFFA8B6ABFF
+ A9B7ACFFAAB8ADFFAABAAFFFA7B7ACFFA0B0A5FF9BABA0FFA0B0A5FFA7B7ACFF
+ A6B6ABFFA0B0A5FF99A99EFF99A99EFF99A99EFF9BABA0FFA1B1A6FFA5B5AAFF
+ 9EAEA3FF92A297FFA1B1AAFFC2D2CBFFD1E1DAFFC8D8D1FFBBCBC4FFA7B7B0FF
+ 92A29BFF8C9C95FF85958EFF94A49DFFA3B3ACFFA8B8B1FF6D7673FF818A87FF
+ 77807DFF79827FFF7A8380FF6E7774FF717A77FF6D7673FF5D6663FF313A37FF
+ 232C29FF4A5350FF7A8380FF99A29FFFB1BAB7FFC0CBC8FFB1C0BCFFAEBFBBFF
+ AFC0BCFFB3C4C0FFB2C3BFFFA8B9B5FF9AABA7FF90A19DFF95A6A2FF97A8A4FF
+ 99AAA6FF98A9A5FF96A7A3FF96A7A3FF98A9A5FF9AABA7FF96A7A3FF95A6A2FF
+ 92A39FFF8FA09CFF889995FF82938FFF80918DFF80918DFF8A9B97FF90A19DFF
+ 94A5A1FF9EAFABFF748581FF839490FF849591FF82938FFF82918DFF7E8D89FF
+ 7A8884FF75837FFF74827EFF73817DFF747F7CFF737E7BFF737C79FF7C8582FF
+ 737C79FF5A6360FF757C79FF5A615EFF535A57FF626966FF7F8885FF6E7774FF
+ 616A67FF646D6AFF6B7471FF6E7774FF737C79FF79827FFF808986FF7F8885FF
+ 808986FF858E8BFF8C9592FF8E9794FF8B9491FF87908DFF95A09DFFAFBAB7FF
+ ACB7B4FF838E8BFF697471FF727D7AFF7C8784FF77827FFF77827FFF788380FF
+ 7A8582FF7E8986FF848F8CFF8C9794FF929D9AFF94A29EFFA5B6B3FFBED1CEFF
+ BED1CEFFACBFBCFFACBDBAFFADBEBBFF9FB0ADFF91A29FFF97A5A3FF93A19FFF
+ 95A2A0FF8A9795FF7A8785FF7E8B89FF8A9593FF84918FFF818F8BFF7E8D89FF
+ 83918DFF788682FF6E7C78FF263430FF596461FF606B68FF656E6BFF636C69FF
+ 6F7875FF636C69FF626966FF6D7471FF666D6AFF6B7471FF727B78FF717C79FF
+ 737E7BFF737E7BFF717C79FF717C79FF76817EFF7C8784FF7F8A87FF798481FF
+ 747F7CFF747F7CFF737E7BFF737E7BFF798481FF818C89FF96A4A0FF95A39FFF
+ 98A6A2FF98A6A2FF8C9A96FF808E8AFF85938FFF93A19DFF899793FF8D9B97FF
+ 93A19DFF95A39FFF8F9D99FF919F9BFFACBAB6FFCAD9D5FFB2C3BFFFB3C7C2FF
+ B9CDC8FFBED2CDFFC5D6D2FFC8D9D5FFCADBD7FFCADBD7FFC8D7D3FFC1D0CCFF
+ AFBDB9FFA7B5B1FF94A29EFF8B9995FF8B9693FF636E6BFF6B7975FF606E6AFF
+ 63716DFF74827EFF7A8884FF75837FFF7C8A86FF8C9A96FF879591FF8C9A96FF
+ 909E9AFF919F9BFF94A29EFF97A5A1FF97A5A1FF95A39FFF95A39DFF98A6A0FF
+ 9CAAA4FF9EACA6FF99A7A1FF94A29CFF99A7A1FFA3B1ABFFA0AEA8FFA5B3ADFF
+ A7B5AFFFA3B1ABFF9DABA5FF9AA8A2FF9AA8A2FF9AA8A2FF9AA8A2FF9DABA5FF
+ 9FADA7FF9EACA6FF9BA9A3FF9BA9A3FF9FADA7FFA4B2ACFFA5B3ADFFA4B2ACFF
+ A2B0AAFF9EACA6FF9BA9A3FF97A59FFF95A39DFF94A29CFF96A29CFF97A39DFF
+ 9AA6A0FF94A09AFF919D97FF7A8680FF59655FFF808C86FF79857FFF77837DFF
+ 76827CFF76827CFF78847EFF78847EFF76827CFF74807AFF727C76FF757F79FF
+ 757F79FF717B75FF707A74FF76807AFF7A847EFF7A847EFF78827CFF7A847EFF
+ 7D8781FF7E8882FF7F8983FF828C86FF86908AFF89948CFF8C9991FF909E93FF
+ 92A095FF94A297FF9AA89DFFA3B1A6FFA6B4A9FFA3B1A6FF9FADA2FFA1AFA4FF
+ A3B1A6FFA5B3A8FFA6B4A9FFA6B4A9FFA6B4A9FFA6B4A9FFAABAAFFFAFBFB4FF
+ A8B8ADFF9AAA9FFF9AAA9FFFA7B7ACFFA9B9AEFFA0B0A5FF96A69BFF98A89DFF
+ 97A79CFF96A69BFF9BABA0FFA2B2A7FFA2B2A7FF9CACA1FF98A8A1FFBACAC3FF
+ CCDCD5FFC8D8D1FFC1D1CAFFB0C0B9FF9AAAA3FF92A29BFF8D9D96FF96A69FFF
+ A0B0A9FFA6B6AFFF69726FFF7F8885FF77807DFF7B8481FF808986FF77807DFF
+ 77807DFF6E7774FF57605DFF303936FF161F1CFF2F3835FF626B68FF8A9390FF
+ AAB3B0FFC3CECBFFADBBB7FFAEBDB9FFB2C1BDFFB6C5C1FFB7C6C2FFB3C2BEFF
+ A8B7B3FF9FAEAAFF94A39FFF96A5A1FF97A6A2FF98A7A3FF97A6A2FF97A6A2FF
+ 98A7A3FF99A8A4FF9FAEAAFF9FAEAAFF9CABA7FF94A39FFF8C9B97FF899894FF
+ 899894FF899894FF93A29EFF8C9B97FF8F9E9AFFA8B7B3FF889793FF8F9E9AFF
+ 879692FF81908CFF7A8985FF768581FF73817DFF717F7BFF707E7AFF6D7B77FF
+ 6A7572FF66716EFF767F7CFF79827FFF6A7370FF505956FF6B726FFF505754FF
+ 525956FF6D7471FF78817EFF636C69FF59625FFF67706DFF77807DFF7B8481FF
+ 79827FFF7A8380FF7E8784FF7F8885FF828B88FF868F8CFF8A9390FF8E9794FF
+ 919A97FF939C99FF8C9794FFB0BBB8FFBAC5C2FF97A29FFF75807DFF737E7BFF
+ 77827FFF737E7BFF7C8784FF7C8784FF7E8986FF808B88FF85908DFF8A9592FF
+ 8E9996FF8F9D99FF97A8A5FFB3C6C3FFB8CBC8FFABBEBBFFADBEBBFFADBEBBFF
+ A2B3B0FF99AAA7FF94A2A0FF919F9DFF93A09EFF889593FF778482FF7B8886FF
+ 899492FF859290FF7C8A86FF7C8B87FF7D8B87FF72807CFF717F7BFF283632FF
+ 545F5CFF5D6865FF59625FFF5B6461FF6C7572FF626B68FF616865FF69706DFF
+ 606764FF656E6BFF717A77FF727D7AFF737E7BFF6E7976FF6B7673FF6E7976FF
+ 75807DFF7B8683FF818C89FF7C8784FF798481FF7B8683FF7A8582FF77827FFF
+ 77827FFF7A8582FF8D9B97FF879591FF8A9894FF93A19DFF8F9D99FF83918DFF
+ 82908CFF8B9995FF879591FF869490FF8C9A96FF92A09CFF8F9D99FF919F9BFF
+ AAB8B4FFC7D6D2FFB7C8C4FFB6CAC5FFB8CCC7FFBBCFCAFFC2D3CFFFC7D8D4FF
+ CCDDD9FFCFE0DCFFC7D6D2FFC4D3CFFFADBBB7FFA5B3AFFF98A6A2FF8D9B97FF
+ 8C9794FF6E7976FF6A7874FF62706CFF65736FFF75837FFF7B8985FF788682FF
+ 7E8C88FF8C9A96FF899793FF8F9D99FF92A09CFF909E9AFF92A09CFF98A6A2FF
+ 98A6A2FF94A29EFF97A59FFF99A7A1FF9DABA5FF9FADA7FF9BA9A3FF96A49EFF
+ 9AA8A2FFA2B0AAFF9BA9A3FFA0AEA8FFA6B4AEFFA7B5AFFFA3B1ABFF9DABA5FF
+ 9BA9A3FF9CAAA4FF9BA9A3FF9EACA6FFA1AFA9FFA0AEA8FF9CAAA4FF9CAAA4FF
+ 9FADA7FFA3B1ABFFA2B0AAFFA1AFA9FF9FADA7FF9CAAA4FF9AA8A2FF97A59FFF
+ 95A39DFF94A29CFF95A19BFF939F99FF98A49EFF919D97FF8E9A94FF6E7A74FF
+ 5C6862FF79857FFF76827CFF74807AFF737F79FF737F79FF76827CFF77837DFF
+ 76827CFF75817BFF707A74FF737D77FF707A74FF69736DFF66706AFF6B756FFF
+ 717B75FF737D77FF757F79FF77817BFF79837DFF7B857FFF7C8680FF7E8882FF
+ 828C86FF869189FF85928AFF89978CFF8C9A8FFF909E93FF99A79CFFA4B2A7FF
+ A6B4A9FFA3B1A6FFA3B1A6FFA3B1A6FFA3B1A6FFA4B2A7FFA5B3A8FFA5B3A8FF
+ A4B2A7FFA3B1A6FFA9B9AEFFB3C3B8FFADBDB2FF9AAA9FFF96A69BFFA3B3A8FF
+ A8B8ADFFA0B0A5FF93A398FF97A79CFF96A69BFF90A095FF90A095FF98A89DFF
+ A1B1A6FFA5B5AAFF98A8A1FFB8C8C1FFC9D9D2FFC8D8D1FFC6D6CFFFB9C9C2FF
+ A5B5AEFF9DADA6FF90A099FF93A39CFF98A8A1FF9DADA6FF69726FFF77807DFF
+ 737C79FF78817EFF79827FFF77807DFF7D8683FF69726FFF4B5451FF363F3CFF
+ 19221FFF1D2623FF48514EFF747D7AFF99A29FFFBAC5C2FFABB9B5FFB0BFBBFF
+ B4C3BFFFB2C1BDFFB1C0BCFFAFBEBAFFA9B8B4FFA3B2AEFF99A8A4FF97A6A2FF
+ 96A5A1FF97A6A2FF99A8A4FF98A7A3FF96A5A1FF93A29EFF9BAAA6FF9EADA9FF
+ 9BAAA6FF91A09CFF8A9995FF8C9B97FF8F9E9AFF91A09CFF9CABA7FF96A5A1FF
+ 93A29EFF9EADA9FF95A4A0FF96A5A1FF899894FF7C8B87FF7B8A86FF788783FF
+ 768480FF75837FFF75837FFF717F7BFF6B7673FF646F6CFF767F7CFF6B7471FF
+ 5F6865FF515A57FF717875FF5F6663FF5D6461FF666D6AFF7A8380FF626B68FF
+ 58615EFF69726FFF7B8481FF7D8683FF7A8380FF7C8582FF7E8784FF7E8784FF
+ 7F8885FF818A87FF858E8BFF8C9592FF949D9AFF99A29FFF818C89FF9EA9A6FF
+ B1BCB9FFA3AEABFF87928FFF76817EFF717C79FF6F7A77FF7A8582FF7C8784FF
+ 818C89FF86918EFF8B9693FF8F9A97FF919C99FF919F9BFF8C9D9AFFAABDBAFF
+ B5C8C5FFACBFBCFFAEBFBCFFACBDBAFFA2B3B0FF9DAEABFF93A19FFF919F9DFF
+ 93A09EFF899694FF798684FF7B8886FF879290FF818E8CFF768480FF7A8985FF
+ 778581FF6C7A76FF74827EFF2A3834FF525D5AFF5F6A67FF565F5CFF57605DFF
+ 68716EFF5F6865FF5F6663FF666D6AFF5C6360FF5F6865FF68716EFF6D7875FF
+ 6E7976FF687370FF646F6CFF687370FF707B78FF75807DFF818C89FF7E8986FF
+ 7F8A87FF838E8BFF818C89FF7C8784FF7B8683FF7F8A87FF7F8D89FF7C8A86FF
+ 83918DFF92A09CFF97A5A1FF8F9D99FF869490FF869490FF899793FF8A9894FF
+ 8E9C98FF93A19DFF92A09CFF96A4A0FFADBBB7FFC5D4D0FFC0D1CDFFBCD0CBFF
+ BACEC9FFB9CDC8FFBDCECAFFC2D3CFFFC7D8D4FFCBDCD8FFC3D2CEFFC3D2CEFF
+ AAB8B4FFA3B1ADFF9DABA7FF919F9BFF919C99FF7E8986FF616F6BFF63716DFF
+ 697773FF73817DFF798783FF7D8B87FF85938FFF8F9D99FF899793FF92A09CFF
+ 95A39FFF919F9BFF94A29EFF9BA9A5FF9BA9A5FF94A29EFF95A39DFF94A29CFF
+ 98A6A0FF9DABA5FF9DABA5FF9AA8A2FF9BA9A3FFA0AEA8FF97A59FFF99A7A1FF
+ 9FADA7FFA6B4AEFFA7B5AFFFA2B0AAFFA0AEA8FFA3B1ABFFA4B2ACFFA5B3ADFF
+ A5B3ADFFA4B2ACFFA1AFA9FF9FADA7FFA0AEA8FFA1AFA9FF9FADA7FF9EACA6FF
+ 9DABA5FF9BA9A3FF99A7A1FF97A59FFF95A39DFF94A29CFF939F99FF8E9A94FF
+ 94A09AFF8D9993FF89958FFF636F69FF616D67FF75817BFF74807AFF717D77FF
+ 6F7B75FF6F7B75FF707C76FF717D77FF717D77FF6F7B75FF6E7872FF717B75FF
+ 6E7872FF656F69FF606A64FF656F69FF6C7670FF6F7973FF727C76FF757F79FF
+ 77817BFF79837DFF79837DFF7C8680FF808A84FF848F87FF818E86FF859388FF
+ 88968BFF8E9C91FF99A79CFFA4B2A7FFA6B4A9FFA1AFA4FFA8B6ABFFA6B4A9FF
+ A4B2A7FFA4B2A7FFA5B3A8FFA5B3A8FFA3B1A6FFA2B0A5FFA4B4A9FFAFBFB4FF
+ ACBCB1FF9CACA1FF95A59AFF9FAFA4FFA6B6ABFFA4B4A9FF95A59AFF9AAA9FFF
+ 99A99EFF8F9F94FF8A9A8FFF90A095FF9CACA1FFA3B3A8FF9EAEA7FFBBCBC4FF
+ C9D9D2FFC9D9D2FFCCDCD5FFC3D3CCFFB1C1BAFFA9B9B2FF9AAAA3FF97A7A0FF
+ 98A8A1FF9DADA6FF6F7875FF727B78FF717A77FF78817EFF6F7875FF747D7AFF
+ 838C89FF646D6AFF424B48FF454E4BFF29322FFF151E1BFF2D3633FF525B58FF
+ 77807DFF9AA5A2FFA6B4B0FFAEBDB9FFB1C0BCFFABBAB6FFA5B4B0FFA6B5B1FF
+ A7B6B2FFA5B4B0FFA4B3AFFF9FAEAAFF99A8A4FF9AA9A5FF9DACA8FF9BAAA6FF
+ 94A39FFF8C9B97FF909F9BFF95A4A0FF91A09CFF859490FF7E8D89FF81908CFF
+ 879692FF899894FF96A5A1FFA1B0ACFF99A8A4FF7F8E8AFF8F9E9AFF99A8A4FF
+ 92A19DFF7B8A86FF81908CFF7D8C88FF7A8884FF7A8884FF7B8985FF788682FF
+ 727D7AFF6B7673FF6C7572FF626B68FF67706DFF5C6562FF707774FF656C69FF
+ 707774FF717875FF7D8683FF67706DFF5D6663FF69726FFF737C79FF717A77FF
+ 747D7AFF7D8683FF838C89FF7D8683FF77807DFF78817EFF818A87FF8B9491FF
+ 929B98FF969F9CFF828D8AFF8B9693FF9EA9A6FFABB6B3FFA0ABA8FF85908DFF
+ 75807DFF75807DFF75807DFF7A8582FF838E8BFF8B9693FF929D9AFF949F9CFF
+ 949F9CFF919F9BFF8A9B98FFA9BCB9FFB7CAC7FFB1C4C1FFB0C1BEFFA9BAB7FF
+ 9DAEABFF99AAA7FF919F9DFF8D9B99FF909D9BFF879492FF778482FF788583FF
+ 7F8A88FF74817FFF72807CFF788783FF72807CFF677571FF75837FFF2D3B37FF
+ 535E5BFF636E6BFF5E6764FF5C6562FF666F6CFF5B6461FF5B625FFF646B68FF
+ 5A615EFF5D6663FF5F6865FF687370FF6F7A77FF6A7572FF65706DFF687370FF
+ 6D7875FF6F7A77FF828D8AFF818C89FF838E8BFF86918EFF848F8CFF808B88FF
+ 838E8BFF8A9592FF85938FFF84928EFF879591FF8E9C98FF94A29EFF94A29EFF
+ 909E9AFF8D9B97FF8B9995FF92A09CFF97A5A1FF95A39FFF909E9AFF97A5A1FF
+ ADBBB7FFC2D1CDFFC2D3CFFFBDD1CCFFBACEC9FFB8CCC7FFBACBC7FFBECFCBFF
+ C3D4D0FFC6D7D3FFC3D2CEFFC6D5D1FFAAB8B4FFA2B0ACFFA1AFABFF93A19DFF
+ 939E9BFF87928FFF5B6965FF677571FF707E7AFF717F7BFF74827EFF7D8B87FF
+ 879591FF8B9995FF869490FF919F9BFF96A4A0FF93A19DFF96A4A0FFA0AEAAFF
+ 9FADA9FF96A4A0FF9BA9A3FF97A59FFF97A59FFF9DABA5FFA1AFA9FF9EACA6FF
+ 9CAAA4FF9DABA5FF9EACA6FF99A7A1FF9AA8A2FFA2B0AAFFA5B3ADFFA3B1ABFF
+ A2B0AAFFA6B4AEFFA5B3ADFFA4B2ACFFA3B1ABFFA3B1ABFFA4B2ACFFA4B2ACFF
+ A2B0AAFFA0AEA8FF9FADA7FF9EACA6FF9CAAA4FF9AA8A2FF97A59FFF95A39DFF
+ 93A19BFF92A09AFF909C96FF89958FFF909C96FF89958FFF86928CFF5C6862FF
+ 68746EFF75817BFF77837DFF74807AFF6F7B75FF6D7973FF6C7872FF6C7872FF
+ 6A7670FF68746EFF68726CFF6E7872FF6F7973FF68726CFF636D67FF66706AFF
+ 6B756FFF6E7872FF727C76FF747E78FF77817BFF78827CFF79837DFF7C8680FF
+ 808A84FF838E86FF828F87FF859388FF88968BFF8E9C91FF9AA89DFFA5B3A8FF
+ A5B3A8FF9FADA2FFA5B3A8FFA2B0A5FF9FADA2FF9FADA2FFA1AFA4FFA2B0A5FF
+ A1AFA4FF9EACA1FF9CACA1FFA6B6ABFFA8B8ADFF9DADA2FF96A69BFF9BABA0FF
+ A5B5AAFFAABAAFFFA3B3A8FFA6B6ABFFA2B2A7FF97A79CFF91A196FF94A499FF
+ 99A99EFF9BABA0FFA0B0A9FFBCCCC5FFC9D9D2FFCBDBD4FFD0E0D9FFC8D8D1FF
+ B6C6BFFFADBDB6FFA0B0A9FF99A9A2FF98A8A1FF9FAFA8FF78817EFF727B78FF
+ 737C79FF79827FFF69726FFF747D7AFF89928FFF636C69FF3B4441FF4D5653FF
+ 333C39FF0E1714FF161F1CFF323B38FF525B58FF747F7CFF94A29EFFA0AFABFF
+ A7B6B2FFA2B1ADFF9FAEAAFFA7B6B2FFAFBEBAFFB2C1BDFFAFBEBAFFA6B5B1FF
+ 9EADA9FF9DACA8FFA1B0ACFF9EADA9FF93A29EFF889793FF879692FF8C9B97FF
+ 879692FF788783FF6F7E7AFF73827EFF788783FF798884FF7E8D89FF9DACA8FF
+ 95A4A0FF5E6D69FF84938FFF9EADA9FFA4B3AFFF879692FF82918DFF7C8B87FF
+ 788682FF778581FF788682FF768480FF727D7AFF6C7774FF656E6BFF666F6CFF
+ 79827FFF656E6BFF5D6461FF525956FF727976FF7B827FFF646D6AFF5A6360FF
+ 5F6865FF737C79FF79827FFF6F7875FF6E7774FF79827FFF89928FFF7C8582FF
+ 707976FF717A77FF7E8784FF8B9491FF909996FF8F9895FF899491FF818C89FF
+ 929D9AFFB2BDBAFFB5C0BDFF96A19EFF7F8A87FF7F8A87FF77827FFF7E8986FF
+ 899491FF939E9BFF99A4A1FF9AA5A2FF98A3A0FF93A19DFF8E9F9CFFADC0BDFF
+ BCCFCCFFB5C8C5FFB1C2BFFFA6B7B4FF98A9A6FF94A5A2FF8D9B99FF899795FF
+ 8B9896FF83908EFF74817FFF727F7DFF75807EFF677472FF707E7AFF778682FF
+ 6E7C78FF64726EFF778581FF2F3D39FF545F5CFF66716EFF69726FFF626B68FF
+ 67706DFF58615EFF585F5CFF636A67FF5A615EFF5D6663FF5A6360FF687370FF
+ 737E7BFF707B78FF6B7673FF6C7774FF6E7976FF6C7774FF838E8BFF828D8AFF
+ 85908DFF87928FFF848F8CFF828D8AFF899491FF939E9BFF93A19DFF909E9AFF
+ 899793FF82908CFF84928EFF8C9A96FF93A19DFF95A39FFF899793FF97A5A1FF
+ 9FADA9FF96A4A0FF8C9A96FF93A19DFFABB9B5FFBFCECAFFBCCDC9FFB9CDC8FF
+ B7CBC6FFB7CBC6FFBBCCC8FFBECFCBFFC3D4D0FFC5D6D2FFC8D7D3FFCBDAD6FF
+ ADBBB7FFA3B1ADFFA2B0ACFF92A09CFF909B98FF87928FFF5B6965FF6E7C78FF
+ 778581FF707E7AFF6E7C78FF7A8884FF84928EFF83918DFF82908CFF8F9D99FF
+ 96A4A0FF93A19DFF98A6A2FFA3B1ADFFA2B0ACFF99A7A3FFA6B4AEFF9FADA7FF
+ 9CAAA4FFA2B0AAFFA5B3ADFFA1AFA9FF9BA9A3FF99A7A1FFABB9B3FF9FADA7FF
+ 9AA8A2FF9EACA6FFA1AFA9FF9FADA7FF9FADA7FFA4B2ACFF9FADA7FF9DABA5FF
+ 9CAAA4FF9FADA7FFA4B2ACFFA6B4AEFFA4B2ACFFA1AFA9FFA0AEA8FF9FADA7FF
+ 9DABA5FF9AA8A2FF97A59FFF94A29CFF919F99FF909E98FF8E9A94FF86928CFF
+ 8D9993FF87938DFF84908AFF59655FFF6D7973FF78847EFF7D8983FF78847EFF
+ 737F79FF6E7A74FF6C7872FF6A7670FF67736DFF64706AFF646E68FF6D7771FF
+ 717B75FF6C7670FF68726CFF6A746EFF6E7872FF6F7973FF737D77FF757F79FF
+ 78827CFF79837DFF7A847EFF7C8680FF818B85FF848F87FF85928AFF88968BFF
+ 8A988DFF8F9D92FF9BA99EFFA5B3A8FFA4B2A7FF9EACA1FF9EACA1FF9BA99EFF
+ 98A69BFF99A79CFF9CAA9FFF9EACA1FF9CAA9FFF9AA89DFF96A69BFF9EAEA3FF
+ A3B3A8FF9EAEA3FF98A89DFF9AAA9FFFA5B5AAFFAFBFB4FFB2C2B7FFB1C1B6FF
+ ABBBB0FFA2B2A7FF9EAEA3FF9DADA2FF9AAA9FFF95A59AFF9EAEA7FFB9C9C2FF
+ C7D7D0FFCADAD3FFD0E0D9FFC9D9D2FFB5C5BEFFABBBB4FF9CACA5FF93A39CFF
+ 90A099FF98A8A1FF656E6BFF717A77FF6D7673FF737C79FF77807DFF808986FF
+ 838C89FF5B6461FF535C59FF3D4643FF242D2AFF1D2623FF1B2421FF151E1BFF
+ 303936FF626D6AFF8C9A96FF94A29EFFA7B5B1FFB2C0BCFFA7B5B1FF94A29EFF
+ 98A6A2FFAAB8B4FFB8C6C2FFAEBCB8FFA2B0ACFF9FADA9FFA6B4B0FFA5B3AFFF
+ 92A09CFF7C8A86FF84928EFF8E9C98FF889692FF7D8B87FF7B8985FF74827EFF
+ 6C7A76FF717F7BFF7B8985FF93A19DFF6F7D79FF465450FF889692FF909E9AFF
+ 899793FF93A19DFF7C8B87FF7C8B87FF7C8A86FF7A8884FF768480FF72807CFF
+ 717C79FF6E7976FF707976FF646D6AFF79827FFF6C7572FF444B48FF575E5BFF
+ 808784FF707774FF5D6663FF656E6BFF6E7774FF727B78FF727B78FF737C79FF
+ 77807DFF7C8582FF87908DFF808986FF6C7572FF87908DFF8F9895FF7D8683FF
+ 909996FF919A97FF8C9794FF7D8885FF899491FF949F9CFFB5C0BDFF939E9BFF
+ 889390FF87928FFF87928FFF87928FFF889390FF8B9693FF909B98FF95A09DFF
+ 98A3A0FF97A5A1FF899A97FFB1C4C1FFB6C9C6FFB5C8C5FFB2C3C0FF9FB0ADFF
+ 95A6A3FF839491FF8B9997FF8D9B99FF8A9795FF7E8B89FF74817FFF6D7A78FF
+ 677270FF5E6B69FF63716DFF6B7A76FF6E7C78FF697773FF63716DFF32403CFF
+ 505B58FF6D7875FF5F6865FF6A7370FF636C69FF57605DFF5C6360FF5F6663FF
+ 5D6461FF5F6865FF626B68FF616C69FF6A7572FF6B7673FF65706DFF6C7774FF
+ 747F7CFF6E7976FF7C8784FF828D8AFF8A9592FF8E9996FF889390FF818C89FF
+ 838E8BFF8C9794FF83918DFF8B9995FF889692FF7A8884FF788682FF869490FF
+ 92A09CFF92A09CFF95A39FFF92A09CFF9AA8A4FFA1AFABFF95A39FFF899793FF
+ 9DABA7FFBFCECAFFBDCECAFFB9CDC8FFBACEC9FFBFD3CEFFC1D2CEFFBCCDC9FF
+ BACBC7FFBCCDC9FFBFCECAFFC9D8D4FFC5D3CFFFAFBDB9FF9EACA8FF9BA9A5FF
+ 9AA5A2FF929D9AFF606E6AFF7F8D89FF808E8AFF7B8985FF73817DFF75837FFF
+ 869490FF7C8A86FF879591FF8E9C98FF95A39FFF98A6A2FF98A6A2FF9AA8A4FF
+ 9EACA8FFA2B0ACFF909E98FF98A6A0FF9FADA7FFA3B1ABFFA7B5AFFFA9B7B1FF
+ A3B1ABFF9BA9A3FF9CAAA4FF97A59FFF9AA8A2FFA3B1ABFFA7B5AFFFA2B0AAFF
+ 9FADA7FFA1AFA9FFA1AFA9FF9FADA7FF9DABA5FF9BA9A3FF9CAAA4FF9EACA6FF
+ A2B0AAFFA4B2ACFF9FADA7FFA1AFA9FFA2B0AAFF9EACA6FF97A59FFF919F99FF
+ 8F9D97FF909E98FF939F99FF89958FFF88948EFF85918BFF87938DFF3F4B45FF
+ 707C76FF7E8A84FF77837DFF77837DFF76827CFF717D77FF6C7872FF69756FFF
+ 68746EFF69756FFF6B756FFF6C7670FF6F7973FF717B75FF6B756FFF636D67FF
+ 626C66FF68726CFF6A746EFF6D7771FF727C76FF77817BFF7B857FFF7D8781FF
+ 7D8781FF7D8880FF85928AFF839186FF839186FF88968BFF909E93FF96A499FF
+ 99A79CFF99A79CFF9DABA0FFA0AEA3FFA1AFA4FF9EACA1FF9CAA9FFF9DABA0FF
+ 9DABA0FF9BA99EFF9AAA9FFF9EAEA3FFA3B3A8FFA2B2A7FF9EAEA3FF98A89DFF
+ 94A499FF93A398FFAABAAFFFB7C7BCFFBACABFFFAFBFB4FFA8B8ADFFAABAAFFF
+ A5B5AAFF9BABA0FFA1B1AAFFACBCB5FFC3D3CCFFCFDFD8FFCBDBD4FFCADAD3FF
+ BFCFC8FFA7B7B0FF9EAEA7FF97A7A0FF94A49DFF97A7A0FF6C7572FF737C79FF
+ 656E6BFF616A67FF646D6AFF757E7BFF7E8784FF57605DFF454E4BFF37403DFF
+ 262F2CFF242D2AFF212A27FF131C19FF212A27FF48514EFF717C79FF83918DFF
+ A0AEAAFFB5C3BFFFB3C1BDFFA5B3AFFF9EACA8FFA0AEAAFFB0BEBAFFA7B5B1FF
+ 9BA9A5FF95A39FFF9BA9A5FFA1AFABFF9BA9A5FF8F9D99FF8C9A96FF96A4A0FF
+ 919F9BFF8B9995FF8D9B97FF889692FF83918DFF899793FF82908CFF889692FF
+ 6B7975FF3D4B47FF919F9BFF9DABA7FF869490FF808E8AFF7B8A86FF7A8985FF
+ 798783FF778581FF75837FFF74827EFF75807DFF747F7CFF6B7471FF626B68FF
+ 67706DFF707976FF414845FF646B68FF777E7BFF686F6CFF5B6461FF636C69FF
+ 6C7572FF707976FF717A77FF737C79FF77807DFF7C8582FF868F8CFF838C89FF
+ 727B78FF87908DFF8F9895FF838C89FF8F9895FF8A9390FF8C9794FF899491FF
+ 818C89FF949F9CFFACB7B4FFAFBAB7FF98A3A0FF909B98FF919C99FF96A19EFF
+ 939E9BFF8D9895FF929D9AFF9DA8A5FF9CA7A4FF919F9BFF8A9B98FFAFC2BFFF
+ B0C3C0FFADC0BDFFAABBB8FF9AABA8FF95A6A3FF869794FF8B9997FF879593FF
+ 7E8B89FF73807EFF6D7A78FF6A7775FF646F6DFF586563FF5E6C68FF62716DFF
+ 64726EFF5C6A66FF55635FFF293733FF4B5653FF687370FF646D6AFF6F7875FF
+ 68716EFF5E6764FF636A67FF646B68FF606764FF626B68FF5E6764FF606B68FF
+ 6C7774FF6D7875FF65706DFF6C7774FF76817EFF717C79FF7D8885FF7C8784FF
+ 7E8986FF838E8BFF838E8BFF808B88FF828D8AFF87928FFF899793FF94A29EFF
+ 93A19DFF85938FFF7E8C88FF85938FFF8B9995FF899793FF919F9BFF8D9B97FF
+ 96A4A0FFA5B3AFFFA2B0ACFF97A5A1FFA1AFABFFB9C8C4FFBBCCC8FFB7CBC6FF
+ B8CCC7FFBED2CDFFC2D3CFFFC0D1CDFFC0D1CDFFC4D5D1FFC7D6D2FFC5D4D0FF
+ C0CECAFFB3C1BDFFA1AFABFF94A29EFF97A29FFF9FAAA7FF6A7874FF899793FF
+ 869490FF7D8B87FF788682FF7C8A86FF8F9D99FF899793FF818F8BFF899793FF
+ 92A09CFF97A5A1FF98A6A2FF9AA8A4FF9DABA7FFA1AFABFF97A59FFF9BA9A3FF
+ 9FADA7FFA2B0AAFFA7B5AFFFACBAB4FFA7B5AFFF9FADA7FFA1AFA9FF9CAAA4FF
+ 9DABA5FFA4B2ACFFA7B5AFFFA3B1ABFFA1AFA9FFA3B1ABFFA1AFA9FFA0AEA8FF
+ 9EACA6FF9DABA5FF9DABA5FF9DABA5FF9DABA5FF9EACA6FF97A59FFF9AA8A2FF
+ 9CAAA4FF9AA8A2FF95A39DFF909E98FF8D9B95FF8D9B95FF939F99FF8B9791FF
+ 8B9791FF85918BFF828E88FF37433DFF64706AFF6F7B75FF717D77FF727E78FF
+ 727E78FF707C76FF6C7872FF6A7670FF6A7670FF6B7771FF6F7973FF6F7973FF
+ 6F7973FF6F7973FF67716BFF5D6761FF5C6660FF616B65FF656F69FF6C7670FF
+ 757F79FF78827CFF76807AFF76807AFF79837DFF7E8981FF818E86FF829085FF
+ 859388FF8D9B90FF95A398FF9BA99EFF9DABA0FF9CAA9FFF9EACA1FF9EACA1FF
+ 9FADA2FFA1AFA4FFA1AFA4FFA0AEA3FFA1AFA4FFA3B1A6FF9BABA0FF9EAEA3FF
+ A3B3A8FFA6B6ABFFA6B6ABFFA3B3A8FFA1B1A6FF9FAFA4FFA3B3A8FFAABAAFFF
+ B1C1B6FFB2C2B7FFABBBB0FFA5B5AAFFA9B9AEFFB1C1B6FFA0B0A9FFA9B9B2FF
+ BFCFC8FFCCDCD5FFCADAD3FFC9D9D2FFBFCFC8FFA9B9B2FF99A9A2FF93A39CFF
+ 91A19AFF95A59EFF68716EFF727B78FF636C69FF5D6663FF616A67FF79827FFF
+ 848D8AFF5B6461FF444D4AFF3B4441FF2D3633FF2B3431FF28312EFF17201DFF
+ 19221FFF353E3BFF5E6966FF7C8784FF9FAAA7FFB5C0BDFFBBC6C3FFB5C0BDFF
+ A8B3B0FF9CA7A4FFA5B0ADFFA3AEABFF9DA8A5FF96A19EFF98A3A0FF9EA9A6FF
+ 9FAAA7FF9BA6A3FF8E9996FF96A19EFF939E9BFF909B98FF95A09DFF929D9AFF
+ 8E9996FF96A19EFF9CA7A4FF929D9AFF808B88FF394441FF899491FF98A3A0FF
+ 86918EFF82908CFF7A8985FF788783FF75837FFF73817DFF72807CFF74827EFF
+ 788380FF7A8582FF646D6AFF5E6764FF535C59FF6E7774FF3C4340FF6B726FFF
+ 6A716EFF5E6562FF5E6764FF656E6BFF6D7673FF727B78FF737C79FF767F7CFF
+ 7B8481FF7F8885FF818A87FF828B88FF757E7BFF808986FF89928FFF87908DFF
+ 8D9693FF818A87FF818C89FF8F9A97FF808B88FF9BA6A3FFA8B3B0FFC0CBC8FF
+ 98A3A0FF85908DFF8A9592FF9BA6A3FFA0ABA8FF97A29FFF95A09DFF9DA8A5FF
+ 9CA7A4FF8E9C98FF8B9C99FFAEC1BEFFABBEBBFFA5B8B5FFA2B3B0FF96A7A4FF
+ 95A6A3FF899A97FF8D9B99FF859391FF7A8785FF707D7BFF707D7BFF727F7DFF
+ 6E7977FF626F6DFF5F6D69FF5D6C68FF5E6C68FF54625EFF4A5854FF24322EFF
+ 4B5653FF646F6CFF5F6865FF69726FFF646D6AFF5C6562FF616865FF5F6663FF
+ 5A615EFF5C6562FF5C6562FF5E6966FF6A7572FF6B7673FF626D6AFF687370FF
+ 707B78FF6B7673FF85908DFF7F8A87FF7D8885FF828D8AFF889390FF899491FF
+ 8A9592FF8D9895FF889692FF93A19DFF96A4A0FF8C9A96FF85938FFF879591FF
+ 879591FF82908CFF919F9BFF879591FF8C9A96FFA0AEAAFFA5B3AFFF9EACA8FF
+ A5B3AFFFB7C6C2FFBECFCBFFB9CDC8FFB8CCC7FFBDD1CCFFC1D2CEFFC0D1CDFF
+ C3D4D0FFC8D9D5FFCCDBD7FFBECDC9FFB6C4C0FFB2C0BCFFA3B1ADFF92A09CFF
+ 99A4A1FFAAB5B2FF5A6864FF83918DFF818F8BFF75837FFF717F7BFF75837FFF
+ 8B9995FF8B9995FF7D8B87FF85938FFF8F9D99FF95A39FFF97A5A1FF98A6A2FF
+ 9CAAA6FF9FADA9FF9EACA6FF9EACA6FF9CAAA4FF9DABA5FFA4B2ACFFACBAB4FF
+ A9B7B1FFA2B0AAFFA4B2ACFF9FADA7FF9EACA6FFA2B0AAFFA4B2ACFFA1AFA9FF
+ A0AEA8FFA1AFA9FFA1AFA9FFA1AFA9FFA1AFA9FFA1AFA9FFA0AEA8FF9DABA5FF
+ 9AA8A2FF99A7A1FF94A29CFF97A59FFF9AA8A2FF9AA8A2FF97A59FFF92A09AFF
+ 8F9D97FF8D9B95FF8E9A94FF8A9690FF8B9791FF838F89FF7D8983FF303C36FF
+ 5B6761FF64706AFF6A7670FF6C7872FF6F7B75FF6E7A74FF6C7872FF6B7771FF
+ 6C7872FF6D7973FF6F7973FF6D7771FF6D7771FF6B756FFF626C66FF59635DFF
+ 59635DFF5E6862FF606A64FF6B756FFF76807AFF77817BFF727C76FF707A74FF
+ 76807AFF7D8880FF7E8B83FF818F84FF87958AFF8F9D92FF96A499FF9BA99EFF
+ 9CAA9FFF9BA99EFF99A79CFF93A196FF95A398FF9DABA0FFA1AFA4FF9EACA1FF
+ A0AEA3FFA8B6ABFF99A99EFF9BABA0FF9EAEA3FFA2B2A7FFA5B5AAFFA4B4A9FF
+ A1B1A6FF9EAEA3FFA5B5AAFFA4B4A9FFABBBB0FFB1C1B6FFA5B5AAFF95A59AFF
+ 9AAA9FFFAEBEB3FFA1B1AAFFA8B8B1FFBDCDC6FFCBDBD4FFC9D9D2FFC6D6CFFF
+ BBCBC4FFA5B5AEFF96A69FFF91A19AFF90A099FF95A59EFF636C69FF727B78FF
+ 6B7471FF67706DFF6A7370FF7C8582FF828B88FF555E5BFF4B5451FF414A47FF
+ 2E3734FF262F2CFF242D2AFF17201DFF18211EFF2D3633FF545F5CFF798481FF
+ 9BA6A3FFA7B2AFFFABB6B3FFAEB9B6FFA6B1AEFF97A29FFF96A19EFF9DA8A5FF
+ 9FAAA7FF9AA5A2FF96A19EFF95A09DFF939E9BFF909B98FF848F8CFF889390FF
+ 838E8BFF838E8BFF899491FF848F8CFF808B88FF8A9592FF949F9CFF95A09DFF
+ 9EA9A6FF4E5956FF87928FFF8A9592FF848F8CFF8E9C98FF7B8985FF768581FF
+ 717F7BFF6D7B77FF6D7B77FF707E7AFF788380FF7C8784FF646D6AFF5B6461FF
+ 4F5855FF616A67FF3D4441FF626966FF626966FF59605DFF68716EFF6D7673FF
+ 737C79FF767F7CFF78817EFF7A8380FF7E8784FF818A87FF7C8582FF7E8784FF
+ 767F7CFF747D7AFF7D8683FF87908DFF89928FFF7C8582FF7E8986FF8B9693FF
+ 828D8AFF939E9BFFA1ACA9FFB4BFBCFF9FAAA7FF99A4A1FF808B88FF909B98FF
+ 9DA8A5FF9DA8A5FF98A3A0FF95A09DFF949F9CFF909E9AFF8D9E9BFFAFC2BFFF
+ AABDBAFFA3B6B3FFA0B1AEFF94A5A2FF94A5A2FF899A97FF869492FF83918FFF
+ 7C8987FF74817FFF73807EFF768381FF76817FFF6E7B79FF65736FFF5F6E6AFF
+ 62706CFF576561FF485652FF263430FF505B58FF616C69FF5A6360FF646D6AFF
+ 606966FF5A6360FF5F6663FF5A615EFF545B58FF58615EFF5F6865FF5B6663FF
+ 626D6AFF636E6BFF5D6865FF636E6BFF67726FFF5C6764FF848F8CFF7F8A87FF
+ 808B88FF87928FFF8D9895FF8E9996FF909B98FF939E9BFF83918DFF889692FF
+ 899793FF879591FF899793FF8E9C98FF8B9995FF83918DFF94A29EFF869490FF
+ 85938FFF94A29EFF9AA8A4FF98A6A2FFA6B4B0FFBDCCC8FFC3D4D0FFBBCFCAFF
+ B9CDC8FFBACEC9FFBDCECAFFBCCDC9FFBFD0CCFFC5D6D2FFC8D7D3FFBBCAC6FF
+ B0BEBAFFAAB8B4FFA1AFABFF98A6A2FF9BA6A3FFA3AEABFF364440FF73817DFF
+ 7A8884FF6E7C78FF6A7874FF6B7975FF808E8AFF899793FF808E8AFF869490FF
+ 8E9C98FF92A09CFF93A19DFF95A39FFF9AA8A4FF9FADA9FFA2B0AAFF9EACA6FF
+ 98A6A0FF97A59FFF9FADA7FFA9B7B1FFA9B7B1FFA3B1ABFFA5B3ADFFA1AFA9FF
+ 9EACA6FF9FADA7FFA0AEA8FF9FADA7FF9EACA6FF9EACA6FFA1AFA9FFA2B0AAFF
+ A5B3ADFFA5B3ADFFA4B2ACFFA1AFA9FF9DABA5FF9AA8A2FF99A7A1FF9BA9A3FF
+ 9EACA6FF9FADA7FF9CAAA4FF97A59FFF93A19BFF909E98FF88948EFF85918BFF
+ 86928CFF7C8882FF79857FFF303C36FF5F6B65FF68746EFF68746EFF6B7771FF
+ 6F7B75FF707C76FF6E7A74FF6C7872FF6C7872FF6D7973FF6A746EFF69736DFF
+ 69736DFF68726CFF616B65FF5A645EFF5B655FFF626C66FF606A64FF69736DFF
+ 737D77FF757F79FF727C76FF717B75FF757F79FF7B867EFF7D8A82FF808E83FF
+ 849287FF8A988DFF919F94FF96A499FF98A69BFF99A79CFF93A196FF8A988DFF
+ 8A988DFF96A499FF9CAA9FFF99A79CFF9DABA0FFA8B6ABFFA0B0A5FF9FAFA4FF
+ A0B0A5FFA2B2A7FFA3B3A8FFA2B2A7FF9DADA2FF98A89DFFA2B2A7FFA3B3A8FF
+ A8B8ADFFA9B9AEFF9EAEA3FF8F9F94FF8E9E93FF98A89DFFA0B0A9FFA5B5AEFF
+ BBCBC4FFCCDCD5FFC9D9D2FFC3D3CCFFB4C4BDFF9DADA6FF95A59EFF90A099FF
+ 90A099FF95A59EFF666F6CFF747D7AFF6E7774FF6B7471FF68716EFF717A77FF
+ 77807DFF505956FF4A5350FF414A47FF2D3633FF232C29FF232C29FF1A2320FF
+ 151E1BFF212A27FF424D4AFF6D7875FF939E9BFF9BA6A3FF9BA6A3FFA0ABA8FF
+ 9DA8A5FF929D9AFF919C99FF9AA5A2FF9EA9A6FF98A3A0FF919C99FF8E9996FF
+ 8B9693FF87928FFF85908DFF86918EFF808B88FF818C89FF899491FF828D8AFF
+ 7E8986FF8A9592FF818C89FF8D9895FFA3AEABFF6F7A77FF97A29FFF8C9794FF
+ 85908DFF8B9995FF7C8A86FF758480FF6E7C78FF697773FF687672FF6D7B77FF
+ 76817EFF7B8683FF6E7774FF616A67FF5C6562FF565F5CFF454C49FF535A57FF
+ 646B68FF626966FF707976FF737C79FF767F7CFF78817EFF79827FFF7A8380FF
+ 7C8582FF7E8784FF7E8784FF7D8683FF78817EFF6C7572FF727B78FF858E8BFF
+ 868F8CFF808986FF87928FFF848F8CFF86918EFF828D8AFF9CA7A4FF9BA6A3FF
+ AFBAB7FFC4CFCCFF99A4A1FF8D9895FF889390FF919C99FF98A3A0FF95A09DFF
+ 8F9A97FF8B9995FF90A19EFFB2C5C2FFAEC1BEFFA6B9B6FFA2B3B0FF94A5A2FF
+ 91A29FFF849592FF798785FF7D8B89FF7D8A88FF73807EFF6B7876FF6A7775FF
+ 6B7674FF677472FF65736FFF5B6A66FF62706CFF586662FF44524EFF25332FFF
+ 525D5AFF596461FF5F6865FF67706DFF636C69FF606966FF666D6AFF5F6663FF
+ 5A615EFF606966FF636C69FF596461FF5A6562FF5D6865FF5D6865FF66716EFF
+ 67726FFF57625FFF727D7AFF747F7CFF7B8683FF848F8CFF87928FFF86918EFF
+ 899491FF8E9996FF889692FF82908CFF7C8A86FF7F8D89FF8B9995FF94A29EFF
+ 919F9BFF889692FF93A19DFF889692FF8A9894FF96A4A0FF96A4A0FF92A09CFF
+ A4B2AEFFC0CFCBFFC0D1CDFFB8CCC7FFB5C9C4FFB6CAC5FFB9CAC6FFB9CAC6FF
+ BDCECAFFC3D4D0FFC6D5D1FFC1D0CCFFB3C1BDFFA1AFABFF99A7A3FF9AA8A4FF
+ 97A29FFF8D9895FF1E2C28FF707E7AFF82908CFF778581FF74827EFF6F7D79FF
+ 7F8D89FF8D9B97FF869490FF8A9894FF8E9C98FF8F9D99FF8E9C98FF919F9BFF
+ 98A6A2FF9EACA8FFA3B1ABFFA0AEA8FF9AA8A2FF97A59FFF9EACA6FFA8B6B0FF
+ AAB8B2FFA5B3ADFFA7B5AFFFA5B3ADFFA2B0AAFFA0AEA8FFA0AEA8FFA1AFA9FF
+ A0AEA8FF9DABA5FFA2B0AAFFA3B1ABFFA5B3ADFFA6B4AEFFA6B4AEFFA4B2ACFF
+ A1AFA9FF9FADA7FF9EACA6FF9FADA7FF9FADA7FF9FADA7FF9DABA5FF98A6A0FF
+ 93A19BFF8F9D97FF88948EFF84908AFF808C86FF75817BFF75817BFF34403AFF
+ 64706AFF6C7872FF69756FFF6D7973FF717D77FF727E78FF707C76FF6D7973FF
+ 6C7872FF6B7771FF69736DFF68726CFF6A746EFF69736DFF636D67FF5B655FFF
+ 5C6660FF626C66FF626C66FF67716BFF6D7771FF727C76FF747E78FF76807AFF
+ 77817BFF78837BFF7B8880FF7C8A7FFF808E83FF859388FF8D9B90FF95A398FF
+ 9EACA1FFA3B1A6FF98A69BFF8F9D92FF8D9B90FF96A499FF9DABA0FF9DABA0FF
+ A1AFA4FFAAB8ADFFAABAAFFFAABAAFFFAABAAFFFAABAAFFFA9B9AEFFA6B6ABFF
+ A2B2A7FF9FAFA4FF99A99EFFA4B4A9FFAABAAFFFA6B6ABFFA2B2A7FFA1B1A6FF
+ 99A99EFF8D9D92FF99A9A2FF9CACA5FFB4C4BDFFCADAD3FFCBDBD4FFC3D3CCFF
+ B4C4BDFF9DADA6FF94A49DFF8E9E97FF8D9D96FF91A19AFF656E6BFF6C7572FF
+ 666F6CFF69726FFF656E6BFF6D7673FF818A87FF6F7875FF525B58FF505956FF
+ 424B48FF39423FFF3C4542FF313A37FF212A27FF1F2825FF2F3A37FF5E6966FF
+ 8C9794FF9DA8A5FF9FAAA7FFA1ACA9FF9DA8A5FF96A19EFF9DA8A5FFA0ABA8FF
+ 9EA9A6FF97A29FFF939E9BFF949F9CFF929D9AFF8F9A97FF919C99FF8E9996FF
+ 87928FFF8A9592FF939E9BFF8C9794FF87928FFF949F9CFF98A3A0FF949F9CFF
+ 828D8AFF747F7CFF95A09DFF8E9996FF8B9693FF8A9592FF7B8985FF74837FFF
+ 6D7B77FF677571FF677571FF6C7A76FF76817EFF7C8784FF79827FFF6C7572FF
+ 666F6CFF545D5AFF4D5451FF505754FF686F6CFF6F7673FF737C79FF737C79FF
+ 747D7AFF757E7BFF77807DFF78817EFF79827FFF79827FFF838C89FF7D8683FF
+ 7E8784FF6C7572FF6C7572FF7F8885FF7E8784FF838C89FF7F8A87FF808B88FF
+ 919C99FF899491FFA2ADAAFF8A9592FF9BA6A3FFAAB5B2FFBEC9C6FF9DA8A5FF
+ 808B88FF818C89FF929D9AFF98A3A0FF8F9A97FF818F8BFF92A3A0FFB4C7C4FF
+ AFC2BFFFA7BAB7FFA1B2AFFF90A19EFF8A9B98FF7C8D8AFF778583FF7E8C8AFF
+ 7E8B89FF717E7CFF64716FFF5E6B69FF606B69FF5D6A68FF5E6C68FF505F5BFF
+ 5A6864FF515F5BFF394743FF202E2AFF515C59FF515C59FF616A67FF656E6BFF
+ 616A67FF616A67FF676E6BFF606764FF5C6360FF666F6CFF67706DFF5A6562FF
+ 596461FF5C6764FF5E6966FF6A7572FF6C7774FF5D6865FF65706DFF697471FF
+ 737E7BFF7D8885FF818C89FF7F8A87FF838E8BFF899491FF94A29EFF879591FF
+ 7B8985FF7C8A86FF899793FF93A19DFF919F9BFF8A9894FF8D9B97FF8A9894FF
+ 94A29EFFA2B0ACFF9EACA8FF94A29EFFA4B2AEFFBFCECAFFB8C9C5FFB1C5C0FF
+ B0C4BFFFB3C7C2FFB8C9C5FFB9CAC6FFBFD0CCFFC5D6D2FFC6D5D1FFC8D7D3FF
+ B9C7C3FF9EACA8FF909E9AFF909E9AFF8D9895FF808B88FF1D2B27FF788682FF
+ 899793FF7B8985FF7D8B87FF75837FFF7D8B87FF8C9A96FF879591FF8A9894FF
+ 8E9C98FF8E9C98FF8D9B97FF8F9D99FF96A4A0FF9CAAA6FFA1AFA9FFA2B0AAFF
+ 9EACA6FF9BA9A3FF9EACA6FFA6B4AEFFA9B7B1FFA7B5AFFFA8B6B0FFA9B7B1FF
+ A6B4AEFFA2B0AAFFA3B1ABFFA5B3ADFFA3B1ABFF9DABA5FFA2B0AAFFA2B0AAFF
+ A2B0AAFFA1AFA9FFA1AFA9FFA1AFA9FFA1AFA9FFA1AFA9FF9BA9A3FF9AA8A2FF
+ 98A6A0FF97A59FFF96A49EFF93A19BFF8E9C96FF8A9892FF8A9690FF828E88FF
+ 7B8781FF6D7973FF727E78FF35413BFF65716BFF67736DFF68746EFF6D7973FF
+ 727E78FF74807AFF727E78FF6E7A74FF6B7771FF69756FFF6B756FFF6B756FFF
+ 6C7670FF6C7670FF656F69FF5B655FFF59635DFF5E6862FF616B65FF636D67FF
+ 69736DFF6F7973FF757F79FF78827CFF78827CFF78837BFF76837BFF79877CFF
+ 7E8C81FF859388FF8E9C91FF9AA89DFFA8B6ABFFB0BEB3FFA6B4A9FFA0AEA3FF
+ 9BA99EFF9CAA9FFFA2B0A5FFA8B6ABFFABB9AEFFACBAAFFFA6B6ABFFA8B8ADFF
+ ABBBB0FFABBBB0FFA8B8ADFFA6B6ABFFA5B5AAFFA6B6ABFFA1B1A6FFAFBFB4FF
+ B3C3B8FFACBCB1FFABBBB0FFADBDB2FFA0B0A5FF8B9B90FF92A29BFF92A29BFF
+ A9B9B2FFC4D4CDFFC9D9D2FFC4D4CDFFB8C8C1FFA6B6AFFF94A49DFF8D9D96FF
+ 899992FF8B9B94FF616A67FF626B68FF5D6663FF69726FFF636C69FF67706DFF
+ 87908DFF88918EFF717A77FF717A77FF646D6AFF5A6360FF5E6764FF535C59FF
+ 3C4542FF313A37FF29322FFF515A57FF808986FF9BA4A1FFA4ADAAFFA5AEABFF
+ A2ABA8FF9DA6A3FFA0A9A6FFA0A9A6FF9CA5A2FF97A09DFF98A19EFF98A19EFF
+ 909996FF858E8BFF818A87FF7B8481FF717A77FF747D7AFF7B8481FF707976FF
+ 6A7370FF77807DFF848D8AFF7D8683FF49524FFF6C7572FF87908DFF848D8AFF
+ 8D9693FF889390FF798783FF73827EFF6D7B77FF687672FF697773FF707E7AFF
+ 7A8582FF808B88FF7A8380FF727B78FF5E6764FF5A6360FF4A514EFF59605DFF
+ 646B68FF757C79FF747D7AFF737C79FF737C79FF757E7BFF77807DFF79827FFF
+ 7A8380FF7A8380FF848D8AFF7A8380FF828B88FF6D7673FF666F6CFF727B78FF
+ 6C7572FF7D8683FF75807DFF838E8BFF8B9693FF8D9895FF9CA7A4FF939E9BFF
+ 85908DFF7E8986FFB4BFBCFFB4BFBCFFA2ADAAFF889390FF838E8BFF8E9996FF
+ 8C9794FF7C8A86FF94A5A2FFB4C7C4FFADC0BDFFA1B4B1FF99AAA7FF879895FF
+ 829390FF738481FF7B8987FF7D8B89FF798684FF6C7977FF616E6CFF5E6B69FF
+ 606B69FF5D6A68FF5B6965FF495854FF53615DFF4A5854FF32403CFF212F2BFF
+ 586360FF56615EFF5C6562FF5F6865FF5A6360FF5B6461FF626966FF5C6360FF
+ 5A615EFF666F6CFF6C7572FF626D6AFF616C69FF5E6966FF586360FF616C69FF
+ 697471FF606B68FF65706DFF636E6BFF697471FF747F7CFF7D8885FF808B88FF
+ 828D8AFF86918EFF97A5A1FF8B9995FF7F8D89FF7E8C88FF83918DFF889692FF
+ 8A9894FF899793FF8E9C98FF8A9894FF94A29EFFA2B0ACFF9FADA9FF97A5A1FF
+ A6B4B0FFC2D1CDFFB5C6C2FFAFC3BEFFAFC3BEFFB4C8C3FFB8C9C5FFB9CAC6FF
+ BDCECAFFC4D5D1FFC2D1CDFFC3D2CEFFBAC8C4FFA2B0ACFF899793FF808E8AFF
+ 889390FF8F9A97FF303E3AFF84928EFF879591FF72807CFF7C8A86FF75837FFF
+ 768480FF808E8AFF7E8C88FF85938FFF8C9A96FF8F9D99FF8F9D99FF8F9D99FF
+ 93A19DFF96A4A0FF99A7A1FF9EACA6FF9FADA7FF9BA9A3FF9BA9A3FF9FADA7FF
+ A3B1ABFFA3B1ABFFA2B0AAFFA6B4AEFFA5B3ADFFA1AFA9FFA2B0AAFFA5B3ADFF
+ A1AFA9FF99A7A1FFA3B1ABFFA0AEA8FF9BA9A3FF98A6A0FF96A49EFF97A59FFF
+ 9AA8A2FF9CAAA4FF95A39DFF92A09AFF8E9C96FF8D9B95FF8D9B95FF8D9B95FF
+ 8A9892FF87958FFF84908AFF7B8781FF727E78FF67736DFF707C76FF37433DFF
+ 626E68FF5E6A64FF64706AFF6A7670FF707C76FF737F79FF717D77FF6D7973FF
+ 6A7670FF68746EFF66706AFF67716BFF6C7670FF6D7771FF67716BFF5C6660FF
+ 59635DFF5D6761FF59635DFF606A64FF68726CFF6E7872FF717B75FF737D77FF
+ 77817BFF7A857DFF738078FF78867BFF7F8D82FF869489FF8F9D92FF9AA89DFF
+ A6B4A9FFAFBDB2FFADBBB0FFADBBB0FFA5B3A8FF9BA99EFF9FADA2FFACBAAFFF
+ ADBBB0FFA5B3A8FF99A99EFFA0B0A5FFA5B5AAFFA4B4A9FF9EAEA3FF9BABA0FF
+ 9EAEA3FFA3B3A8FFA3B3A8FFAABAAFFFB0C0B5FFB1C1B6FFADBDB2FFA6B6ABFF
+ 9DADA2FF94A499FF97A7A0FF91A19AFFA2B2ABFFBBCBC4FFC1D1CAFFC0D0C9FF
+ B9C9C2FFACBCB5FF99A9A2FF91A19AFF8A9A93FF8A9A93FF646B68FF5F6865FF
+ 5F6663FF6A7370FF606764FF555E5BFF757C79FF7B8481FF8E9592FF8B9491FF
+ 7B827FFF6B7471FF707774FF666F6CFF525956FF444D4AFF262F2CFF434C49FF
+ 6B7471FF8A9390FF99A29FFF9DA6A3FF9CA5A2FF9AA3A0FF929B98FF929B98FF
+ 919A97FF929B98FF949D9AFF8E9794FF7B8481FF67706DFF59625FFF505956FF
+ 434C49FF434C49FF48514EFF3A4340FF313A37FF3D4643FF2C3532FF3F4845FF
+ 17201DFF6D7673FF848D8AFF7B8481FF868F8CFF808986FF798481FF73817DFF
+ 6F7A77FF6C7774FF6E7976FF75807DFF818A87FF87908DFF757E7BFF737C79FF
+ 515855FF616865FF424946FF636A67FF5C6360FF747B78FF757E7BFF757E7BFF
+ 757E7BFF77807DFF7A8380FF7D8683FF7E8784FF7E8784FF818A87FF757E7BFF
+ 828B88FF6D7673FF616A67FF666F6CFF5C6562FF737C79FF7D8683FF8D9693FF
+ 77807DFF7D8683FF88918EFFAAB5B2FF97A09DFF899491FF8C9794FFC1CCC9FF
+ CFDAD7FF9DA8A5FF75807DFF7C8784FF87928FFF7D8B87FF95A6A3FFB3C6C3FF
+ A9BCB9FF9BAEABFF91A29FFF7F908DFF7B8C89FF6E7F7CFF798785FF768482FF
+ 6D7A78FF626F6DFF5D6A68FF606D6BFF636E6CFF5E6B69FF5E6C68FF4A5854FF
+ 52605CFF495753FF333E3BFF283330FF646F6CFF616C69FF5C6562FF5D6663FF
+ 58615EFF59625FFF616865FF5B625FFF5B625FFF69726FFF707976FF6A7572FF
+ 697471FF5F6A67FF4F5A57FF545F5CFF5F6A67FF5B6663FF65706DFF5D6865FF
+ 5C6764FF697471FF77827FFF7E8986FF808B88FF818C89FF929D9AFF899793FF
+ 838E8BFF7E8C88FF7F8A87FF7E8C88FF85908DFF889692FF96A19EFF899793FF
+ 8D9895FF97A5A1FF9AA5A2FF95A39FFFABB6B3FFC8D6D2FFB8C9C5FFB4C5C1FF
+ B4C5C2FFB7C8C4FFB9CAC7FFB7C8C4FFBCCAC8FFC0CFCBFFBCCAC8FFBAC9C5FF
+ B6C3C1FFA6B4B0FF889593FF75837FFF889391FFA7B2AFFF485350FF919F9BFF
+ 86918EFF6A7874FF7B8683FF768480FF747F7CFF788682FF788380FF7F8D89FF
+ 8C9794FF919F9BFF939E9BFF909E9AFF939E9BFF92A09CFF8F9D97FF98A6A0FF
+ 9CAAA4FF98A6A0FF95A39DFF98A6A0FF9BA9A3FF9CAAA4FF9BA9A3FFA0AEA8FF
+ A1AFA9FF9DABA5FF9EACA6FFA1AFA9FF9CAAA4FF93A19BFFA3B1ABFF9EACA6FF
+ 96A49EFF909E98FF8D9B95FF8F9D97FF93A19BFF96A49EFF919F99FF8D9B95FF
+ 889690FF87958FFF8A9892FF8B9993FF8A9892FF889690FF7A8680FF717D77FF
+ 6C7670FF626E68FF737D77FF39453FFF646E68FF59655FFF626C66FF66726CFF
+ 707A74FF727E78FF737D77FF6D7973FF6C7670FF6A746EFF5D6761FF636B64FF
+ 6A716CFF6F7770FF6A716CFF5F6A62FF5D6761FF606B63FF515B55FF5D6860FF
+ 69736DFF6E7971FF6D7771FF6E7971FF757F79FF7B8880FF738176FF79877CFF
+ 818F84FF88968BFF8D9B90FF95A398FF9DABA0FFA3B1A6FFACBAAFFFB0BEB3FF
+ A5B3A8FF94A297FF97A59AFFA8B6ABFFA8B6ABFF9AA89DFF96A69BFF9EAEA3FF
+ A5B4ACFFA1B1A6FF98A79FFF94A499FF99A8A0FFA0B0A5FF92A199FF93A398FF
+ 9EADA5FFACBCB1FFAAB9B1FF9EAEA3FF9EADA5FFA8B7AFFFA2B2ABFF96A69FFF
+ A1B1AAFFB5C5BEFFBACAC3FFB9C9C2FFB6C6BFFFACBCB5FFA1B1AAFF98A6A0FF
+ 909E98FF8E9C96FF676D68FF656C67FF676D68FF656C67FF606661FF5E6560FF
+ 6A706BFF777E79FF6E746FFF868D88FF9CA29DFF959C97FF7E847FFF6A716CFF
+ 636964FF606762FF4D5653FF37423FFF333E3BFF545F5CFF818C89FF97A29FFF
+ 939E9BFF899491FF7D8885FF6E7976FF5F6A67FF5E6966FF697471FF737E7BFF
+ 747F7CFF717C79FF868F8CFF858E8BFF87908DFF87908DFF78817EFF616A67FF
+ 535C59FF515A57FF49524FFF4B5451FF3C4542FF69726FFF747D7AFF808986FF
+ 808986FF7E8784FF7C8380FF7A817EFF787F7CFF757C79FF707774FF707774FF
+ 7D8481FF8D9491FF868D8AFF737A77FF474C4AFF636866FF474C4AFF676C6AFF
+ 676C6AFF717875FF79837DFF76807AFF747E78FF757F79FF78827CFF7B857FFF
+ 7A847EFF78827CFF7E8882FF7D8781FF717B75FF67716BFF67716BFF606A64FF
+ 616B65FF717B75FF7F8683FF7E8582FF808784FF868D8AFF8A918EFF8A9390FF
+ 909794FF929B98FF8C9592FF929B98FFBFCAC7FFD8E3E0FFABB6B3FF7E8986FF
+ 7D8B87FF879692FFA1B5B0FFA3B9B4FF9EB4AFFF90A6A1FF869A95FF7D918CFF
+ 72837FFF657672FF6C7D79FF697A76FF697874FF687773FF687672FF65736FFF
+ 5E6C68FF586662FF57625FFF4C5754FF56615EFF535E5BFF3D4643FF404946FF
+ 505956FF69726FFF606966FF59625FFF59625FFF5F6865FF5D6663FF555E5BFF
+ 5C6562FF6A7370FF6F7973FF747E78FF6D7771FF66706AFF656F69FF5B655FFF
+ 59635DFF67716BFF67716BFF525C56FF656F69FF76807AFF66706AFF707A74FF
+ 848E88FF77807DFF848D8AFF889391FF848C8BFF818C8AFF8B9392FF889391FF
+ 858D8CFF8A9593FF979F9EFF939E9CFF919998FF95A09EFF9DA5A4FF95A09EFF
+ 9FA7A6FFB9C4C2FFB6C3C1FFB3C1BFFFAFBDBCFFACBAB8FFAEBCBBFFB4C2C0FF
+ B8C4C4FFB7C4C2FFB6C2C2FFB6C3C1FFB2BEBEFFA5B2B0FF909C9CFF828F8DFF
+ 889494FF97A2A0FF65706EFF899492FF9BA3A2FF737E7CFF757D7CFF778280FF
+ 626A69FF85908EFF777F7EFF7B8684FF868E8DFF8B9694FF8F9796FF8D9896FF
+ 8F9796FF8D9895FF8E9C96FF92A09AFF96A49EFF98A6A0FF97A59FFF97A59FFF
+ 98A6A0FF99A7A1FF9AA8A2FF9CAAA4FF9FADA7FFA1AFA9FFA2B0AAFF9FADA7FF
+ 9CAAA4FF9AA8A2FF9BA9A3FF9AA8A2FF98A6A0FF97A59FFF96A49EFF96A49EFF
+ 97A59FFF97A59FFF99A7A1FF92A09AFF8B9993FF8A9892FF8E9C96FF919F99FF
+ 8E9C96FF8C9892FF818B85FF6F7973FF7D847FFF737D77FF616863FF56605AFF
+ 4D544FFF535D57FF69706BFF606A64FF676E69FF717B75FF707772FF5F6963FF
+ 5F6661FF69706BFF626962FF5D655BFF5D645DFF646C62FF666D66FF60695FFF
+ 59615AFF565F55FF5F6760FF626B61FF616C64FF606B61FF647169FF6D7B70FF
+ 727F77FF717F74FF758378FF79897EFF78887DFF7B8B80FF88988DFF8E9E93FF
+ 95A59AFFA7B7ACFFA5B5AAFFAABAAFFFA9B9AEFF9BABA0FF8B9B90FF8B9B90FF
+ 9CACA1FFAEBEB3FF97A69EFF9CABA3FFA2B0AAFFA3B2AAFF9FADA7FF99A8A0FF
+ 96A49EFF95A49CFF97A59FFF98A79FFF9BA9A3FF9FAEA6FFA3B1ABFFA3B2AAFF
+ A1AFA9FF9FADA7FF91A19AFF99A9A2FFA5B5AEFFB2C2BBFFBACAC3FFB9C9C2FF
+ B5C3BDFFB0BEB8FFA2B0AAFF8F9B95FF94A09AFF88948EFF616762FF636964FF
+ 666C67FF676D68FF626863FF5F6560FF676D68FF727873FF656B66FF757B76FF
+ 8B918CFF9CA29DFFA2A8A3FF999F9AFF818782FF6A716CFF77807DFF66716EFF
+ 606B68FF6E7976FF7E8986FF828D8AFF7C8784FF76817EFF919C99FF8E9996FF
+ 8C9794FF8D9895FF909B98FF919C99FF8E9996FF8A9592FF808986FF828B88FF
+ 87908DFF89928FFF7A8380FF606966FF4D5653FF464F4CFF454E4BFF4A5350FF
+ 3E4744FF6D7673FF78817EFF828B88FF808986FF7D8683FF777C7AFF747977FF
+ 737876FF727775FF6E7371FF6C716FFF727775FF7C817FFF868B89FF797E7CFF
+ 4D5250FF565B59FF494E4CFF595E5CFF797E7CFF757C79FF79807BFF747E78FF
+ 727C76FF737D77FF77817BFF78827CFF77817BFF76807AFF757F79FF77817BFF
+ 6F7973FF69736DFF6B756FFF636D67FF616B65FF6E7872FF767B79FF7A7F7DFF
+ 808583FF838886FF828986FF838A87FF8A918EFF929996FF949D9AFF7F8885FF
+ 909B98FFB9C4C1FFCCD7D4FFCFDAD7FFB1BFBBFF7E8D89FFA8BCB7FFA8BEB9FF
+ A2B8B3FF93A9A4FF899D98FF80948FFF768783FF6B7C78FF72837FFF6E7F7BFF
+ 6B7A76FF697874FF697773FF677571FF64726EFF616F6BFF67706DFF5C6562FF
+ 616A67FF58615EFF444D4AFF48514EFF57605DFF656E6BFF636C69FF5A6360FF
+ 58615EFF5E6764FF5E6764FF5A6360FF606966FF6D7673FF636D67FF6B756FFF
+ 6B756FFF6B756FFF6F7973FF66706AFF646E68FF717B75FF6C7670FF5A645EFF
+ 6A746EFF78827CFF67716BFF717B75FF86908AFF7D8781FF7F8885FF828A89FF
+ 7D8584FF818988FF919998FF939B9AFF8B9392FF8D9594FF858D8CFF858D8CFF
+ 848C8BFF8C9493FF969E9DFF969E9DFFA5ADACFFC5D0CEFFB5BFBFFFB0BCBCFF
+ ADB9B9FFACB8B8FFB1BDBDFFB6C2C2FFB7C3C3FFB5C1C1FFADB9B9FFAEBABAFF
+ ACB8B8FFA1ADADFF8F9B9BFF838F8FFF899595FF97A4A2FF5F6766FF88908FFF
+ 919998FF757D7CFF757D7CFF737B7AFF676F6EFF808887FF777F7EFF7B8382FF
+ 808887FF838B8AFF858D8CFF878F8EFF899190FF8A9592FF8B9791FF8D9B95FF
+ 919F99FF93A19BFF94A29CFF94A29CFF96A49EFF98A6A0FF97A59FFF99A7A1FF
+ 9CAAA4FF9FADA7FF9FADA7FF9DABA5FF9AA8A2FF99A7A1FF9BA9A3FF9AA8A2FF
+ 99A7A1FF97A59FFF96A49EFF95A39DFF95A39DFF95A39DFF8F9D97FF8E9C96FF
+ 8E9C96FF909E98FF92A09AFF8F9D97FF889690FF838F89FF87918BFF7B827DFF
+ 7F8681FF727974FF5F6661FF4D544FFF3C433EFF505752FF5E6560FF5D645FFF
+ 646B66FF707772FF707772FF666D68FF626964FF666E67FF666A64FF61665DFF
+ 5F645BFF61665DFF5D655BFF565E54FF515A50FF515A50FF5F685EFF626B61FF
+ 616C62FF606B61FF637166FF6C7A6FFF707E73FF6F7D72FF748479FF79897EFF
+ 75857AFF75857AFF839388FF8D9D92FF98A89DFFACBCB1FFA0B0A5FFA3B3A8FF
+ A3B3A8FF9DADA2FF94A499FF91A196FF95A59AFF9AAA9FFF9DABA5FFA2B0AAFF
+ A8B6B0FFA9B7B1FFA5B3ADFFA0AEA8FF9DABA5FF9BA9A3FF9BA9A3FF9BA9A3FF
+ 9DABA5FF9EACA6FF9DABA5FF9BA9A3FF98A6A0FF96A49EFF8F9F98FF95A59EFF
+ A2B2ABFFB1C1BAFFBBCBC4FFBBCBC4FFB3C1BBFFAAB8B2FFA0ACA6FF8E9A94FF
+ 949E98FF838D87FF5C625DFF5F6560FF646A65FF686E69FF636964FF5F6560FF
+ 636964FF6C726DFF6B716CFF6D736EFF747A75FF848A85FF9CA29DFFACB2ADFF
+ A9AFAAFF9CA39EFFA8B1AEFFA4AFACFFA3AEABFFA3AEABFF9EA9A6FF96A19EFF
+ 949F9CFF97A29FFF87928FFF8C9794FF919C99FF909B98FF8A9592FF848F8CFF
+ 838E8BFF85908DFF7F8885FF818A87FF848D8AFF858E8BFF79827FFF666F6CFF
+ 565F5CFF515A57FF4F5855FF555E5BFF4A5350FF77807DFF7E8784FF858E8BFF
+ 808986FF7B8481FF737876FF6F7472FF6F7472FF717674FF6F7472FF696E6CFF
+ 676C6AFF696E6CFF7C817FFF767B79FF5D6260FF4D5250FF494E4CFF505553FF
+ 787D7BFF6C7370FF757C77FF727C76FF717B75FF727C76FF747E78FF757F79FF
+ 747E78FF737D77FF737D77FF77817BFF717B75FF6F7973FF727C76FF68726CFF
+ 616B65FF6B756FFF6D7270FF777C7AFF808583FF808583FF7B827FFF7C8380FF
+ 858C89FF8F9693FF909996FF7A8380FF788380FF8B9693FFAEB9B6FFDCE7E4FF
+ D5E3DFFF9EADA9FFABBFBAFFA8BEB9FFA2B6B1FF94A8A3FF889C97FF7F938EFF
+ 778884FF6E7F7BFF72817DFF6E7D79FF677672FF64736FFF64726EFF64726EFF
+ 65736FFF64726EFF6E7774FF69726FFF69726FFF58615EFF4A5350FF4D5653FF
+ 626B68FF636C69FF656E6BFF59625FFF525B58FF555E5BFF57605DFF555E5BFF
+ 5A6360FF636C69FF656F69FF6C7670FF69736DFF68726CFF6C7670FF656F69FF
+ 636D67FF707A74FF69736DFF5B655FFF68726CFF6F7973FF5F6963FF67716BFF
+ 7D8781FF7D8781FF7C8582FF7E8784FF78817EFF7D8683FF919A97FF949D9AFF
+ 8A9390FF8A9390FF848D8AFF848D8AFF818A87FF87908DFF8E9794FF8D9693FF
+ A0A9A6FFC2CDCAFFB4BFBDFFACB9B7FFA8B5B3FFAAB7B5FFAFBCBAFFB1BEBCFF
+ AFBCBAFFABB8B6FFA3B0AEFFA1AEACFF9FACAAFF99A6A4FF8C9997FF83908EFF
+ 889593FF929F9DFF505857FF7F8885FF7C8582FF6F7875FF6F7875FF666F6CFF
+ 69726FFF717A77FF747D7AFF757E7BFF77807DFF77807DFF78817EFF7B8481FF
+ 818A87FF848F8CFF85918BFF87958FFF8B9993FF8E9C96FF909E98FF92A09AFF
+ 95A39DFF97A59FFF93A19BFF95A39DFF98A6A0FF9AA8A2FF9BA9A3FF9AA8A2FF
+ 98A6A0FF97A59FFF9CAAA4FF9BA9A3FF98A6A0FF96A49EFF95A39DFF94A29CFF
+ 93A19BFF93A19BFF8D9B95FF8F9D97FF919F99FF92A09AFF919F99FF8D9B95FF
+ 889690FF86928CFF838D87FF7E8580FF7B827DFF6E7570FF676E69FF4E5550FF
+ 373E39FF585F5AFF555C57FF5A615CFF626964FF6A716CFF6D746FFF6A716CFF
+ 636A65FF5F6760FF6A6E68FF656A61FF61665DFF5E635AFF555D53FF4C544AFF
+ 4A5248FF4D554BFF5A6359FF5F685EFF606B61FF5F6A60FF646F65FF6C776DFF
+ 6E7C71FF6D7B70FF717F74FF78867BFF758378FF78867BFF89978CFF94A297FF
+ 9BA99EFFA7B5AAFFA8B6ABFFA4B2A7FFA1AFA4FF9FADA2FF9FADA2FF9DABA0FF
+ 98A69BFF94A297FF9CA8A2FFA0ACA6FFA5B1ABFFA7B3ADFFA4B0AAFFA0ACA6FF
+ 9DA9A3FF9BA7A1FF9BA7A1FF9DA9A3FFA0ACA6FFA0ACA6FF9DA9A3FF98A49EFF
+ 95A19BFF919F99FF8A9A93FF8F9F98FF9CACA5FFAEBEB7FFBECCC6FFBECCC6FF
+ B1BFB9FFA3B1ABFF99A59FFF8B9791FF919B95FF7A847EFF5A605BFF5C625DFF
+ 616762FF646A65FF616762FF5D635EFF606661FF686E69FF6B716CFF6D736EFF
+ 6C726DFF6C726DFF7B817CFF979D98FFB3B9B4FFC2C9C4FFA4ADAAFFA9B4B1FF
+ AEB9B6FFAAB5B2FF9FAAA7FF98A3A0FF9AA5A2FFA1ACA9FF8B9693FF8D9895FF
+ 8C9794FF848F8CFF7C8784FF7A8582FF7F8A87FF86918EFF838C89FF828B88FF
+ 808986FF7E8784FF79827FFF747D7AFF707976FF707976FF666F6CFF6A7370FF
+ 5B6461FF828B88FF838C89FF858E8BFF7E8784FF79827FFF757A78FF6F7472FF
+ 6D7270FF717674FF717674FF6C716FFF666B69FF656A68FF737876FF6F7472FF
+ 757A78FF575C5AFF444947FF616664FF646967FF646967FF737A75FF717B75FF
+ 717B75FF727C76FF727C76FF727C76FF717B75FF717B75FF717B75FF747E78FF
+ 6E7872FF6D7771FF707A74FF66706AFF5E6862FF69706BFF6C716FFF767B79FF
+ 7E8381FF7D8280FF7A817EFF7D8481FF848B88FF89908DFF88918EFF808986FF
+ 7F8A87FF7A8582FF828D8AFFB1BCB9FFCCDAD6FFB7C6C2FFA9BDB8FFA3B9B4FF
+ 9BAFAAFF8EA29DFF829691FF788C87FF738480FF6D7E7AFF6E7D79FF6B7A76FF
+ 677672FF64736FFF64726EFF64726EFF667470FF687370FF6A7370FF6F7875FF
+ 707976FF58615EFF4B5451FF47504DFF6A7370FF646D6AFF68716EFF5B6461FF
+ 505956FF505956FF515A57FF515A57FF545D5AFF59625FFF68726CFF6A746EFF
+ 626C66FF5F6963FF646E68FF606A64FF626C66FF727C76FF737D77FF6B756FFF
+ 737D77FF76807AFF68726CFF6D7771FF828C86FF89938DFF808986FF828B88FF
+ 7A8380FF7A8380FF88918EFF8A9390FF828B88FF858E8BFF87908DFF88918EFF
+ 858E8BFF88918EFF8C9592FF87908DFF98A19EFFBBC4C1FFB5C0BEFFAAB7B5FF
+ A4B1AFFFA6B3B1FFAAB7B5FFA7B4B2FFA1AEACFF9CA9A7FF9DAAA8FF95A2A0FF
+ 8E9B99FF8B9896FF879492FF808D8BFF7E8B89FF818C8AFF47504DFF767F7CFF
+ 6C7572FF6B7471FF6B7471FF5E6764FF6C7572FF656E6BFF6B7471FF6C7572FF
+ 6D7673FF6E7774FF6F7875FF737C79FF79827FFF7E8784FF818D87FF83918BFF
+ 889690FF8B9993FF8E9C96FF919F99FF96A49EFF99A7A1FF8F9D97FF919F99FF
+ 94A29CFF96A49EFF98A6A0FF97A59FFF96A49EFF95A39DFF9BA9A3FF9AA8A2FF
+ 97A59FFF95A39DFF92A09AFF919F99FF909E98FF909E98FF8D9B95FF8C9A94FF
+ 8A9892FF87958FFF84928CFF84928CFF87958FFF8B9791FF808782FF7C837EFF
+ 727974FF656C67FF6B726DFF505752FF2F3631FF525954FF545B56FF5B625DFF
+ 606762FF626964FF676E69FF6A716CFF636A65FF5A615AFF686D64FF656A61FF
+ 63685FFF5F645BFF535B51FF474F45FF454D43FF495147FF525B51FF596258FF
+ 5C675DFF5D685EFF626D63FF6A756BFF6D7B70FF6C7A6FFF6C7A6FFF748277FF
+ 748277FF7E8C81FF96A499FF9FADA2FF98A69BFF96A499FFAAB8ADFFA2B0A5FF
+ 9AA89DFF98A69BFF9BA99EFF9EACA1FF9CAA9FFF99A79CFF98A49EFF9BA7A1FF
+ 9EAAA4FFA1ADA7FFA0ACA6FF9DA9A3FF99A59FFF97A39DFF94A09AFF99A59FFF
+ A0ACA6FFA3AFA9FFA1ADA7FF9CA8A2FF96A29CFF909E98FF86948EFF889891FF
+ 94A49DFFAABAB3FFBECCC6FFC0CEC8FFB0BEB8FF9FADA7FF919D97FF84908AFF
+ 8C9690FF76807AFF595F5AFF595F5AFF5B615CFF5E645FFF5C625DFF595F5AFF
+ 5E645FFF656B66FF5F6560FF696F6AFF6F7570FF6E746FFF747A75FF888E89FF
+ 9FA5A0FFAEB5B0FF9AA3A0FF9EA9A6FFA0ABA8FF9AA5A2FF919C99FF8A9592FF
+ 899491FF8A9592FF919C99FF8D9895FF87928FFF7F8A87FF7B8683FF7B8683FF
+ 808B88FF848F8CFF818A87FF818A87FF808986FF7E8784FF7F8885FF818A87FF
+ 818A87FF808986FF77807DFF79827FFF656E6BFF868F8CFF838C89FF838C89FF
+ 7D8683FF79827FFF777C7AFF6F7472FF6A6F6DFF6E7371FF707573FF6C716FFF
+ 686D6BFF676C6AFF6F7472FF656A68FF838886FF626765FF383D3BFF7C817FFF
+ 515654FF6E7371FF707772FF717873FF737A75FF737A75FF737A75FF717873FF
+ 717873FF707772FF6B726DFF6C736EFF656C67FF656C67FF6C736EFF666D68FF
+ 616863FF6B726DFF6C716FFF747977FF797E7CFF777C7AFF787F7CFF7E8582FF
+ 808784FF7D8481FF88918EFF7D8683FF838E8BFF86918EFF848F8CFFA0ABA8FF
+ B7C5C1FFACBBB7FFA6B7B3FF9EB2ADFF95A9A4FF8A9E99FF81928EFF768783FF
+ 70817DFF6D7E7AFF6D7C78FF6D7C78FF6D7B77FF6C7A76FF6B7975FF6B7975FF
+ 6E7976FF6E7976FF6D7673FF7A8380FF7B8481FF5C6562FF4C5552FF39423FFF
+ 6B7471FF656E6BFF69726FFF5E6764FF535C59FF515A57FF535C59FF555E5BFF
+ 58615EFF5B6461FF5F6661FF646B66FF626964FF656C67FF6E7570FF6C736EFF
+ 6C736EFF7A817CFF6F7671FF6C736EFF717873FF717873FF69706BFF6A716CFF
+ 7A817CFF868D88FF838A87FF89908DFF828986FF7D8481FF838A87FF828986FF
+ 828986FF8C9390FF818885FF838A87FF828986FF878E8BFF8C9390FF858C89FF
+ 929996FFB0B9B6FFB2BDBBFFA7B2B0FFA1ACAAFFA4AFADFFA5B0AEFF9FAAA8FF
+ 98A3A1FF97A2A0FF99A4A2FF8A9593FF7E8987FF7D8886FF7F8A88FF7A8583FF
+ 707B79FF697472FF47504DFF707774FF686F6CFF6B726FFF686F6CFF5F6663FF
+ 6F7673FF606764FF606764FF646B68FF686F6CFF6C7370FF6D7471FF707774FF
+ 747B78FF757E7BFF7C8882FF808C86FF85918BFF89958FFF8C9892FF919D97FF
+ 96A29CFF9AA6A0FF8E9A94FF8F9B95FF929E98FF94A09AFF96A29CFF97A39DFF
+ 96A29CFF96A29CFF9AA6A0FF99A59FFF96A29CFF94A09AFF929E98FF909C96FF
+ 8F9B95FF8F9B95FF86928CFF86928CFF84908AFF808C86FF7D8983FF7D8983FF
+ 7F8B85FF828E88FF808881FF7B827BFF6B726BFF5C635CFF666D66FF4F564FFF
+ 262D26FF3D443DFF565D56FF585F58FF596059FF5B625BFF636A63FF6A716AFF
+ 666D66FF5C635CFF5E635AFF60635AFF5E635AFF5D6259FF52574EFF454A41FF
+ 3E463CFF40483EFF475046FF515A50FF596258FF5C655BFF5F6A60FF677268FF
+ 6D786EFF6E796FFF707E73FF748277FF707E73FF79877CFF98A69BFFA5B3A8FF
+ 98A69BFF8D9B90FF9BA99EFF97A59AFF93A196FF93A196FF95A398FF97A59AFF
+ 98A69BFF97A59AFF9CA8A2FF9DA9A3FFA0ACA6FFA3AFA9FFA3AFA9FFA2AEA8FF
+ 9FABA5FF9CA8A2FF929E98FF97A39DFF9FABA5FFA6B2ACFFA8B4AEFFA2AEA8FF
+ 98A49EFF8E9C96FF84928CFF84948DFF909E98FFA5B3ADFFBAC8C2FFBECCC6FF
+ B1BDB7FFA0ACA6FF8F9993FF7E8882FF858F89FF7A847EFF545A55FF525853FF
+ 545A55FF585E59FF575D58FF555B56FF585E59FF5E645FFF676D68FF696F6AFF
+ 686E69FF6A706BFF757B76FF868C87FF929893FF949B96FFA0A9A6FFA1ACA9FF
+ 9FAAA7FF99A4A1FF949F9CFF909B98FF8A9592FF828D8AFF828D8AFF808B88FF
+ 7D8885FF7B8683FF7A8582FF788380FF76817EFF747F7CFF79827FFF7E8784FF
+ 818A87FF828B88FF858E8BFF868F8CFF808986FF79827FFF7C8582FF7D8683FF
+ 69726FFF87908DFF818A87FF7F8885FF7A8380FF78817EFF727775FF6B706EFF
+ 666B69FF696E6CFF6B706EFF686D6BFF656A68FF666B69FF676C6AFF5A5F5DFF
+ 777C7AFF5B605EFF2A2F2DFF7B807EFF4A4F4DFF737876FF6C736EFF6F7671FF
+ 717873FF717873FF6F7671FF6D746FFF6C736EFF6D746FFF686F6AFF686F6AFF
+ 626964FF646B66FF6F7671FF6E7570FF6D746FFF787F7AFF6B706EFF737876FF
+ 757A78FF727775FF747B78FF7B827FFF7B827FFF737A77FF848D8AFF79827FFF
+ 828D8AFF889390FF7E8986FF919C99FFB0BEBAFFB4C3BFFFA3B4B0FF9AAEA9FF
+ 92A6A1FF8B9F9AFF82938FFF768783FF70817DFF70817DFF687773FF6A7975FF
+ 6C7A76FF6C7A76FF6B7975FF6B7975FF6F7A77FF707B78FF7B8481FF87908DFF
+ 868F8CFF656E6BFF525B58FF2B3431FF68716EFF626B68FF5C6562FF57605DFF
+ 505956FF4D5653FF4E5754FF525B58FF565F5CFF59625FFF5E6560FF676E69FF
+ 69706BFF707772FF787F7AFF6F7671FF656C67FF6C736EFF626964FF646B66FF
+ 666D68FF676E69FF666D68FF646B66FF6C736EFF79807BFF7D8481FF868D8AFF
+ 828986FF7D8481FF818885FF808784FF838A87FF909794FF818885FF7F8683FF
+ 79807DFF7C8380FF7F8683FF757C79FF7B827FFF969D9AFFACB4B3FF9FAAA8FF
+ 9CA4A3FF9CA7A5FF9BA3A2FF8F9A98FF8D9594FF8F9A98FF8B9392FF7A8583FF
+ 717978FF707B79FF747C7BFF6B7674FF626A69FF5A6360FF484F4CFF5F6663FF
+ 616865FF5F6663FF5A615EFF5B625FFF626966FF535A57FF585F5CFF5D6461FF
+ 636A67FF676E6BFF69706DFF69706DFF6B726FFF6C7370FF747E78FF76827CFF
+ 7C8680FF7E8A84FF848E88FF87938DFF909A94FF929E98FF8A948EFF8A9690FF
+ 8E9892FF8F9B95FF939D97FF929E98FF959F99FF939F99FF98A29CFF94A09AFF
+ 949E98FF909C96FF909A94FF8D9993FF8F9993FF8D9993FF87918BFF86928CFF
+ 89938DFF87938DFF86908AFF7E8A84FF79837DFF757F79FF767E77FF727972FF
+ 686F68FF565D56FF5F665FFF5B625BFF3D443DFF484F48FF565D56FF515851FF
+ 4F564FFF565D56FF606760FF656C65FF626962FF5C635CFF565950FF55584FFF
+ 545950FF545950FF4C5148FF40453CFF383D34FF363E34FF40483EFF4A5349FF
+ 555E54FF596258FF5B665CFF636E64FF687369FF6A756BFF747F75FF758378FF
+ 6A786DFF6D7B70FF8A988DFF9FADA2FF9AA89DFF94A297FF909E93FF92A095FF
+ 97A59AFF9BA99EFF9CAA9FFF9AA89DFF97A59AFF95A398FF9DA9A3FF9DA9A3FF
+ 9FABA5FFA2AEA8FFA4B0AAFFA4B0AAFFA1ADA7FF9EAAA4FF95A19BFF95A19BFF
+ 99A59FFFA1ADA7FFA7B3ADFFA4B0AAFF98A49EFF8D9993FF899791FF879790FF
+ 8F9D97FFA1AFA9FFB3C1BBFFB8C6C0FFADB9B3FF9FABA5FF8E9892FF747E78FF
+ 7F8983FF838D87FF4A504BFF4A504BFF4E544FFF545A55FF545A55FF505651FF
+ 505651FF535954FF6A706BFF686E69FF646A65FF636964FF6F7570FF838984FF
+ 929893FF969D98FF9AA3A0FF99A4A1FF949F9CFF8E9996FF8C9794FF8B9693FF
+ 818C89FF747F7CFF7E8986FF808B88FF818C89FF818C89FF7F8A87FF7D8885FF
+ 798481FF788380FF767F7CFF7C8582FF7F8885FF7F8885FF828B88FF858E8BFF
+ 7F8885FF757E7BFF818A87FF848D8AFF707976FF8D9693FF838C89FF7D8683FF
+ 757E7BFF717A77FF6D7270FF686D6BFF666B69FF696E6CFF676C6AFF626765FF
+ 5F6462FF616664FF606563FF5D6260FF6A6F6DFF5A5F5DFF373C3AFF5F6462FF
+ 505553FF646967FF676E69FF6A716CFF6E7570FF6E7570FF6B726DFF686F6AFF
+ 676E69FF686F6AFF69706BFF69706BFF636A65FF666D68FF737A75FF727974FF
+ 6E7570FF787F7AFF6A6F6DFF767B79FF7B807EFF747977FF717875FF777E7BFF
+ 787F7CFF727976FF7C8582FF79827FFF85908DFF86918EFF77827FFF8E9996FF
+ B2C0BCFFB8C7C3FF9EAFABFF96A7A3FF90A19DFF8C9D99FF839490FF768783FF
+ 71807CFF72817DFF677571FF687672FF6B7673FF697471FF687370FF6A7572FF
+ 6F7A77FF747F7CFF88918EFF8C9592FF868F8CFF68716EFF59625FFF242D2AFF
+ 666F6CFF5F6865FF535C59FF535C59FF4E5754FF48514EFF454E4BFF47504DFF
+ 4B5451FF4E5754FF616863FF666D68FF646B66FF666D68FF6B726DFF606762FF
+ 545B56FF59605BFF646B66FF69706BFF69706BFF6D746FFF727974FF6F7671FF
+ 6F7671FF7A817CFF737A75FF7C837EFF7A817CFF79807BFF808782FF7F8681FF
+ 7C837EFF858C87FF818883FF79807BFF6C736EFF6D746FFF707772FF666D68FF
+ 69706BFF808782FFA5ACA9FF98A19EFF939A97FF8F9895FF868D8AFF757E7BFF
+ 757C79FF7B8481FF747B78FF6C7572FF6A716EFF68716EFF676E6BFF5C6562FF
+ 59605DFF59605DFF4C5350FF515853FF616863FF555C57FF4E5550FF5C635EFF
+ 565D58FF4C534EFF565D58FF5A615CFF5F6661FF616863FF616863FF606762FF
+ 616863FF626964FF686F6AFF69736DFF707772FF717B75FF777E79FF7A847EFF
+ 838A85FF86908AFF868D88FF86908AFF8A918CFF8A948EFF8F9691FF8F9993FF
+ 939A95FF919B95FF959C97FF929C96FF929994FF8F9993FF8F9691FF8D9791FF
+ 8F9691FF8D9791FF929994FF8D9791FF8C938EFF87918BFF868D88FF7C8680FF
+ 737A75FF6B726DFF656C65FF636A63FF656C65FF4E554EFF4F564FFF626962FF
+ 5D645DFF606760FF5A615AFF4D544DFF4A514AFF565D56FF606760FF5B625BFF
+ 535A53FF505750FF565950FF50534AFF4D5047FF4D5047FF484B42FF3C4138FF
+ 343930FF31392FFF3D453BFF495147FF545D53FF576056FF596258FF5F685EFF
+ 646D63FF636E64FF677268FF727D73FF6C776DFF69746AFF808B81FF96A197FF
+ 9BA69CFF9EA99FFF99A49AFF99A49AFF9BA69CFF9FAAA0FFA2ADA3FFA2ADA3FF
+ 9EA99FFF99A49AFF9CA6A0FF9BA59FFF9CA6A0FF9FA9A3FFA3ADA7FFA4AEA8FF
+ A1ABA5FF9DA7A1FF959F99FF8F9993FF8C9690FF959F99FFA2ACA6FFA7B1ABFF
+ 9EA8A2FF919D97FF92A09AFF909E98FF92A09AFF9EACA6FFADB9B3FFB1BDB7FF
+ AAB4AEFF9FA9A3FF929C96FF6D7771FF7B827DFF909792FF424843FF434944FF
+ 4A504BFF525853FF535954FF4D534EFF494F4AFF4A504BFF535954FF616762FF
+ 6D736EFF6F7570FF727873FF7F8580FF909691FF99A09BFF9FA8A5FF9DA8A5FF
+ 96A19EFF8C9794FF87928FFF848F8CFF77827FFF67726FFF7A8582FF7C8784FF
+ 7D8885FF7A8582FF76817EFF75807DFF788380FF7B8683FF79827FFF7C8582FF
+ 7A8380FF77807DFF7B8481FF848D8AFF848D8AFF7D8683FF89928FFF8D9693FF
+ 79827FFF959E9BFF87908DFF7D8683FF707976FF69726FFF6A6F6DFF686D6BFF
+ 696E6CFF6B706EFF686D6BFF606563FF5C615FFF5D6260FF616664FF6C716FFF
+ 6D7270FF686D6BFF555A58FF4C514FFF5E6361FF525755FF636A65FF676E69FF
+ 6B726DFF6B726DFF676E69FF646B66FF636A65FF646B66FF656C67FF666D68FF
+ 606762FF626964FF6D746FFF69706BFF626964FF69706BFF6A6F6DFF7C817FFF
+ 848987FF7A7F7DFF717875FF767D7AFF79807DFF767D7AFF7A8380FF79827FFF
+ 87928FFF909B98FF929D9AFFACB7B4FFB4C2BEFF98A7A3FF9BAAA6FF91A29EFF
+ 8C9D99FF8A9B97FF82938FFF748581FF6F7E7AFF71807CFF6D7B77FF6D7B77FF
+ 6D7875FF6A7572FF697471FF6D7875FF75807DFF7C8784FF8A9390FF87908DFF
+ 7E8784FF666F6CFF5E6764FF222B28FF666F6CFF5E6764FF58615EFF5A6360FF
+ 565F5CFF4C5552FF444D4AFF424B48FF444D4AFF464F4CFF585F5AFF585F5AFF
+ 4E5550FF4D544FFF545B56FF515853FF4E5550FF5A615CFF515853FF585F5AFF
+ 585F5AFF5D645FFF686F6AFF626964FF5D645FFF676E69FF6C736EFF737A75FF
+ 717873FF737A75FF7E8580FF7B827DFF717873FF727974FF767D78FF6B726DFF
+ 5D645FFF606762FF6A716CFF666D68FF6C736EFF848B86FFA0A7A4FF949B98FF
+ 8B928FFF848B88FF727976FF5E6562FF5B625FFF666D6AFF5F6663FF626966FF
+ 676E6BFF666D6AFF5D6461FF535A57FF555C59FF5D645FFF585F5AFF525954FF
+ 6B726DFF575E59FF4F5651FF666D68FF575E59FF515853FF585F5AFF5A615CFF
+ 5C635EFF5C635EFF5A615CFF59605BFF5A615CFF5B625DFF5E6560FF616863FF
+ 646B66FF686F6AFF6B726DFF717873FF787F7AFF7D847FFF828984FF838A85FF
+ 858C87FF888F8AFF8B928DFF8D948FFF8F9691FF909792FF929994FF919893FF
+ 909792FF8F9691FF8E9590FF8E9590FF8E9590FF8E9590FF99A09BFF8F9691FF
+ 828984FF79807BFF757C77FF707772FF676E69FF606762FF5B625BFF5B625BFF
+ 626962FF444B44FF373E37FF565D56FF616861FF616861FF616861FF4F564FFF
+ 4A514AFF596059FF5F665FFF515851FF434A43FF424640FF5C5F56FF52554CFF
+ 4A4D44FF494C43FF464940FF3E4138FF353A31FF33382FFF3E433AFF495147FF
+ 545C52FF565F55FF576056FF5B645AFF5E675DFF5F685EFF535E54FF6A756BFF
+ 707B71FF6E796FFF7D887EFF8F9A90FF98A399FF9FAAA0FFA3AEA4FF9BA69CFF
+ 939E94FF939E94FF9AA59BFF9FAAA0FF9EA99FFF9BA69CFF9DA7A1FF9CA6A0FF
+ 9CA6A0FFA0AAA4FFA4AEA8FFA5AFA9FFA2ACA6FF9FA9A3FF909A94FF858F89FF
+ 7E8882FF88928CFF9BA59FFFA7B1ABFFA3ADA7FF9AA49EFF9CA8A2FF96A49EFF
+ 96A49EFF9DABA5FFA8B4AEFFAAB6B0FFA5AFA9FF9DA7A1FF959F99FF69736DFF
+ 787F7AFF979E99FF454B46FF4F5550FF535954FF4C524DFF484E49FF4B514CFF
+ 4E544FFF4C524DFF494F4AFF5D635EFF676D68FF626863FF696F6AFF818782FF
+ 959B96FF99A09BFF9EA7A4FF98A3A0FF8F9A97FF909B98FF919C99FF7B8683FF
+ 65706DFF66716EFF798481FF808B88FF7F8A87FF7A8582FF7C8784FF838E8BFF
+ 7C8784FF6F7A77FF78817EFF79827FFF79827FFF7A8380FF7C8582FF7D8683FF
+ 7D8683FF7E8784FF7D8683FF808986FF5F6865FF939C99FF949D9AFF77807DFF
+ 6D7673FF6F7875FF696E6CFF606563FF5C615FFF5E6361FF5D6260FF575C5AFF
+ 575C5AFF5C615FFF616664FF6D7270FF5E6361FF6D7270FF444947FF434846FF
+ 4F5452FF555A58FF5D635EFF636964FF666C67FF626863FF606661FF616762FF
+ 616762FF5E645FFF5F6560FF5F6560FF606661FF626863FF646A65FF646A65FF
+ 626863FF606661FF5B605EFF757A78FF797E7CFF757A78FF7C8380FF747B78FF
+ 717875FF878E8BFF808986FF868F8CFF85908DFF85908DFF8F9A97FF9DA8A5FF
+ 9CAAA6FF93A29EFF93A29EFF8FA09CFF83928EFF7D8C88FF81908CFF798884FF
+ 6F7D79FF717F7BFF747F7CFF6F7A77FF6C7774FF6F7A77FF77807DFF7A8380FF
+ 767F7CFF717A77FF757E7BFF8E9794FF78817EFF67706DFF57605DFF262F2CFF
+ 59625FFF656E6BFF5F6865FF58615EFF515A57FF4E5754FF4D5653FF47504DFF
+ 39423FFF2D3633FF424944FF3D433EFF373D38FF3A403BFF494F4AFF595F5AFF
+ 5F6560FF5D635EFF555B56FF535954FF535954FF585E59FF5F6560FF636964FF
+ 626863FF5F6560FF5F665FFF6B726BFF6D746DFF636A63FF636A63FF6F766FFF
+ 737A73FF6B726BFF6C736CFF6D746DFF6B726BFF646B64FF626962FF666D66FF
+ 6B726BFF6D746DFF979D98FF838984FF939994FF838984FF484E49FF4D534EFF
+ 6B716CFF575D58FF595F5AFF565C57FF505651FF606661FF595F5AFF626863FF
+ 3F4540FF535954FF535954FF646B64FF5A615AFF6A716AFF616861FF686F68FF
+ 515851FF585F58FF6A716AFF5C635CFF656C65FF596059FF495049FF5F665FFF
+ 6A716AFF5E655EFF5D635EFF636964FF5E645FFF5C625DFF646A65FF656B66FF
+ 696F6AFF767C77FF737974FF7B817CFF828883FF838984FF858B86FF8B918CFF
+ 8F9590FF8F9590FF8F9590FF969C97FF828883FF777D78FF6F7570FF6E746FFF
+ 818782FF7C827DFF747A75FF8A908BFF676D68FF5C625DFF5D635EFF575D58FF
+ 686E69FF5B615CFF4E524CFF494E45FF62675EFF656A61FF3C4138FF32372EFF
+ 4A4F46FF50554CFF3C4138FF484D44FF3D4239FF61665DFF5D6259FF70756CFF
+ 363B32FF484D44FF72756CFF7A7B72FF77786FFF62635AFF464940FF35382FFF
+ 2F3229FF2D3229FF30352CFF384036FF535B51FF5B6359FF5F675DFF656D63FF
+ 5A6359FF5F685EFF6A7369FF636C62FF687167FF6E776DFF747D73FF8B948AFF
+ A4ADA3FFA8B1A7FFAAB3A9FFA0A99FFF959E94FF919A90FF959E94FF9BA49AFF
+ 9EA79DFF9EA79DFF979E99FF9FA6A1FF9BA29DFF9BA29DFFA7AEA9FFA9B0ABFF
+ A1A8A3FFA2A9A4FF838A85FF8E9590FF909792FF878E89FF888F8AFF969D98FF
+ 9EA5A0FF99A39DFF9EAAA4FF939F99FF909C96FF9CA8A2FFA9B3ADFFA7B1ABFF
+ 9FA9A3FF99A39DFF8E9590FF6E7570FF646A65FF6D736EFF575D58FF5B615CFF
+ 585E59FF4F5550FF484E49FF464C47FF414742FF393F3AFF444A45FF595F5AFF
+ 686E69FF676D68FF6D736EFF828883FF949A95FF99A09BFFA4ADAAFF9EA9A6FF
+ 949F9CFF909B98FF8D9895FF76817EFF626D6AFF65706DFF7A8582FF7C8784FF
+ 7B8683FF798481FF7A8582FF7D8885FF7C8784FF77827FFF7B8481FF7B8481FF
+ 7B8481FF7B8481FF7B8481FF7B8481FF7B8481FF7B8481FF77807DFF7D8683FF
+ 59625FFF858E8BFF87908DFF6F7875FF67706DFF656E6BFF696E6CFF606563FF
+ 5B605EFF5D6260FF5C615FFF575C5AFF565B59FF5A5F5DFF606563FF686D6BFF
+ 555A58FF606563FF404543FF464B49FF515654FF4E5351FF585E59FF606661FF
+ 656B66FF636964FF626863FF636964FF626863FF5F6560FF606661FF5F6560FF
+ 5E645FFF5D635EFF5C625DFF5D635EFF5E645FFF606661FF5C615FFF737876FF
+ 767B79FF747977FF7A817EFF737A77FF6E7572FF7F8683FF757E7BFF7C8582FF
+ 7D8885FF808B88FF8E9996FFA0ABA8FFA3B1ADFF9DABA7FF96A5A1FF92A39FFF
+ 879692FF7F8E8AFF81908CFF758480FF697773FF6C7A76FF6A7572FF67726FFF
+ 65706DFF67726FFF6E7774FF727B78FF717A77FF6F7875FF6D7673FF828B88FF
+ 7E8784FF79827FFF606966FF262F2CFF505956FF525B58FF5A6360FF535C59FF
+ 4C5552FF4B5451FF4D5653FF4D5653FF47504DFF434A47FF343A35FF353B36FF
+ 363C37FF3A403BFF454B46FF535954FF5E645FFF646A65FF5D635EFF5C625DFF
+ 5B615CFF5B615CFF5C625DFF5D635EFF5B615CFF5A605BFF5E655EFF565D56FF
+ 585F58FF636A63FF636A63FF5A615AFF5E655EFF6B726BFF5B625BFF5B625BFF
+ 5C635CFF5C635CFF5A615AFF585F58FF596059FF5D645DFF858B86FF7C827DFF
+ 777B76FF707671FF636762FF535954FF535752FF555B56FF60645FFF616762FF
+ 616560FF656B66FF5F635EFF686E69FF4F534EFF626863FF636A63FF6F766FFF
+ 666D66FF7A817AFF777E77FF757C75FF4D544DFF444B44FF5A615AFF535A53FF
+ 616861FF5D645DFF4F564FFF5E655EFF6F766FFF6D746DFF4D534EFF636964FF
+ 6A6E69FF656B66FF6E726DFF686E69FF575B56FF494F4AFF5D615CFF6A706BFF
+ 797D78FF797F7AFF777B76FF717772FF6E726DFF676D68FF5E625DFF666C67FF
+ 5C605BFF585E59FF535752FF4B514CFF5E625DFF5A605BFF666A65FF545A55FF
+ 4C504BFF4D534EFF5A5E59FF515752FF474B46FF565A54FF565B52FF50554CFF
+ 43483FFF3B4037FF3C4138FF373C33FF32372EFF373C33FF41463DFF4C5148FF
+ 3F443BFF53584FFF51564DFF7C8178FF4D5249FF4A4D44FF3F4037FF56574EFF
+ 72736AFF696A61FF676A61FF53564DFF494C43FF34372EFF33382FFF494E45FF
+ 3F443BFF454D43FF4D554BFF555D53FF6A7369FF5B645AFF5C655BFF5E675DFF
+ 656E64FF666F65FF656E64FF767F75FF8D968CFF969F95FFACB5ABFFA4ADA3FF
+ 9AA399FF969F95FF99A298FF9CA59BFF9CA59BFF9BA49AFF949B96FF9AA19CFF
+ 979E99FF99A09BFFA5ACA7FFA5ACA7FFA4ABA6FFAEB5B0FF979E99FF969D98FF
+ 959C97FF949B96FF909792FF8C938EFF8E9590FF939A95FF9DA7A1FF8D9993FF
+ 8D9993FF9FABA5FFABB5AFFFA2ACA6FF99A39DFF98A29CFF8B928DFF6C736EFF
+ 606661FF656B66FF636964FF646A65FF616762FF5B615CFF575D58FF545A55FF
+ 4C524DFF444A45FF3E443FFF555B56FF686E69FF6C726DFF717772FF828883FF
+ 959B96FF9EA5A0FFACB5B2FFA8B3B0FF9DA8A5FF95A09DFF8C9794FF727D7AFF
+ 606B68FF687370FF7E8986FF7A8582FF798481FF7A8582FF77827FFF747F7CFF
+ 76817EFF7B8683FF79827FFF79827FFF7A8380FF7B8481FF7B8481FF7B8481FF
+ 7A8380FF7A8380FF77807DFF818A87FF59625FFF7B8481FF7E8784FF727B78FF
+ 6C7572FF646D6AFF6B706EFF636866FF5D6260FF5C615FFF5A5F5DFF555A58FF
+ 535856FF535856FF676C6AFF6A6F6DFF535856FF555A58FF3F4442FF494E4CFF
+ 555A58FF474C4AFF50544FFF5A5E59FF636762FF656964FF656964FF666A65FF
+ 636762FF5E625DFF616560FF616560FF60645FFF5B5F5AFF575B56FF575B56FF
+ 5C605BFF616560FF5C615FFF6C716FFF6F7472FF707573FF767D7AFF707774FF
+ 6A716EFF737A77FF707976FF767F7CFF788380FF7C8784FF8D9895FFA3AEABFF
+ A9B7B3FFA5B3AFFF9AA9A5FF97A6A2FF8A9995FF83928EFF82908CFF73817DFF
+ 687370FF6D7875FF6A7572FF697471FF69726FFF69726FFF6D7471FF6F7673FF
+ 717875FF727976FF747D7AFF757E7BFF7B8481FF7C8582FF5C6562FF2C3532FF
+ 5F6865FF636C69FF555E5BFF4F5855FF49524FFF47504DFF4A5350FF4E5754FF
+ 4F5855FF515855FF454B46FF4B4F4AFF4F534EFF4E524DFF4C504BFF4F534EFF
+ 595D58FF636762FF5E625DFF5F635EFF5E625DFF5B5F5AFF585C57FF565A55FF
+ 575B56FF585C57FF51554FFF4A4E48FF4C504AFF575B55FF575B55FF4E524CFF
+ 51554FFF5D615BFF595D57FF545852FF555953FF595D57FF535751FF474B45FF
+ 434741FF484C46FF757974FF828681FF696A66FF545853FF5B5C58FF444843FF
+ 51524EFF929691FF636460FF6A6E69FF6D6E6AFF636762FF5F605CFF6C706BFF
+ 5D5E5AFF6E726DFF666A64FF676B65FF575B55FF676B65FF747872FF7B7F79FF
+ 5F635DFF575B55FF5F635DFF4F534DFF4F534DFF595D57FF595D57FF5F635DFF
+ 666A64FF5E625CFF5C605BFF6B6F6AFF6E6F6BFF646863FF60615DFF545853FF
+ 575854FF646863FF454642FF525651FF61625EFF60645FFF5C5D59FF535752FF
+ 4D4E4AFF444843FF4E4F4BFF585C57FF565753FF5D615CFF585955FF494D48FF
+ 595A56FF595D58FF494A46FF474B46FF575854FF383C37FF42433FFF595D58FF
+ 41423EFF4D4F49FF3E4138FF565A4FFF45493EFF34382DFF41453AFF393D32FF
+ 2D3126FF43473CFF606459FF494D42FF33372CFF41453AFF383C31FF65695EFF
+ 484C41FF42463BFF3A3B32FF47453DFF56574EFF484940FF515249FF494A41FF
+ 4E5148FF44473EFF45483FFF555A51FF32372EFF4B5047FF4F574DFF40483EFF
+ 666E64FF545C52FF5C655BFF616A60FF656E64FF656E64FF6C756BFF7E877DFF
+ 90998FFF98A197FFAAB3A9FFA4ADA3FF9EA79DFF9CA59BFF9DA69CFF9EA79DFF
+ 9BA49AFF98A197FF959C97FF969D98FF929994FF979E99FFA1A8A3FF9EA5A0FF
+ A0A7A2FFB2B9B4FFA9B0ABFF9DA49FFF99A09BFF9DA49FFF959C97FF858C87FF
+ 828984FF8D948FFF88928CFF7A847EFF7C8680FF929C96FF9FA9A3FF959F99FF
+ 8B928DFF89908BFF757B76FF585E59FF4C504BFF4A4E49FF5D635EFF5F6560FF
+ 606661FF5E645FFF5B615CFF575D58FF535954FF4E544FFF3E443FFF515752FF
+ 656B66FF6D736EFF737974FF818782FF989E99FFA8AFAAFFAEB7B4FFADB8B5FF
+ A5B0ADFF9DA8A5FF919C99FF75807DFF646F6CFF6E7976FF838E8BFF7D8885FF
+ 7D8885FF818C89FF7B8683FF707B78FF727D7AFF7C8784FF767F7CFF78817EFF
+ 79827FFF7B8481FF7C8582FF7C8582FF7B8481FF7B8481FF6F7875FF7B8481FF
+ 4D5653FF666F6CFF69726FFF67706DFF666F6CFF5A6360FF646967FF5F6462FF
+ 5B605EFF5C615FFF5F6462FF5F6462FF5E6361FF5C615FFF454A48FF4A4F4DFF
+ 393E3CFF353A38FF272C2AFF323735FF474C4AFF383D3BFF474B46FF535752FF
+ 5E625DFF626661FF636762FF646863FF616560FF5C605BFF5D615CFF60645FFF
+ 616560FF5C605BFF565A55FF555954FF5A5E59FF60645FFF5A5F5DFF636866FF
+ 696E6CFF6E7371FF727976FF707774FF6B726FFF6C7370FF757E7BFF7A8380FF
+ 7B8683FF7F8A87FF8F9A97FFA5B0ADFFADBBB7FFA9B7B3FF9FAEAAFF9BAAA6FF
+ 8D9C98FF859490FF83918DFF73817DFF6C7774FF77827FFF6E7976FF6E7976FF
+ 6E7774FF6C7572FF6B726FFF6B726FFF6E7572FF717875FF767F7CFF656E6BFF
+ 747D7AFF767F7CFF515A57FF28312EFF5B6461FF5F6865FF535C59FF4F5855FF
+ 4A5350FF464F4CFF444D4AFF464F4CFF49524FFF4D5451FF515752FF555954FF
+ 575B56FF555954FF4D514CFF484C47FF4C504BFF555954FF535752FF555954FF
+ 565A55FF545853FF515550FF515550FF565A55FF5B5F5AFF484C46FF555953FF
+ 585C56FF4E524CFF4D514BFF585C56FF595D57FF51554FFF5C605AFF555953FF
+ 565A54FF5D615BFF575B55FF4A4E48FF474B45FF4F534DFF4B4C48FF6E6F6BFF
+ 6D6E6AFF676864FF6C6D69FF535450FF535450FF898A86FF5C5D59FF656662FF
+ 666763FF545551FF575854FF696A66FF5E5F5BFF6A6C66FF747872FF71756FFF
+ 5E625CFF5B5F59FF5F635DFF5C605AFF494D47FF464A44FF585C56FF50544EFF
+ 494D47FF595D57FF5B5F59FF535751FF5C605AFF5B5F59FF5A5B57FF5C5D59FF
+ 686965FF7F807CFF858682FF6A6B67FF5A5B57FF6B6C68FF555652FF5A5B57FF
+ 5C5D59FF5A5B57FF5A5B57FF5C5D59FF5A5B57FF545551FF4B4C48FF575854FF
+ 565753FF62635FFF5A5B57FF484945FF555652FF585955FF454642FF575854FF
+ 656662FF4A4B47FF444541FF50514DFF464743FF565852FF30332AFF4E5247FF
+ 53574CFF484C41FF474B40FF3E4237FF363A2FFF41453AFF81857AFF4A4E43FF
+ 3E4237FF5E6257FF4B4F44FF54584DFF3E4237FF474B40FF5F5D55FF535149FF
+ 3E3F36FF3A3B32FF2E2F26FF37382FFF484B42FF63665DFF4E5148FF4E5148FF
+ 373C33FF595E55FF555D53FF31392FFF474F45FF4B5349FF4D554BFF525B51FF
+ 4E574DFF4F584EFF646D63FF7C857BFF8A9389FF919A90FFA0A99FFF9EA79DFF
+ 9CA59BFF9CA59BFF9DA69CFF9BA49AFF97A096FF939C92FF939A95FF8E9590FF
+ 878E89FF8E9590FF99A09BFF939A95FF919893FFA2A9A4FFA2A9A4FF989F9AFF
+ 909792FF8D948FFF868D88FF7C837EFF7B827DFF818883FF727C76FF6C7670FF
+ 6D7771FF7A847EFF8C9690FF8F9993FF808782FF6C736EFF636964FF505651FF
+ 4C504BFF4E524DFF626863FF656B66FF676D68FF666C67FF606661FF5A605BFF
+ 585E59FF595F5AFF444A45FF4E544FFF5C625DFF666C67FF6D736EFF7B817CFF
+ 959B96FFACB3AEFFA7B0ADFFA9B4B1FFA6B1AEFFA0ABA8FF95A09DFF798481FF
+ 6A7572FF75807DFF848F8CFF818C89FF848F8CFF8B9693FF86918EFF7A8582FF
+ 7A8582FF838E8BFF7D8683FF7E8784FF808986FF808986FF7F8885FF7D8683FF
+ 7A8380FF78817EFF77807DFF808986FF4A5350FF5A6360FF5C6562FF5F6865FF
+ 616A67FF545D5AFF636866FF5C615FFF525755FF494E4CFF444947FF3F4442FF
+ 363B39FF2D3230FF343937FF3C413FFF373C3AFF303533FF262B29FF292E2CFF
+ 494E4CFF404543FF454944FF515550FF5B5F5AFF60645FFF626661FF646863FF
+ 616560FF5D615CFF575B56FF5D615CFF616560FF5E625DFF585C57FF555954FF
+ 585C57FF5D615CFF5B605EFF5D6260FF676C6AFF707573FF717875FF737A77FF
+ 737A77FF6F7673FF78817EFF7E8784FF7F8A87FF848F8CFF95A09DFFACB7B4FF
+ B4C2BEFFB1BFBBFFA6B4B0FFA0AEAAFF919F9BFF8A9894FF85938FFF768480FF
+ 75807DFF889390FF6C7572FF6C7572FF6D7471FF6B726FFF69706DFF69706DFF
+ 6B726FFF6E7572FF6E7774FF5D6663FF77807DFF77807DFF535C59FF27302DFF
+ 434C49FF3C4542FF4C5552FF4D5653FF4D5653FF48514EFF424B48FF3F4845FF
+ 414A47FF464D4AFF434944FF424641FF444843FF4A4E49FF4A4E49FF454944FF
+ 454944FF4A4E49FF50544FFF525651FF535752FF515550FF50544FFF535752FF
+ 5A5E59FF616560FF565A54FF63685FFF666B62FF5C6158FF5A5F56FF63685FFF
+ 63685FFF5A5F56FF62675EFF5D6259FF5E635AFF646960FF646960FF5F645BFF
+ 63685FFF6D7269FF5D5F59FF61615BFF61615BFF60605AFF63635DFF65655FFF
+ 62625CFF5D5D57FF595953FF5A5A54FF5C5C56FF464640FF55554FFF64645EFF
+ 5B5B55FF5F615BFF646862FF70756CFF747970FF6C7168FF6B7067FF585D54FF
+ 4C5148FF4D5249FF484D44FF555A51FF4D5249FF5C6158FF5A5F56FF494E45FF
+ 5F645BFF6B6F69FF636460FF61605CFF5E5D59FF706F6BFF8A8985FF858480FF
+ 6D6C68FF63625EFF656460FF61605CFF5B5A56FF5A5955FF61605CFF696864FF
+ 676662FF5F5E5AFF565551FF61605CFF5C5B57FF64635FFF5A5955FF4A4945FF
+ 565551FF565551FF454440FF3C3B37FF34332FFF5B5A56FF5B5A56FF262521FF
+ 282723FF464640FF4A4D44FF44483DFF505449FF55594EFF484C41FF474B40FF
+ 41453AFF272B20FF696D62FF404439FF4B4F44FF6C7065FF5D6156FF5E6257FF
+ 4E5247FF5B5F54FF66645CFF58564EFF413F37FF65635BFF42433AFF494A41FF
+ 4B4C43FF7E7F76FF42453CFF40433AFF464B42FF4A4F46FF42473EFF3A3F36FF
+ 42473EFF555D53FF424A40FF586056FF545C52FF485046FF555D53FF687066FF
+ 7B8379FF90988EFF979F95FF979F95FF979F95FF979F95FF959D93FF8F978DFF
+ 889086FF838B81FF818782FF7C827DFF747A75FF7C827DFF8A908BFF858B86FF
+ 7E847FFF878D88FF8F9590FF8C928DFF808681FF6F7570FF6A706BFF707671FF
+ 747A75FF6F7671FF727C76FF757F79FF6F7973FF6C7670FF818883FF919893FF
+ 7C827DFF555B56FF4D534EFF464C47FF515550FF5C605BFF575D58FF555B56FF
+ 575D58FF5A605BFF595F5AFF555B56FF555B56FF585E59FF4A504BFF494F4AFF
+ 4F5550FF595F5AFF616762FF6C726DFF868C87FF9FA6A1FF99A29FFF9BA6A3FF
+ 98A3A0FF96A19EFF8F9A97FF77827FFF6B7673FF77827FFF818C89FF828D8AFF
+ 87928FFF8C9794FF8C9794FF87928FFF85908DFF889390FF858E8BFF858E8BFF
+ 858E8BFF838C89FF7F8885FF7A8380FF757E7BFF717A77FF757E7BFF767F7CFF
+ 39423FFF47504DFF48514EFF4A5350FF4F5855FF464F4CFF343937FF363B39FF
+ 383D3BFF3E4341FF4C514FFF595E5CFF5B605EFF565B59FF525755FF555A58FF
+ 565B59FF4A4F4DFF3B403EFF292E2CFF494E4CFF464B49FF484C47FF515550FF
+ 595D58FF5B5F5AFF5D615CFF60645FFF60645FFF5D615CFF555954FF595D58FF
+ 5C605BFF5B5F5AFF565A55FF525651FF525651FF545853FF5D6260FF5A5F5DFF
+ 676C6AFF717674FF6C7370FF727976FF787F7CFF717875FF747D7AFF7C8582FF
+ 808B88FF87928FFF9BA6A3FFB4BFBCFFBDCBC7FFBAC8C4FFACBAB6FFA6B4B0FF
+ 98A6A2FF919F9BFF8A9894FF788682FF798481FF909B98FF6A7370FF6A7370FF
+ 6C7370FF6D7471FF6E7572FF6E7572FF6E7572FF6E7572FF757E7BFF646D6AFF
+ 77807DFF6C7572FF5B6461FF424B48FF58615EFF555E5BFF444D4AFF4B5451FF
+ 505956FF4D5653FF454E4BFF404946FF444D4AFF4B524FFF4B514CFF474B46FF
+ 484C47FF535752FF575B56FF4F534EFF4A4E49FF4C504BFF595D58FF595D58FF
+ 575B56FF565A55FF575B56FF5C605BFF636762FF686C66FF676B65FF5F645BFF
+ 62675EFF6B7067FF686D64FF5B6057FF595E55FF646960FF72776EFF70756CFF
+ 6D7269FF696E65FF676C63FF696E65FF6E736AFF75786FFF7F7F79FF6E6E68FF
+ 696963FF595953FF43433DFF55554FFF6C6C66FF5F5F59FF5A5A54FF53534DFF
+ 595953FF45453FFF5B5B55FF60605AFF585852FF5E5E58FF61645BFF6E736AFF
+ 7B8077FF6F746BFF777C73FF696E65FF71766DFF7E837AFF5D6259FF62675EFF
+ 3D4239FF4B5047FF5E635AFF51564DFF5B6057FF53564DFF5A5955FF767571FF
+ 6F6E6AFF54534FFF5A5955FF6F6E6AFF71706CFF696864FF64635FFF62615DFF
+ 5F5E5AFF605F5BFF686763FF6D6C68FF656460FF595854FF64635FFF706F6BFF
+ 666561FF64635FFF5C5B57FF53524EFF5D5C58FF555450FF605F5BFF595854FF
+ 41403CFF72716DFF84837FFF53524EFF4C4B47FF44443EFF52554CFF42463BFF
+ 575B50FF63675CFF494D42FF45493EFF4F5348FF3C4035FF53574CFF484C41FF
+ 4F5348FF4B4F44FF4C5045FF707469FF7C8075FF8C8D83FF605E56FF535149FF
+ 46443CFF75736BFF56574EFF52534AFF494A41FF76776EFF363930FF474A41FF
+ 585D54FF3D4239FF373C33FF545950FF60655CFF6F746BFF424A40FF6B7369FF
+ 6B7369FF4E564CFF485046FF4E564CFF636B61FF868E84FF8A9288FF8B9389FF
+ 8C948AFF8A9288FF858D83FF7C847AFF737B71FF6D756BFF686E69FF6B716CFF
+ 656B66FF676D68FF757B76FF767C77FF707671FF747A75FF888E89FF888E89FF
+ 787E79FF626863FF5F6560FF6D736EFF737974FF6B726DFF787F7AFF7B857FFF
+ 727C76FF66706AFF737A75FF828984FF6F7570FF494F4AFF4A504BFF4B514CFF
+ 5D615CFF666A65FF4E544FFF424843FF3B413CFF424843FF4A504BFF494F4AFF
+ 454B46FF444A45FF4C524DFF434944FF424843FF4C524DFF535954FF595F5AFF
+ 6E746FFF858C87FF8B9491FF8A9592FF838E8BFF808B88FF7E8986FF6D7875FF
+ 65706DFF737E7BFF7E8986FF818C89FF818C89FF808B88FF818C89FF848F8CFF
+ 828D8AFF7D8885FF7C8582FF7D8683FF7D8683FF7C8582FF78817EFF737C79FF
+ 6D7673FF6A7370FF626B68FF5C6562FF1C2522FF303936FF343D3AFF363F3CFF
+ 404946FF3F4845FF767B79FF737876FF6B706EFF646967FF646967FF666B69FF
+ 5D6260FF4F5452FF5A5F5DFF555A58FF5A5F5DFF505553FF414644FF1C211FFF
+ 3A3F3DFF393E3CFF464A45FF4F504CFF535450FF52534FFF535450FF585955FF
+ 5B5C58FF5A5B57FF595A56FF585955FF565753FF52534FFF4F504CFF4C4D49FF
+ 4A4B47FF474B46FF595E5CFF535856FF626765FF6B706EFF5F6663FF666D6AFF
+ 737A77FF6B726FFF6E7774FF77807DFF7E8986FF889390FF9DA8A5FFB6C1BEFF
+ BFCDC9FFBBC9C5FFB2C0BCFFACBAB6FFA1AFABFF9AA8A4FF919C99FF788380FF
+ 747F7CFF8A9592FF6E7774FF6C7572FF6C7370FF6E7572FF707774FF6E7572FF
+ 6A6F6DFF646B68FF6A7370FF5F6865FF67706DFF515A57FF5A6360FF5B6461FF
+ 717A77FF79827FFF464F4CFF4F5855FF57605DFF545D5AFF4B5451FF48514EFF
+ 4E5754FF59605DFF656964FF5F605CFF61625EFF6B6C68FF6A6B67FF5D5E5AFF
+ 545551FF555652FF646561FF60615DFF5C5D59FF5D5E5AFF62635FFF696A66FF
+ 70716DFF73756FFF6A6C66FF62655CFF64675EFF6D7067FF686B62FF595C53FF
+ 575A51FF60635AFF74776EFF7A7D74FF75786FFF676A61FF62655CFF6A6D64FF
+ 6D7067FF696C63FF5C5C56FF64645EFF7B7B75FF7B7B75FF5E5E58FF54544EFF
+ 5F5F59FF61615BFF5D5D57FF53534DFF61615BFF4F4F49FF666660FF5D5D57FF
+ 585852FF64645EFF7B7E75FF7B7E75FF7B7E75FF63665DFF71746BFF64675EFF
+ 72756CFF7D8077FF75786FFF7D8077FF45483FFF494C43FF60635AFF54574EFF
+ 5B5E55FF464940FF3D3C38FF656460FF777672FF6B6A66FF656460FF62615DFF
+ 5D5C58FF5D5C58FF686763FF6D6C68FF6F6E6AFF6E6D69FF71706CFF73726EFF
+ 6E6D69FF676662FF61605CFF72716DFF64635FFF5C5B57FF585753FF595854FF
+ 61605CFF4D4C48FF595854FF63625EFF53524EFF504F4BFF61605CFF63625EFF
+ 4F4E4AFF373731FF4D4E44FF4D4F43FF606256FF6F7165FF616357FF4E5044FF
+ 505246FF5B5D51FF626458FF636559FF606256FF47493DFF54564AFF77796DFF
+ 838579FF97988EFF65635BFF524F47FF504E46FF5C5A52FF605E56FF4F4D45FF
+ 4F5047FF5D5E55FF363930FF51544BFF60635AFF676A61FF62675EFF60655CFF
+ 6D7269FF6E736AFF3E463CFF656D63FF5C645AFF3F473DFF434B41FF464E44FF
+ 4A5248FF636B61FF777F75FF798177FF7B8379FF7A8278FF757D73FF6D756BFF
+ 646C62FF5F675DFF5C625DFF6D736EFF696F6AFF5D635EFF636964FF6A706BFF
+ 6B716CFF6F7570FF868C87FF7E847FFF707671FF666C67FF666C67FF6E746FFF
+ 747A75FF757C77FF737A75FF707A74FF6D746FFF686F6AFF69706BFF686F6AFF
+ 606661FF545A55FF6A6E69FF6E726DFF7C807BFF7F837EFF7D817CFF636A63FF
+ 545853FF565D56FF626661FF5D645DFF525651FF474E47FF4E524DFF3E453EFF
+ 3C403BFF444B44FF4B4F4AFF4B524BFF5D615CFF717772FF858C87FF7F8885FF
+ 747D7AFF717A77FF717A77FF656E6BFF606966FF707976FF808986FF838C89FF
+ 7D8683FF737C79FF747D7AFF7C8582FF79827FFF6D7673FF6E7572FF707774FF
+ 727976FF737A77FF727976FF6E7572FF6A716EFF686F6CFF737A77FF69706DFF
+ 2A312EFF444B48FF4E5552FF525956FF616865FF666D6AFF606563FF606563FF
+ 5C615FFF5B605EFF636866FF6B706EFF666B69FF5A5F5DFF535856FF494E4CFF
+ 545957FF555A58FF505553FF282D2BFF474C4AFF494E4CFF444541FF494A46FF
+ 4A4B47FF474844FF474844FF4D4E4AFF52534FFF52534FFF5C5D59FF575854FF
+ 4F504CFF494A46FF464743FF444541FF42433FFF3E423DFF535856FF4B504EFF
+ 5B605EFF626765FF525956FF59605DFF69706DFF626966FF6C7572FF767F7CFF
+ 7F8885FF87928FFF9EA7A4FFB4BFBCFFBDC8C5FFB7C5C1FFB5C3BFFFB0BFBBFF
+ A8B6B2FFA2B0ACFF93A19DFF76817EFF6D7875FF828D8AFF6F7875FF6B7471FF
+ 69706DFF686F6CFF69706DFF646B68FF5B605EFF515654FF484F4AFF4A514CFF
+ 565D58FF404742FF585F5AFF5B625DFF616863FF646B66FF4F5651FF59605BFF
+ 606762FF5C635EFF525954FF4F5651FF585F5AFF646A65FF646863FF61635DFF
+ 656662FF70726CFF6D6E6AFF5D5F59FF565753FF5A5C56FF646561FF5F615BFF
+ 5B5C58FF5D5F59FF666763FF71736DFF777874FF7A7C76FF666960FF72756CFF
+ 74776EFF676A61FF62655CFF676A61FF63665DFF585B52FF5E6158FF6C6F66FF
+ 6B6E65FF5D6057FF5C5F56FF6C6F66FF72756CFF696C63FF55554FFF55554FFF
+ 595953FF676761FF6B6B65FF5D5D57FF5F5F59FF75756FFF5E5E58FF54544EFF
+ 6A6A64FF595953FF6D6D67FF5A5A54FF585852FF6B6B65FF5E6158FF5D6057FF
+ 65685FFF595C53FF787B72FF6A6D64FF6E7168FF6B6E65FF63665DFF94978EFF
+ 71746BFF63665DFF585B52FF42453CFF676A61FF71746BFF686862FF4F4F49FF
+ 42413DFF5D5D57FF787773FF6C6C66FF5F5E5AFF6C6C66FF565551FF5E5E58FF
+ 62615DFF5D5D57FF5B5A56FF5F5F59FF64635FFF666660FF6A6965FF7F7F79FF
+ 72716DFF676761FF676662FF6F6F69FF74736FFF585852FF83827EFF75756FFF
+ 797874FF60605AFF5F5E5AFF666660FF54534FFF6D6D67FF5A5B51FF595B4FFF
+ 515248FF686A5EFF83847AFF626458FF3C3D33FF47493DFF525349FF54564AFF
+ 5C5D53FF55574BFF63645AFF56584CFF3F4036FF53544AFF66645CFF525048FF
+ 64625AFF4D4E45FF78766EFF5A5B52FF66675EFF505148FF373A31FF4E5148FF
+ 595C53FFA0A39AFF9A9F96FF545950FF5B6057FF565B52FF52574EFF666E64FF
+ 50554CFF3C443AFF5E635AFF676F65FF575C53FF565E54FF676C63FF697167FF
+ 6F746BFF6F776DFF6E736AFF666E64FF63685FFF5D655BFF626660FF798079FF
+ 787C76FF5E655EFF5C605AFF646B64FF6D716BFF717871FF7F837DFF6C736CFF
+ 646862FF676E67FF6D716BFF6A716AFF727670FF7D847DFF6E766FFF656D66FF
+ 686F68FF6F766FFF697069FF5A615AFF5C635CFF6D716BFF6F736DFF747872FF
+ 838781FF868A84FF7A7C76FF878C83FF646660FF4B5047FF767872FF70756CFF
+ 5C5E58FF6B7067FF5F615BFF5E635AFF5F615BFF5D6259FF8C8E88FF676C63FF
+ 5C5E58FF6C706AFF727671FF767A75FF90948FFF979B96FF545853FF616560FF
+ 767A75FF6D716CFF6A6E69FF676B66FF6C706BFF6C706BFF6A6E69FF737772FF
+ 797D78FF70746FFF676B66FF646863FF8C908BFF676B66FF636762FF656964FF
+ 666A65FF5F635EFF656964FF4D514CFF414540FF4E524DFF5A5E59FF575B56FF
+ 545853FF595D58FF636964FF666C67FF666C67FF656B66FF6A706BFF707671FF
+ 717772FF6D736EFF565C57FF575D58FF5F6560FF5C625DFF555B56FF242A25FF
+ 3B413CFF434944FF484945FF4B4C48FF464743FF494A46FF52534FFF4A4B47FF
+ 3F403CFF444541FF51524EFF5A5B57FF5A5B57FF454642FF383935FF363733FF
+ 454642FF4A4E49FF525853FF5A615CFF606762FF59605BFF535A55FF585F5AFF
+ 606762FF676E69FF6E7570FF6A716CFF727974FF89938DFFA5ACA7FFB3BDB7FF
+ BAC4BEFFBDC9C3FFB2C2BBFFABBDB6FFA8B8B1FFA0B0A9FF8F9F98FF7C8A84FF
+ 6E7C76FF6B7973FF727E78FF49554FFF848E88FF36403AFF555C57FF49504BFF
+ 666C67FF6E746FFF454943FF444842FF434741FF4C504AFF646862FF767A74FF
+ 6C706AFF555953FF464A44FF4C504AFF525650FF565A54FF575B55FF565A54FF
+ 535751FF50544EFF7C7E78FF6B6E65FF5F615BFF74776EFF5F615BFF787B72FF
+ 6E706AFF5A5D54FF666862FF7D8077FF62645EFF52554CFF5A5C56FF5D6057FF
+ 72746EFF80837AFF65685FFF6C6F66FF5C5F56FF73766DFF50534AFF595C53FF
+ 72756CFF72756CFF676A61FF70736AFF696C63FF666960FF65685FFF64675EFF
+ 686B62FF5C5F56FF6C6F66FF686B62FF565950FF62655CFF5E6158FF71746BFF
+ 64675EFF5F6259FF8F9289FF4E5148FF575A51FF71746BFF787B72FF70736AFF
+ 64675EFF83867DFF696C63FF5A5D54FF484B42FF6B6E65FF80837AFF64675EFF
+ 60635AFF6B6E65FF5E6158FF686B62FF75786FFF797C73FF71746BFF696C63FF
+ 6F7269FF7A7D74FF7F8279FF61645BFF464842FF686B62FF6E706AFF575A51FF
+ 60625CFF52554CFF5B5D57FF4E5148FF6F716BFF7D8077FF70726CFF84877EFF
+ 52544EFF53564DFF686A64FF7C7F76FF686A64FF6C6F66FF747670FF7C7F76FF
+ 959791FF81847BFF5B5D57FF55584FFF52544EFF585B52FF646660FF686B62FF
+ 63655FFF5B5E55FF55584FFF72766BFF63665DFF5C6055FF7D8077FF777B70FF
+ 5F6259FF6F7368FF666960FF5E6257FF474A41FF5E6257FF64675EFF81857AFF
+ 6D7067FF63665DFF5D5E55FF6C6D64FF72736AFF61645BFF707168FF71746BFF
+ 5C5F56FF6E7168FF50534AFF72756CFF696C63FF5D6057FF5D6057FF5E6158FF
+ 696C63FF62655CFF6A6D64FF5C6158FF63665DFF6C7168FF6D7067FF6D7269FF
+ 71746BFF686D64FF73766DFF676C63FF6E7168FF72776EFF696C63FF656A61FF
+ 71746BFF72776EFF6C6F66FF72776EFF6C6F66FF747970FF6B6E65FF8C9188FF
+ 80837AFF656A61FF676A61FF51564DFF565950FF72776EFF60635AFF494E45FF
+ 6E7168FF7F847BFF696E65FF60655CFF676C63FF6F746BFF63685FFF5B6057FF
+ 61665DFF65685FFF71746BFF61645BFF73766DFF767970FF72756CFF6A6D64FF
+ 595C53FF5E6158FF5F6259FF6A6D64FF63665DFF63665DFF54574EFF64675EFF
+ 65685FFF63665DFF7D8077FF6D7067FF71746BFF94978EFF52534FFF6B6C68FF
+ B3B4B0FFE4E5E1FF989995FF72736FFF696A66FF676864FF686965FF6F706CFF
+ 737470FF6F706CFF6B6C68FF6D6E6AFF6E6F6BFF6D6E6AFF666763FF62635FFF
+ 7F807CFF6A6B67FF656662FF70716DFF676864FF5D5E5AFF696A66FF545551FF
+ 4A4B47FF565753FF62635FFF60615DFF5C5D59FF5D5E5AFF585C57FF5D635EFF
+ 626863FF636964FF676D68FF6C726DFF6E746FFF6B716CFF737974FF5E645FFF
+ 4F5550FF5C625DFF5C625DFF333934FF333934FF333732FF454642FF4A4B47FF
+ 454642FF41423EFF3E3F3BFF343531FF393A36FF50514DFF4F504CFF595A56FF
+ 5B5C58FF4C4D49FF40413DFF40413DFF494A46FF4D514CFF515752FF5A615CFF
+ 565D58FF585F5AFF59605BFF5C635EFF69706BFF666D68FF69706BFF6B726DFF
+ 737A75FF858C87FF9DA49FFFB0B7B2FFBAC1BCFFBBC5BFFFB3C1BBFF9FB1AAFF
+ 90A099FF86968FFF7E8E87FF74827CFF6A7872FF68746EFF49554FFF3D4741FF
+ 6A746EFF555C57FF585F5AFF545A55FF565C57FF5E625CFF555751FF595C53FF
+ 5F6259FF65685FFF6E7168FF72756CFF6B6E65FF5F6259FF575A51FF6E7168FF
+ 75786FFF676A61FF65685FFF71746BFF6E7168FF5D6057FF686B62FF696C63FF
+ 5E6158FF65685FFF666960FF9B9E95FF91948BFF63665DFF6E7168FF7D8077FF
+ 6B6E65FF676A61FF70736AFF75786FFF84877EFF81847BFF666960FF565950FF
+ 71746BFF60635AFF696C63FF71746BFF52554CFF60635AFF63665DFF767970FF
+ 7C7F76FF74776EFF61645BFF585B52FF666960FF6F7269FF6A6D64FF686B62FF
+ 585B52FF64675EFF5F6259FF71746BFF65685FFF63665DFF52554CFF595C53FF
+ 7D8077FF767970FF6B6E65FF767970FF6F7269FF75786FFF80837AFF85887FFF
+ 666960FF565950FF54574EFF54574EFF65685FFF65685FFF777A71FF80837AFF
+ 82857CFF75786FFF686B62FF64675EFF666960FF676A61FF686B62FF5E6158FF
+ 4F5249FF686B62FF6D7067FF676A61FF777A71FF666960FF5D6057FF5A5D54FF
+ 5E6158FF6C6F66FF6B6E65FF7F8279FF64675EFF6C6F66FF65685FFF65685FFF
+ 5B5E55FF62655CFF676A61FF65685FFF6D7067FF686B62FF73766DFF6A6D64FF
+ 60635AFF60635AFF686B62FF70736AFF73766DFF73766DFF6E7168FF7F8279FF
+ 6E7168FF60635AFF6D7067FF676A61FF595C53FF65685FFF5B5E55FF6D7067FF
+ 686B62FF70736AFF64675EFF787B72FF6D7067FF686B62FF64675EFF6E7168FF
+ 75786FFF6B6E65FF7C7F76FF82857CFF6D7067FF797C73FF65685FFF6E7168FF
+ 60635AFF6C6F66FF72756CFF61645BFF65685FFF6B6E65FF82857CFF72756CFF
+ 70736AFF74776EFF71746BFF75786FFF7E8178FF7B7E75FF7A7D74FF6E7168FF
+ 71746BFF74776EFF696C63FF65685FFF6B6E65FF6B6E65FF686C61FF6A6E63FF
+ 676B60FF7B7F74FF71756AFF808479FF6D7166FF5F6358FF676B60FF696D62FF
+ 676B60FF72766BFF65695EFF595D52FF6E7267FF71756AFF6E7267FF6D7166FF
+ 75796EFF767A6FFF6A6E63FF6A6E63FF71756AFF6D7166FF8B8F84FF7C8075FF
+ 84887DFF777B70FF878A81FF6B6E65FF6C6F66FF8C8F86FF5C5F56FF6B6E65FF
+ 65685FFF52554CFF60635AFF64675EFF474A41FF464940FF585B52FF64675EFF
+ 5B5E55FF6C6F66FF646561FF5B5C58FF767773FF9B9C98FF6B6C68FF656662FF
+ 686965FF696A66FF4A4B47FF5D5E5AFF636460FF61625EFF676864FF6A6B67FF
+ 6D6E6AFF767773FF747571FF656662FF60615DFF555652FF4B4C48FF676864FF
+ 646561FF636460FF5D5E5AFF52534FFF4F504CFF5B5C58FF666763FF656662FF
+ 636460FF656662FF626661FF676B66FF666A65FF5F635EFF5A5E59FF5D615CFF
+ 60645FFF616560FF636762FF5A5E59FF484C47FF5D615CFF4A4E49FF2C302BFF
+ 292D28FF313530FF333430FF3C3D39FF434440FF4C4D49FF4D4E4AFF3D3E3AFF
+ 3B3C38FF50514DFF4B4C48FF545551FF52534FFF4C4D49FF3E3F3BFF40413DFF
+ 40413DFF424641FF4F5550FF5B625DFF4B524DFF585F5AFF5F6661FF5A615CFF
+ 6A716CFF59605BFF606762FF69706BFF707772FF777E79FF89908BFFA1A8A3FF
+ ADB4AFFFAAB4AEFFA3B1ABFF91A19AFF84928CFF82908AFF7F8D87FF727E78FF
+ 5A6660FF4C5650FF4B554FFF535A55FF636A65FF828883FF6A706BFF737772FF
+ 6A6E69FF747872FF61635DFF676A61FF72756CFF7B7E75FF797C73FF71746BFF
+ 6F7269FF72756CFF5D6057FF6F7269FF777A71FF70736AFF6E7168FF74776EFF
+ 71746BFF65685FFF7B7E75FF71746BFF6E7168FF797C73FF686B62FF74776EFF
+ 787B72FF7C7F76FF767970FF797C73FF6E7168FF70736AFF6F7269FF70736AFF
+ 787B72FF5E6158FF64675EFF5F6259FF6C6F66FF52554CFF8F9289FF878A81FF
+ 5F6259FF6A6D64FF676A61FF6C6F66FF767970FF797C73FF70736AFF62655CFF
+ 595C53FF5A5D54FF54574EFF61645BFF676A61FF80837AFF767970FF74776EFF
+ 53564DFF45483FFF777A71FF8F9289FF9A9D94FF6B6E65FF4E5148FF61645BFF
+ 696C63FF6F7269FF91948BFF80837AFF6C6F66FF82857CFF878A81FF686B62FF
+ 585B52FF494C43FF5A5D54FF71746BFF83867DFF83867DFF7C7F76FF74776EFF
+ 64675EFF53564DFF5C5F56FF63665DFF65685FFF72756CFF71746BFF72756CFF
+ 7C7F76FF676A61FF797C73FF878A81FF63665DFF6B6E65FF6C6F66FF6E7168FF
+ 5F6259FF64675EFF72756CFF64675EFF6F7269FF797C73FF7A7D74FF70736AFF
+ 61645BFF6B6E65FF7B7E75FF74776EFF6C6F66FF6A6D64FF6E7168FF767970FF
+ 7E8178FF83867DFF686B62FF70736AFF70736AFF6C6F66FF6F7269FF73766DFF
+ 74776EFF75786FFF686B62FF70736AFF666960FF696C63FF696C63FF80837AFF
+ 73766DFF63665DFF6B6E65FF6E7168FF72756CFF686B62FF72756CFF767970FF
+ 5D6057FF60635AFF61645BFF64675EFF53564DFF63665DFF72756CFF64675EFF
+ 64675EFF64675EFF70736AFF61645BFF5F6259FF63665DFF5E6158FF63665DFF
+ 6E7168FF6F7269FF70736AFF64675EFF666960FF6B6E65FF64675EFF64675EFF
+ 686B62FF63665DFF7E8277FF74786DFF696D62FF787C71FF707469FF707469FF
+ 666A5FFF6A6E63FF6A6E63FF83877CFF75796EFF6B6F64FF6B6F64FF6D7166FF
+ 787C71FF71756AFF6E7267FF71756AFF7A7E73FF787C71FF6F7368FF777B70FF
+ 82867BFF7D8176FF7B7F74FF6F7368FF7C8075FF72766BFF7B7E75FF6A6D64FF
+ 70736AFFA6A9A0FF71746BFF81847BFF73766DFF6A6D64FF62655CFF63665DFF
+ 40433AFF484B42FF595C53FF7D8077FF6E7168FF70736AFF666763FF585955FF
+ 4F504CFF575854FF40413DFF62635FFF646561FF4C4D49FF3E3F3BFF4F504CFF
+ 51524EFF50514DFF5F605CFF676864FF6A6B67FF767773FF6B6C68FF737470FF
+ 7E7F7BFF969793FF81827EFF888985FF676864FF545551FF5C5D59FF5D5E5AFF
+ 61625EFF646561FF636460FF5E5F5BFF5D5E5AFF5F605CFF646863FF666A65FF
+ 616560FF525651FF494D48FF4C504BFF545853FF595D58FF4F534EFF5C605BFF
+ 4B4F4AFF626661FF4B4F4AFF464A45FF40443FFF414540FF3F403CFF3F403CFF
+ 40413DFF4D4E4AFF585955FF474844FF3A3B37FF444541FF444541FF4B4C48FF
+ 444541FF4A4B47FF3E3F3BFF474844FF42433FFF454944FF474D48FF59605BFF
+ 484F4AFF5A615CFF5E6560FF515853FF5E6560FF444B46FF49504BFF585F5AFF
+ 616863FF646B66FF757C77FF939A95FFA3AAA5FFA0A7A2FF8F9B95FF828E88FF
+ 79857FFF7D8983FF828C86FF757F79FF5F6963FF505752FF666D68FF6B716CFF
+ 626863FF8E928DFF70746FFF7A7E79FF7F837EFF8F938DFF757771FF72756CFF
+ 767970FF7F8279FF7C7F76FF71746BFF6E7168FF75786FFF73766DFF686B62FF
+ 6D7067FF83867DFF888B82FF797C73FF74776EFF7D8077FF777A71FF676A61FF
+ 676A61FF777A71FF6B6E65FF62655CFF74776EFF95988FFF72756CFF6F7269FF
+ 686B62FF6B6E65FF5E6158FF60635AFF6B6E65FF4A4D44FF95988FFFB3B6ADFF
+ 6A6D64FF5E6158FF9A9D94FF73766DFF696C63FF63665DFF676A61FF5D6057FF
+ 696C63FF72756CFF7C7F76FF81847BFF7A7D74FF81847BFF797C73FF787B72FF
+ 6A6D64FF75786FFF676A61FF6D7067FF60635AFF63665DFF5F6259FF6D7067FF
+ 777A71FF6F7269FF696C63FF666960FF63665DFF6C6F66FF8A8D84FF61645BFF
+ 474A41FF6A6D64FF7A7D74FF6D7067FF777A71FF797C73FF666960FF676A61FF
+ 676A61FF676A61FF6A6D64FF70736AFF767970FF7A7D74FF75786FFF797C73FF
+ 84877EFF8E9188FF868980FF81847BFF7F8279FF6E7168FF81847BFFA3A69DFF
+ 686B62FF74776EFF777A71FF666960FF5C5F56FF575A51FF565950FF4B4E45FF
+ 6A6D64FF6C6F66FF696C63FF65685FFF4C4F46FF5D6057FF60635AFF60635AFF
+ 61645BFF61645BFF63665DFF676A61FF6C6F66FF6F7269FF6A6D64FF65685FFF
+ 70736AFF73766DFF686B62FF6B6E65FF6A6D64FF575A51FF6C6F66FF61645BFF
+ 52554CFF565950FF60635AFF70736AFF6D7067FF676A61FF61645BFF61645BFF
+ 6B6E65FF5F6259FF5F6259FF61645BFF4C4F46FF4B4E45FF53564DFF6A6D64FF
+ 595C53FF565950FF676A61FF72756CFF767970FF64675EFF5E6158FF54574EFF
+ 595C53FF5E6158FF55584FFF54574EFF5A5D54FF585B52FF64675EFF5B5E55FF
+ 60635AFF696C63FF696C63FF6F7269FF74776EFF6C6F66FF6E7267FF6B6F64FF
+ 62665BFF686C61FF6B6F64FF696D62FF63675CFF6C7065FF6C7065FF888C81FF
+ 6E7267FF5E6257FF6A6E63FF707469FF797D72FF777B70FF8F9388FF83877CFF
+ 81857AFF7B7F74FF696D62FF63675CFF686C61FF676B60FF767A6FFF65695EFF
+ 777B70FF7A7E73FF71746BFF73766DFF63665DFF8A8D84FF6B6E65FF75786FFF
+ 5C5F56FF6E7168FF6D7067FF7E8178FF6E7168FF70736AFF65685FFF7E8178FF
+ 75786FFF7B7E75FF696A66FF6C6D69FF666763FF696A66FF52534FFF70716DFF
+ 70716DFF5F605CFF646561FF646561FF5A5B57FF535450FF595A56FF61625EFF
+ 62635FFF636460FF72736FFF71726EFF676864FF7A7B77FF60615DFF6B6C68FF
+ 696A66FF696A66FF6E6F6BFF797A76FF7F807CFF757672FF656662FF5A5B57FF
+ 575854FF585955FF4E524DFF555954FF585C57FF525651FF4F534EFF545853FF
+ 5C605BFF60645FFF6B6F6AFF787C77FF5C605BFF70746FFF727671FF888C87FF
+ 757974FF525651FF646561FF5D5E5AFF4C4D49FF444541FF444541FF3B3C38FF
+ 373834FF454642FF383935FF3A3B37FF2D2E2AFF3E3F3BFF333430FF464743FF
+ 3D3E3AFF434742FF444A45FF595F5AFF565C57FF666C67FF686E69FF5B615CFF
+ 5F6560FF494F4AFF404641FF4F5550FF585E59FF5B615CFF6E746FFF8C928DFF
+ 9CA29DFF989F9AFF858C87FF757F79FF6A746EFF6B756FFF747B76FF767D78FF
+ 777E79FF797F7AFF666C67FF636762FF5F635EFF7C7D79FF6A6B67FF666763FF
+ 747571FF7E807AFF898B85FF797C73FF70736AFF75786FFF777A71FF6F7269FF
+ 6A6D64FF6C6F66FF767970FF63665DFF63665DFF7B7E75FF868980FF7A7D74FF
+ 71746BFF75786FFF75786FFF75786FFF6B6E65FF5F6259FF72756CFF80837AFF
+ 7D8077FF6E7168FF6D7067FF6E7168FF6B6E65FF6E7168FF60635AFF686B62FF
+ 81847BFF6C6F66FF888B82FFB3B6ADFF50534AFF51544BFF74776EFF61645BFF
+ 5C5F56FF62655CFF767970FF696C63FF6F7269FF5B5E55FF50534AFF5B5E55FF
+ 63665DFF82857CFF7E8178FF787B72FF676A61FF74776EFF6A6D64FF767970FF
+ 71746BFF7D8077FF72756CFF7D8077FF7C7F76FF888B82FF94978EFF8B8E85FF
+ 8C8F86FF9FA299FF8E9188FF8B8E85FF777A71FF676A61FF55584FFF63665DFF
+ 8A8D84FF84877EFF7A7D74FF6A6D64FF61645BFF63665DFF61645BFF5C5F56FF
+ 63665DFF71746BFF6B6E65FF5C5F56FF6A6D64FF787B72FF74776EFF71746BFF
+ 72756CFF75786FFF676A61FF93968DFF585B52FF6D7067FF787B72FF6B6E65FF
+ 6C6F66FF62655CFF6A6D64FF686B62FF83867DFF767970FF70736AFF7B7E75FF
+ 6E7168FF7E8178FF6A6D64FF6C6F66FF6D7067FF6D7067FF6B6E65FF6B6E65FF
+ 6D7067FF6F7269FF6F7269FF62655CFF6E7168FF767970FF6D7067FF777A71FF
+ 7A7D74FF60635AFF61645BFF585B52FF595C53FF5B5E55FF595C53FF50534AFF
+ 5F6259FF74776EFF565950FF595C53FF6E7168FF676A61FF60635AFF676A61FF
+ 5F6259FF62655CFF5F6259FF797C73FF696C63FF63665DFF70736AFF7B7E75FF
+ 868980FF7B7E75FF767970FF6E7168FF74776EFF777A71FF6B6E65FF676A61FF
+ 6D7067FF6C6F66FF70736AFF6A6D64FF71746BFF787B72FF797C73FF80837AFF
+ 84877EFF7A7D74FF61655AFF71756AFF73776CFF6F7368FF83877CFF82867BFF
+ 797D72FF777B70FF6E7267FF7F8378FF65695EFF5F6358FF6A6E63FF62665BFF
+ 666A5FFF6A6E63FF65695EFF52564BFF585C51FF6C7065FF6E7267FF71756AFF
+ 81857AFF8F9388FF7D8176FF666A5FFF81857AFF9A9E93FF676A61FF71746BFF
+ 51544BFF5E6158FF5B5E55FF64675EFF51544BFF71746BFF898C83FF8C8F86FF
+ 84877EFF81847BFF777A71FF7E8178FF72756CFF666960FF71726EFF60615DFF
+ 555652FF71726EFF6E6F6BFF81827EFF7E7F7BFF80817DFF898A86FF767773FF
+ 6C6D69FF646561FF5B5C58FF656662FF6C6D69FF5D5E5AFF676864FF71726EFF
+ 797A76FF979894FF868783FF7A7B77FF7E7F7BFF777874FF72736FFF82837FFF
+ 8A8B87FF80817DFF72736FFF6D6E6AFF6C6D69FF696A66FF4D514CFF5A5E59FF
+ 676B66FF6B6F6AFF6A6E69FF6A6E69FF666A65FF616560FF767A75FF878B86FF
+ 737772FF777B76FF7D817CFF8E928DFF868A85FF636762FF676864FF72736FFF
+ 696A66FF585955FF51524EFF4D4E4AFF4D4E4AFF585955FF595A56FF555652FF
+ 3D3E3AFF535450FF42433FFF555652FF41423EFF454944FF535752FF5D635EFF
+ 6F7570FF787E79FF7F8580FF818782FF767C77FF6D736EFF606661FF666C67FF
+ 676D68FF666C67FF707671FF808681FF868C87FF818782FF7C827DFF757B76FF
+ 727873FF767C77FF787E79FF797D78FF787C77FF797D78FF666A65FF61625EFF
+ 767773FF7F807CFF777874FF6B6C68FF696A66FF696B65FF81837DFF73766DFF
+ 696C63FF6C6F66FF74776EFF777A71FF777A71FF767970FF6D7067FF70736AFF
+ 6B6E65FF666960FF70736AFF7C7F76FF73766DFF5E6158FF7C7F76FF80837AFF
+ 7E8178FF70736AFF83867DFF787B72FF6E7168FF65685FFF767970FF81847BFF
+ 797C73FF767970FF6B6E65FF72756CFF8D9087FF878A81FF7E8178FF979A91FF
+ 6F7269FF6E7168FF7E8178FF979A91FF80837AFF9A9D94FF82857CFF6F7269FF
+ 75786FFF585B52FF4E5148FF585B52FF3F4239FF464940FF52554CFF54574EFF
+ 54574EFF74776EFF71746BFF787B72FF686B62FF6C6F66FF70736AFF8D9087FF
+ 787B72FF686B62FF6B6E65FF676A61FF75786FFF878A81FF91948BFF8B8E85FF
+ 8A8D84FF91948BFF777A71FF6C6F66FF7B7E75FF65685FFF6C6F66FF676A61FF
+ 686B62FF6C6F66FF63665DFF4E5148FF41443BFF41443BFF494C43FF31342BFF
+ 41443BFF4C4F46FF4E5148FF5C5F56FF696C63FF80837AFF686B62FF8A8D84FF
+ 55584FFF676A61FF6B6E65FF696C63FF70736AFF62655CFF64675EFF62655CFF
+ 676A61FF595C53FF575A51FF65685FFF696C63FF74776EFF85887FFF83867DFF
+ 7E8178FF797C73FF74776EFF72756CFF74776EFF75786FFF65685FFF585B52FF
+ 60635AFF676A61FF65685FFF787B72FF888B82FF797C73FF72756CFF63665DFF
+ 696C63FF6C6F66FF767970FF64675EFF6A6D64FF71746BFF63665DFF62655CFF
+ 7C7F76FF75786FFF666960FF70736AFF6F7269FF71746BFF666960FF6F7269FF
+ 62655CFF6F7269FF777A71FF6C6F66FF7A7D74FF878A81FF7B7E75FF74776EFF
+ 7A7D74FF7F8279FF767970FF797C73FF898C83FF8F9289FF7F8279FF7C7F76FF
+ 82857CFF84877EFF7E8178FF82857CFF83867DFF777A71FF868A7FFF909489FF
+ 82867BFF696D62FF85897EFF83877CFF81857AFF84887DFF767A6FFF7D8176FF
+ 6C7065FF707469FF707469FF5D6156FF5F6358FF606459FF85897EFF6B6F64FF
+ 666A5FFF6F7368FF686C61FF5E6257FF5E6257FF5C6055FF676B60FF505449FF
+ 6E7267FF8A8E83FF51544BFF585B52FF4B4E45FF53564DFF63665DFF74776EFF
+ 75786FFF878A81FF7F8279FF72756CFF777A71FF7E8178FF91948BFF979A91FF
+ 979A91FF83867DFF6A6B67FF61625EFF5A5B57FF7A7B77FF7D7E7AFF888985FF
+ 737470FF6C6D69FF878884FF6B6C68FF71726EFF71726EFF5A5B57FF6C6D69FF
+ 81827EFF686965FF6C6D69FF636460FF5C5D59FF686965FF676864FF595A56FF
+ 80817DFF82837FFF6A6B67FF787975FF7F807CFF7A7B77FF7A7B77FF81827EFF
+ 7E7F7BFF737470FF656662FF6F706CFF787975FF7A7B77FF777874FF71726EFF
+ 666763FF5A5B57FF676864FF70716DFF6A6B67FF676864FF6E6F6BFF696A66FF
+ 7B7C78FF6E6F6BFF646561FF767773FF737470FF6A6B67FF777874FF81827EFF
+ 757672FF676864FF7A7B77FF757672FF595A56FF767773FF62635FFF757672FF
+ 585955FF5A5E59FF5D615CFF545A55FF757B76FF747A75FF848A85FF9CA29DFF
+ 818782FF848A85FF848A85FF7E847FFF777D78FF767C77FF7A807BFF7A807BFF
+ 767C77FF707671FF7B7F7AFF7A7E79FF80847FFF8A8E89FF8C908BFF82837FFF
+ 747571FF6C6D69FF787975FF71706CFF8E8D89FF8B8A86FF7C7B77FF868581FF
+ 71706CFF75756FFF72746EFF75786FFF73766DFF6F7269FF72756CFF7B7E75FF
+ 83867DFF868980FF7E8178FF8B8E85FF878A81FF777A71FF7A7D74FF8C8F86FF
+ 898C83FF74776EFF73766DFF787B72FF80837AFF777A71FF8A8D84FF6E7168FF
+ 787B72FF91948BFF7D8077FF91948BFF80837AFF74776EFF70736AFF6C6F66FF
+ 7B7E75FF7B7E75FF72756CFF80837AFF767970FF72756CFF71746BFF797C73FF
+ 787B72FF71746BFF777A71FF676A61FF7B7E75FF6D7067FF80837AFF9C9F96FF
+ 6B6E65FF575A51FF676A61FF5A5D54FF484B42FF5F6259FF5E6158FF6E7168FF
+ 6A6D64FF767970FF52554CFF888B82FF7E8178FF7C7F76FF868980FF73766DFF
+ 6E7168FF6B6E65FF7E8178FF52554CFF4A4D44FF71746BFF70736AFF6C6F66FF
+ 85887FFF7B7E75FF777A71FF797C73FF6C6F66FF52554CFF464940FF4C4F46FF
+ 50534AFF4C4F46FF4D5047FF43463DFF5B5E55FF54574EFF4E5148FF64675EFF
+ 71746BFF868980FF777A71FF8A8D84FF686B62FF767970FF6F7269FF787B72FF
+ 7B7E75FF696C63FF696C63FF61645BFF55584FFF64675EFF6E7168FF6A6D64FF
+ 71746BFF6F7269FF7A7D74FF797C73FF777A71FF74776EFF71746BFF6C6F66FF
+ 676A61FF63665DFF63665DFF5F6259FF5F6259FF575A51FF4D5047FF55584FFF
+ 62655CFF5F6259FF81847BFF73766DFF73766DFF696C63FF878A81FF85887FFF
+ 83867DFF6B6E65FF777A71FF6C6F66FF80837AFF75786FFF5F6259FF676A61FF
+ 65685FFF60635AFF54574EFF60635AFF585B52FF6A6D64FF767970FF6B6E65FF
+ 777A71FF82857CFF6D7067FF696C63FF74776EFF797C73FF6F7269FF71746BFF
+ 81847BFF888B82FF797C73FF7A7D74FF82857CFF81847BFF777A71FF7A7D74FF
+ 7C7F76FF6F7269FF8D9186FF878B80FF707469FF565A4FFF7A7E73FF6A6E63FF
+ 696D62FF777B70FF767A6FFF777B70FF6E7267FF73776CFF696D62FF64685DFF
+ 767A6FFF6F7368FF777B70FF6E7267FF6E7267FF6F7368FF707469FF75796EFF
+ 6B6F64FF4F5348FF585C51FF464A3FFF53574CFF4E5247FF6C6F66FF686B62FF
+ 6C6F66FF6A6D64FF6D7067FF72756CFF74776EFF65685FFF666960FF60635AFF
+ 7A7D74FF777A71FF81847BFF777A71FF8F9289FF8C8F86FF90918DFFA5A6A2FF
+ 939490FF7C7D79FF5B5C58FF71726EFF747571FF787975FF7A7B77FF5B5C58FF
+ 70716DFF767773FF545551FF696A66FF898A86FF6B6C68FF5D5E5AFF545551FF
+ 585955FF666763FF71726EFF52534FFF757672FF6B6C68FF6C6D69FF747571FF
+ 737470FF6F706CFF777874FF82837FFF797A76FF656662FF6D6E6AFF71726EFF
+ 71726EFF6E6F6BFF6B6C68FF686965FF5F605CFF555652FF696A66FF50514DFF
+ 444541FF4C4D49FF70716DFF61625EFF777874FF6C6D69FF80817DFF7E7F7BFF
+ 646561FF5A5B57FF81827EFFA2A39FFF8D8E8AFF6A6B67FF50514DFF4E4F4BFF
+ 373834FF62635FFF545551FF6F706CFF51524EFF565753FF575B56FF3D433EFF
+ 646A65FF5C625DFF747A75FF9AA09BFF737974FF7D837EFF878D88FF7C827DFF
+ 767C77FF7D837EFF848A85FF828883FF7C827DFF7B7F7AFF82837FFF7C7D79FF
+ 7F7E7AFF888985FF92918DFF8F8E8AFF878682FF83827EFF858480FF757470FF
+ 898884FF7E7D79FF64635FFF8C8B87FF6F6E6AFF82827CFF777973FF878A81FF
+ 8B8E85FF7C7F76FF6E7168FF73766DFF7E8178FF82857CFF84877EFF868980FF
+ 878A81FF84877EFF82857CFF84877EFF888B82FF8A8D84FF8D9087FF9C9F96FF
+ 8B8E85FF575A51FF74776EFF7B7E75FF82857CFF787B72FF777A71FF92958CFF
+ 7B7E75FF6E7168FF71746BFF686B62FF6B6E65FF6D7067FF74776EFF90938AFF
+ 797C73FF8A8D84FF8D9087FF6A6D64FFAAADA4FF6F7269FF7D8077FF767970FF
+ 8D9087FF6D7067FF73766DFF979A91FF75786FFF6F7269FF81847BFF767970FF
+ 686B62FF82857CFF7E8178FF81847BFF6E7168FF70736AFF75786FFF8E9188FF
+ 6D7067FF74776EFF888B82FF6B6E65FF62655CFF65685FFF7C7F76FF6F7269FF
+ 6A6D64FF6B6E65FF575A51FF686B62FF8B8E85FF6E7168FF72756CFF8C8F86FF
+ 878A81FF62655CFF55584FFF65685FFF63665DFF4B4E45FF53564DFF5B5E55FF
+ 7D8077FF63665DFF4C4F46FF5F6259FF5F6259FF676A61FF6B6E65FF7A7D74FF
+ 72756CFF8A8D84FF84877EFF9C9F96FF9DA097FF888B82FF797C73FF6E7168FF
+ 5F6259FF90938AFFA6A9A0FF8B8E85FF8A8D84FF7C7F76FF787B72FF7C7F76FF
+ 83867DFF898C83FF898C83FF80837AFF73766DFF686B62FF60635AFF6B6E65FF
+ 73766DFF6D7067FF63665DFF666960FF72756CFF797C73FF6D7067FF787B72FF
+ 81847BFF5E6158FF71746BFF7D8077FF8E9188FF777A71FF7C7F76FF696C63FF
+ 797C73FF6D7067FF575A51FF60635AFF5C5F56FF50534AFF42453CFF64675EFF
+ 61645BFF65685FFF787B72FF84877EFF8D9087FF80837AFF777A71FF767970FF
+ 82857CFF84877EFF70736AFF65685FFF676A61FF676A61FF6B6E65FF70736AFF
+ 7D8077FF7D8077FF74776EFF797C73FF7E8178FF73766DFF72766BFF6F7368FF
+ 6E7267FF707469FFA0A499FF7A7E73FF686C61FF777B70FF6A6E63FF696D62FF
+ 62665BFF61655AFF565A4FFF676B60FF8F9388FF84887DFF676B60FF71756AFF
+ 777B70FF71756AFF787C71FF8E9287FF7E8277FF4B4F44FF595D52FF53574CFF
+ 585C51FF3D4136FF82857CFF888B82FF5C5F56FF73766DFF777A71FF767970FF
+ 6D7067FF62655CFF7E8178FF878A81FF5E6158FF72756CFF7C7F76FF7F8279FF
+ 75786FFF81847BFF959692FFABACA8FFAAABA7FF989995FF696A66FF787975FF
+ 767773FF71726EFF777874FF797A76FF6F706CFF5E5F5BFF5F605CFF6E6F6BFF
+ 6F706CFF636460FF6F706CFF666763FF52534FFF444541FF4E4F4BFF686965FF
+ 787975FF777874FF696A66FF81827EFF7A7B77FF676864FF6E6F6BFF737470FF
+ 767773FF868783FF80817DFF6C6D69FF6C6D69FF797A76FF777874FF6F706CFF
+ 61625EFF4F504CFF4C4D49FF565753FF4B4C48FF51524EFF3B3C38FF545551FF
+ 5E5F5BFF71726EFF898A86FF71726EFF71726EFF7A7B77FF72736FFF777874FF
+ 7E7F7BFF70716DFF595A56FF595A56FF565753FF5E5F5BFF676864FF5A5B57FF
+ 4D4E4AFF555652FF5A5E59FF4F534EFF5F635EFF6A6E69FF6E726DFF939792FF
+ 9EA29DFF727671FF787C77FF777B76FF828681FF797D78FF737772FF6C706BFF
+ 6C706BFF929691FF979692FF83827EFF878480FF8C8B87FF86837FFF8C8985FF
+ 94918DFF888581FF757470FF73726EFF787773FF767571FF6C6B67FF757470FF
+ 84837FFF84847EFF7F817BFF83867DFF787B72FF84877EFF787B72FF6B6E65FF
+ 7E8178FF6E7168FF73766DFF7B7E75FF878A81FF898C83FF70736AFF70736AFF
+ 898C83FF81847BFF8B8E85FF72756CFF696C63FF70736AFF75786FFF7E8178FF
+ 80837AFF767970FF464940FF75786FFF989B92FF565950FF6B6E65FF62655CFF
+ 7C7F76FF666960FF7E8178FF6C6F66FF6E7168FF7B7E75FF767970FF6A6D64FF
+ 5E6158FF50534AFF61645BFF60635AFF6F7269FF64675EFF6F7269FF63665DFF
+ 6B6E65FF686B62FF6F7269FF6F7269FF6E7168FF70736AFF7E8178FF8D9087FF
+ 91948BFF8C8F86FF898C83FF83867DFF7B7E75FF787B72FF7D8077FF7F8279FF
+ 73766DFF63665DFF70736AFF686B62FF62655CFF61645BFF5F6259FF60635AFF
+ 6A6D64FF767970FF6F7269FF74776EFF80837AFF85887FFF80837AFF82857CFF
+ 767970FF5A5D54FF61645BFF686B62FF64675EFF565950FF55584FFF676A61FF
+ 7A7D74FF81847BFF7A7D74FF8C8F86FF7B7E75FF82857CFF7B7E75FF91948BFF
+ 888B82FF969990FF83867DFF70736AFF74776EFF868980FF7E8178FF90938AFF
+ 6F7269FF83867DFF8C8F86FF878A81FF8F9289FF84877EFF95988FFF73766DFF
+ 71746BFF74776EFF767970FF5A5D54FF7F8279FF82857CFF6D7067FF7A7D74FF
+ 797C73FF787B72FF686B62FF73766DFF7D8077FF767970FF696C63FF75786FFF
+ 85887FFF85887FFF7E8178FF8A8D84FF81847BFF7C7F76FF878A81FF7D8077FF
+ 6E7168FF767970FF64675EFF5D6057FF5D6057FF676A61FF6F7269FF73766DFF
+ 7C7F76FF878A81FF777A71FF74776EFF7A7D74FF94978EFFA3A69DFF868980FF
+ 63665DFF5B5E55FF93968DFF80837AFF81847BFF73766DFF787B72FF61645BFF
+ 696C63FF696C63FF6C7065FF787C71FF666A5FFF6F7368FF686C61FF6E7267FF
+ 787C71FFAEB2A7FF9B9F94FF676B60FF71756AFF45493EFF707469FF6B6F64FF
+ 74786DFF75796EFF7C8075FF6A6E63FF797D72FF65695EFF666A5FFF666A5FFF
+ 84887DFF75796EFF52564BFF75796EFF686C61FF868A7FFF7D8077FF91948BFF
+ 686B62FF686B62FF60635AFF70736AFF7D8077FF80837AFF72756CFF868980FF
+ 60635AFF7A7D74FF7F8279FF898C83FF696C63FF5C5F56FF676864FF6D6E6AFF
+ 676864FF81827EFF72736FFF7E7F7BFF80817DFF787975FF676864FF72736FFF
+ 82837FFF8D8E8AFF8C8D89FF80817DFF70716DFF676864FF6D6E6AFF737470FF
+ 757672FF71726EFF6E6F6BFF6F706CFF6F706CFF6C6D69FF8A8B87FF8A8B87FF
+ 757672FF5A5B57FF545551FF5E5F5BFF757672FF8E8F8BFF7B7C78FF72736FFF
+ 72736FFF686965FF535450FF585955FF7A7B77FF939490FF636460FF595A56FF
+ 5C5D59FF555652FF4D4E4AFF4E4F4BFF60615DFF646561FF70716DFF5D5E5AFF
+ 646561FF797A76FF7B7C78FF757672FF7C7D79FF858682FF6E6F6BFF696A66FF
+ 61625EFF6A6B67FF787975FF6D6E6AFF5F605CFF62635FFF616560FF515550FF
+ 636762FF787C77FF787C77FF898D88FF8E928DFF6F736EFF787C77FF7C807BFF
+ 898D88FF818580FF797D78FF70746FFF6C706BFF91928EFF96938FFF8B8884FF
+ 8F8C88FF94918DFF888581FF817E7AFF8E8B87FF999894FF8E8D89FF8A8985FF
+ 92918DFF93928EFF858480FF7F807CFF858480FF80827CFF80827CFF82857CFF
+ 7E8178FF91948BFF878A81FF72756CFF7A7D74FF676A61FF5C5F56FF585B52FF
+ 5E6158FF6E7168FF6A6D64FF64675EFF6F7269FF71746BFF72756CFF64675EFF
+ 696C63FF75786FFF777A71FF777A71FF73766DFF666960FF585B52FF6F7269FF
+ 63665DFF70736AFF5B5E55FF696C63FF60635AFF797C73FF898C83FF73766DFF
+ 64675EFF696C63FF585B52FF5F6259FF666960FF6E7168FF696C63FF7B7E75FF
+ 868980FF74776EFF797C73FF6C6F66FF797C73FF666960FF70736AFF70736AFF
+ 65685FFF5A5D54FF666960FF83867DFF94978EFF94978EFFB6B9B0FFA3A69DFF
+ 878A81FF74776EFF75786FFF7F8279FF81847BFF7D8077FF686B62FF6D7067FF
+ 6E7168FF676A61FF61645BFF63665DFF6A6D64FF70736AFF64675EFF676A61FF
+ 75786FFF7D8077FF7E8178FF878A81FF878A81FF75786FFF7D8077FF81847BFF
+ 80837AFF7A7D74FF797C73FF81847BFF8A8D84FF8E9188FF84877EFF95988FFF
+ 81847BFF7B7E75FF6D7067FF7E8178FF7D8077FF8E9188FF8C8F86FF73766DFF
+ 6A6D64FF72756CFF6F7269FF81847BFF595C53FF5B5E55FF5B5E55FF666960FF
+ 5D6057FF787B72FF7C7F76FF8D9087FF7C7F76FF898C83FF7B7E75FF666960FF
+ 7C7F76FF777A71FF6C6F66FF80837AFF82857CFF85887FFF868980FF82857CFF
+ 6E7168FF767970FF7B7E75FF90938AFF868980FF82857CFF75786FFF7D8077FF
+ 7E8178FF80837AFF888B82FF868980FF7F8279FF82857CFF74776EFF6E7168FF
+ 6E7168FF75786FFF797C73FF777A71FF787B72FF7D8077FF75786FFF6F7269FF
+ 6D7067FF7D8077FF8B8E85FF7F8279FF767970FF83867DFF777A71FF6F7269FF
+ 787B72FF65685FFF64675EFF5D6057FF70736AFF676A61FF5D6156FF63675CFF
+ 585C51FF666A5FFF595D52FF5C6055FF565A4FFF6D7166FF8D9186FF707469FF
+ 6F7368FF5B5F54FF5B5F54FF5C6055FF4A4E43FF505449FF676B60FF868A7FFF
+ 9FA398FF71756AFF5F6358FF63675CFF808479FF74786DFF73776CFF6F7368FF
+ 585C51FF878B80FF585B52FF767970FF5B5E55FF575A51FF4F5249FF63665DFF
+ 686B62FF686B62FF60635AFF7E8178FF585B52FF70736AFF666960FF878A81FF
+ 777A71FF767970FF747571FF7D7E7AFF747571FF9C9D99FF7F807CFF6D6E6AFF
+ 7B7C78FF81827EFF787975FF797A76FF878884FF979894FF8F908CFF767773FF
+ 6A6B67FF6F706CFF6C6D69FF6E6F6BFF71726EFF6E6F6BFF656662FF61625EFF
+ 6C6D69FF7A7B77FF939490FF878884FF7E7F7BFF70716DFF5D5E5AFF62635FFF
+ 7F807CFF939490FF7C7B77FF71706CFF757470FF797874FF6E6D69FF64635FFF
+ 5C5B57FF504F4BFF7B7A76FF5D5C58FF6B6A66FF61605CFF656460FF555450FF
+ 6E6D69FF63625EFF696A66FF60615DFF666763FF80817DFF898A86FF767773FF
+ 767773FF92938FFF71726EFF777874FF72736FFF6D6E6AFF6B6C68FF6C6D69FF
+ 838480FFAAABA7FF858682FF6D6E6AFF767773FF878884FF7C7D79FF797A76FF
+ 7A7B77FF6B6C68FF888985FF8B8C88FF969793FF8B8C88FF80817DFF72736FFF
+ 646561FF80817DFF96938FFF85807DFF75726EFF7D7A76FF8C8985FF878480FF
+ 82817DFF8F8E8AFF91908CFF82837FFF858682FF888985FF7C7D79FF757974FF
+ 80817DFF858781FF72746EFF6B6E65FF6D7067FF888B82FF868980FF767970FF
+ 7C7F76FF71746BFF7D8077FF6E7168FF676A61FF73766DFF7A7D74FF696C63FF
+ 5C5F56FF686B62FF676A61FF5C5F56FF60635AFF686B62FF65685FFF6A6D64FF
+ 74776EFF74776EFF72756CFF6A6D64FF5E6158FF62655CFF65685FFF5B5E55FF
+ 5B5E55FF71746BFF5E6158FF64675EFF6D7067FF888B82FF666960FF60635AFF
+ 4D5047FF4D5047FF51544BFF787B72FF82857CFF777A71FF7D8077FF6C6F66FF
+ 7F8279FF5B5E55FF6E7168FF75786FFF70736AFF65685FFF696C63FF7D8077FF
+ 868980FF82857CFF85887FFF888B82FF8C8F86FF8E9188FF90938AFF888B82FF
+ 72756CFF5D6057FF5D6057FF6D7067FF797C73FF777A71FF70736AFF6C6F66FF
+ 6C6F66FF6B6E65FF6B6E65FF686B62FF71746BFF767970FF74776EFF7E8178FF
+ 868980FF7E8178FF7D8077FF7B7E75FF7C7F76FF7E8178FF7D8077FF777A71FF
+ 75786FFF777A71FF70736AFF8E9188FF8D9087FF898C83FF797C73FF7C7F76FF
+ 70736AFF777A71FF95988FFF888B82FF7E8178FF7C7F76FF7B7E75FF8E9188FF
+ 73766DFF6D7067FF6E7168FF777A71FF63665DFF70736AFF70736AFF80837AFF
+ 676A61FF666960FF75786FFF6E7168FF73766DFF676A61FF6D7067FF898C83FF
+ 8F9289FF95988FFF787B72FF80837AFF6B6E65FF74776EFF7B7E75FF84877EFF
+ 787B72FF8C8F86FF7F8279FF7C7F76FF83867DFF888B82FF83867DFF84877EFF
+ 868980FF80837AFF7C7F76FF797C73FF7A7D74FF7F8279FF80837AFF7B7E75FF
+ 767970FF74776EFF6D7067FF6A6D64FF65685FFF6C6F66FF73766DFF696C63FF
+ 6B6E65FF80837AFF787B72FF73766DFF82857CFF676A61FF5B5E55FF5F6259FF
+ 7E8178FF6E7168FF65695EFF666A5FFF666A5FFF7D8176FF74786DFF868A7FFF
+ 808479FF7D8176FF767A6FFF777B70FF707469FF81857AFF62665BFF73776CFF
+ 505449FF5E6257FF3F4338FF64685DFF777B70FF5D6156FF686C61FF73776CFF
+ 81857AFF7B7F74FF5D6156FF52564BFF3F4338FF63675CFF686B62FF74776EFF
+ 5C5F56FF64675EFF64675EFF72756CFF63665DFF62655CFF595C53FF797C73FF
+ 5C5F56FF767970FF4E5148FF686B62FF6F7269FF8A8D84FF92938FFF9D9E9AFF
+ 878884FFA2A39FFF757672FF595A56FF6A6B67FF6D6E6AFF848581FF7D7E7AFF
+ 7E7F7BFF838480FF7C7D79FF6E6F6BFF6C6D69FF747571FF8C8D89FF7E7F7BFF
+ 747571FF71726EFF6F706CFF71726EFF838480FF999A96FF8F908CFF7D7E7AFF
+ 838480FF838480FF676864FF62635FFF787975FF81827EFF757470FF7C7B77FF
+ 8A8985FF84837FFF6A6965FF676662FF7B7A76FF898884FF94938FFF71706CFF
+ 7C7B77FF82817DFF82817DFF7C7B77FF908F8BFF858480FF72736FFF767773FF
+ 757672FF82837FFF8F908CFF787975FF6B6C68FF848581FF6C6D69FF737470FF
+ 70716DFF686965FF666763FF6A6B67FF8A8B87FFB9BAB6FF9C9D99FF878884FF
+ 848581FF858682FF777874FF747571FF7A7B77FF767773FF91928EFF8F908CFF
+ 959692FF8B8C88FF898A86FF81827EFF6E6F6BFF82817DFF898682FF85807DFF
+ 6C6965FF696662FF83807CFF868581FF7C7B77FF838480FF91928EFF838480FF
+ 878884FF8E928DFF848883FF7C827DFF878B86FF8D918BFF999B95FF80837AFF
+ 7A7D74FF898C83FF84877EFF797C73FF7D8077FF7B7E75FF83867DFF7E8178FF
+ 75786FFF6E7168FF7A7D74FF71746BFF5D6057FF72756CFF74776EFF6A6D64FF
+ 6C6F66FF6D7067FF62655CFF65685FFF74776EFF7A7D74FF80837AFF898C83FF
+ 7F8279FF62655CFF6C6F66FF6C6F66FF6A6D64FF5F6259FF5E6158FF64675EFF
+ 65685FFF7C7F76FF575A51FF5D6057FF5B5E55FF6B6E65FF6E7168FF888B82FF
+ 81847BFF7A7D74FF83867DFF71746BFF90938AFF75786FFF71746BFF73766DFF
+ 75786FFF777A71FF777A71FF777A71FF797C73FF7C7F76FF7D8077FF7E8178FF
+ 7E8178FF7E8178FF81847BFF82857CFF787B72FF6C6F66FF65685FFF6C6F66FF
+ 7B7E75FF888B82FF868980FF787B72FF70736AFF71746BFF63665DFF5A5D54FF
+ 5D6057FF60635AFF5B5E55FF60635AFF696C63FF676A61FF70736AFF666960FF
+ 62655CFF676A61FF63665DFF565950FF50534AFF53564DFF4F5249FF74776EFF
+ 84877EFF84877EFF82857CFF7F8279FF70736AFF6C6F66FF81847BFF888B82FF
+ 878A81FF7C7F76FF787B72FF898C83FF868980FF80837AFF80837AFF82857CFF
+ 83867DFF6C6F66FF878A81FF7A7D74FF73766DFF60635AFF5E6158FF65685FFF
+ 5C5F56FF4B4E45FF595C53FF6F7269FF71746BFF72756CFF5F6259FF70736AFF
+ 6F7269FF6E7168FF878A81FF767970FF73766DFF92958CFF8A8D84FF7F8279FF
+ 878A81FF8A8D84FF7A7D74FF7E8178FF878A81FF7C7F76FF898C83FF85887FFF
+ 83867DFF84877EFF83867DFF7C7F76FF73766DFF6D7067FF62655CFF666960FF
+ 676A61FF6F7269FF73766DFF62655CFF595C53FF65685FFF6E7168FF6E7168FF
+ 92958CFF898C83FF7B7E75FF70736AFF868980FF75786FFF83877CFF797D72FF
+ 72766BFF7C8075FF65695EFF7D8176FF7D8176FF6F7368FF676B60FF72766BFF
+ 6C7065FF8B8F84FF73776CFF888C81FF72766BFF81857AFF71756AFF787C71FF
+ 71756AFF6C7065FF797D72FF696D62FF606459FF6F7368FF64685DFF707469FF
+ 666A5FFF595D52FF90938AFF84877EFF6E7168FF797C73FF72756CFF75786FFF
+ 666960FF81847BFF666960FF777A71FF6C6F66FF95988FFF65685FFF565950FF
+ 51544BFF686B62FF959692FF969793FF767773FF858682FF72736FFF797A76FF
+ 80817DFF6D6E6AFF5D5E5AFF60615DFF656662FF696A66FF6C6D69FF6A6B67FF
+ 636460FF5B5C58FF858682FF71726EFF656662FF6A6B67FF71726EFF70716DFF
+ 70716DFF757672FF8E8F8BFF7A7B77FF7E7F7BFF7C7D79FF5D5E5AFF535450FF
+ 61625EFF656662FF5C5B57FF706D69FF8D8A86FF94918DFF827F7BFF7C7975FF
+ 85827EFF86837FFF86837FFF74716DFF6F6C68FF85827EFF7B7874FF8A8783FF
+ 8D8A86FF8C8B87FF6F706CFF7E7F7BFF797A76FF797A76FF888985FF7F807CFF
+ 6E6F6BFF747571FF777874FF6E6F6BFF636460FF6E6F6BFF81827EFF7D7E7AFF
+ 70716DFF747571FF8A8B87FF878884FF848581FF7B7C78FF767773FF80817DFF
+ 8A8B87FF868783FF868783FF7D7E7AFF80817DFF7D7E7AFF8E8F8BFF969793FF
+ 848581FF92918DFF787571FF95928EFF8D8A86FF73706CFF71706CFF757470FF
+ 797874FF888985FF71726EFF666A65FF717570FF7B817CFF717772FF656C67FF
+ 656B66FF616861FF888C86FF6E7168FF6D7067FF777A71FF767970FF787B72FF
+ 7C7F76FF82857CFF63665DFF72756CFF7A7D74FF65685FFF73766DFF898C83FF
+ 83867DFF9FA299FF85887FFF82857CFF8B8E85FF8D9087FF7A7D74FF6F7269FF
+ 6F7269FF6C6F66FF7A7D74FFA5A89FFF84877EFF8B8E85FF686B62FF979A91FF
+ 6F7269FF696C63FF6E7168FF676A61FF60635AFF6D7067FF565950FF696C63FF
+ 7F8279FF9A9D94FF9DA097FF969990FF83867DFF7A7D74FF83867DFF6E7168FF
+ 8E9188FF898C83FF81847BFF71746BFF6F7269FF7B7E75FF7C7F76FF72756CFF
+ 7A7D74FF8E9188FF989B92FF91948BFF85887FFF7A7D74FF7A7D74FF84877EFF
+ 8A8D84FF8A8D84FF696C63FF55584FFF55584FFF696C63FF6C6F66FF595C53FF
+ 53564DFF5E6158FF62655CFF54574EFF575A51FF61645BFF5D6057FF5E6158FF
+ 676A61FF686B62FF6E7168FF60635AFF585B52FF585B52FF53564DFF474A41FF
+ 44473EFF4A4D44FF464940FF62655CFF6E7168FF676A61FF767970FF7D8077FF
+ 7C7F76FF767970FF7A7D74FF83867DFF7E8178FF6F7269FF74776EFF7D8077FF
+ 84877EFF75786FFF81847BFF888B82FF90938AFF7A7D74FF92958CFF84877EFF
+ 7F8279FF6F7269FF7E8178FF8B8E85FF7C7F76FF6D7067FF73766DFF797C73FF
+ 74776EFF686B62FF64675EFF676A61FF72756CFF686B62FFA2A59CFF7F8279FF
+ 7D8077FF868980FF888B82FF7C7F76FF83867DFF84877EFF74776EFF7A7D74FF
+ 888B82FF80837AFF8E9188FF8A8D84FF85887FFF82857CFF81847BFF7E8178FF
+ 75786FFF6D7067FF65685FFF676A61FF676A61FF71746BFF7C7F76FF72756CFF
+ 666960FF6C6F66FF53564DFF565950FF898C83FF9EA198FF9EA198FF7E8178FF
+ 84877EFF7D8077FF7E8277FF767A6FFF6C7065FF6D7166FF4C5045FF606459FF
+ 65695EFF5E6257FF6C7065FF6B6F64FF62665BFF6F7368FF6E7267FF71756AFF
+ 72766BFF75796EFF5F6358FF6D7166FF6A6E63FF71756AFF767A6FFF6E7267FF
+ 71756AFF969A8FFF64685DFF6F7368FF74786DFF5C6055FF8A8D84FF85887FFF
+ 85887FFF92958CFF7B7E75FF6E7168FF5E6158FF90938AFF7C7F76FF6B6E65FF
+ 666960FF989B92FF888B82FF6F7269FF6D7067FF71746BFF838480FF898A86FF
+ 80817DFF7B7C78FF6A6B67FF8D8E8AFF8D8E8AFF82837FFF7F807CFF81827EFF
+ 81827EFF80817DFF848581FF868783FF7E7F7BFF72736FFF91928EFF7F807CFF
+ 72736FFF787975FF868783FF8C8D89FF888985FF848581FF7B7C78FF797A76FF
+ 838480FF868783FF767773FF696A66FF646561FF5E5F5BFF898682FF7A7773FF
+ 716E6AFF6B6864FF676460FF726F6BFF7A7773FF706D69FF696662FF716E6AFF
+ 63605CFF75726EFF696662FF7D7A76FF716E6AFF797874FF6A6965FF777874FF
+ 787975FF787975FF848581FF8A8B87FF82837FFF7C7D79FF7F807CFF767773FF
+ 6B6C68FF767773FF878884FF7F807CFF6E6F6BFF6E6F6BFF787975FF81827EFF
+ 81827EFF797A76FF7A7B77FF838480FF858682FF80817DFF787975FF6D6E6AFF
+ 6B6C68FF686965FF7F807CFF8D8E8AFF7C7D79FF858480FF7E7D79FF93908CFF
+ 8F8C88FF777672FF706F6BFF71726EFF737470FF737772FF7E827DFF737974FF
+ 747A75FF737A75FF6C736EFF727974FF7B827DFF788079FF60645EFF4F5249FF
+ 5D6057FF62655CFF63665DFF6F7269FF6D7067FF70736AFF6F7269FF787B72FF
+ 8A8D84FF696C63FF6C6F66FF90938AFF8E9188FFA6A9A0FF8B8E85FF84877EFF
+ 8A8D84FF8D9087FF81847BFF7C7F76FF7F8279FF7D8077FF71746BFF85887FFF
+ 7F8279FF888B82FF83867DFF8A8D84FF75786FFF777A71FF6E7168FF64675EFF
+ 71746BFF7C7F76FF787B72FF72756CFF7C7F76FF7F8279FF888B82FF7D8077FF
+ 8F9289FF8E9188FF989B92FF7D8077FF7D8077FF80837AFF92958CFF81847BFF
+ 81847BFF92958CFF90938AFF7C7F76FF777A71FF868980FF7C7F76FF81847BFF
+ 82857CFF81847BFF81847BFF84877EFF82857CFF7D8077FF91948BFF6F7269FF
+ 5D6057FF666960FF6A6D64FF5E6158FF5F6259FF6E7168FF73766DFF5D6057FF
+ 5D6057FF696C63FF666960FF61645BFF64675EFF64675EFF61645BFF595C53FF
+ 51544BFF4C4F46FF474A41FF43463DFF45483FFF4A4D44FF4B4E45FF666960FF
+ 767970FF6B6E65FF82857CFF868980FF868980FF7A7D74FF7C7F76FF7D8077FF
+ 70736AFF696C63FF7F8279FF81847BFF8C8F86FF70736AFF7F8279FF8F9289FF
+ 80837AFF8B8E85FF83867DFF8D9087FF73766DFF75786FFF6D7067FF787B72FF
+ 70736AFF71746BFF6D7067FF696C63FF6D7067FF595C53FF5E6158FF65685FFF
+ 777A71FF666960FF8C8F86FF6C6F66FF74776EFF797C73FF868980FF82857CFF
+ 84877EFF80837AFF74776EFF74776EFF7B7E75FF7A7D74FF74776EFF72756CFF
+ 70736AFF71746BFF7A7D74FF81847BFF7F8279FF787B72FF797C73FF71746BFF
+ 63665DFF64675EFF74776EFF74776EFF70736AFF787B72FF686B62FF60635AFF
+ 767970FF83867DFF94978EFF75786FFF7E8178FF8F9289FF787C71FF7E8277FF
+ 7B7F74FF82867BFF64685DFF6C7065FF6D7166FF767A6FFF787C71FF6D7166FF
+ 62665BFF5F6358FF6E7267FF5E6257FF6F7368FF65695EFF6C7065FF797D72FF
+ 6B6F64FF676B60FF64685DFF74786DFF6E7267FF72766BFF7C8075FF6A6E63FF
+ 7B7F74FF797D72FF80837AFF84877EFF94978EFF9FA299FF888B82FF81847BFF
+ 6A6D64FF999C93FF898C83FF64675EFF5F6259FF7D8077FF888B82FF7B7E75FF
+ 95988FFF90938AFF696A66FF6E6F6BFF858682FF747571FF595A56FF838480FF
+ 737470FF7D7E7AFF858682FF7B7C78FF757672FF767773FF72736FFF686965FF
+ 656662FF6A6B67FF80817DFF777874FF6C6D69FF676864FF71726EFF81827EFF
+ 888985FF878884FF696A66FF7A7B77FF838480FF888985FF8E8F8BFF858682FF
+ 737470FF6B6C68FF504D49FF726F6BFF9B9894FF9F9C98FF83807CFF787571FF
+ 7E7B77FF7D7A76FF6C6965FF8D8A86FF86837FFF7B7874FF84817DFF84817DFF
+ 74716DFF7D7C78FF73726EFF70716DFF7A7B77FF81827EFF7E7F7BFF81827EFF
+ 878884FF848581FF72736FFF737470FF6E6F6BFF70716DFF767773FF72736FFF
+ 797A76FF90918DFF7F7E7AFF807F7BFF7B7A76FF7B7A76FF807F7BFF7C7B77FF
+ 797874FF81807CFF777672FF6F6E6AFF6D6C68FF64635FFF73726EFF7D7C78FF
+ 6B6A66FF72716DFF878682FF767571FF74736FFF7A7975FF787773FF737470FF
+ 6F706CFF646863FF797D78FF727873FF6E746FFF626964FF5C635EFF6C7670FF
+ 7B857FFF757D76FF7A7E78FF6F7269FF80837AFF71746BFF666960FF72756CFF
+ 64675EFF60635AFF8E9188FF787B72FF878A81FF666960FF5A5D54FF767970FF
+ 696C63FF74776EFF7C7F76FF6D7067FF6D7067FF74776EFF73766DFF7A7D74FF
+ 868980FF868980FF75786FFF6B6E65FF81847BFF6D7067FF999C93FF70736AFF
+ 7B7E75FF74776EFF868980FF696C63FF75786FFF6D7067FF7F8279FF6A6D64FF
+ 787B72FF6A6D64FF696C63FF696C63FFA2A59CFF989B92FF9FA299FF90938AFF
+ 797C73FF83867DFF8E9188FF8D9087FF91948BFF989B92FF989B92FF8B8E85FF
+ 7D8077FF75786FFF777A71FF767970FF6E7168FF64675EFF64675EFF6E7168FF
+ 787B72FF7C7F76FF7C7F76FF6C6F66FF5B5E55FF55584FFF565950FF585B52FF
+ 585B52FF595C53FF83867DFF65685FFF5E6158FF696C63FF64675EFF595C53FF
+ 575A51FF55584FFF52554CFF575A51FF585B52FF52554CFF4F5249FF51544BFF
+ 55584FFF565950FF575A51FF767970FF8D9087FF7A7D74FF8F9289FF8B8E85FF
+ 8C8F86FF7D8077FF6E7168FF75786FFF71746BFF6C6F66FF80837AFF74776EFF
+ 8D9087FF797C73FF70736AFF767970FF666960FF7E8178FF82857CFF91948BFF
+ 7D8077FF878A81FF74776EFF767970FF767970FF868980FF797C73FF72756CFF
+ 868980FF70736AFF5D6057FF6C6F66FF6E7168FF686B62FF5D6057FF61645BFF
+ 696C63FF767970FF7D8077FF868980FF868980FF80837AFF7D8077FF74776EFF
+ 6E7168FF74776EFF666960FF676A61FF676A61FF6A6D64FF767970FF81847BFF
+ 80837AFF767970FF7A7D74FF74776EFF64675EFF61645BFF6D7067FF6D7067FF
+ 696C63FF70736AFF7A7D74FF777A71FF6F7269FF65685FFF888B82FF72756CFF
+ 75786FFF8D9087FF7C8075FF8B8F84FF868A7FFF909489FF777B70FF6E7267FF
+ 63675CFF7A7E73FF787C71FF767A6FFF6B6F64FF6F7368FF7C8075FF676B60FF
+ 797D72FF6B6F64FF64685DFF62665BFF5B5F54FF71756AFF707469FF8D9186FF
+ 85897EFF797D72FF6F7368FF5F6358FF7B7F74FF6B6F64FF81837DFF7C7F76FF
+ 7C7E78FF7B7E75FF73756FFF888B82FF757771FF9B9E95FF8B8D87FF6C6F66FF
+ 6D6F69FF6D7067FF757771FF62655CFF8B8D87FF7D7F79FF696A66FF555652FF
+ 767773FF71726EFF6B6C68FF9FA09CFF737470FF7A7B77FF868783FF7B7C78FF
+ 81827EFF939490FF8C8D89FF71726EFF6B6C68FF7B7C78FF7C7D79FF848581FF
+ 82837FFF777874FF747571FF7D7E7AFF81827EFF7F807CFF71726EFF80817DFF
+ 737470FF676864FF787975FF7C7D79FF71726EFF72736FFF62615DFF706F6BFF
+ 878480FF888783FF7D7A76FF7E7D79FF86837FFF7C7B77FF686561FF94938FFF
+ 9C9995FF757470FF96938FFF7E7D79FF73706CFF797874FF7D7E7AFF6D6E6AFF
+ 7B7C78FF878884FF737470FF696A66FF767773FF7B7C78FF60615DFF5D5E5AFF
+ 595A56FF646561FF757672FF737470FF6F706CFF7B7C78FF848581FF777874FF
+ 6E6D69FF767773FF83827EFF777874FF7B7A76FF92938FFF777672FF737470FF
+ 787773FF6B6C68FF777672FF7D7E7AFF6F6E6AFF767773FF7B7A76FF60615DFF
+ 72716DFF8A8B87FF787975FF656662FF6C706BFF777B76FF767C77FF808681FF
+ 8B918CFF828984FF787F7AFF7D847FFF737D77FF585F5AFF6B6F69FF676A61FF
+ 7E807AFF6D7067FF686A64FF83867DFF7D7F79FF7C7F76FFA4A6A0FF71746BFF
+ 80827CFF6C6F66FF60625CFF75786FFF60625CFF64675EFF63655FFF585B52FF
+ 5F615BFF6D7067FF6F716BFF71746BFF6F716BFF65685FFF80827CFF83867DFF
+ 7A7C76FF787B72FF848680FF83867DFF767872FF71746BFF80827CFF5F6259FF
+ 797B75FF71746BFF979993FF75786FFF7E807AFF60635AFF62645EFF5E6158FF
+ 989A94FF6A6D64FF696B65FF75786FFF676963FF81847BFF80837AFF85887FFF
+ 81847BFF787B72FF7F8279FF90938AFF90938AFF81847BFF85887FFF84877EFF
+ 7B7E75FF6D7067FF666960FF696C63FF6E7168FF70736AFF7B7E75FF878A81FF
+ 85887FFF767970FF75786FFF80837AFF7A7D74FF696C63FFA3A69DFF80837AFF
+ 767970FF83867DFF80837AFF767970FF73766DFF72756CFF585B52FF686B62FF
+ 71746BFF6D7067FF6B6E65FF72756CFF75786FFF72756CFF696C63FF83867DFF
+ 90938AFF6D7067FF7E8178FF7E8178FF90938AFF8C8F86FF74776EFF8D9087FF
+ 959791FF8A8D84FF888A84FF696C63FF93958FFF93968DFF858781FF71746BFF
+ 6D6F69FF686B62FF8D8F89FF7C7F76FF7C7E78FF7B7E75FF868980FF7D8077FF
+ 7D8077FF92958CFF797C73FF6D7067FF8B8E85FF74776EFF7C7F76FF797C73FF
+ 565950FF696C63FF4F5249FF82857CFF75786FFF72756CFF676A61FF7E8178FF
+ 80837AFF7F8279FF888B82FF7D8077FF71746BFF7D8077FF7D8077FF7D8077FF
+ 797C73FF75786FFF7A7D74FF7E8178FF74776EFF65685FFF65685FFF6A6D64FF
+ 686B62FF6C6F66FF787B72FF72756CFF676A61FF686B62FF595C53FF71746BFF
+ 71746BFF686B62FF9A9D94FF82857CFF6B6E65FF73766DFF5E6257FF73776CFF
+ 71756AFF868A7FFF81857AFF7B7F74FF72766BFF9A9E93FF707469FF7B7F74FF
+ 6F7368FF82867BFF82867BFF6E7267FF787C71FF6B6F64FF6D7166FF61655AFF
+ 686C61FF898D82FF5D6156FF52564BFF4D5146FF5B5F54FF61655AFF787C71FF
+ ADB1A6FF878B80FF8A8B87FF8C8E88FF797A76FF73756FFF838480FF7F817BFF
+ 757672FF81837DFF959692FF848680FF70716DFF696B65FF71726EFF777973FF
+ 6E6F6BFF60615DFF747873FF60645FFF535752FF4D514CFF595D58FF828681FF
+ 898D88FF60645FFF676B66FF838782FF8F938EFF717570FF838782FF70746FFF
+ 747873FF797D78FF7F807CFF80817DFF8E8F8BFF6D6E6AFF656662FF7B7C78FF
+ 6C6D69FF6E6F6BFF636460FF72736FFF6C6D69FF71726EFF6E6F6BFF62635FFF
+ 60615DFF4C4D49FF6E6F6BFF60615DFF61605CFF6E6F6BFF767571FF6C6D69FF
+ 6B6A66FF70716DFF7F7E7AFF7F807CFF8D8C88FF868783FF9B9A96FF6F706CFF
+ 6D6C68FF7D7E7AFF6C6D69FF6A6B67FF80817DFF979894FF666763FF7B7C78FF
+ 81827EFF6B6C68FF71726EFF51524EFF666763FF52534FFF6C6D69FF676864FF
+ 91928EFF80817DFF6F706CFF6A6E69FF666763FF6E726DFF80817DFF7A7E79FF
+ 747571FF7A7E79FF898A86FF7E827DFF7C7D79FF838782FF6F706CFF60645FFF
+ 737470FF626661FF737470FF585C57FF767773FF6B6F6AFF6B6F6AFF737772FF
+ 535752FF686C67FF6B6F6AFF747873FF818580FF646A65FF717772FF727873FF
+ 8C928DFF898F8AFF858984FF7D817BFF8B8F8AFF949892FF8C908BFF949892FF
+ 999D98FF828680FF838782FF81857FFF767A75FF70746EFF6D716CFF626660FF
+ 636762FF797D77FF737772FF60645EFF626661FF5C605AFF5E625DFF636761FF
+ 5C605BFF6B6F69FF7C807BFF797D77FF7D817CFF71756FFF636762FF777B75FF
+ 828681FF6D6F69FF838480FF81817BFF706F6BFF71716BFF767571FF83837DFF
+ 8F8E8AFF70706AFF6E6D69FF7C7C76FF71706CFF55554FFF61605CFF4D4D47FF
+ 605F5BFF545650FF777A71FF70756CFF6C7168FF6B7067FF83887FFF6D7269FF
+ 7F847BFF6D7269FF7B8077FF7D8279FF81867DFF878C83FF898E85FF81867DFF
+ 72776EFF656A61FF7A7F76FF7D8279FF7E837AFF7C8178FF7E837AFF868B82FF
+ 8E938AFF92978EFF9BA097FF868B82FF7E837AFF868B82FF73786FFF8C9188FF
+ 797E75FF7D8279FF878C83FF7E837AFF747970FF7F847BFF949990FF92978EFF
+ 888D84FF8D9289FF949990FF82877EFF73786FFF8E938AFF949990FF7F847BFF
+ 848980FF868980FF7D7F79FF686862FF5B5A56FF666660FF7A7975FF878781FF
+ 908F8BFF999993FF81807CFF7B7B75FF7E7D79FF7F7F79FF7A7975FF888882FF
+ 9D9C98FFA1A39DFF6D7067FF7A7F76FF83887FFF7E837AFF787D74FF787D74FF
+ 787D74FF757A71FF7A7F76FF8E938AFF747970FF747970FF6F746BFF7E837AFF
+ 6A6F66FF777C73FF8C9188FF6D7269FF6C7168FF6B7067FF797E75FF7A7F76FF
+ 666B62FF858A81FF686D64FF787D74FF767B72FF91968DFF8C9188FF6B7067FF
+ 696E65FF595E55FF60655CFF61665DFF656A61FF555A51FF4D5249FF797E75FF
+ 565B52FF70756CFF696E65FF83887FFF6A6F66FF747970FF686D64FF5F645BFF
+ 5D6259FF73786FFF5F645BFF7C8178FF9DA299FF71766DFF858A81FF686D64FF
+ 757A71FF666B62FF6E736AFF5F645BFF80857CFF93988FFF797E75FF83887FFF
+ 979C93FF80857CFF797F74FF777D72FF7B8176FF7E8479FF767C71FF6E7469FF
+ 7B8176FF92988DFF878D82FF8D9388FF9CA297FFACB2A7FF898A86FF91928EFF
+ 91928EFF8E8F8BFF8E8F8BFF868783FF82837FFF898A86FF80817DFF757672FF
+ 6E6F6BFF757672FF838480FF8D8E8AFF8E8F8BFF8B8C88FF636762FF6D716CFF
+ 757974FF6C706BFF646863FF717570FF767A75FF686C67FF5E625DFF5C605BFF
+ 616560FF5F635EFF7C807BFF636762FF6C706BFF858984FF6D6E6AFF676864FF
+ 71726EFF71726EFF71726EFF6F706CFF60615DFF61625EFF62635FFF70716DFF
+ 737470FF868783FF898A86FF797A76FF737470FF60615DFF838480FF72736FFF
+ 666763FF656662FF636460FF636460FF71726EFF868783FF676864FF6F706CFF
+ 757672FF888985FF8D8E8AFF838480FF777874FF81827EFF72736FFF656662FF
+ 6B6C68FF737470FF565753FF666763FF787975FF747571FF888985FF72736FFF
+ 6D6E6AFF636460FF70716DFF757672FF848581FF7C7D79FF9A9E99FF7E827DFF
+ 6C706BFF7F837EFF90948FFF7E827DFF777B76FF8D918CFF838782FF818580FF
+ 787C77FF80847FFF747873FF636762FF696D68FF5C605BFF656964FF4E524DFF
+ 666A65FF5C605BFF5B5F5AFF626661FF434742FF555954FF686C67FF686C67FF
+ 737772FF656964FF787C77FF787C77FF898D88FF858984FF888C87FF7C807BFF
+ 80847FFF848883FF80847FFF8A8E89FF858984FF666A65FF686C67FF6B6F6AFF
+ 676B66FF686C67FF6A6E69FF626661FF656964FF7B7F7AFF737772FF666A65FF
+ 6E726DFF6C706BFF757974FF838782FF7F837EFF8A8E89FF8C908BFF7F837EFF
+ 787C77FF737772FF6E726DFF757974FF7C807BFF777B76FF7D7E7AFF7A7975FF
+ 6C6B67FF73726EFF757470FF7B7A76FF878682FF706F6BFF676662FF6C6B67FF
+ 555450FF5F5E5AFF62615DFF5A5955FF676662FF757771FF525650FF565B52FF
+ 656A61FF666B62FF7E837AFF72776EFF80857CFF7C8178FF7C8178FF797E75FF
+ 767B72FF73786FFF6F746BFF63685FFF53584FFF474C43FF4E534AFF4D5249FF
+ 545950FF656A61FF797E75FF80857CFF747970FF656A61FF5D6259FF787D74FF
+ 93988FFF93988FFF747970FF8B9087FF7D8279FF81867DFF7C8178FF898E85FF
+ 80857CFF70756CFF787D74FF82877EFF80857CFF7F847BFF8A8F86FF7D8279FF
+ 787D74FF93988FFF959A91FF858A81FF8A8F86FF7F847BFF61625EFF5C5B57FF
+ 5B5A56FF63625EFF6B6A66FF6E6D69FF6F6E6AFF706F6BFF6E6D69FF62615DFF
+ 63625EFF6E6D69FF777672FF81807CFF7F7E7AFF70726CFF5D615BFF71766DFF
+ 878C83FF898E85FF73786FFF62675EFF6D7269FF858A81FF898E85FF70756CFF
+ 555A51FF787D74FF83887FFF858A81FF6F746BFF7F847BFF83887FFF83887FFF
+ 8C9188FF747970FF6A6F66FF6F746BFF6C7168FF898E85FF7C8178FF8C9188FF
+ 73786FFF676C63FF666B62FF6C7168FF7A7F76FF5F645BFF545950FF61665DFF
+ 545950FF5D6259FF51564DFF575C53FF4E534AFF60655CFF5D6259FF71766DFF
+ 5C6158FF747970FF7A7F76FF82877EFF6D7269FF565B52FF646960FF82877EFF
+ A5AAA1FF7D8279FF8A8F86FF6B7067FF7D8279FF7B8077FF747970FF656A61FF
+ 72776EFF777C73FF646960FF6E736AFF81867DFF777C73FF80867BFF71776CFF
+ 6B7166FF757B70FF7B8176FF787E73FF797F74FF7F857AFF6B7166FF6E7469FF
+ 777D72FF81877CFF6D6E6AFF6C6D69FF757672FF7B7C78FF787975FF7B7C78FF
+ 7E7F7BFF787975FF8D8E8AFF838480FF7F807CFF848581FF858682FF80817DFF
+ 7F807CFF848581FF757974FF787C77FF6D716CFF636762FF696D68FF6E726DFF
+ 6D716CFF717570FF868A85FF757974FF6D716CFF6C706BFF7E827DFF666A65FF
+ 656964FF757974FF737470FF656662FF60615DFF7E7F7BFF848581FF696A66FF
+ 636460FF636460FF7C7D79FF72736FFF5D5E5AFF696A66FF70716DFF6D6E6AFF
+ 7D7E7AFF7F807CFF7D7E7AFF797A76FF787975FF757672FF686965FF5D5E5AFF
+ 636460FF71726EFF6A6B67FF6A6B67FF62635FFF797A76FF6A6B67FF848581FF
+ 7F807CFF82837FFF72736FFF6F706CFF80817DFF878884FF898A86FF777874FF
+ 767773FF747571FF7F807CFF767773FF5F605CFF5F605CFF686965FF737470FF
+ 6B6C68FF6D6E6AFF919590FF7B7F7AFF6A6E69FF777B76FF8B8F8AFF858984FF
+ 7E827DFF8B8F8AFF80847FFF878B86FF797D78FF828681FF868A85FF747873FF
+ 6F736EFF686C67FF767A75FF636762FF727671FF636762FF5D615CFF60645FFF
+ 444843FF4E524DFF797D78FF6C706BFF6C706BFF686C67FF757974FF6A6E69FF
+ 6B6F6AFF656964FF7B7F7AFF888C87FF969A95FF898D88FF727671FF747873FF
+ 7D817CFF737772FF747873FF777B76FF757974FF797D78FF7D817CFF737772FF
+ 717570FF828681FF7A7E79FF747873FF7D817CFF767A75FF7B7F7AFF8A8E89FF
+ 838782FF888C87FF8D918CFF8B8F8AFF898D88FF919590FF979B96FF888C87FF
+ 7A7E79FF7F837EFF90918DFF81827EFF6D6E6AFF737470FF6F706CFF70716DFF
+ 878884FF81827EFF737470FF6D6E6AFF494A46FF70716DFF696A66FF656662FF
+ 686965FF8A8C86FF71756FFF767B72FF83887FFF6E736AFF70756CFF5D6259FF
+ 52574EFF575C53FF81867DFF7B8077FF72776EFF6B7067FF656A61FF5D6259FF
+ 52574EFF4A4F46FF575C53FF5A5F56FF5C6158FF5B6057FF5B6057FF5D6259FF
+ 646960FF6A6F66FF676C63FF686D64FF6F746BFF73786FFF787D74FF969B92FF
+ 7E837AFF72776EFF898E85FF888D84FF7E837AFF7B8077FF80857CFF7B8077FF
+ 767B72FF80857CFF7A7F76FF72776EFF787D74FF91968DFF8C9188FF868B82FF
+ 91968DFF777C73FF646561FF61625EFF585955FF4C4D49FF4B4C48FF575854FF
+ 666763FF6D6E6AFF6A6B67FF6C6D69FF6F706CFF6E6F6BFF686965FF646561FF
+ 636460FF62645EFF6D716BFF71766DFF7E837AFF83887FFF71766DFF666B62FF
+ 858A81FFB3B8AFFF9BA097FF686D64FF4D5249FF6E736AFF73786FFF757A71FF
+ 71766DFF7F847BFF7D8279FF868B82FF8F948BFF777C73FF72776EFF80857CFF
+ 72776EFF6A6F66FF898E85FF7A7F76FF63685FFF6D7269FF6C7168FF5C6158FF
+ 61665DFF5F645BFF71766DFF8D9289FF62675EFF62675EFF50554CFF4A4F46FF
+ 686D64FF71766DFF656A61FF757A71FF63685FFF6D7269FF61665DFF787D74FF
+ 797E75FF5F645BFF6F746BFF71766DFF7E837AFF696E65FF8C9188FF787D74FF
+ 7B8077FF6E736AFF898E85FF848980FF81867DFF7E837AFF7B8077FF81867DFF
+ 8B9087FF8F948BFF868C81FF787E73FF71776CFF7B8176FF83897EFF81877CFF
+ 7D8378FF7D8378FF71776CFF70766BFF757B70FF7E8479FF797A76FF646561FF
+ 646561FF6B6C68FF6A6B67FF787975FF7C7D79FF656662FF70716DFF6B6C68FF
+ 6E6F6BFF787975FF787975FF6F706CFF72736FFF7E7F7BFF777B76FF747873FF
+ 5E625DFF585C57FF6A6E69FF6A6E69FF666A65FF767A75FF7A7E79FF7B7F7AFF
+ 787C77FF737772FF818580FF888C87FF888C87FF838782FF8D8E8AFF82837FFF
+ 6D6E6AFF8D8E8AFF92938FFF72736FFF797A76FF747571FF8B8C88FF81827EFF
+ 72736FFF878884FF8D8E8AFF7E7F7BFF848581FF838480FF777874FF80817DFF
+ 8B8C88FF8E8F8BFF848581FF777874FF71726EFF72736FFF70716DFF6E6F6BFF
+ 70716DFF797A76FF636460FF797A76FF7B7C78FF6C6D69FF787975FF82837FFF
+ 9E9F9BFFA8A9A5FFC1C2BEFF91928EFF7C7D79FF797A76FF80817DFF838480FF
+ 747571FF6A6B67FF7D7E7AFF777874FF6C6D69FF737470FF626661FF70746FFF
+ 686C67FF5E625DFF70746FFF818580FF797D78FF6C706BFF777B76FF838782FF
+ 70746FFF7C807BFF919590FF818580FF797D78FF787C77FF80847FFF757974FF
+ 7E827DFF6F736EFF6B6F6AFF70746FFF5B5F5AFF5E625DFF828681FF717570FF
+ 6F736EFF787C77FF80847FFF747873FF70746FFF727671FF6F736EFF898D88FF
+ 989C97FF858984FF6D716CFF70746FFF818580FF888C87FF7B7F7AFF787C77FF
+ 727671FF777B76FF7E827DFF737772FF696D68FF727671FF757974FF777B76FF
+ 838782FF757974FF717570FF7C807BFF737772FF777B76FF757974FF868A85FF
+ 868A85FF878B86FF90948FFF7E827DFF6C706BFF757974FF92938FFF838480FF
+ 757672FF81827EFF787975FF6C6D69FF81827EFF838480FF686965FF5D5E5AFF
+ 3D3E3AFF595A56FF585955FF474844FF434440FF555751FF3E423CFF4E534AFF
+ 62675EFF5C6158FF72776EFF7D8279FF767B72FF8C9188FF83887FFF7D8279FF
+ 767B72FF71766DFF70756CFF6F746BFF6E736AFF6C7168FF63685FFF747970FF
+ 868B82FF898E85FF797E75FF666B62FF60655CFF646960FF676C63FF676C63FF
+ 70756CFF6A6F66FF6A6F66FF767B72FF73786FFF8B9087FF7E837AFF7E837AFF
+ 757A71FF777C73FF878C83FF878C83FF7C8178FF7C8178FF767B72FF73786FFF
+ 777C73FF878C83FF7D8279FF80857CFF91968DFF73786FFF7E7F7BFF797A76FF
+ 666763FF4E4F4BFF494A46FF5B5C58FF6D6E6AFF747571FF72736FFF7C7D79FF
+ 7C7D79FF757672FF6E6F6BFF656662FF62635FFF686A64FF727670FF686D64FF
+ 666B62FF6B7067FF6C7168FF6F746BFF82877EFF9CA198FF7D8279FF686D64FF
+ 6A6F66FF73786FFF62675EFF686D64FF747970FF73786FFF6D7269FF72776EFF
+ 7D8279FF7B8077FF7E837AFF878C83FF747970FF565B52FF92978EFF7B8077FF
+ 767B72FF90958CFF91968DFF747970FF70756CFF7F847BFF5C6158FF8B9087FF
+ 767B72FF6B7067FF5E635AFF595E55FF70756CFF696E65FF686D64FF6D7269FF
+ 5F645BFF6C7168FF52574EFF6C7168FF858A81FF7A7F76FF6D7269FF61665DFF
+ 61665DFF5A5F56FF848980FF7A7F76FF767B72FF696E65FF797E75FF83887FFF
+ 7F847BFF7F847BFF8D9289FF8D9289FF888D84FF92978EFF7E8479FF7E8479FF
+ 81877CFF858B80FF82887DFF7B8176FF7C8277FF83897EFF767C71FF72786DFF
+ 71776CFF777D72FF8D8E8AFF7D7E7AFF7B7C78FF767773FF676864FF6C6D69FF
+ 6D6E6AFF545551FF5F605CFF5E5F5BFF646561FF6C6D69FF6B6C68FF646561FF
+ 666763FF70716DFF626661FF717570FF6F736EFF6C706BFF6F736EFF60645FFF
+ 5B5F5AFF747873FF656964FF636762FF616560FF666A65FF696D68FF7B7F7AFF
+ 848883FF868A85FF8E8F8BFF92938FFF7E7F7BFF90918DFF91928EFF7D7E7AFF
+ 868783FF787975FF7B7C78FF72736FFF666763FF7B7C78FF81827EFF71726EFF
+ 797A76FF787975FF6E6F6BFF72736FFF747571FF747571FF787975FF7E7F7BFF
+ 81827EFF81827EFF838480FF797A76FF838480FF6D6E6AFF666763FF71726EFF
+ 8F908CFF82837FFF7E7F7BFF81827EFF888985FF858682FFA4A5A1FF7F807CFF
+ 787975FF878884FF7D7E7AFF838480FF8C8D89FF70716DFF8F908CFF6F706CFF
+ 737470FF757672FF5A5E59FF70746FFF6B6F6AFF595D58FF616560FF6F736EFF
+ 6B6F6AFF636762FF6A6E69FF757974FF60645FFF6D716CFF858984FF7A7E79FF
+ 757974FF767A75FF6E726DFF6D716CFF737772FF6A6E69FF6D716CFF797D78FF
+ 717570FF6F736EFF898D88FF7C807BFF767A75FF828681FF7A7E79FF6A6E69FF
+ 616560FF6A6E69FF6F736EFF747873FF6F736EFF696D68FF70746FFF797D78FF
+ 7A7E79FF787C77FF787C77FF70746FFF646863FF696D68FF767A75FF6C706BFF
+ 5F635EFF646863FF616560FF666A65FF7A7E79FF717570FF6E726DFF787C77FF
+ 747873FF7E827DFF7A7E79FF929691FF878B86FF6D716CFF6E726DFF70746FFF
+ 717570FF7E827DFF737470FF6E6F6BFF72736FFF8C8D89FF81827EFF6A6B67FF
+ 747571FF70716DFF71726EFF6D6E6AFF5C5D59FF5B5C58FF6F706CFF545551FF
+ 51524EFF42443EFF464A44FF595E55FF53584FFF51564DFF6A6F66FF797E75FF
+ 6E736AFF80857CFF868B82FF81867DFF7A7F76FF757A71FF747970FF757A71FF
+ 777C73FF787D74FF7A7E78FF757973FF777B75FF828680FF888C86FF838781FF
+ 7B7F79FF777B75FF636761FF6F736DFF757973FF5C605AFF696D67FF787C76FF
+ 6F736DFF787C76FF5B6057FF72776EFF71766DFF646960FF70756CFF83887FFF
+ 888D84FF878C83FF898E85FF888D84FF80857CFF82877EFF777C73FF7A7F76FF
+ 8D9289FF797E75FF81827EFF848581FF7E7F7BFF737470FF72736FFF777874FF
+ 72736FFF666763FF737470FF6C6D69FF555652FF51524EFF666763FF6A6B67FF
+ 5E5F5BFF5F615BFF6F736DFF73786FFF787D74FF7B8077FF7E837AFF7B8077FF
+ 71766DFF666B62FF585D54FF5A5F56FF7C8178FF8B9087FF7D8279FF757A71FF
+ 7F847BFF777C73FF666B62FF646960FF71766DFF7D8279FF70756CFF6D7269FF
+ 7A7F76FF757A71FF6E736AFF73786FFF72776EFF63685FFF60655CFF6D7269FF
+ 72776EFF73786FFF686D64FF73786FFF72776EFF686D64FF686D64FF61665DFF
+ 6E736AFF82877EFF7A7F76FF6E736AFF61665DFF82877EFF6B7067FF696E65FF
+ 676C63FF555A51FF61665DFF696E65FF72776EFF696E65FF797E75FF6F746BFF
+ 797E75FF83887FFF71766DFF81867DFF797E75FF797E75FF8F948BFF8A8F86FF
+ 7B8077FF858A81FF73796EFF757B70FF797F74FF7B8176FF787E73FF72786DFF
+ 72786DFF757B70FF767C71FF6D7368FF666C61FF656B60FF7E7F7BFF898A86FF
+ 939490FF868783FF6E6F6BFF666763FF636460FF585955FF7D7E7AFF7C7D79FF
+ 7B7C78FF777874FF71726EFF6B6C68FF666763FF636460FF7F837EFF7D817CFF
+ 727671FF6C706BFF6E726DFF686C67FF676B66FF717570FF7E827DFF5F635EFF
+ 535752FF6A6E69FF585C57FF575B56FF636762FF7D817CFF797A76FF82837FFF
+ 7D7E7AFF848581FF888985FF838480FF81827EFF6F706CFF8B8C88FF848581FF
+ 71726EFF7C7D79FF82837FFF81827EFF979894FF9FA09CFF6B6C68FF6B6C68FF
+ 676864FF62635FFF696A66FF757672FF757672FF6D6E6AFF5B5C58FF6A6B67FF
+ 949591FF8F908CFF9C9D99FF8B8C88FF949591FF7F807CFF737470FF747571FF
+ 6A6B67FF61625EFF72736FFF656662FF686965FF80817DFF646561FF676864FF
+ 838480FF686965FF888985FF676864FF7C7D79FF797A76FF696D68FF686C67FF
+ 60645FFF60645FFF656964FF60645FFF676B66FF7E827DFF6B6F6AFF6F736EFF
+ 5E625DFF6C706BFF7A7E79FF70746FFF70746FFF6A6E69FF6E726DFF757974FF
+ 747873FF6B6F6AFF6E726DFF7B7F7AFF7A7E79FF70746FFF848883FF828681FF
+ 80847FFF8F938EFF7E827DFF727671FF656964FF70746FFF6A6E69FF6D716CFF
+ 666A65FF686C67FF727671FF6E726DFF686C67FF727671FF7F837EFF747873FF
+ 626661FF5F635EFF646863FF585C57FF4E524DFF555954FF5B5F5AFF575B56FF
+ 696D68FF6A6E69FF6B6F6AFF717570FF6C706BFF7B7F7AFF7B7F7AFF929691FF
+ 8F938EFF747873FF6C706BFF757974FF7A7E79FF7C807BFF6B6C68FF656662FF
+ 636460FF787975FF72736FFF666763FF7A7B77FF7B7C78FF5C5D59FF5F605CFF
+ 555652FF474844FF6A6B67FF555652FF535450FF31332DFF3F433DFF646960FF
+ 454A41FF555A51FF757A71FF81867DFF7B8077FF83887FFF90958CFF8B9087FF
+ 83887FFF7B8077FF757A71FF70756CFF6D7269FF6B7067FF838781FF747872FF
+ 6A6E68FF6C706AFF727670FF7A7E78FF8B8F89FF9DA19BFF7C807AFF878B85FF
+ 747872FF393D37FF595D57FF777B75FF60645EFF474B45FF61665DFF60655CFF
+ 676C63FF777C73FF747970FF63685FFF80857CFFC0C5BCFF969B92FF9DA299FF
+ 888D84FF82877EFF7F847BFF7B8077FF898E85FF868B82FF7C7D79FF7E7F7BFF
+ 81827EFF878884FF8F908CFF92938FFF878884FF797A76FF797A76FF6E6F6BFF
+ 40413DFF20211DFF2C2D29FF393A36FF4B4C48FF6E706AFF70746EFF80857CFF
+ 8B9087FF878C83FF81867DFF80857CFF7B8077FF72776EFF777C73FF63685FFF
+ 767B72FF878C83FF8F948BFF797E75FF83887FFF8C9188FF83887FFF676C63FF
+ 60655CFF767B72FF6B7067FF666B62FF878C83FF898E85FF848980FF82877EFF
+ 878C83FF72776EFF666B62FF6A6F66FF656A61FF6F746BFF83887FFF666B62FF
+ 686D64FF777C73FF82877EFF565B52FF53584FFF767B72FF646960FF696E65FF
+ 666B62FF8A8F86FF6F746BFF5D6259FF5B6057FF60655CFF62675EFF6D7269FF
+ 6D7269FF646960FF6F746BFF70756CFF73786FFF787D74FF898E85FF90958CFF
+ 82877EFF7D8279FF8E938AFF898E85FF7A7F76FF81867DFF71776CFF6A7065FF
+ 676D62FF6C7267FF747A6FFF757B70FF6C7267FF63695EFF777D72FF6C7267FF
+ 63695EFF61675CFF7A7B77FF90918DFF949591FF888985FF838480FF7D7E7AFF
+ 737470FF6E6F6BFF797A76FF7E7F7BFF7D7E7AFF797A76FF7E7F7BFF888985FF
+ 858682FF787975FFA2A6A1FF8A8E89FF757974FF6A6E69FF696D68FF757974FF
+ 7C807BFF747873FF7F837EFF5F635EFF5A5E59FF80847FFF6C706BFF717570FF
+ 7C807BFF939792FF7C7D79FF72736FFF767773FF767773FF81827EFF8B8C88FF
+ 7B7C78FF747571FF686965FF767773FF757672FF838480FF858682FF7D7E7AFF
+ 868783FF7F807CFF757672FF7C7D79FF7A7B77FF737470FF757672FF7B7C78FF
+ 71726EFF5F605CFF838480FF7D7E7AFF6B6C68FF595A56FF686965FF7C7D79FF
+ 9A9B97FFB4B5B1FF767773FF81827EFF787975FF767773FF6D6E6AFF6B6C68FF
+ 636460FF70716DFF70716DFF6B6C68FF81827EFF787975FF848581FF797A76FF
+ 8E8F8BFF888985FF70746FFF686C67FF5F635EFF656964FF6D716CFF656964FF
+ 6B6F6AFF868A85FF737772FF70746FFF696D68FF7A7E79FF787C77FF6E726DFF
+ 737772FF636762FF747873FF80847FFF797D78FF6E726DFF70746FFF7C807BFF
+ 80847FFF70746FFF696D68FF777B76FF80847FFFA0A49FFF999D98FFA0A49FFF
+ 939792FF9A9E99FF727671FF7C807BFF7E827DFF858984FF878B86FF6C706BFF
+ 626661FF7C807BFF7F837EFF787C77FF646863FF565A55FF4E524DFF3E423DFF
+ 3C403BFF4F534EFF696D68FF515550FF585C57FF60645FFF686C67FF666A65FF
+ 575B56FF636762FF5D615CFF656964FF737772FF737772FF6B6F6AFF6E726DFF
+ 70746FFF656964FF6E726DFF666A65FF5C605BFF676B66FF636762FF646863FF
+ 80847FFF818580FF696D68FF6A6E69FF4F534EFF4D514CFF656964FF5F635EFF
+ 555954FF393D37FF3F433DFF7D8279FF4A4F46FF6A6F66FF868B82FF80857CFF
+ 7D8279FF747970FF90958CFF8F948BFF8B9087FF848980FF7C8178FF747970FF
+ 6E736AFF6A6F66FF656963FF6E726CFF838781FF949892FF8F938DFF80847EFF
+ 7E827CFF898D87FF797D77FF959993FF979B95FF535751FF545852FF494D47FF
+ 464A44FF5A5E58FF686D64FF5A5F56FF62675EFF7F847BFF7B8077FF5B6057FF
+ 777C73FFC2C7BEFF81867DFF969B92FF7E837AFF7C8178FF8B9087FF7E837AFF
+ 83887FFF949990FF80847FFF777B76FF737772FF7A7E79FF828681FF848883FF
+ 838782FF828681FF797D78FF868A85FF646863FF363A35FF2B2F2AFF2D312CFF
+ 4E524DFF8C908AFF6A6E68FF6D7269FF70756CFF71766DFF70756CFF73786FFF
+ 7F847BFF8A8F86FF8F948BFF7F847BFF7C8178FF70756CFF81867DFF6E736AFF
+ 7A7F76FF888D84FF8F948BFF73786FFF6D7269FF8B9087FF7C8178FF6D7269FF
+ 858A81FF72776EFF797E75FF6B7067FF7C8178FF777C73FF6D7269FF62675EFF
+ 4D5249FF5C6158FF595E55FF595E55FF5C6158FF878C83FF9FA49BFF52574EFF
+ 40453CFF2C3128FF343930FF565B52FF575C53FF73786FFF646960FF62675EFF
+ 747970FF93988FFF696E65FF6F746BFF60655CFF565B52FF656A61FF71766DFF
+ 666B62FF5B6057FF81867DFF80857CFF757A71FF73786FFF7E837AFF7C8178FF
+ 70756CFF6E736AFF6A7065FF686E63FF666C61FF686E63FF6E7469FF70766BFF
+ 6B7166FF63695EFF6F756AFF646A5FFF5B6156FF5C6257FF82837FFF8B8C88FF
+ 777874FF6B6C68FF80817DFF838480FF6D6E6AFF61625EFF737470FF7A7B77FF
+ 767773FF6E6F6BFF787975FF8A8B87FF858682FF71726EFF8F938EFF8D918CFF
+ 949893FF868A85FF6A6E69FF6F736EFF818580FF7B7F7AFF7B7F7AFF727671FF
+ 757974FF939792FF7E827DFF949893FF929691FF8B8F8AFF969793FF737470FF
+ 747571FF70716DFF81827EFF949591FF7D7E7AFF848581FF81827EFF8B8C88FF
+ 7C7D79FF777874FF72736FFF737470FF888985FF868783FF696A66FF71726EFF
+ 6E6F6BFF636460FF656662FF70716DFF6E6F6BFF60615DFF60615DFF72736FFF
+ 62635FFF747571FF787975FF81827EFF6C6D69FF7E7F7BFF8F908CFFA0A19DFF
+ 969793FF969793FF777874FF7B7C78FF6B6C68FF6F706CFF8A8B87FF7C7D79FF
+ 80817DFF848581FF747571FF7B7C78FF858682FF7C7D79FF757974FF7C807BFF
+ 737772FF696D68FF70746FFF727671FF6D716CFF6D716CFF737772FF6C706BFF
+ 6F736EFF838782FF787C77FF6D716CFF777B76FF5E625DFF626661FF737772FF
+ 6C706BFF666A65FF6C706BFF7D817CFF878B86FF757974FF60645FFF717570FF
+ 777B76FF959994FF888C87FF8D918CFF737772FF70746FFF8B8F8AFF868A85FF
+ 80847FFF959994FFA7ABA6FF858984FF676B66FF777B76FF868A85FF868A85FF
+ 787C77FF676B66FF585C57FF4B4F4AFF555954FF747873FF767A75FF4F534EFF
+ 4D514CFF5B5F5AFF6A6E69FF646863FF4D514CFF565A55FF5D615CFF4C504BFF
+ 595D58FF6C706BFF686C67FF6F736EFF7B7F7AFF757974FF5E625DFF616560FF
+ 636762FF737772FF6E726DFF686C67FF757974FF676B66FF6E726DFF696D68FF
+ 373B36FF444843FF464A45FF4C504BFF363A35FF272B25FF242822FF787D74FF
+ 41463DFF73786FFF91968DFF82877EFF858A81FF747970FF848980FF868B82FF
+ 888D84FF888D84FF848980FF7E837AFF787D74FF757A71FF737771FF6E726CFF
+ 797D77FF949892FFA2A6A0FF979B95FF858983FF7D817BFF80847EFF7E827CFF
+ 8E928CFF81857FFF959993FF5E625CFF424640FF656963FF454A41FF666B62FF
+ 686D64FF555A51FF5F645BFF767B72FF7D8279FF787D74FF60655CFF81867DFF
+ 6B7067FF72776EFF91968DFF7F847BFF7E837AFF9CA198FF858984FF777B76FF
+ 6F736EFF727671FF6F736EFF626661FF5C605BFF5E625DFF6E726DFF919590FF
+ 8C908BFF7A7E79FF7D817CFF6E726DFF6E726DFF939791FF757973FF666B62FF
+ 666B62FF797E75FF82877EFF7D8279FF7F847BFF8B9087FF6A6F66FF8A8F86FF
+ 92978EFF686D64FF777C73FF6B7067FF70756CFF6B7067FF70756CFF7E837AFF
+ 9A9F96FFB8BDB4FF898E85FF62675EFF73786FFF5B6057FF5D6259FF6B7067FF
+ 7E837AFF61665DFF656A61FF8A8F86FF797E75FF6D7269FF62675EFF7A7F76FF
+ 4B5047FF5E635AFF868B82FF5D6259FF7F847BFF474C43FF51564DFF71766DFF
+ 5A5F56FF666B62FF656A61FF646960FF595E55FF5E635AFF666B62FF7F847BFF
+ 777C73FF61665DFF5C6158FF676C63FF62675EFF5F645BFF6E736AFF6B7067FF
+ 6A6F66FF71766DFF7A7F76FF7A7F76FF6F746BFF656A61FF5A6055FF666C61FF
+ 6F756AFF6A7065FF61675CFF5E6459FF656B60FF6C7267FF7B8176FF6E7469FF
+ 63695EFF61675CFF90918DFF6D6E6AFF70716DFF7E7F7BFF747571FF7C7D79FF
+ 878884FF737470FF8A8B87FF959692FF70716DFF62635FFF696A66FF7E7F7BFF
+ 9FA09CFF8D8E8AFF7D817CFF797D78FF828681FF8F938EFF898D88FF797D78FF
+ 7D817CFF8F938EFF838782FF737772FF80847FFF747873FF717570FF797D78FF
+ 6C706BFF7F837EFF82837FFF858682FF747571FF939490FF979894FF767773FF
+ 8F908CFFACADA9FF6B6C68FF878884FF787975FF767773FF757672FF767773FF
+ 82837FFF646561FF70716DFF5A5B57FF4D4E4AFF5B5C58FF72736FFF787975FF
+ 6A6B67FF5A5B57FF5B5C58FF999A96FF71726EFF696A66FF656662FF777874FF
+ 80817DFF8B8C88FF7F807CFF989995FF8D8E8AFF7D7E7AFF7C7D79FF7C7D79FF
+ 7D7E7AFF767773FF70716DFF81827EFF898A86FF7B7C78FF6A6B67FF6E6F6BFF
+ 838480FF979894FF7E827DFF8A8E89FF636762FF8B8F8AFFA2A6A1FF8D918CFF
+ 6A6E69FF80847FFF7E827DFF858984FF757974FF7B7F7AFF757974FF757974FF
+ 8F938EFF7B7F7AFF5A5E59FF60645FFF646863FF878B86FF858984FF979B96FF
+ 757974FF545853FF565A55FF70746FFF666A65FF7A7E79FF767A75FF7A7E79FF
+ 6D716CFF6F736EFF717570FF848883FF6C706BFF727671FF717570FF7C807BFF
+ 686C67FF787C77FF747873FF636762FF7B7F7AFF747873FF767A75FF70746FFF
+ 898D88FF7A7E79FF666A65FF646863FF5D615CFF3D413CFF4E524DFF636762FF
+ 525651FF6A6E69FF6E726DFF5E625DFF797D78FF4D514CFF5A5E59FF838782FF
+ 8C908BFF6A6E69FF5B615CFF575D58FF6F7570FF6E746FFF7B817CFF626863FF
+ 757B76FF828883FF727873FF6B716CFF6C726DFF595F5AFF3E443FFF2A302BFF
+ 5B615CFF394039FF434741FF555A51FF5B6057FF858A81FF8D9289FF787D74FF
+ 8F948BFF93988FFF8D9289FF8D9289FF81867DFF767B72FF8E938AFF767B72FF
+ 80857CFF747970FF595D57FF515550FF676B66FF70746FFF727671FF6F736EFF
+ 636762FF737772FF7D817CFF848883FF9B9F9AFF868A85FF878B86FF949893FF
+ 7D817CFF8A8E88FF4F544BFF555A51FF7E837AFF7B8077FF70756CFF6A6F66FF
+ 50554CFF5E635AFF656A61FF60655CFF696E65FF5D6259FF7B8077FF7E837AFF
+ 8B9087FF7D8279FF939994FF555B56FF969C97FF9CA29DFF717772FF5B615CFF
+ 676D68FF5F6560FF5F6560FF555B56FF575D58FF525853FF626863FF747A75FF
+ 6C726DFF777E77FF868A84FF92978EFF7D8279FF6A6F66FF7E837AFF8D9289FF
+ 8B9087FF90958CFF7D8279FF8A8F86FF6F746BFF6B7067FF8F948BFF6B7067FF
+ 888D84FF9CA198FF70756CFF70756CFF777C73FF80857CFF7D8279FF6E736AFF
+ 61665DFF5C6158FF4F544BFF646960FF5B6057FF646960FF767B72FF797E75FF
+ 80857CFF7A7F76FF70756CFF7E837AFF90958CFF73786FFF797E75FF747970FF
+ 8E938AFF8D9289FF868B82FF92978EFF61665DFF60655CFF888D84FF747970FF
+ 5F645BFF6E736AFF6D7269FF7B8077FF686D64FF5E635AFF70756CFF676C63FF
+ 575C53FF6A6F66FF7E837AFF777C73FF696E65FF747970FF656A61FF81867DFF
+ 7B8077FF767B72FF60665BFF656B60FF646A5FFF646A5FFF60665BFF787E73FF
+ 6F756AFFAAB0A5FF61675CFF6A7065FF6E7469FF686E63FF5A5B57FF71726EFF
+ 81827EFF6A6B67FF585955FF757672FF81827EFF60615DFF7B7C78FF71726EFF
+ 60615DFF7C7D79FF82837FFF6C6D69FF797A76FF7C7D79FF80847FFF7E827DFF
+ 80847FFF888C87FF8F938EFF8E928DFF878B86FF818580FF6F736EFF666A65FF
+ 797D78FF757974FF747873FF787C77FF696D68FF767A75FF797A76FF888985FF
+ 7F807CFF6B6C68FF878884FF999A96FFB4B5B1FFA9AAA6FF8A8B87FF8E8F8BFF
+ 8A8B87FFA4A5A1FF9B9C98FF72736FFF6F706CFF6A6B67FF62635FFF61625EFF
+ 676864FF70716DFF737470FF6D6E6AFF666763FF636460FF62635FFF7D7E7AFF
+ 5C5D59FF636460FF5D5E5AFF6A6B67FF80817DFF979894FF898A86FF82837FFF
+ 7B7C78FF8A8B87FF8A8B87FF6A6B67FF61625EFF747571FF71726EFF6F706CFF
+ 7D7E7AFF92938FFF959692FF878884FF81827EFF898A86FF828681FF828681FF
+ 787C77FF989C97FF8F938EFF717570FF696D68FF717570FF848883FF828681FF
+ 737772FF80847FFF848883FF838782FF898D88FF666A65FF7B7F7AFF7E827DFF
+ 717570FF6A6E69FF636762FF70746FFF717570FF757974FF5D615CFF70746FFF
+ 656964FF787C77FF797D78FF818580FF717570FF737772FF777B76FF6B6F6AFF
+ 646863FF727671FF828681FF646863FF5E625DFF7C807BFF6F736EFF676B66FF
+ 6F736EFF757974FF636762FF696D68FF70746FFF686C67FF8B8F8AFF70746FFF
+ 5A5E59FF4B4F4AFF6C706BFF838782FF6D716CFF7B7F7AFF858984FF7C807BFF
+ 999D98FF8C908BFF616560FF666A65FF696D68FF787C77FF707671FF777D78FF
+ 838984FF6C726DFF757B76FF6E746FFF737974FF626863FF585E59FF353B36FF
+ 272D28FF2D332EFF434944FF616762FF787E79FF474E47FF585C56FF6E736AFF
+ 747970FF7D8279FF858A81FF898E85FF8C9188FF7A7F76FF868B82FF8E938AFF
+ 73786FFF757A71FF7A7F76FF7A7F76FF858A81FF8B8F89FF90948FFF868A85FF
+ 868A85FF6C706BFF5B5F5AFF595D58FF4B4F4AFF515550FF50544FFF666A65FF
+ 737772FF7B7F7AFF7F837EFF898D88FF989C97FF949893FF80847EFF7A7F76FF
+ 777C73FF63685FFF5B6057FF63685FFF63685FFF6D7269FF575C53FF585D54FF
+ 61665DFF7C8178FF898E85FF8B9087FF81867DFF7F847BFF9EA49FFF757B76FF
+ 828883FF777D78FF777D78FF737974FF7A807BFF6A706BFF707671FF686E69FF
+ 777D78FF5E645FFF4E544FFF737974FF797F7AFF616861FF797D77FF7E837AFF
+ 777C73FF73786FFF7F847BFF878C83FF83887FFF81867DFF949990FF8D9289FF
+ 83887FFF747970FF878C83FF82877EFF81867DFF979C93FF797E75FF7C8178FF
+ 787D74FF6A6F66FF575C53FF464B42FF3A3F36FF33382FFF545950FF696E65FF
+ 5E635AFF656A61FF73786FFF757A71FF80857CFF7E837AFF989D94FF777C73FF
+ 777C73FF797E75FF8B9087FF6F746BFF72776EFF767B72FF5F645BFF6B7067FF
+ 6D7269FF848980FF8A8F86FF7A7F76FF7C8178FF747970FF656A61FF767B72FF
+ 72776EFF70756CFF81867DFF7F847BFF6F746BFF71766DFF797E75FF757A71FF
+ 72776EFF72776EFF6F746BFF6A6F66FF71766DFF5A5F56FF62685DFF5D6358FF
+ 6B7166FF5A6055FF5C6257FF60665BFF5D6358FF7B8176FF565C51FF5F655AFF
+ 63695EFF60665BFF535450FF656662FF747571FF6F706CFF696A66FF72736FFF
+ 7F807CFF82837FFF636460FF555652FF555652FF80817DFF8B8C88FF6F706CFF
+ 747571FF81827EFF7B7F7AFF7F837EFF7E827DFF797D78FF7D817CFF868A85FF
+ 838782FF797D78FF656964FF60645FFF6E726DFF6D716CFF6C706BFF6C706BFF
+ 60645FFF6A6E69FF6F706CFF6D6E6AFF8B8C88FF858682FF868783FF70716DFF
+ 767773FF8C8D89FF979894FF90918DFF797A76FF7E7F7BFF888985FF898A86FF
+ 90918DFF838480FF8F908CFF7D7E7AFF6F706CFF6E6F6BFF72736FFF70716DFF
+ 696A66FF646561FF656662FF666763FF646561FF868783FF767773FF696A66FF
+ 72736FFF7E7F7BFF72736FFF797A76FF7A7B77FF7D7E7AFF848581FF7C7D79FF
+ 737470FF7B7C78FF787975FF989995FFA6A7A3FF949591FF888985FF8F908CFF
+ 8F908CFF82837FFF898D88FF6B6F6AFF646863FF777B76FF7B7F7AFF757974FF
+ 929691FF858984FF777B76FF757974FF717570FF80847FFF868A85FF888C87FF
+ 8D918CFF717570FF6E726DFF888C87FF8B8F8AFF727671FF6E726DFF5A5E59FF
+ 5B5F5AFF6D716CFF666A65FF6D716CFF60645FFF737772FF7B7F7AFF888C87FF
+ 727671FF747873FF5C605BFF767A75FF797D78FF484C47FF636762FF6F736EFF
+ 7B7F7AFF646863FF787C77FF777B76FF6D716CFF7C807BFF5F635EFF727671FF
+ 6E726DFF70746FFF878B86FF7C807BFF797D78FF777B76FF878B86FF888C87FF
+ 717570FF7A7E79FF8C908BFF757974FF797D78FF8C908BFF686C67FF7D817CFF
+ 7D817CFF929691FF515752FF6F7570FF878D88FF6D736EFF5E645FFF565C57FF
+ 6C726DFF747A75FF6C726DFF595F5AFF5A605BFF595F5AFF525853FF727873FF
+ 606661FF383F38FF484C46FF52574EFF646960FF646960FF72776EFF888D84FF
+ 80857CFF777C73FF80857CFF92978EFF70756CFF7E837AFF70756CFF7A7F76FF
+ 7B8077FF888C86FF818580FF7B7E7CFF7C7F7DFF6C6F6DFF717472FF7C7F7DFF
+ 5E615FFF494C4AFF353836FF565957FF5D605EFF6B6E6CFF565957FF565957FF
+ 8E918FFF868A85FF888C86FF8D9289FF83887FFF878C83FF898E85FF82877EFF
+ 7B8077FF666B62FF646960FF60655CFF5D6259FF898E85FF83887FFF868B82FF
+ 70756CFF7C8178FF717772FF707671FF5B615CFF454B46FF636964FF676D68FF
+ 777D78FF666C67FF848A85FF717772FF8B918CFF777D78FF545A55FF757B76FF
+ 848A85FF646B64FF7E827CFF73786FFF777C73FF7F847BFF7D8279FF7A7F76FF
+ 787D74FF72776EFF767B72FF6F746BFF82877EFF7C8178FF7F847BFF9A9F96FF
+ 7A7F76FF848980FF797E75FF80857CFF7F847BFF71766DFF656A61FF666B62FF
+ 6F746BFF757A71FF5B6057FF6F746BFF63685FFF646960FF6A6F66FF656A61FF
+ 70756CFF72776EFF666B62FF5A5F56FF595E55FF575C53FF757A71FF7D8279FF
+ 7F847BFF6E736AFF686D64FF51564DFF5F645BFF858A81FF7C8178FF7D8279FF
+ 898E85FF5B6057FF585D54FF676C63FF6F746BFF73786FFF83887FFF949990FF
+ 90958CFF83887FFF70756CFF73786FFF757A71FF70756CFF7A7F76FF63685FFF
+ 83887FFF656A61FF6E7469FF646A5FFF82887DFF6A7065FF72786DFF6B7166FF
+ 73796EFF6C7267FF63695EFF686E63FF6A7065FF666C61FF838480FF747571FF
+ 676864FF6C6D69FF6F706CFF5E5F5BFF5D5E5AFF747571FF747571FF737470FF
+ 6C6D69FF6D6E6AFF70716DFF72736FFF767773FF72736FFF7D817CFF848883FF
+ 858984FF7B7F7AFF727671FF757974FF828681FF8C908BFF787C77FF717570FF
+ 717570FF6D716CFF686C67FF646863FF626661FF6A6E69FF8B8C88FF8C8D89FF
+ 9B9C98FF939490FFADAEAAFFE3E4E0FFB0B1ADFF787975FF60615DFF80817DFF
+ 91928EFF8F908CFF888985FF8E8F8BFF9FA09CFFA2A39FFFA1A29EFF8C8D89FF
+ 7A7B77FF787975FF7E7F7BFF7C7D79FF737470FF6C6D69FF676864FF5A5B57FF
+ 747571FF9B9C98FF838480FF6D6E6AFF6E6F6BFF666763FF72736FFF80817DFF
+ 8B8C88FF82837FFF898A86FF91928EFF8A8B87FF959692FF8D8E8AFFB0B1ADFF
+ B6B7B3FF939490FF7F807CFF8C8D89FF939490FF878884FF939792FF8A8E89FF
+ 7C807BFF636762FF6C706BFF666A65FF878B86FF747873FF70746FFF747873FF
+ 7C807BFF80847FFF787C77FF7D817CFF90948FFF919590FF6B6F6AFF80847FFF
+ 8E928DFF8B8F8AFFB8BCB7FF969A95FF747873FF666A65FF6F736EFF6B6F6AFF
+ 60645FFF70746FFF7A7E79FF8B8F8AFF6C706BFF727671FF727671FF717570FF
+ 6E726DFF595D58FF676B66FF6B6F6AFF7E827DFF818580FF737772FF727671FF
+ 696D68FF6E726DFF5F635EFF6C706BFF6D716CFF747873FF6B6F6AFF727671FF
+ 7A7E79FF7B7F7AFF818580FF838782FF777B76FF747873FF797D78FF6D716CFF
+ 777B76FF8F938EFF848883FF959994FF858984FF6E726DFF6E746FFF6A706BFF
+ 707671FF6D736EFF5D635EFF434944FF464C47FF555B56FF515752FF5B615CFF
+ 737974FF676D68FF3D433EFF585E59FF3B413CFF373E37FF4F534DFF42473EFF
+ 5C6158FF5A5F56FF5A5F56FF60655CFF545950FF6E736AFF767B72FF8A8F86FF
+ 767B72FF82877EFF7A7F76FF71766DFF686D64FF666A64FF898D88FF7F8280FF
+ 828583FF757876FF7C7F7DFF8B8E8CFF7C7F7DFF777A78FF626563FF626563FF
+ 626563FF616462FF444745FF4D504EFF797C7AFF676B66FF989C96FF92978EFF
+ 797E75FF959A91FFA2A79EFF8D9289FF8C9188FF757A71FF5D6259FF50554CFF
+ 40453CFF50554CFF474C43FF484D44FF3F443BFF494E45FF313732FF494F4AFF
+ 434944FF3A403BFF4B514CFF464C47FF6E746FFF606661FF747A75FF585E59FF
+ 6C726DFF727873FF626863FF676D68FF686E69FF6B726BFF828680FF6B7067FF
+ 757A71FF868B82FF7C8178FF757A71FF7A7F76FF747970FF787D74FF7E837AFF
+ 8C9188FF92978EFF83887FFFA8ADA4FF93988FFF8F948BFF71766DFF686D64FF
+ 5C6158FF50554CFF43483FFF40453CFF4F544BFF646960FF81867DFF92978EFF
+ 7F847BFF757A71FF6A6F66FF555A51FF585D54FF595E55FF272C23FF363B32FF
+ 3E433AFF383D34FF4C5148FF686D64FF777C73FF6F746BFF858A81FF63685FFF
+ 5A5F56FF6E736AFF62675EFF6D7269FF848980FF5E635AFF61665DFF666B62FF
+ 696E65FF666B62FF6F746BFF8D9289FF979C93FF82877EFF777C73FF7E837AFF
+ 747970FF767B72FF797E75FF6D7269FF999E95FF858A81FF6A7065FF646A5FFF
+ 7D8378FF72786DFF70766BFF72786DFF797F74FF5F655AFF6F756AFF6F756AFF
+ 6D7368FF696F64FF949591FF90918DFF81827EFF787975FF7B7C78FF787975FF
+ 737470FF797A76FF757672FF7C7D79FF7C7D79FF6C6D69FF70716DFF848581FF
+ 858682FF7D7E7AFF888C87FF838782FF868A85FF8D918CFF888C87FF80847FFF
+ 8B8F8AFF9EA29DFF8A8E89FF868A85FF7E827DFF7B7F7AFF747873FF6C706BFF
+ 70746FFF747873FF8D8E8AFF848581FF767773FF777874FF7C7D79FFD7D8D4FF
+ A8A9A5FF787975FF7C7D79FF6B6C68FF747571FF8B8C88FF91928EFF858682FF
+ 82837FFF969793FF747571FF7F807CFF90918DFF989995FF90918DFF81827EFF
+ 7B7C78FF7E7F7BFF70716DFF565753FF71726EFF7C7D79FF666763FF676864FF
+ 7A7B77FF71726EFF898A86FF80817DFF979894FFA1A29EFF9E9F9BFF868783FF
+ 72736FFF9B9C98FF9C9D99FF868783FF838480FF979894FF9C9D99FF8B8C88FF
+ 848581FF8D8E8AFF757974FFB9BDB8FFBDC1BCFF898D88FF8A8E89FF757974FF
+ 8B8F8AFF8F938EFF838782FF818580FF8E928DFF8A8E89FF7B7F7AFF7F837EFF
+ 8D918CFF989C97FF7B7F7AFF727671FF676B66FF70746FFFBFC3BEFFB4B8B3FF
+ 919590FF787C77FF7A7E79FF6E726DFF696D68FF777B76FF7F837EFF90948FFF
+ 676B66FF727671FF797D78FF80847FFF787C77FF787C77FF6B6F6AFF848883FF
+ 8B8F8AFF8D918CFF747873FF757974FF7A7E79FF6E726DFF767A75FF686C67FF
+ 6B6F6AFF6A6E69FF626661FF5E625DFF525651FF545853FF6C706BFF8C908BFF
+ 939792FF7A7E79FF959994FF7F837EFF7F837EFF6E726DFF616560FF676B66FF
+ 9EA29DFFABAFAAFF6B716CFF757C77FF818883FF858C87FF666D68FF464D48FF
+ 3D443FFF4C534EFF414843FF3F4641FF454C47FF383F3AFF1F2621FF444B46FF
+ 303732FF3B423BFF40443EFF40453CFF62675EFF5A5F56FF4F544BFF585D54FF
+ 5A5F56FF81867DFF6A6F66FF777C73FF767B72FF7A7F76FF8E938AFF73786FFF
+ 6F746BFF5D615BFF525651FF565957FF757876FF7C7F7DFF777A78FF727573FF
+ 686B69FF797C7AFF9C9F9DFF717472FF757876FF676A68FF5C5F5DFF787B79FF
+ 727573FF565A55FF656963FF646960FF6B7067FFAFB4ABFFC2C7BEFF8D9289FF
+ 6E736AFF4E534AFF71766DFF676C63FF63685FFF50554CFF565B52FF4D5249FF
+ 51564DFF484D44FF313732FF353C37FF454C47FF515853FF4B524DFF3D443FFF
+ 747B76FF656C67FF666D68FF5F6661FF5F6661FF646B66FF79807BFF707772FF
+ 565D58FF737A73FF6F736DFF5B6057FF6C7168FF858A81FF7E837AFF767B72FF
+ 7C8178FF787D74FF7F847BFF92978EFF787D74FF7A7F76FF5B6057FF6F746BFF
+ 7E837AFF72776EFF868B82FF676C63FF50554CFF4A4F46FF3C4138FF2C3128FF
+ 3A3F36FF585D54FF777C73FF8B9087FF81867DFF82877EFF7E837AFF6E736AFF
+ 767B72FF7D8279FF767B72FF696E65FF666B62FF757A71FF72776EFF6D7269FF
+ 777C73FF90958CFF7A7F76FF81867DFF72776EFF6B7067FF5F645BFF5C6158FF
+ 797E75FF80857CFF767B72FF777C73FF72776EFF646960FF646960FF7C8178FF
+ 848980FF70756CFF7F847BFF888D84FF73786FFF7E837AFF696E65FF72776EFF
+ 8A8F86FF83887FFF70766BFF73796EFF73796EFF7E8479FF686E63FF787E73FF
+ 757B70FF5C6257FF878D82FF848A7FFF82887DFF82887DFF9C9D99FF92938FFF
+ 979894FFA4A5A1FF9D9E9AFF8B8C88FF8C8D89FF9A9B97FF7D7E7AFF787975FF
+ 898A86FF8D8E8AFF92938FFF969793FF8B8C88FF92938FFF838782FF6F736EFF
+ 6F736EFF888C87FF979B96FF8F938EFF868A85FF8A8E89FF818580FF858984FF
+ 7C807BFF848883FF80847FFF737772FF7C807BFF7A7E79FF888985FF7D7E7AFF
+ 7D7E7AFF91928EFF646561FF868783FF878884FF989995FFA0A19DFF878884FF
+ 7F807CFF757672FF80817DFF91928EFF888985FF898A86FF797A76FF7D7E7AFF
+ 878884FF91928EFF91928EFF888985FF81827EFF7F807CFF80817DFF646561FF
+ 7F807CFF6D6E6AFF5A5B57FF61625EFF777874FF70716DFF6F706CFF797A76FF
+ 9E9F9BFF989995FF92938FFF878884FF636460FF767773FF8B8C88FF7C7D79FF
+ 777874FF82837FFF878884FF81827EFF838480FF8E8F8BFF555954FFA2A6A1FF
+ 9EA29DFF7D817CFF929691FF90948FFF9DA19CFFACB0ABFF888C87FF7B7F7AFF
+ 8E928DFF919590FF8C908BFF919590FF8B8F8AFF8D918CFF7B7F7AFF80847FFF
+ 7B7F7AFF737772FF888C87FF7F837EFF80847FFF90948FFF80847FFF747873FF
+ 7B7F7AFF858984FF888C87FF969A95FF676B66FF797D78FF676B66FF8D918CFF
+ 8C908BFF80847FFF646863FF979B96FF919590FF717570FF70746FFF777B76FF
+ 858984FF727671FF838782FF616560FF5A5E59FF525651FF5A5E59FF60645FFF
+ 5B5F5AFF636762FF6A6E69FF7D817CFF919590FF787C77FF777B76FF696D68FF
+ 8C908BFF9EA29DFF919590FF5E625DFF858984FF8D938EFF646A65FF7E8580FF
+ 878E89FF8C938EFF7A817CFF787F7AFF5C635EFF474E49FF474E49FF404742FF
+ 3A413CFF333A35FF29302BFF333A35FF282F2AFF313932FF1C201AFF41463DFF
+ 61665DFF4F544BFF484D44FF63685FFF767B72FF848980FF6B7067FF72776EFF
+ 747970FF747970FF989D94FF81867DFF8C9188FF7D817BFF414540FF2E312FFF
+ 3D403EFF4E514FFF5F6260FF646765FF565957FF616462FF8D908EFF737674FF
+ 878A88FF696C6AFF515452FF646765FF525553FF4D514CFF5E625CFF464B42FF
+ 42473EFF72776EFF898E85FF777C73FF757A71FF7B8077FF81867DFF83887FFF
+ 949990FF80857CFF92978EFF82877EFF83887FFF6B7369FF5E645FFF3F4641FF
+ 4D544FFF575E59FF525954FF464D48FF6F7671FF646B66FF676E69FF7B827DFF
+ 6D746FFF5B625DFF7E8580FF7F8681FF59605BFF6F7770FF646862FF5C6158FF
+ 6B7067FF7F847BFF7D8279FF71766DFF6D7269FF6C7168FF8D9289FFABB0A7FF
+ 8A8F86FF868B82FF70756CFF696E65FF7E837AFF71766DFF676C63FF4B5047FF
+ 3A3F36FF3D4239FF393E35FF33382FFF484D44FF696E65FF5E635AFF71766DFF
+ 6B7067FF767B72FF7C8178FF72776EFF80857CFF8C9188FF81867DFF767B72FF
+ 63685FFF6A6F66FF63685FFF6B7067FF656A61FF6A6F66FF70756CFF8B9087FF
+ 777C73FF70756CFF797E75FF6B7067FF6B7067FF72776EFF73786FFF7C8178FF
+ 787D74FF6D7269FF70756CFF7B8077FF7A7F76FF70756CFF6D7269FF72776EFF
+ 6F746BFF7B8077FF5E635AFF757A71FF6D7269FF6E736AFF73796EFF7E8479FF
+ 6D7368FF878D82FF747A6FFF848A7FFF81877CFF767C71FF93998EFF90968BFF
+ 92988DFF9AA095FFA5A6A2FF838480FF8B8C88FFA5A6A2FF989995FF838480FF
+ 82837FFF848581FFA3A4A0FF8E8F8BFF9C9D99FF9B9C98FF969793FF8C8D89FF
+ 787975FF8A8B87FF7F837EFF6F736EFF686C67FF787C77FF8A8E89FF8A8E89FF
+ 7E827DFF757974FF777B76FF7F837EFF727671FF7F837EFF80847FFF757974FF
+ 888C87FF868A85FF6C6D69FF7A7B77FF858682FF797A76FF6E6F6BFF8C8D89FF
+ A7A8A4FF797A76FF6F706CFFA1A29EFFCACBC7FF9D9E9AFF7F807CFF92938FFF
+ 8F908CFF90918DFF9C9D99FF898A86FF7A7B77FF7E7F7BFF888985FF8B8C88FF
+ 858682FF7F807CFF8C8D89FF737470FF949591FF7B7C78FF6B6C68FF61625EFF
+ 696A66FF6A6B67FF5B5C58FF797A76FFA0A19DFF7F807CFF838480FF9C9D99FF
+ 70716DFF656662FF787975FF8E8F8BFF90918DFF7A7B77FF747571FF878884FF
+ 8F908CFF868783FF656964FF757974FF555954FF585C57FF646863FF6C706BFF
+ 6D716CFF6E726DFF737772FF676B66FF858984FF898D88FF828681FF868A85FF
+ 797D78FF80847FFF7D817CFF969A95FFA5A9A4FFA3A7A2FF7F837EFF70746FFF
+ 797D78FF999D98FF7D817CFF757974FF888C87FF929691FF8F938EFF9A9E99FF
+ 676B66FF80847FFF80847FFF717570FF7C807BFF8F938EFF787C77FF6E726DFF
+ 727671FF757974FF5D615CFF6C706BFF6B6F6AFF626661FF6A6E69FF575B56FF
+ 474B46FF4C504BFF626661FF6B6F6AFF787C77FF8F938EFF797D78FF646863FF
+ 797D78FF6E726DFF989C97FF7F837EFF7C807BFF989C97FF868A85FF626661FF
+ 747873FF686E69FF9FA5A0FF888F8AFF636A65FF787F7AFF919893FFAAB1ACFF
+ 6F7671FF343B36FF303732FF313833FF2D342FFF323934FF3A413CFF232A25FF
+ 2C332EFF353D36FF343832FF5D6259FF666B62FF5A5F56FF4F544BFF575C53FF
+ 646960FF565B52FF70756CFF7A7F76FF6C7168FF72776EFF83887FFF7C8178FF
+ 878C83FF858983FF9FA2A0FF6B6D6DFF424444FF262828FF313333FF4F5151FF
+ 575959FF666868FF676969FF6C6E6EFF6A6C6CFF484A4AFF2B2D2DFF2B2D2DFF
+ 333535FF3D403EFF383C36FF30352CFF494E45FF676C63FF7C8178FF7F847BFF
+ 72776EFF797E75FF6C7168FF6E736AFF787D74FF7D8279FF848980FF7D8279FF
+ 797E75FF71796FFF777D78FF5B625DFF5E6560FF4C534EFF585F5AFF4D544FFF
+ 565D58FF646B66FF6A716CFF6F7671FF686F6AFF59605BFF6B726DFF6F7671FF
+ 585F5AFF6C746DFF6A6E68FF6C7168FF6C7168FF72776EFF787D74FF71766DFF
+ 6D7269FF777C73FF858A81FF959A91FF868B82FF70756CFF7A7F76FF70756CFF
+ 797E75FF82877EFF6E736AFF676C63FF5C6158FF50554CFF484D44FF4E534AFF
+ 63685FFF787D74FF797E75FF81867DFF6E736AFF6D7269FF6A6F66FF585D54FF
+ 61665DFF6B7067FF6F746BFF7D8279FF6C7168FF676C63FF60655CFF81867DFF
+ 767B72FF676C63FF797E75FF848980FF6D7269FF73786FFF898E85FF81867DFF
+ 73786FFF5E635AFF666B62FF797E75FF757A71FF6F746BFF7B8077FF7A7F76FF
+ 72776EFF7B8077FF60655CFF555A51FF747970FF6D7269FF63685FFF787D74FF
+ 61665DFF656A61FF61675CFF6F756AFF5E6459FF72786DFF797F74FF71776CFF
+ 7A8075FF797F74FF757B70FF71776CFF747A6FFF80867BFF7F807CFF72736FFF
+ 787975FF7D7E7AFF8A8B87FFBABBB7FFC1C2BEFF8A8B87FF90918DFF7E7F7BFF
+ 898A86FF7D7E7AFF7F807CFF90918DFF8C8D89FFA2A39FFF8C908BFF898D88FF
+ 80847FFF777B76FF7A7E79FF838782FF838782FF7C807BFF7F837EFF848883FF
+ 6F736EFF7B7F7AFF7D817CFF787C77FF979B96FF999D98FF969793FF888985FF
+ A5A6A2FF9A9B97FF898A86FF52534FFF969793FF8A8B87FF888985FF7B7C78FF
+ 82837FFF6E6F6BFF72736FFF878884FF747571FF747571FF8D8E8AFF8B8C88FF
+ 8B8C88FF8D8E8AFF8A8B87FF858682FF888985FF8E8F8BFF8F908CFF72736FFF
+ 949591FF7B7C78FF71726EFF60615DFF686965FF7C7D79FF81827EFF7D7E7AFF
+ 9A9B97FF8A8B87FF949591FFA1A29EFF747571FF7F807CFF7A7B77FF7F807CFF
+ 898A86FF989995FFA5A6A2FFA4A5A1FF8F908CFF787975FF757974FF656964FF
+ 525651FF787C77FF5F635EFF5A5E59FF5A5E59FF565A55FF636762FF5F635EFF
+ 858984FF7D817CFF636762FF5F635EFF595D58FF70746FFF7A7E79FF7C807BFF
+ 81827EFF9DA19CFF8B8C88FF8E928DFF80817DFF7E827DFF797A76FF727671FF
+ 8F908CFF979B96FF939490FF9A9E99FF676864FF848883FF878884FF80847FFF
+ 949591FF757974FF6D6E6AFF6B6F6AFF848581FF676B66FF6A6B67FF7A7E79FF
+ 656662FF686C67FF676864FF6E726DFF60615DFF747873FF848883FF6D716CFF
+ 686C67FF929691FF848883FF636762FF767A75FF6D716CFF7E827DFF828681FF
+ 6F736EFF8D918CFF767A75FF848883FF919590FF777B76FF858B86FF7D847FFF
+ 707671FF89908BFF808681FF8A918CFF858B86FF979E99FF525853FF3C433EFF
+ 1E241FFF242B26FF454B46FF212823FF3A403BFF3A403BFF4B524BFF626660FF
+ 5E625CFF737771FF71756FFF5C605AFF656963FF555953FF6D716BFF7E827CFF
+ 60645EFF6D716BFF60645EFF646862FF61655FFF696D67FF818482FF7E8080FF
+ 767878FF474949FF2D2F2FFF3A3C3CFF444646FF585A5AFF686A6AFF646666FF
+ 2A2C2CFF1A1C1CFF212323FF242626FF3A3C3CFF2E312FFF40443EFF3E433AFF
+ 5B6057FF585D54FF63685FFF7A7F76FF696E65FF71766DFF858A81FF7B8077FF
+ 6D7269FF878C83FF7B8077FF83887FFF7F847BFF959A91FF787F78FF79817AFF
+ 7B817CFF4B534CFF646A65FF555D56FF454B46FF707871FF878D88FF646C65FF
+ 6D736EFF788079FF757B76FF6C746DFF6F7570FF8F968FFF6D7269FF747970FF
+ 676C63FF62675EFF767B72FF7E837AFF868B82FF9FA49BFFACB1A8FF9A9F96FF
+ 8E938AFF565B52FF797E75FF868B82FF8E938AFFBCC1B8FF6A6F66FF7A7F76FF
+ 757973FF585D54FF4B4F49FF5E635AFF747872FF7C8178FF787C76FF7E837AFF
+ 6A6E68FF6E736AFF737771FF6A6F66FF7B7F79FF898E85FF787C76FF797E75FF
+ 71756FFF878C83FF71756FFF73786FFF6A6E68FF7D8279FF767A74FF7C8178FF
+ 757973FF7E837AFF80847EFF848980FF8F938DFF7A7F76FF6A6E68FF7F847BFF
+ 737771FF686D64FF767A74FF6B7067FF60645EFF787D74FF6E726CFF50554CFF
+ 858983FF62675EFF6A6E68FF777C73FF60645EFF646960FF686D64FF73796EFF
+ 656B60FF676D62FF858B80FF5E6459FF6F756AFF71776CFF63695EFF5D6358FF
+ 5E6459FF686E63FF80847FFF9CA09BFF838782FF929691FF7E827DFFA9ADA8FF
+ D0D4CFFF90948FFF676B66FF929691FFA0A49FFF9A9E99FFA7ABA6FF7F837EFF
+ 535752FF848883FF858886FF8A8D8BFF909391FF909391FF868987FF7F8280FF
+ 878A88FF969997FF7A7D7BFF959896FF989B99FF757876FF858886FF7D807EFF
+ 868987FF8E918FFF8F9290FF8F9290FFA3A6A4FF929593FF8E918FFF8B8E8CFF
+ 6F7270FF838684FF7E817FFF6E716FFF888B89FF848785FF767977FF6C6F6DFF
+ 5C5F5DFF7F837EFF6B6F6AFF6D716BFF71756FFF848882FF888C86FF81857FFF
+ 8D918BFF90948EFF7E827CFF8D918BFF686C66FF838781FF7C807AFF878B85FF
+ 5E625CFF777B76FF6A6E69FF7B7E7CFF757876FF707371FF7F8280FF818482FF
+ 808381FF909391FF767977FF9EA19FFF777A78FF818482FF7C7F7DFF8D908EFF
+ 919492FF7D817CFF858984FFA5A9A3FF9EA29CFF5C605AFF646862FF626660FF
+ 727670FF747872FF7D817BFF5F635DFF70746EFF6A6E68FF646862FF6D716BFF
+ 666A64FF7A7E79FF868783FF747573FF7F7D7CFF727371FF868483FF7F807EFF
+ 888685FF6A6B69FF9A9897FF70716FFF7B7978FF757674FF8B8988FF8B8C8AFF
+ 6B6968FF989997FF807E7DFF888987FF8B8988FF7A7B79FF888685FF717270FF
+ 7C7A79FF5B5C5AFF636160FF7B7C7AFF5F5D5CFF787977FF757372FF949593FF
+ 706E6DFF777874FF747873FF7D817BFF7A7E78FF71756FFF868A84FF80847EFF
+ 696D67FF8B8F89FF838781FF777B75FF797D77FF9B9F99FF868A84FF949892FF
+ 8F938DFF8D918CFF757974FF727775FF7E817FFF6F7472FF848785FF8B908EFF
+ 717472FF848987FF7C7F7DFF5F6462FF4E514FFF535856FF656866FF6B706EFF
+ 707371FF727775FF717772FF717772FF6F7570FF6F7570FF7B817CFF888E89FF
+ 878D88FF7E847FFF636964FF646A65FF636964FF6E746FFF7A807BFF707671FF
+ 676D68FF707671FF6C716FFF3A3F3DFF282D2BFF707573FF828785FF595E5CFF
+ 545957FF3F4442FF555A58FF3C413FFF1A1F1DFF121715FF232826FF2C312FFF
+ 2B302EFF303631FF50544EFF5F645BFF62675EFF61665DFF63685FFF5B6057FF
+ 575C53FF60655CFF757A71FF999E95FF82877EFF80857CFF858A81FF91968DFF
+ 747970FF82877EFF7F847BFF8C948AFF7E827CFF6A7268FF71756FFF676F65FF
+ 5E625CFF676F65FF6C706AFF71796FFF8E928CFF5F675DFF5E625CFF788076FF
+ 5D615BFF6F746BFF6E736AFF787D74FF676C63FF747970FF60655CFF565B52FF
+ 52574EFF888D84FF898E85FF7B8077FF6C7168FF787D74FF666B62FF777C73FF
+ 7A7F76FF81867DFF7D7F79FF6E706AFF636460FF666862FF70716DFF767872FF
+ 787975FF7A7C76FF7D7E7AFF8A8C86FF80817DFF747670FF7B7C78FF797B75FF
+ 7D7E7AFF959791FF656964FF676B65FF7E827DFF828680FF6B6F6AFF6B6F69FF
+ 757974FF696D67FF767A75FF787C76FF727671FF737771FF7E827DFF7D817BFF
+ 7A7E79FF848882FF8C928DFF787F78FF757B76FF697069FF787E79FF676E67FF
+ 686E69FF5D645DFF5B615CFF535A53FF5C625DFF5F665FFF6E746FFFB7BEB7FF
+ 545A55FF656C65FF71796FFF60685EFF4F574DFF6C746AFF525A50FF6B7369FF
+ 50584EFF71796FFF70786EFF626A60FF6C746AFF71796FFF787C77FF898D88FF
+ 828681FF959994FF6F736EFF7B7F7AFF8D918CFF686C67FF737772FF7E827DFF
+ 747873FF6C706BFF9B9F9AFFA9ADA8FF838782FF8C908BFF868987FF8C8F8DFF
+ 8D908EFF848785FF7A7D7BFF7E817FFF919492FFA3A6A4FF848785FF8A8D8BFF
+ 8E918FFF828583FF999C9AFF848785FF878A88FF959896FF8D908EFF999C9AFF
+ 959896FF979A98FF989B99FF878A88FF808381FF828583FF7A7D7BFF777A78FF
+ 7A7D7BFF8B8E8CFF858886FF707371FF727573FF7D817CFF737772FF595D57FF
+ 777B75FF8D918BFF6F736DFF828680FF9FA39DFF747872FF8C908AFF979B95FF
+ 81857FFF8F938DFF797D77FFA4A8A2FF8E928CFF7F837DFF727573FF7A7D7BFF
+ 787B79FF747775FF757876FF757876FF7E817FFF909391FF7B7E7CFF878A88FF
+ 8F9290FF7B7E7CFF6E716FFF8D908EFF6A6D6BFF7A7E79FF828681FF949892FF
+ 939791FF6D716BFF7A7E78FF6E726CFF737771FF757973FF8C908AFF7D817BFF
+ 828680FF81857FFF7E827CFF7F837DFF80847EFF949892FF7B7C7AFF858382FF
+ 8D8B8AFF8A8887FF747271FF737170FF767473FF767473FF7E7C7BFF737170FF
+ 92908FFF888685FF7D7B7AFF8F8D8CFF7A7877FF696766FF787675FF878584FF
+ 858382FF807E7DFF858382FF7D7B7AFF868483FF716F6EFF6F6D6CFF787675FF
+ 737170FF757372FF807E7DFF868483FF797776FF70716DFF7F837EFF80847EFF
+ 7B7F79FF7A7E78FF979B95FF91958FFF6C706AFF7B7F79FF828680FF8D918BFF
+ 747872FF666A64FF868A84FF7E827CFF7F837DFFA7ABA5FF898C8AFF727573FF
+ 6A6D6BFF636664FF858886FF8F9290FF828583FF7D807EFF6B6E6CFF666967FF
+ 676A68FF707371FF757876FF737674FF6F7270FF6D706EFF5F6462FF5B605EFF
+ 545957FF4F5452FF595E5CFF6B706EFF757A78FF757A78FF777C7AFF717674FF
+ 727775FF858A88FF8D9290FF717674FF5C615FFF676C6AFF7C817FFF5D6260FF
+ 3F4442FF444947FF6E7371FF7E8381FF686D6BFF626765FF424745FF2B302EFF
+ 141917FF0A0F0DFF0D1210FF1D2220FF343937FF454B46FF585C56FF585D54FF
+ 575C53FF5F645BFF646960FF575C53FF555A51FF6A6F66FF5E635AFF6A6F66FF
+ 656A61FF71766DFF9DA299FF92978EFF73786FFF70756CFF5B6057FF6F746BFF
+ 7C8178FF8F948BFF9EA39AFF898E85FF71766DFF787D74FF7D8279FF6E736AFF
+ 6D7269FF777C73FF7F847BFF6D7269FF595E55FF6A6F66FF70756CFF787D74FF
+ 6F746BFF6F746BFF656A61FF5D6259FF4A4F46FF4D5249FF5F645BFF82877EFF
+ 51564DFF676C63FF50554CFF555A51FF82877EFF63685FFF7E7F7BFF767773FF
+ 747571FF7C7D79FF858682FF868783FF82837FFF7F807CFF777874FF82837FFF
+ 81827EFF7A7B77FF747571FF696A66FF646561FF6C6D69FF6D716CFF565A55FF
+ 575B56FF656964FF6B6F6AFF7A7E79FF818580FF717570FF838782FF777B76FF
+ 676B66FF6D716CFF7E827DFF7C807BFF747873FF7B7F7AFF8C928DFF797F7AFF
+ 777D78FF6C726DFF7C827DFF6B716CFF6A706BFF5F6560FF393F3AFF3F4540FF
+ 4C524DFF414742FF3D433EFF6C726DFF3B413CFF606760FF545B54FF4F574DFF
+ 444C42FF4A5248FF394137FF545C52FF373F35FF3C443AFF586056FF535B51FF
+ 656D63FF71796FFF7C807BFF747873FF7D817CFF9EA29DFF7F837EFF7D817CFF
+ 747873FF696D68FF70746FFF959994FFA0A49FFF717570FF636762FF777B76FF
+ 7C807BFF8F938EFF949795FF848785FF6C6F6DFF606361FF6E716FFF838684FF
+ 858886FF7A7D7BFF787B79FF686B69FF6C6F6DFF747775FF929593FF797C7AFF
+ 7E817FFF909391FF7F8280FF929593FF7A7D7BFF909391FF9A9D9BFF828583FF
+ 8C8F8DFF818482FF7C7F7DFF858886FF757876FF949795FF969997FF7B7E7CFF
+ 8A8D8BFF80847FFF90948FFF8B8F89FFB1B5AFFFA9ADA7FF6F736DFF7A7E78FF
+ 9A9E98FF7F837DFF838781FF7C807AFF737771FF848882FF626660FF91958FFF
+ 8E928CFF6F736DFF777A78FF717472FF777A78FF797C7AFF6C6F6DFF6B6E6CFF
+ 808381FF919492FF828583FF8A8D8BFF999C9AFF868987FF767977FF838684FF
+ 646765FF7E827DFF666A65FF6B6F69FF71756FFF6D716BFF838781FF767A74FF
+ 71756FFF71756FFF777B75FF7B7F79FF6D716BFF727670FF757973FF676B65FF
+ 6E726CFF7B7F79FF4E4F4DFF616260FF696A68FF898A88FF787977FF7E7F7DFF
+ 626361FF5D5E5CFF636462FF5A5B59FF747573FF727371FF5B5C5AFF767775FF
+ 767775FF3B3C3AFF5E5F5DFF767775FF717270FF7E7F7DFF7B7C7AFF848583FF
+ 8E8F8DFF878886FF848583FF767775FF878886FF6E6F6DFF80817FFF6F706EFF
+ 828381FF6F706CFF5F635EFF5C605AFF575B55FF555953FF767A74FF838781FF
+ 757973FF8D918BFF757973FF858983FF7F837DFF646862FF8C908AFF727670FF
+ 747872FF90948EFF696C6AFF595C5AFF555856FF494C4AFF555856FF474A48FF
+ 5C5F5DFF4A4D4BFF414442FF474A48FF4F5250FF565957FF5D605EFF5D605EFF
+ 505351FF424543FF606563FF5D6260FF555A58FF4D5250FF4F5452FF5B605EFF
+ 666B69FF6A6F6DFF7B807EFF707573FF717674FF8C918FFF989D9BFF7C817FFF
+ 6A6F6DFF797E7CFF696E6CFF7B807EFF7E8381FF575C5AFF6D7270FF828785FF
+ 5C615FFF707573FF686D6BFF505553FF464B49FF363B39FF1A1F1DFF212624FF
+ 414644FF4E544FFF5E625CFF565B52FF545950FF676C63FF70756CFF5C6158FF
+ 575C53FF6F746BFF7C8178FF6B7067FF656A61FF63685FFF959A91FF7C8178FF
+ 747970FF787D74FF656A61FF5D6259FF575C53FF676C63FF7A7F76FF777C73FF
+ 7E837AFF9A9F96FF83887FFF868B82FF6A6F66FF6D7269FF7A7F76FF777C73FF
+ 80857CFF7C8178FF6F746BFF7A7F76FF878C83FF777C73FF72776EFF6E736AFF
+ 646960FF42473EFF3E433AFF4A4F46FF60655CFF5A5F56FF3E433AFF62675EFF
+ 6A6F66FF82877EFF686C67FF666A65FF686C67FF6F736EFF717570FF6A6E69FF
+ 626661FF5F635EFF656964FF6A6E69FF777B76FF797D78FF6B6F6AFF636762FF
+ 616560FF5B5F5AFF5D615CFF474B46FF454944FF4D514CFF4E524DFF595D58FF
+ 6D716CFF757974FF616560FF626661FF6B6F6AFF878B86FF9A9E99FF8B8F8AFF
+ 7F837EFF8C908BFF848A85FF747A75FF757B76FF6D736EFF7D837EFF6B716CFF
+ 6A706BFF5E645FFF5E645FFF585E59FF535954FF404641FF3F4540FF454B46FF
+ 323833FF444B44FF4B524BFF51594FFF525A50FF454D43FF485046FF676F65FF
+ 4D554BFF384036FF343C32FF3B4339FF565E54FF6C746AFF818580FF636762FF
+ 686C67FF8E928DFF888C87FF939792FF7B7F7AFF7A7E79FF757974FF7F837EFF
+ 888C87FF686C67FF60645FFF7F837EFF7E827DFF747873FF8F9290FF818482FF
+ 6C6F6DFF656866FF7B7E7CFF939694FF888B89FF6B6E6CFF7D807EFF646765FF
+ 636664FF656866FF7A7D7BFF626563FF676A68FF707371FF6C6F6DFF747775FF
+ 666967FF7B7E7CFF8D908EFF7F8280FF828583FF7F8280FF868987FF898C8AFF
+ 7E817FFF919492FF949795FF858886FF8C8F8DFF848785FF7B7F7AFF7C807AFF
+ 757973FF686C66FF777B75FF838781FF787C76FF81857FFF848882FF747872FF
+ 6D716BFF878B85FF6E726CFF7C807AFF787C76FF777B76FF797C7AFF686B69FF
+ 747775FF7F8280FF6F7270FF717472FF888B89FF919492FF838684FF9DA09EFF
+ 868987FF929593FF898C8AFF717472FF818482FF848785FF5F635EFF5E625CFF
+ 61655FFF6B6F69FF80847EFF7F837DFF757973FF6B6F69FF6E726CFF7B7F79FF
+ 60645EFF6C706AFF727670FF595D57FF5D615BFF595D58FF4E4F4DFF454644FF
+ 323331FF464745FF565755FF6F706EFF717270FF818280FF6F706EFF565755FF
+ 494A48FF4C4D4BFF414240FF4F504EFF5C5D5BFF353634FF4D4E4CFF6B6C6AFF
+ 656664FF7F807EFF737472FF848583FF8D8E8CFF8F908EFF848583FF6D6E6CFF
+ 838482FF6D6E6CFF7A7B79FF6F706EFF929391FF828381FF787C77FF7A7E78FF
+ 797D77FF666A64FF686C66FF70746EFF71756FFF929690FF81857FFF777B75FF
+ 898D87FF80847EFF737771FF60645EFF61655FFF484C47FF262927FF252826FF
+ 323533FF3A3D3BFF464947FF343735FF636664FF484B49FF3B3E3CFF3A3D3BFF
+ 383B39FF3B3E3CFF4B4E4CFF585B59FF4D504EFF383B39FF484D4BFF4C514FFF
+ 4D5250FF4B504EFF494E4CFF4A4F4DFF4D5250FF505553FF696E6CFF646967FF
+ 606563FF6E7371FF808583FF7C817FFF797E7CFF888D8BFF4D5250FF6B706EFF
+ 888D8BFF757A78FF6B706EFF686D6BFF525755FF5D6260FF8C918FFF747977FF
+ 787D7BFF6F7472FF464B49FF434846FF595E5CFF555B56FF60645EFF5F645BFF
+ 60655CFF6F746BFF797E75FF6A6F66FF5E635AFF6A6F66FF81867DFF7D8279FF
+ 747970FF63685FFF70756CFF5E635AFF656A61FF787D74FF82877EFF7A7F76FF
+ 747970FF787D74FF797E75FF6E736AFF676C63FF6D7269FFA4A9A0FFAAAFA6FF
+ 91968DFF767B72FF71766DFF71766DFF70756CFF6E736AFF71766DFF7A7F76FF
+ 9A9F96FF82877EFF797E75FF72776EFF81867DFF62675EFF50554CFF353A31FF
+ 6F746BFF6B7067FF454A41FF5E635AFF40453CFF828680FF2F332EFF373B36FF
+ 454944FF535752FF585C57FF5A5E59FF616560FF6A6E69FF656964FF60645FFF
+ 6E726DFF717570FF5A5E59FF545853FF575B56FF4A4E49FF3D413CFF343833FF
+ 353934FF393D38FF333732FF343833FF484C47FF5D615CFF6C706BFF686C67FF
+ 666A65FF70746FFF757974FF727671FF929691FFCACEC9FF858B86FF797F7AFF
+ 808681FF7A807BFF8A908BFF777D78FF767C77FF6B716CFF686E69FF626863FF
+ 626863FF5D635EFF6D736EFF595F5AFF626863FF606661FF656C65FF676F65FF
+ 71796FFF60685EFF70786EFF8A9288FF757D73FF5C645AFF586056FF60685EFF
+ 6D756BFF737B71FF797D78FF626661FF5A5E59FF6F736EFF6B6F6AFF7F837EFF
+ 70746FFF797D78FF898D88FF6C706BFF6A6E69FF636762FF6E726DFF888C87FF
+ 757974FF575B56FF505351FF686B69FF787B79FF777A78FF787B79FF818482FF
+ 7F8280FF747775FF838684FF747775FF787B79FF6A6D6BFF747775FF646765FF
+ 656866FF565957FF666967FF5C5F5DFF666967FF6B6E6CFF7B7E7CFF7D807EFF
+ 6A6D6BFF7D807EFF919492FF858886FF8F9290FF868987FF858886FF8B8E8CFF
+ 7D807EFF868987FF8D918CFF777B76FF686C67FF60645FFF797D78FF7F837EFF
+ 6E726DFF919590FF7A7E79FF858984FF7A7E79FF858984FF848883FF80847FFF
+ 717570FF888C87FF7E817FFF6D706EFF797C7AFF878A88FF7D807EFF808381FF
+ 8E918FFF8B8E8CFF888B89FF969997FF7D807EFF868987FF8B8E8CFF717472FF
+ 848785FF848785FF797D78FF777B76FF717570FF747873FF7A7E79FF898D88FF
+ 7F837EFF6B6F6AFF6B6F6AFF737772FF5D615CFF6E726DFF737772FF5B5F5AFF
+ 575B56FF40443FFF494A48FF40413FFF3B3C3AFF353634FF50514FFF4A4B49FF
+ 5E5F5DFF7A7B79FF6F706EFF717270FF545553FF424341FF3D3E3CFF393A38FF
+ 424341FF414240FF545553FF6E6F6DFF656664FF7B7C7AFF676866FF6D6E6CFF
+ 70716FFF737472FF5A5B59FF4E4F4DFF60615FFF676866FF666765FF6E6F6DFF
+ 858684FF80817FFF6D716CFF777B76FF878B86FF797D78FF727671FF757974FF
+ 727671FF888C87FF858984FF797D78FF696D68FF626661FF3E423DFF414540FF
+ 30342FFF161A15FF262927FF181B19FF161917FF2A2D2BFF3F4240FF373A38FF
+ 545755FF2B2E2CFF363937FF393C3AFF373A38FF333634FF3B3E3CFF4B4E4CFF
+ 4E514FFF454846FF303533FF363B39FF3F4442FF434846FF414644FF3F4442FF
+ 404543FF434846FF555A58FF616664FF595E5CFF4F5452FF5E6361FF6F7472FF
+ 727775FF747977FF6C716FFF6F7472FF737876FF767B79FF646967FF767B79FF
+ 929795FF656A68FF767B79FF606563FF6D7270FF767B79FF5F6462FF626765FF
+ 727775FF646A65FF656963FF70746EFF6C706AFF686C66FF71756FFF70746EFF
+ 676B65FF666A64FF686C66FF828680FF858983FF878B85FF767A74FF7A7E78FF
+ 6F736DFF757973FF666A64FF70746EFF7A7E78FF7A7E78FF777B75FF777B75FF
+ 6D716BFF5B5F59FF70746EFF565A54FF6F736DFF7B7F79FF8F938DFF91958FFF
+ 737771FF959993FF7E827CFF777B75FF949892FF8A8E88FF868A84FF787C76FF
+ 888C86FF747872FF7B7F79FF727670FF626660FF7B7F79FF585C56FF40443EFF
+ 31352FFF2A2E28FF20241FFF2C302BFF3F433EFF4D514CFF4F534EFF4E524DFF
+ 585C57FF646863FF686C67FF5F635EFF686C67FF656964FF484C47FF3A3E39FF
+ 363A35FF232722FF2D312CFF262A25FF232722FF2C302BFF363A35FF333732FF
+ 313530FF393D38FF434742FF4B4F4AFF595D58FF6C706BFF6B6F6AFF575B56FF
+ 626661FF8D918CFF6F7570FF6A706BFF797F7AFF767C77FF848A85FF6F7570FF
+ 707671FF686E69FF606661FF676D68FF787E79FF727873FF767C77FF555B56FF
+ 767C77FF737974FF7C837CFF727972FF798079FF707770FF7D847DFF8A918AFF
+ 798079FF6F766FFF7A817AFF7F867FFF798079FF6C736CFF717570FF7A7E79FF
+ 70746FFF7C807BFF676B66FF6D716CFF757974FF8D918CFF959994FF838782FF
+ 888C87FF777B76FF646863FF646863FF5B5F5AFF5C605BFF3D403EFF555856FF
+ 6B6E6CFF717472FF727573FF717472FF6A6D6BFF5F6260FF565957FF525553FF
+ 636664FF5B5E5CFF6D706EFF757876FF7D807EFF5E615FFF676A68FF565957FF
+ 6B6E6CFF666967FF6E716FFF717472FF575A58FF787B79FF989B99FF868987FF
+ 969997FF7F8280FF7E817FFF909391FF797C7AFF838684FFB8BCB7FF696D68FF
+ 6A6E69FF70746FFF6E726DFF7F837EFF727671FF747873FF686C67FF90948FFF
+ 858984FF757974FF848883FF8C908BFF7C807BFF868A85FF7F8280FF7B7E7CFF
+ 818482FF888B89FF878A88FF8A8D8BFF8B8E8CFF838684FF969997FF828583FF
+ 8F9290FF747775FF848785FF868987FF737674FF868987FF7D817CFF7A7E79FF
+ 737772FF777B76FF6C706BFF848883FF828681FF727671FF616560FF5A5E59FF
+ 5A5E59FF6A6E69FF656964FF595D58FF515550FF30342FFF3F403EFF3C3D3BFF
+ 464745FF494A48FF6F706EFF414240FF2A2B29FF2A2B29FF3E3F3DFF696A68FF
+ 6D6E6CFF4C4D4BFF40413FFF3D3E3CFF3A3B39FF4D4E4CFF5A5B59FF6A6B69FF
+ 5D5E5CFF616260FF4B4C4AFF3F403EFF414240FF3E3F3DFF2E2F2DFF30312FFF
+ 353634FF4D4E4CFF414240FF4E4F4DFF4B4C4AFF4F504EFF323631FF313530FF
+ 424641FF414540FF4D514CFF6A6E69FF737772FF838782FF7D817CFF989C97FF
+ 686C67FF5C605BFF60645FFF6A6E69FF3E423DFF484C47FF2B2E2CFF262927FF
+ 1D201EFF2B2E2CFF2D302EFF333634FF3C3F3DFF303331FF1D201EFF2C2F2DFF
+ 353836FF2D302EFF212422FF232624FF323533FF3F4240FF333836FF333836FF
+ 363B39FF383D3BFF353A38FF313634FF333836FF393E3CFF484D4BFF656A68FF
+ 626765FF4C514FFF555A58FF6A6F6DFF6B706EFF626765FF6E7371FF7B807EFF
+ 797E7CFF707573FF4B504EFF717674FFABB0AEFF616664FF676C6AFF565B59FF
+ 5E6361FF696E6CFF616664FF666B69FF707573FF686E69FF6D716CFF7B7F79FF
+ 70746EFF5E625CFF636761FF6C706AFF6A6E68FF6A6E68FF696D67FF7E827CFF
+ 7C807AFF8C908AFF7E827CFF969A94FF80847EFF727670FF626660FF666A64FF
+ 686C66FF595D57FF50544EFF676B65FF777B75FF6A6E68FF71756FFF535751FF
+ 666A64FF565A54FF727670FF8F938DFF61655FFF71756FFF8D918BFF7A7E78FF
+ 848882FF949892FFA4A8A2FF999D97FF929690FF828680FF8D918BFF858983FF
+ 71756FFF727670FF636761FF6E726CFF3F433DFF0C100AFF1C201BFF212520FF
+ 2B2F2AFF343833FF353934FF30342FFF30342FFF353934FF454944FF474B46FF
+ 535752FF565A55FF484C47FF3B3F3AFF313530FF242823FF262A25FF363A35FF
+ 3A3E39FF373B36FF383C37FF2E322DFF272B26FF313530FF373B36FF282C27FF
+ 191D18FF222621FF323631FF363A35FF484C47FF6B6F6AFF595F5AFF5D635EFF
+ 767C77FF747A75FF7E847FFF676D68FF6C726DFF696F6AFF767C77FF6E746FFF
+ 787E79FF6D736EFF707671FF5E645FFF757B76FF646A65FF787F78FF6D746DFF
+ 717871FF767D76FF767D76FF838A83FF757C75FF818881FF747B74FF7A817AFF
+ 666D66FF4E554EFF747873FF929691FF868A85FFA5A9A4FF8C908BFF757974FF
+ 858984FF9FA39EFF949893FF848883FF838782FF767A75FF797D78FF80847FFF
+ 6F736EFF6D716CFF6D706EFF6A6D6BFF6B6E6CFF757876FF808381FF808381FF
+ 727573FF646765FF484B49FF343735FF3C3F3DFF363937FF4F5250FF656866FF
+ 787B79FF575A58FF575A58FF575A58FF5D605EFF626563FF636664FF565957FF
+ 535654FF6F7270FF888B89FF818482FF7C7F7DFF737674FF797C7AFF848785FF
+ 797C7AFF6E716FFFC0C4BFFF646863FF5E625DFF737772FFA0A49FFFCACEC9FF
+ A0A49FFF838782FF757974FF858984FF838782FF767A75FF7E827DFF8C908BFF
+ 898D88FF7D817CFF6F7270FF7F8280FF818482FF7B7E7CFF818482FF878A88FF
+ 818482FF7D807EFF939694FF828583FF959896FF727573FF878A88FF898C8AFF
+ 787B79FF848785FF7D817CFF737772FF70746FFF818580FF646863FF727671FF
+ 747873FF757974FF6F736EFF565A55FF727671FF797D78FF5E625DFF626661FF
+ 5A5E59FF3A3E39FF4D504EFF454846FF3A3D3BFF4E514FFF757876FF555856FF
+ 2F3230FF363937FF3C3F3DFF414442FF676A68FF5D605EFF4B4E4CFF4C4F4DFF
+ 424543FF565957FF515452FF535654FF474A48FF3B3E3CFF323533FF1A1D1BFF
+ 262927FF202321FF1F2220FF222523FF181B19FF272A28FF282B29FF2F3230FF
+ 282B29FF373A38FF3C403BFF30342FFF363A35FF262A25FF252924FF464A45FF
+ 5B5F5AFF6D716CFF838782FFA5A9A4FF8E928DFF7E827DFF9B9F9AFFA3A7A2FF
+ 8B8F8AFF929691FF979A98FF9B9E9CFF828583FF727573FF424543FF3C3F3DFF
+ 141715FF222523FF272A28FF2D302EFF303331FF292C2AFF1A1D1BFF131614FF
+ 1F2220FF313432FF2D3230FF292E2CFF2A2F2DFF2E3331FF2D3230FF282D2BFF
+ 292E2CFF2F3432FF4B504EFF686D6BFF676C6AFF515654FF525755FF5C615FFF
+ 5C615FFF595E5CFF3E4341FF525755FF6B706EFF5A5F5DFF333836FF4A4F4DFF
+ 656A68FF3E4341FF5C615FFF5B605EFF616664FF666B69FF636866FF606563FF
+ 646967FF6A706BFF6F736EFF797D77FF727670FF676B65FF686C66FF676B65FF
+ 666A64FF6E726CFF737771FF696D67FF636761FF6A6E68FF6D716BFF7B7F79FF
+ 7B7F79FF70746EFF8E928CFF8C908AFF939791FF858983FF686C66FF676B65FF
+ 6A6E68FF595D57FF5E625CFF696D67FF656963FF3B3F39FF50544EFF868A84FF
+ 81857FFF7C807AFF8E928CFF888C86FF7D817BFF929690FFA1A59FFFA2A6A0FF
+ 8B8F89FF868A84FF7E827CFF7F837DFF939791FF80847EFF6E726CFF969A94FF
+ 626660FF484C46FF272D28FF171D18FF0C120DFF121813FF1E241FFF252B26FF
+ 252B26FF252B26FF222823FF2E342FFF353B36FF3A403BFF414742FF3B413CFF
+ 333934FF353B36FF1C201BFF40443FFF474B46FF383C37FF373B36FF343833FF
+ 363A35FF474B46FF2C302BFF242823FF191D18FF1E221DFF2C302BFF292D28FF
+ 272B26FF343833FF505651FF5D635EFF7D837EFF7D837EFF828883FF6A706BFF
+ 737974FF757B76FF6D736EFF5C625DFF696F6AFF686E69FF747A75FF858B86FF
+ 8B918CFF707671FF6B726BFF6E756EFF6E756EFF7B827BFF686F68FF838A83FF
+ 737A73FF8A918AFF727972FF7D847DFF656C65FF464D46FF787C77FF969A95FF
+ 838782FFBABEB9FFA8ACA7FF787C77FF7E827DFF8C908BFF8A8E89FF929691FF
+ 979B96FF828681FF828681FF898D88FF767A75FF787C77FF767977FF717472FF
+ 707371FF757876FF777A78FF767977FF7A7D7BFF818482FF808381FF4E514FFF
+ 393C3AFF222523FF303331FF3E413FFF515452FF323533FF404341FF545755FF
+ 484B49FF5D605EFF5B5E5CFF3D403EFF555856FF676A68FF6C6F6DFF727573FF
+ 555856FF606361FF6D706EFF6C6F6DFF727573FF4F5250FF5B5F5AFF6B6F6AFF
+ 7F837EFF676B66FF828681FF8D918CFF686C67FF9B9F9AFF7F837EFF5D615CFF
+ 646863FF70746FFF696D68FF6B6F6AFF767A75FF646863FF595C5AFF7A7D7BFF
+ 7A7D7BFF6B6E6CFF767977FF7E817FFF797C7AFF7B7E7CFF7D807EFF909391FF
+ 818482FF777A78FF8E918FFF747775FF8D908EFF797C7AFF969A95FF828681FF
+ 80847FFF9A9E99FF6C706BFF656964FF646863FF727671FF7A7E79FF555954FF
+ 838782FF7F837EFF525651FF60645FFF5A5E59FF3E423DFF2F3230FF4E514FFF
+ 555856FF868987FF939694FF7E817FFF555856FF757876FF808381FF323533FF
+ 5D605EFF757876FF616462FF5E615FFF4C4F4DFF616462FF474A48FF424543FF
+ 3A3D3BFF292C2AFF2E312FFF141715FF2D302EFF272A28FF232624FF222523FF
+ 101311FF111412FF2B2E2CFF343735FF3C3F3DFF595C5AFF40443FFF424641FF
+ 545853FF3B3F3AFF222621FF333732FF484C47FF5E625DFF7D817CFF767A75FF
+ 838782FF6A6E69FF737772FF828681FF9FA39EFF868A85FF929593FF989B99FF
+ 878A88FF969997FF858886FFA2A5A3FF5E615FFF737674FF3D403EFF292C2AFF
+ 1A1D1BFF171A18FF141715FF0E110FFF101311FF181B19FF292E2CFF282D2BFF
+ 313634FF404543FF474C4AFF464B49FF474C4AFF4C514FFF595E5CFF6B706EFF
+ 646967FF4D5250FF434846FF404543FF404543FF474C4AFF3C413FFF2F3432FF
+ 4C514FFF4B504EFF4B504EFF535856FF3A3F3DFF3F4442FF363B39FF4B504EFF
+ 5C615FFF656A68FF676C6AFF616664FF656A68FF787D7BFF6C706BFF737771FF
+ 767A74FF7A7E78FF7A7E78FF686C66FF61655FFF6F736DFF7C807AFF636761FF
+ 71756FFF71756FFF7F837DFF727670FF888C86FF878B85FF959993FF8A8E88FF
+ 969A94FF969A94FF7C807AFF777B75FF858983FF838781FF6C706AFF868A84FF
+ 797D77FF666A64FF5C605AFF5C605AFF757973FF848882FF868A84FF959993FF
+ 7C807AFF7F837DFF7A7E78FF80847EFF676B65FF737771FF6C706AFFA4A8A2FF
+ 959993FFAFB3ADFF7F837DFF666A64FF878B85FF727670FF848A85FF595F5AFF
+ 2B312CFF1A201BFF212722FF262C27FF202621FF171D18FF282E29FF343A35FF
+ 282E29FF202621FF2B312CFF242A25FF1C221DFF292F2AFF151914FF2E322DFF
+ 272B26FF20241FFF414540FF595D58FF575B56FF5A5E59FF727671FF656964FF
+ 414540FF20241FFF111510FF080C07FF0E120DFF232722FF2F3530FF404641FF
+ 656B66FF666C67FF696F6AFF4F5550FF5A605BFF606661FF5E645FFF606661FF
+ 828883FF787E79FF676D68FF7B817CFF7B817CFF6D736EFF686F68FF787F78FF
+ 737A73FF7C837CFF575E57FF7A817AFF646B64FF7B827BFF545B54FF6C736CFF
+ 636A63FF545B54FF90948FFF7E827DFF8B8F8AFFBABEB9FFC2C6C1FF8B8F8AFF
+ 696D68FF7D817CFF7C807BFF868A85FF80847FFF7D817CFF989C97FF6F736EFF
+ 717570FF8A8E89FF848785FF787B79FF8B8E8CFF626563FF616462FF6C6F6DFF
+ 8A8D8BFF929593FF767977FF909391FF7A7D7BFF646765FF323533FF141715FF
+ 383B39FF4A4D4BFF353836FF464947FF474A48FF474A48FF4C4F4DFF3B3E3CFF
+ 343735FF4B4E4CFF4C4F4DFF5E615FFF505351FF656866FF444745FF464947FF
+ 6C6F6DFF7F8280FF5E615FFF7D807EFF858886FF838684FF858886FF717472FF
+ 606361FF6D706EFF7A7D7BFF838684FF818482FF7D807EFF707371FF7C7F7DFF
+ 646765FF777A78FF808381FF717472FF7C7F7DFF6A6D6BFF5E615FFF646765FF
+ 666967FF8D908EFF686B69FF7D807EFF8A8D8BFF838684FF7C7F7DFF7E817FFF
+ 7C7F7DFF747775FF9FA2A0FFC0C3C1FF7C7F7DFF868987FF8E918FFF6C6F6DFF
+ 4A4D4BFF5F6260FF6D706EFF515452FF484B49FF535654FF333634FF616462FF
+ 737674FF5A5D5BFF646967FF353A38FF2B302EFF545957FF686D6BFF525755FF
+ 4A4F4DFF5C615FFF858A88FF4A4F4DFF3E4341FF4E5351FF696E6CFF5D6260FF
+ 494E4CFF888D8BFF3D4240FF232826FF191E1CFF1C211FFF181D1BFF181D1BFF
+ 1C211FFF181D1BFF232826FF232826FF0D1210FF171C1AFF151A18FF1B201EFF
+ 444947FF3F4442FF242725FF414442FF3C3F3DFF414442FF303331FF414442FF
+ 3F4240FF525553FF4C4F4DFF474A48FF5F6260FF717472FF636664FF686B69FF
+ 898C8AFF9B9E9CFF898C8AFFA9ACAAFF929593FF7A7D7BFF929593FF919492FF
+ 818482FF949795FF898C8AFF787B79FF6F7270FF575A58FF393C3AFF444745FF
+ 575A58FF4B4E4CFF3C413FFF515654FF5C615FFF656A68FF727775FF6E7371FF
+ 5D6260FF575C5AFF646967FF6A6F6DFF717674FF424745FF5A5F5DFF303533FF
+ 3A3F3DFF404543FF353A38FF1D2220FF282D2BFF3F4442FF3B403EFF373C3AFF
+ 383D3BFF2C312FFF3E4341FF4F5452FF444947FF636866FF727775FF7F8482FF
+ 666B69FF767B79FF727671FF777B76FF6A6E69FF6A6E69FF60645FFF565A55FF
+ 6E726DFF787C77FF717570FF656964FF9CA09BFF747873FF676B66FF848883FF
+ 5E625DFF80847FFF7A7E79FF737772FF616560FF6F736EFF929691FF929691FF
+ 888C87FF989C97FF838782FF6C706BFF8F938EFF818580FF70746FFF7D817CFF
+ 6D716CFF878B86FF7E827DFF767A75FF8D918CFF666A65FF626661FF686C67FF
+ 7F837EFF818580FF767A75FF90948FFF979B96FF848883FF777B76FF999D98FF
+ 696D68FF626661FF838984FF6E7570FF505752FF363D38FF29302BFF282F2AFF
+ 2A312CFF2B322DFF171E19FF3E4540FF373E39FF4D544FFF29302BFF282F2AFF
+ 313833FF1D231EFF383C37FF242823FF2F332EFF3B3F3AFF737772FF686C67FF
+ 525651FF5E625DFF6B6F6AFF7F837EFF70746FFF535752FF464A45FF313530FF
+ 232722FF30342FFF3D433EFF525853FF676D68FF808681FF686E69FF7F8580FF
+ 747A75FF5B615CFF636964FF6F7570FF6B716CFF7E847FFF999F9AFF787E79FF
+ 505651FF5E645FFF5A605BFF7C827DFF7F8580FF6C726DFF6F7570FF787E79FF
+ 6E746FFF616762FF434944FF515752FF535954FF474D48FF888C87FF828681FF
+ 858984FF9B9F9AFFA4A8A3FF888C87FF777B76FF858984FF737772FF9A9E99FF
+ 7B7F7AFF9A9E99FFB3B7B2FF70746FFF8D918CFF717570FF7E817FFF626563FF
+ 727573FF686B69FF828583FF8B8E8CFF858886FF6E716FFF8B8E8CFFA2A5A3FF
+ A4A7A5FF8A8D8BFF6F7270FF474A48FF353836FF141715FF3F4240FF414442FF
+ 3F4240FF404341FF404341FF323533FF272A28FF2E312FFF282B29FF4C4F4DFF
+ 575A58FF878A88FF7B7E7CFF6D706EFF707371FF787B79FF545755FF7B7E7CFF
+ 7D807EFF9C9F9DFF8B8E8CFF7F8280FF454846FF424543FF666967FF666967FF
+ 646765FF6B6E6CFF646765FF6E716FFF545755FF6C6F6DFF858886FF777A78FF
+ 797C7AFF6C6F6DFF6D706EFF6D706EFF5A5D5BFF717472FF7C7F7DFF7D807EFF
+ 808381FF818482FF7D807EFF777A78FF757876FF777A78FF747775FF888B89FF
+ 747775FF7C7F7DFF878A88FF838684FF5B5E5CFF797C7AFF6B6E6CFF5B5E5CFF
+ 7A7D7BFF909391FF7D807EFF6C6F6DFF737674FF6A6D6BFF454A48FF2B302EFF
+ 1D2220FF282D2BFF373C3AFF393E3CFF383D3BFF3B403EFF3F4442FF414644FF
+ 353A38FF3A3F3DFF474C4AFF464B49FF464B49FF474C4AFF595E5CFF505553FF
+ 4E5351FF404543FF222725FF121715FF141917FF121715FF0F1412FF0A0F0DFF
+ 050A08FF121715FF151A18FF1A1F1DFF272C2AFF1A1F1DFF1B1E1CFF2B2E2CFF
+ 2D302EFF313432FF3B3E3CFF5D605EFF5D605EFF4E514FFF414442FF383B39FF
+ 424543FF555856FF565957FF525553FF555856FF565957FF363937FF6D706EFF
+ 757876FF606361FF686B69FF6F7270FF686B69FF707371FF808381FF898C8AFF
+ 979A98FF838684FF595C5AFF585B59FF707371FF757876FF4F5452FF555A58FF
+ 4E5351FF4A4F4DFF595E5CFF616664FF616664FF656A68FF5B605EFF6C716FFF
+ 7B807EFF656A68FF7C817FFF525755FF3A3F3DFF242927FF2D3230FF1E2321FF
+ 1F2422FF2B302EFF323735FF3E4341FF4B504EFF4E5351FF494E4CFF646967FF
+ 696E6CFF787D7BFF6A6F6DFF707573FF666B69FF777C7AFF767A75FF737772FF
+ 626661FF6B6F6AFF6B6F6AFF5C605BFF5B5F5AFF4E524DFF626661FF575B56FF
+ 80847FFF6C706BFF6D716CFF828681FF5D615CFF6A6E69FF656964FF646863FF
+ 555954FF585C57FF6D716CFF747873FF838782FFA7ABA6FF919590FF6B6F6AFF
+ 828681FF7D817CFF7E827DFF878B86FF5E625DFF595D58FF777B76FF626661FF
+ 6C706BFF767A75FF7A7E79FF8D918CFF828681FF7F837EFF7D817CFF7E827DFF
+ 737772FF818580FF979B96FFB4B8B3FF838782FF6B716CFF6C726DFF6C736EFF
+ 6E7570FF6B726DFF5F6661FF545B56FF545B56FF5B625DFF262D28FF323934FF
+ 5B625DFF676E69FF606762FF5C635EFF636A65FF676E69FF585C57FF5C605BFF
+ 6C706BFF616560FF8A8E89FF818580FF5C605BFF474B46FF555954FF6F736EFF
+ 747873FF747873FF7D817CFF737772FF626661FF646863FF4B514CFF4E544FFF
+ 626863FF6B716CFF6E746FFF6F7570FF797F7AFF767C77FF6F7570FF8B918CFF
+ 7F8580FF717772FF878D88FF868C87FF686E69FF5F6560FF797F7AFF686E69FF
+ 5D635EFF727873FF8C928DFF7A807BFF4F5550FF393F3AFF333934FF3D433EFF
+ 3D433EFF2F3530FF7E827DFF858984FF7F837EFF797D78FF7F837EFF7F837EFF
+ 7F837EFF888C87FF787C77FF919590FF747873FF8A8E89FF9DA19CFF727671FF
+ 979B96FF6F736EFF7F8280FF6E716FFF8A8D8BFF848785FF858886FF7C7F7DFF
+ 737674FF6C6F6DFF737674FF777A78FF8E918FFF6E716FFF848785FF7B7E7CFF
+ 666967FF3B3E3CFF232624FF252826FF3B3E3CFF555856FF595C5AFF4E514FFF
+ 3B3E3CFF262927FF292C2AFF4E514FFF565957FF888B89FF888B89FF6E716FFF
+ 555856FF626563FF6C6E6EFF6C6E6EFF565858FF626464FF727474FF878989FF
+ 818383FF8B8D8DFF9A9C9CFF696B6BFF353737FF343636FF494B4BFF707272FF
+ 616363FF767878FF717472FF767977FF777A78FF6C6F6DFF777A78FF757876FF
+ 646765FF7D807EFF777A78FF646765FF5C5F5DFF656866FF676A68FF5D605EFF
+ 585B59FF5D605EFF6B6D6DFF5D5F5FFF5B5D5DFF4C4E4EFF505252FF6C6E6EFF
+ 565858FF7D7F7FFF585A5AFF606262FF747676FF5B5D5DFF686A6AFF616363FF
+ 707272FF5D5F5FFF303533FF202523FF181D1BFF222725FF2E3331FF323735FF
+ 363B39FF3B403EFF323735FF505553FF454A48FF494E4CFF404543FF3D4240FF
+ 585D5BFF393E3CFF4B504EFF4E5351FF575C5AFF515654FF414644FF464B49FF
+ 555A58FF585D5BFF434846FF282D2BFF212624FF151A18FF0D1210FF161B19FF
+ 121715FF0D1210FF171919FF141616FF212323FF212323FF3A3C3CFF5A5C5CFF
+ 5A5C5CFF242626FF282A2AFF2A2C2CFF2E3030FF3B3D3DFF454747FF373939FF
+ 252727FF252727FF0B0E0CFF3C3F3DFF535654FF464947FF484B49FF5D605EFF
+ 626563FF555856FF5B5E5CFF505351FF575A58FF686B69FF727573FF777A78FF
+ 666967FF444745FF575C5AFF585D5BFF4C514FFF474C4AFF5A5F5DFF686D6BFF
+ 6C716FFF737876FF505553FF686D6BFF767B79FF6D7270FF7A7F7DFF6B706EFF
+ 555A58FF404543FF646967FF585D5BFF383D3BFF202523FF262B29FF393E3CFF
+ 4B504EFF5A5F5DFF444947FF424745FF3E4341FF515654FF5C615FFF808583FF
+ 818684FF747977FF787B79FF767977FF606361FF595C5AFF494C4AFF353836FF
+ 3F4240FF3E413FFF343735FF313432FF494C4AFF535654FF6C6F6DFF868987FF
+ 7A7D7BFF7A7D7BFF727573FF6E716FFF616462FF5C5F5DFF626563FF616462FF
+ 6B6E6CFF868987FF8C8F8DFF6A6D6BFF757876FF696C6AFF666967FF7A7D7BFF
+ 707371FF7C7F7DFF676A68FF585B59FF626563FF858886FF7B7E7CFF959896FF
+ 878A88FF9A9D9BFF7E817FFF8C8F8DFF7A7D7BFF868987FF828583FF7D807EFF
+ 727573FF717674FF565C57FF484F4AFF4C534EFF656C67FF777E79FF707772FF
+ 626964FF5D645FFF464D48FF383F3AFF7E8580FF7C837EFF878E89FF7A817CFF
+ 79807BFF8C938EFF787C77FF6E726DFF70746FFF545853FF70746FFF6D716CFF
+ 575B56FF4A4E49FF464A45FF575B56FF5F635EFF6A6E69FF7D817CFF777B76FF
+ 5E625DFF515550FF424843FF373D38FF404641FF383E39FF545A55FF454B46FF
+ 616762FF7A807BFF8D938EFFBCC2BDFFAEB4AFFF7F8580FF828883FF8B918CFF
+ 6A706BFF464C47FF606563FF6A6F6DFF646967FF5F6462FF6E7371FF6F7472FF
+ 535856FF3A3F3DFF444947FF4A4F4DFF484D4BFF3B403EFF787C77FF858984FF
+ 7F837EFF737772FF767A75FF7B7F7AFF7F837EFF898D88FF8D918CFF7F837EFF
+ 8F938EFF7B7F7AFF888C87FF90948FFF999D98FF8C908BFF8B8E8CFF868987FF
+ A3A6A4FF979A98FF787B79FF696C6AFF717472FF888B89FF828583FF6D706EFF
+ 8A8D8BFF585B59FF797C7AFF7B7E7CFF7E817FFF727573FF666967FF4F5250FF
+ 4F5250FF535654FF4C4F4DFF535654FF585B59FF474A48FF5B5E5CFF6A6D6BFF
+ 545755FF676A68FF656866FF4E514FFF373A38FF5C5F5DFF989A9AFF7A7C7CFF
+ 7A7C7CFF5A5C5CFF8D8F8FFF828484FF9EA0A0FF939595FFB3B5B5FF7D7F7FFF
+ 313333FF111313FF1C1E1EFF535555FF545656FF6E7070FF616462FF7B7E7CFF
+ 7A7D7BFF656866FF626563FF5A5D5BFF595C5AFF7A7D7BFF525553FF404341FF
+ 373A38FF3F4240FF494C4AFF444745FF3A3D3BFF343735FF4A4C4CFF414343FF
+ 4F5151FF4C4E4EFF464848FF4D4F4FFF343636FF303232FF4B4D4DFF5E6060FF
+ 575959FF303232FF3B3D3DFF464848FF636565FF757777FF3E4341FF262B29FF
+ 262B29FF3E4341FF3E4341FF242927FF1F2422FF313634FF3F4442FF474C4AFF
+ 565B59FF6D7270FF535856FF3B403EFF4E5351FF434846FF4A4F4DFF424745FF
+ 404543FF3E4341FF414644FF595E5CFF6C716FFF686D6BFF747977FF525755FF
+ 4E5351FF292E2CFF0E1311FF181D1BFF111614FF1E2321FF2D2F2FFF202222FF
+ 434545FF464848FF545656FF585A5AFF595B5BFF1C1E1EFF191B1BFF2A2C2CFF
+ 2B2D2DFF2A2C2CFF2C2E2EFF171919FF090B0BFF1A1C1CFF1C1F1DFF232624FF
+ 2F3230FF2F3230FF343735FF535654FF5F6260FF484B49FF4D504EFF474A48FF
+ 4E514FFF606361FF707371FF777A78FF717472FF656866FF585D5BFF5C615FFF
+ 515654FF484D4BFF4B504EFF434846FF2E3331FF252A28FF323735FF4E5351FF
+ 575C5AFF4F5452FF4A4F4DFF535856FF505553FF4B504EFF626765FF797E7CFF
+ 747977FF6A6F6DFF787D7BFF737876FF585D5BFF4B504EFF494E4CFF2A2F2DFF
+ 191E1CFF272C2AFF484D4BFF828785FF909593FF717674FF717472FF6B6E6CFF
+ 4E514FFF424543FF303331FF212422FF313432FF353836FF3E413FFF3C3F3DFF
+ 343735FF3B3E3CFF464947FF505351FF595C5AFF555856FF737674FF6C6F6DFF
+ 676A68FF707371FF797C7AFF717472FF636664FF5F6260FF676A68FF5D605EFF
+ 767977FF717472FF636664FF686B69FF5C5F5DFF616462FF777A78FF616462FF
+ 616462FF686B69FF5B5E5CFF737674FF737674FF868987FF909391FF8E918FFF
+ 5A5D5BFF5C5F5DFF666967FF5F6260FF606361FF4B504EFF4F5651FF323934FF
+ 2A312CFF464D48FF616863FF636A65FF5F6661FF636A65FF6F7671FF646B66FF
+ 8D948FFF8A918CFF878E89FF787F7AFF717873FF737A75FFA4AAA5FF7B7F7AFF
+ 747873FF60645FFF727671FF666A65FF666A65FF797D78FF7B7F7AFF787C77FF
+ 717570FF727671FF7D817CFF797D78FF60645FFF4A4E49FF5D635EFF575D58FF
+ 4A504BFF363C37FF454B46FF323833FF3E443FFF5B615CFF6D736EFF959B96FF
+ 8F9590FF676D68FF626863FF6D736EFF606661FF4D534EFF484D4BFF6E7371FF
+ 757A78FF5F6462FF5C615FFF646967FF5F6462FF575C5AFF656A68FF6A6F6DFF
+ 696E6CFF616664FF6E726DFF7A7E79FF7F837EFF818580FF848883FF7B7F7AFF
+ 797D78FF868A85FF797D78FF6F736EFF8B8F8AFF727671FF7B7F7AFF878B86FF
+ 898D88FF818580FF8D908EFF7C7F7DFF8B8E8CFF8E918FFF7F8280FF828583FF
+ 7C7F7DFF888B89FF858886FF767977FFA3A6A4FF7A7D7BFF898C8AFF757876FF
+ 848785FF999C9AFF848785FF717472FF717472FF6F7270FF606361FF646765FF
+ 6A6D6BFF595C5AFF6C6F6DFF747775FF5B5E5CFF606361FF5E615FFF565957FF
+ 464947FF777A78FFA8AAAAFF8C8E8EFF959797FF747676FF949696FF797B7BFF
+ 8B8D8DFF757777FF7A7C7CFF838585FF656767FF2F3131FF060808FF1E2020FF
+ 1F2121FF3E4040FF626563FF7D807EFF737674FF5A5D5BFF484B49FF363937FF
+ 353836FF414442FF323533FF2F3230FF2B2E2CFF2E312FFF3C3F3DFF434644FF
+ 323533FF1B1E1CFF3B3D3DFF3D3F3FFF3A3C3CFF424444FF3F4141FF343636FF
+ 363838FF0F1111FF292B2BFF343636FF343636FF4F5151FF464848FF2D2F2FFF
+ 343636FF7D7F7FFF828785FF707774FF6F7673FF7B827FFF6F7673FF4D5451FF
+ 404744FF4B524FFF2D3431FF202724FF525956FF69706DFF4E5552FF353C39FF
+ 272E2BFF353C39FF454C49FF373E3BFF2F3633FF272E2BFF232A27FF313835FF
+ 3E4542FF383F3CFF505754FF424946FF535A57FF333A37FF101714FF161D1AFF
+ 171E1BFF2F3432FF2A2C2CFF232525FF595B5BFF686A6AFF616363FF454747FF
+ 4B4D4DFF2B2D2DFF1F2121FF2C2E2EFF222424FF161818FF171919FF090B0BFF
+ 030505FF181A1AFF222523FF0B0E0CFF101311FF1D201EFF1C1F1DFF303331FF
+ 454846FF3B3E3CFF464947FF3B3E3CFF2E312FFF2B2E2CFF323533FF3A3D3BFF
+ 4D504EFF636664FF5A5F5DFF636866FF5E6361FF5A5F5DFF5E6361FF545957FF
+ 3E4341FF333836FF393E3CFF4A4F4DFF535856FF505553FF464B49FF4C514FFF
+ 444947FF343937FF121715FF353A38FF424745FF4D5250FF707573FF777C7AFF
+ 5A5F5DFF474C4AFF444947FF343937FF2F3432FF1D2220FF181D1BFF363B39FF
+ 555A58FF484D4BFF555856FF434644FF252826FF313432FF404341FF3C3F3DFF
+ 3B3E3CFF282B29FF2E312FFF373A38FF2E312FFF343735FF333634FF323533FF
+ 4C4F4DFF535654FF494C4AFF444745FF4D504EFF616462FF6F7270FF737674FF
+ 6C6F6DFF606361FF545755FF474A48FF535654FF555856FF555856FF626563FF
+ 5F6260FF5A5D5BFF8E918FFF626563FF545755FF323533FF3D403EFF4D504EFF
+ 4C4F4DFF3A3D3BFF5D605EFF6C6F6DFF464947FF373A38FF444745FF454846FF
+ 585B59FF444947FF2E3530FF1E2822FF1E2822FF2B352FFF303A34FF313B35FF
+ 4A544EFF6C7670FF77817BFF858F89FF7A847EFF8A948EFF76807AFF76807AFF
+ 747E78FF5C635EFFA3A9A4FF7E827DFF878B86FF7A7E79FF828681FF70746FFF
+ 70746FFF7D817CFF7F837EFF747873FF6C706BFF6B6F6AFF6F736EFF747873FF
+ 6B6F6AFF585C57FF848A85FF949A95FF7C827DFF727873FF636964FF5A605BFF
+ 3F4540FF494F4AFF666C67FF6E746FFF676D68FF525853FF434944FF3F4540FF
+ 4A504BFF5C625DFF626765FF5D6260FF5A5F5DFF696E6CFF737876FF636866FF
+ 565B59FF636866FF6A6F6DFF6F7472FF727775FF717674FF5E625DFF6A6E69FF
+ 777B76FF858984FF898D88FF767A75FF6B6F6AFF777B76FF636762FF727671FF
+ 616560FF5B5F5AFF6B6F6AFF5C605BFF828681FF6F736EFF7D807EFF6F7270FF
+ 7A7D7BFF878A88FF7C7F7DFF888B89FF727573FF707371FF575A58FF5B5E5CFF
+ 8A8D8BFF808381FF888B89FF727573FF8F9290FFB0B3B1FF686B69FF737674FF
+ 898C8AFF949795FF8C8F8DFF808381FF6C6F6DFF545755FF4C4F4DFF5B5E5CFF
+ 626563FF737674FF757876FF7C7F7DFF646765FF858886FF888A8AFF777979FF
+ 666868FF676969FF545656FF646666FF676969FF656767FF676969FF858787FF
+ 7F8181FF555757FF242626FF2C2E2EFF1D1F1FFF343636FF5E615FFF6B6E6CFF
+ 626563FF5B5E5CFF505351FF464947FF434644FF272A28FF252826FF2B2E2CFF
+ 2B2E2CFF2B2E2CFF373A38FF424543FF313432FF151816FF3D3F3FFF404242FF
+ 252727FF1E2020FF242626FF1F2121FF424444FF1F2121FF111313FF181A1AFF
+ 0E1010FF3F4141FF4C4E4EFF494B4BFF282A2AFF3E4342FF606563FF6A716EFF
+ 6F7673FF6A716EFF666D6AFF666D6AFF626966FF5A615EFF3E4542FF2C3330FF
+ 4E5552FF474E4BFF39403DFF3C4340FF2C3330FF434A47FF424946FF39403DFF
+ 3A413EFF353C39FF202724FF19201DFF212825FF232A27FF2E3532FF2E3532FF
+ 3D4441FF282F2CFF09100DFF0D1411FF232A27FF3C4340FF1B1D1DFF1F2121FF
+ 4D4F4FFF616363FF484A4AFF222424FF252727FF262828FF272929FF222424FF
+ 141616FF0F1111FF1A1C1CFF1E2020FF1F2121FF262828FF131614FF000301FF
+ 0D100EFF1D201EFF111412FF141715FF2C2F2DFF343735FF444745FF404341FF
+ 343735FF323533FF323533FF272A28FF2B2E2CFF454846FF2E3331FF393E3CFF
+ 383D3BFF3A3F3DFF4D5250FF595E5CFF5C615FFF626765FF595E5CFF4B504EFF
+ 4F5452FF4D5250FF545957FF535856FF505553FF353A38FF2F3432FF363B39FF
+ 2F3432FF2D3230FF474C4AFF626765FF686D6BFF656A68FF3D4240FF3C413FFF
+ 414644FF242927FF171C1AFF141917FF2B302EFF292E2CFF323533FF2B2E2CFF
+ 181B19FF292C2AFF3A3D3BFF3F4240FF4E514FFF494C4AFF6A6D6BFF727573FF
+ 6C6F6DFF626563FF464947FF2C2F2DFF313432FF363937FF3A3D3BFF323533FF
+ 373A38FF3C3F3DFF393C3AFF454846FF555856FF545755FF5E615FFF5A5D5BFF
+ 5A5D5BFF4E514FFF404341FF505351FF6D706EFF797C7AFF6C6F6DFF525553FF
+ 595C5AFF2D302EFF343735FF373A38FF3A3D3BFF242725FF212422FF484B49FF
+ 4D504EFF2D302EFF262927FF1D201EFF373A38FF3A3F3DFF1A211CFF131D17FF
+ 18221CFF27312BFF2D3731FF2F3933FF3F4943FF56605AFF56605AFF727C76FF
+ 59635DFF78827CFF656F69FF737D77FF7A847EFF5C635EFF6A706BFF5E625DFF
+ 757974FF5B5F5AFF5D615CFF626661FF686C67FF5E625DFF4E524DFF4B4F4AFF
+ 545853FF585C57FF565A55FF616560FF696D68FF5F635EFF5A605BFF717772FF
+ 6B716CFF7F8580FF747A75FF7E847FFF5F6560FF5C625DFF686E69FF5F6560FF
+ 606661FF5F6560FF474D48FF2C322DFF303631FF474D48FF5A5F5DFF555A58FF
+ 464B49FF444947FF515654FF575C5AFF5C615FFF6B706EFF5A5F5DFF5E6361FF
+ 626765FF666B69FF616560FF717570FF7B7F7AFF838782FF868A85FF767A75FF
+ 656964FF686C67FF6C706BFF787C77FF616560FF5B5F5AFF7D817CFF6E726DFF
+ 888C87FF858984FF7D807EFF797C7AFF7D807EFF7B7E7CFF5D605EFF727573FF
+ 656866FF6A6D6BFF565957FF626563FF6C6F6DFF717472FF757876FF6B6E6CFF
+ 848785FF8D908EFF878A88FF8F9290FF898C8AFF808381FF818482FF7B7E7CFF
+ 6D706EFF666967FF4B4E4CFF545755FF686B69FF777A78FF727573FF828583FF
+ 5F6260FF656866FF595B5BFF545657FF484A4BFF5E6061FF37393AFF484A4BFF
+ 363839FF2C2E2FFF6F7172FF6B6D6EFF5B5D5EFF525455FF464849FF5A5C5DFF
+ 4D4F50FF6A6C6CFF686B69FF6D706EFF6B6E6CFF717472FF606361FF636664FF
+ 707371FF3F4240FF2A2D2BFF272A28FF252826FF282B29FF2F3230FF303331FF
+ 262927FF191C1AFF141616FF242627FF303233FF1E2021FF2D2F30FF292B2CFF
+ 363839FF202223FF27292AFF2D2F30FF1B1D1EFF1E2021FF454748FF686A6BFF
+ 505253FF2B302FFF3E4341FF525956FF616865FF656C69FF6B726FFF747B78FF
+ 737A77FF69706DFF5B625FFF4E5552FF424946FF373E3BFF383F3CFF353C39FF
+ 343B38FF474E4BFF525956FF3F4643FF3F4643FF444B48FF333A37FF242B28FF
+ 282F2CFF2E3532FF343B38FF39403DFF373E3BFF333A37FF1E2522FF1C2320FF
+ 3A413EFF414845FF2B2D2DFF37393AFF464849FF535556FF383A3BFF262829FF
+ 202223FF2F3132FF262829FF202223FF212324FF232526FF232526FF2C2E2FFF
+ 363839FF333535FF101311FF080B09FF101311FF171A18FF111412FF141715FF
+ 212422FF262927FF0D100EFF303331FF484B49FF4A4D4BFF343735FF0B0E0CFF
+ 090C0AFF343735FF424745FF4B504EFF444947FF3D4240FF484D4BFF515654FF
+ 585D5BFF646967FF535856FF353A38FF444947FF3A3F3DFF464B49FF393E3CFF
+ 505553FF414644FF393E3CFF3A3F3DFF414644FF414644FF3F4442FF464B49FF
+ 494E4CFF3E4341FF4E5351FF464B49FF424745FF323735FF494E4CFF3E4341FF
+ 424745FF3D4240FF363838FF414343FF3C3E3EFF424444FF3C3E3EFF393B3BFF
+ 5A5C5CFF6B6D6DFF5F6161FF656767FF747676FF757777FF696B6BFF5B5D5DFF
+ 555757FF5F6161FF575959FF404242FF373939FF2F3131FF212323FF2B2D2DFF
+ 383A3AFF2F3131FF4D4F4FFF696B6BFF818383FF797B7BFF525454FF3F4141FF
+ 494B4BFF474949FF434545FF424444FF5D5F5FFF4E5050FF3B3D3DFF373939FF
+ 353737FF373939FF2C2E2EFF2A2C2CFF353737FF1E2020FF343636FF2F3131FF
+ 292B2BFF262B29FF3B423DFF39433DFF434D47FF57615BFF646E68FF606A64FF
+ 545E58FF4B554FFF4C5650FF545E58FF5D6761FF6D7771FF66706AFF6B756FFF
+ 707A74FF666D68FF585E59FF494D48FF626661FF474B46FF434742FF4B4F4AFF
+ 5B5F5AFF535752FF464A45FF4D514CFF646863FF676B66FF555954FF5F635EFF
+ 777B76FF777B76FF3B413CFF313732FF383E39FF535954FF5E645FFF6D736EFF
+ 727873FF737974FF444A45FF3E443FFF454B46FF484E49FF3A403BFF313732FF
+ 343A35FF363C37FF383D3BFF555A59FF515655FF343938FF2F3433FF424746FF
+ 575C5BFF656A69FF444948FF444948FF464B4AFF4A4F4EFF787C77FF8A8E89FF
+ 8D918CFF888C87FF888C87FF7E827DFF6C706BFF656964FF5E625DFF575B56FF
+ 757974FF626661FF959994FF979B96FF70746FFF888C87FF949795FF848785FF
+ 717472FF626563FF464947FF6F7270FF6D706EFF777A78FF676A68FF7A7D7BFF
+ 696C6AFF7A7D7BFF828583FF838684FF8B8E8CFF707371FF707371FF818482FF
+ 7B7E7CFF797C7AFF8E918FFF919492FF838684FF838684FF767977FF6A6D6BFF
+ 717472FF6C6F6DFF575A58FF6C6F6DFF454846FF3B3E3CFF464848FF343636FF
+ 393B3CFF3D3F3FFF333536FF3B3D3DFF464849FF373939FF4B4D4EFF393B3BFF
+ 2E3031FF404242FF464849FF5E6060FF656768FF9D9F9FFF898C8AFF8C8F8DFF
+ 8C8F8DFF888B89FF5C5F5DFF5D605EFF7D807EFF4B4E4CFF353836FF262927FF
+ 202321FF272A28FF292C2AFF1F2220FF1B1E1CFF1F2220FF0A0C0CFF121414FF
+ 343637FF090B0BFF212324FF363838FF3E4041FF4C4E4EFF333536FF333535FF
+ 393B3CFF242626FF3B3D3EFF404242FF565859FF4F5453FF3D4240FF414644FF
+ 545957FF6A6F6DFF696E6CFF535856FF444947FF434846FF4E5351FF4C514FFF
+ 282D2BFF3E4341FF474C4AFF181D1BFF141917FF1A211EFF3B423FFF161D1AFF
+ 131A17FF313835FF424946FF484F4CFF535A57FF5A615EFF323936FF434A47FF
+ 434A47FF59605DFF4F5653FF3E4542FF4D5451FF373E3BFF2D3231FF414343FF
+ 353738FF3C3E3EFF2C2E2FFF373939FF2C2E2FFF3C3E3EFF262829FF2A2C2CFF
+ 3E4041FF3C3E3EFF1E2021FF1C1E1EFF2C2E2FFF292B2BFF151816FF0D100EFF
+ 030604FF010402FF0C0F0DFF1A1D1BFF181B19FF0C0F0DFF1A1D1BFF1C1F1DFF
+ 1B1E1CFF303331FF464947FF2D302EFF141715FF212624FF313634FF3F4643FF
+ 3F4442FF373E3BFF3C413FFF3C4340FF3D4240FF444B48FF484D4BFF353C39FF
+ 616664FF505754FF4F5452FF282F2CFF515654FF505553FF434846FF3F4442FF
+ 4F5452FF545957FF454A48FF4E5351FF616664FF5C615FFF515654FF454A48FF
+ 3A3F3DFF2B302EFF525755FF414644FF404543FF444947FF565B5AFF626766FF
+ 616665FF6D7271FF676C6BFF565B5AFF5D6261FF5A5F5EFF4C5150FF474C4BFF
+ 5E6362FF636867FF646968FF646968FF575C5BFF636867FF686D6CFF454A48FF
+ 373C3BFF373C3AFF343938FF3F4442FF3B403FFF1B201EFF272C2BFF3B403EFF
+ 4E5352FF595E5CFF4D5251FF474C4AFF4B504FFF383D3BFF4A4C4CFF3F4240FF
+ 4A4C4CFF606361FF454747FF474A48FF282A2AFF2C2F2DFF1D1F1FFF1A1D1BFF
+ 414343FF2C2F2DFF3D3F3FFF343735FF3C3E3EFF626765FF4C534EFF606A64FF
+ 7D847FFF86908AFF808782FF6C7670FF5B625DFF4E5852FF6C736EFF545E58FF
+ 878E89FF79837DFF7C837EFF6A746EFF666D68FF717873FF636964FF424641FF
+ 60645FFF595D58FF4B4F4AFF343833FF3B3F3AFF3F433EFF363A35FF40443FFF
+ 5A5E59FF575B56FF393D38FF434742FF666A65FF6E746FFF6F7570FF353C37FF
+ 343A35FF383F3AFF4B514CFF484F4AFF707671FF777E79FF666C67FF585F5AFF
+ 454B46FF29302BFF1E241FFF313833FF414742FF333A35FF383F3CFF49504DFF
+ 59605DFF616865FF555C59FF363D3AFF303734FF484F4CFF2D3431FF2A302FFF
+ 292F2EFF2C3231FF747775FF757876FF737674FF8A8D8BFF767977FF6F7270FF
+ 636664FF747775FF717472FF797C7AFF7F8280FF939694FF787B79FF999C9AFF
+ 6B6E6CFF787B79FF8D9290FF898E8CFF808583FF808583FF585D5BFF494E4CFF
+ 6C716FFF5A5F5DFF585D5BFF717674FF6A6F6DFF737876FF838886FF858A88FF
+ 888D8BFF7D8280FF7C817FFF707573FF858A88FF6A6F6DFF868B89FF727775FF
+ 999E9CFFA1A6A4FF7B807EFF717674FF646967FF5C615FFF5E6361FF5C615FFF
+ 4E5351FF3C413FFF323735FF1B201EFF313635FF323735FF212625FF292E2CFF
+ 292E2DFF282D2BFF404544FF555A58FF373C3BFF2C312FFF565B5AFF585D5BFF
+ 606564FF9EA3A1FF7B807EFF6E7371FF888D8BFF8F9492FF5F6462FF494E4CFF
+ 575C5AFF585D5BFF5D6260FF525755FF3A3F3DFF090E0CFF454A48FF353A38FF
+ 373C3AFF2F3432FF292E2CFF3C413FFF242928FF525755FF454A49FF515654FF
+ 616665FF313634FF4D5251FF494E4CFF3F4443FF353A38FF353A39FF3B403EFF
+ 3D4241FF3A3F3DFF4D504EFF595C5AFF585B59FF444745FF6B6E6CFF595C5AFF
+ 3C3F3DFF1E211FFF444745FF535654FF484B49FF272A28FF2B2E2CFF242725FF
+ 040705FF141917FF262D2AFF353E3BFF27302DFF222B28FF3A4340FF3E4744FF
+ 4C5552FF7C8582FF646D6AFF707976FF6E7774FF6C7572FF48514EFF606966FF
+ 4E5754FF2D3431FF434846FF545957FF454A49FF353A38FF454A49FF4B504EFF
+ 3C4140FF373C3AFF2A2F2EFF303533FF2D3231FF434846FF282D2CFF1F2422FF
+ 090E0DFF131816FF191E1CFF0B100EFF040907FF0C110FFF191E1CFF1D2220FF
+ 1D2220FF1D2220FF1D2220FF232826FF1B201EFF0F1412FF1C211FFF3C413FFF
+ 4C514FFF474C4AFF3D4441FF47504DFF404744FF37403DFF39403DFF2A3330FF
+ 464D4AFF8A9390FF646B68FF39423FFF49504DFF565F5CFF4D5451FF434C49FF
+ 3A413EFF3B423FFF404543FF424745FF383D3BFF4C514FFF3C413FFF4E5351FF
+ 565B59FF727775FF6E7371FF7B807EFF5F6462FF4A4F4DFF2B302EFF404543FF
+ 2C312FFF1B201EFF353C39FF5E6562FF636A67FF747B78FF363D3AFF535A57FF
+ 4C5350FF585F5CFF646B68FF49504DFF636A67FF6D7471FF777E7BFF606764FF
+ 676E6BFF545B58FF606764FF525954FF484F4CFF49504BFF4D5451FF4F5651FF
+ 565D5AFF5F6661FF5D6461FF252C27FF141B18FF313833FF484F4CFF505752FF
+ 3C4340FF161D18FF242927FF1B211CFF0A0F0DFF333934FF434846FF2C322DFF
+ 373C3AFF323833FF313634FF393F3AFF494E4CFF5B615CFF444947FF4F5550FF
+ 6F7472FF5E645FFF4E544FFF555C57FF717772FF616863FF666C67FF7E8580FF
+ 777D78FF7E8580FF666C67FF868D88FF838984FF787F7AFF8F9590FFB1B8B3FF
+ 737974FF6F7570FF414742FF4D534EFF454B46FF505651FF3C423DFF4C524DFF
+ 434944FF4B514CFF3A403BFF4C524DFF3D433EFF464C47FF464C47FF3F4540FF
+ 555B56FF4A504BFF454C47FF646E68FF4F5651FF3D4741FF343B36FF4F5953FF
+ 525954FF68726CFF727974FF79837DFF6C736EFF6F7973FF606762FF5F6963FF
+ 5C635EFF76807AFF5B6860FF404F47FF324139FF43524AFF6C7A74FF606E68FF
+ 67756FFF505E58FF42504AFF4F5D59FF566460FF4E5C58FF797C7AFF797C7AFF
+ 676A68FF696C6AFF585B59FF656866FF5D605EFF636664FF686B69FF666967FF
+ 666967FF717472FF646765FF858886FF6C6F6DFF7C7F7DFF5B605EFF767B79FF
+ 6F7472FF6F7472FF626765FF4F5452FF646967FF6D7270FF707573FF7F8482FF
+ 737876FF7A7F7DFF808583FF797E7CFF8C918FFF9A9F9DFF9CA19FFF8A8F8DFF
+ 959A98FF787D7BFF8E9391FF757A78FF8E9391FF8C918FFF6A6F6DFF6C716FFF
+ 6B706EFF696E6CFF676C6AFF606563FF4F5452FF3D4240FF3F4442FF242927FF
+ 303533FF2C312FFF222725FF313634FF373C3AFF3C413FFF2C312FFF3B403EFF
+ 3D4240FF303533FF5E6361FF444947FF484D4BFF666B69FF5D6260FF4E5351FF
+ 535856FF5A5F5DFF585D5BFF616664FF676C6AFF5B605EFF3F4442FF585D5BFF
+ 565B59FF363B39FF494E4CFF4D5250FF515654FF4E5351FF3F4442FF4E5351FF
+ 474C4AFF585D5BFF3C413FFF363B39FF4D5250FF393E3CFF353A38FF444947FF
+ 505553FF4F5452FF4A4F4DFF4A4F4DFF4E5351FF4F5452FF515452FF5F605EFF
+ 5F605EFF575856FF6B6C6AFF616260FF5C5D5BFF636462FF434442FF484947FF
+ 444543FF2C2D2BFF323331FF313230FF181917FF202321FF242B28FF3B4441FF
+ 3D4643FF434C49FF565F5CFF48514EFF3A4340FF515A57FF59625FFF606966FF
+ 666F6CFF6F7875FF606966FF5A6360FF3A4340FF1A2320FF1E2321FF2A2F2DFF
+ 2E3331FF363B39FF4D5250FF565B59FF494E4CFF3C413FFF404543FF424745FF
+ 2E3331FF282D2BFF0B100EFF131816FF0C110FFF141917FF0D1210FF0E1311FF
+ 111614FF131816FF171C1AFF1D2220FF232826FF272C2AFF242927FF232826FF
+ 2E3331FF444947FF505553FF515654FF515654FF555C59FF4F5653FF47504DFF
+ 3B4441FF2C3532FF29322FFF3B4441FF49524FFF444D4AFF353E3BFF303936FF
+ 414A47FF3C4542FF414A47FF58615EFF4C5552FF3E4744FF474C4AFF5C615FFF
+ 585D5BFF545957FF333836FF3E4341FF404543FF4F5452FF676C6AFF838886FF
+ 868B89FF848987FF5D6260FF575C5AFF444947FF434A47FF252C29FF3B4441FF
+ 4D5653FF6E7774FF4D5653FF565F5CFF454E4BFF444D4AFF47504DFF4B5451FF
+ 616A67FF59625FFF6F7875FF78817EFF88918EFF737C79FF78827CFF6D7771FF
+ 656F69FF68726CFF6D7771FF6E7872FF727C76FF78827CFF909A94FF636D67FF
+ 39433DFF222C26FF18221CFF1F2923FF2B352FFF2E3832FF202621FF272D28FF
+ 252B26FF313732FF363C37FF313732FF373D38FF323833FF595F5AFF656B66FF
+ 464C47FF4C524DFF656B66FF575D58FF525853FF5D635EFF535954FF4B514CFF
+ A1A7A2FF6D736EFFAFB5B0FF7D837EFF929893FF7A807BFF777D78FF9DA39EFF
+ 9DA39EFF676D68FF7F8580FF999F9AFF6B716CFF505651FF5A605BFF424843FF
+ 202621FF313732FF3B413CFF565C57FF454B46FF3C423DFF444A45FF5B615CFF
+ 4D534EFF333934FF2A302BFF3D433EFF5A605BFF555C57FF49504BFF616B65FF
+ 6F7973FF66706AFF68726CFF616B65FF5D6761FF59635DFF6C7670FF6E7872FF
+ 555F59FF555F59FF4B554FFF5D6761FF6A746EFF8E9B93FF697870FF5D6E63FF
+ 4E5E53FF47584DFF67766EFF6A7B72FF84938BFF708178FF7B8983FF6E7E77FF
+ 5C6A66FF4D5C58FF797C7AFF838684FF737674FF6E716FFF5B5E5CFF676A68FF
+ 4E514FFF3D403EFF2A2D2BFF303331FF3F4240FF444745FF3F4240FF535654FF
+ 555856FF6C6F6DFF808583FF878C8AFF595E5CFF505553FF6B706EFF676C6AFF
+ 666B69FF737876FF707573FF717674FF646967FF7D8280FF909593FF7B807EFF
+ 727775FF6E7371FF767B79FF606563FF626765FF484D4BFF5C615FFF464B49FF
+ 585D5BFF545957FF575C5AFF585D5BFF535856FF4B504EFF474C4AFF464B49FF
+ 424745FF3C413FFF3C413FFF212624FF262B29FF222725FF1F2422FF2F3432FF
+ 323735FF393E3CFF3F4442FF393E3CFF494E4CFF373C3AFF5E6361FF3D4240FF
+ 4A4F4DFF515654FF363B39FF4A4F4DFF555A58FF5B605EFF666B69FF656A68FF
+ 555A58FF474C4AFF5A5F5DFF676C6AFF565B59FF3E4341FF393E3CFF545957FF
+ 515654FF414644FF363B39FF3D4240FF585D5BFF5D6260FF4E5351FF363B39FF
+ 3D4240FF353A38FF434846FF3D4240FF343937FF343937FF3F4442FF4B504EFF
+ 4A4F4DFF424745FF464947FF4A4D4BFF434644FF494C4AFF3F4240FF393C3AFF
+ 474A48FF767977FF5F6260FF515452FF4B4E4CFF353836FF343735FF424543FF
+ 3C3F3DFF444947FF565D5AFF626B68FF5A6360FF565F5CFF5B6461FF3E4744FF
+ 1E2724FF212A27FF27302DFF262F2CFF303936FF3F4845FF5F6865FF58615EFF
+ 4E5754FF47504DFF303533FF222725FF181D1BFF0F1412FF070C0AFF121715FF
+ 242927FF292E2CFF222725FF383D3BFF393E3CFF353A38FF222725FF262B29FF
+ 141917FF060B09FF1A1F1DFF242927FF232826FF141917FF0D1210FF191E1CFF
+ 2B302EFF353A38FF5B605EFF585D5BFF5D6260FF6B706EFF717674FF6D7270FF
+ 6D7270FF717875FF4C5350FF3D4643FF434C49FF353E3BFF1B2421FF303936FF
+ 424B48FF242D2AFF323B38FF47504DFF545D5AFF3C4542FF414A47FF58615EFF
+ 4C5552FF4A5350FF464B49FF3D4240FF3F4442FF565B59FF393E3CFF222725FF
+ 303533FF666B69FF565B59FF666B69FF737876FF878C8AFF747977FF656A68FF
+ 4C514FFF484F4CFF3D4441FF2D3633FF333C39FF49524FFF4B5451FF4C5552FF
+ 49524FFF434C49FF444D4AFF505956FF545D5AFF424B48FF565F5CFF5C6562FF
+ 646D6AFF5F6865FF7A847EFF707A74FF69736DFF6A746EFF6C7670FF6C7670FF
+ 6B756FFF6C7670FF747E78FF7A847EFF6D7771FF57615BFF4A544EFF404A44FF
+ 39433DFF3D4741FF383E39FF474D48FF515752FF373D38FF2C322DFF3B413CFF
+ 3C423DFF3E443FFF1F2520FF404641FF3B413CFF4D534EFF797F7AFF6D736EFF
+ 5D635EFF515752FF828883FF737974FF868C87FF777D78FF8A908BFF8D938EFF
+ 9FA5A0FFB1B7B2FF8A908BFF868C87FF8D938EFF707671FF939994FF858B86FF
+ 7D837EFF898F8AFF5F6560FF535954FF414742FF4A504BFF404641FF3F4540FF
+ 313732FF353B36FF222823FF343A35FF464C47FF343A35FF2E342FFF474D48FF
+ 5B615CFF6E7570FF6B726DFF5D6761FF727C76FF6F7973FF838D87FF6B756FFF
+ 646E68FF444E48FF616B65FF68726CFF555F59FF58625CFF4B554FFF525C56FF
+ 4D5751FF646F67FF4F5C54FF58685DFF526055FF3A4A3FFF4B5850FF4B5A52FF
+ 66736BFF4C5B53FF5B6761FF4B5953FF3A4542FF2F3D39FF6F7270FF7F8280FF
+ 7A7D7BFF808381FF6D706EFF707371FF4F5250FF3A3D3BFF262927FF282B29FF
+ 3B3E3CFF4A4D4BFF5B5E5CFF5E615FFF595C5AFF585B59FF575C5AFF4B504EFF
+ 282D2BFF2A2F2DFF515654FF606563FF5E6361FF606563FF787D7BFF747977FF
+ 555A58FF5A5F5DFF686D6BFF616664FF666B69FF656A68FF747977FF626765FF
+ 616664FF4C514FFF5A5F5DFF4A4F4DFF595E5CFF585D5BFF5E6361FF5C615FFF
+ 545957FF4B504EFF484D4BFF4B504EFF4A4F4DFF454A48FF454A48FF323735FF
+ 3B403EFF3B403EFF3E4341FF474C4AFF3C413FFF404543FF414644FF313634FF
+ 3C413FFF3A3F3DFF484D4BFF393E3CFF474C4AFF464B49FF474C4AFF505553FF
+ 3C413FFF343937FF4D5250FF525755FF4E5351FF626765FF5F6462FF5A5F5DFF
+ 585D5BFF4E5351FF515654FF616664FF696E6CFF575C5AFF585D5BFF484D4BFF
+ 676C6AFF676C6AFF787D7BFF616664FF575C5AFF4F5452FF4A4F4DFF3B403EFF
+ 292E2CFF272C2AFF393E3CFF4D5250FF4F5452FF474C4AFF3B3E3CFF3E413FFF
+ 444745FF6A6D6BFF505351FF3E413FFF3A3D3BFF6A6D6BFF787B79FF666967FF
+ 676A68FF515452FF3E413FFF444745FF424543FF474C4AFF5A615EFF616A67FF
+ 5E6764FF636C69FF717A77FF67706DFF535C59FF525B58FF444D4AFF434C49FF
+ 444D4AFF3E4744FF6E7774FF69726FFF707976FF767F7CFF7B807EFF696E6CFF
+ 626765FF474C4AFF131816FF040907FF1A1F1DFF252A28FF2F3432FF383D3BFF
+ 363B39FF303533FF282D2BFF2F3432FF2D3230FF2A2F2DFF2A2F2DFF313634FF
+ 282D2BFF111614FF0D1210FF242927FF3A3F3DFF414644FF545957FF636866FF
+ 666B69FF5C615FFF616664FF727775FF737876FF666B69FF6D7471FF5B6461FF
+ 626B68FF656E6BFF535C59FF515A57FF5D6663FF5B6461FF4E5754FF49524FFF
+ 424B48FF3D4643FF616A67FF78817EFF646D6AFF6F7673FF656A68FF4F5452FF
+ 535856FF6F7472FF595E5CFF2E3331FF303533FF5C615FFF696E6CFF616664FF
+ 5F6462FF747977FF848987FF868B89FF6D7270FF585F5CFF6A716EFF49524FFF
+ 424B48FF38413EFF4B5451FF4D5653FF59625FFF464F4CFF47504DFF49524FFF
+ 464F4CFF515A57FF6D7673FF656E6BFF656E6BFF7C8582FF76807AFF6E7872FF
+ 66706AFF67716BFF6D7771FF707A74FF717B75FF6F7973FF5F6963FF747E78FF
+ 67716BFF545E58FF5E6862FF616B65FF58625CFF5A645EFF5F6560FF676D68FF
+ 797F7AFF535954FF454B46FF5F6560FF5E645FFF6E746FFF666C67FF6E746FFF
+ 7D837EFF767C77FF757B76FF878D88FFACB2ADFF7F8580FF797F7AFF808681FF
+ 5D635EFF8D938EFF525853FF737974FF494F4AFF696F6AFF7D837EFF676D68FF
+ 696F6AFF757B76FF919792FF7D837EFF8A908BFFB5BBB6FF9DA39EFF797F7AFF
+ 5C625DFF676D68FF727873FF6B716CFF4F5550FF3E443FFF1A201BFF0D130EFF
+ 2F3530FF383E39FF363C37FF3A403BFF3E443FFF707671FF7A817CFF5F6963FF
+ 6E7872FF737D77FF76807AFF6F7973FF7F8983FF747E78FF646E68FF737D77FF
+ 68726CFF6E7872FF5B655FFF515B55FF333D37FF364139FF37423AFF4D5B50FF
+ 5B665CFF4F5D52FF5A655DFF47544CFF535E56FF334038FF4B554FFF535F59FF
+ 5D6663FF5B6663FF636664FF6C6F6DFF696C6AFF7B7E7CFF6D706EFF717472FF
+ 616462FF626563FF5F6260FF4F5250FF4A4D4BFF616462FF7A7D7BFF6F7270FF
+ 535654FF333634FF242927FF272C2AFF494E4CFF5C615FFF555A58FF565B59FF
+ 535856FF444947FF444947FF6C716FFF666B69FF545957FF464B49FF3F4442FF
+ 555A58FF5E6361FF5E6361FF575C5AFF5D6260FF515654FF525755FF3E4341FF
+ 3F4442FF3D4240FF4F5452FF525755FF525755FF525755FF535856FF4E5351FF
+ 3D4240FF2C312FFF3C413FFF323735FF3B403EFF3D4240FF474C4AFF4C514FFF
+ 3A3F3DFF404543FF4B504EFF454A48FF494E4CFF686D6BFF595E5CFF636866FF
+ 5D6260FF5D6260FF575C5AFF555A58FF484D4BFF686D6BFFA1A6A4FF979C9AFF
+ 777C7AFF848987FF616664FF5E6361FF898E8CFF848987FF898E8CFF606563FF
+ 707573FF6D7270FF878C8AFF696E6CFF6B706EFF5A5F5DFF717674FF626765FF
+ 5E6361FF616664FF484D4BFF4F5452FF4E5351FF424745FF363B39FF333836FF
+ 363B39FF383D3BFF313432FF333634FF4D504EFF8E918FFF7E817FFF646765FF
+ 494C4AFF5C5F5DFF676A68FF636664FF777A78FF676A68FF494C4AFF3F4240FF
+ 353836FF393E3CFF353C39FF3D4643FF47504DFF565F5CFF6A7370FF6E7774FF
+ 666F6CFF616A67FF424B48FF4E5754FF4F5855FF3A4340FF626B68FF636C69FF
+ 6C7572FF6C7572FF616664FF656A68FF7F8482FF7F8482FF505553FF292E2CFF
+ 181D1BFF060B09FF484D4BFF3D4240FF393E3CFF363B39FF373C3AFF303533FF
+ 383D3BFF414644FF292E2CFF323735FF323735FF2A2F2DFF323735FF464B49FF
+ 4A4F4DFF404543FF1B201EFF353A38FF4B504EFF555A58FF666B69FF777C7AFF
+ 6F7472FF595E5CFF858C89FF7E8582FF6B726FFF6F7673FF858C89FF7F8683FF
+ 737A77FF7E8582FF6C7370FF484F4CFF222926FF1C2320FF585F5CFF7A817EFF
+ 535A57FF404744FF404543FF535856FF636866FF5E6361FF606563FF5C615FFF
+ 4D5250FF333836FF626765FF686D6BFF6B706EFF676C6AFF737876FF7D8280FF
+ 7E8381FF707774FF787F7CFF6B7471FF717A77FF535C59FF636C69FF626B68FF
+ 69726FFF424B48FF545D5AFF59625FFF555E5BFF6B7471FF848D8AFF7F8885FF
+ 727B78FF868F8CFF69736DFF626C66FF5B655FFF5D6761FF68726CFF747E78FF
+ 79837DFF78827CFF747E78FF88928CFF77817BFF606A64FF6B756FFF76807AFF
+ 717B75FF757F79FF757B76FF727873FF8A908BFF7B817CFF767C77FF878D88FF
+ 838984FF999F9AFF858B86FF7A807BFF858B86FF7D837EFF7C827DFF777D78FF
+ 9BA19CFF747A75FF686E69FF6B716CFF6B716CFF8A908BFF7A807BFF6B716CFF
+ 585E59FF5E645FFF595F5AFF646A65FF5A605BFF686E69FF676D68FF747A75FF
+ 767C77FF818782FF9CA29DFF787E79FF5B615CFF585E59FF6A706BFF6C726DFF
+ 6A706BFF656B66FF646A65FF424843FF4C524DFF494F4AFF434944FF3F4540FF
+ 383E39FF616762FF747B76FF717873FF7B827DFF888F8AFF5E6560FF5B625DFF
+ 69706BFF7A817CFF777E79FF828984FF737A75FF777E79FF6B726DFF6B726DFF
+ 515853FF535B54FF404841FF4E594FFF60695FFF667167FF79817AFF5F6A62FF
+ 69716AFF4F5A52FF4F5651FF5E6862FF6F7673FF6E7774FF5C5F5DFF646765FF
+ 646765FF7C7F7DFF717472FF777A78FF6B6E6CFF727573FF737674FF727573FF
+ 5D605EFF666967FF525553FF393C3AFF2C2F2DFF232624FF1F2422FF1B201EFF
+ 515654FF646967FF4C514FFF484D4BFF393E3CFF1E2321FF0D1210FF454A48FF
+ 505553FF474C4AFF3E4341FF353A38FF373C3AFF2A2F2DFF434846FF494E4CFF
+ 595E5CFF5E6361FF5B605EFF454A48FF3A3F3DFF333836FF373C3AFF343937FF
+ 2E3331FF2A2F2DFF2B302EFF292E2CFF1C211FFF0D1210FF1D2220FF181D1BFF
+ 1C211FFF191E1CFF282D2BFF2E3331FF1E2321FF2F3432FF333836FF313634FF
+ 242927FF4A4F4DFF2F3432FF4C514FFF454A48FF565B59FF626765FF535856FF
+ 3A3F3DFF4C514FFF747977FF6C716FFF686D6BFF929795FF737876FF5D6260FF
+ 7D8280FF797E7CFF939896FF545957FF585D5BFF585D5BFF727775FF727775FF
+ 666B69FF575C5AFF5C615FFF494E4CFF4C514FFF545957FF575C5AFF575C5AFF
+ 515654FF484D4BFF444947FF474C4AFF4A4F4DFF494E4CFF4B4E4CFF343735FF
+ 3D403EFF686B69FF646765FF595C5AFF4F5250FF535654FF505351FF555856FF
+ 676A68FF5A5D5BFF4A4D4BFF494C4AFF4E514FFF6B706EFF424946FF3F4845FF
+ 3B4441FF37403DFF39423FFF434C49FF49524FFF49524FFF3A4340FF404946FF
+ 3A4340FF27302DFF3F4845FF57605DFF6E7774FF737C79FF717674FF737876FF
+ 828785FF8D9290FF868B89FF787D7BFF626765FF494E4CFF505553FF3F4442FF
+ 414644FF404543FF484D4BFF373C3AFF414644FF4B504EFF373C3AFF454A48FF
+ 535856FF5B605EFF616664FF606563FF4C514FFF343937FF1F2422FF1E2321FF
+ 2D3230FF4C514FFF636866FF676C6AFF626765FF606563FF606764FF7A817EFF
+ 69706DFF575E5BFF6B726FFF6D7471FF646B68FF767D7AFF787F7CFF6F7673FF
+ 575E5BFF303734FF424946FF646B68FF474E4BFF282F2CFF1F2422FF292E2CFF
+ 363B39FF313634FF505553FF636866FF6A6F6DFF545957FF323735FF585D5BFF
+ 777C7AFF5C615FFF494E4CFF434846FF606563FF6D7471FF717875FF747D7AFF
+ 7E8784FF59625FFF5F6865FF666F6CFF747D7AFF515A57FF69726FFF7E8784FF
+ 79827FFF7A8380FF79827FFF848D8AFF707976FF666F6CFF6A746EFF626C66FF
+ 57615BFF535D57FF5B655FFF66706AFF68726CFF626C66FF6E7872FF8C9690FF
+ 97A19BFF8F9993FF8E9892FF8F9993FF8C9690FF8B958FFF7D837EFF787E79FF
+ 898F8AFF8F9590FF8D938EFF878D88FF7F8580FF8C928DFF848A85FF7F8580FF
+ 787E79FF818782FFB5BBB6FF7C827DFF707671FF6D736EFF494F4AFF424843FF
+ 3D433EFF4B514CFF595F5AFF505651FF6B716CFF747A75FF515752FF5B615CFF
+ 4D534EFF737974FF686E69FF6D736EFF656B66FF646A65FF636964FF606661FF
+ 646A65FF535954FF555B56FF4F5550FF626863FF6A706BFF727873FF676D68FF
+ 636964FF555B56FF545A55FF595F5AFF494F4AFF434944FF646B66FF646B66FF
+ 656C67FF878E89FF747B76FF7B827DFF656C67FF636A65FF757C77FF818883FF
+ 727974FF7A817CFF777E79FF818883FF6A716CFF6A726BFF626962FF61695FFF
+ 60685EFF61695FFF757C75FF666D66FF787F78FF6A716AFF707671FF737974FF
+ 727775FF707573FF5A5D5BFF656866FF606361FF6E716FFF6C6F6DFF848785FF
+ 7C7F7DFF797C7AFF6C6F6DFF7E817FFF5F6260FF676A68FF2F3230FF1E211FFF
+ 2B2E2CFF454846FF464B49FF3F4442FF5C615FFF636866FF686D6BFF747977FF
+ 636866FF616664FF444947FF505553FF333836FF282D2BFF333836FF3A3F3DFF
+ 434846FF383D3BFF2F3432FF343937FF404543FF505553FF535856FF494E4CFF
+ 3C413FFF363B39FF3C413FFF353A38FF272C2AFF181D1BFF141917FF181D1BFF
+ 1A1F1DFF181D1BFF161B19FF161B19FF161B19FF0F1412FF1D2220FF1E2321FF
+ 0E1311FF252A28FF313634FF2F3432FF1F2422FF323735FF232826FF373C3AFF
+ 3B403EFF555A58FF474C4AFF565B59FF5C615FFF676C6AFF6B706EFF505553FF
+ 474C4AFF666B69FF5A5F5DFF444947FF434846FF4C514FFF7D8280FF5E6361FF
+ 505553FF525755FF535856FF787D7BFF5F6462FF666B69FF616664FF4F5452FF
+ 4E5351FF4C514FFF575C5AFF4B504EFF414644FF484D4BFF636866FF7A7F7DFF
+ 7C817FFF737876FF666B69FF3B403EFF313634FF2F3432FF303533FF323735FF
+ 474C4AFF444947FF3E4341FF484D4BFF4E5351FF404543FF434846FF494E4CFF
+ 525755FF838886FF5A615EFF535C59FF4B5451FF3D4643FF343D3AFF444D4AFF
+ 5B6461FF626B68FF757E7BFF616A67FF4A5350FF48514EFF444D4AFF616A67FF
+ 747D7AFF7C8582FF7D8280FF808583FF737876FF6B706EFF797E7CFF878C8AFF
+ 888D8BFF868B89FF707573FF585D5BFF4B504EFF2F3432FF3A3F3DFF383D3BFF
+ 535856FF5D6260FF464B49FF515654FF5D6260FF626765FF5D6260FF515654FF
+ 454A48FF3E4341FF515654FF373C3AFF242927FF2A2F2DFF3A3F3DFF444947FF
+ 4B504EFF505553FF49504DFF5A615EFF636A67FF5F6663FF59605DFF575E5BFF
+ 666D6AFF7E8582FF757C79FF808784FF909794FF747B78FF646B68FF787F7CFF
+ 707774FF616865FF4C514FFF393E3CFF3B403EFF353A38FF505553FF505553FF
+ 696E6CFF727775FF454A48FF5C615FFF7C817FFF666B69FF575C5AFF3F4442FF
+ 585D5BFF686F6CFF69706DFF67706DFF68716EFF4B5451FF464F4CFF59625FFF
+ 77807DFF707976FF6A7370FF7E8784FF858E8BFF8F9895FF7B8481FF929B98FF
+ 8F9895FF88918EFF8D9791FF858F89FF77817BFF6D7771FF707A74FF76807AFF
+ 707A74FF646E68FF707A74FF78827CFF848E88FF828C86FF7B857FFF858F89FF
+ 949E98FF949E98FF878D88FF8A908BFF848A85FF8C928DFF868C87FF757B76FF
+ 797F7AFF797F7AFFA1A7A2FF929893FF737974FF555B56FF808681FF4E544FFF
+ 535954FF515752FF4A504BFF525853FF333934FF505651FF434944FF4D534EFF
+ 575D58FF5F6560FF6E746FFF5E645FFF4E544FFF757B76FF787E79FF676D68FF
+ 707671FF6B716CFF6E746FFF656B66FF696F6AFF5F6560FF7E847FFF7C827DFF
+ 757B76FF555B56FF4F5550FF565C57FF4B514CFF4E544FFF565C57FF565C57FF
+ 4B514CFF2C322DFF414843FF3C433EFF363D38FF545B56FF7B827DFF8F9691FF
+ 828984FF79807BFF6C736EFF79807BFF6B726DFF767D78FF767D78FF808782FF
+ 656C67FF606760FF7A7E78FF7C8178FF70756CFF5E635AFF6F736DFF6C706AFF
+ 828680FF6D716BFF676B66FF646863FF5E615FFF5C5F5DFF5A5D5BFF616462FF
+ 484B49FF454846FF4F5250FF8C8F8DFF9A9D9BFF979A98FF666967FF686B69FF
+ 333634FF525553FF2F3230FF393C3AFF414442FF545755FF545957FF686D6BFF
+ 797E7CFF636866FF686D6BFF676C6AFF545957FF7D8280FF787D7BFF7C817FFF
+ 5F6462FF595E5CFF5B605EFF535856FF5D6260FF616664FF4A4F4DFF454A48FF
+ 434846FF515654FF575C5AFF595E5CFF505553FF4D5250FF383D3BFF3A3F3DFF
+ 353A38FF292E2CFF202523FF1E2321FF1E2321FF1D2220FF121715FF171C1AFF
+ 191E1CFF0F1412FF191E1CFF131816FF000100FF131816FF191E1CFF1F2422FF
+ 232826FF2B302EFF2E3331FF252A28FF252A28FF373C3AFF414644FF484D4BFF
+ 474C4AFF4C514FFF575C5AFF515654FF4B504EFF555A58FF474C4AFF585D5BFF
+ 515654FF5E6361FF737876FF5D6260FF3A3F3DFF464B49FF4C514FFF777C7AFF
+ 414644FF535856FF505553FF4A4F4DFF4B504EFF3F4442FF4F5452FF525755FF
+ 545957FF545957FF555A58FF515654FF424745FF323735FF474C4AFF242927FF
+ 272C2AFF151A18FF181D1BFF161B19FF2F3432FF1E2321FF2A2F2DFF3E4341FF
+ 464B49FF3A3F3DFF424745FF353A38FF232826FF4B524FFF555E5BFF59625FFF
+ 5F6865FF545D5AFF404946FF454E4BFF535C59FF505956FF5B6461FF3D4643FF
+ 2F3835FF505956FF404946FF545D5AFF555E5BFF58615EFF565B59FF777C7AFF
+ 767B79FF676C6AFF707573FF787D7BFF787D7BFF838886FF6F7472FF6C716FFF
+ 6D7270FF4B504EFF505553FF424745FF464B49FF333836FF3E4341FF414644FF
+ 434846FF3E4341FF333836FF313634FF444947FF5A5F5DFF7B807EFF696E6CFF
+ 434846FF262B29FF2E3331FF4C514FFF525755FF434846FF515855FF272E2BFF
+ 39403DFF646B68FF5F6663FF575E5BFF6D7471FF7C8380FF838A87FF676E6BFF
+ 7A817EFF828986FF777E7BFF727976FF5B625FFF484F4CFF3D4240FF4B504EFF
+ 5A5F5DFF3D4240FF4D5250FF535856FF686D6BFF5A5F5DFF7E8381FF686D6BFF
+ 6F7472FF6C716FFF7F8482FF636866FF656A68FF616865FF5F6663FF5A6360FF
+ 5A6360FF4F5855FF454E4BFF565F5CFF757E7BFF808986FF6C7572FF6B7471FF
+ 78817EFF98A19EFF747D7AFF7E8784FF89928FFF9CA5A2FF9AA49EFF959F99FF
+ 8B958FFF848E88FF88928CFF8E9892FF86908AFF78827CFF858F89FF79837DFF
+ 838D87FF8C9690FF838D87FF88928CFF88928CFF727C76FF8F9590FF9AA09BFF
+ 828883FF848A85FF7E847FFF757B76FF8F9590FF8A908BFF848A85FF808681FF
+ 8A908BFF555B56FF4D534EFF3D433EFF656B66FF2B312CFF353B36FF363C37FF
+ 191F1AFF242A25FF2D332EFF363C37FF5D635EFF626863FF888E89FF828883FF
+ 6A706BFF505651FF606661FF626863FF7F8580FF4F5550FF636964FF6E746FFF
+ 7D837EFF646A65FF757B76FF757B76FF848A85FF737974FF7A807BFF6E746FFF
+ 4B514CFF5D635EFF646A65FF525853FF595F5AFF484E49FF2F3631FF2F3631FF
+ 252C27FF080F0AFF282F2AFF2A312CFF444B46FF5A615CFF717873FF787F7AFF
+ 616863FF656C67FF676E69FF787F7AFF636A65FF626962FF5F635DFF75786FFF
+ 71746BFF575A51FF686A64FF6D6F69FF80827CFF5D5F59FF5B5C58FF61625EFF
+ 646563FF5F605EFF303331FF4B4E4CFF5F6260FF3C3F3DFF515452FF505351FF
+ 626563FF959896FF595C5AFF5A5D5BFF424543FF4E514FFF454846FF4F5250FF
+ 474A48FF616462FF707573FF787D7BFF686D6BFF353A38FF333836FF1B201EFF
+ 1B201EFF202523FF505553FF535856FF6E7371FF595E5CFF535856FF535856FF
+ 7A7F7DFF797E7CFF6D7270FF848987FF696E6CFF8B908EFF717674FF696E6CFF
+ 494E4CFF848987FF888D8BFF656A68FF676C6AFF737876FF575C5AFF424745FF
+ 4E5351FF5B605EFF4A4F4DFF212624FF202523FF2E3331FF151A18FF000402FF
+ 0A0F0DFF151A18FF282D2BFF2F3432FF383D3BFF2F3432FF1E2321FF262B29FF
+ 353A38FF333836FF222725FF383D3BFF2D3230FF3E4341FF434846FF303533FF
+ 3D4240FF3D4240FF4B504EFF2D3230FF4B504EFF565B59FF494E4CFF5A5F5DFF
+ 636866FF616664FF676C6AFF6A6F6DFF5C615FFF595E5CFF6A6F6DFF626765FF
+ 4C514FFF4A4F4DFF5A5F5DFF4F5452FF4E5351FF363B39FF4A4F4DFF404543FF
+ 414644FF282D2BFF525956FF3B423FFF333A37FF2A312EFF1A211EFF282F2CFF
+ 39403DFF313835FF2E3532FF282F2CFF2B322FFF3F4643FF4D5451FF464D4AFF
+ 2E3532FF1B221FFF3E4744FF363F3CFF28312EFF434C49FF3E4744FF48514EFF
+ 343D3AFF363F3CFF28312EFF303936FF37403DFF343D3AFF262F2CFF1C2522FF
+ 242D2AFF323B38FF202523FF3B403EFF313634FF1F2422FF343937FF464B49FF
+ 3D4240FF343937FF4F5452FF4A4F4DFF5A5F5DFF787D7BFF7F8482FF6D7270FF
+ 5F6462FF626765FF5F6462FF5B605EFF797E7CFF727775FF4D5250FF6D7270FF
+ 878C8AFF575C5AFF7C817FFF878C8AFF747977FF656A68FF5F6462FF505553FF
+ 494E4CFF424745FF464B49FF4E5351FF4E5351FF575C5AFF6C716FFF6E7371FF
+ 5F6462FF585D5BFF878C8AFF727775FF5D6260FF5E6361FF757A78FF838886FF
+ 707573FF525755FF676C6AFF4F5452FF4E5351FF474C4AFF505553FF3D4240FF
+ 565B59FF6C716FFF545957FF666B69FF787D7BFF7D8280FF5C615FFF676C6AFF
+ 545957FF6B726FFF636A67FF5F6865FF67706DFF7A8380FF88918EFF8A9390FF
+ 87908DFF858E8BFF7B8481FF7C8582FF7C8582FF7A8380FF77807DFF757E7BFF
+ 757E7BFF77807DFF949E98FF8C9690FF8F9993FF8F9993FF86908AFF86908AFF
+ 8B958FFF848E88FF727C76FF9DA7A1FF86908AFF919B95FF9BA59FFF8F9993FF
+ 9FA9A3FF828C86FF8C928DFF8C928DFF999F9AFF909691FF848A85FF878D88FF
+ 7A807BFF848A85FF818782FF8C928DFF8D938EFF717772FF737974FF4C524DFF
+ 434944FF4D534EFF2A302BFF404641FF323833FF4B514CFF2E342FFF272D28FF
+ 7E847FFF777D78FF696F6AFF7D837EFFCAD0CBFF9CA29DFF696F6AFF7A807BFF
+ 5B615CFF585E59FF5A605BFF484E49FF7D837EFF6C726DFF8A908BFF6A706BFF
+ 5F6560FF5D635EFF8D938EFF6F7570FF5B615CFF737974FF6E746FFF6E746FFF
+ 8F9590FF787E79FF7D837EFF7C827DFF808681FF717772FF696F6AFF303631FF
+ 383E39FF2E342FFF444A45FF444A45FF545A55FF818782FF747A75FF838984FF
+ 767C77FF686F68FF878B85FF8F9289FF80837AFF787B72FF80827CFF72746EFF
+ 656761FF73756FFF70716DFF4F504CFF3F403EFF4F504EFF454846FF4F5250FF
+ 5D605EFF424543FF5F6260FF5B5E5CFF474A48FF444745FF3B3E3CFF4D504EFF
+ 4E514FFF454846FF606361FF747775FF757876FF6C6F6DFF666B69FF636866FF
+ 545957FF2E3331FF3F4442FF3F4442FF3F4442FF2C312FFF575C5AFF5D6260FF
+ 565B59FF5D6260FF626765FF5E6361FF636866FF868B89FF696E6CFF838886FF
+ 676C6AFF6A6F6DFF6C716FFF8C918FFF727775FF717674FFA1A6A4FF6E7371FF
+ 5E6361FF6E7371FF727775FF747977FF7C817FFF787D7BFF5C615FFF464B49FF
+ 4A4F4DFF4D5250FF313634FF1D2220FF1B201EFF141917FF141917FF060B09FF
+ 1E2321FF414644FF353A38FF151A18FF131816FF232826FF2B302EFF373C3AFF
+ 212624FF202523FF272C2AFF282D2BFF2E3331FF101513FF151A18FF434846FF
+ 313634FF1B201EFF3E4341FF4D5250FF414644FF494E4CFF5F6462FF464B49FF
+ 4D5250FF4A4F4DFF353A38FF515654FF656A68FF414644FF5E6361FF5A5F5DFF
+ 5E6361FF4B504EFF595E5CFF4D5250FF494E4CFF303533FF353C39FF373E3BFF
+ 3A413EFF323936FF2D3431FF363D3AFF363D3AFF242B28FF434A47FF3D4441FF
+ 3D4441FF474E4BFF4D5451FF484F4CFF3D4441FF363D3AFF3A4340FF3A4340FF
+ 343D3AFF3D4643FF3A4340FF3B4441FF29322FFF1F2825FF1B2421FF222B28FF
+ 2A3330FF2B3431FF212A27FF161F1CFF19221FFF222B28FF171C1AFF292E2CFF
+ 282D2BFF1B201EFF181D1BFF1B201EFF202523FF292E2CFF222725FF3E4341FF
+ 515654FF4E5351FF515654FF5C615FFF585D5BFF474C4AFF636866FF5B605EFF
+ 656A68FF898E8CFF9BA09EFF7A7F7DFF5D6260FF636866FF696E6CFF747977FF
+ 707573FF737876FF767B79FF696E6CFF666B69FF6D7270FF606563FF868B89FF
+ 8A8F8DFF707573FF707573FF818684FF858A88FF7F8482FF696E6CFF6F7472FF
+ 757A78FF707573FF606563FF585D5BFF696E6CFF828785FF6C716FFF636866FF
+ 5E6361FF474C4AFF5B605EFF616664FF707573FF646967FF646967FF666B69FF
+ 646967FF777C7AFF707573FF797E7CFF5C615FFF555C59FF646B68FF5B6461FF
+ 555E5BFF5A6360FF68716EFF77807DFF7F8885FF828B88FF868F8CFF858E8BFF
+ 838C89FF7F8885FF7B8481FF7A8380FF7C8582FF7E8784FF6D7771FF6A746EFF
+ 727C76FF747E78FF6A746EFF6A746EFF6E7872FF68726CFF707A74FF9BA59FFF
+ 8D9791FF949E98FF8A948EFF747E78FF97A19BFF9FA9A3FF888E89FF858B86FF
+ 9CA29DFF939994FF969C97FF8E948FFF7E847FFF7B817CFF9AA09BFF888E89FF
+ 919792FF979D98FF9EA49FFF646A65FF4F5550FF535954FF464C47FF4A504BFF
+ 4D534EFF5E645FFF696F6AFF5C625DFF535954FF545A55FF666C67FF565C57FF
+ 858B86FF7F8580FF606661FF5D635EFF484E49FF4B514CFF595F5AFF4D534EFF
+ 727873FF5D635EFF707671FF646A65FF666C67FF6F7570FF7E847FFF6B716CFF
+ 393F3AFF3B413CFF4E544FFF575D58FF707671FF717772FF909691FF909691FF
+ 7C827DFF979D98FF8C928DFF7D837EFF7D837EFF898F8AFF8F9590FF888E89FF
+ 858B86FF7B817CFF808681FF898F8AFF838984FF676B65FF6E706AFF878A81FF
+ 83867DFF71746BFF72746EFF71736DFF70726CFF7D7F79FF646561FF434440FF
+ 282927FF262725FF373A38FF4B4E4CFF6D706EFF494C4AFF424543FF3A3D3BFF
+ 3C3F3DFF3F4240FF3B3E3CFF424543FF464947FF2D302EFF525553FF535654FF
+ 565957FF414442FF555A58FF5E6361FF707573FF5B605EFF676C6AFF747977FF
+ 8D9290FF7E8381FF747977FF838886FF4F5452FF4B504EFF555A58FF646967FF
+ 545957FF848987FF636866FF6E7371FF707573FF6F7472FF6D7270FF717674FF
+ 6C716FFF6A6F6DFF7F8482FF636866FF5B605EFF666B69FF6E7371FF7B807EFF
+ 898E8CFF8A8F8DFF565B59FF585D5BFF666B69FF686D6BFF535856FF414644FF
+ 313634FF1B201EFF545957FF2A2F2DFF2F3432FF565B59FF525755FF2B302EFF
+ 1A1F1DFF1F2422FF1F2422FF2C312FFF323735FF383D3BFF282D2BFF1A1F1DFF
+ 1F2422FF0D1210FF101513FF343937FF323735FF282D2BFF3F4442FF5E6361FF
+ 656A68FF545957FF5D6260FF505553FF5B605EFF505553FF363B39FF535856FF
+ 676C6AFF3F4442FF464B49FF424745FF424745FF363B39FF494E4CFF515654FF
+ 595E5CFF4C514FFF353C39FF3F4643FF333A37FF232A27FF2A312EFF39403DFF
+ 3B423FFF383F3CFF4C5350FF49504DFF4A514EFF4C5350FF49504DFF414845FF
+ 3D4441FF3E4542FF39423FFF3C4542FF434C49FF3B4441FF424B48FF3C4542FF
+ 3A4340FF2E3734FF232C29FF232C29FF252E2BFF252E2BFF1E2724FF161F1CFF
+ 151E1BFF19221FFF1B201EFF1C211FFF292E2CFF303533FF262B29FF252A28FF
+ 323735FF3A3F3DFF353A38FF333836FF3A3F3DFF484D4BFF545957FF535856FF
+ 4A4F4DFF434846FF4E5351FF585D5BFF575C5AFF636866FF808583FF858A88FF
+ 797E7CFF7B807EFF707573FF707573FF747977FF7F8482FF838886FF6D7270FF
+ 626765FF747977FF5B5E5CFF7E817FFF7F8280FF616462FF5F6260FF757876FF
+ 838684FF888B89FF676A68FF727573FF818482FF7B7E7CFF555856FF383B39FF
+ 515452FF7E817FFF797E7CFF737876FF6C716FFF4C514FFF595E5CFF606563FF
+ 717674FF656A68FF696E6CFF6F7472FF606563FF6B706EFF5F6462FF5C615FFF
+ 525755FF4A514EFF515855FF535C59FF535C59FF525B58FF5F6865FF727B78FF
+ 7A8380FF77807DFF808986FF7F8885FF7B8481FF767F7CFF717A77FF6F7875FF
+ 707976FF737C79FF68726CFF67716BFF717B75FF707A74FF606A64FF5B655FFF
+ 5E6862FF58625CFF67716BFF78827CFF67716BFF828C86FF909A94FF77817BFF
+ 7D8781FF76807AFFA0A6A1FF898F8AFF999F9AFF828883FF9CA29DFF929893FF
+ 8C928DFF828883FFA9AFAAFF828883FF888E89FF919792FF969C97FF656B66FF
+ 515752FF414742FF404641FF494F4AFF6F7570FF6E746FFF8C928DFF8C928DFF
+ 555B56FF7B817CFF5A605BFF3C423DFF454B46FF585E59FF505651FF4B514CFF
+ 474D48FF393F3AFF444A45FF454B46FF595F5AFF474D48FF484E49FF4D534EFF
+ 545A55FF606661FF555B56FF646A65FF404641FF404641FF636964FF5C625DFF
+ 4A504BFF454B46FFBCC0BBFFBDC1BCFF878B86FFB3B7B2FF8F938EFF939792FF
+ 737772FF848883FF878B86FFB0B4AFFFC2C6C1FF848883FF7A7E79FF737772FF
+ 8E928DFF8D918BFF7D7F79FF94978EFF90938AFF7B7E75FF797B75FF767872FF
+ 646660FF555751FF838480FF696A66FF4D4E4CFF3F403EFF4C4F4DFF3F4240FF
+ 595C5AFF474A48FF4C4F4DFF494C4AFF4A4D4BFF444745FF414442FF343735FF
+ 2E312FFF2A2D2BFF454846FF3D403EFF444745FF4E514FFF3B403EFF3F4442FF
+ 686D6BFF6B706EFF6F7472FF727775FF939896FF8C918FFF666B69FF797E7CFF
+ 454A48FF1E2321FF2B302EFF5B605EFF636866FF777C7AFF616664FF404543FF
+ 626765FF878C8AFF828785FF414644FF494E4CFF6A6F6DFF666B69FF626765FF
+ 636866FF666B69FF676C6AFF6D7270FF747977FF747977FF4B504EFF4A4F4DFF
+ 515654FF535856FF4B504EFF434846FF3E4341FF3B403EFF5D6260FF545957FF
+ 5C615FFF666B69FF616664FF5D6260FF5C615FFF545957FF717674FF595E5CFF
+ 5E6361FF747977FF5F6462FF434846FF525755FF686D6BFF777C7AFF6B706EFF
+ 757A78FF606563FF595E5CFF606563FF434846FF3C413FFF5C615FFF787D7BFF
+ 757A78FF656A68FF676C6AFF5F6462FF494E4CFF434846FF464B49FF3D4240FF
+ 2F3432FF232826FF2F3432FF3B403EFF3C413FFF2E3331FF404744FF434A47FF
+ 2C3330FF1E2522FF2F3633FF373E3BFF3B423FFF4E5552FF414845FF414845FF
+ 464D4AFF4B524FFF484F4CFF3F4643FF3B423FFF3D4441FF4F5855FF47504DFF
+ 515A57FF424B48FF4C5552FF363F3CFF404946FF3E4744FF444D4AFF39423FFF
+ 2F3835FF29322FFF242D2AFF1C2522FF19221FFF1B2421FF181D1BFF0D1210FF
+ 1D2220FF303533FF2F3432FF373C3AFF3D4240FF2D3230FF414644FF393E3CFF
+ 3F4442FF525755FF5A5F5DFF515654FF4A4F4DFF4D5250FF2E3331FF424745FF
+ 6F7472FF7A7F7DFF6F7472FF8E9391FF9DA2A0FF757A78FF868B89FF757A78FF
+ 767B79FF7F8482FF818684FF686D6BFF505553FF646967FF7D807EFF7C7F7DFF
+ 717472FF717472FF7F8280FF858886FF8A8D8BFF989B99FF838684FF7D807EFF
+ 7C7F7DFF7A7D7BFF686B69FF525553FF525553FF606361FF818684FF767B79FF
+ 737876FF565B59FF4F5452FF3D4240FF5B605EFF717674FF787D7BFF7A7F7DFF
+ 626765FF5F6462FF525755FF4D5250FF5C615FFF5C6360FF59605DFF646D6AFF
+ 646D6AFF59625FFF59625FFF69726FFF707976FF6B7471FF868F8CFF87908DFF
+ 868F8CFF818A87FF7C8582FF78817EFF767F7CFF77807DFF7A847EFF7A847EFF
+ 838D87FF818B85FF6F7973FF6A746EFF707A74FF6E7872FF646E68FF606A64FF
+ 454F49FF616B65FF848E88FF79837DFF66706AFF47514BFF606661FF656B66FF
+ 929893FF646A65FF656B66FF4E544FFF747A75FF919792FF7E847FFF656B66FF
+ 707671FF6D736EFF7B817CFF7E847FFF8C928DFF717772FF4B514CFF4F5550FF
+ 6E746FFF545A55FF5E645FFF737974FF515752FF727873FF5A605BFF4F5550FF
+ 3E443FFF4C524DFF4B514CFF535954FF626863FF383E39FF4B514CFF5B615CFF
+ 656B66FF5E645FFF575D58FF606661FF5D635EFF5D635EFF4F5550FF656B66FF
+ 5F6560FF616762FF747A75FF6A706BFF4C524DFF373D38FF646863FF80847FFF
+ 565A55FF8B8F8AFF7D817CFF989C97FF797D78FF868A85FF777B76FF9EA29DFF
+ A4A8A3FF7F837EFF8F938EFF929691FF919590FF878B85FF999D97FF9BA097FF
+ 8E9188FF777C73FF71736DFF70746EFF6E706AFF686C66FF5E5F5BFF4D514CFF
+ 3B3C3AFF2C2F2DFF575A58FF464947FF696C6AFF656866FF646765FF4C4F4DFF
+ 484B49FF4D504EFF424543FF414442FF2D302EFF313432FF2A2D2BFF2D302EFF
+ 2B2E2CFF454846FF3E4341FF272C2AFF474C4AFF5F6462FF6E7371FF5D6260FF
+ 646967FF535856FF646967FF606563FF505553FF1D2220FF1A1F1DFF2F3432FF
+ 484D4BFF353A38FF585D5BFF323735FF545957FF787D7BFF878C8AFF4C514FFF
+ 515654FF616664FF767B79FF707573FF656A68FF646967FF707573FF747977FF
+ 6A6F6DFF616664FF6F7472FF5D6260FF4F5452FF4E5351FF4E5351FF484D4BFF
+ 545957FF6D7270FF3E4341FF595E5CFF737876FF6A6F6DFF505553FF515654FF
+ 5D6260FF595E5CFF636866FF414644FF4B504EFF727775FF7A7F7DFF5D6260FF
+ 454A48FF494E4CFF484D4BFF595E5CFF6D7270FF4E5351FF878C8AFF9BA09EFF
+ 4D5250FF828785FF646967FF757A78FF767B79FF757A78FF767B79FF5E6361FF
+ 4A4F4DFF535856FF474C4AFF3F4442FF2E3331FF2E3331FF383D3BFF474C4AFF
+ 393E3CFF242927FF39403DFF39423FFF313A37FF3B4441FF4B5451FF3C4542FF
+ 303936FF434C49FF3A4340FF353E3BFF343D3AFF38413EFF3A4340FF353E3BFF
+ 323B38FF323B38FF29322FFF212A27FF3C4542FF464F4CFF5C6562FF48514EFF
+ 5B6461FF69726FFF5A6360FF4D5653FF3F4845FF39423FFF323B38FF262F2CFF
+ 1B2421FF151E1BFF222725FF1D2220FF272C2AFF292E2CFF222725FF323735FF
+ 373C3AFF1E2321FF111614FF373C3AFF484D4BFF3C413FFF3F4442FF585D5BFF
+ 5C615FFF494E4CFF585D5BFF313634FF3A3F3DFF555A58FF4C514FFF4F5452FF
+ 747977FF8E9391FF808583FF696E6CFF6B706EFF6F7472FF7C817FFF747977FF
+ 565B59FF696E6CFF7C7F7DFF787B79FF6E716FFF747775FF868987FF888B89FF
+ 838684FF8B8E8CFF8F9290FF8D908EFF868987FF7F8280FF7C7F7DFF7D807EFF
+ 7B7E7CFF777A78FF848987FF818684FF858A88FF686D6BFF616664FF515654FF
+ 6C716FFF7C817FFF959A98FF848987FF6E7371FF696E6CFF747977FF797E7CFF
+ 828785FF7A817EFF7F8683FF838C89FF77807DFF59625FFF4A5350FF565F5CFF
+ 656E6BFF68716EFF7F8885FF838C89FF88918EFF89928FFF868F8CFF808986FF
+ 7C8582FF7A8380FF79837DFF79837DFF838D87FF838D87FF77817BFF7A847EFF
+ 88928CFF8A948EFF6B756FFF77817BFF606A64FF545E58FF5C6660FF606A64FF
+ 606A64FF555F59FF404641FF323833FF515752FF2E342FFF494F4AFF3E443FFF
+ 595F5AFF656B66FF747A75FF656B66FF727873FF636964FF616762FF5E645FFF
+ 717772FF5C625DFF818782FF7B817CFF7C827DFF676D68FF606661FF828883FF
+ 898F8AFF717772FF6C726DFF696F6AFF525853FF5C625DFF525853FF505651FF
+ 6B716CFF444A45FF565C57FF696F6AFF6F7570FF747A75FF757B76FF7B817CFF
+ 787E79FF6D736EFF6D736EFF636964FF6A706BFF626863FF565C57FF676D68FF
+ 6D736EFF5C625DFF484C47FF767A75FF5D615CFF737772FF838782FF9CA09BFF
+ 919590FF949893FF7E827DFF999D98FF90948FFF949893FF999D98FFA0A49FFF
+ 848883FF838781FF8B8F89FF8A9288FF989D94FF9BA399FF888C86FF686F68FF
+ 5A5E58FF535A53FF3E423DFF343A35FF2B2E2CFF212624FF505351FF4F5250FF
+ 707371FF616462FF5A5D5BFF3F4240FF454846FF626563FF3D403EFF5A5D5BFF
+ 444745FF313432FF0E110FFF1B1E1CFF090C0AFF0F1210FF3F4442FF363B39FF
+ 5A5F5DFF707573FF7E8381FF5F6462FF5E6361FF575C5AFF717674FF565B59FF
+ 646967FF4F5452FF414644FF222725FF2D3230FF171C1AFF3F4442FF5C615FFF
+ 777C7AFF5C615FFF656A68FF5F6462FF6A6F6DFF595E5CFF5C615FFF616664FF
+ 585D5BFF535856FF5C615FFF616664FF686D6BFF7A7F7DFF727775FF686D6BFF
+ 5C615FFF606563FF616664FF4C514FFF484D4BFF616664FF5C615FFF4E5351FF
+ 4D5250FF4B504EFF3E4341FF3B403EFF3F4442FF3C413FFF434846FF4E5351FF
+ 666B69FF747977FF898E8CFF828785FF5F6462FF626765FF4F5452FF575C5AFF
+ 7B807EFF585D5BFF797E7CFFA0A5A3FF5F6462FF6B706EFF7A7F7DFF5C615FFF
+ 707573FF828785FF636866FF626765FF797E7CFF707573FF525755FF494E4CFF
+ 313634FF363B39FF3F4442FF5C615FFF545957FF484F4CFF3A413EFF363F3CFF
+ 39423FFF49524FFF515A57FF404946FF343D3AFF3D4643FF424B48FF323B38FF
+ 232C29FF1E2724FF1C2522FF19221FFF17201DFF17201DFF0B1411FF131C19FF
+ 363F3CFF555E5BFF6E7774FF68716EFF757E7BFF828B88FF616A67FF57605DFF
+ 4F5855FF4E5754FF48514EFF37403DFF232C29FF18211EFF2E3331FF373C3AFF
+ 3B403EFF2A2F2DFF1C211FFF2A2F2DFF3B403EFF373C3AFF161B19FF1E2321FF
+ 212624FF282D2BFF484D4BFF696E6CFF606563FF404543FF232826FF1C211FFF
+ 131816FF3F4442FF6E7371FF494E4CFF2E3331FF606563FF6C716FFF5C615FFF
+ 636866FF575C5AFF686D6BFF777C7AFF585D5BFF636866FF505351FF6C6F6DFF
+ 717472FF666967FF717472FF828583FF848785FF838684FF7D807EFF8D908EFF
+ 909391FF7E817FFF717472FF797C7AFF8B8E8CFF979A98FF838886FF949997FF
+ 9BA09EFF767B79FF818684FF8D9290FF979C9AFF7C817FFF919694FF848987FF
+ 959A98FF828785FF8A8F8DFF898E8CFF818684FF838A87FF7D8481FF808986FF
+ 79827FFF666F6CFF5A6360FF5E6764FF646D6AFF656E6BFF656E6BFF6D7673FF
+ 79827FFF818A87FF838C89FF818A87FF7D8683FF7B8481FF7C8680FF79837DFF
+ 7F8983FF7F8983FF747E78FF78827CFF858F89FF87918BFF727C76FF88928CFF
+ 7E8882FF626C66FF5A645EFF5D6761FF5B655FFF58625CFF646A65FF343A35FF
+ 282E29FF060C07FF2B312CFF363C37FF404641FF3D433EFF373D38FF2F3530FF
+ 525853FF666C67FF737974FF5E645FFF6E746FFF767C77FF6C726DFF7E847FFF
+ 818782FF787E79FF565C57FF636964FF878D88FF5D635EFF777D78FF656B66FF
+ 545A55FF646A65FF505651FF3E443FFF595F5AFF4C524DFF535954FF5F6560FF
+ 646A65FF6C726DFF7B817CFF787E79FF888E89FF7C827DFF626863FF515752FF
+ 717772FF737974FF5D635EFF707671FF787E79FF6C726DFF747873FF989C97FF
+ 767A75FF636762FF777B76FF7A7E79FF797D78FF7D817CFF828681FF969A95FF
+ 8F938EFF9CA09BFF828681FF838782FF757974FF8C908AFF787F78FF626A60FF
+ 6F776DFF929A90FF959C95FF7A817AFF575E57FF3A413AFF464C47FF3C423DFF
+ 353A38FF383D3BFF595C5AFF474A48FF414442FF303331FF656866FF6C6F6DFF
+ 525553FF444745FF2C2F2DFF4B4E4CFF494C4AFF333634FF242725FF282B29FF
+ 232624FF252826FF272C2AFF444947FF6C716FFF717674FF818684FF6B706EFF
+ 6D7270FF6F7472FF565B59FF4F5452FF505553FF555A58FF595E5CFF444947FF
+ 3D4240FF434846FF303533FF717674FF838886FF555A58FF575C5AFF616664FF
+ 666B69FF5C615FFF444947FF525755FF4D5250FF464B49FF4A4F4DFF4B504EFF
+ 616664FF8C918FFF4D5250FF565B59FF4F5452FF4C514FFF525755FF434846FF
+ 353A38FF434846FF666B69FF3E4341FF2D3230FF393E3CFF444947FF4C514FFF
+ 515654FF4E5351FF545957FF6B706EFF6B706EFF4F5452FF606563FF6E7371FF
+ 6C716FFFA5AAA8FF737876FF5E6361FF787D7BFF7D8280FF717674FF858A88FF
+ 7D8280FF525755FF7B807EFF616664FF757A78FF7F8482FF616664FF676C6AFF
+ 7E8381FF6E7371FF676C6AFF656A68FF4C514FFF4C514FFF424745FF575C5AFF
+ 484D4BFF3D4441FF404744FF3C4542FF3F4845FF3E4744FF3C4542FF444D4AFF
+ 47504DFF3C4542FF424B48FF343D3AFF27302DFF232C29FF232C29FF212A27FF
+ 222B28FF262F2CFF444D4AFF58615EFF646D6AFF6E7774FF69726FFF717A77FF
+ 69726FFF646D6AFF6F7875FF666F6CFF606966FF616A67FF5F6865FF545D5AFF
+ 454E4BFF3D4643FF2C312FFF363B39FF333836FF2A2F2DFF282D2BFF2A2F2DFF
+ 343937FF454A48FF3F4442FF272C2AFF181D1BFF2A2F2DFF4C514FFF5A5F5DFF
+ 474C4AFF2E3331FF1F2422FF383D3BFF252A28FF2A2F2DFF626765FF696E6CFF
+ 5A5F5DFF777C7AFF6B706EFF6A6F6DFF757A78FF4C514FFF505553FF6A6F6DFF
+ 454A48FF464B49FF111412FF30312FFF363735FF2B2C2AFF333432FF424341FF
+ 494A48FF4E4F4DFF5D5E5CFF676866FF6F706EFF6C6D6BFF636462FF636462FF
+ 737472FF838684FF727775FF858A88FF8B908EFF626765FF6F7472FF7D8280FF
+ 858A88FF646967FF646967FF5B605EFF959A98FF777C7AFF797E7CFF767B79FF
+ 5C615FFF6D7471FF616865FF5F6865FF606966FF646D6AFF666F6CFF636C69FF
+ 5A6360FF525B58FF505956FF5B6461FF6B7471FF79827FFF828B88FF87908DFF
+ 8A9390FF8B9491FF89938DFF838D87FF86908AFF848E88FF77817BFF78827CFF
+ 7E8882FF7A847EFF77817BFF7E8882FF7B857FFF6F7973FF747E78FF717B75FF
+ 5B655FFF545E58FF5F6560FF5A605BFF5F6560FF323833FF181E19FF161C17FF
+ 313732FF585E59FF565C57FF545A55FF666C67FF6F7570FF848A85FF666C67FF
+ 656B66FF6E746FFF757B76FF969C97FF9BA19CFF8C928DFF646A65FF4C524DFF
+ 5F6560FF5A605BFF727873FF5E645FFF555B56FF5A605BFF494F4AFF4A504BFF
+ 606661FF555B56FF626863FF676D68FF6E746FFF6E746FFF858B86FF6C726DFF
+ 8E948FFF858B86FF4D534EFF494F4AFF6B716CFF737974FF727873FF777D78FF
+ 676D68FF6D736EFF585C57FF71726EFF464743FF42433FFF60615DFF62635FFF
+ 686965FF848581FF8D8E8AFF787975FF6A6B67FF6F706CFF6E6F6BFF757672FF
+ 737470FF6A6E68FF747B74FF454E44FF343D33FF424B41FF525A53FF6B736CFF
+ 7D857EFF777F78FF474E49FF333A35FF29302DFF323936FF383D3BFF494E4CFF
+ 4F5452FF353A38FF707573FF797E7CFF4D5250FF303533FF292E2CFF2C312FFF
+ 383D3BFF292E2CFF343937FF191E1CFF272C2AFF393E3CFF2E3331FF505754FF
+ 686D6BFF5F6663FF898E8CFF868D8AFF7A7F7DFF656C69FF555A59FF69706DFF
+ 3D4240FF2F3633FF383D3BFF434A47FF2A2F2DFF414644FF353A38FF545957FF
+ 555A58FF585D5BFF737876FF6C716FFF575C5AFF606563FF6B706EFF656A68FF
+ 4E5351FF4C514FFF5E6361FF5B605EFF5D6260FF7B807EFF5C615FFF686D6BFF
+ 505553FF373C3AFF454A48FF545957FF5D6260FF707573FF525755FF515654FF
+ 5A5F5DFF585D5BFF474C4AFF434846FF4B504EFF4A4F4DFF525755FF5E6361FF
+ 5B605EFF505553FF6D7270FF5B605EFF383D3BFF797E7CFF747977FF777C7AFF
+ 565B59FF7E8381FF929795FF6B706EFF6F7472FF656A68FF5F6462FF787D7BFF
+ 767B79FF6B706EFF6E7371FF636866FF4E5351FF4B504EFF3F4442FF575C5AFF
+ 5C615FFF717674FF606563FF656A68FF414644FF2E3331FF373E3BFF3E4744FF
+ 4B524FFF3D4643FF353C39FF4D5653FF565D5AFF303936FF39403DFF353E3BFF
+ 3C4340FF454E4BFF515855FF545D5AFF5D6461FF656C69FF656C69FF848B88FF
+ 7C8380FF737A77FF606764FF828986FF777E7BFF656E6BFF858E8BFF79827FFF
+ 6E7774FF6D7673FF6F7875FF6D7673FF6B7471FF6B7471FF414845FF3E4542FF
+ 333836FF3B423FFF4E5351FF3E4542FF323735FF434A47FF3A3F3DFF545B58FF
+ 505553FF282F2CFF1C211FFF2D3431FF2D3230FF121916FF1A211EFF2D3431FF
+ 464D4AFF515855FF59605DFF6E7572FF7B827FFF767B79FF757A78FF818684FF
+ 8F9492FF525755FF474C4AFF636866FF393E3CFF343937FF2A2D2BFF252826FF
+ 1C1F1DFF212422FF2A2D2BFF232624FF222523FF333634FF3F4240FF333432FF
+ 383937FF555654FF686967FF646563FF5D5E5CFF5F605EFF5A5D5BFF5C615FFF
+ 606563FF3C413FFF383D3BFF303533FF434846FF424745FF414644FF202523FF
+ 646967FF4A4F4DFF6A6F6DFF7A7F7DFF494E4CFF525755FF606764FF4D5451FF
+ 404744FF454C49FF4F5653FF4E5552FF434A47FF39423FFF303936FF3C4542FF
+ 4E5754FF5F6865FF6E7774FF79827FFF818A87FF858E8BFF8B958FFF848E88FF
+ 88928CFF89938DFF808A84FF808A84FF848E88FF7C8680FF7F8983FF77817BFF
+ 737D77FF6F7973FF77817BFF737D77FF69706BFF787F7AFF777D78FF797F7AFF
+ 878D88FF7D837EFF6D736EFF6C726DFF5D635EFF686E69FF646A65FF6D736EFF
+ 676D68FF4F5550FF707671FF6C726DFF696F6AFF636964FF666C67FF757B76FF
+ 6F7570FF696F6AFF6E746FFF585E59FF4A504BFF686E69FF6C726DFF676D68FF
+ 646A65FF4F5550FF4A504BFF727873FF838984FF646A65FF686E69FF6A706BFF
+ 767C77FF6E746FFF838984FF535954FF7C827DFF747A75FF616762FF575D58FF
+ 525853FF444A45FF5C625DFF666C67FF595F5AFF898D88FF7D817CFF848882FF
+ 4B4C48FF555953FF686965FF595D57FF50514DFF797D77FF6D6E6AFF636761FF
+ 787975FF595D57FF484945FF3C403AFF646561FF626660FF60685EFF5B6359FF
+ 5F675DFF495248FF252C25FF313932FF5C645DFF6C746DFF838B84FF646B66FF
+ 525954FF5A615CFF363D3AFF383F3CFF2B322FFF242B28FF323936FF3C4340FF
+ 3E4542FF444B48FF2F3633FF242B28FF2A312EFF333A37FF2D3431FF2F3633FF
+ 3D4441FF434A47FF363D38FF444E48FF505752FF5F6865FF5D6461FF5F6766FF
+ 808685FF7D8584FF7E8384FF68706FFF575D5CFF0F1815FF262D2AFF3D4741FF
+ 2C332EFF151C17FF232826FF535856FF3E4341FF494E4CFF6F7472FF717674FF
+ 808583FF656A68FF7E8381FF848987FF7C817FFF595E5CFF797E7CFF606563FF
+ 434846FF5B605EFF7D8280FF5F6462FF7F8482FF535856FF757A78FF555A58FF
+ 464B49FF4D5250FF525755FF4E5351FF525755FF626765FF595E5CFF4C514FFF
+ 535856FF4C514FFF6F7472FF666B69FF5B605EFF565B59FF5B605EFF656A68FF
+ 707573FF767B79FF555A58FF444947FF333836FF4B504EFF6A6F6DFF6F7472FF
+ 626765FF474C4AFF4B504EFF666B69FF696E6CFF6F7472FF4D5250FF515654FF
+ 474C4AFF525755FF505553FF565B59FF646967FF727775FF787D7BFF797E7CFF
+ 7F8482FF868B89FF676C6AFF767D7AFF7F8482FF707774FF595E5CFF4C5350FF
+ 545957FF5F6663FF565B59FF535A57FF666B69FF7C8380FF767B79FF909794FF
+ 818684FF828785FF878A88FF7F8280FF777C7AFF767B79FF747977FF737876FF
+ 7D8280FF8A918EFF6D7471FF777E7BFF676E6BFF656C69FF767F7CFF6C7572FF
+ 6E7774FF98A19EFF6D7673FF656E6BFF515855FF505956FF4C5350FF2B3431FF
+ 2B322FFF39423FFF343B38FF2A3330FF3E4542FF48514EFF1B221FFF242D2AFF
+ 1E2522FF2A3330FF515D57FF434F49FF5B655FFF58625CFF56605AFF656F69FF
+ 747E78FF888F8AFF777E79FF707772FF848B86FF7E8580FF808681FF666C67FF
+ 5E645FFF424843FF3C433EFF373E39FF1B221DFF2F3631FF1C221DFF161C17FF
+ 212722FF343A35FF4A504BFF4E524DFF60645FFF585C57FF474B46FF656964FF
+ 767773FF4D4E4AFF3C3F3DFF3C3F3DFF343735FF2B2E2CFF202321FF111412FF
+ 1C1F1DFF3E413FFF505351FF3A3D3BFF3F4240FF4F5250FF717472FF575A58FF
+ 595C5AFF6A6D6BFF595C5AFF5F6260FF646967FF272C2AFF252A28FF373C3AFF
+ 444947FF3B423FFF303734FF2F3633FF4E5552FF676E6BFF717A77FF6A7370FF
+ 939C99FF88918EFF7C8784FF889390FF86918EFF7F8A87FF7D8885FF76817EFF
+ 757E7BFF808986FF575E5BFF69706DFF69706DFF5E6562FF515855FF6B726FFF
+ 888D8BFF626765FF888E89FF909691FF747A75FF808681FF999F9AFF717772FF
+ 878D88FF747A75FF9CA29DFF6C726DFF616762FF5F6560FF636964FF707671FF
+ 6E746FFF747A75FF6C726DFF5D635EFF767C77FF878D88FF6F7570FF6E746FFF
+ 818782FF7C827DFF5F6560FF646A65FF5D635EFF717772FF5C625DFF606661FF
+ 575D58FF686E69FF5B5E5CFF4C4F4DFF5E615FFF5B5E5CFF6B6E6CFF666967FF
+ 808381FF7D807EFF7E817FFF7D807EFF545755FF666967FF686B69FF828583FF
+ 838684FF575B56FF7B7F79FFB6BEB4FF5F635DFF747C72FF323630FF5E665CFF
+ 4A4E48FF727A70FF727670FF6B7369FF666A64FF626A60FF81857FFF4C544AFF
+ 3A3E38FF51564DFF444940FF6D7269FF787D74FF6B7369FF545950FF2B3329FF
+ 2C342AFF4E564CFF6F786EFF777F78FF8B938CFFA3ABA4FF1F2825FF2A3330FF
+ 2A3330FF2C3532FF3D4643FF49524FFF4C5552FF545D5AFF8A9390FF6D7673FF
+ 606966FF646D6AFF636C69FF606966FF57605DFF46504AFF3A443EFF48534BFF
+ 4B554FFF56605AFF525A59FF535B5AFF6B7373FF666E6EFF9DA5A5FF8A9292FF
+ 798180FF2D3633FF1D2623FF141E18FF162119FF29342CFF393E3CFF353A38FF
+ 363B39FF747977FF949997FF676C6AFF5E6361FF767B79FF676C6AFF696E6CFF
+ 6D7270FF535856FF6D7270FF595E5CFF424745FF4F5452FF6F7472FF5E6361FF
+ 7B807EFF585D5BFF717674FF666B69FF575C5AFF636866FF595E5CFF525755FF
+ 5A5F5DFF666B69FF545957FF444947FF484D4BFF414644FF4B504EFF515654FF
+ 4E5351FF474C4AFF4F5452FF5F6462FF5E6361FF505553FF3F4442FF333836FF
+ 282D2BFF363B39FF4A4F4DFF515654FF4D5250FF404543FF393E3CFF4C514FFF
+ 4F5452FF5E6361FF515654FF5F6462FF585D5BFF5C615FFF5A5F5DFF5F6462FF
+ 696E6CFF767B79FF7F8482FF7D8280FF7C817FFF828785FF797E7CFF818684FF
+ 808583FF6F7472FF5A5F5DFF545957FF606563FF6D7270FF737876FF6A6F6DFF
+ 757A78FF888D8BFF818684FF9BA09EFF878C8AFF858A88FF868785FF7D7E7CFF
+ 747775FF777A78FF7A7D7BFF7B7E7CFF7F8482FF878C8AFF848B88FF808784FF
+ 6A716EFF5C6360FF5E6764FF57605DFF58615EFF6D7673FF7A8380FF7B8481FF
+ 737C79FF78817EFF747D7AFF5A6360FF49524FFF464F4CFF3D4643FF2F3835FF
+ 37403DFF3C4542FF161F1CFF262F2CFF222B28FF2F3A37FF6F7B75FF65736DFF
+ 808C86FF7F8B85FF717D77FF707C76FF6D7771FF747E78FF818883FF7C837EFF
+ 909792FF878E89FF848A85FF6B716CFF696F6AFF535A55FF575E59FF525C56FF
+ 38423CFF505A54FF404742FF383F3AFF3B423DFF464D48FF5B615CFF5A605BFF
+ 6E726DFF6C706BFF60645FFF7C807BFF90918DFF71726EFF2D302EFF222523FF
+ 161917FF171A18FF181B19FF0E110FFF121513FF2A2D2BFF646765FF585B59FF
+ 666967FF777A78FF989B99FF858886FF8A8D8BFF969997FF616260FF757674FF
+ 8C8F8DFF636664FF6A6D6BFF727573FF686D6BFF545957FF4F5653FF4E5552FF
+ 646B68FF6D7471FF69726FFF57605DFF7B8481FF707B78FF6B7673FF6A7874FF
+ 5D6865FF525D5AFF55605DFF535E5BFF535C59FF5D6663FF555C59FF565D5AFF
+ 69706DFF8A918EFF7A7F7DFF646967FF767B79FF737876FF848A85FF8D938EFF
+ 717772FF6F7570FF7C827DFF545A55FF666C67FF4C524DFF797F7AFF616762FF
+ 676D68FF686E69FF686E69FF6B716CFF5A605BFF565C57FF787E79FF686E69FF
+ 6D736EFF727873FF646A65FF6B716CFF878D88FF969C97FF767C77FF616762FF
+ 474D48FF616762FF696F6AFF7B817CFF696F6AFF676D68FF6F7270FF636664FF
+ 727573FF707371FF7E817FFF727573FF7F8280FF777A78FF7F8280FF888B89FF
+ 6C6F6DFF797C7AFF6A6D6BFF767977FF6F7270FF484C47FF525952FF6F776DFF
+ 5C645AFF535B51FF4D554BFF3A4238FF464E44FF4C544AFF5A6258FF5A6258FF
+ 586056FF636B61FFA2AAA0FF8B9389FF60685EFF474F45FF55584FFF676A61FF
+ 71766DFF868B82FF868B82FF676C63FF4D554BFF3C443AFF5C655BFF636C62FF
+ 737C72FF858E84FF353E3BFF47504DFF4C5552FF4B5451FF525B58FF525B58FF
+ 4E5754FF535C59FF6C7572FF565F5CFF555E5BFF68716EFF79827FFF868F8CFF
+ 838C89FF737D77FF838D87FF8D9890FF818B85FF7F8983FF777F7EFF6E7675FF
+ 767E7EFF6A7272FF6A7272FF666E6EFF747C7BFF505956FF3F4845FF18221CFF
+ 1D2820FF444F47FF444947FF3A3F3DFF383D3BFF414644FF4C514FFF4B504EFF
+ 363B39FF484D4BFF565B59FF505553FF686D6BFF595E5CFF696E6CFF5D6260FF
+ 4F5452FF4B504EFF515654FF535856FF686D6BFF4E5351FF565B59FF686D6BFF
+ 565B59FF686D6BFF5F6462FF555A58FF686D6BFF6F7472FF545957FF434846FF
+ 444947FF3E4341FF444947FF4D5250FF474C4AFF383D3BFF3F4442FF4F5452FF
+ 434846FF262B29FF282D2BFF2F3432FF3C413FFF474C4AFF4C514FFF464B49FF
+ 373C3AFF2C312FFF3D4240FF434846FF414644FF515654FF555A58FF676C6AFF
+ 5D6260FF585D5BFF616664FF666B69FF6A6F6DFF767B79FF858A88FF808583FF
+ 757A78FF777C7AFF717674FF757A78FF747977FF6A6F6DFF5C615FFF585D5BFF
+ 616664FF6D7270FF808583FF727775FF767B79FF828785FF767B79FF8E9391FF
+ 787D7BFF747977FF767775FF6E6F6DFF686B69FF6D706EFF757876FF797C7AFF
+ 7A7F7DFF7D8280FF888F8CFF7E8582FF757C79FF69706DFF5E6764FF616A67FF
+ 636C69FF5A6360FF606966FF5E6764FF5A6360FF58615EFF656E6BFF77807DFF
+ 7F8885FF818A87FF707976FF636C69FF6A7370FF6A7370FF505956FF5C6562FF
+ 555E5BFF5F6A67FF727E78FF6F7D77FF8C9892FF929E98FF7D8983FF7C8882FF
+ 717B75FF76807AFF858C87FF808782FF949B96FF89908BFF868C87FF727873FF
+ 7A807BFF6B726DFF767D78FF737D77FF5E6862FF7D8781FF757C77FF6E7570FF
+ 69706BFF6B726DFF727873FF696F6AFF737772FF6F736EFF5E625DFF6B6F6AFF
+ 797A76FF656662FF434644FF272A28FF171A18FF242725FF2E312FFF252826FF
+ 212422FF2B2E2CFF414442FF414442FF5D605EFF6A6D6BFF858886FF777A78FF
+ 7F8280FF818482FF676866FF777876FF868987FF606361FF757876FF848785FF
+ 7D8280FF707573FF6D7471FF6F7673FF7A817EFF747B78FF656E6BFF48514EFF
+ 656E6BFF5A6562FF7F8A87FF75837FFF636E6BFF5D6865FF6B7673FF6D7875FF
+ 666F6CFF656E6BFF606764FF535A57FF5B625FFF7D8481FF696E6CFF474C4AFF
+ 656A68FF838886FF686E69FF777D78FF686E69FF5C625DFF636964FF494F4AFF
+ 5E645FFF424843FF767C77FF6A706BFF6B716CFF585E59FF535954FF5F6560FF
+ 5A605BFF5F6560FF404641FF565C57FF737974FF8A908BFF8D938EFF797F7AFF
+ 6B716CFF717772FF828883FF5D635EFF3A403BFF505651FF666C67FF7C827DFF
+ 6E746FFF666C67FF747775FF6A6D6BFF6F7270FF6A6D6BFF737674FF696C6AFF
+ 727573FF717472FF6E716FFF808381FF767977FF818482FF696C6AFF757876FF
+ 747775FF5E625DFF6B726BFF60685EFF747C72FF61695FFF6D756BFF343C32FF
+ 4D554BFF3B4339FF464E44FF60685EFF697167FF5D655BFF8D958BFF90988EFF
+ 858D83FF747C72FF7A7D74FF6A6D64FF63685FFF83887FFF8B9087FF81867DFF
+ 727A70FF434B41FF565F55FF5B645AFF656E64FF6F786EFF59625FFF6E7774FF
+ 717A77FF67706DFF5E6764FF4F5855FF434C49FF464F4CFF4C5552FF4D5653FF
+ 5E6764FF6F7875FF747D7AFF7E8784FF89928FFF87918BFF8B958FFF95A098FF
+ 7D8781FF727C76FF6B7372FF5D6564FF596161FF495151FF454D4DFF485050FF
+ 666E6DFF6D7673FF7B8481FF57615BFF545F57FF69746CFF7A7F7DFF838886FF
+ 797E7CFF363B39FF2B302EFF707573FF555A58FF494E4CFF4D5250FF424745FF
+ 6A6F6DFF646967FF6B706EFF656A68FF5E6361FF4A4F4DFF3A3F3DFF4B504EFF
+ 575C5AFF414644FF363B39FF5C615FFF454A48FF5C615FFF646967FF555A58FF
+ 767B79FF7C817FFF585D5BFF4C514FFF4B504EFF474C4AFF585D5BFF515654FF
+ 404543FF333836FF3B403EFF474C4AFF3B403EFF232826FF323735FF3E4341FF
+ 585D5BFF5B605EFF565B59FF4C514FFF303533FF252A28FF494E4CFF474C4AFF
+ 434846FF4C514FFF595E5CFF676C6AFF606563FF545957FF606563FF676C6AFF
+ 646967FF707573FF878C8AFF7F8482FF6B706EFF6C716FFF6C716FFF737876FF
+ 7D8280FF828785FF7D8280FF767B79FF757A78FF787D7BFF797E7CFF6C716FFF
+ 6E7371FF737876FF5D6260FF717674FF5E6361FF606563FF5C5D5BFF5B5C5AFF
+ 5B5E5CFF616462FF686B69FF6D706EFF6E7371FF717674FF7C8380FF787F7CFF
+ 878E8BFF848B88FF6E7774FF77807DFF7B8481FF5B6461FF646D6AFF58615EFF
+ 4A5350FF29322FFF2B3431FF59625FFF757E7BFF7D8683FF79827FFF7A8380FF
+ 8E9794FF8A9390FF78817EFF77807DFF6A7370FF717C79FF6C7872FF687670FF
+ 7E8A84FF88948EFF717D77FF7D8983FF79837DFF88928CFF818883FF777E79FF
+ 878E89FF7E8580FF848A85FF797F7AFF868C87FF7A817CFF7D847FFF7C8680FF
+ 6B756FFF909A94FF919893FF919893FF8A918CFF868D88FF989E99FF898F8AFF
+ 868A85FF7C807BFF656964FF616560FF686965FF5E5F5BFF6B6E6CFF404341FF
+ 2F3230FF434644FF4C4F4DFF3F4240FF363937FF363937FF252826FF2E312FFF
+ 535654FF5B5E5CFF6A6D6BFF5E615FFF666967FF5C5F5DFF636462FF686967FF
+ 646765FF363937FF575A58FF717472FF737876FF757A78FF757C79FF7B827FFF
+ 818885FF767D7AFF6D7673FF4C5552FF5F6865FF525D5AFF7E8986FF73817DFF
+ 67726FFF6F7A77FF8A9592FF8D9895FF78817EFF69726FFF676E6BFF656C69FF
+ 555C59FF505754FF3C413FFF353A38FF5E6361FF767B79FF505651FF636964FF
+ 666C67FF565C57FF5B615CFF545A55FF717772FF555B56FF828883FF7F8580FF
+ 747A75FF4C524DFF454B46FF5E645FFF696F6AFF7E847FFF515752FF717772FF
+ 828883FF939994FFA4AAA5FF8C928DFF777D78FF8B918CFF959B96FF7A807BFF
+ 626863FF686E69FF717772FF7B817CFF7D837EFF828883FF676A68FF626563FF
+ 595C5AFF4E514FFF515452FF525553FF646765FF797C7AFF656866FF737674FF
+ 707371FF787B79FF626563FF7B7E7CFF858886FF838782FF838A83FF60685EFF
+ 6E766CFF848C82FF798177FF666E64FF7A8278FF798177FF464E44FF6B7369FF
+ 7C847AFF5C645AFF6C746AFF71796FFF889086FF91998FFF95988FFF797C73FF
+ 686D64FF80857CFF747970FF73786FFF848C82FF535B51FF5C655BFF5F685EFF
+ 656E64FF687167FF}
+ BitmapAlign = baCenter
+ Scale = 1.000000000000000000
+ ScaleMode = smNormal
+ TabOrder = 0
+ OnPaintStage = Image32PaintStage
+ end
+ object PnlSettings: TPanel
+ Left = 316
+ Top = 0
+ Width = 143
+ Height = 258
+ Align = alRight
+ TabOrder = 1
+ object Label3: TLabel
+ Left = 8
+ Top = 32
+ Width = 58
+ Height = 13
+ Caption = 'Twirl Power:'
+ end
+ object Panel4: TPanel
+ Left = 1
+ Top = 1
+ Width = 141
+ Height = 16
+ Align = alTop
+ BevelOuter = bvNone
+ Caption = 'Twirl Distortion'
+ Color = clBtnShadow
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindow
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ TabOrder = 0
+ end
+ object gbTwist: TGaugeBar
+ Left = 8
+ Top = 48
+ Width = 129
+ Height = 12
+ Backgnd = bgPattern
+ HandleSize = 16
+ Max = 50
+ Min = -50
+ ShowArrows = False
+ ShowHandleGrip = True
+ Style = rbsMac
+ Position = 0
+ OnChange = gbTwistChange
+ end
+ object rbGetPixelFS: TRadioButton
+ Left = 8
+ Top = 96
+ Width = 129
+ Height = 17
+ Caption = 'TBitmap32.PixelFS'
+ TabOrder = 2
+ OnClick = gbTwistChange
+ end
+ object rbPixelS: TRadioButton
+ Left = 8
+ Top = 72
+ Width = 105
+ Height = 17
+ Caption = 'TBitmap32.PixelS'
+ Checked = True
+ TabOrder = 3
+ TabStop = True
+ OnClick = gbTwistChange
+ end
+ end
+end
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,167 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is PixelF_Ex
+ *
+ * The Initial Developer of the Original Code is
+ * Michael Hansen
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, GR32, GR32_Lowlevel, GR32_Image, StdCtrls, GR32_RangeBars,
+ ExtCtrls, Math;
+
+type
+ TMainForm = class(TForm)
+ Image32: TImage32;
+ PnlSettings: TPanel;
+ Label3: TLabel;
+ Panel4: TPanel;
+ gbTwist: TGaugeBar;
+ rbGetPixelFS: TRadioButton;
+ rbPixelS: TRadioButton;
+ procedure Image32PaintStage(Sender: TObject; Buffer: TBitmap32;
+ StageNum: Cardinal);
+ procedure FormCreate(Sender: TObject);
+ procedure gbTwistChange(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ Src: TBitmap32;
+ procedure TwirlDistortion(Dst, Src: TBitmap32; const Value: Integer);
+ end;
+
+var
+ MainForm: TMainForm;
+
+implementation
+
+{$R *.dfm}
+
+procedure TMainForm.TwirlDistortion(Dst, Src: TBitmap32; const Value: Integer);
+{twirl algoritm inspired by Patrick Quinn´s remap demo}
+var
+ X, Y, DstR, DstB: Integer;
+ r, rx, ry, t, tt, v: Single;
+begin
+ rx := Src.Width / 2;
+ ry := Src.Height / 2;
+ v := -Value / 5 / Src.Height;
+ DstR := Dst.Width - 1;
+ DstB := Dst.Height - 1;
+
+ if rbGetPixelFS.Checked then
+ for Y := 0 to DstB do
+ for X := 0 to DstR do begin
+ r := Hypot(X - rx, Y - ry);
+ t := ArcTan2(Y - ry, X - rx);
+ tt := t + r * v;
+ Dst.Pixel[X, Y] := Src.PixelFS[ rx + r * Cos(tt),
+ ry + r * Sin(tt) ];
+ end
+ else if rbPixelS.Checked then
+ for Y := 0 to DstB do
+ for X := 0 to DstR do begin
+ r := Hypot(X - rx, Y - ry);
+ t := ArcTan2(Y - ry, X - rx);
+ tt := t + r * v;
+ Dst.Pixel[X, Y] := Src.PixelS[ Round(rx + r * Cos(tt)),
+ Round(ry + r * Sin(tt)) ];
+ end;
+end;
+
+procedure TMainForm.Image32PaintStage(Sender: TObject; Buffer: TBitmap32;
+ StageNum: Cardinal);
+const
+ Colors: array [0..1] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
+var
+ W, I, J, Parity: Integer;
+ Line1, Line2: TArrayOfColor32; // a buffer for a couple of scanlines
+begin
+ with Image32.Buffer do
+ if StageNum = 0 then
+ begin
+ W := Width;
+ SetLength(Line1, W);
+ SetLength(Line2, W);
+ for I := 0 to W - 1 do
+ begin
+ Parity := I shr 3 and $1;
+ Line1[I] := Colors[Parity];
+ Line2[I] := Colors[1 - Parity];
+ end;
+ for J := 0 to Height - 1 do
+ begin
+ Parity := J shr 3 and $1;
+ if Boolean(Parity) then MoveLongword(Line1[0], ScanLine[J]^, W)
+ else MoveLongword(Line2[0], ScanLine[J]^, W);
+ end;
+ end
+ else
+ FrameRectS(BoundsRect , $FF000000);
+end;
+
+procedure TMainForm.FormCreate(Sender: TObject);
+var
+ i: integer;
+begin
+ with Image32 do
+ begin
+ if PaintStages[0].Stage = PST_CLEAR_BACKGND then PaintStages[0].Stage := PST_CUSTOM;
+ PaintStages.Add.Stage := PST_CUSTOM;
+ end;
+
+ Src := TBitmap32.Create;
+ with Src do begin //Making distorted borders look better
+ Assign(Image32.Bitmap);
+ for i:= 0 to Width - 1 do begin
+ Pixel[i, 0] := Pixel[i, 0] and $00FFFFFF;
+ Pixel[i, Height - 1] := Pixel[i, 0] and $00FFFFFF;
+ end;
+ for i:= 0 to Height - 1 do begin
+ Pixel[0, i] := Pixel[i, 0] and $00FFFFFF or $7F000000;
+ Pixel[Width - 1, i] := Pixel[i, 0] and $00FFFFFF;
+ end;
+ OuterColor := $00000000;
+ end;
+end;
+
+procedure TMainForm.gbTwistChange(Sender: TObject);
+begin
+ with Image32 do
+ begin
+ TwirlDistortion(Bitmap, Src, gbTwist.Position);
+ gbTwist.Repaint;
+ Repaint;
+ end;
+end;
+
+procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ Src.Free;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.cfg
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.cfg 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.cfg 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,35 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J-
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q-
+-$R-
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$YD
+-$Z1
+-cg
+-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+-H+
+-W+
+-M
+-$M16384,1048576
+-K$00400000
+-LE"d:\program\borland\delphi7\Projects\Bpl"
+-LN"d:\program\borland\delphi7\Projects\Bpl"
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.dof
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.dof 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.dof 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,141 @@
+[FileVersion]
+Version=7.0
+[Compiler]
+A=8
+B=0
+C=1
+D=1
+E=0
+F=0
+G=1
+H=1
+I=1
+J=0
+K=0
+L=1
+M=0
+N=1
+O=1
+P=1
+Q=0
+R=0
+S=0
+T=0
+U=0
+V=1
+W=0
+X=1
+Y=1
+Z=1
+ShowHints=1
+ShowWarnings=1
+UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+NamespacePrefix=
+SymbolDeprecated=1
+SymbolLibrary=1
+SymbolPlatform=1
+UnitLibrary=1
+UnitPlatform=1
+UnitDeprecated=1
+HResultCompat=1
+HidingMember=1
+HiddenVirtual=1
+Garbage=1
+BoundsError=1
+ZeroNilCompat=1
+StringConstTruncated=1
+ForLoopVarVarPar=1
+TypedConstVarPar=1
+AsgToTypedConst=1
+CaseLabelRange=1
+ForVariable=1
+ConstructingAbstract=1
+ComparisonFalse=1
+ComparisonTrue=1
+ComparingSignedUnsigned=1
+CombiningSignedUnsigned=1
+UnsupportedConstruct=1
+FileOpen=1
+FileOpenUnitSrc=1
+BadGlobalSymbol=1
+DuplicateConstructorDestructor=1
+InvalidDirective=1
+PackageNoLink=1
+PackageThreadVar=1
+ImplicitImport=1
+HPPEMITIgnored=1
+NoRetVal=1
+UseBeforeDef=1
+ForLoopVarUndef=1
+UnitNameMismatch=1
+NoCFGFileFound=1
+MessageDirective=1
+ImplicitVariants=1
+UnicodeToLocale=1
+LocaleToUnicode=1
+ImagebaseMultiple=1
+SuspiciousTypecast=1
+PrivatePropAccessor=1
+UnsafeType=1
+UnsafeCode=1
+UnsafeCast=1
+[Linker]
+MapFile=0
+OutputObjs=0
+ConsoleApp=1
+DebugInfo=0
+RemoteSymbols=0
+MinStackSize=16384
+MaxStackSize=1048576
+ImageBase=4194304
+ExeDescription=
+[Directories]
+OutputDir=
+UnitOutputDir=
+PackageDLLOutputDir=
+PackageDCPOutputDir=
+SearchPath=
+Packages=vcl;rtl;dbrtl;adortl;vcldb;vclx;bdertl;vcldbx;ibxpress;dsnap;cds;bdecds;qrpt;teeui;teedb;tee;dss;teeqr;visualclx;visualdbclx;dsnapcrba;dsnapcon;VclSmp;vclshlctrls;vclie;xmlrtl;inet;inetdbbde;inetdbxpress;inetdb;nmfast;webdsnap;websnap;soaprtl;dbexpress;dbxcds;indy;dclOffice2k;GR32_D6;GR32_DSGN_D6;GR32_Add_Package_D6;TabletD6;tb2k_d6;tbx_d6;ThemeManager6;ImportedVCLs
+Conditionals=
+DebugSourceDirs=
+UsePackages=0
+[Parameters]
+RunParams=
+HostApplication=
+Launcher=
+UseLauncher=0
+DebugCWD=
+[Language]
+ActiveLang=
+ProjectLang=
+RootDir=C:\Program Files\Borland\Delphi7\Bin\
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1030
+CodePage=1252
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+[Excluded Packages]
+c:\program files\borland\delphi7\Projects\Bpl\GR32_ThirdParty.bpl=(untitled)
+c:\program files\borland\delphi7\Projects\Bpl\PS_D7.bpl=Photoshop VCL Components (Mattias Andersson)
+c:\program files\borland\delphi7\Projects\Bpl\PS_dsgn_D7.bpl=Photoshop IDE Wizard (Mattias Andersson)
+c:\program files\borland\delphi7\Projects\Bpl\LUT_Install.bpl=LUTControl
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program PixelF_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {MainForm};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TMainForm, MainForm);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/PixelF_Ex/PixelF_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,174 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ GR32, GR32_Image, GR32_Layers, GR32_Polygons, StdCtrls, ExtCtrls;
+
+type
+ TForm1 = class(TForm)
+ Image: TImage32;
+ Panel1: TPanel;
+ Antialiase: TCheckBox;
+ Label1: TLabel;
+ LineAlpha: TScrollBar;
+ Label2: TLabel;
+ FillAlpha: TScrollBar;
+ FillMode: TRadioGroup;
+ Button1: TButton;
+ LineThickness: TScrollBar;
+ Label3: TLabel;
+ ThickOutline: TCheckBox;
+ Label4: TLabel;
+ BitmapList: TBitmap32List;
+ AntialiasMode: TRadioGroup;
+ Memo1: TMemo;
+ Memo2: TMemo;
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure ImageResize(Sender: TObject);
+ procedure ParamsChanged(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure ThicknessChanged(Sender: TObject);
+ private
+ Polygon: TPolygon32;
+ Outline: TPolygon32;
+ UseOutlinePoly: Boolean;
+ LineSize: Single;
+ procedure Build;
+ procedure Draw;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.DFM}
+
+procedure TForm1.Draw;
+begin
+ Image.Bitmap.BeginUpdate;
+ Image.Bitmap.Clear(clWhite32);
+ Image.Bitmap.Draw(50, 50, BitmapList.Bitmaps[0].Bitmap);
+ Polygon.Antialiased := Antialiase.Checked;
+ Polygon.AntialiasMode := TAntialiasMode(AntialiasMode.ItemIndex);
+
+ if UseOutlinePoly then
+ begin
+ Outline.Antialiased := Antialiase.Checked;
+ Outline.AntialiasMode := TAntialiasMode(AntialiasMode.ItemIndex);
+ end;
+
+ if FillMode.ItemIndex = 0 then Polygon.FillMode := pfAlternate else Polygon.FillMode := pfWinding;
+
+ Polygon.DrawFill(Image.Bitmap, SetAlpha(clGreen32, FillAlpha.Position));
+
+ if UseOutlinePoly then
+ Outline.DrawFill(Image.Bitmap, SetAlpha(clBlack32, LineAlpha.Position))
+ else
+ Polygon.DrawEdge(Image.Bitmap, SetAlpha(clBlack32, LineAlpha.Position));
+
+ Image.Bitmap.EndUpdate;
+ Image.Bitmap.Changed;
+ Image.Refresh; // force repaint
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ Polygon := TPolygon32.Create;
+end;
+
+procedure TForm1.FormDestroy(Sender: TObject);
+begin
+ Outline.Free;
+ Polygon.Free;
+end;
+
+procedure TForm1.ImageMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ if Button = mbLeft then Polygon.Add(FixedPoint(X, Y))
+ else Polygon.Clear;
+ Build;
+ Draw;
+end;
+
+procedure TForm1.ImageResize(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ Build;
+ Draw;
+end;
+
+procedure TForm1.ParamsChanged(Sender: TObject);
+begin
+ AntialiasMode.Enabled := Antialiase.Checked and ThickOutline.Checked;
+ Draw;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+begin
+ Polygon.NewLine;
+end;
+
+procedure TForm1.Build;
+var
+ TmpPoly: TPolygon32;
+begin
+ Outline.Free;
+ Outline := nil;
+
+ if UseOutlinePoly then
+ begin
+ TmpPoly := Polygon.Outline;
+ Outline := TmpPoly.Grow(Fixed(LineSize / 2), 0.5);
+ Outline.FillMode := pfWinding;
+ TmpPoly.Free;
+ end;
+
+ if UseOutlinePoly then
+ Label4.Caption := Format('(%.1f)', [LineSize])
+ else
+ Label4.Caption := '(1)';
+end;
+
+procedure TForm1.ThicknessChanged(Sender: TObject);
+begin
+ AntialiasMode.Enabled := Antialiase.Checked and ThickOutline.Checked;
+ UseOutlinePoly := ThickOutline.Checked;
+ LineSize := LineThickness.Position / 10;
+ Build;
+ Draw;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,49 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="Polygons_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj Polygons_Ex.obj"/>
+ <RESFILES value="Polygons_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="Vcl50.lib GR32_CB5.lib"/>
+ <PACKAGES value="Vcl50.bpi Vclx50.bpi bcbsmp50.bpi Vcldb50.bpi vclado50.bpi ibsmp50.bpi
+ VCLBDE50.bpi vcldbx50.bpi Qrpt50.bpi TeeUI50.bpi TeeDB50.bpi Tee50.bpi
+ Dss50.bpi TeeQR50.bpi VCLIB50.bpi Vclmid50.bpi vclie50.bpi Inetdb50.bpi
+ Inet50.bpi NMFast50.bpi webmid50.bpi bcbie50.bpi dclocx50.bpi
+ bcb2kaxserver50.bpi GR32_CB5.bpi TB2K_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="Polygons_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("Polygons_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, Form1);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TForm1), &Form1);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Polygons_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Polygons_Ex/Polygons_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex/G32_ProgressBar.dcr
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex/G32_ProgressBar.dcr
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex/G32_ProgressBar.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex/G32_ProgressBar.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/ProgressBar_Ex/G32_ProgressBar.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,255 @@
+unit G32_ProgressBar;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Classes, Graphics, Forms, GR32, GR32_Image, GR32_Blend;
+
+type
+ TG32_ProgressBar = class(TCustomPaintBox32)
+ private
+ FBackColor: TColor;
+ FBorderStyle: TBorderStyle;
+ FContrast: Integer;
+ FFramed: Boolean;
+ FMax: Integer;
+ FMin: Integer;
+ FPosition: Integer;
+ procedure SetBackColor(Value: TColor);
+ procedure SetBorderStyle(Value: TBorderStyle);
+ procedure SetContrast(Value: Integer);
+ procedure SetFramed(Value: Boolean);
+ procedure SetMax(Value: Integer);
+ procedure SetMin(Value: Integer);
+ procedure SetPosition(Value: Integer);
+ protected
+ procedure DoPaintBuffer; override;
+ function GetBarRect: TRect;
+ procedure PaintBar(Buffer: TBitmap32; ARect: TRect);
+ procedure PaintFrame(Buffer: TBitmap32; ARect: TRect);
+ public
+ constructor Create(AOwner: TComponent); override;
+ published
+ property Align;
+ property Anchors;
+ property BackColor: TColor read FBackColor write SetBackColor default clBtnShadow;
+ property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle;
+ property Caption;
+ property Color;
+ property Constraints;
+ property Contrast: Integer read FContrast write SetContrast default 64;
+ property Cursor;
+ property DragCursor;
+ property DragKind;
+ property DragMode;
+ property Font;
+ property Framed: Boolean read FFramed write SetFramed default True;
+ property Height default 16;
+ property HelpContext;
+ property Max: Integer read FMax write SetMax default 100;
+ property Min: Integer read FMin write SetMin default 0;
+ property ParentColor;
+ property ParentFont;
+ property ParentShowHint;
+ property PopupMenu;
+ property Position: Integer read FPosition write SetPosition;
+ property ShowHint;
+ property Visible;
+ property Width default 150;
+ property OnDragDrop;
+ property OnDragOver;
+ property OnEndDrag;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnStartDrag;
+ end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+ RegisterComponents('Graphics32', [TG32_ProgressBar]);
+end;
+
+{ TG32_ProgressBar }
+
+constructor TG32_ProgressBar.Create(AOwner: TComponent);
+begin
+ inherited;
+ Width := 150;
+ Height := 16;
+ FBackColor := clBtnShadow;
+ FContrast := 64;
+ FMax := 100;
+ FFramed := True;
+end;
+
+procedure TG32_ProgressBar.DoPaintBuffer;
+var
+ Rect: TRect;
+begin
+ inherited;
+ Rect := ClientRect;
+ PaintFrame(Buffer, Rect);
+ PaintBar(Buffer, GetBarRect);
+end;
+
+function TG32_ProgressBar.GetBarRect: TRect;
+var
+ X: Integer;
+begin
+ Result := ClientRect;
+ if Framed then InflateRect(Result, -1, -1);
+ with Result do
+ if (Position > Min) and (Max > Min) then
+ begin
+ X := Left + (Position - Min) * (Right - Left) div (Max - Min);
+ if X < Right then Right := X;
+ end
+ else
+ Right := Left; // return an empty rectagle
+end;
+
+procedure TG32_ProgressBar.PaintBar(Buffer: TBitmap32; ARect: TRect);
+var
+ Clr, LineColor: TColor32;
+ I, CY, H: Integer;
+begin
+ if IsRectEmpty(ARect) then Exit;
+
+ Clr := Color32(Color);
+
+ if Contrast <> 0 then
+ begin
+ with ARect do
+ try
+ H := Bottom - Top;
+ CY := (Top + Bottom) div 2;
+ for I := Top to Bottom - 1 do
+ begin
+ LineColor := Lighten(Clr, (CY - I) * Contrast div H);
+ Buffer.HorzLineS(Left, I, Right - 1, LineColor);
+ end;
+ finally
+ EMMS; // the low-level blending function was used EMMS is required
+ end;
+ end
+ else Buffer.FillRectS(ARect, Clr);
+
+ Buffer.RaiseRectTS(ARect, 32);
+
+ if Framed then
+ with ARect do Buffer.VertLineS(Right, Top, Bottom, Color32(clWindowFrame));
+end;
+
+procedure TG32_ProgressBar.PaintFrame(Buffer: TBitmap32; ARect: TRect);
+var
+ Clr: TColor32;
+begin
+ if BorderStyle = bsSingle then
+ begin
+ end;
+
+ { Paint frame border }
+ if Framed then
+ begin
+ Clr := TColor32(clWindowFrame);
+ Buffer.FrameRectS(ARect, Clr);
+ InflateRect(ARect, -1, -1);
+ end;
+
+ { Fill the background }
+ Clr := Color32(BackColor);
+ Buffer.FillRectS(ARect, Clr);
+
+ { Paint shadow on top of background}
+ with ARect do
+ begin
+ Dec(Right);
+ Dec(Bottom);
+ Clr := Lighten(Clr, -32);
+ Buffer.HorzLineS(Left, Top, Right, Clr);
+ Buffer.VertLineS(Left, Top + 1, Bottom, Clr);
+ if not Framed then
+ begin
+ Clr := Lighten(Clr, 64);
+ Buffer.HorzLineS(Left, Bottom, Right, Clr);
+ Buffer.VertLineS(Right, Top + 1, Bottom, Clr);
+ end;
+ end;
+end;
+
+procedure TG32_ProgressBar.SetBackColor(Value: TColor);
+begin
+ FBackColor := Value;
+ Invalidate;
+end;
+
+procedure TG32_ProgressBar.SetBorderStyle(Value: TBorderStyle);
+begin
+ FBorderStyle := Value;
+ Invalidate;
+end;
+
+procedure TG32_ProgressBar.SetContrast(Value: Integer);
+begin
+ FContrast := Value;
+ Invalidate;
+end;
+
+procedure TG32_ProgressBar.SetFramed(Value: Boolean);
+begin
+ FFramed := Value;
+ Invalidate;
+end;
+
+procedure TG32_ProgressBar.SetMax(Value: Integer);
+begin
+ FMax := Value;
+ Invalidate;
+end;
+
+procedure TG32_ProgressBar.SetMin(Value: Integer);
+begin
+ FMin := Value;
+ Invalidate;
+end;
+
+procedure TG32_ProgressBar.SetPosition(Value: Integer);
+begin
+ if Value <> Position then
+ begin
+ FPosition := Value;
+ Repaint;
+ end;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,116 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, ExtCtrls, GR32, ComCtrls, GR32_Image, Buttons;
+
+type
+ TForm1 = class(TForm)
+ Image: TImage32;
+ Panel1: TPanel;
+ Edit1: TEdit;
+ Label1: TLabel;
+ Button1: TButton;
+ Label2: TLabel;
+ SpeedButton1: TSpeedButton;
+ SpeedButton2: TSpeedButton;
+ SpeedButton3: TSpeedButton;
+ SpeedButton4: TSpeedButton;
+ SpeedButton5: TSpeedButton;
+ procedure Edit1Change(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure ImageResize(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure SpeedButton1Click(Sender: TObject);
+ public
+ AALevel: Integer;
+ procedure Draw;
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.DFM}
+
+procedure TForm1.Draw;
+begin
+ Image.Bitmap.Clear;
+ Image.Bitmap.RenderText(10, 10, Edit1.Text, AALevel, $FFFFFFFF);
+end;
+
+procedure TForm1.Edit1Change(Sender: TObject);
+begin
+ Draw;
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ with Image.Bitmap.Font do
+ begin
+ Name := 'Tahoma';
+ Size := 20;
+ Style := [fsBold, fsItalic];
+ end;
+ Panel1.DoubleBuffered := True;
+ Edit1.DoubleBuffered := True;
+end;
+
+procedure TForm1.ImageResize(Sender: TObject);
+begin
+ Image.SetupBitmap;
+ Draw;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+var
+ I: Integer;
+begin
+ Screen.Cursor := crHourGlass;
+ with Image.Bitmap do
+ for I := 0 to 100 do
+ RenderText(
+ Random(Width - 40),
+ Random(Height - 40),
+ IntToStr(Random(100)),
+ AALevel,
+ Color32(Random(255), Random(255), Random(255), Random(255)));
+ Screen.Cursor := crDefault;
+end;
+
+procedure TForm1.SpeedButton1Click(Sender: TObject);
+begin
+ AALevel := TControl(Sender).Tag;
+ Draw;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="RenderText_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj RenderText_Ex.obj"/>
+ <RESFILES value="RenderText_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="Vcl50.lib GR32_CB5.lib"/>
+ <PACKAGES value="Vcl50.bpi GR32_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="RenderText_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("RenderText_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, Form1);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TForm1), &Form1);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program RenderText_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/RenderText_Ex/RenderText_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/GR32_RotLayer.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/GR32_RotLayer.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/GR32_RotLayer.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,172 @@
+unit GR32_RotLayer;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ SysUtils, Classes, Controls, Forms, Graphics, GR32, GR32_Layers, GR32_Transforms;
+
+type
+ TCustomAffineLayer = class(TCustomLayer)
+ private
+ FAlphaHit: Boolean;
+ FTransformation: TAffineTransformation;
+ FBitmapCenter: TFloatPoint;
+ FBitmap: TBitmap32;
+ procedure BitmapChanged(Sender: TObject);
+ procedure SetBitmap(Value: TBitmap32);
+ protected
+ procedure AdjustTransformation; virtual;
+ function DoHitTest(X, Y: Integer): Boolean; override;
+ procedure Paint(Buffer: TBitmap32); override;
+ property Transformation: TAffineTransformation read FTransformation;
+ public
+ constructor Create(ALayerCollection: TLayerCollection); override;
+ destructor Destroy; override;
+ property AlphaHit: Boolean read FAlphaHit write FAlphaHit;
+ property Bitmap: TBitmap32 read FBitmap write SetBitmap;
+ end;
+
+ TAffineLayer = class(TCustomAffineLayer)
+ public
+ property Transformation;
+ end;
+
+ TRotLayer = class(TCustomAffineLayer)
+ private
+ FPosition: TFloatPoint;
+ FScaled: Boolean;
+ FAngle: Single;
+ procedure SetAngle(Value: Single);
+ procedure SetPosition(const Value: TFloatPoint);
+ procedure SetScaled(Value: Boolean);
+ procedure SetBitmapCenter(const Value: TFloatPoint);
+ protected
+ procedure AdjustTransformation; override;
+ public
+ property Angle: Single read FAngle write SetAngle;
+ property BitmapCenter: TFloatPoint read FBitmapCenter write SetBitmapCenter;
+ property Scaled: Boolean read FScaled write SetScaled;
+ property Position: TFloatPoint read FPosition write SetPosition;
+ end;
+
+implementation
+
+{ TCustomAffineLayer }
+
+type TATAccess = class(TAffineTransformation);
+
+procedure TCustomAffineLayer.AdjustTransformation;
+begin
+ // do nothing here
+end;
+
+procedure TCustomAffineLayer.BitmapChanged(Sender: TObject);
+begin
+ Transformation.SrcRect := FloatRect(0, 0, Bitmap.Width - 1, Bitmap.Height - 1);
+ Changed;
+end;
+
+constructor TCustomAffineLayer.Create(ALayerCollection: TLayerCollection);
+begin
+ inherited;
+ FBitmap := TBitmap32.Create;
+ FBitmap.OnChange := BitmapChanged;
+ FTransformation := TAffineTransformation.Create;
+end;
+
+destructor TCustomAffineLayer.Destroy;
+begin
+ FTransformation.Free;
+ FBitmap.Free;
+ inherited;
+end;
+
+function TCustomAffineLayer.DoHitTest(X, Y: Integer): Boolean;
+var
+ BX, BY: Integer;
+ Pt: TPoint;
+begin
+ with TATAccess(Transformation) do Transform(X, Y, BX, BY); // BX,BY - in 'FBitmap' coordinates
+ Pt := Point(BX, BY);
+ if PtInRect(Rect(0, 0, Bitmap.Width, Bitmap.Height), Pt) then Result := True;
+ if Result and AlphaHit and (Bitmap.PixelS[BX, BY] and $FF000000 = 0) then
+ Result := False;
+end;
+
+procedure TCustomAffineLayer.Paint(Buffer: TBitmap32);
+begin
+ AdjustTransformation;
+ Transform(Buffer, FBitmap, Transformation);
+end;
+
+procedure TCustomAffineLayer.SetBitmap(Value: TBitmap32);
+begin
+ FBitmap.Assign(Value);
+end;
+
+{ TRotLayer }
+
+procedure TRotLayer.AdjustTransformation;
+begin
+ Transformation.Clear;
+ Transformation.Translate(-BitmapCenter.X, -BitmapCenter.Y);
+ Transformation.Rotate(0, 0, Angle);
+ Transformation.Translate(Position.X, Position.Y);
+ if Scaled and Assigned(LayerCollection) and Assigned(LayerCollection.CoordXForm) then
+ with LayerCollection.CoordXForm^ do
+ begin
+ Transformation.Scale(ScaleX / 65536, ScaleY / 65536);
+ Transformation.Translate(ShiftX, ShiftY);
+ end;
+end;
+
+procedure TRotLayer.SetAngle(Value: Single);
+begin
+ FAngle := Value;
+ Changed;
+end;
+
+procedure TRotLayer.SetBitmapCenter(const Value: TFloatPoint);
+begin
+ FBitmapCenter := Value;
+ Changed;
+end;
+
+procedure TRotLayer.SetPosition(const Value: TFloatPoint);
+begin
+ FPosition := Value;
+ Changed;
+end;
+
+procedure TRotLayer.SetScaled(Value: Boolean);
+begin
+ FScaled := Value;
+ Changed;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/MainUnit.dfm
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/MainUnit.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/MainUnit.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,127 @@
+object Form1: TForm1
+ Left = 208
+ Top = 110
+ Width = 340
+ Height = 483
+ Caption = 'Form1'
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ DesignSize = (
+ 332
+ 456)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Label1: TLabel
+ Left = 12
+ Top = 292
+ Width = 76
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'RotLayer.Angle:'
+ end
+ object Label2: TLabel
+ Left = 12
+ Top = 324
+ Width = 96
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'RotLayer.Position.X:'
+ end
+ object Label3: TLabel
+ Left = 12
+ Top = 352
+ Width = 96
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'RotLayer.Position.Y:'
+ end
+ object Label4: TLabel
+ Left = 12
+ Top = 420
+ Width = 85
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'ImgView32.Scale:'
+ end
+ object ImgView: TImgView32
+ Left = 4
+ Top = 8
+ Width = 321
+ Height = 273
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Scale = 1.000000000000000000
+ ScrollBars.Color = clBtnShadow
+ ScrollBars.ShowHandleGrip = True
+ ScrollBars.Style = rbsDefault
+ SizeGrip = sgAuto
+ TabOrder = 0
+ end
+ object GaugeBar1: TGaugeBar
+ Left = 120
+ Top = 292
+ Width = 153
+ Height = 16
+ Anchors = [akLeft, akBottom]
+ Backgnd = bgPattern
+ Max = 180
+ Min = -180
+ ShowHandleGrip = True
+ Position = 0
+ OnChange = GaugeBar1Change
+ end
+ object GaugeBar2: TGaugeBar
+ Left = 120
+ Top = 324
+ Width = 153
+ Height = 16
+ Anchors = [akLeft, akBottom]
+ Backgnd = bgPattern
+ Max = 200
+ ShowHandleGrip = True
+ Position = 100
+ OnChange = GaugeBar2Change
+ end
+ object GaugeBar3: TGaugeBar
+ Left = 120
+ Top = 352
+ Width = 153
+ Height = 16
+ Anchors = [akLeft, akBottom]
+ Backgnd = bgPattern
+ Max = 200
+ ShowHandleGrip = True
+ Position = 100
+ OnChange = GaugeBar2Change
+ end
+ object GaugeBar4: TGaugeBar
+ Left = 120
+ Top = 420
+ Width = 153
+ Height = 16
+ Anchors = [akLeft, akBottom]
+ Backgnd = bgPattern
+ Min = -100
+ ShowHandleGrip = True
+ Position = 0
+ OnChange = GaugeBar4Change
+ end
+ object CheckBox1: TCheckBox
+ Left = 8
+ Top = 384
+ Width = 125
+ Height = 17
+ Alignment = taLeftJustify
+ Anchors = [akLeft, akBottom]
+ Caption = 'RotLayer.Scaled:'
+ Checked = True
+ State = cbChecked
+ TabOrder = 5
+ OnClick = CheckBox1Click
+ end
+end
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,124 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, GR32, GR32_Image, GR32_RotLayer, GR32_Transforms, GR32_RangeBars;
+
+type
+ TForm1 = class(TForm)
+ ImgView: TImgView32;
+ GaugeBar1: TGaugeBar;
+ Label1: TLabel;
+ GaugeBar2: TGaugeBar;
+ Label2: TLabel;
+ GaugeBar3: TGaugeBar;
+ Label3: TLabel;
+ GaugeBar4: TGaugeBar;
+ Label4: TLabel;
+ CheckBox1: TCheckBox;
+ procedure FormCreate(Sender: TObject);
+ procedure GaugeBar1Change(Sender: TObject);
+ procedure GaugeBar2Change(Sender: TObject);
+ procedure GaugeBar4Change(Sender: TObject);
+ procedure CheckBox1Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ L: TRotLayer;
+ procedure FillBitmap(B: TBitmap32; N: Integer);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+uses Math;
+
+{$R *.DFM}
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ ImgView.Bitmap.SetSize(200, 200);
+ FillBitmap(ImgView.Bitmap, 0);
+ L := TRotLayer.Create(ImgView.Layers);
+ L.Bitmap := TBitmap32.Create;
+ with L.Bitmap do
+ begin
+ BeginUpdate;
+ SetSize(100, 60);
+ L.BitmapCenter := FloatPoint(Width / 2, Height / 2);
+ FillBitmap(L.Bitmap, 127);
+ SetBorderTransparent(L.Bitmap, Rect(0, 0, Width - 1, Height - 1));
+ DrawMode := dmBlend;
+ StretchFilter := sfLinear;
+ EndUpdate;
+ Changed;
+ end;
+ L.Scaled := True;
+ L.Position := FloatPoint(100, 100);
+end;
+
+procedure TForm1.GaugeBar1Change(Sender: TObject);
+begin
+ L.Angle := GaugeBar1.Position;
+end;
+
+procedure TForm1.GaugeBar2Change(Sender: TObject);
+var
+ P: TFloatPoint;
+begin
+ P := L.Position;
+ P.X := GaugeBar2.Position;
+ P.Y := GaugeBar3.Position;
+ L.Position := P;
+end;
+
+procedure TForm1.GaugeBar4Change(Sender: TObject);
+begin
+ ImgView.Scale := Power(10, GaugeBar4.Position / 100);
+ ImgView.Update;
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ L.Scaled := not L.Scaled;
+end;
+
+procedure TForm1.FillBitmap(B: TBitmap32; N: Integer);
+var
+ X, Y: Integer;
+begin
+ for Y := 0 to B.Height - 1 do
+ for X := 0 to B.Width - 1 do
+ B[X, Y] := Color32(Random(127) + N, Random(127) + N, Random(127) + N, Random(127) + N);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/RotLayer_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/RotLayer_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/RotLayer_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program RotLayer_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/RotLayer_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/RotLayer_Ex/RotLayer_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,113 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ GR32, GR32_Image, GR32_Transforms, ComCtrls, Math, GR32_RangeBars;
+
+type
+ TForm1 = class(TForm)
+ Src: TImage32;
+ Dst: TImage32;
+ Angle: TGaugeBar;
+ procedure FormCreate(Sender: TObject);
+ procedure AngleChange(Sender: TObject);
+ public
+ procedure ScaleRot(Alpha: Single);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.DFM}
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Dst.Bitmap.SetSize(Src.Bitmap.Width, Src.Bitmap.Height);
+
+ // erase the transparency of edge pixels
+ SetBorderTransparent(Src.Bitmap, Rect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1));
+
+ // show the picture
+ ScaleRot(0);
+end;
+
+procedure TForm1.ScaleRot(Alpha: Single);
+var
+ SrcR: Integer;
+ SrcB: Integer;
+ T: TAffineTransformation;
+ Sx, Sy, Scale: Single;
+begin
+ SrcR := Src.Bitmap.Width - 1;
+ SrcB := Src.Bitmap.Height - 1;
+ T := TAffineTransformation.Create;
+ T.SrcRect := FloatRect(0, 0, SrcR + 1, SrcB + 1);
+ try
+ // shift the origin
+ T.Clear;
+
+ // move the origin to a center for scaling and rotation
+ T.Translate(-SrcR / 2, -SrcB / 2);
+ T.Rotate(0, 0, Alpha);
+ Alpha := Alpha * 3.14159265358979 / 180;
+
+ // get the width and height of rotated image (without scaling)
+ Sx := Abs(SrcR * Cos(Alpha)) + Abs(SrcB * Sin(Alpha));
+ Sy := Abs(SrcR * Sin(Alpha)) + Abs(SrcB * Cos(Alpha));
+
+ // calculate a new scale so that the image fits in original boundaries
+ Sx := Src.Bitmap.Width / Sx;
+ Sy := Src.Bitmap.Height / Sy;
+ scale := Min(Sx, Sy);
+
+ T.Scale(Scale, Scale);
+
+ // move the origin back
+ T.Translate(SrcR / 2, SrcB / 2);
+
+ // transform the bitmap
+ Dst.BeginUpdate;
+ Dst.Bitmap.Clear(clGray32);
+ Transform(Dst.Bitmap, Src.Bitmap, T);
+ Dst.EndUpdate;
+ Dst.Repaint;
+ finally
+ T.Free;
+ end;
+end;
+
+procedure TForm1.AngleChange(Sender: TObject);
+begin
+ ScaleRot(-Angle.Position);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.bpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.bpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.bpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="Rotate_Ex.exe"/>
+ <OBJFILES value="MainUnit.obj Rotate_Ex.obj"/>
+ <RESFILES value="Rotate_Ex.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) MainUnit.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="Vcl50.lib GR32_CB5.lib"/>
+ <PACKAGES value="Vcl50.bpi GR32_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;"/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="Rotate_Ex.cpp"/>
+ <INCLUDEPATH value="$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tW -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpe -x -Gn -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0w32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+USERES("Rotate_Ex.res");
+USEFORMNS("MainUnit.pas", Mainunit, Form1);
+//---------------------------------------------------------------------------
+WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
+{
+ try
+ {
+ Application->Initialize();
+ Application->CreateForm(__classid(TForm1), &Form1);
+ Application->Run();
+ }
+ catch (Exception &exception)
+ {
+ Application->ShowException(&exception);
+ }
+ return 0;
+}
+//---------------------------------------------------------------------------
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Rotate_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Rotate_Ex/Rotate_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,134 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ GR32, GR32_Transforms, StdCtrls, AppEvnts, GR32_Image, GR32_Layers;
+
+type
+ TForm1 = class(TForm)
+ Image32: TImage32;
+ Button1: TButton;
+ Edit1: TEdit;
+ Button2: TButton;
+ BitmapList: TBitmap32List;
+ Label1: TLabel;
+ procedure Button1Click(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ public
+ Velocities: TArrayOfFloatPoint;
+ procedure IdleHandler(Sender: TObject; var Done: Boolean);
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+{$R *.DFM}
+
+procedure TForm1.Button1Click(Sender: TObject);
+var
+ X: Integer;
+ ALayer: TBitmapLayer;
+ L: TFloatRect;
+ I: Integer;
+begin
+ Image32.BeginUpdate;
+ for X := 0 to 49 do
+ begin
+ // create a new layer...
+ ALayer := TBitmapLayer.Create(Image32.Layers);
+ with ALayer do
+ begin
+ Bitmap := BitmapList.Bitmaps[Random(BitmapList.Bitmaps.Count)].Bitmap;
+ Bitmap.DrawMode := dmBlend;
+ Bitmap.MasterAlpha := Random(255);
+
+ // put it somethere
+ L.Left := Random(Image32.Width);
+ L.Top := Random(Image32.Height);
+ L.Right := L.Left + Bitmap.Width;
+ L.Bottom := L.Top + Bitmap.Height;
+ ALayer.Location := L;
+
+ I := Length(Velocities);
+ SetLength(Velocities, I + 1);
+ Velocities[I] := FloatPoint(Random - 0.5, Random - 0.5);
+ end;
+ end;
+ Image32.EndUpdate;
+ Image32.Changed;
+ Edit1.Text := IntToStr(Image32.Layers.Count) + ' layers';
+end;
+
+procedure TForm1.IdleHandler(Sender: TObject; var Done: Boolean);
+var
+ I: Integer;
+ R: TFloatRect;
+begin
+ if Image32.Layers.Count = 0 then Exit;
+ Image32.BeginUpdate;
+ for I := 0 to Image32.Layers.Count - 1 do
+ begin
+ with TBitmapLayer(Image32.Layers[I]) do
+ begin
+ Bitmap.MasterAlpha := (Bitmap.MasterAlpha + 1) mod 256;
+ R := Location;
+ with Velocities[I] do
+ begin
+ OffsetRectF(R, X, Y);
+ X := X + (Random - 0.5) * 0.1;
+ Y := Y + (Random - 0.5) * 0.1;
+ if (R.Left < 0) and (X < 0) then X := 1;
+ if (R.Top < 0) and (Y < 0) then Y := 1;
+ if (R.Right > Image32.Width) and (X > 0) then X := -1;
+ if (R.Bottom > Image32.Height) and (Y > 0) then Y := -1;
+ end;
+ Location := R;
+ end;
+ end;
+ Image32.EndUpdate;
+ Image32.Invalidate;
+end;
+
+procedure TForm1.Button2Click(Sender: TObject);
+begin
+ Image32.Layers.Clear;
+ Velocities := nil;
+ Edit1.Text := '0 layers';
+end;
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Application.OnIdle := IdleHandler;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/Sprites_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/Sprites_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/Sprites_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Sprites_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/Sprites_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Sprites_Ex/Sprites_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/MainUnit.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/MainUnit.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/MainUnit.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/MainUnit.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/MainUnit.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,594 @@
+unit MainUnit;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ GR32, GR32_Image, GR32_Transforms, GR32_Layers, ExtCtrls, StdCtrls, Buttons,
+ ComCtrls, Grids, GR32_RangeBars;
+
+type
+ TOpType = (opNone, opTranslate, opScale, opRotate, opSkew);
+ TOpRec = record
+ OpType: TOpType;
+ Dx, Dy: Extended; // shifts for opTranslate mode
+ Sx, Sy: Extended; // scale factors for opScale mode
+ Cx, Cy, Alpha: Extended; // rotation center and angle (deg) for opRotate mode
+ Fx, Fy: Extended; // skew factors for opSkew mode
+ end;
+ TOpRecs = array[0..7] of TOpRec;
+
+const
+ OpTypes: array [0..4] of TOpType = (opNone, opTranslate, opScale, opRotate,
+ opSkew);
+
+type
+ TTransformMode = (tmAffine, tmProjective, tmBilinear);
+
+ TForm1 = class(TForm)
+ Src: TImage32;
+ Dst: TImage32;
+ PageControl1: TPageControl;
+ TabSheet1: TTabSheet;
+ Panel2: TPanel;
+ Shape1: TShape;
+ Shape2: TShape;
+ StringGrid: TStringGrid;
+ ListBox: TListBox;
+ Button1: TButton;
+ Label9: TLabel;
+ CodeString: TEdit;
+ Panel1: TPanel;
+ Label1: TLabel;
+ ComboBox: TComboBox;
+ Notebook: TNotebook;
+ Label2: TLabel;
+ Label3: TLabel;
+ Label4: TLabel;
+ Label5: TLabel;
+ eDx: TEdit;
+ eDy: TEdit;
+ Label6: TLabel;
+ Label7: TLabel;
+ Label8: TLabel;
+ eSy: TEdit;
+ eSx: TEdit;
+ Label11: TLabel;
+ Label13: TLabel;
+ Label16: TLabel;
+ Label15: TLabel;
+ eCx: TEdit;
+ eAlpha: TEdit;
+ eCy: TEdit;
+ Label12: TLabel;
+ Label14: TLabel;
+ Label17: TLabel;
+ eFx: TEdit;
+ eFy: TEdit;
+ Label10: TLabel;
+ RadioGroup1: TRadioGroup;
+ Panel3: TPanel;
+ TabSheet2: TTabSheet;
+ Label18: TLabel;
+ OpacityBar: TGaugeBar;
+ sbDx: TGaugeBar;
+ sbDy: TGaugeBar;
+ sbSx: TGaugeBar;
+ sbSy: TGaugeBar;
+ sbAlpha: TGaugeBar;
+ sbFx: TGaugeBar;
+ sbFy: TGaugeBar;
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure ListBoxClick(Sender: TObject);
+ procedure ComboBoxChange(Sender: TObject);
+ procedure TranslationChanged(Sender: TObject);
+ procedure ScaleChanged(Sender: TObject);
+ procedure TranslationScrolled(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure ScaleScrolled(Sender: TObject);
+ procedure RotationChanged(Sender: TObject);
+ procedure RotationScrolled(Sender: TObject);
+ procedure SkewChanged(Sender: TObject);
+ procedure SkewScrolled(Sender: TObject);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure OpacityChange(Sender: TObject);
+ procedure PageControl1Change(Sender: TObject);
+
+ procedure RubberLayerMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure RubberLayerMouseMove(Sender: TObject; Shift: TShiftState; X,
+ Y: Integer; Layer: TCustomLayer);
+ procedure RubberLayerMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+
+ procedure AppEventsIdle(Sender: TObject; var Done: Boolean);
+ protected
+ LoadingValues: Boolean;
+ DraggedVertex: Integer;
+ LastMousePos: TPoint;
+ StippleStart: Single;
+ procedure PaintHandles(Sender: TObject; BackBuffer: TBitmap32);
+ public
+ Operation: TOpRecs;
+ Current: ^TOpRec;
+ AT: TAffineTransformation;
+ PT: TProjectiveTransformation;
+ TT: TTransformation;
+ Vertices: array[0..3] of TPoint;
+ Mode: TTransformMode;
+ procedure ClearTransformations;
+ procedure DoTransform;
+ procedure GenTransform;
+ procedure PrepareSource;
+ procedure ShowSettings(OperationNum: Integer);
+ procedure InitVertices; // for projective mapping
+ end;
+
+var
+ Form1: TForm1;
+
+implementation
+
+function GetVal(Src: string; var Dst: Extended): Boolean;
+var
+ Code: Integer;
+begin
+ Val(Src, Dst, Code);
+ Result := Code = 0;
+end;
+
+{$R *.DFM}
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ with TCustomLayer.Create(Dst.Layers) do
+ begin
+ OnPaint := PaintHandles;
+ end;
+
+ DraggedVertex := -1;
+ Dst.SetupBitmap; // set the destination bitmap size to match the image size
+ PrepareSource;
+ ClearTransformations;
+ ShowSettings(0);
+ AT := TAffineTransformation.Create;
+ PT := TProjectiveTransformation.Create;
+ TT := AT;
+ DoTransform;
+
+ Application.OnIdle := AppEventsIdle;
+end;
+
+procedure TForm1.ClearTransformations;
+var
+ I: Integer;
+begin
+ FillChar(Operation[0], SizeOf(TOpRecs), 0);
+ for I := 0 to 7 do
+ begin
+ Operation[I].Sx := 1;
+ Operation[I].Sy := 1;
+ Operation[I].Cx := Src.Bitmap.Width / 2;
+ Operation[I].Cy := Src.Bitmap.Height / 2;
+ end;
+end;
+
+procedure TForm1.PrepareSource;
+begin
+ // make the border pixels transparent while keeping their RGB components
+ SetBorderTransparent(Src.Bitmap,
+ Rect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1));
+end;
+
+procedure TForm1.DoTransform;
+var
+ i, j: Integer;
+ P: PColor32;
+begin
+ Application.ProcessMessages;
+ GenTransform;
+ Dst.BeginUpdate;
+
+ // Fill Dst with checkerboard pattern
+ P := Dst.Bitmap.PixelPtr[0, 0];
+ for j := 0 to Dst.Bitmap.Height - 1 do
+ for i := 0 to Dst.Bitmap.Width - 1 do
+ begin
+ if Odd(i shr 4) = Odd(j shr 4) then P^ := clGray32
+ else P^ := clWhite32;
+ Inc(P);
+ end;
+
+ Transform(Dst.Bitmap, Src.Bitmap, TT);
+ Dst.EndUpdate;
+ Dst.Repaint;
+
+ if Mode = tmAffine then
+ begin
+ // fill the string grid
+ for j := 0 to 2 do
+ for i := 0 to 2 do
+ StringGrid.Cells[i, j] := Format('%.3g', [AT.Matrix[i, j]]);
+ StringGrid.Col := 3; // hide grid cursor
+ end;
+end;
+
+procedure TForm1.GenTransform;
+var
+ I: Integer;
+ Rec: TOpRec;
+ S: string;
+begin
+ TT.SrcRect := FloatRect(0, 0, Src.Bitmap.Width - 1, Src.Bitmap.Height - 1);
+ if Mode = tmProjective then
+ begin
+ PT.X0 := Vertices[0].X;
+ PT.Y0 := Vertices[0].Y;
+ PT.X1 := Vertices[1].X;
+ PT.Y1 := Vertices[1].Y;
+ PT.X2 := Vertices[2].X;
+ PT.Y2 := Vertices[2].Y;
+ PT.X3 := Vertices[3].X;
+ PT.Y3 := Vertices[3].Y;
+ end
+ else {if Mode = tmAffine then }
+ begin
+ // affine mode
+ AT.Clear;
+ for I := 0 to 7 do
+ begin
+ Rec := Operation[I];
+ case Rec.OpType of
+ opTranslate: AT.Translate(Rec.Dx, Rec.Dy);
+ opScale: AT.Scale(Rec.Sx, Rec.Sy);
+ opRotate: AT.Rotate(Rec.Cx, Rec.Cy, Rec.Alpha);
+ opSkew: AT.Skew(Rec.Fx, Rec.Fy);
+ end;
+ case Rec.OpType of
+ opTranslate: s := s + Format('Translate(%.3g, %.3g); ', [Rec.Dx, Rec.Dy]);
+ opScale: s := s + Format('Scale(%.3g, %.3g); ', [Rec.Sx, Rec.Sy]);
+ opRotate: s := s + Format('Rotate(%.3g, %.3g, %3g); ', [Rec.Cx, Rec.Cy, Rec.Alpha]);
+ opSkew: s := s + Format('Skew(%.3g, %.3g); ', [Rec.Fx, Rec.Fy]);
+ end;
+ end;
+ if Length(s) = 0 then s := 'Clear;';
+ CodeString.Text := s;
+ end;
+end;
+
+procedure TForm1.FormDestroy(Sender: TObject);
+begin
+ AT.Free;
+ PT.Free;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+begin
+ ClearTransformations;
+ ShowSettings(Listbox.ItemIndex);
+ DoTransform;
+end;
+
+procedure TForm1.ListBoxClick(Sender: TObject);
+begin
+ ShowSettings(ListBox.ItemIndex);
+end;
+
+procedure TForm1.ShowSettings(OperationNum: Integer);
+begin
+ LoadingValues := True;
+ ListBox.ItemIndex := OperationNum;
+ Current := @Operation[OperationNum];
+ Combobox.ItemIndex := Ord(Current.OpType);
+ NoteBook.PageIndex := Ord(Current.OpType);
+ eDx.Text := Format('%.4g', [Current.Dx]);
+ eDy.Text := Format('%.4g', [Current.Dy]);
+ sbDx.Position := Round(Current.Dx * 10);
+ sbDy.Position := Round(Current.Dy * 10);
+ eSx.Text := Format('%.4g', [Current.Sx]);
+ eSy.Text := Format('%.4g', [Current.Sy]);
+ sbSx.Position := Round(Current.Sx * 100);
+ sbSy.Position := Round(Current.Sy * 100);
+ eCx.Text := Format('%.4g', [Current.Cx]);
+ eCy.Text := Format('%.4g', [Current.Cy]);
+ eAlpha.Text := Format('%.4g', [Current.Alpha]);
+ sbAlpha.Position := Round(Current.Alpha * 2);
+ eFx.Text := Format('%.4g', [Current.Fx]);
+ eFy.Text := Format('%.4g', [Current.Fy]);
+ sbFx.Position := Round(Current.Fx * 100);
+ sbFy.Position := Round(Current.Fy * 100);
+ LoadingValues := False;
+end;
+
+procedure TForm1.ComboBoxChange(Sender: TObject);
+begin
+ Current.OpType := OpTypes[ComboBox.ItemIndex];
+ ShowSettings(ListBox.ItemIndex);
+ DoTransform;
+end;
+
+procedure TForm1.TranslationChanged(Sender: TObject);
+var
+ Tx, Ty: Extended;
+begin
+ if LoadingValues then Exit;
+ if GetVal(eDx.Text, Tx) and GetVal(eDy.Text, Ty) then
+ begin
+ Current.Dx := Tx;
+ Current.Dy := Ty;
+ DoTransform;
+ LoadingValues := True;
+ sbDx.Position := Round(Current.Dx * 10);
+ sbDy.Position := Round(Current.Dy * 10);
+ LoadingValues := False;
+ end;
+end;
+
+procedure TForm1.TranslationScrolled(Sender: TObject);
+begin
+ if LoadingValues then Exit;
+ Current.Dx := sbDx.Position / 10;
+ Current.Dy := sbDy.Position / 10;
+ DoTransform;
+ LoadingValues := True;
+ eDx.Text := FloatToStr(Current.Dx);
+ eDy.Text := FloatToStr(Current.Dy);
+ LoadingValues := False;
+end;
+
+procedure TForm1.ScaleChanged(Sender: TObject);
+var
+ Sx, Sy: Extended;
+begin
+ if LoadingValues then Exit;
+ if GetVal(eSx.Text, Sx) and GetVal(eSy.Text, Sy) then
+ begin
+ Current.Sx := Sx;
+ Current.Sy := Sy;
+ DoTransform;
+ LoadingValues := True;
+ sbSx.Position := Round(Current.Sx * 100);
+ sbSy.Position := Round(Current.Sy * 100);
+ LoadingValues := False;
+ end;
+end;
+
+procedure TForm1.ScaleScrolled(Sender: TObject);
+begin
+ if LoadingValues then Exit;
+ Current.Sx := sbSx.Position / 100;
+ Current.Sy := sbSy.Position / 100;
+ DoTransform;
+ LoadingValues := True;
+ eSx.Text := FloatToStr(Current.Sx);
+ eSy.Text := FloatToStr(Current.Sy);
+ LoadingValues := False;
+end;
+
+procedure TForm1.RotationChanged(Sender: TObject);
+var
+ Cx, Cy, Alpha: Extended;
+begin
+ if LoadingValues then Exit;
+ if GetVal(eCx.Text, Cx) and GetVal(eCy.Text, Cy) and
+ GetVal(eAlpha.Text, Alpha) then
+ begin
+ Current.Cx := Cx;
+ Current.Cy := Cy;
+ Current.Alpha := Alpha;
+ DoTransform;
+ LoadingValues := True;
+ sbAlpha.Position := Round(Alpha * 2);
+ LoadingValues := False;
+ end;
+end;
+
+procedure TForm1.RotationScrolled(Sender: TObject);
+begin
+ if LoadingValues then Exit;
+ Current.Alpha := sbAlpha.Position / 2;
+ DoTransform;
+ LoadingValues := True;
+ eAlpha.Text := FloatToStr(Current.Alpha / 2);
+ LoadingValues := False;
+end;
+
+procedure TForm1.SkewChanged(Sender: TObject);
+var
+ Fx, Fy: Extended;
+begin
+ if LoadingValues then Exit;
+ if GetVal(eFx.Text, Fx) and GetVal(eFy.Text, Fy) then
+ begin
+ Current.Fx := Fx;
+ Current.Fy := Fy;
+ DoTransform;
+ LoadingValues := True;
+ sbFx.Position := Round(Current.Fx * 10);
+ sbFy.Position := Round(Current.Fy * 10);
+ LoadingValues := False;
+ end;
+end;
+
+procedure TForm1.SkewScrolled(Sender: TObject);
+begin
+ if LoadingValues then Exit;
+ Current.Fx := sbFx.Position / 10;
+ Current.Fy := sbFy.Position / 10;
+ DoTransform;
+ LoadingValues := True;
+ eFx.Text := FloatToStr(Current.Fx);
+ eFy.Text := FloatToStr(Current.Fy);
+ LoadingValues := False;
+end;
+
+procedure TForm1.RadioGroup1Click(Sender: TObject);
+const
+ STRETCH_FILTER: array [0..1] of TStretchFilter = (sfNearest, sfLinear);
+begin
+ Src.Bitmap.StretchFilter := STRETCH_FILTER[RadioGroup1.ItemIndex];
+ DoTransform;
+end;
+
+procedure TForm1.OpacityChange(Sender: TObject);
+begin
+ OpacityBar.Update;
+ Src.Bitmap.MasterAlpha := OpacityBar.Position;
+ DoTransform;
+end;
+
+procedure TForm1.InitVertices;
+begin
+ Vertices[0].X := 0;
+ Vertices[0].Y := 0;
+ Vertices[1].X := Src.Bitmap.Width - 1;
+ Vertices[1].Y := 0;
+ Vertices[2].X := Src.Bitmap.Width - 1;
+ Vertices[2].Y := Src.Bitmap.Height - 1;
+ Vertices[3].X := 0;
+ Vertices[3].Y := Src.Bitmap.Height - 1;
+end;
+
+procedure TForm1.PageControl1Change(Sender: TObject);
+begin
+ if PageControl1.ActivePage = TabSheet1 then
+ begin
+ Mode := tmAffine;
+ TT := AT;
+ RadioGroup1.Parent := TabSheet1;
+ end
+ else {if PageControl1.ActivePage = TabSheet2 then }
+ begin
+ // set current transformation as projective
+ Mode := tmProjective;
+ TT := PT;
+ InitVertices;
+ RadioGroup1.Parent := TabSheet2;
+ end;
+ DoTransform;
+end;
+
+procedure TForm1.RubberLayerMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+var
+ I: Integer;
+begin
+ if Mode = tmAffine then Exit;
+
+ DraggedVertex := -1;
+
+ // find the vertex to drag
+ for I := 0 to 3 do
+ if (Abs(Vertices[I].X - X) < 3) and (Abs(Vertices[I].Y - Y) < 3) then
+ begin
+ DraggedVertex := I;
+ Break;
+ end;
+
+ // or drag all of them, (DragVertex = 4)
+ if DraggedVertex = -1 then DraggedVertex := 4;
+
+ // store current mouse position
+ LastMousePos := Point(X, Y);
+end;
+
+procedure TForm1.RubberLayerMouseMove(Sender: TObject; Shift: TShiftState;
+ X, Y: Integer; Layer: TCustomLayer);
+var
+ Dx, Dy, I: Integer;
+begin
+ if Mode = tmAffine then Exit;
+
+ if DraggedVertex = -1 then Exit; // mouse is not pressed
+
+ Dx := X - LastMousePos.X;
+ Dy := Y - LastMousePos.Y;
+ LastMousePos := Point(X, Y);
+
+ // update coords
+ if DraggedVertex = 4 then
+ begin
+ for I := 0 to 3 do
+ begin
+ Inc(Vertices[I].X, Dx);
+ Inc(Vertices[I].Y, Dy);
+ end;
+ end
+ else
+ begin
+ Inc(Vertices[DraggedVertex].X, Dx);
+ Inc(Vertices[DraggedVertex].Y, Dy);
+ end;
+
+ DoTransform;
+end;
+
+procedure TForm1.RubberLayerMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ DraggedVertex := -1;
+end;
+
+procedure TForm1.AppEventsIdle(Sender: TObject; var Done: Boolean);
+begin
+ StippleStart := StippleStart - 0.05;
+ Dst.Invalidate;
+end;
+
+procedure TForm1.PaintHandles(Sender: TObject; BackBuffer: TBitmap32);
+var
+ I, X0, Y0, X1, Y1: Integer;
+
+ procedure PaintVertex(X, Y: Integer);
+ begin
+ BackBuffer.FillRectS(X - 2, Y - 2, X + 2, Y + 2, clWhite32);
+ BackBuffer.FrameRectS(X - 3, Y - 3, X + 3, Y + 3, clBlack32);
+ end;
+
+begin
+ if PageControl1.ActivePage = TabSheet1 then Exit;
+
+ BackBuffer.SetStipple([clBlack32, clBlack32, clWhite32, clWhite32]);
+ BackBuffer.StippleStep := 0.5;
+ BackBuffer.StippleCounter := StippleStart;
+
+ X0 := Vertices[3].X;
+ Y0 := Vertices[3].Y;
+ for I := 0 to 3 do
+ begin
+ X1 := Vertices[I].X;
+ Y1 := Vertices[I].Y;
+ BackBuffer.LineFSP(X0, Y0, X1, Y1);
+ X0 := X1;
+ Y0 := Y1;
+ end;
+ for I := 0 to 3 do PaintVertex(Vertices[I].X, Vertices[I].Y);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/Transform_Ex.dpr
===================================================================
--- trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/Transform_Ex.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/Transform_Ex.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program Transform_Ex;
+
+uses
+ Forms,
+ MainUnit in 'MainUnit.pas' {Form1};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/Transform_Ex.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Examples/Vcl/Transform_Ex/Transform_Ex.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32.inc
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32.inc 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32.inc 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,66 @@
+{$IFDEF VER150}
+ {$DEFINE COMPILER7}
+ {$DEFINE COMPILER6}
+ {$DEFINE COMPILER5}
+ {$DEFINE COMPILER4}
+ {$IFNDEF BCB}
+ {$DEFINE DELPHI7}
+ {$ELSE}
+ {$DEFINE BCB7}
+ {$ENDIF}
+{$ENDIF}
+
+{$IFDEF VER140}
+ {$DEFINE COMPILER6}
+ {$DEFINE COMPILER5}
+ {$DEFINE COMPILER4}
+ {$IFNDEF BCB}
+ {$DEFINE DELPHI6}
+ {$ELSE}
+ {$DEFINE BCB6}
+ {$ENDIF}
+{$ENDIF}
+
+{$IFDEF VER130}
+ {$DEFINE COMPILER5}
+ {$DEFINE COMPILER4}
+ {$IFNDEF BCB}
+ {$DEFINE DELPHI5}
+ {$DEFINE DELPHI4}
+ {$ELSE}
+ {$ObjExportAll On}
+ {$DEFINE BCB5}
+ {$DEFINE BCB4}
+ {$ENDIF}
+{$ENDIF}
+
+{$IFDEF VER125}
+ {$DEFINE COMPILER4}
+ {$DEFINE BCB4}
+{$ENDIF}
+
+{$IFDEF VER120}
+ {$DEFINE COMPILER4}
+ {$DEFINE DELPHI4}
+{$ENDIF}
+
+{$IFNDEF COMPILER4}
+//////////////////////////////////////////////////////////////////////
+' Graphics32 may only be installed with Delphi 4, Delphi 5, '
+' Delphi6, Delphi7, C++ Builder 4, C++ Builder 5, or C++Builder 6 ! '
+//////////////////////////////////////////////////////////////////////
+{$ENDIF}
+
+{$IFDEF DELPHI5}
+ {$DEFINE EXT_PROP_EDIT}
+{$ENDIF}
+
+{$IFDEF LINUX}
+ {$DEFINE CLX}
+{$ENDIF}
+
+//{$DEFINE CLX} // uncomment this if you want CLX for Windows
+
+{$R-}{$Q-} // switch off overflow and range checking
+
+{$DEFINE XPTHEMES} // enable support for windows xp themes
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/GR32.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,4100 @@
+unit GR32;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Michael Hansen <dyster_tid at hotmail.com>
+ * Andre Beckedorf <Andre at metaException.de>
+ * Mattias Andersson <mattias at centaurix.com>
+ * J. Tulach <tulach at position.cz>
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32.pas,v 1.2 2004/07/07 11:39:58 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+{$IFDEF CLX}
+ Qt, Types,
+ {$IFDEF LINUX}Libc,{$ENDIF}
+ {$IFDEF MSWINDOWS}Windows,{$ENDIF}
+{$ELSE}
+ Windows,
+{$ENDIF}
+ Classes, SysUtils,
+{$IFDEF CLX}
+ QControls, QGraphics, QConsts
+{$ELSE}
+ Messages, Controls, Graphics
+{$ENDIF};
+
+{ Version Control }
+
+const
+ Graphics32Version = '1.6.0';
+
+{ 32-bit Color }
+
+type
+ PColor32 = ^TColor32;
+ TColor32 = type Cardinal;
+
+ PColor32Array = ^TColor32Array;
+ TColor32Array = array [0..0] of TColor32;
+ TArrayOfColor32 = array of TColor32;
+
+ PPalette32 = ^TPalette32;
+ TPalette32 = array [Byte] of TColor32;
+
+const
+ // Some predefined color constants
+ clBlack32 = TColor32($FF000000);
+ clDimGray32 = TColor32($FF3F3F3F);
+ clGray32 = TColor32($FF7F7F7F);
+ clLightGray32 = TColor32($FFBFBFBF);
+ clWhite32 = TColor32($FFFFFFFF);
+ clMaroon32 = TColor32($FF7F0000);
+ clGreen32 = TColor32($FF007F00);
+ clOlive32 = TColor32($FF7F7F00);
+ clNavy32 = TColor32($FF00007F);
+ clPurple32 = TColor32($FF7F007F);
+ clTeal32 = TColor32($FF007F7F);
+ clRed32 = TColor32($FFFF0000);
+ clLime32 = TColor32($FF00FF00);
+ clYellow32 = TColor32($FFFFFF00);
+ clBlue32 = TColor32($FF0000FF);
+ clFuchsia32 = TColor32($FFFF00FF);
+ clAqua32 = TColor32($FF00FFFF);
+
+ // Some semi-transparent color constants
+ clTrWhite32 = TColor32($7FFFFFFF);
+ clTrBlack32 = TColor32($7F000000);
+ clTrRed32 = TColor32($7FFF0000);
+ clTrGreen32 = TColor32($7F00FF00);
+ clTrBlue32 = TColor32($7F0000FF);
+
+// Color construction and conversion functions
+function Color32(WinColor: TColor): TColor32; overload;
+function Color32(R, G, B: Byte; A: Byte = $FF): TColor32; overload;
+function Color32(Index: Byte; var Palette: TPalette32): TColor32; overload;
+function Gray32(Intensity: Byte; Alpha: Byte = $FF): TColor32;
+function WinColor(Color32: TColor32): TColor;
+function ArrayOfColor32(Colors: array of TColor32): TArrayOfColor32;
+
+// Color component access
+function RedComponent(Color32: TColor32): Integer;
+function GreenComponent(Color32: TColor32): Integer;
+function BlueComponent(Color32: TColor32): Integer;
+function AlphaComponent(Color32: TColor32): Integer;
+function Intensity(Color32: TColor32): Integer;
+function SetAlpha(Color32: TColor32; NewAlpha: Integer): TColor32;
+
+// Color space conversion
+function HSLtoRGB(H, S, L: Single): TColor32;
+procedure RGBtoHSL(RGB: TColor32; out H, S, L : Single);
+
+{$IFNDEF CLX}
+// Palette conversion functions
+function WinPalette(const P: TPalette32): HPALETTE;
+{$ENDIF}
+
+{ A fixed-point type }
+
+type
+ // this type has data bits arrangement compatible with Windows.TFixed
+ TFixed = type Integer;
+ PFixed = ^TFixed;
+
+ // a little bit of fixed point math
+ function Fixed(S: Single): TFixed; overload;
+ function Fixed(I: Integer): TFixed; overload;
+ function FixedFloor(A: TFixed): Integer;
+ function FixedCeil(A: TFixed): Integer;
+ function FixedMul(A, B: TFixed): TFixed;
+ function FixedDiv(A, B: TFixed): TFixed;
+ function FixedRound(A: TFixed): Integer;
+
+{ Points }
+
+type
+ TPoint = {$IFDEF CLX}Types{$ELSE}Windows{$ENDIF}.TPoint;
+ PPoint = ^TPoint;
+ TFloatPoint = record
+ X, Y: Single;
+ end;
+ PFloatPoint = ^TFloatPoint;
+ TFixedPoint = record
+ X, Y: TFixed;
+ end;
+ PFixedPoint = ^TFixedPoint;
+ TArrayOfPoint = array of TPoint;
+ TArrayOfArrayOfPoint = array of TArrayOfPoint;
+ TArrayOfFloatPoint = array of TFloatPoint;
+ TArrayOfArrayOfFloatPoint = array of TArrayOfFloatPoint;
+ TArrayOfFixedPoint = array of TFixedPoint;
+ TArrayOfArrayOfFixedPoint = array of TArrayOfFixedPoint;
+
+// construction and conversion of point types
+function Point(X, Y: Integer): TPoint; overload;
+function Point(const FP: TFloatPoint): TPoint; overload;
+function Point(const FXP: TFixedPoint): TPoint; overload;
+function FloatPoint(X, Y: Single): TFloatPoint; overload;
+function FloatPoint(const P: TPoint): TFloatPoint; overload;
+function FloatPoint(const FXP: TFixedPoint): TFloatPoint; overload;
+function FixedPoint(X, Y: Integer): TFixedPoint; overload;
+function FixedPoint(X, Y: Single): TFixedPoint; overload;
+function FixedPoint(const P: TPoint): TFixedPoint; overload;
+function FixedPoint(const FP: TFloatPoint): TFixedPoint; overload;
+
+{ Rectangles }
+
+type
+ TFloatRect = packed record
+ case Integer of
+ 0: (Left, Top, Right, Bottom: Single);
+ 1: (TopLeft, BottomRight: TFloatPoint);
+ end;
+ TFixedRect = packed record
+ case Integer of
+ 0: (Left, Top, Right, Bottom: TFixed);
+ 1: (TopLeft, BottomRight: TFixedPoint);
+ end;
+ TRectRounding = (rrClosest, rrOutside, rrInside);
+
+// Rectangle construction/conversion functions
+function MakeRect(L, T, R, B: Integer): TRect; overload;
+function MakeRect(const FR: TFloatRect; Rounding: TRectRounding = rrClosest): TRect; overload;
+function MakeRect(const FXR: TFixedRect; Rounding: TRectRounding = rrClosest): TRect; overload;
+function FloatRect(L, T, R, B: Single): TFloatRect; overload;
+function FloatRect(const ARect: TRect): TFloatRect; overload;
+
+// Some basic operations over rectangles
+function IntersectRect(out Dst: TRect; const R1, R2: TRect): Boolean;
+function IntersectRectF(out Dst: TFloatRect; const FR1, FR2: TFloatRect): Boolean;
+function EqualRect(const R1, R2: TRect): Boolean;
+procedure InflateRect(var R: TRect; Dx, Dy: Integer); overload;
+procedure InflateRectF(var FR: TFloatRect; Dx, Dy: Single);
+procedure OffsetRect(var R: TRect; Dx, Dy: Integer); overload;
+procedure OffsetRectF(var FR: TFloatRect; Dx, Dy: Single); overload;
+function IsRectEmpty(const R: TRect): Boolean; overload;
+function IsRectEmptyF(const FR: TFloatRect): Boolean; overload;
+function PtInRect(const R: TRect; const P: TPoint): Boolean;
+
+
+{ Other dynamic arrays }
+type
+ TArrayOfByte = array of Byte;
+ TArrayOfInteger = array of Integer;
+ TArrayOfArrayOfInteger = array of TArrayOfInteger;
+ TArrayOfSingle = array of Single;
+
+{$IFDEF CLX}
+ HBITMAP = QImageH;
+ HDC = QPainterH;
+ HFont = QFontH;
+{$ENDIF}
+
+{ TBitmap32 draw mode }
+type
+ TDrawMode = (dmOpaque, dmBlend, dmCustom);
+
+
+{ Stretch filters }
+ TStretchFilter = (sfNearest, sfDraft, sfLinear, sfCosine, sfSpline, sfLanczos, sfMitchell);
+
+{ Gamma bias for line/pixel antialiasing }
+
+var
+ GAMMA_TABLE: array [Byte] of Byte;
+
+procedure SetGamma(Gamma: Single = 0.7);
+
+{$IFDEF CLX}
+{ TextOut Flags for WinAPI compatibility }
+const
+ DT_LEFT = Integer(AlignmentFlags_AlignLeft);
+ DT_RIGHT = Integer(AlignmentFlags_AlignRight);
+ DT_TOP = Integer(AlignmentFlags_AlignTop);
+ DT_BOTTOM = Integer(AlignmentFlags_AlignBottom);
+ DT_CENTER = Integer(AlignmentFlags_AlignHCenter);
+ DT_VCENTER = Integer(AlignmentFlags_AlignVCenter);
+ DT_EXPANDTABS = Integer(AlignmentFlags_ExpandTabs);
+ DT_NOCLIP = Integer(AlignmentFlags_DontClip);
+ DT_WORDBREAK = Integer(AlignmentFlags_WordBreak);
+ DT_SINGLELINE = Integer(AlignmentFlags_SingleLine);
+{ missing since there is no QT equivalent:
+ DT_CALCRECT (make no sense with TBitmap32.TextOut[2])
+ DT_EDITCONTOL
+ DT_END_ELLIPSIS and DT_PATH_ELLIPSIS
+ DT_EXTERNALLEADING
+ DT_MODIFYSTRING
+ DT_NOPREFIX
+ DT_RTLREADING
+ DT_TABSTOP
+}
+{$ENDIF}
+
+type
+ { TThreadPersistent }
+ { TThreadPersistent is an ancestor for TBitmap32 object. In addition to
+ TPersistent methods, it provides thread-safe locking and change notification }
+ TThreadPersistent = class(TPersistent)
+ private
+ FLock: TRTLCriticalSection;
+ FLockCount: Integer;
+ FUpdateCount: Integer;
+ FOnChange: TNotifyEvent;
+ protected
+ property LockCount: Integer read FLockCount;
+ property UpdateCount: Integer read FUpdateCount;
+ public
+ constructor Create; virtual;
+ destructor Destroy; override;
+ procedure Changed; virtual;
+ procedure BeginUpdate;
+ procedure EndUpdate;
+ procedure Lock;
+ procedure Unlock;
+ property OnChange: TNotifyEvent read FOnChange write FOnChange;
+ end;
+
+ { TCustomMap }
+ { An ancestor for bitmaps and similar 2D distributions wich have width and
+ height properties }
+ TCustomMap = class(TThreadPersistent)
+ private
+ FHeight: Integer;
+ FWidth: Integer;
+ FOnResize: TNotifyEvent;
+ procedure SetHeight(NewHeight: Integer);
+ procedure SetWidth(NewWidth: Integer);
+ protected
+ procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); virtual;
+ public
+ procedure Delete; virtual;
+ function Empty: Boolean; virtual;
+ procedure Resized; virtual;
+ function SetSizeFrom(Source: TPersistent): Boolean;
+ function SetSize(NewWidth, NewHeight: Integer): Boolean; virtual;
+ property Height: Integer read FHeight write SetHeight;
+ property Width: Integer read FWidth write SetWidth;
+ property OnResize: TNotifyEvent read FOnResize write FOnResize;
+ end;
+
+ { TBitmap32 }
+ { This is the core of Graphics32 unit. The TBitmap32 class is responsible
+ for storage of a bitmap, as well as for drawing in it.
+ The OnCombine event is fired only when DrawMode is set to dmCustom and two
+ bitmaps are blended together. Unlike most normal events, it does contain
+ "Sender" parameter and is not called through some virtual method. This
+ (a little bit non-standard) approach allows for faster operation }
+
+ TPixelCombineEvent = procedure(F: TColor32; var B: TColor32; M: TColor32) of object;
+
+ TBitmap32 = class(TCustomMap)
+ private
+ FBits: PColor32Array;
+ FCanvas: TCanvas;
+ FDrawMode: TDrawMode;
+ FFont: TFont;
+ FHandle: HBITMAP;
+ FHDC: HDC;
+{$IFDEF CLX}
+ FPixmap: QPixmapH;
+ FPainterCount: Integer;
+ FPixmapActive: Boolean;
+ FPixmapChanged: Boolean;
+{$ELSE}
+ FBitmapInfo: TBitmapInfo;
+{$ENDIF}
+ FMasterAlpha: Cardinal;
+ FOuterColor: TColor32;
+ FPenColor: TColor32;
+ FStippleCounter: Single;
+ FStipplePattern: TArrayOfColor32;
+ FStippleStep: Single;
+ FStretchFilter: TStretchFilter;
+ FOnHandleChanged: TNotifyEvent;
+ FOnPixelCombine: TPixelCombineEvent;
+ procedure FontChanged(Sender: TObject);
+ procedure CanvasChanged(Sender: TObject);
+ function GetCanvas: TCanvas;
+ function GetPixel(X, Y: Integer): TColor32;
+ function GetPixelS(X, Y: Integer): TColor32;
+ function GetPixelF(X, Y: Single): TColor32;
+ function GetPixelFS(X, Y: Single): TColor32;
+ function GetPixelX(X, Y: TFixed): TColor32;
+ function GetPixelXS(X, Y: TFixed): TColor32;
+ function GetPixelPtr(X, Y: Integer): PColor32;
+ function GetScanLine(Y: Integer): PColor32Array;
+{$IFDEF CLX}
+ function GetBits: PColor32Array;
+ function GetPixmap: QPixmapH;
+ function GetPainter: QPainterH;
+{$ENDIF}
+ procedure SetDrawMode(Value: TDrawMode);
+ procedure SetFont(Value: TFont);
+ procedure SetMasterAlpha(Value: Cardinal);
+ procedure SetPixel(X, Y: Integer; Value: TColor32);
+ procedure SetPixelS(X, Y: Integer; Value: TColor32);
+ procedure SetStretchFilter(Value: TStretchFilter);
+ procedure TextScaleDown(const B, B2: TBitmap32; const N: Integer;
+ const Color: TColor32);
+ procedure TextBlueToAlpha(const B: TBitmap32; const Color: TColor32);
+ protected
+ FontHandle: HFont;
+ RasterX, RasterY: Integer;
+ RasterXF, RasterYF: TFixed;
+ procedure AssignTo(Dst: TPersistent); override;
+ procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
+ procedure HandleChanged; virtual;
+ function Equal(B: TBitmap32): Boolean;
+ procedure SET_T256(X, Y: Integer; C: TColor32);
+ procedure SET_TS256(X, Y: Integer; C: TColor32);
+ function GET_T256(X, Y: Integer): TColor32;
+ function GET_TS256(X, Y: Integer): TColor32;
+ procedure ReadData(Stream: TStream); virtual;
+ procedure WriteData(Stream: TStream); virtual;
+ procedure DefineProperties(Filer: TFiler); override;
+ function GetPixelB(X, Y: Integer): TColor32;
+{$IFDEF CLX}
+ procedure PixmapNeeded;
+ procedure ImageNeeded;
+ procedure CheckPixmap;
+ procedure StartPainter;
+ procedure StopPainter;
+{$ENDIF}
+ public
+ constructor Create; override;
+ destructor Destroy; override;
+
+ procedure Assign(Source: TPersistent); override;
+ function BoundsRect: TRect;
+ function Empty: Boolean; override;
+ procedure Clear; overload;
+ procedure Clear(FillColor: TColor32); overload;
+ procedure Delete; override;
+
+ procedure LoadFromStream(Stream: TStream);
+ procedure SaveToStream(Stream: TStream);
+ procedure LoadFromFile(const FileName: string);
+ procedure SaveToFile(const FileName: string);
+ procedure LoadFromResourceID(Instance: THandle; ResID: Integer);
+ procedure LoadFromResourceName(Instance: THandle; const ResName: string);
+
+ procedure ResetAlpha;
+
+ procedure Draw(DstX, DstY: Integer; Src: TBitmap32); overload;
+ procedure Draw(DstX, DstY: Integer; const SrcRect: TRect; Src: TBitmap32); overload;
+ procedure Draw(const DstRect, SrcRect: TRect; Src: TBitmap32); overload;
+{$IFDEF CLX}
+ procedure Draw(const DstRect, SrcRect: TRect; SrcPixmap: QPixmapH); overload;
+{$ELSE}
+ procedure Draw(const DstRect, SrcRect: TRect; hSrc: HDC); overload;
+{$ENDIF}
+
+ procedure DrawTo(Dst: TBitmap32); overload;
+ procedure DrawTo(Dst: TBitmap32; DstX, DstY: Integer; const SrcRect: TRect); overload;
+ procedure DrawTo(Dst: TBitmap32; DstX, DstY: Integer); overload;
+ procedure DrawTo(Dst: TBitmap32; const DstRect: TRect); overload;
+ procedure DrawTo(Dst: TBitmap32; const DstRect, SrcRect: TRect); overload;
+ procedure DrawTo(hDst: HDC; DstX, DstY: Integer); overload;
+ procedure DrawTo(hDst: HDC; const DstRect, SrcRect: TRect); overload;
+ procedure TileTo(hDst: HDC; const DstRect, SrcRect: TRect);
+
+ procedure SetPixelT(X, Y: Integer; Value: TColor32); overload;
+ procedure SetPixelT(var Ptr: PColor32; Value: TColor32); overload;
+ procedure SetPixelTS(X, Y: Integer; Value: TColor32);
+ procedure SetPixelF(X, Y: Single; Value: TColor32); {$IFDEF COMPILER6}deprecated;{$ENDIF}
+ procedure SetPixelX(X, Y: TFixed; Value: TColor32); {$IFDEF COMPILER6}deprecated;{$ENDIF}
+ procedure SetPixelFS(X, Y: Single; Value: TColor32); {$IFDEF COMPILER6}deprecated;{$ENDIF}
+ procedure SetPixelXS(X, Y: TFixed; Value: TColor32); {$IFDEF COMPILER6}deprecated;{$ENDIF}
+
+ procedure SetStipple(NewStipple: TArrayOfColor32); overload;
+ procedure SetStipple(NewStipple: array of TColor32); overload;
+ procedure AdvanceStippleCounter(LengthPixels: Single);
+ function GetStippleColor: TColor32;
+
+ procedure HorzLine(X1, Y, X2: Integer; Value: TColor32);
+ procedure HorzLineS(X1, Y, X2: Integer; Value: TColor32);
+ procedure HorzLineT(X1, Y, X2: Integer; Value: TColor32);
+ procedure HorzLineTS(X1, Y, X2: Integer; Value: TColor32);
+ procedure HorzLineTSP(X1, Y, X2: Integer);
+
+ procedure VertLine(X, Y1, Y2: Integer; Value: TColor32);
+ procedure VertLineS(X, Y1, Y2: Integer; Value: TColor32);
+ procedure VertLineT(X, Y1, Y2: Integer; Value: TColor32);
+ procedure VertLineTS(X, Y1, Y2: Integer; Value: TColor32);
+ procedure VertLineTSP(X, Y1, Y2: Integer);
+
+ procedure Line(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean = False);
+ procedure LineS(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean = False);
+ procedure LineT(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean = False);
+ procedure LineTS(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean = False);
+ procedure LineA(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean = False);
+ procedure LineAS(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean = False);
+ procedure LineX(X1, Y1, X2, Y2: TFixed; Value: TColor32; L: Boolean = False); overload;
+ procedure LineF(X1, Y1, X2, Y2: Single; Value: TColor32; L: Boolean = False); overload;
+ procedure LineXS(X1, Y1, X2, Y2: TFixed; Value: TColor32; L: Boolean = False); overload;
+ procedure LineFS(X1, Y1, X2, Y2: Single; Value: TColor32; L: Boolean = False); overload;
+ procedure LineXP(X1, Y1, X2, Y2: TFixed; L: Boolean = False); overload;
+ procedure LineFP(X1, Y1, X2, Y2: Single; L: Boolean = False); overload;
+ procedure LineXSP(X1, Y1, X2, Y2: TFixed; L: Boolean = False); overload;
+ procedure LineFSP(X1, Y1, X2, Y2: Single; L: Boolean = False); overload;
+
+ property PenColor: TColor32 read FPenColor write FPenColor;
+ procedure MoveTo(X, Y: Integer);
+ procedure LineToS(X, Y: Integer);
+ procedure LineToTS(X, Y: Integer);
+ procedure LineToAS(X, Y: Integer);
+ procedure MoveToX(X, Y: TFixed);
+ procedure MoveToF(X, Y: Single);
+ procedure LineToXS(X, Y: TFixed);
+ procedure LineToFS(X, Y: Single);
+ procedure LineToXSP(X, Y: TFixed);
+ procedure LineToFSP(X, Y: Single);
+
+ procedure FillRect(X1, Y1, X2, Y2: Integer; Value: TColor32);
+ procedure FillRectS(X1, Y1, X2, Y2: Integer; Value: TColor32); overload;
+ procedure FillRectT(X1, Y1, X2, Y2: Integer; Value: TColor32);
+ procedure FillRectTS(X1, Y1, X2, Y2: Integer; Value: TColor32); overload;
+ procedure FillRectS(const ARect: TRect; Value: TColor32); overload;
+ procedure FillRectTS(const ARect: TRect; Value: TColor32); overload;
+
+ procedure FrameRectS(X1, Y1, X2, Y2: Integer; Value: TColor32); overload;
+ procedure FrameRectTS(X1, Y1, X2, Y2: Integer; Value: TColor32); overload;
+ procedure FrameRectTSP(X1, Y1, X2, Y2: Integer);
+ procedure FrameRectS(const ARect: TRect; Value: TColor32); overload;
+ procedure FrameRectTS(const ARect: TRect; Value: TColor32); overload;
+
+ procedure RaiseRectTS(X1, Y1, X2, Y2: Integer; Contrast: Integer); overload;
+ procedure RaiseRectTS(const ARect: TRect; Contrast: Integer); overload;
+
+ procedure UpdateFont;
+{$IFDEF CLX}
+ procedure Textout(X, Y: Integer; const Text: Widestring); overload;
+ procedure Textout(X, Y: Integer; const ClipRect: TRect; const Text: Widestring); overload;
+ procedure Textout(DstRect: TRect; const Flags: Cardinal; const Text: Widestring); overload;
+ function TextExtent(const Text: Widestring): TSize;
+ function TextHeight(const Text: Widestring): Integer;
+ function TextWidth(const Text: Widestring): Integer;
+ procedure RenderText(X, Y: Integer; const Text: Widestring; AALevel: Integer; Color: TColor32);
+{$ELSE}
+ procedure Textout(X, Y: Integer; const Text: String); overload;
+ procedure Textout(X, Y: Integer; const ClipRect: TRect; const Text: String); overload;
+ procedure Textout(DstRect: TRect; const Flags: Cardinal; const Text: String); overload;
+ function TextExtent(const Text: String): TSize;
+ function TextHeight(const Text: String): Integer;
+ function TextWidth(const Text: String): Integer;
+ procedure RenderText(X, Y: Integer; const Text: String; AALevel: Integer; Color: TColor32);
+{$ENDIF}
+ procedure TextoutW(X, Y: Integer; const Text: Widestring); overload;
+ procedure TextoutW(X, Y: Integer; const ClipRect: TRect; const Text: Widestring); overload;
+ procedure TextoutW(DstRect: TRect; const Flags: Cardinal; const Text: Widestring); overload;
+ function TextExtentW(const Text: Widestring): TSize;
+ function TextHeightW(const Text: Widestring): Integer;
+ function TextWidthW(const Text: Widestring): Integer;
+ procedure RenderTextW(X, Y: Integer; const Text: Widestring; AALevel: Integer; Color: TColor32);
+
+ procedure Roll(Dx, Dy: Integer; FillBack: Boolean; FillColor: TColor32);
+ procedure FlipHorz(Dst: TBitmap32 = nil);
+ procedure FlipVert(Dst: TBitmap32 = nil);
+ procedure Rotate90(Dst: TBitmap32 = nil);
+ procedure Rotate180(Dst: TBitmap32 = nil);
+ procedure Rotate270(Dst: TBitmap32 = nil);
+
+ property Canvas: TCanvas read GetCanvas;
+ function CanvasAllocated: Boolean;
+ procedure DeleteCanvas;
+
+ property Pixel[X, Y: Integer]: TColor32 read GetPixel write SetPixel; default;
+ property PixelS[X, Y: Integer]: TColor32 read GetPixelS write SetPixelS;
+ property PixelX[X, Y: TFixed]: TColor32 read GetPixelX write SetPixelX;
+ property PixelXS[X, Y: TFixed]: TColor32 read GetPixelXS write SetPixelXS;
+ property PixelF[X, Y: Single]: TColor32 read GetPixelF write SetPixelF;
+ property PixelFS[X, Y: Single]: TColor32 read GetPixelFS write SetPixelFS;
+{$IFDEF CLX}
+ property Pixmap: QPixmapH read GetPixmap;
+ property Bits: PColor32Array read GetBits;
+ property Handle: QPainterH read GetPainter;
+ property PixmapChanged: Boolean read FPixmapChanged write FPixmapChanged;
+{$ELSE}
+ property BitmapHandle: HBITMAP read FHandle;
+ property BitmapInfo: TBitmapInfo read FBitmapInfo;
+ property Bits: PColor32Array read FBits;
+ property Handle: HDC read FHDC;
+{$ENDIF}
+ property Font: TFont read FFont write SetFont;
+ property PixelPtr[X, Y: Integer]: PColor32 read GetPixelPtr;
+ property ScanLine[Y: Integer]: PColor32Array read GetScanLine;
+ property StippleCounter: Single read FStippleCounter write FStippleCounter;
+ property StippleStep: Single read FStippleStep write FStippleStep;
+ published
+ property DrawMode: TDrawMode read FDrawMode write SetDrawMode default dmOpaque;
+ property MasterAlpha: Cardinal read FMasterAlpha write SetMasterAlpha default $FF;
+ property OuterColor: TColor32 read FOuterColor write FOuterColor default 0;
+ property StretchFilter: TStretchFilter read FStretchFilter write SetStretchFilter default sfNearest;
+ property OnChange;
+ property OnHandleChanged: TNotifyEvent read FOnHandleChanged write FOnHandleChanged;
+ property OnPixelCombine: TPixelCombineEvent read FOnPixelCombine write FOnPixelCombine;
+ property OnResize;
+ end;
+
+{$IFDEF CLX}
+ TBitmap32Canvas = class(TCanvas)
+ private
+ FBitmap: TBitmap32;
+ protected
+ procedure BeginPainting; override;
+ procedure CreateHandle; override;
+ public
+ constructor Create(Bitmap: TBitmap32);
+ end;
+{$ENDIF}
+
+implementation
+
+uses
+ GR32_Blend, GR32_Transforms, GR32_LowLevel, GR32_Filters, Math, TypInfo,
+ GR32_System,
+{$IFDEF CLX}
+ QClipbrd,
+{$ELSE}
+ Clipbrd,
+{$ENDIF}
+ GR32_DrawingEx;
+
+var
+ CounterLock: TRTLCriticalSection;
+ Interpolator: function(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
+
+{$IFDEF CLX}
+ StockFont: TFont;
+{$ELSE}
+ StockFont: HFONT;
+{$ENDIF}
+ StockBitmap: TBitmap;
+
+type
+ TGraphicAccess = class(TGraphic);
+
+const
+ ZERO_RECT: TRect = (Left: 0; Top: 0; Right: 0; Bottom: 0);
+
+
+{$IFDEF CLX}
+function StretchPixmap(DestPainter: QPainterH; DestX, DestY, DestWidth, DestHeight,
+ SrcX, SrcY, SrcWidth, SrcHeight: Integer; SrcPixmap: QPixmapH): Integer;
+var
+ NewMatrix: QWMatrixH;
+begin
+ QPainter_saveWorldMatrix(DestPainter);
+ try
+ NewMatrix:= QWMatrix_create(DestWidth / SrcWidth, 0, 0, DestHeight / SrcHeight, DestX, DestY);
+ try
+ QPainter_setWorldMatrix(DestPainter, NewMatrix, True);
+ QPainter_drawPixmap(DestPainter, 0, 0, SrcPixmap, SrcX, SrcY, SrcWidth, SrcHeight);
+ finally
+ QWMatrix_destroy(NewMatrix);
+ end;
+ finally
+ QPainter_restoreWorldMatrix(DestPainter);
+ end;
+ Result := 0;
+end;
+{$ENDIF}
+
+{ Color construction and conversion functions }
+
+function Color32(WinColor: TColor): TColor32; overload;
+{$IFDEF WIN_COLOR_FIX}
+var
+ I: Longword;
+{$ENDIF}
+begin
+{$IFDEF CLX}
+ WinColor := ColorToRGB(WinColor);
+{$ELSE}
+ if WinColor < 0 then WinColor := GetSysColor(WinColor and $000000FF);
+{$ENDIF}
+
+{$IFDEF WIN_COLOR_FIX}
+ Result := $FF000000;
+ I := (WinColor and $00FF0000) shr 16;
+ if I <> 0 then Result := Result or TColor32(Integer(I) - 1);
+ I := WinColor and $0000FF00;
+ if I <> 0 then Result := Result or TColor32(Integer(I) - $00000100);
+ I := WinColor and $000000FF;
+ if I <> 0 then Result := Result or TColor32(Integer(I) - 1) shl 16;
+{$ELSE}
+ asm
+ MOV EAX,WinColor
+ BSWAP EAX
+ MOV AL,$FF
+ ROR EAX,8
+ MOV Result,EAX
+ end;
+{$ENDIF}
+end;
+
+function Color32(R, G, B: Byte; A: Byte = $FF): TColor32; overload;
+asm
+ MOV AH,A
+ SHL EAX,16
+ MOV AH,DL
+ MOV AL,CL
+end;
+
+function Color32(Index: Byte; var Palette: TPalette32): TColor32; overload;
+begin
+ Result := Palette[Index];
+end;
+
+function Gray32(Intensity: Byte; Alpha: Byte = $FF): TColor32;
+begin
+ Result := TColor32(Alpha) shl 24 + TColor32(Intensity) shl 16 +
+ TColor32(Intensity) shl 8 + TColor32(Intensity);
+end;
+
+function WinColor(Color32: TColor32): TColor;
+asm
+ // the alpha channel byte is set to zero!
+ ROL EAX,8 // ABGR -> BGRA
+ XOR AL,AL // BGRA -> BGR0
+ BSWAP EAX // BGR0 -> 0RGB
+end;
+
+function ArrayOfColor32(Colors: array of TColor32): TArrayOfColor32;
+var
+ L: Integer;
+begin
+ // build a dynamic color array from specified colors
+ L := High(Colors) + 1;
+ SetLength(Result, L);
+ MoveLongword(Colors[0], Result[0], L);
+end;
+
+function RedComponent(Color32: TColor32): Integer;
+begin
+ Result := (Color32 and $00FF0000) shr 16;
+end;
+
+function GreenComponent(Color32: TColor32): Integer;
+begin
+ Result := (Color32 and $0000FF00) shr 8;
+end;
+
+function BlueComponent(Color32: TColor32): Integer;
+begin
+ Result := Color32 and $000000FF;
+end;
+
+function AlphaComponent(Color32: TColor32): Integer;
+begin
+ Result := Color32 shr 24;
+end;
+
+function Intensity(Color32: TColor32): Integer;
+begin
+// (R * 61 + G * 174 + B * 21) / 256
+ Result := (
+ (Color32 and $00FF0000) shr 16 * 61 +
+ (Color32 and $0000FF00) shr 8 * 174 +
+ (Color32 and $000000FF) * 21
+ ) shr 8;
+end;
+
+function SetAlpha(Color32: TColor32; NewAlpha: Integer): TColor32;
+begin
+ if NewAlpha < 0 then NewAlpha := 0
+ else if NewAlpha > 255 then NewAlpha := 255;
+ Result := (Color32 and $00FFFFFF) or (TColor32(NewAlpha) shl 24);
+end;
+
+{ Color space conversions }
+
+function HSLtoRGB(H, S, L: Single): TColor32;
+const
+ OneOverThree = 1 / 3;
+var
+ M1, M2: Single;
+ R, G, B: Byte;
+
+ function HueToColor(Hue: Single): Byte;
+ var
+ V: Double;
+ begin
+ Hue := Hue - Floor(Hue);
+ if 6 * Hue < 1 then V := M1 + (M2 - M1) * Hue * 6
+ else if 2 * Hue < 1 then V := M2
+ else if 3 * Hue < 2 then V := M1 + (M2 - M1) * (2 / 3 - Hue) * 6
+ else V := M1;
+ Result := Round(255 * V);
+ end;
+
+begin
+ if S = 0 then
+ begin
+ R := Round(255 * L);
+ G := R;
+ B := R;
+ end
+ else
+ begin
+ if L <= 0.5 then M2 := L * (1 + S)
+ else M2 := L + S - L * S;
+ M1 := 2 * L - M2;
+ R := HueToColor(H + OneOverThree);
+ G := HueToColor(H);
+ B := HueToColor(H - OneOverThree)
+ end;
+ Result := Color32(R, G, B, 255);
+end;
+
+procedure RGBtoHSL(RGB: TColor32; out H, S, L : Single);
+var
+ R, G, B, D, Cmax, Cmin: Single;
+begin
+ R := RedComponent(RGB) / 255;
+ G := GreenComponent(RGB) / 255;
+ B := BlueComponent(RGB) / 255;
+ Cmax := Max(R, Max(G, B));
+ Cmin := Min(R, Min(G, B));
+ L := (Cmax + Cmin) / 2;
+
+ if Cmax = Cmin then
+ begin
+ H := 0;
+ S := 0
+ end
+ else
+ begin
+ D := Cmax - Cmin;
+ if L < 0.5 then S := D / (Cmax + Cmin)
+ else S := D / (2 - Cmax - Cmin);
+ if R = Cmax then H := (G - B) / D
+ else
+ if G = Cmax then H := 2 + (B - R) / D
+ else H := 4 + (R - G) / D;
+ H := H / 6;
+ if H < 0 then H := H + 1
+ end;
+end;
+
+{ Palette conversion }
+
+{$IFNDEF CLX}
+function WinPalette(const P: TPalette32): HPALETTE;
+var
+ L: TMaxLogPalette;
+ L0: LOGPALETTE absolute L;
+ I: Cardinal;
+ Cl: TColor32;
+begin
+ L.palVersion := $300;
+ L.palNumEntries := 256;
+ for I := 0 to 255 do
+ begin
+ Cl := P[I];
+ with L.palPalEntry[I] do
+ begin
+ peFlags := 0;
+ peRed := RedComponent(Cl);
+ peGreen := GreenComponent(Cl);
+ peBlue := BlueComponent(Cl);
+ end;
+ end;
+ Result := CreatePalette(l0);
+end;
+{$ENDIF}
+
+{ Fixed-point math }
+
+function Fixed(S: Single): TFixed;
+begin
+ Result := Round(S * 65536);
+end;
+
+function Fixed(I: Integer): TFixed;
+begin
+ Result := I * $10000{I shl 16};
+end;
+
+function FixedFloor(A: TFixed): Integer;
+asm
+ SAR EAX, 16;
+end;
+
+function FixedCeil(A: TFixed): Integer;
+asm
+ ADD EAX, $0000FFFF
+ SAR EAX, 16;
+end;
+
+function FixedRound(A: TFixed): Integer;
+asm
+ ADD EAX, $00007FFF
+ SAR EAX, 16
+end;
+
+function FixedMul(A, B: TFixed): TFixed;
+asm
+ IMUL EDX
+ SHRD EAX, EDX, 16
+end;
+
+function FixedDiv(A, B: TFixed): TFixed;
+asm
+ MOV ECX, B
+ CDQ
+ SHLD EDX, EAX, 16
+ SHL EAX, 16
+ IDIV ECX
+end;
+
+{ Points }
+
+function Point(X, Y: Integer): TPoint;
+begin
+ Result.X := X;
+ Result.Y := Y;
+end;
+
+function Point(const FP: TFloatPoint): TPoint;
+begin
+ Result.X := Round(FP.X);
+ Result.Y := Round(FP.Y);
+end;
+
+function Point(const FXP: TFixedPoint): TPoint;
+begin
+ Result.X := FixedRound(FXP.X);
+ Result.Y := FixedRound(FXP.Y);
+end;
+
+function FloatPoint(X, Y: Single): TFloatPoint;
+begin
+ Result.X := X;
+ Result.Y := Y;
+end;
+
+function FloatPoint(const P: TPoint): TFloatPoint;
+begin
+ Result.X := P.X;
+ Result.Y := P.Y;
+end;
+
+function FloatPoint(const FXP: TFixedPoint): TFloatPoint;
+const
+ F = 1 / 65536;
+begin
+ with FXP do
+ begin
+ Result.X := X * F;
+ Result.Y := Y * F;
+ end;
+end;
+
+function FixedPoint(X, Y: Integer): TFixedPoint; overload;
+begin
+ Result.X := X shl 16;
+ Result.Y := Y shl 16;
+end;
+
+function FixedPoint(X, Y: Single): TFixedPoint; overload;
+begin
+ Result.X := Round(X * 65536);
+ Result.Y := Round(Y * 65536);
+end;
+
+function FixedPoint(const P: TPoint): TFixedPoint; overload;
+begin
+ Result.X := P.X shl 16;
+ Result.Y := P.Y shl 16;
+end;
+
+function FixedPoint(const FP: TFloatPoint): TFixedPoint; overload;
+begin
+ Result.X := Round(FP.X * 65536);
+ Result.Y := Round(FP.Y * 65536);
+end;
+
+
+{ Rectangles }
+
+function MakeRect(L, T, R, B: Integer): TRect;
+begin
+ with Result do
+ begin
+ Left := L;
+ Top := T;
+ Right := R;
+ Bottom := B;
+ end;
+end;
+
+function MakeRect(const FR: TFloatRect; Rounding: TRectRounding): TRect;
+begin
+ with FR do
+ case Rounding of
+ rrClosest:
+ Result := MakeRect(Round(Left), Round(Top), Round(Right), Round(Bottom));
+
+ rrInside:
+ begin
+ Result := MakeRect(Ceil(Left), Ceil(Top), Floor(Right), Floor(Bottom));
+ if Result.Right < Result.Left then Result.Right := Result.Left;
+ if Result.Bottom < Result.Top then Result.Bottom := Result.Top;
+ end;
+
+ rrOutside:
+ Result := MakeRect(Floor(Left), Floor(Top), Ceil(Right), Ceil(Bottom));
+ end;
+end;
+
+function MakeRect(const FXR: TFixedRect; Rounding: TRectRounding): TRect;
+begin
+ with FXR do
+ case Rounding of
+ rrClosest:
+ begin
+ Result.Left := FixedRound(Left);
+ Result.Top := FixedRound(Top);
+ Result.Right := FixedRound(Right);
+ Result.Bottom := FixedRound(Bottom);
+ end;
+
+ rrInside:
+ begin
+ Result.Left := FixedCeil(Left);
+ Result.Top := FixedCeil(Top);
+ Result.Right := FixedFloor(Right);
+ Result.Bottom := FixedFloor(Bottom);
+ if Result.Right < Result.Left then Result.Right := Result.Left;
+ if Result.Bottom < Result.Top then Result.Bottom := Result.Top;
+ end;
+
+ rrOutside:
+ begin
+ Result.Left := FixedFloor(Left);
+ Result.Top := FixedFloor(Top);
+ Result.Right := FixedCeil(Right);
+ Result.Bottom := FixedCeil(Bottom);
+ end;
+ end;
+end;
+
+function FloatRect(L, T, R, B: Single): TFloatRect;
+begin
+ with Result do
+ begin
+ Left := L;
+ Top := T;
+ Right := R;
+ Bottom := B;
+ end;
+end;
+
+function FloatRect(const ARect: TRect): TFloatRect;
+begin
+ with Result do
+ begin
+ Left := ARect.Left;
+ Top := ARect.Top;
+ Right := ARect.Right;
+ Bottom := ARect.Bottom;
+ end;
+end;
+
+function IntersectRect(out Dst: TRect; const R1, R2: TRect): Boolean;
+begin
+ if R1.Left >= R2.Left then Dst.Left := R1.Left else Dst.Left := R2.Left;
+ if R1.Right <= R2.Right then Dst.Right := R1.Right else Dst.Right := R2.Right;
+ if R1.Top >= R2.Top then Dst.Top := R1.Top else Dst.Top := R2.Top;
+ if R1.Bottom <= R2.Bottom then Dst.Bottom := R1.Bottom else Dst.Bottom := R2.Bottom;
+ Result := (Dst.Right >= Dst.Left) and (Dst.Bottom >= Dst.Top);
+ if not Result then Dst := ZERO_RECT;
+end;
+
+function IntersectRectF(out Dst: TFloatRect; const FR1, FR2: TFloatRect): Boolean;
+begin
+ Dst.Left := Max(FR1.Left, FR2.Left);
+ Dst.Right := Min(FR1.Right, FR2.Right);
+ Dst.Top := Max(FR1.Top, FR2.Top);
+ Dst.Bottom := Min(FR1.Bottom, FR2.Bottom);
+ Result := (Dst.Right >= Dst.Left) and (Dst.Bottom >= Dst.Top);
+ if not Result then FillLongword(Dst, 4, 0);
+end;
+
+function EqualRect(const R1, R2: TRect): Boolean;
+begin
+ Result := CompareMem(@R1, @R2, SizeOf(TRect));
+end;
+
+procedure InflateRect(var R: TRect; Dx, Dy: Integer);
+begin
+ Dec(R.Left, Dx); Dec(R.Top, Dy);
+ Inc(R.Right, Dx); Inc(R.Bottom, Dy);
+end;
+
+procedure InflateRectF(var FR: TFloatRect; Dx, Dy: Single);
+begin
+ with FR do
+ begin
+ Left := Left - Dx; Top := Top - Dy;
+ Right := Right + Dx; Bottom := Bottom + Dy;
+ end;
+end;
+
+procedure OffsetRect(var R: TRect; Dx, Dy: Integer);
+begin
+ Inc(R.Left, Dx); Inc(R.Top, Dy);
+ Inc(R.Right, Dx); Inc(R.Bottom, Dy);
+end;
+
+procedure OffsetRectF(var FR: TFloatRect; Dx, Dy: Single);
+begin
+ with FR do
+ begin
+ Left := Left + Dx; Top := Top + Dy;
+ Right := Right + Dx; Bottom := Bottom + Dy;
+ end;
+end;
+
+function IsRectEmpty(const R: TRect): Boolean;
+begin
+ Result := (R.Right <= R.Left) or (R.Bottom <= R.Top);
+end;
+
+function IsRectEmptyF(const FR: TFloatRect): Boolean;
+begin
+ Result := (FR.Right <= FR.Left) or (FR.Bottom <= FR.Top);
+end;
+
+function PtInRect(const R: TRect; const P: TPoint): Boolean;
+begin
+ Result := (P.X >= R.Left) and (P.X < R.Right) and
+ (P.Y >= R.Top) and (P.Y < R.Bottom);
+end;
+
+{ Gamma / Pixel Shape Correction table }
+
+procedure SetGamma(Gamma: Single);
+var
+ i: Integer;
+begin
+ for i := 0 to 255 do
+ GAMMA_TABLE[i] := Round(255 * Power(i / 255, Gamma));
+end;
+
+
+
+{ TThreadPersistent }
+
+constructor TThreadPersistent.Create;
+begin
+ InitializeCriticalSection(FLock);
+end;
+
+destructor TThreadPersistent.Destroy;
+begin
+ DeleteCriticalSection(FLock);
+ inherited;
+end;
+
+procedure TThreadPersistent.BeginUpdate;
+begin
+ Inc(FUpdateCount);
+end;
+
+procedure TThreadPersistent.Changed;
+begin
+ if (FUpdateCount = 0) and Assigned(FOnChange) then FOnChange(Self);
+end;
+
+procedure TThreadPersistent.EndUpdate;
+begin
+ Assert(FUpdateCount > 0, 'Unpaired TThreadPersistent.EndUpdate');
+ Dec(FUpdateCount);
+end;
+
+procedure TThreadPersistent.Lock;
+begin
+ EnterCriticalSection(CounterLock);
+ Inc(FLockCount);
+ LeaveCriticalSection(CounterLock);
+ EnterCriticalSection(FLock);
+end;
+
+procedure TThreadPersistent.Unlock;
+begin
+ LeaveCriticalSection(FLock);
+ EnterCriticalSection(CounterLock);
+ Dec(FLockCount);
+ LeaveCriticalSection(CounterLock);
+end;
+
+
+{ TCustomMap }
+
+procedure TCustomMap.ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer);
+begin
+ Width := NewWidth;
+ Height := NewHeight;
+end;
+
+procedure TCustomMap.Delete;
+begin
+ SetSize(0, 0);
+end;
+
+function TCustomMap.Empty: Boolean;
+begin
+ Result := (Width = 0) or (Height = 0);
+end;
+
+procedure TCustomMap.Resized;
+begin
+ if Assigned(FOnResize) then FOnResize(Self);
+end;
+
+procedure TCustomMap.SetHeight(NewHeight: Integer);
+begin
+ SetSize(Width, NewHeight);
+end;
+
+function TCustomMap.SetSize(NewWidth, NewHeight: Integer): Boolean;
+begin
+ if NewWidth < 0 then NewWidth := 0;
+ if NewHeight < 0 then NewHeight := 0;
+ Result := (NewWidth <> FWidth) or (NewHeight <> FHeight);
+ if Result then
+ begin
+ ChangeSize(FWidth, FHeight, NewWidth, NewHeight);
+ Changed;
+ Resized;
+ end;
+end;
+
+function TCustomMap.SetSizeFrom(Source: TPersistent): Boolean;
+begin
+ if Source is TCustomMap then
+ Result := SetSize(TCustomMap(Source).Width, TCustomMap(Source).Height)
+ else if Source is TGraphic then
+ Result := SetSize(TGraphic(Source).Width, TGraphic(Source).Height)
+ else if Source is TControl then
+ Result := SetSize(TControl(Source).Width, TControl(Source).Height)
+ else if Source = nil then
+ Result := SetSize(0, 0)
+ else
+ raise Exception.Create('Can''t set size from ''' + Source.ClassName + '''');
+end;
+
+procedure TCustomMap.SetWidth(NewWidth: Integer);
+begin
+ SetSize(NewWidth, Height);
+end;
+
+
+{ TBitmap32 }
+
+constructor TBitmap32.Create;
+begin
+ inherited;
+{$IFNDEF CLX}
+ FillChar(FBitmapInfo, SizeOf(TBitmapInfo), 0);
+ with FBitmapInfo.bmiHeader do
+ begin
+ biSize := SizeOf(TBitmapInfoHeader);
+ biPlanes := 1;
+ biBitCount := 32;
+ biCompression := BI_RGB;
+ end;
+{$ENDIF}
+ FOuterColor := $00000000; // by default as full transparency black
+ FFont := TFont.Create;
+ FFont.OnChange := FontChanged;
+{$IFNDEF CLX}
+ FFont.OwnerCriticalSection := @FLock;
+{$ENDIF}
+ FMasterAlpha := $FF;
+ FPenColor := clWhite32;
+ FStippleStep := 1;
+end;
+
+destructor TBitmap32.Destroy;
+begin
+ BeginUpdate;
+ Lock;
+ try
+ DeleteCanvas;
+ SetSize(0, 0);
+ FFont.Free;
+ finally
+ Unlock;
+ end;
+ inherited;
+end;
+
+procedure TBitmap32.HandleChanged;
+begin
+ if FCanvas <> nil then FCanvas.Handle := Self.Handle;
+ if Assigned(FOnHandleChanged) then FOnHandleChanged(Self);
+end;
+
+procedure TBitmap32.ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer);
+begin
+ try
+ FontChanged(Self);
+ DeleteCanvas; // Patch by Thomas Bauer.....
+
+{$IFDEF CLX}
+ if Assigned(FHDC) then QPainter_destroy(FHDC);
+ FHDC := nil;
+ if Assigned(FHandle) then QImage_destroy(FHandle);
+ FHandle := nil;
+{$ELSE}
+ if FHDC <> 0 then DeleteDC(FHDC);
+ FHDC := 0;
+ if FHandle <> 0 then DeleteObject(FHandle);
+ FHandle := 0;
+{$ENDIF}
+
+ FBits := nil;
+ Width := 0;
+ Height := 0;
+ if (NewWidth > 0) and (NewHeight > 0) then
+ begin
+{$IFDEF CLX}
+ FHandle := QImage_create(NewWidth, NewHeight, 32, 1, QImageEndian_IgnoreEndian);
+ if FHandle <> nil then
+ begin
+ FBits := Pointer(QImage_bits(FHandle));
+ // clear it since QT doesn't initialize the image data:
+ FillLongword(FBits[0], NewWidth * NewHeight, clBlack32);
+ end;
+{$ELSE}
+ with FBitmapInfo.bmiHeader do
+ begin
+ biWidth := NewWidth;
+ biHeight := -NewHeight;
+ end;
+ FHandle := CreateDIBSection(0, FBitmapInfo, DIB_RGB_COLORS, Pointer(FBits), 0, 0);
+{$ENDIF}
+
+ if FBits = nil then raise Exception.Create('Can''t allocate the DIB handle');
+
+{$IFDEF CLX}
+ FHDC := QPainter_create;
+ if FHDC = nil then
+ begin
+ QImage_destroy(FHandle);
+ FBits := nil;
+ raise Exception.Create('Can''t create compatible DC');
+ end;
+
+ FPixmap := QPixmap_create;
+ FPixmapActive := False;
+{$ELSE}
+ FHDC := CreateCompatibleDC(0);
+ if FHDC = 0 then
+ begin
+ DeleteObject(FHandle);
+ FHandle := 0;
+ FBits := nil;
+ raise Exception.Create('Can''t create compatible DC');
+ end;
+
+ if SelectObject(FHDC, FHandle) = 0 then
+ begin
+ DeleteDC(FHDC);
+ DeleteObject(FHandle);
+ FHDC := 0;
+ FHandle := 0;
+ FBits := nil;
+ raise Exception.Create('Can''t select an object into DC');
+ end;
+{$ENDIF}
+ end;
+
+ Width := NewWidth;
+ Height := NewHeight;
+ finally
+ HandleChanged;
+ end;
+end;
+
+function TBitmap32.Empty: Boolean;
+begin
+{$IFDEF CLX}
+ Result := not(Assigned(FHandle) or Assigned(FPixmap)) or inherited Empty;
+{$ELSE}
+ Result := (FHandle = 0) or inherited Empty;
+{$ENDIF}
+end;
+
+procedure TBitmap32.Clear;
+begin
+ Clear(clBlack32);
+end;
+
+procedure TBitmap32.Clear(FillColor: TColor32);
+begin
+ if Empty then Exit;
+ FillLongword(Bits[0], Width * Height, FillColor);
+ Changed;
+end;
+
+procedure TBitmap32.Delete;
+begin
+ SetSize(0, 0);
+end;
+
+procedure TBitmap32.Assign(Source: TPersistent);
+var
+ Canvas: TCanvas;
+ Picture: TPicture;
+ TempBitmap: TBitmap32;
+ I: integer;
+ DstP, SrcP: PColor32;
+ DstColor: TColor32;
+
+ procedure AssignFromBitmap(SrcBmp: TBitmap);
+ var
+ TransparentColor: TColor32;
+ I: integer;
+ begin
+ SetSize(SrcBmp.Width, SrcBmp.Height);
+ if Empty then Exit;
+{$IFDEF CLX}
+ if not QPainter_isActive(Handle) then
+ if not QPainter_begin(Handle, Pixmap) then
+ raise EInvalidGraphicOperation.CreateRes(@SInvalidCanvasState);
+ QPainter_drawPixmap(Handle, 0, 0, SrcBmp.Handle, 0, 0, Width, Height);
+ QPainter_end(Handle);
+ PixmapChanged := True;
+{$ELSE}
+ BitBlt(Handle, 0, 0, Width, Height, SrcBmp.Canvas.Handle, 0, 0, SRCCOPY);
+{$ENDIF}
+ if SrcBmp.PixelFormat <> pf32bit then ResetAlpha;
+ if SrcBmp.Transparent then
+ begin
+ TransparentColor := Color32(SrcBmp.TransparentColor) and $00FFFFFF;
+ DstP := @Bits[0];
+ for I := 0 to Width * Height - 1 do
+ begin
+ DstColor := DstP^ and $00FFFFFF;
+ if DstColor = TransparentColor then
+ DstP^ := DstColor;
+ inc(DstP);
+ end;
+ end;
+ end;
+
+begin
+ BeginUpdate;
+ try
+ if Source = nil then
+ begin
+ SetSize(0, 0);
+ Exit;
+ end
+ else if Source is TBitmap32 then
+ begin
+ SetSize(TBitmap32(Source).Width, TBitmap32(Source).Height);
+ if Empty then Exit;
+{$IFDEF CLX}
+ Move(TBitmap32(Source).Bits[0], Bits[0], Width * Height * 4);
+{$ELSE}
+ BitBlt(Handle, 0, 0, Width, Height, TBitmap32(Source).Handle, 0, 0, SRCCOPY);
+ //Move(TBitmap32(Source).Bits[0], Bits[0], Width * Height * 4);
+ // Move is up to 2x faster with FastMove by the FastCode Project
+{$ENDIF}
+ FDrawMode := TBitmap32(Source).FDrawMode;
+ FMasterAlpha := TBitmap32(Source).FMasterAlpha;
+ FOuterColor := TBitmap32(Source).FOuterColor;
+ FStretchFilter := TBitmap32(Source).FStretchFilter;
+ Exit;
+ end
+ else if Source is TBitmap then
+ begin
+ AssignFromBitmap(TBitmap(Source));
+ Exit;
+ end
+ else if Source is TGraphic then
+ begin
+ SetSize(TGraphic(Source).Width, TGraphic(Source).Height);
+ if Empty then Exit;
+ Canvas := TCanvas.Create;
+ try
+ Canvas.Handle := Self.Handle;
+ TGraphicAccess(Source).Draw(Canvas, MakeRect(0, 0, Width, Height));
+ ResetAlpha;
+ finally
+ Canvas.Free;
+ end;
+ end
+ else if Source is TPicture then
+ begin
+ with TPicture(Source) do
+ begin
+ if TPicture(Source).Graphic is TBitmap then
+ AssignFromBitmap(TBitmap(TPicture(Source).Graphic))
+ else if (TPicture(Source).Graphic is TIcon) {$IFNDEF CLX}or
+ (TPicture(Source).Graphic is TMetaFile) {$ENDIF} then
+ begin
+ // icons, metafiles etc...
+ SetSize(TPicture(Source).Graphic.Width, TPicture(Source).Graphic.Height);
+ if Empty then Exit;
+
+ TempBitmap := TBitmap32.Create;
+ Canvas := TCanvas.Create;
+ try
+ Self.Clear(clBlue32); // mask on blue;
+ Canvas.Handle := Self.Handle;
+ TGraphicAccess(Graphic).Draw(Canvas, MakeRect(0, 0, Width, Height));
+
+ TempBitmap.SetSize(TPicture(Source).Graphic.Width, TPicture(Source).Graphic.Height);
+ TempBitmap.Clear(clRed32); // mask on red;
+ Canvas.Handle := TempBitmap.Handle;
+ TGraphicAccess(Graphic).Draw(Canvas, MakeRect(0, 0, Width, Height));
+
+ DstP := @Bits[0];
+ SrcP := @TempBitmap.Bits[0];
+ for I := 0 to Width * Height - 1 do
+ begin
+ DstColor := DstP^ and $00FFFFFF;
+ // this checks for transparency by comparing the pixel of
+ // temporary bitmap (red masked) with the pixel of our
+ // bitmap (blue masked). If they match, make that pixel opaque
+ if DstColor = (SrcP^ and $00FFFFFF) then
+ DstP^ := DstColor or $FF000000
+ else
+ // if the colors don't match (that is the case if there is a
+ // match "is clRed32 = clBlue32 ?"), just make that pixel
+ // transparent:
+ DstP^ := DstColor;
+
+ inc(SrcP); inc(DstP);
+ end;
+ finally
+ TempBitmap.Free;
+ Canvas.Free;
+ end;
+ end
+ else
+ begin
+ // anything else...
+ SetSize(TPicture(Source).Graphic.Width, TPicture(Source).Graphic.Height);
+ if Empty then Exit;
+ Canvas := TCanvas.Create;
+ try
+ Canvas.Handle := Self.Handle;
+ TGraphicAccess(Graphic).Draw(Canvas, MakeRect(0, 0, Width, Height));
+ ResetAlpha;
+ finally
+ Canvas.Free;
+ end;
+ end;
+ end;
+ Exit;
+ end
+ else if Source is TClipboard then
+ begin
+ Picture := TPicture.Create;
+ try
+ Picture.Assign(TClipboard(Source));
+ SetSize(Picture.Width, Picture.Height);
+ if Empty then Exit;
+ Canvas := TCanvas.Create;
+ try
+ Canvas.Handle := Self.Handle;
+ TGraphicAccess(Picture.Graphic).Draw(Canvas, MakeRect(0, 0, Width, Height));
+ ResetAlpha;
+ finally
+ Canvas.Free;
+ end;
+ finally
+ Picture.Free;
+ end;
+ Exit;
+ end
+ else
+ inherited; // default handler
+ finally;
+ EndUpdate;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.AssignTo(Dst: TPersistent);
+var
+ Bmp: TBitmap;
+
+ procedure CopyToBitmap(Bmp: TBitmap);
+ begin
+{$IFNDEF CLX}
+ Bmp.HandleType := bmDIB;
+{$ENDIF}
+ Bmp.PixelFormat := pf32Bit;
+ Bmp.Width := Width;
+ Bmp.Height := Height;
+ DrawTo(Bmp.Canvas.Handle, 0, 0);
+ end;
+
+begin
+ if Dst is TPicture then CopyToBitmap(TPicture(Dst).Bitmap)
+ else if Dst is TBitmap then CopyToBitmap(TBitmap(Dst))
+ else if Dst is TClipboard then
+ begin
+ Bmp := TBitmap.Create;
+ try
+ CopyToBitmap(Bmp);
+ TClipboard(Dst).Assign(Bmp);
+ finally
+ Bmp.Free;
+ end;
+ end
+ else inherited;
+end;
+
+function TBitmap32.GetCanvas: TCanvas;
+begin
+ if FCanvas = nil then
+ begin
+{$IFDEF CLX}
+ FCanvas := TBitmap32Canvas.Create(Self);
+{$ELSE}
+ FCanvas := TCanvas.Create;
+{$ENDIF}
+ FCanvas.Handle := Handle;
+ FCanvas.OnChange := CanvasChanged;
+ end;
+ Result := FCanvas;
+end;
+
+procedure TBitmap32.CanvasChanged(Sender: TObject);
+begin
+ Changed;
+end;
+
+function TBitmap32.CanvasAllocated: Boolean;
+begin
+ Result := FCanvas <> nil;
+end;
+
+procedure TBitmap32.DeleteCanvas;
+begin
+ if FCanvas <> nil then
+ begin
+{$IFDEF CLX}
+ FCanvas.Handle := nil;
+{$ELSE}
+ FCanvas.Handle := 0;
+{$ENDIF}
+ FCanvas.Free;
+ FCanvas := nil;
+ end;
+end;
+
+procedure TBitmap32.SetPixel(X, Y: Integer; Value: TColor32);
+begin
+ Bits[X + Y * Width] := Value;
+end;
+
+procedure TBitmap32.SetPixelS(X, Y: Integer; Value: TColor32);
+begin
+ if (X >= 0) and (X < Width) and (Y >= 0) and (Y < Height) then
+ Bits[X + Y * Width] := Value;
+end;
+
+function TBitmap32.GetScanLine(Y: Integer): PColor32Array;
+begin
+ Result := @Bits[Y * FWidth];
+end;
+
+function TBitmap32.GetPixel(X, Y: Integer): TColor32;
+begin
+ Result := Bits[X + Y * Width];
+end;
+
+function TBitmap32.GetPixelS(X, Y: Integer): TColor32;
+begin
+ if (X >= 0) and (X < Width) and (Y >= 0) and (Y < Height) then
+ Result := Bits[X + Y * Width]
+ else
+ Result := OuterColor;
+end;
+
+function TBitmap32.GetPixelPtr(X, Y: Integer): PColor32;
+begin
+ Result := @Bits[X + Y * Width];
+end;
+
+procedure TBitmap32.Draw(DstX, DstY: Integer; Src: TBitmap32);
+begin
+ if Assigned(Src) then Src.DrawTo(Self, DstX, DstY);
+end;
+
+procedure TBitmap32.Draw(DstX, DstY: Integer; const SrcRect: TRect; Src: TBitmap32);
+begin
+ if Assigned(Src) then Src.DrawTo(Self, DstX, DstY, SrcRect);
+end;
+
+procedure TBitmap32.Draw(const DstRect, SrcRect: TRect; Src: TBitmap32);
+begin
+ if Assigned(Src) then Src.DrawTo(Self, DstRect, SrcRect);
+end;
+
+{$IFDEF CLX}
+procedure TBitmap32.Draw(const DstRect, SrcRect: TRect; SrcPixmap: QPixmapH);
+var
+ NewMatrix: QWMatrixH;
+ SrcHeight, SrcWidth: Integer;
+begin
+ if Empty then Exit;
+ StartPainter;
+ QPainter_saveWorldMatrix(Handle);
+ try
+ SrcWidth := SrcRect.Right - SrcRect.Left;
+ SrcHeight := SrcRect.Bottom - SrcRect.Top;
+ // use world transformation to translate and scale.
+ NewMatrix:= QWMatrix_create((DstRect.Right - DstRect.Left) / SrcWidth ,
+ 0, 0, (DstRect.Bottom - DstRect.Top) / SrcHeight, DstRect.Left, DstRect.Top);
+ try
+ QPainter_setWorldMatrix(Handle, NewMatrix, True);
+ QPainter_drawPixmap(Handle, 0, 0, SrcPixmap,
+ SrcRect.Left, SrcRect.Top, SrcWidth, SrcHeight);
+ finally
+ QWMatrix_destroy(NewMatrix);
+ end;
+ finally
+ QPainter_restoreWorldMatrix(Handle);
+ StopPainter;
+ end;
+ Changed;
+end;
+
+{$ELSE}
+
+procedure TBitmap32.Draw(const DstRect, SrcRect: TRect; hSrc: HDC);
+begin
+ if Empty then Exit;
+ StretchBlt(Handle, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left,
+ DstRect.Bottom - DstRect.Top, hSrc, SrcRect.Left, SrcRect.Top,
+ SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top, SRCCOPY);
+ Changed;
+end;
+{$ENDIF}
+
+procedure TBitmap32.DrawTo(Dst: TBitmap32);
+begin
+ if Empty or Dst.Empty then Exit;
+ BlockTransfer(Dst, 0, 0, Dst.BoundsRect, Self, BoundsRect, DrawMode, FOnPixelCombine);
+ Dst.Changed;
+end;
+
+procedure TBitmap32.DrawTo(Dst: TBitmap32; DstX, DstY: Integer);
+begin
+ if Empty or Dst.Empty then Exit;
+ BlockTransfer(Dst, DstX, DstY, Dst.BoundsRect, Self, BoundsRect, DrawMode, FOnPixelCombine);
+ Dst.Changed;
+end;
+
+procedure TBitmap32.DrawTo(Dst: TBitmap32; DstX, DstY: Integer; const SrcRect: TRect);
+begin
+ if Empty or Dst.Empty then Exit;
+ BlockTransfer(Dst, DstX, DstY, Dst.BoundsRect, Self, SrcRect, DrawMode, FOnPixelCombine);
+ Dst.Changed;
+end;
+
+procedure TBitmap32.DrawTo(Dst: TBitmap32; const DstRect: TRect);
+begin
+ if Empty or Dst.Empty then Exit;
+ StretchTransfer(Dst, DstRect, Dst.BoundsRect, Self, BoundsRect, StretchFilter, DrawMode, FOnPixelCombine);
+ Dst.Changed;
+end;
+
+procedure TBitmap32.DrawTo(Dst: TBitmap32; const DstRect, SrcRect: TRect);
+begin
+ if Empty or Dst.Empty then Exit;
+ StretchTransfer(Dst, DstRect, Dst.BoundsRect, Self, SrcRect, StretchFilter, DrawMode, FOnPixelCombine);
+ Dst.Changed;
+end;
+
+procedure TBitmap32.DrawTo(hDst: HDC; DstX, DstY: Integer);
+begin
+ if Empty then Exit;
+{$IFDEF CLX}
+ StretchPixmap(
+ hDst, DstX, DstY, Width, Height,
+ 0, 0, Width, Height, GetPixmap);
+{$ELSE}
+ StretchDIBits(
+ hDst, DstX, DstY, Width, Height,
+ 0, 0, Width, Height, Bits, FBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
+{$ENDIF}
+end;
+
+procedure TBitmap32.DrawTo(hDst: HDC; const DstRect, SrcRect: TRect);
+begin
+ if Empty then Exit;
+{$IFDEF CLX}
+ StretchPixmap(
+ hDst,
+ DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top,
+ SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left,
+ SrcRect.Bottom - SrcRect.Top, GetPixmap);
+{$ELSE}
+ StretchDIBits(
+ hDst,
+ DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top,
+ SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left,
+ SrcRect.Bottom - SrcRect.Top, Bits, FBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
+{$ENDIF}
+end;
+
+procedure TBitmap32.TileTo(hDst: HDC; const DstRect, SrcRect: TRect);
+const
+ MaxTileSize = 1024;
+var
+ DstW, DstH: Integer;
+ TilesX, TilesY: Integer;
+ Buffer: TBitmap32;
+ I, J: Integer;
+ ClipRect, R: TRect;
+ X, Y: Integer;
+begin
+ DstW := DstRect.Right - DstRect.Left;
+ DstH := DstRect.Bottom - DstRect.Top;
+ TilesX := (DstW + MaxTileSize - 1) div MaxTileSize;
+ TilesY := (DstH + MaxTileSize - 1) div MaxTileSize;
+ Buffer := TBitmap32.Create;
+ try
+ for J := 0 to TilesY - 1 do
+ begin
+ for I := 0 to TilesX - 1 do
+ begin
+ ClipRect.Left := I * MaxTileSize;
+ ClipRect.Top := J * MaxTileSize;
+ ClipRect.Right := (I + 1) * MaxTileSize;
+ ClipRect.Bottom := (J + 1) * MaxTileSize;
+ if ClipRect.Right > DstW then ClipRect.Right := DstW;
+ if ClipRect.Bottom > DstH then ClipRect.Bottom := DstH;
+ X := ClipRect.Left;
+ Y := ClipRect.Top;
+ OffsetRect(ClipRect, -X, -Y);
+ R := DstRect;
+ OffsetRect(R, -X - DstRect.Left, -Y - DstRect.Top);
+ Buffer.SetSize(ClipRect.Right, ClipRect.Bottom);
+ StretchTransfer(Buffer, R, ClipRect, Self, SrcRect, StretchFilter, DrawMode, FOnPixelCombine);
+
+{$IFDEF CLX}
+ StretchPixmap(
+ hDst, X + DstRect.Left, Y + DstRect.Top, ClipRect.Right, ClipRect.Bottom,
+ 0, 0, Buffer.Width, Buffer.Height, GetPixmap);
+{$ELSE}
+ StretchDIBits(
+ hDst, X + DstRect.Left, Y + DstRect.Top, ClipRect.Right, ClipRect.Bottom,
+ 0, 0, Buffer.Width, Buffer.Height,
+ Buffer.Bits, Buffer.FBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
+{$ENDIF}
+ end;
+ end;
+ finally
+ Buffer.Free;
+ end;
+end;
+
+procedure TBitmap32.ResetAlpha;
+var
+ I: Integer;
+ P: PByte;
+ NH, NL: Integer;
+begin
+ P := Pointer(FBits);
+ Inc(P, 3); // shift the pointer to 'alpha' component of the first pixel
+
+ { Enroll the loop 4 times }
+ I := Width * Height;
+ NH := I shr 2;
+ NL := I and $3;
+ for I := 0 to NH - 1 do
+ begin
+ P^ := $FF; Inc(P, 4);
+ P^ := $FF; Inc(P, 4);
+ P^ := $FF; Inc(P, 4);
+ P^ := $FF; Inc(P, 4);
+ end;
+ for I := 0 to NL - 1 do
+ begin
+ P^ := $FF; Inc(P, 4);
+ end;
+ Changed;
+end;
+
+function TBitmap32.GetPixelB(X, Y: Integer): TColor32;
+begin
+ // WARNING: this function should never be used on empty bitmaps !!!
+ if X < 0 then X := 0
+ else if X >= Width then X := Width - 1;
+ if Y < 0 then Y := 0
+ else if Y >= Height then Y := Height - 1;
+ Result := Bits[X + Y * Width];
+end;
+
+procedure TBitmap32.SetPixelT(X, Y: Integer; Value: TColor32);
+begin
+ BlendMem(Value, Bits[X + Y * Width]);
+ EMMS;
+end;
+
+procedure TBitmap32.SetPixelT(var Ptr: PColor32; Value: TColor32);
+begin
+ BlendMem(Value, Ptr^);
+ EMMS;
+ Inc(Ptr);
+end;
+
+procedure TBitmap32.SetPixelTS(X, Y: Integer; Value: TColor32);
+begin
+ if (X >= 0) and (X < Width) and (Y >= 0) and (Y < Height) then
+ begin
+ BlendMem(Value, Bits[X + Y * Width]);
+ EMMS;
+ end;
+end;
+
+procedure TBitmap32.SET_T256(X, Y: Integer; C: TColor32);
+var
+ flrx, flry, celx, cely: Longword;
+ P: PColor32;
+ A: TColor32;
+begin
+ { Warning: EMMS should be called after using this method }
+ A := C shr 24; // opacity
+
+ flrx := X and $FF;
+ flry := Y and $FF;
+
+ asm
+ SAR X, 8 //X := SAR_8(X);
+ SAR Y, 8 //Y := SAR_8(Y);
+ end;
+
+ celx := A * GAMMA_TABLE[flrx xor 255];
+ cely := GAMMA_TABLE[flry xor 255];
+ P := @FBits[X + Y * FWidth];
+ flrx := A * GAMMA_TABLE[flrx];
+ flry := GAMMA_TABLE[flry];
+
+ CombineMem(C, P^, celx * cely shr 16); Inc(P);
+ CombineMem(C, P^, flrx * cely shr 16); Inc(P, FWidth);
+ CombineMem(C, P^, flrx * flry shr 16); Dec(P);
+ CombineMem(C, P^, celx * flry shr 16);
+end;
+
+procedure TBitmap32.SET_TS256(X, Y: Integer; C: TColor32);
+var
+ flrx, flry, celx, cely: Longword;
+ P: PColor32;
+ A: TColor32;
+begin
+ { Warning: EMMS should be called after using this method }
+ if (X < -256) or (Y < -256) then Exit;
+
+ flrx := X and $FF;
+ flry := Y and $FF;
+
+ asm
+ SAR X, 8
+ SAR Y, 8
+ end;
+
+ if (X >= FWidth) or (Y >= FHeight) then Exit;
+
+ A := C shr 24; // opacity
+
+ celx := A * GAMMA_TABLE[flrx xor 255];
+ cely := GAMMA_TABLE[flry xor 255];
+ P := @FBits[X + Y * FWidth];
+ flrx := A * GAMMA_TABLE[flrx];
+ flry := GAMMA_TABLE[flry];
+
+ if (X >= 0) and (Y >= 0) and (X < FWidth - 1) and (Height < FHeight - 1) then
+ begin
+ CombineMem(C, P^, celx * cely shr 16); Inc(P);
+ CombineMem(C, P^, flrx * cely shr 16); Inc(P, FWidth);
+ CombineMem(C, P^, flrx * flry shr 16); Dec(P);
+ CombineMem(C, P^, celx * flry shr 16);
+ end
+ else // "pixel" lies on the edge of the bitmap
+ begin
+ if (X >= 0) and (Y >= 0) then CombineMem(C, P^, celx * cely shr 16); Inc(P);
+ if (X < FWidth - 1) and (Y >= 0) then CombineMem(C, P^, flrx * cely shr 16); Inc(P, FWidth);
+ if (X < FWidth - 1) and (Y < FHeight - 1) then CombineMem(C, P^, flrx * flry shr 16); Dec(P);
+ if (X >= 0) and (Y < FHeight - 1) then CombineMem(C, P^, celx * flry shr 16);
+ end;
+end;
+
+procedure TBitmap32.SetPixelF(X, Y: Single; Value: TColor32);
+begin
+ SET_T256(Round(X * 256), Round(Y * 256), Value);
+ EMMS;
+end;
+
+procedure TBitmap32.SetPixelX(X, Y: TFixed; Value: TColor32);
+begin
+ asm
+ ADD X, $7F
+ ADD Y, $7F
+ SAR X, 8
+ SAR Y, 8
+ end;
+ SET_T256(X, Y, Value);
+ EMMS;
+end;
+
+procedure TBitmap32.SetPixelFS(X, Y: Single; Value: TColor32);
+begin
+ SET_TS256(Round(X * 256), Round(Y * 256), Value);
+ EMMS;
+end;
+
+procedure TBitmap32.SetPixelXS(X, Y: TFixed; Value: TColor32);
+begin
+ asm
+ ADD X, $7F
+ ADD Y, $7F
+ SAR X, 8
+ SAR Y, 8
+ end;
+ SET_TS256(X, Y, Value);
+ EMMS;
+end;
+
+function TBitmap32.GET_T256(X, Y: Integer): TColor32;
+//When using this, remember that it interpolates towards next x and y!
+var
+ Pos: Cardinal;
+begin
+ Pos := (X shr 8) + (Y shr 8) * FWidth;
+ Result := Interpolator( GAMMA_TABLE[X and $FF xor 255],
+ GAMMA_TABLE[Y and $FF xor 255],
+ @FBits[Pos], @FBits[Pos + FWidth] );
+end;
+
+function TBitmap32.GET_TS256(X, Y: Integer): TColor32;
+begin
+ if (X > 0) and (Y > 0) and (X < (FWidth - 1) shl 8) and (Y < (FHeight - 1) shl 8) then
+ Result := GET_T256(X,Y)
+ else
+ Result := FOuterColor;
+end;
+
+function TBitmap32.GetPixelF(X, Y: Single): TColor32;
+begin
+ Result := GET_T256(Round(X * 256), Round(Y * 256));
+ EMMS;
+end;
+
+function TBitmap32.GetPixelFS(X, Y: Single): TColor32;
+begin
+ Result := GET_TS256(Round(X * 256), Round(Y * 256));
+ EMMS;
+end;
+
+function TBitmap32.GetPixelX(X, Y: TFixed): TColor32;
+begin
+ asm
+ ADD X, $7F
+ ADD Y, $7F
+ SAR X, 8
+ SAR Y, 8
+ end;
+ Result := GET_T256(X, Y);
+ EMMS;
+end;
+
+function TBitmap32.GetPixelXS(X, Y: TFixed): TColor32;
+begin
+ asm
+ ADD X, $7F
+ ADD Y, $7F
+ SAR X, 8
+ SAR Y, 8
+ end;
+ Result := GET_TS256(X, Y);
+ EMMS;
+end;
+
+procedure TBitmap32.SetStipple(NewStipple: TArrayOfColor32);
+begin
+ FStippleCounter := 0;
+ FStipplePattern := Copy(NewStipple, 0, Length(NewStipple));
+end;
+
+procedure TBitmap32.SetStipple(NewStipple: array of TColor32);
+var
+ L: Integer;
+begin
+ FStippleCounter := 0;
+ L := High(NewStipple) + 1;
+ SetLength(FStipplePattern, L);
+ Move(NewStipple[0], FStipplePattern[0], L shl 2);
+end;
+
+procedure TBitmap32.AdvanceStippleCounter(LengthPixels: Single);
+var
+ L: Integer;
+ Delta: Single;
+begin
+ L := Length(FStipplePattern);
+ Delta := LengthPixels * FStippleStep;
+ if (L = 0) or (Delta = 0) then Exit;
+ FStippleCounter := FStippleCounter + Delta;
+ FStippleCounter := FStippleCounter - Floor(FStippleCounter / L) * L;
+end;
+
+function TBitmap32.GetStippleColor: TColor32;
+var
+ L: Integer;
+ NextIndex, PrevIndex: Integer;
+ PrevWeight: Integer;
+begin
+ L := Length(FStipplePattern);
+ if L = 0 then
+ begin
+ // no pattern defined, just return something and exit
+ Result := clBlack32;
+ Exit;
+ end;
+ while FStippleCounter >= L do FStippleCounter := FStippleCounter - L;
+ while FStippleCounter < 0 do FStippleCounter := FStippleCounter + L;
+ PrevIndex := Round(FStippleCounter - 0.5);
+ PrevWeight := 255 - Round(255 * (FStippleCounter - PrevIndex));
+ if PrevIndex < 0 then FStippleCounter := L - 1;
+ NextIndex := PrevIndex + 1;
+ if NextIndex >= L then NextIndex := 0;
+ if PrevWeight = 255 then Result := FStipplePattern[PrevIndex]
+ else
+ begin
+ Result := CombineReg(
+ FStipplePattern[PrevIndex],
+ FStipplePattern[NextIndex],
+ PrevWeight);
+ EMMS;
+ end;
+ FStippleCounter := FStippleCounter + FStippleStep;
+end;
+
+procedure TBitmap32.HorzLine(X1, Y, X2: Integer; Value: TColor32);
+begin
+ FillLongword(Bits[X1 + Y * Width], X2 - X1 + 1, Value);
+end;
+
+procedure TBitmap32.HorzLineS(X1, Y, X2: Integer; Value: TColor32);
+begin
+ if (Y >= 0) and (Y < Height) and TestClip(X1, X2, Width) then
+ HorzLine(X1, Y, X2, Value);
+end;
+
+procedure TBitmap32.HorzLineT(X1, Y, X2: Integer; Value: TColor32);
+var
+ i: Integer;
+ P: PColor32;
+begin
+ if X2 < X1 then Exit;
+ P := PixelPtr[X1, Y];
+ for i := X1 to X2 do
+ begin
+ BlendMem(Value, P^);
+ Inc(P);
+ end;
+ EMMS;
+end;
+
+procedure TBitmap32.HorzLineTS(X1, Y, X2: Integer; Value: TColor32);
+begin
+ if (Y >= 0) and (Y < Height) and TestClip(X1, X2, Width) then
+ HorzLineT(X1, Y, X2, Value);
+end;
+
+procedure TBitmap32.HorzLineTSP(X1, Y, X2: Integer);
+var
+ I, N: Integer;
+begin
+ if Empty then Exit;
+ if (Y >= 0) and (Y < Height) then
+ begin
+ if ((X1 < 0) and (X2 < 0)) or ((X1 >= Width) and (X2 >= Width)) then
+ begin
+ AdvanceStippleCounter(Abs(X2 - X1) + 1);
+ Exit;
+ end;
+ if X1 < 0 then
+ begin
+ AdvanceStippleCounter(-X1);
+ X1 := 0;
+ end
+ else if X1 >= Width then
+ begin
+ AdvanceStippleCounter(X1 - (Width - 1));
+ X1 := Width - 1;
+ end;
+ N := 0;
+ if X2 < 0 then
+ begin
+ N := -X2;
+ X2 := 0;
+ end
+ else if X2 >= Width then
+ begin
+ N := X2 - (Width - 1);
+ X2 := Width - 1;
+ end;
+
+ if X2 >= X1 then
+ for I := X1 to X2 do SetPixelT(I, Y, GetStippleColor)
+ else
+ for I := X1 downto X2 do SetPixelT(I, Y, GetStippleColor);
+
+ if N > 0 then AdvanceStippleCounter(N);
+ end;
+end;
+
+procedure TBitmap32.VertLine(X, Y1, Y2: Integer; Value: TColor32);
+var
+ I, NH, NL: Integer;
+ P: PColor32;
+begin
+ if Y2 < Y1 then Exit;
+ P := PixelPtr[X, Y1];
+ I := Y2 - Y1 + 1;
+ NH := I shr 2;
+ NL := I and $03;
+ for I := 0 to NH - 1 do
+ begin
+ P^ := Value; Inc(P, Width);
+ P^ := Value; Inc(P, Width);
+ P^ := Value; Inc(P, Width);
+ P^ := Value; Inc(P, Width);
+ end;
+ for I := 0 to NL - 1 do
+ begin
+ P^ := Value; Inc(P, Width);
+ end;
+end;
+
+procedure TBitmap32.VertLineS(X, Y1, Y2: Integer; Value: TColor32);
+begin
+ if (X >= 0) and (X < Width) and TestClip(Y1, Y2, Height) then
+ VertLine(X, Y1, Y2, Value);
+end;
+
+procedure TBitmap32.VertLineT(X, Y1, Y2: Integer; Value: TColor32);
+var
+ i: Integer;
+ P: PColor32;
+begin
+ P := PixelPtr[X, Y1];
+ for i := Y1 to Y2 do
+ begin
+ BlendMem(Value, P^);
+ Inc(P, Width);
+ end;
+ EMMS;
+end;
+
+procedure TBitmap32.VertLineTS(X, Y1, Y2: Integer; Value: TColor32);
+begin
+ if (X >= 0) and (X < Width) and TestClip(Y1, Y2, Height) then
+ VertLineT(X, Y1, Y2, Value);
+end;
+
+procedure TBitmap32.VertLineTSP(X, Y1, Y2: Integer);
+var
+ I, N: Integer;
+begin
+ if Empty then Exit;
+ if (X >= 0) and (X < Width) then
+ begin
+ if ((Y1 < 0) and (Y2 < 0)) or ((Y1 >= Height) and (Y2 >= Height)) then
+ begin
+ AdvanceStippleCounter(Abs(Y2 - Y1) + 1);
+ Exit;
+ end;
+ if Y1 < 0 then
+ begin
+ AdvanceStippleCounter(-Y1);
+ Y1 := 0;
+ end
+ else if Y1 >= Height then
+ begin
+ AdvanceStippleCounter(Y1 - (Height - 1));
+ Y1 := Height - 1;
+ end;
+ N := 0;
+ if Y2 < 0 then
+ begin
+ N := -Y2;
+ Y2 := 0;
+ end
+ else if Y2 >= Height then
+ begin
+ N := Y2 - (Height - 1);
+ Y2 := Height - 1;
+ end;
+
+ if Y2 >= Y1 then
+ for I := Y1 to Y2 do SetPixelT(X, I, GetStippleColor)
+ else
+ for I := Y1 downto Y2 do SetPixelT(X, I, GetStippleColor);
+
+ if N > 0 then AdvanceStippleCounter(N);
+ end;
+end;
+
+procedure TBitmap32.Line(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean);
+var
+ Dy, Dx, Sy, Sx, I, Delta: Integer;
+ P: PColor32;
+begin
+ try
+ Dx := X2 - X1;
+ Dy := Y2 - Y1;
+
+ if Dx > 0 then Sx := 1
+ else if Dx < 0 then
+ begin
+ Dx := -Dx;
+ Sx := -1;
+ end
+ else // Dx = 0
+ begin
+ if Dy > 0 then VertLine(X1, Y1, Y2 - 1, Value)
+ else if Dy < 0 then VertLine(X1, Y2 + 1, Y1, Value);
+ if L then Pixel[X2, Y2] := Value;
+ Exit;
+ end;
+
+ if Dy > 0 then Sy := 1
+ else if Dy < 0 then
+ begin
+ Dy := -Dy;
+ Sy := -1;
+ end
+ else // Dy = 0
+ begin
+ if X2 > X1 then HorzLine(X1, Y1, X2 - 1, Value)
+ else HorzLine(X2 + 1, Y1, X1, Value);
+ if L then Pixel[X2, Y2] := Value;
+ Exit;
+ end;
+
+ P := PixelPtr[X1, Y1];
+ Sy := Sy * Width;
+
+ if Dx > Dy then
+ begin
+ Delta := Dx shr 1;
+ for I := 0 to Dx - 1 do
+ begin
+ P^ := Value;
+ Inc(P, Sx);
+ Inc(Delta, Dy);
+ if Delta > Dx then
+ begin
+ Inc(P, Sy);
+ Dec(Delta, Dx);
+ end;
+ end;
+ end
+ else // Dx < Dy
+ begin
+ Delta := Dy shr 1;
+ for I := 0 to Dy - 1 do
+ begin
+ P^ := Value;
+ Inc(P, Sy);
+ Inc(Delta, Dx);
+ if Delta > Dy then
+ begin
+ Inc(P, Sx);
+ Dec(Delta, Dy);
+ end;
+ end;
+ end;
+ if L then P^ := Value;
+ finally
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.LineS(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean);
+begin
+ if ClipLine(X1, Y1, X2, Y2, 0, 0, Width - 1, Height - 1) then
+ Line(X1, Y1, X2, Y2, Value, L);
+end;
+
+procedure TBitmap32.LineT(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean);
+var
+ Dy, Dx, Sy, Sx, I, Delta: Integer;
+ P: PColor32;
+begin
+ try
+ Dx := X2 - X1;
+ Dy := Y2 - Y1;
+
+ if Dx > 0 then Sx := 1
+ else if Dx < 0 then
+ begin
+ Dx := -Dx;
+ Sx := -1;
+ end
+ else // Dx = 0
+ begin
+ if Dy > 0 then VertLineT(X1, Y1, Y2 - 1, Value)
+ else if Dy < 0 then VertLineT(X1, Y2 + 1, Y1, Value);
+ if L then SetPixelT(X2, Y2, Value);
+ Exit;
+ end;
+
+ if Dy > 0 then Sy := 1
+ else if Dy < 0 then
+ begin
+ Dy := -Dy;
+ Sy := -1;
+ end
+ else // Dy = 0
+ begin
+ if X2 > X1 then HorzLineT(X1, Y1, X2 - 1, Value)
+ else HorzLineT(X2 + 1, Y1, X1, Value);
+ if L then SetPixelT(X2, Y2, Value);
+ Exit;
+ end;
+
+ P := PixelPtr[X1, Y1];
+ Sy := Sy * Width;
+
+ try
+ if Dx > Dy then
+ begin
+ Delta := Dx shr 1;
+ for I := 0 to Dx - 1 do
+ begin
+ BlendMem(Value, P^);
+ Inc(P, Sx);
+ Inc(Delta, Dy);
+ if Delta > Dx then
+ begin
+ Inc(P, Sy);
+ Dec(Delta, Dx);
+ end;
+ end;
+ end
+ else // Dx < Dy
+ begin
+ Delta := Dy shr 1;
+ for I := 0 to Dy - 1 do
+ begin
+ BlendMem(Value, P^);
+ Inc(P, Sy);
+ Inc(Delta, Dx);
+ if Delta > Dy then
+ begin
+ Inc(P, Sx);
+ Dec(Delta, Dy);
+ end;
+ end;
+ end;
+ if L then BlendMem(Value, P^);
+ finally
+ EMMS;
+ end;
+ finally
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.LineTS(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean);
+var
+ OldX2, OldY2: Integer;
+begin
+ OldX2 := X2; OldY2 := Y2;
+ if ClipLine(X1, Y1, X2, Y2, 0, 0, Width - 1, Height - 1) then
+ begin
+ if (OldX2 <> X2) or (OldY2 <> Y2) then L := True;
+ LineT(X1, Y1, X2, Y2, Value, L);
+ end;
+end;
+
+procedure TBitmap32.LineX(X1, Y1, X2, Y2: TFixed; Value: TColor32; L: Boolean);
+var
+ n, i: Integer;
+ nx, ny, hyp: Integer;
+ A: TColor32;
+ h: Single;
+begin
+ try
+ nx := X2 - X1; ny := Y2 - Y1;
+ Inc(X1, 127); Inc(Y1, 127); Inc(X2, 127); Inc(Y2, 127);
+ hyp := Round(Hypot(nx, ny));
+ if L then Inc(hyp, 65536);
+ if hyp < 256 then Exit;
+ n := hyp shr 16;
+ if n > 0 then
+ begin
+ h := 65536 / hyp;
+ nx := Round(nx * h); ny := Round(ny * h);
+ for i := 0 to n - 1 do
+ begin
+ SET_T256(X1 shr 8, Y1 shr 8, Value);
+ Inc(X1, nx);
+ Inc(Y1, ny);
+ end;
+ end;
+ A := Value shr 24;
+ hyp := hyp - n shl 16;
+ A := A * Cardinal(hyp) shl 8 and $FF000000;
+ SET_T256((X1 + X2 - nx) shr 9, (Y1 + Y2 - ny) shr 9, Value and $00FFFFFF + A);
+ finally
+ EMMS;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.LineF(X1, Y1, X2, Y2: Single; Value: TColor32; L: Boolean);
+begin
+ LineX(Fixed(X1), Fixed(Y1), Fixed(X2), Fixed(Y2), Value, L);
+end;
+
+procedure TBitmap32.LineXS(X1, Y1, X2, Y2: TFixed; Value: TColor32; L: Boolean);
+var
+ n, i: Integer;
+ ex, ey, nx, ny, hyp: Integer;
+ A: TColor32;
+ LongWidth, LongHeight: Integer;
+ h: Single;
+begin
+ LongWidth := FWidth shl 16;
+ LongHeight := FHeight shl 16;
+
+ ex := X2; ey := Y2;
+
+ // Check for visibility and clip the coordinates
+ if not ClipLine(Integer(X1), Integer(Y1), Integer(X2), Integer(Y2),
+ -$10000, -$10000, LongWidth, LongHeight) then Exit;
+
+ if (ex <> X2) or (ey <> Y2) then L := True;
+
+ // Check if it lies entirely in the bitmap area. Even after clipping
+ // some pixels may lie outside the bitmap due to antialiasing
+ if (X1 > 0) and (X1 < LongWidth - $20000) and
+ (Y1 > 0) and (Y1 < LongHeight - $20000) and
+ (X2 > 0) and (X2 < LongWidth - $20000) and
+ (Y2 > 0) and (Y2 < LongHeight - $20000) then
+ begin
+ LineX(X1, Y1, X2, Y2, Value);
+ Exit;
+ end;
+
+ // If we are still here, it means that the line touches one or several bitmap
+ // boundaries. Use the safe version of antialiased pixel routine
+ try
+ nx := X2 - X1; ny := Y2 - Y1;
+ Inc(X1, 127); Inc(Y1, 127); Inc(X2, 127); Inc(Y2, 127);
+ hyp := Round(Hypot(nx, ny));
+ if L then Inc(Hyp, 65536);
+ if hyp < 256 then Exit;
+ n := hyp shr 16;
+ if n > 0 then
+ begin
+ h := 65536 / hyp;
+ nx := Round(nx * h); ny := Round(ny * h);
+ for i := 0 to n - 1 do
+ begin
+ SET_TS256(SAR_8(X1), SAR_8(Y1), Value);
+ X1 := X1 + nx;
+ Y1 := Y1 + ny;
+ end;
+ end;
+ A := Value shr 24;
+ hyp := hyp - n shl 16;
+ A := A * Longword(hyp) shl 8 and $FF000000;
+ SET_TS256(SAR_9(X1 + X2 - nx), SAR_9(Y1 + Y2 - ny), Value and $00FFFFFF + A);
+ finally
+ EMMS;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.LineFS(X1, Y1, X2, Y2: Single; Value: TColor32; L: Boolean);
+begin
+ LineXS(Fixed(X1), Fixed(Y1), Fixed(X2), Fixed(Y2), Value, L);
+end;
+
+procedure TBitmap32.LineXP(X1, Y1, X2, Y2: TFixed; L: Boolean);
+var
+ n, i: Integer;
+ nx, ny, hyp: Integer;
+ A, C: TColor32;
+begin
+ try
+ nx := X2 - X1; ny := Y2 - Y1;
+ Inc(X1, 127); Inc(Y1, 127); Inc(X2, 127); Inc(Y2, 127);
+ hyp := Round(Hypot(nx, ny));
+ if L then Inc(hyp, 65536);
+ if hyp < 256 then Exit;
+ n := hyp shr 16;
+ if n > 0 then
+ begin
+ nx := Round(nx / hyp * 65536);
+ ny := Round(ny / hyp * 65536);
+ for i := 0 to n - 1 do
+ begin
+ C := GetStippleColor;
+ SET_T256(X1 shr 8, Y1 shr 8, C);
+ EMMS;
+ X1 := X1 + nx;
+ Y1 := Y1 + ny;
+ end;
+ end;
+ C := GetStippleColor;
+ A := C shr 24;
+ hyp := hyp - n shl 16;
+ A := A * Longword(hyp) shl 8 and $FF000000;
+ SET_T256((X1 + X2 - nx) shr 9, (Y1 + Y2 - ny) shr 9, C and $00FFFFFF + A);
+ EMMS;
+ finally
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.LineFP(X1, Y1, X2, Y2: Single; L: Boolean);
+begin
+ LineXP(Fixed(X1), Fixed(Y1), Fixed(X2), Fixed(Y2), L);
+end;
+
+procedure TBitmap32.LineXSP(X1, Y1, X2, Y2: TFixed; L: Boolean);
+const
+ StippleInc: array [Boolean] of Single = (0, 1);
+var
+ n, i: Integer;
+ sx, sy, ex, ey, nx, ny, hyp: Integer;
+ A, C: TColor32;
+ LongWidth, LongHeight: Integer;
+begin
+ LongWidth := FWidth shl 16;
+ LongHeight := FHeight shl 16;
+
+ sx := X1; sy := Y1; ex := X2; ey := Y2;
+
+ // Check for visibility and clip the coordinates
+ if not ClipLine(Integer(X1), Integer(Y1), Integer(X2), Integer(Y2),
+ -$10000, -$10000, LongWidth, LongHeight) then
+ begin
+ AdvanceStippleCounter(Hypot((X2 - X1) / 65536, (Y2 - Y1) / 65536) - StippleInc[L]);
+ Exit;
+ end;
+
+ if (ex <> X2) or (ey <> Y2) then L := True;
+
+ // Check if it lies entirely in the bitmap area. Even after clipping
+ // some pixels may lie outside the bitmap due to antialiasing
+ if (X1 > 0) and (X1 < LongWidth - $20000) and
+ (Y1 > 0) and (Y1 < LongHeight - $20000) and
+ (X2 > 0) and (X2 < LongWidth - $20000) and
+ (Y2 > 0) and (Y2 < LongHeight - $20000) then
+ begin
+ LineXP(X1, Y1, X2, Y2);
+ Exit;
+ end;
+
+ if (sx <> X1) or (sy <> Y1) then
+ AdvanceStippleCounter(Hypot((X1 - sx) / 65536, (Y1 - sy) / 65536));
+
+ // If we are still here, it means that the line touches one or several bitmap
+ // boundaries. Use the safe version of antialiased pixel routine
+ try
+ nx := X2 - X1; ny := Y2 - Y1;
+ Inc(X1, 127); Inc(Y1, 127); Inc(X2, 127); Inc(Y2, 127);
+ hyp := Round(Hypot(nx, ny));
+ if L then Inc(hyp, 65536);
+ if hyp < 256 then Exit;
+ n := hyp shr 16;
+ if n > 0 then
+ begin
+ nx := Round(nx / hyp * 65536); ny := Round(ny / hyp * 65536);
+ for i := 0 to n - 1 do
+ begin
+ C := GetStippleColor;
+ SET_TS256(SAR_8(X1), SAR_8(Y1), C);
+ EMMS;
+ X1 := X1 + nx;
+ Y1 := Y1 + ny;
+ end;
+ end;
+ C := GetStippleColor;
+ A := C shr 24;
+ hyp := hyp - n shl 16;
+ A := A * Longword(hyp) shl 8 and $FF000000;
+ SET_TS256(SAR_9(X1 + X2 - nx), SAR_9(Y1 + Y2 - ny), C and $00FFFFFF + A);
+ EMMS;
+
+ if (ex <> X2) or (ey <> Y2) then
+ AdvanceStippleCounter(Hypot((X2 - ex) / 65536, (Y2 - ey) / 65536) - StippleInc[L]);
+
+ finally
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.LineFSP(X1, Y1, X2, Y2: Single; L: Boolean);
+begin
+ LineXSP(Fixed(X1), Fixed(Y1), Fixed(X2), Fixed(Y2), L);
+end;
+
+procedure TBitmap32.LineA(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean);
+var
+ Dx, Dy, Sx, Sy, D: Integer;
+ EC, EA: Word;
+ CI: Byte;
+ P: PColor32;
+begin
+ if (X1 = X2) or (Y1 = Y2) then
+ begin
+ LineT(X1, Y1, X2, Y2, Value, L);
+ Exit;
+ end;
+
+ Dx := X2 - X1;
+ Dy := Y2 - Y1;
+
+ if Dx > 0 then Sx := 1
+ else
+ begin
+ Sx := -1;
+ Dx := -Dx;
+ end;
+
+ if Dy > 0 then Sy := 1
+ else
+ begin
+ Sy := -1;
+ Dy := -Dy;
+ end;
+
+ try
+ EC := 0;
+ BlendMem(Value, Bits[X1 + Y1 * Width]);
+
+ if Dy > Dx then
+ begin
+ EA := Dx shl 16 div Dy;
+ if not L then Dec(Dy);
+ while Dy > 0 do
+ begin
+ Dec(Dy);
+ D := EC;
+ Inc(EC, EA);
+ if EC <= D then Inc(X1, Sx);
+ Inc(Y1, Sy);
+ CI := EC shr 8;
+ P := @Bits[X1 + Y1 * Width];
+ BlendMemEx(Value, P^, GAMMA_TABLE[CI xor 255]);
+ Inc(P, Sx);
+ BlendMemEx(Value, P^, GAMMA_TABLE[CI]);
+ end;
+ end
+ else // DY <= DX
+ begin
+ EA := Dy shl 16 div Dx;
+ if not L then Dec(Dx);
+ while Dx > 0 do
+ begin
+ Dec(Dx);
+ D := EC;
+ Inc(EC, EA);
+ if EC <= D then Inc(Y1, Sy);
+ Inc(X1, Sx);
+ CI := EC shr 8;
+ P := @Bits[X1 + Y1 * Width];
+ BlendMemEx(Value, P^, GAMMA_TABLE[CI xor 255]);
+ if Sy = 1 then Inc(P, Width) else Dec(P, Width);
+ BlendMemEx(Value, P^, GAMMA_TABLE[CI]);
+ end;
+ end;
+ finally
+ EMMS;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.LineAS(X1, Y1, X2, Y2: Integer; Value: TColor32; L: Boolean);
+begin
+ if ClipLine(X1, Y1, X2, Y2, 0, 0, Width - 1, Height - 1) then
+ LineA(X1, Y1, X2, Y2, Value, L);
+end;
+
+procedure TBitmap32.MoveTo(X, Y: Integer);
+begin
+ RasterX := X;
+ RasterY := Y;
+end;
+
+procedure TBitmap32.LineToS(X, Y: Integer);
+begin
+ LineS(RasterX, RasterY, X, Y, PenColor);
+ RasterX := X;
+ RasterY := Y;
+end;
+
+procedure TBitmap32.LineToTS(X, Y: Integer);
+begin
+ LineTS(RasterX, RasterY, X, Y, PenColor);
+ RasterX := X;
+ RasterY := Y;
+end;
+
+procedure TBitmap32.LineToAS(X, Y: Integer);
+begin
+ LineAS(RasterX, RasterY, X, Y, PenColor);
+ RasterX := X;
+ RasterY := Y;
+end;
+
+procedure TBitmap32.MoveToX(X, Y: TFixed);
+begin
+ RasterXF := X;
+ RasterYF := Y;
+end;
+
+procedure TBitmap32.MoveToF(X, Y: Single);
+begin
+ RasterXF := Fixed(X);
+ RasterYF := Fixed(Y);
+end;
+
+procedure TBitmap32.LineToXS(X, Y: TFixed);
+begin
+ LineXS(RasterXF, RasterYF, X, Y, PenColor);
+ RasterXF := X;
+ RasterYF := Y;
+end;
+
+procedure TBitmap32.LineToFS(X, Y: Single);
+begin
+ LineToXS(Fixed(X), Fixed(Y));
+end;
+
+procedure TBitmap32.LineToXSP(X, Y: TFixed);
+begin
+ LineXSP(RasterXF, RasterYF, X, Y);
+ RasterXF := X;
+ RasterYF := Y;
+end;
+
+procedure TBitmap32.LineToFSP(X, Y: Single);
+begin
+ LineToXSP(Fixed(X), Fixed(Y));
+end;
+
+procedure TBitmap32.FillRect(X1, Y1, X2, Y2: Integer; Value: TColor32);
+var
+ j: Integer;
+ P: PColor32Array;
+begin
+ for j := Y1 to Y2 - 1 do
+ begin
+ P := Pointer(GetScanLine(j));
+ FillLongword(P[X1], X2 - X1, Value);
+ end;
+ Changed;
+end;
+
+procedure TBitmap32.FillRectS(X1, Y1, X2, Y2: Integer; Value: TColor32);
+begin
+ if (X2 > X1) and (Y2 > Y1) and (X1 < Width) and (Y1 < Height) and
+ (X2 > 0) and (Y2 > 0) then
+ begin
+ if X1 < 0 then X1 := 0;
+ if Y1 < 0 then Y1 := 0;
+ if X2 > Width then X2 := Width;
+ if Y2 > Height then Y2 := Height;
+ FillRect(X1, Y1, X2, Y2, Value);
+ end;
+end;
+
+procedure TBitmap32.FillRectT(X1, Y1, X2, Y2: Integer; Value: TColor32);
+var
+ i, j: Integer;
+ P: PColor32;
+ A: Integer;
+begin
+ A := Value shr 24;
+ if A = $FF then FillRect(X1, Y1, X2, Y2, Value)
+ else
+ try
+ Dec(Y2);
+ Dec(X2);
+ for j := Y1 to Y2 do
+ begin
+ P := GetPixelPtr(X1, j);
+ for i := X1 to X2 do
+ begin
+ CombineMem(Value, P^, A);
+ Inc(P);
+ end;
+ end;
+ finally
+ EMMS;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.FillRectTS(X1, Y1, X2, Y2: Integer; Value: TColor32);
+begin
+ if (X2 > X1) and (Y2 > Y1) and (X1 < Width) and (Y1 < Height) and
+ (X2 > 0) and (Y2 > 0) then
+ begin
+ if X1 < 0 then X1 := 0;
+ if Y1 < 0 then Y1 := 0;
+ if X2 > Width then X2 := Width;
+ if Y2 > Height then Y2 := Height;
+ FillRectT(X1, Y1, X2, Y2, Value);
+ end;
+end;
+
+procedure TBitmap32.FillRectS(const ARect: TRect; Value: TColor32);
+begin
+ with ARect do FillRectS(Left, Top, Right, Bottom, Value);
+end;
+
+procedure TBitmap32.FillRectTS(const ARect: TRect; Value: TColor32);
+begin
+ with ARect do FillRectTS(Left, Top, Right, Bottom, Value);
+end;
+
+procedure TBitmap32.FrameRectS(X1, Y1, X2, Y2: Integer; Value: TColor32);
+begin
+ if (X2 > X1) and (Y2 > Y1) and (X1 < Width) and (Y1 < Height) and
+ (X2 > 0) and (Y2 > 0) then
+ begin
+ Dec(Y2);
+ Dec(X2);
+ HorzLineS(X1, Y1, X2, Value);
+ if Y2 > Y1 then HorzLineS(X1, Y2, X2, Value);
+ if Y2 > Y1 + 1 then
+ begin
+ VertLineS(X1, Y1 + 1, Y2 - 1, Value);
+ if X2 > X1 then VertLineS(X2, Y1 + 1, Y2 - 1, Value);
+ end;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.FrameRectTS(X1, Y1, X2, Y2: Integer; Value: TColor32);
+begin
+ if (X2 > X1) and (Y2 > Y1) and (X1 < Width) and (Y1 < Height) and
+ (X2 > 0) and (Y2 > 0) then
+ begin
+ Dec(Y2);
+ Dec(X2);
+ HorzLineTS(X1, Y1, X2, Value);
+ if Y2 > Y1 then HorzLineTS(X1, Y2, X2, Value);
+ if Y2 > Y1 + 1 then
+ begin
+ VertLineTS(X1, Y1 + 1, Y2 - 1, Value);
+ if X2 > X1 then VertLineTS(X2, Y1 + 1, Y2 - 1, Value);
+ end;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.FrameRectTSP(X1, Y1, X2, Y2: Integer);
+begin
+ if (X2 > X1) and (Y2 > Y1) and (X1 < Width) and (Y1 < Height) and
+ (X2 > 0) and (Y2 > 0) then
+ begin
+ Dec(X2);
+ Dec(Y2);
+ if X1 = X2 then
+ if Y1 = Y2 then SetPixelT(X1, Y1, GetStippleColor)
+ else VertLineTSP(X1, Y1, Y2)
+ else
+ if Y1 = Y2 then HorzLineTSP(X1, Y1, X2)
+ else
+ begin
+ HorzLineTSP(X1, Y1, X2 - 1);
+ VertLineTSP(X2, Y1, Y2 - 1);
+ HorzLineTSP(X2, Y2, X1 + 1);
+ VertLineTSP(X1, Y2, Y1 + 1);
+ end;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.FrameRectS(const ARect: TRect; Value: TColor32);
+begin
+ with ARect do FrameRectS(Left, Top, Right, Bottom, Value);
+end;
+
+procedure TBitmap32.FrameRectTS(const ARect: TRect; Value: TColor32);
+begin
+ with ARect do FrameRectTS(Left, Top, Right, Bottom, Value);
+end;
+
+procedure TBitmap32.RaiseRectTS(X1, Y1, X2, Y2: Integer; Contrast: Integer);
+var
+ C1, C2: TColor32;
+begin
+ if (X2 > X1) and (Y2 > Y1) and (X1 < Width) and (Y1 < Height) and
+ (X2 > 0) and (Y2 > 0) then
+ try
+ if Contrast > 0 then
+ begin
+ C1 := SetAlpha(clWhite32, Clamp(Contrast * 512 div 100));
+ C2 := SetAlpha(clBlack32, Clamp(Contrast * 255 div 100));
+ end
+ else if Contrast < 0 then
+ begin
+ Contrast := -Contrast;
+ C1 := SetAlpha(clBlack32, Clamp(Contrast * 255 div 100));
+ C2 := SetAlpha(clWhite32, Clamp(Contrast * 512 div 100));
+ end
+ else Exit;
+
+ Dec(X2);
+ Dec(Y2);
+ HorzLineTS(X1, Y1, X2, C1);
+ HorzLineTS(X1, Y2, X2, C2);
+ Inc(Y1);
+ Dec(Y2);
+ VertLineTS(X1, Y1, Y2, C1);
+ VertLineTS(X2, Y1, Y2, C2);
+ finally
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.RaiseRectTS(const ARect: TRect; Contrast: Integer);
+begin
+ with ARect do RaiseRectTS(Left, Top, Right, Bottom, Contrast);
+end;
+
+procedure TBitmap32.LoadFromStream(Stream: TStream);
+var
+ B: TBitmap;
+begin
+ B := TBitmap.Create;
+ try
+ B.LoadFromStream(Stream);
+ Assign(B);
+ finally
+ B.Free;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.SaveToStream(Stream: TStream);
+begin
+ with TBitmap.Create do
+ try
+ Assign(Self);
+ SaveToStream(Stream);
+ finally
+ Free;
+ end;
+end;
+
+function TBitmap32.Equal(B: TBitmap32): Boolean;
+var
+ S1, S2: TMemoryStream;
+begin
+ Result := (B <> nil) and (ClassType = B.ClassType);
+
+ if Empty or B.Empty then
+ begin
+ Result := Empty and B.Empty;
+ Exit;
+ end;
+
+ if Result then
+ begin
+ S1 := TMemoryStream.Create;
+ try
+ SaveToStream(S1);
+ S2 := TMemoryStream.Create;
+ try
+ B.SaveToStream(S2);
+ Result := (S1.Size = S2.Size) and CompareMem(S1.Memory, S2.Memory, S1.Size);
+ finally
+ S2.Free;
+ end;
+ finally
+ S1.Free;
+ end;
+ end;
+end;
+
+procedure TBitmap32.DefineProperties(Filer: TFiler);
+
+ function DoWrite: Boolean;
+ begin
+ if Filer.Ancestor <> nil then
+ Result := not (Filer.Ancestor is TBitmap32) or
+ not Equal(TBitmap32(Filer.Ancestor))
+ else
+ Result := not Empty;
+ end;
+
+begin
+ Filer.DefineBinaryProperty('Data', ReadData, WriteData, DoWrite);
+end;
+
+procedure TBitmap32.ReadData(Stream: TStream);
+var
+ w, h: Integer;
+begin
+ try
+ Stream.ReadBuffer(w, 4);
+ Stream.ReadBuffer(h, 4);
+ SetSize(w, h);
+ Stream.ReadBuffer(FBits[0], FWidth * FHeight * 4);
+ finally
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.WriteData(Stream: TStream);
+begin
+ Stream.WriteBuffer(FWidth, 4);
+ Stream.WriteBuffer(FHeight, 4);
+ Stream.WriteBuffer(FBits[0], FWidth * FHeight * 4);
+end;
+
+procedure TBitmap32.LoadFromFile(const FileName: string);
+var
+ P: TPicture;
+begin
+ P := TPicture.Create;
+ try
+ P.LoadFromFile(FileName);
+ Assign(P);
+ finally
+ P.Free;
+ end;
+end;
+
+procedure TBitmap32.SaveToFile(const FileName: string);
+begin
+ with TBitmap.Create do
+ try
+ Assign(Self);
+ SaveToFile(FileName);
+ finally
+ Free;
+ end;
+end;
+
+procedure TBitmap32.LoadFromResourceID(Instance: THandle; ResID: Integer);
+var
+ B: TBitmap;
+begin
+ B := TBitmap.Create;
+ try
+ B.LoadFromResourceID(Instance, ResID);
+ Assign(B);
+ finally
+ B.Free;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.LoadFromResourceName(Instance: THandle; const ResName: string);
+var
+ B: TBitmap;
+begin
+ B := TBitmap.Create;
+ try
+ B.LoadFromResourceName(Instance, ResName);
+ Assign(B);
+ finally
+ B.Free;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.SetFont(Value: TFont);
+begin
+ FFont.Assign(Value);
+ FontChanged(Self);
+end;
+
+procedure TBitmap32.FontChanged(Sender: TObject);
+begin
+{$IFDEF CLX}
+ if Assigned(FontHandle) then FontHandle := nil;
+{$ELSE}
+ if FontHandle <> 0 then
+ begin
+ if Handle <> 0 then SelectObject(Handle, StockFont);
+ FontHandle := 0;
+ end;
+{$ENDIF}
+end;
+
+procedure TBitmap32.UpdateFont;
+begin
+{$IFDEF CLX}
+ FontHandle := Font.Handle;
+{$ELSE}
+ if (FontHandle = 0) and (Handle <> 0) then
+ begin
+ SelectObject(Handle, Font.Handle);
+ SetTextColor(Handle, ColorToRGB(Font.Color));
+ SetBkMode(Handle, Windows.TRANSPARENT);
+ FontHandle := Font.Handle;
+ end
+ else
+ begin
+ SelectObject(Handle, FontHandle);
+ SetTextColor(Handle, ColorToRGB(Font.Color));
+ SetBkMode(Handle, Windows.TRANSPARENT);
+ end;
+{$ENDIF}
+end;
+
+procedure TBitmap32.SetDrawMode(Value: TDrawMode);
+begin
+ if FDrawMode <> Value then
+ begin
+ FDrawMode := Value;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.SetMasterAlpha(Value: Cardinal);
+begin
+ if FMasterAlpha <> Value then
+ begin
+ FMasterAlpha := Value;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.SetStretchFilter(Value: TStretchFilter);
+begin
+ if FStretchFilter <> Value then
+ begin
+ FStretchFilter := Value;
+ Changed;
+ end;
+end;
+
+// Text and Fonts //
+
+{$IFDEF CLX}
+function TBitmap32.TextExtent(const Text: Widestring): TSize;
+begin
+ Result := TextExtentW(Text); // QT uses Unicode.
+end;
+{$ELSE}
+function TBitmap32.TextExtent(const Text: String): TSize;
+var
+ DC: HDC;
+ OldFont: HGDIOBJ;
+begin
+ UpdateFont;
+ Result.cX := 0;
+ Result.cY := 0;
+ if Handle <> 0 then
+ Windows.GetTextExtentPoint32(Handle, PChar(Text), Length(Text), Result)
+ else
+ begin
+ StockBitmap.Canvas.Lock;
+ try
+ DC := StockBitmap.Canvas.Handle;
+ OldFont := SelectObject(DC, Font.Handle);
+ Windows.GetTextExtentPoint32(DC, PChar(Text), Length(Text), Result);
+ SelectObject(DC, OldFont);
+ finally
+ StockBitmap.Canvas.Unlock;
+ end;
+ end;
+end;
+{$ENDIF}
+
+// -------------------------------------------------------------------
+
+function TBitmap32.TextExtentW(const Text: Widestring): TSize;
+var
+{$IFDEF CLX}
+ OldFont: TFont;
+{$ELSE}
+ DC: HDC;
+ OldFont: HGDIOBJ;
+{$ENDIF}
+begin
+ UpdateFont;
+ Result.cX := 0;
+ Result.cY := 0;
+{$IFDEF CLX}
+ if Assigned(Handle) then
+ begin // doing it the ugly way to avoid QImage <-> QPixMap conversion.
+ with TBitmap.Create do
+ try
+ Width := 5;
+ Height := 5;
+ Canvas.Font.Assign(Font);
+ Result := Canvas.TextExtent(Text);
+ finally
+ Free;
+ end;
+ end
+ else
+ begin
+ StockBitmap.Canvas.Lock;
+ try
+ OldFont := TFont.Create;
+ OldFont.Assign(StockBitmap.Canvas.Font);
+ StockBitmap.Canvas.Font.Assign(Font);
+ Result := StockBitmap.Canvas.TextExtent(Text);
+ StockBitmap.Canvas.Font.Assign(OldFont);
+ OldFont.Free;
+ finally
+ StockBitmap.Canvas.Unlock;
+ end;
+ end;
+{$ELSE}
+ if Handle <> 0 then
+ Windows.GetTextExtentPoint32W(Handle, PWideChar(Text), Length(Text), Result)
+ else
+ begin
+ StockBitmap.Canvas.Lock;
+ try
+ DC := StockBitmap.Canvas.Handle;
+ OldFont := SelectObject(DC, Font.Handle);
+ Windows.GetTextExtentPoint32W(DC, PWideChar(Text), Length(Text), Result);
+ SelectObject(DC, OldFont);
+ finally
+ StockBitmap.Canvas.Unlock;
+ end;
+ end;
+{$ENDIF};
+end;
+
+// -------------------------------------------------------------------
+
+{$IFDEF CLX}
+procedure TBitmap32.Textout(X, Y: Integer; const Text: Widestring);
+begin
+ TextoutW(X, Y, Text); // QT uses Unicode
+end;
+{$ELSE}
+procedure TBitmap32.Textout(X, Y: Integer; const Text: String);
+begin
+ UpdateFont;
+ ExtTextout(Handle, X, Y, 0, nil, PChar(Text), Length(Text), nil);
+ Changed;
+end;
+{$ENDIF}
+
+procedure TBitmap32.TextoutW(X, Y: Integer; const Text: Widestring);
+{$IFDEF CLX}
+var
+ R: TRect;
+{$ENDIF}
+begin
+ UpdateFont;
+{$IFDEF CLX}
+ StartPainter;
+ R := Rect(X, Y, High(Word), High(Word));
+ QPainter_setFont(Handle, Font.Handle);
+ QPainter_setPen(Handle, Font.FontPen);
+ QPainter_drawText(Handle, @R, 0, @Text, -1, nil, nil);
+ StopPainter;
+{$ELSE}
+ ExtTextoutW(Handle, X, Y, 0, nil, PWideChar(Text), Length(Text), nil);
+{$ENDIF}
+ Changed;
+end;
+
+// -------------------------------------------------------------------
+
+{$IFDEF CLX}
+procedure TBitmap32.Textout(X, Y: Integer; const ClipRect: TRect; const Text: Widestring);
+begin
+ TextoutW(X, Y, ClipRect, Text);
+end;
+{$ELSE}
+procedure TBitmap32.Textout(X, Y: Integer; const ClipRect: TRect; const Text: String);
+begin
+ UpdateFont;
+ ExtTextout(Handle, X, Y, ETO_CLIPPED, @ClipRect, PChar(Text), Length(Text), nil);
+ Changed;
+end;
+{$ENDIF}
+
+procedure TBitmap32.TextoutW(X, Y: Integer; const ClipRect: TRect; const Text: Widestring);
+{$IFDEF CLX}
+var
+ TextW: WideString;
+ R: TRect;
+{$ENDIF}
+begin
+ UpdateFont;
+{$IFDEF CLX}
+ StartPainter;
+ TextW := WideString(Text);
+ R := Rect(X, Y, High(Word), High(Word));
+ QPainter_setFont(Handle, Font.Handle);
+ QPainter_setPen(Handle, Font.FontPen);
+ QPainter_setClipRect(Handle, @ClipRect);
+ QPainter_setClipping(Handle, True);
+ QPainter_drawText(Handle, @R, 0, @TextW, -1, nil, nil);
+ QPainter_setClipping(Handle, False);
+ StopPainter;
+{$ELSE}
+ ExtTextoutW(Handle, X, Y, ETO_CLIPPED, @ClipRect, PWideChar(Text), Length(Text), nil);
+{$ENDIF}
+ Changed;
+end;
+
+// -------------------------------------------------------------------
+
+{$IFDEF CLX}
+procedure TBitmap32.Textout(DstRect: TRect; const Flags: Cardinal; const Text: Widestring);
+begin
+ TextoutW(DstRect, Flags, Text);
+end;
+{$ELSE}
+procedure TBitmap32.Textout(DstRect: TRect; const Flags: Cardinal; const Text: String);
+begin
+ UpdateFont;
+ DrawText(Handle, PChar(Text), Length(Text), DstRect, Flags);
+ Changed;
+end;
+{$ENDIF}
+
+procedure TBitmap32.TextoutW(DstRect: TRect; const Flags: Cardinal;
+ const Text: Widestring);
+begin
+ UpdateFont;
+{$IFDEF CLX}
+ StartPainter;
+ QPainter_setFont(Handle, Font.Handle);
+ QPainter_setPen(Handle, Font.FontPen);
+ QPainter_drawText(Handle, @DstRect, Flags, @Text, -1, nil, nil);
+ StopPainter;
+{$ELSE}
+ DrawTextW(Handle, PWideChar(Text), Length(Text), DstRect, Flags);
+{$ENDIF}
+ Changed;
+end;
+
+// -------------------------------------------------------------------
+
+{$IFDEF CLX}
+function TBitmap32.TextHeight(const Text: Widestring): Integer;
+begin
+ Result := TextExtentW(Text).cY;
+end;
+{$ELSE}
+function TBitmap32.TextHeight(const Text: String): Integer;
+begin
+ Result := TextExtent(Text).cY;
+end;
+{$ENDIF}
+
+function TBitmap32.TextHeightW(const Text: Widestring): Integer;
+begin
+ Result := TextExtentW(Text).cY;
+end;
+
+// -------------------------------------------------------------------
+
+{$IFDEF CLX}
+function TBitmap32.TextWidth(const Text: Widestring): Integer;
+begin
+ Result := TextExtentW(Text).cX;
+end;
+{$ELSE}
+function TBitmap32.TextWidth(const Text: String): Integer;
+begin
+ Result := TextExtent(Text).cX;
+end;
+{$ENDIF}
+
+function TBitmap32.TextWidthW(const Text: Widestring): Integer;
+begin
+ Result := TextExtentW(Text).cX;
+end;
+
+// -------------------------------------------------------------------
+
+procedure TBitmap32.TextScaleDown(const B, B2: TBitmap32; const N: Integer;
+ const Color: TColor32); // use only the blue channel
+var
+ I, J, X, Y, P, Q, Sz, S: Integer;
+ Src: PColor32;
+ Dst: PColor32;
+begin
+ Sz := 1 shl N - 1;
+ Dst := B.PixelPtr[0, 0];
+ for J := 0 to B.Height - 1 do
+ begin
+ Y := J shl N;
+ for I := 0 to B.Width - 1 do
+ begin
+ X := I shl N;
+ S := 0;
+ for Q := Y to Y + Sz do
+ begin
+ Src := B2.PixelPtr[X, Q];
+ for P := X to X + Sz do
+ begin
+ S := S + Integer(Src^ and $000000FF);
+ Inc(Src);
+ end;
+ end;
+ S := S shr N shr N;
+ Dst^ := TColor32(S shl 24) + Color;
+ Inc(Dst);
+ end;
+ end;
+end;
+
+procedure TBitmap32.TextBlueToAlpha(const B: TBitmap32; const Color: TColor32);
+var
+ I: Integer;
+ P: PColor32;
+ C: TColor32;
+begin
+ // convert blue channel to alpha and fill the color
+ P := @B.Bits[0];
+ for I := 0 to B.Width * B.Height - 1 do
+ begin
+ C := P^;
+ if C <> 0 then
+ begin
+ C := P^ shl 24; // transfer blue channel to alpha
+ C := C + Color;
+ P^ := C;
+ end;
+ Inc(P);
+ end;
+end;
+
+{$IFDEF CLX}
+procedure TBitmap32.RenderText(X, Y: Integer; const Text: Widestring; AALevel: Integer; Color: TColor32);
+begin
+ RenderTextW(X, Y, Text, AALevel, Color); // QT does Unicode
+end;
+{$ELSE}
+procedure TBitmap32.RenderText(X, Y: Integer; const Text: String; AALevel: Integer; Color: TColor32);
+var
+ B, B2: TBitmap32;
+ Sz: TSize;
+ Alpha: TColor32;
+ StockCanvas: TCanvas;
+ PaddedText: String;
+begin
+ if Empty then Exit;
+
+ Alpha := Color shr 24;
+ Color := Color and $00FFFFFF;
+ AALevel := Constrain(AALevel, 0, 4);
+ PaddedText := Text + ' ';
+
+ B := TBitmap32.Create;
+ try
+ if AALevel = 0 then
+ begin
+ TextBlueToAlpha(B, Color);
+ Sz := TextExtent(PaddedText);
+ B.SetSize(Sz.cX, Sz.cY);
+ B.Font := Font;
+ B.Clear(0);
+ B.Font.Color := clWhite;
+ B.Textout(0, 0, Text);
+ TextBlueToAlpha(B, Color);
+ end
+ else
+ begin
+ StockCanvas := StockBitmap.Canvas;
+ StockCanvas.Lock;
+ try
+ StockCanvas.Font := Font;
+ StockCanvas.Font.Size := Font.Size shl AALevel;
+ Sz := StockCanvas.TextExtent(PaddedText);
+ Sz.Cx := (Sz.cx shr AALevel + 1) shl AALevel;
+ B2 := TBitmap32.Create;
+ try
+ B2.SetSize(Sz.Cx, Sz.Cy);
+ B2.Clear(0);
+ B2.Font := StockCanvas.Font;
+ B2.Font.Color := clWhite;
+ B2.Textout(0, 0, Text);
+ B2.StretchFilter := sfLinear;
+ B.SetSize(Sz.cx shr AALevel, Sz.cy shr AALevel);
+ TextScaleDown(B, B2, AALevel, Color);
+ finally
+ B2.Free;
+ end;
+ finally
+ StockCanvas.Unlock;
+ end;
+ end;
+
+ B.DrawMode := dmBlend;
+ B.MasterAlpha := Alpha;
+
+ B.DrawTo(Self, X, Y);
+ finally
+ B.Free;
+ end;
+end;
+{$ENDIF}
+
+procedure TBitmap32.RenderTextW(X, Y: Integer; const Text: Widestring; AALevel: Integer; Color: TColor32);
+var
+ B, B2: TBitmap32;
+ Sz: TSize;
+ Alpha: TColor32;
+ StockCanvas: TCanvas;
+ PaddedText: Widestring;
+begin
+ if Empty then Exit;
+
+ Alpha := Color shr 24;
+ Color := Color and $00FFFFFF;
+ AALevel := Constrain(AALevel, 0, 4);
+ PaddedText := Text + ' ';
+
+ B := TBitmap32.Create;
+ try
+ if AALevel = 0 then
+ begin
+{$IFDEF CLX}
+ B.Font := Font;
+ Sz := B.TextExtentW(PaddedText);
+ B.SetSize(Sz.cX, Sz.cY);
+{$ELSE}
+ Sz := TextExtentW(PaddedText);
+ B.SetSize(Sz.cX, Sz.cY);
+ B.Font := Font;
+{$ENDIF}
+ B.Clear(0);
+ B.Font.Color := clWhite;
+ B.Textout(0, 0, Text);
+ TextBlueToAlpha(B, Color);
+ end
+ else
+ begin
+ StockCanvas := StockBitmap.Canvas;
+ StockCanvas.Lock;
+ try
+ StockCanvas.Font := Font;
+ StockCanvas.Font.Size := Font.Size shl AALevel;
+{$IFDEF CLX}
+ Sz := StockCanvas.TextExtent(PaddedText);
+{$ELSE}
+ Windows.GetTextExtentPoint32W(StockCanvas.Handle, PWideChar(PaddedText),
+ Length(PaddedText), Sz);
+{$ENDIF}
+ Sz.Cx := (Sz.cx shr AALevel + 1) shl AALevel;
+ B2 := TBitmap32.Create;
+ try
+ B2.SetSize(Sz.Cx, Sz.Cy);
+ B2.Clear(0);
+ B2.Font := StockCanvas.Font;
+ B2.Font.Color := clWhite;
+ B2.TextoutW(0, 0, Text);
+ B2.StretchFilter := sfLinear;
+ B.SetSize(Sz.cx shr AALevel, Sz.cy shr AALevel);
+ TextScaleDown(B, B2, AALevel, Color);
+ finally
+ B2.Free;
+ end;
+ finally
+ StockCanvas.Unlock;
+ end;
+ end;
+
+ B.DrawMode := dmBlend;
+ B.MasterAlpha := Alpha;
+
+ B.DrawTo(Self, X, Y);
+ finally
+ B.Free;
+ end;
+end;
+
+// -------------------------------------------------------------------
+
+procedure TBitmap32.Roll(Dx, Dy: Integer; FillBack: Boolean; FillColor: TColor32);
+var
+ Shift, L: Integer;
+ R: TRect;
+begin
+ if Empty or ((Dx = 0) and (Dy = 0)) then Exit;
+ if (Abs(Dx) >= Width) or (Abs(Dy) >= Height) then
+ begin
+ if FillBack then Clear(FillColor);
+ Exit;
+ end;
+
+ Shift := Dx + Dy * Width;
+ L := (Width * Height - Abs(Shift)) shl 2;
+ if Shift > 0 then Move(Bits[0], Bits[Shift], L)
+ else Move(Bits[-Shift], Bits[0], L);
+
+ if FillBack then
+ begin
+ R := MakeRect(0, 0, Width, Height);
+ OffsetRect(R, Dx, Dy);
+ IntersectRect(R, R, MakeRect(0, 0, Width, Height));
+ if R.Top > 0 then FillRect(0, 0, Width, R.Top, FillColor)
+ else if R.Top = 0 then FillRect(0, R.Bottom, Width, Height, FillColor);
+ if R.Left > 0 then FillRect(0, R.Top, R.Left, R.Bottom, FillColor)
+ else if R.Left = 0 then FillRect(R.Right, R.Top, Width, R.Bottom, FillColor);
+ end;
+
+ Changed;
+end;
+
+procedure TBitmap32.FlipHorz(Dst: TBitmap32);
+var
+ i, j: Integer;
+ P1, P2: PColor32;
+ tmp: TColor32;
+ W, W2: Integer;
+begin
+ W := Width;
+ if (Dst = nil) or (Dst = Self) then
+ begin
+ { In-place flipping }
+ P1 := PColor32(Bits);
+ P2 := P1;
+ Inc(P2, Width - 1);
+ W2 := Width shr 1;
+ for J := 0 to Height - 1 do
+ begin
+ for I := 0 to W2 - 1 do
+ begin
+ tmp := P1^;
+ P1^ := P2^;
+ P2^ := tmp;
+ Inc(P1);
+ Dec(P2);
+ end;
+ Inc(P1, W - W2);
+ Inc(P2, W + W2);
+ end;
+ Changed;
+ end
+ else
+ begin
+ { Flip to Dst }
+ Dst.BeginUpdate;
+ Dst.SetSize(W, Height);
+ P1 := PColor32(Bits);
+ P2 := PColor32(Dst.Bits);
+ Inc(P2, W - 1);
+ for J := 0 to Height - 1 do
+ begin
+ for I := 0 to W - 1 do
+ begin
+ P2^ := P1^;
+ Inc(P1);
+ Dec(P2);
+ end;
+ Inc(P2, W shl 1);
+ end;
+ Dst.EndUpdate;
+ Dst.Changed;
+ end;
+end;
+
+procedure TBitmap32.FlipVert(Dst: TBitmap32);
+var
+ J, J2: Integer;
+ Buffer: PColor32Array;
+ P1, P2: PColor32;
+begin
+ if (Dst = nil) or (Dst = Self) then
+ begin
+ { in-place }
+ J2 := Height - 1;
+ GetMem(Buffer, Width shl 2);
+ for J := 0 to Height div 2 - 1 do
+ begin
+ P1 := PixelPtr[0, J];
+ P2 := PixelPtr[0, J2];
+ MoveLongword(P1^, Buffer^, Width);
+ MoveLongword(P2^, P1^, Width);
+ MoveLongword(Buffer^, P2^, Width);
+ Dec(J2);
+ end;
+ FreeMem(Buffer);
+ Changed;
+ end
+ else
+ begin
+ Dst.SetSize(Width, Height);
+ J2 := Height - 1;
+ for J := 0 to Height - 1 do
+ begin
+ MoveLongword(PixelPtr[0, J]^, Dst.PixelPtr[0, J2]^, Width);
+ Dec(J2);
+ end;
+ Dst.Changed;
+ end;
+end;
+
+procedure TBitmap32.Rotate90(Dst: TBitmap32);
+var
+ Tmp: TBitmap32;
+ X, Y, I, J: Integer;
+begin
+ if Dst = nil then
+ begin
+ Tmp := TBitmap32.Create;
+ Dst := Tmp;
+ end
+ else
+ begin
+ Tmp := nil;
+ Dst.BeginUpdate;
+ end;
+
+
+ Dst.SetSize(Height, Width);
+ I := 0;
+ for Y := 0 to Height - 1 do
+ begin
+ J := Height - 1 - Y;
+ for X := 0 to Width - 1 do
+ begin
+ Dst.Bits[J] := Bits[I];
+ Inc(I);
+ Inc(J, Height);
+ end;
+ end;
+
+ if Tmp <> nil then
+ begin
+ Tmp.DrawMode := DrawMode;
+ Tmp.StretchFilter := StretchFilter;
+ Tmp.MasterAlpha := MasterAlpha;
+ Tmp.OuterColor := OuterColor;
+ Assign(Tmp);
+ Tmp.Free;
+ end
+ else
+ begin
+ Dst.EndUpdate;
+ Dst.Changed;
+ end;
+end;
+
+procedure TBitmap32.Rotate180(Dst: TBitmap32);
+var
+ I, I2: Integer;
+ Tmp: TColor32;
+begin
+ if Dst <> nil then
+ begin
+ Dst.SetSize(Width, Height);
+ I2 := Width * Height - 1;
+ for I := 0 to Width * Height - 1 do
+ begin
+ Dst.Bits[I2] := Bits[I];
+ Inc(I2);
+ end;
+ Dst.Changed;
+ end
+ else
+ begin
+ I2 := Width * Height - 1;
+ for I := 0 to Width * Height div 2 - 1 do
+ begin
+ Tmp := Bits[I2];
+ Bits[I2] := Bits[I];
+ Bits[I] := Tmp;
+ Dec(I2);
+ end;
+ Changed;
+ end;
+end;
+
+procedure TBitmap32.Rotate270(Dst: TBitmap32);
+var
+ Tmp: TBitmap32;
+ X, Y, I, J: Integer;
+begin
+ if Dst = nil then
+ begin
+ Tmp := TBitmap32.Create;
+ Dst := Tmp;
+ end
+ else
+ begin
+ Tmp := nil;
+ Dst.BeginUpdate;
+ end;
+
+ Dst.SetSize(Height, Width);
+ I := 0;
+ for Y := 0 to Height - 1 do
+ begin
+ J := (Width - 1) * Height + Y;
+ for X := 0 to Width - 1 do
+ begin
+ Dst.Bits[J] := Bits[I];
+ Inc(I);
+ Dec(J, Height);
+ end;
+ end;
+
+ if Tmp <> nil then
+ begin
+ Tmp.DrawMode := DrawMode;
+ Tmp.StretchFilter := StretchFilter;
+ Tmp.MasterAlpha := MasterAlpha;
+ Tmp.OuterColor := OuterColor;
+ Assign(Tmp);
+ Tmp.Free;
+ end
+ else Dst.Changed;
+end;
+
+function TBitmap32.BoundsRect: TRect;
+begin
+ Result.Left := 0;
+ Result.Top := 0;
+ Result.Right := Width;
+ Result.Bottom := Height;
+end;
+
+{$IFDEF CLX}
+procedure TBitmap32.PixmapNeeded;
+begin
+ if Assigned(FPixmap) and Assigned(FHandle) and not FPixmapActive then
+ begin
+ QPixmap_convertFromImage(FPixmap, FHandle, QPixmapColorMode(QPixmapColorMode_Auto));
+ FPixmapActive := True;
+ FPixmapChanged := False;
+ end;
+end;
+
+procedure TBitmap32.ImageNeeded;
+begin
+ if Assigned(FPixmap) and Assigned(FHandle) and FPixmapActive and FPixmapChanged then
+ begin
+ QPixmap_convertToImage(FPixmap, FHandle);
+ FPixmapActive := False;
+ FPixmapChanged := False;
+ FBits := Pointer(QImage_bits(FHandle));
+ end;
+end;
+
+procedure TBitmap32.CheckPixmap;
+begin
+ if not FPixmapChanged then
+ // try to avoid QPixmap -> QImage conversion, since we don't need that.
+ FPixmapActive := False;
+ // else the conversion takes place as soon as the Bits property is accessed.
+end;
+
+function TBitmap32.GetBits: PColor32Array;
+begin
+ ImageNeeded;
+ Result := FBits;
+end;
+
+function TBitmap32.GetPixmap: QPixmapH;
+begin
+ PixmapNeeded;
+ Result := FPixmap;
+end;
+
+function TBitmap32.GetPainter: QPainterH;
+begin
+ PixmapNeeded;
+ Result := FHDC;
+end;
+
+procedure TBitmap32.StartPainter;
+begin
+ If (FPainterCount = 0) and not QPainter_isActive(Handle) then
+ if not QPainter_begin(Handle, Pixmap) then
+ raise EInvalidGraphicOperation.CreateRes(@SInvalidCanvasState);
+
+ Inc(FPainterCount);
+end;
+
+procedure TBitmap32.StopPainter;
+begin
+ Dec(FPainterCount);
+ If (FPainterCount = 0) then
+ begin
+ QPainter_end(Handle);
+ FPixmapChanged := True;
+ end;
+end;
+
+{ TBitmap32Canvas }
+
+procedure TBitmap32Canvas.BeginPainting;
+begin
+ if not QPainter_isActive(FBitmap.Handle) then
+ if not QPainter_begin(FBitmap.Handle, FBitmap.Pixmap) then
+ raise EInvalidGraphicOperation.CreateRes(@SInvalidCanvasState);
+
+ FBitmap.PixmapChanged := True; // whatever happens, we've potentially changed
+ // the Pixmap, so propagate that status...
+end;
+
+constructor TBitmap32Canvas.Create(Bitmap: TBitmap32);
+begin
+ inherited Create;
+ FBitmap := Bitmap;
+end;
+
+procedure TBitmap32Canvas.CreateHandle;
+begin
+ Handle := QPainter_create;
+end;
+
+{$ENDIF}
+
+{ Interpolators }
+
+function _Interpolator(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
+var
+ C1, C3: TColor32;
+begin
+ if WX_256 > $FF then WX_256:= $FF;
+ if WY_256 > $FF then WY_256:= $FF;
+ C1 := C11^; Inc(C11);
+ C3 := C21^; Inc(C21);
+ Result := CombineReg(CombineReg(C1, C11^, WX_256),
+ CombineReg(C3, C21^, WX_256), WY_256);
+end;
+
+function M_Interpolator(WX_256, WY_256: Cardinal; C11, C21: PColor32): TColor32;
+asm
+ db $0F,$6F,$09 /// MOVQ MM1,[ECX]
+ MOV ECX,C21
+ db $0F,$6F,$19 /// MOVQ MM3,[ECX]
+ db $0F,$6F,$D1 /// MOVQ MM2,MM1
+ db $0F,$6F,$E3 /// MOVQ MM4,MM3
+ db $0F,$73,$D1,$20 /// PSRLQ MM1,32
+ db $0F,$73,$D3,$20 /// PSRLQ MM3,32
+
+ db $0F,$6E,$E8 /// MOVD MM5,EAX
+ db $0F,$61,$ED /// PUNPCKLWD MM5,MM5
+ db $0F,$62,$ED /// PUNPCKLDQ MM5,MM5
+
+ db $0F,$EF,$C0 /// PXOR MM0, MM0
+
+ db $0F,$60,$C8 /// PUNPCKLBW MM1,MM0
+ db $0F,$60,$D0 /// PUNPCKLBW MM2,MM0
+ db $0F,$F9,$D1 /// PSUBW MM2,MM1
+ db $0F,$D5,$D5 /// PMULLW MM2,MM5
+ db $0F,$71,$F1,$08 /// PSLLW MM1,8
+ db $0F,$FD,$D1 /// PADDW MM2,MM1
+ db $0F,$71,$D2,$08 /// PSRLW MM2,8
+
+ db $0F,$60,$D8 /// PUNPCKLBW MM3,MM0
+ db $0F,$60,$E0 /// PUNPCKLBW MM4,MM0
+ db $0F,$F9,$E3 /// PSUBW MM4,MM3
+ db $0F,$D5,$E5 /// PMULLW MM4,MM5
+ db $0F,$71,$F3,$08 /// PSLLW MM3,8
+ db $0F,$FD,$E3 /// PADDW MM4,MM3
+ db $0F,$71,$D4,$08 /// PSRLW MM4,8
+
+ db $0F,$6E,$EA /// MOVD MM5,EDX
+ db $0F,$61,$ED /// PUNPCKLWD MM5,MM5
+ db $0F,$62,$ED /// PUNPCKLDQ MM5,MM5
+
+ db $0F,$F9,$D4 /// PSUBW MM2,MM4
+ db $0F,$D5,$D5 /// PMULLW MM2,MM5
+ db $0F,$71,$F4,$08 /// PSLLW MM4,8
+ db $0F,$FD,$D4 /// PADDW MM2,MM4
+ db $0F,$71,$D2,$08 /// PSRLW MM2,8
+
+ db $0F,$67,$D0 /// PACKUSWB MM2,MM0
+ db $0F,$7E,$D0 /// MOVD EAX,MM2
+end;
+
+procedure SetupFunctions;
+var
+ MMX_ACTIVE: Boolean;
+ ACTIVE_3DNow: Boolean;
+begin
+ MMX_ACTIVE := HasMMX;
+ ACTIVE_3DNow := Has3DNow;
+ if ACTIVE_3DNow then
+ begin
+ // link 3DNow functions
+ Interpolator := M_Interpolator;
+ end
+ else
+ if MMX_ACTIVE then
+ begin
+ // link MMX functions
+ Interpolator := M_Interpolator;
+ end
+ else
+ begin
+ // link IA32 functions
+ Interpolator := _Interpolator;
+ end
+end;
+
+initialization
+ InitializeCriticalSection(CounterLock);
+ SetupFunctions;
+ SetGamma;
+{$IFDEF CLX}
+ StockFont := TFont.Create;
+{$ELSE}
+ StockFont := GetStockObject(SYSTEM_FONT);
+{$ENDIF}
+ StockBitmap := TBitmap.Create;
+ StockBitmap.Width := 8;
+ StockBitmap.Height := 8;
+
+finalization
+{$IFDEF CLX}
+ StockFont.Free;
+{$ENDIF}
+ StockBitmap.Free;
+ DeleteCriticalSection(CounterLock);
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_Blend.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Blend.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Blend.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Blend.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Blend.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1265 @@
+unit GR32_Blend;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mattias Andersson
+ * - 2004/07/07 - MMX Blendmodes
+ *
+ * Michael Hansen <dyster_tid at hotmail.com>
+ * - 2004/07/07 - Pascal Blendmodes, function setup
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Blend.pas,v 1.2 2004/07/07 11:39:58 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ GR32;
+
+var
+ MMX_ACTIVE: Boolean;
+
+type
+{ Function Prototypes }
+ TCombineReg = function(X, Y, W: TColor32): TColor32;
+ TCombineMem = procedure(F: TColor32; var B: TColor32; W: TColor32);
+ TBlendReg = function(F, B: TColor32): TColor32;
+ TBlendMem = procedure(F: TColor32; var B: TColor32);
+ TBlendRegEx = function(F, B, M: TColor32): TColor32;
+ TBlendMemEx = procedure(F: TColor32; var B: TColor32; M: TColor32);
+ TBlendLine = procedure(Src, Dst: PColor32; Count: Integer);
+ TBlendLineEx = procedure(Src, Dst: PColor32; Count: Integer; M: TColor32);
+
+procedure EMMS;
+
+var
+{ Function Variables }
+ CombineReg: TCombineReg;
+ CombineMem: TCombineMem;
+
+ BlendReg: TBlendReg;
+ BlendMem: TBlendMem;
+
+ BlendRegEx: TBlendRegEx;
+ BlendMemEx: TBlendMemEx;
+
+ BlendLine: TBlendLine;
+ BlendLineEx: TBlendLineEx;
+
+{ Color algebra functions }
+ ColorAdd: TBlendReg;
+ ColorSub: TBlendReg;
+ ColorModulate: TBlendReg;
+ ColorMax: TBlendReg;
+ ColorMin: TBlendReg;
+ ColorDifference: TBlendReg;
+ ColorExclusion: TBlendReg;
+
+{ Special LUT pointers }
+ AlphaTable: Pointer;
+ bias_ptr: Pointer;
+ alpha_ptr: Pointer;
+
+{ Misc stuff }
+function Lighten(C: TColor32; Amount: Integer): TColor32;
+
+
+
+
+implementation
+
+uses Math, GR32_System;
+
+{ Non-MMX versions }
+
+const bias = $00800080;
+
+function _CombineReg(X, Y, W: TColor32): TColor32;
+asm
+ // combine RGBA channels of colors X and Y with the weight of X given in W
+ // Result Z = W * X + (1 - W) * Y (all channels are combined, including alpha)
+ // EAX <- X
+ // EDX <- Y
+ // ECX <- W
+
+ // W = 0 or $FF?
+ JCXZ @1 // CX = 0 ? => Result := EDX
+ CMP ECX,$FF // CX = $FF ? => Result := EDX
+ JE @2
+
+ PUSH EBX
+
+ // P = W * X
+ MOV EBX,EAX // EBX <- Xa Xr Xg Xb
+ AND EAX,$00FF00FF // EAX <- 00 Xr 00 Xb
+ AND EBX,$FF00FF00 // EBX <- Xa 00 Xg 00
+ IMUL EAX,ECX // EAX <- Pr ** Pb **
+ SHR EBX,8 // EBX <- 00 Xa 00 Xg
+ IMUL EBX,ECX // EBX <- Pa ** Pg **
+ ADD EAX,bias
+ AND EAX,$FF00FF00 // EAX <- Pa 00 Pg 00
+ SHR EAX,8 // EAX <- 00 Pr 00 Pb
+ ADD EBX,bias
+ AND EBX,$FF00FF00 // EBX <- Pa 00 Pg 00
+ OR EAX,EBX // EAX <- Pa Pr Pg Pb
+
+ // W = 1 - W; Q = W * Y
+ XOR ECX,$000000FF // ECX <- 1 - ECX
+ MOV EBX,EDX // EBX <- Ya Yr Yg Yb
+ AND EDX,$00FF00FF // EDX <- 00 Yr 00 Yb
+ AND EBX,$FF00FF00 // EBX <- Ya 00 Yg 00
+ IMUL EDX,ECX // EDX <- Qr ** Qb **
+ SHR EBX,8 // EBX <- 00 Ya 00 Yg
+ IMUL EBX,ECX // EBX <- Qa ** Qg **
+ ADD EDX,bias
+ AND EDX,$FF00FF00 // EDX <- Qr 00 Qb 00
+ SHR EDX,8 // EDX <- 00 Qr ** Qb
+ ADD EBX,bias
+ AND EBX,$FF00FF00 // EBX <- Qa 00 Qg 00
+ OR EBX,EDX // EBX <- Qa Qr Qg Qb
+
+ // Z = P + Q (assuming no overflow at each byte)
+ ADD EAX,EBX // EAX <- Za Zr Zg Zb
+
+ POP EBX
+ RET
+
+ at 1: MOV EAX,EDX
+ at 2: RET
+end;
+
+procedure _CombineMem(F: TColor32; var B: TColor32; W: TColor32);
+asm
+ // EAX <- F
+ // [EDX] <- B
+ // ECX <- W
+
+ // Check W
+ JCXZ @1 // W = 0 ? => write nothing
+ CMP ECX,$FF // W = 255? => write F
+ JZ @2
+
+ PUSH EBX
+ PUSH ESI
+
+ // P = W * F
+ MOV EBX,EAX // EBX <- ** Fr Fg Fb
+ AND EAX,$00FF00FF // EAX <- 00 Fr 00 Fb
+ AND EBX,$0000FF00 // EBX <- 00 00 Fg 00
+ IMUL EAX,ECX // EAX <- Pr ** Pb **
+ SHR EBX,8 // EBX <- 00 00 00 Fg
+ IMUL EBX,ECX // EBX <- 00 00 Pg **
+ ADD EAX,bias
+ AND EAX,$FF00FF00 // EAX <- Pr 00 Pb 00
+ SHR EAX,8 // EAX <- 00 Pr 00 Pb
+ ADD EBX,bias
+ AND EBX,$0000FF00 // EBX <- 00 00 Pg 00
+ OR EAX,EBX // EAX <- 00 Pr Pg Pb
+
+ // W = 1 - W; Q = W * B
+ MOV ESI,[EDX]
+ XOR ECX,$000000FF // ECX <- 1 - ECX
+ MOV EBX,ESI // EBX <- 00 Br Bg Bb
+ AND ESI,$00FF00FF // ESI <- 00 Br 00 Bb
+ AND EBX,$0000FF00 // EBX <- 00 00 Bg 00
+ IMUL ESI,ECX // ESI <- Qr ** Qb **
+ SHR EBX,8 // EBX <- 00 00 00 Bg
+ IMUL EBX,ECX // EBX <- 00 00 Qg **
+ ADD ESI,bias
+ AND ESI,$FF00FF00 // ESI <- Qr 00 Qb 00
+ SHR ESI,8 // ESI <- 00 Qr ** Qb
+ ADD EBX,bias
+ AND EBX,$0000FF00 // EBX <- 00 00 Qg 00
+ OR EBX,ESI // EBX <- 00 Qr Qg Qb
+
+ // Z = P + Q (assuming no overflow at each byte)
+ ADD EAX,EBX // EAX <- 00 Zr Zg Zb
+
+ MOV [EDX],EAX
+
+ POP ESI
+ POP EBX
+ at 1: RET
+
+ at 2: MOV [EDX],EAX
+ RET
+end;
+
+function _BlendReg(F, B: TColor32): TColor32;
+asm
+ // blend foregrownd color (F) to a background color (B),
+ // using alpha channel value of F
+ // Result Z = Fa * Frgb + (1 - Fa) * Brgb
+ // EAX <- F
+ // EDX <- B
+
+ // Test Fa = 255 ?
+ CMP EAX,$FF000000 // Fa = 255 ? => Result = EAX
+ JNC @2
+
+ // Test Fa = 0 ?
+ TEST EAX,$FF000000 // Fa = 0 ? => Result = EDX
+ JZ @1
+
+ // Get weight W = Fa * M
+ MOV ECX,EAX // ECX <- Fa Fr Fg Fb
+ SHR ECX,24 // ECX <- 00 00 00 Fa
+
+ PUSH EBX
+
+ // P = W * F
+ MOV EBX,EAX // EBX <- Fa Fr Fg Fb
+ AND EAX,$00FF00FF // EAX <- 00 Fr 00 Fb
+ AND EBX,$FF00FF00 // EBX <- Fa 00 Fg 00
+ IMUL EAX,ECX // EAX <- Pr ** Pb **
+ SHR EBX,8 // EBX <- 00 Fa 00 Fg
+ IMUL EBX,ECX // EBX <- Pa ** Pg **
+ ADD EAX,bias
+ AND EAX,$FF00FF00 // EAX <- Pr 00 Pb 00
+ SHR EAX,8 // EAX <- 00 Pr ** Pb
+ ADD EBX,bias
+ AND EBX,$FF00FF00 // EBX <- Pa 00 Pg 00
+ OR EAX,EBX // EAX <- Pa Pr Pg Pb
+
+ // W = 1 - W; Q = W * B
+ XOR ECX,$000000FF // ECX <- 1 - ECX
+ MOV EBX,EDX // EBX <- Ba Br Bg Bb
+ AND EDX,$00FF00FF // EDX <- 00 Br 00 Bb
+ AND EBX,$FF00FF00 // EBX <- Ba 00 Bg 00
+ IMUL EDX,ECX // EDX <- Qr ** Qb **
+ SHR EBX,8 // EBX <- 00 Ba 00 Bg
+ IMUL EBX,ECX // EBX <- Qa ** Qg **
+ ADD EDX,bias
+ AND EDX,$FF00FF00 // EDX <- Qr 00 Qb 00
+ SHR EDX,8 // EDX <- 00 Qr ** Qb
+ ADD EBX,bias
+ AND EBX,$FF00FF00 // EBX <- Qa 00 Qg 00
+ OR EBX,EDX // EBX <- Qa Qr Qg Qb
+
+ // Z = P + Q (assuming no overflow at each byte)
+ ADD EAX,EBX // EAX <- Za Zr Zg Zb
+
+ POP EBX
+ RET
+
+ at 1: MOV EAX,EDX
+ at 2: RET
+end;
+
+procedure _BlendMem(F: TColor32; var B: TColor32);
+asm
+ // EAX <- F
+ // [EDX] <- B
+
+
+ // Test Fa = 0 ?
+ TEST EAX,$FF000000 // Fa = 0 ? => do not write
+ JZ @2
+
+ // Get weight W = Fa * M
+ MOV ECX,EAX // ECX <- Fa Fr Fg Fb
+ SHR ECX,24 // ECX <- 00 00 00 Fa
+
+ // Test Fa = 255 ?
+ CMP ECX,$FF
+ JZ @1
+
+ PUSH EBX
+ PUSH ESI
+
+ // P = W * F
+ MOV EBX,EAX // EBX <- Fa Fr Fg Fb
+ AND EAX,$00FF00FF // EAX <- 00 Fr 00 Fb
+ AND EBX,$FF00FF00 // EBX <- Fa 00 Fg 00
+ IMUL EAX,ECX // EAX <- Pr ** Pb **
+ SHR EBX,8 // EBX <- 00 Fa 00 Fg
+ IMUL EBX,ECX // EBX <- Pa ** Pg **
+ ADD EAX,bias
+ AND EAX,$FF00FF00 // EAX <- Pr 00 Pb 00
+ SHR EAX,8 // EAX <- 00 Pr ** Pb
+ ADD EBX,bias
+ AND EBX,$FF00FF00 // EBX <- Pa 00 Pg 00
+ OR EAX,EBX // EAX <- Pa Pr Pg Pb
+
+ // W = 1 - W; Q = W * B
+ MOV ESI,[EDX]
+ XOR ECX,$000000FF // ECX <- 1 - ECX
+ MOV EBX,ESI // EBX <- Ba Br Bg Bb
+ AND ESI,$00FF00FF // ESI <- 00 Br 00 Bb
+ AND EBX,$FF00FF00 // EBX <- Ba 00 Bg 00
+ IMUL ESI,ECX // ESI <- Qr ** Qb **
+ SHR EBX,8 // EBX <- 00 Ba 00 Bg
+ IMUL EBX,ECX // EBX <- Qa ** Qg **
+ ADD ESI,bias
+ AND ESI,$FF00FF00 // ESI <- Qr 00 Qb 00
+ SHR ESI,8 // ESI <- 00 Qr ** Qb
+ ADD EBX,bias
+ AND EBX,$FF00FF00 // EBX <- Qa 00 Qg 00
+ OR EBX,ESI // EBX <- Qa Qr Qg Qb
+
+ // Z = P + Q (assuming no overflow at each byte)
+ ADD EAX,EBX // EAX <- Za Zr Zg Zb
+ MOV [EDX],EAX
+
+ POP ESI
+ POP EBX
+ RET
+
+ at 1: MOV [EDX],EAX
+ at 2: RET
+end;
+
+function _BlendRegEx(F, B, M: TColor32): TColor32;
+asm
+ // blend foregrownd color (F) to a background color (B),
+ // using alpha channel value of F multiplied by master alpha (M)
+ // no checking for M = $FF, if this is the case when Graphics32 uses BlendReg
+ // Result Z = Fa * M * Frgb + (1 - Fa * M) * Brgb
+ // EAX <- F
+ // EDX <- B
+ // ECX <- M
+
+ // Check Fa > 0 ?
+ TEST EAX,$FF000000 // Fa = 0? => Result := EDX
+ JZ @2
+
+ PUSH EBX
+
+ // Get weight W = Fa * M
+ MOV EBX,EAX // EBX <- Fa Fr Fg Fb
+ INC ECX // 255:256 range bias
+ SHR EBX,24 // EBX <- 00 00 00 Fa
+ IMUL ECX,EBX // ECX <- 00 00 W **
+ SHR ECX,8 // ECX <- 00 00 00 W
+ JZ @1 // W = 0 ? => Result := EDX
+
+ // P = W * F
+ MOV EBX,EAX // EBX <- ** Fr Fg Fb
+ AND EAX,$00FF00FF // EAX <- 00 Fr 00 Fb
+ AND EBX,$0000FF00 // EBX <- 00 00 Fg 00
+ IMUL EAX,ECX // EAX <- Pr ** Pb **
+ SHR EBX,8 // EBX <- 00 00 00 Fg
+ IMUL EBX,ECX // EBX <- 00 00 Pg **
+ ADD EAX,bias
+ AND EAX,$FF00FF00 // EAX <- Pr 00 Pb 00
+ SHR EAX,8 // EAX <- 00 Pr ** Pb
+ ADD EBX,bias
+ AND EBX,$0000FF00 // EBX <- 00 00 Pg 00
+ OR EAX,EBX // EAX <- 00 Pr Pg Pb
+
+ // W = 1 - W; Q = W * B
+ XOR ECX,$000000FF // ECX <- 1 - ECX
+ MOV EBX,EDX // EBX <- 00 Br Bg Bb
+ AND EDX,$00FF00FF // EDX <- 00 Br 00 Bb
+ AND EBX,$0000FF00 // EBX <- 00 00 Bg 00
+ IMUL EDX,ECX // EDX <- Qr ** Qb **
+ SHR EBX,8 // EBX <- 00 00 00 Bg
+ IMUL EBX,ECX // EBX <- 00 00 Qg **
+ ADD EDX,bias
+ AND EDX,$FF00FF00 // EDX <- Qr 00 Qb 00
+ SHR EDX,8 // EDX <- 00 Qr ** Qb
+ ADD EBX,bias
+ AND EBX,$0000FF00 // EBX <- 00 00 Qg 00
+ OR EBX,EDX // EBX <- 00 Qr Qg Qb
+
+ // Z = P + Q (assuming no overflow at each byte)
+ ADD EAX,EBX // EAX <- 00 Zr Zg Zb
+
+ POP EBX
+ RET
+
+ at 1: POP EBX
+ at 2: MOV EAX,EDX
+ RET
+end;
+
+procedure _BlendMemEx(F: TColor32; var B: TColor32; M: TColor32);
+asm
+ // EAX <- F
+ // [EDX] <- B
+ // ECX <- M
+
+ // Check Fa > 0 ?
+ TEST EAX,$FF000000 // Fa = 0? => write nothing
+ JZ @2
+
+ PUSH EBX
+
+ // Get weight W = Fa * M
+ MOV EBX,EAX // EBX <- Fa Fr Fg Fb
+ INC ECX // 255:256 range bias
+ SHR EBX,24 // EBX <- 00 00 00 Fa
+ IMUL ECX,EBX // ECX <- 00 00 W **
+ SHR ECX,8 // ECX <- 00 00 00 W
+ JZ @1 // W = 0 ? => write nothing
+
+ PUSH ESI
+
+ // P = W * F
+ MOV EBX,EAX // EBX <- ** Fr Fg Fb
+ AND EAX,$00FF00FF // EAX <- 00 Fr 00 Fb
+ AND EBX,$0000FF00 // EBX <- 00 00 Fg 00
+ IMUL EAX,ECX // EAX <- Pr ** Pb **
+ SHR EBX,8 // EBX <- 00 00 00 Fg
+ IMUL EBX,ECX // EBX <- 00 00 Pg **
+ ADD EAX,bias
+ AND EAX,$FF00FF00 // EAX <- Pr 00 Pb 00
+ SHR EAX,8 // EAX <- 00 Pr ** Pb
+ ADD EBX,bias
+ AND EBX,$0000FF00 // EBX <- 00 00 Pg 00
+ OR EAX,EBX // EAX <- 00 Pr Pg Pb
+
+ // W = 1 - W; Q = W * B
+ MOV ESI,[EDX]
+ XOR ECX,$000000FF // ECX <- 1 - ECX
+ MOV EBX,ESI // EBX <- 00 Br Bg Bb
+ AND ESI,$00FF00FF // ESI <- 00 Br 00 Bb
+ AND EBX,$0000FF00 // EBX <- 00 00 Bg 00
+ IMUL ESI,ECX // ESI <- Qr ** Qb **
+ SHR EBX,8 // EBX <- 00 00 00 Bg
+ IMUL EBX,ECX // EBX <- 00 00 Qg **
+ ADD ESI,bias
+ AND ESI,$FF00FF00 // ESI <- Qr 00 Qb 00
+ SHR ESI,8 // ESI <- 00 Qr ** Qb
+ ADD EBX,bias
+ AND EBX,$0000FF00 // EBX <- 00 00 Qg 00
+ OR EBX,ESI // EBX <- 00 Qr Qg Qb
+
+ // Z = P + Q (assuming no overflow at each byte)
+ ADD EAX,EBX // EAX <- 00 Zr Zg Zb
+
+ MOV [EDX],EAX
+ POP ESI
+
+ at 1: POP EBX
+ at 2: RET
+end;
+
+procedure _BlendLine(Src, Dst: PColor32; Count: Integer);
+asm
+ // EAX <- Src
+ // EDX <- Dst
+ // ECX <- Count
+
+ // test the counter for zero or negativity
+ TEST ECX,ECX
+ JS @4
+
+ PUSH EBX
+ PUSH ESI
+ PUSH EDI
+
+ MOV ESI,EAX // ESI <- Src
+ MOV EDI,EDX // EDI <- Dst
+
+ // loop start
+ at 1: MOV EAX,[ESI]
+ TEST EAX,$FF000000
+ JZ @3 // complete transparency, proceed to next point
+
+ PUSH ECX // store counter
+
+ // Get weight W = Fa * M
+ MOV ECX,EAX // ECX <- Fa Fr Fg Fb
+ SHR ECX,24 // ECX <- 00 00 00 Fa
+
+ // Test Fa = 255 ?
+ CMP ECX,$FF
+ JZ @2
+
+ // P = W * F
+ MOV EBX,EAX // EBX <- Fa Fr Fg Fb
+ AND EAX,$00FF00FF // EAX <- 00 Fr 00 Fb
+ AND EBX,$FF00FF00 // EBX <- Fa 00 Fg 00
+ IMUL EAX,ECX // EAX <- Pr ** Pb **
+ SHR EBX,8 // EBX <- 00 Fa 00 Fg
+ IMUL EBX,ECX // EBX <- Pa ** Pg **
+ ADD EAX,bias
+ AND EAX,$FF00FF00 // EAX <- Pr 00 Pb 00
+ SHR EAX,8 // EAX <- 00 Pr ** Pb
+ ADD EBX,bias
+ AND EBX,$FF00FF00 // EBX <- Pa 00 Pg 00
+ OR EAX,EBX // EAX <- Pa Pr Pg Pb
+
+ // W = 1 - W; Q = W * B
+ MOV EDX,[EDI]
+ XOR ECX,$000000FF // ECX <- 1 - ECX
+ MOV EBX,EDX // EBX <- Ba Br Bg Bb
+ AND EDX,$00FF00FF // ESI <- 00 Br 00 Bb
+ AND EBX,$FF00FF00 // EBX <- Ba 00 Bg 00
+ IMUL EDX,ECX // ESI <- Qr ** Qb **
+ SHR EBX,8 // EBX <- 00 Ba 00 Bg
+ IMUL EBX,ECX // EBX <- Qa ** Qg **
+ ADD EDX,bias
+ AND EDX,$FF00FF00 // ESI <- Qr 00 Qb 00
+ SHR EDX,8 // ESI <- 00 Qr ** Qb
+ ADD EBX,bias
+ AND EBX,$FF00FF00 // EBX <- Qa 00 Qg 00
+ OR EBX,EDX // EBX <- Qa Qr Qg Qb
+
+ // Z = P + Q (assuming no overflow at each byte)
+ ADD EAX,EBX // EAX <- Za Zr Zg Zb
+ at 2: MOV [EDI],EAX
+
+ POP ECX // restore counter
+
+ at 3: ADD ESI,4
+ ADD EDI,4
+
+ // loop end
+ DEC ECX
+ JNZ @1
+
+ POP EDI
+ POP ESI
+ POP EBX
+
+ at 4: RET
+end;
+
+procedure _BlendLineEx(Src, Dst: PColor32; Count: Integer; M: TColor32);
+begin
+ while Count > 0 do
+ begin
+ _BlendMemEx(Src^, Dst^, M);
+ Inc(Src);
+ Inc(Dst);
+ Dec(Count);
+ end;
+end;
+
+
+{ MMX versions }
+
+
+procedure GenAlphaTable;
+var
+ I: Integer;
+ L: Longword;
+ P: ^Longword;
+begin
+ GetMem(AlphaTable, 257 * 8);
+ alpha_ptr := Pointer(Integer(AlphaTable) and $FFFFFFF8);
+ if Integer(alpha_ptr) < Integer(AlphaTable) then
+ alpha_ptr := Pointer(Integer(alpha_ptr) + 8);
+ P := alpha_ptr;
+ for I := 0 to 255 do
+ begin
+ L := I + I shl 16;
+ P^ := L;
+ Inc(P);
+ P^ := L;
+ Inc(P);
+ end;
+ bias_ptr := Pointer(Integer(alpha_ptr) + $80 * 8);
+end;
+
+procedure FreeAlphaTable;
+begin
+ FreeMem(AlphaTable);
+end;
+
+procedure EMMS;
+begin
+ if MMX_ACTIVE then
+ asm
+ db $0F,$77 /// EMMS
+ end;
+end;
+
+function M_CombineReg(X, Y, W: TColor32): TColor32;
+asm
+ // EAX - Color X
+ // EDX - Color Y
+ // ECX - Weight of X [0..255]
+ // Result := W * (X - Y) + Y
+
+ db $0F,$6E,$C8 /// MOVD MM1,EAX
+ db $0F,$EF,$C0 /// PXOR MM0,MM0
+ SHL ECX,3
+ db $0F,$6E,$D2 /// MOVD MM2,EDX
+ db $0F,$60,$C8 /// PUNPCKLBW MM1,MM0
+ db $0F,$60,$D0 /// PUNPCKLBW MM2,MM0
+ ADD ECX,alpha_ptr
+ db $0F,$F9,$CA /// PSUBW MM1,MM2
+ db $0F,$D5,$09 /// PMULLW MM1,[ECX]
+ db $0F,$71,$F2,$08 /// PSLLW MM2,8
+ MOV ECX,bias_ptr
+ db $0F,$FD,$11 /// PADDW MM2,[ECX]
+ db $0F,$FD,$CA /// PADDW MM1,MM2
+ db $0F,$71,$D1,$08 /// PSRLW MM1,8
+ db $0F,$67,$C8 /// PACKUSWB MM1,MM0
+ db $0F,$7E,$C8 /// MOVD EAX,MM1
+end;
+
+procedure M_CombineMem(F: TColor32; var B: TColor32; W: TColor32);
+asm
+ // EAX - Color X
+ // [EDX] - Color Y
+ // ECX - Weight of X [0..255]
+ // Result := W * (X - Y) + Y
+
+ JCXZ @1
+ CMP ECX,$FF
+ JZ @2
+
+ db $0F,$6E,$C8 /// MOVD MM1,EAX
+ db $0F,$EF,$C0 /// PXOR MM0,MM0
+ SHL ECX,3
+ db $0F,$6E,$12 /// MOVD MM2,[EDX]
+ db $0F,$60,$C8 /// PUNPCKLBW MM1,MM0
+ db $0F,$60,$D0 /// PUNPCKLBW MM2,MM0
+ ADD ECX,alpha_ptr
+ db $0F,$F9,$CA /// PSUBW MM1,MM2
+ db $0F,$D5,$09 /// PMULLW MM1,[ECX]
+ db $0F,$71,$F2,$08 /// PSLLW MM2,8
+ MOV ECX,bias_ptr
+ db $0F,$FD,$11 /// PADDW MM2,[ECX]
+ db $0F,$FD,$CA /// PADDW MM1,MM2
+ db $0F,$71,$D1,$08 /// PSRLW MM1,8
+ db $0F,$67,$C8 /// PACKUSWB MM1,MM0
+ db $0F,$7E,$0A /// MOVD [EDX],MM1
+ at 1: RET
+
+ at 2: MOV [EDX],EAX
+end;
+
+function M_BlendReg(F, B: TColor32): TColor32;
+asm
+ // blend foregrownd color (F) to a background color (B),
+ // using alpha channel value of F
+ // EAX <- F
+ // EDX <- B
+ // Result := Fa * (Frgb - Brgb) + Brgb
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$EF,$DB /// PXOR MM3,MM3
+ db $0F,$6E,$D2 /// MOVD MM2,EDX
+ db $0F,$60,$C3 /// PUNPCKLBW MM0,MM3
+ MOV ECX,bias_ptr
+ db $0F,$60,$D3 /// PUNPCKLBW MM2,MM3
+ db $0F,$6F,$C8 /// MOVQ MM1,MM0
+ db $0F,$69,$C9 /// PUNPCKHWD MM1,MM1
+ db $0F,$F9,$C2 /// PSUBW MM0,MM2
+ db $0F,$6A,$C9 /// PUNPCKHDQ MM1,MM1
+ db $0F,$71,$F2,$08 /// PSLLW MM2,8
+ db $0F,$D5,$C1 /// PMULLW MM0,MM1
+ db $0F,$FD,$11 /// PADDW MM2,[ECX]
+ db $0F,$FD,$D0 /// PADDW MM2,MM0
+ db $0F,$71,$D2,$08 /// PSRLW MM2,8
+ db $0F,$67,$D3 /// PACKUSWB MM2,MM3
+ db $0F,$7E,$D0 /// MOVD EAX,MM2
+end;
+
+procedure M_BlendMem(F: TColor32; var B: TColor32);
+asm
+ // EAX - Color X
+ // [EDX] - Color Y
+ // Result := W * (X - Y) + Y
+
+ TEST EAX,$FF000000
+ JZ @1
+ CMP EAX,$FF000000
+ JNC @2
+
+ db $0F,$EF,$DB /// PXOR MM3,MM3
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$6E,$12 /// MOVD MM2,[EDX]
+ db $0F,$60,$C3 /// PUNPCKLBW MM0,MM3
+ MOV ECX,bias_ptr
+ db $0F,$60,$D3 /// PUNPCKLBW MM2,MM3
+ db $0F,$6F,$C8 /// MOVQ MM1,MM0
+ db $0F,$69,$C9 /// PUNPCKHWD MM1,MM1
+ db $0F,$F9,$C2 /// PSUBW MM0,MM2
+ db $0F,$6A,$C9 /// PUNPCKHDQ MM1,MM1
+ db $0F,$71,$F2,$08 /// PSLLW MM2,8
+ db $0F,$D5,$C1 /// PMULLW MM0,MM1
+ db $0F,$FD,$11 /// PADDW MM2,[ECX]
+ db $0F,$FD,$D0 /// PADDW MM2,MM0
+ db $0F,$71,$D2,$08 /// PSRLW MM2,8
+ db $0F,$67,$D3 /// PACKUSWB MM2,MM3
+ db $0F,$7E,$12 /// MOVD [EDX],MM2
+ at 1: RET
+
+ at 2: MOV [EDX],EAX
+end;
+
+function M_BlendRegEx(F, B, M: TColor32): TColor32;
+asm
+ // blend foregrownd color (F) to a background color (B),
+ // using alpha channel value of F
+ // EAX <- F
+ // EDX <- B
+ // ECX <- M
+ // Result := M * Fa * (Frgb - Brgb) + Brgb
+ PUSH EBX
+ MOV EBX,EAX
+ SHR EBX,24
+ INC ECX // 255:256 range bias
+ IMUL ECX,EBX
+ SHR ECX,8
+ JZ @1
+
+ db $0F,$EF,$C0 /// PXOR MM0,MM0
+ db $0F,$6E,$C8 /// MOVD MM1,EAX
+ SHL ECX,3
+ db $0F,$6E,$D2 /// MOVD MM2,EDX
+ db $0F,$60,$C8 /// PUNPCKLBW MM1,MM0
+ db $0F,$60,$D0 /// PUNPCKLBW MM2,MM0
+ ADD ECX,alpha_ptr
+ db $0F,$F9,$CA /// PSUBW MM1,MM2
+ db $0F,$D5,$09 /// PMULLW MM1,[ECX]
+ db $0F,$71,$F2,$08 /// PSLLW MM2,8
+ MOV ECX,bias_ptr
+ db $0F,$FD,$11 /// PADDW MM2,[ECX]
+ db $0F,$FD,$CA /// PADDW MM1,MM2
+ db $0F,$71,$D1,$08 /// PSRLW MM1,8
+ db $0F,$67,$C8 /// PACKUSWB MM1,MM0
+ db $0F,$7E,$C8 /// MOVD EAX,MM1
+
+ POP EBX
+ RET
+
+ at 1: MOV EAX,EDX
+ POP EBX
+end;
+
+procedure M_BlendMemEx(F: TColor32; var B:TColor32; M: TColor32);
+asm
+ // blend foregrownd color (F) to a background color (B),
+ // using alpha channel value of F
+ // EAX <- F
+ // [EDX] <- B
+ // ECX <- M
+ // Result := M * Fa * (Frgb - Brgb) + Brgb
+ TEST EAX,$FF000000
+ JZ @2
+
+ PUSH EBX
+ MOV EBX,EAX
+ SHR EBX,24
+ INC ECX // 255:256 range bias
+ IMUL ECX,EBX
+ SHR ECX,8
+ JZ @1
+
+ db $0F,$EF,$C0 /// PXOR MM0,MM0
+ db $0F,$6E,$C8 /// MOVD MM1,EAX
+ SHL ECX,3
+ db $0F,$6E,$12 /// MOVD MM2,[EDX]
+ db $0F,$60,$C8 /// PUNPCKLBW MM1,MM0
+ db $0F,$60,$D0 /// PUNPCKLBW MM2,MM0
+ ADD ECX,alpha_ptr
+ db $0F,$F9,$CA /// PSUBW MM1,MM2
+ db $0F,$D5,$09 /// PMULLW MM1,[ECX]
+ db $0F,$71,$F2,$08 /// PSLLW MM2,8
+ MOV ECX,bias_ptr
+ db $0F,$FD,$11 /// PADDW MM2,[ECX]
+ db $0F,$FD,$CA /// PADDW MM1,MM2
+ db $0F,$71,$D1,$08 /// PSRLW MM1,8
+ db $0F,$67,$C8 /// PACKUSWB MM1,MM0
+ db $0F,$7E,$0A /// MOVD [EDX],MM1
+ at 1: POP EBX
+ at 2:
+end;
+
+procedure M_BlendLine(Src, Dst: PColor32; Count: Integer);
+asm
+ // EAX <- Src
+ // EDX <- Dst
+ // ECX <- Count
+
+ // test the counter for zero or negativity
+ TEST ECX,ECX
+ JS @4
+
+ PUSH ESI
+ PUSH EDI
+
+ MOV ESI,EAX // ESI <- Src
+ MOV EDI,EDX // EDI <- Dst
+
+ // loop start
+ at 1: MOV EAX,[ESI]
+ TEST EAX,$FF000000
+ JZ @3 // complete transparency, proceed to next point
+ CMP EAX,$FF000000
+ JNC @2 // opaque pixel, copy without blending
+
+ // blend
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$EF,$DB /// PXOR MM3,MM3
+ db $0F,$6E,$17 /// MOVD MM2,[EDI]
+ db $0F,$60,$C3 /// PUNPCKLBW MM0,MM3
+ MOV EAX,bias_ptr
+ db $0F,$60,$D3 /// PUNPCKLBW MM2,MM3
+ db $0F,$6F,$C8 /// MOVQ MM1,MM0
+ db $0F,$69,$C9 /// PUNPCKHWD MM1,MM1
+ db $0F,$F9,$C2 /// PSUBW MM0,MM2
+ db $0F,$6A,$C9 /// PUNPCKHDQ MM1,MM1
+ db $0F,$71,$F2,$08 /// PSLLW MM2,8
+ db $0F,$D5,$C1 /// PMULLW MM0,MM1
+ db $0F,$FD,$10 /// PADDW MM2,[EAX]
+ db $0F,$FD,$D0 /// PADDW MM2,MM0
+ db $0F,$71,$D2,$08 /// PSRLW MM2,8
+ db $0F,$67,$D3 /// PACKUSWB MM2,MM3
+ db $0F,$7E,$D0 /// MOVD EAX,MM2
+
+ at 2: MOV [EDI],EAX
+
+ at 3: ADD ESI,4
+ ADD EDI,4
+
+ // loop end
+ DEC ECX
+ JNZ @1
+
+ POP EDI
+ POP ESI
+
+ at 4: RET
+end;
+
+procedure M_BlendLineEx(Src, Dst: PColor32; Count: Integer; M: TColor32);
+asm
+ // EAX <- Src
+ // EDX <- Dst
+ // ECX <- Count
+
+ // test the counter for zero or negativity
+ TEST ECX,ECX
+ JS @4
+
+ PUSH ESI
+ PUSH EDI
+ PUSH EBX
+
+ MOV ESI,EAX // ESI <- Src
+ MOV EDI,EDX // EDI <- Dst
+ MOV EDX,M // EDX <- Master Alpha
+
+ // loop start
+ at 1: MOV EAX,[ESI]
+ TEST EAX,$FF000000
+ JZ @3 // complete transparency, proceed to next point
+ MOV EBX,EAX
+ SHR EBX,24
+ INC EBX // 255:256 range bias
+ IMUL EBX,EDX
+ SHR EBX,8
+ JZ @3 // complete transparency, proceed to next point
+
+ // blend
+ db $0F,$EF,$C0 /// PXOR MM0,MM0
+ db $0F,$6E,$C8 /// MOVD MM1,EAX
+ SHL EBX,3
+ db $0F,$6E,$17 /// MOVD MM2,[EDI]
+ db $0F,$60,$C8 /// PUNPCKLBW MM1,MM0
+ db $0F,$60,$D0 /// PUNPCKLBW MM2,MM0
+ ADD EBX,alpha_ptr
+ db $0F,$F9,$CA /// PSUBW MM1,MM2
+ db $0F,$D5,$0B /// PMULLW MM1,[EBX]
+ db $0F,$71,$F2,$08 /// PSLLW MM2,8
+ MOV EBX,bias_ptr
+ db $0F,$FD,$13 /// PADDW MM2,[EBX]
+ db $0F,$FD,$CA /// PADDW MM1,MM2
+ db $0F,$71,$D1,$08 /// PSRLW MM1,8
+ db $0F,$67,$C8 /// PACKUSWB MM1,MM0
+ db $0F,$7E,$C8 /// MOVD EAX,MM1
+
+ at 2: MOV [EDI],EAX
+
+ at 3: ADD ESI,4
+ ADD EDI,4
+
+ // loop end
+ DEC ECX
+ JNZ @1
+
+ POP EBX
+ POP EDI
+ POP ESI
+ at 4:
+end;
+
+{ Non-MMX Color algebra versions }
+
+function _ColorAdd(C1, C2: TColor32): TColor32;
+var
+ r1, g1, b1, a1: Integer;
+ r2, g2, b2, a2: Integer;
+begin
+ a1 := C1 shr 24;
+ r1 := C1 and $00FF0000;
+ g1 := C1 and $0000FF00;
+ b1 := C1 and $000000FF;
+
+ a2 := C2 shr 24;
+ r2 := C2 and $00FF0000;
+ g2 := C2 and $0000FF00;
+ b2 := C2 and $000000FF;
+
+ a1 := a1 + a2;
+ r1 := r1 + r2;
+ g1 := g1 + g2;
+ b1 := b1 + b2;
+
+ if a1 > $FF then a1 := $FF;
+ if r1 > $FF0000 then r1 := $FF0000;
+ if g1 > $FF00 then g1 := $FF00;
+ if b1 > $FF then b1 := $FF;
+
+ Result := a1 shl 24 + r1 + g1 + b1;
+end;
+
+function _ColorSub(C1, C2: TColor32): TColor32;
+var
+ r1, g1, b1, a1: Integer;
+ r2, g2, b2, a2: Integer;
+begin
+ a1 := C1 shr 24;
+ r1 := C1 and $00FF0000;
+ g1 := C1 and $0000FF00;
+ b1 := C1 and $000000FF;
+
+ r1 := r1 shr 16;
+ g1 := g1 shr 8;
+
+ a2 := C2 shr 24;
+ r2 := C2 and $00FF0000;
+ g2 := C2 and $0000FF00;
+ b2 := C2 and $000000FF;
+
+ r2 := r2 shr 16;
+ g2 := g2 shr 8;
+
+ a1 := a1 - a2;
+ r1 := r1 - r2;
+ g1 := g1 - g2;
+ b1 := b1 - b2;
+
+ if a1 < 0 then a1 := 0;
+ if r1 < 0 then r1 := 0;
+ if g1 < 0 then g1 := 0;
+ if b1 < 0 then b1 := 0;
+
+ Result := a1 shl 24 + r1 shl 16 + g1 shl 8 + b1;
+end;
+
+function _ColorModulate(C1, C2: TColor32): TColor32;
+var
+ r1, g1, b1, a1: Integer;
+ r2, g2, b2, a2: Integer;
+begin
+ a1 := C1 shr 24;
+ r1 := C1 and $00FF0000;
+ g1 := C1 and $0000FF00;
+ b1 := C1 and $000000FF;
+
+ r1 := r1 shr 16;
+ g1 := g1 shr 8;
+
+ a2 := C2 shr 24;
+ r2 := C2 and $00FF0000;
+ g2 := C2 and $0000FF00;
+ b2 := C2 and $000000FF;
+
+ r2 := r2 shr 16;
+ g2 := g2 shr 8;
+
+ a1 := a1 * a2 shr 8;
+ r1 := r1 * r2 shr 8;
+ g1 := g1 * g2 shr 8;
+ b1 := b1 * b2 shr 8;
+
+ if a1 > 255 then a1 := 255;
+ if r1 > 255 then r1 := 255;
+ if g1 > 255 then g1 := 255;
+ if b1 > 255 then b1 := 255;
+
+ Result := a1 shl 24 + r1 shl 16 + g1 shl 8 + b1;
+end;
+
+function _ColorMax(C1, C2: TColor32): TColor32;
+var
+ r1, g1, b1, a1: TColor32;
+ r2, g2, b2, a2: TColor32;
+begin
+ a1 := C1 shr 24;
+ r1 := C1 and $00FF0000;
+ g1 := C1 and $0000FF00;
+ b1 := C1 and $000000FF;
+
+ a2 := C2 shr 24;
+ r2 := C2 and $00FF0000;
+ g2 := C2 and $0000FF00;
+ b2 := C2 and $000000FF;
+
+ if a2 > a1 then a1 := a2;
+ if r2 > r1 then r1 := r2;
+ if g2 > g1 then g1 := g2;
+ if b2 > b1 then b1 := b2;
+
+ Result := a1 shl 24 + r1 + g1 + b1;
+end;
+
+function _ColorMin(C1, C2: TColor32): TColor32;
+var
+ r1, g1, b1, a1: TColor32;
+ r2, g2, b2, a2: TColor32;
+begin
+ a1 := C1 shr 24;
+ r1 := C1 and $00FF0000;
+ g1 := C1 and $0000FF00;
+ b1 := C1 and $000000FF;
+
+ a2 := C2 shr 24;
+ r2 := C2 and $00FF0000;
+ g2 := C2 and $0000FF00;
+ b2 := C2 and $000000FF;
+
+ if a2 < a1 then a1 := a2;
+ if r2 < r1 then r1 := r2;
+ if g2 < g1 then g1 := g2;
+ if b2 < b1 then b1 := b2;
+
+ Result := a1 shl 24 + r1 + g1 + b1;
+end;
+
+function _ColorDifference(C1, C2: TColor32): TColor32;
+var
+ r1, g1, b1, a1: TColor32;
+ r2, g2, b2, a2: TColor32;
+begin
+ a1 := C1 shr 24;
+ r1 := C1 and $00FF0000;
+ g1 := C1 and $0000FF00;
+ b1 := C1 and $000000FF;
+
+ r1 := r1 shr 16;
+ g1 := g1 shr 8;
+
+ a2 := C2 shr 24;
+ r2 := C2 and $00FF0000;
+ g2 := C2 and $0000FF00;
+ b2 := C2 and $000000FF;
+
+ r2 := r2 shr 16;
+ g2 := g2 shr 8;
+
+ a1 := abs(a2 - a1);
+ r1 := abs(r2 - r1);
+ g1 := abs(g2 - g1);
+ b1 := abs(b2 - b1);
+
+ Result := a1 shl 24 + r1 shl 16 + g1 shl 8 + b1;
+end;
+
+function _ColorExclusion(C1, C2: TColor32): TColor32;
+var
+ r1, g1, b1, a1: TColor32;
+ r2, g2, b2, a2: TColor32;
+begin
+ a1 := C1 shr 24;
+ r1 := C1 and $00FF0000;
+ g1 := C1 and $0000FF00;
+ b1 := C1 and $000000FF;
+
+ r1 := r1 shr 16;
+ g1 := g1 shr 8;
+
+ a2 := C2 shr 24;
+ r2 := C2 and $00FF0000;
+ g2 := C2 and $0000FF00;
+ b2 := C2 and $000000FF;
+
+ r2 := r2 shr 16;
+ g2 := g2 shr 8;
+
+ a1 := a1 + a2 - (a1 * a2 shr 7);
+ r1 := r1 + r2 - (r1 * r2 shr 7);
+ g1 := g1 + g2 - (g1 * g2 shr 7);
+ b1 := b1 + b2 - (b1 * b2 shr 7);
+
+ Result := a1 shl 24 + r1 shl 16 + g1 shl 8 + b1;
+end;
+
+{ MMX Color algebra versions }
+
+function M_ColorAdd(C1, C2: TColor32): TColor32;
+asm
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$6E,$CA /// MOVD MM1,EDX
+ db $0F,$DC,$C1 /// PADDUSB MM0,MM1
+ db $0F,$7E,$C0 /// MOVD EAX,MM0
+end;
+
+function M_ColorSub(C1, C2: TColor32): TColor32;
+asm
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$6E,$CA /// MOVD MM1,EDX
+ db $0F,$D8,$C1 /// PSUBUSB MM0,MM1
+ db $0F,$7E,$C0 /// MOVD EAX,MM0
+end;
+
+function M_ColorModulate(C1, C2: TColor32): TColor32;
+asm
+ db $0F,$EF,$D2 /// PXOR MM2,MM2
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$60,$C2 /// PUNPCKLBW MM0,MM2
+ db $0F,$6E,$CA /// MOVD MM1,EDX
+ db $0F,$60,$CA /// PUNPCKLBW MM1,MM2
+ db $0F,$D5,$C1 /// PMULLW MM0,MM1
+ db $0F,$71,$D0,$08 /// PSRLW MM0,8
+ db $0F,$67,$C2 /// PACKUSWB MM0,MM2
+ db $0F,$7E,$C0 /// MOVD EAX,MM0
+end;
+
+function M_ColorMax(C1, C2: TColor32): TColor32;
+asm
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$6E,$CA /// MOVD MM1,EDX
+ db $0F,$DE,$C1 /// PMAXUB MM0,MM1
+ db $0F,$7E,$C0 /// MOVD EAX,MM0
+end;
+
+function M_ColorMin(C1, C2: TColor32): TColor32;
+asm
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$6E,$CA /// MOVD MM1,EDX
+ db $0F,$DA,$C1 /// PMINUB MM0,MM1
+ db $0F,$7E,$C0 /// MOVD EAX,MM0
+end;
+
+
+function M_ColorDifference(C1, C2: TColor32): TColor32;
+asm
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$6E,$CA /// MOVD MM1,EDX
+ db $0F,$6F,$D0 /// MOVQ MM2,MM0
+ db $0F,$D8,$C1 /// PSUBUSB MM0,MM1
+ db $0F,$D8,$CA /// PSUBUSB MM1,MM2
+ db $0F,$EB,$C1 /// POR MM0,MM1
+ db $0F,$7E,$C0 /// MOVD EAX,MM0
+end;
+
+function M_ColorExclusion(C1, C2: TColor32): TColor32;
+asm
+ db $0F,$EF,$D2 /// PXOR MM2,MM2
+ db $0F,$6E,$C0 /// MOVD MM0,EAX
+ db $0F,$60,$C2 /// PUNPCKLBW MM0,MM2
+ db $0F,$6E,$CA /// MOVD MM1,EDX
+ db $0F,$60,$CA /// PUNPCKLBW MM1,MM2
+ db $0F,$6F,$D8 /// MOVQ MM3,MM0
+ db $0F,$FD,$C1 /// PADDW MM0,MM1
+ db $0F,$D5,$CB /// PMULLW MM1,MM3
+ db $0F,$71,$D1,$07 /// PSRLW MM1,7
+ db $0F,$D9,$C1 /// PSUBUSW MM0,MM1
+ db $0F,$67,$C2 /// PACKUSWB MM0,MM2
+ db $0F,$7E,$C0 /// MOVD EAX,MM0
+end;
+
+{ Misc stuff }
+
+function Lighten(C: TColor32; Amount: Integer): TColor32;
+var
+ r, g, b, a: Integer;
+begin
+ a := C shr 24;
+ r := C and $00FF0000;
+ g := C and $0000FF00;
+ b := C and $000000FF;
+
+ r := r shr 16;
+ g := g shr 8;
+
+ Inc(r, Amount);
+ Inc(g, Amount);
+ Inc(b, Amount);
+
+ if r > 255 then r := 255 else if r < 0 then r := 0;
+ if g > 255 then g := 255 else if g < 0 then g := 0;
+ if b > 255 then b := 255 else if b < 0 then b := 0;
+
+ Result := a shl 24 + r shl 16 + g shl 8 + b;
+end;
+
+{ MMX Detection and linking }
+
+procedure SetupFunctions;
+begin
+ MMX_ACTIVE := HasMMX;
+ if MMX_ACTIVE then
+ begin
+ // link MMX functions
+ CombineReg := M_CombineReg;
+ CombineMem := M_CombineMem;
+ BlendReg := M_BlendReg;
+ BlendMem := M_BlendMem;
+ BlendRegEx := M_BlendRegEx;
+ BlendMemEx := M_BlendMemEx;
+ BlendLine := M_BlendLine;
+ BlendLineEx := M_BlendLineEx;
+
+ ColorAdd := M_ColorAdd;
+ ColorSub := M_ColorSub;
+ ColorModulate:= M_ColorModulate;
+ ColorMax:= M_ColorMax;
+ ColorMin:= M_ColorMin;
+ ColorDifference:= M_ColorDifference;
+ ColorExclusion:= M_ColorExclusion;
+ end
+ else
+ begin
+ // link non-MMX functions
+ CombineReg := _CombineReg;
+ CombineMem := _CombineMem;
+ BlendReg := _BlendReg;
+ BlendMem := _BlendMem;
+ BlendRegEx := _BlendRegEx;
+ BlendMemEx := _BlendMemEx;
+ BlendLine := _BlendLine;
+ BlendLineEx := _BlendLineEx;
+
+ ColorAdd := _ColorAdd;
+ ColorSub := _ColorSub;
+ ColorModulate:= _ColorModulate;
+ ColorMax:= _ColorMax;
+ ColorMin:= _ColorMin;
+ ColorDifference:= _ColorDifference;
+ ColorExclusion:= _ColorExclusion;
+ end;
+end;
+
+initialization
+ SetupFunctions;
+ if MMX_ACTIVE then GenAlphaTable;
+
+finalization
+ if MMX_ACTIVE then FreeAlphaTable;
+
+end.
+
+
+
Added: trunk/WPGM/Components/Graphics32/GR32_ByteMaps.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_ByteMaps.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_ByteMaps.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_ByteMaps.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_ByteMaps.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,345 @@
+unit GR32_ByteMaps;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_ByteMaps.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ {$IFDEF CLX}
+ Qt, Types, {$IFDEF LINUX}Libc, {$ENDIF}
+ {$ELSE}
+ Windows,
+ {$ENDIF}
+ Classes, SysUtils,
+ {$IFDEF CLX}
+ QControls, QGraphics,
+ {$ELSE}
+ Controls, Graphics,
+ {$ENDIF}
+ GR32, GR32_Transforms;
+
+type
+ TConversionType = (ctRed, ctGreen, ctBlue, ctAlpha, ctUniformRGB, ctWeightedRGB);
+
+ TByteMap = class(TCustomMap)
+ private
+ FBytes: TArrayOfByte;
+ function GetValue(X, Y: Integer): Byte;
+ function GetValPtr(X, Y: Integer): PByte;
+ procedure SetValue(X, Y: Integer; Value: Byte);
+ protected
+ procedure AssignTo(Dst: TPersistent); override;
+ procedure ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer); override;
+ public
+ destructor Destroy; override;
+ procedure Assign(Source: TPersistent); override;
+ function Empty: Boolean; override;
+ procedure Clear(FillValue: Byte);
+ procedure ReadFrom(Source: TBitmap32; Conversion: TConversionType);
+ procedure WriteTo(Dest: TBitmap32; Conversion: TConversionType); overload;
+ procedure WriteTo(Dest: TBitmap32; const Palette: TPalette32); overload;
+ property Bytes: TArrayOfByte read FBytes;
+ property ValPtr[X, Y: Integer]: PByte read GetValPtr;
+ property Value[X, Y: Integer]: Byte read GetValue write SetValue; default;
+ end;
+
+implementation
+
+uses Math;
+
+{ TByteMap }
+
+procedure TByteMap.Assign(Source: TPersistent);
+begin
+ BeginUpdate;
+ try
+ if Source is TByteMap then
+ begin
+ inherited SetSize(TByteMap(Source).Width, TByteMap(Source).Height);
+ FBytes := Copy(TByteMap(Source).Bytes, 0, Width * Height);
+ end
+ else if Source is TBitmap32 then
+ ReadFrom(TBitmap32(Source), ctWeightedRGB)
+ else
+ inherited;
+ finally
+ EndUpdate;
+ Changed;
+ end;
+end;
+
+procedure TByteMap.AssignTo(Dst: TPersistent);
+begin
+ if Dst is TBitmap32 then WriteTo(TBitmap32(Dst), ctUniformRGB)
+ else inherited;
+end;
+
+procedure TByteMap.ChangeSize(var Width, Height: Integer; NewWidth, NewHeight: Integer);
+begin
+ SetLength(FBytes, NewWidth * NewHeight);
+ Width := NewWidth;
+ Height := NewHeight;
+end;
+
+procedure TByteMap.Clear(FillValue: Byte);
+begin
+ FillChar(Bytes[0], Width * Height, FillValue);
+ Changed;
+end;
+
+destructor TByteMap.Destroy;
+begin
+ FBytes := nil;
+ inherited;
+end;
+
+function TByteMap.Empty: Boolean;
+begin
+ Result := not Assigned(Bytes);
+end;
+
+function TByteMap.GetValPtr(X, Y: Integer): PByte;
+begin
+ Result := @Bytes[X + Y * Width];
+end;
+
+function TByteMap.GetValue(X, Y: Integer): Byte;
+begin
+ Result := Bytes[X + Y * Width];
+end;
+
+procedure TByteMap.ReadFrom(Source: TBitmap32; Conversion: TConversionType);
+var
+ W, H, I, N: Integer;
+ SrcC: PColor32;
+ SrcB, DstB: PByte;
+ Value: TColor32;
+begin
+ BeginUpdate;
+ try
+ SetSize(Source.Width, Source.Height);
+ if Empty then Exit;
+
+ W := Source.Width;
+ H := Source.Height;
+ N := W * H - 1;
+ SrcC := Source.PixelPtr[0, 0];
+ SrcB := Pointer(SrcC);
+ DstB := @Bytes[0];
+ case Conversion of
+
+ ctRed:
+ begin
+ Inc(SrcB, 2);
+ for I := 0 to N do
+ begin
+ DstB^ := SrcB^;
+ Inc(DstB);
+ Inc(SrcB, 4);
+ end;
+ end;
+
+ ctGreen:
+ begin
+ Inc(SrcB, 1);
+ for I := 0 to N do
+ begin
+ DstB^ := SrcB^;
+ Inc(DstB);
+ Inc(SrcB, 4);
+ end;
+ end;
+
+ ctBlue:
+ begin
+ for I := 0 to N do
+ begin
+ DstB^ := SrcB^;
+ Inc(DstB);
+ Inc(SrcB, 4);
+ end;
+ end;
+
+ ctAlpha:
+ begin
+ Inc(SrcB, 3);
+ for I := 0 to N do
+ begin
+ DstB^ := SrcB^;
+ Inc(DstB);
+ Inc(SrcB, 4);
+ end;
+ end;
+
+ ctUniformRGB:
+ begin
+ for I := 0 to N do
+ begin
+ Value := SrcC^;
+ Value := (Value and $00FF0000) shr 16 + (Value and $0000FF00) shr 8 +
+ (Value and $000000FF);
+ Value := Value div 3;
+ DstB^ := Value;
+ Inc(DstB);
+ Inc(SrcC);
+ end;
+ end;
+
+ ctWeightedRGB:
+ begin
+ for I := 0 to N do
+ begin
+ DstB^ := Intensity(SrcC^);
+ Inc(DstB);
+ Inc(SrcC);
+ end;
+ end;
+ end;
+ finally
+ EndUpdate;
+ Changed;
+ end;
+end;
+
+procedure TByteMap.SetValue(X, Y: Integer; Value: Byte);
+begin
+ Bytes[X + Y * Width] := Value;
+end;
+
+procedure TByteMap.WriteTo(Dest: TBitmap32; Conversion: TConversionType);
+var
+ W, H, I, N: Integer;
+ DstC: PColor32;
+ DstB, SrcB: PByte;
+ Resized: Boolean;
+begin
+ Dest.BeginUpdate;
+ Resized := False;
+ try
+ Resized := Dest.SetSize(Width, Height);
+ if Empty then Exit;
+
+ W := Width;
+ H := Height;
+ N := W * H - 1;
+ DstC := Dest.PixelPtr[0, 0];
+ DstB := Pointer(DstC);
+ SrcB := @Bytes[0];
+ case Conversion of
+
+ ctRed:
+ begin
+ Inc(DstB, 2);
+ for I := 0 to N do
+ begin
+ DstB^ := SrcB^;
+ Inc(DstB, 4);
+ Inc(SrcB);
+ end;
+ end;
+
+ ctGreen:
+ begin
+ Inc(DstB, 1);
+ for I := 0 to N do
+ begin
+ DstB^ := SrcB^;
+ Inc(DstB, 4);
+ Inc(SrcB);
+ end;
+ end;
+
+ ctBlue:
+ begin
+ for I := 0 to N do
+ begin
+ DstB^ := SrcB^;
+ Inc(DstB, 4);
+ Inc(SrcB);
+ end;
+ end;
+
+ ctAlpha:
+ begin
+ Inc(DstB, 3);
+ for I := 0 to N do
+ begin
+ DstB^ := SrcB^;
+ Inc(DstB, 4);
+ Inc(SrcB);
+ end;
+ end;
+
+ ctUniformRGB, ctWeightedRGB:
+ begin
+ for I := 0 to N do
+ begin
+ DstC^ := Gray32(SrcB^);
+ Inc(DstC);
+ Inc(SrcB);
+ end;
+ end;
+ end;
+ finally
+ Dest.EndUpdate;
+ Dest.Changed;
+ if Resized then Dest.Resized;
+ end;
+end;
+
+procedure TByteMap.WriteTo(Dest: TBitmap32; const Palette: TPalette32);
+var
+ W, H, I, N: Integer;
+ DstC: PColor32;
+ SrcB: PByte;
+begin
+ Dest.BeginUpdate;
+ try
+ Dest.SetSize(Width, Height);
+ if Empty then Exit;
+
+ W := Width;
+ H := Height;
+ N := W * H - 1;
+ DstC := Dest.PixelPtr[0, 0];
+ SrcB := @Bytes[0];
+
+ for I := 0 to N do
+ begin
+ DstC^ := Palette[SrcB^];
+ Inc(DstC);
+ Inc(SrcB);
+ end;
+ finally
+ Dest.EndUpdate;
+ Dest.Changed;
+ end;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_DrawingEx.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_DrawingEx.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_DrawingEx.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_DrawingEx.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_DrawingEx.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,103 @@
+unit GR32_DrawingEx;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_DrawingEx.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ {$IFDEF CLX}
+ Qt, Types, {$IFDEF LINUX}Libc, {$ENDIF}
+ {$ELSE}
+ Windows,
+ {$ENDIF}
+ GR32, SysUtils;
+
+{ ClipLine }
+{ Clips the (X1, Y1)-(X2,Y2) line to the rectangle using Sutherland-Cohen Line
+ Clipping Algorithm }
+function ClipLine(var X1, Y1, X2, Y2: Integer; MinX, MinY, MaxX, MaxY: Integer): Boolean;
+
+type
+ TBlendLineProc = procedure(Src, Dst: PColor32; Count: Integer);
+
+implementation
+
+uses GR32_LowLevel, GR32_Blend, Math;
+
+function ClipLine(var X1, Y1, X2, Y2: Integer; MinX, MinY, MaxX, MaxY: Integer): Boolean;
+var
+ C1, C2: Integer;
+ V: Integer;
+begin
+ { Get edge codes }
+ C1 := Ord(X1 < MinX) + Ord(X1 > MaxX) shl 1 + Ord(Y1 < MinY) shl 2 + Ord(Y1 > MaxY) shl 3;
+ C2 := Ord(X2 < MinX) + Ord(X2 > MaxX) shl 1 + Ord(Y2 < MinY) shl 2 + Ord(Y2 > MaxY) shl 3;
+
+ if ((C1 and C2) = 0) and ((C1 or C2) <> 0) then
+ begin
+ if (C1 and 12) <> 0 then
+ begin
+ if C1 < 8 then V := MinY else V := MaxY;
+ Inc(X1, MulDiv(V - Y1, X2 - X1, Y2 - Y1));
+ Y1 := V;
+ C1 := Ord(X1 < MinX) + Ord(X1 > MaxX) shl 1;
+ end;
+
+ if (C2 and 12) <> 0 then
+ begin
+ if C2 < 8 then V := MinY else V := MaxY;
+ Inc(X2, MulDiv(V - Y2, X2 - X1, Y2 - Y1));
+ Y2 := V;
+ C2 := Ord(X2 < MinX) + Ord(X2 > MaxX) shl 1;
+ end;
+
+ if ((C1 and C2) = 0) and ((C1 or C2) <> 0) then
+ begin
+ if C1 <> 0 then
+ begin
+ if C1 = 1 then V := MinX else V := MaxX;
+ Inc(Y1, MulDiv(V - X1, Y2 - Y1, X2 - X1));
+ X1 := V;
+ C1 := 0;
+ end;
+
+ if C2 <> 0 then
+ begin
+ if C2 = 1 then V := MinX else V := MaxX;
+ Inc(Y2, MulDiv(V - X2, Y2 - Y1, X2 - X1));
+ X2 := V;
+ C2 := 0;
+ end;
+ end;
+ end;
+
+ Result := (C1 or C2) = 0;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,515 @@
+unit GR32_Dsgn_Bitmap;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Dsgn_Bitmap.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+{$IFDEF CLX}
+ {$IFDEF MSWINDOWS}Windows,{$ENDIF}
+ {$IFDEF LINUX}Libc,{$ENDIF}
+ QT, QGraphics, QControls, QForms, QDialogs, QExtCtrls, QStdCtrls, QComCtrls,
+ QMenus, QImgList, QTypes, QClipbrd,
+{$ELSE}
+ Windows, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ExtDlgs,
+ ComCtrls, Menus, ToolWin, Registry, ImgList, Clipbrd,
+{$ENDIF}
+ SysUtils, Classes, Consts,
+ GR32, GR32_Image, GR32_Layers, GR32_Filters,
+{$IFDEF COMPILER6}
+ DesignIntf, DesignEditors
+{$ELSE}
+ DsgnIntf
+{$ENDIF};
+
+type
+ TPictureEditorForm = class(TForm)
+ ToolBar1: TToolBar;
+ Load: TToolButton;
+ Save: TToolButton;
+ ImageList: TImageList;
+ Clear: TToolButton;
+ ToolButton2: TToolButton;
+ Copy: TToolButton;
+ Paste: TToolButton;
+ Timer: TTimer;
+ PageControl: TPageControl;
+ ImageSheet: TTabSheet;
+ AlphaSheet: TTabSheet;
+ // TODO: Remove
+ //OpenDialog: TOpenPictureDialog;
+ //SaveDialog: TSavePictureDialog;
+ OpenDialog: TOpenDialog;
+ SaveDialog: TSaveDialog;
+ PopupMenu: TPopupMenu;
+ mnSave: TMenuItem;
+ mnSeparator: TMenuItem;
+ mnCopy: TMenuItem;
+ mnPaste: TMenuItem;
+ mnClear: TMenuItem;
+ Load1: TMenuItem;
+ mnSeparator2: TMenuItem;
+ mnInvert: TMenuItem;
+ Panel1: TPanel;
+ OKButton: TButton;
+ Cancel: TButton;
+ Label1: TLabel;
+ MagnCombo: TComboBox;
+ Panel2: TPanel;
+ Bevel1: TBevel;
+ procedure LoadClick(Sender: TObject);
+ procedure SaveClick(Sender: TObject);
+ procedure ClearClick(Sender: TObject);
+ procedure CopyClick(Sender: TObject);
+ procedure PasteClick(Sender: TObject);
+ procedure TimerTimer(Sender: TObject);
+ procedure PopupMenuPopup(Sender: TObject);
+ procedure mnInvertClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure MagnComboChange(Sender: TObject);
+ protected
+ AlphaChannel: TImage32;
+ RGBChannels: TImage32;
+ procedure AlphaChannelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure RGBChannelsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ function CurrentImage: TImage32;
+ public
+ constructor Create(AOwner: TComponent); override;
+ end;
+
+ TBitmap32Editor = class(TComponent)
+ private
+ FBitmap32: TBitmap32;
+ FPicDlg: TPictureEditorForm;
+ procedure SetBitmap32(Value: TBitmap32);
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ function Execute: Boolean;
+ property Bitmap32: TBitmap32 read FBitmap32 write SetBitmap32;
+ end;
+
+ TBitmap32Property = class(TClassProperty)
+ public
+ procedure Edit; override;
+ function GetAttributes: TPropertyAttributes; override;
+ function GetValue: string; override;
+ procedure SetValue(const Value: string); override;
+{$IFDEF EXT_PROP_EDIT}
+ procedure PropDrawValue(Canvas: TCanvas; const ARect: TRect; Selected: Boolean); override;
+{$ENDIF}
+ end;
+
+ TImage32Editor = class(TComponentEditor)
+ public
+ procedure ExecuteVerb(Index: Integer); override;
+ function GetVerb(Index: Integer): string; override;
+ function GetVerbCount: Integer; override;
+ end;
+
+implementation
+
+{$IFDEF CLX}
+{$R *.xfm}
+{$ELSE}
+{$R *.dfm}
+{$ENDIF}
+
+{ TPictureEditorForm }
+
+procedure TPictureEditorForm.LoadClick(Sender: TObject);
+var
+ Picture: TPicture;
+ DoAlpha: Boolean;
+ S: string;
+begin
+ if OpenDialog.Execute then
+ begin
+ Picture := TPicture.Create;
+ try
+ Picture.LoadFromFile(OpenDialog.Filename);
+ DoAlpha := False;
+ if (Picture.Graphic is TBitmap) and (Picture.Bitmap.PixelFormat = pf32Bit) then
+ begin
+ S := ExtractFileName(OpenDialog.FileName);
+ S := '''' + S + ''' file contains RGB and Alpha channels.'#13#10 +
+ 'Do you want to load all channels?';
+ case MessageDlg(S, mtConfirmation, mbYesNoCancel, 0) of
+ mrYes: DoAlpha := True;
+ mrCancel: Exit;
+ end;
+ end;
+
+ if DoAlpha then
+ begin
+ RGBChannels.Bitmap.Assign(Picture.Bitmap);
+ AlphaToGrayscale(AlphaChannel.Bitmap, RGBChannels.Bitmap);
+ RGBChannels.Bitmap.ResetAlpha;
+ end
+ else with CurrentImage do
+ begin
+ Bitmap.Assign(Picture);
+ if CurrentImage = AlphaChannel then ColorToGrayscale(Bitmap, Bitmap);
+ end;
+ finally
+ Picture.Free;
+ end;
+ end;
+end;
+
+procedure TPictureEditorForm.SaveClick(Sender: TObject);
+var
+ Picture: TPicture;
+begin
+ Picture := TPicture.Create;
+ try
+ Picture.Bitmap.Assign(CurrentImage.Bitmap);
+{$IFDEF CLX}
+ Picture.Bitmap.PixelFormat := pf32Bit;
+{$ELSE}
+ Picture.Bitmap.PixelFormat := pf24Bit;
+{$ENDIF}
+
+ if Picture.Graphic <> nil then
+ begin
+ with SaveDialog do
+ begin
+ DefaultExt := GraphicExtension(TGraphicClass(Picture.Graphic.ClassType));
+ Filter := GraphicFilter(TGraphicClass(Picture.Graphic.ClassType));
+ if Execute then Picture.SaveToFile(Filename);
+ end;
+ end;
+ finally
+ Picture.Free;
+ end;
+end;
+
+procedure TPictureEditorForm.ClearClick(Sender: TObject);
+begin
+ CurrentImage.Bitmap.Delete;
+end;
+
+procedure TPictureEditorForm.CopyClick(Sender: TObject);
+begin
+ Clipboard.Assign(CurrentImage.Bitmap);
+end;
+
+procedure TPictureEditorForm.PasteClick(Sender: TObject);
+begin
+{$IFDEF CLX}
+ if Clipboard.Provides('image/delphi.bitmap') or
+ Clipboard.Provides('image/delphi.picture') then
+ CurrentImage.Bitmap.Assign(Clipboard);
+{$ELSE}
+ if Clipboard.HasFormat(CF_BITMAP) or Clipboard.HasFormat(CF_PICTURE) then
+ CurrentImage.Bitmap.Assign(Clipboard);
+{$ENDIF}
+ if CurrentImage = AlphaChannel then
+ ColorToGrayscale(CurrentImage.Bitmap, CurrentImage.Bitmap);
+end;
+
+procedure TPictureEditorForm.TimerTimer(Sender: TObject);
+begin
+ Save.Enabled := not CurrentImage.Bitmap.Empty;
+ Clear.Enabled := Save.Enabled;
+ Copy.Enabled := Save.Enabled;
+
+{$IFDEF CLX}
+ Paste.Enabled := Clipboard.Provides('image/delphi.bitmap') or
+ Clipboard.Provides('image/delphi.picture');
+{$ELSE}
+ Paste.Enabled := Clipboard.HasFormat(CF_BITMAP) or Clipboard.HasFormat(CF_PICTURE);
+{$ENDIF}
+end;
+
+function TPictureEditorForm.CurrentImage: TImage32;
+begin
+ if PageControl.ActivePage = ImageSheet then Result := RGBChannels
+ else Result := AlphaChannel;
+end;
+
+procedure TPictureEditorForm.PopupMenuPopup(Sender: TObject);
+begin
+ mnSave.Enabled := not CurrentImage.Bitmap.Empty;
+ mnClear.Enabled := Save.Enabled;
+ mnCopy.Enabled := Save.Enabled;
+ mnInvert.Enabled := Save.Enabled;
+{$IFDEF CLX}
+ mnPaste.Enabled := Clipboard.Provides('image/delphi.bitmap') or
+ Clipboard.Provides('image/delphi.picture');
+{$ELSE}
+ mnPaste.Enabled := Clipboard.HasFormat(CF_BITMAP) or Clipboard.HasFormat(CF_PICTURE);
+{$ENDIF}
+end;
+
+procedure TPictureEditorForm.mnInvertClick(Sender: TObject);
+begin
+ InvertRGB(CurrentImage.Bitmap, CurrentImage.Bitmap);
+end;
+
+procedure TPictureEditorForm.FormCreate(Sender: TObject);
+begin
+ MagnCombo.ItemIndex := 2;
+{$IFDEF CLX}
+ OpenDialog.Filter := GraphicFilter(TGraphic, True);
+ SaveDialog.Filter := GraphicFilter(TGraphic, True);
+{$ELSE}
+ OpenDialog.Filter := GraphicFilter(TGraphic);
+ SaveDialog.Filter := GraphicFilter(TGraphic);
+{$ENDIF}
+end;
+
+procedure TPictureEditorForm.MagnComboChange(Sender: TObject);
+const
+ MAGN: array[0..6] of Integer = (25, 50, 100, 200, 400, 800, -1);
+var
+ S: Integer;
+begin
+ S := MAGN[MagnCombo.ItemIndex];
+ if S = -1 then
+ begin
+ RGBChannels.ScaleMode := smResize;
+ AlphaChannel.ScaleMode := smResize;
+ end
+ else
+ begin
+ RGBChannels.ScaleMode := smScale;
+ RGBChannels.Scale := S / 100;
+ AlphaChannel.ScaleMode := smScale;
+ AlphaChannel.Scale := S / 100;
+ end;
+end;
+
+constructor TPictureEditorForm.Create(AOwner: TComponent);
+begin
+ inherited;
+ RGBChannels := TImage32.Create(Self);
+ RGBChannels.Parent := ImageSheet;
+ RGBChannels.Align := alClient;
+ RGBChannels.OnMouseMove := RGBChannelsMouseMove;
+ AlphaChannel := TImage32.Create(Self);
+ AlphaChannel.Parent := AlphaSheet;
+ AlphaChannel.Align := alClient;
+ AlphaChannel.OnMouseMove := AlphaChannelMouseMove;
+end;
+
+
+{ TBitmap32Editor }
+
+constructor TBitmap32Editor.Create(AOwner: TComponent);
+begin
+ inherited;
+ FBitmap32 := TBitmap32.Create;
+ FPicDlg := TPictureEditorForm.Create(Self);
+end;
+
+destructor TBitmap32Editor.Destroy;
+begin
+ FBitmap32.Free;
+ inherited;
+end;
+
+function TBitmap32Editor.Execute: Boolean;
+var
+ B: TBitmap32;
+begin
+ FPicDlg.RGBChannels.Bitmap := FBitmap32;
+ AlphaToGrayscale(FPicDlg.AlphaChannel.Bitmap, FBitmap32);
+ Result := (FPicDlg.ShowModal = mrOK);
+ if Result then
+ begin
+ FBitmap32.Assign(FPicDlg.RGBChannels.Bitmap);
+ FBitmap32.ResetAlpha;
+ if not FBitmap32.Empty and not FPicDlg.AlphaChannel.Bitmap.Empty then
+ begin
+ B := TBitmap32.Create;
+ try
+ B.SetSize(FBitmap32.Width, FBitmap32.Height);
+ FPicDlg.AlphaChannel.Bitmap.DrawTo(B, Rect(0, 0, B.Width, B.Height));
+ IntensityToAlpha(FBitmap32, B);
+ finally
+ B.Free;
+ end;
+ end;
+ end;
+end;
+
+procedure TBitmap32Editor.SetBitmap32(Value: TBitmap32);
+begin
+ try
+ FBitmap32.Assign(Value);
+ except
+ on E: Exception do ShowMessage(E.Message);
+ end;
+end;
+
+{ TBitmap32Property }
+
+procedure TBitmap32Property.Edit;
+var
+ BitmapEditor: TBitmap32Editor;
+begin
+ try
+ BitmapEditor := TBitmap32Editor.Create(nil);
+ try
+ BitmapEditor.Bitmap32 := TBitmap32(Pointer(GetOrdValue));
+ if BitmapEditor.Execute then
+ begin
+ SetOrdValue(Longint(BitmapEditor.Bitmap32));
+ Designer.Modified;
+ end;
+ finally
+ BitmapEditor.Free;
+ end;
+ except
+ on E: Exception do ShowMessage(E.Message);
+ end;
+end;
+
+function TBitmap32Property.GetAttributes: TPropertyAttributes;
+begin
+ Result := [paDialog, paSubProperties];
+end;
+
+function TBitmap32Property.GetValue: string;
+var
+ Bitmap: TBitmap32;
+begin
+ try
+ Bitmap := TBitmap32(GetOrdValue);
+ if (Bitmap = nil) or Bitmap.Empty then Result := srNone
+ else Result := Format('%s [%d,%d]', [Bitmap.ClassName, Bitmap.Width, Bitmap.Height]);
+ except
+ on E: Exception do ShowMessage(E.Message);
+ end;
+end;
+
+{$IFDEF EXT_PROP_EDIT}
+procedure TBitmap32Property.PropDrawValue(Canvas: TCanvas;
+ const ARect: TRect; Selected: Boolean);
+var
+ Bitmap32: TBitmap32;
+ R: TRect;
+begin
+ Bitmap32 := TBitmap32(GetOrdValue);
+ if Bitmap32.Empty then inherited
+ else
+ begin
+ R := ARect;
+ R.Right := R.Left + R.Bottom - R.Top;
+ Bitmap32.DrawTo(Canvas.Handle, R, Classes.Rect(0, 0, Bitmap32.Width, Bitmap32.Height));
+ R.Left := R.Right;
+ R.Right := ARect.Right;
+ inherited PropDrawValue(Canvas, R, Selected);
+ end;
+end;
+{$ENDIF}
+
+procedure TBitmap32Property.SetValue(const Value: string);
+begin
+ if Value = '' then SetOrdValue(0);
+end;
+
+{ TImage32Editor }
+
+procedure TImage32Editor.ExecuteVerb(Index: Integer);
+var
+ Img: TCustomImage32;
+ BitmapEditor: TBitmap32Editor;
+begin
+ Img := Component as TCustomImage32;
+ if Index = 0 then
+ begin
+ BitmapEditor := TBitmap32Editor.Create(nil);
+ try
+ BitmapEditor.Bitmap32 := Img.Bitmap;
+ if BitmapEditor.Execute then
+ begin
+ Img.Bitmap := BitmapEditor.Bitmap32;
+ Designer.Modified;
+ end;
+ finally
+ BitmapEditor.Free;
+ end;
+ end;
+end;
+
+function TImage32Editor.GetVerb(Index: Integer): string;
+begin
+ if Index = 0 then Result := 'Bitmap32 Editor...';
+end;
+
+function TImage32Editor.GetVerbCount: Integer;
+begin
+ Result := 1;
+end;
+
+procedure TPictureEditorForm.AlphaChannelMouseMove(Sender: TObject;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+var
+ P: TPoint;
+begin
+ if AlphaChannel.Bitmap <> nil then
+ begin
+ P := AlphaChannel.ControlToBitmap(Point(X, Y));
+ X := P.X;
+ Y := P.Y;
+ if (X >= 0) and (Y >= 0) and (X < AlphaChannel.Bitmap.Width) and
+ (Y < AlphaChannel.Bitmap.Height) then
+ Panel2.Caption := 'Alpha: $' +
+ IntToHex(AlphaChannel.Bitmap[X, Y] and $FF, 2) +
+ Format(' '#9'X: %d'#9'Y: %d', [X, Y])
+ else
+ Panel2.Caption := '';
+ end
+ else Panel2.Caption := '';
+end;
+
+procedure TPictureEditorForm.RGBChannelsMouseMove(Sender: TObject;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+var
+ P: TPoint;
+begin
+ if RGBChannels.Bitmap <> nil then
+ begin
+ P := RGBChannels.ControlToBitmap(Point(X, Y));
+ X := P.X;
+ Y := P.Y;
+ if (X >= 0) and (Y >= 0) and (X < RGBChannels.Bitmap.Width) and
+ (Y < RGBChannels.Bitmap.Height) then
+ Panel2.Caption := 'RGB: $' +
+ IntToHex(RGBChannels.Bitmap[X, Y] and $00FFFFFF, 6) +
+ Format(#9'X: %d'#9'Y: %d', [X, Y])
+ else
+ Panel2.Caption := '';
+ end
+ else Panel2.Caption := '';
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.xfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Bitmap.xfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Color.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Color.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Dsgn_Color.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Dsgn_Color.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Dsgn_Color.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,388 @@
+unit GR32_Dsgn_Color;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Dsgn_Color.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ Classes, SysUtils, Consts,
+{$IFDEF CLX}
+ QGraphics, QDialogs, QForms,
+{$ELSE}
+ Windows, Registry, Graphics, Dialogs, Forms,
+{$ENDIF}
+ GR32, GR32_Image,
+{$IFDEF COMPILER6}
+ DesignIntf, DesignEditors
+{$ELSE}
+ DsgnIntf
+{$ENDIF};
+
+type
+ { TColorManager }
+ PColorEntry = ^TColorEntry;
+ TColorEntry = record
+ Name: string[31];
+ Color: TColor32;
+ end;
+
+ TColorManager = class(TList)
+ public
+ destructor Destroy; override;
+ procedure AddColor(const AName: string; AColor: TColor32);
+ procedure EnumColors(Proc: TGetStrProc);
+ function FindColor(const AName: string): TColor32;
+ function GetColor(const AName: string): TColor32;
+ function GetColorName(AColor: TColor32): string;
+ procedure RegisterDefaultColors;
+ procedure RemoveColor(const AName: string);
+ end;
+
+ { TColor32Property }
+ TColor32Property = class(TIntegerProperty)
+ public
+ function GetAttributes: TPropertyAttributes; override;
+ function GetValue: string; override;
+ procedure GetValues(Proc: TGetStrProc); override;
+ procedure SetValue(const Value: string); override;
+{$IFDEF EXT_PROP_EDIT}
+ procedure Edit; override;
+ procedure ListDrawValue(const Value: string; ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); override;
+ procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); override;
+{$ENDIF}
+ end;
+
+procedure RegisterColor(const AName: string; AColor: TColor32);
+procedure UnregisterColor(const AName: string);
+
+var ColorManager: TColorManager;
+
+implementation
+
+{ TColorManager }
+
+destructor TColorManager.Destroy;
+var
+ I: Integer;
+begin
+ for I := 0 to Count - 1 do FreeMem(Items[I], SizeOf(TColorEntry));
+ inherited;
+end;
+
+procedure TColorManager.AddColor(const AName: string; AColor: TColor32);
+var
+ NewEntry: PColorEntry;
+begin
+ New(NewEntry);
+ if NewEntry = nil then
+ raise Exception.Create('Could not allocate memory for color registration!');
+ with NewEntry^ do
+ begin
+ Name := AName;
+ Color := AColor;
+ end;
+ Add(NewEntry);
+end;
+
+procedure TColorManager.EnumColors(Proc: TGetStrProc);
+var
+ I: Integer;
+begin
+ for I := 0 to Count - 1 do Proc(TColorEntry(Items[I]^).Name);
+end;
+
+function TColorManager.FindColor(const AName: string): TColor32;
+var
+ I: Integer;
+begin
+ Result := clBlack32;
+ for I := 0 to Count - 1 do
+ with TColorEntry(Items[I]^) do
+ if Name = AName then
+ begin
+ Result := Color;
+ Break;
+ end;
+end;
+
+function TColorManager.GetColor(const AName: string): TColor32;
+var
+ S: string;
+
+ function HexToClr(const HexStr: string): Cardinal;
+ var
+ I: Integer;
+ C: Char;
+ begin
+ Result := 0;
+ for I := 1 to Length(HexStr) do
+ begin
+ C := HexStr[I];
+ case C of
+ '0'..'9': Result := Int64(16) * Result + (Ord(C) - $30);
+ 'A'..'F': Result := Int64(16) * Result + (Ord(C) - $37);
+ 'a'..'f': Result := Int64(16) * Result + (Ord(C) - $57);
+ else
+ raise EConvertError.Create('Illegal character in hex string');
+ end;
+ end;
+ end;
+
+begin
+ S := Trim(AName);
+ if S[1] = '$' then S := Copy(S, 2, Length(S) - 1);
+ if (S[1] = 'c') and (S[2] = 'l') then Result := FindColor(S)
+ else
+ try
+ Result := HexToClr(S);
+ except
+ Result := clBlack32;
+ end;
+end;
+
+function TColorManager.GetColorName(AColor: TColor32): string;
+var
+ I: Integer;
+begin
+ for I := 0 to Count - 1 do
+ with TColorEntry(Items[I]^) do
+ if Color = AColor then
+ begin
+ Result := TColorEntry(Items[I]^).Name;
+ Exit;
+ end;
+ Result := '$' + IntToHex(AColor, 8);
+end;
+
+procedure TColorManager.RegisterDefaultColors;
+begin
+ Capacity := 50;
+ AddColor('clBlack32', clBlack32);
+ AddColor('clDimGray32', clDimGray32);
+ AddColor('clGray32', clGray32);
+ AddColor('clLightGray32', clLightGray32);
+ AddColor('clWhite32', clWhite32);
+ AddColor('clMaroon32', clMaroon32);
+ AddColor('clGreen32', clGreen32);
+ AddColor('clOlive32', clOlive32);
+ AddColor('clNavy32', clNavy32);
+ AddColor('clPurple32', clPurple32);
+ AddColor('clTeal32', clTeal32);
+ AddColor('clRed32', clRed32);
+ AddColor('clLime32', clLime32);
+ AddColor('clYellow32', clYellow32);
+ AddColor('clBlue32', clBlue32);
+ AddColor('clFuchsia32', clFuchsia32);
+ AddColor('clAqua32', clAqua32);
+
+ AddColor('clTrWhite32', clTrWhite32);
+ AddColor('clTrBlack32', clTrBlack32);
+ AddColor('clTrRed32', clTrRed32);
+ AddColor('clTrGreen32', clTrGreen32);
+ AddColor('clTrBlue32', clTrBlue32);
+end;
+
+procedure TColorManager.RemoveColor(const AName: string);
+var
+ I: Integer;
+begin
+ for I := 0 to Count - 1 do
+ if CompareText(TColorEntry(Items[I]^).Name, AName) = 0 then
+ begin
+ Delete(I);
+ Break;
+ end;
+end;
+
+procedure RegisterColor(const AName: string; AColor: TColor32);
+begin
+ ColorManager.AddColor(AName, AColor);
+end;
+
+procedure UnregisterColor(const AName: string);
+begin
+ ColorManager.RemoveColor(AName);
+end;
+
+
+{ TColor32Property }
+
+{$IFDEF EXT_PROP_EDIT}
+procedure TColor32Property.Edit;
+var
+ ColorDialog: TColorDialog;
+ IniFile: TRegIniFile;
+
+ procedure GetCustomColors;
+ begin
+ if BaseRegistryKey = '' then Exit;
+ IniFile := TRegIniFile.Create(BaseRegistryKey);
+ try
+ IniFile.ReadSectionValues(SCustomColors, ColorDialog.CustomColors);
+ except
+ { Ignore errors while reading values }
+ end;
+ end;
+
+ procedure SaveCustomColors;
+ var
+ I, P: Integer;
+ S: string;
+ begin
+ if IniFile <> nil then
+ with ColorDialog do
+ for I := 0 to CustomColors.Count - 1 do
+ begin
+ S := CustomColors.Strings[I];
+ P := Pos('=', S);
+ if P <> 0 then
+ begin
+ S := Copy(S, 1, P - 1);
+ IniFile.WriteString(SCustomColors, S, CustomColors.Values[S]);
+ end;
+ end;
+ end;
+
+begin
+ IniFile := nil;
+ ColorDialog := TColorDialog.Create(Application);
+ try
+ GetCustomColors;
+ ColorDialog.Color := WinColor(GetOrdValue);
+ ColorDialog.HelpContext := 25010;
+ ColorDialog.Options := [cdShowHelp];
+ if ColorDialog.Execute then
+ SetOrdValue(Cardinal(Color32(ColorDialog.Color)));
+ SaveCustomColors;
+ finally
+ IniFile.Free;
+ ColorDialog.Free;
+ end;
+end;
+{$ENDIF}
+
+function TColor32Property.GetAttributes: TPropertyAttributes;
+begin
+ Result := [paMultiSelect, {$IFDEF EXT_PROP_EDIT}paDialog,{$ENDIF} paValueList,
+ paRevertable];
+end;
+
+procedure TColor32Property.GetValues(Proc: TGetStrProc);
+begin
+ try
+ ColorManager.EnumColors(Proc);
+ except
+ on E: Exception do ShowMessage(E.Message);
+ end;
+end;
+
+function TColor32Property.GetValue: string;
+begin
+ try
+ Result := ColorManager.GetColorName(Cardinal(GetOrdValue));
+ except
+ on E: Exception do ShowMessage(E.Message);
+ end;
+end;
+
+procedure TColor32Property.SetValue(const Value: string);
+begin
+ try
+ SetOrdValue(Cardinal(ColorManager.GetColor(Value)));
+ Modified;
+ except
+ on E: Exception do ShowMessage(E.Message);
+ end;
+end;
+
+{$IFDEF EXT_PROP_EDIT}
+procedure TColor32Property.ListDrawValue(const Value: string; ACanvas: TCanvas;
+ const ARect: TRect; ASelected: Boolean);
+var
+ Right: Integer;
+ C: TColor32;
+ i, j: Integer;
+ W, H: Integer;
+ Bitmap32: TBitmap32;
+begin
+ try
+ Right := (ARect.Bottom - ARect.Top) + ARect.Left;
+ ACanvas.FillRect(Rect(ARect.Left, ARect.Top, Right, ARect.Bottom));
+ Bitmap32 := TBitmap32.Create;
+ try
+ Bitmap32.SetSize(Right - ARect.Left - 2, ARect.Bottom - ARect.Top - 2);
+ if Assigned(ColorManager) then C := ColorManager.GetColor(Value)
+ else C := clWhite32;
+ W := Bitmap32.Width;
+ H := Bitmap32.Height;
+ if (W > 8) and (H > 8) then
+ begin
+ if C and $FF000000 = $FF000000 then
+ Bitmap32.FillRect(0, 0, W - 1, H - 1, C)
+ else // transparent
+ begin
+ for j := 0 to H - 1 do
+ for i := 0 to W - 1 do
+ if Odd(i div 3) = Odd(j div 3) then
+ Bitmap32[i, j] := clBlack32
+ else
+ Bitmap32[i, j] := clWhite32;
+ end;
+ Bitmap32.FillRectT(0, 0, W - 1, H - 1, C);
+ end;
+ Bitmap32.FrameRectTS(0, 0, W - 1, H - 1, $DF000000);
+ Bitmap32.RaiseRectTS(1, 1, W - 2, H - 2, 20);
+ Bitmap32.DrawTo(ACanvas.Handle, ARect.Left + 1, ARect.Top + 1);
+ finally
+ Bitmap32.Free;
+ inherited ListDrawValue(Value, ACanvas,
+ Rect(Right, ARect.Top, ARect.Right, ARect.Bottom), ASelected);
+ end;
+ except
+ on E: Exception do ShowMessage(E.Message);
+ end;
+end;
+
+procedure TColor32Property.PropDrawValue(ACanvas: TCanvas; const ARect: TRect;
+ ASelected: Boolean);
+begin
+ if GetVisualValue <> '' then ListDrawValue(GetVisualValue, ACanvas, ARect, True)
+ else inherited PropDrawValue(ACanvas, ARect, ASelected);
+end;
+{$ENDIF}
+
+
+initialization
+ ColorManager := TColorManager.Create;
+ ColorManager.RegisterDefaultColors;
+
+finalization
+ ColorManager.Free;
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_Filters.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Filters.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Filters.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Filters.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Filters.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,195 @@
+unit GR32_Filters;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Filters.pas,v 1.2 2004/07/07 11:39:58 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ {$IFDEF CLX}
+ Qt, Types, {$IFDEF LINUX}Libc, {$ENDIF}
+ {$ELSE}
+ Windows,
+ {$ENDIF}
+ Classes, SysUtils, GR32, GR32_Blend, GR32_ByteMaps;
+
+{ Basic processing }
+type
+ TLUT8 = array [Byte] of Byte;
+
+procedure AlphaToGrayscale(Dst, Src: TBitmap32);
+procedure IntensityToAlpha(Dst, Src: TBitmap32);
+procedure Invert(Dst, Src: TBitmap32);
+procedure InvertRGB(Dst, Src: TBitmap32);
+procedure ColorToGrayscale(Dst, Src: TBitmap32);
+procedure ApplyLUT(Dst, Src: TBitmap32; const LUT: TLUT8);
+
+procedure CheckParams(Dst, Src: TBitmap32);
+
+implementation
+
+const
+ SEmptySource = 'The source is nil';
+ SEmptyDestination = 'Destination is nil';
+ SNoInPlace = 'In-place operation is unsupported';
+
+procedure CheckParams(Dst, Src: TBitmap32);
+begin
+ if Src = nil then raise Exception.Create(SEmptySource);
+ if Dst = nil then raise Exception.Create(SEmptyDestination);
+ Dst.SetSize(Src.Width, Src.Height);
+end;
+
+{rocedure CheckParamsNoInPlace(Dst, Src: TBitmap32);
+begin
+ if (Src = nil) then
+ raise Exception.Create(SEmptySource);
+ if Dst = nil then
+ raise Exception.Create(SEmptyDestination);
+ if Dst = Src then
+ raise Exception.Create(SNoInPlace);
+ Dst.SetSize(Src);
+end; }
+
+procedure AlphaToGrayscale(Dst, Src: TBitmap32);
+var
+ I: Integer;
+ D, S: PColor32;
+begin
+ CheckParams(Dst, Src);
+ Dst.SetSize(Src.Width, Src.Height);
+ D := @Dst.Bits[0];
+ S := @Src.Bits[0];
+ for I := 0 to Src.Width * Src.Height - 1 do
+ begin
+ D^ := Gray32(AlphaComponent(S^));
+ Inc(S); Inc(D);
+ end;
+ Dst.Changed;
+end;
+
+procedure IntensityToAlpha(Dst, Src: TBitmap32);
+var
+ I: Integer;
+ D, S: PColor32;
+begin
+ CheckParams(Dst, Src);
+ Dst.SetSize(Src.Width, Src.Height);
+ D := @Dst.Bits[0];
+ S := @Src.Bits[0];
+ for I := 0 to Src.Width * Src.Height - 1 do
+ begin
+ D^ := SetAlpha(D^, Intensity(S^));
+ Inc(S); Inc(D);
+ end;
+ Dst.Changed;
+end;
+
+procedure Invert(Dst, Src: TBitmap32);
+var
+ I: Integer;
+ D, S: PColor32;
+begin
+ CheckParams(Dst, Src);
+ Dst.SetSize(Src.Width, Src.Height);
+ D := @Dst.Bits[0];
+ S := @Src.Bits[0];
+ for I := 0 to Src.Width * Src.Height - 1 do
+ begin
+ D^ := S^ xor $FFFFFFFF;
+ Inc(S); Inc(D);
+ end;
+ Dst.Changed;
+end;
+
+procedure InvertRGB(Dst, Src: TBitmap32);
+var
+ I: Integer;
+ D, S: PColor32;
+begin
+ CheckParams(Dst, Src);
+ Dst.SetSize(Src.Width, Src.Height);
+ D := @Dst.Bits[0];
+ S := @Src.Bits[0];
+ for I := 0 to Src.Width * Src.Height - 1 do
+ begin
+ D^ := S^ xor $00FFFFFF;
+ Inc(S); Inc(D);
+ end;
+ Dst.Changed;
+end;
+
+procedure ColorToGrayscale(Dst, Src: TBitmap32);
+var
+ I: Integer;
+ D, S: PColor32;
+begin
+ CheckParams(Dst, Src);
+ Dst.SetSize(Src.Width, Src.Height);
+ D := @Dst.Bits[0];
+ S := @Src.Bits[0];
+ for I := 0 to Src.Width * Src.Height - 1 do
+ begin
+ D^ := Gray32(Intensity(S^));
+ Inc(S); Inc(D);
+ end;
+ Dst.Changed;
+end;
+
+procedure ApplyLUT(Dst, Src: TBitmap32; const LUT: TLUT8);
+var
+ I: Integer;
+ D, S: PColor32;
+ r, g, b: TColor32;
+ C: TColor32;
+begin
+ CheckParams(Src, Dst);
+ Dst.SetSize(Src.Width, Src.Height);
+ D := @Dst.Bits[0];
+ S := @Src.Bits[0];
+
+ for I := 0 to Src.Width * Src.Height - 1 do
+ begin
+ C := S^;
+ r := C and $00FF0000;
+ g := C and $0000FF00;
+ r := r shr 16;
+ b := C and $000000FF;
+ g := g shr 8;
+ r := LUT[r];
+ g := LUT[g];
+ b := LUT[b];
+ D^ := $FF000000 or r shl 16 or g shl 8 or b;
+ Inc(S);
+ Inc(D);
+ end;
+ Dst.Changed;
+end;
+
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_Image.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Image.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Image.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Image.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Image.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,2048 @@
+unit GR32_Image;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mattias Andersson <mattias at centaurix.com>
+ * Andre Beckedorf <Andre at metaException.de>
+ * Andrew P. Rybin <aprybin at users.sourceforge.net>
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Image.pas,v 1.2 2004/07/07 11:39:58 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+{$IFDEF CLX}
+ Qt, Types, QControls, QGraphics, QForms, QConsts,
+ {$IFDEF LINUX}Libc,{$ENDIF}
+ {$IFDEF MSWINDOWS}Windows,{$ENDIF}
+{$ELSE}
+ Windows, Messages, Controls, Graphics, Forms,
+{$ENDIF}
+ Classes, SysUtils, GR32, GR32_Layers, GR32_RangeBars;
+
+const
+ { Paint Stage Constants }
+ PST_CUSTOM = 1; // Calls OnPaint with # of current stage in parameter
+ PST_CLEAR_BUFFER = 2; // Clears the buffer
+ PST_CLEAR_BACKGND = 3; // Clears a visible buffer area
+ PST_DRAW_BITMAP = 4; // Draws a bitmap
+ PST_DRAW_LAYERS = 5; // Draw layers (Parameter = Layer Mask)
+ PST_CONTROL_FRAME = 6; // Draws a dotted frame around the control
+ PST_BITMAP_FRAME = 7; // Draws a dotted frame around the scaled bitmap
+
+type
+ TPaintStageEvent = procedure(Sender: TObject; Buffer: TBitmap32; StageNum: Cardinal) of object;
+
+ TBitmap32Access = class(TBitmap32);
+
+ { TPaintStage }
+ PPaintStage = ^TPaintStage;
+ TPaintStage = record
+ DsgnTime: Boolean;
+ RunTime: Boolean;
+ Stage: Cardinal; // a PST_* constant
+ Parameter: Cardinal; // an optional parameter
+ end;
+
+ { TPaintStages }
+ TPaintStages = class
+ private
+ FItems: array of TPaintStage;
+ function GetItem(Index: Integer): PPaintStage;
+ public
+ destructor Destroy; override;
+ function Add: PPaintStage;
+ procedure Clear;
+ function Count: Integer;
+ procedure Delete(Index: Integer);
+ function Insert(Index: Integer): PPaintStage;
+ property Items[Index: Integer]: PPaintStage read GetItem; default;
+ end;
+
+ { Alignment of the bitmap in TCustomImage32 }
+ TBitmapAlign = (baTopLeft, baCenter, baTile, baCustom);
+ TScaleMode = (smNormal, smStretch, smScale, smResize);
+ TPaintBoxOptions = set of (pboWantArrowKeys, pboAutoFocus);
+
+ { TCustomPaintBox32 }
+ TCustomPaintBox32 = class(TCustomControl)
+ private
+ FBuffer: TBitmap32;
+ FBufferOversize: Integer;
+ FBufferValid: Boolean;
+ FOptions: TPaintBoxOptions;
+ FOnGDIOverlay: TNotifyEvent;
+ FMouseInControl: Boolean;
+ FOnMouseEnter: TNotifyEvent;
+ FOnMouseLeave: TNotifyEvent;
+ procedure SetBufferOversize(Value: Integer);
+{$IFNDEF CLX}
+ procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
+ procedure WMGetDlgCode(var Msg: TWmGetDlgCode); message WM_GETDLGCODE;
+ procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
+ procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
+{$ENDIF}
+ protected
+ procedure DoPaintBuffer; virtual;
+ procedure DoPaintGDIOverlay; virtual;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
+{$IFDEF CLX}
+ procedure MouseEnter(AControl: TControl); override;
+ procedure MouseLeave(AControl: TControl); override;
+{$ELSE}
+ procedure MouseEnter; virtual;
+ procedure MouseLeave; virtual;
+{$ENDIF}
+ procedure Paint; override;
+ procedure ResizeBuffer;
+ property BufferValid: Boolean read FBufferValid write FBufferValid;
+{$IFDEF CLX}
+ function WidgetFlags: Integer; override;
+{$ENDIF}
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ function GetViewportRect: TRect; virtual;
+ procedure Flush; overload;
+ procedure Flush(const SrcRect: TRect); overload;
+ procedure Invalidate; override;
+ procedure Loaded; override;
+ procedure Resize; override;
+ procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
+ property Buffer: TBitmap32 read FBuffer;
+ property BufferOversize: Integer read FBufferOversize write SetBufferOversize;
+ property Options: TPaintBoxOptions read FOptions write FOptions default [];
+ property MouseInControl: Boolean read FMouseInControl;
+ property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
+ property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
+ property OnGDIOverlay: TNotifyEvent read FOnGDIOverlay write FOnGDIOverlay;
+ end;
+
+ { TPaintBox32 }
+ TPaintBox32 = class(TCustomPaintBox32)
+ private
+ FOnPaintBuffer: TNotifyEvent;
+ protected
+ procedure DoPaintBuffer; override;
+ public
+ property Canvas;
+ published
+ property Align;
+ property Anchors;
+{$IFNDEF CLX}
+ property AutoSize;
+{$ENDIF}
+ property Constraints;
+ property Cursor;
+{$IFNDEF CLX}
+ property DragCursor;
+{$ENDIF}
+ property Options;
+ property ParentShowHint;
+ property PopupMenu;
+ property ShowHint;
+ property TabOrder;
+ property TabStop;
+ property Visible;
+{$IFNDEF CLX}
+ property OnCanResize;
+{$ENDIF}
+ property OnClick;
+{$IFDEF DELPHI5}
+ property OnContextPopup;
+{$ENDIF}
+ property OnDblClick;
+ property OnDragDrop;
+ property OnDragOver;
+ property OnEndDrag;
+ property OnGDIOverlay;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnMouseWheel;
+ property OnMouseWheelDown;
+ property OnMouseWheelUp;
+ property OnMouseEnter;
+ property OnMouseLeave;
+ property OnPaintBuffer: TNotifyEvent read FOnPaintBuffer write FOnPaintBuffer;
+ property OnResize;
+ property OnStartDrag;
+ end;
+
+ { TCustomImage32 }
+ TImgMouseEvent = procedure(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer) of object;
+ TImgMouseMoveEvent = procedure(Sender: TObject; Shift: TShiftState;
+ X, Y: Integer; Layer: TCustomLayer) of object;
+
+ TCustomImage32 = class(TCustomPaintBox32)
+ private
+ FBitmap: TBitmap32;
+ FBitmapAlign: TBitmapAlign;
+ FLayers: TLayerCollection;
+ FOffsetHorz: Single;
+ FOffsetVert: Single;
+ FPaintStages: TPaintStages;
+ FScale: Single;
+ FScaleMode: TScaleMode;
+ FUpdateCount: Integer;
+ FOnBitmapResize: TNotifyEvent;
+ FOnChange: TNotifyEvent;
+ FOnInitStages: TNotifyEvent;
+ FOnMouseDown: TImgMouseEvent;
+ FOnMouseEnter: TNotifyEvent;
+ FOnMouseLeave: TNotifyEvent;
+ FOnMouseMove: TImgMouseMoveEvent;
+ FOnMouseUp: TImgMouseEvent;
+ FOnPaintStage: TPaintStageEvent;
+ procedure ResizedHandler(Sender: TObject);
+ procedure ChangedHandler(Sender: TObject);
+ function GetOnPixelCombine: TPixelCombineEvent;
+ procedure GDIUpdateHandler(Sender: TObject);
+ procedure SetBitmap(Value: TBitmap32); {$IFDEF CLX}reintroduce;{$ENDIF}
+ procedure SetBitmapAlign(Value: TBitmapAlign);
+ procedure SetLayers(Value: TLayerCollection);
+ procedure SetOffsetHorz(Value: Single);
+ procedure SetOffsetVert(Value: Single);
+ procedure SetScale(Value: Single);
+ procedure SetScaleMode(Value: TScaleMode);
+ procedure SetOnPixelCombine(Value: TPixelCombineEvent);
+ protected
+ CachedBitmapRect: TRect;
+ CachedXForm: TCoordXForm;
+ CacheValid: Boolean;
+ OldSzX, OldSzY: Integer;
+ PaintToMode: Boolean;
+ procedure BitmapResized; virtual;
+{$IFNDEF CLX}
+ function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
+{$ENDIF}
+ procedure DoInitStages; virtual;
+ procedure DoPaintBuffer; override;
+ procedure DoPaintGDIOverlay; override;
+ procedure DoScaleChange; virtual;
+ procedure InitDefaultStages; virtual;
+ procedure InvalidateCache;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); overload; override;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); overload; override;
+ procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); overload; override;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer); reintroduce; overload; dynamic;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer); reintroduce; overload; dynamic;
+ procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer); reintroduce; overload; dynamic;
+{$IFDEF CLX}
+ procedure MouseLeave(AControl: TControl); override;
+{$ELSE}
+ procedure MouseLeave; override;
+{$ENDIF}
+ procedure UpdateCache;
+ property UpdateCount: Integer read FUpdateCount;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ procedure BeginUpdate; virtual;
+ function BitmapToControl(const APoint: TPoint): TPoint;
+ procedure Changed; virtual;
+ function ControlToBitmap(const APoint: TPoint): TPoint;
+ procedure EndUpdate; virtual;
+ procedure ExecBitmapFrame(Dest: TBitmap32; StageNum: Integer); virtual; // PST_BITMAP_FRAME
+ procedure ExecClearBuffer(Dest: TBitmap32; StageNum: Integer); virtual; // PST_CLEAR_BUFFER
+ procedure ExecClearBackgnd(Dest: TBitmap32; StageNum: Integer); virtual; // PST_CLEAR_BACKGND
+ procedure ExecControlFrame(Dest: TBitmap32; StageNum: Integer); virtual; // PST_CONTROL_FRAME
+ procedure ExecCustom(Dest: TBitmap32; StageNum: Integer); virtual; // PST_CUSTOM
+ procedure ExecDrawBitmap(Dest: TBitmap32; StageNum: Integer); virtual; // PST_DRAW_BITMAP
+ procedure ExecDrawLayers(Dest: TBitmap32; StageNum: Integer); virtual; // PST_DRAW_LAYERS
+ function GetBitmapRect: TRect; virtual;
+ function GetBitmapSize: TSize; virtual;
+ procedure Invalidate; override;
+ procedure Loaded; override;
+ procedure PaintTo(Dest: TBitmap32; DestRect: TRect);
+ procedure Resize; override;
+ procedure SetupBitmap(DoClear: Boolean = False; ClearColor: TColor32 = $FF000000);
+ property Bitmap: TBitmap32 read FBitmap write SetBitmap;
+ property BitmapAlign: TBitmapAlign read FBitmapAlign write SetBitmapAlign;
+ property Canvas;
+ property Layers: TLayerCollection read FLayers write SetLayers;
+ property OffsetHorz: Single read FOffsetHorz write SetOffsetHorz;
+ property OffsetVert: Single read FOffsetVert write SetOffsetVert;
+ property PaintStages: TPaintStages read FPaintStages;
+ property Scale: Single read FScale write SetScale;
+ property ScaleMode: TScaleMode read FScaleMode write SetScaleMode;
+ property OnBitmapResize: TNotifyEvent read FOnBitmapResize write FOnBitmapResize;
+ property OnBitmapPixelCombine: TPixelCombineEvent read GetOnPixelCombine write SetOnPixelCombine;
+ property OnChange: TNotifyEvent read FOnChange write FOnChange;
+ property OnInitStages: TNotifyEvent read FOnInitStages write FOnInitStages;
+ property OnMouseDown: TImgMouseEvent read FOnMouseDown write FOnMouseDown;
+ property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
+ property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
+ property OnMouseMove: TImgMouseMoveEvent read FOnMouseMove write FOnMouseMove;
+ property OnMouseUp: TImgMouseEvent read FOnMouseUp write FOnMouseUp;
+ property OnPaintStage: TPaintStageEvent read FOnPaintStage write FOnPaintStage;
+ end;
+
+ TImage32 = class(TCustomImage32)
+ published
+ property Align;
+ property Anchors;
+{$IFNDEF CLX}
+ property AutoSize;
+{$ENDIF}
+ property Bitmap;
+ property BitmapAlign;
+ property Color;
+ property Constraints;
+ property Cursor;
+{$IFNDEF CLX}
+ property DragCursor;
+{$ENDIF}
+ property ParentColor;
+ property ParentShowHint;
+ property PopupMenu;
+ property Scale;
+ property ScaleMode;
+ property ShowHint;
+ property TabOrder;
+ property TabStop;
+ property Visible;
+ property OnBitmapResize;
+{$IFNDEF CLX}
+ property OnCanResize;
+{$ENDIF}
+ property OnClick;
+ property OnChange;
+{$IFDEF DELPHI5}
+ property OnContextPopup;
+{$ENDIF}
+ property OnDblClick;
+ property OnGDIOverlay;
+ property OnDragDrop;
+ property OnDragOver;
+ property OnEndDrag;
+ property OnInitStages;
+ property OnKeyDown;
+ property OnKeyPress;
+ property OnKeyUp;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnMouseWheel;
+ property OnMouseWheelDown;
+ property OnMouseWheelUp;
+ property OnMouseEnter;
+ property OnMouseLeave;
+ property OnPaintStage;
+ property OnResize;
+ property OnStartDrag;
+ end;
+
+ TCustomImgView32 = class;
+
+ { TIVScrollProperties }
+ TIVScrollProperties = class(TArrowBarAccess)
+ private
+ function GetIncrement: Integer;
+ function GetSize: Integer;
+ procedure SetIncrement(Value: Integer);
+ procedure SetSize(Value: Integer);
+ protected
+ ImgView: TCustomImgView32;
+ published
+ property Increment: Integer read GetIncrement write SetIncrement default 8;
+ property Size: Integer read GetSize write SetSize default 0;
+ end;
+
+ TSizeGripStyle = (sgAuto, sgNone, sgAlways);
+
+ { TCustomImgView32 }
+ TCustomImgView32 = class(TCustomImage32)
+ private
+ FCentered: Boolean;
+ FScrollBarSize: Integer;
+ FScrollBars: TIVScrollProperties;
+ FSizeGrip: TSizeGripStyle;
+ FOnScroll: TNotifyEvent;
+ FOverSize: Integer;
+ procedure SetCentered(Value: Boolean);
+ procedure SetScrollBars(Value: TIVScrollProperties);
+ procedure SetSizeGrip(Value: TSizeGripStyle);
+ procedure SetOverSize(const Value: Integer);
+ protected
+ DisableScrollUpdate: Boolean;
+ HScroll: TCustomRangeBar;
+ VScroll: TCustomRangeBar;
+ procedure AlignAll;
+ procedure BitmapResized; override;
+ procedure DoDrawSizeGrip(R: TRect);
+ procedure DoScaleChange; override;
+ procedure DoScroll; virtual;
+ function GetScrollBarSize: Integer;
+ function GetSizeGripRect: TRect;
+ function IsSizeGripVisible: Boolean;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
+ procedure Paint; override;
+ procedure ScrollHandler(Sender: TObject); virtual;
+ procedure UpdateImage; virtual;
+ procedure UpdateScrollBars; virtual;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ function GetViewportRect: TRect; override;
+ procedure Loaded; override;
+ procedure Resize; override;
+ procedure ScrollToCenter(X, Y: Integer);
+ procedure Scroll(Dx, Dy: Integer);
+ property Centered: Boolean read FCentered write SetCentered default True;
+ property ScrollBars: TIVScrollProperties read FScrollBars write SetScrollBars;
+ property SizeGrip: TSizeGripStyle read FSizeGrip write SetSizeGrip;
+ property OverSize: Integer read FOverSize write SetOverSize;
+ property OnScroll: TNotifyEvent read FOnScroll write FOnScroll;
+ end;
+
+ TImgView32 = class(TCustomImgView32)
+ property Align;
+ property Anchors;
+{$IFNDEF CLX}
+ property AutoSize;
+{$ENDIF}
+ property Bitmap;
+ property Centered;
+ property Color;
+ property Constraints;
+ property Cursor;
+{$IFNDEF CLX}
+ property DragCursor;
+{$ENDIF}
+ property ParentColor;
+ property ParentShowHint;
+ property PopupMenu;
+ property Scale;
+ property ScrollBars;
+ property ShowHint;
+ property SizeGrip;
+ property OverSize;
+ property TabOrder;
+ property TabStop;
+ property Visible;
+ property OnBitmapResize;
+{$IFNDEF CLX}
+ property OnCanResize;
+{$ENDIF}
+ property OnClick;
+ property OnChange;
+{$IFDEF DELPHI5}
+ property OnContextPopup;
+{$ENDIF}
+ property OnDblClick;
+ property OnDragDrop;
+ property OnDragOver;
+ property OnEndDrag;
+ property OnGDIOverlay;
+ property OnInitStages;
+ property OnKeyDown;
+ property OnKeyPress;
+ property OnKeyUp;
+ property OnMouseDown;
+ property OnMouseEnter;
+ property OnMouseLeave;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnMouseWheel;
+ property OnMouseWheelDown;
+ property OnMouseWheelUp;
+ property OnPaintStage;
+ property OnResize;
+ property OnScroll;
+ property OnStartDrag;
+ end;
+
+ { TBitmap32Item }
+ { A bitmap container designed to be inserted into TBitmap32Collection }
+ TBitmap32Item = class(TCollectionItem)
+ private
+ FBitmap: TBitmap32;
+ procedure SetBitmap(ABitmap: TBitmap32);
+ public
+ constructor Create(Collection: TCollection); override;
+ destructor Destroy; override;
+ published
+ property Bitmap: TBitmap32 read FBitmap write SetBitmap;
+ end;
+
+ TBitmap32ItemClass = class of TBitmap32Item;
+
+ { TBitmap32Collection }
+ { A collection of TBitmap32Item objects }
+ TBitmap32Collection = class(TCollection)
+ private
+ FOwner: TPersistent;
+ function GetItem(Index: Integer): TBitmap32Item;
+ procedure SetItem(Index: Integer; Value: TBitmap32Item);
+ protected
+ function GetOwner: TPersistent; override;
+ public
+ constructor Create(AOwner: TPersistent; ItemClass: TBitmap32ItemClass);
+ function Add: TBitmap32Item;
+ property Items[Index: Integer]: TBitmap32Item read GetItem write SetItem; default;
+ end;
+
+ { TBitmap32List }
+ { A component that stores TBitmap32Collection }
+ TBitmap32List = class(TComponent)
+ private
+ FBitmap32Collection: TBitmap32Collection;
+ procedure SetBitmap(Index: Integer; Value: TBitmap32);
+ function GetBitmap(Index: Integer): TBitmap32;
+ procedure SetBitmap32Collection(Value: TBitmap32Collection);
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ property Bitmap[Index: Integer]: TBitmap32 read GetBitmap write SetBitmap; default;
+ published
+ property Bitmaps: TBitmap32Collection read FBitmap32Collection write SetBitmap32Collection;
+ end;
+
+implementation
+
+uses Math, TypInfo, GR32_System;
+
+type
+ TLayerAccess = class(TCustomLayer);
+ TLayerCollectionAccess = class(TLayerCollection);
+
+const
+ UnitXForm: TCoordXForm = (
+ ScaleX: $10000;
+ ScaleY: $10000;
+ ShiftX: 0;
+ ShiftY: 0;
+ RevScaleX: 65536;
+ RevScaleY: 65536);
+
+{ TPaintStages }
+
+function TPaintStages.Add: PPaintStage;
+var
+ L: Integer;
+begin
+ L := Length(FItems);
+ SetLength(FItems, L + 1);
+ Result := @FItems[L];
+ with Result^ do
+ begin
+ DsgnTime := False;
+ RunTime := True;
+ Stage := 0;
+ Parameter := 0;
+ end;
+end;
+
+procedure TPaintStages.Clear;
+begin
+ FItems := nil;
+end;
+
+function TPaintStages.Count: Integer;
+begin
+ Result := Length(FItems);
+end;
+
+procedure TPaintStages.Delete(Index: Integer);
+var
+ Count: Integer;
+begin
+ if (Index < 0) or (Index > High(FItems)) then
+ raise EListError.Create('Invalid stage index');
+ Count := Length(FItems) - Index - 1;
+ if Count > 0 then
+ Move(FItems[Index + 1], FItems[Index], Count * SizeOf(TPaintStage));
+ SetLength(FItems, High(FItems));
+end;
+
+destructor TPaintStages.Destroy;
+begin
+ Clear;
+ inherited;
+end;
+
+function TPaintStages.GetItem(Index: Integer): PPaintStage;
+begin
+ Result := @FItems[Index];
+end;
+
+function TPaintStages.Insert(Index: Integer): PPaintStage;
+var
+ Count: Integer;
+begin
+ if Index < 0 then Index := 0
+ else if Index > Length(FItems) then Index := Length(FItems);
+ Count := Length(FItems) - Index;
+ SetLength(FItems, Length(FItems) + 1);
+ if Count > 0 then
+ Move(FItems[Index], FItems[Index + 1], Count * SizeOf(TPaintStage));
+ Result := @FItems[Index];
+ with Result^ do
+ begin
+ DsgnTime := False;
+ RunTime := True;
+ Stage := 0;
+ Parameter := 0;
+ end;
+end;
+
+
+{ TCustomPaintBox32 }
+
+{$IFNDEF CLX}
+procedure TCustomPaintBox32.CMMouseEnter(var Message: TMessage);
+begin
+ inherited;
+ MouseEnter;
+end;
+
+procedure TCustomPaintBox32.CMMouseLeave(var Message: TMessage);
+begin
+ MouseLeave;
+ inherited;
+end;
+{$ENDIF}
+
+constructor TCustomPaintBox32.Create(AOwner: TComponent);
+begin
+ inherited;
+ FBuffer := TBitmap32.Create;
+ FBuffer.BeginUpdate; // just to speed the things up a little
+ FBufferOversize := 40;
+ Height := 192;
+ Width := 192;
+end;
+
+destructor TCustomPaintBox32.Destroy;
+begin
+ FBuffer.Free;
+ inherited;
+end;
+
+procedure TCustomPaintBox32.DoPaintBuffer;
+begin
+ // do nothing by default, descendants should override this method
+ // for painting operations, not the Paint method!!!
+ FBufferValid := True;
+end;
+
+procedure TCustomPaintBox32.DoPaintGDIOverlay;
+begin
+ if Assigned(FOnGDIOverlay) then FOnGDIOverlay(Self);
+end;
+
+procedure TCustomPaintBox32.Flush;
+begin
+{$IFDEF CLX}
+ if Assigned(Canvas.Handle) and Assigned(FBuffer.Handle) then
+{$ELSE}
+ if (Canvas.Handle <> 0) and (FBuffer.Handle <> 0) then
+{$ENDIF}
+ begin
+ Canvas.Lock;
+ try
+ FBuffer.Lock;
+ try
+ with GetViewportRect do
+{$IFDEF CLX}
+ begin
+ if not QPainter_isActive(FBuffer.Handle) then
+ if not QPainter_begin(FBuffer.Handle, FBuffer.Pixmap) then
+ raise EInvalidGraphicOperation.CreateRes(@SInvalidCanvasState);
+ QPainter_drawPixmap(Canvas.Handle, Top, Left, FBuffer.Pixmap, 0, 0, Right - Left, Bottom - Top);
+ QPainter_end(FBuffer.Handle);
+
+ TBitmap32Access(FBuffer).CheckPixmap; // try to avoid QPixmap -> QImage conversion, since we don't need that.
+ end;
+{$ELSE}
+ BitBlt(Canvas.Handle, Left, Top, Right - Left, Bottom - Top,
+ FBuffer.Handle, 0, 0, SRCCOPY);
+{$ENDIF}
+ finally
+ FBuffer.Unlock;
+ end;
+ finally
+ Canvas.Unlock;
+ end;
+ end;
+end;
+
+procedure TCustomPaintBox32.Flush(const SrcRect: TRect);
+var
+ R: TRect;
+begin
+{$IFDEF CLX}
+ if Assigned(Canvas.Handle) and Assigned(FBuffer.Handle) then
+{$ELSE}
+ if (Canvas.Handle <> 0) and (FBuffer.Handle <> 0) then
+{$ENDIF}
+ begin
+ Canvas.Lock;
+ try
+ FBuffer.Lock;
+ try
+ R := GetViewPortRect;
+ with SrcRect do
+{$IFDEF CLX}
+ begin
+ if not QPainter_isActive(FBuffer.Handle) then
+ if not QPainter_begin(FBuffer.Handle, FBuffer.Pixmap) then
+ raise EInvalidGraphicOperation.CreateRes(@SInvalidCanvasState);
+ QPainter_drawPixmap(Canvas.Handle, Top + R.Top, Left + R.Left,
+ FBuffer.Pixmap, 0, 0, Right - Left, Bottom - Top);
+ QPainter_end(FBuffer.Handle);
+
+ TBitmap32Access(FBuffer).CheckPixmap; // try to avoid QPixmap -> QImage conversion, since we don't need that.
+ end;
+{$ELSE}
+ BitBlt(Canvas.Handle, Left + R.Left, Top + R.Top, Right - Left, Bottom - Top,
+ FBuffer.Handle, Left, Top, SRCCOPY);
+{$ENDIF}
+ finally
+ FBuffer.Unlock;
+ end;
+ finally
+ Canvas.Unlock;
+ end;
+ end;
+end;
+
+function TCustomPaintBox32.GetViewportRect: TRect;
+begin
+ // returns position of the buffered area within the control bounds
+ with Result do
+ begin
+ // by default, the whole control is buffered
+ Left := 0;
+ Top := 0;
+ Right := Width;
+ Bottom := Height;
+ end;
+end;
+
+procedure TCustomPaintBox32.Invalidate;
+begin
+ FBufferValid := False;
+ inherited;
+end;
+
+procedure TCustomPaintBox32.Loaded;
+begin
+ FBufferValid := False;
+ inherited;
+end;
+
+procedure TCustomPaintBox32.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ if (pboAutoFocus in Options) and CanFocus then SetFocus;
+ inherited;
+end;
+
+{$IFDEF CLX}
+procedure TCustomPaintBox32.MouseEnter(AControl: TControl);
+begin
+ FMouseInControl := True;
+ inherited;
+end;
+
+procedure TCustomPaintBox32.MouseLeave(AControl: TControl);
+begin
+ FMouseInControl := False;
+ inherited;
+end;
+
+{$ELSE}
+
+procedure TCustomPaintBox32.MouseEnter;
+begin
+ FMouseInControl := True;
+ if Assigned(FOnMouseEnter) then
+ FOnMouseEnter(Self);
+end;
+
+procedure TCustomPaintBox32.MouseLeave;
+begin
+ FMouseInControl := False;
+ if Assigned(FOnMouseLeave) then
+ FOnMouseLeave(Self);
+end;
+{$ENDIF}
+
+procedure TCustomPaintBox32.Paint;
+begin
+ ResizeBuffer;
+ if not FBufferValid then
+ begin
+{$IFDEF CLX}
+ TBitmap32Access(FBuffer).ImageNeeded;
+{$ENDIF}
+ DoPaintBuffer;
+ end;
+
+ FBuffer.Lock;
+ try
+ with GetViewportRect do
+{$IFDEF CLX}
+ begin
+ if not QPainter_isActive(FBuffer.Handle) then
+ if not QPainter_begin(FBuffer.Handle, FBuffer.Pixmap) then
+ raise EInvalidGraphicOperation.CreateRes(@SInvalidCanvasState);
+ QPainter_drawPixmap(Canvas.Handle, Top, Left, FBuffer.Pixmap, 0, 0, Right - Left, Bottom - Top);
+ QPainter_end(FBuffer.Handle);
+
+ TBitmap32Access(FBuffer).CheckPixmap; // try to avoid QPixmap -> QImage conversion, since we don't need that.
+ end;
+{$ELSE}
+ BitBlt(Canvas.Handle, Left, Top, Right - Left, Bottom - Top,
+ FBuffer.Handle, 0, 0, SRCCOPY);
+{$ENDIF}
+ finally
+ FBuffer.Unlock;
+ end;
+ DoPaintGDIOverlay;
+end;
+
+procedure TCustomPaintBox32.Resize;
+begin
+ ResizeBuffer;
+ BufferValid := False;
+ inherited;
+end;
+
+procedure TCustomPaintBox32.ResizeBuffer;
+var
+ NewWidth, NewHeight, W, H: Integer;
+begin
+ // get the viewport parameters
+ with GetViewportRect do
+ begin
+ NewWidth := Right - Left;
+ NewHeight := Bottom - Top;
+ end;
+ if NewWidth < 0 then NewWidth := 0;
+ if NewHeight < 0 then NewHeight := 0;
+
+ W := FBuffer.Width;
+ if NewWidth > W then W := NewWidth + FBufferOversize
+ else if NewWidth < W - FBufferOversize then W := NewWidth;
+ if W < 1 then W := 1;
+
+ H := FBuffer.Height;
+ if NewHeight > H then H := NewHeight + FBufferOversize
+ else if NewHeight < H - FBufferOversize then H := NewHeight;
+ if H < 1 then H := 1;
+
+ if (W <> FBuffer.Width) or (H <> FBuffer.Height) then
+ begin
+ FBuffer.Lock;
+ FBuffer.SetSize(NewWidth, NewHeight);
+ FBuffer.Unlock;
+ FBufferValid := False;
+ end;
+end;
+
+procedure TCustomPaintBox32.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
+begin
+ FBufferValid := False;
+ inherited;
+end;
+
+procedure TCustomPaintBox32.SetBufferOversize(Value: Integer);
+begin
+ if Value < 0 then Value := 0;
+ FBufferOversize := Value;
+end;
+
+{$IFDEF CLX}
+function TCustomPaintBox32.WidgetFlags: Integer;
+begin
+ Result := Inherited WidgetFlags or Integer(WidgetFlags_WRepaintNoErase) or
+ Integer(WidgetFlags_WResizeNoErase);
+end;
+{$ELSE}
+procedure TCustomPaintBox32.WMEraseBkgnd(var Message: TWmEraseBkgnd);
+begin
+ Message.Result := 1;
+end;
+
+procedure TCustomPaintBox32.WMGetDlgCode(var Msg: TWmGetDlgCode);
+begin
+ with Msg do if pboWantArrowKeys in Options then
+ Result:= Result or DLGC_WANTARROWS
+ else
+ Result:= Result and not DLGC_WANTARROWS;
+end;
+{$ENDIF}
+
+
+
+{ TPaintBox32 }
+
+procedure TPaintBox32.DoPaintBuffer;
+begin
+ if Assigned(FOnPaintBuffer) then FOnPaintBuffer(Self);
+end;
+
+
+
+
+
+{ TCustomImage32 }
+
+procedure TCustomImage32.BeginUpdate;
+begin
+ // disable OnChange & OnChanging generation
+ Inc(FUpdateCount);
+end;
+
+procedure TCustomImage32.BitmapResized;
+{$IFNDEF CLX}
+var
+ W, H: Integer;
+begin
+ if AutoSize then
+ begin
+ W := Bitmap.Width;
+ H := Bitmap.Height;
+ if ScaleMode = smScale then
+ begin
+ W := Round(W * Scale);
+ H := Round(H * Scale);
+ end;
+ if AutoSize and (W > 0) and (H > 0) then SetBounds(Left, Top, W, H);
+ end;
+{$ELSE}
+begin
+{$ENDIF}
+ if (FUpdateCount <> 0) and Assigned(FOnBitmapResize) then FOnBitmapResize(Self);
+ InvalidateCache;
+ Invalidate;
+end;
+
+function TCustomImage32.BitmapToControl(const APoint: TPoint): TPoint;
+begin
+ // convert coordinates from bitmap's ref. frame to control's ref. frame
+ UpdateCache;
+ with CachedXForm, APoint do
+ begin
+ Result.X := X * ScaleX div $10000 + ShiftX;
+ Result.Y := Y * ScaleY div $10000 + ShiftY;
+ end;
+end;
+
+{$IFNDEF CLX}
+function TCustomImage32.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
+var
+ W, H: Integer;
+begin
+ InvalidateCache;
+ Result := True;
+ W := Bitmap.Width;
+ H := Bitmap.Height;
+ if ScaleMode = smScale then
+ begin
+ W := Round(W * Scale);
+ H := Round(H * Scale);
+ end;
+ if not (csDesigning in ComponentState) or (W > 0) and (H > 0) then
+ begin
+ if Align in [alNone, alLeft, alRight] then NewWidth := W;
+ if Align in [alNone, alTop, alBottom] then NewHeight := H;
+ end;
+end;
+{$ENDIF}
+
+procedure TCustomImage32.Changed;
+begin
+ if FUpdateCount = 0 then
+ begin
+ Invalidate;
+ if Assigned(FOnChange) then FOnChange(Self);
+ end;
+end;
+
+procedure TCustomImage32.ChangedHandler(Sender: TObject);
+begin
+ Changed;
+end;
+
+function TCustomImage32.ControlToBitmap(const APoint: TPoint): TPoint;
+begin
+ // convert point coords from control's ref. frame to bitmap's ref. frame
+ // the coordinates are not clipped to bitmap image boundary
+ UpdateCache;
+ with CachedXForm, APoint do
+ begin
+ Result.X := (X - ShiftX) * RevScaleX div $10000;
+ Result.Y := (Y - ShiftY) * RevScaleY div $10000;
+ end;
+end;
+
+constructor TCustomImage32.Create(AOwner: TComponent);
+begin
+ inherited;
+ ControlStyle := [csAcceptsControls, csCaptureMouse, csClickEvents,
+ csDoubleClicks, csReplicatable, csOpaque];
+ FBitmap := TBitmap32.Create;
+ FBitmap.OnChange := ChangedHandler;
+ FBitmap.OnResize := ResizedHandler;
+ FLayers := TLayerCollection.Create(Self);
+ with TLayerCollectionAccess(FLayers) do
+ begin
+ CoordXForm := @CachedXForm;
+ OnChange := ChangedHandler;
+ OnGDIUpdate := GDIUpdateHandler;
+ end;
+ FPaintStages := TPaintStages.Create;
+ FScale := 1.0;
+ InitDefaultStages;
+end;
+
+destructor TCustomImage32.Destroy;
+begin
+ BeginUpdate;
+ FPaintStages.Free;
+ FLayers.Free;
+ FBitmap.Free;
+ inherited;
+end;
+
+procedure TCustomImage32.DoInitStages;
+begin
+ if Assigned(FOnInitStages) then FOnInitStages(Self);
+end;
+
+procedure TCustomImage32.DoPaintBuffer;
+var
+ I: Integer;
+ DT, RT: Boolean;
+begin
+ UpdateCache;
+ DT := csDesigning in ComponentState;
+ RT := not DT;
+
+ for I := 0 to FPaintStages.Count - 1 do
+ with FPaintStages[I]^ do
+ if (DsgnTime and DT) or (RunTime and RT) then
+ case Stage of
+ PST_CUSTOM: ExecCustom(Buffer, I);
+ PST_CLEAR_BUFFER: ExecClearBuffer(Buffer, I);
+ PST_CLEAR_BACKGND: ExecClearBackgnd(Buffer, I);
+ PST_DRAW_BITMAP: ExecDrawBitmap(Buffer, I);
+ PST_DRAW_LAYERS: ExecDrawLayers(Buffer, I);
+ PST_CONTROL_FRAME: ExecControlFrame(Buffer, I);
+ PST_BITMAP_FRAME: ExecBitmapFrame(Buffer, I);
+ end;
+ inherited;
+end;
+
+procedure TCustomImage32.DoPaintGDIOverlay;
+var
+ I: Integer;
+begin
+ for I := 0 to Layers.Count - 1 do
+ if (Layers[I].LayerOptions and $40000000) <> 0 then
+ TLayerAccess(Layers[I]).PaintGDI(Canvas);
+ inherited;
+end;
+
+procedure TCustomImage32.DoScaleChange;
+begin
+ // do nothing here
+end;
+
+procedure TCustomImage32.EndUpdate;
+begin
+ // re-enable OnChange & OnChanging generation
+ Dec(FUpdateCount);
+ Assert(FUpdateCount >= 0, 'Unpaired EndUpdate call');
+end;
+
+procedure TCustomImage32.ExecBitmapFrame(Dest: TBitmap32; StageNum: Integer);
+begin
+ Dest.Canvas.DrawFocusRect(CachedBitmapRect);
+end;
+
+procedure TCustomImage32.ExecClearBackgnd(Dest: TBitmap32; StageNum: Integer);
+var
+ C: TColor32;
+begin
+ C := Color32(Color);
+ if (Bitmap.Empty) or (Bitmap.DrawMode <> dmOpaque) then Dest.Clear(C)
+ else
+ with CachedBitmapRect do
+ begin
+ if (Left > 0) or (Right < Width) or (Top > 0) or (Bottom < Height) and
+ not (BitmapAlign = baTile) then
+ begin
+ // clean only the part of the buffer lying around image edges
+ Dest.FillRectS(0, 0, Width, Top, C); // top
+ Dest.FillRectS(0, Bottom, Width, Height, C); // bottom
+ Dest.FillRectS(0, Top, Left, Bottom, C); // left
+ Dest.FillRectS(Right, Top, Width, Bottom, C); // right
+ end;
+ end;
+end;
+
+procedure TCustomImage32.ExecClearBuffer(Dest: TBitmap32; StageNum: Integer);
+begin
+ Dest.Clear(Color32(Color));
+end;
+
+procedure TCustomImage32.ExecControlFrame(Dest: TBitmap32; StageNum: Integer);
+begin
+ {$IFDEF CLX}
+ Dest.Canvas.DrawFocusRect(Rect(0, 0, Width, Height));
+ {$ELSE}
+ DrawFocusRect(Dest.Handle, Rect(0, 0, Width, Height));
+ {$ENDIF}
+end;
+
+procedure TCustomImage32.ExecCustom(Dest: TBitmap32; StageNum: Integer);
+begin
+ if Assigned(FOnPaintStage) then FOnPaintStage(Self, Dest, StageNum);
+end;
+
+procedure TCustomImage32.ExecDrawBitmap(Dest: TBitmap32; StageNum: Integer);
+var
+ I, J, Tx, Ty: Integer;
+ R: TRect;
+begin
+ if Bitmap.Empty or IsRectEmpty(CachedBitmapRect) then Exit;
+ Bitmap.Lock;
+ try
+ if BitmapAlign <> baTile then Bitmap.DrawTo(Dest, CachedBitmapRect)
+ else with CachedBitmapRect do
+ begin
+ Tx := Dest.Width div Right;
+ Ty := Dest.Height div Bottom;
+ for J := 0 to Ty do
+ for I := 0 to Tx do
+ begin
+ R := CachedBitmapRect;
+ OffsetRect(R, Right * I, Bottom * J);
+ Bitmap.DrawTo(Dest, R);
+ end;
+ end;
+ finally
+ Bitmap.Unlock;
+ end;
+end;
+
+procedure TCustomImage32.ExecDrawLayers(Dest: TBitmap32; StageNum: Integer);
+var
+ I: Integer;
+ Mask: Cardinal;
+begin
+ Mask := PaintStages[StageNum]^.Parameter;
+ for I := 0 to Layers.Count - 1 do
+ if (Layers.Items[I].LayerOptions and Mask) <> 0 then
+ TLayerAccess(Layers.Items[I]).DoPaint(Dest);
+end;
+
+procedure TCustomImage32.GDIUpdateHandler(Sender: TObject);
+begin
+ Paint;
+end;
+
+function TCustomImage32.GetBitmapRect: TRect;
+var
+ Size: TSize;
+begin
+ if Bitmap.Empty then
+ with Result do
+ begin
+ Left := 0;
+ Right := 0;
+ Top := 0;
+ Bottom := 0;
+ end
+ else
+ begin
+ Size := GetBitmapSize;
+ with Size do
+ begin
+ Result := Rect(0, 0, Cx, Cy);
+ if BitmapAlign = baCenter then
+ OffsetRect(Result, (Width - Cx) div 2, (Height - Cy) div 2)
+ else if BitmapAlign = baCustom then
+ OffsetRect(Result, Round(OffsetHorz), Round(OffsetVert));
+ end;
+ end;
+end;
+
+function TCustomImage32.GetBitmapSize: TSize;
+var
+ ScaleX, ScaleY: Single;
+begin
+ with Result do
+ begin
+ if Bitmap.Empty or (Width = 0) or (Height = 0) then
+ begin
+ Cx := 0;
+ Cy := 0;
+ Exit;
+ end;
+
+ case ScaleMode of
+ smNormal:
+ begin
+ Cx := Bitmap.Width;
+ Cy := Bitmap.Height;
+ end;
+
+ smStretch:
+ begin
+ Cx := Width;
+ Cy := Height;
+ end;
+
+ smResize:
+ begin
+ Cx := Bitmap.Width;
+ Cy := Bitmap.Height;
+ ScaleX := Width / Cx;
+ ScaleY := Height / Cy;
+ if ScaleX >= ScaleY then
+ begin
+ Cx := Round(Cx * ScaleY);
+ Cy := Height;
+ end
+ else
+ begin
+ Cx := Width;
+ Cy := Round(Cy * ScaleX);
+ end;
+ end;
+ else // smScale
+ begin
+ Cx := Round(Bitmap.Width * Scale);
+ Cy := Round(Bitmap.Height * Scale);
+ end;
+ end;
+ if Cx <= 0 then Cx := 0;
+ if Cy <= 0 then Cy := 0;
+ end;
+end;
+
+function TCustomImage32.GetOnPixelCombine: TPixelCombineEvent;
+begin
+ Result := FBitmap.OnPixelCombine;
+end;
+
+procedure TCustomImage32.InitDefaultStages;
+begin
+ // background
+ with PaintStages.Add^ do
+ begin
+ DsgnTime := True;
+ RunTime := True;
+ Stage := PST_CLEAR_BACKGND;
+ end;
+
+ // control frame
+ with PaintStages.Add^ do
+ begin
+ DsgnTime := True;
+ RunTime := False;
+ Stage := PST_CONTROL_FRAME;
+ end;
+
+ // bitmap
+ with PaintStages.Add^ do
+ begin
+ DsgnTime := True;
+ RunTime := True;
+ Stage := PST_DRAW_BITMAP;
+ end;
+
+ // bitmap frame
+ with PaintStages.Add^ do
+ begin
+ DsgnTime := True;
+ RunTime := False;
+ Stage := PST_BITMAP_FRAME;
+ end;
+
+ // layers
+ with PaintStages.Add^ do
+ begin
+ DsgnTime := True;
+ RunTime := True;
+ Stage := PST_DRAW_LAYERS;
+ Parameter := $80000000;
+ end;
+end;
+
+procedure TCustomImage32.Invalidate;
+begin
+ BufferValid := False;
+ CacheValid := False;
+ inherited;
+end;
+
+procedure TCustomImage32.InvalidateCache;
+begin
+ CacheValid := False;
+end;
+
+procedure TCustomImage32.Loaded;
+begin
+ inherited;
+ DoInitStages;
+end;
+
+procedure TCustomImage32.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+var
+ Layer: TCustomLayer;
+begin
+ inherited;
+
+ if TabStop and CanFocus then SetFocus;
+
+ if Layers.MouseEvents then
+ Layer := TLayerCollectionAccess(Layers).MouseDown(Button, Shift, X, Y)
+ else
+ Layer := nil;
+
+ // lock the capture only if mbLeft was pushed or any mouse listener was activated
+ if (Button = mbLeft) or (TLayerCollectionAccess(Layers).MouseListener <> nil) then
+ MouseCapture := True;
+
+ MouseDown(Button, Shift, X, Y, Layer);
+end;
+
+procedure TCustomImage32.MouseMove(Shift: TShiftState; X, Y: Integer);
+var
+ Layer: TCustomLayer;
+begin
+ inherited;
+ if Layers.MouseEvents then
+ Layer := TLayerCollectionAccess(Layers).MouseMove(Shift, X, Y)
+ else
+ Layer := nil;
+
+ MouseMove(Shift, X, Y, Layer);
+end;
+
+procedure TCustomImage32.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+var
+ Layer: TCustomLayer;
+begin
+ if Layers.MouseEvents then
+ Layer := TLayerCollectionAccess(Layers).MouseUp(Button, Shift, X, Y)
+ else
+ Layer := nil;
+
+ // unlock the capture only if mbLeft was raised and there is no active mouse listeners
+ if (Button = mbLeft) and (TLayerCollectionAccess(Layers).MouseListener = nil) then
+ MouseCapture := False;
+
+ MouseUp(Button, Shift, X, Y, Layer);
+end;
+
+procedure TCustomImage32.MouseDown(Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+begin
+ if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y, Layer);
+end;
+
+procedure TCustomImage32.MouseMove(Shift: TShiftState; X, Y: Integer;
+ Layer: TCustomLayer);
+begin
+ if Assigned(FOnMouseMove) then FOnMouseMove(Self, Shift, X, Y, Layer);
+end;
+
+procedure TCustomImage32.MouseUp(Button: TMouseButton; Shift: TShiftState;
+ X, Y: Integer; Layer: TCustomLayer);
+begin
+ if Assigned(FOnMouseUp) then FOnMouseUp(Self, Button, Shift, X, Y, Layer);
+end;
+
+{$IFDEF CLX}
+procedure TCustomImage32.MouseLeave(AControl: TControl);
+begin
+ if (Layers.MouseEvents) and (Layers.MouseListener = nil) then
+ Screen.Cursor := crDefault;
+ inherited;
+end;
+
+{$ELSE}
+
+procedure TCustomImage32.MouseLeave;
+begin
+ if (Layers.MouseEvents) and (Layers.MouseListener = nil) then
+ Screen.Cursor := crDefault;
+ inherited;
+end;
+{$ENDIF}
+
+procedure TCustomImage32.PaintTo(Dest: TBitmap32; DestRect: TRect);
+var
+ I: Integer;
+begin
+ CachedBitmapRect := DestRect;
+
+ with CachedBitmapRect, CachedXForm do
+ begin
+ if (Right - Left <= 0) or (Bottom - Top <= 0) or Bitmap.Empty then
+ CachedXForm := UnitXForm
+ else
+ begin
+ ShiftX := Left;
+ ShiftY := Top;
+ ScaleX := MulDiv(Right - Left, $10000, Bitmap.Width);
+ ScaleY := MulDiv(Bottom - Top, $10000, Bitmap.Height);
+ RevScaleX := MulDiv(Bitmap.Width, $10000, Right - Left);
+ RevScaleY := MulDiv(Bitmap.Height, $10000, Bottom - Top);
+ end;
+ end;
+ CacheValid := True;
+
+ PaintToMode := True;
+ try
+ for I := 0 to FPaintStages.Count - 1 do
+ with FPaintStages[I]^ do
+ if RunTime then
+ case Stage of
+ PST_CUSTOM: ExecCustom(Dest, I);
+ PST_CLEAR_BUFFER: ExecClearBuffer(Dest, I);
+ PST_CLEAR_BACKGND: ExecClearBackgnd(Dest, I);
+ PST_DRAW_BITMAP: ExecDrawBitmap(Dest, I);
+ PST_DRAW_LAYERS: ExecDrawLayers(Dest, I);
+ PST_CONTROL_FRAME: ExecControlFrame(Dest, I);
+ PST_BITMAP_FRAME: ExecBitmapFrame(Dest, I);
+ end;
+ finally
+ PaintToMode := False;
+ end;
+ CacheValid := False;
+end;
+
+procedure TCustomImage32.Resize;
+begin
+ InvalidateCache;
+ inherited;
+end;
+
+procedure TCustomImage32.ResizedHandler(Sender: TObject);
+begin
+{$IFDEF CLX}
+ // workaround to stop CLX from calling BitmapResized and to prevent
+ // AV when accessing Layers. Layers is already freed at that time
+ if not(csDestroying in ComponentState) then
+{$ENDIF}
+ BitmapResized;
+end;
+
+procedure TCustomImage32.SetBitmap(Value: TBitmap32);
+begin
+ InvalidateCache;
+ FBitmap.Assign(Value);
+end;
+
+procedure TCustomImage32.SetBitmapAlign(Value: TBitmapAlign);
+begin
+ InvalidateCache;
+ FBitmapAlign := Value;
+ Changed;
+end;
+
+procedure TCustomImage32.SetLayers(Value: TLayerCollection);
+begin
+ FLayers.Assign(Value);
+end;
+
+procedure TCustomImage32.SetOffsetHorz(Value: Single);
+begin
+ if Value <> FOffsetHorz then
+ begin
+ InvalidateCache;
+ FOffsetHorz := Value;
+ Changed;
+ end;
+end;
+
+procedure TCustomImage32.SetOffsetVert(Value: Single);
+begin
+ if Value <> FOffsetVert then
+ begin
+ FOffsetVert := Value;
+ InvalidateCache;
+ Changed;
+ end;
+end;
+
+procedure TCustomImage32.SetOnPixelCombine(Value: TPixelCombineEvent);
+begin
+ FBitmap.OnPixelCombine := Value;
+ Changed;
+end;
+
+procedure TCustomImage32.SetScale(Value: Single);
+begin
+ if Value < 0.001 then Value := 0.001;
+ if Value <> FScale then
+ begin
+ InvalidateCache;
+ FScale := Value;
+ DoScaleChange;
+ Changed;
+ end;
+end;
+
+procedure TCustomImage32.SetScaleMode(Value: TScaleMode);
+begin
+ if Value <> FScaleMode then
+ begin
+ InvalidateCache;
+ FScaleMode := Value;
+ Changed;
+ end;
+end;
+
+procedure TCustomImage32.SetupBitmap(DoClear: Boolean = False; ClearColor: TColor32 = $FF000000);
+begin
+ FBitmap.BeginUpdate;
+ with GetViewPortRect do
+ FBitmap.SetSize(Right - Left, Bottom - Top);
+ if DoClear then FBitmap.Clear(ClearColor);
+ FBitmap.EndUpdate;
+ InvalidateCache;
+ Changed;
+end;
+
+procedure TCustomImage32.UpdateCache;
+begin
+ if CacheValid then Exit;
+ CachedBitmapRect := GetBitmapRect;
+ with CachedBitmapRect, CachedXForm do
+ begin
+ if Bitmap.Empty then CachedXForm := UnitXForm
+ else
+ begin
+ Assert((Right > Left) and (Bottom > Top));
+ ShiftX := Left;
+ ShiftY := Top;
+ ScaleX := MulDiv(Right - Left, $10000, Bitmap.Width);
+ ScaleY := MulDiv(Bottom - Top, $10000, Bitmap.Height);
+ RevScaleX := MulDiv(Bitmap.Width, $10000, Right - Left);
+ RevScaleY := MulDiv(Bitmap.Height, $10000, Bottom - Top);
+ end;
+ end;
+ CacheValid := True;
+end;
+
+
+
+
+{ TIVScrollProperties }
+
+function TIVScrollProperties.GetIncrement: Integer;
+begin
+ Result := Round(TCustomRangeBar(Master).Increment);
+end;
+
+function TIVScrollProperties.GetSize: Integer;
+begin
+ Result := ImgView.FScrollBarSize;
+end;
+
+procedure TIVScrollProperties.SetIncrement(Value: Integer);
+begin
+ TCustomRangeBar(Master).Increment := Value;
+ TCustomRangeBar(Slave).Increment := Value;
+end;
+
+procedure TIVScrollProperties.SetSize(Value: Integer);
+begin
+ ImgView.FScrollBarSize := Value;
+ ImgView.AlignAll;
+end;
+
+
+
+
+{ TCustomImgView32 }
+
+procedure TCustomImgView32.AlignAll;
+begin
+ with GetViewportRect do
+ begin
+ If Assigned(HScroll) then
+ begin
+ HScroll.BoundsRect := Rect(Left, Bottom, Right, Height);
+ HScroll.Repaint;
+ end;
+
+ If Assigned(VScroll) then
+ begin
+ VScroll.BoundsRect := Rect(Right, Top, Width, Bottom);
+ VScroll.Repaint;
+ end;
+ end;
+end;
+
+procedure TCustomImgView32.BitmapResized;
+begin
+ inherited;
+ UpdateScrollBars;
+ if Centered then ScrollToCenter(Bitmap.Width div 2, Bitmap.Height div 2)
+ else
+ begin
+ HScroll.Position := 0;
+ VScroll.Position := 0;
+ UpdateImage;
+ end;
+end;
+
+constructor TCustomImgView32.Create(AOwner: TComponent);
+begin
+ inherited;
+
+ HScroll := TCustomRangeBar.Create(Self);
+ VScroll := TCustomRangeBar.Create(Self);
+
+ with HScroll do
+ begin
+ HScroll.Parent := Self;
+ BorderStyle := bsNone;
+ Centered := True;
+ OnUserChange := ScrollHandler;
+ end;
+
+ with VScroll do
+ begin
+ Parent := Self;
+ BorderStyle := bsNone;
+ Centered := True;
+ Kind := sbVertical;
+ OnUserChange := ScrollHandler;
+ end;
+
+ FCentered := True;
+ ScaleMode := smScale;
+ BitmapAlign := baCustom;
+ with GetViewportRect do
+ begin
+ OldSzX := Right - Left;
+ OldSzY := Bottom - Top;
+ end;
+
+ FScrollBars := TIVScrollProperties.Create;
+ FScrollBars.ImgView := Self;
+ FScrollBars.Master := HScroll;
+ FScrollBars.Slave := VScroll;
+
+ AlignAll;
+end;
+
+destructor TCustomImgView32.Destroy;
+begin
+ FScrollBars.Free;
+ inherited;
+end;
+
+procedure TCustomImgView32.DoDrawSizeGrip(R: TRect);
+begin
+{$IFNDEF CLX}
+ if USE_THEMES then
+ begin
+ Canvas.Brush.Color := clBtnFace;
+ Canvas.FillRect(R);
+ DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, SBP_SIZEBOX, SZB_RIGHTALIGN, R, nil);
+ end
+ else
+ DrawFrameControl(Canvas.Handle, R, DFC_SCROLL, DFCS_SCROLLSIZEGRIP)
+{$ENDIF}
+end;
+
+procedure TCustomImgView32.DoScaleChange;
+begin
+ InvalidateCache;
+ UpdateScrollBars;
+ UpdateImage;
+ Invalidate;
+end;
+
+procedure TCustomImgView32.DoScroll;
+begin
+ if Assigned(FOnScroll) then FOnScroll(Self);
+end;
+
+function TCustomImgView32.GetScrollBarSize: Integer;
+{$IFDEF CLX}
+var
+ Size: TSize;
+{$ENDIF}
+begin
+ Result := FScrollBarSize;
+{$IFDEF CLX}
+ QStyle_scrollBarExtent(Application.Style.Handle, @Size);
+ if Result = 0 then Result := Size.cy;
+{$ELSE}
+ if Result = 0 then Result := GetSystemMetrics(SM_CYHSCROLL);
+{$ENDIF}
+end;
+
+function TCustomImgView32.GetSizeGripRect: TRect;
+var
+ Sz: Integer;
+begin
+ Sz := GetScrollBarSize;
+ Result := GetClientRect;
+ with Result do
+ begin
+ Left := Right - Sz;
+ Top := Bottom - Sz;
+ end;
+end;
+
+function TCustomImgView32.GetViewportRect: TRect;
+var
+ Sz: Integer;
+begin
+ Result := Rect(0, 0, Width, Height);
+ Sz := GetScrollBarSize;
+ Dec(Result.Right, Sz);
+ Dec(Result.Bottom, Sz);
+end;
+
+function TCustomImgView32.IsSizeGripVisible: Boolean;
+var
+ P: TWinControl;
+begin
+ case SizeGrip of
+ sgAuto:
+ begin
+ Result := False;
+ if Align <> alClient then Exit;
+ P := Parent;
+ while True do
+ begin
+ if P is TCustomForm then
+ begin
+ Result := True;
+ Break;
+ end
+ else if not Assigned(P) or (P.Align <> alClient) then Exit;
+ P := P.Parent;
+ end;
+ end;
+
+ sgNone: Result := False
+
+ else { sgAlways }
+ Result := True;
+ end;
+end;
+
+procedure TCustomImgView32.Loaded;
+begin
+ AlignAll;
+ Invalidate;
+ UpdateScrollBars;
+ if Centered then with Bitmap do ScrollToCenter(Width div 2, Height div 2);
+ inherited;
+end;
+
+procedure TCustomImgView32.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+{$IFNDEF CLX}
+var
+ Action: Cardinal;
+ Msg: TMessage;
+ P: TPoint;
+begin
+ if IsSizeGripVisible and (Owner is TCustomForm) then
+ begin
+ P.X := X; P.Y := Y;
+ if PtInRect(GetSizeGripRect, P) then
+ begin
+ Action := HTBOTTOMRIGHT;
+ Application.ProcessMessages;
+ Msg.Msg := WM_NCLBUTTONDOWN;
+ Msg.WParam := Action;
+ SetCaptureControl(nil);
+ with Msg do SendMessage(TCustomForm(Owner).Handle, Msg, wParam, lParam);
+ Exit;
+ end;
+ end;
+{$ELSE}
+begin
+{$ENDIF}
+ inherited;
+end;
+
+procedure TCustomImgView32.MouseMove(Shift: TShiftState; X, Y: Integer);
+var
+ P: TPoint;
+begin
+ inherited;
+ if IsSizeGripVisible then
+ begin
+ P.X := X; P.Y := Y;
+ if PtInRect(GetSizeGripRect, P) then Screen.Cursor := crSizeNWSE;
+ end;
+end;
+
+procedure TCustomImgView32.Paint;
+begin
+ if IsSizeGripVisible then
+ DoDrawSizeGrip(GetSizeGripRect)
+ else
+ begin
+ Canvas.Brush.Color := clBtnFace;
+ Canvas.FillRect(GetSizeGripRect);
+ end;
+ inherited;
+end;
+
+procedure TCustomImgView32.Resize;
+begin
+ AlignAll;
+ if IsSizeGripVisible then
+ DoDrawSizeGrip(GetSizeGripRect)
+ else
+ begin
+ Canvas.Brush.Color := clBtnFace;
+ Canvas.FillRect(GetSizeGripRect);
+ end;
+ InvalidateCache;
+ UpdateScrollBars;
+ UpdateImage;
+ Invalidate;
+ inherited;
+end;
+
+procedure TCustomImgView32.Scroll(Dx, Dy: Integer);
+begin
+ DisableScrollUpdate := True;
+ HScroll.Position := HScroll.Position + Dx;
+ VScroll.Position := VScroll.Position + Dy;
+ DisableScrollUpdate := False;
+ UpdateImage;
+end;
+
+procedure TCustomImgView32.ScrollHandler(Sender: TObject);
+begin
+ if DisableScrollUpdate then Exit;
+ if Sender = HScroll then HScroll.Repaint;
+ if Sender = VScroll then VScroll.Repaint;
+ UpdateImage;
+ DoScroll;
+ Repaint;
+end;
+
+procedure TCustomImgView32.ScrollToCenter(X, Y: Integer);
+var
+ ScaledDOversize: Integer;
+begin
+ DisableScrollUpdate := True;
+ AlignAll;
+
+ ScaledDOversize := Round(FOversize * Scale);
+ with GetViewportRect do
+ begin
+ HScroll.Position := X * Scale - (Right - Left) / 2 + ScaledDOversize;
+ VScroll.Position := Y * Scale - (Bottom - Top) / 2 + ScaledDOversize;
+ end;
+ DisableScrollUpdate := False;
+ UpdateImage;
+end;
+
+procedure TCustomImgView32.SetCentered(Value: Boolean);
+begin
+ InvalidateCache;
+ FCentered := Value;
+ HScroll.Centered := Value;
+ VScroll.Centered := Value;
+ UpdateScrollBars;
+ UpdateImage;
+ if Value then with Bitmap do ScrollToCenter(Width div 2, Height div 2)
+ else ScrollToCenter(0, 0);
+end;
+
+procedure TCustomImgView32.SetOverSize(const Value: Integer);
+begin
+ if Value <> FOverSize then
+ begin
+ FOverSize := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TCustomImgView32.SetScrollBars(Value: TIVScrollProperties);
+begin
+ FScrollBars.Assign(Value);
+end;
+
+procedure TCustomImgView32.SetSizeGrip(Value: TSizeGripStyle);
+begin
+ if Value <> FSizeGrip then
+ begin
+ FSizeGrip := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TCustomImgView32.UpdateImage;
+var
+ Sz: TSize;
+ W, H: Integer;
+ ScaledOversize: Integer;
+begin
+ Sz := GetBitmapSize;
+ ScaledOversize := Round(FOversize * Scale);
+
+ with GetViewportRect do
+ begin
+ W := Right - Left;
+ H := Bottom - Top;
+ end;
+ BeginUpdate;
+ if not Centered then
+ begin
+ OffsetHorz := -HScroll.Position + ScaledOversize;
+ OffsetVert := -VScroll.Position + ScaledOversize;
+ end
+ else
+ begin
+ if W > Sz.Cx + 2 * ScaledOversize then // Viewport is bigger than scaled Bitmap
+ OffsetHorz := (W - Sz.Cx) / 2
+ else
+ OffsetHorz := -HScroll.Position + ScaledOversize;
+
+ if H > Sz.Cy + 2 * ScaledOversize then // Viewport is bigger than scaled Bitmap
+ OffsetVert := (H - Sz.Cy) / 2
+ else
+ OffsetVert := -VScroll.Position + ScaledOversize;
+ end;
+ InvalidateCache;
+ EndUpdate;
+ Changed;
+end;
+
+procedure TCustomImgView32.UpdateScrollBars;
+var
+ Sz: TSize;
+ ScaledDOversize: Integer;
+begin
+ If Assigned(HScroll) and Assigned(VScroll) then
+ begin
+ Sz := GetBitmapSize;
+ ScaledDOversize := Round(2 * FOversize * Scale);
+
+ HScroll.Range := Sz.Cx + ScaledDOversize;
+ VScroll.Range := Sz.Cy + ScaledDOversize;
+ end;
+end;
+
+{ TBitmap32Item }
+
+constructor TBitmap32Item.Create(Collection: TCollection);
+begin
+ inherited;
+ FBitmap := TBitmap32.Create;
+end;
+
+destructor TBitmap32Item.Destroy;
+begin
+ FBitmap.Free;
+ inherited;
+end;
+
+procedure TBitmap32Item.SetBitmap(ABitmap: TBitmap32);
+begin
+ FBitmap.Assign(ABitmap)
+end;
+
+
+
+
+{ TBitmap32Collection }
+
+function TBitmap32Collection.Add: TBitmap32Item;
+begin
+ Result := TBitmap32Item(inherited Add);
+end;
+
+constructor TBitmap32Collection.Create(AOwner: TPersistent; ItemClass: TBitmap32ItemClass);
+begin
+ inherited Create(ItemClass);
+ FOwner := AOwner;
+end;
+
+function TBitmap32Collection.GetItem(Index: Integer): TBitmap32Item;
+begin
+ Result := TBitmap32Item(inherited GetItem(Index));
+end;
+
+function TBitmap32Collection.GetOwner: TPersistent;
+begin
+ Result := FOwner;
+end;
+
+procedure TBitmap32Collection.SetItem(Index: Integer; Value: TBitmap32Item);
+begin
+ inherited SetItem(Index, Value);
+end;
+
+
+
+
+{ TBitmap32List }
+
+constructor TBitmap32List.Create(AOwner: TComponent);
+begin
+ inherited;
+ FBitmap32Collection := TBitmap32Collection.Create(Self, TBitmap32Item);
+end;
+
+destructor TBitmap32List.Destroy;
+begin
+ FBitmap32Collection.Free;
+ inherited;
+end;
+
+function TBitmap32List.GetBitmap(Index: Integer): TBitmap32;
+begin
+ Result := FBitmap32Collection.Items[Index].Bitmap;
+end;
+
+procedure TBitmap32List.SetBitmap(Index: Integer; Value: TBitmap32);
+begin
+ FBitmap32Collection.Items[Index].Bitmap := Value;
+end;
+
+procedure TBitmap32List.SetBitmap32Collection(Value: TBitmap32Collection);
+begin
+ FBitmap32Collection := Value;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_Layers.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Layers.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Layers.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Layers.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Layers.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1169 @@
+unit GR32_Layers;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Layers.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$INCLUDE GR32.inc}
+
+uses
+{$IFDEF CLX}
+ Qt, Types, QControls, QGraphics, QForms,
+ {$IFDEF LINUX}Libc, {$ENDIF}
+ {$IFDEF MSWINDOWS}Windows, {$ENDIF}
+{$ELSE}
+ Windows, Controls, Graphics, Forms,
+{$ENDIF}
+ Classes, SysUtils, GR32;
+
+const
+ { Layer Options Bits }
+ LOB_VISIBLE = $80000000; // 31-st bit
+ LOB_GDI_OVERLAY = $40000000; // 30-th bit
+ LOB_MOUSE_EVENTS = $20000000; // 29-th bit
+ LOB_NO_UPDATE = $10000000; // 28-th bit
+ LOB_NO_CAPTURE = $08000000; // 27-th bit
+ LOB_RESERVED_26 = $04000000; // 26-th bit
+ LOB_RESERVED_25 = $02000000; // 25-th bit
+ LOB_RESERVED_24 = $01000000; // 24-th bit
+ LOB_RESERVED_MASK = $FF000000;
+
+type
+ TCustomLayer = class;
+ TPositionedLayer = class;
+ TLayerClass = class of TCustomLayer;
+
+ { TCoordXForm - transformations from bitmap image to buffer origin }
+ TCoordXForm = record
+ ScaleX: TFixed; // bitmap image to buf
+ ScaleY: TFixed;
+ ShiftX: Integer;
+ ShiftY: Integer;
+ RevScaleX: TFixed;
+ RevScaleY: TFixed;
+ end;
+ PCoordXForm = ^TCoordXForm;
+
+ TLayerCollection = class(TPersistent)
+ private
+ FCoordXForm: PCoordXForm;
+ FItems: TList;
+ FMouseEvents: Boolean;
+ FMouseListener: TCustomLayer;
+ FUpdateCount: Integer;
+ FOwner: TComponent;
+ FOnChanging: TNotifyEvent;
+ FOnChange: TNotifyEvent;
+ FOnGDIUpdate: TNotifyEvent;
+ function GetCount: Integer;
+ procedure InsertItem(Item: TCustomLayer);
+ procedure RemoveItem(Item: TCustomLayer);
+ procedure SetMouseEvents(Value: Boolean);
+ procedure SetMouseListener(Value: TCustomLayer);
+ protected
+ procedure BeginUpdate;
+ procedure Changed;
+ procedure Changing;
+ procedure EndUpdate;
+ function FindLayerAtPos(X, Y: Integer; OptionsMask: Cardinal): TCustomLayer;
+ function GetItem(Index: Integer): TCustomLayer;
+ function GetOwner: TPersistent; override;
+ procedure GDIUpdate;
+ procedure SetItem(Index: Integer; Value: TCustomLayer);
+ function MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
+ function MouseMove(Shift: TShiftState; X, Y: Integer): TCustomLayer;
+ function MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
+ property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
+ property OnChange: TNotifyEvent read FOnChange write FOnChange;
+ property OnGDIUpdate: TNotifyEvent read FOnGDIUpdate write FOnGDIUpdate;
+ public
+ constructor Create(AOwner: TComponent);
+ destructor Destroy; override;
+ function Add(ItemClass: TLayerClass): TCustomLayer;
+ procedure Assign(Source: TPersistent); override;
+ procedure Clear;
+ procedure Delete(Index: Integer);
+ function Insert(Index: Integer; ItemClass: TLayerClass): TCustomLayer;
+ property Count: Integer read GetCount;
+ property CoordXForm: PCoordXForm read FCoordXForm write FCoordXForm;
+ property Items[Index: Integer]: TCustomLayer read GetItem write SetItem; default;
+ property MouseListener: TCustomLayer read FMouseListener write SetMouseListener;
+ property MouseEvents: Boolean read FMouseEvents write SetMouseEvents;
+ end;
+
+ TLayerState = (lsMouseLeft, lsMouseRight, lsMouseMiddle);
+ TLayerStates = set of TLayerState;
+
+ TPaintLayerEvent = procedure(Sender: TObject; Buffer: TBitmap32) of object;
+ THitTestEvent = procedure(Sender: TObject; X, Y: Integer; var Passed: Boolean) of object;
+
+ TCustomLayer = class(TPersistent)
+ private
+ FCursor: TCursor;
+ FFreeNotifies: TList;
+ FLayerCollection: TLayerCollection;
+ FLayerStates: TLayerStates;
+ FLayerOptions: Cardinal;
+ FOnHitTest: THitTestEvent;
+ FOnMouseDown: TMouseEvent;
+ FOnMouseMove: TMouseMoveEvent;
+ FOnMouseUp: TMouseEvent;
+ FOnPaint: TPaintLayerEvent;
+ FTag: Integer;
+ FOnDestroy: TNotifyEvent;
+ function GetIndex: Integer;
+ function GetMouseEvents: Boolean;
+ function GetVisible: Boolean;
+ procedure SetCursor(Value: TCursor);
+ procedure SetLayerCollection(Value: TLayerCollection);
+ procedure SetLayerOptions(Value: Cardinal);
+ procedure SetMouseEvents(Value: Boolean);
+ procedure SetVisible(Value: Boolean);
+ protected
+ procedure AddNotification(ALayer: TCustomLayer);
+ procedure Changed;
+ procedure Changing;
+ function DoHitTest(X, Y: Integer): Boolean; virtual;
+ procedure DoPaint(Buffer: TBitmap32);
+ function GetOwner: TPersistent; override;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); virtual;
+ procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure Notification(ALayer: TCustomLayer); virtual;
+ procedure Paint(Buffer: TBitmap32); virtual;
+ procedure PaintGDI(Canvas: TCanvas); virtual;
+ procedure RemoveNotification(ALayer: TCustomLayer);
+ procedure SetIndex(Value: Integer); virtual;
+ public
+ constructor Create(ALayerCollection: TLayerCollection); virtual;
+ destructor Destroy; override;
+ procedure BeforeDestruction; override;
+ procedure BringToFront;
+ function HitTest(X, Y: Integer): Boolean;
+ procedure SendToBack;
+ procedure SetAsMouseListener;
+ property Cursor: TCursor read FCursor write SetCursor;
+ property Index: Integer read GetIndex write SetIndex;
+ property LayerCollection: TLayerCollection read FLayerCollection write SetLayerCollection;
+ property LayerOptions: Cardinal read FLayerOptions write SetLayerOptions;
+ property LayerStates: TLayerStates read FLayerStates;
+ property MouseEvents: Boolean read GetMouseEvents write SetMouseEvents;
+ property Tag: Integer read FTag write FTag;
+ property Visible: Boolean read GetVisible write SetVisible;
+ property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
+ property OnHitTest: THitTestEvent read FOnHitTest write FOnHitTest;
+ property OnPaint: TPaintLayerEvent read FOnPaint write FOnPaint;
+ property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
+ property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
+ property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
+ end;
+
+ TPositionedLayer = class(TCustomLayer)
+ private
+ FLocation: TFloatRect;
+ FScaled: Boolean;
+ procedure SetLocation(const Value: TFloatRect);
+ procedure SetScaled(Value: Boolean);
+ protected
+ function DoHitTest(X, Y: Integer): Boolean; override;
+ procedure DoSetLocation(const NewLocation: TFloatRect); virtual;
+ public
+ constructor Create(ALayerCollection: TLayerCollection); override;
+ function GetAdjustedLocation: TFloatRect;
+ property Location: TFloatRect read FLocation write SetLocation;
+ property Scaled: Boolean read FScaled write SetScaled;
+ end;
+
+ TBitmapLayer = class(TPositionedLayer)
+ private
+ FBitmap: TBitmap32;
+ FAlphaHit: Boolean;
+ FCropped: Boolean;
+ procedure BitmapChanged(Sender: TObject);
+ procedure SetBitmap(Value: TBitmap32);
+ procedure SetCropped(Value: Boolean);
+ protected
+ function DoHitTest(X, Y: Integer): Boolean; override;
+ procedure Paint(Buffer: TBitmap32); override;
+ public
+ constructor Create(ALayerCollection: TLayerCollection); override;
+ destructor Destroy; override;
+ property AlphaHit: Boolean read FAlphaHit write FAlphaHit;
+ property Bitmap: TBitmap32 read FBitmap write SetBitmap;
+ property Cropped: Boolean read FCropped write SetCropped;
+ end;
+
+ TDragState = (dsNone, dsMove, dsSizeL, dsSizeT, dsSizeR, dsSizeB,
+ dsSizeTL, dsSizeTR, dsSizeBL, dsSizeBR);
+ TRBHandles = set of (rhCenter, rhSides, rhCorners, rhFrame);
+ TRBResizingEvent = procedure(
+ Sender: TObject;
+ const OldLocation: TFloatRect;
+ var NewLocation: TFloatRect;
+ DragState: TDragState;
+ Shift: TShiftState) of object;
+
+ TRubberbandLayer = class(TPositionedLayer)
+ private
+ FChildLayer: TPositionedLayer;
+ FHandleFrame: TColor;
+ FHandleFill: TColor;
+ FHandles: TRBHandles;
+ FHandleSize: Integer;
+ FMinWidth: Single;
+ FMaxHeight: Single;
+ FMinHeight: Single;
+ FMaxWidth: Single;
+ FOnUserChange: TNotifyEvent;
+ FOnResizing: TRBResizingEvent;
+ procedure SetChildLayer(Value: TPositionedLayer);
+ procedure SetHandleFill(Value: TColor);
+ procedure SetHandleFrame(Value: TColor);
+ procedure SetHandles(Value: TRBHandles);
+ procedure SetHandleSize(Value: Integer);
+ protected
+ IsDragging: Boolean;
+ DragState: TDragState;
+ OldLocation: TFloatRect;
+ MouseShift: TFloatPoint;
+ function DoHitTest(X, Y: Integer): Boolean; override;
+ procedure DoResizing(var OldLocation, NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState); virtual;
+ procedure DoSetLocation(const NewLocation: TFloatRect); override;
+ function GetDragState(X, Y: Integer): TDragState; virtual;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
+ procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
+ procedure Notification(ALayer: TCustomLayer); override;
+ procedure Paint(Buffer: TBitmap32); override;
+ procedure UpdateChildLayer;
+ public
+ constructor Create(ALayerCollection: TLayerCollection); override;
+ property ChildLayer: TPositionedLayer read FChildLayer write SetChildLayer;
+ property Handles: TRBHandles read FHandles write SetHandles;
+ property HandleSize: Integer read FHandleSize write SetHandleSize;
+ property HandleFill: TColor read FHandleFill write SetHandleFill;
+ property HandleFrame: TColor read FHandleFrame write SetHandleFrame;
+ property MaxHeight: Single read FMaxHeight write FMaxHeight;
+ property MaxWidth: Single read FMaxWidth write FMaxWidth;
+ property MinHeight: Single read FMinHeight write FMinHeight;
+ property MinWidth: Single read FMinWidth write FMinWidth;
+ property OnUserChange: TNotifyEvent read FOnUserChange write FOnUserChange;
+ property OnResizing: TRBResizingEvent read FOnResizing write FOnResizing;
+ end;
+
+implementation
+
+uses TypInfo, GR32_Image, GR32_LowLevel, GR32_Transforms;
+
+{ mouse state mapping }
+const
+ CStateMap: array [TMouseButton] of TLayerState =
+ (lsMouseLeft, lsMouseRight, lsMouseMiddle);
+
+type
+ TImage32Access = class(TCustomImage32);
+
+{ TLayerCollection }
+
+function TLayerCollection.Add(ItemClass: TLayerClass): TCustomLayer;
+begin
+ Result := ItemClass.Create(Self);
+end;
+
+procedure TLayerCollection.Assign(Source: TPersistent);
+var
+ I: Integer;
+ Item: TCustomLayer;
+begin
+ if Source is TLayerCollection then
+ begin
+ BeginUpdate;
+ try
+ while FItems.Count > 0 do TCustomLayer(FItems.Last).Free;
+ for I := 0 to TLayerCollection(Source).Count - 1 do
+ begin
+ Item := TLayerCollection(Source).Items[I];
+ Add(TLayerClass(Item.ClassType)).Assign(Item);
+ end;
+ finally
+ EndUpdate;
+ end;
+ Exit;
+ end;
+ inherited Assign(Source);
+end;
+
+procedure TLayerCollection.BeginUpdate;
+begin
+ if FUpdateCount = 0 then Changing;
+ Inc(FUpdateCount);
+end;
+
+procedure TLayerCollection.Changed;
+begin
+ if Assigned(FOnChange) then FOnChange(Self);
+end;
+
+procedure TLayerCollection.Changing;
+begin
+ if Assigned(FOnChanging) then FOnChanging(Self);
+end;
+
+procedure TLayerCollection.Clear;
+begin
+ BeginUpdate;
+ try
+ while FItems.Count > 0 do TCustomLayer(FItems.Last).Free;
+ finally
+ EndUpdate;
+ end;
+end;
+
+constructor TLayerCollection.Create(AOwner: TComponent);
+begin
+ FOwner := AOwner;
+ FItems := TList.Create;
+ FMouseEvents := True;
+end;
+
+procedure TLayerCollection.Delete(Index: Integer);
+begin
+ TCollectionItem(FItems[Index]).Free;
+end;
+
+destructor TLayerCollection.Destroy;
+begin
+ FUpdateCount := 1; // disable update notification
+ if FItems <> nil then Clear;
+ FItems.Free;
+ inherited;
+end;
+
+procedure TLayerCollection.EndUpdate;
+begin
+ Dec(FUpdateCount);
+ if FUpdateCount = 0 then Changed;
+ Assert(FUpdateCount >= 0, 'Unpaired EndUpdate');
+end;
+
+function TLayerCollection.FindLayerAtPos(X, Y: Integer; OptionsMask: Cardinal): TCustomLayer;
+var
+ I: Integer;
+begin
+ for I := Count - 1 downto 0 do
+ begin
+ Result := Items[I];
+ if (Result.LayerOptions and OptionsMask) = 0 then Continue; // skip to the next one
+ if Result.HitTest(X, Y) then Exit;
+ end;
+ Result := nil;
+end;
+
+procedure TLayerCollection.GDIUpdate;
+begin
+ if (FUpdateCount = 0) and Assigned(FOnGDIUpdate) then FOnGDIUpdate(Self);
+end;
+
+function TLayerCollection.GetCount: Integer;
+begin
+ Result := FItems.Count;
+end;
+
+function TLayerCollection.GetItem(Index: Integer): TCustomLayer;
+begin
+ Result := FItems[Index];
+end;
+
+function TLayerCollection.GetOwner: TPersistent;
+begin
+ Result := FOwner;
+end;
+
+function TLayerCollection.Insert(Index: Integer; ItemClass: TLayerClass): TCustomLayer;
+begin
+ BeginUpdate;
+ try
+ Result := Add(ItemClass);
+ Result.Index := Index;
+ finally
+ EndUpdate;
+ end;
+end;
+
+procedure TLayerCollection.InsertItem(Item: TCustomLayer);
+begin
+ BeginUpdate;
+ try
+ FItems.Add(Item);
+ Item.FLayerCollection := Self;
+ finally
+ EndUpdate;
+ end;
+end;
+
+function TLayerCollection.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
+begin
+ if MouseListener <> nil then Result := MouseListener
+ else Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
+
+ if (Button = mbLeft) and (Result <> MouseListener) and
+ ((Result = nil) or ((Result.FLayerOptions and LOB_NO_CAPTURE) = 0)) then
+ MouseListener := Result; // capture the mouse
+
+ if Assigned(MouseListener) then
+ begin
+ Include(MouseListener.FLayerStates, CStateMap[Button]);
+ MouseListener.MouseDown(Button, Shift, X, Y);
+ end;
+end;
+
+function TLayerCollection.MouseMove(Shift: TShiftState; X, Y: Integer): TCustomLayer;
+begin
+ Result := MouseListener;
+ if Result = nil then Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
+ if Assigned(Result) then Result.MouseMove(Shift, X, Y)
+ else if FOwner is TControl then Screen.Cursor := TControl(FOwner).Cursor;
+end;
+
+function TLayerCollection.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): TCustomLayer;
+begin
+ Result := MouseListener;
+ if Result = nil then Result := FindLayerAtPos(X, Y, LOB_MOUSE_EVENTS);
+
+ if Assigned(Result) then
+ begin
+ Exclude(Result.FLayerStates, CStateMap[Button]);
+ Result.MouseUp(Button, Shift, X, Y);
+ end;
+
+ if Assigned(MouseListener) and
+ (MouseListener.FLayerStates *
+ [lsMouseLeft, lsMouseRight, lsMouseMiddle] = []) then
+ MouseListener := nil; // reset mouse capture
+end;
+
+procedure TLayerCollection.RemoveItem(Item: TCustomLayer);
+begin
+ BeginUpdate;
+ try
+ FItems.Remove(Item);
+ Item.FLayerCollection := nil;
+ finally
+ EndUpdate;
+ end;
+end;
+
+procedure TLayerCollection.SetItem(Index: Integer; Value: TCustomLayer);
+begin
+ TCollectionItem(FItems[Index]).Assign(Value);
+end;
+
+procedure TLayerCollection.SetMouseEvents(Value: Boolean);
+begin
+ FMouseEvents := Value;
+ MouseListener := nil;
+end;
+
+procedure TLayerCollection.SetMouseListener(Value: TCustomLayer);
+begin
+ if Value <> FMouseListener then
+ begin
+ if FMouseListener <> nil then
+ FMouseListener.FLayerStates := FMouseListener.FLayerStates -
+ [lsMouseLeft, lsMouseRight, lsMouseMiddle];
+ FMouseListener := Value;
+ end;
+end;
+
+{ TCustomLayer }
+
+procedure TCustomLayer.AddNotification(ALayer: TCustomLayer);
+begin
+ if not Assigned(FFreeNotifies) then FFreeNotifies := TList.Create;
+ if FFreeNotifies.IndexOf(ALayer) < 0 then FFreeNotifies.Add(ALayer);
+end;
+
+procedure TCustomLayer.BeforeDestruction;
+begin
+ if Assigned(FOnDestroy) then FOnDestroy(Self);
+ inherited;
+end;
+
+procedure TCustomLayer.BringToFront;
+begin
+ Index := LayerCollection.Count;
+end;
+
+procedure TCustomLayer.Changed;
+begin
+ if (FLayerCollection <> nil) and ((FLayerOptions and LOB_NO_UPDATE) = 0) then
+ begin
+ if Visible then FLayerCollection.Changed
+ else if (FLayerOptions and LOB_GDI_OVERLAY) <> 0 then
+ FLayerCollection.GDIUpdate;
+ end;
+end;
+
+procedure TCustomLayer.Changing;
+begin
+ if Visible and (FLayerCollection <> nil) and
+ ((FLayerOptions and LOB_NO_UPDATE) = 0) then
+ FLayerCollection.Changing;
+end;
+
+constructor TCustomLayer.Create(ALayerCollection: TLayerCollection);
+begin
+ LayerCollection := ALayerCollection;
+ FLayerOptions := LOB_VISIBLE;
+end;
+
+destructor TCustomLayer.Destroy;
+var
+ I: Integer;
+begin
+ if FFreeNotifies <> nil then
+ begin
+ for I := FFreeNotifies.Count - 1 downto 0 do
+ begin
+ TCustomLayer(FFreeNotifies[I]).Notification(Self);
+ if FFreeNotifies = nil then Break;
+ end;
+ FFreeNotifies.Free;
+ FFreeNotifies := nil;
+ end;
+ SetLayerCollection(nil);
+ inherited;
+end;
+
+function TCustomLayer.DoHitTest(X, Y: Integer): Boolean;
+begin
+ Result := True;
+end;
+
+procedure TCustomLayer.DoPaint(Buffer: TBitmap32);
+begin
+ Paint(Buffer);
+ if Assigned(FOnPaint) then FOnPaint(Self, Buffer);
+end;
+
+function TCustomLayer.GetIndex: Integer;
+begin
+ if FLayerCollection <> nil then Result := FLayerCollection.FItems.IndexOf(Self)
+ else Result := -1;
+end;
+
+function TCustomLayer.GetMouseEvents: Boolean;
+begin
+ Result := FLayerOptions and LOB_MOUSE_EVENTS <> 0;
+end;
+
+function TCustomLayer.GetOwner: TPersistent;
+begin
+ Result := FLayerCollection;
+end;
+
+function TCustomLayer.GetVisible: Boolean;
+begin
+ Result := FLayerOptions and LOB_VISIBLE <> 0;
+end;
+
+function TCustomLayer.HitTest(X, Y: Integer): Boolean;
+begin
+ Result := DoHitTest(X, Y);
+ if Assigned(FOnHitTest) then FOnHitTest(Self, X, Y, Result);
+end;
+
+procedure TCustomLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y);
+end;
+
+procedure TCustomLayer.MouseMove(Shift: TShiftState; X, Y: Integer);
+begin
+ Screen.Cursor := Cursor;
+ if Assigned(FOnMouseMove) then FOnMouseMove(Self, Shift, X, Y);
+end;
+
+procedure TCustomLayer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ Screen.Cursor := crDefault;
+ if Assigned(FOnMouseUp) then FOnMouseUp(Self, Button, Shift, X, Y);
+end;
+
+procedure TCustomLayer.Notification(ALayer: TCustomLayer);
+begin
+ // do nothing by default
+end;
+
+procedure TCustomLayer.Paint(Buffer: TBitmap32);
+begin
+ // descendants override this method
+end;
+
+procedure TCustomLayer.PaintGDI(Canvas: TCanvas);
+begin
+ // descendants override this method
+end;
+
+procedure TCustomLayer.RemoveNotification(ALayer: TCustomLayer);
+begin
+ if FFreeNotifies <> nil then
+ begin
+ FFreeNotifies.Remove(ALayer);
+ if FFreeNotifies.Count = 0 then
+ begin
+ FFreeNotifies.Free;
+ FFreeNotifies := nil;
+ end;
+ end;
+end;
+
+procedure TCustomLayer.SendToBack;
+begin
+ Index := 0;
+end;
+
+procedure TCustomLayer.SetAsMouseListener;
+begin
+ FLayerCollection.MouseListener := Self;
+ Screen.Cursor := Cursor;
+end;
+
+procedure TCustomLayer.SetCursor(Value: TCursor);
+begin
+ if Value <> FCursor then
+ begin
+ FCursor := Value;
+ if FLayerCollection.MouseListener = Self then Screen.Cursor := Value;
+ end;
+end;
+
+procedure TCustomLayer.SetIndex(Value: Integer);
+var
+ CurIndex: Integer;
+begin
+ CurIndex := GetIndex;
+ if (CurIndex >= 0) and (CurIndex <> Value) then
+ with FLayerCollection do
+ begin
+ if Value < 0 then Value := 0;
+ if Value >= Count then Value := Count - 1;
+ if Value <> CurIndex then
+ begin
+ if Visible then BeginUpdate;
+ try
+ FLayerCollection.FItems.Move(CurIndex, Value);
+ finally
+ if Visible then EndUpdate;
+ end;
+ end;
+ end;
+end;
+
+procedure TCustomLayer.SetLayerCollection(Value: TLayerCollection);
+begin
+ if FLayerCollection <> Value then
+ begin
+ if FLayerCollection <> nil then
+ begin
+ if FLayerCollection.MouseListener = Self then
+ FLayerCollection.MouseListener := nil;
+ FLayerCollection.RemoveItem(Self);
+ end;
+ if Value <> nil then Value.InsertItem(Self);
+ end;
+end;
+
+procedure TCustomLayer.SetLayerOptions(Value: Cardinal);
+begin
+ Changing;
+ FLayerOptions := Value;
+ Changed;
+end;
+
+procedure TCustomLayer.SetMouseEvents(Value: Boolean);
+begin
+ if Value then LayerOptions := LayerOptions or LOB_MOUSE_EVENTS
+ else LayerOptions := LayerOptions and not LOB_MOUSE_EVENTS;
+end;
+
+procedure TCustomLayer.SetVisible(Value: Boolean);
+begin
+ if Value then LayerOptions := LayerOptions or LOB_VISIBLE
+ else LayerOptions := LayerOptions and not LOB_VISIBLE;
+end;
+
+{ TPositionedLayer }
+
+constructor TPositionedLayer.Create(ALayerCollection: TLayerCollection);
+begin
+ inherited;
+ with FLocation do
+ begin
+ Left := 0;
+ Top := 0;
+ Right := 64;
+ Bottom := 64;
+ end;
+ FLayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS;
+end;
+
+function TPositionedLayer.DoHitTest(X, Y: Integer): Boolean;
+begin
+ with GetAdjustedLocation do
+ Result := (X >= Left) and (X < Right) and (Y >= Top) and (Y < Bottom);
+end;
+
+procedure TPositionedLayer.DoSetLocation(const NewLocation: TFloatRect);
+begin
+ FLocation := NewLocation;
+end;
+
+function TPositionedLayer.GetAdjustedLocation: TFloatRect;
+
+ procedure AdjustPoint(var APoint: TFloatPoint);
+ begin
+ with APoint, FLayerCollection.CoordXForm^ do
+ begin
+ X := X * ScaleX / 65536 + ShiftX;
+ Y := Y * ScaleY / 65536 + ShiftY;
+ end;
+ end;
+
+begin
+ Result := FLocation;
+ if Scaled and Assigned(FLayerCollection) and Assigned(FLayerCollection.CoordXForm) then
+ with Result do
+ begin
+ AdjustPoint(TopLeft);
+ AdjustPoint(BottomRight);
+ end;
+end;
+
+procedure TPositionedLayer.SetLocation(const Value: TFloatRect);
+begin
+ Changing;
+ DoSetLocation(Value);
+ Changed;
+end;
+
+procedure TPositionedLayer.SetScaled(Value: Boolean);
+begin
+ if Value <> FScaled then
+ begin
+ Changing;
+ FScaled := Value;
+ Changed;
+ end;
+end;
+
+{ TBitmapLayer }
+
+procedure TBitmapLayer.BitmapChanged(Sender: TObject);
+begin
+ Changed;
+end;
+
+constructor TBitmapLayer.Create(ALayerCollection: TLayerCollection);
+begin
+ inherited;
+ FBitmap := TBitmap32.Create;
+ FBitmap.OnChange := BitmapChanged;
+end;
+
+function TBitmapLayer.DoHitTest(X, Y: Integer): Boolean;
+var
+ BitmapX, BitmapY: Integer;
+ LayerWidth, LayerHeight: Integer;
+begin
+ Result := inherited DoHitTest(X, Y);
+ if Result and AlphaHit then
+ begin
+ with GetAdjustedLocation do
+ begin
+ LayerWidth := Round(Right - Left);
+ LayerHeight := Round(Bottom - Top);
+ if (LayerWidth < 0.5) or (LayerHeight < 0.5) then Result := False
+ else
+ begin
+ // check the pixel alpha at (X, Y) position
+ BitmapX := Round((X - Left) * Bitmap.Width / LayerWidth);
+ BitmapY := Round((Y - Top) * Bitmap.Height / LayerHeight);
+ if Bitmap.PixelS[BitmapX, BitmapY] and $FF000000 = 0 then Result := False;
+ end;
+ end;
+ end;
+end;
+
+destructor TBitmapLayer.Destroy;
+begin
+ FBitmap.Free;
+ inherited;
+end;
+
+procedure TBitmapLayer.Paint(Buffer: TBitmap32);
+var
+ SrcRect, DstRect, ClipRect: TRect;
+ ImageRect: TRect;
+ LayerWidth, LayerHeight: Single;
+begin
+ if Bitmap.Empty then Exit;
+ DstRect := MakeRect(GetAdjustedLocation);
+ SrcRect := MakeRect(0, 0, Bitmap.Width, Bitmap.Height);
+ ClipRect := MakeRect(0, 0, Buffer.Width, Buffer.Height);
+ if Cropped and (LayerCollection.FOwner is TCustomImage32) and
+ not (TImage32Access(LayerCollection.FOwner).PaintToMode) then
+ begin
+ with DstRect do
+ begin
+ LayerWidth := Right - Left;
+ LayerHeight := Bottom - Top;
+ end;
+ if (LayerWidth < 0.5) or (LayerHeight < 0.5) then Exit;
+ ImageRect := TCustomImage32(LayerCollection.FOwner).GetBitmapRect;
+ IntersectRect(ClipRect, ClipRect, ImageRect);
+ end;
+ StretchTransfer(Buffer, DstRect, ClipRect, FBitmap, SrcRect, FBitmap.StretchFilter, FBitmap.DrawMode, FBitmap.OnPixelCombine);
+// FBitmap.DrawTo(Buffer, DstRect, SrcRect);
+end;
+{var
+ SrcRect, DstRect, CroppedDst: TRect;
+ ImageRect: TRect;
+ LayerWidth, LayerHeight: Single;
+begin
+ DstRect := MakeRect(GetAdjustedLocation);
+ SrcRect := MakeRect(0, 0, Bitmap.Width, Bitmap.Height);
+ if Cropped and (LayerCollection.FOwner is TCustomImage32) and
+ not (TImage32Access(LayerCollection.FOwner).PaintToMode) then
+ begin
+ with DstRect do
+ begin
+ LayerWidth := Right - Left;
+ LayerHeight := Bottom - Top;
+ end;
+ if (LayerWidth < 0.5) or (LayerHeight < 0.5) then Exit;
+ ImageRect := TCustomImage32(LayerCollection.FOwner).GetBitmapRect;
+ IntersectRect(CroppedDst, DstRect, ImageRect);
+ SrcRect.Left := Round((CroppedDst.Left - DstRect.Left) * Bitmap.Width / LayerWidth);
+ SrcRect.Right := Round((CroppedDst.Right - DstRect.Left) * Bitmap.Width / LayerWidth);
+ SrcRect.Top := Round((CroppedDst.Top - DstRect.Top) * Bitmap.Height / LayerHeight);
+ SrcRect.Bottom := Round((CroppedDst.Bottom - DstRect.Top) * Bitmap.Height / LayerHeight);
+ DstRect := CroppedDst;
+ end;
+ FBitmap.DrawTo(Buffer, DstRect, SrcRect);
+end; }
+
+procedure TBitmapLayer.SetBitmap(Value: TBitmap32);
+begin
+ FBitmap.Assign(Value);
+end;
+
+procedure TBitmapLayer.SetCropped(Value: Boolean);
+begin
+ if Value <> FCropped then
+ begin
+ FCropped := Value;
+ Changed;
+ end;
+end;
+
+{ TRubberbandLayer }
+
+constructor TRubberbandLayer.Create(ALayerCollection: TLayerCollection);
+begin
+ inherited;
+ FHandleFrame := clBlack;
+ FHandleFill := clWhite;
+ FHandles := [rhCenter, rhSides, rhCorners, rhFrame];
+ FHandleSize := 3;
+ FMinWidth := 10;
+ FMinHeight := 10;
+ FLayerOptions := LOB_VISIBLE or LOB_MOUSE_EVENTS;
+end;
+
+function TRubberbandLayer.DoHitTest(X, Y: Integer): Boolean;
+begin
+ Result := GetDragState(X, Y) <> dsNone;
+end;
+
+procedure TRubberbandLayer.DoResizing(var OldLocation,
+ NewLocation: TFloatRect; DragState: TDragState; Shift: TShiftState);
+begin
+ if Assigned(FOnResizing) then
+ FOnResizing(Self, OldLocation, NewLocation, DragState, Shift);
+end;
+
+procedure TRubberbandLayer.DoSetLocation(const NewLocation: TFloatRect);
+begin
+ inherited;
+ UpdateChildLayer;
+end;
+
+function TRubberbandLayer.GetDragState(X, Y: Integer): TDragState;
+var
+ R: TRect;
+ dh_center, dh_sides, dh_corners: Boolean;
+ dl, dt, dr, db, dx, dy: Boolean;
+ Sz: Integer;
+begin
+ Result := dsNone;
+ Sz := FHandleSize + 1;
+ dh_center := rhCenter in FHandles;
+ dh_sides := rhSides in FHandles;
+ dh_corners := rhCorners in FHandles;
+ R := MakeRect(GetAdjustedLocation);
+ with R do
+ begin
+ Dec(Right);
+ Dec(Bottom);
+ dl := Abs(Left - X) <= Sz;
+ dr := Abs(Right - X) <= Sz;
+ dx := Abs((Left + Right) div 2 - X) <= Sz;
+ dt := Abs(Top - Y) <= Sz;
+ db := Abs(Bottom - Y) <= Sz;
+ dy := Abs((Top + Bottom) div 2 - Y) <= Sz;
+ end;
+
+ if dr and db and dh_corners then Result := dsSizeBR
+ else if dl and db and dh_corners then Result := dsSizeBL
+ else if dr and dt and dh_corners then Result := dsSizeTR
+ else if dl and dt and dh_corners then Result := dsSizeTL
+ else if dr and dy and dh_sides then Result := dsSizeR
+ else if db and dx and dh_sides then Result := dsSizeB
+ else if dl and dy and dh_sides then Result := dsSizeL
+ else if dt and dx and dh_sides then Result := dsSizeT
+ else if dh_center and PtInRect(R, Point(X, Y)) then Result := dsMove;
+end;
+
+procedure TRubberbandLayer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+var
+ ALoc: TFloatRect;
+begin
+ if IsDragging then Exit;
+ DragState := GetDragState(X, Y);
+ IsDragging := DragState <> dsNone;
+ if IsDragging then
+ begin
+ OldLocation := Location;
+ ALoc := GetAdjustedLocation;
+ case DragState of
+ dsMove: MouseShift := FloatPoint(X - ALoc.Left, Y - ALoc.Top);
+ else
+ MouseShift := FloatPoint(0, 0);
+ end;
+ end;
+ inherited;
+end;
+
+procedure TRubberbandLayer.MouseMove(Shift: TShiftState; X, Y: Integer);
+const
+ CURSOR_ID: array [TDragState] of TCursor = (crDefault, crDefault, crSizeWE,
+ crSizeNS, crSizeWE, crSizeNS, crSizeNWSE, crSizeNESW, crSizeNESW, crSizeNWSE);
+var
+ Mx, My: Single;
+ L, T, R, B, W, H: Single;
+ ALoc, NewLocation: TFloatRect;
+
+ procedure IncLT(var LT, RB: Single; Delta, MinSize, MaxSize: Single);
+ begin
+ LT := LT + Delta;
+ if RB - LT < MinSize then LT := RB - MinSize;
+ if MaxSize >= MinSize then if RB - LT > MaxSize then LT := RB - MaxSize;
+ end;
+
+ procedure IncRB(var LT, RB: Single; Delta, MinSize, MaxSize: Single);
+ begin
+ RB := RB + Delta;
+ if RB - LT < MinSize then RB := LT + MinSize;
+ if MaxSize >= MinSize then if RB - LT > MaxSize then RB := LT + MaxSize;
+ end;
+
+begin
+ if not IsDragging then
+ begin
+ DragState := GetDragState(X, Y);
+ if DragState = dsMove then Screen.Cursor := Cursor
+ else Screen.Cursor := CURSOR_ID[DragState];
+ end
+ else
+ begin
+ Mx := X - MouseShift.X;
+ My := Y - MouseShift.Y;
+ if Scaled then with Location do
+ begin
+ ALoc := GetAdjustedLocation;
+ if IsRectEmptyF(ALoc) then Exit;
+ Mx := (Mx - ALoc.Left) / (ALoc.Right - ALoc.Left) * (Right - Left) + Left;
+ My := (My - ALoc.Top) / (ALoc.Bottom - ALoc.Top) * (Bottom - Top) + Top;
+ end;
+
+ with OldLocation do
+ begin
+ L := Left; T := Top; R := Right; B := Bottom; W := R - L; H := B - T;
+ end;
+
+ if DragState = dsMove then
+ begin
+ L := Mx; T := My; R := L + W; B := T + H;
+ end
+ else
+ begin
+ if DragState in [dsSizeL, dsSizeTL, dsSizeBL] then
+ IncLT(L, R, Mx - L, MinWidth, MaxWidth);
+ if DragState in [dsSizeR, dsSizeTR, dsSizeBR] then
+ IncRB(L, R, Mx - R, MinWidth, MaxWidth);
+ if DragState in [dsSizeT, dsSizeTL, dsSizeTR] then
+ IncLT(T, B, My - T, MinHeight, MaxHeight);
+ if DragState in [dsSizeB, dsSizeBL, dsSizeBR] then
+ IncRB(T, B, My - B, MinHeight, MaxHeight);
+ end;
+
+ NewLocation := FloatRect(L, T, R, B);
+ DoResizing(OldLocation, NewLocation, DragState, Shift);
+
+ if (NewLocation.Left <> Location.Left) or
+ (NewLocation.Right <> Location.Right) or
+ (NewLocation.Top <> Location.Top) or
+ (NewLocation.Bottom <> Location.Bottom) then
+ begin
+ Location := NewLocation;
+ if Assigned(FOnUserChange) then FOnUserChange(Self);
+ end;
+ end;
+end;
+
+procedure TRubberbandLayer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ IsDragging := False;
+ inherited;
+end;
+
+procedure TRubberbandLayer.Notification(ALayer: TCustomLayer);
+begin
+ if ALayer = FChildLayer then FChildLayer := nil;
+ if FChildLayer <> nil then FLayerOptions := FLayerOptions or LOB_NO_UPDATE
+ else FLayerOptions := FLayerOptions and not LOB_NO_UPDATE;
+end;
+
+procedure TRubberbandLayer.Paint(Buffer: TBitmap32);
+var
+ Cx, Cy: Integer;
+ R: TRect;
+
+ procedure DrawHandle(X, Y: Integer);
+ begin
+ Buffer.FillRectS(X - FHandleSize, Y - FHandleSize, X + FHandleSize, Y + FHandleSize, FHandleFill);
+ Buffer.FrameRectS(X - FHandleSize, Y - FHandleSize, X + FHandleSize, Y + FHandleSize, FHandleFrame);
+ end;
+
+begin
+ R := MakeRect(GetAdjustedLocation);
+ with R do
+ begin
+ if rhFrame in FHandles then
+ begin
+ Buffer.SetStipple([clWhite32, clWhite32, clBlack32, clBlack32]);
+ Buffer.StippleCounter := 0;
+ Buffer.StippleStep := 1;
+ Buffer.FrameRectTSP(Left, Top, Right, Bottom);
+ end;
+ if rhCorners in FHandles then
+ begin
+ DrawHandle(Left, Top);
+ DrawHandle(Right, Top);
+ DrawHandle(Left, Bottom);
+ DrawHandle(Right, Bottom);
+ end;
+ if rhSides in FHandles then
+ begin
+ Cx := (Left + Right) div 2;
+ Cy := (Top + Bottom) div 2;
+ DrawHandle(Cx, Top);
+ DrawHandle(Left, Cy);
+ DrawHandle(Right, Cy);
+ DrawHandle(Cx, Bottom);
+ end;
+ end;
+end;
+
+procedure TRubberbandLayer.SetChildLayer(Value: TPositionedLayer);
+begin
+ if FChildLayer <> nil then RemoveNotification(FChildLayer);
+ FChildLayer := Value;
+ if Value <> nil then
+ begin
+ Location := Value.Location;
+ Scaled := Value.Scaled;
+ AddNotification(FChildLayer);
+ end;
+ if FChildLayer <> nil then FLayerOptions := FLayerOptions or LOB_NO_UPDATE
+ else FLayerOptions := FLayerOptions and not LOB_NO_UPDATE;
+end;
+
+procedure TRubberbandLayer.SetHandleFill(Value: TColor);
+begin
+ if Value <> FHandleFill then
+ begin
+ FHandleFill := Value;
+ FLayerCollection.GDIUpdate;
+ end;
+end;
+
+procedure TRubberbandLayer.SetHandleFrame(Value: TColor);
+begin
+ if Value <> FHandleFrame then
+ begin
+ FHandleFrame := Value;
+ FLayerCollection.GDIUpdate;
+ end;
+end;
+
+procedure TRubberbandLayer.SetHandles(Value: TRBHandles);
+begin
+ if Value <> FHandles then
+ begin
+ FHandles := Value;
+ FLayerCollection.GDIUpdate;
+ end;
+end;
+
+procedure TRubberbandLayer.SetHandleSize(Value: Integer);
+begin
+ if Value < 1 then Value := 1;
+ if Value <> FHandleSize then
+ begin
+ FHandleSize := Value;
+ FLayerCollection.GDIUpdate;
+ end;
+end;
+
+procedure TRubberbandLayer.UpdateChildLayer;
+begin
+ if Assigned(FChildLayer) then FChildLayer.Location := Location;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_LowLevel.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_LowLevel.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_LowLevel.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_LowLevel.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_LowLevel.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,259 @@
+unit GR32_LowLevel;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_LowLevel.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ {$IFDEF CLX}
+ QGraphics,
+ {$ELSE}
+ Graphics,
+ {$ENDIF}
+ GR32;
+
+{ Clamp function restricts Value to [0..255] range }
+function Clamp(Value: Integer): TColor32;
+
+{ An analogue of FillChar for 32 bit values }
+procedure FillLongword(var X; Count: Integer; Value: Longword);
+
+{ An analogue of Move for 32 bit values }
+procedure MoveLongword(const Source; var Dest; Count: Integer);
+
+{ Exchange two 32-bit values }
+procedure Swap(var A, B: Integer);
+
+{ Exhange A <-> B only if B < A }
+procedure TestSwap(var A, B: Integer);
+
+{ Exhange A <-> B only if B < A then restrict both to [0..Size-1] range }
+{ returns true if resulting range has common points with [0..Size-1] range }
+function TestClip(var A, B: Integer; Size: Integer): Boolean;
+
+{ Returns Value constrained to [Lo..Hi] range}
+function Constrain(Value, Lo, Hi: Integer): Integer;
+
+{ shift right with sign conservation }
+function SAR_4(Value: Integer): Integer;
+function SAR_8(Value: Integer): Integer;
+function SAR_9(Value: Integer): Integer;
+function SAR_12(Value: Integer): Integer;
+function SAR_13(Value: Integer): Integer;
+function SAR_14(Value: Integer): Integer;
+function SAR_16(Value: Integer): Integer;
+
+{ ColorSwap exchanges ARGB <-> ABGR and fill A with $FF }
+function ColorSwap(WinColor: TColor): TColor32;
+
+{ MulDiv a faster implementation of Windows.MulDiv funtion }
+function MulDiv(Multiplicand, Multiplier, Divisor: Integer): Integer;
+
+implementation
+
+{$R-}{$Q-} // switch off overflow and range checking
+
+function Clamp(Value: Integer): TColor32;
+begin
+ if Value < 0 then Result := 0
+ else if Value > 255 then Result := 255
+ else Result := Value;
+end;
+
+procedure FillLongword(var X; Count: Integer; Value: Longword);
+asm
+// EAX = X
+// EDX = Count
+// ECX = Value
+ PUSH EDI
+
+ MOV EDI,EAX // Point EDI to destination
+ MOV EAX,ECX
+ MOV ECX,EDX
+ TEST ECX,ECX
+ JS @exit
+
+ REP STOSD // Fill count dwords
+ at exit:
+ POP EDI
+end;
+
+procedure MoveLongword(const Source; var Dest; Count: Integer);
+asm
+// EAX = Source
+// EDX = Dest
+// ECX = Count
+ PUSH ESI
+ PUSH EDI
+
+ MOV ESI,EAX
+ MOV EDI,EDX
+ MOV EAX,ECX
+ CMP EDI,ESI
+ JE @exit
+
+ REP MOVSD
+ at exit:
+ POP EDI
+ POP ESI
+end;
+
+procedure Swap(var A, B: Integer);
+asm
+// EAX = [A]
+// EDX = [B]
+ MOV ECX,[EAX] // ECX := [A]
+ XCHG ECX,[EDX] // ECX <> [B];
+ MOV [EAX],ECX // [A] := ECX
+end;
+
+procedure TestSwap(var A, B: Integer);
+asm
+// EAX = [A]
+// EDX = [B]
+ MOV ECX,[EAX] // ECX := [A]
+ CMP ECX,[EDX]
+ JLE @exit // ECX <= [B]? Exit
+ XCHG ECX,[EDX] // ECX <-> [B];
+ MOV [EAX],ECX // [A] := ECX
+ at exit:
+end;
+
+function TestClip(var A, B: Integer; Size: Integer): Boolean;
+begin
+ TestSwap(A, B); // now A = min(A,B) and B = max(A, B)
+ if A < 0 then A := 0;
+ if B >= Size then B := Size - 1;
+ Result := B >= A;
+end;
+
+function Constrain(Value, Lo, Hi: Integer): Integer;
+begin
+ if Value < Lo then Result := Lo
+ else if Value > Hi then Result := Hi
+ else Result := Value;
+end;
+
+{ shift right with sign conservation }
+function SAR_4(Value: Integer): Integer;
+asm
+ SAR EAX,4
+end;
+
+function SAR_8(Value: Integer): Integer;
+asm
+ SAR EAX,8
+end;
+
+function SAR_9(Value: Integer): Integer;
+asm
+ SAR EAX,9
+end;
+
+function SAR_12(Value: Integer): Integer;
+asm
+ SAR EAX,12
+end;
+
+function SAR_13(Value: Integer): Integer;
+asm
+ SAR EAX,13
+end;
+
+function SAR_14(Value: Integer): Integer;
+asm
+ SAR EAX,14
+end;
+
+function SAR_16(Value: Integer): Integer;
+asm
+ SAR EAX,16
+end;
+
+{ Colorswap exchanges ARGB <-> ABGR and fill A with $FF }
+function ColorSwap(WinColor: TColor): TColor32;
+asm
+// EAX = WinColor
+// this function swaps R and B bytes in ABGR
+// and writes $FF into A component
+ BSWAP EAX
+ MOV AL, $FF
+ ROR EAX,8
+end;
+
+function MulDiv(Multiplicand, Multiplier, Divisor: Integer): Integer;
+asm
+ PUSH EBX // Imperative save
+ PUSH ESI // of EBX and ESI
+
+ MOV EBX,EAX // Result will be negative or positive so set rounding direction
+ XOR EBX,EDX // Negative: substract 1 in case of rounding
+ XOR EBX,ECX // Positive: add 1
+
+ OR EAX,EAX // Make all operands positive, ready for unsigned operations
+ JNS @m1Ok // minimizing branching
+ NEG EAX
+ at m1Ok:
+ OR EDX,EDX
+ JNS @m2Ok
+ NEG EDX
+ at m2Ok:
+ OR ECX,ECX
+ JNS @DivOk
+ NEG ECX
+ at DivOK:
+ MUL EDX // Unsigned multiply (Multiplicand*Multiplier)
+
+ MOV ESI,EDX // Check for overflow, by comparing
+ SHL ESI,1 // 2 times the high-order 32 bits of the product (edx)
+ CMP ESI,ECX // with the Divisor.
+ JAE @Overfl // If equal or greater than overflow with division anticipated
+
+ DIV ECX // Unsigned divide of product by Divisor
+
+ SUB ECX,EDX // Check if the result must be corregized by adding or substracting
+ CMP ECX,EDX // 1 (*.5 -> nearest integer), by comparing the difference of
+ JA @NoAdd // Divisor and remainder with the remainder. If it is greater then
+ INC EAX // no rounding needed; add 1 to result otherwise
+ at NoAdd:
+ OR EBX,EDX // From unsigned operations back the to original sign of the result
+ JNS @exit // must be positive
+ NEG EAX // must be negative
+ JMP @exit
+ at Overfl:
+ OR EAX,-1 // 3 bytes alternative for mov eax,-1. Windows.MulDiv "overflow"
+ // and "zero-divide" return value
+ at exit:
+ POP ESI // Restore
+ POP EBX // esi and ebx
+end;
+
+
+end.
+
Added: trunk/WPGM/Components/Graphics32/GR32_Polygons.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Polygons.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Polygons.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Polygons.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Polygons.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1148 @@
+unit GR32_Polygons;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Andre Beckedorf <Andre at metaException.de>
+ * Mattias Andersson <mattias at centaurix.com>
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Polygons.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+{$IFDEF CLX}
+ Qt, Types,
+ {$IFDEF LINUX}Libc, {$ENDIF}
+ {$IFDEF MSWINDOWS}Windows, {$ENDIF}
+{$ELSE}
+ Windows,
+{$ENDIF}
+ SysUtils, GR32, GR32_LowLevel, GR32_Blend;
+
+{ Polylines }
+
+procedure PolylineTS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
+ Color: TColor32; Closed: Boolean = False);
+procedure PolylineAS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
+ Color: TColor32; Closed: Boolean = False);
+procedure PolylineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
+ Color: TColor32; Closed: Boolean = False);
+
+procedure PolyPolylineTS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32; Closed: Boolean = False);
+procedure PolyPolylineAS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32; Closed: Boolean = False);
+procedure PolyPolylineXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32; Closed: Boolean = False);
+
+{ Polygons }
+
+type
+ TPolyFillMode = (pfAlternate, pfWinding);
+
+ TShiftFunc = function(Value: Integer): Integer; // needed for antialiasing to speed things up
+ TAntialiasMode = (am16times, am8times, am4times);
+
+const
+ DefaultAAMode = am8times; // Use 54 levels of transparency for antialiasing.
+
+procedure PolygonTS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
+ Color: TColor32; Mode: TPolyFillMode = pfAlternate);
+procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
+ Color: TColor32; Mode: TPolyFillMode = pfAlternate;
+ const AAMode: TAntialiasMode = DefaultAAMode);
+
+procedure PolyPolygonTS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32; Mode: TPolyFillMode = pfAlternate);
+procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32; Mode: TPolyFillMode = pfAlternate;
+ const AAMode: TAntialiasMode = DefaultAAMode);
+
+function PtInPolygon(const Pt: TFixedPoint; const Points: TArrayOfFixedPoint): Boolean;
+
+{ TPolygon32 }
+{ TODO : Bezier Curves, and QSpline curves for TrueType font rendering }
+{ TODO : Check if QSpline is compatible with Type1 fonts }
+type
+ TPolygon32 = class
+ private
+ FAntialiased: Boolean;
+ FClosed: Boolean;
+ FFillMode: TPolyFillMode;
+ FNormals: TArrayOfArrayOfFixedPoint;
+ FPoints: TArrayOfArrayOfFixedPoint;
+ FAntialiasMode: TAntialiasMode;
+ protected
+ procedure BuildNormals;
+ public
+ constructor Create; virtual;
+ destructor Destroy; override;
+ procedure Add(const P: TFixedPoint);
+ procedure AddPoints(var First: TFixedPoint; Count: Integer);
+ function ContainsPoint(const P: TFixedPoint): Boolean;
+ procedure Clear;
+ function Grow(const Delta: TFixed; EdgeSharpness: Single = 0): TPolygon32;
+ procedure Draw(Bitmap: TBitmap32; OutlineColor, FillColor: TColor32);
+ procedure DrawEdge(Bitmap: TBitmap32; Color: TColor32);
+ procedure DrawFill(Bitmap: TBitmap32; Color: TColor32);
+ procedure NewLine;
+ procedure Offset(const Dx, Dy: TFixed);
+ function Outline: TPolygon32;
+ property Antialiased: Boolean read FAntialiased write FAntialiased;
+ property AntialiasMode: TAntialiasMode read FAntialiasMode write FAntialiasMode;
+ property Closed: Boolean read FClosed write FClosed;
+ property FillMode: TPolyFillMode read FFillMode write FFillMode;
+ property Normals: TArrayOfArrayOfFixedPoint read FNormals write FNormals;
+ property Points: TArrayOfArrayOfFixedPoint read FPoints write FPoints;
+ end;
+
+implementation
+
+uses Math;
+
+const
+ AA_LINES: Array[TAntialiasMode] of Integer = (16, 8, 4);
+ AA_SHIFT: Array[TAntialiasMode] of Integer = (4, 3, 2);
+ AA_MULTI: Array[TAntialiasMode] of Integer = (273, 1167, 5460);
+ AA_SAR: Array[TAntialiasMode] of TShiftFunc = (SAR_12, SAR_13, SAR_14);
+
+type
+// These are for edge scan info. Note, that the most significant bit of the
+// edge in a scan line is used for winding (edge direction) info.
+ TScanLine = TArrayOfInteger;
+ TScanLines = TArrayOfArrayOfInteger;
+ PIntegerArray = ^TIntegerArray;
+ TIntegerArray = array [0..0] of Integer;
+ PFixedPointArray = ^TFixedPointArray;
+ TFixedPointArray = array [0..0] of TFixedPoint;
+
+procedure PolylineTS(
+ Bitmap: TBitmap32;
+ const Points: TArrayOfFixedPoint;
+ Color: TColor32;
+ Closed: Boolean);
+var
+ I, Count: Integer;
+ DoAlpha: Boolean;
+begin
+ Count := Length(Points);
+ if (Count = 1) and Closed then
+ with Points[0] do Bitmap.SetPixelTS(FixedRound(X), FixedRound(Y), Color);
+ if Count < 2 then Exit;
+ DoAlpha := Color and $FF000000 <> $FF000000;
+ Bitmap.BeginUpdate;
+ Bitmap.PenColor := Color;
+ with Points[0] do Bitmap.MoveTo(FixedRound(X), FixedRound(Y));
+ if DoAlpha then
+ for I := 1 to Count - 1 do
+ with Points[I] do
+ Bitmap.LineToTS(FixedRound(X), FixedRound(Y))
+ else
+ for I := 1 to Count - 1 do
+ with Points[I] do
+ Bitmap.LineToS(FixedRound(X), FixedRound(Y));
+ if Closed then with Points[0] do Bitmap.LineToTS(FixedRound(X), FixedRound(Y));
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+end;
+
+procedure PolylineAS(
+ Bitmap: TBitmap32;
+ const Points: TArrayOfFixedPoint;
+ Color: TColor32;
+ Closed: Boolean);
+var
+ I, Count: Integer;
+begin
+ Count := Length(Points);
+ if (Count = 1) and Closed then
+ with Points[0] do Bitmap.SetPixelTS(FixedRound(X), FixedRound(Y), Color);
+ if Count < 2 then Exit;
+ Bitmap.BeginUpdate;
+ Bitmap.PenColor := Color;
+ with Points[0] do Bitmap.MoveTo(FixedRound(X), FixedRound(Y));
+ for I := 1 to Count - 1 do
+ with Points[I] do
+ Bitmap.LineToAS(FixedRound(X), FixedRound(Y));
+ if Closed then with Points[0] do Bitmap.LineToAS(FixedRound(X), FixedRound(Y));
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+end;
+
+procedure PolylineXS(
+ Bitmap: TBitmap32;
+ const Points: TArrayOfFixedPoint;
+ Color: TColor32;
+ Closed: Boolean);
+var
+ I, Count: Integer;
+begin
+ Count := Length(Points);
+ if (Count = 1) and Closed then with Points[0] do Bitmap.PixelXS[X, Y] := Color;
+ if Count < 2 then Exit;
+ Bitmap.BeginUpdate;
+ Bitmap.PenColor := Color;
+ with Points[0] do Bitmap.MoveToX(X, Y);
+ for I := 1 to Count - 1 do with Points[I] do Bitmap.LineToXS(X, Y);
+ if Closed then with Points[0] do Bitmap.LineToXS(X, Y);
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+end;
+
+procedure PolyPolylineTS(
+ Bitmap: TBitmap32;
+ const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32;
+ Closed: Boolean = False);
+var
+ I: Integer;
+begin
+ for I := 0 to High(Points) do PolylineTS(Bitmap, Points[I], Color, Closed);
+end;
+
+procedure PolyPolylineAS(
+ Bitmap: TBitmap32;
+ const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32;
+ Closed: Boolean = False);
+var
+ I: Integer;
+begin
+ for I := 0 to High(Points) do PolylineAS(Bitmap, Points[I], Color, Closed);
+end;
+
+procedure PolyPolylineXS(
+ Bitmap: TBitmap32;
+ const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32;
+ Closed: Boolean = False);
+var
+ I: Integer;
+begin
+ for I := 0 to High(Points) do PolylineXS(Bitmap, Points[I], Color, Closed);
+end;
+
+procedure QSortLine(const ALine: TScanLine; L, R: Integer);
+var
+ I, J, P: Integer;
+begin
+ repeat
+ I := L;
+ J := R;
+ P := ALine[(L + R) shr 1] and $7FFFFFFF;
+ repeat
+ while (ALine[I] and $7FFFFFFF) < P do Inc(I);
+ while (ALine[J] and $7FFFFFFF) > P do Dec(J);
+ if I <= J then
+ begin
+ Swap(ALine[I], ALine[J]);
+ Inc(I);
+ Dec(J);
+ end;
+ until I > J;
+ if L < J then QSortLine(ALine, L, J);
+ L := I;
+ until I >= R;
+end;
+
+procedure SortLine(const ALine: TScanLine);
+var
+ L, Tmp: Integer;
+begin
+ L := Length(ALine);
+ Assert(not Odd(L));
+ if L = 2 then
+ begin
+ if (ALine[0] and $7FFFFFFF) > (ALine[1] and $7FFFFFFF) then
+ begin
+ Tmp := ALine[0];
+ ALine[0] := ALine[1];
+ ALine[1] := Tmp;
+ end;
+ end
+ else if L > 2 then QSortLine(ALine, 0, L - 1);
+end;
+
+procedure SortLines(const ScanLines: TScanLines);
+var
+ I: Integer;
+begin
+ for I := 0 to High(ScanLines) do SortLine(ScanLines[I]);
+end;
+
+procedure AddPolygon(const Points: TArrayOfPoint; BaseY: Integer;
+ MaxX, MaxY: Integer; var ScanLines: TScanLines; SubSampleX: Boolean);
+var
+ I, X1, Y1, X2, Y2: Integer;
+ Direction, PrevDirection: Integer; // up = 1 or down = -1
+
+ function Sign(I: Integer): Integer;
+ begin
+ if I > 0 then Result := 1
+ else if I < 0 then Result := -1
+ else Result := 0;
+ end;
+
+ procedure AddEdgePoint(X, Y: Integer; Direction: Integer);
+ var
+ L: Integer;
+ begin
+ // positive direction (+1) is down
+ if (Y < 0) or (Y > MaxY) then Exit;
+ if X < 0 then X := 0 else if X > MaxX then X := MaxX;
+ L := Length(ScanLines[Y - BaseY]);
+ SetLength(ScanLines[Y - BaseY], L + 1);
+ if Direction < 0 then X := Integer(Longword(X) or $80000000); // set the highest bit if the winding is up
+ ScanLines[Y - BaseY][L] := X;
+ end;
+
+ function DrawEdge(X1, Y1, X2, Y2: Integer): Integer;
+ var
+ X, Y, I, K: Integer;
+ Dx, Dy, Sx, Sy: Integer;
+ Delta: Integer;
+ begin
+ // this function 'renders' a line into the edge (ScanLines) buffer
+ // and returns the line direction (1 - down, -1 - up, 0 - horizontal)
+ Result := 0;
+ if Y2 = Y1 then Exit;
+ Dx := X2 - X1;
+ Dy := Y2 - Y1;
+ if Dy > 0 then Sy := 1
+ else
+ begin
+ Sy := -1;
+ Dy := -Dy;
+ end;
+ Result := Sy;
+ if Dx > 0 then Sx := 1
+ else
+ begin
+ Sx := -1;
+ Dx := -Dx;
+ end;
+ Delta := (Dx mod Dy) shr 1;
+ X := X1; Y := Y1;
+ for I := 0 to Dy - 1 do
+ begin
+ AddEdgePoint(X, Y, Result);
+ Inc(Y, Sy);
+ Inc(Delta, Dx);
+
+
+ // try it two times and if anything else left, use div and mod
+ if Delta > Dy then
+ begin
+ Inc(X, Sx);
+ Dec(Delta, Dy);
+
+ if Delta > Dy then // segment is tilted more than 45 degrees?
+ begin
+ Inc(X, Sx);
+ Dec(Delta, Dy);
+
+ if Delta > Dy then // are we still here?
+ begin
+ K := (Delta + Dy - 1) div Dy;
+ Inc(X, Sx * K);
+ Dec(Delta, Dy * K);
+ end;
+ end;
+ end;
+ end;
+ end;
+begin
+ if Length(Points) < 3 then Exit;
+
+ with Points[0] do
+ begin
+ X1 := X;
+ if SubSampleX then X1 := X1 shl 8;
+ Y1 := Y;
+ end;
+
+ // find the last Y different from Y1 and assign it to Y0
+ PrevDirection := 0;
+ I := High(Points);
+ while I > 0 do
+ begin
+ PrevDirection := Sign(Y1 - Points[I].Y);
+ if PrevDirection <> 0 then Break;
+ Dec(I);
+ end;
+
+ for I := 1 to High(Points) do
+ begin
+ with Points[I] do
+ begin
+ X2 := X;
+ Y2 := Y;
+ if SubSampleX then X2 := X2 shl 8;
+ end;
+ if Y1 <> Y2 then
+ begin
+ Direction := DrawEdge(X1, Y1, X2, Y2);
+ if Direction <> PrevDirection then
+ begin
+ AddEdgePoint(X1, Y1, -Direction);
+ PrevDirection := Direction;
+ end;
+ end;
+ X1 := X2; Y1 := Y2;
+ end;
+ with Points[0] do
+ begin
+ X2 := X;
+ Y2 := Y;
+ if SubSampleX then X2 := X2 shl 8;
+ end;
+ if Y1 <> Y2 then
+ begin
+ Direction := DrawEdge(X1, Y1, X2, Y2);
+ if Direction <> PrevDirection then AddEdgePoint(X1, Y1, -Direction);
+ end;
+end;
+
+procedure FillLines(Bitmap: TBitmap32; BaseY: Integer;
+ const ScanLines: TScanLines; Color: TColor32; Mode: TPolyFillMode);
+var
+ I, J, L: Integer;
+ Left, Right, OldRight, LP, RP: Integer;
+ DoAlpha: Boolean;
+ Winding, NextWinding: Integer;
+begin
+ DoAlpha := Color and $FF000000 <> $FF000000;
+ for J := 0 to High(ScanLines) do
+ begin
+ L := Length(ScanLines[J]); // assuming length is even
+ if L = 0 then Continue;
+ I := 0;
+ OldRight := -1;
+ if Mode = pfAlternate then
+ while I < L do
+ begin
+ Left := ScanLines[J][I] and $7FFFFFFF;
+ Inc(I);
+ Right := ScanLines[J][I] and $7FFFFFFF - 1;
+ if Right > Left then
+ begin
+ if Mode = pfAlternate then
+ begin
+ if (Left and $FF) < $80 then Left := Left shr 8
+ else Left := Left shr 8 + 1;
+ if (Right and $FF) < $80 then Right := Right shr 8
+ else Right := Right shr 8 + 1;
+
+ if Right >= Bitmap.Width - 1 then Right := Bitmap.Width - 1;
+
+ if Left <= OldRight then Left := OldRight + 1;
+ OldRight := Right;
+ if Right >= Left then
+ if DoAlpha then Bitmap.HorzLineT(Left, BaseY + J, Right, Color)
+ else Bitmap.HorzLine(Left, BaseY + J, Right, Color);
+ end;
+ end;
+ Inc(I);
+ end
+ else // Mode = pfWinding
+ begin
+ Winding := 0;
+ Left := ScanLines[J][0];
+ if (Left and $80000000) <> 0 then Inc(Winding) else Dec(Winding);
+ Left := Left and $7FFFFFFF;
+ Inc(I);
+ while I < L do
+ begin
+ Right := ScanLines[J][I];
+ if (Right and $80000000) <> 0 then NextWinding := 1 else NextWinding := -1;
+ Right := Right and $7FFFFFFF;
+ Inc(I);
+
+ if Winding <> 0 then
+ begin
+ if (Left and $FF) < $80 then LP := Left shr 8
+ else LP := Left shr 8 + 1;
+ if (Right and $FF) < $80 then RP := Right shr 8
+ else RP := Right shr 8 + 1;
+
+ if RP >= Bitmap.Width - 1 then RP := Bitmap.Width - 1;
+
+ if RP >= LP then
+ if DoAlpha then Bitmap.HorzLineT(LP, BaseY + J, RP, Color)
+ else Bitmap.HorzLine(LP, BaseY + J, RP, Color);
+ end;
+
+ Inc(Winding, NextWinding);
+ Left := Right;
+ end;
+ end;
+ end;
+end;
+
+procedure FillLines2(Bitmap: TBitmap32; BaseY: Integer;
+ const ScanLines: TScanLines; Color: TColor32; Mode: TPolyFillMode;
+ const AAMode: TAntialiasMode = DefaultAAMode);
+var
+ I, J, L, N: Integer;
+ MinY, MaxY, Y, Top, Bottom: Integer;
+ MinX, MaxX, X, Dx: Integer;
+ Left, Right: Integer;
+ Buffer: array of Integer;
+ ColorBuffer: array of TColor32;
+ BufferSize: Integer;
+ C, A: TColor32;
+ ScanLine: PIntegerArray;
+ Winding, NextWinding: Integer;
+ AAShift, AALines, AAMultiplicator: Integer;
+begin
+ A := Color shr 24;
+
+ AAShift := AA_SHIFT[AAMode];
+ AALines := AA_LINES[AAMode] - 1; // we do the -1 here for optimization.
+ AAMultiplicator := AA_MULTI[AAMode];
+
+ // find the range of Y screen coordinates
+ MinY := BaseY shr AAShift;
+ MaxY := (BaseY + Length(ScanLines) + AALines) shr AAShift;
+
+ Y := MinY;
+ while Y < MaxY do
+ begin
+ Top := Y shl AAShift - BaseY;
+ Bottom := Top + AALines;
+ if Top < 0 then Top := 0;
+ if Bottom >= Length(ScanLines) then Bottom := High(ScanLines);
+
+ // find left and right edges of the screen scanline
+ MinX := $7F000000; MaxX := -$7F000000;
+ for J := Top to Bottom do
+ begin
+ L := Length(ScanLines[J]) - 1;
+ if L > 0 then
+ begin
+ Left := (ScanLines[J][0] and $7FFFFFFF);
+ Right := (ScanLines[J][L] and $7FFFFFFF + AALines);
+ if Left < MinX then MinX := Left;
+ if Right > MaxX then MaxX := Right;
+ end
+ end;
+
+ if MaxX >= MinX then
+ begin
+ MinX := MinX shr AAShift;
+ MaxX := MaxX shr AAShift;
+ // allocate buffer for a single scanline
+ BufferSize := MaxX - MinX + 2;
+ if Length(Buffer) < BufferSize then
+ begin
+ SetLength(Buffer, BufferSize + 64);
+ SetLength(ColorBuffer, BufferSize + 64);
+ end;
+ FillLongword(Buffer[0], BufferSize, 0);
+
+ // ...and fill it
+ for J := Top to Bottom do
+ begin
+ I := 0;
+ L := Length(ScanLines[J]);
+ ScanLine := @ScanLines[J][0];
+ if Mode = pfAlternate then
+ while I < L do
+ begin
+ // Left edge
+ X := ScanLine[I] and $7FFFFFFF;
+ Dx := X and AALines;
+ X := X shr AAShift - MinX;
+ Inc(Buffer[X], Dx xor AALines);
+ Inc(Buffer[X + 1], Dx);
+ Inc(I);
+
+ // Right edge
+ X := ScanLine[I] and $7FFFFFFF;
+ Dx := X and AALines;
+ X := X shr AAShift - MinX;
+ Dec(Buffer[X], Dx xor AALines);
+ Dec(Buffer[X + 1], Dx);
+ Inc(I);
+ end
+ else // mode = pfWinding
+ begin
+ Winding := 0;
+ while I < L do
+ begin
+ X := ScanLine[I];
+ Inc(I);
+ if (X and $80000000) <> 0 then NextWinding := 1 else NextWinding := -1;
+ X := X and $7FFFFFFF;
+ if Winding = 0 then
+ begin
+ Dx := X and AALines;
+ X := X shr AAShift - MinX;
+ Inc(Buffer[X], Dx xor AALines);
+ Inc(Buffer[X + 1], Dx);
+ end;
+ Inc(Winding, NextWinding);
+ if Winding = 0 then
+ begin
+ Dx := X and AALines;
+ X := X shr AAShift - MinX;
+ Dec(Buffer[X], Dx xor AALines);
+ Dec(Buffer[X + 1], Dx);
+ end;
+ end;
+ end;
+ end;
+
+ // integrate the buffer
+ N := 0;
+ C := Color and $00FFFFFF;
+ for I := 0 to BufferSize - 1 do
+ begin
+ Inc(N, Buffer[I]);
+ ColorBuffer[I] := TColor32(N * AAMultiplicator and $FF00) shl 16 or C;
+ end;
+
+ // draw it to the screen
+ BlendLineEx(@ColorBuffer[0], Pointer(Bitmap.PixelPtr[MinX, Y]), BufferSize, A);
+ EMMS;
+ end;
+
+ Inc(Y);
+ end;
+end;
+
+procedure GetMinMax(const Points: TArrayOfPoint; out MinY, MaxY: Integer); overload;
+var
+ I, Y: Integer;
+begin
+ MinY := $7F000000; MaxY := -$7F000000;
+ for I := 0 to High(Points) do
+ begin
+ Y := Points[I].Y;
+ if Y < MinY then MinY := Y;
+ if Y > MaxY then MaxY := Y;
+ end;
+end;
+
+procedure PolygonTS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; Color: TColor32; Mode: TPolyFillMode);
+var
+ L, I, MinY, MaxY: Integer;
+ ScanLines: TScanLines;
+ PP: TArrayOfPoint;
+begin
+ L := Length(Points);
+ if (L < 3) or (Color and $FF000000 = 0) then Exit;
+ SetLength(PP, L);
+
+ for I := 0 to L - 1 do
+ with Points[I] do
+ begin
+ PP[I].X := SAR_16(X + $00007FFF);
+ PP[I].Y := SAR_16(Y + $00007FFF);
+ end;
+
+ GetMinMax(PP, MinY, MaxY);
+ MinY := Constrain(MinY, 0, Bitmap.Height);
+ MaxY := Constrain(MaxY, 0, Bitmap.Height);
+ if MinY >= MaxY then Exit;
+
+ SetLength(ScanLines, MaxY - MinY + 1);
+ AddPolygon(PP, MinY, Bitmap.Width shl 8 - 1, Bitmap.Height - 1, ScanLines, True);
+ SortLines(ScanLines);
+ Bitmap.BeginUpdate;
+ try
+ FillLines(Bitmap, MinY, ScanLines, Color, Mode);
+ finally
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+ end;
+end;
+
+procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
+ Color: TColor32; Mode: TPolyFillMode; const AAMode: TAntialiasMode);
+var
+ L, I, MinY, MaxY: Integer;
+ ScanLines: TScanLines;
+ PP: TArrayOfPoint;
+ AAShift, AABmpHeight: Integer;
+ AASAR: TShiftFunc;
+begin
+ AAShift := AA_SHIFT[AAMode];
+ AASAR := AA_SAR[AAMode];
+ AABmpHeight := Bitmap.Height shl AAShift - 1; // optimize a bit since that is done 3 times below...
+
+ L := Length(Points);
+ if (L < 3) or (Color and $FF000000 = 0) then Exit;
+ SetLength(PP, L);
+
+ for I := 0 to L - 1 do
+ with Points[I] do
+ begin
+ PP[I].X := AASAR(X + $00007FF);
+ PP[I].Y := AASAR(Y + $00007FF);
+ end;
+
+ GetMinMax(PP, MinY, MaxY);
+ MinY := Constrain(MinY, 0, AABmpHeight);
+ MaxY := Constrain(MaxY, 0, AABmpHeight);
+ if MinY >= MaxY then Exit;
+
+ SetLength(ScanLines, MaxY - MinY + 1);
+ AddPolygon(PP, MinY, Bitmap.Width shl AAShift - 1, AABmpHeight, ScanLines, False);
+ SortLines(ScanLines);
+ Bitmap.BeginUpdate;
+ try
+ FillLines2(Bitmap, MinY, ScanLines, Color, Mode, AAMode);
+ finally
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+ end;
+end;
+
+procedure PolyPolygonTS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32; Mode: TPolyFillMode = pfAlternate);
+var
+ L, I, J, min, max, MinY, MaxY: Integer;
+ ScanLines: TScanLines;
+ PP: TArrayOfArrayOfPoint;
+begin
+ SetLength(PP, Length(Points));
+
+ for J := 0 to High(Points) do
+ begin
+ L := Length(Points[J]);
+ SetLength(PP[J], L);
+ for I := 0 to L - 1 do
+ with Points[J][I] do
+ begin
+ PP[J][I].X := SAR_16(X + $00007FFF);
+ PP[J][I].Y := SAR_16(Y + $00007FFF);
+ end;
+ end;
+
+ MaxY := -$7FFFFFFF;
+ MinY := $7FFFFFFF;
+ for J := 0 to High(PP) do
+ begin
+ GetMinMax(PP[J], min, max);
+ if min < MinY then MinY := min;
+ if max > MaxY then MaxY := max;
+ end;
+
+ MinY := Constrain(MinY, 0, Bitmap.Height);
+ MaxY := Constrain(MaxY, 0, Bitmap.Height);
+ if MinY >= MaxY then Exit;
+
+ SetLength(ScanLines, MaxY - MinY + 1);
+ for J := 0 to High(Points) do
+ AddPolygon(PP[J], MinY, Bitmap.Width shl 8 - 1, Bitmap.Height - 1, ScanLines, True);
+
+ SortLines(ScanLines);
+ Bitmap.BeginUpdate;
+ try
+ FillLines(Bitmap, MinY, ScanLines, Color, Mode);
+ finally
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+ end;
+end;
+
+procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
+ Color: TColor32; Mode: TPolyFillMode; const AAMode: TAntialiasMode);
+var
+ L, I, J, min, max, MinY, MaxY: Integer;
+ ScanLines: TScanLines;
+ PP: TArrayOfArrayOfPoint;
+ AAShift, AABmpHeight, AABmpWidth: Integer;
+ AASAR: TShiftFunc;
+begin
+ AAShift := AA_SHIFT[AAMode];
+ AASAR := AA_SAR[AAMode];
+ AABmpHeight := Bitmap.Height shl AAShift - 1; // optimize a bit since that is done 3 times below...
+ AABmpWidth := Bitmap.Width shl AAShift - 1;
+
+ SetLength(PP, Length(Points));
+
+ for J := 0 to High(Points) do
+ begin
+ L := Length(Points[J]);
+ if L > 2 then
+ begin
+ SetLength(PP[J], L);
+ for I := 0 to L - 1 do
+ with Points[J][I] do
+ begin
+ PP[J][I].X := AASAR(X + $000007FF);
+ PP[J][I].Y := AASAR(Y + $000007FF);
+ end;
+ end
+ else SetLength(PP[J], 0);
+ end;
+
+ MaxY := -$7F000000;
+ MinY := $7F000000;
+ for J := 0 to High(PP) do
+ begin
+ GetMinMax(PP[J], min, max);
+ if min < MinY then MinY := min;
+ if max > MaxY then MaxY := max;
+ end;
+
+ MinY := Constrain(MinY, 0, AABmpHeight);
+ MaxY := Constrain(MaxY, 0, AABmpHeight);
+ if MinY >= MaxY then Exit;
+
+ SetLength(ScanLines, MaxY - MinY + 1);
+ for J := 0 to High(Points) do
+ AddPolygon(PP[J], MinY, AABmpWidth, AABmpHeight, ScanLines, False);
+
+ SortLines(ScanLines);
+ Bitmap.BeginUpdate;
+ try
+ FillLines2(Bitmap, MinY, ScanLines, Color, Mode, AAMode);
+ finally
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+ end;
+end;
+
+function PtInPolygon(const Pt: TFixedPoint; const Points: TArrayOfFixedPoint): Boolean;
+var
+ I: Integer;
+ iPt, jPt: PFixedPoint;
+begin
+ Result := False;
+ iPt := @Points[0];
+ jPt := @Points[High(Points)];
+ for I := 0 to High(Points) do
+ begin
+ Result := Result xor (((Pt.Y >= iPt.Y) xor (Pt.Y >= jPt.Y)) and
+ (Pt.X - iPt.X < MulDiv(jPt.X - iPt.X, Pt.Y - iPt.Y, jPt.Y - iPt.Y)));
+ jPt := iPt;
+ Inc(iPt);
+ end;
+end;
+
+{ TPolygon32 }
+
+procedure TPolygon32.Add(const P: TFixedPoint);
+var
+ H, L: Integer;
+begin
+ H := High(Points);
+ L := Length(Points[H]);
+ SetLength(Points[H], L + 1);
+ Points[H][L] := P;
+ Normals := nil;
+end;
+
+procedure TPolygon32.AddPoints(var First: TFixedPoint; Count: Integer);
+var
+ H, L, I: Integer;
+begin
+ H := High(Points);
+ L := Length(Points[H]);
+ SetLength(Points[H], L + Count);
+ for I := 0 to Count - 1 do
+ Points[H][L + I] := PFixedPointArray(@First)[I];
+ Normals := nil;
+end;
+
+procedure TPolygon32.BuildNormals;
+var
+ I, J, Count, NextI: Integer;
+ dx, dy, f: Single;
+begin
+ if Length(Normals) <> 0 then Exit;
+ SetLength(FNormals, Length(Points));
+
+ for J := 0 to High(Points) do
+ begin
+ Count := Length(Points[J]);
+ SetLength(Normals[J], Count);
+
+ if Count = 0 then Exit;
+ if Count = 1 then
+ begin
+ FillChar(Normals[J][0], SizeOf(TFixedPoint), 0);
+ Exit;
+ end;
+
+ I := 0;
+ NextI := 1;
+ dx := 0;
+ dy := 0;
+
+ while I < Count do
+ begin
+ if Closed and (NextI >= Count) then NextI := 0;
+ if NextI < Count then
+ begin
+ dx := (Points[J][NextI].X - Points[J][I].X) / $10000;
+ dy := (Points[J][NextI].Y - Points[J][I].Y) / $10000;
+ end;
+ if (dx <> 0) or (dy <> 0) then
+ begin
+ f := 1 / Hypot(dx, dy);
+ dx := dx * f;
+ dy := dy * f;
+ end;
+ with Normals[J][I] do
+ begin
+ X := Fixed(dy);
+ Y := Fixed(-dx);
+ end;
+ Inc(I);
+ Inc(NextI);
+ end;
+ end;
+end;
+
+procedure TPolygon32.Clear;
+begin
+ Points := nil;
+ Normals := nil;
+ NewLine;
+end;
+
+function TPolygon32.ContainsPoint(const P: TFixedPoint): Boolean;
+var
+ I: Integer;
+begin
+ Result := False;
+ for I := 0 to High(FPoints) do
+ if PtInPolygon(P, FPoints[I]) then
+ begin
+ Result := True;
+ Exit;
+ end;
+end;
+
+constructor TPolygon32.Create;
+begin
+ FClosed := True;
+ FAntialiasMode := DefaultAAMode;
+ NewLine; // initiate a new contour
+end;
+
+destructor TPolygon32.Destroy;
+begin
+ Clear;
+ inherited;
+end;
+
+procedure TPolygon32.Draw(Bitmap: TBitmap32; OutlineColor, FillColor: TColor32);
+begin
+ Bitmap.BeginUpdate;
+ if Antialiased then
+ begin
+ if (FillColor and $FF000000) <> 0 then
+ PolyPolygonXS(Bitmap, Points, FillColor, FillMode, AntialiasMode);
+ if (OutlineColor and $FF000000) <> 0 then
+ PolyPolylineXS(Bitmap, Points, OutlineColor, Closed);
+ end
+ else
+ begin
+ if (FillColor and $FF000000) <> 0 then
+ PolyPolygonTS(Bitmap, Points, FillColor, FillMode);
+ if (OutlineColor and $FF000000) <> 0 then
+ PolyPolylineTS(Bitmap, Points, OutlineColor, Closed);
+ end;
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+end;
+
+procedure TPolygon32.DrawEdge(Bitmap: TBitmap32; Color: TColor32);
+begin
+ Bitmap.BeginUpdate;
+ if Antialiased then
+ PolyPolylineXS(Bitmap, Points, Color, Closed)
+ else
+ PolyPolylineTS(Bitmap, Points, Color, Closed);
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+end;
+
+procedure TPolygon32.DrawFill(Bitmap: TBitmap32; Color: TColor32);
+begin
+ Bitmap.BeginUpdate;
+ if Antialiased then
+ PolyPolygonXS(Bitmap, Points, Color, FillMode, AntialiasMode)
+ else
+ PolyPolygonTS(Bitmap, Points, Color, FillMode);
+ Bitmap.EndUpdate;
+ Bitmap.Changed;
+end;
+
+function TPolygon32.Grow(const Delta: TFixed; EdgeSharpness: Single = 0): TPolygon32;
+var
+ J, I, PrevI: Integer;
+ PX, PY, AX, AY, BX, BY, CX, CY, R, D, E: Integer;
+
+ procedure AddPoint(LongDeltaX, LongDeltaY: Integer);
+ var
+ N, L: Integer;
+ begin
+ with Result do
+ begin
+ N := High(Points);
+ L := Length(Points[N]);
+ SetLength(Points[N], L + 1);
+ end;
+ with Result.Points[N][L] do
+ begin
+ X := PX + LongDeltaX;
+ Y := PY + LongDeltaY;
+ end;
+ end;
+
+begin
+ BuildNormals;
+
+ if EdgeSharpness > 0.99 then EdgeSharpness := 0.99
+ else if EdgeSharpness < 0 then EdgeSharpness := 0;
+
+ D := Delta;
+ E := Round(D * (1 - EdgeSharpness));
+
+ Result := TPolygon32.Create;
+ Result.Antialiased := Antialiased;
+ Result.Closed := Closed;
+ Result.FillMode := FillMode;
+
+ if Delta = 0 then
+ begin
+ // simply copy the data
+ SetLength(Result.FPoints, Length(Points));
+ for J := 0 to High(Points) do
+ Result.Points[J] := Copy(Points[J], 0, Length(Points[J]));
+ Exit;
+ end;
+
+ Result.Points := nil;
+
+ for J := 0 to High(Points) do
+ begin
+ if Length(Points[J]) < 2 then Continue;
+
+ Result.NewLine;
+
+ for I := 0 to High(Points[J]) do
+ begin
+ with Points[J][I] do
+ begin
+ PX := X;
+ PY := Y;
+ end;
+
+ with Normals[J][I] do
+ begin
+ BX := MulDiv(X, D, $10000);
+ BY := MulDiv(Y, D, $10000);
+ end;
+
+ if (I > 0) or Closed then
+ begin
+ PrevI := I - 1;
+ if PrevI < 0 then PrevI := High(Points[J]);
+ with Normals[J][PrevI] do
+ begin
+ AX := MulDiv(X, D, $10000);
+ AY := MulDiv(Y, D, $10000);
+ end;
+
+ if (I = High(Points[J])) and (not Closed) then AddPoint(AX, AY)
+ else
+ begin
+ CX := AX + BX;
+ CY := AY + BY;
+ R := MulDiv(AX, CX, D) + MulDiv(AY, CY, D);
+ if R > E then AddPoint(MulDiv(CX, D, R), MulDiv(CY, D, R))
+ else
+ begin
+ AddPoint(AX, AY);
+ AddPoint(BX, BY);
+ end;
+ end;
+ end
+ else AddPoint(BX, BY);
+ end;
+ end;
+end;
+
+procedure TPolygon32.NewLine;
+begin
+ SetLength(FPoints, Length(Points) + 1);
+ Normals := nil;
+end;
+
+procedure TPolygon32.Offset(const Dx, Dy: TFixed);
+var
+ J, I: Integer;
+begin
+ for J := 0 to High(Points) do
+ for I := 0 to High(Points[J]) do
+ with Points[J][I] do
+ begin
+ Inc(X, Dx);
+ Inc(Y, Dy);
+ end;
+end;
+
+function TPolygon32.Outline: TPolygon32;
+var
+ J, I: Integer;
+begin
+ BuildNormals;
+
+ Result := TPolygon32.Create;
+ Result.Antialiased := Antialiased;
+ Result.Closed := Closed;
+ Result.FillMode := FillMode;
+
+ Result.Points := nil;
+
+ for J := 0 to High(Points) do
+ begin
+ if Length(Points[J]) < 2 then Continue;
+
+ if Closed then
+ begin
+ Result.NewLine;
+ for I := 0 to High(Points[J]) do Result.Add(Points[J][I]);
+ Result.NewLine;
+ for I := High(Points[J]) downto 0 do Result.Add(Points[J][I]);
+ end
+ else // not closed
+ begin
+ Result.NewLine;
+ for I := 0 to High(Points[J]) do Result.Add(Points[J][I]);
+ for I := High(Points[J]) downto 0 do Result.Add(Points[J][I]);
+ end;
+ end;
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_RangeBars.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_RangeBars.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_RangeBars.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_RangeBars.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_RangeBars.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1925 @@
+unit GR32_RangeBars;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Andre Beckedorf <Andre at metaException.de>
+ * Marc Lafon
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_RangeBars.pas,v 1.2 2004/07/07 11:39:58 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+{$IFDEF CLX}
+ Qt, Types,
+ {$IFDEF LINUX}Libc,{$ENDIF}
+ {$IFDEF MSWINDOWS}Windows,{$ENDIF}
+{$ELSE}
+ Windows, Messages, GR32,
+{$ENDIF}
+ SysUtils, Classes,
+{$IFDEF CLX}
+ QGraphics, QControls, QForms, QDialogs, QExtCtrls
+{$ELSE}
+ Graphics, Controls, Forms, Dialogs, ExtCtrls
+{$ENDIF};
+
+{$IFDEF CLX}
+const
+ DFCS_INACTIVE = $100;
+ DFCS_PUSHED = $200;
+ DFCS_FLAT = $4000;
+ DFCS_SCROLLUP = 0;
+ DFCS_SCROLLDOWN = 1;
+ DFCS_SCROLLLEFT = 2;
+ DFCS_SCROLLRIGHT = 3;
+{$ENDIF}
+
+type
+ TRBDirection = (drLeft, drUp, drRight, drDown);
+ TRBDirections = set of TRBDirection;
+ TRBZone = (zNone, zBtnPrev, zTrackPrev, zHandle, zTrackNext, zBtnNext);
+ TRBStyle = (rbsDefault, rbsMac);
+ TRBBackgnd = (bgPattern, bgSolid);
+ TRBGetSizeEvent = procedure(Sender: TObject; var Size: Integer) of object;
+
+ TArrowBar = class(TCustomControl)
+ private
+ FBackgnd: TRBBackgnd;
+ FBorderStyle: TBorderStyle;
+ FButtonSize: Integer;
+ FHandleColor: TColor;
+ FButtoncolor:TColor;
+ FHighLightColor:TColor;
+ FShadowColor:TColor;
+ FBorderColor:TColor;
+ FKind: TScrollBarKind;
+ FShowArrows: Boolean;
+ FShowHandleGrip: Boolean;
+ FStyle: TRBStyle;
+ FOnChange: TNotifyEvent;
+ FOnUserChange: TNotifyEvent;
+ procedure SetButtonSize(Value: Integer);
+ procedure SetBorderStyle(Value: TBorderStyle);
+ procedure SetHandleColor(Value: TColor);
+ procedure SetHighLightColor(Value: TColor);
+ procedure SetShadowColor(Value: TColor);
+ procedure SetButtonColor(Value: TColor);
+ procedure SetBorderColor(Value: TColor);
+ procedure SetKind(Value: TScrollBarKind);
+ procedure SetShowArrows(Value: Boolean);
+ procedure SetShowHandleGrip(Value: Boolean);
+ procedure SetStyle(Value: TRBStyle);
+ procedure SetBackgnd(Value: TRBBackgnd);
+{$IFNDEF CLX}
+ procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
+ procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
+ procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
+ procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
+ procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
+{$ENDIF}
+ protected
+ GenChange: Boolean;
+ DragZone: TRBZone;
+ HotZone: TRBZone;
+ Timer: TTimer;
+ TimerMode: Integer;
+ StoredX, StoredY: Integer;
+ PosBeforeDrag: Single;
+ procedure DoChange; virtual;
+ procedure DoDrawButton(R: TRect; Direction: TRBDirection; Pushed, Enabled, Hot: Boolean); virtual;
+ procedure DoDrawHandle(R: TRect; Horz: Boolean; Pushed, Hot: Boolean); virtual;
+ procedure DoDrawTrack(R: TRect; Direction: TRBDirection; Pushed, Enabled, Hot: Boolean); virtual;
+{$IFNDEF CLX}
+ procedure DrawNCArea(ADC: HDC; const Clip: HRGN); dynamic;
+{$ENDIF}
+ function DrawEnabled: Boolean; virtual;
+ function GetBorderSize: Integer;
+ function GetHandleRect: TRect; virtual;
+ function GetButtonSize: Integer;
+ function GetTrackBoundary: TRect;
+ function GetZone(X, Y: Integer): TRBZone;
+ function GetZoneRect(Zone: TRBZone): TRect;
+{$IFDEF CLX}
+ procedure MouseLeave(AControl: TControl); override;
+ procedure EnabledChanged; override;
+ function WidgetFlags: Integer; override;
+{$ENDIF}
+ procedure MouseLeft; virtual;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
+ procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
+ procedure Paint; override;
+ procedure StartDragTracking;
+ procedure StartHotTracking;
+ procedure StopDragTracking;
+ procedure StopHotTracking;
+ procedure TimerHandler(Sender: TObject); virtual;
+ public
+ constructor Create(AOwner: TComponent); override;
+ property Color default clScrollBar;
+ property Backgnd: TRBBackgnd read FBackgnd write SetBackgnd;
+ property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
+ property ButtonSize: Integer read FButtonSize write SetButtonSize default 0;
+ property HandleColor: TColor read FHandleColor write SetHandleColor default clBtnShadow;
+ property ButtonColor:TColor read FButtonColor write SetButtonColor default clBtnFace;
+ property HighLightColor:TColor read FHighLightColor write SetHighLightColor default clBtnHighlight;
+ property ShadowColor:TColor read FShadowColor write SetShadowColor default clBtnShadow;
+ property BorderColor:TColor read FBorderColor write SetBorderColor default clWindowFrame;
+ property Kind: TScrollBarKind read FKind write SetKind default sbHorizontal;
+ property ShowArrows: Boolean read FShowArrows write SetShowArrows default True;
+ property ShowHandleGrip: Boolean read FShowHandleGrip write SetShowHandleGrip;
+ property Style: TRBStyle read FStyle write SetStyle default rbsDefault;
+ property OnChange: TNotifyEvent read FOnChange write FOnChange;
+ property OnUserChange: TNotifyEvent read FOnUserChange write FOnUserChange;
+ end;
+
+ TRBIncrement = 1..32768;
+
+ TCustomRangeBar = class(TArrowBar)
+ private
+ FCentered: Boolean;
+ FEffectiveWindow: Integer;
+ FIncrement: TRBIncrement;
+ FPosition: Single;
+ FRange: Integer;
+ FWindow: Integer;
+ function IsPositionStored: Boolean;
+ procedure SetPosition(Value: Single);
+ procedure SetRange(Value: Integer);
+ procedure SetWindow(Value: Integer);
+ protected
+ procedure AdjustPosition;
+ function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
+ {$IFDEF CLX}const{$ENDIF} MousePos: TPoint): Boolean; override;
+ function DrawEnabled: Boolean; override;
+ function GetHandleRect: TRect; override;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
+ procedure TimerHandler(Sender: TObject); override;
+ procedure UpdateEffectiveWindow;
+ property EffectiveWindow: Integer read FEffectiveWindow;
+ public
+ constructor Create(AOwner: TComponent); override;
+ procedure Resize; override;
+ procedure SetParams(NewRange, NewWindow: Integer);
+ property Centered: Boolean read FCentered write FCentered;
+ property Increment: TRBIncrement read FIncrement write FIncrement default 8;
+ property Position: Single read FPosition write SetPosition stored IsPositionStored;
+ property Range: Integer read FRange write SetRange default 0;
+ property Window: Integer read FWindow write SetWindow default 0;
+ end;
+
+ TRangeBar = class(TCustomRangeBar)
+ published
+ property Align;
+ property Anchors;
+ property Constraints;
+ property Color;
+ property Backgnd;
+ property BorderStyle;
+ property ButtonSize;
+ property Enabled;
+ property HandleColor;
+ property ButtonColor;
+ property HighLightColor;
+ property ShadowColor;
+ property BorderColor;
+ property Increment;
+ property Kind;
+ property Range;
+ property Style;
+ property Visible;
+ property Window;
+ property ShowArrows;
+ property ShowHandleGrip;
+ property Position; // this should be located after the Range property
+ property OnChange;
+ property OnDragDrop;
+ property OnDragOver;
+ property OnEndDrag;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnMouseWheelUp;
+ property OnMouseWheelDown;
+ property OnStartDrag;
+ property OnUserChange;
+ end;
+
+ TCustomGaugeBar = class(TArrowBar)
+ private
+ FHandleSize: Integer;
+ FLargeChange: Integer;
+ FMax: Integer;
+ FMin: Integer;
+ FPosition: Integer;
+ FSmallChange: Integer;
+ procedure SetHandleSize(Value: Integer);
+ procedure SetMax(Value: Integer);
+ procedure SetMin(Value: Integer);
+ procedure SetPosition(Value: Integer);
+ procedure SetLargeChange(Value: Integer);
+ procedure SetSmallChange(Value: Integer);
+ protected
+ procedure AdjustPosition;
+ function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
+ {$IFDEF CLX}const{$ENDIF} MousePos: TPoint): Boolean; override;
+ function GetHandleRect: TRect; override;
+ function GetHandleSize: Integer;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
+ procedure TimerHandler(Sender: TObject); override;
+ public
+ constructor Create(AOwner: TComponent); override;
+ property HandleSize: Integer read FHandleSize write SetHandleSize default 0;
+ property LargeChange: Integer read FLargeChange write SetLargeChange default 1;
+ property Max: Integer read FMax write SetMax default 100;
+ property Min: Integer read FMin write SetMin default 0;
+ property Position: Integer read FPosition write SetPosition;
+ property SmallChange: Integer read FSmallChange write SetSmallChange default 1;
+ property OnChange;
+ property OnUserChange;
+ end;
+
+ TGaugeBar = class(TCustomGaugeBar)
+ published
+ property Align;
+ property Anchors;
+ property Constraints;
+ property Color;
+ property Backgnd;
+ property BorderStyle;
+ property ButtonSize;
+ property Enabled;
+ property HandleColor;
+ property ButtonColor;
+ property HighLightColor;
+ property ShadowColor;
+ property BorderColor;
+ property HandleSize;
+ property Kind;
+ property LargeChange;
+ property Max;
+ property Min;
+ property ShowArrows;
+ property ShowHandleGrip;
+ property Style;
+ property SmallChange;
+ property Visible;
+ property Position;
+ property OnChange;
+ property OnDragDrop;
+ property OnDragOver;
+ property OnEndDrag;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnStartDrag;
+ property OnUserChange;
+ end;
+
+ { TArrowBarAccess }
+ { This class is designed to facilitate access to
+ properties of TArrowBar class when creating custom controls, which
+ incorporate TArrowBar. It allows controlling up to two arrow bars.
+ Master is used to read and write properties, slave - only to write.
+
+ Well, maybe it is not so useful itself, but it is a common ancestor
+ for TRangeBarAccess and TGaugeBarAccess classes, which work much the
+ same way.
+
+ When writing a new control, which uses TArrowBar, declare the bar as
+ protected member, TArrowBarAccess as published property, and assign
+ its Master to the arrow bar }
+ TArrowBarAccess = class(TPersistent)
+ private
+ FMaster: TArrowBar;
+ FSlave: TArrowBar;
+ function GetBackgnd: TRBBackgnd;
+ function GetButtonSize: Integer;
+ function GetColor: TColor;
+ function GetHandleColor: TColor;
+ function GetHighLightColor: TColor;
+ function GetButtonColor: TColor;
+ function GetBorderColor: TColor;
+ function GetShadowColor: TColor;
+ function GetShowArrows: Boolean;
+ function GetShowHandleGrip: Boolean;
+ function GetStyle: TRBStyle;
+ procedure SetBackgnd(Value: TRBBackgnd);
+ procedure SetButtonSize(Value: Integer);
+ procedure SetColor(Value: TColor);
+ procedure SetHandleColor(Value: TColor);
+ procedure SetShowArrows(Value: Boolean);
+ procedure SetShowHandleGrip(Value: Boolean);
+ procedure SetStyle(Value: TRBStyle);
+ procedure SetHighLightColor(Value: TColor);
+ procedure SetShadowColor(Value: TColor);
+ procedure SetButtonColor(Value: TColor);
+ procedure SetBorderColor(Value: TColor);
+ public
+ property Master: TArrowBar read FMaster write FMaster;
+ property Slave: TArrowBar read FSlave write FSlave;
+ published
+ property Color: TColor read GetColor write SetColor default clScrollBar;
+ property Backgnd: TRBBackgnd read GetBackgnd write SetBackgnd default bgPattern;
+ property ButtonSize: Integer read GetButtonSize write SetButtonSize default 0;
+ property HandleColor: TColor read GetHandleColor write SetHandleColor default clBtnShadow;
+ property ButtonColor:TColor read GetButtonColor write SetButtonColor default clBtnFace;
+ property HighLightColor:TColor read GetHighLightColor write SetHighLightColor default clBtnHighlight;
+ property ShadowColor:TColor read GetShadowColor write SetShadowColor default clBtnShadow;
+ property BorderColor:TColor read GetBorderColor write SetBorderColor default clWindowFrame;
+ property ShowArrows: Boolean read GetShowArrows write SetShowArrows default True;
+ property ShowHandleGrip: Boolean read GetShowHandleGrip write SetShowHandleGrip;
+ property Style: TRBStyle read GetStyle write SetStyle;
+ end;
+
+implementation
+
+uses Math, GR32_System;
+
+const
+ OppositeDirection: array [TRBDirection] of TRBDirection = (drRight, drDown, drLeft, drUp);
+ tmScrollFirst = 1;
+ tmScroll = 2;
+ tmHotTrack = 3;
+
+function ClrLighten(C: TColor; Amount: Integer): TColor;
+var
+ R, G, B: Integer;
+begin
+{$IFDEF CLX}
+ C := ColorToRGB(C);
+{$ELSE}
+ if C < 0 then C := GetSysColor(C and $000000FF);
+{$ENDIF}
+ R := C and $FF + Amount;
+ G := C shr 8 and $FF + Amount;
+ B := C shr 16 and $FF + Amount;
+ if R < 0 then R := 0 else if R > 255 then R := 255;
+ if G < 0 then G := 0 else if G > 255 then G := 255;
+ if B < 0 then B := 0 else if B > 255 then B := 255;
+ Result := R or (G shl 8) or (B shl 16);
+end;
+
+function MixColors(C1, C2: TColor; W1: Integer): TColor;
+var
+ W2: Cardinal;
+begin
+ Assert(W1 in [0..255]);
+ W2 := W1 xor 255;
+{$IFDEF CLX}
+ C1 := ColorToRGB(C1);
+ C2 := ColorToRGB(C2);
+{$ELSE}
+ if Integer(C1) < 0 then C1 := GetSysColor(C1 and $000000FF);
+ if Integer(C2) < 0 then C2 := GetSysColor(C2 and $000000FF);
+{$ENDIF}
+ Result := Integer(
+ ((Cardinal(C1) and $FF00FF) * Cardinal(W1) +
+ (Cardinal(C2) and $FF00FF) * W2) and $FF00FF00 +
+ ((Cardinal(C1) and $00FF00) * Cardinal(W1) +
+ (Cardinal(C2) and $00FF00) * W2) and $00FF0000) shr 8;
+end;
+
+procedure DitherRect(Canvas: TCanvas; const R: TRect; C1, C2: TColor);
+var
+ B: TBitmap;
+{$IFNDEF CLX}
+ Brush: HBRUSH;
+{$ELSE}
+ Brush: TBrush;
+ OldBrush: TBrush;
+{$ENDIF}
+begin
+ if IsRectEmpty(R) then Exit;
+{$IFDEF CLX}
+ Brush := TBrush.Create;
+ if C1 = C2 then
+ begin
+ Brush.Color := ColorToRGB(C1);
+ end
+ else
+ begin
+ B := AllocPatternBitmap(C1, C2);
+ Brush.Bitmap := B;
+ end;
+ OldBrush := TBrush.Create;
+ OldBrush.Assign(Canvas.Brush);
+ Canvas.Brush.Assign(Brush);
+ Canvas.FillRect(R);
+ Canvas.Brush.Assign(OldBrush);
+ Brush.Free;
+ OldBrush.Free;
+{$ELSE}
+ if C1 = C2 then
+ Brush := CreateSolidBrush(ColorToRGB(C1))
+ else
+ begin
+ B := AllocPatternBitmap(C1, C2);
+ B.HandleType := bmDDB;
+ Brush := CreatePatternBrush(B.Handle);
+ end;
+ FillRect(Canvas.Handle, R, Brush);
+ DeleteObject(Brush);
+{$ENDIF}
+end;
+
+procedure DrawRectEx(Canvas: TCanvas; var R: TRect; Sides: TRBDirections; C: TColor);
+begin
+ if Sides <> [] then with Canvas, R do
+ begin
+ Pen.Color := C;
+ if drUp in Sides then
+ begin
+ MoveTo(Left, Top); LineTo(Right, Top); Inc(Top);
+ end;
+ if drDown in Sides then
+ begin
+ Dec(Bottom); MoveTo(Left, Bottom); LineTo(Right, Bottom);
+ end;
+ if drLeft in Sides then
+ begin
+ MoveTo(Left, Top); LineTo(Left, Bottom); Inc(Left);
+ end;
+ if drRight in Sides then
+ begin
+ Dec(Right); MoveTo(Right, Top); LineTo(Right, Bottom);
+ end;
+ end;
+end;
+
+{$IFDEF CLX}
+procedure FrameRect(Canvas: TCanvas; const R: TRect);
+begin
+ with Canvas, R do
+ Rectangle(Left, Top, Right, Bottom);
+end;
+{$ENDIF}
+
+procedure Frame3D(Canvas: TCanvas; var ARect: TRect; TopColor, BottomColor: TColor; AdjustRect: Boolean = True);
+var
+ TopRight, BottomLeft: TPoint;
+begin
+ with Canvas, ARect do
+ begin
+ Pen.Width := 1;
+ Dec(Bottom); Dec(Right);
+ TopRight.X := Right;
+ TopRight.Y := Top;
+ BottomLeft.X := Left;
+ BottomLeft.Y := Bottom;
+ Pen.Color := TopColor;
+ PolyLine([BottomLeft, TopLeft, TopRight]);
+ Pen.Color := BottomColor;
+ Dec(Left);
+ PolyLine([TopRight, BottomRight, BottomLeft]);
+ if AdjustRect then
+ begin
+ Inc(Top); Inc(Left, 2);
+ end
+ else
+ begin
+ Inc(Left); Inc(Bottom); Inc(Right);
+ end;
+ end;
+end;
+
+procedure DrawHandle(Canvas: TCanvas; R: TRect; Color: TColor;
+ Pushed, ShowGrip, IsHorz: Boolean; ColorBorder: TColor);
+var
+ CHi, CLo: TColor;
+ I, S: Integer;
+begin
+ CHi := ClrLighten(Color, 24);
+ CLo := ClrLighten(Color, -24);
+
+{$IFDEF CLX}
+ Canvas.Pen.Color := ColorBorder; // CLX FrameRect function is using Pen instead of Brush
+ FrameRect(Canvas, R);
+{$ELSE}
+ Canvas.Brush.Color := ColorBorder;
+ FrameRect(Canvas.Handle, R, Canvas.Brush.Handle);
+{$ENDIF}
+
+ InflateRect(R, -1, -1);
+ if Pushed then Frame3D(Canvas, R, CLo, Color)
+ else Frame3D(Canvas, R, CHi, MixColors(ColorBorder, Color, 96));
+ Canvas.Brush.Color := Color;
+ Canvas.FillRect(R);
+
+ if ShowGrip then
+ begin
+ if Pushed then OffsetRect(R, 1, 1);
+ if IsHorz then
+ begin
+ S := R.Right - R.Left;
+ R.Left := (R.Left + R.Right) div 2 - 5;
+ R.Right := R.Left + 2;
+ Inc(R.Top); Dec(R.Bottom);
+
+ if S > 10 then Frame3D(Canvas, R, CHi, CLo, False);
+ Inc(R.Left, 3); Inc(R.Right, 3);
+ Frame3D(Canvas, R, CHi, CLo, False);
+ Inc(R.Left, 3); Inc(R.Right, 3);
+ Frame3D(Canvas, R, CHi, CLo, False);
+ Inc(R.Left, 3); Inc(R.Right, 3);
+ if S > 10 then Frame3D(Canvas, R, CHi, CLo, False);
+ end
+ else
+ begin
+ I := (R.Top + R.Bottom) div 2;
+ S := R.Bottom - R.Top;
+ R.Top := I - 1;
+ R.Bottom := I + 1;
+ Dec(R.Right);
+ Inc(R.Left);
+
+ OffsetRect(R, 0, -4);
+ if S > 10 then
+ begin
+ Frame3D(Canvas, R, CHi, CLo, False);
+ end;
+
+ OffsetRect(R, 0, 3);
+ Frame3D(Canvas, R, CHi, CLo, False);
+
+ OffsetRect(R, 0, 3);
+ Frame3D(Canvas, R, CHi, CLo, False);
+
+ if S > 10 then
+ begin
+ OffsetRect(R, 0, 3);
+ Frame3D(Canvas, R, CHi, CLo, False);
+ end;
+ end;
+ end;
+end;
+
+procedure DrawArrow(Canvas: TCanvas; R: TRect; Direction: TRBDirection; Color: TColor);
+var
+ X, Y, Sz, Shift: Integer;
+begin
+ X := (R.Left + R.Right - 1) div 2;
+ Y := (R.Top + R.Bottom - 1) div 2;
+ Sz := (Min(X - R.Left, Y - R.Top)) * 3 div 4 - 1;
+ if Sz = 0 then Sz := 1;
+ if Direction in [drUp, drLeft] then Shift := (Sz + 1) * 1 div 3
+ else Shift := Sz * 1 div 3;
+ Canvas.Pen.Color := Color;
+ Canvas.Brush.Color := Color;
+ case Direction of
+ drUp:
+ begin
+ Inc(Y, Shift);
+ Canvas.Polygon([Point(X + Sz, Y), Point(X, Y - Sz), Point(X - Sz, Y)]);
+ end;
+ drDown:
+ begin
+ Dec(Y, Shift);
+ Canvas.Polygon([Point(X + Sz, Y), Point(X, Y + Sz), Point(X - Sz, Y)]);
+ end;
+ drLeft:
+ begin
+ Inc(X, Shift);
+ Canvas.Polygon([Point(X, Y + Sz), Point(X - Sz, Y), Point(X, Y - Sz)]);
+ end;
+ drRight:
+ begin
+ Dec(X, Shift);
+ Canvas.Polygon([Point(X, Y + Sz), Point(X + Sz, Y), Point(X, Y - Sz)]);
+ end;
+ end;
+end;
+
+const
+ FIRST_DELAY = 600;
+ SCROLL_INTERVAL = 100;
+ HOTTRACK_INTERVAL = 150;
+ MIN_SIZE = 17;
+
+{ TArrowBar }
+
+{$IFDEF CLX}
+procedure TArrowBar.EnabledChanged;
+{$ELSE}
+procedure TArrowBar.CMEnabledChanged(var Message: TMessage);
+{$ENDIF}
+begin
+ inherited;
+ Invalidate;
+end;
+
+{$IFDEF CLX}
+procedure TArrowBar.MouseLeave(AControl: TControl);
+{$ELSE}
+procedure TArrowBar.CMMouseLeave(var Message: TMessage);
+{$ENDIF}
+begin
+ MouseLeft;
+end;
+
+constructor TArrowBar.Create(AOwner: TComponent);
+begin
+ inherited;
+ ControlStyle := ControlStyle - [csAcceptsControls, csDoubleClicks] + [csOpaque];
+ Width := 100;
+ Height := 16;
+ ParentColor := False;
+ Color := clScrollBar;
+ Timer := TTimer.Create(Self);
+ Timer.OnTimer := TimerHandler;
+ FShowArrows := True;
+ FBorderStyle := bsSingle;
+ FHandleColor := clBtnShadow;
+ FButtonColor := clBtnFace;
+ FHighLightColor := clBtnHighlight;
+ FShadowColor := clBtnShadow;
+ FBorderColor := clWindowFrame;
+ FShowHandleGrip := True;
+end;
+
+procedure TArrowBar.DoChange;
+begin
+ if Assigned(FOnChange) then FOnChange(Self);
+ if GenChange and Assigned(FOnUserChange) then FOnUserChange(Self);
+end;
+
+procedure TArrowBar.DoDrawButton(R: TRect; Direction: TRBDirection; Pushed, Enabled, Hot: Boolean);
+const
+ EnabledFlags: array [Boolean] of Integer = (DFCS_INACTIVE, 0);
+ PushedFlags: array [Boolean] of Integer = (0, DFCS_PUSHED or DFCS_FLAT);
+ DirectionFlags: array [TRBDirection] of Integer = (DFCS_SCROLLLEFT, DFCS_SCROLLUP,
+ DFCS_SCROLLRIGHT, DFCS_SCROLLDOWN);
+{$IFNDEF CLX}
+ DirectionXPFlags: array [TRBDirection] of Cardinal = (ABS_LEFTNORMAL, ABS_UPNORMAL,
+ ABS_RIGHTNORMAL, ABS_DOWNNORMAL);
+{$ENDIF}
+var
+ Edges: TRBDirections;
+{$IFNDEF CLX}
+ Flags: Integer;
+{$ENDIF}
+begin
+ if Style = rbsDefault then
+ begin
+{$IFDEF CLX}
+ Canvas.Brush.Color := clButton;
+ Canvas.FillRect(R);
+ DrawWinButton(Canvas, R, Pushed);
+ InflateRect(R, -2, -2);
+
+ If not DrawEnabled then
+ begin
+ InflateRect(R, -1, -1);
+ OffsetRect(R, 1, 1);
+ DrawArrow(Canvas, R, Direction, clWhite);
+ OffsetRect(R, -1, -1);
+ DrawArrow(Canvas, R, Direction, clDisabledButtonText);
+ end
+ else
+ begin
+ If Pushed then OffsetRect(R, 1, 1);
+ DrawArrow(Canvas, R, Direction, clButtonText);
+ end;
+{$ELSE}
+ if USE_THEMES then
+ begin
+ Flags := DirectionXPFlags[Direction];
+ if not Enabled then Inc(Flags, 3)
+ else if Pushed then Inc(Flags, 2)
+ else if Hot then Inc(Flags);
+ DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, SBP_ARROWBTN, Flags, R, nil);
+ end
+ else
+ DrawFrameControl(Canvas.Handle, R, DFC_SCROLL,
+ DirectionFlags[Direction] or EnabledFlags[DrawEnabled] or PushedFlags[Pushed])
+{$ENDIF}
+ end
+ else
+ begin
+ Edges := [drLeft, drUp, drRight, drDown];
+ Exclude(Edges, OppositeDirection[Direction]);
+
+ if not DrawEnabled then
+ begin
+ DrawRectEx(Canvas, R, Edges, fShadowColor);
+ Canvas.Brush.Color := fButtonColor;
+{$IFDEF CLX}
+ Canvas.FillRect(R);
+{$ELSE}
+ FillRect(Canvas.Handle, R, Canvas.Brush.Handle);
+{$ENDIF}
+ InflateRect(R, -1, -1);
+ OffsetRect(R, 1, 1);
+ DrawArrow(Canvas, R, Direction, fHighLightColor);
+ OffsetRect(R, -1, -1);
+ DrawArrow(Canvas, R, Direction, fShadowColor);
+ end
+ else
+ begin
+ DrawRectEx(Canvas, R, Edges, fBorderColor);
+ if Pushed then
+ begin
+ Canvas.Brush.Color := fButtonColor;
+{$IFDEF CLX}
+ Canvas.FillRect(R);
+{$ELSE}
+ FillRect(Canvas.Handle, R, Canvas.Brush.Handle);
+{$ENDIF}
+ OffsetRect(R, 1, 1);
+ InflateRect(R, -1, -1);
+ end
+ else
+ begin
+ Frame3D(Canvas, R, fHighLightColor, fShadowColor, True);
+ Canvas.Brush.Color := fButtonColor;
+{$IFDEF CLX}
+ Canvas.FillRect(R);
+{$ELSE}
+ FillRect(Canvas.Handle, R, Canvas.Brush.Handle);
+{$ENDIF}
+ end;
+ DrawArrow(Canvas, R, Direction, fBorderColor);
+ end;
+ end;
+end;
+
+procedure TArrowBar.DoDrawHandle(R: TRect; Horz, Pushed, Hot: Boolean);
+{$IFNDEF CLX}
+const
+ PartXPFlags: array [Boolean] of Cardinal = (SBP_THUMBBTNVERT, SBP_THUMBBTNHORZ);
+ GripperFlags: array [Boolean] of Cardinal = (SBP_GRIPPERVERT, SBP_GRIPPERHORZ);
+var
+ Flags: Cardinal;
+{$ENDIF}
+begin
+ if IsRectEmpty(R) then Exit;
+ case Style of
+ rbsDefault:
+{$IFNDEF CLX}
+ if USE_THEMES then
+ begin
+ Flags := SCRBS_NORMAL;
+ if not Enabled then Inc(Flags, 3)
+ else if Pushed then Inc(Flags, 2)
+ else if Hot then Inc(Flags);
+ DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, PartXPFlags[Horz], Flags, R, nil);
+ if ShowHandleGrip then
+ DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, GripperFlags[Horz], 0, R, nil);
+ end
+ else
+ DrawEdge(Canvas.Handle, R, EDGE_RAISED, BF_RECT or BF_MIDDLE);
+{$ELSE}
+ begin
+ Canvas.Brush.Color := clButton;
+ Canvas.FillRect(R);
+ DrawWinButton(Canvas, R, False);
+ end;
+{$ENDIF}
+ rbsMac:
+ DrawHandle(Canvas, R, HandleColor, Pushed, ShowHandleGrip, Horz, fBorderColor);
+ end;
+end;
+
+procedure TArrowBar.DoDrawTrack(R: TRect; Direction: TRBDirection; Pushed, Enabled, Hot: Boolean);
+{$IFNDEF CLX}
+const
+ PartXPFlags: array [TRBDirection] of Cardinal =
+ (SBP_LOWERTRACKHORZ, SBP_LOWERTRACKVERT, SBP_UPPERTRACKHORZ, SBP_UPPERTRACKVERT);
+{$ENDIF}
+var
+{$IFNDEF CLX}
+ Flags: Cardinal;
+{$ENDIF}
+ C: TColor;
+ Edges: set of TRBDirection;
+begin
+ if (R.Right <= R.Left) or (R.Bottom <= R.Top) then Exit;
+ if Style = rbsDefault then
+ begin
+{$IFNDEF CLX}
+ if USE_THEMES then
+ begin
+ Flags := SCRBS_NORMAL;
+ if Pushed then Inc(Flags, 2);
+ DrawThemeBackground(SCROLLBAR_THEME, Canvas.Handle, PartXPFlags[Direction], Flags, R, nil);
+ end
+ else
+{$ENDIF}
+ begin
+ if Pushed then DitherRect(Canvas, R, clWindowFrame, clWindowFrame)
+ else DitherRect(Canvas, R, clBtnHighlight, Color);
+ end;
+ end
+ else
+ with Canvas, R do
+ begin
+ if DrawEnabled then C := FBorderColor
+ else C := FShadowColor;
+ Edges := [drLeft, drUp, drRight, drDown];
+ Exclude(Edges, OppositeDirection[Direction]);
+ DrawRectEx(Canvas, R, Edges, C);
+ if Pushed then DitherRect(Canvas, R, fBorderColor,fBorderColor)
+ else if not IsRectEmpty(R) then with R do
+ begin
+ if DrawEnabled then
+ begin
+ Pen.Color := MixColors(fBorderColor, MixColors(fHighLightColor, Color, 127), 32);
+ case Direction of
+ drLeft, drUp:
+ begin
+ MoveTo(Left, Bottom - 1); LineTo(Left, Top); LineTo(Right, Top);
+ Inc(Top); Inc(Left);
+ end;
+ drRight:
+ begin
+ MoveTo(Left, Top); LineTo(Right, Top);
+ Inc(Top);
+ end;
+ drDown:
+ begin
+ MoveTo(Left, Top); LineTo(Left, Bottom);
+ Inc(Left);
+ end;
+ end;
+ if Backgnd = bgPattern then DitherRect(Canvas, R, fHighLightColor, Color)
+ else DitherRect(Canvas, R, Color, Color);
+ end
+ else
+ begin
+ Brush.Color := fButtonColor;
+ FillRect(R);
+ end;
+ end;
+ end;
+end;
+
+function TArrowBar.DrawEnabled: Boolean;
+begin
+ Result := Enabled;
+end;
+
+{$IFNDEF CLX}
+procedure TArrowBar.DrawNCArea(ADC: HDC; const Clip: HRGN);
+var
+ DC: HDC;
+ R: TRect;
+begin
+ if BorderStyle = bsNone then Exit;
+ if ADC = 0 then DC := GetWindowDC(Handle)
+ else DC := ADC;
+ try
+ GetWindowRect(Handle, R);
+ OffsetRect(R, -R.Left, -R.Top);
+ DrawEdge(DC, R, BDR_SUNKENOUTER, BF_RECT);
+ finally
+ if ADC = 0 then ReleaseDC(Handle, DC);
+ end;
+end;
+{$ENDIF}
+
+function TArrowBar.GetBorderSize: Integer;
+const
+ CSize: array [Boolean] of Integer = (0, 1);
+begin
+ Result := CSize[BorderStyle = bsSingle];
+end;
+
+function TArrowBar.GetButtonSize: Integer;
+var
+ W, H: Integer;
+begin
+ if not ShowArrows then Result := 0
+ else
+ begin
+ Result := ButtonSize;
+ if Kind = sbHorizontal then
+ begin
+ W := ClientWidth;
+ H := ClientHeight;
+ end
+ else
+ begin
+ W := ClientHeight;
+ H := ClientWidth;
+ end;
+ if Result = 0 then Result := Min(H, 32);
+ if Result * 2 >= W then Result := W div 2;
+ if Style = rbsMac then Dec(Result);
+ if Result < 2 then Result := 0;
+ end;
+end;
+
+function TArrowBar.GetHandleRect: TRect;
+begin
+ Result := Rect(0, 0, 0, 0);
+end;
+
+function TArrowBar.GetTrackBoundary: TRect;
+begin
+ Result := ClientRect;
+ if Kind = sbHorizontal then InflateRect(Result, -GetButtonSize, 0)
+ else InflateRect(Result, 0, -GetButtonSize);
+end;
+
+function TArrowBar.GetZone(X, Y: Integer): TRBZone;
+var
+ P: TPoint;
+ R, R1: TRect;
+ Sz: Integer;
+begin
+ Result := zNone;
+
+ P := Point(X, Y);
+ R := ClientRect;
+ if not PtInrect(R, P) then Exit;
+
+ Sz := GetButtonSize;
+ R1 := R;
+ if Kind = sbHorizontal then
+ begin
+ R1.Right := R1.Left + Sz;
+ if PtInRect(R1, P) then Result := zBtnPrev
+ else
+ begin
+ R1.Right := R.Right;
+ R1.Left := R.Right - Sz;
+ if PtInRect(R1, P) then Result := zBtnNext;
+ end;
+ end
+ else
+ begin
+ R1.Bottom := R1.Top + Sz;
+ if PtInRect(R1, P) then Result := zBtnPrev
+ else
+ begin
+ R1.Bottom := R.Bottom;
+ R1.Top := R.Bottom - Sz;
+ if PtInRect(R1, P) then Result := zBtnNext;
+ end;
+ end;
+
+ if Result = zNone then
+ begin
+ R := GetHandleRect;
+ P := Point(X, Y);
+ if PtInRect(R, P) then Result := zHandle
+ else
+ begin
+ if Kind = sbHorizontal then
+ begin
+ if (X > 0) and (X < R.Left) then Result := zTrackPrev
+ else if (X >= R.Right) and (X < ClientWidth - 1) then Result := zTrackNext;
+ end
+ else
+ begin
+ if (Y > 0) and (Y < R.Top) then Result := zTrackPrev
+ else if (Y >= R.Bottom) and (Y < ClientHeight - 1) then Result := zTrackNext;
+ end;
+ end;
+ end;
+end;
+
+function TArrowBar.GetZoneRect(Zone: TRBZone): TRect;
+const
+ CEmptyRect: TRect = (Left: 0; Top: 0; Right: 0; Bottom: 0);
+var
+ BtnSize: Integer;
+ Horz: Boolean;
+ R: TRect;
+begin
+ Horz := Kind = sbHorizontal;
+ BtnSize:= GetButtonSize;
+ case Zone of
+ zNone: Result := CEmptyRect;
+ zBtnPrev:
+ begin
+ Result := ClientRect;
+ if Horz then Result.Right := Result.Left + BtnSize
+ else Result.Bottom := Result.Top + BtnSize;
+ end;
+ zTrackPrev..zTrackNext:
+ begin
+ Result := GetTrackBoundary;
+ R := GetHandleRect;
+ if not DrawEnabled or IsRectEmpty(R) then
+ begin
+ R.Left := (Result.Left + Result.Right) div 2;
+ R.Top := (Result.Top + Result.Bottom) div 2;
+ R.Right := R.Left;
+ R.Bottom := R.Top;
+ end;
+ case Zone of
+ zTrackPrev:
+ if Horz then Result.Right := R.Left
+ else Result.Bottom := R.Top;
+ zHandle:
+ Result := R;
+ zTrackNext:
+ if Horz then Result.Left := R.Right
+ else Result.Top := R.Bottom;
+ end;
+ end;
+ zBtnNext:
+ begin
+ Result := ClientRect;
+ if Horz then Result.Left := Result.Right - BtnSize
+ else Result.Top := Result.Bottom - BtnSize;
+ end;
+ end;
+end;
+
+procedure TArrowBar.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ inherited;
+ if Button <> mbLeft then Exit;
+ DragZone := GetZone(X, Y);
+ Invalidate;
+ StoredX := X;
+ StoredY := Y;
+ StartDragTracking;
+end;
+
+procedure TArrowBar.MouseLeft;
+begin
+ StopHotTracking;
+end;
+
+procedure TArrowBar.MouseMove(Shift: TShiftState; X, Y: Integer);
+var
+ NewHotZone: TRBZone;
+begin
+ inherited;
+ if (DragZone = zNone) and DrawEnabled then
+ begin
+ NewHotZone := GetZone(X, Y);
+ if NewHotZone <> HotZone then
+ begin
+ HotZone := NewHotZone;
+ if HotZone <> zNone then StartHotTracking;
+ Invalidate;
+ end;
+ end;
+end;
+
+procedure TArrowBar.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ inherited;
+ DragZone := zNone;
+ Invalidate;
+ StopDragTracking;
+end;
+
+procedure TArrowBar.Paint;
+const
+ CPrevDirs: array [Boolean] of TRBDirection = (drUp, drLeft);
+ CNextDirs: array [Boolean] of TRBDirection = (drDown, drRight);
+var
+ BSize: Integer;
+ ShowEnabled: Boolean;
+ R, BtnRect, HandleRect: TRect;
+ Horz, ShowHandle: Boolean;
+begin
+ R := ClientRect;
+ Horz := Kind = sbHorizontal;
+ ShowEnabled := DrawEnabled;
+ BSize := GetButtonSize;
+
+ if ShowArrows then
+ begin
+ { left / top button }
+ BtnRect := R;
+ with BtnRect do if Horz then Right := Left + BSize else Bottom := Top + BSize;
+ DoDrawButton(BtnRect, CPrevDirs[Horz], DragZone = zBtnPrev, ShowEnabled, HotZone = zBtnPrev);
+
+ { right / bottom button }
+ BtnRect := R;
+ with BtnRect do if Horz then Left := Right - BSize else Top := Bottom - BSize;
+ DoDrawButton(BtnRect, CNextDirs[Horz], DragZone = zBtnNext, ShowEnabled, HotZone = zBtnNext);
+ end;
+
+ if Horz then InflateRect(R, -BSize, 0) else InflateRect(R, 0, -BSize);
+ if ShowEnabled then HandleRect := GetHandleRect
+ else HandleRect := Rect(0, 0, 0, 0);
+ ShowHandle := not IsRectEmpty(HandleRect);
+
+ DoDrawTrack(GetZoneRect(zTrackPrev), CPrevDirs[Horz], DragZone = zTrackPrev, ShowEnabled, HotZone = zTrackPrev);
+ DoDrawTrack(GetZoneRect(zTrackNext), CNextDirs[Horz], DragZone = zTrackNext, ShowEnabled, HotZone = zTrackNext);
+ if ShowHandle then DoDrawHandle(HandleRect, Horz, DragZone = zHandle, HotZone = zHandle);
+end;
+
+procedure TArrowBar.SetBackgnd(Value: TRBBackgnd);
+begin
+ if Value <> FBackgnd then
+ begin
+ FBackgnd := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetBorderStyle(Value: TBorderStyle);
+begin
+ if Value <> FBorderStyle then
+ begin
+ FBorderStyle := Value;
+{$IFDEF CLX}
+ Invalidate;
+{$ELSE}
+ RecreateWnd;
+{$ENDIF}
+ end;
+end;
+
+procedure TArrowBar.SetButtonSize(Value: Integer);
+begin
+ if Value <> FButtonSize then
+ begin
+ FButtonSize := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetHandleColor(Value: TColor);
+begin
+ if Value <> FHandleColor then
+ begin
+ FHandleColor := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetHighLightColor(Value: TColor);
+begin
+ if Value <> FHighLightColor then
+ begin
+ FHighLightColor := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetButtonColor(Value: TColor);
+begin
+ if Value <> FButtonColor then
+ begin
+ FButtonColor := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetBorderColor(Value: TColor);
+begin
+ if Value <> FBorderColor then
+ begin
+ FBorderColor := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetShadowColor(Value: TColor);
+begin
+ if Value <> FShadowColor then
+ begin
+ FShadowColor := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetKind(Value: TScrollBarKind);
+var
+ Tmp: Integer;
+begin
+ if Value <> FKind then
+ begin
+ FKind := Value;
+ if (csDesigning in ComponentState) and not (csLoading in ComponentState) then
+ begin
+ Tmp := Width;
+ Width := Height;
+ Height := Tmp;
+ end;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetShowArrows(Value: Boolean);
+begin
+ if Value <> FShowArrows then
+ begin
+ FShowArrows := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetShowHandleGrip(Value: Boolean);
+begin
+ if Value <> FShowHandleGrip then
+ begin
+ FShowHandleGrip := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TArrowBar.SetStyle(Value: TRBStyle);
+begin
+ FStyle := Value;
+{$IFDEF CLX}
+ Invalidate;
+{$ELSE}
+ RecreateWnd;
+{$ENDIF}
+end;
+
+procedure TArrowBar.StartDragTracking;
+begin
+ Timer.Interval := FIRST_DELAY;
+ TimerMode := tmScroll;
+ TimerHandler(Self);
+ TimerMode := tmScrollFirst;
+ Timer.Enabled := True;
+end;
+
+procedure TArrowBar.StartHotTracking;
+begin
+ Timer.Interval := HOTTRACK_INTERVAL;
+ TimerMode := tmHotTrack;
+ Timer.Enabled := True;
+end;
+
+procedure TArrowBar.StopDragTracking;
+begin
+ StartHotTracking;
+end;
+
+procedure TArrowBar.StopHotTracking;
+begin
+ Timer.Enabled := False;
+ HotZone := zNone;
+ Invalidate;
+end;
+
+procedure TArrowBar.TimerHandler(Sender: TObject);
+var
+ Pt: TPoint;
+begin
+ case TimerMode of
+ tmScrollFirst:
+ begin
+ Timer.Interval := SCROLL_INTERVAL;
+ TimerMode := tmScroll;
+ end;
+ tmHotTrack:
+ begin
+ Pt := ScreenToClient(Mouse.CursorPos);
+ if not PtInRect(ClientRect, Pt) then
+ begin
+ StopHotTracking;
+ Invalidate;
+ end;
+ end;
+ end;
+end;
+
+{$IFNDEF CLX}
+procedure TArrowBar.WMEraseBkgnd(var Message: TWmEraseBkgnd);
+begin
+ Message.Result := -1;
+end;
+
+procedure TArrowBar.WMNCCalcSize(var Message: TWMNCCalcSize);
+var
+ Sz: Integer;
+begin
+ Sz := GetBorderSize;
+ InflateRect(Message.CalcSize_Params.rgrc[0], -Sz, -Sz);
+end;
+
+procedure TArrowBar.WMNCPaint(var Message: TMessage);
+begin
+ DrawNCArea(0, HRGN(Message.WParam));
+end;
+{$ELSE}
+
+function TArrowBar.WidgetFlags: Integer;
+begin
+ Result := Inherited WidgetFlags or Integer(WidgetFlags_WRepaintNoErase) or
+ Integer(WidgetFlags_WResizeNoErase);
+end;
+{$ENDIF}
+
+{ TCustomRangeBar }
+
+procedure TCustomRangeBar.AdjustPosition;
+begin
+ if FPosition > Range - EffectiveWindow then FPosition := Range - EffectiveWindow;
+ if FPosition < 0 then FPosition := 0;
+end;
+
+constructor TCustomRangeBar.Create(AOwner: TComponent);
+begin
+ inherited;
+ FIncrement := 8;
+end;
+
+function TCustomRangeBar.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
+ {$IFDEF CLX}const{$ENDIF} MousePos: TPoint): Boolean;
+begin
+ Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos);
+ if not Result then Position := Position + Increment * WheelDelta / 120;
+ Result := True;
+end;
+
+function TCustomRangeBar.DrawEnabled: Boolean;
+begin
+ Result := Enabled and (Range > EffectiveWindow);
+end;
+
+function TCustomRangeBar.GetHandleRect: TRect;
+var
+ BtnSz, ClientSz: Integer;
+ HandleSz, HandlePos: Integer;
+ R: TRect;
+ Horz: Boolean;
+begin
+ R := Rect(0, 0, ClientWidth, ClientHeight);
+ Horz := Kind = sbHorizontal;
+ BtnSz := GetButtonSize;
+ if Horz then
+ begin
+ InflateRect(R, -BtnSz, 0);
+ ClientSz := R.Right - R.Left;
+ end
+ else
+ begin
+ InflateRect(R, 0, -BtnSz);
+ ClientSz := R.Bottom - R.Top;
+ end;
+ if ClientSz < 18 then
+ begin
+ Result := Rect(0, 0, 0, 0);
+ Exit;
+ end;
+
+ if Range > EffectiveWindow then
+ begin
+ HandleSz := Round(ClientSz * EffectiveWindow / Range);
+ if HandleSz >= MIN_SIZE then HandlePos := Round(ClientSz * Position / Range)
+ else
+ begin
+ HandleSz := MIN_SIZE;
+ HandlePos := Round((ClientSz - MIN_SIZE) * Position / (Range - EffectiveWindow));
+ end;
+ Result := R;
+ if Horz then
+ begin
+ Result.Left := R.Left + HandlePos;
+ Result.Right := R.Left + HandlePos + HandleSz;
+ end
+ else
+ begin
+ Result.Top := R.Top + HandlePos;
+ Result.Bottom := R.Top + HandlePos + HandleSz;
+ end;
+ end
+ else Result := R;
+end;
+
+function TCustomRangeBar.IsPositionStored: Boolean;
+begin
+ Result := FPosition > 0;
+end;
+
+procedure TCustomRangeBar.MouseDown(Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+begin
+ if Range <= EffectiveWindow then DragZone := zNone
+ else
+ begin
+ inherited;
+ if DragZone = zHandle then
+ begin
+ StopDragTracking;
+ PosBeforeDrag := Position;
+ end;
+ end;
+end;
+
+procedure TCustomRangeBar.MouseMove(Shift: TShiftState; X, Y: Integer);
+var
+ Delta: Single;
+ WinSz: Single;
+ ClientSz, HandleSz: Integer;
+begin
+ inherited;
+ if DragZone = zHandle then
+ begin
+ WinSz := EffectiveWindow;
+
+ if Range <= WinSz then Exit;
+ if Kind = sbHorizontal then Delta := X - StoredX else Delta := Y - StoredY;
+
+ if Kind = sbHorizontal then ClientSz := ClientWidth else ClientSz := ClientHeight;
+ Dec(ClientSz, GetButtonSize * 2);
+ if BorderStyle = bsSingle then Dec(ClientSz, 2);
+ HandleSz := Round(ClientSz * WinSz / Range);
+
+ if HandleSz < MIN_SIZE then Delta := Round(Delta * (Range - WinSz) / (ClientSz - MIN_SIZE))
+ else Delta := Delta * Range / ClientSz;
+
+ GenChange := True;
+ Position := PosBeforeDrag + Delta;
+ GenChange := False;
+ end;
+end;
+
+procedure TCustomRangeBar.Resize;
+var
+ OldWindow: Integer;
+ Center: Single;
+begin
+ if Centered then
+ begin
+ OldWindow := EffectiveWindow;
+ UpdateEffectiveWindow;
+ if Range > EffectiveWindow then
+ begin
+ if Range > OldWindow then Center := (FPosition + OldWindow * 0.5) / Range
+ else Center := 0.5;
+ FPosition := Center * Range - EffectiveWindow * 0.5;
+ end;
+ end;
+ AdjustPosition;
+ inherited;
+end;
+
+procedure TCustomRangeBar.SetParams(NewRange, NewWindow: Integer);
+var
+ OldWindow, OldRange: Integer;
+ Center: Single;
+begin
+ if NewRange < 0 then NewRange := 0;
+ if NewWindow < 0 then NewWindow := 0;
+ if (NewRange <> FRange) or (NewWindow <> EffectiveWindow) then
+ begin
+ OldWindow := EffectiveWindow;
+ OldRange := Range;
+ FRange := NewRange;
+ FWindow := NewWindow;
+ UpdateEffectiveWindow;
+ if Centered and (Range > EffectiveWindow) then
+ begin
+ if (OldRange > OldWindow) and (OldRange <> 0) then
+ Center := (FPosition + OldWindow * 0.5) / OldRange
+ else
+ Center := 0.5;
+ FPosition := Center * Range - EffectiveWindow * 0.5;
+ end;
+ AdjustPosition;
+ Invalidate;
+ end;
+end;
+
+procedure TCustomRangeBar.SetPosition(Value: Single);
+var
+ OldPosition: Single;
+begin
+ if Value <> FPosition then
+ begin
+ OldPosition := FPosition;
+ FPosition := Value;
+ AdjustPosition;
+ if OldPosition <> FPosition then
+ begin
+ Invalidate;
+ DoChange;
+ end;
+ end;
+end;
+
+procedure TCustomRangeBar.SetRange(Value: Integer);
+begin
+ SetParams(Value, Window);
+end;
+
+procedure TCustomRangeBar.SetWindow(Value: Integer);
+begin
+ SetParams(Range, Value);
+end;
+
+procedure TCustomRangeBar.TimerHandler(Sender: TObject);
+var
+ OldPosition: Single;
+ Pt: TPoint;
+
+ function MousePos: TPoint;
+ begin
+ Result := ScreenToClient(Mouse.CursorPos);
+ if Result.X < 0 then Result.X := 0;
+ if Result.Y < 0 then Result.Y := 0;
+ if Result.X >= ClientWidth then Result.X := ClientWidth - 1;
+ if Result.Y >= ClientHeight then Result.Y := ClientHeight - 1
+ end;
+
+begin
+ inherited;
+ GenChange := True;
+ OldPosition := Position;
+
+ case DragZone of
+ zBtnPrev:
+ begin
+ Position := Position - Increment;
+ if Position = OldPosition then StopDragTracking;
+ end;
+
+ zBtnNext:
+ begin
+ Position := Position + Increment;
+ if Position = OldPosition then StopDragTracking;
+ end;
+
+ zTrackNext:
+ begin
+ Pt := MousePos;
+ if GetZone(Pt.X, Pt.Y) in [zTrackNext, zBtnNext] then
+ Position := Position + EffectiveWindow;
+ end;
+
+ zTrackPrev:
+ begin
+ Pt := MousePos;
+ if GetZone(Pt.X, Pt.Y) in [zTrackPrev, zBtnPrev] then
+ Position := Position - EffectiveWindow;
+ end;
+ end;
+ GenChange := False;
+end;
+
+procedure TCustomRangeBar.UpdateEffectiveWindow;
+begin
+ if FWindow > 0 then FEffectiveWindow := FWindow
+ else
+ begin
+ if Kind = sbHorizontal then FEffectiveWindow := Width
+ else FEffectiveWindow := Height;
+ end;
+end;
+
+//----------------------------------------------------------------------------//
+
+{ TCustomGaugeBar }
+
+procedure TCustomGaugeBar.AdjustPosition;
+begin
+ if Position < Min then Position := Min
+ else if Position > Max then Position := Max;
+end;
+
+constructor TCustomGaugeBar.Create(AOwner: TComponent);
+begin
+ inherited;
+ FLargeChange := 1;
+ FMax := 100;
+ FSmallChange := 1;
+end;
+
+function TCustomGaugeBar.DoMouseWheel(Shift: TShiftState;
+ WheelDelta: Integer; {$IFDEF CLX}const{$ENDIF} MousePos: TPoint): Boolean;
+begin
+ Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos);
+ if not Result then Position := Position + FSmallChange * WheelDelta div 120;
+ Result := True;
+end;
+
+function TCustomGaugeBar.GetHandleRect: TRect;
+var
+ Sz, HandleSz: Integer;
+ Horz: Boolean;
+ Pos: Integer;
+begin
+ Result := GetTrackBoundary;
+ Horz := Kind = sbHorizontal;
+ HandleSz := GetHandleSize;
+
+ if Horz then Sz := Result.Right - Result.Left
+ else Sz := Result.Bottom - Result.Top;
+
+
+ Pos := Round((Position - Min) * (Sz - GetHandleSize) / (Max - Min));
+
+ if Horz then
+ begin
+ Inc(Result.Left, Pos);
+ Result.Right := Result.Left + HandleSz;
+ end
+ else
+ begin
+ Inc(Result.Top, Pos);
+ Result.Bottom := Result.Top + HandleSz;
+ end;
+end;
+
+function TCustomGaugeBar.GetHandleSize: Integer;
+var
+ R: TRect;
+ Sz: Integer;
+begin
+ Result := HandleSize;
+ if Result = 0 then
+ begin
+ if Kind = sbHorizontal then Result := ClientHeight else Result := ClientWidth;
+ end;
+ R := GetTrackBoundary;
+ if Kind = sbHorizontal then Sz := R.Right - R.Left
+ else Sz := R.Bottom - R.Top;
+ if Sz - Result < 1 then Result := Sz - 1;
+ if Result < 0 then Result := 0;
+end;
+
+procedure TCustomGaugeBar.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+begin
+ inherited;
+ if DragZone = zHandle then
+ begin
+ StopDragTracking;
+ PosBeforeDrag := Position;
+ end;
+end;
+
+procedure TCustomGaugeBar.MouseMove(Shift: TShiftState; X, Y: Integer);
+var
+ Delta: Single;
+ R: TRect;
+ ClientSz: Integer;
+begin
+ inherited;
+ if DragZone = zHandle then
+ begin
+ if Kind = sbHorizontal then Delta := X - StoredX else Delta := Y - StoredY;
+ R := GetTrackBoundary;
+
+ if Kind = sbHorizontal then ClientSz := R.Right - R.Left
+ else ClientSz := R.Bottom - R.Top;
+
+ Delta := Delta * (Max - Min) / (ClientSz - GetHandleSize);
+
+ GenChange := True;
+ Position := Round(PosBeforeDrag + Delta);
+ GenChange := False;
+ end;
+end;
+
+procedure TCustomGaugeBar.SetHandleSize(Value: Integer);
+begin
+ if Value < 0 then Value := 0;
+ if Value <> FHandleSize then
+ begin
+ FHandleSize := Value;
+ Invalidate;
+ end;
+end;
+
+procedure TCustomGaugeBar.SetLargeChange(Value: Integer);
+begin
+ if Value < 1 then Value := 1;
+ FLargeChange := Value;
+end;
+
+procedure TCustomGaugeBar.SetMax(Value: Integer);
+begin
+ if (Value <= FMin) and not (csLoading in ComponentState) then Value := FMin + 1;
+ if Value <> FMax then
+ begin
+ FMax := Value;
+ AdjustPosition;
+ Invalidate;
+ end;
+end;
+
+procedure TCustomGaugeBar.SetMin(Value: Integer);
+begin
+ if (Value >= FMax) and not (csLoading in ComponentState) then Value := FMax - 1;
+ if Value <> FMin then
+ begin
+ FMin := Value;
+ AdjustPosition;
+ Invalidate;
+ end;
+end;
+
+procedure TCustomGaugeBar.SetPosition(Value: Integer);
+begin
+ if Value < Min then Value := Min
+ else if Value > Max then Value := Max;
+ if Round(FPosition) <> Value then
+ begin
+ FPosition := Value;
+ Invalidate;
+ DoChange;
+ end;
+end;
+
+procedure TCustomGaugeBar.SetSmallChange(Value: Integer);
+begin
+ if Value < 1 then Value := 1;
+ FSmallChange := Value;
+end;
+
+procedure TCustomGaugeBar.TimerHandler(Sender: TObject);
+var
+ OldPosition: Single;
+ Pt: TPoint;
+
+ function MousePos: TPoint;
+ begin
+ Result := ScreenToClient(Mouse.CursorPos);
+ if Result.X < 0 then Result.X := 0;
+ if Result.Y < 0 then Result.Y := 0;
+ if Result.X >= ClientWidth then Result.X := ClientWidth - 1;
+ if Result.Y >= ClientHeight then Result.Y := ClientHeight - 1
+ end;
+
+begin
+ inherited;
+ GenChange := True;
+ OldPosition := Position;
+
+ case DragZone of
+ zBtnPrev:
+ begin
+ Position := Position - SmallChange;
+ if Position = OldPosition then StopDragTracking;
+ end;
+
+ zBtnNext:
+ begin
+ Position := Position + SmallChange;
+ if Position = OldPosition then StopDragTracking;
+ end;
+
+ zTrackNext:
+ begin
+ Pt := MousePos;
+ if GetZone(Pt.X, Pt.Y) in [zTrackNext, zBtnNext] then
+ Position := Position + LargeChange;
+ end;
+
+ zTrackPrev:
+ begin
+ Pt := MousePos;
+ if GetZone(Pt.X, Pt.Y) in [zTrackPrev, zBtnPrev] then
+ Position := Position - LargeChange;
+ end;
+ end;
+ GenChange := False;
+end;
+
+{ TArrowBarAccess }
+
+function TArrowBarAccess.GetBackgnd: TRBBackgnd;
+begin
+ Result := FMaster.Backgnd;
+end;
+
+function TArrowBarAccess.GetButtonSize: Integer;
+begin
+ Result := FMaster.ButtonSize;
+end;
+
+function TArrowBarAccess.GetColor: TColor;
+begin
+ Result := FMaster.Color;
+end;
+
+function TArrowBarAccess.GetHandleColor: TColor;
+begin
+ Result := FMaster.HandleColor;
+end;
+
+function TArrowBarAccess.GetHighLightColor: TColor;
+begin
+ Result := FMaster.HighLightColor;
+end;
+
+function TArrowBarAccess.GetShadowColor: TColor;
+begin
+ Result := FMaster.ShadowColor;
+end;
+
+function TArrowBarAccess.GetButtonColor: TColor;
+begin
+ Result := FMaster.ButtonColor;
+end;
+
+function TArrowBarAccess.GetBorderColor: TColor;
+begin
+ Result := FMaster.BorderColor;
+end;
+
+function TArrowBarAccess.GetShowArrows: Boolean;
+begin
+ Result := FMaster.ShowArrows;
+end;
+
+function TArrowBarAccess.GetShowHandleGrip: Boolean;
+begin
+ Result := FMaster.ShowHandleGrip;
+end;
+
+function TArrowBarAccess.GetStyle: TRBStyle;
+begin
+ Result := FMaster.Style;
+end;
+
+procedure TArrowBarAccess.SetBackgnd(Value: TRBBackgnd);
+begin
+ FMaster.Backgnd := Value;
+ if FSlave <> nil then FSlave.Backgnd := Value;
+end;
+
+procedure TArrowBarAccess.SetButtonSize(Value: Integer);
+begin
+ FMaster.ButtonSize := Value;
+ if FSlave <> nil then FSlave.ButtonSize := Value;
+end;
+
+procedure TArrowBarAccess.SetColor(Value: TColor);
+begin
+ FMaster.Color := Value;
+ if FSlave <> nil then FSlave.Color := Value;
+end;
+
+procedure TArrowBarAccess.SetHandleColor(Value: TColor);
+begin
+ FMaster.HandleColor := Value;
+ if FSlave <> nil then FSlave.HandleColor := Value;
+end;
+
+procedure TArrowBarAccess.SetHighLightColor(Value: TColor);
+begin
+ FMaster.HighLightColor := Value;
+ if FSlave <> nil then FSlave.HighLightColor := Value;
+end;
+
+procedure TArrowBarAccess.SetShadowColor(Value: TColor);
+begin
+ FMaster.ShadowColor := Value;
+ if FSlave <> nil then FSlave.ShadowColor := Value;
+end;
+
+procedure TArrowBarAccess.SetButtonColor(Value: TColor);
+begin
+ FMaster.ButtonColor := Value;
+ if FSlave <> nil then FSlave.ButtonColor := Value;
+end;
+
+procedure TArrowBarAccess.SetBorderColor(Value: TColor);
+begin
+ FMaster.BorderColor := Value;
+ if FSlave <> nil then FSlave.BorderColor := Value;
+end;
+
+procedure TArrowBarAccess.SetShowArrows(Value: Boolean);
+begin
+ FMaster.ShowArrows := Value;
+ if FSlave <> nil then FSlave.ShowArrows := Value;
+end;
+
+procedure TArrowBarAccess.SetShowHandleGrip(Value: Boolean);
+begin
+ FMaster.ShowHandleGrip := Value;
+ if FSlave <> nil then FSlave.ShowHandleGrip := Value;
+end;
+
+procedure TArrowBarAccess.SetStyle(Value: TRBStyle);
+begin
+ FMaster.Style := Value;
+ if FSlave <> nil then FSlave.Style := Value;
+end;
+
+end.
+
Added: trunk/WPGM/Components/Graphics32/GR32_Reg.dcr
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Reg.dcr
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Reg.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Reg.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Reg.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Reg.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Reg.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,63 @@
+unit GR32_Reg;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Reg.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ Classes, TypInfo,
+{$IFDEF COMPILER6}
+ DesignIntf
+{$ELSE}
+ DsgnIntf
+{$ENDIF};
+
+procedure Register;
+
+implementation
+
+uses
+ GR32,
+ GR32_Dsgn_Color,
+ GR32_Dsgn_Bitmap,
+ GR32_Image,
+ GR32_Layers,
+ GR32_RangeBars;
+
+{ Registration }
+procedure Register;
+begin
+ RegisterComponents('Graphics32', [TPaintBox32, TImage32, TBitmap32List,
+ TRangeBar, TGaugeBar, TImgView32]);
+ RegisterPropertyEditor(TypeInfo(TColor32), nil, '', TColor32Property);
+ RegisterPropertyEditor(TypeInfo(TBitmap32), nil, '', TBitmap32Property);
+ RegisterComponentEditor(TCustomImage32, TImage32Editor);
+end;
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_System.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_System.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_System.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_System.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_System.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,403 @@
+unit GR32_System;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Andre Beckedorf
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_System.pas,v 1.1 2004/07/05 15:32:04 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ {$IFDEF CLX}
+ Qt, Types {$IFDEF LINUX}, Libc{$ENDIF}
+ {$ELSE}
+ Windows
+ {$ENDIF};
+
+{ HasMMX returns 'true' if CPU supports MMX instructions }
+function HasMMX: Boolean;
+{ Has3DNow returns 'true' if CPU supports 3DNow! instructions }
+function Has3DNow: Boolean;
+{ Has3DNowExt returns 'true' if CPU supports 3DNow! Extended instructions }
+function Has3DNowExt: Boolean;
+{ HasSSE returns 'true' if CPU supports SSE instructions }
+function HasSSE: Boolean;
+{ HasSSE2 returns 'true' if CPU supports SSE2 instructions }
+function HasSSE2: Boolean;
+
+type
+ TCPUInstructionSet = (ciMMX, ciSSE, ciSSE2, ci3DNow, ci3DNowExt);
+
+{ General function that returns whether as particular instrucion set is
+ supported for the current CPU or not }
+function HasInstructionSet(const InstructionSet: TCPUInstructionSet): Boolean;
+
+const
+ CPUISChecks: Array[TCPUInstructionSet] of Cardinal =
+ ($800000, $2000000, $4000000, $F000000, $F00000);
+// ciMMX , ciSSE , ciSSE2 , ci3DNow , ci3DNowExt
+
+{$IFNDEF CLX}
+{ Internal support for Windows XP themes }
+var
+ USE_THEMES: Boolean = False;
+ SCROLLBAR_THEME: THandle = 0;
+ GLOBALS_THEME: THandle = 0;
+
+const
+ THEMEMGR_VERSION = 1;
+ WM_THEMECHANGED = $031A;
+
+{ "Scrollbar" Parts & States }
+ { SCROLLBARPARTS }
+ SBP_ARROWBTN = 1;
+ SBP_THUMBBTNHORZ = 2;
+ SBP_THUMBBTNVERT = 3;
+ SBP_LOWERTRACKHORZ = 4;
+ SBP_UPPERTRACKHORZ = 5;
+ SBP_LOWERTRACKVERT = 6;
+ SBP_UPPERTRACKVERT = 7;
+ SBP_GRIPPERHORZ = 8;
+ SBP_GRIPPERVERT = 9;
+ SBP_SIZEBOX = 10;
+
+ { ARROWBTNSTATES }
+ ABS_UPNORMAL = 1;
+ ABS_UPHOT = 2;
+ ABS_UPPRESSED = 3;
+ ABS_UPDISABLED = 4;
+ ABS_DOWNNORMAL = 5;
+ ABS_DOWNHOT = 6;
+ ABS_DOWNPRESSED = 7;
+ ABS_DOWNDISABLED = 8;
+ ABS_LEFTNORMAL = 9;
+ ABS_LEFTHOT = 10;
+ ABS_LEFTPRESSED = 11;
+ ABS_LEFTDISABLED = 12;
+ ABS_RIGHTNORMAL = 13;
+ ABS_RIGHTHOT = 14;
+ ABS_RIGHTPRESSED = 15;
+ ABS_RIGHTDISABLED = 16;
+
+ { SCROLLBARSTATES }
+ SCRBS_NORMAL = 1;
+ SCRBS_HOT = 2;
+ SCRBS_PRESSED = 3;
+ SCRBS_DISABLED = 4;
+
+ { SIZEBOXSTATES }
+ SZB_RIGHTALIGN = 1;
+ SZB_LEFTALIGN = 2;
+
+{ Access to uxtheme.dll }
+
+type
+ HIMAGELIST = THandle;
+ HTHEME = THandle;
+ _MARGINS = record
+ cxLeftWidth: Integer; // width of left border that retains its size
+ cxRightWidth: Integer; // width of right border that retains its size
+ cyTopHeight: Integer; // height of top border that retains its size
+ cyBottomHeight: Integer; // height of bottom border that retains its size
+ end;
+ MARGINS = _MARGINS;
+ PMARGINS = ^MARGINS;
+ TMargins = MARGINS;
+
+var
+ OpenThemeData: function(hwnd: HWND; pszClassList: LPCWSTR): HTHEME; stdcall;
+ CloseThemeData: function(hTheme: HTHEME): HRESULT; stdcall;
+ DrawThemeBackground: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer;
+ const Rect: TRect; pClipRect: PRect): HRESULT; stdcall;
+ DrawThemeEdge: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pDestRect: TRect; uEdge,
+ uFlags: UINT; pContentRect: PRECT): HRESULT; stdcall;
+ GetThemeColor: function(hTheme: HTHEME; iPartId, iStateId, iPropId: Integer; var pColor: COLORREF): HRESULT; stdcall;
+ GetThemeMetric: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId, iPropId: Integer;
+ var piVal: Integer): HRESULT; stdcall;
+ GetThemeMargins: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId, iPropId: Integer; prc: PRECT;
+ var pMargins: MARGINS): HRESULT; stdcall;
+ SetWindowTheme: function(hwnd: HWND; pszSubAppName: LPCWSTR; pszSubIdList: LPCWSTR): HRESULT; stdcall;
+ IsThemeActive: function: BOOL; stdcall;
+ IsAppThemed: function: BOOL; stdcall;
+ EnableTheming: function(fEnable: BOOL): HRESULT; stdcall;
+{$ENDIF}
+
+implementation
+
+{$IFNDEF CLX}
+uses
+ Messages, Forms, Classes;
+{$ENDIF}
+
+function CPUID_Available: Boolean;
+asm
+ MOV EDX,False
+ PUSHFD
+ POP EAX
+ MOV ECX,EAX
+ XOR EAX,$00200000
+ PUSH EAX
+ POPFD
+ PUSHFD
+ POP EAX
+ XOR ECX,EAX
+ JZ @1
+ MOV EDX,True
+ at 1: PUSH EAX
+ POPFD
+ MOV EAX,EDX
+end;
+
+function CPU_Signature: Integer;
+asm
+ PUSH EBX
+ MOV EAX,1
+ DW $A20F // CPUID
+ POP EBX
+end;
+
+function CPU_Features: Integer;
+asm
+ PUSH EBX
+ MOV EAX,1
+ DW $A20F // CPUID
+ POP EBX
+ MOV EAX,EDX
+end;
+
+function CPU_AMDExtensions: Integer;
+asm
+ PUSH EBX
+ MOV EAX, $80000000
+ DW $A20F // CPUID
+ POP EBX
+ MOV EAX,EDX
+end;
+
+function CPU_AMDExtFeatures: Integer;
+asm
+ PUSH EBX
+ MOV EAX, $80000001
+ DW $A20F // CPUID
+ POP EBX
+ MOV EAX,EDX
+end;
+
+function HasInstructionSet(const InstructionSet: TCPUInstructionSet): Boolean;
+begin
+ Result := False;
+ if not CPUID_Available then Exit; // no CPUID available
+ if CPU_Signature shr 8 and $0F < 5 then Exit; // not a Pentium class
+ if (InstructionSet = ci3DNow) or
+ (InstructionSet = ci3DNowExt) then
+ begin
+ if (CPU_AMDExtensions and $F000000 = 0) or // check bit 31
+ (CPU_AMDExtFeatures and CPUISChecks[InstructionSet] = 0) then
+ Exit; // no 3DNow(Ext)
+ end
+ else
+ if CPU_Features and CPUISChecks[InstructionSet] = 0 then
+ Exit; // no MMX
+
+ Result := True;
+end;
+
+function HasMMX: Boolean;
+begin
+ Result := HasInstructionSet(ciMMX);
+end;
+
+function HasSSE: Boolean;
+begin
+ Result := HasInstructionSet(ciSSE);
+end;
+
+function HasSSE2: Boolean;
+begin
+ Result := HasInstructionSet(ciSSE2);
+end;
+
+function Has3DNow: Boolean;
+begin
+ Result := HasInstructionSet(ci3DNow);
+end;
+
+function Has3DNowExt: Boolean;
+begin
+ Result := HasInstructionSet(ci3DNowExt);
+end;
+
+{$IFNDEF CLX}
+const
+ UXTHEME_DLL = 'uxtheme.dll';
+
+var
+ DllHandle: THandle;
+
+procedure FreeXPThemes;
+begin
+ if DllHandle <> 0 then
+ begin
+ FreeLibrary(DllHandle);
+ DllHandle := 0;
+ OpenThemeData := nil;
+ CloseThemeData := nil;
+ DrawThemeBackground := nil;
+ DrawThemeEdge := nil;
+ GetThemeColor := nil;
+ GetThemeMetric := nil;
+ GetThemeMargins := nil;
+ SetWindowTheme := nil;
+ IsThemeActive := nil;
+ IsAppThemed := nil;
+ EnableTheming := nil;
+ end;
+end;
+
+function InitXPThemes: Boolean;
+begin
+ if DllHandle = 0 then
+ begin
+ DllHandle := LoadLibrary(UXTHEME_DLL);
+ if DllHandle > 0 then
+ begin
+ OpenThemeData := GetProcAddress(DllHandle, 'OpenThemeData');
+ CloseThemeData := GetProcAddress(DllHandle, 'CloseThemeData');
+ DrawThemeBackground := GetProcAddress(DllHandle, 'DrawThemeBackground');
+ DrawThemeEdge := GetProcAddress(DllHandle, 'DrawThemeEdge');
+ GetThemeColor := GetProcAddress(DllHandle, 'GetThemeColor');
+ GetThemeMetric := GetProcAddress(DllHandle, 'GetThemeMetric');
+ GetThemeMargins := GetProcAddress(DllHandle, 'GetThemeMargins');
+ SetWindowTheme := GetProcAddress(DllHandle, 'SetWindowTheme');
+ IsThemeActive := GetProcAddress(DllHandle, 'IsThemeActive');
+ IsAppThemed := GetProcAddress(DllHandle, 'IsAppThemed');
+ EnableTheming := GetProcAddress(DllHandle, 'EnableTheming');
+ if (@OpenThemeData = nil) or (@CloseThemeData = nil) or (@IsThemeActive = nil) or
+ (@IsAppThemed = nil) or (@EnableTheming = nil) then FreeXPThemes;
+ end;
+ end;
+ Result := DllHandle > 0;
+end;
+
+function UseXPThemes: Boolean;
+begin
+ Result := (DllHandle > 0) and IsAppThemed and IsThemeActive;
+end;
+
+type
+ TThemeNexus = class
+ private
+ FWindowHandle: HWND;
+ protected
+ procedure WndProc(var Message: TMessage);
+ procedure OpenVisualStyles;
+ procedure CloseVisualStyles;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+{$IFDEF XPTHEMES}
+var
+ ThemeNexus: TThemeNexus;
+{$ENDIF}
+
+{ TThemeNexus }
+
+procedure TThemeNexus.CloseVisualStyles;
+begin
+ if UseXPThemes then
+ begin
+ if SCROLLBAR_THEME <> 0 then
+ begin
+ CloseThemeData(SCROLLBAR_THEME);
+ SCROLLBAR_THEME := 0;
+ end;
+ if GLOBALS_THEME <> 0 then
+ begin
+ CloseThemeData(GLOBALS_THEME);
+ GLOBALS_THEME := 0;
+ end;
+ end;
+ FreeXPThemes;
+end;
+
+constructor TThemeNexus.Create;
+begin
+ FWindowHandle := {$IFDEF COMPILER6}Classes.{$ENDIF}AllocateHWnd(WndProc);
+ OpenVisualStyles;
+end;
+
+destructor TThemeNexus.Destroy;
+begin
+ CloseVisualStyles;
+ {$IFDEF COMPILER6}Classes.{$ENDIF}DeallocateHWnd(FWindowHandle);
+ inherited;
+end;
+
+procedure TThemeNexus.OpenVisualStyles;
+begin
+ USE_THEMES := False;
+ if InitXPThemes then
+ begin
+ USE_THEMES := UseXPThemes;
+ if USE_THEMES then
+ begin
+ SCROLLBAR_THEME := OpenThemeData(FWindowHandle, 'SCROLLBAR');
+ GLOBALS_THEME := OpenThemeData(FWindowHandle, 'GLOBALS');
+ end;
+ end;
+end;
+
+procedure TThemeNexus.WndProc(var Message: TMessage);
+begin
+ case Message.Msg of
+ WM_THEMECHANGED:
+ begin
+ CloseVisualStyles;
+ OpenVisualStyles;
+ end;
+ end;
+ with Message do Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
+end;
+{$ENDIF}
+
+initialization
+{$IFNDEF CLX}
+ {$IFDEF XPTHEMES}
+ ThemeNexus := TThemeNexus.Create;
+ {$ENDIF}
+{$ENDIF}
+
+finalization
+{$IFNDEF CLX}
+ {$IFDEF XPTHEMES}
+ ThemeNexus.Free;
+ {$ENDIF}
+{$ENDIF}
+
+end.
Added: trunk/WPGM/Components/Graphics32/GR32_Transforms.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/GR32_Transforms.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/GR32_Transforms.pas
===================================================================
--- trunk/WPGM/Components/Graphics32/GR32_Transforms.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/GR32_Transforms.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1767 @@
+unit GR32_Transforms;
+
+(* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Graphics32
+ *
+ * The Initial Developer of the Original Code is
+ * Alex A. Denisov
+ *
+ * Portions created by the Initial Developer are Copyright (C) 2000-2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Andre Beckedorf <Andre at metaException.de>
+ * Mattias Andersson <Mattias at Centaurix.com>
+ * J. Tulach <tulach at position.cz>
+ * Michael Hansen <dyster_tid at hotmail.com>
+ *
+ * ***** END LICENSE BLOCK ***** *)
+// $Id: GR32_Transforms.pas,v 1.2 2004/07/07 11:39:58 abeckedorf Exp $
+
+interface
+
+{$I GR32.inc}
+
+uses
+ {$IFDEF CLX}
+ Qt, Types, {$IFDEF LINUX}Libc, {$ENDIF}
+ {$ELSE}
+ Windows,
+ {$ENDIF}
+ SysUtils, Classes, GR32, GR32_Blend;
+
+type
+ ETransformError = class(Exception);
+
+procedure BlockTransfer(
+ Dst: TBitmap32; DstX: Integer; DstY: Integer; DstClip: TRect;
+ Src: TBitmap32; SrcRect: TRect;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
+
+
+procedure StretchTransfer(
+ Dst: TBitmap32; DstRect: TRect; DstClip: TRect;
+ Src: TBitmap32; SrcRect: TRect;
+ StretchFilter: TStretchFilter;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent = nil);
+
+type
+ TFloatMatrix = array[0..2, 0..2] of Single; // 3x3 single precision
+
+const
+ IdentityMatrix: TFloatMatrix = (
+ (1, 0, 0),
+ (0, 1, 0),
+ (0, 0, 1));
+
+type
+ TVector3f = array[0..2] of Single;
+ TVector3i = array[0..2] of Integer;
+
+procedure Adjoint(var M: TFloatMatrix);
+function Determinant(const M: TFloatMatrix): Single;
+procedure Scale(var M: TFloatMatrix; Factor: Single);
+procedure Invert(var M: TFloatMatrix);
+function Mult(const M1, M2: TFloatMatrix): TFloatMatrix;
+function VectorTransform(const M: TFloatMatrix; const V: TVector3f): TVector3f;
+
+type
+ TTransformation = class(TObject)
+ private
+ FSrcRect: TFloatRect;
+ procedure SetSrcRect(const Value: TFloatRect);
+ procedure Transform(DstX, DstY: Integer; out SrcX, SrcY: Integer); virtual; abstract;
+ procedure Transform256(DstX, DstY: Integer; out SrcX256, SrcY256: Integer); virtual; abstract;
+ protected
+ TransformValid: Boolean;
+ procedure PrepareTransform; virtual; abstract;
+ public
+ function GetTransformedBounds: TRect; virtual; abstract;
+ property SrcRect: TFloatRect read FSrcRect write SetSrcRect;
+ end;
+
+ TAffineTransformation = class(TTransformation)
+ protected
+ A, B, C: Integer;
+ D, E, F: Integer;
+ procedure PrepareTransform; override;
+ procedure Transform(DstX, DstY: Integer; out SrcX, SrcY: Integer); override;
+ procedure Transform256(DstX, DstY: Integer; out SrcX256, SrcY256: Integer); override;
+ public
+ Matrix: TFloatMatrix;
+ constructor Create; virtual;
+ function GetTransformedBounds: TRect; override;
+ procedure Clear;
+ procedure Rotate(Cx, Cy, Alpha: Single); // degrees
+ procedure Skew(Fx, Fy: Single);
+ procedure Scale(Sx, Sy: Single);
+ procedure Translate(Dx, Dy: Single);
+ end;
+
+ TProjectiveTransformation = class(TTransformation)
+ private
+ Wx0, Wx1, Wx2, Wx3: Single;
+ Wy0, Wy1, Wy2, Wy3: Single;
+ procedure SetX0(Value: Single);
+ procedure SetX1(Value: Single);
+ procedure SetX2(Value: Single);
+ procedure SetX3(Value: Single);
+ procedure SetY0(Value: Single);
+ procedure SetY1(Value: Single);
+ procedure SetY2(Value: Single);
+ procedure SetY3(Value: Single);
+ protected
+ M: TFloatMatrix;
+ procedure PrepareTransform; override;
+ procedure Transform(DstX, DstY: Integer; out SrcX, SrcY: Integer); override;
+ procedure Transform256(DstX, DstY: Integer; out SrcX256, SrcY256: Integer); override;
+ public
+ function GetTransformedBounds: TRect; override;
+ property X0: Single read Wx0 write SetX0;
+ property X1: Single read Wx1 write SetX1;
+ property X2: Single read Wx2 write SetX2;
+ property X3: Single read Wx3 write SetX3;
+ property Y0: Single read Wy0 write SetY0;
+ property Y1: Single read Wy1 write SetY1;
+ property Y2: Single read Wy2 write SetY2;
+ property Y3: Single read Wy3 write SetY3;
+ end;
+
+procedure Transform(Dst, Src: TBitmap32; Transformation: TTransformation);
+procedure SetBorderTransparent(ABitmap: TBitmap32; ARect: TRect);
+
+{ FullEdge controls how the bitmap is resampled }
+var
+ FullEdge: Boolean = True;
+
+implementation
+
+{$R-}{$Q-} // switch off overflow and range checking
+
+uses GR32_LowLevel, GR32_System, Math;
+
+type
+ {provides access to proctected members of TBitmap32 by typecasting}
+ TBitmap32Access = class(TBitmap32);
+
+const
+ SDstEmpty = 'Destination bitmap is nil or empty';
+ SSrcEmpty = 'Source bitmap is nil or empty';
+ SSrcInvalid = 'Source rectangle is invalid';
+
+var
+ BlockAverage : function (Dlx, Dly, RowSrc, OffSrc: Cardinal): TColor32;
+ LinearInterpolator: function(PWX_256, PWY_256: Cardinal; C11, C21: PColor32): TColor32;
+
+
+procedure CheckBitmaps(Dst, Src: TBitmap32);
+begin
+ if not Assigned(Dst) or Dst.Empty then raise ETransformError.Create(SDstEmpty);
+ if not Assigned(Src) or Src.Empty then raise ETransformError.Create(SSrcEmpty);
+end;
+
+function CheckSrcRect(Src: TBitmap32; const SrcRect: TRect): Boolean;
+begin
+ Result := False;
+ if IsRectEmpty(SrcRect) then Exit;
+ if (SrcRect.Left < 0) or (SrcRect.Right > Src.Width) or
+ (SrcRect.Top < 0) or (SrcRect.Bottom > Src.Height) then
+ raise ETransformError.Create(SSrcInvalid);
+ Result := True;
+end;
+
+procedure BlendBlock(
+ Dst: TBitmap32; DstRect: TRect;
+ Src: TBitmap32; SrcX, SrcY: Integer;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
+var
+ SrcP, DstP: PColor32;
+ SP, DP: PColor32;
+ W, I, DstY: Integer;
+begin
+ { Internal routine }
+ W := DstRect.Right - DstRect.Left;
+ SrcP := Src.PixelPtr[SrcX, SrcY];
+ DstP := Dst.PixelPtr[DstRect.Left, DstRect.Top];
+
+ case CombineOp of
+ dmOpaque:
+ begin
+ for DstY := DstRect.Top to DstRect.Bottom - 1 do
+ begin
+ //Move(SrcP^, DstP^, W*4); // for FastCode
+ MoveLongWord(SrcP^, DstP^, W);
+ Inc(SrcP, Src.Width);
+ Inc(DstP, Dst.Width);
+ end;
+ end;
+ dmBlend:
+ if Src.MasterAlpha >= 255 then
+ for DstY := DstRect.Top to DstRect.Bottom - 1 do
+ begin
+ BlendLine(SrcP, DstP, W);
+ Inc(SrcP, Src.Width);
+ Inc(DstP, Dst.Width);
+ end
+ else
+ for DstY := DstRect.Top to DstRect.Bottom - 1 do
+ begin
+ BlendLineEx(SrcP, DstP, W, Src.MasterAlpha);
+ Inc(SrcP, Src.Width);
+ Inc(DstP, Dst.Width);
+ end;
+ else // dmCustom:
+ begin
+ for DstY := DstRect.Top to DstRect.Bottom - 1 do
+ begin
+ SP := SrcP;
+ DP := DstP;
+ for I := 0 to W - 1 do
+ begin
+ CombineCallBack(SP^, DP^, Src.MasterAlpha);
+ Inc(SP); Inc(DP);
+ end;
+ Inc(SrcP, Src.Width);
+ Inc(DstP, Dst.Width);
+ end;
+ end;
+ end;
+end;
+
+procedure BlockTransfer(
+ Dst: TBitmap32; DstX: Integer; DstY: Integer; DstClip: TRect;
+ Src: TBitmap32; SrcRect: TRect;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
+var
+ SrcX, SrcY: Integer;
+begin
+ if Src.Empty then Exit;
+ CheckBitmaps(Src, Dst);
+
+ if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
+ CombineOp := dmOpaque;
+
+ if (CombineOp = dmBlend) and (Src.MasterAlpha = 0) then Exit;
+
+ SrcX := SrcRect.Left;
+ SrcY := SrcRect.Top;
+
+ IntersectRect(DstClip, DstClip, Dst.BoundsRect);
+ IntersectRect(SrcRect, SrcRect, Src.BoundsRect);
+ OffsetRect(SrcRect, DstX - SrcX, DstY - SrcY);
+ IntersectRect(SrcRect, DstClip, SrcRect);
+ DstClip := SrcRect;
+ OffsetRect(SrcRect, SrcX - DstX, SrcY - DstY);
+
+ if not IsRectEmpty(SrcRect) then
+ try
+ BlendBlock(Dst, DstClip, Src, SrcRect.Left, SrcRect.Top, CombineOp, CombineCallBack);
+ finally
+ EMMS;
+ end;
+end;
+
+
+procedure StretchNearest(
+ Dst: TBitmap32; DstRect, DstClip: TRect;
+ Src: TBitmap32; SrcRect: TRect;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
+var
+ R: TRect;
+ SrcW, SrcH, DstW, DstH, DstClipW, DstClipH: Integer;
+ SrcY, OldSrcY: Integer;
+ I, J: Integer;
+ MapHorz: array of Integer;
+ SrcLine, DstLine: PColor32Array;
+ Buffer: TArrayOfColor32;
+ Scale: Single;
+begin
+ IntersectRect(DstClip, DstClip, MakeRect(0, 0, Dst.Width, Dst.Height));
+ IntersectRect(DstClip, DstClip, DstRect);
+ if IsRectEmpty(DstClip) then Exit;
+ IntersectRect(R, DstClip, DstRect);
+ if IsRectEmpty(R) then Exit;
+ if (SrcRect.Left < 0) or (SrcRect.Top < 0) or (SrcRect.Right > Src.Width) or
+ (SrcRect.Bottom > Src.Height) then raise Exception.Create('Invalid SrcRect');
+
+ SrcW := SrcRect.Right - SrcRect.Left;
+ SrcH := SrcRect.Bottom - SrcRect.Top;
+ DstW := DstRect.Right - DstRect.Left;
+ DstH := DstRect.Bottom - DstRect.Top;
+ DstClipW := DstClip.Right - DstClip.Left;
+ DstClipH := DstClip.Bottom - DstClip.Top;
+ try
+ if (SrcW = DstW) and (SrcH = DstH) then
+ begin
+ { Copy without resampling }
+ BlendBlock(Dst, DstClip, Src, SrcRect.Left + DstClip.Left - DstRect.Left,
+ SrcRect.Top + DstClip.Top - DstRect.Top, CombineOp, CombineCallBack);
+ end
+ else
+ begin
+ SetLength(MapHorz, DstClipW);
+
+ if DstW > 1 then
+ begin
+ if FullEdge then
+ begin
+ Scale := SrcW / DstW;
+ for I := 0 to DstClipW - 1 do
+ MapHorz[I] := Trunc(SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale);
+ end
+ else
+ begin
+ Scale := (SrcW - 1) / (DstW - 1);
+ for I := 0 to DstClipW - 1 do
+ MapHorz[I] := Round(SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale);
+ end;
+ Assert(MapHorz[0] >= SrcRect.Left);
+ Assert(MapHorz[DstClipW - 1] < SrcRect.Right);
+ end
+ else
+ MapHorz[0] := (SrcRect.Left + SrcRect.Right - 1) div 2;
+
+ if DstH <= 1 then Scale := 0
+ else if FullEdge then Scale := SrcH / DstH
+ else Scale := (SrcH - 1) / (DstH - 1);
+
+ if CombineOp = dmOpaque then
+ begin
+ DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
+ OldSrcY := -1;
+ for J := 0 to DstClipH - 1 do
+ begin
+ if DstH <= 1 then
+ SrcY := (SrcRect.Top + SrcRect.Bottom - 1) div 2
+ else if FullEdge then
+ SrcY := Trunc(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale)
+ else
+ SrcY := Round(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale);
+ if SrcY <> OldSrcY then
+ begin
+ SrcLine := Src.ScanLine[SrcY];
+ for I := 0 to DstClipW - 1 do DstLine[I] := SrcLine[MapHorz[I]];
+ OldSrcY := SrcY;
+ end
+ else
+ MoveLongWord(DstLine[-Dst.Width], DstLine[0], DstClipW);
+ Inc(DstLine, Dst.Width);
+ end;
+ end
+ else
+ begin
+ SetLength(Buffer, DstClipW);
+ DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
+ OldSrcY := -1;
+ for J := 0 to DstClipH - 1 do
+ begin
+ if DstH > 1 then
+ begin
+ EMMS;
+ if FullEdge then
+ SrcY := Trunc(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale)
+ else
+ SrcY := Round(SrcRect.Top + (J + DstClip.Top - DstRect.Top) * Scale);
+ end
+ else
+ SrcY := (SrcRect.Top + SrcRect.Bottom - 1) div 2;
+ if SrcY <> OldSrcY then
+ begin
+ SrcLine := Src.ScanLine[SrcY];
+ for I := 0 to DstClipW - 1 do Buffer[I] := SrcLine[MapHorz[I]];
+ OldSrcY := SrcY;
+ end;
+
+ if CombineOp = dmBlend then
+ begin
+ if Src.MasterAlpha >= 255 then BlendLine(@Buffer[0], @DstLine[0], DstClipW)
+ else BlendLineEx(@Buffer[0], @DstLine[0], DstClipW, Src.MasterAlpha);
+ end
+ else
+ for I := 0 to DstClipW - 1 do
+ CombineCallBack(Buffer[I], DstLine[I], Src.MasterAlpha);
+
+ Inc(DstLine, Dst.Width);
+ end;
+ end;
+ end;
+ finally
+ EMMS;
+ end;
+end;
+
+type
+ TPointRec = record
+ Pos: Integer;
+ Weight: Cardinal;
+ end;
+
+procedure StretchHorzStretchVertLinear(
+ Dst: TBitmap32; DstRect, DstClip: TRect;
+ Src: TBitmap32; SrcRect: TRect;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
+//Assure DstRect is >= SrcRect, otherwise quality loss will occur
+
+var
+ SrcW, SrcH, DstW, DstH, DstClipW, DstClipH: Integer;
+ MapHorz, MapVert: array of TPointRec;
+ t2, Scale: Single;
+ SrcLine, DstLine: PColor32Array;
+ SrcIndex, OldSrcIndex: Integer;
+ I, J: Integer;
+ WY: Cardinal;
+ C: TColor32;
+
+begin
+ SrcW := SrcRect.Right - SrcRect.Left;
+ SrcH := SrcRect.Bottom - SrcRect.Top;
+ DstW := DstRect.Right - DstRect.Left;
+ DstH := DstRect.Bottom - DstRect.Top;
+ DstClipW := DstClip.Right - DstClip.Left;
+ DstClipH := DstClip.Bottom - DstClip.Top;
+
+ SetLength(MapHorz, DstClipW);
+ if FullEdge then Scale := SrcW / DstW
+ else Scale := (SrcW - 1) / (DstW - 1);
+ for I := 0 to DstClipW - 1 do
+ begin
+ if FullEdge then t2 := SrcRect.Left - 0.5 + (I + DstClip.Left - DstRect.Left + 0.5) * Scale
+ else t2 := SrcRect.Left + (I + DstClip.Left - DstRect.Left) * Scale;
+ if t2 < 0 then t2 := 0
+ else if t2 > Src.Width - 1 then t2 := Src.Width - 1;
+ MapHorz[I].Pos := Floor(t2);
+ MapHorz[I].Weight := 256 - Round(Frac(t2) * 256);
+ //Pre-pack weights to reduce MMX Reg. setups per pixel:
+ MapHorz[I].Weight:= MapHorz[I].Weight shl 16 + MapHorz[I].Weight;
+ end;
+ I := DstClipW - 1;
+ while MapHorz[I].Pos = SrcRect.Right - 1 do
+ begin
+ Dec(MapHorz[I].Pos);
+ MapHorz[I].Weight := 0;
+ Dec(I);
+ end;
+
+ SetLength(MapVert, DstClipH);
+ if FullEdge then Scale := SrcH / DstH
+ else Scale := (SrcH - 1) / (DstH - 1);
+ for I := 0 to DstClipH - 1 do
+ begin
+ if FullEdge then t2 := SrcRect.Top - 0.5 + (I + DstClip.Top - DstRect.Top + 0.5) * Scale
+ else t2 := SrcRect.Top + (I + DstClip.Top - DstRect.Top) * Scale;
+ if t2 < 0 then t2 := 0
+ else if t2 > Src.Height - 1 then t2 := Src.Height - 1;
+ MapVert[I].Pos := Floor(t2);
+ MapVert[I].Weight := 256 - Round(Frac(t2) * 256);
+ //Pre-pack weights to reduce MMX Reg. setups per pixel:
+ MapVert[I].Weight := MapVert[I].Weight shl 16 + MapVert[I].Weight;
+ end;
+ I := DstClipH - 1;
+ while MapVert[I].Pos = SrcRect.Bottom - 1 do
+ begin
+ Dec(MapVert[I].Pos);
+ MapVert[I].Weight := 0;
+ Dec(I);
+ end;
+
+ DstLine := PColor32Array(Dst.PixelPtr[DstClip.Left, DstClip.Top]);
+ for J := 0 to DstClipH - 1 do
+ begin
+ SrcLine := Src.ScanLine[MapVert[J].Pos];
+ WY := MapVert[J].Weight;
+ OldSrcIndex := -1;
+ case CombineOp of
+ dmOpaque:
+ for I := 0 to DstClipW - 1 do
+ begin
+ SrcIndex := MapHorz[I].Pos;
+ if SrcIndex <> OldSrcIndex then OldSrcIndex := SrcIndex;
+ DstLine[I] := LinearInterpolator( MapHorz[I].Weight, WY, @SrcLine[SrcIndex],
+ @SrcLine[SrcIndex + Src.Width]);
+ end;
+ else
+ for I := 0 to DstClipW - 1 do
+ begin
+ SrcIndex := MapHorz[I].Pos;
+ C := LinearInterpolator( MapHorz[I].Weight, WY, @SrcLine[SrcIndex],
+ @SrcLine[SrcIndex + Src.Width]);
+ if SrcIndex <> OldSrcIndex then OldSrcIndex := SrcIndex;
+ if CombineOp = dmBlend then BlendMemEx(C, DstLine[I], Src.MasterAlpha)
+ else CombineCallBack(C, DstLine[I], Src.MasterAlpha);
+ end;
+ end;
+ Inc(DstLine, Dst.Width);
+ end;
+ EMMS;
+end;
+
+{ StretchFlt }
+
+type
+ TCluster = array of TPointRec;
+ TMappingTable = array of TCluster;
+ TFilterFunc = function(Value: Single): Single;
+
+function NearestFilter(Value: Single): Single;
+begin
+ if (Value > -0.5) and (Value <= 0.5) then Result := 1
+ else Result := 0;
+end;
+
+function LinearFilter(Value: Single): Single;
+begin
+ if Value < -1 then Result := 0
+ else if Value < 0 then Result := 1 + Value
+ else if Value < 1 then Result := 1 - Value
+ else Result := 0;
+end;
+
+function DraftFilter(Value: Single): Single;
+//This function is only present to keep compatibility
+//Draft resampling is handled separately, and this function will never be used.
+//But since draft resampling is closest to linear, this function is provided.
+begin
+ if Value < -1 then Result := 0
+ else if Value < 0 then Result := 1 + Value
+ else if Value < 1 then Result := 1 - Value
+ else Result := 0;
+end;
+
+function CosineFilter(Value: Single): Single;
+begin
+ Result := 0;
+ if Abs(Value) < 1 then
+ Result := (Cos(Value * Pi) + 1) / 2;
+end;
+
+function SplineFilter(Value: Single): Single;
+var
+ tt: Single;
+begin
+ Value := Abs(Value);
+ if Value < 1 then
+ begin
+ tt := Sqr(Value);
+ Result := 0.5 * tt * Value - tt + 2 / 3;
+ end
+ else if Value < 2 then
+ begin
+ Value := 2 - Value;
+ Result := 1 / 6 * Sqr(Value) * Value;
+ end
+ else Result := 0;
+end;
+
+function LanczosFilter(Value: Single): Single;
+ function Sinc(Value: Single): Single;
+ begin
+ if Value <> 0 then
+ begin
+ Value := Value * Pi;
+ Result := Sin(Value) / Value;
+ end
+ else Result := 1;
+ end;
+begin
+ Value := Abs(Value);
+ if Value < 3 then Result := Sinc(Value) * Sinc(Value / 3)
+ else Result := 0;
+end;
+
+function MitchellFilter(Value: Single): Single;
+var
+ tt, ttt: Single;
+begin
+ Value := Abs(Value);
+ tt := Sqr(Value);
+ ttt := tt * Value;
+ if Value < 1 then Result := (7 * ttt + -12 * tt + 16 / 3) / 6
+ else if Value < 2 then Result := (-7 / 3 * ttt + 12 * tt - 20 * Value + 32 / 3) / 6
+ else Result := 0;
+end;
+
+function BuildMappingTable(
+ DstLo, DstHi: Integer;
+ ClipLo, ClipHi: Integer;
+ SrcLo, SrcHi: Integer;
+ StretchFilter: TStretchFilter): TMappingTable;
+const
+ { the first filter from these arrays is never used since the nearest and linear
+ filter is implemented separately. This also applies to draft-resampling }
+ FILTERS: array[TStretchFilter] of TFilterFunc = (NearestFilter, DraftFilter, LinearFilter,
+ CosineFilter, SplineFilter, LanczosFilter, MitchellFilter);
+ FILTERWIDTHS: array [TStretchFilter] of Single = (1, 1, 1, 1, 2, 3, 2);
+var
+ SrcW, DstW, ClipW: Integer;
+ Filter: TFilterFunc;
+ FilterWidth: Single;
+ Scale, OldScale: Single;
+ Center: Single;
+ Count: Integer;
+ Left, Right: Integer;
+ I, J, K: Integer;
+ Weight: Integer;
+begin
+ SrcW := SrcHi - SrcLo;
+ DstW := DstHi - DstLo;
+ ClipW := ClipHi - ClipLo;
+ if SrcW = 0 then
+ begin
+ Result := nil;
+ Exit;
+ end
+ else if SrcW = 1 then
+ begin
+ SetLength(Result, ClipW);
+ for I := 0 to ClipW - 1 do
+ begin
+ SetLength(Result[I], 1);
+ Result[I][0].Pos := 0;
+ Result[I][0].Weight := 256;
+ end;
+ Exit;
+ end;
+ SetLength(Result, ClipW);
+ if ClipW = 0 then Exit;
+
+ if FullEdge then Scale := DstW / SrcW
+ else Scale := (DstW - 1) / (SrcW - 1);
+
+ Filter := FILTERS[StretchFilter];
+ FilterWidth := FILTERWIDTHS[StretchFilter];
+ K := 0;
+
+ if Scale = 0 then
+ begin
+ Assert(Length(Result) = 1);
+ SetLength(Result[0], 1);
+ Result[0][0].Pos := (SrcLo + SrcHi) div 2;
+ Result[0][0].Weight := 256;
+ end
+ else if Scale < 1 then
+ begin
+ OldScale := Scale;
+ Scale := 1 / Scale;
+ FilterWidth := FilterWidth * Scale;
+ for I := 0 to ClipW - 1 do
+ begin
+ if FullEdge then
+ Center := SrcLo - 0.5 + (I - DstLo + ClipLo + 0.5) * Scale
+ else
+ Center := SrcLo + (I - DstLo + ClipLo) * Scale;
+ Left := Floor(Center - FilterWidth);
+ Right := Ceil(Center + FilterWidth);
+ Count := -256;
+ for J := Left to Right do
+ begin
+ Weight := Round(256 * Filter((Center - J) * OldScale) * OldScale);
+ if Weight <> 0 then
+ begin
+ Inc(Count, Weight);
+ K := Length(Result[I]);
+ SetLength(Result[I], K + 1);
+ Result[I][K].Pos := Constrain(J, SrcLo, SrcHi - 1);
+ Result[I][K].Weight := Weight;
+ end;
+ end;
+ if Length(Result[I]) = 0 then
+ begin
+ SetLength(Result[I], 1);
+ Result[I][0].Pos := Floor(Center);
+ Result[I][0].Weight := 256;
+ end
+ else if Count <> 0 then
+ Dec(Result[I][K div 2].Weight, Count);
+ end;
+ end
+ else // scale > 1
+ begin
+ Scale := 1 / Scale;
+ for I := 0 to ClipW - 1 do
+ begin
+ if FullEdge then
+ Center := SrcLo - 0.5 + (I - DstLo + ClipLo + 0.5) * Scale
+ else
+ Center := SrcLo + (I - DstLo + ClipLo) * Scale;
+ Left := Floor(Center - FilterWidth);
+ Right := Ceil(Center + FilterWidth);
+ Count := -256;
+ for J := Left to Right do
+ begin
+ Weight := Round(256 * Filter(Center - j));
+ if Weight <> 0 then
+ begin
+ Inc(Count, Weight);
+ K := Length(Result[I]);
+ SetLength(Result[I], k + 1);
+ Result[I][K].Pos := Constrain(j, SrcLo, SrcHi - 1);
+ Result[I][K].Weight := Weight;
+ end;
+ end;
+ if Count <> 0 then
+ Dec(Result[I][K div 2].Weight, Count);
+ end;
+ end;
+end;
+
+{$WARNINGS OFF}
+procedure Resample(
+ Dst: TBitmap32; DstRect: TRect; DstClip: TRect;
+ Src: TBitmap32; SrcRect: TRect;
+ StretchFilter: TStretchFilter;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
+type
+ TBufferEntry = record
+ R, G, B, A: Integer;
+ end;
+var
+ SrcW, SrcH: Single;
+ DstW, DstH: Integer;
+ DstClipW, DstClipH: Integer;
+ t: Single;
+ MapX, MapY: TMappingTable;
+ I, J, X, Y, Index: Integer;
+ MapXLoPos, MapXHiPos: Integer;
+ HorzBuffer: array of TBufferEntry;
+ ClusterX, ClusterY: TCluster;
+ ClusterXSize, ClusterYSize: Integer;
+ C, Wt, Cr, Cg, Cb, Ca: Integer;
+ ClustYP, ClustYW, ClustXP, ClustXW: Integer;
+ SrcP: PColor32;
+ DstLine: PColor32Array;
+ RangeCheck: Boolean;
+begin
+ if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then
+ CombineOp := dmOpaque;
+
+ { check source and destination }
+ if (CombineOp = dmBlend) and (Src.MasterAlpha = 0) then Exit;
+
+ SrcW := SrcRect.Right - SrcRect.Left;
+ SrcH := SrcRect.Bottom - SrcRect.Top;
+ DstW := DstRect.Right - DstRect.Left;
+ DstH := DstRect.Bottom - DstRect.Top;
+ DstClipW := DstClip.Right - DstClip.Left;
+ DstClipH := DstClip.Bottom - DstClip.Top;
+
+ // mapping tables
+ MapX := BuildMappingTable(DstRect.Left, DstRect.Right, DstClip.Left, DstClip.Right, SrcRect.Left, SrcRect.Right, StretchFilter);
+ MapY := BuildMappingTable(DstRect.Top, DstRect.Bottom, DstClip.Top, DstClip.Bottom, SrcRect.Top, SrcRect.Bottom, StretchFilter);
+ ClusterX := nil;
+ ClusterY := nil;
+ try
+ RangeCheck := StretchFilter in [sfLanczos, sfMitchell];
+ if (MapX = nil) or (MapY = nil) then Exit;
+
+ MapXLoPos := MapX[0][0].Pos;
+ MapXHiPos := MapX[DstClipW - 1][High(MapX[DstClipW - 1])].Pos;
+ SetLength(HorzBuffer, MapXHiPos - MapXLoPos + 1);
+
+ { transfer pixels }
+ for J := DstClip.Top to DstClip.Bottom - 1 do
+ begin
+
+ ClusterY := MapY[J - DstClip.Top];
+ for X := MapXLoPos to MapXHiPos do
+ begin
+ Ca := 0; Cr := 0; Cg := 0; Cb := 0;
+ for Y := 0 to Length(ClusterY) - 1 do
+ begin
+ C := Src.Bits[X + ClusterY[Y].Pos * Src.Width];
+ ClustYW := ClusterY[Y].Weight;
+ Inc(Ca, C shr 24 * ClustYW);
+ Inc(Cr, (C and $00FF0000) shr 16 * ClustYW);
+ Inc(Cg, (C and $0000FF00) shr 8 * ClustYW);
+ Inc(Cb, (C and $000000FF) * ClustYW);
+ end;
+ with HorzBuffer[X - MapXLoPos] do
+ begin
+ R := Cr;
+ G := Cg;
+ B := Cb;
+ A := Ca;
+ end;
+ end;
+
+ DstLine := Dst.ScanLine[J];
+ for I := DstClip.Left to DstClip.Right - 1 do
+ begin
+ ClusterX := MapX[I - DstClip.Left];
+ Ca := 0; Cr := 0; Cg := 0; Cb := 0;
+ for X := 0 to Length(ClusterX) - 1 do
+ begin
+ Wt := ClusterX[X].Weight;
+ with HorzBuffer[ClusterX[X].Pos - MapXLoPos] do
+ begin
+ Inc(Ca, A * Wt);
+ Inc(Cr, R * Wt);
+ Inc(Cg, G * Wt);
+ Inc(Cb, B * Wt);
+ end;
+ end;
+
+ if RangeCheck then
+ begin
+ if Ca > $FF0000 then Ca := $FF0000
+ else if Ca < 0 then Ca := 0
+ else Ca := Ca and $00FF0000;
+
+ if Cr > $FF0000 then Cr := $FF0000
+ else if Cr < 0 then Cr := 0
+ else Cr := Cr and $00FF0000;
+
+ if Cg > $FF0000 then Cg := $FF0000
+ else if Cg < 0 then Cg := 0
+ else Cg := Cg and $00FF0000;
+
+ if Cb > $FF0000 then Cb := $FF0000
+ else if Cb < 0 then Cb := 0
+ else Cb := Cb and $00FF0000;
+
+ C := (Ca shl 8) or Cr or (Cg shr 8) or (Cb shr 16);
+ end
+ else
+ C := ((Ca and $00FF0000) shl 8) or (Cr and $00FF0000) or ((Cg and $00FF0000) shr 8) or ((Cb and $00FF0000) shr 16);
+
+
+ // combine it with the background
+ case CombineOp of
+ dmOpaque: DstLine[I] := C;
+ dmBlend: BlendMemEx(C, DstLine[I], Src.MasterAlpha);
+ dmCustom: CombineCallBack(C, DstLine[I], Src.MasterAlpha);
+ end;
+ end;
+ end;
+ finally
+ EMMS;
+ MapX := nil;
+ MapY := nil;
+ end;
+end;
+{$WARNINGS ON}
+
+{ Draft Resample Routines }
+
+function BlockAverage_MMX(Dlx, Dly, RowSrc, OffSrc: Cardinal): TColor32;
+asm
+ push ebx
+ push esi
+ push edi
+
+ mov ebx, OffSrc
+ mov esi, eax
+ mov edi, edx
+ sub ecx, $04
+
+ db $0F,$EF,$C9 /// pxor mm1, mm1
+ db $0F,$EF,$D2 /// pxor mm2, mm2
+ db $0F,$EF,$FF /// pxor mm7, mm7
+
+ @@LoopY:
+ mov esi, eax
+ db $0F,$EF,$C0 /// pxor mm0, mm0
+ @@LoopX:
+ db $0F,$6E,$34,$B1 /// movd mm6, [ecx + esi * 4]
+ db $0F,$60,$F7 /// punpcklbw mm6, mm7
+ db $0F,$FD,$C6 /// paddw mm0, mm6
+ dec esi
+ jnz @@LoopX
+
+ db $0F,$6F,$F0 /// movq mm6, mm0
+ db $0F,$61,$F7 /// punpcklwd mm6, mm7
+ db $0F,$FE,$CE /// paddd mm1, mm6
+ db $0F,$6F,$F0 /// movq mm6, mm0
+ db $0F,$69,$F7 /// punpckhwd mm6, mm7
+ db $0F,$FE,$D6 /// paddd mm2, mm6
+ add ecx, ebx
+ dec edx
+ jnz @@LoopY
+
+ mul edi
+ mov ecx, eax
+ mov eax, $01000000
+ div ecx
+ mov ecx, eax
+
+ db $0F,$7E,$C8 /// movd eax, mm1
+ mul ecx
+ shr eax, $18
+ mov edi, eax
+
+ db $0F,$73,$D1,$20 /// psrlq mm1, $20
+ db $0F,$7E,$C8 /// movd eax, mm1
+ mul ecx
+ shr eax, $10
+ and eax, $0000FF00
+ add edi, eax
+
+ db $0F,$7E,$D0 /// movd eax, mm2
+ mul ecx
+ shr eax, $08
+ and eax, $00FF0000
+ add edi, eax
+
+ db $0F,$73,$D2,$20 /// psrlq mm2, $20
+ db $0F,$7E,$D0 /// movd eax, mm2
+ mul ecx
+ and eax, $FF000000
+ add eax, edi
+
+ pop edi
+ pop esi
+ pop ebx
+end;
+
+function BlockAverage_3dNow(Dlx, Dly, RowSrc, OffSrc: Cardinal): TColor32;
+asm
+ push ebx
+ push esi
+ push edi
+
+ mov ebx, OffSrc
+ mov esi, eax
+ mov edi, edx
+
+ shl esi, $02
+ sub ebx, esi
+
+ db $0F,$EF,$C9 /// pxor mm1, mm1
+ db $0F,$EF,$D2 /// pxor mm2, mm2
+ db $0F,$EF,$FF /// pxor mm7, mm7
+
+ @@LoopY:
+ mov esi, eax
+ db $0F,$EF,$C0 /// pxor mm0, mm0
+ db $0F,$0D,$34,$F1 /// prefetch [ecx + esi * 8]
+ @@LoopX:
+ db $0F,$6E,$31 /// movd mm6, [ecx]
+ db $0F,$60,$F7 /// punpcklbw mm6, mm7
+ db $0F,$FD,$C6 /// paddw mm0, mm6
+ add ecx, $04
+ dec esi
+
+ jnz @@LoopX
+
+ db $0F,$6F,$F0 /// movq mm6, mm0
+ db $0F,$61,$F7 /// punpcklwd mm6, mm7
+ db $0F,$FE,$CE /// paddd mm1, mm6
+ db $0F,$6F,$F0 /// movq mm6, mm0
+ db $0F,$69,$F7 /// punpckhwd mm6, mm7
+ db $0F,$FE,$D6 /// paddd mm2, mm6
+ add ecx, ebx
+ dec edx
+
+ jnz @@LoopY
+
+ mul edi
+ mov ecx, eax
+ mov eax, $01000000
+ div ecx
+ mov ecx, eax
+
+ db $0F,$7E,$C8 /// movd eax, mm1
+ mul ecx
+ shr eax, $18
+ mov edi, eax
+
+ db $0F,$73,$D1,$20 /// psrlq mm1, $20
+ db $0F,$7E,$C8 /// movd eax, mm1
+ mul ecx
+ shr eax, $10
+ and eax, $0000FF00
+ add edi, eax
+
+ db $0F,$7E,$D0 /// movd eax, mm2
+ mul ecx
+ shr eax, $08
+ and eax, $00FF0000
+ add edi, eax
+
+ db $0F,$73,$D2,$20 /// psrlq mm2, $20
+ db $0F,$7E,$D0 /// movd eax, mm2
+ mul ecx
+ and eax, $FF000000
+ add eax, edi
+
+ pop edi
+ pop esi
+ pop ebx
+end;
+
+function BlockAverage_IA32(Dlx, Dly, RowSrc, OffSrc: Cardinal): TColor32;
+type
+ PCardinal = ^Cardinal;
+ PRGBA = ^TRGBA;
+ TRGBA = record B,G,R,A: Byte end;
+
+var
+ C: PRGBA;
+ ix,iy,
+ iA,iR,iG,iB, Area: Cardinal;
+begin
+ iR:=0; iB:=iR; iG:=iR; iA:=iR;
+ for iy := 1 to Dly do
+ begin
+ C:= PRGBA(RowSrc);
+ for ix := 1 to Dlx do
+ begin
+ inc(iB, C.B);
+ inc(iG, C.G);
+ inc(iR, C.R);
+ inc(iA, C.A);
+ inc(C);
+ end;
+ inc(RowSrc, OffSrc);
+ end;
+ Area := Dlx * Dly;
+ Area := $1000000 div Area;
+ Result:= iA * Area and $FF000000 or
+ iR * Area shr 8 and $FF0000 or
+ iG * Area shr 16 and $FF00 or
+ iB * Area shr 24 and $FF;
+end;
+
+procedure DraftResample(Dst: TBitmap32; DstRect: TRect; DstClip: TRect;
+ Src: TBitmap32; SrcRect: TRect;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
+var
+ SrcW, SrcH,
+ DstW, DstH,
+ DstClipW, DstClipH: Cardinal;
+ RowSrc, OffSrc,
+ dy, dx,
+ c1, c2, r1, r2,
+ xs, xsrc, M: Cardinal;
+ C: TColor32;
+ DstLine: PColor32Array;
+ ScaleFactor,lx, fe: Single;
+ FSrcTop,I,J,ly,
+ sc, sr, cx, cy: integer;
+ Y_256: TFixed;
+begin
+ { rangechecking and rect intersection done by caller }
+
+ SrcW := SrcRect.Right - SrcRect.Left;
+ SrcH := SrcRect.Bottom - SrcRect.Top;
+
+ DstW := DstRect.Right - DstRect.Left;
+ DstH := DstRect.Bottom - DstRect.Top;
+
+ DstClipW := DstClip.Right - DstClip.Left;
+ DstClipH := DstClip.Bottom - DstClip.Top;
+
+
+ if (DstW > SrcW)or(DstH > SrcH) then
+ StretchHorzStretchVertLinear(Dst,DstRect,DstClip,Src,SrcRect,CombineOp,CombineCallBack)
+ else
+ begin //Full Scaledown, ignores Fulledge - cannot be integrated into this resampling method
+ OffSrc := Src.Width * 4;
+
+ ScaleFactor:= SrcW / DstW;
+ cx := Trunc( (DstClip.Left - DstRect.Left) * ScaleFactor);
+ r2 := Trunc(ScaleFactor);
+ sr := Trunc( $10000 * ScaleFactor );
+
+ ScaleFactor:= SrcH / DstH;
+ cy := Trunc( (DstClip.Top - DstRect.Top) * ScaleFactor);
+ c2 := Trunc(ScaleFactor);
+ sc := Trunc( $10000 * ScaleFactor );
+
+ DstLine := PColor32Array(Dst.PixelPtr[0, DstClip.Top]);
+ RowSrc := Cardinal(Src.PixelPtr[ SrcRect.Left + cx, SrcRect.Top + cy ]);
+
+ xs := r2;
+ c1 := 0;
+ Dec(DstClip.Left, 2);
+ Inc(DstClipW);
+ Inc(DstClipH);
+ for J := 2 to DstClipH do
+ begin
+ dy:= c2 - c1;
+ c1:= c2;
+ c2:= J * sc shr 16;
+ r1:= 0;
+ r2:= xs;
+ xsrc:= RowSrc;
+ case CombineOp of
+ dmOpaque: for I := 2 to DstClipW do
+ begin
+ dx := r2 - r1; r1 := r2;
+ r2 := I * sr shr 16;
+ DstLine[DstClip.Left + I]:= BlockAverage(dx, dy, xsrc, OffSrc);
+ xsrc := xsrc + dx shl 2;
+ end;
+ dmBlend : for I := 2 to DstClipW do
+ begin
+ dx := r2 - r1; r1 := r2;
+ r2 := I * sr shr 16;
+ BlendMemEx(BlockAverage(dx, dy, xsrc, OffSrc), DstLine[DstClip.Left + I], Src.MasterAlpha);
+ xsrc := xsrc + dx shl 2;
+ end;
+ dmCustom: for I := 2 to DstClipW do
+ begin
+ dx := r2 - r1; r1 := r2;
+ r2 := I * sr shr 16;
+ CombineCallBack(BlockAverage(dx, dy, xsrc, OffSrc), DstLine[DstClip.Left + I], Src.MasterAlpha);
+ xsrc := xsrc + dx shl 2;
+ end;
+ end;
+ Inc(DstLine, Dst.Width);
+ inc(RowSrc, OffSrc * dy);
+ end;
+ end;
+ EMMS;
+end;
+
+{ Stretch Transfer }
+
+{$WARNINGS OFF}
+procedure StretchTransfer(
+ Dst: TBitmap32; DstRect: TRect; DstClip: TRect;
+ Src: TBitmap32; SrcRect: TRect;
+ StretchFilter: TStretchFilter;
+ CombineOp: TDrawMode; CombineCallBack: TPixelCombineEvent);
+var
+ SrcW, SrcH: Single;
+ DstW, DstH: Integer;
+ R: TRect;
+begin
+ if Src.Empty then Exit;
+ CheckBitmaps(Dst, Src);
+ if not CheckSrcRect(Src, SrcRect) then Exit;
+ IntersectRect(DstClip, DstClip, MakeRect(0, 0, Dst.Width, Dst.Height));
+ IntersectRect(DstClip, DstClip, DstRect);
+ if IsRectEmpty(DstClip) then Exit;
+ IntersectRect(R, DstClip, DstRect);
+ if IsRectEmpty(R) then Exit;
+
+ if (CombineOp = dmCustom) and not Assigned(CombineCallBack) then CombineOp := dmOpaque;
+ if (CombineOp = dmBlend) and (Src.MasterAlpha = 0) then Exit;
+
+ SrcW := SrcRect.Right - SrcRect.Left;
+ SrcH := SrcRect.Bottom - SrcRect.Top;
+ DstW := DstRect.Right - DstRect.Left;
+ DstH := DstRect.Bottom - DstRect.Top;
+
+ try
+ if (SrcW = DstW) and (SrcH = DstH) then
+ BlendBlock(Dst, DstClip, Src, SrcRect.Left + DstClip.Left - DstRect.Left,
+ SrcRect.Top + DstClip.Top - DstRect.Top, CombineOp, CombineCallBack)
+ else case StretchFilter of
+ sfNearest: StretchNearest(Dst, DstRect, DstClip, Src, SrcRect, CombineOp, CombineCallBack);
+ sfDraft: DraftResample(Dst, DstRect, DstClip, Src, SrcRect, CombineOp, CombineCallBack);
+ sfLinear:
+ if (DstW > SrcW) and (DstH > SrcH) then
+ StretchHorzStretchVertLinear(Dst, DstRect, DstClip, Src, SrcRect, CombineOp, CombineCallBack)
+ else
+ Resample(Dst, DstRect, DstClip, Src, SrcRect, sfLinear, CombineOp, CombineCallBack);
+ else
+ Resample(Dst, DstRect, DstClip, Src, SrcRect, StretchFilter, CombineOp, CombineCallBack);
+ end;
+
+ finally
+ EMMS;
+ end;
+end;
+{$WARNINGS ON}
+
+
+{ A bit of linear algebra }
+
+function _DET(a1, a2, b1, b2: Single): Single; overload;
+begin
+ Result := a1 * b2 - a2 * b1;
+end;
+
+function _DET(a1, a2, a3, b1, b2, b3, c1, c2, c3: Single): Single; overload;
+begin
+ Result :=
+ a1 * (b2 * c3 - b3 * c2) -
+ b1 * (a2 * c3 - a3 * c2) +
+ c1 * (a2 * b3 - a3 * b2);
+end;
+
+procedure Adjoint(var M: TFloatMatrix);
+var
+ a1, a2, a3: Single;
+ b1, b2, b3: Single;
+ c1, c2, c3: Single;
+begin
+ a1 := M[0,0]; a2:= M[0,1]; a3 := M[0,2];
+ b1 := M[1,0]; b2:= M[1,1]; b3 := M[1,2];
+ c1 := M[2,0]; c2:= M[2,1]; c3 := M[2,2];
+
+ M[0,0]:= _DET(b2, b3, c2, c3);
+ M[0,1]:=-_DET(a2, a3, c2, c3);
+ M[0,2]:= _DET(a2, a3, b2, b3);
+
+ M[1,0]:=-_DET(b1, b3, c1, c3);
+ M[1,1]:= _DET(a1, a3, c1, c3);
+ M[1,2]:=-_DET(a1, a3, b1, b3);
+
+ M[2,0]:= _DET(b1, b2, c1, c2);
+ M[2,1]:=-_DET(a1, a2, c1, c2);
+ M[2,2]:= _DET(a1, a2, b1, b2);
+end;
+
+function Determinant(const M: TFloatMatrix): Single;
+begin
+ Result := _DET(M[0,0], M[1,0], M[2,0],
+ M[0,1], M[1,1], M[2,1],
+ M[0,2], M[1,2], M[2,2]);
+end;
+
+procedure Scale(var M: TFloatMatrix; Factor: Single);
+var
+ i, j: Integer;
+begin
+ for i := 0 to 2 do
+ for j := 0 to 2 do
+ M[i,j] := M[i,j] * Factor;
+end;
+
+procedure Invert(var M: TFloatMatrix);
+var
+ Det: Single;
+begin
+ Det := Determinant(M);
+ if Abs(Det) < 1E-5 then M := IdentityMatrix
+ else
+ begin
+ Adjoint(M);
+ Scale(M, 1 / Det);
+ end;
+end;
+
+function Mult(const M1, M2: TFloatMatrix): TFloatMatrix;
+var
+ i, j: Integer;
+begin
+ for i := 0 to 2 do
+ for j := 0 to 2 do
+ Result[i, j] :=
+ M1[0, j] * M2[i, 0] +
+ M1[1, j] * M2[i, 1] +
+ M1[2, j] * M2[i, 2];
+end;
+
+function VectorTransform(const M: TFloatMatrix; const V: TVector3f): TVector3f;
+begin
+ Result[0] := M[0,0] * V[0] + M[1,0] * V[1] + M[2,0] * V[2];
+ Result[1] := M[0,1] * V[0] + M[1,1] * V[1] + M[2,1] * V[2];
+ Result[2] := M[0,2] * V[0] + M[1,2] * V[1] + M[2,2] * V[2];
+end;
+
+
+{ Transformation functions }
+
+procedure Transform(Dst, Src: TBitmap32; Transformation: TTransformation);
+var
+ C, SrcAlpha: TColor32;
+ R, SrcRectI, DstRect, SrcRect256: TRect;
+ Pixels: PColor32Array;
+ I, J, X, Y: Integer;
+ DrawMode: TDrawMode;
+ CombineCallBack: TPixelCombineEvent;
+
+ function GET_S256(X256, Y256: Integer; out C: TColor32): Boolean;
+ begin
+ X := SAR_8(X256);
+ Y := SAR_8(Y256);
+ if (x > SrcRectI.Left) and (x < SrcRectI.Right - 1) and
+ (y > SrcRectI.Top) and (y < SrcRectI.Bottom - 1) then
+ begin
+ // everything is ok interpolate between four neighbors
+ C:= Src.PixelX[X256 shl 8, Y256 shl 8];
+ Result := True;
+ end
+ else if (x < SrcRectI.Left - 1) or (y < SrcRectI.Top - 1) or
+ (x >= SrcRectI.Right) or (y >= SrcRectI.Bottom) then
+ begin
+ // (X,Y) coordinate is out of the SrcRect, do not interpolate
+ C := 0; // just write something to disable compiler warnings
+ Result := False;
+ end
+ else
+ begin
+ // handle edge
+ C:= Src.PixelXS[X256 shl 8, Y256 shl 8];
+ Result := True;
+ end;
+ end;
+
+begin
+ if not Transformation.TransformValid then Transformation.PrepareTransform;
+
+ CombineCallBack := Src.OnPixelCombine; // store it into a local variable
+ DrawMode := Src.DrawMode; // store it into a local variable
+ SrcAlpha := Src.MasterAlpha;
+ if (DrawMode = dmCustom) and not Assigned(CombineCallBack) then
+ DrawMode := dmOpaque;
+
+ // clip SrcRect
+
+ // workaround C++ Builder throwing exceptions:
+ R := MakeRect(Round(Transformation.SrcRect.Left), Round(Transformation.SrcRect.Top),
+ Round(Transformation.SrcRect.Right), Round(Transformation.SrcRect.Bottom));
+
+ IntersectRect(SrcRectI, R, MakeRect(0, 0, Src.Width - 1, Src.Height - 1));
+
+ with Transformation.SrcRect do
+ begin
+ IntersectRect(SrcRect256, MakeRect(Round(Left * 256), Round(Top * 256),
+ Round(Right * 256), Round(Bottom * 256)), MakeRect(0, 0, (Src.Width - 1) * 256,
+ (Src.Height - 1) * 256));
+ end;
+
+ // clip DstRect
+ R := Transformation.GetTransformedBounds;
+ IntersectRect(DstRect, R, MakeRect(0, 0, Dst.Width - 1, Dst.Height - 1));
+ if IsRectEmpty(DstRect) then Exit;
+
+ try
+ if Src.StretchFilter <> sfNearest then
+ for J := DstRect.Top to DstRect.Bottom do
+ begin
+ Pixels := Dst.ScanLine[J];
+ for I := DstRect.Left to DstRect.Right do
+ begin
+ Transformation.Transform256(I, J, X, Y);
+ if GET_S256(X, Y, C) then
+ case DrawMode of
+ dmOpaque: Pixels[I] := C;
+ dmBlend: BlendMemEx(C, Pixels[I], SrcAlpha);
+ else // dmCustom:
+ CombineCallBack(C, Pixels[I], SrcAlpha);
+ end;
+ end;
+ end
+ else // nearest filter
+ for J := DstRect.Top to DstRect.Bottom do
+ begin
+ Pixels := Dst.ScanLine[J];
+ for I := DstRect.Left to DstRect.Right do
+ begin
+ Transformation.Transform(I, J, X, Y);
+ if (X >= SrcRectI.Left) and (X <= SrcRectI.Right) and
+ (Y >= SrcRectI.Top) and (Y <= SrcRectI.Bottom) then
+ case DrawMode of
+ dmOpaque: Pixels[I] := Src.Pixel[X, Y];
+ dmBlend: BlendMemEx(Src.Pixel[X, Y], Pixels[I], SrcAlpha);
+ else // dmCustom:
+ CombineCallBack(Src.Pixel[X, Y], Pixels[I], SrcAlpha);
+ end;
+ end;
+ end;
+ finally
+ EMMS;
+ end;
+ Dst.Changed;
+end;
+
+procedure SetBorderTransparent(ABitmap: TBitmap32; ARect: TRect);
+var
+ I: Integer;
+begin
+ if TestClip(ARect.Left, ARect.Right, ABitmap.Width) and
+ TestClip(ARect.Top, ARect.Bottom, ABitmap.Height) then
+ begin
+ for I := ARect.Left to ARect.Right do
+ ABitmap[I, ARect.Top] := ABitmap[I, ARect.Top] and $00FFFFFF;
+
+ for I := ARect.Left to ARect.Right do
+ ABitmap[I, ARect.Bottom] := ABitmap[I, ARect.Bottom] and $00FFFFFF;
+
+ if ARect.Bottom > ARect.Top + 1 then
+ for I := ARect.Top + 1 to ARect.Bottom - 1 do
+ begin
+ ABitmap[ARect.Left, I] := ABitmap[ARect.Left, I] and $00FFFFFF;
+ ABitmap[ARect.Right, I] := ABitmap[ARect.Right, I] and $00FFFFFF;
+ end;
+
+ ABitmap.Changed;
+ end;
+end;
+
+
+{ TTransformation }
+
+procedure TTransformation.SetSrcRect(const Value: TFloatRect);
+begin
+ FSrcRect := Value;
+ TransformValid := False;
+end;
+
+
+{ TAffineTransformation }
+
+procedure TAffineTransformation.Clear;
+begin
+ Matrix := IdentityMatrix;
+ TransformValid := False;
+end;
+
+constructor TAffineTransformation.Create;
+begin
+ Clear;
+end;
+
+function TAffineTransformation.GetTransformedBounds: TRect;
+var
+ V1, V2, V3, V4: TVector3f;
+begin
+ V1[0] := FSrcRect.Left; V1[1] := FSrcRect.Top; V1[2] := 1;
+ V2[0] := FSrcRect.Right; V2[1] := V1[1]; V2[2] := 1;
+ V3[0] := V1[0]; V3[1] := FSrcRect.Bottom; V3[2] := 1;
+ V4[0] := V2[0]; V4[1] := V3[1]; V4[2] := 1;
+ V1 := VectorTransform(Matrix, V1);
+ V2 := VectorTransform(Matrix, V2);
+ V3 := VectorTransform(Matrix, V3);
+ V4 := VectorTransform(Matrix, V4);
+ Result.Left := Round(Min(Min(V1[0], V2[0]), Min(V3[0], V4[0])) - 0.5);
+ Result.Right := Round(Max(Max(V1[0], V2[0]), Max(V3[0], V4[0])) + 0.5);
+ Result.Top := Round(Min(Min(V1[1], V2[1]), Min(V3[1], V4[1])) - 0.5);
+ Result.Bottom := Round(Max(Max(V1[1], V2[1]), Max(V3[1], V4[1])) + 0.5);
+end;
+
+procedure TAffineTransformation.PrepareTransform;
+var
+ M: TFloatMatrix;
+begin
+ M := Matrix;
+ Invert(M);
+
+ // calculate a fixed point (4096) factors
+ A := Round(M[0,0] * 4096); B := Round(M[1,0] * 4096); C := Round(M[2,0] * 4096);
+ D := Round(M[0,1] * 4096); E := Round(M[1,1] * 4096); F := Round(M[2,1] * 4096);
+
+ TransformValid := True;
+end;
+
+procedure TAffineTransformation.Rotate(Cx, Cy, Alpha: Single);
+var
+ S, C: Single;
+ M: TFloatMatrix;
+begin
+ TransformValid := False;
+ if (Cx <> 0) or (Cy <> 0) then Translate(-Cx, -Cy);
+ Alpha := DegToRad(Alpha);
+ S := Sin(Alpha); C := Cos(Alpha);
+ M := IdentityMatrix;
+ M[0,0] := C; M[1,0] := S;
+ M[0,1] := -S; M[1,1] := C;
+ Matrix := Mult(M, Matrix);
+ if (Cx <> 0) or (Cy <> 0) then Translate(Cx, Cy);
+end;
+
+procedure TAffineTransformation.Scale(Sx, Sy: Single);
+var
+ M: TFloatMatrix;
+begin
+ TransformValid := False;
+ M := IdentityMatrix;
+ M[0,0] := Sx;
+ M[1,1] := Sy;
+ Matrix := Mult(M, Matrix);
+end;
+
+procedure TAffineTransformation.Skew(Fx, Fy: Single);
+var
+ M: TFloatMatrix;
+begin
+ TransformValid := False;
+ M := IdentityMatrix;
+ M[1, 0] := Fx;
+ M[0, 1] := Fy;
+ Matrix := Mult(M, Matrix);
+end;
+
+procedure TAffineTransformation.Transform(
+ DstX, DstY: Integer;
+ out SrcX, SrcY: Integer);
+begin
+ SrcX := SAR_12(DstX * A + DstY * B + C + 2047);
+ SrcY := SAR_12(DstX * D + DstY * E + F + 2047);
+end;
+
+procedure TAffineTransformation.Transform256(
+ DstX, DstY: Integer;
+ out SrcX256, SrcY256: Integer);
+begin
+ SrcX256 := SAR_4(DstX * A + DstY * B + C + 7);
+ SrcY256 := SAR_4(DstX * D + DstY * E + F + 7);
+end;
+
+procedure TAffineTransformation.Translate(Dx, Dy: Single);
+var
+ M: TFloatMatrix;
+begin
+ TransformValid := False;
+ M := IdentityMatrix;
+ M[2,0] := Dx;
+ M[2,1] := Dy;
+ Matrix := Mult(M, Matrix);
+end;
+
+
+{ TProjectiveTransformation }
+
+function TProjectiveTransformation.GetTransformedBounds: TRect;
+begin
+ Result.Left := Round(Min(Min(Wx0, Wx1), Min(Wx2, Wx3)) - 0.5);
+ Result.Right := Round(Max(Max(Wx0, Wx1), Max(Wx2, Wx3)) + 0.5);
+ Result.Top := Round(Min(Min(Wy0, Wy1), Min(Wy2, Wy3)) - 0.5);
+ Result.Bottom := Round(Max(Max(Wy0, Wy1), Max(Wy2, Wy3)) + 0.5);
+end;
+
+procedure TProjectiveTransformation.PrepareTransform;
+var
+ dx1, dx2, px, dy1, dy2, py: Single;
+ g, h, k: Single;
+ R: TFloatMatrix;
+begin
+ px := Wx0 - Wx1 + Wx2 - Wx3;
+ py := Wy0 - Wy1 + Wy2 - Wy3;
+
+ if (px = 0) and (py = 0) then
+ begin
+ // affine mapping
+ M[0,0] := Wx1 - Wx0;
+ M[1,0] := Wx2 - Wx1;
+ M[2,0] := Wx0;
+
+ M[0,1] := Wy1 - Wy0;
+ M[1,1] := Wy2 - Wy1;
+ M[2,1] := Wy0;
+
+ M[0,2] := 0;
+ M[1,2] := 0;
+ M[2,2] := 1;
+ end
+ else
+ begin
+ // projective mapping
+ dx1 := Wx1 - Wx2;
+ dx2 := Wx3 - Wx2;
+ dy1 := Wy1 - Wy2;
+ dy2 := Wy3 - Wy2;
+ k := dx1 * dy2 - dx2 * dy1;
+ if k <> 0 then
+ begin
+ g := (px * dy2 - py * dx2) / k;
+ h := (dx1 * py - dy1 * px) / k;
+
+ M[0,0] := Wx1 - Wx0 + g * Wx1;
+ M[1,0] := Wx3 - Wx0 + h * Wx3;
+ M[2,0] := Wx0;
+
+ M[0,1] := Wy1 - Wy0 + g * Wy1;
+ M[1,1] := Wy3 - Wy0 + h * Wy3;
+ M[2,1] := Wy0;
+
+ M[0,2] := g;
+ M[1,2] := h;
+ M[2,2] := 1;
+ end
+ else
+ begin
+ FillChar(M, SizeOf(M), 0);
+ end;
+ end;
+
+ // denormalize texture space (u, v)
+ R := IdentityMatrix;
+ R[0,0] := 1 / (SrcRect.Right - SrcRect.Left);
+ R[1,1] := 1 / (SrcRect.Bottom - SrcRect.Top);
+ M := Mult(M, R);
+
+ R := IdentityMatrix;
+ R[2,0] := -SrcRect.Left;
+ R[2,1] := -SrcRect.Top;
+ M := Mult(M, R);
+
+ Invert(M);
+
+ TransformValid := True;
+end;
+
+procedure TProjectiveTransformation.SetX0(Value: Single);
+begin
+ Wx0 := Value; TransformValid := False;
+end;
+
+procedure TProjectiveTransformation.SetX1(Value: Single);
+begin
+ Wx1 := Value; TransformValid := False;
+end;
+
+procedure TProjectiveTransformation.SetX2(Value: Single);
+begin
+ Wx2 := Value; TransformValid := False;
+end;
+
+procedure TProjectiveTransformation.SetX3(Value: Single);
+begin
+ Wx3 := Value; TransformValid := False;
+end;
+
+procedure TProjectiveTransformation.SetY0(Value: Single);
+begin
+ Wy0 := Value; TransformValid := False;
+end;
+
+procedure TProjectiveTransformation.SetY1(Value: Single);
+begin
+ Wy1 := Value; TransformValid := False;
+end;
+
+procedure TProjectiveTransformation.SetY2(Value: Single);
+begin
+ Wy2 := Value; TransformValid := False;
+end;
+
+procedure TProjectiveTransformation.SetY3(Value: Single);
+begin
+ Wy3 := Value; TransformValid := False;
+end;
+
+procedure TProjectiveTransformation.Transform(DstX, DstY: Integer;
+ out SrcX, SrcY: Integer);
+var
+ X, Y, Z: Single;
+begin
+ EMMS;
+ X := DstX; Y := DstY;
+ Z := M[0,2] * X + M[1,2] * Y + M[2,2];
+ if Z = 0 then Exit
+ else if Z = 1 then
+ begin
+ SrcX := Round(M[0,0] * X + M[1,0] * Y + M[2,0]);
+ SrcY := Round(M[0,1] * X + M[1,1] * Y + M[2,1]);
+ end
+ else
+ begin
+ Z := 1 / Z;
+ SrcX := Round((M[0,0] * X + M[1,0] * Y + M[2,0]) * Z);
+ SrcY := Round((M[0,1] * X + M[1,1] * Y + M[2,1]) * Z);
+ end;
+end;
+
+procedure TProjectiveTransformation.Transform256(DstX, DstY: Integer;
+ out SrcX256, SrcY256: Integer);
+var
+ X, Y, Z: Single;
+begin
+ EMMS;
+ X := DstX; Y := DstY;
+ Z := M[0,2] * X + M[1,2] * Y + M[2,2];
+ if Z = 0 then Exit
+ else if Z = 1 then
+ begin
+ SrcX256 := Round(256 * (M[0,0] * X + M[1,0] * Y + M[2,0]));
+ SrcY256 := Round(256 * (M[0,1] * X + M[1,1] * Y + M[2,1]));
+ end
+ else
+ begin
+ Z := 1 / Z;
+ SrcX256 := Round(256 * (M[0,0] * X + M[1,0] * Y + M[2,0]) * Z);
+ SrcY256 := Round(256 * (M[0,1] * X + M[1,1] * Y + M[2,1]) * Z);
+ end;
+end;
+
+{ Special interpolators (for sfLinear and sfDraft) }
+
+function M_LinearInterpolator(PWX_256, PWY_256: Cardinal; C11, C21: PColor32): TColor32;
+asm
+ db $0F,$6F,$09 /// MOVQ MM1,[ECX]
+ MOV ECX,C21
+ db $0F,$6F,$19 /// MOVQ MM3,[ECX]
+ db $0F,$6F,$D1 /// MOVQ MM2,MM1
+ db $0F,$6F,$E3 /// MOVQ MM4,MM3
+ db $0F,$73,$D1,$20 /// PSRLQ MM1,32
+ db $0F,$73,$D3,$20 /// PSRLQ MM3,32
+ db $0F,$6E,$E8 /// MOVD MM5,EAX
+ db $0F,$62,$ED /// PUNPCKLDQ MM5,MM5
+ db $0F,$EF,$C0 /// PXOR MM0, MM0
+ db $0F,$60,$C8 /// PUNPCKLBW MM1,MM0
+ db $0F,$60,$D0 /// PUNPCKLBW MM2,MM0
+ db $0F,$F9,$D1 /// PSUBW MM2,MM1
+ db $0F,$D5,$D5 /// PMULLW MM2,MM5
+ db $0F,$71,$F1,$08 /// PSLLW MM1,8
+ db $0F,$FD,$D1 /// PADDW MM2,MM1
+ db $0F,$71,$D2,$08 /// PSRLW MM2,8
+ db $0F,$60,$D8 /// PUNPCKLBW MM3,MM0
+ db $0F,$60,$E0 /// PUNPCKLBW MM4,MM0
+ db $0F,$F9,$E3 /// PSUBW MM4,MM3
+ db $0F,$D5,$E5 /// PMULLW MM4,MM5
+ db $0F,$71,$F3,$08 /// PSLLW MM3,8
+ db $0F,$FD,$E3 /// PADDW MM4,MM3
+ db $0F,$71,$D4,$08 /// PSRLW MM4,8
+ db $0F,$6E,$EA /// MOVD MM5,EDX
+ db $0F,$62,$ED /// PUNPCKLDQ MM5,MM5
+ db $0F,$F9,$D4 /// PSUBW MM2,MM4
+ db $0F,$D5,$D5 /// PMULLW MM2,MM5
+ db $0F,$71,$F4,$08 /// PSLLW MM4,8
+ db $0F,$FD,$D4 /// PADDW MM2,MM4
+ db $0F,$71,$D2,$08 /// PSRLW MM2,8
+ db $0F,$67,$D0 /// PACKUSWB MM2,MM0
+ db $0F,$7E,$D0 /// MOVD EAX,MM2
+end;
+
+function _LinearInterpolator(PWX_256, PWY_256: Cardinal; C11, C21: PColor32): TColor32;
+var
+ C1, C3: TColor32;
+begin
+ PWX_256:= PWX_256 shr 16; if PWX_256 > $FF then PWX_256:= $FF;
+ PWY_256:= PWY_256 shr 16; if PWY_256 > $FF then PWY_256:= $FF;
+ C1 := C11^; Inc(C11);
+ C3 := C21^; Inc(C21);
+ Result := CombineReg(CombineReg(C1, C11^, PWX_256),
+ CombineReg(C3, C21^, PWX_256), PWY_256);
+end;
+
+
+procedure SetupFunctions;
+var
+ MMX_ACTIVE: Boolean;
+ ACTIVE_3DNow: Boolean;
+begin
+ MMX_ACTIVE := HasMMX;
+ ACTIVE_3DNow := Has3DNow;
+ if ACTIVE_3DNow then
+ begin
+ // link 3DNow functions
+ BlockAverage:= BlockAverage_3DNow;
+ LinearInterpolator:= M_LinearInterpolator;
+ end
+ else
+ if MMX_ACTIVE then
+ begin
+ // link MMX functions
+ BlockAverage:= BlockAverage_MMX;
+ LinearInterpolator:= M_LinearInterpolator;
+ end
+ else
+ begin
+ // link IA32 functions
+ BlockAverage:= BlockAverage_IA32;
+ LinearInterpolator:= _LinearInterpolator;
+ end
+end;
+
+initialization
+ SetupFunctions;
+
+end.
Added: trunk/WPGM/Components/Graphics32/Graphics32.chm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Graphics32.chm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/License.html
===================================================================
--- trunk/WPGM/Components/Graphics32/License.html 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/License.html 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,834 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html><head>
+
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+
+ <meta name="GENERATOR" content="Mozilla/4.5 [en]C-NSCP (Win95; U) [Netscape]">
+
+ <title>Mozilla Public License version 1.1</title></head>
+
+
+
+<body alink="#ff0000" bgcolor="#ffffff" link="#0000ee" text="#000000" vlink="#551a8b">
+
+
+
+<center><b><font size="+2">MOZILLA PUBLIC LICENSE</font></b>
+
+<br><b>Version 1.1</b>
+
+<p>
+
+</p><hr width="20%"></center>
+
+
+<a name="1"></a>
+<p><b>1. Definitions.</b>
+
+<a name="1.0.1"></a>
+</p><ul><b>1.0.1. "Commercial Use" </b>means distribution or otherwise making
+
+the Covered Code available to a third party.
+
+<a name="1.1"></a>
+<p><b>1.1. ''Contributor''</b> means each entity that creates or contributes
+
+to the creation of Modifications.
+
+<a name="1.2"></a>
+</p><p><b>1.2. ''Contributor Version''</b> means the combination of the Original
+
+Code, prior Modifications used by a Contributor, and the Modifications
+
+made by that particular Contributor.
+
+<a name="1.3"></a>
+</p><p><b>1.3. ''Covered Code''</b> means the Original Code or Modifications
+
+or the combination of the Original Code and Modifications, in each case
+
+including portions thereof<b>.</b>
+
+<a name="1.4"></a>
+</p><p><b>1.4. ''Electronic Distribution Mechanism''</b> means a mechanism
+
+generally accepted in the software development community for the electronic
+
+transfer of data.
+
+<a name="1.5"></a>
+</p><p><b>1.5. ''Executable''</b> means Covered Code in any form other than
+
+Source Code.
+
+<a name="1.6"></a>
+</p><p><b>1.6. ''Initial Developer''</b> means the individual or entity identified
+
+as the Initial Developer in the Source Code notice required by <b>Exhibit
+
+A</b>.
+
+<a name="1.7"></a>
+</p><p><b>1.7. ''Larger Work''</b> means a work which combines Covered Code
+
+or portions thereof with code not governed by the terms of this License.
+
+<a name="1.8"></a>
+</p><p><b>1.8. ''License''</b> means this document.
+
+<a name="1.8.1"></a>
+</p><p><b>1.8.1. "Licensable"</b> means having the right to grant, to the maximum
+
+extent possible, whether at the time of the initial grant or subsequently
+
+acquired, any and all of the rights conveyed herein.
+
+<a name="1.9"></a>
+</p><p><b>1.9. ''Modifications''</b> means any addition to or deletion from
+
+the substance or structure of either the Original Code or any previous
+
+Modifications. When Covered Code is released as a series of files, a Modification
+
+is:
+
+</p><ul><b>A.</b> Any addition to or deletion from the contents of a file containing
+
+Original Code or previous Modifications.
+
+<p><b>B.</b> Any new file that contains any part of the Original Code or
+
+previous Modifications.
+
+<br> </p></ul>
+
+<a name="1.10"></a>
+<b>1.10. ''Original Code''</b> means Source Code of computer software code
+
+which is described in the Source Code notice required by <b>Exhibit A</b>
+
+as Original Code, and which, at the time of its release under this License
+
+is not already Covered Code governed by this License.
+
+<a name="1.10.1"></a>
+<p><b>1.10.1. "Patent Claims"</b> means any patent claim(s), now owned
+
+or hereafter acquired, including without limitation, method, process,
+
+and apparatus claims, in any patent Licensable by grantor.
+
+<a name="1.11"></a>
+</p><p><b>1.11. ''Source Code''</b> means the preferred form of the Covered
+
+Code for making modifications to it, including all modules it contains,
+
+plus any associated interface definition files, scripts used to control
+
+compilation and installation of an Executable, or source code differential
+
+comparisons against either the Original Code or another well known, available
+
+Covered Code of the Contributor's choice. The Source Code can be in a compressed
+
+or archival form, provided the appropriate decompression or de-archiving
+
+software is widely available for no charge.
+
+<a name="1.12"></a>
+</p><p><b>1.12. "You'' (or "Your") </b> means an individual or a legal
+
+entity exercising rights under, and complying with all of the terms of,
+
+this License or a future version of this License issued under Section 6.1.
+
+For legal entities, "You'' includes any entity which controls, is controlled
+
+by, or is under common control with You. For purposes of this definition,
+
+"control'' means (a) the power, direct or indirect, to cause the direction
+
+or management of such entity, whether by contract or otherwise, or (b)
+
+ownership of more than fifty percent (50%) of the outstanding shares or
+
+beneficial ownership of such entity.</p></ul>
+
+<a name="2"></a>
+<b>2. Source Code License.</b>
+
+<a name="2.1"></a>
+<ul><b>2.1. The Initial Developer Grant.</b>
+
+<br>The Initial Developer hereby grants You a world-wide, royalty-free,
+
+non-exclusive license, subject to third party intellectual property claims:
+
+<ul><b>(a)</b> <b> </b>under intellectual property rights (other than
+
+patent or trademark) Licensable by Initial Developer to use, reproduce,
+
+modify, display, perform, sublicense and distribute the Original Code (or
+
+portions thereof) with or without Modifications, and/or as part of a Larger
+
+Work; and
+
+<p><b>(b)</b> under Patents Claims infringed by the making, using or selling
+
+of Original Code, to make, have made, use, practice, sell, and offer for
+
+sale, and/or otherwise dispose of the Original Code (or portions thereof).
+
+</p><ul>
+
+<ul> </ul>
+
+</ul>
+
+<b>(c) </b>the licenses granted in this Section 2.1(a) and (b) are effective
+
+on the date Initial Developer first distributes Original Code under the
+
+terms of this License.
+
+<p><b>(d) </b>Notwithstanding Section 2.1(b) above, no patent license is
+
+granted: 1) for code that You delete from the Original Code; 2) separate
+
+from the Original Code; or 3) for infringements caused by: i) the
+
+modification of the Original Code or ii) the combination of the Original
+
+Code with other software or devices.
+
+<br> </p></ul>
+
+<a name="2.2"></a>
+<b>2.2. Contributor Grant.</b>
+
+<br>Subject to third party intellectual property claims, each Contributor
+
+hereby grants You a world-wide, royalty-free, non-exclusive license
+
+<ul>
+
+<br><b>(a)</b> <b> </b>under intellectual property rights (other than
+
+patent or trademark) Licensable by Contributor, to use, reproduce, modify,
+
+display, perform, sublicense and distribute the Modifications created by
+
+such Contributor (or portions thereof) either on an unmodified basis, with
+
+other Modifications, as Covered Code and/or as part of a Larger Work; and
+
+<p><b>(b)</b> under Patent Claims infringed by the making, using, or selling
+
+of Modifications made by that Contributor either alone and/or in<font color="#000000">
+
+combination with its Contributor Version (or portions of such combination),
+
+to make, use, sell, offer for sale, have made, and/or otherwise dispose
+
+of: 1) Modifications made by that Contributor (or portions thereof); and
+
+2) the combination of Modifications made by that Contributor with
+
+its Contributor Version (or portions of such combination).</font>
+
+</p><p><b>(c) </b>the licenses granted in Sections 2.2(a) and 2.2(b) are effective
+
+on the date Contributor first makes Commercial Use of the Covered Code.
+
+</p><p><b>(d) </b> Notwithstanding Section 2.2(b) above, no
+
+patent license is granted: 1) for any code that Contributor has deleted
+
+from the Contributor Version; 2) separate from the Contributor Version;
+
+3) for infringements caused by: i) third party modifications of Contributor
+
+Version or ii) the combination of Modifications made by that Contributor
+
+with other software (except as part of the Contributor Version) or
+
+other devices; or 4) under Patent Claims infringed by Covered Code in the
+
+absence of Modifications made by that Contributor.</p></ul>
+
+</ul>
+
+
+
+<a name="3"></a>
+<p><br><b>3. Distribution Obligations.</b>
+
+<a name="3.1"></a>
+</p><ul><b>3.1. Application of License.</b>
+
+<br>The Modifications which You create or to which You contribute are governed
+
+by the terms of this License, including without limitation Section <b>2.2</b>.
+
+The Source Code version of Covered Code may be distributed only under the
+
+terms of this License or a future version of this License released under
+
+Section <b>6.1</b>, and You must include a copy of this License with every
+
+copy of the Source Code You distribute. You may not offer or impose any
+
+terms on any Source Code version that alters or restricts the applicable
+
+version of this License or the recipients' rights hereunder. However, You
+
+may include an additional document offering the additional rights described
+
+in Section <b>3.5</b>.
+
+<a name="3.2"></a>
+<p><b>3.2. Availability of Source Code.</b>
+
+<br>Any Modification which You create or to which You contribute must be
+
+made available in Source Code form under the terms of this License either
+
+on the same media as an Executable version or via an accepted Electronic
+
+Distribution Mechanism to anyone to whom you made an Executable version
+
+available; and if made available via Electronic Distribution Mechanism,
+
+must remain available for at least twelve (12) months after the date it
+
+initially became available, or at least six (6) months after a subsequent
+
+version of that particular Modification has been made available to such
+
+recipients. You are responsible for ensuring that the Source Code version
+
+remains available even if the Electronic Distribution Mechanism is maintained
+
+by a third party.
+
+<a name="3.3"></a>
+</p><p><b>3.3. Description of Modifications.</b>
+
+<br>You must cause all Covered Code to which You contribute to contain
+
+a file documenting the changes You made to create that Covered Code and
+
+the date of any change. You must include a prominent statement that the
+
+Modification is derived, directly or indirectly, from Original Code provided
+
+by the Initial Developer and including the name of the Initial Developer
+
+in (a) the Source Code, and (b) in any notice in an Executable version
+
+or related documentation in which You describe the origin or ownership
+
+of the Covered Code.
+
+<a name="3.4"></a>
+</p><p><b>3.4. Intellectual Property Matters</b>
+
+</p><ul><b>(a) Third Party Claims</b>.
+
+<br>If Contributor has knowledge that a license under a third party's intellectual
+
+property rights is required to exercise the rights granted by such Contributor
+
+under Sections 2.1 or 2.2, Contributor must include a text file with the
+
+Source Code distribution titled "LEGAL'' which describes the claim and
+
+the party making the claim in sufficient detail that a recipient will know
+
+whom to contact. If Contributor obtains such knowledge after the Modification
+
+is made available as described in Section 3.2, Contributor shall promptly
+
+modify the LEGAL file in all copies Contributor makes available thereafter
+
+and shall take other steps (such as notifying appropriate mailing lists
+
+or newsgroups) reasonably calculated to inform those who received the Covered
+
+Code that new knowledge has been obtained.
+
+<p><b>(b) Contributor APIs</b>.
+
+<br>If Contributor's Modifications include an application programming interface
+
+and Contributor has knowledge of patent licenses which are reasonably necessary
+
+to implement that API, Contributor must also include this information in
+
+the LEGAL file.
+
+<br> </p></ul>
+
+ <b>(c)
+
+Representations.</b>
+
+<ul>Contributor represents that, except as disclosed pursuant to Section
+
+3.4(a) above, Contributor believes that Contributor's Modifications are
+
+Contributor's original creation(s) and/or Contributor has sufficient rights
+
+to grant the rights conveyed by this License.</ul>
+
+
+
+<a name="3.5"></a>
+<p><br><b>3.5. Required Notices.</b>
+
+<br>You must duplicate the notice in <b>Exhibit A</b> in each file of the
+
+Source Code. If it is not possible to put such notice in a particular
+
+Source Code file due to its structure, then You must include such notice
+
+in a location (such as a relevant directory) where a user would be likely
+
+to look for such a notice. If You created one or more Modification(s)
+
+You may add your name as a Contributor to the notice described in <b>Exhibit
+
+A</b>. You must also duplicate this License in any documentation
+
+for the Source Code where You describe recipients' rights or ownership
+
+rights relating to Covered Code. You may choose to offer, and to
+
+charge a fee for, warranty, support, indemnity or liability obligations
+
+to one or more recipients of Covered Code. However, You may do so only
+
+on Your own behalf, and not on behalf of the Initial Developer or any Contributor.
+
+You must make it absolutely clear than any such warranty, support, indemnity
+
+or liability obligation is offered by You alone, and You hereby agree to
+
+indemnify the Initial Developer and every Contributor for any liability
+
+incurred by the Initial Developer or such Contributor as a result of warranty,
+
+support, indemnity or liability terms You offer.
+
+<a name="3.6"></a>
+</p><p><b>3.6. Distribution of Executable Versions.</b>
+
+<br>You may distribute Covered Code in Executable form only if the requirements
+
+of Section <b>3.1-3.5</b> have been met for that Covered Code, and if You
+
+include a notice stating that the Source Code version of the Covered Code
+
+is available under the terms of this License, including a description of
+
+how and where You have fulfilled the obligations of Section <b>3.2</b>.
+
+The notice must be conspicuously included in any notice in an Executable
+
+version, related documentation or collateral in which You describe recipients'
+
+rights relating to the Covered Code. You may distribute the Executable
+
+version of Covered Code or ownership rights under a license of Your choice,
+
+which may contain terms different from this License, provided that You
+
+are in compliance with the terms of this License and that the license for
+
+the Executable version does not attempt to limit or alter the recipient's
+
+rights in the Source Code version from the rights set forth in this License.
+
+If You distribute the Executable version under a different license You
+
+must make it absolutely clear that any terms which differ from this License
+
+are offered by You alone, not by the Initial Developer or any Contributor.
+
+You hereby agree to indemnify the Initial Developer and every Contributor
+
+for any liability incurred by the Initial Developer or such Contributor
+
+as a result of any such terms You offer.
+
+<a name="3.7"></a>
+</p><p><b>3.7. Larger Works.</b>
+
+<br>You may create a Larger Work by combining Covered Code with other code
+
+not governed by the terms of this License and distribute the Larger Work
+
+as a single product. In such a case, You must make sure the requirements
+
+of this License are fulfilled for the Covered Code.</p></ul>
+
+<a name="4"></a>
+<b>4. Inability to Comply Due to Statute or Regulation.</b>
+
+<ul>If it is impossible for You to comply with any of the terms of this
+
+License with respect to some or all of the Covered Code due to statute,
+
+judicial order, or regulation then You must: (a) comply with the terms
+
+of this License to the maximum extent possible; and (b) describe the limitations
+
+and the code they affect. Such description must be included in the LEGAL
+
+file described in Section <b>3.4</b> and must be included with all distributions
+
+of the Source Code. Except to the extent prohibited by statute or regulation,
+
+such description must be sufficiently detailed for a recipient of ordinary
+
+skill to be able to understand it.</ul>
+
+<a name="5"></a>
+<b>5. Application of this License.</b>
+
+<ul>This License applies to code to which the Initial Developer has attached
+
+the notice in <b>Exhibit A</b> and to related Covered Code.</ul>
+
+<a name="6"></a>
+<b>6. Versions of the License.</b>
+
+<a name="6.1"></a>
+<ul><b>6.1. New Versions</b>.
+
+<br>Netscape Communications Corporation (''Netscape'') may publish revised
+
+and/or new versions of the License from time to time. Each version will
+
+be given a distinguishing version number.
+
+<a name="6.2"></a>
+<p><b>6.2. Effect of New Versions</b>.
+
+<br>Once Covered Code has been published under a particular version of
+
+the License, You may always continue to use it under the terms of that
+
+version. You may also choose to use such Covered Code under the terms of
+
+any subsequent version of the License published by Netscape. No one other
+
+than Netscape has the right to modify the terms applicable to Covered Code
+
+created under this License.
+
+<a name="6.3"></a>
+</p><p><b>6.3. Derivative Works</b>.
+
+<br>If You create or use a modified version of this License (which you
+
+may only do in order to apply it to code which is not already Covered Code
+
+governed by this License), You must (a) rename Your license so that the
+
+phrases ''Mozilla'', ''MOZILLAPL'', ''MOZPL'', ''Netscape'', "MPL", ''NPL''
+
+or any confusingly similar phrase do not appear in your license (except
+
+to note that your license differs from this License) and (b) otherwise
+
+make it clear that Your version of the license contains terms which differ
+
+from the Mozilla Public License and Netscape Public License. (Filling in
+
+the name of the Initial Developer, Original Code or Contributor in the
+
+notice described in <b>Exhibit A</b> shall not of themselves be deemed
+
+to be modifications of this License.)</p></ul>
+
+<a name="7"></a>
+<b>7. DISCLAIMER OF WARRANTY.</b>
+
+<ul>COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS'' BASIS, WITHOUT
+
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
+
+WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT
+
+FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY
+
+AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE
+
+PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER
+
+CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
+
+NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.</ul>
+
+<a name="8"></a>
+<b>8. TERMINATION.</b>
+
+<a name="8.1"></a>
+<ul><b>8.1. </b>This License and the rights granted hereunder will
+
+terminate automatically if You fail to comply with terms herein and fail
+
+to cure such breach within 30 days of becoming aware of the breach. All
+
+sublicenses to the Covered Code which are properly granted shall survive
+
+any termination of this License. Provisions which, by their nature, must
+
+remain in effect beyond the termination of this License shall survive.
+
+<a name="8.2"></a>
+<p><b>8.2. </b>If You initiate litigation by asserting a patent infringement
+
+claim (excluding declatory judgment actions) against Initial Developer
+
+or a Contributor (the Initial Developer or Contributor against whom You
+
+file such action is referred to as "Participant") alleging that:
+
+</p><p><b>(a) </b>such Participant's Contributor Version directly or
+
+indirectly infringes any patent, then any and all rights granted by such
+
+Participant to You under Sections 2.1 and/or 2.2 of this License shall,
+
+upon 60 days notice from Participant terminate prospectively, unless if
+
+within 60 days after receipt of notice You either: (i) agree in writing
+
+to pay Participant a mutually agreeable reasonable royalty for Your past
+
+and future use of Modifications made by such Participant, or (ii) withdraw
+
+Your litigation claim with respect to the Contributor Version against such
+
+Participant. If within 60 days of notice, a reasonable royalty and
+
+payment arrangement are not mutually agreed upon in writing by the parties
+
+or the litigation claim is not withdrawn, the rights granted by Participant
+
+to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration
+
+of the 60 day notice period specified above.
+
+</p><p><b>(b)</b> any software, hardware, or device, other than such
+
+Participant's Contributor Version, directly or indirectly infringes any
+
+patent, then any rights granted to You by such Participant under Sections
+
+2.1(b) and 2.2(b) are revoked effective as of the date You first made,
+
+used, sold, distributed, or had made, Modifications made by that Participant.
+
+<a name="8.3"></a>
+</p><p><b>8.3. </b>If You assert a patent infringement claim against
+
+Participant alleging that such Participant's Contributor Version directly
+
+or indirectly infringes any patent where such claim is resolved (such as
+
+by license or settlement) prior to the initiation of patent infringement
+
+litigation, then the reasonable value of the licenses granted by such Participant
+
+under Sections 2.1 or 2.2 shall be taken into account in determining the
+
+amount or value of any payment or license.
+
+<a name="8.4"></a>
+</p><p><b>8.4.</b> In the event of termination under Sections 8.1 or
+
+8.2 above, all end user license agreements (excluding distributors
+
+and resellers) which have been validly granted by You or any distributor
+
+hereunder prior to termination shall survive termination.</p></ul>
+
+<a name="9"></a>
+<b>9. LIMITATION OF LIABILITY.</b>
+
+<ul>UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING
+
+NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER,
+
+ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER
+
+OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL,
+
+INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+
+LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE
+
+OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN
+
+IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR
+
+PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE
+
+LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION
+
+OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION
+
+AND LIMITATION MAY NOT APPLY TO YOU.</ul>
+
+<a name="10"></a>
+<b>10. U.S. GOVERNMENT END USERS.</b>
+
+<ul>The Covered Code is a ''commercial item,'' as that term is defined
+
+in 48 C.F.R. 2.101 (Oct. 1995), consisting of ''commercial computer software''
+
+and ''commercial computer software documentation,'' as such terms are used
+
+in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and
+
+48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government
+
+End Users acquire Covered Code with only those rights set forth herein.</ul>
+
+<a name="11"></a>
+<b>11. MISCELLANEOUS.</b>
+
+<ul>This License represents the complete agreement concerning subject matter
+
+hereof. If any provision of this License is held to be unenforceable, such
+
+provision shall be reformed only to the extent necessary to make it enforceable.
+
+This License shall be governed by California law provisions (except to
+
+the extent applicable law, if any, provides otherwise), excluding its conflict-of-law
+
+provisions. With respect to disputes in which at least one party is a citizen
+
+of, or an entity chartered or registered to do business in the United States
+
+of America, any litigation relating to this License shall be subject to
+
+the jurisdiction of the Federal Courts of the Northern District of California,
+
+with venue lying in Santa Clara County, California, with the losing party
+
+responsible for costs, including without limitation, court costs and reasonable
+
+attorneys' fees and expenses. The application of the United Nations Convention
+
+on Contracts for the International Sale of Goods is expressly excluded.
+
+Any law or regulation which provides that the language of a contract shall
+
+be construed against the drafter shall not apply to this License.</ul>
+
+<a name="12"></a>
+<b>12. RESPONSIBILITY FOR CLAIMS.</b>
+
+<ul>As between Initial Developer and the Contributors, each party is responsible
+
+for claims and damages arising, directly or indirectly, out of its utilization
+
+of rights under this License and You agree to work with Initial Developer
+
+and Contributors to distribute such responsibility on an equitable basis.
+
+Nothing herein is intended or shall be deemed to constitute any admission
+
+of liability.</ul>
+
+<a name="13"></a>
+<b>13. MULTIPLE-LICENSED CODE.</b>
+
+<ul>Initial Developer may designate portions of the Covered Code as “Multiple-Licensed”.
+
+“Multiple-Licensed” means that the Initial Developer permits you to utilize
+
+portions of the Covered Code under Your choice of the MPL or the alternative
+
+licenses, if any, specified by the Initial Developer in the file described
+
+in Exhibit A.</ul>
+
+
+
+<a name="EXHIBIT-A"></a>
+<p><br><b>EXHIBIT A -Mozilla Public License.</b>
+
+</p><ul>``The contents of this file are subject to the Mozilla Public License
+
+Version 1.1 (the "License"); you may not use this file except in compliance
+
+with the License. You may obtain a copy of the License at
+
+<br>http://www.mozilla.org/MPL/
+
+<p>Software distributed under the License is distributed on an "AS IS"
+
+basis, WITHOUT WARRANTY OF
+
+<br>ANY KIND, either express or implied. See the License for the specific
+
+language governing rights and
+
+<br>limitations under the License.
+
+</p><p>The Original Code is ______________________________________.
+
+</p><p>The Initial Developer of the Original Code is ________________________.
+
+Portions created by
+
+<br> ______________________ are Copyright (C) ______ _______________________.
+
+All Rights
+
+<br>Reserved.
+
+</p><p>Contributor(s): ______________________________________.
+
+</p><p>Alternatively, the contents of this file may be used under the terms
+
+of the _____ license (the “[___] License”), in which case the provisions
+
+of [______] License are applicable instead of those above.
+
+If you wish to allow use of your version of this file only under the terms
+
+of the [____] License and not to allow others to use your version of this
+
+file under the MPL, indicate your decision by deleting the provisions
+
+above and replace them with the notice and other provisions required
+
+by the [___] License. If you do not delete the provisions above,
+
+a recipient may use your version of this file under either the MPL or the
+
+[___] License."
+
+</p><p>[NOTE: The text of this Exhibit A may differ slightly from the text
+
+of the notices in the Source Code files of the Original Code. You should
+
+use the text of this Exhibit A rather than the text found in the Original
+
+Code Source Code for Your Modifications.]
+
+</p><p>
+
+</p></ul></body></html>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/License.txt
===================================================================
--- trunk/WPGM/Components/Graphics32/License.txt 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/License.txt 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,470 @@
+ MOZILLA PUBLIC LICENSE
+ Version 1.1
+
+ ---------------
+
+1. Definitions.
+
+ 1.0.1. "Commercial Use" means distribution or otherwise making the
+ Covered Code available to a third party.
+
+ 1.1. "Contributor" means each entity that creates or contributes to
+ the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Code, prior Modifications used by a Contributor, and the Modifications
+ made by that particular Contributor.
+
+ 1.3. "Covered Code" means the Original Code or Modifications or the
+ combination of the Original Code and Modifications, in each case
+ including portions thereof.
+
+ 1.4. "Electronic Distribution Mechanism" means a mechanism generally
+ accepted in the software development community for the electronic
+ transfer of data.
+
+ 1.5. "Executable" means Covered Code in any form other than Source
+ Code.
+
+ 1.6. "Initial Developer" means the individual or entity identified
+ as the Initial Developer in the Source Code notice required by Exhibit
+ A.
+
+ 1.7. "Larger Work" means a work which combines Covered Code or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.8. "License" means this document.
+
+ 1.8.1. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means any addition to or deletion from the
+ substance or structure of either the Original Code or any previous
+ Modifications. When Covered Code is released as a series of files, a
+ Modification is:
+ A. Any addition to or deletion from the contents of a file
+ containing Original Code or previous Modifications.
+
+ B. Any new file that contains any part of the Original Code or
+ previous Modifications.
+
+ 1.10. "Original Code" means Source Code of computer software code
+ which is described in the Source Code notice required by Exhibit A as
+ Original Code, and which, at the time of its release under this
+ License is not already Covered Code governed by this License.
+
+ 1.10.1. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.11. "Source Code" means the preferred form of the Covered Code for
+ making modifications to it, including all modules it contains, plus
+ any associated interface definition files, scripts used to control
+ compilation and installation of an Executable, or source code
+ differential comparisons against either the Original Code or another
+ well known, available Covered Code of the Contributor's choice. The
+ Source Code can be in a compressed or archival form, provided the
+ appropriate decompression or de-archiving software is widely available
+ for no charge.
+
+ 1.12. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of, this
+ License or a future version of this License issued under Section 6.1.
+ For legal entities, "You" includes any entity which controls, is
+ controlled by, or is under common control with You. For purposes of
+ this definition, "control" means (a) the power, direct or indirect,
+ to cause the direction or management of such entity, whether by
+ contract or otherwise, or (b) ownership of more than fifty percent
+ (50%) of the outstanding shares or beneficial ownership of such
+ entity.
+
+2. Source Code License.
+
+ 2.1. The Initial Developer Grant.
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property
+ claims:
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Code (or portions thereof) with or without Modifications, and/or
+ as part of a Larger Work; and
+
+ (b) under Patents Claims infringed by the making, using or
+ selling of Original Code, to make, have made, use, practice,
+ sell, and offer for sale, and/or otherwise dispose of the
+ Original Code (or portions thereof).
+
+ (c) the licenses granted in this Section 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ Original Code under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: 1) for code that You delete from the Original Code; 2)
+ separate from the Original Code; or 3) for infringements caused
+ by: i) the modification of the Original Code or ii) the
+ combination of the Original Code with other software or devices.
+
+ 2.2. Contributor Grant.
+ Subject to third party intellectual property claims, each Contributor
+ hereby grants You a world-wide, royalty-free, non-exclusive license
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor, to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof) either on an
+ unmodified basis, with other Modifications, as Covered Code
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either alone
+ and/or in combination with its Contributor Version (or portions
+ of such combination), to make, use, sell, offer for sale, have
+ made, and/or otherwise dispose of: 1) Modifications made by that
+ Contributor (or portions thereof); and 2) the combination of
+ Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+
+ (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first makes Commercial Use of
+ the Covered Code.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: 1) for any code that Contributor has deleted from the
+ Contributor Version; 2) separate from the Contributor Version;
+ 3) for infringements caused by: i) third party modifications of
+ Contributor Version or ii) the combination of Modifications made
+ by that Contributor with other software (except as part of the
+ Contributor Version) or other devices; or 4) under Patent Claims
+ infringed by Covered Code in the absence of Modifications made by
+ that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Application of License.
+ The Modifications which You create or to which You contribute are
+ governed by the terms of this License, including without limitation
+ Section 2.2. The Source Code version of Covered Code may be
+ distributed only under the terms of this License or a future version
+ of this License released under Section 6.1, and You must include a
+ copy of this License with every copy of the Source Code You
+ distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this
+ License or the recipients' rights hereunder. However, You may include
+ an additional document offering the additional rights described in
+ Section 3.5.
+
+ 3.2. Availability of Source Code.
+ Any Modification which You create or to which You contribute must be
+ made available in Source Code form under the terms of this License
+ either on the same media as an Executable version or via an accepted
+ Electronic Distribution Mechanism to anyone to whom you made an
+ Executable version available; and if made available via Electronic
+ Distribution Mechanism, must remain available for at least twelve (12)
+ months after the date it initially became available, or at least six
+ (6) months after a subsequent version of that particular Modification
+ has been made available to such recipients. You are responsible for
+ ensuring that the Source Code version remains available even if the
+ Electronic Distribution Mechanism is maintained by a third party.
+
+ 3.3. Description of Modifications.
+ You must cause all Covered Code to which You contribute to contain a
+ file documenting the changes You made to create that Covered Code and
+ the date of any change. You must include a prominent statement that
+ the Modification is derived, directly or indirectly, from Original
+ Code provided by the Initial Developer and including the name of the
+ Initial Developer in (a) the Source Code, and (b) in any notice in an
+ Executable version or related documentation in which You describe the
+ origin or ownership of the Covered Code.
+
+ 3.4. Intellectual Property Matters
+ (a) Third Party Claims.
+ If Contributor has knowledge that a license under a third party's
+ intellectual property rights is required to exercise the rights
+ granted by such Contributor under Sections 2.1 or 2.2,
+ Contributor must include a text file with the Source Code
+ distribution titled "LEGAL" which describes the claim and the
+ party making the claim in sufficient detail that a recipient will
+ know whom to contact. If Contributor obtains such knowledge after
+ the Modification is made available as described in Section 3.2,
+ Contributor shall promptly modify the LEGAL file in all copies
+ Contributor makes available thereafter and shall take other steps
+ (such as notifying appropriate mailing lists or newsgroups)
+ reasonably calculated to inform those who received the Covered
+ Code that new knowledge has been obtained.
+
+ (b) Contributor APIs.
+ If Contributor's Modifications include an application programming
+ interface and Contributor has knowledge of patent licenses which
+ are reasonably necessary to implement that API, Contributor must
+ also include this information in the LEGAL file.
+
+ (c) Representations.
+ Contributor represents that, except as disclosed pursuant to
+ Section 3.4(a) above, Contributor believes that Contributor's
+ Modifications are Contributor's original creation(s) and/or
+ Contributor has sufficient rights to grant the rights conveyed by
+ this License.
+
+ 3.5. Required Notices.
+ You must duplicate the notice in Exhibit A in each file of the Source
+ Code. If it is not possible to put such notice in a particular Source
+ Code file due to its structure, then You must include such notice in a
+ location (such as a relevant directory) where a user would be likely
+ to look for such a notice. If You created one or more Modification(s)
+ You may add your name as a Contributor to the notice described in
+ Exhibit A. You must also duplicate this License in any documentation
+ for the Source Code where You describe recipients' rights or ownership
+ rights relating to Covered Code. You may choose to offer, and to
+ charge a fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Code. However, You
+ may do so only on Your own behalf, and not on behalf of the Initial
+ Developer or any Contributor. You must make it absolutely clear than
+ any such warranty, support, indemnity or liability obligation is
+ offered by You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty,
+ support, indemnity or liability terms You offer.
+
+ 3.6. Distribution of Executable Versions.
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered Code,
+ and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License,
+ including a description of how and where You have fulfilled the
+ obligations of Section 3.2. The notice must be conspicuously included
+ in any notice in an Executable version, related documentation or
+ collateral in which You describe recipients' rights relating to the
+ Covered Code. You may distribute the Executable version of Covered
+ Code or ownership rights under a license of Your choice, which may
+ contain terms different from this License, provided that You are in
+ compliance with the terms of this License and that the license for the
+ Executable version does not attempt to limit or alter the recipient's
+ rights in the Source Code version from the rights set forth in this
+ License. If You distribute the Executable version under a different
+ license You must make it absolutely clear that any terms which differ
+ from this License are offered by You alone, not by the Initial
+ Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by
+ the Initial Developer or such Contributor as a result of any such
+ terms You offer.
+
+ 3.7. Larger Works.
+ You may create a Larger Work by combining Covered Code with other code
+ not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to
+ statute, judicial order, or regulation then You must: (a) comply with
+ the terms of this License to the maximum extent possible; and (b)
+ describe the limitations and the code they affect. Such description
+ must be included in the LEGAL file described in Section 3.4 and must
+ be included with all distributions of the Source Code. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Application of this License.
+
+ This License applies to code to which the Initial Developer has
+ attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+ 6.1. New Versions.
+ Netscape Communications Corporation ("Netscape") may publish revised
+ and/or new versions of the License from time to time. Each version
+ will be given a distinguishing version number.
+
+ 6.2. Effect of New Versions.
+ Once Covered Code has been published under a particular version of the
+ License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms
+ of any subsequent version of the License published by Netscape. No one
+ other than Netscape has the right to modify the terms applicable to
+ Covered Code created under this License.
+
+ 6.3. Derivative Works.
+ If You create or use a modified version of this License (which you may
+ only do in order to apply it to code which is not already Covered Code
+ governed by this License), You must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+ "MPL", "NPL" or any confusingly similar phrase do not appear in your
+ license (except to note that your license differs from this License)
+ and (b) otherwise make it clear that Your version of the license
+ contains terms which differ from the Mozilla Public License and
+ Netscape Public License. (Filling in the name of the Initial
+ Developer, Original Code or Contributor in the notice described in
+ Exhibit A shall not of themselves be deemed to be modifications of
+ this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+ DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+ IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+ YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+ COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+ OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+ 8.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall
+ survive any termination of this License. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License
+ shall survive.
+
+ 8.2. If You initiate litigation by asserting a patent infringement
+ claim (excluding declatory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom
+ You file such action is referred to as "Participant") alleging that:
+
+ (a) such Participant's Contributor Version directly or indirectly
+ infringes any patent, then any and all rights granted by such
+ Participant to You under Sections 2.1 and/or 2.2 of this License
+ shall, upon 60 days notice from Participant terminate prospectively,
+ unless if within 60 days after receipt of notice You either: (i)
+ agree in writing to pay Participant a mutually agreeable reasonable
+ royalty for Your past and future use of Modifications made by such
+ Participant, or (ii) withdraw Your litigation claim with respect to
+ the Contributor Version against such Participant. If within 60 days
+ of notice, a reasonable royalty and payment arrangement are not
+ mutually agreed upon in writing by the parties or the litigation claim
+ is not withdrawn, the rights granted by Participant to You under
+ Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+ the 60 day notice period specified above.
+
+ (b) any software, hardware, or device, other than such Participant's
+ Contributor Version, directly or indirectly infringes any patent, then
+ any rights granted to You by such Participant under Sections 2.1(b)
+ and 2.2(b) are revoked effective as of the date You first made, used,
+ sold, distributed, or had made, Modifications made by that
+ Participant.
+
+ 8.3. If You assert a patent infringement claim against Participant
+ alleging that such Participant's Contributor Version directly or
+ indirectly infringes any patent where such claim is resolved (such as
+ by license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 8.4. In the event of termination under Sections 8.1 or 8.2 above,
+ all end user license agreements (excluding distributors and resellers)
+ which have been validly granted by You or any distributor hereunder
+ prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+ DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+ OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+ CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+ WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+ The Covered Code is a "commercial item," as that term is defined in
+ 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" and "commercial computer software documentation," as such
+ terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+ C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+ all U.S. Government End Users acquire Covered Code with only those
+ rights set forth herein.
+
+11. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ With respect to disputes in which at least one party is a citizen of,
+ or an entity chartered or registered to do business in the United
+ States of America, any litigation relating to this License shall be
+ subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys' fees and
+ expenses. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly excluded.
+ Any law or regulation which provides that the language of a contract
+ shall be construed against the drafter shall not apply to this
+ License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+ Initial Developer may designate portions of the Covered Code as
+ "Multiple-Licensed". "Multiple-Licensed" means that the Initial
+ Developer permits you to utilize portions of the Covered Code under
+ Your choice of the NPL or the alternative licenses, if any, specified
+ by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+ ``The contents of this file are subject to the Mozilla Public License
+ Version 1.1 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ License for the specific language governing rights and limitations
+ under the License.
+
+ The Original Code is ______________________________________.
+
+ The Initial Developer of the Original Code is ________________________.
+ Portions created by ______________________ are Copyright (C) ______
+ _______________________. All Rights Reserved.
+
+ Contributor(s): ______________________________________.
+
+ Alternatively, the contents of this file may be used under the terms
+ of the _____ license (the "[___] License"), in which case the
+ provisions of [______] License are applicable instead of those
+ above. If you wish to allow use of your version of this file only
+ under the terms of the [____] License and not to allow others to use
+ your version of this file under the MPL, indicate your decision by
+ deleting the provisions above and replace them with the notice and
+ other provisions required by the [___] License. If you do not delete
+ the provisions above, a recipient may use your version of this file
+ under either the MPL or the [___] License."
+
+ [NOTE: The text of this Exhibit A may differ slightly from the text of
+ the notices in the Source Code files of the Original Code. You should
+ use the text of this Exhibit A rather than the text found in the
+ Original Code Source Code for Your Modifications.]
+
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.bpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.bpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.bpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,49 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="GR32_CB5.bpl"/>
+ <OBJFILES value="..\GR32.obj ..\GR32_Blend.obj ..\GR32_ByteMaps.obj ..\GR32_System.obj
+ ..\GR32_DrawingEx.obj ..\GR32_Filters.obj ..\GR32_Image.obj ..\GR32_Layers.obj
+ ..\GR32_LowLevel.obj ..\GR32_Polygons.obj ..\GR32_RangeBars.obj
+ ..\GR32_Transforms.obj GR32_CB5.obj"/>
+ <RESFILES value="GR32_CB5.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES)"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="Vcl50.lib"/>
+ <PACKAGES value="vcl50.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;.."/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="GR32_CB5.cpp"/>
+ <INCLUDEPATH value="..\;..;$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="..\;$(BCB)\Projects\Lib;..;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I..\. -I.. -I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -D_DEBUG
+ -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"Graphics32" -aa -Tpp -x -Gn -Gl -Gi -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0pkg32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,62 @@
+//---------------------------------------------------------------------------
+
+
+
+#include <vcl.h>
+
+#pragma hdrstop
+
+USERES("GR32_CB5.res");
+
+USEPACKAGE("vcl50.bpi");
+
+USEUNIT("..\GR32.pas");
+
+USEUNIT("..\GR32_Blend.pas");
+
+USEUNIT("..\GR32_ByteMaps.pas");
+
+USEUNIT("..\GR32_System.pas");
+
+USEUNIT("..\GR32_DrawingEx.pas");
+
+USEUNIT("..\GR32_Filters.pas");
+
+USEUNIT("..\GR32_Image.pas");
+
+USEUNIT("..\GR32_Layers.pas");
+
+USEUNIT("..\GR32_LowLevel.pas");
+
+USEUNIT("..\GR32_Polygons.pas");
+
+USEUNIT("..\GR32_RangeBars.pas");
+
+USEUNIT("..\GR32_Transforms.pas");
+
+//---------------------------------------------------------------------------
+
+#pragma package(smart_init)
+
+//---------------------------------------------------------------------------
+
+
+
+// Package source.
+
+//---------------------------------------------------------------------------
+
+
+
+#pragma argsused
+
+int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
+
+{
+
+ return 1;
+
+}
+
+//---------------------------------------------------------------------------
+
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_CB5.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.bpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.bpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.bpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,75 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.06.00"/>
+ <PROJECT value="GR32_CB6.bpl"/>
+ <OBJFILES value="GR32_CB6.obj ..\GR32.obj ..\GR32_Blend.obj ..\GR32_ByteMaps.obj
+ ..\GR32_System.obj ..\GR32_DrawingEx.obj ..\GR32_Filters.obj
+ ..\GR32_Image.obj ..\GR32_Layers.obj ..\GR32_LowLevel.obj
+ ..\GR32_Polygons.obj ..\GR32_RangeBars.obj ..\GR32_Transforms.obj"/>
+ <RESFILES value="GR32_CB6.res"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES)"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="rtl.lib vcl.lib"/>
+ <PACKAGES value="rtl.bpi vcl.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;..;..;..;..;..;..;..;..;..;..;..;.."/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="ilink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="GR32_CB6.cpp"/>
+ <INCLUDEPATH value="..\;..;$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="..\;$(BCB)\Projects\Lib;..;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ <OTHERFILES value=""/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-src_suffix cpp -D_DEBUG -I..\. -I.. -I$(BCB)\include -I$(BCB)\include\vcl
+ -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl60.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y
+ -v -vi- -c -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -$A8 -v -JPHNE -M"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"Graphics32" -aa -Tpp -x -Gn -Gl -Gi -v"/>
+ <OTHERFILES value=""/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0pkg32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ <OTHERFILES value=""/>
+ </LINKER>
+ <FILELIST>
+ <FILE FILENAME="GR32_CB6.cpp" FORMNAME="" UNITNAME="GR32_CB6" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="GR32_CB6.res" FORMNAME="" UNITNAME="GR32_CB6.res" CONTAINERID="ResTool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32.pas" FORMNAME="" UNITNAME="GR32" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Blend.pas" FORMNAME="" UNITNAME="GR32_Blend" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_ByteMaps.pas" FORMNAME="" UNITNAME="GR32_ByteMaps" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_System.pas" FORMNAME="" UNITNAME="GR32_System" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_DrawingEx.pas" FORMNAME="" UNITNAME="GR32_DrawingEx" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Filters.pas" FORMNAME="" UNITNAME="GR32_Filters" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Image.pas" FORMNAME="" UNITNAME="GR32_Image" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Layers.pas" FORMNAME="" UNITNAME="GR32_Layers" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_LowLevel.pas" FORMNAME="" UNITNAME="GR32_LowLevel" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Polygons.pas" FORMNAME="" UNITNAME="GR32_Polygons" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_RangeBars.pas" FORMNAME="" UNITNAME="GR32_RangeBars" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Transforms.pas" FORMNAME="" UNITNAME="GR32_Transforms" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="rtl.bpi" FORMNAME="" UNITNAME="rtl" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="vcl.bpi" FORMNAME="" UNITNAME="vcl" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ </FILELIST>
+ <BUILDTOOLS>
+ </BUILDTOOLS>
+
+ <IDEOPTIONS>
+ </IDEOPTIONS>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,32 @@
+//---------------------------------------------------------------------------
+
+
+
+#include <vcl.h>
+
+#pragma hdrstop
+
+#pragma package(smart_init)
+
+//---------------------------------------------------------------------------
+
+
+
+// Package source.
+
+//---------------------------------------------------------------------------
+
+
+
+#pragma argsused
+
+int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
+
+{
+
+ return 1;
+
+}
+
+//---------------------------------------------------------------------------
+
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_CB6.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D4.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_D4.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_D4.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+package GR32_D4;
+
+{$R *.RES}
+{$ALIGN ON}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST ON}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32'}
+{$IMPLICITBUILD ON}
+
+requires
+ Vcl40;
+
+contains
+ GR32 in '..\GR32.pas',
+ GR32_Transforms in '..\GR32_Transforms.pas',
+ GR32_Blend in '..\GR32_Blend.pas',
+ GR32_ByteMaps in '..\GR32_ByteMaps.pas',
+ GR32_DrawingEx in '..\GR32_DrawingEx.pas',
+ GR32_Filters in '..\GR32_Filters.pas',
+ GR32_Image in '..\GR32_Image.pas',
+ GR32_Layers in '..\GR32_Layers.pas',
+ GR32_LowLevel in '..\GR32_LowLevel.pas',
+ GR32_Polygons in '..\GR32_Polygons.pas',
+ GR32_RangeBars in '..\GR32_RangeBars.pas',
+ GR32_System in '..\GR32_System.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D4.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_D4.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D5.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_D5.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_D5.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+package GR32_D5;
+
+{$R *.RES}
+{$ALIGN ON}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST ON}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32'}
+{$IMPLICITBUILD ON}
+
+requires
+ Vcl50;
+
+contains
+ GR32 in '..\GR32.pas',
+ GR32_Transforms in '..\GR32_Transforms.pas',
+ GR32_Blend in '..\GR32_Blend.pas',
+ GR32_ByteMaps in '..\GR32_ByteMaps.pas',
+ GR32_DrawingEx in '..\GR32_DrawingEx.pas',
+ GR32_Filters in '..\GR32_Filters.pas',
+ GR32_Image in '..\GR32_Image.pas',
+ GR32_Layers in '..\GR32_Layers.pas',
+ GR32_LowLevel in '..\GR32_LowLevel.pas',
+ GR32_Polygons in '..\GR32_Polygons.pas',
+ GR32_RangeBars in '..\GR32_RangeBars.pas',
+ GR32_System in '..\GR32_System.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D5.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_D5.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D6.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_D6.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_D6.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+package GR32_D6;
+
+{$R *.res}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST ON}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32'}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl;
+
+contains
+ GR32 in '..\GR32.pas',
+ GR32_Transforms in '..\GR32_Transforms.pas',
+ GR32_Blend in '..\GR32_Blend.pas',
+ GR32_ByteMaps in '..\GR32_ByteMaps.pas',
+ GR32_DrawingEx in '..\GR32_DrawingEx.pas',
+ GR32_Filters in '..\GR32_Filters.pas',
+ GR32_Image in '..\GR32_Image.pas',
+ GR32_Layers in '..\GR32_Layers.pas',
+ GR32_LowLevel in '..\GR32_LowLevel.pas',
+ GR32_Polygons in '..\GR32_Polygons.pas',
+ GR32_RangeBars in '..\GR32_RangeBars.pas',
+ GR32_System in '..\GR32_System.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D6.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_D6.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D6_CLX.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_D6_CLX.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_D6_CLX.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,44 @@
+package GR32_D6_CLX;
+
+{$R *.res}
{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST ON}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 CLX'}
+{$IMPLICITBUILD ON}
+{$DEFINE CLX}
+
+requires
rtl,
+ visualclx;
+
+contains
GR32 in '..\GR32.pas',
+ GR32_Transforms in '..\GR32_Transforms.pas',
+ GR32_Blend in '..\GR32_Blend.pas',
+ GR32_ByteMaps in '..\GR32_ByteMaps.pas',
+ GR32_DrawingEx in '..\GR32_DrawingEx.pas',
+ GR32_Filters in '..\GR32_Filters.pas',
+ GR32_Image in '..\GR32_Image.pas',
+ GR32_Layers in '..\GR32_Layers.pas',
+ GR32_LowLevel in '..\GR32_LowLevel.pas',
+ GR32_Polygons in '..\GR32_Polygons.pas',
+ GR32_RangeBars in '..\GR32_RangeBars.pas',
+ GR32_System in '..\GR32_System.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D6_CLX.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_D6_CLX.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D7.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_D7.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D7.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_D7.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_D7.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,45 @@
+package GR32_D7;
+
+{$R *.res}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST ON}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32'}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl;
+
+contains
+ GR32 in '..\GR32.pas',
+ GR32_Transforms in '..\GR32_Transforms.pas',
+ GR32_Blend in '..\GR32_Blend.pas',
+ GR32_ByteMaps in '..\GR32_ByteMaps.pas',
+ GR32_DrawingEx in '..\GR32_DrawingEx.pas',
+ GR32_Filters in '..\GR32_Filters.pas',
+ GR32_Image in '..\GR32_Image.pas',
+ GR32_Layers in '..\GR32_Layers.pas',
+ GR32_LowLevel in '..\GR32_LowLevel.pas',
+ GR32_Polygons in '..\GR32_Polygons.pas',
+ GR32_RangeBars in '..\GR32_RangeBars.pas',
+ GR32_System in '..\GR32_System.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D7.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_D7.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D7_CLX.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_D7_CLX.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_D7_CLX.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,44 @@
+package GR32_D7_CLX;
+
+{$R *.res}
{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST ON}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 CLX'}
+{$IMPLICITBUILD ON}
+{$DEFINE CLX}
+
+requires
rtl,
+ visualclx;
+
+contains
GR32 in '..\GR32.pas',
+ GR32_Transforms in '..\GR32_Transforms.pas',
+ GR32_Blend in '..\GR32_Blend.pas',
+ GR32_ByteMaps in '..\GR32_ByteMaps.pas',
+ GR32_DrawingEx in '..\GR32_DrawingEx.pas',
+ GR32_Filters in '..\GR32_Filters.pas',
+ GR32_Image in '..\GR32_Image.pas',
+ GR32_Layers in '..\GR32_Layers.pas',
+ GR32_LowLevel in '..\GR32_LowLevel.pas',
+ GR32_Polygons in '..\GR32_Polygons.pas',
+ GR32_RangeBars in '..\GR32_RangeBars.pas',
+ GR32_System in '..\GR32_System.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_D7_CLX.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_D7_CLX.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.bpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.bpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.bpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,46 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.05.03"/>
+ <PROJECT value="GR32_DSGN_CB5.bpl"/>
+ <OBJFILES value="..\GR32_Reg.obj ..\GR32_Dsgn_Color.obj ..\GR32_Dsgn_Bitmap.obj
+ GR32_DSGN_CB5.obj"/>
+ <RESFILES value="..\GR32_Reg.dcr"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) ..\GR32_Dsgn_Bitmap.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="vcl50.lib dclstd50.lib GR32_CB5.lib"/>
+ <PACKAGES value="vcl50.bpi dclstd50.bpi GR32_CB5.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;.."/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="tlink32"/>
+ <USERDEFINES value=""/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="GR32_DSGN_CB5.cpp"/>
+ <INCLUDEPATH value="..\;..;$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="..\;$(BCB)\Projects\Lib;..;$(BCB)\Source\ToolsAPI;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par"/>
+ </MACROS>
+ <OPTIONS>
+ <IDLCFLAGS value="-I..\. -I.. -I$(BCB)\include -I$(BCB)\include\vcl -src_suffix cpp -boa"/>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl50.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -v -JPHNE -M -LUdclstd50"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"Graphics32 Design Time Package" -aa -Tpp -Gpd -x -Gn -Gl -Gi -v"/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0pkg32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ </LINKER>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,40 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+
+#pragma hdrstop
+
+USEPACKAGE("vcl50.bpi");
+
+USEUNIT("..\GR32_Reg.pas");
+
+USERES("..\GR32_Reg.dcr");
+
+USEPACKAGE("dclstd50.bpi");
+
+USEPACKAGE("GR32_CB5.bpi");
+
+USEUNIT("..\GR32_Dsgn_Color.pas");
+
+USEFORMNS("..\GR32_Dsgn_Bitmap.pas", GR32_dsgn_bitmap, PictureEditorForm);
+
+//---------------------------------------------------------------------------
+
+#pragma package(smart_init)
+
+//---------------------------------------------------------------------------
+
+// Package source.
+
+//---------------------------------------------------------------------------
+
+int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
+
+{
+
+ return 1;
+
+}
+
+//---------------------------------------------------------------------------
+
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB5.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.bpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.bpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.bpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,65 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!-- C++Builder XML Project -->
+<PROJECT>
+ <MACROS>
+ <VERSION value="BCB.06.00"/>
+ <PROJECT value="GR32_DSGN_CB6.bpl"/>
+ <OBJFILES value="GR32_DSGN_CB6.obj ..\GR32_Reg.obj ..\GR32_Dsgn_Bitmap.obj
+ ..\GR32_Dsgn_Color.obj"/>
+ <RESFILES value="..\GR32_Reg.dcr"/>
+ <IDLFILES value=""/>
+ <IDLGENFILES value=""/>
+ <DEFFILE value=""/>
+ <RESDEPEN value="$(RESFILES) ..\GR32_Dsgn_Bitmap.dfm"/>
+ <LIBFILES value=""/>
+ <LIBRARIES value=""/>
+ <SPARELIBS value="rtl.lib vcl.lib dclstd.lib"/>
+ <PACKAGES value="rtl.bpi designide.bpi vcl.bpi GR32_CB6.bpi dclstd.bpi"/>
+ <PATHCPP value=".;"/>
+ <PATHPAS value=".;..;..;.."/>
+ <PATHRC value=".;"/>
+ <PATHASM value=".;"/>
+ <DEBUGLIBPATH value="$(BCB)\lib\debug"/>
+ <RELEASELIBPATH value="$(BCB)\lib\release"/>
+ <LINKER value="ilink32"/>
+ <USERDEFINES value="_DEBUG"/>
+ <SYSDEFINES value="_RTLDLL;NO_STRICT;USEPACKAGES"/>
+ <MAINSOURCE value="GR32_DSGN_CB6.cpp"/>
+ <INCLUDEPATH value="..\;$(BCB)\include;$(BCB)\include\vcl"/>
+ <LIBPATH value="$(BCB)\Projects\Lib;$(BCB)\lib\obj;$(BCB)\lib"/>
+ <WARNINGS value="-w-par -w-8027 -w-8026"/>
+ <OTHERFILES value=""/>
+ </MACROS>
+ <OPTIONS>
+ <CFLAG1 value="-Od -H=$(BCB)\lib\vcl60.csm -Hc -Vx -Ve -X- -r- -a8 -b- -k -y -v -vi- -c
+ -tWM"/>
+ <PFLAGS value="-$YD -$W -$O- -$A8 -v -JPHNE -M -LUdclstd -LUdesignide"/>
+ <RFLAGS value=""/>
+ <AFLAGS value="/mx /w2 /zd"/>
+ <LFLAGS value="-D"" -aa -Tpp -x -Gn -Gl -Gi -v"/>
+ <OTHERFILES value=""/>
+ </OPTIONS>
+ <LINKER>
+ <ALLOBJ value="c0pkg32.obj $(PACKAGES) Memmgr.Lib sysinit.obj $(OBJFILES)"/>
+ <ALLRES value="$(RESFILES)"/>
+ <ALLLIB value="$(LIBFILES) $(LIBRARIES) import32.lib cp32mti.lib"/>
+ <OTHERFILES value=""/>
+ </LINKER>
+ <FILELIST>
+ <FILE FILENAME="GR32_DSGN_CB6.cpp" FORMNAME="" UNITNAME="GR32_DSGN_CB6" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Reg.pas" FORMNAME="" UNITNAME="GR32_Reg" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Reg.dcr" FORMNAME="" UNITNAME="" CONTAINERID="DcrTool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Dsgn_Bitmap.pas" FORMNAME="PictureEditorForm" UNITNAME="GR32_Dsgn_Bitmap" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="..\GR32_Dsgn_Color.pas" FORMNAME="" UNITNAME="GR32_Dsgn_Color" CONTAINERID="PascalCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="C:\Borland\CBuilder6\Lib\designide.bpi" FORMNAME="" UNITNAME="designide" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="rtl.bpi" FORMNAME="" UNITNAME="rtl" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="vcl.bpi" FORMNAME="" UNITNAME="vcl" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="GR32_CB6.bpi" FORMNAME="" UNITNAME="GR32_CB6" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ <FILE FILENAME="dclstd.bpi" FORMNAME="" UNITNAME="dclstd" CONTAINERID="BPITool" DESIGNCLASS="" LOCALCOMMAND=""/>
+ </FILELIST>
+ <BUILDTOOLS>
+ </BUILDTOOLS>
+
+ <IDEOPTIONS>
+ </IDEOPTIONS>
+</PROJECT>
\ No newline at end of file
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.cpp
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.cpp 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.cpp 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,36 @@
+//---------------------------------------------------------------------------
+
+
+
+#include <basepch.h>
+
+#pragma hdrstop
+
+USEFORMNS("..\GR32_Dsgn_Bitmap.pas", Gr32_dsgn_bitmap, PictureEditorForm);
+
+//---------------------------------------------------------------------------
+
+#pragma package(smart_init)
+
+//---------------------------------------------------------------------------
+
+
+
+// Package source.
+
+//---------------------------------------------------------------------------
+
+
+
+#pragma argsused
+
+int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
+
+{
+
+ return 1;
+
+}
+
+//---------------------------------------------------------------------------
+
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_CB6.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D4.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D4.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D4.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,40 @@
+package GR32_DSGN_D4;
+
+{$R *.res}
+{$R '..\GR32_Reg.dcr'}
+{$ALIGN ON}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 Design Time Package'}
+{$DESIGNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl40,
+ dclstd40,
+ GR32_D4;
+
+contains
+ GR32_Reg in '..\GR32_Reg.pas',
+ GR32_Dsgn_Color in '..\GR32_Dsgn_Color.pas',
+ GR32_Dsgn_Bitmap in '..\GR32_Dsgn_Bitmap.pas' {PictureEditorForm};
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D4.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D4.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D5.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D5.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D5.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,40 @@
+package GR32_DSGN_D5;
+
+{$R *.RES}
+{$R '..\GR32_Reg.dcr'}
+{$ALIGN ON}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 Design Time Package'}
+{$DESIGNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl50,
+ dclstd50,
+ GR32_D5;
+
+contains
+ GR32_Reg in '..\GR32_Reg.pas',
+ GR32_Dsgn_Color in '..\GR32_Dsgn_Color.pas',
+ GR32_Dsgn_Bitmap in '..\GR32_Dsgn_Bitmap.pas' {PictureEditorForm};
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D5.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D5.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,40 @@
+package GR32_DSGN_D6;
+
+{$R *.res}
+{$R '..\GR32_Reg.dcr'}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 Design Time Package'}
+{$IMPLICITBUILD ON}
+
+requires
+ designide,
+ vcl,
+ GR32_D6,
+ rtl;
+
+contains
+ GR32_Dsgn_Bitmap in '..\GR32_Dsgn_Bitmap.pas' {PictureEditorForm},
+ GR32_Reg in '..\GR32_Reg.pas',
+ GR32_Dsgn_Color in '..\GR32_Dsgn_Color.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6_CLX.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6_CLX.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6_CLX.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,37 @@
+package GR32_DSGN_D6_CLX;
+
+{$R *.res}
{$R '..\GR32_Reg.dcr'}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 Design Time Package CLX'}
+{$IMPLICITBUILD ON}
+{$DEFINE CLX}
+
+requires
designide,
+ rtl,
+ GR32_D6_CLX;
+
+contains
GR32_Dsgn_Bitmap in '..\GR32_Dsgn_Bitmap.pas' {PictureEditorForm},
+ GR32_Reg in '..\GR32_Reg.pas',
+ GR32_Dsgn_Color in '..\GR32_Dsgn_Color.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6_CLX.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D6_CLX.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,40 @@
+package GR32_DSGN_D7;
+
+{$R *.res}
+{$R '..\GR32_Reg.dcr'}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 Design Time Package'}
+{$IMPLICITBUILD ON}
+
+requires
+ designide,
+ vcl,
+ rtl,
+ GR32_D7;
+
+contains
+ GR32_Dsgn_Bitmap in '..\GR32_Dsgn_Bitmap.pas' {PictureEditorForm},
+ GR32_Reg in '..\GR32_Reg.pas',
+ GR32_Dsgn_Color in '..\GR32_Dsgn_Color.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7_CLX.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7_CLX.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7_CLX.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,37 @@
+package GR32_DSGN_D7_CLX;
+
+{$R *.res}
{$R '..\GR32_Reg.dcr'}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 Design Time Package CLX'}
+{$IMPLICITBUILD ON}
+{$DEFINE CLX}
+
+requires
designide,
+ rtl,
+ GR32_D7_CLX;
+
+contains
GR32_Dsgn_Bitmap in '..\GR32_Dsgn_Bitmap.pas' {PictureEditorForm},
+ GR32_Reg in '..\GR32_Reg.pas',
+ GR32_Dsgn_Color in '..\GR32_Dsgn_Color.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7_CLX.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_D7_CLX.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.conf
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.conf 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.conf 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,32 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J-
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q-
+-$R-
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$YD
+-$Z1
+-cg
+-H+
+-W+
+-M
+-$M1048576
+-K$00400000
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,41 @@
+package GR32_DSGN_K;
+
+{$R *.res}
+{$R '../GR32_Reg.dcr'}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32 Design Time Package'}
+{$DESIGNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ rtl,
+ visualclx,
+ designide,
+ GR32_K;
+
+contains
+ GR32_Reg in '../GR32_Reg.pas',
+ GR32_Dsgn_Bitmap in '../GR32_Dsgn_Bitmap.pas' {PictureEditorForm},
+ GR32_Dsgn_Color in '../GR32_Dsgn_Color.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_DSGN_K.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_K.conf
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_K.conf 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_K.conf 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,32 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J-
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q-
+-$R-
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$YD
+-$Z1
+-cg
+-H+
+-W+
+-M
+-$M1048576
+-K$00400000
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_K.dpk
===================================================================
--- trunk/WPGM/Components/Graphics32/Packages/GR32_K.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Packages/GR32_K.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,47 @@
+package GR32_K;
+
+{$R *.res}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Graphics32'}
+{$IMPLICITBUILD ON}
+
+requires
+ rtl,
+ visualclx,
+ vcl;
+
+contains
+ GR32 in '../GR32.pas',
+ GR32_Blend in '../GR32_Blend.pas',
+ GR32_ByteMaps in '../GR32_ByteMaps.pas',
+ GR32_DrawingEx in '../GR32_DrawingEx.pas',
+ GR32_Filters in '../GR32_Filters.pas',
+ GR32_Image in '../GR32_Image.pas',
+ GR32_Layers in '../GR32_Layers.pas',
+ GR32_LowLevel in '../GR32_LowLevel.pas',
+ GR32_Polygons in '../GR32_Polygons.pas',
+ GR32_RangeBars in '../GR32_RangeBars.pas',
+ GR32_System in '../GR32_System.pas',
+ GR32_Transforms in '../GR32_Transforms.pas';
+
+end.
Added: trunk/WPGM/Components/Graphics32/Packages/GR32_K.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Graphics32/Packages/GR32_K.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/Graphics32/Readme.txt
===================================================================
--- trunk/WPGM/Components/Graphics32/Readme.txt 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/Readme.txt 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,17 @@
+See Graphics32.chm file for installation instructions, list of changes, license, and reference.
+
+SUPPORT
+-------
+
+For latest news and support visit the Graphics32 home page at http://g32.org and the newsgroup at g32org.public.graphics32.
+For the lastest version please visit http://sourceforge.net/projects/graphics32
+
+
+DONATIONS
+---------
+
+Given that Graphics32 is licensed under the terms of the MPL 1.1, you can use the Graphics32 package free of charge even for commercial and shareware applications. However, if you wish to express your appreciation for the time Alex Denisov spend on developing, documenting and supporting the initial version, he does accept and appreciate donations.
+
+If you wish to make your donation, visit the site above. The base amount is US$20, but if you would like to donate more, feel free to order multiple copies of the "Graphics32/G32 donation" product.
+
+Thank you for your support.
Added: trunk/WPGM/Components/Graphics32/_clean.bat
===================================================================
--- trunk/WPGM/Components/Graphics32/_clean.bat 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/Graphics32/_clean.bat 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,23 @@
+del /S *.~*
+del /S *.dcu
+del /S *.elf
+del /S *.dpu
+del /S *.dsk
+del /S *.cfg
+del /S *.dof
+del /S *.obj
+del /S *.hpp
+del /S *.ddp
+del /S *.mps
+del /S *.mpt
+del /S *.map
+del /S *.log
+del /s *.exe
+del /s *.so
+del /s *.stat
+del /s *.tci
+del /s /A Thumbs.db
+cd Examples\Clx
+REM dfm files aren't needed for Kylix and CLX...
+del /s *.dfm
+pause
Added: trunk/WPGM/Components/PDJButton.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/PDJButton.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/PDJButton.pas
===================================================================
--- trunk/WPGM/Components/PDJButton.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/PDJButton.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1983 @@
+
+unit PDJButton;
+{
+*****************************
+* PDJTools *
+*****************************
+}
+// TPDJButton version 4.01
+// Author Peric Djordje
+// Freeware Component for D3,D4,D5,D6
+// Copyright © 2000-2001 by PDJTools
+// Birthday of Component 07.04.2001.
+// Home Page: http://www.ptt.yu/korisnici/p/e/pericddn/
+// E-mail: pericddn at ptt.yu
+// If I' find any errors or rubbish in TPDJButton please send me Your suggest or Reclamation.
+
+{$IFDEF VER100}
+ {$DEFINE PDJ_D3}
+{$ELSE}
+ {$IFDEF VER120}
+ {$DEFINE PDJ_D4}
+ {$ELSE}
+ {$DEFINE PDJ_D5Up}
+ {$ENDIF}
+{$ENDIF}
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs
+ ,MMSystem,ExtCtrls,Menus,Buttons,StdCtrls;
+
+ {$R PDJBUTTON.res}
+
+
+type
+ TOnMouseOverEvent = procedure(Sender: TObject) of object;
+ TOnMouseOutEvent = procedure(Sender: TObject) of object;
+ TLayout=(blGlyphLeft,blGlyphBottom,blGlyphRight,blGlyphTop);
+ TNumGlyphs = 1..4;
+ TNumGlyphsHot = 1..4;
+ TSpacing = 1..5;
+ TMargin = -5..5;
+ TMarkGap = 1..5;
+ TPositionPopup = (puDown,puLeft,puRight);
+ TStyle = (stFlat,stDefault,stNone,stRaised,stFlatDot,
+ stRaisedDot,stFrameLowered,stFrameRaised);
+ TKind = (skCustom, skOK, skCancel, skHelp, skYes, skNo, skClose,
+ skAbort, skRetry, skIgnore,skAll,skSilly);
+ TColorMarginDefault = (cmDefault,cmCustom);
+
+ TPDJCustomButton = class(TCustomControl)
+ private
+
+ MainRect,
+ Secenje,
+ Duplikat,
+ Ispravni,
+ Gde,
+ CaptRect,
+ MarkRect,
+ GdeMark:Trect;
+ I,
+ IG,
+ Xpromtext,
+ Ypromtext,
+ Xveliki,
+ Yveliki,
+ Ymark,
+ Xmark:integer;
+ DC: THandle;
+ {$IFDEF PDJ_D3}
+ {$ELSE}
+ BiDiFlags: Longint ;
+ {$ENDIF}
+ FRepeat,
+ FStart: TTimer;
+ FMarkGap:TMarkGap;
+ FSpacing:TSpacing;
+ FMargin:TMargin;
+ FStyle:TStyle;
+ FNumGlyphs:TNumGlyphs;
+ FNumGlyphsHot:TNumGlyphsHot;
+ FKind:TKind;
+ FVersion: string;
+ FHintTwo:String;
+ FPositionPopup:TPositionPopup;
+ FPopupMenu: TPopupMenu;
+ FOnMouseOver: TOnMouseOverEvent;
+ FOnMouseOut: TOnMouseOutEvent;
+ FGlyph,
+ FIspravniGlyph,
+ FGlyphHot,
+ FMonoBmp,
+ Fmark:TBitmap;
+ FLayout:TLayout;
+ FMouseInPos,
+ FHotTrack,
+ FPlayMusic,
+ FActive,
+ FCancel,
+ FDefault,
+ FMarkMenu,
+ FShowHandCursor,
+ Focused,
+ FShowFocused,
+ FRepeatFunction:Boolean;
+ FColorMarginDefault:TColorMarginDefault;
+ Fx,
+ FRavno,
+ FRavno1,
+ Fslovo:integer;
+ FBoja,
+ FBojaHot,
+ FHotTrackColor,
+ FColorHighLight,
+ FColorShadow,
+ FColorHighLightPomocni,
+ FColorShadowPomocni:TColor;
+
+ function GetRepeatInterval: integer;
+ procedure SetRepeatInterval(const Value: integer);
+ procedure SetStartInterval(const Value: integer);
+ function GetStartInterval: integer;
+ procedure SetRepeatFunction(ARepeatFunction:boolean);
+ function GetVersion: string;
+ procedure SetVersion(const Value: string);
+ function GetHintTwo: string;
+ procedure DrawGlyph;
+ procedure DrawGlyphHot;
+ procedure PozicijaGlyph;
+ procedure DrawCaption;
+ procedure PozijaCaption;
+ procedure DrawMark;
+ procedure PozicijaMark;
+ procedure DrawFocus;
+ procedure DrawCaptionEnabled;
+ procedure SetShowHandCursor(AShowHandCursor:boolean);
+ procedure SetKind(value:TKind);
+ procedure SetColorMarginDefault(value:TColorMarginDefault);
+ procedure SetShowFocused(AShowFocused: Boolean);
+ procedure SetColorPomocni(index: integer; value: TColor);
+ procedure SetHintTwo(AHintTwo: string);
+ procedure SetMarkGap(value:TMarkGap);
+ procedure SetDefault(Value: Boolean);
+ procedure SetMarkMenu(AMarkMenu: Boolean);
+ procedure SetPositionPopup(value:TPositionPopup);
+ procedure SetPlayMusic(APlayMusic:boolean);
+ procedure SetHotTrack(AHotTrack:Boolean);
+ procedure SetSpacing(value:TSpacing);
+ procedure SetMargin(value:TMargin);
+ procedure SetStyle(value:TStyle);
+ procedure SetNumGlyphs(value: TNumGlyphs);
+ procedure SetNumGlyphsHot(value: TNumGlyphsHot);
+ procedure SetGlyph(value: TBitmap);
+ procedure SetGlyphHot(value: TBitmap);
+ procedure SetHotTrackColor(AHotTrackColor: TColor);
+ procedure SetLayout(Value:TLayout);
+ procedure DrawDisabledBitmap(Canvas: TCanvas; x, y: Integer; bmp: TBitmap);
+ procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
+ procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
+ procedure CMMouseEnter(var AMsg: TMessage);message CM_MOUSEENTER;
+ procedure CMMouseLeave(var AMsg: TMessage);message CM_MOUSELEAVE;
+ procedure CmEnabledChanged(var Message: TWmNoParams); message CM_ENABLEDCHANGED;
+ procedure CmParentColorChanged(var Message: TWMNoParams); message CM_PARENTCOLORCHANGED;
+ procedure CmTextChanged(var Message: TWmNoParams); message CM_TEXTCHANGED;
+ procedure CmVisibleChanged(var Message: TWmNoParams); message CM_VISIBLECHANGED;
+ procedure CmParentFontChanged(var Message: TWMNoParams); message CM_FONTCHANGED;
+ procedure SetPopupMenu(value: TPopupMenu);
+ procedure CnCommand(var Message: TWMCommand); message CN_COMMAND;
+ procedure CmDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
+ procedure CmDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
+ procedure CmFocusChanged(var Message: TCMFocusChanged); message CM_FOCUSCHANGED;
+ procedure WMLButtonDblClk (var Message: TWMLButtonDown); message WM_LBUTTONDBLCLK;
+
+ protected
+ procedure Click;override;
+ procedure SetButtonStyle(ADefault: Boolean); virtual;
+ procedure Music(song : pchar);
+ procedure Paint;override;
+ procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
+ X, Y: Integer); override;
+ procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
+ X, Y: Integer); override;
+ procedure Notification(AComponent: TComponent; Operation: TOperation);override;
+ procedure DoEnter; override;
+ procedure DoExit; override;
+ procedure doRepeat(Sender: TObject);
+ procedure doStart(Sender: TObject);
+ property RepeatAction:boolean read FRepeatFunction write SetRepeatFunction default false;
+ property RepeatInterval: integer read GetRepeatInterval write SetRepeatInterval;
+ property RepeatStartInterval: integer read GetStartInterval write SetStartInterval;
+ property ShowFocused:boolean read FShowFocused write SetShowFocused default True;
+ property CursorHandCustom:boolean read FShowHandCursor write SetShowHandCursor default True;
+ property ButtonKind:TKind read FKind write SetKind default skCustom;
+ property ColorMarginLeftTop: TColor
+ index 1 read FColorHighLightPomocni write SetColorPomocni default clBtnHighLight;
+ property ColorMarginRightBottom: TColor
+ index 2 read FColorShadowPomocni write SetColorPomocni default clBtnShadow;
+ property ColorMarginStyle:TColorMarginDefault
+ read FColorMarginDefault write SetColorMarginDefault default cmDefault;
+ property Version: string read GetVersion write SetVersion;
+ property PopupMenuMark:boolean read FMarkMenu write SetMarkMenu default False;
+ property PopupMenuMarkGap:TMarkGap read FMarkGap write SetMarkGap default 5;
+ property PositionPopup: TPositionPopup read FPositionPopup write SetPositionPopup default puDown;
+ property PlayMusic: boolean read FPlayMusic write SetPlayMusic default False;
+ property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
+ property HotTrackColor:TColor read FHotTrackColor write SetHotTrackColor default clBlue;
+ property HotTrack:Boolean read FHotTrack write SetHotTrack default True;
+ property Spacing:TSpacing read FSpacing write SetSpacing default 4;
+ property SpacingLayout:TMargin read FMargin write SetMargin default 3;
+ property OnMouseOver: TOnMouseOverEvent read FOnMouseOver write FOnMouseOver;
+ property OnMouseOut: TOnMouseOutEvent read FOnMouseOut write FOnMouseOut;
+ property NumGlyphs: TNumGlyphs read FNumGlyphs write SetNumGlyphs default 2;
+ property NumGlyphsHot: TNumGlyphsHot read FNumGlyphsHot write SetNumGlyphsHot default 2;
+ property Glyph: TBitmap read FGlyph write SetGlyph;
+ property GlyphHot: TBitmap read FGlyphHot write SetGlyphHot;
+ property Layout: TLayout read FLayout write SetLayout default blGlyphLeft;
+ property ButtonStyle: TStyle read FStyle write SetStyle default stFlat;
+ property Cancel: Boolean read FCancel write FCancel default False;
+ property Default: Boolean read FDefault write SetDefault default False;
+ property HintSecondLine:string read GetHintTwo write SetHintTwo;
+
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ end;
+
+ TPDJButton = class (TPDJCustomButton)
+
+ published
+
+ property RepeatAction;
+ property RepeatInterval;
+ property RepeatStartInterval;
+ property ShowFocused;
+ property CursorHandCustom;
+ property ButtonKind;
+ property ColorMarginLeftTop;
+ property ColorMarginRightBottom;
+ property ColorMarginStyle;
+ property Version;
+ property PopupMenuMark;
+ property PopupMenuMarkGap;
+ property PositionPopup;
+ property PlayMusic;
+ property PopupMenu;
+ property HotTrackColor;
+ property HotTrack;
+ property Spacing;
+ property SpacingLayout;
+ property OnMouseOver;
+ property OnMouseOut;
+ property NumGlyphs;
+ property NumGlyphsHot;
+ property Glyph;
+ property GlyphHot;
+ property Layout;
+ property ButtonStyle;
+ property Cancel;
+ property Default;
+ property HintSecondLine;
+ property Enabled;
+ property Caption;
+ property ParentFont;
+ property Font;
+ property OnClick;
+ property OnDblClick;
+ property OnDragDrop;
+ property OnDragOver;
+ property OnEndDrag;
+ property OnMouseDown;
+ property OnMouseUp;
+ property OnMouseMove;
+ property OnStartDrag;
+ property ShowHint;
+ property ParentColor;
+ property Visible;
+ property Color;
+ property HelpContext;
+ property TabStop;
+ property OnKeyDown;
+ property OnKeyPress;
+ property OnKeyUp;
+ property TabOrder;
+ property OnEnter;
+ property OnExit;
+ property Align;
+ {$IFDEF PDJ_D5up}
+ property OnContextPopup;
+ {$ENDIF}
+ {$IFDEF PDJ_D3}
+ {$ELSE}
+
+ property Action;
+ property Anchors;
+ property Constraints;
+ property BiDiMode;
+ property ParentBiDiMode;
+ {$ENDIF}
+ end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+ RegisterComponents('PDJ', [TPDJButton]);
+end;
+
+constructor TPDJCustomButton.Create(AOwner: TComponent);
+begin
+inherited Create(AOwner);
+SetBounds(0, 0, 75, 25);
+FColorHighLight := clBtnHighLight;
+FColorShadow := clBtnShadow;
+FColorHighLightPomocni := clBtnHighLight;
+FColorShadowPomocni := clBtnShadow;
+FMouseInPos:=false;
+FLayout:=blGlyphLeft;
+Fx:=0;
+FNumGlyphs :=2;
+FNumGlyphsHot :=2;
+FVersion:='Version 4.01, Copyright © 2000-2001 by Peric, http://www.ptt.yu/korisnici/p/e/pericddn/, E-mail: pericddn at ptt.yu';
+FRavno:=0;
+Fravno1:=1;
+FStyle:=stFlat;
+FSpacing:=4;
+FMargin:=3;
+Fslovo:=2;
+FHotTrack:=True;
+FHotTrackColor:=clBlue;
+FPlayMusic:=False;
+FPositionPopup:=puDown;
+FMarkMenu:=False;
+FMarkGap:=5;
+FKind:=skCustom;
+FGlyph := TBitmap.Create;
+FGlyphHot := TBitmap.Create;
+FIspravniGlyph := TBitmap.Create;
+FMonoBmp := TBitmap.Create;
+FShowHandCursor :=True;
+FShowFocused:=True;
+FColorMarginDefault:=cmDefault;
+FRepeat:=TTimer.Create(Self);
+FRepeat.Enabled:=false;
+FRepeat.Interval:=50;
+FRepeat.OnTimer:=doRepeat;
+FStart:=TTimer.Create(Self);
+FStart.Enabled:=false;
+FStart.Interval:=50;
+FStart.OnTimer:=doStart;
+FRepeatFunction:=False;
+end;
+
+
+procedure TPDJCustomButton.SetVersion(const Value: string);
+begin
+ FVersion:=FVersion;
+end;
+
+function TPDJCustomButton.GetVersion: string;
+begin
+ Result:=FVersion;
+end;
+
+
+destructor TPDJCustomButton.Destroy;
+begin
+FStart.Free;
+FRepeat.Free;
+FGlyph.Free;
+FGlyphHot.Free;
+FIspravniGlyph.Free;
+FMonoBmp.free;
+inherited Destroy;
+end;
+
+procedure TPDJCustomButton.SetRepeatFunction(ARepeatFunction:boolean);
+begin
+FRepeatFunction:=ARepeatFunction;
+end;
+
+procedure TPDJCustomButton.doRepeat(Sender: TObject);
+begin
+if FRepeatFunction then
+ if assigned(OnClick) then OnClick(Self);
+end;
+
+procedure TPDJCustomButton.doStart(Sender: TObject);
+begin
+if FRepeatFunction then begin
+ FStart.Enabled:=false;
+ FRepeat.Enabled:=true;
+end;
+end;
+
+function TPDJCustomButton.GetRepeatInterval: integer;
+begin
+ Result:=FRepeat.Interval;
+end;
+
+function TPDJCustomButton.GetStartInterval: integer;
+begin
+ Result:=FStart.Interval;
+end;
+
+procedure TPDJCustomButton.SetRepeatInterval(const Value: integer);
+begin
+ FRepeat.Interval:=Value;
+end;
+
+procedure TPDJCustomButton.SetStartInterval(const Value: integer);
+begin
+ FStart.Interval:=Value;
+end;
+
+procedure TPDJCustomButton.SetShowFocused(AShowFocused:boolean);
+begin
+FShowFocused:=AShowFocused;
+end;
+
+procedure TPDJCustomButton.SetShowHandCursor(AShowHandCursor:boolean);
+begin
+FShowHandCursor:=AShowHandCursor;
+end;
+
+procedure TPDJCustomButton.SetKind(value:TKind);
+begin
+ if value <> FKind then
+ begin
+ FKind := value;
+ FGlyph.Free;
+ FGlyphHot.Free;
+ FIspravniGlyph.Free;
+ FMonoBmp.free;
+ FGlyph := TBitmap.Create;
+ FGlyphHot := TBitmap.Create;
+ FIspravniGlyph := TBitmap.Create;
+ FMonoBmp := TBitmap.Create;
+
+ end;
+
+ case Fkind of
+ skOK:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'dagpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'dapdjb');
+
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='OK';
+ end;
+ skCancel:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'iksicgpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'iksicpdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='Cancel';
+ end;
+ skHelp:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'pomocgpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'pomocpdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='&Help';
+ end;
+ skYes:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'dagpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'dapdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='&Yes';
+ end;
+ skNo:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'negpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'nepdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='&No';
+ end;
+ skClose:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'exitgpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'exitpdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='&Close';
+ end;
+ skAbort:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'iksicgpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'iksicpdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='Abort';
+ end;
+ skRetry:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'Retrigpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'Retripdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='&Retry';
+ end;
+ skIgnore:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'ignogpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'ignopdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='&Ignore';
+ end;
+ skAll:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'svegpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'svepdjb');
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='&All';
+ end;
+
+ skSilly:
+ begin
+ FGlyph.Handle := LoadBitmap(hInstance, 'glupigpdjb');
+ FGlyphHot.Handle := LoadBitmap(hInstance, 'glupipdjb');
+
+ if ((csLoading in ComponentState) and (Caption <> '')) or
+ (not (csLoading in ComponentState)) then caption:='&Silly';
+ end;
+ end;
+ if FKind<>skCustom then
+ begin
+ FNumGlyphs :=1;
+ FNumGlyphsHot :=1;
+
+ end;
+ Invalidate;
+ if (FKind=skCancel) or (FKind=skNo) then
+ Cancel:=True else Cancel:=False;
+ if (FKind=skOK) or (FKind=skYes) then
+ FDefault:=True else FDefault:=False;
+end;
+
+
+procedure TPDJCustomButton.Click;
+var
+ Form: TCustomForm;
+ Control: TWinControl;
+ q: TPoint;
+begin
+////////VP////////// Fixed Vladimir Prieto {19.02.2002}
+ inherited Click;
+ case FKind of
+ skClose:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.Close;
+ end;
+ skHelp:
+ begin
+ Control := Self;
+ while (Control <> nil) and (Control.HelpContext = 0) do
+ Control := Control.Parent;
+ if Control <> nil then Application.HelpContext(Control.HelpContext);
+ end;
+ skOk:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.ModalResult := mrOk;
+ end;
+ skCancel:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.ModalResult := mrCancel;
+ end;
+ skYes:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.ModalResult := mrYes;
+ end;
+ skNo:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.ModalResult := mrNo;
+ end;
+ skAbort:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.ModalResult := mrAbort;
+ end;
+ skIgnore:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.ModalResult := mrIgnore;
+ end;
+ skRetry:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.ModalResult := mrRetry;
+ end;
+ skAll:
+ begin
+ Form := GetParentForm(Self);
+ if Form <> nil then Form.ModalResult := mrAll;
+ end;
+////////VP//////////
+
+ end;
+
+//******************************************************************************
+
+{{fixed 28.10.2001.)}
+Begin
+if FPopupMenu = nil then exit;
+if not enabled then exit;
+
+if FRepeatFunction then FStart.Enabled:=true;
+Fslovo:=0;
+IG:=1;
+
+DC := Canvas.Handle;
+MainRect:=clientRect;
+
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+Frame3d(Canvas, MainRect, FColorShadow,FColorHighLight,Fravno1);
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawEdge(DC, MainRect, BDR_SUNKENOUTER,BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE);
+end;
+i:=1;
+if (FGlyphHot.empty)then DrawGlyph;
+if (not FGlyphHot.empty)and (not FGlyph.empty) then
+begin
+if not enabled then
+DrawGlyph else DrawGlyphHot;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawFocus;
+end;
+DrawCaption;
+///if FPopupMenu = nil then exit;
+ FPopupMenu.AutoPopup:= false;
+ // Add 20.11.2001.
+ FPopupMenu.PopupComponent:=TPDJButton(self);
+ q.X:= 0;
+ q.Y:= 0;
+ q:= ClientToScreen(q);
+
+Case FPositionPopup of
+puDown:
+begin
+ FPopupMenu.Alignment:=paLeft;
+ FPopupMenu.Popup(q.X - 1, q.Y + Height);
+end;
+puRight:
+begin
+ FPopupMenu.Alignment:=paLeft;
+ FPopupMenu.Popup(q.X+width+1, q.Y );
+end;
+puLeft:
+begin
+ FPopupMenu.Alignment:=paRight;
+ FPopupMenu.Popup(q.X-1, q.Y );
+end;
+end;
+
+
+DC := Canvas.Handle;
+MainRect:=clientRect;
+
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+Case FStyle of
+stFlat,stNone,stFlatDot:
+Frame3d(Canvas, MainRect, FColorShadow,FColorHighLight,0);
+stDefault,stFrameLowered,stFrameRaised:
+Frame3d(Canvas, MainRect,FColorHighLight ,FColorShadow,1);
+stRaised,stRaisedDot:
+Frame3d(Canvas, MainRect,FColorHighLight ,FColorShadow,2);
+end;
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawEdge(DC, MainRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE );
+end;
+IG:=0;
+DrawGlyph;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawFocus;
+end;
+Fslovo:=1;
+DrawCaption;
+
+if FRepeatFunction then begin
+ FRepeat.Enabled:=false;
+ FStart.Enabled:=false;
+end;
+
+i:=0;
+end;
+//******************************************************************************
+end;
+
+procedure TPDJCustomButton.SetMarkMenu(AMarkMenu: Boolean);
+begin
+FMarkMenu:=AMarkMenu;
+Invalidate;
+end;
+
+procedure TPDJCustomButton.SetMarkGap(value: TMarkGap);
+begin
+ if value <> FMarkGap then
+ begin
+ FMarkGap := value;
+ Invalidate;
+ end;
+end;
+
+function TPDJCustomButton.GetHintTwo: string;
+begin
+ Result:=FHintTwo;
+end;
+
+procedure TPDJCustomButton.SetHintTwo(AHintTwo:String);
+begin
+FHintTwo:=AHintTwo;
+if csDesigning in ComponentState then
+ Exit;
+ if hint<>'' then
+ if FHintTwo<>'' then
+hint:=hint+#13+FHintTwo else
+hint:=hint;
+end;
+
+
+procedure TPDJCustomButton.SetButtonStyle(ADefault: Boolean);
+const
+ BS_MASK = $000F;
+var
+ Style: Word;
+begin
+ if HandleAllocated then
+ begin
+ if ADefault then Style := BS_DEFPUSHBUTTON else Style := BS_PUSHBUTTON;
+ if GetWindowLong(Handle, GWL_STYLE) and BS_MASK <> Style then
+ SendMessage(Handle, BM_SETSTYLE, Style, 1);
+ end;
+end;
+
+procedure TPDJCustomButton.DoEnter;
+begin
+ inherited DoEnter;
+ Case FStyle of stDefault,stFrameLowered,stFrameRaised:
+ Focused := true;
+end;
+end;
+
+procedure TPDJCustomButton.DoExit;
+begin
+ inherited DoExit;
+ Case FStyle of stDefault,stFrameLowered,stFrameRaised:
+ begin
+ Focused := false;
+ if ShowFocused then Invalidate;
+ end;
+ end;
+end;
+
+procedure TPDJCustomButton.SetDefault(Value: Boolean);
+begin
+Fdefault:=value;
+end;
+
+procedure TPDJCustomButton.CMFocusChanged(var Message: TCMFocusChanged);
+begin
+
+ with Message do
+ if Sender is TPDJCustomButton then
+ begin
+ FActive := Sender = Self;
+ end
+ else
+ begin
+ FActive := FDefault;
+ end;
+
+ begin SetButtonStyle(FActive);
+ Case FStyle of stDefault,stFrameLowered,stFrameRaised:
+ begin
+
+ if focused then
+ begin
+ if FShowFocused then Invalidate;
+
+ end;
+ end;
+ end;
+end; inherited;
+end;
+
+procedure TPDJCustomButton.DrawFocus;
+begin
+Case FStyle of stDefault,stFrameLowered,stFrameRaised:
+ begin
+if FShowFocused then begin
+if focused then
+DrawFocusrect(Canvas.Handle,Rect(MainRect.left+3,MainRect.top+3,MainRect.Right-3,MainRect.bottom-3));
+
+end ;
+end;
+end;
+end;
+
+
+
+
+procedure TPDJCustomButton.CNCommand(var Message: TWMCommand);
+begin
+ if Message.NotifyCode = BN_CLICKED then Click;
+end;
+
+procedure TPDJCustomButton.CMDialogKey(var Message: TCMDialogKey);
+
+begin
+
+ with Message do
+ if (((CharCode = VK_RETURN) and FActive) or ((CharCode = VK_ESCAPE) and FCancel))
+ and (KeyDataToShiftState(Message.KeyData) = []) and CanFocus then
+ begin
+
+ Click;
+
+
+ Result := 1;
+
+ end
+ else
+ inherited;
+end;
+
+procedure TPDJCustomButton.CMDialogChar(var Message: TCMDialogChar);
+begin
+ with Message do
+ if IsAccel(CharCode, Caption) and CanFocus then
+ begin
+ Click;
+ Result := 1;
+ end
+ else
+ inherited;
+end;
+
+
+procedure TPDJCustomButton.Music(song : pchar);
+var
+ h: THandle;
+ p: pointer;
+begin
+ h := FindResource(hInstance,song,'WAV');
+ h := LoadResource(hInstance, h);
+ p := LockResource(h);
+ sndPlaySound(p,SND_MEMORY or SND_SYNC);
+ UnLockResource(h);
+ FreeResource(h);
+ end;
+
+procedure TPDJCustomButton.SetPopupMenu(value: TPopupMenu);
+begin
+ FPopupMenu := Value;
+ if Value <> nil then
+ begin
+ Value.FreeNotification(Self);
+ Invalidate;
+ end;
+end;
+
+procedure TPDJCustomButton.Notification(AComponent: TComponent; Operation: TOperation);
+begin
+ inherited Notification(AComponent, Operation);
+ if (Operation = opRemove) and (AComponent = FPopupMenu) then FPopupMenu := nil;
+end;
+
+procedure TPDJCustomButton.SetHotTrack(AHotTrack:boolean);
+begin
+FHotTrack:=AHotTrack;
+end;
+
+procedure TPDJCustomButton.SetPlayMusic(APlayMusic:boolean);
+begin
+FPlayMusic:=APlayMusic;
+end;
+
+procedure TPDJCustomButton.SetHotTrackColor(AHotTrackColor:TColor);
+begin
+FHotTrackColor:=AHotTrackColor;
+end;
+
+procedure TPDJCustomButton.SetSpacing(value:TSpacing);
+begin
+ if value <> FSpacing then
+ begin
+ FSpacing := value;
+ Invalidate;
+ end;
+end;
+
+procedure TPDJCustomButton.SetPositionPopup(value:TPositionPopup);
+begin
+ if value <> FPositionPopup then
+ begin
+ FPositionPopup := value;
+ end;
+end;
+
+
+procedure TPDJCustomButton.SetMargin(value:TMargin);
+begin
+ if value <> FMargin then
+ begin
+ FMargin := value;
+ Invalidate;
+ end;
+end;
+
+
+procedure TPDJCustomButton.PozicijaGlyph;
+begin
+with canvas do
+begin
+if (caption='') and (not FGlyph.empty) then
+begin
+
+Xveliki:=(MainRect.left+((MainRect.right-MainRect.left)- (Ispravni.right-Ispravni.left)) div 2);
+Yveliki:=(MainRect.top+((MainRect.bottom-MainRect.top)- (Ispravni.bottom-Ispravni.top)) div 2);
+begin
+if not FMarkMenu then
+Gde:= Rect(Xveliki+IG, Yveliki+IG, Xveliki+FispravniGlyph.Width+IG, Yveliki+FispravniGlyph.Height+IG)
+else
+Gde:= Rect(Xveliki+IG-5, Yveliki+IG, Xveliki+FispravniGlyph.Width+IG-5, Yveliki+FispravniGlyph.Height+IG);
+end;
+end
+else
+begin
+case FLayout of
+blGlyphLeft:
+begin
+
+Xveliki:=((MainRect.left+((MainRect.right-MainRect.left)- ((Ispravni.right-Ispravni.left)+(TextWidth(Caption))))div 2))-FMargin;
+Yveliki:=(MainRect.top+((MainRect.bottom-MainRect.top)- (Ispravni.bottom-Ispravni.top)) div 2);
+Gde:= Rect(Xveliki+IG, Yveliki+IG, Xveliki+FispravniGlyph.Width+IG, Yveliki+FispravniGlyph.Height+IG);
+end;
+blGlyphBottom:
+begin
+Xveliki:=(MainRect.left+((MainRect.right-MainRect.left)- (Ispravni.right-Ispravni.left)) div 2);
+Yveliki:=(MainRect.top+((MainRect.bottom-MainRect.top)- (Ispravni.bottom-Ispravni.top)) div 2)+ ((textheight(caption))div 2)+FMargin;
+Gde:= Rect(Xveliki+IG, Yveliki+IG, Xveliki+FispravniGlyph.Width+IG, Yveliki+FispravniGlyph.Height+IG);
+end;
+blGlyphTop:
+begin
+Xveliki:=(MainRect.left+((MainRect.right-MainRect.left)- (Ispravni.right-Ispravni.left)) div 2);
+Yveliki:=(MainRect.top+((MainRect.bottom-MainRect.top)- (Ispravni.bottom-Ispravni.top)) div 2)- ((textheight(caption))div 2)-FMargin;
+Gde:= Rect(Xveliki+IG, Yveliki+IG, Xveliki+FispravniGlyph.Width+IG, Yveliki+FispravniGlyph.Height+IG);
+end;
+blGlyphRight:
+begin
+Xveliki:=((MainRect.left+((MainRect.right-MainRect.left)- ((Ispravni.right-Ispravni.left)-(TextWidth(Caption))))div 2))+FMargin;
+Yveliki:=(MainRect.top+((MainRect.bottom-MainRect.top)- (Ispravni.bottom-Ispravni.top)) div 2);
+Gde:= Rect(Xveliki+IG, Yveliki+IG, Xveliki+FispravniGlyph.Width+IG, Yveliki+FispravniGlyph.Height+IG);
+end;
+end;
+end;
+end;
+end;
+
+procedure TPDJCustomButton.PozicijaMark;
+begin
+with canvas do
+begin
+if (not FGlyph.empty) then
+Ymark:=(Gde.top+((Gde.bottom-Gde.top)- (MarkRect.bottom-MarkRect.top)) div 2);
+Xmark:=(Gde.left+FispravniGlyph.Width)+FMarkGap;
+GdeMark:=(Rect(Xmark,Ymark,(MarkRect.Right-MarkRect.Left)+Xmark,(MarkRect.bottom-MarkRect.top)+Ymark));
+end;
+end;
+
+
+
+procedure TPDJCustomButton.DrawMark;
+var fmarkBoja:Tcolor;
+begin
+FMark := TBitmap.Create;
+
+if Fglyph.Empty then Exit;
+if not FMarkMenu then Exit;
+if ((Flayout=blGlyphLeft) or (Flayout=blGlyphRight)) and (Caption>'') then Exit;
+
+FMark.Handle := LoadBitmap(hInstance, 'Strela');
+
+begin
+if not enabled then
+begin
+MarkRect := Rect(0, 0, FMark.Width, FMark.Height);
+Pozicijamark;
+DrawDisabledBitmap(Canvas,GdeMark.left, GdeMark.top, FMark);
+
+end
+else
+begin
+FMarkboja:=FMark.Canvas.Pixels[0,FMark.Height-1];
+MarkRect := Rect(0, 0, FMark.Width, FMark.Height);
+Pozicijamark;
+canvas.BrushCopy(GdeMark, FMark ,MarkRect, fMarkBoja);
+Fmark.Free;
+end;
+end;
+end;
+
+procedure TPDJCustomButton.DrawGlyph;
+begin
+if Fglyph.Empty then exit;
+Secenje:=Rect(0,0,FGlyph.Width div FNumGlyphs,Fglyph.Height);
+if (FNumGlyphs=2) and (not enabled) then
+Secenje:=Rect(FGlyph.Width div FNumGlyphs,0,FGlyph.Width,Fglyph.Height);
+
+Duplikat:=Rect(0,0,FGlyph.Width div FNumGlyphs,Fglyph.Height);
+FIspravniGlyph.width:=FGlyph.Width div FNumGlyphs;
+FIspravniGlyph.height:=FGlyph.height;
+FispravniGlyph.Canvas.Copyrect(Duplikat,FGlyph.canvas,Secenje);
+if (not enabled) and (FNumGlyphs<>2) then
+begin
+Ispravni:=Rect(0,0,FIspravniGlyph.width,FIspravniGlyph.height);
+PozicijaGlyph;
+DrawDisabledBitmap(Canvas,gde.left, gde.top, FIspravniGlyph);
+end
+else
+begin
+Ispravni:=Rect(0,0,FIspravniGlyph.width,FIspravniGlyph.height);
+PozicijaGlyph;
+Fboja:=FispravniGlyph.Canvas.Pixels[0,FispravniGlyph.Height-1];
+Canvas.BrushCopy(Gde,FispravniGlyph,Ispravni,FBoja);
+end;
+DrawMark;
+end;
+
+
+procedure TPDJCustomButton.DrawDisabledBitmap(Canvas: TCanvas; x, y: Integer; bmp: TBitmap);
+begin
+FMonoBmp.Assign(bmp);
+FMonobmp.Canvas.Brush.Color := clBlack;
+FMonobmp.Monochrome := True;
+Canvas.Brush.Color := clBtnHighlight;
+SetTextColor(Canvas.Handle, clBlack);
+SetBkColor(Canvas.Handle, clWhite);
+BitBlt(Canvas.Handle, x+1, y+1, bmp.Width, bmp.Height,
+FMonobmp.Canvas.Handle, 0, 0, $00E20746);
+Canvas.Brush.Color := clBtnShadow;
+SetTextColor(Canvas.Handle, clBlack);
+SetBkColor(Canvas.Handle, clWhite);
+BitBlt(Canvas.Handle, x, y, bmp.Width, bmp.Height,
+FMonobmp.Canvas.Handle, 0, 0, $00E20746);
+end;
+
+procedure TPDJCustomButton.DrawGlyphHot;
+
+begin
+if FglyphHot.Empty then exit;
+Secenje:=Rect(0,0,FGlyphHot.Width div FNumGlyphsHot,FglyphHot.Height);
+Duplikat:=Rect(0,0,FGlyphHot.Width div FNumGlyphsHot,FglyphHot.Height);
+FIspravniGlyph.width:=FGlyphHot.Width div FNumGlyphsHot;
+FIspravniGlyph.height:=FGlyphHot.height;
+FispravniGlyph.Canvas.Copyrect(Duplikat,FGlyphHot.canvas,Secenje);
+Ispravni:=Rect(0,0,FIspravniGlyph.width,FIspravniGlyph.height);
+PozicijaGlyph;
+
+FbojaHot:=FispravniGlyph.Canvas.Pixels[0,FispravniGlyph.Height-1];
+Canvas.BrushCopy(Gde,FispravniGlyph,Ispravni,FBojaHot);
+DrawMark;
+end;
+
+
+procedure TPDJCustomButton.pozijaCaption;
+begin
+with Canvas do
+begin
+if (caption<>'') and (FGlyph.empty) then
+begin
+xpromtext:=(MainRect.left+((MainRect.right-MainRect.left)-Textwidth(Caption)) div 2);
+ypromtext:=(MainRect.top+((MainRect.bottom-MainRect.top)-TextHeight(Caption)) div 2);
+CaptRect := Rect(Xpromtext+IG, Ypromtext+IG , Xpromtext+TextWidth(Caption)+IG, ypromtext+TextHeight(Caption)+IG);
+end
+else
+begin
+case FLayout of
+blGlyphLeft:
+begin
+xpromtext:=gde.right+FSpacing;
+ypromtext:=(gde.top+((gde.Bottom-gde.top)-textheight(caption)) div 2);
+CaptRect := Rect(Xpromtext, Ypromtext , Xpromtext+TextWidth(Caption), ypromtext+TextHeight(Caption));
+end;
+blGlyphRight:
+begin
+xpromtext:= gde.left-textwidth(caption)-FSpacing;
+ypromtext:=(gde.top+((gde.Bottom-gde.top)-textheight(caption)) div 2);
+CaptRect := Rect(Xpromtext, Ypromtext , Xpromtext+TextWidth(Caption), ypromtext+TextHeight(Caption));
+end;
+blGlyphBottom:
+begin
+xpromtext:=gde.left-(Textwidth(Caption)div 2)+((gde.Right-gde.Left)div 2);
+ypromtext:=gde.top-8-FSpacing-(TextHeight(Caption)div 2);
+CaptRect := Rect(Xpromtext, Ypromtext , Xpromtext+TextWidth(Caption), ypromtext+TextHeight(Caption));
+end;
+blGlyphTop:
+begin
+xpromtext:=gde.left-(Textwidth(Caption)div 2)+((gde.Right-gde.Left)div 2);
+ypromtext:=(gde.bottom+FSpacing);
+CaptRect := Rect(Xpromtext, Ypromtext, Xpromtext+TextWidth(Caption), ypromtext+TextHeight(Caption));
+end;
+end;
+end;
+end;
+end;
+
+
+procedure TPDJCustomButton.DrawCaption;
+var
+Farbica:TColor;
+begin
+with Canvas do
+begin
+
+Font.Assign(Self.Font);
+
+
+
+farbica:=font.color;
+ if FHotTrack then
+ begin
+ if Fslovo=0 then font.color:=FHotTrackColor else font.color:=farbica;
+ end;
+
+Brush.Style := bsClear;
+
+pozijaCaption;
+begin
+if not Enabled then DrawCaptionEnabled;
+{$IFDEF PDJ_D3}
+DrawText(Handle, PChar(Caption), Length(Caption), CaptRect, (DT_EXPANDTABS or DT_center ));
+{$ELSE}
+DrawText(Handle, PChar(Caption), Length(Caption), CaptRect, (DT_EXPANDTABS or DT_center or BiDiFlags ));
+{$ENDIF}
+end;
+
+end;
+end;
+
+
+
+procedure TPDJCustomButton.DrawCaptionEnabled;
+var ECaptRect:TRect;
+begin
+with canvas do
+ begin
+ Font := Self.Font;
+ brush.style:=bsClear;
+ {$IFDEF PDJ_D3}
+ DrawText(Handle, PChar(Caption), Length(Caption), CaptRect, (DT_EXPANDTABS or DT_center ));
+ {$ELSE}
+ DrawText(Handle, PChar(Caption), Length(Caption), CaptRect, (DT_EXPANDTABS or DT_center or BiDiFlags ));
+ {$ENDIF}
+ font.Color :=clBtnHighlight;
+ ECaptRect:=Rect(CaptRect.Left+1,CaptRect.top+1,CaptRect.Right+1,CaptRect.Bottom+1);
+ {$IFDEF PDJ_D3}
+ DrawText(Handle, PChar(Caption), Length(Caption), ECaptRect, (DT_EXPANDTABS or DT_center ));
+ {$ELSE}
+ DrawText(Handle, PChar(Caption), Length(Caption), ECaptRect, (DT_EXPANDTABS or DT_center or BiDiFlags));
+ {$ENDIF}
+ font.color :=clBtnShadow;
+ end;
+end;
+
+procedure TPDJCustomButton.SetGlyph(value: TBitmap);
+begin
+ if value <> FGlyph then
+ begin
+ FGlyph.Assign(value);
+ if not FGlyph.Empty then
+ begin
+ if Fglyph.width<Glyph.Height then
+ begin
+ FNumGlyphs:=1;
+ Invalidate;
+ end;
+ if FGlyph.Width div FGlyph.Height<2 then
+ begin
+ FNumGlyphs:=1;
+ Invalidate;
+ end;
+
+ if FGlyph.Width mod FGlyph.Height = 0 then
+ begin
+ FNumGlyphs := FGlyph.Width div FGlyph.Height;
+
+ if FNumGlyphs > 4 then FNumGlyphs := 1;
+ Invalidate
+ end;
+ end
+ else
+ Invalidate;
+
+ end;
+ FKind:=skCustom;
+end;
+
+procedure TPDJCustomButton.SetGlyphHot(value: TBitmap);
+begin
+ if value <> FGlyphHot then
+ begin
+ FGlyphHot.Assign(value);
+ if not FGlyphHot.Empty then
+ begin
+ if FglyphHot.width<GlyphHot.Height then
+ begin
+ FNumGlyphsHot:=1;
+ Invalidate;
+ end;
+ if FGlyphHot.Width div FGlyphHot.Height<2 then
+ begin
+ FNumGlyphsHot:=1;
+ Invalidate;
+ end;
+
+ if FGlyphHot.Width mod FGlyphHot.Height = 0 then
+ begin
+ FNumGlyphsHot := FGlyphHot.Width div FGlyphHot.Height;
+ if FNumGlyphsHot > 4 then FNumGlyphsHot := 1;
+ Invalidate
+ end;
+ end
+ else
+ Invalidate;
+
+ end;
+ FKind:=skCustom;
+end;
+
+procedure TPDJCustomButton.SetColorMarginDefault(value:TColorMarginDefault);
+begin
+ FColorMarginDefault := value;
+ if FColorMarginDefault=cmDefault then
+ begin
+ Case FStyle of
+
+stFlat,stRaised,stFrameRaised,stFlatDot,stRaisedDot:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBtnShadow;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+stDefault:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBlack;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := clBlack;
+ end;
+stFrameLowered:
+ begin
+ FColorHighLight := clBtnShadow;
+ FColorShadow := clBtnHighLight;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+ end;
+
+end;
+invalidate;
+end;
+
+procedure TPDJCustomButton.SetColorPomocni(index: integer; value: TColor);
+begin
+case index of
+1: if value <> FColorHighLightPomocni then
+begin
+FColorHighLightPomocni := value;
+FColorHighLight :=FColorHighLightPomocni;
+ Case FStyle of
+stRaisedDot,stFlat,stFrameRaised,stFlatDot,stRaised,stDefault:
+ begin
+ Case FColorMarginDefault of cmDefault:
+begin
+ if FColorHighLightPomocni <> clBtnHighLight then
+ FColorMarginDefault:=cmCustom;
+ end;
+ end;
+ end;
+stFrameLowered:
+ begin
+ Case FColorMarginDefault of cmDefault:
+begin
+ if FColorHighLightPomocni <> clBtnShadow then
+ FColorMarginDefault:=cmCustom;
+ end;
+ end;
+ end;
+end;
+Invalidate;
+end;
+
+2: if value <> FColorShadowPomocni then
+begin
+FColorShadowPomocni := value;
+FColorShadow := FColorShadowPomocni;
+Case FStyle of
+stRaisedDot,stFlat,stFrameRaised,stFlatDot,stRaised:
+begin
+ Case FColorMarginDefault of cmDefault:
+ begin
+ if FColorShadowPomocni <> clBtnShadow then
+ FColorMarginDefault:=cmCustom;
+ end;
+ end;
+end;
+stDefault:
+begin
+ Case FColorMarginDefault of cmDefault:
+ begin
+ if FColorShadowPomocni <> clBlack then
+ FColorMarginDefault:=cmCustom;
+ end;
+ end;
+end;
+stFrameLowered:
+begin
+ Case FColorMarginDefault of cmDefault:
+ begin
+ if FColorShadowPomocni <> clBtnHighLight then
+ FColorMarginDefault:=cmCustom;
+ end;
+ end;
+end;
+end;
+Invalidate;
+end;
+end;
+end;
+
+procedure TPDJCustomButton.SetStyle(value: TStyle);
+begin
+ begin
+ FStyle := value;
+ Case FStyle of
+
+stFlat:
+ begin
+ Fravno:=0;
+ Fravno1:=1;
+ Canvas.pen.Style:=psSolid;
+
+ Case FColorMarginDefault of
+ cmDefault:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBtnShadow;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+ cmCustom:
+ begin
+ FColorHighLight := FColorHighLightPomocni;
+ FColorShadow := FColorShadowPomocni;
+ end;
+ end;
+ end;
+stNone:
+ begin
+ Fravno:=0;
+ Fravno1:=0;
+ end;
+stRaised:
+ begin
+ Fravno:=2;
+ Fravno1:=2;
+ Canvas.pen.Style:=psSolid;
+ Case FColorMarginDefault of
+ cmDefault:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBtnShadow;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+ cmCustom:
+ begin
+ FColorHighLight := FColorHighLightPomocni;
+ FColorShadow := FColorShadowPomocni;
+ end;
+ end;
+ end;
+stDefault:
+ begin
+ ParentColor:=False;
+ Color:=clBtnface;
+ Fravno:=1;
+ Fravno1:=1;
+ Canvas.pen.Style:=psSolid;
+ Case FColorMarginDefault of
+ cmDefault:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBlack;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := clBlack;
+ end;
+ cmCustom:
+ begin
+ FColorHighLight := FColorHighLightPomocni;
+ FColorShadow := FColorShadowPomocni;
+ end;
+ end;
+ end;
+stFrameRaised:
+ begin
+ ParentColor:=False;
+ Color:=clBtnface;
+ Fravno:=1;
+ Fravno1:=1;
+ Canvas.pen.Style:=psSolid;
+ Case FColorMarginDefault of
+ cmDefault:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBtnShadow;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+ cmCustom:
+ begin
+ FColorHighLight := FColorHighLightPomocni;
+ FColorShadow := FColorShadowPomocni;
+ end;
+ end;
+ end;
+stFrameLowered:
+ begin
+ ParentColor:=False;
+ Color:=clBtnface;
+ Fravno:=1;
+ Fravno1:=1;
+ Canvas.pen.Style:=psSolid;
+ Case FColorMarginDefault of
+ cmDefault:
+ begin
+ FColorHighLight := clBtnShadow;
+ FColorShadow := clBtnHighLight;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+ cmCustom:
+ begin
+ FColorHighLight := FColorHighLightPomocni;
+ FColorShadow := FColorShadowPomocni;
+ end;
+ end;
+ end;
+
+stFlatDot:
+ begin
+ Fravno:=0;
+ Fravno1:=1;
+ Canvas.pen.Style:=psDot;
+ Case FColorMarginDefault of
+ cmDefault:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBtnShadow;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+ cmCustom:
+ begin
+ FColorHighLight := FColorHighLightPomocni;
+ FColorShadow := FColorShadowPomocni;
+ end;
+ end;
+ end;
+stRaisedDot:
+ begin
+ Fravno:=2;
+ Fravno1:=2;
+ Canvas.pen.Style:=psDot;
+ Case FColorMarginDefault of
+ cmDefault:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBtnShadow;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+ cmCustom:
+ begin
+ FColorHighLight := FColorHighLightPomocni;
+ FColorShadow := FColorShadowPomocni;
+ end;
+ end;
+ end;
+
+end;
+
+ Invalidate;
+ end;
+end;
+
+
+
+procedure TPDJCustomButton.SetNumGlyphs(value: TNumGlyphs);
+begin
+ if value <> FNumGlyphs then
+ begin
+ FNumGlyphs := value;
+ Invalidate;
+ end;
+end;
+
+procedure TPDJCustomButton.SetNumGlyphsHot(value: TNumGlyphsHot);
+begin
+ if value <> FNumGlyphsHot then
+ begin
+ FNumGlyphsHot := value;
+ Invalidate;
+ end;
+end;
+
+
+
+
+procedure TPDJCustomButton.SetLayout(value: TLayout);
+begin
+ if value <> FLayout then FLayout := value;
+Invalidate;
+end;
+
+
+procedure TPDJCustomButton.Paint;
+begin
+inherited Paint;
+DC := Canvas.Handle;
+
+if (FStyle=stFlat) or (FStyle=stFlatDot) then begin
+FRavno:=0;
+if csDesigning in ComponentState then
+FRavno:=1;
+end;
+MainRect:=clientRect;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+
+Frame3d(Canvas, MainRect, FColorHighLight,FColorShadow,FRavno);
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+ begin
+DrawEdge(DC, MainRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE );
+end;
+end;
+
+DrawGlyph;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawFocus;
+end;
+DrawCaption;
+end;
+
+procedure TPDJCustomButton.CMMouseEnter(var AMsg: TMessage);
+
+begin
+if not Enabled then exit;
+if Assigned(FOnMouseOver) then FOnMouseOver(Self);
+FMouseInPos:=True;
+IG:=0;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+ begin
+if ((FPopupmenu<>nil) ) then setfocus;
+end;
+end;
+if FShowHandCursor then begin
+Screen.Cursors[1] := LoadCursor(hinstance,'HANDpdjb');
+Cursor := 1; end;
+Fslovo:=0;
+if FPlayMusic then music('PREKO');
+DC := Canvas.Handle;
+MainRect:=clientRect;
+
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+ Case FStyle of
+stFlat:
+ begin
+ Fravno:=0;
+ Fravno1:=1;
+ Canvas.pen.Style:=psSolid;
+
+ Case FColorMarginDefault of
+ cmDefault:
+ begin
+ FColorHighLight := clBtnHighLight;
+ FColorShadow := clBtnShadow;
+ FColorHighLightPomocni := FColorHighLight;
+ FColorShadowPomocni := FColorShadow;
+ end;
+ cmCustom:
+ begin
+ FColorHighLight := FColorHighLightPomocni;
+ FColorShadow := FColorShadowPomocni;
+ end;
+ end;
+ end;
+ end;
+
+Frame3d(Canvas, MainRect, FColorHighLight,FColorShadow,Fravno1);
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawEdge(DC, MainRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE );
+end;
+i:=0;
+if (FGlyphHot.empty)then DrawGlyph;
+if (not FGlyphHot.empty)and (not FGlyph.empty) then
+begin
+if not enabled then
+DrawGlyph else DrawGlyphHot;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+ DrawFocus;
+end;
+DrawCaption;
+
+Fx:=0;
+end;
+
+
+procedure TPDJCustomButton.CMMouseLeave(var AMsg: TMessage);
+begin
+
+if not Enabled then exit;
+if Assigned(FOnMouseOut) then FOnMouseOut(Self);
+FMouseInpos:=False;
+IG:=0;
+if FShowHandCursor then begin
+Screen.Cursors[0] := crDefault;
+Cursor := 0; end;
+if FRepeatFunction then begin
+ FRepeat.Enabled:=false;
+ FStart.Enabled:=false;
+end;
+Fslovo:=1;
+DC := Canvas.Handle;
+MainRect:=clientRect;
+
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+Frame3d(Canvas, MainRect,FColorHighLight ,FColorShadow,FRavno);
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawEdge(DC, MainRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE );
+end;
+DrawGlyph;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+{if TabStop then} DrawFocus;
+end;
+DrawCaption;
+
+Fx:=1;
+i:=0;
+end;
+
+
+procedure TPDJCustomButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
+ X, Y: Integer);
+begin
+if Button<>mbleft then exit else begin
+
+if not Enabled then exit;
+if Fx=1 then exit;
+
+if FRepeatFunction then begin
+ FRepeat.Enabled:=false;
+ FStart.Enabled:=false;
+end;
+
+IG:=0;
+DC := Canvas.Handle;
+MainRect:=clientRect;
+
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+Frame3d(Canvas, MainRect, FColorHighLight,FColorShadow,Fravno1);
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+
+DrawEdge(DC, MainRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE );
+
+end;
+i:=0;
+
+if (FGlyphHot.empty)then DrawGlyph;
+
+if (not FGlyphHot.empty)and (not FGlyph.empty) then
+begin
+if not enabled then
+DrawGlyph else DrawGlyphHot;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawFocus;
+end;
+DrawCaption;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+ begin
+ SetFocus;
+end;
+end;
+inherited MouseUp(Button, Shift, X, Y);
+end;
+
+
+
+procedure TPDJCustomButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
+ X, Y: Integer);
+ var
+ q: TPoint;
+Begin
+if Button<>mbleft then exit else begin
+if not enabled then exit;
+
+if FRepeatFunction then FStart.Enabled:=true;
+Fslovo:=0;
+IG:=1;
+
+DC := Canvas.Handle;
+MainRect:=clientRect;
+
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+Frame3d(Canvas, MainRect, FColorShadow,FColorHighLight,Fravno1);
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawEdge(DC, MainRect, BDR_SUNKENOUTER,BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE);
+end;
+i:=1;
+if (FGlyphHot.empty)then DrawGlyph;
+if (not FGlyphHot.empty)and (not FGlyph.empty) then
+begin
+if not enabled then
+DrawGlyph else DrawGlyphHot;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawFocus;
+end;
+DrawCaption;
+if FPopupMenu = nil then exit;
+ FPopupMenu.AutoPopup:= false;
+ // Add 20.11.2001.
+ FPopupMenu.PopupComponent:=TPDJButton(self);
+ q.X:= 0;
+ q.Y:= 0;
+ q:= ClientToScreen(q);
+
+Case FPositionPopup of
+puDown:
+begin
+ FPopupMenu.Alignment:=paLeft;
+ FPopupMenu.Popup(q.X - 1, q.Y + Height);
+end;
+puRight:
+begin
+ FPopupMenu.Alignment:=paLeft;
+ FPopupMenu.Popup(q.X+width+1, q.Y );
+end;
+puLeft:
+begin
+ FPopupMenu.Alignment:=paRight;
+ FPopupMenu.Popup(q.X-1, q.Y );
+end;
+end;
+
+
+DC := Canvas.Handle;
+MainRect:=clientRect;
+
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+Case FStyle of
+stFlat,stNone,stFlatDot:
+Frame3d(Canvas, MainRect, FColorShadow,FColorHighLight,0);
+stDefault,stFrameLowered,stFrameRaised:
+Frame3d(Canvas, MainRect,FColorHighLight ,FColorShadow,1);
+stRaised,stRaisedDot:
+Frame3d(Canvas, MainRect,FColorHighLight ,FColorShadow,2);
+end;
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawEdge(DC, MainRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE );
+end;
+IG:=0;
+DrawGlyph;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawFocus;
+end;
+Fslovo:=1;
+DrawCaption;
+
+if FRepeatFunction then begin
+ FRepeat.Enabled:=false;
+ FStart.Enabled:=false;
+end;
+
+i:=0;
+end;
+
+inherited MouseDown(Button, Shift, X, Y);
+end;
+
+procedure TPDJCustomButton.WMLButtonDblClk (var Message: TWMLButtonDown);
+begin
+ inherited;
+ Click;
+end;
+
+procedure TPDJCustomButton.CmTextChanged(var Message: TWmNoParams);
+begin
+ inherited;
+ Invalidate;
+end;
+
+procedure TPDJCustomButton.CmVisibleChanged(var Message: TWmNoParams);
+begin
+ inherited;
+ Invalidate;
+end;
+
+procedure TPDJCustomButton.CmParentColorChanged(var Message: TWMNoParams);
+begin
+ inherited;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised: Color :=clBtnFace; end;
+ if ParentColor then
+ Invalidate;
+end;
+
+procedure TPDJCustomButton.CMColorChanged(var Message: TMessage);
+begin
+ inherited;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised: Color :=clBtnFace; end;
+ if ParentColor then
+ Invalidate;
+end;
+
+procedure TPDJCustomButton.CMSysColorChange(var Message: TMessage);
+begin
+ inherited;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised: Color :=clBtnFace; end;
+ if ParentColor then
+ Invalidate;
+end;
+
+procedure TPDJCustomButton.CmEnabledChanged(var Message: TWmNoParams);
+begin
+ inherited;
+ if (not enabled) and (not (csDesigning in ComponentState)) then begin
+ IG:=0;
+ Fslovo:=1;
+DC := Canvas.Handle;
+MainRect:=clientRect;
+
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+Canvas.brush.color:=clBtnFace;
+ stFlat,stNone,stRaised,stFlatDot,stRaisedDot:
+ Canvas.brush.color:=color;
+ end;
+
+Frame3d(Canvas, MainRect, FColorHighLight,FColorShadow,Fravno1);
+Canvas.FillRect(MainRect);
+case FStyle of stFrameRaised:
+begin
+ inc(MainRect.left); inc(MainRect.top);dec(MainRect.right); dec(MainRect.bottom);
+end;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawEdge(DC, MainRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT or BF_TOPLEFT or BF_MIDDLE );
+end;
+i:=0;
+if (FGlyphHot.empty)then DrawGlyph;
+if (not FGlyphHot.empty)and (not FGlyph.empty) then
+begin
+if not enabled then
+DrawGlyph else DrawGlyphHot;
+end;
+ case FStyle of stDefault,stFrameLowered,stFrameRaised:
+DrawFocus;
+end;
+DrawCaption;
+end;
+ Invalidate;
+end;
+
+procedure TPDJCustomButton.CmParentFontChanged(var Message: TWMNoParams);
+begin
+ inherited;
+ Canvas.Font.Assign(Self.Font);
+ Invalidate;
+end;
+
+
+
+
+end.
Added: trunk/WPGM/Components/Pdjbutton.RES
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/Pdjbutton.RES
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Compilers.inc
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Compilers.inc 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Compilers.inc 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,269 @@
+//----------------------------------------------------------------------------------------------------------------------
+// Include file to determine which compiler is currently being used to build the project/component.
+// This file uses ideas from Brad Stowers DFS.inc file (www.delphifreestuff.com).
+//
+// Portions created by Mike Lischke are Copyright
+// (C) 1999-2002 Dipl. Ing. Mike Lischke. All Rights Reserved.
+//----------------------------------------------------------------------------------------------------------------------
+// The following symbols are defined:
+//
+// COMPILER_1 : Kylix/Delphi/BCB 1.x is the compiler.
+// COMPILER_1_UP : Kylix/Delphi/BCB 1.x or higher is the compiler.
+// COMPILER_2 : Kylix/Delphi 2.x or BCB 1.x is the compiler.
+// COMPILER_2_UP : Kylix/Delphi 2.x or higher, or BCB 1.x or higher is the compiler.
+// COMPILER_3 : Kylix/Delphi/BCB 3.x is the compiler.
+// COMPILER_3_UP : Kylix/Delphi/BCB 3.x or higher is the compiler.
+// COMPILER_4 : Kylix/Delphi/BCB 4.x is the compiler.
+// COMPILER_4_UP : Kylix/Delphi/BCB 4.x or higher is the compiler.
+// COMPILER_5 : Kylix/Delphi/BCB 5.x is the compiler.
+// COMPILER_5_UP : Kylix/Delphi/BCB 5.x or higher is the compiler.
+// COMPILER_6 : Kylix/Delphi/BCB 6.x is the compiler.
+// COMPILER_6_UP : Kylix/Delphi/BCB 6.x or higher is the compiler.
+// COMPILER_7 : Kylix/Delphi/BCB 7.x is the compiler.
+// COMPILER_7_UP : Kylix/Delphi/BCB 7.x or higher is the compiler.
+//
+// Only defined if Windows is the target:
+// CPPB : Any version of BCB is being used.
+// CPPB_1 : BCB v1.x is being used.
+// CPPB_3 : BCB v3.x is being used.
+// CPPB_3_UP : BCB v3.x or higher is being used.
+// CPPB_4 : BCB v4.x is being used.
+// CPPB_4_UP : BCB v4.x or higher is being used.
+// CPPB_5 : BCB v5.x is being used.
+// CPPB_5_UP : BCB v5.x or higher is being used.
+//
+// Only defined if Windows is the target:
+// DELPHI : Any version of Delphi is being used.
+// DELPHI_1 : Delphi v1.x is being used.
+// DELPHI_2 : Delphi v2.x is being used.
+// DELPHI_2_UP : Delphi v2.x or higher is being used.
+// DELPHI_3 : Delphi v3.x is being used.
+// DELPHI_3_UP : Delphi v3.x or higher is being used.
+// DELPHI_4 : Delphi v4.x is being used.
+// DELPHI_4_UP : Delphi v4.x or higher is being used.
+// DELPHI_5 : Delphi v5.x is being used.
+// DELPHI_5_UP : Delphi v5.x or higher is being used.
+// DELPHI_6 : Delphi v6.x is being used.
+// DELPHI_6_UP : Delphi v6.x or higher is being used.
+// DELPHI_7 : Delphi v7.x is being used.
+// DELPHI_7_UP : Delphi v7.x or higher is being used.
+//
+// Only defined if Linux is the target:
+// KYLIX : Any version of Kylix is being used.
+// KYLIX_1 : Kylix 1.x is being used.
+// KYLIX_1_UP : Kylix 1.x or higher is being used.
+// KYLIX_2 : Kylix 2.x is being used.
+// KYLIX_2_UP : Kylix 2.x or higher is being used.
+// KYLIX_3 : Kylix 3.x is being used.
+// KYLIX_3_UP : Kylix 3.x or higher is being used.
+//
+// Only defined if Linux is the target:
+// QT_CLX : Trolltech's QT library is being used.
+//----------------------------------------------------------------------------------------------------------------------
+
+{$ifdef Win32}
+ {$ifdef VER150}
+ {$define COMPILER_7}
+ {$define DELPHI}
+ {$define DELPHI_7}
+ {$endif}
+
+ {$ifdef VER140}
+ {$define COMPILER_6}
+ {$define DELPHI}
+ {$define DELPHI_6}
+ {$endif}
+
+ {$ifdef VER130}
+ {$define COMPILER_5}
+ {$ifdef BCB}
+ {$define CPPB}
+ {$define CPPB_5}
+ {$else}
+ {$define DELPHI}
+ {$define DELPHI_5}
+ {$endif}
+ {$endif}
+
+ {$ifdef VER125}
+ {$define COMPILER_4}
+ {$define CPPB}
+ {$define CPPB_4}
+ {$endif}
+
+ {$ifdef VER120}
+ {$define COMPILER_4}
+ {$define DELPHI}
+ {$define DELPHI_4}
+ {$endif}
+
+ {$ifdef VER110}
+ {$define COMPILER_3}
+ {$define CPPB}
+ {$define CPPB_3}
+ {$endif}
+
+ {$ifdef VER100}
+ {$define COMPILER_3}
+ {$define DELPHI}
+ {$define DELPHI_3}
+ {$endif}
+
+ {$ifdef VER93}
+ {$define COMPILER_2} // C++ Builder v1 compiler is really v2
+ {$define CPPB}
+ {$define CPPB_1}
+ {$endif}
+
+ {$ifdef VER90}
+ {$define COMPILER_2}
+ {$define DELPHI}
+ {$define DELPHI_2}
+ {$endif}
+
+ {$ifdef VER80}
+ {$define COMPILER_1}
+ {$define DELPHI}
+ {$define DELPHI_1}
+ {$endif}
+
+ {$ifdef DELPHI_2}
+ {$define DELPHI_2_UP}
+ {$endif}
+
+ {$ifdef DELPHI_3}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$endif}
+
+ {$ifdef DELPHI_4}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$endif}
+
+ {$ifdef DELPHI_5}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$define DELPHI_5_UP}
+ {$endif}
+
+ {$ifdef DELPHI_6}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$define DELPHI_5_UP}
+ {$define DELPHI_6_UP}
+ {$endif}
+
+ {$ifdef DELPHI_7}
+ {$define DELPHI_2_UP}
+ {$define DELPHI_3_UP}
+ {$define DELPHI_4_UP}
+ {$define DELPHI_5_UP}
+ {$define DELPHI_6_UP}
+ {$define DELPHI_7_UP}
+ {$endif}
+
+ {$ifdef CPPB_3}
+ {$define CPPB_3_UP}
+ {$endif}
+
+ {$ifdef CPPB_4}
+ {$define CPPB_3_UP}
+ {$define CPPB_4_UP}
+ {$endif}
+
+ {$ifdef CPPB_5}
+ {$define CPPB_3_UP}
+ {$define CPPB_4_UP}
+ {$define CPPB_5_UP}
+ {$endif}
+
+ {$ifdef CPPB_3_UP}
+ // C++ Builder requires this if you use Delphi components in run-time packages.
+ {$ObjExportAll On}
+ {$endif}
+
+{$else (not Windows)}
+ // Linux is the target
+ {$define QT_CLX}
+
+ {$define KYLIX}
+ {$define KYLIX_1}
+ {$define KYLIX_1_UP}
+
+ {$ifdef VER150}
+ {$define COMPILER_7}
+ {$define KYLIX_3}
+ {$endif}
+
+ {$ifdef VER140}
+ {$define COMPILER_6}
+ {$define KYLIX_2}
+ {$endif}
+
+ {$ifdef KYLIX_2}
+ {$define KYLIX_2_UP}
+ {$endif}
+
+ {$ifdef KYLIX_3}
+ {$define KYLIX_2_UP}
+ {$define KYLIX_3_UP}
+ {$endif}
+
+{$endif}
+
+// Compiler defines common to all platforms.
+{$ifdef COMPILER_1}
+ {$define COMPILER_1_UP}
+{$endif}
+
+{$ifdef COMPILER_2}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+{$endif}
+
+{$ifdef COMPILER_3}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+{$endif}
+
+{$ifdef COMPILER_4}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+{$endif}
+
+{$ifdef COMPILER_5}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+ {$define COMPILER_5_UP}
+{$endif}
+
+{$ifdef COMPILER_6}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+ {$define COMPILER_5_UP}
+ {$define COMPILER_6_UP}
+{$endif}
+
+{$ifdef COMPILER_7}
+ {$define COMPILER_1_UP}
+ {$define COMPILER_2_UP}
+ {$define COMPILER_3_UP}
+ {$define COMPILER_4_UP}
+ {$define COMPILER_5_UP}
+ {$define COMPILER_6_UP}
+ {$define COMPILER_7_UP}
+{$endif}
+
+//----------------------------------------------------------------------------------------------------------------------
+
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Advanced.dpr
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Advanced.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Advanced.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,28 @@
+program Advanced;
+
+{$R 'Res\ExtraRes.res' 'Res\ExtraRes.rc'}
+
+uses
+ Forms,
+ SpeedDemo in 'SpeedDemo.pas' {SpeedForm},
+ DrawTreeDemo in 'DrawTreeDemo.pas' {DrawTreeForm},
+ GeneralAbilitiesDemo in 'GeneralAbilitiesDemo.pas' {frmGeneralAbilities},
+ PropertiesDemo in 'PropertiesDemo.pas' {PropertiesForm},
+ GridDemo in 'GridDemo.pas' {GridForm},
+ Editors in 'Editors.pas',
+ VisibilityDemo in 'VisibilityDemo.pas' {VisibilityForm},
+ AlignDemo in 'AlignDemo.pas' {AlignForm},
+ Main in 'Main.pas' {MainForm},
+ WindowsXPStyleDemo in 'WindowsXPStyleDemo.pas' {WindowsXPForm},
+ NodeDemo in 'NodeDemo.pas' {NodeForm},
+ HeaderCustomDrawDemo in 'HeaderCustomDrawDemo.pas' {HeaderOwnerDrawForm},
+ States in 'States.pas' {StateForm};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TMainForm, MainForm);
+ Application.CreateForm(TStateForm, StateForm);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Advanced.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Advanced.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/AlignDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/AlignDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/AlignDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/AlignDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/AlignDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,614 @@
+unit AlignDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - Header with images and different glyph and column alignment.
+// - Header popup with images.
+// - Multilingual treeview with english, greek, hebrew and arabic texts.
+// - Interaction between column alignment and column directionality (bidi).
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, Buttons, VirtualTrees, ComCtrls, ExtCtrls, ImgList, Menus;
+
+type
+ TAlignForm = class(TForm)
+ AlignTree: TVirtualStringTree;
+ Label8: TLabel;
+ TreeImages: TImageList;
+ HeaderImages: TImageList;
+ IconPopup: TPopupMenu;
+ Label1: TLabel;
+ AlignCombo0: TComboBox;
+ Label2: TLabel;
+ Label3: TLabel;
+ AlignCombo1: TComboBox;
+ Label4: TLabel;
+ AlignCombo2: TComboBox;
+ BidiGroup0: TRadioGroup;
+ BidiGroup1: TRadioGroup;
+ BidiGroup2: TRadioGroup;
+ GroupBox1: TGroupBox;
+ ShowGlyphsOptionBox: TCheckBox;
+ HotTrackOptionBox: TCheckBox;
+ ShowTextOptionBox: TCheckBox;
+ VisibleOptionBox: TCheckBox;
+ EnabledOptionBox: TCheckBox;
+ Label5: TLabel;
+ LayoutCombo: TComboBox;
+ procedure AlignTreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer);
+ procedure AlignTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure AlignTreePaintText(Sender: TBaseVirtualTree; const Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType);
+ procedure AlignTreeGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
+ procedure AlignTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure AlignTreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure IconPopupPopup(Sender: TObject);
+ procedure AlignComboChange(Sender: TObject);
+ procedure BidiGroupClick(Sender: TObject);
+ procedure AlignTreeHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+ procedure OptionBoxClick(Sender: TObject);
+ procedure LayoutComboChange(Sender: TObject);
+ procedure AlignTreeFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
+ procedure AlignTreeStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+ private
+ FArabicFont,
+ FHebrewFont: TFont;
+ procedure ChangeHeaderText;
+ procedure MeasureIconItem(Sender: TObject; ACanvas: TCanvas; var Width, Height: Integer);
+ procedure MenuItemClick(Sender: TObject);
+ end;
+
+var
+ AlignForm: TAlignForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ Main, States;
+
+{$R *.DFM}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+const
+ DefaultHintColumn0 = 'Text is initially centered and has a left-to-right directionality.';
+ DefaultHintColumn1 = 'Text is initially left aligned and has a left-to-right directionality.';
+ DefaultHintColumn2 = 'Text is initially left aligned and has a right-to-left directionality.';
+ CommonHeaderHint = 'Right click to pick a column glyph. Left click to switch sort glyph (no sorting is performed).';
+
+type
+ PAlignData = ^TAlignData;
+ TAlignData = record
+ MainColumnText,
+ GreekText,
+ RTLText: WideString;
+ ImageIndex: Integer;
+ end;
+
+// These arrays store some text which is originally displayed right-to-left, so it supports the demonstration of
+// alignment even more than normal text. This text will be filled at runtime from a resource file.
+// Additionally, some greek text for another column is stored here too just because I like how it looks (the text,
+// not the storage ;-)).
+var
+ GreekStrings: array[0..8] of WideString;
+ ArabicStrings: array[0..3] of WideString;
+ HebrewStrings: array[0..2] of WideString;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure LoadStrings;
+
+// Helper routine to load Unicode strings from the resource. Putting these strings directly into the
+// source code does not work, since Delphi does not support Unicode source code.
+
+begin
+ // Take the first arabic string as identification whether we have already loaded the strings or not.
+ if Length(ArabicStrings[0]) = 0 then
+ begin
+ LoadUnicodeStrings('Greek', GreekStrings);
+ LoadUnicodeStrings('Arabic', ArabicStrings);
+ LoadUnicodeStrings('Hebrew', HebrewStrings);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreeGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
+
+// Node data size can also be set at design time (if you know the size of the record) or in FormCreate.
+// We do it here just because to show this third way too.
+
+begin
+ NodeDataSize := SizeOf(TAlignData);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreePaintText(Sender: TBaseVirtualTree; const Canvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType);
+
+begin
+ // In order to display arabic and hebrew texts with a nice font we have assign one explicitely. Otherwise the
+ // system picks one and this often leads to non-ideal results.
+ case Column of
+ 1:
+ // Make the second column lighter.
+ Canvas.Font.Color := clSilver;
+ 2:
+ begin
+ if not Odd(Node.Parent.Index) then
+ Canvas.Font := FArabicFont
+ else
+ Canvas.Font := FHebrewFont;
+ end;
+ end;
+
+ // Reset the text color for selected and drop target nodes.
+ if ((Node = Sender.DropTargetNode) or (vsSelected in Node.States)) and (Column = Sender.FocusedColumn) then
+ Canvas.Font.Color := clHighlightText;
+ if Node.Parent = Sender.RootNode then
+ Canvas.Font.Style := [fsBold];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+
+var
+ Data: PAlignData;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ Text := '';
+ case Column of
+ 0: // left alignd column
+ Text := Data.MainColumnText;
+ 1: // centered column
+ Text := Data.GreekText;
+ 2: // right aligned column
+ Text := Data.RTLText;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
+ Column: TColumnIndex; var Ghosted: Boolean; var Index: Integer);
+
+var
+ Data: PAlignData;
+
+begin
+ if Kind in [ikNormal, ikSelected] then
+ begin
+ Data := Sender.GetNodeData(Node);
+ Index := Data.ImageIndex;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+var
+ Data: PAlignData;
+
+begin
+ // intialize caption strings
+ LoadStrings;
+
+ Data := Sender.GetNodeData(Node);
+
+ Data.ImageIndex := 0;
+ if ParentNode = nil then
+ begin
+ with Data^ do
+ begin
+ if not Odd(Node.Index) then
+ MainColumnText := 'Arabic texts'
+ else
+ MainColumnText := 'Hebrew texts';
+
+ GreekText := GreekStrings[(Node.Index and 1) * 5];
+ RTLText := '';
+ end;
+ InitialStates := InitialStates + [ivsHasChildren, ivsExpanded];
+ end
+ else
+ begin
+ if not Odd(ParentNode.Index) then
+ begin
+ with Data^ do
+ begin
+ MainColumnText := Format('Arabic text %d', [Node.Index]);
+ GreekText := GreekStrings[Node.Index + 1];
+ RTLText := ArabicStrings[Node.Index];
+ end;
+ end
+ else
+ begin
+ with Data^ do
+ begin
+ MainColumnText := Format('Hebrew text %d', [Node.Index]);
+ GreekText := GreekStrings[6 + Node.Index];
+ RTLText := HebrewStrings[Node.Index];
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+
+begin
+ if not Odd(Node.Index) then
+ ChildCount := 4 // arabic text
+ else
+ ChildCount := 3; // hebrew text
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.FormCreate(Sender: TObject);
+
+var
+ I: Integer;
+ NewItem: TMenuItem;
+
+begin
+ // High color image lists look much better.
+ ConvertToHighColor(TreeImages);
+ ConvertToHighColor(HeaderImages);
+
+ // To display the various texts in a nice manner we use some specialized fonts of the system.
+ // We could directly assign the font names used here in the OnPaintText event, but since this
+ // would then be the only reference for the font it would cause the font to be recreated every
+ // time it is used (a font is reference counted in Graphics.pas). In order to avoid this overhead
+ // it is better to create the fonts once and for all.
+ // Note: if the fonts used here are not installed on the target system then the font mapper of Windows
+ // will pick similar fonts which are capable of rendering the required glyphs (however Arial and Times New Roman
+ // should be available on any Windows system).
+ FArabicFont := TFont.Create;
+ with FArabicFont do
+ begin
+ if Screen.Fonts.IndexOf('Traditional Arabic') > -1 then
+ begin
+ Name := 'Traditional Arabic';
+ Size := 20;
+ end
+ else
+ begin
+ Name := 'Arial';
+ Size := 14;
+ end;
+ Color := $FF6B43;
+ if Handle = 0 then
+ Beep;
+ end;
+ FHebrewFont := TFont.Create;
+ with FHebrewFont do
+ begin
+ Name := 'Times New Roman';
+ Size := 14;
+ Color := $436BFF;
+ end;
+
+ // To demonstrate header clicks together with the header menu a glyph picker menu is provided.
+ with IconPopup do
+ begin
+ for I := 0 to HeaderImages.Count - 1 do
+ begin
+ NewItem := TMenuItem.Create(Self);
+ NewItem.Caption := '';
+ NewItem.ImageIndex := I;
+ NewItem.RadioItem := True;
+ NewItem.OnClick := MenuItemClick;
+ if (I mod 10) = 0 then
+ NewItem.Break := mbBreak;
+ NewItem.OnMeasureItem := MeasureIconItem;
+ Items.Add(NewItem);
+ end;
+ end;
+
+ // Add some additional info to the column hints. This can only be done in code as the object inspector does not
+ // allow to enter multiline strings (it does not allow to edit wide strings correctly at all).
+ with AlignTree.Header do
+ begin
+ Columns[0].Hint := DefaultHintColumn0 + #13 + CommonHeaderHint;
+ Columns[1].Hint := DefaultHintColumn1 + #13 + CommonHeaderHint;
+ Columns[2].Hint := DefaultHintColumn2 + #13 + CommonHeaderHint;
+ end;
+
+ // Set up the initial values of the alignment and bidi-mode pickers as well as layout and options.
+ with AlignTree.Header do
+ begin
+ // Alignment and bidi
+ AlignCombo0.ItemIndex := Ord(Columns[0].Alignment);
+ BidiGroup0.ItemIndex := Ord(Columns[0].BidiMode <> bdLeftToRight);
+ AlignCombo1.ItemIndex := Ord(Columns[1].Alignment);
+ BidiGroup1.ItemIndex := Ord(Columns[1].BidiMode <> bdLeftToRight);
+ AlignCombo2.ItemIndex := Ord(Columns[2].Alignment);
+ BidiGroup2.ItemIndex := Ord(Columns[2].BidiMode <> bdLeftToRight);
+
+ // Button layout
+ LayoutCombo.ItemIndex := Ord(Columns[0].Layout);
+ if not (hoShowImages in Options) then
+ Height := 24
+ else
+ if Columns[0].Layout in [blGlyphTop, blGlyphBottom] then
+ Height := 64
+ else
+ Height := 40;
+
+ // Options
+ ShowGlyphsOptionBox.Checked := hoShowImages in Options;
+ HotTrackOptionBox.Checked := hoHotTrack in Options;
+ ShowTextOptionBox.Checked := True;
+ ChangeHeaderText;
+ VisibleOptionBox.Checked := hoVisible in Options;
+ EnabledOptionBox.Checked := coEnabled in Columns[0].Options;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.FormDestroy(Sender: TObject);
+
+begin
+ FArabicFont.Free;
+ FHebrewFont.Free;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.ChangeHeaderText;
+
+// Sets or clears the text of all columns depending on the state of SetTextOptionBox.
+
+begin
+ with AlignTree.Header do
+ if ShowTextOptionBox.Checked then
+ begin
+ Columns[0].Text := 'English text column';
+ Columns[1].Text := 'Greek text column';
+ Columns[2].Text := 'Hebrew/arabic text column';
+ end
+ else
+ begin
+ Columns[0].Text := '';
+ Columns[1].Text := '';
+ Columns[2].Text := '';
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.MeasureIconItem(Sender: TObject; ACanvas: TCanvas; var Width, Height: Integer);
+
+// Used to tell the popup menu how large it is. I don't want menu item captions so the menu item size is
+// made as small as possible here.
+
+begin
+ // The icons are 32 bits wide but some extra space will be added implicitely.
+ Width := 24;
+ Height := 36;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.MenuItemClick(Sender: TObject);
+
+// During the the right click on the header the clicked column is recorded in Tree.Header.Columns.ClickIndex.
+// We can use this information to determine to which column the new image index must be assigned.
+
+var
+ Index: Integer;
+
+begin
+ with AlignTree.Header do
+ begin
+ Index := Columns.ClickIndex;
+ if Index > NoColumn then
+ begin
+ (Sender as TMenuItem).Checked := True;
+ Columns[Index].ImageIndex := (Sender as TMenuItem).ImageIndex;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.IconPopupPopup(Sender: TObject);
+
+// Mark the selected image before presenting the popup to the user.
+
+var
+ Index: Integer;
+
+begin
+ with AlignTree.Header do
+ begin
+ Index := Columns.ClickIndex;
+ if Index > NoColumn then
+ (Sender as TPopupMenu).Items[Columns[Index].ImageIndex].Checked := True;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignComboChange(Sender: TObject);
+
+begin
+ with Sender as TComboBox do
+ case Tag of
+ 0:
+ AlignTree.Header.Columns[0].Alignment := TAlignment(AlignCombo0.ItemIndex);
+ 1:
+ AlignTree.Header.Columns[1].Alignment := TAlignment(AlignCombo1.ItemIndex);
+ 2:
+ AlignTree.Header.Columns[2].Alignment := TAlignment(AlignCombo2.ItemIndex);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.BidiGroupClick(Sender: TObject);
+
+begin
+ with Sender as TRadioGroup do
+ case Tag of
+ 0:
+ AlignTree.Header.Columns[0].BidiMode := TBidiMode(BidiGroup0.ItemIndex);
+ 1:
+ AlignTree.Header.Columns[1].BidiMode := TBidiMode(BidiGroup1.ItemIndex);
+ 2:
+ AlignTree.Header.Columns[2].BidiMode := TBidiMode(BidiGroup2.ItemIndex);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreeHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState;
+ X, Y: Integer);
+
+// This method sets sort column and direction on a header click.
+// Note: this is only to show the header layout. There gets nothing really sorted.
+
+begin
+ if Button = mbLeft then
+ begin
+ with Sender do
+ begin
+ if SortColumn <> Column then
+ begin
+ SortColumn := Column;
+ SortDirection := sdAscending;
+ end
+ else
+ case SortDirection of
+ sdAscending:
+ SortDirection := sdDescending;
+ sdDescending:
+ SortColumn := NoColumn;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.OptionBoxClick(Sender: TObject);
+
+var
+ I: Integer;
+
+begin
+ with Sender as TCheckBox, AlignTree.Header do
+ case Tag of
+ 0:
+ if Checked then
+ begin
+ Options := Options + [hoShowImages];
+ if Columns[0].Layout in [blGlyphTop, blGlyphBottom] then
+ Height := 64
+ else
+ Height := 40;
+ end
+ else
+ begin
+ Options := Options - [hoShowImages];
+ Height := 24;
+ end;
+ 1:
+ if Checked then
+ Options := Options + [hoHotTrack]
+ else
+ Options := Options - [hoHotTrack];
+ 2:
+ ChangeHeaderText;
+ 3:
+ if Checked then
+ Options := Options + [hoVisible]
+ else
+ Options := Options - [hoVisible];
+ 4:
+ for I := 0 to Columns.Count - 1 do
+ if Checked then
+ Columns[I].Options := Columns[I].Options + [coEnabled]
+ else
+ Columns[I].Options := Columns[I].Options - [coEnabled];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.LayoutComboChange(Sender: TObject);
+
+var
+ I: Integer;
+
+begin
+ with Sender as TComboBox, AlignTree.Header do
+ begin
+ for I := 0 to Columns.Count - 1 do
+ Columns[I].Layout := TVTHeaderColumnLayout(ItemIndex);
+
+ if not (hoShowImages in Options) then
+ Height := 24
+ else
+ if Columns[0].Layout in [blGlyphTop, blGlyphBottom] then
+ Height := 64
+ else
+ Height := 40;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreeFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex);
+
+const
+ FocusedText = #13'Text of focused node is: ';
+
+var
+ Data: PAlignData;
+
+begin
+ if Assigned(Node) then
+ begin
+ Data := Sender.GetNodeData(Node);
+ with AlignTree.Header do
+ begin
+ Columns[0].Hint := DefaultHintColumn0 + #13 + CommonHeaderHint + FocusedText + Data.MainColumnText;
+ Columns[1].Hint := DefaultHintColumn1 + #13 + CommonHeaderHint + FocusedText + Data.GreekText;
+ Columns[2].Hint := DefaultHintColumn2 + #13 + CommonHeaderHint + FocusedText + Data.RTLText;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TAlignForm.AlignTreeStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/DrawTreeDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/DrawTreeDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/DrawTreeDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/DrawTreeDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/DrawTreeDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,745 @@
+unit DrawTreeDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - General use of TVirtualDrawTree.
+// - Use of vertical node image alignment.
+// - Effective use of node initialization on demand to load images.
+// Written by Mike Lischke.
+//
+// Note: define the symbol "GraphicEx" if you have my GraphicEx library
+// available (see http://www.delphi-gems.com) which allows to load
+// more image formats into the application.
+// Otherwise disable the conditional symbol to compile this demo.
+
+{.$define GraphicEx}
+
+{$ifdef VER140}
+ {$define RemoveWarnings}
+{$endif VER140}
+{$ifdef VER150}
+ {$define RemoveWarnings}
+{$endif VER150}
+
+{$ifdef RemoveWarnings}
+ // We do not need warnings for platform specific stuff.
+ {$warn UNIT_PLATFORM OFF}
+ {$warn SYMBOL_PLATFORM OFF}
+{$endif}
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ VirtualTrees, StdCtrls, {$ifdef GraphicEx} GraphicEx, {$else} JPEG, {$endif}
+ ImgList, ComCtrls;
+
+type
+ TDrawTreeForm = class(TForm)
+ VDT1: TVirtualDrawTree;
+ Label7: TLabel;
+ SystemImages: TImageList;
+ Label1: TLabel;
+ TrackBar1: TTrackBar;
+ Label3: TLabel;
+ procedure FormCreate(Sender: TObject);
+ procedure VDT1CompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex;
+ var Result: Integer);
+ procedure VDT1DrawHint(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; R: TRect; Column: TColumnIndex);
+ procedure VDT1DrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
+ procedure VDT1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure VDT1GetHintSize(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var R: TRect);
+ procedure VDT1GetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer);
+ procedure VDT1GetNodeWidth(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ var NodeWidth: Integer);
+ procedure VDT1HeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+ procedure VDT1InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+ procedure VDT1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure TrackBar1Change(Sender: TObject);
+ procedure VDT1StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+ private
+ FThumbSize: Integer;
+ FExtensionsInitialized: Boolean;
+ FExtensionList: TStringList;
+ FDriveStrings: string;
+ function CanDisplay(const Name: String): Boolean;
+ function GetDriveString(Index: Integer): string;
+ function ReadAttributes(const Name: WideString): Cardinal;
+ procedure RescaleImage(Source, Target: TBitmap);
+ end;
+
+var
+ DrawTreeForm: TDrawTreeForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ FileCtrl, ShellAPI, Mask, ShlObj, ActiveX, States;
+
+{$R *.DFM}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ // This data record contains all necessary information about a particular file system object.
+ // This can either be a folder (virtual or real) or an image file.
+ PShellObjectData = ^TShellObjectData;
+ TShellObjectData = record
+ FullPath,
+ Display: WideString;
+ Attributes: Cardinal;
+ OpenIndex,
+ CloseIndex: Integer; // image indices into the system image list
+ Image: TBitmap;
+ Properties: WideString; // some image properties, preformatted
+ end;
+
+//----------------- utility functions ----------------------------------------------------------------------------------
+
+function IncludeTrailingBackslash(const S: string): string;
+
+begin
+ if not IsPathDelimiter(S, Length(S)) then
+ Result := S + '\'
+ else
+ Result := S;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function ExcludeTrailingBackslash(const S: string): string;
+
+begin
+ Result := S;
+ if IsPathDelimiter(Result, Length(Result)) then
+ SetLength(Result, Length(Result) - 1);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function HasChildren(const Folder: string): Boolean;
+
+// Determines whether folder contains other file objects.
+
+var
+ SR: TSearchRec;
+
+begin
+ Result := FindFirst(IncludeTrailingBackslash(Folder) + '*.*', faReadOnly or faHidden or faSysFile or faArchive, SR) = 0;
+ if Result then
+ FindClose(SR);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function GetIconIndex(Name: string; Flags: Cardinal): Integer;
+
+// Returns the index of the system icon for the given file object.
+
+var
+ SFI: TSHFileInfo;
+
+begin
+ if SHGetFileInfo(PChar(Name), 0, SFI, SizeOf(TSHFileInfo), Flags) = 0 then
+ Result := -1
+ else
+ Result := SFI.iIcon;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure GetOpenAndClosedIcons(Name: string; var Open, Closed: Integer);
+
+begin
+ Closed := GetIconIndex(Name, SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
+ Open := GetIconIndex(Name, SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_OPENICON);
+end;
+
+//----------------- TDrawTreeForm --------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.FormCreate(Sender: TObject);
+
+var
+ SFI: TSHFileInfo;
+ I,
+ Count: Integer;
+ DriveMap,
+ Mask: Cardinal;
+
+begin
+ VDT1.NodeDataSize := SizeOf(TShellObjectData);
+
+ // Fill root level of image tree. Determine which drives are mapped.
+ Count := 0;
+ DriveMap := GetLogicalDrives;
+ Mask := 1;
+ for I := 0 to 25 do
+ begin
+ if (DriveMap and Mask) <> 0 then
+ Inc(Count);
+ Mask := Mask shl 1;
+ end;
+ VDT1.RootNodeCount := Count;
+ // Determine drive strings which are used in the initialization process.
+ Count := GetLogicalDriveStrings(0, nil);
+ SetLength(FDriveStrings, Count);
+ GetLogicalDriveStrings(Count, PChar(FDriveStrings));
+
+ SystemImages.Handle := SHGetFileInfo('', 0, SFI, SizeOf(SFI), SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
+ SystemImages.ShareImages := True;
+
+ FThumbSize := 100;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TDrawTreeForm.CanDisplay(const Name: string): Boolean;
+
+// Determines whether the given file is one we can display in the image tree.
+
+var
+ Ext: string;
+ I: Integer;
+
+begin
+ if not FExtensionsInitialized then
+ begin
+ FExtensionsInitialized := True;
+ FExtensionList := TStringList.Create;
+ {$ifdef GraphicEx}
+ FileFormatList.GetExtensionList(FExtensionList);
+ for I := 0 to FExtensionList.Count - 1 do
+ FExtensionList[I] := '.' + FExtensionList[I];
+ {$else}
+ // GraphicEx is not used so add some default extensions
+ with FExtensionList do
+ begin
+ Add('.bmp');
+ Add('.ico');
+ Add('.jpg');
+ Add('.jpeg');
+ Add('.wmf');
+ Add('.emf');
+ end;
+ {$endif}
+ FExtensionList.Sort;
+ end;
+
+ Ext := ExtractFileExt(Name);
+ Result := FExtensionList.Find(Ext, I);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TDrawTreeForm.GetDriveString(Index: Integer): string;
+
+// Helper method to extract a sub string (given by Index) from FDriveStrings.
+
+var
+ Head, Tail: PChar;
+
+begin
+ Head := PChar(FDriveStrings);
+ Result := '';
+ repeat
+ Tail := Head;
+ while Tail^ <> #0 do
+ Inc(Tail);
+ if Index = 0 then
+ begin
+ SetString(Result, Head, Tail - Head);
+ Break;
+ end;
+ Dec(Index);
+ Head := Tail + 1;
+ until Head^ = #0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TDrawTreeForm.ReadAttributes(const Name: WideString): Cardinal;
+
+// Determines the attributes of the given shell object (file, folder).
+
+const
+ SFGAO_CONTENTSMASK = $F0000000; // This value is wrongly defined in ShlObj.
+
+var
+ Desktop: IShellFolder;
+ Eaten: Cardinal;
+ PIDL: PItemIDList;
+ Malloc: IMalloc;
+
+begin
+ // Get the root folder of the shell name space.
+ SHGetDesktopFolder(Desktop);
+ // While parsing the name also the shell object's attributes are determined.
+ // These is what we are really interested in.
+ Result := SFGAO_DISPLAYATTRMASK or SFGAO_CONTENTSMASK or SFGAO_COMPRESSED;
+ Desktop.ParseDisplayName(0, nil, PWideChar(Name), Eaten, PIDL, Result);
+ // Don't forget to free the returned PIDL. The shell folder is released automatically.
+ SHGetMalloc(Malloc);
+ Malloc.Free(PIDL);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.RescaleImage(Source, Target: TBitmap);
+
+// if source is in at least one dimension larger than the thumb size then
+// rescale source but keep aspect ratio
+
+var
+ NewWidth,
+ NewHeight: Integer;
+begin
+ if (Source.Width > FThumbSize) or (Source.Height > FThumbSize) then
+ begin
+ if Source.Width > Source.Height then
+ begin
+ NewWidth := FThumbSize;
+ NewHeight := Round(FThumbSize * Source.Height / Source.Width);
+ end
+ else
+ begin
+ NewHeight := FThumbSize;
+ NewWidth := Round(FThumbSize * Source.Width / Source.Height);
+ end;
+
+ Target.Width := NewWidth;
+ Target.Height := NewHeight;
+ SetStretchBltMode(Target.Canvas.Handle, HALFTONE);
+ StretchBlt(Target.Canvas.Handle, 0, 0, NewWidth, NewHeight,
+ Source.Canvas.Handle, 0, 0, Source.Width, Source.Height, SRCCOPY);
+ end
+ else
+ Target.Assign(Source);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+var
+ Data: PShellObjectData;
+ Picture: TPicture;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ if ParentNode = nil then
+ begin
+ // top level node, initialize first enumeration
+ Data.FullPath := GetDriveString(Node.Index);
+ Data.Display := Data.FullPath;
+ GetOpenAndClosedIcons(Data.FullPath, Data.OpenIndex, Data.CloseIndex);
+ end
+ else
+ begin
+ Picture := TPicture.Create;
+ Data.Display := ExtractFileName(ExcludeTrailingBackslash(Data.FullPath));
+ if (Data.Attributes and SFGAO_FOLDER) = 0 then
+ try
+ try
+ Data.Image := TBitmap.Create;
+ Picture.LoadFromFile(Data.FullPath);
+ if not (Picture.Graphic is TBitmap) then
+ begin
+ // Some extra steps needed to keep non TBitmap descentants alive when
+ // scaling. This is needed because when accessing Picture.Bitmap all
+ // non-TBitmap content will simply be erased (definitly the wrong
+ // action, but we can't do anything to prevent this). Hence we
+ // must explicitly draw the graphic to a bitmap.
+ with Data.Image do
+ begin
+ Width := Picture.Width;
+ Height := Picture.Height;
+ Canvas.Draw(0, 0, Picture.Graphic);
+ end;
+ Picture.Bitmap.Assign(Data.Image);
+ end;
+ RescaleImage(Picture.Bitmap, Data.Image);
+
+ // Collect some additional image properties.
+ Data.Properties := Data.Properties + Format('%d x %d pixels', [Picture.Width, Picture.Height]);
+ case Picture.Bitmap.PixelFormat of
+ pf1bit:
+ Data.Properties := Data.Properties + ', 2 colors';
+ pf4bit:
+ Data.Properties := Data.Properties + ', 16 colors';
+ pf8bit:
+ Data.Properties := Data.Properties + ', 256 colors';
+ pf15bit:
+ Data.Properties := Data.Properties + ', 32K colors';
+ pf16bit:
+ Data.Properties := Data.Properties + ', 64K colors';
+ pf24bit:
+ Data.Properties := Data.Properties + ', 16M colors';
+ pf32bit:
+ Data.Properties := Data.Properties + ', 16M+ colors';
+ end;
+ if Cardinal(Data.Image.Height) + 4 > TVirtualDrawTree(Sender).DefaultNodeHeight then
+ Sender.NodeHeight[Node] := Data.Image.Height + 4;
+ except
+ Data.Image.Free;
+ Data.Image := nil;
+ end;
+ finally
+ Picture.Free;
+ end;
+ end;
+ Data.Attributes := ReadAttributes(Data.FullPath);
+ if ((Data.Attributes and SFGAO_HASSUBFOLDER) <> 0) or
+ (((Data.Attributes and SFGAO_FOLDER) <> 0) and HasChildren(Data.FullPath)) then
+ Include(InitialStates, ivsHasChildren);
+
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
+
+var
+ Data: PShellObjectData;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ Data.Image.Free;
+ Finalize(Data^); // Clear string data.
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1DrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
+
+// This is the main paint routine for a node in a draw tree. There is nothing special here. Demonstrating the
+// specific features of a draw tree (compared to the string tree) is a bit difficult, since the only difference is
+// that the draw tree does not handle node content (captions in the case of the string tree).
+
+var
+ Data: PShellObjectData;
+ X: Integer;
+ S: WideString;
+ R: TRect;
+
+begin
+ with Sender as TVirtualDrawTree, PaintInfo do
+ begin
+ Data := Sender.GetNodeData(Node);
+ if (Column = FocusedColumn) and (Node = FocusedNode) then
+ Canvas.Font.Color := clHighlightText
+ else
+ if (Data.Attributes and SFGAO_COMPRESSED) <> 0 then
+ Canvas.Font.Color := clBlue
+ else
+ Canvas.Font.Color := clWindowText;
+
+ SetBKMode(Canvas.Handle, TRANSPARENT);
+
+ R := ContentRect;
+ InflateRect(R, -TextMargin, 0);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ S := '';
+ case Column of
+ 0, 2:
+ begin
+ if Column = 2 then
+ begin
+ if Assigned(Data.Image) then
+ S:= Data.Properties;
+ end
+ else
+ S := Data.Display;
+ if Length(S) > 0 then
+ begin
+ with R do
+ begin
+ if (NodeWidth - 2 * Margin) > (Right - Left) then
+ S := ShortenString(Canvas.Handle, S, Right - Left, False);
+ end;
+ DrawTextW(Canvas.Handle, PWideChar(S), Length(S), R, DT_TOP or DT_LEFT or DT_VCENTER or DT_SINGLELINE, False);
+ end;
+ end;
+ 1:
+ begin
+ if Assigned(Data.Image) then
+ begin
+ X := ContentRect.Left + (VDT1.Header.Columns[1].Width - Data.Image.Width - Margin) div 2;
+ BitBlt(Canvas.Handle, X, ContentRect.Top + 2, Data.Image.Width, Data.Image.Height, Data.Image.Canvas.Handle,
+ 0, 0, SRCCOPY);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1GetNodeWidth(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ var NodeWidth: Integer);
+
+// Since the draw tree does not know what is in a cell, we have to return the width of the content (not the entire
+// cell width, this could be determined by the column width).
+
+var
+ Data: PShellObjectData;
+ AMargin: Integer;
+
+begin
+ with Sender as TVirtualDrawTree do
+ AMargin := TextMargin;
+
+ begin
+ Data := Sender.GetNodeData(Node);
+ case Column of
+ 0:
+ begin
+ if Node.Parent = Sender.RootNode then
+ NodeWidth := Canvas.TextWidth(Data.FullPath) + 2 * AMargin
+ else
+ NodeWidth := Canvas.TextWidth(ExtractFileName(Data.FullPath)) + 2 * AMargin;
+ end;
+ 1:
+ begin
+ if Assigned(Data.Image) then
+ NodeWidth := Data.Image.Width;
+ end;
+ 2:
+ NodeWidth := Canvas.TextWidth(Data.Properties) + 2 * AMargin;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+
+// Called just before a node with children (only folder nodes can have children) is expanded.
+
+var
+ Data,
+ ChildData: PShellObjectData;
+ SR: TSearchRec;
+ ChildNode: PVirtualNode;
+ NewName: String;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ if FindFirst(IncludeTrailingBackslash(Data.FullPath) + '*.*', faAnyFile, SR) = 0 then
+ begin
+ Screen.Cursor := crHourGlass;
+ try
+ repeat
+ if (SR.Name <> '.') and (SR.Name <> '..') then
+ begin
+ NewName := IncludeTrailingBackslash(Data.FullPath) + SR.Name;
+ if (SR.Attr and faDirectory <> 0) or CanDisplay(NewName) then
+ begin
+ ChildNode := Sender.AddChild(Node);
+ ChildData := Sender.GetNodeData(ChildNode);
+ ChildData.FullPath := NewName;
+ ChildData.Attributes := ReadAttributes(NewName);
+ if (ChildData.Attributes and SFGAO_FOLDER) = 0 then
+ ChildData.Properties := Format('%n KB, ', [SR.Size / 1024]);
+ GetOpenAndClosedIcons(ChildData.FullPath, ChildData.OpenIndex, ChildData.CloseIndex);
+
+ Sender.ValidateNode(Node, False);
+ end;
+ end;
+ until FindNext(SR) <> 0;
+ ChildCount := Sender.ChildCount[Node];
+
+ // finally sort node
+ if ChildCount > 0 then
+ Sender.Sort(Node, 0, TVirtualStringTree(Sender).Header.SortDirection, False);
+ finally
+ FindClose(SR);
+ Screen.Cursor := crDefault;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1GetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
+ Column: TColumnIndex; var Ghosted: Boolean; var Index: Integer);
+
+// Returns the proper node image which has been determine on initialization time. Also overlay images are
+// used properly for shared folders.
+
+var
+ Data: PShellObjectData;
+
+begin
+ if Column = 0 then
+ begin
+ Data := Sender.GetNodeData(Node);
+ case Kind of
+ ikNormal,
+ ikSelected:
+ begin
+ if Sender.Expanded[Node] then
+ Index := Data.OpenIndex
+ else
+ Index := Data.CloseIndex;
+ end;
+ ikOverlay:
+ if (Data.Attributes and SFGAO_SHARE) <> 0 then
+ Index := 0
+ else
+ if (Data.Attributes and SFGAO_LINK) <> 0 then
+ Index := 1;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1GetHintSize(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var R: TRect);
+
+// Draw trees must manage parts of the hints themselves. Here we return the size of the hint window we want to show
+// or an empty rectangle in the case we don't want a hint at all.
+
+var
+ Data: PShellObjectData;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ if Assigned(Data) and Assigned(Data.Image) and (Column = 1) then
+ R := Rect(0, 0, 2 * Data.Image.Width, 2 * Data.Image.Height)
+ else
+ R := Rect(0, 0, 0, 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1DrawHint(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; R: TRect;
+ Column: TColumnIndex);
+
+// Here we actually paint the hint. It is the image in a larger size.
+
+var
+ Data: PShellObjectData;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ if Assigned(Data) and Assigned(Data.Image) and (Column = 1) then
+ begin
+ SetStretchBltMode(Canvas.Handle, HALFTONE);
+ StretchBlt(Canvas.Handle, 0, 0, 2 * Data.Image.Width, 2 * Data.Image.Height, Data.Image.Canvas.Handle, 0, 0,
+ Data.Image.Width, Data.Image.Height, SRCCOPY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1CompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex;
+ var Result: Integer);
+
+// The node comparison routine is the heart of the tree sort. Here we have to tell the caller which node we consider
+// being "larger" or "smaller".
+
+var
+ Data1,
+ Data2: PShellObjectData;
+
+begin
+ Data1 := Sender.GetNodeData(Node1);
+ Data2 := Sender.GetNodeData(Node2);
+
+ // Folder are always before files. Check if *both* are folders or *both* are non-folders, but not different.
+ if ((Data1.Attributes xor Data2.Attributes) and SFGAO_FOLDER) <> 0 then
+ begin
+ // One of both is a folder the other is a file.
+ if (Data1.Attributes and SFGAO_FOLDER) <> 0 then
+ Result := -1
+ else
+ Result := 1;
+ end
+ else
+ // Both are of same type (folder or file). Just compare captions.
+ // Note that we use ANSI comparison, while the strings are Unicode. Since this will implicitely convert the captions
+ // to ANSI for comparation it might happen that the sort order is wrong for names which contain text in a language
+ // other than the current OS language. A full blown Unicode comparison is beyond the scope of this demo.
+ Result := CompareText(Data1.FullPath, Data2.FullPath);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1HeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState;
+ X, Y: Integer);
+
+// Click handler to switch the column on which will be sorted. Since we cannot sort image data sorting is actually
+// limited to the main column.
+
+begin
+ if Button = mbLeft then
+ begin
+ with Sender do
+ begin
+ if Column <> MainColumn then
+ SortColumn := NoColumn
+ else
+ begin
+ if SortColumn = NoColumn then
+ begin
+ SortColumn := Column;
+ SortDirection := sdAscending;
+ end
+ else
+ if SortDirection = sdAscending then
+ SortDirection := sdDescending
+ else
+ SortDirection := sdAscending;
+ Treeview.SortTree(SortColumn, SortDirection, False);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.TrackBar1Change(Sender: TObject);
+
+// This part has nothing to do with the tree content and is only to show the effect of vertical image alignment for nodes
+// (since this does not justify an own demo).
+// Btw: look how fast this stuff is. Even with several thousands of nodes you still can adjust the position interactively.
+
+var
+ Run: PVirtualNode;
+
+begin
+ Label3.Caption := Format('%d%%', [Trackbar1.Position]);
+ with VDT1, Trackbar1 do
+ begin
+ BeginUpdate;
+ try
+ Run := GetFirst;
+ while Assigned(Run) do
+ begin
+ VerticalAlignment[Run] := Position;
+ Run := GetNextVisible(Run);
+ end;
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TDrawTreeForm.VDT1StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Editors.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Editors.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Editors.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,630 @@
+unit Editors;
+
+// Utility unit for the advanced Virtual Treeview demo application which contains the implementation of edit link
+// interfaces used in other samples of the demo.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, VirtualTrees, ExtDlgs, ImgList, Buttons, ExtCtrls, ComCtrls,
+ Mask;
+
+type
+ // Describes the type of value a property tree node stores in its data property.
+ TValueType = (
+ vtNone,
+ vtString,
+ vtPickString,
+ vtNumber,
+ vtPickNumber,
+ vtMemo,
+ vtDate
+ );
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ // Node data record for the the document properties treeview.
+ PPropertyData = ^TPropertyData;
+ TPropertyData = record
+ ValueType: TValueType;
+ Value: WideString; // This value can actually be a date or a number too.
+ Changed: Boolean;
+ end;
+
+ // Our own edit link to implement several different node editors.
+ TPropertyEditLink = class(TInterfacedObject, IVTEditLink)
+ private
+ FEdit: TWinControl; // One of the property editor classes.
+ FTree: TVirtualStringTree; // A back reference to the tree calling.
+ FNode: PVirtualNode; // The node being edited.
+ FColumn: Integer; // The column of the node being edited.
+ FOldEditProc: TWndMethod; // Used to capture some important messages
+ // regardless of the type of edit control we use.
+ protected
+ procedure EditWindowProc(var Message: TMessage);
+ procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+ public
+ destructor Destroy; override;
+
+ function BeginEdit: Boolean; stdcall;
+ function CancelEdit: Boolean; stdcall;
+ function EndEdit: Boolean; stdcall;
+ function GetBounds: TRect; stdcall;
+ function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
+ procedure ProcessMessage(var Message: TMessage); stdcall;
+ procedure SetBounds(R: TRect); stdcall;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ TPropertyTextKind = (
+ ptkText,
+ ptkHint
+ );
+
+// The following constants provide the property tree with default data.
+
+const
+ // Types of editors to use for a certain node in VST3.
+ ValueTypes: array[0..1, 0..12] of TValueType = (
+ (
+ vtString, // Title
+ vtString, // Theme
+ vtPickString, // Category
+ vtMemo, // Keywords
+ vtNone, // Template
+ vtNone, // Page count
+ vtNone, // Word count
+ vtNone, // Character count
+ vtNone, // Lines
+ vtNone, // Paragraphs
+ vtNone, // Scaled
+ vtNone, // Links to update
+ vtMemo), // Comments
+ (
+ vtString, // Author
+ vtNone, // Most recently saved by
+ vtNumber, // Revision number
+ vtPickString, // Primary application
+ vtString, // Company name
+ vtNone, // Creation date
+ vtDate, // Most recently saved at
+ vtNone, // Last print
+ vtNone,
+ vtNone,
+ vtNone,
+ vtNone,
+ vtNone)
+ );
+
+ // types of editors to use for a certain node in VST3
+ DefaultValue: array[0..1, 0..12] of String = (
+ (
+ 'Virtual Treeview', // Title
+ 'native Delphi controls', // Theme
+ 'Virtual Controls', // Category
+ 'virtual, treeview, VCL', // Keywords
+ 'no template used', // Template
+ '> 900', // Page count
+ '?', // Word count
+ '~ 1.000.000', // Character count
+ '~ 28.000', // Lines
+ '', // Paragraphs
+ 'False', // Scaled
+ 'www.delphi-gems.com', // Links to update
+ 'Virtual Treeview is much more than a simple treeview.'), // Comments
+ (
+ 'Dipl. Ing. Mike Lischke', // Author
+ 'Mike Lischke', // Most recently saved by
+ '3.0', // Revision number
+ 'Delphi', // Primary application
+ '', // Company name
+ 'July 1999', // Creation date
+ 'January 2002', // Most recently saved at
+ '', // Last print
+ '',
+ '',
+ '',
+ '',
+ '')
+ );
+
+ // Fixed strings for property tree (VST3).
+ PropertyTexts: array[0..1, 0..12, TPropertyTextKind] of string = (
+ (// first (upper) subtree
+ ('Title', 'Title of the file or document'),
+ ('Theme', 'Theme of the file or document'),
+ ('Category', 'Category of theme'),
+ ('Keywords', 'List of keywords which describe the content of the file'),
+ ('Template', 'Name of the template which was used to create the document'),
+ ('Page count', 'Number of pages in the document'),
+ ('Word count', 'Number of words in the document'),
+ ('Character count', 'Number of characters in the document'),
+ ('Lines', 'Number of lines in the document'),
+ ('Paragraphs', 'Number of paragraphs in the document'),
+ ('Scaled', 'Scaling of the document for output'),
+ ('Links to update', 'Links which must be updated'),
+ ('Comments', 'Description or comments for the file')
+ ),
+ (// second (lower) subtree
+ ('Author', 'name of the author of the file or document'),
+ ('Most recently saved by', 'Name of the person who has saved the document last'),
+ ('Revision number', 'Revision number of the file or document'),
+ ('Primary application', 'Name of the application which is primarily used to create this kind of file'),
+ ('Company name', 'Name of the company or institution'),
+ ('Creation date', 'Date when the file or document was created'),
+ ('Most recently saved at', 'Date when the file or document was saved the last time'),
+ ('Last print', 'Date when the file or document was printed the last time'),
+ ('', ''), // the remaining 5 entries are not used
+ ('', ''),
+ ('', ''),
+ ('', ''),
+ ('', '')
+ )
+ );
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ PGridData = ^TGridData;
+ TGridData = record
+ ValueType: array[0..3] of TValueType; // one for each column
+ Value: array[0..3] of Variant;
+ Changed: Boolean;
+ end;
+
+ // Our own edit link to implement several different node editors.
+ TGridEditLink = class(TPropertyEditLink, IVTEditLink)
+ public
+ function EndEdit: Boolean; stdcall;
+ function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ PropertiesDemo, GridDemo;
+
+//----------------- TPropertyEditLink ----------------------------------------------------------------------------------
+
+// This implementation is used in VST3 to make a connection beween the tree
+// and the actual edit window which might be a simple edit, a combobox
+// or a memo etc.
+
+destructor TPropertyEditLink.Destroy;
+
+begin
+ FEdit.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertyEditLink.EditWindowProc(var Message: TMessage);
+
+// Here we can capture messages for keeping track of focus changes.
+
+begin
+ case Message.Msg of
+ WM_KILLFOCUS:
+ if FEdit is TDateTimePicker then
+ begin
+ // When the user clicks on a dropped down calender we also get
+ // the kill focus message.
+ if not TDateTimePicker(FEdit).DroppedDown then
+ FTree.EndEditNode;
+ end
+ else
+ FTree.EndEditNode;
+ else
+ FOldEditProc(Message);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertyEditLink.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+
+var
+ CanAdvance: Boolean;
+
+begin
+ case Key of
+ VK_RETURN,
+ VK_UP,
+ VK_DOWN:
+ begin
+ // Consider special cases before finishing edit mode.
+ CanAdvance := Shift = [];
+ if FEdit is TComboBox then
+ CanAdvance := CanAdvance and not TComboBox(FEdit).DroppedDown;
+ if FEdit is TDateTimePicker then
+ CanAdvance := CanAdvance and not TDateTimePicker(FEdit).DroppedDown;
+
+ if CanAdvance then
+ begin
+ FTree.EndEditNode;
+ with FTree do
+ begin
+ if Key = VK_UP then
+ FocusedNode := GetPreviousVisible(FocusedNode)
+ else
+ FocusedNode := GetNextVisible(FocusedNode);
+ Selected[FocusedNode] := True;
+ end;
+ Key := 0;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TPropertyEditLink.BeginEdit: Boolean;
+
+begin
+ Result := True;
+ FEdit.Show;
+ FEdit.SetFocus;
+ // Set a window procedure hook (aka subclassing) to get notified about important messages.
+ FOldEditProc := FEdit.WindowProc;
+ FEdit.WindowProc := EditWindowProc;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TPropertyEditLink.CancelEdit: Boolean;
+
+begin
+ Result := True;
+ // Restore the edit's window proc.
+ FEdit.WindowProc := FOldEditProc;
+ FEdit.Hide;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TPropertyEditLink.EndEdit: Boolean;
+
+var
+ Data: PPropertyData;
+ Buffer: array[0..1024] of Char;
+ S: WideString;
+ P: TPoint;
+ Dummy: Integer;
+
+begin
+ // Check if the place the user click on yields another node as the one we
+ // are currently editing. If not then do not stop editing.
+ GetCursorPos(P);
+ P := FTree.ScreenToClient(P);
+ Result := FTree.GetNodeAt(P.X, P.Y, True, Dummy) <> FNode;
+
+ if Result then
+ begin
+ // restore the edit's window proc
+ FEdit.WindowProc := FOldEditProc;
+ Data := FTree.GetNodeData(FNode);
+ if FEdit is TComboBox then
+ S := TComboBox(FEdit).Text
+ else
+ begin
+ GetWindowText(FEdit.Handle, Buffer, 1024);
+ S := Buffer;
+ end;
+
+ if S <> Data.Value then
+ begin
+ Data.Value := S;
+ Data.Changed := True;
+ FTree.InvalidateNode(FNode);
+ end;
+ FEdit.Hide;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TPropertyEditLink.GetBounds: TRect;
+
+begin
+ Result := FEdit.BoundsRect;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TPropertyEditLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+var
+ Data: PPropertyData;
+
+begin
+ Result := True;
+ FTree := Tree as TVirtualStringTree;
+ FNode := Node;
+ FColumn := Column;
+
+ // determine what edit type actually is needed
+ FEdit.Free;
+ FEdit := nil;
+ Data := FTree.GetNodeData(Node);
+ case Data.ValueType of
+ vtString:
+ begin
+ FEdit := TEdit.Create(nil);
+ with FEdit as TEdit do
+ begin
+ Visible := False;
+ Parent := Tree;
+ Text := Data.Value;
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtPickString:
+ begin
+ FEdit := TComboBox.Create(nil);
+ with FEdit as TComboBox do
+ begin
+ Visible := False;
+ Parent := Tree;
+ Text := Data.Value;
+ Items.Add(Text);
+ Items.Add('Standard');
+ Items.Add('Additional');
+ Items.Add('Win32');
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtNumber:
+ begin
+ FEdit := TMaskEdit.Create(nil);
+ with FEdit as TMaskEdit do
+ begin
+ Visible := False;
+ Parent := Tree;
+ EditMask := '9999';
+ Text := Data.Value;
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtPickNumber:
+ begin
+ FEdit := TComboBox.Create(nil);
+ with FEdit as TComboBox do
+ begin
+ Visible := False;
+ Parent := Tree;
+ Text := Data.Value;
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtMemo:
+ begin
+ FEdit := TComboBox.Create(nil);
+ // In reality this should be a drop down memo but this requires
+ // a special control.
+ with FEdit as TComboBox do
+ begin
+ Visible := False;
+ Parent := Tree;
+ Text := Data.Value;
+ Items.Add(Data.Value);
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtDate:
+ begin
+ FEdit := TDateTimePicker.Create(nil);
+ with FEdit as TDateTimePicker do
+ begin
+ Visible := False;
+ Parent := Tree;
+ CalColors.MonthBackColor := clWindow;
+ CalColors.TextColor := clBlack;
+ CalColors.TitleBackColor := clBtnShadow;
+ CalColors.TitleTextColor := clBlack;
+ CalColors.TrailingTextColor := clBtnFace;
+ Date := StrToDate(Data.Value);
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ else
+ Result := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertyEditLink.ProcessMessage(var Message: TMessage);
+
+begin
+ FEdit.WindowProc(Message);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertyEditLink.SetBounds(R: TRect);
+
+var
+ Dummy: Integer;
+
+begin
+ // Since we don't want to activate grid extensions in the tree (this would influence how the selection is drawn)
+ // we have to set the edit's width explicitly to the width of the column.
+ FTree.Header.Columns.GetColumnBounds(FColumn, Dummy, R.Right);
+ FEdit.BoundsRect := R;
+end;
+
+//---------------- TGridEditLink ---------------------------------------------------------------------------------------
+
+function TGridEditLink.EndEdit: Boolean;
+
+var
+ Data: PGridData;
+ Buffer: array[0..1024] of Char;
+ S: WideString;
+ I: Integer;
+
+begin
+ Result := True;
+ // Restore the edit's window proc.
+ FEdit.WindowProc := FOldEditProc;
+ Data := FTree.GetNodeData(FNode);
+ if FEdit is TComboBox then
+ begin
+ S := TComboBox(FEdit).Text;
+ if S <> Data.Value[FColumn - 1] then
+ begin
+ Data.Value[FColumn - 1] := S;
+ Data.Changed := True;
+ end;
+ end
+ else
+ if FEdit is TMaskEdit then
+ begin
+ I := StrToInt(Trim(TMaskEdit(FEdit).EditText));
+ if I <> Data.Value[FColumn - 1] then
+ begin
+ Data.Value[FColumn - 1] := I;
+ Data.Changed := True;
+ end;
+ end
+ else
+ begin
+ GetWindowText(FEdit.Handle, Buffer, 1024);
+ S := Buffer;
+ if S <> Data.Value[FColumn - 1] then
+ begin
+ Data.Value[FColumn - 1] := S;
+ Data.Changed := True;
+ end;
+ end;
+
+ if Data.Changed then
+ FTree.InvalidateNode(FNode);
+ FEdit.Hide;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TGridEditLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+var
+ Data: PGridData;
+begin
+ Result := True;
+ FTree := Tree as TVirtualStringTree;
+ FNode := Node;
+ FColumn := Column;
+
+ // Determine what edit type actually is needed.
+ FEdit.Free;
+ FEdit := nil;
+ Data := FTree.GetNodeData(Node);
+ case Data.ValueType[FColumn - 1] of
+ vtString:
+ begin
+ FEdit := TEdit.Create(nil);
+ with FEdit as TEdit do
+ begin
+ Visible := False;
+ Parent := Tree;
+ Text := Data.Value[FColumn - 1];
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtPickString:
+ begin
+ FEdit := TComboBox.Create(nil);
+ with FEdit as TComboBox do
+ begin
+ Visible := False;
+ Parent := Tree;
+ Text := Data.Value[FColumn - 1];
+ // Here you would usually do a lookup somewhere to get
+ // values for the combobox. We only add some dummy values.
+ case FColumn of
+ 2:
+ begin
+ Items.Add('John');
+ Items.Add('Mike');
+ Items.Add('Barney');
+ Items.Add('Tim');
+ end;
+ 3:
+ begin
+ Items.Add('Doe');
+ Items.Add('Lischke');
+ Items.Add('Miller');
+ Items.Add('Smith');
+ end;
+ end;
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtNumber:
+ begin
+ FEdit := TMaskEdit.Create(nil);
+ with FEdit as TMaskEdit do
+ begin
+ Visible := False;
+ Parent := Tree;
+ EditMask := '9999;0; ';
+ Text := Data.Value[FColumn - 1];
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtPickNumber:
+ begin
+ FEdit := TComboBox.Create(nil);
+ with FEdit as TComboBox do
+ begin
+ Visible := False;
+ Parent := Tree;
+ Text := Data.Value[FColumn - 1];
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtMemo:
+ begin
+ FEdit := TComboBox.Create(nil);
+ // In reality this should be a drop down memo but this requires
+ // a special control.
+ with FEdit as TComboBox do
+ begin
+ Visible := False;
+ Parent := Tree;
+ Text := Data.Value[FColumn - 1];
+ Items.Add(Data.Value[FColumn - 1]);
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ vtDate:
+ begin
+ FEdit := TDateTimePicker.Create(nil);
+ with FEdit as TDateTimePicker do
+ begin
+ Visible := False;
+ Parent := Tree;
+ CalColors.MonthBackColor := clWindow;
+ CalColors.TextColor := clBlack;
+ CalColors.TitleBackColor := clBtnShadow;
+ CalColors.TitleTextColor := clBlack;
+ CalColors.TrailingTextColor := clBtnFace;
+ Date := StrToDate(Data.Value[FColumn - 1]);
+ OnKeyDown := EditKeyDown;
+ end;
+ end;
+ else
+ Result := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GeneralAbilitiesDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GeneralAbilitiesDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GeneralAbilitiesDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GeneralAbilitiesDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GeneralAbilitiesDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,531 @@
+unit GeneralAbilitiesDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - General use and feel of TVirtualStringTree.
+// - Themed/non-themed painting.
+// - Node button styles.
+// - Selection rectangle styles.
+// - Multiple columns, header, customize column backgrounds, header popup.
+// - Unicode strings.
+// - OLE drag'n drop image.
+// - Switchable main column.
+// - Right click select and drag.
+// - Node specific popup menu.
+// - Save tree content as text file.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, Buttons, VirtualTrees, ComCtrls, ExtCtrls, ImgList, Menus,
+ StdActns, ActnList, VTHeaderPopup;
+
+type
+ TGeneralForm = class(TForm)
+ VST2: TVirtualStringTree;
+ CheckMarkCombo: TComboBox;
+ Label18: TLabel;
+ MainColumnUpDown: TUpDown;
+ Label19: TLabel;
+ BitBtn1: TBitBtn;
+ Label8: TLabel;
+ TreeImages: TImageList;
+ FontDialog1: TFontDialog;
+ PopupMenu1: TPopupMenu;
+ Onemenuitem1: TMenuItem;
+ forrightclickselection1: TMenuItem;
+ withpopupmenu1: TMenuItem;
+ RadioGroup1: TRadioGroup;
+ RadioGroup2: TRadioGroup;
+ VTHPopup: TVTHeaderPopupMenu;
+ ThemeRadioGroup: TRadioGroup;
+ SaveButton: TBitBtn;
+ SaveDialog: TSaveDialog;
+ procedure BitBtn1Click(Sender: TObject);
+ procedure VST2InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure VST2InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+ procedure VST2NewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; Text: WideString);
+ procedure VST2GetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer);
+ procedure VST2GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure VST2PaintText(Sender: TBaseVirtualTree; const Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType);
+ procedure VST2GetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
+ procedure CheckMarkComboChange(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure MainColumnUpDownChanging(Sender: TObject; var AllowChange: Boolean);
+ procedure VST2GetPopupMenu(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; const P: TPoint;
+ var AskParent: Boolean; var PopupMenu: TPopupMenu);
+ procedure VST2KeyDown(Sender: TObject; var Key: Word;
+ Shift: TShiftState);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure VST2FocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn,
+ NewColumn: TColumnIndex; var Allowed: Boolean);
+ procedure RadioGroup2Click(Sender: TObject);
+ procedure ThemeRadioGroupClick(Sender: TObject);
+ procedure SaveButtonClick(Sender: TObject);
+ procedure VST2StateChange(Sender: TBaseVirtualTree; Enter,
+ Leave: TVirtualTreeStates);
+ procedure VST2DragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint;
+ Mode: TDropMode; var Effect: Integer; var Accept: Boolean);
+ end;
+
+var
+ GeneralForm: TGeneralForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ ShellAPI, Main, States;
+
+{$R *.DFM}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ PNodeData2 = ^TNodeData2;
+ TNodeData2 = record
+ Caption,
+ StaticText,
+ ForeignText: WideString;
+ ImageIndex,
+ Level: Integer;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.FormCreate(Sender: TObject);
+
+var
+ I: Integer;
+
+begin
+ // Determine if we are running on Windows XP.
+ ThemeRadioGroup.Enabled := (Win32MajorVersion >= 5) and (Win32MinorVersion >= 1);
+ if ThemeRadioGroup.Enabled then
+ ThemeRadioGroup.ItemIndex := 0;
+
+ CheckMarkCombo.ItemIndex := 3;
+
+ // Add a second line of hint text for column headers (not possible in the object inspector).
+ with VST2.Header do
+ for I := 0 to Columns.Count - 1 do
+ Columns[I].Hint := Columns[I].Hint + #10 + '(Can show further information in hints too.)';
+
+ ConvertToHighColor(TreeImages);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2GetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
+
+// Returns the size of a node record. Since this size is fixed already at
+// creation time it would make sense to avoid this event and assign the value
+// in OnCreate of the form (see there for the other trees). But this is a
+// demo program, so I want to show this way too. Note the -1 value in
+// VST2.NodeDataSize which primarily causes this event to be fired.
+
+begin
+ NodeDataSize := SizeOf(TNodeData2);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2PaintText(Sender: TBaseVirtualTree; const Canvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType);
+
+var
+ Data: PNodeData2;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ case Column of
+ 0: // main column
+ case TextType of
+ ttNormal:
+ if Data.Level = 0 then
+ Canvas.Font.Style := Canvas.Font.Style + [fsBold];
+ ttStatic:
+ begin
+ Canvas.Font.Color := clBlue;
+ Canvas.Font.Style := Canvas.Font.Style - [fsBold];
+ end;
+ end;
+ 1: // image column (there is no text)
+ ;
+ 2: // language column (no customization)
+ ;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+
+// Returns the text as it is stored in the nodes data record.
+
+var
+ Data: PNodeData2;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ Text := '';
+ case Column of
+ 0: // main column (has two different captions)
+ case TextType of
+ ttNormal:
+ Text := Data.Caption;
+ ttStatic:
+ Text := Data.StaticText;
+ end;
+ 1: // no text in the image column
+ ;
+ 2:
+ if TextType = ttNormal then
+ Text := Data.ForeignText;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+const
+ LevelToCheckType: array[0..4] of TCheckType = (
+ ctButton, ctRadioButton, ctTriStateCheckBox, ctCheckBox, ctNone
+ );
+
+var
+ Data: PNodeData2;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ with Data^ do
+ begin
+ Level := Sender.GetNodeLevel(Node);
+ if Level < 4 then
+ begin
+ Include(InitialStates, ivsHasChildren);
+ if Level = 0 then
+ Include(InitialStates, ivsExpanded);
+ end;
+
+ Caption := Format('Level %d, Index %d', [Level, Node.Index]);
+ if Level in [0, 3] then
+ StaticText := '(static text)';
+
+ ForeignText := '';
+ case Data.Level of
+ 1:
+ begin
+ ForeignText := WideChar($2200);
+ ForeignText := ForeignText + WideChar($2202) + WideChar($221C) + WideChar($221E) + WideChar($2230) +
+ WideChar($2233) + WideChar($2257) + WideChar($225D) + WideChar($22B6) + WideChar($22BF);
+ end;
+ 2:
+ begin
+ ForeignText := WideChar($32E5);
+ ForeignText := ForeignText + WideChar($32E6) + WideChar($32E7) + WideChar($32E8) + WideChar($32E9);
+ end;
+ 3:
+ begin
+ ForeignText := WideChar($03B1);
+ ForeignText := ForeignText + WideChar($03B2) + WideChar($03B3) + WideChar($03B4) + WideChar($03B5) +
+ WideChar($03B6) + WideChar($03B7) + WideChar($03B8) + WideChar($03B9);
+ end;
+ 4:
+ begin
+ ForeignText := WideChar($20AC);
+ ForeignText := 'nichts is unmöglich ' + ForeignText;
+ end;
+ end;
+ Node.CheckType := LevelToCheckType[Data.Level];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2GetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
+ Column: TColumnIndex; var Ghosted: Boolean; var Index: Integer);
+
+var
+ Data: PNodeData2;
+
+begin
+ // For this demo only the normal image is shown, you can easily
+ // change this for the state and overlay images.
+ case Kind of
+ ikNormal, ikSelected:
+ begin
+ Data := Sender.GetNodeData(Node);
+ Ghosted := Node.Index = 1;
+ case Column of
+ -1, // general case
+ 0: // main column
+ Index := Data.Level + 7;
+ 1: // image only column
+ if Sender.FocusedNode = Node then
+ Index := 6;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+
+// The tree is set to 5 levels a 5 children (~4000 nodes).
+
+var
+ Data: PNodeData2;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ if Data.Level < 4 then
+ ChildCount := 5;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2NewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ Text: WideString);
+
+// The caption of a node has been changed, keep this in the node record.
+
+var
+ Data: PNodeData2;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ Data.Caption := Text;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.BitBtn1Click(Sender: TObject);
+
+begin
+ with FontDialog1 do
+ begin
+ Font := VST2.Font;
+ if Execute then
+ VST2.Font := Font;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.CheckMarkComboChange(Sender: TObject);
+
+begin
+ VST2.CheckImageKind := TCheckImageKind(CheckMarkCombo.ItemIndex);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.MainColumnUpDownChanging(Sender: TObject; var AllowChange: Boolean);
+
+begin
+ VST2.Header.MainColumn := MainColumnUpDown.Position;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2GetPopupMenu(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ const P: TPoint; var AskParent: Boolean; var PopupMenu: TPopupMenu);
+
+begin
+ case Column of
+ 0:
+ PopupMenu := PopupMenu1
+ else
+ PopupMenu := nil;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+
+begin
+ if ssCtrl in Shift then
+ case Key of
+ Ord('C'):
+ VST2.CopyToClipboard;
+ Ord('X'):
+ VST2.CutToClipboard;
+ end
+ else
+ case Key of
+ VK_DELETE:
+ if Assigned(VST2.FocusedNode) then
+ VST2.DeleteNode(VST2.FocusedNode);
+ VK_INSERT:
+ if Assigned(VST2.FocusedNode) then
+ VST2.AddChild(VST2.FocusedNode);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.RadioGroup1Click(Sender: TObject);
+
+begin
+ with Sender as TRadioGroup do
+ if ItemIndex = 0 then
+ begin
+ VST2.TreeOptions.PaintOptions := VST2.TreeOptions.PaintOptions + [toShowTreeLines];
+ VST2.ButtonStyle := bsRectangle;
+ end
+ else
+ begin
+ VST2.TreeOptions.PaintOptions := VST2.TreeOptions.PaintOptions - [toShowTreeLines];
+ VST2.ButtonStyle := bsTriangle;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2FocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn,
+ NewColumn: TColumnIndex; var Allowed: Boolean);
+
+begin
+ Allowed := NewColumn in [0, 2];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.RadioGroup2Click(Sender: TObject);
+
+begin
+ with Sender as TRadioGroup do
+ if ItemIndex = 0 then
+ begin
+ VST2.DrawSelectionMode := smDottedRectangle;
+ end
+ else
+ begin
+ VST2.DrawSelectionMode := smBlendedRectangle;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.ThemeRadioGroupClick(Sender: TObject);
+
+begin
+ with VST2.TreeOptions do
+ if ThemeRadioGroup.ItemIndex = 0 then
+ PaintOptions := PaintOptions + [toThemeAware]
+ else
+ PaintOptions := PaintOptions - [toThemeAware];
+
+ RadioGroup1.Enabled := ThemeRadioGroup.ItemIndex = 1;
+ RadioGroup2.Enabled := ThemeRadioGroup.ItemIndex = 1;
+ Label18.Enabled := ThemeRadioGroup.ItemIndex = 1;
+ CheckMarkCombo.Enabled := ThemeRadioGroup.ItemIndex = 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.SaveButtonClick(Sender: TObject);
+
+const
+ HTMLHead = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">'#13#10 +
+ '<html>'#13#10 +
+ ' <head>'#13#10 +
+ ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8">'#13#10 +
+ ' <title>Virtual Treeview export</title>'#13#10 +
+ ' </head>'#13#10 +
+ '<body>'#13#10;
+
+var
+ S: string;
+ WS: WideString;
+ Data: Pointer;
+ DataSize: Cardinal;
+ TargetName: string;
+
+begin
+ with SaveDialog do
+ begin
+ if Execute then
+ begin
+ TargetName := FileName;
+ case FilterIndex of
+ 1: // HTML
+ begin
+ if Pos('.', TargetName) = 0 then
+ TargetName := TargetName + '.html';
+ S := HTMLHead + VST2.ContentToHTML(tstVisible) + '</body></html>';
+ Data := PChar(S);
+ DataSize := Length(S);
+ end;
+ 2: // Unicode UTF-16 text file
+ begin
+ TargetName := ChangeFileExt(TargetName, '.uni');
+ WS := VST2.ContentToUnicode(tstVisible, #9);
+ Data := PWideChar(WS);
+ DataSize := 2 * Length(WS);
+ end;
+ 3: // Rich text UTF-16 file
+ begin
+ TargetName := ChangeFileExt(TargetName, '.rtf');
+ S := VST2.ContentToRTF(tstVisible);
+ Data := PChar(S);
+ DataSize := Length(S);
+ end;
+ 4: // Comma separated values ANSI text file
+ begin
+ TargetName := ChangeFileExt(TargetName, '.csv');
+ S := VST2.ContentToText(tstVisible, ListSeparator);
+ Data := PChar(S);
+ DataSize := Length(S);
+ end;
+ else
+ // Plain text file
+ TargetName := ChangeFileExt(TargetName, '.txt');
+ S := VST2.ContentToText(tstVisible, #9);
+ Data := PChar(S);
+ DataSize := Length(S);
+ end;
+
+ with TFileStream.Create(TargetName, fmCreate) do
+ try
+ WriteBuffer(Data^, DataSize);
+ finally
+ Free;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGeneralForm.VST2DragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState;
+ Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean);
+
+begin
+ Accept := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GridDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GridDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GridDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GridDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/GridDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,226 @@
+unit GridDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - TVirtualStringTree with enabled grid extensions.
+// - Owner draw column to simulate a fixed column.
+// - Extend focus, multiselection without selection rectangle.
+// - Various editors, specific to each column.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, VirtualTrees, ImgList;
+
+type
+ TGridForm = class(TForm)
+ VST5: TVirtualStringTree;
+ GridLineCheckBox: TCheckBox;
+ Label15: TLabel;
+ TreeImages: TImageList;
+ Label1: TLabel;
+ procedure VST5BeforeCellPaint(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ CellRect: TRect);
+ procedure VST5BeforeItemErase(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
+ var Color: TColor; var EraseAction: TItemEraseAction);
+ procedure VST5CreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
+ procedure VST5FocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn,
+ NewColumn: TColumnIndex; var Allowed: Boolean);
+ procedure VST5GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure VST5InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure VST5PaintText(Sender: TBaseVirtualTree; const Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType);
+ procedure GridLineCheckBoxClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure VST5AfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ CellRect: TRect);
+ procedure VST5StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+ end;
+
+var
+ GridForm: TGridForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ Editors, States;
+
+{$R *.DFM}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.FormCreate(Sender: TObject);
+
+begin
+ VST5.NodeDataSize := SizeOf(TGridData);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5BeforeItemErase(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
+ var Color: TColor; var EraseAction: TItemEraseAction);
+
+// Some nodes get a different background color.
+
+begin
+ with Canvas do
+ begin
+ if Node.Index mod 6 = 0 then
+ Color := $49DDEF // $70A33F // $436BFF
+ else
+ Color := VST5.Color;
+ EraseAction := eaColor;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5FocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn,
+ NewColumn: TColumnIndex; var Allowed: Boolean);
+
+begin
+ // Do not allow focusing the indicator column (which simulates a fixed column).
+ Allowed := NewColumn > 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+var
+ Data: PGridData;
+ D: TDateTime;
+
+begin
+ Data := Sender.GetNodeData(Node);
+
+ // These are the editor kinds used in the grid tree.
+ Data.ValueType[0] := vtNumber;
+ Data.ValueType[1] := vtPickString;
+ Data.ValueType[2] := vtPickString;
+ Data.ValueType[3] := vtDate;
+
+ // fill some default values
+ Data.Value[0] := Variant(Node.Index);
+ Data.Value[1] := 'John';
+ Data.Value[2] := 'Doe';
+ // A date value slightly randomized around today. Need the way
+ // using a local variable to tell the compiler we are not
+ // using a float as variant, but a TDateTime.
+ D := Date + Random(14) - 7;
+ Data.Value[3] := D;
+
+ if Sender.FocusedColumn < 1 then
+ Sender.FocusedColumn := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+
+var
+ Data: PGridData;
+
+begin
+ if Column > 0 then
+ begin
+ Data := Sender.GetNodeData(Node);
+ Text := Data.Value[Column - 1];
+ end
+ else
+ Text := '';
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5PaintText(Sender: TBaseVirtualTree; const Canvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType);
+
+var
+ Data: PGridData;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ if Data.Changed then
+ Canvas.Font.Style := [fsBold];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5BeforeCellPaint(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ CellRect: TRect);
+
+begin
+ // Fill random cells with our own background, but don't touch the currently focused cell.
+ if ((Column <> Sender.FocusedColumn) or (Node <> Sender.FocusedNode)) and
+ ((Column - 2) = (Integer(Node.Index) mod (VST5.Header.Columns.Count - 1))) then
+ begin
+ Canvas.Brush.Color := $E0E0E0;
+ Canvas.FillRect(CellRect);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5CreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ out EditLink: IVTEditLink);
+
+// This is the callback of the tree control to ask for an application defined edit link. Providing one here allows
+// us to control the editing process up to which actual control will be created.
+// TGridEditLink implements an interface and hence benefits from reference counting. We don't need to keep a reference
+// to free it. As soon as the tree finished editing the class will be destroyed automatically.
+
+begin
+ EditLink := TGridEditLink.Create;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.GridLineCheckBoxClick(Sender: TObject);
+
+begin
+ if GridLineCheckBox.Checked then
+ VST5.TreeOptions.PaintOptions := VST5.TreeOptions.PaintOptions + [toShowHorzGridLines, toShowVertGridLines]
+ else
+ VST5.TreeOptions.PaintOptions := VST5.TreeOptions.PaintOptions - [toShowHorzGridLines, toShowVertGridLines];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5AfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; CellRect: TRect);
+
+begin
+ if Column = 0 then
+ with TargetCanvas do
+ begin
+ // Simulate a fixed column by filling the main column with an edge similar to that of TCustomGrid.
+ if toShowVertGridLines in VST5.TreeOptions.PaintOptions then
+ Inc(CellRect.Right);
+ if toShowHorzGridLines in VST5.TreeOptions.PaintOptions then
+ Inc(CellRect.Bottom);
+ DrawEdge(Handle, CellRect, BDR_RAISEDINNER, BF_RECT or BF_MIDDLE);
+ if Node = Sender.FocusedNode then
+ TreeImages.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 17);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TGridForm.VST5StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/HeaderCustomDrawDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/HeaderCustomDrawDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/HeaderCustomDrawDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/HeaderCustomDrawDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/HeaderCustomDrawDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,294 @@
+unit HeaderCustomDrawDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - Advanced header custom draw.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, ImgList, VirtualTrees, StdCtrls, ExtCtrls;
+
+type
+ THeaderOwnerDrawForm = class(TForm)
+ Label8: TLabel;
+ HeaderCustomDrawTree: TVirtualStringTree;
+ HeaderImages: TImageList;
+ AnimationTimer: TTimer;
+ procedure HeaderCustomDrawTreeHeaderDrawQueryElements(Sender: TVTHeader; const PaintInfo: THeaderPaintInfo;
+ var Elements: THeaderPaintElements);
+ procedure HeaderCustomDrawTreeAdvancedHeaderDraw(Sender: TVTHeader; const PaintInfo: THeaderPaintInfo;
+ const Elements: THeaderPaintElements);
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure AnimationTimerTimer(Sender: TObject);
+ procedure HeaderCustomDrawTreeHeaderMouseUp(Sender: TVTHeader; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+ procedure HeaderCustomDrawTreeHeaderMouseDown(Sender: TVTHeader; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+ procedure HeaderCustomDrawTreeStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+ private
+ FBackBitmap1,
+ FBackBitmap2,
+ FCheckerBackground: TBitmap;
+ FHeaderBitmap: TBitmap;
+ FLeftPos: Integer;
+ procedure CreateCheckerBackground;
+ procedure PaintSelection(Bitmap: TBitmap);
+ procedure FillBackground(R: TRect; Target: TCanvas);
+ end;
+
+var
+ HeaderOwnerDrawForm: THeaderOwnerDrawForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ States;
+
+{$R *.dfm}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.HeaderCustomDrawTreeHeaderDrawQueryElements(Sender: TVTHeader; const PaintInfo: THeaderPaintInfo;
+ var Elements: THeaderPaintElements);
+
+// This event tells the tree which part we want to draw ourselves. Don't forget to enable custom drawing in the header
+// options and switch the Style property of every column, which we handle here to vsOwnerDraw.
+
+begin
+ with PaintInfo do
+ begin
+ // First check the column member. If it is NoColumn then it's about the header background.
+ if Column = nil then
+ Elements := [hpeBackground] // No other flag is recognized for the header background.
+ else
+ begin
+ // Using the index here ensures a column, regardless of its position, always has the same draw style.
+ // By using the Position member, we could make a certain column place stand out, regardless of the column order.
+ // Don't forget to change the AdvancedHeaderDraw event body accordingly after you changed the indicator here.
+ case Column.Index of
+ 0: // Default drawing.
+ ;
+ 1: // Background only customization.
+ Include(Elements, hpeBackground);
+ 2: // Full customization (well, quite).
+ Elements := [hpeBackground, hpeText{, hpeDropMark, hpeHeaderGlyph, hpeSortGlyph}];
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.HeaderCustomDrawTreeAdvancedHeaderDraw(Sender: TVTHeader; const PaintInfo: THeaderPaintInfo;
+ const Elements: THeaderPaintElements);
+
+var
+ S: string;
+ Size: TSize;
+ SourceRect,
+ TargetRect: TRect;
+
+begin
+ with PaintInfo do
+ begin
+ // First check the column member. If it is NoColumn then it's about the header background.
+ if Column = nil then
+ begin
+ if hpeBackground in Elements then
+ begin
+ TargetCanvas.Brush.Color := clBackground;
+ TargetCanvas.FillRect(PaintRectangle);
+ end;
+ end
+ else
+ begin
+ case Column.Index of
+ 0: // Will never come here.
+ ;
+ 1: // Background only customization.
+ begin
+ FBackBitmap1.Width := PaintRectangle.Right - PaintRectangle.Left;
+ FBackBitmap1.Height := PaintRectangle.Bottom - PaintRectangle.Top;
+ FillBackground(PaintRectangle, FBackbitmap1.Canvas);
+ if IsHoverIndex and MMXAvailable then
+ PaintSelection(FBackBitmap1);
+ TargetCanvas.Draw(PaintRectangle.Left, Paintrectangle.Top, FBackbitmap1);
+ end;
+ 2: // Full customization. Check elements to learn what must be drawn in the various stages.
+ begin
+ if hpeBackground in Elements then
+ with FBackBitmap2 do
+ begin
+ Width := PaintRectangle.Right - PaintRectangle.Left;
+ Height := PaintRectangle.Bottom - PaintRectangle.Top;
+ TargetRect := Rect(0, 0, Width, Height);
+ Canvas.Brush.Color := clInfoBk;
+ Canvas.FillRect(TargetRect);
+ InflateRect(TargetRect, - 10, -10);
+ SourceRect := TargetRect;
+ OffsetRect(SourceRect, -SourceRect.Left + FLeftPos, -SourceRect.Top);
+ Canvas.CopyRect(TargetRect, FHeaderBitmap.Canvas, SourceRect);
+
+ TargetCanvas.Draw(PaintRectangle.Left, Paintrectangle.Top, FBackbitmap2);
+ end;
+ if hpeText in Elements then
+ begin
+ TargetCanvas.Font.Name := 'Webdings';
+ TargetCanvas.Font.Charset := SYMBOL_CHARSET;
+ TargetCanvas.Font.Size := 60;
+ if IsHoverIndex then
+ TargetCanvas.Font.Color := $80FF;
+ S := 'û';
+ Size := TargetCanvas.TextExtent(S);
+ SetBkMode(TargetCanvas.Handle, TRANSPARENT);
+ TargetCanvas.TextOut(PaintRectangle.Left + 10, Paintrectangle.Bottom - Size.cy, S);
+ end;
+ // Other elements go here.
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.CreateCheckerBackground;
+
+begin
+ FCheckerBackground := TBitmap.Create;
+ with FCheckerBackground do
+ begin
+ Width := 16;
+ Height := 16;
+ Canvas.Brush.Color := clBtnFace;
+ Canvas.FillRect(Rect(0, 0, Width, Height));
+ Canvas.Brush.Color := clBtnHighlight;
+ Canvas.FillRect(Rect(0, 0, 8, 8));
+ Canvas.FillRect(Rect(8, 8, 16, 16));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.PaintSelection(Bitmap: TBitmap);
+
+const
+ Alpha = 75;
+
+var
+ R: TRect;
+
+begin
+ R := Rect(0, 0, Bitmap.Width, Bitmap.Height);
+ VirtualTrees.AlphaBlend(0, Bitmap.Canvas.Handle, R, Point(0, 0), bmConstantAlphaAndColor, Alpha,
+ ColorToRGB(clHighlight));
+ with Bitmap do
+ begin
+ Canvas.Pen.Color := clHighlight;
+ Canvas.Brush.Style := bsClear;
+ Canvas.Rectangle(0, 0, Width, Height);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.FillBackground(R: TRect; Target: TCanvas);
+
+// Tiles the background image over the given target bitmap.
+
+var
+ X, Y: Integer;
+ dX, dY: Integer;
+
+begin
+ with Target do
+ begin
+ dX := FCheckerBackground.Width;
+ dY := FCheckerBackground.Height;
+
+ Y := 0;
+ while Y < R.Bottom - R.Top do
+ begin
+ X := 0;
+ while X < R.Right - R.Left do
+ begin
+ Draw(X, Y, FCheckerBackground);
+ Inc(X, dX);
+ end;
+ Inc(Y, dY);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.FormCreate(Sender: TObject);
+
+begin
+ FBackBitmap1 := TBitmap.Create;
+ FBackBitmap1.PixelFormat := pf32Bit;
+ FBackBitmap2 := TBitmap.Create;
+ FBackBitmap2.PixelFormat := pf32Bit;
+ CreateCheckerBackground;
+ FHeaderBitmap := TBitmap.Create;
+ FHeaderBitmap.Handle := LoadImage(HInstance, 'Transcriptions', IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.FormDestroy(Sender: TObject);
+
+begin
+ FCheckerBackground.Free;
+ FBackBitmap1.Free;
+ FBackBitmap2.Free;
+ FHeaderBitmap.Free;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.AnimationTimerTimer(Sender: TObject);
+
+begin
+ FLeftPos := (FLeftPos + FHeaderBitmap.Width div 2000) mod FHeaderBitmap.Width;
+ with HeaderCustomDrawTree.Header do
+ Invalidate(Columns[2]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.HeaderCustomDrawTreeHeaderMouseUp(Sender: TVTHeader; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+
+begin
+ // Reenable animation after a drag operation.
+ AnimationTimer.Enabled := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.HeaderCustomDrawTreeHeaderMouseDown(Sender: TVTHeader; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+
+begin
+ // Stop animation when mouse button is down.
+ AnimationTimer.Enabled := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure THeaderOwnerDrawForm.HeaderCustomDrawTreeStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Main.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Main.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Main.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Main.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Main.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,201 @@
+unit Main;
+
+// Advanced demo for Virtual Treeview showing various effects and features in several forms.
+// This is the main form which serves as container window for the demo forms.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ ComCtrls, ToolWin, Buttons, ExtCtrls, StdCtrls, ImgList;
+
+type
+ TMainForm = class(TForm)
+ PageScroller1: TPageScroller;
+ SpeedDemoButton: TSpeedButton;
+ AbilitiesDemoButton: TSpeedButton;
+ PropertiesDemoButton: TSpeedButton;
+ VisibilityDemoButton: TSpeedButton;
+ GridDemoButton: TSpeedButton;
+ AlignDemoButton: TSpeedButton;
+ QuitButton: TSpeedButton;
+ PaintTreeDemoButton: TSpeedButton;
+ Bevel1: TBevel;
+ MainPanel: TPanel;
+ Bevel2: TBevel;
+ Bevel3: TBevel;
+ StatusBar: TStatusBar;
+ ContainerPanel: TPanel;
+ Label1: TLabel;
+ Label2: TLabel;
+ XPDemoButton: TSpeedButton;
+ TreeImages: TImageList;
+ SpeedButton1: TSpeedButton;
+ SpeedButton2: TSpeedButton;
+ procedure QuitButtonClick(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure DemoButtonClick(Sender: TObject);
+ procedure FormShow(Sender: TObject);
+ end;
+
+var
+ MainForm: TMainForm;
+
+procedure ConvertToHighColor(ImageList: TImageList);
+procedure LoadUnicodeStrings(Name: string; var Strings: array of WideString);
+procedure SetStatusbarText(const S: string);
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ CommCtrl,
+ SpeedDemo, GeneralAbilitiesDemo, DrawTreeDemo, PropertiesDemo,
+ GridDemo, VisibilityDemo, AlignDemo, WindowsXPStyleDemo, NodeDemo, HeaderCustomDrawDemo,
+ States;
+
+{$R *.DFM}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure ConvertToHighColor(ImageList: TImageList);
+
+// To show smooth images we have to convert the image list from 16 colors to high color.
+
+var
+ IL: TImageList;
+
+begin
+ // Have to create a temporary copy of the given list, because the list is cleared on handle creation.
+ IL := TImageList.Create(nil);
+ IL.Assign(ImageList);
+
+ with ImageList do
+ Handle := ImageList_Create(Width, Height, ILC_COLOR16 or ILC_MASK, Count, AllocBy);
+ ImageList.Assign(IL);
+ IL.Free;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure LoadUnicodeStrings(Name: string; var Strings: array of WideString);
+
+// Loads the Unicode strings from the resource.
+
+var
+ Stream: TResourceStream;
+ Head, Tail: PWideChar;
+ I: Integer;
+
+begin
+ Stream := TResourceStream.Create(0, Name, 'Unicode');
+ try
+ Head := Stream.Memory;
+ // Skip byte order mark.
+ Inc(Head);
+ Tail := Head;
+ for I := 0 to High(Strings) do
+ begin
+ Head := Tail;
+ while not (Tail^ in [WideChar(#0), WideChar(#13)]) do
+ Inc(Tail);
+ SetString(Strings[I], Head, Tail - Head);
+ // Skip carriage return and linefeed.
+ Inc(Tail, 2);
+ end;
+ finally
+ Stream.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure SetStatusbarText(const S: string);
+
+begin
+ MainForm.StatusBar.SimpleText := S;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.QuitButtonClick(Sender: TObject);
+
+begin
+ Close;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.FormCreate(Sender: TObject);
+
+begin
+ // Show hints 10 seconds.
+ Application.HintHidePause := 10000;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.DemoButtonClick(Sender: TObject);
+
+// This method is a kind of scheduler. Here we switch between the demo forms.
+
+var
+ NewDemoClass: TFormClass;
+ NewDemo: TForm;
+
+begin
+ case (Sender as TSpeedButton).Tag of
+ 0:
+ NewDemoClass := TSpeedForm;
+ 1:
+ NewDemoClass := TGeneralForm;
+ 2:
+ NewDemoClass := TPropertiesForm;
+ 3:
+ NewDemoClass := TVisibilityForm;
+ 5:
+ NewDemoClass := TGridForm;
+ 6:
+ NewDemoClass := TDrawTreeForm;
+ 7:
+ NewDemoClass := TAlignForm;
+ 8:
+ NewDemoClass := TWindowsXPForm;
+ 9:
+ NewDemoClass := TNodeForm;
+ 10:
+ NewDemoClass := THeaderOwnerDrawForm;
+ else
+ NewDemoClass := nil;
+ end;
+
+ if (ContainerPanel.ControlCount = 0) or not (ContainerPanel.Controls[0] is NewDemoClass) then
+ begin
+ if ContainerPanel.ControlCount > 0 then
+ ContainerPanel.Controls[0].Free;
+
+ if Assigned(NewDemoClass) then
+ begin
+ NewDemo := NewDemoClass.Create(Self);
+ NewDemo.Hide;
+ NewDemo.BorderStyle := bsNone;
+ NewDemo.Parent := ContainerPanel;
+ NewDemo.Align := alClient;
+ NewDemo.Show;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.FormShow(Sender: TObject);
+
+begin
+ StateForm.Show;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/NodeDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/NodeDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/NodeDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/NodeDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/NodeDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,126 @@
+unit NodeDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - Multiline node captions.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, SysUtils, Classes, Forms, Controls, Graphics, VirtualTrees,
+ ExtCtrls, StdCtrls;
+
+type
+ TNodeForm = class(TForm)
+ Panel1: TPanel;
+ MLTree: TVirtualStringTree;
+ Label8: TLabel;
+ procedure MLTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure FormCreate(Sender: TObject);
+ procedure MLTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var CellText: WideString);
+ procedure MLTreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType);
+ procedure MLTreeEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
+ procedure MLTreeStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ Main, States;
+
+{$R *.dfm}
+
+var
+ DemoText: array[0..29] of WideString;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TNodeForm.MLTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+begin
+ Node.Align := 20; // Alignment of expand/collapse button nearly at the top of the node.
+ if (Node.Index mod 3) = 0 then
+ begin
+ MLTree.NodeHeight[Node] := 40;
+ end
+ else
+ begin
+ MLTree.NodeHeight[Node] := 120;
+ Include(InitialStates, ivsMultiline);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TNodeForm.FormCreate(Sender: TObject);
+
+begin
+ LoadUnicodeStrings('LoremIpsum', DemoText);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TNodeForm.MLTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var CellText: WideString);
+
+// Returns the text for the given node. This text was loaded at form creation time from the application resource.
+
+begin
+ // The display is organized so that for every two main text nodes a node with empty main text is used. This
+ // node however gets text in its second column (with column spanning enabled).
+ // This creates the visual effect of a chapter heading and two indented paragraphs.
+ // Another possibility to get this effect is to use child nodes and only one column.
+ case Column of
+ 0: // Main column.
+ if (Node.Index mod 3) = 0 then
+ CellText := ''
+ else
+ CellText := DemoText[Node.Index mod 30];
+ 1:
+ if (Node.Index mod 3) = 0 then
+ CellText := DemoText[Node.Index mod 30]
+ else
+ CellText := '';
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TNodeForm.MLTreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType);
+
+begin
+ if (Node.Index mod 3) = 0 then
+ begin
+ TargetCanvas.Font.Size := 12;
+ TargetCanvas.Font.Style := [fsBold];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TNodeForm.MLTreeEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var Allowed: Boolean);
+
+begin
+ Allowed := (Node.Index mod 3) <> 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TNodeForm.MLTreeStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/PropertiesDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/PropertiesDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/PropertiesDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/PropertiesDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/PropertiesDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,297 @@
+unit PropertiesDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - Property page like string tree with individual node editors.
+// - Incremental search.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, VirtualTrees, ImgList, ExtCtrls;
+
+type
+ TPropertiesForm = class(TForm)
+ VST3: TVirtualStringTree;
+ Label9: TLabel;
+ Label10: TLabel;
+ TreeImages: TImageList;
+ RadioGroup1: TRadioGroup;
+ procedure FormCreate(Sender: TObject);
+ procedure VST3Change(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure VST3CreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
+ procedure VST3Editing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
+ procedure VST3GetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure VST3GetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer);
+ procedure VST3GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure VST3InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+ procedure VST3InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure VST3PaintText(Sender: TBaseVirtualTree; const Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType);
+ procedure VST3IncrementalSearch(Sender: TBaseVirtualTree; Node: PVirtualNode; const Text: WideString;
+ var Result: Integer);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure VST3StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+ end;
+
+var
+ PropertiesForm: TPropertiesForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ Editors, Math, Main, States;
+
+{$R *.DFM}
+
+//----------------- TPropertiesForm ------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.FormCreate(Sender: TObject);
+
+begin
+ // Always tell the tree how much data space per node it must allocated for us. We can do this here, in the
+ // property inspector or in the OnGetNodeDataSize event.
+ VST3.NodeDataSize := SizeOf(TPropertyData);
+ // The VCL (D7 and lower) still uses 16 color image lists. We create a high color version explicitely because it
+ // looks so much nicer.
+ ConvertToHighColor(TreeImages);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+
+begin
+ case Node.Index of
+ 0:
+ ChildCount := 13;
+ 1:
+ ChildCount := 8;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+var
+ Data: PPropertyData;
+
+begin
+ if ParentNode = nil then
+ InitialStates := InitialStates + [ivsHasChildren, ivsExpanded]
+ else
+ begin
+ Data := Sender.GetNodeData(Node);
+ Data.ValueType := ValueTypes[ParentNode.Index, Node.Index];
+ if Data.ValueType = vtDate then
+ Data.Value := DateToStr(Now)
+ else
+ Data.Value := DefaultValue[ParentNode.Index, Node.Index];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+
+var
+ Data: PPropertyData;
+
+begin
+ if TextType = ttNormal then
+ case Column of
+ 0:
+ if Node.Parent = Sender.RootNode then
+ begin
+ // root nodes
+ if Node.Index = 0 then
+ Text := 'Description'
+ else
+ Text := 'Origin';
+ end
+ else
+ Text := PropertyTexts[Node.Parent.Index, Node.Index, ptkText];
+ 1:
+ begin
+ Data := Sender.GetNodeData(Node);
+ Text := Data.Value;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3GetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+
+begin
+ // Add a dummy hint to the normal hint to demonstrate multiline hints.
+ if (Column = 0) and (Node.Parent <> Sender.RootNode) then
+ Text := PropertyTexts[Node.Parent.Index, Node.Index, ptkHint] + #13 + '(Multiline hints are supported too).';
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3GetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
+ Column: TColumnIndex; var Ghosted: Boolean; var Index: Integer);
+
+var
+ Data: PPropertyData;
+
+begin
+ if (Kind in [ikNormal, ikSelected]) and (Column = 0) then
+ begin
+ if Node.Parent = Sender.RootNode then
+ Index := 12 // root nodes, this is an open folder
+ else
+ begin
+ Data := Sender.GetNodeData(Node);
+ if Data.ValueType <> vtNone then
+ Index := 14
+ else
+ Index := 13;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3Editing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
+
+var
+ Data: PPropertyData;
+
+begin
+ with Sender do
+ begin
+ Data := GetNodeData(Node);
+ Allowed := (Node.Parent <> RootNode) and (Column = 1) and (Data.ValueType <> vtNone);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3Change(Sender: TBaseVirtualTree; Node: PVirtualNode);
+
+begin
+ with Sender do
+ begin
+ // Start immediate editing as soon as another node gets focused.
+ if Assigned(Node) and (Node.Parent <> RootNode) and not (tsIncrementalSearching in TreeStates) then
+ begin
+ // Note: the test whether a node can really be edited is done in the OnEditing event.
+ EditNode(Node, 1);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3CreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ out EditLink: IVTEditLink);
+
+// This is the callback of the tree control to ask for an application defined edit link. Providing one here allows
+// us to control the editing process up to which actual control will be created.
+// TPropertyEditLink implements an interface and hence benefits from reference counting. We don't need to keep a
+// reference to free it. As soon as the tree finished editing the class will be destroyed automatically.
+
+begin
+ EditLink := TPropertyEditLink.Create;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3PaintText(Sender: TBaseVirtualTree; const Canvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType);
+
+var
+ Data: PPropertyData;
+
+begin
+ // Make the root nodes underlined and draw changed nodes in bold style.
+ if Node.Parent = Sender.RootNode then
+ Canvas.Font.Style := [fsUnderline]
+ else
+ begin
+ Data := Sender.GetNodeData(Node);
+ if Data.Changed then
+ Canvas.Font.Style := [fsBold]
+ else
+ Canvas.Font.Style := [];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3IncrementalSearch(Sender: TBaseVirtualTree; Node: PVirtualNode; const Text: WideString;
+ var Result: Integer);
+
+var
+ S,
+ PropText: string;
+
+begin
+ // Note: This code requires a proper Unicode/WideString comparation routine which I did not want to link here for
+ // size and clarity reasons. For now strings are (implicitely) converted to ANSI to make the comparation work.
+ // Search is not case sensitive.
+ S := Text;
+ SetStatusbarText('Searching for: ' + S);
+
+ if Node.Parent = Sender.RootNode then
+ begin
+ // root nodes
+ if Node.Index = 0 then
+ PropText := 'Description'
+ else
+ PropText := 'Origin';
+ end
+ else
+ begin
+ PropText := PropertyTexts[Node.Parent.Index, Node.Index, ptkText];
+ end;
+
+ // By using StrLIComp we can specify a maximum length to compare. This allows us to find also nodes
+ // which match only partially. Don't forget to specify the shorter string length as search length.
+ Result := StrLIComp(PChar(S), PChar(PropText), Min(Length(S), Length(PropText)))
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.RadioGroup1Click(Sender: TObject);
+
+begin
+ with Sender as TRadioGroup do
+ if ItemIndex = 0 then
+ VST3.IncrementalSearchDirection := sdForward
+ else
+ VST3.IncrementalSearchDirection := sdBackward;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TPropertiesForm.VST3StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if tsIncrementalSearching in Enter then
+ // Note: Unicode will be converted to ANSI here, but for demonstration purposes we accept that for now.
+ SetStatusbarText('Searching for: ' + Sender.SearchBuffer);
+ if tsIncrementalSearching in Leave then
+ SetStatusbarText('');
+
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Arabic.uni
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Arabic.uni
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Background.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Background.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Background2.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Background2.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Book.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Book.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Chart.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Chart.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Chinese.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Chinese.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Clipboard.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Clipboard.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Cyrillic.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Cyrillic.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Earth.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Earth.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Exit.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Exit.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.aps
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.aps
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.rc
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.rc 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.rc 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,8 @@
+Arabic Unicode "Arabic.uni"
+Hebrew Unicode "Hebrew.uni"
+Greek Unicode "Greek.uni"
+
+LoremIpsum Unicode "Lorem ipsum.uni"
+
+Transcriptions Bitmap "Transcriptions.bmp"
+
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ExtraRes.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Eye.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Eye.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Fist.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Fist.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ForeignStrings.rc
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ForeignStrings.rc 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ForeignStrings.rc 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,5 @@
+Arabic Unicode "Arabic.uni"
+Hebrew Unicode "Hebrew.uni"
+Greek Unicode "Greek.uni"
+
+LoremIpsum Unicode "Lorem ipsum.uni"
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ForeignStrings.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/ForeignStrings.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Greek.uni
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Greek.uni
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Header.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Header.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Hebrew.uni
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Hebrew.uni
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Image list 24x24.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Image list 24x24.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Image list 32x32.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Image list 32x32.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Lorem ipsum.uni
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Lorem ipsum.uni
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Multiline.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Multiline.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Omega.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Omega.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Paintbrush.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Paintbrush.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Sheets.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Sheets.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Transcriptions.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/Transcriptions.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/XP.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/Res/XP.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/SpeedDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/SpeedDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/SpeedDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/SpeedDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/SpeedDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,198 @@
+unit SpeedDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - Speed.
+// - Background image.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, VirtualTrees, ExtDlgs, ComCtrls, jpeg;
+
+type
+ TSpeedForm = class(TForm)
+ Label1: TLabel;
+ VST1: TVirtualStringTree;
+ Label3: TLabel;
+ Label6: TLabel;
+ GroupBox2: TGroupBox;
+ SBCheckBox: TCheckBox;
+ LoadBackgroundButton: TButton;
+ GroupBox1: TGroupBox;
+ AddRootButton: TButton;
+ NodeCountEdit: TEdit;
+ AddChildButton: TButton;
+ DeleteSelectionButton: TButton;
+ Label4: TLabel;
+ OPD: TOpenPictureDialog;
+ Label2: TLabel;
+ Label5: TLabel;
+ Label7: TLabel;
+ Label8: TLabel;
+ ClearButton: TButton;
+ procedure SBCheckBoxClick(Sender: TObject);
+ procedure LoadBackgroundButtonClick(Sender: TObject);
+ procedure ClearButtonClick(Sender: TObject);
+ procedure AddButtonClick(Sender: TObject);
+ procedure VST1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure VST1Change(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure VST1StructureChange(Sender: TBaseVirtualTree; Node: PVirtualNode; Reason: TChangeReason);
+ procedure DeleteSelectionButtonClick(Sender: TObject);
+ procedure VST1StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+ end;
+
+var
+ SpeedForm: TSpeedForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ Math, States;
+
+{$R *.DFM}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.AddButtonClick(Sender: TObject);
+
+var
+ Count: Integer;
+ Start: Cardinal;
+
+begin
+ Screen.Cursor := crHourGlass;
+ with VST1 do
+ try
+ Start := GetTickCount;
+ case (Sender as TButton).Tag of
+ 0: // add to root
+ begin
+ Count := StrToInt(NodeCountEdit.Text);
+ RootNodeCount := Integer(RootNodeCount) + Count;
+ end;
+ 1: // add as child
+ if Assigned(FocusedNode) then
+ begin
+ Count := StrToInt(NodeCountEdit.Text);
+ ChildCount[FocusedNode] := Integer(ChildCount[FocusedNode]) + Count;
+ Expanded[FocusedNode] := True;
+ InvalidateToBottom(FocusedNode);
+ end;
+ end;
+ Label1.Caption := Format('Last operation duration: %d ms', [GetTickCount - Start]);
+ Label3.Caption := Format('Nodes in tree: %d', [VST1.TotalCount]);
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.ClearButtonClick(Sender: TObject);
+
+var
+ Start: Cardinal;
+
+begin
+ Screen.Cursor := crHourGlass;
+ try
+ Start := GetTickCount;
+ VST1.Clear;
+ Label1.Caption := Format('Clear operation duration: %d ms', [GetTickCount - Start]);
+ Label3.Caption := 'Nodes in tree: 0';
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.LoadBackgroundButtonClick(Sender: TObject);
+
+begin
+ with OPD do
+ begin
+ if Execute then
+ begin
+ VST1.Background.LoadFromFile(FileName);
+ if SBCheckBox.Checked then
+ VST1.Invalidate
+ else
+ SBCheckBox.Checked := True;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.SBCheckBoxClick(Sender: TObject);
+
+begin
+ if SBCheckBox.Checked then
+ VST1.TreeOptions.PaintOptions := VST1.TreeOptions.PaintOptions + [toShowBackground]
+ else
+ VST1.TreeOptions.PaintOptions := VST1.TreeOptions.PaintOptions - [toShowBackground];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.VST1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+
+begin
+ Text := Format('Level %d, Index %d', [Sender.GetNodeLevel(Node), Node.Index]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.VST1Change(Sender: TBaseVirtualTree; Node: PVirtualNode);
+
+begin
+ Label6.Caption := Format('Selected: %d', [VST1.SelectedCount]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.VST1StructureChange(Sender: TBaseVirtualTree; Node: PVirtualNode; Reason: TChangeReason);
+
+begin
+ Label6.Caption := Format('Selected: %d', [VST1.SelectedCount]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.DeleteSelectionButtonClick(Sender: TObject);
+
+var
+ Start: Cardinal;
+
+begin
+ Screen.Cursor := crHourGlass;
+ try
+ Start := GetTickCount;
+ VST1.DeleteSelectedNodes;
+ Label1.Caption := Format('Delete operation duration: %d ms', [GetTickCount - Start]);
+ Label3.Caption := 'Nodes in tree: ' + IntToStr(VST1.TotalCount);
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TSpeedForm.VST1StateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/States.dfm
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/States.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/States.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,495 @@
+object StateForm: TStateForm
+ Left = 11
+ Top = 11
+ BorderStyle = bsToolWindow
+ Caption = 'Watch Virtual Treeview at work:'
+ ClientHeight = 512
+ ClientWidth = 423
+ Color = clBtnFace
+ Font.Charset = ANSI_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Arial Narrow'
+ Font.Style = []
+ OldCreateOrder = False
+ PixelsPerInch = 96
+ TextHeight = 15
+ object EnableCheckBox: TCheckBox
+ Left = 8
+ Top = 12
+ Width = 141
+ Height = 17
+ Caption = 'Enable state tracking'
+ TabOrder = 0
+ OnClick = EnableCheckBoxClick
+ end
+ object GroupBox1: TGroupBox
+ Left = 16
+ Top = 36
+ Width = 201
+ Height = 85
+ Caption = ' Changes: '
+ TabOrder = 1
+ object CheckBox1: TCheckBox
+ Left = 8
+ Top = 16
+ Width = 140
+ Height = 17
+ Caption = 'Change pending'
+ Enabled = False
+ TabOrder = 0
+ end
+ object CheckBox3: TCheckBox
+ Left = 8
+ Top = 32
+ Width = 140
+ Height = 17
+ Caption = 'Clear focus selection'
+ Enabled = False
+ TabOrder = 1
+ end
+ object CheckBox4: TCheckBox
+ Left = 8
+ Top = 48
+ Width = 140
+ Height = 17
+ Caption = 'Clear pending'
+ Enabled = False
+ TabOrder = 2
+ end
+ object CheckBox32: TCheckBox
+ Left = 8
+ Top = 64
+ Width = 140
+ Height = 17
+ Caption = 'Structure change pending'
+ Enabled = False
+ TabOrder = 3
+ end
+ end
+ object GroupBox2: TGroupBox
+ Left = 16
+ Top = 216
+ Width = 201
+ Height = 149
+ Caption = ' Mouse actions: '
+ TabOrder = 2
+ object CheckBox8: TCheckBox
+ Left = 8
+ Top = 112
+ Width = 140
+ Height = 17
+ Caption = 'Draw selection pending'
+ Enabled = False
+ TabOrder = 0
+ end
+ object CheckBox9: TCheckBox
+ Left = 8
+ Top = 128
+ Width = 140
+ Height = 17
+ Caption = 'Draw selecting'
+ Enabled = False
+ TabOrder = 1
+ end
+ object CheckBox19: TCheckBox
+ Left = 8
+ Top = 16
+ Width = 140
+ Height = 17
+ Caption = 'Left mouse button down'
+ Enabled = False
+ TabOrder = 2
+ end
+ object CheckBox20: TCheckBox
+ Left = 8
+ Top = 32
+ Width = 140
+ Height = 17
+ Caption = 'Mouse check pending'
+ Enabled = False
+ TabOrder = 3
+ end
+ object CheckBox21: TCheckBox
+ Left = 8
+ Top = 48
+ Width = 153
+ Height = 17
+ Caption = 'Middle mouse button down'
+ Enabled = False
+ TabOrder = 4
+ end
+ object CheckBox27: TCheckBox
+ Left = 8
+ Top = 64
+ Width = 140
+ Height = 17
+ Caption = 'Right mouse button down'
+ Enabled = False
+ TabOrder = 5
+ end
+ object CheckBox43: TCheckBox
+ Left = 8
+ Top = 80
+ Width = 129
+ Height = 17
+ Caption = 'Mouse wheel panning'
+ Enabled = False
+ TabOrder = 6
+ end
+ object CheckBox44: TCheckBox
+ Left = 8
+ Top = 96
+ Width = 129
+ Height = 17
+ Caption = 'Mouse wheel scrolling'
+ Enabled = False
+ TabOrder = 7
+ end
+ end
+ object GroupBox3: TGroupBox
+ Left = 228
+ Top = 300
+ Width = 185
+ Height = 101
+ Caption = ' Keyboard actions: '
+ TabOrder = 3
+ object CheckBox10: TCheckBox
+ Left = 8
+ Top = 32
+ Width = 140
+ Height = 17
+ Caption = 'Editing'
+ Enabled = False
+ TabOrder = 0
+ end
+ object CheckBox11: TCheckBox
+ Left = 8
+ Top = 48
+ Width = 140
+ Height = 17
+ Caption = 'Edit pending'
+ Enabled = False
+ TabOrder = 1
+ end
+ object CheckBox15: TCheckBox
+ Left = 8
+ Top = 80
+ Width = 165
+ Height = 17
+ Caption = 'Incremental search in progress'
+ Enabled = False
+ TabOrder = 2
+ end
+ object CheckBox16: TCheckBox
+ Left = 8
+ Top = 64
+ Width = 153
+ Height = 17
+ Caption = 'Incremental search pending'
+ Enabled = False
+ TabOrder = 3
+ end
+ object CheckBox18: TCheckBox
+ Left = 8
+ Top = 16
+ Width = 140
+ Height = 17
+ Caption = 'Key check pending'
+ Enabled = False
+ TabOrder = 4
+ end
+ end
+ object GroupBox4: TGroupBox
+ Left = 228
+ Top = 36
+ Width = 185
+ Height = 161
+ Caption = ' Clipboard and drag'#39'n drop actions: '
+ TabOrder = 4
+ object CheckBox5: TCheckBox
+ Left = 8
+ Top = 96
+ Width = 140
+ Height = 17
+ Caption = 'Clipboard flushing'
+ Enabled = False
+ TabOrder = 0
+ end
+ object CheckBox6: TCheckBox
+ Left = 8
+ Top = 112
+ Width = 140
+ Height = 17
+ Caption = 'Clipboard copy pending'
+ Enabled = False
+ TabOrder = 1
+ end
+ object CheckBox7: TCheckBox
+ Left = 8
+ Top = 128
+ Width = 140
+ Height = 17
+ Caption = 'Clipboard cut pending'
+ Enabled = False
+ TabOrder = 2
+ end
+ object CheckBox24: TCheckBox
+ Left = 8
+ Top = 80
+ Width = 157
+ Height = 17
+ Caption = 'OLE drag'#39'n drop in progress'
+ Enabled = False
+ TabOrder = 3
+ end
+ object CheckBox25: TCheckBox
+ Left = 8
+ Top = 64
+ Width = 140
+ Height = 17
+ Caption = 'OLE drag'#39'n drop pending'
+ Enabled = False
+ TabOrder = 4
+ end
+ object CheckBox37: TCheckBox
+ Left = 8
+ Top = 48
+ Width = 161
+ Height = 17
+ Caption = 'VCL dd with app. drag object'
+ Enabled = False
+ TabOrder = 5
+ end
+ object CheckBox41: TCheckBox
+ Left = 8
+ Top = 16
+ Width = 153
+ Height = 17
+ Caption = 'VCL drag'#39'n drop in progress'
+ Enabled = False
+ TabOrder = 6
+ end
+ object CheckBox42: TCheckBox
+ Left = 8
+ Top = 32
+ Width = 140
+ Height = 17
+ Caption = 'VCL drag'#39'n drop pending'
+ Enabled = False
+ TabOrder = 7
+ end
+ end
+ object GroupBox5: TGroupBox
+ Left = 16
+ Top = 124
+ Width = 201
+ Height = 85
+ Caption = ' Tree cache: '
+ TabOrder = 5
+ object CheckBox31: TCheckBox
+ Left = 8
+ Top = 16
+ Width = 185
+ Height = 17
+ Caption = 'Tree cache validation stop request'
+ Enabled = False
+ TabOrder = 0
+ end
+ object CheckBox36: TCheckBox
+ Left = 8
+ Top = 64
+ Width = 140
+ Height = 17
+ Caption = 'Tree cache valid'
+ Enabled = False
+ TabOrder = 1
+ end
+ object CheckBox39: TCheckBox
+ Left = 8
+ Top = 32
+ Width = 161
+ Height = 17
+ Caption = 'Tree cache is being validated'
+ Enabled = False
+ TabOrder = 2
+ end
+ object CheckBox40: TCheckBox
+ Left = 8
+ Top = 48
+ Width = 161
+ Height = 17
+ Caption = 'Tree cache invalid or unused'
+ Enabled = False
+ TabOrder = 3
+ end
+ end
+ object GroupBox6: TGroupBox
+ Left = 228
+ Top = 204
+ Width = 185
+ Height = 93
+ Caption = ' Collapse/Expand/Scroll: '
+ TabOrder = 6
+ object CheckBox2: TCheckBox
+ Left = 8
+ Top = 16
+ Width = 133
+ Height = 17
+ Caption = 'Full collapse in progress'
+ Enabled = False
+ TabOrder = 0
+ end
+ object CheckBox12: TCheckBox
+ Left = 8
+ Top = 32
+ Width = 129
+ Height = 17
+ Caption = 'Full expand in progress'
+ Enabled = False
+ TabOrder = 1
+ end
+ object CheckBox28: TCheckBox
+ Left = 8
+ Top = 48
+ Width = 61
+ Height = 17
+ Caption = 'Scrolling'
+ Enabled = False
+ TabOrder = 2
+ end
+ object CheckBox29: TCheckBox
+ Left = 8
+ Top = 64
+ Width = 110
+ Height = 17
+ Caption = 'Auto scroll pending'
+ Enabled = False
+ TabOrder = 3
+ end
+ end
+ object GroupBox7: TGroupBox
+ Left = 228
+ Top = 404
+ Width = 185
+ Height = 101
+ Caption = ' Miscellanous: '
+ TabOrder = 7
+ object CheckBox13: TCheckBox
+ Left = 8
+ Top = 32
+ Width = 165
+ Height = 17
+ Caption = 'Last hint window was from VT'
+ Enabled = False
+ TabOrder = 0
+ end
+ object CheckBox14: TCheckBox
+ Left = 8
+ Top = 64
+ Width = 140
+ Height = 17
+ Caption = 'In animation'
+ Enabled = False
+ TabOrder = 1
+ end
+ object CheckBox17: TCheckBox
+ Left = 8
+ Top = 80
+ Width = 140
+ Height = 17
+ Caption = 'Iterating'
+ Enabled = False
+ TabOrder = 2
+ end
+ object CheckBox23: TCheckBox
+ Left = 8
+ Top = 48
+ Width = 140
+ Height = 17
+ Caption = 'Need root count update'
+ Enabled = False
+ TabOrder = 3
+ end
+ object CheckBox33: TCheckBox
+ Left = 8
+ Top = 16
+ Width = 140
+ Height = 17
+ Caption = 'Synchronous mode active'
+ Enabled = False
+ TabOrder = 4
+ end
+ end
+ object GroupBox8: TGroupBox
+ Left = 16
+ Top = 372
+ Width = 201
+ Height = 133
+ Caption = ' Window related actions: '
+ TabOrder = 8
+ object CheckBox22: TCheckBox
+ Left = 8
+ Top = 112
+ Width = 140
+ Height = 17
+ Caption = 'Default node height scale'
+ Enabled = False
+ TabOrder = 0
+ end
+ object CheckBox26: TCheckBox
+ Left = 8
+ Top = 64
+ Width = 140
+ Height = 17
+ Caption = 'Tree painting'
+ Enabled = False
+ TabOrder = 1
+ end
+ object CheckBox30: TCheckBox
+ Left = 8
+ Top = 48
+ Width = 140
+ Height = 17
+ Caption = 'Window resizing'
+ Enabled = False
+ TabOrder = 2
+ end
+ object CheckBox34: TCheckBox
+ Left = 8
+ Top = 80
+ Width = 140
+ Height = 17
+ Caption = 'Tumb tracking (scrollbar)'
+ Enabled = False
+ TabOrder = 3
+ end
+ object CheckBox35: TCheckBox
+ Left = 8
+ Top = 96
+ Width = 140
+ Height = 17
+ Caption = 'Updates locked'
+ Enabled = False
+ TabOrder = 4
+ end
+ object CheckBox38: TCheckBox
+ Left = 8
+ Top = 16
+ Width = 185
+ Height = 17
+ Caption = 'Windows XP Theme support in use'
+ Enabled = False
+ TabOrder = 5
+ end
+ object CheckBox45: TCheckBox
+ Left = 8
+ Top = 32
+ Width = 181
+ Height = 17
+ Caption = 'Treewindow is under construction'
+ Enabled = False
+ TabOrder = 6
+ end
+ end
+end
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/States.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/States.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/States.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,210 @@
+unit States;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, VirtualTrees;
+
+type
+ TStateForm = class(TForm)
+ EnableCheckBox: TCheckBox;
+ GroupBox1: TGroupBox;
+ CheckBox1: TCheckBox;
+ CheckBox3: TCheckBox;
+ CheckBox4: TCheckBox;
+ CheckBox32: TCheckBox;
+ GroupBox2: TGroupBox;
+ CheckBox8: TCheckBox;
+ CheckBox9: TCheckBox;
+ CheckBox19: TCheckBox;
+ CheckBox20: TCheckBox;
+ CheckBox21: TCheckBox;
+ CheckBox27: TCheckBox;
+ CheckBox43: TCheckBox;
+ CheckBox44: TCheckBox;
+ GroupBox3: TGroupBox;
+ CheckBox10: TCheckBox;
+ CheckBox11: TCheckBox;
+ CheckBox15: TCheckBox;
+ CheckBox16: TCheckBox;
+ CheckBox18: TCheckBox;
+ GroupBox4: TGroupBox;
+ CheckBox5: TCheckBox;
+ CheckBox6: TCheckBox;
+ CheckBox7: TCheckBox;
+ CheckBox24: TCheckBox;
+ CheckBox25: TCheckBox;
+ CheckBox37: TCheckBox;
+ CheckBox41: TCheckBox;
+ CheckBox42: TCheckBox;
+ GroupBox5: TGroupBox;
+ CheckBox31: TCheckBox;
+ CheckBox36: TCheckBox;
+ CheckBox39: TCheckBox;
+ CheckBox40: TCheckBox;
+ GroupBox6: TGroupBox;
+ CheckBox2: TCheckBox;
+ CheckBox12: TCheckBox;
+ CheckBox28: TCheckBox;
+ CheckBox29: TCheckBox;
+ GroupBox7: TGroupBox;
+ CheckBox13: TCheckBox;
+ CheckBox14: TCheckBox;
+ CheckBox17: TCheckBox;
+ CheckBox23: TCheckBox;
+ CheckBox33: TCheckBox;
+ GroupBox8: TGroupBox;
+ CheckBox22: TCheckBox;
+ CheckBox26: TCheckBox;
+ CheckBox30: TCheckBox;
+ CheckBox34: TCheckBox;
+ CheckBox35: TCheckBox;
+ CheckBox38: TCheckBox;
+ CheckBox45: TCheckBox;
+ procedure EnableCheckBoxClick(Sender: TObject);
+ protected
+ procedure SetActiveState(CheckBox: TCheckBox; Active: Boolean);
+ end;
+
+var
+ StateForm: TStateForm;
+
+procedure UpdateStateDisplay(CurrentStates, Enter, Leave: TVirtualTreeStates);
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+{$R *.dfm}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure UpdateStateDisplay(CurrentStates, Enter, Leave: TVirtualTreeStates);
+
+var
+ NewStates: TVirtualTreeStates;
+
+begin
+ with StateForm do
+ if EnableCheckBox.Checked then
+ begin
+ // At this point the new states are not yet set. So construct the new set here.
+ NewStates := CurrentStates + Enter - Leave;
+ SetActiveState(CheckBox1, tsChangePending in NewStates);
+ SetActiveState(CheckBox2, tsCollapsing in NewStates);
+ SetActiveState(CheckBox3, tsClearFocusedSelection in NewStates);
+ SetActiveState(CheckBox4, tsClearPending in NewStates);
+ SetActiveState(CheckBox5, tsClipboardFlushing in NewStates);
+ SetActiveState(CheckBox6, tsCopyPending in NewStates);
+ SetActiveState(CheckBox7, tsCutPending in NewStates);
+ SetActiveState(CheckBox8, tsDrawSelPending in NewStates);
+ SetActiveState(CheckBox9, tsDrawSelecting in NewStates);
+ SetActiveState(CheckBox10, tsEditing in NewStates);
+ SetActiveState(CheckBox11, tsEditPending in NewStates);
+ SetActiveState(CheckBox12, tsExpanding in NewStates);
+ SetActiveState(CheckBox13, tsHint in NewStates);
+ SetActiveState(CheckBox14, tsInAnimation in NewStates);
+ SetActiveState(CheckBox15, tsIncrementalSearching in NewStates);
+ SetActiveState(CheckBox16, tsIncrementalSearchPending in NewStates);
+ SetActiveState(CheckBox17, tsIterating in NewStates);
+ SetActiveState(CheckBox18, tsKeyCheckPending in NewStates);
+ SetActiveState(CheckBox19, tsLeftButtonDown in NewStates);
+ SetActiveState(CheckBox20, tsMouseCheckPending in NewStates);
+ SetActiveState(CheckBox21, tsMiddleButtonDown in NewStates);
+ SetActiveState(CheckBox22, tsNeedScale in NewStates);
+ SetActiveState(CheckBox23, tsNeedRootCountUpdate in NewStates);
+ SetActiveState(CheckBox24, tsOLEDragging in NewStates);
+ SetActiveState(CheckBox25, tsOLEDragPending in NewStates);
+ SetActiveState(CheckBox26, tsPainting in NewStates);
+ SetActiveState(CheckBox27, tsRightButtonDown in NewStates);
+ SetActiveState(CheckBox28, tsScrolling in NewStates);
+ SetActiveState(CheckBox29, tsScrollPending in NewStates);
+ SetActiveState(CheckBox30, tsSizing in NewStates);
+ SetActiveState(CheckBox31, tsStopValidation in NewStates);
+ SetActiveState(CheckBox32, tsStructureChangePending in NewStates);
+ SetActiveState(CheckBox33, tsSynchMode in NewStates);
+ SetActiveState(CheckBox34, tsThumbTracking in NewStates);
+ SetActiveState(CheckBox35, tsUpdating in NewStates);
+ SetActiveState(CheckBox36, tsUseCache in NewStates);
+ SetActiveState(CheckBox37, tsUserDragObject in NewStates);
+ SetActiveState(CheckBox38, tsUseThemes in NewStates);
+ SetActiveState(CheckBox39, tsValidating in NewStates);
+ SetActiveState(CheckBox40, tsValidationNeeded in NewStates);
+ SetActiveState(CheckBox41, tsVCLDragging in NewStates);
+ SetActiveState(CheckBox42, tsVCLDragPending in NewStates);
+ SetActiveState(CheckBox43, tsWheelPanning in NewStates);
+ SetActiveState(CheckBox44, tsWheelScrolling in NewStates);
+ SetActiveState(CheckBox45, tsWindowCreating in NewStates);
+
+ Update;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TStateForm.EnableCheckBoxClick(Sender: TObject);
+
+begin
+ CheckBox1.Enabled := EnableCheckBox.Checked;
+ CheckBox2.Enabled := EnableCheckBox.Checked;
+ CheckBox3.Enabled := EnableCheckBox.Checked;
+ CheckBox4.Enabled := EnableCheckBox.Checked;
+ CheckBox5.Enabled := EnableCheckBox.Checked;
+ CheckBox6.Enabled := EnableCheckBox.Checked;
+ CheckBox7.Enabled := EnableCheckBox.Checked;
+ CheckBox8.Enabled := EnableCheckBox.Checked;
+ CheckBox9.Enabled := EnableCheckBox.Checked;
+ CheckBox10.Enabled := EnableCheckBox.Checked;
+ CheckBox11.Enabled := EnableCheckBox.Checked;
+ CheckBox12.Enabled := EnableCheckBox.Checked;
+ CheckBox13.Enabled := EnableCheckBox.Checked;
+ CheckBox14.Enabled := EnableCheckBox.Checked;
+ CheckBox15.Enabled := EnableCheckBox.Checked;
+ CheckBox16.Enabled := EnableCheckBox.Checked;
+ CheckBox17.Enabled := EnableCheckBox.Checked;
+ CheckBox18.Enabled := EnableCheckBox.Checked;
+ CheckBox19.Enabled := EnableCheckBox.Checked;
+ CheckBox20.Enabled := EnableCheckBox.Checked;
+ CheckBox21.Enabled := EnableCheckBox.Checked;
+ CheckBox22.Enabled := EnableCheckBox.Checked;
+ CheckBox23.Enabled := EnableCheckBox.Checked;
+ CheckBox24.Enabled := EnableCheckBox.Checked;
+ CheckBox25.Enabled := EnableCheckBox.Checked;
+ CheckBox26.Enabled := EnableCheckBox.Checked;
+ CheckBox27.Enabled := EnableCheckBox.Checked;
+ CheckBox28.Enabled := EnableCheckBox.Checked;
+ CheckBox29.Enabled := EnableCheckBox.Checked;
+ CheckBox30.Enabled := EnableCheckBox.Checked;
+ CheckBox31.Enabled := EnableCheckBox.Checked;
+ CheckBox32.Enabled := EnableCheckBox.Checked;
+ CheckBox33.Enabled := EnableCheckBox.Checked;
+ CheckBox34.Enabled := EnableCheckBox.Checked;
+ CheckBox35.Enabled := EnableCheckBox.Checked;
+ CheckBox36.Enabled := EnableCheckBox.Checked;
+ CheckBox37.Enabled := EnableCheckBox.Checked;
+ CheckBox38.Enabled := EnableCheckBox.Checked;
+ CheckBox39.Enabled := EnableCheckBox.Checked;
+ CheckBox40.Enabled := EnableCheckBox.Checked;
+ CheckBox41.Enabled := EnableCheckBox.Checked;
+ CheckBox42.Enabled := EnableCheckBox.Checked;
+ CheckBox43.Enabled := EnableCheckBox.Checked;
+ CheckBox44.Enabled := EnableCheckBox.Checked;
+ CheckBox45.Enabled := EnableCheckBox.Checked;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TStateForm.SetActiveState(CheckBox: TCheckBox; Active: Boolean);
+
+begin
+ CheckBox.Checked := Active;
+ if Active then
+ CheckBox.Font.Style := [fsBold]
+ else
+ CheckBox.Font.Style := [];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/VisibilityDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/VisibilityDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/VisibilityDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/VisibilityDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/VisibilityDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,338 @@
+unit VisibilityDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - Hide nodes.
+// - Synchronization between 2 trees (expand, scroll, selection).
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, VirtualTrees, ComCtrls, ExtCtrls, ImgList;
+
+type
+ TVisibilityForm = class(TForm)
+ Label17: TLabel;
+ RadioGroup1: TRadioGroup;
+ VST2: TVirtualStringTree;
+ VST1: TVirtualStringTree;
+ VST3: TVirtualStringTree;
+ Splitter2: TSplitter;
+ Panel2: TPanel;
+ Label1: TLabel;
+ Label2: TLabel;
+ Label3: TLabel;
+ Label4: TLabel;
+ procedure VST1InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+ procedure VST1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure FormCreate(Sender: TObject);
+ procedure RadioGroup1Click(Sender: TObject);
+ procedure VST2GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure VST3Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
+ procedure VST2InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+ procedure VST2Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
+ procedure VSTCollapsedExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure VST2Change(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure Splitter2CanResize(Sender: TObject; var NewSize: Integer;
+ var Accept: Boolean);
+ procedure Splitter2Paint(Sender: TObject);
+ procedure VST1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure FormShow(Sender: TObject);
+ procedure FormHide(Sender: TObject);
+ private
+ FChanging: Boolean;
+ procedure HideNodes(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean);
+ end;
+
+var
+ VisibilityForm: TVisibilityForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses States;
+
+{$R *.DFM}
+
+type
+ PLinkData = ^TLinkData;
+ TLinkData = record
+ Caption: WideString;
+ OtherNode: PVirtualNode;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VST1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+var
+ Level: Integer;
+
+begin
+ Level := Sender.GetNodeLevel(Node);
+ if Level < 4 then
+ Include(InitialStates, ivsHasChildren);
+ if Level > 0 then
+ Node.CheckType := TCheckType(Level)
+ else
+ Node.CheckType := ctTriStateCheckBox;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VST1InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+
+begin
+ ChildCount := Random(5);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.FormCreate(Sender: TObject);
+
+var
+ Run1, Run2: PVirtualNode;
+ Data1, Data2: PLinkData;
+
+begin
+ Randomize;
+ VST1.RootNodeCount := 5;
+
+ // The base idea behind linking two (or more) trees together is that one has access to the nodes of the others.
+ // This can be reached in several ways. I use here the simplest approach by validating both trees fully and creating
+ // cross references for all nodes. Another one would be to create a common data base and link all trees to this.
+ VST2.NodeDataSize := SizeOf(TLinkData);
+ VST2.RootNodeCount := 5;
+ VST3.NodeDataSize := SizeOf(TLinkData);
+ VST3.RootNodeCount := 5;
+
+ VST3.BackgroundOffsetX := Splitter2.Left + Splitter2.Width;
+
+ // Create cross references. This will validate all nodes.
+ Run1 := VST2.GetFirst;
+ Run2 := VST3.GetFirst;
+ while Assigned(Run1) do
+ begin
+ Data1 := VST2.GetNodeData(Run1);
+ Data1.OtherNode := Run2;
+ Data2 := VST3.GetNodeData(Run2);
+ Data2.OtherNode := Run1;
+ Run1 := VST2.GetNext(Run1);
+ Run2 := VST3.GetNext(Run2);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.HideNodes(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean);
+
+begin
+ case Integer(Data) of
+ 0: // show all nodes
+ Sender.IsVisible[Node] := True;
+ 1: // hide every second
+ Sender.IsVisible[Node] := not Odd(Node.Index);
+ 2: // hide nodes with child nodes only
+ Sender.IsVisible[Node] := not Sender.HasChildren[Node];
+ 3: // hide all
+ Sender.IsVisible[Node] := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.RadioGroup1Click(Sender: TObject);
+
+begin
+ with Sender as TRadioGroup do
+ begin
+ VST1.BeginUpdate;
+ try
+ VST1.IterateSubtree(nil, HideNodes, Pointer(ItemIndex), [], True);
+ finally
+ VST1.EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VST2GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+
+var
+ Data: PLinkData;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ if Length(Data.Caption) = 0 then
+ Data.Caption := 'Node ' + IntToStr(Sender.AbsoluteIndex(Node));
+
+ Text := Data.Caption;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VST3Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
+
+// Synchronizes scroll offsets of VST2 and VST3.
+
+begin
+ if not FChanging then
+ begin
+ FChanging := True;
+ try
+ VST3.Update;
+ VST2.OffsetY := VST3.OffsetY;
+ VST2.Update;
+ finally
+ FChanging := False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VST2Scroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
+
+// Synchronizes scroll offsets of VST2 and VST3.
+
+begin
+ if not FChanging then
+ begin
+ FChanging := True;
+ try
+ VST2.Update;
+ VST3.OffsetY := VST2.OffsetY;
+ VST3.Update;
+ finally
+ FChanging := False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VST2InitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+
+begin
+ ChildCount := Sender.GetNodeLevel(Node) + 2;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VSTCollapsedExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode);
+
+// Collapse/Expand state synchronization.
+
+var
+ OtherTree: TBaseVirtualTree;
+ Data: PLinkData;
+
+begin
+ // Avoid recursive calls.
+ if not FChanging then
+ begin
+ FChanging := True;
+ try
+ if Sender = VST2 then
+ OtherTree := VST3
+ else
+ OtherTree := VST2;
+
+ Data := Sender.GetNodeData(Node);
+ OtherTree.ToggleNode(Data.OtherNode);
+ finally
+ FChanging := False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VST2Change(Sender: TBaseVirtualTree; Node: PVirtualNode);
+
+// Keep selected nodes in sync.
+
+var
+ Data: PLinkData;
+ OtherTree: TBaseVirtualTree;
+
+begin
+ if not FChanging and Assigned(Node) then
+ begin
+ FChanging := True;
+ try
+ Data := Sender.GetNodeData(Node);
+ if Sender = VST2 then
+ OtherTree := VST3
+ else
+ OtherTree := VST2;
+
+ OtherTree.Selected[Data.OtherNode] := True;
+ OtherTree.FocusedNode := Data.OtherNode;
+ finally
+ FChanging := False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.Splitter2CanResize(Sender: TObject; var NewSize: Integer; var Accept: Boolean);
+
+// This method is called just before resizing is done. This is a good opportunity to adjust the background image
+// offset.
+
+begin
+ VST3.BackgroundOffsetX := NewSize + Splitter2.Width;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.Splitter2Paint(Sender: TObject);
+
+begin
+ with Splitter2, Canvas do
+ begin
+ Brush.Color := clBtnFace;
+ FillRect(Rect(0, 0, Width, VST2.Header.Height));
+ Brush.Color := clWindow;
+ FillRect(Rect(0, VST2.Header.Height, Width, Height));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.VST1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var CellText: WideString);
+
+begin
+ CellText := Format('Node Level %d, Index %d', [Sender.GetNodeLevel(Node), Node.Index]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.FormShow(Sender: TObject);
+
+begin
+ StateForm.Hide;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVisibilityForm.FormHide(Sender: TObject);
+
+begin
+ StateForm.Show;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/WindowsXPStyleDemo.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/WindowsXPStyleDemo.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/WindowsXPStyleDemo.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/WindowsXPStyleDemo.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Advanced/WindowsXPStyleDemo.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,284 @@
+unit WindowsXPStyleDemo;
+
+// Virtual Treeview sample form demonstrating following features:
+// - Windows XP style treeview.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ {$ifdef VER140}
+ Variants,
+ {$endif}
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
+ Dialogs, VirtualTrees, ImgList, ComCtrls, ToolWin, Menus, StdCtrls;
+
+type
+ TWindowsXPForm = class(TForm)
+ XPTree: TVirtualStringTree;
+ LargeImages: TImageList;
+ SmallImages: TImageList;
+ CoolBar1: TCoolBar;
+ ToolBar1: TToolBar;
+ ToolButton1: TToolButton;
+ ToolButton2: TToolButton;
+ ToolButton3: TToolButton;
+ ToolButton4: TToolButton;
+ ToolButton5: TToolButton;
+ ToolButton6: TToolButton;
+ Label1: TLabel;
+ Label2: TLabel;
+ Label4: TLabel;
+ ToolButton8: TToolButton;
+ ToolButton9: TToolButton;
+ PrintDialog: TPrintDialog;
+ procedure XPTreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
+ Column: TColumnIndex; var Ghosted: Boolean; var Index: Integer);
+ procedure FormCreate(Sender: TObject);
+ procedure XPTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure XPTreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal);
+ procedure XPTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+ procedure XPTreeHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState;
+ X, Y: Integer);
+ procedure XPTreeCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex;
+ var Result: Integer);
+ procedure XPTreeGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+ procedure Label4Click(Sender: TObject);
+ procedure ToolButton9Click(Sender: TObject);
+ procedure XPTreeStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+ end;
+
+var
+ WindowsXPForm: TWindowsXPForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ Main, ShellAPI, Printers, States;
+
+{$R *.dfm}
+
+type
+ PEntry = ^TEntry;
+ TEntry = record
+ Caption: WideString;
+ Image: Integer;
+ Size: Int64;
+ end;
+
+var
+ TreeEntries: array[0..17] of TEntry = (
+ (Caption: 'My Computer'; Image: 0; Size: 0),
+ (Caption: 'Network Places'; Image: 1; Size: 0),
+ (Caption: 'Recycle Bin'; Image: 2; Size: 0),
+ (Caption: 'My Documents'; Image: 3; Size: 0),
+ (Caption: 'My Music'; Image: 4; Size: 0),
+ (Caption: 'My Pictures'; Image: 5; Size: 0),
+ (Caption: 'Control Panel'; Image: 6; Size: 0),
+ (Caption: 'Help'; Image: 7; Size: 0),
+ (Caption: 'Help Document'; Image: 8; Size: 0),
+ (Caption: 'User Accounts'; Image: 9; Size: 0),
+ (Caption: 'Internet'; Image: 10; Size: 0),
+ (Caption: 'Network Group'; Image: 11; Size: 0),
+ (Caption: 'Folder'; Image: 12; Size: 0),
+ (Caption: 'Window'; Image: 13; Size: 0),
+ (Caption: 'Warning'; Image: 14; Size: 0),
+ (Caption: 'Information'; Image: 15; Size: 0),
+ (Caption: 'Critical'; Image: 16; Size: 0),
+ (Caption: 'Security'; Image: 17; Size: 0)
+ );
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.XPTreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var Index: Integer);
+
+var
+ Data: PEntry;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ case Kind of
+ ikNormal, ikSelected:
+ if (Column = 0) and (Node.Parent = Sender.RootNode) then
+ Index := Data.Image;
+ ikState:
+ case Column of
+ 0:
+ if Node.Parent <> Sender.RootNode then
+ Index := 21;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.FormCreate(Sender: TObject);
+
+begin
+ XPTree.NodeDataSize := SizeOf(TEntry);
+
+ ConvertToHighColor(LargeImages);
+ ConvertToHighColor(SmallImages);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.XPTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+var
+ Data: PEntry;
+
+begin
+ if ParentNode = nil then
+ begin
+ Include(InitialStates, ivsHasChildren);
+ Data := Sender.GetNodeData(Node);
+ Data^ := TreeEntries[Node.Index mod 18];
+ Data.Size := Random(100000);
+ Node.CheckType := ctCheckBox;
+ end
+ else
+ Node.CheckType := ctRadioButton;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.XPTreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ var ChildCount: Cardinal);
+
+begin
+ ChildCount := 5;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.XPTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+
+var
+ Data: PEntry;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ case Column of
+ 0:
+ if Node.Parent = Sender.RootNode then
+ Text := Data.Caption
+ else
+ Text := 'More entries';
+ 1:
+ if Node.Parent = Sender.RootNode then
+ Text := FloatToStr(Data.Size / 1000) + ' MB'
+ else
+ Text := '';
+ 2:
+ if Node.Parent = Sender.RootNode then
+ Text := 'System Folder'
+ else
+ Text := '';
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.XPTreeHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Button = mbLeft then
+ begin
+ with Sender, Treeview do
+ begin
+ if SortColumn > NoColumn then
+ Columns[SortColumn].Options := Columns[SortColumn].Options + [coParentColor];
+
+ // Do not sort the last column, it contains nothing to sort.
+ if Column = 2 then
+ SortColumn := NoColumn
+ else
+ begin
+ if (SortColumn = NoColumn) or (SortColumn <> Column) then
+ begin
+ SortColumn := Column;
+ SortDirection := sdAscending;
+ end
+ else
+ if SortDirection = sdAscending then
+ SortDirection := sdDescending
+ else
+ SortDirection := sdAscending;
+
+ Columns[SortColumn].Color := $F7F7F7;
+ SortTree(SortColumn, SortDirection, False);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.XPTreeCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode;
+ Column: TColumnIndex; var Result: Integer);
+
+var
+ Data1, Data2: PEntry;
+
+begin
+ Data1 := Sender.GetNodeData(Node1);
+ Data2 := Sender.GetNodeData(Node2);
+ case Column of
+ 0:
+ Result := CompareText(Data1.Caption, Data2.Caption);
+ 1:
+ Result := Data1.Size - Data2.Size;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.XPTreeGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var Text: WideString);
+
+begin
+ // Show only a dummy hint. It is just to demonstrate how to do it.
+ Text := 'Size larger than 536 MB' + #13 +
+ 'Folders: addins, AppPatch, Config, Connection Wizard, ...' + #13 +
+ 'Files: 1280.bmp, 1280x1024.bmp, 2001 94 mars.bmp, ac3api.ini, ...';
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.Label4Click(Sender: TObject);
+
+begin
+ ShellExecute(0, 'open', 'http://groups.yahoo.com/group/VirtualExplorerTree', nil, nil, SW_SHOW);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.ToolButton9Click(Sender: TObject);
+
+begin
+ if PrintDialog.Execute then
+ XPTree.Print(Printer, False);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWindowsXPForm.XPTreeStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates);
+
+begin
+ if not (csDestroying in ComponentState) then
+ UpdateStateDisplay(Sender.TreeStates, Enter, Leave);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Main.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Main.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Main.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Main.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Main.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,176 @@
+unit Main;
+
+// Demonstration project for TVirtualStringTree to generally show how to get started.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ VirtualTrees, StdCtrls, ExtCtrls;
+
+type
+ TMainForm = class(TForm)
+ VST: TVirtualStringTree;
+ ClearButton: TButton;
+ AddOneButton: TButton;
+ Edit1: TEdit;
+ Button1: TButton;
+ Label1: TLabel;
+ CloseButton: TButton;
+ procedure FormCreate(Sender: TObject);
+ procedure ClearButtonClick(Sender: TObject);
+ procedure AddButtonClick(Sender: TObject);
+ procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure VSTInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure CloseButtonClick(Sender: TObject);
+ end;
+
+var
+ MainForm: TMainForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+{$R *.DFM}
+
+type
+ // This is a very simple record we use to store data in the nodes.
+ // Since the application is responsible to manage all data including the node's caption
+ // this record can be considered as minimal requirement in all VT applications.
+ // Extend it to whatever your application needs.
+ PMyRec = ^TMyRec;
+ TMyRec = record
+ Caption: WideString;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.FormCreate(Sender: TObject);
+
+begin
+ // Let the tree know how much data space we need.
+ VST.NodeDataSize := SizeOf(TMyRec);
+ // Set an initial number of nodes.
+ VST.RootNodeCount := 20;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.ClearButtonClick(Sender: TObject);
+
+var
+ Start: Cardinal;
+
+begin
+ Screen.Cursor := crHourGlass;
+ try
+ Start := GetTickCount;
+ VST.Clear;
+ Label1.Caption := Format('Last operation duration: %d ms', [GetTickCount - Start]);
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.AddButtonClick(Sender: TObject);
+
+var
+ Count: Cardinal;
+ Start: Cardinal;
+
+begin
+ // Add some nodes to the treeview.
+ Screen.Cursor := crHourGlass;
+ with VST do
+ try
+ Start := GetTickCount;
+ case (Sender as TButton).Tag of
+ 0: // add to root
+ begin
+ Count := StrToInt(Edit1.Text);
+ RootNodeCount := RootNodeCount + Count;
+ end;
+ 1: // add as child
+ if Assigned(FocusedNode) then
+ begin
+ Count := StrToInt(Edit1.Text);
+ ChildCount[FocusedNode] := ChildCount[FocusedNode] + Count;
+ Expanded[FocusedNode] := True;
+ InvalidateToBottom(FocusedNode);
+ end;
+ end;
+ Label1.Caption := Format('Last operation duration: %d ms', [GetTickCount - Start]);
+ finally
+ Screen.Cursor := crDefault;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+
+var
+ Data: PMyRec;
+
+begin
+ // A handler for the OnGetText event is always needed as it provides the tree with the string data to display.
+ // Note that we are always using WideString.
+ Data := Sender.GetNodeData(Node);
+ if Assigned(Data) then
+ Text := Data.Caption;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.VSTFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
+
+var
+ Data: PMyRec;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ // Explicitely free the string, the VCL cannot know that there is one but needs to free
+ // it nonetheless. For more fields in such a record which must be freed use Finalize(Data^) instead touching
+ // every member individually.
+ if Assigned(Data) then
+ Data.Caption := '';
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.VSTInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+var
+ Data: PMyRec;
+
+begin
+ with Sender do
+ begin
+ Data := GetNodeData(Node);
+ // Construct a node caption. This event is triggered once for each node but
+ // appears asynchronously, which means when the node is displayed not when it is added.
+ Data.Caption := Format('Level %d, Index %d', [GetNodeLevel(Node), Node.Index]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.CloseButtonClick(Sender: TObject);
+
+begin
+ Close;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Minimal.dpr
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Minimal.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Minimal.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,14 @@
+program Minimal;
+
+uses
+ Forms,
+ Main in 'Main.pas' {MainForm};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TMainForm, MainForm);
+ Application.Run;
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Minimal.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Minimal/Minimal.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Main.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Main.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Main.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Main.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Main.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,661 @@
+unit Main;
+
+// Virtual Treeview sample application demonstrating clipboard and drag'n drop operations.
+// The treeview uses OLE for these operations but can also issue and accept VCL drag'n drop.
+// Written by Mike Lischke.
+
+interface
+
+uses
+ Windows, Messages, ActiveX, SysUtils, Forms, Dialogs, Graphics,
+ VirtualTrees, ActnList, ComCtrls, ExtCtrls, StdCtrls, Controls, Classes;
+
+type
+ TMainForm = class(TForm)
+ ActionList1: TActionList;
+ CutAction: TAction;
+ CopyAction: TAction;
+ PasteAction: TAction;
+ FontDialog: TFontDialog;
+ Panel3: TPanel;
+ Label6: TLabel;
+ Button1: TButton;
+ Button3: TButton;
+ Tree2: TVirtualStringTree;
+ Label1: TLabel;
+ Tree1: TVirtualStringTree;
+ Label2: TLabel;
+ PageControl1: TPageControl;
+ LogTabSheet: TTabSheet;
+ RichTextTabSheet: TTabSheet;
+ LogListBox: TListBox;
+ RichEdit1: TRichEdit;
+ Label3: TLabel;
+ Label7: TLabel;
+ Button2: TButton;
+ TabSheet1: TTabSheet;
+ Label8: TLabel;
+ TabSheet2: TTabSheet;
+ Label4: TLabel;
+ Label5: TLabel;
+ Label9: TLabel;
+ Label10: TLabel;
+ procedure Button1Click(Sender: TObject);
+ procedure CutActionExecute(Sender: TObject);
+ procedure CopyActionExecute(Sender: TObject);
+ procedure PasteActionExecute(Sender: TObject);
+ procedure Tree1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+ procedure FormCreate(Sender: TObject);
+ procedure TreeDragDrop(Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject;
+ Formats: TFormatArray; Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode);
+ procedure Button2Click(Sender: TObject);
+ procedure TreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+ procedure Tree1NewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; Text: WideString);
+ procedure Button3Click(Sender: TObject);
+ procedure Tree2DragAllowed(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
+ procedure TreeDragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState;
+ Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean);
+ procedure Tree2BeforeItemErase(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
+ var ItemColor: TColor; var EraseAction: TItemEraseAction);
+ private
+ procedure AddUnicodeText(DataObject: IDataObject; Target: TVirtualStringTree; Mode: TVTNodeAttachMode);
+ procedure AddVCLText(Target: TVirtualStringTree; const Text: WideString; Mode: TVTNodeAttachMode);
+ function FindCPFormatDescription(CPFormat: Word): string;
+ procedure InsertData(Sender: TVirtualStringTree; DataObject: IDataObject; Formats: TFormatArray; Effect: Integer;
+ Mode: TVTNodeAttachMode);
+ end;
+
+var
+ MainForm: TMainForm;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ TypInfo, ShlObj, UrlMon;
+
+{$R *.DFM}
+{$R Res\Extra.res} // Contains a little rich text for the rich edit control and a XP manifest.
+
+type
+ PNodeData = ^TNodeData;
+ TNodeData = record
+ Caption: WideString;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.Button1Click(Sender: TObject);
+
+begin
+ Close;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.CutActionExecute(Sender: TObject);
+
+begin
+ if ActiveControl = Tree1 then
+ Tree1.CutToClipboard
+ else
+ if ActiveControl = Tree2 then
+ Tree2.CutToClipboard
+ else
+ if ActiveControl = RichEdit1 then
+ RichEdit1.CutToClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.CopyActionExecute(Sender: TObject);
+
+begin
+ if ActiveControl = Tree1 then
+ Tree1.CopyToClipboard
+ else
+ if ActiveControl = Tree2 then
+ Tree2.CopyToClipboard
+ else
+ if ActiveControl = RichEdit1 then
+ RichEdit1.CopyToClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.PasteActionExecute(Sender: TObject);
+
+var
+ DataObject: IDataObject;
+ EnumFormat: IEnumFormatEtc;
+ Format: TFormatEtc;
+ Formats: TFormatArray;
+ Fetched: Integer;
+ Tree: TVirtualStringTree;
+
+begin
+ if ActiveControl is TVirtualStringTree then
+ begin
+ Tree := ActiveControl as TVirtualStringTree;
+
+ if LogListBox.Items.Count > 0 then
+ LogListBox.Items.Add('');
+ if ActiveControl = Tree1 then
+ LogListBox.Items.Add('----- Tree 1')
+ else
+ LogListBox.Items.Add('----- Tree 2');
+
+ if Tree.PasteFromClipboard then
+ LogListBox.Items.Add('Native tree data pasted.')
+ else
+ begin
+ LogListBox.Items.Add('Other data pasted.');
+ // Some other data was pasted. Enumerate the available formats and try to add the data.
+ // 1) Get a data object for the data.
+ OLEGetClipboard(DataObject);
+ // 2) Enumerate all offered formats and create a format array from it which can be used in InsertData.
+ if Succeeded(DataObject.EnumFormatEtc(DATADIR_GET, EnumFormat)) then
+ begin
+ EnumFormat.Reset;
+ while EnumFormat.Next(1, Format, @Fetched) = S_OK do
+ begin
+ SetLength(Formats, Length(Formats) + 1);
+ Formats[High(Formats)] := Format.cfFormat;
+ end;
+
+ InsertData(Tree, DataObject, Formats, DROPEFFECT_COPY, Tree.DefaultPasteMode);
+ end;
+ end;
+ end
+ else
+ if ActiveControl = RichEdit1 then
+ RichEdit1.PasteFromClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.Tree1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+
+var
+ Data: PNodeData;
+
+begin
+ if TextType = ttNormal then
+ begin
+ Data := Sender.GetNodeData(Node);
+ Text := Data.Caption;
+ end
+ else
+ Text := '';
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.FormCreate(Sender: TObject);
+
+var
+ Stream: TResourceStream;
+
+begin
+ Tree1.NodeDataSize := SizeOf(TNodeData);
+ Tree1.RootNodeCount := 30;
+ Tree2.NodeDataSize := SizeOf(TNodeData);
+ Tree2.RootNodeCount := 30;
+
+ // There is a small RTF text stored in the resource to have something to display in the rich edit control.
+ Stream := TResourceStream.Create(HInstance, 'RTF', 'RCDATA');
+ try
+ RichEdit1.Lines.LoadFromStream(Stream);
+ finally
+ Stream.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.AddUnicodeText(DataObject: IDataObject; Target: TVirtualStringTree; Mode: TVTNodeAttachMode);
+
+// This method is called when the drop handler gets called with Unicode text as only
+// understandable clipboard format. This text is retrieved and splitted in lines.
+// Every line is then added as new node.
+
+var
+ FormatEtc: TFormatEtc;
+ Medium: TStgMedium;
+ OLEData,
+ Head, Tail: PWideChar;
+ TargetNode,
+ Node: PVirtualNode;
+ Data: PNodeData;
+
+begin
+ if Mode <> amNowhere then
+ begin
+ // fill the structure used to get the Unicode string
+ with FormatEtc do
+ begin
+ cfFormat := CF_UNICODETEXT;
+ // no specific target device
+ ptd := nil;
+ // normal content to render
+ dwAspect := DVASPECT_CONTENT;
+ // no specific page of multipage data
+ lindex := -1;
+ // pass the data via memory
+ tymed := TYMED_HGLOBAL;
+ end;
+
+ // Check if we can get the Unicode text data.
+ if DataObject.QueryGetData(FormatEtc) = S_OK then
+ begin
+ // Data is accessible so finally get a pointer to it
+ if DataObject.GetData(FormatEtc, Medium) = S_OK then
+ begin
+ OLEData := GlobalLock(Medium.hGlobal);
+ if Assigned(OLEData) then
+ begin
+ Target.BeginUpdate;
+ TargetNode := Target.DropTargetNode;
+ if TargetNode = nil then
+ TargetNode := Target.FocusedNode;
+
+ Head := OLEData;
+ try
+ while Head^ <> #0 do
+ begin
+ Tail := Head;
+ while not (Tail^ in [WideChar(#0), WideChar(#13), WideChar(#10)]) do
+ Inc(Tail);
+ if Head <> Tail then
+ begin
+ // add a new node if we got a non-empty caption
+ Node := Target.InsertNode(TargetNode, Mode);
+ Data := Target.GetNodeData(Node);
+ SetString(Data.Caption, Head, Tail - Head);
+ end;
+ // skip line separators
+ if Tail^ = #13 then
+ Inc(Tail);
+ if Tail^ = #10 then
+ Inc(Tail);
+ Head := Tail;
+ end;
+ finally
+ GlobalUnlock(Medium.hGlobal);
+ Target.EndUpdate;
+ end;
+ end;
+ // never forget to free the storage medium
+ ReleaseStgMedium(Medium);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.AddVCLText(Target: TVirtualStringTree; const Text: WideString; Mode: TVTNodeAttachMode);
+
+// This method is called when the drop handler gets called with a VCL drag source.
+// The given text is retrieved and splitted in lines.
+
+var
+ Head, Tail: PWideChar;
+ TargetNode,
+ Node: PVirtualNode;
+ Data: PNodeData;
+
+begin
+ if Mode <> amNowhere then
+ begin
+ Target.BeginUpdate;
+ try
+ TargetNode := Target.DropTargetNode;
+ if TargetNode = nil then
+ TargetNode := Target.FocusedNode;
+
+ Head := PWideChar(Text);
+ while Head^ <> #0 do
+ begin
+ Tail := Head;
+ while not (Tail^ in [WideChar(#0), WideChar(#13), WideChar(#10)]) do
+ Inc(Tail);
+ if Head <> Tail then
+ begin
+ // add a new node if we got a non-empty caption
+ Node := Target.InsertNode(TargetNode, Mode);
+ Data := Target.GetNodeData(Node);
+ SetString(Data.Caption, Head, Tail - Head);
+ end;
+ // skip line separators
+ if Tail^ = #13 then
+ Inc(Tail);
+ if Tail^ = #10 then
+ Inc(Tail);
+ Head := Tail;
+ end;
+ finally
+ Target.EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TMainForm.FindCPFormatDescription(CPFormat: Word): string;
+
+var
+ Buffer: array[0..2048] of Char;
+
+begin
+ // Try the formats support the by Virtual Treeview first.
+ Result := GetVTClipboardFormatDescription(CPFormat);
+
+ // Retrieve additional formats from system.
+ if Length(Result) = 0 then
+ begin
+ if GetClipboardFormatName(CPFormat, @Buffer, 2048) > 0 then
+ Result := ' - ' + Buffer
+ else
+ Result := Format(' - unknown format (%d)', [CPFormat]);
+ end
+ else
+ Result := ' - ' + Result;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.TreeDragDrop(Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject;
+ Formats: TFormatArray; Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode);
+
+ //--------------- local function --------------------------------------------
+
+ procedure DetermineEffect;
+
+ // Determine the drop effect to use if the source is a Virtual Treeview.
+
+ begin
+ // In the case the source is a Virtual Treeview we know 'move' is the default if dragging within
+ // the same tree and copy if dragging to another tree. Set Effect accordingly.
+ if Shift = [] then
+ begin
+ // No modifier key, so use standard action.
+ if Source = Sender then
+ Effect := DROPEFFECT_MOVE
+ else
+ Effect := DROPEFFECT_COPY;
+ end
+ else
+ begin
+ // A modifier key is pressed, hence use this to determine action.
+ if (Shift = [ssAlt]) or (Shift = [ssCtrl, ssAlt]) then
+ Effect := DROPEFFECT_LINK
+ else
+ if Shift = [ssCtrl] then
+ Effect := DROPEFFECT_COPY
+ else
+ Effect := DROPEFFECT_MOVE;
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ S: string;
+ Attachmode: TVTNodeAttachMode;
+ Nodes: TNodeArray;
+ I: Integer;
+
+begin
+ Nodes := nil;
+
+ if LogListBox.Items.Count > 0 then
+ LogListBox.Items.Add('');
+ if Sender = Tree1 then
+ LogListBox.Items.Add('----- Tree 1')
+ else
+ LogListBox.Items.Add('----- Tree 2');
+
+ if DataObject = nil then
+ LogListBox.Items.Add('VCL drop arrived')
+ else
+ LogListBox.Items.Add('OLE drop arrived');
+
+ S := 'Drop actions allowed:';
+ if Boolean(DROPEFFECT_COPY and Effect) then
+ S := S + ' copy';
+ if Boolean(DROPEFFECT_MOVE and Effect) then
+ S := S + ' move';
+ if Boolean(DROPEFFECT_LINK and Effect) then
+ S := S + ' link';
+ LogListBox.Items.Add(S);
+
+ S := 'Drop mode: ' + GetEnumName(TypeInfo(TDropMode), Ord(Mode));
+ LogListBox.Items.Add(S);
+
+ // Translate the drop position into an node attach mode.
+ case Mode of
+ dmAbove:
+ AttachMode := amInsertBefore;
+ dmOnNode:
+ AttachMode := amAddChildLast;
+ dmBelow:
+ AttachMode := amInsertAfter;
+ else
+ AttachMode := amNowhere;
+ end;
+
+ if DataObject = nil then
+ begin
+ // VCL drag'n drop. Handling this requires detailed knowledge about the sender and its data. This is one reason
+ // why it was a bad decision by Borland to implement something own instead using the system's way.
+ // In this demo we have two known sources of VCL dd data: Tree2 and LogListBox.
+ if Source = Tree2 then
+ begin
+ // Since we know this is a Virtual Treeview we can ignore the drop event entirely and use VT mechanisms.
+ DetermineEffect;
+ Nodes := Tree2.GetSortedSelection(True);
+ if Effect = DROPEFFECT_COPY then
+ begin
+ for I := 0 to High(Nodes) do
+ Tree2.CopyTo(Nodes[I], Sender.DropTargetNode, AttachMode, False);
+ end
+ else
+ for I := 0 to High(Nodes) do
+ Tree2.MoveTo(Nodes[I], Sender.DropTargetNode, AttachMode, False);
+ end
+ else
+ begin
+ // One long string (one node) is added, containing all text currently in the list box.
+ AddVCLText(Sender as TVirtualStringTree, LogListBox.Items.CommaText, AttachMode);
+ LogListBox.Items.Add('List box data accepted as string.');
+ end;
+ end
+ else
+ begin
+ // OLE drag'n drop. Perform full processing.
+
+ LogListBox.Items.Add('There are ' + IntToStr(Length(Formats)) + ' formats available:');
+
+ // Determine action in advance even if we don't use the dropped data.
+ // Note: The Effect parameter is a variable which must be set to the action we
+ // will actually take, to notify the sender of the drag operation about remaining actions.
+ // This value determines what the caller will do after the method returns,
+ // e.g. if DROPEFFECT_MOVE is returned then the source data will be deleted.
+ if Source is TBaseVirtualTree then
+ begin
+ DetermineEffect;
+ end
+ else
+ // Prefer copy if allowed for every other drag source. Alone from Effect you cannot determine the standard action
+ // of the sender, but we assume if copy is allowed then it is also the standard action
+ // (e.g. as in TRichEdit).
+ if Boolean(Effect and DROPEFFECT_COPY) then
+ Effect := DROPEFFECT_COPY
+ else
+ Effect := DROPEFFECT_MOVE;
+
+ InsertData(Sender as TVirtualStringTree, DataObject, Formats, Effect, AttachMode);
+ end;
+
+ // scroll last added entry into view
+ LogListBox.ItemIndex := LogListBox.Items.Count - 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.Button2Click(Sender: TObject);
+
+begin
+ LogListBox.Clear;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.TreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates);
+
+var
+ Data: PNodeData;
+
+begin
+ Data := Sender.GetNodeData(Node);
+ // set a generic caption only if there is not already one (e.g. from drag operations)
+ if Length(Data.Caption) = 0 then
+ Data.Caption := Format('Node Index %d', [Node.Index]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.Tree1NewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; Text: WideString);
+
+var
+ Data: PNodeData;
+
+// Tree1 as well as Tree2 use the soSaveCaptions StringOption which enables automatic caption store action
+// when tree data is serialized into memory (e.g. for drag'n drop). Restoring the caption is done by triggering
+// this event for each loaded node.
+// This mechanism frees us from implementing a SaveNode and LoadNode event since we have only the caption to store.
+
+begin
+ Data := Sender.GetNodeData(Node);
+ Data.Caption := Text;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.Button3Click(Sender: TObject);
+
+begin
+ with FontDialog do
+ begin
+ Font := Tree1.Font;
+ if Execute then
+ begin
+ Tree1.Font := Font;
+ Tree2.Font := Font;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.Tree2DragAllowed(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
+
+// Tree 2 uses manual drag start to tell which node might be dragged.
+
+begin
+ Allowed := Odd(Node.Index);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.TreeDragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState;
+ Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean);
+
+begin
+ Accept := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.Tree2BeforeItemErase(Sender: TBaseVirtualTree; Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
+ var ItemColor: TColor; var EraseAction: TItemEraseAction);
+
+// The second tree uses manual drag and we want to show the lines which are allowed to start a drag operation by
+// a colored background.
+
+begin
+ if Odd(Node.Index) then
+ begin
+ ItemColor := $FFEEEE;
+ EraseAction := eaColor;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMainForm.InsertData(Sender: TVirtualStringTree; DataObject: IDataObject; Formats: TFormatArray;
+ Effect: Integer; Mode: TVTNodeAttachMode);
+
+var
+ FormatAccepted: Boolean;
+ I: Integer;
+
+begin
+ // Go through each available format and see if we can make sense of it.
+ FormatAccepted := False;
+ for I := 0 to High(Formats) do
+ begin
+ case Formats[I] of
+ // standard clipboard formats
+ CF_UNICODETEXT:
+ begin
+ LogListBox.Items.Add(' - Unicode text');
+
+ // As demonstration for non-tree data here an implementation for Unicode text.
+ // Formats are placed in preferred order in the formats parameter. Hence if
+ // there is native tree data involved in this drop operation then it has been
+ // caught earlier in the loop and FormatAccepted is already True.
+ if not FormatAccepted then
+ begin
+ // Unicode text data was dropped (e.g. from RichEdit1) add this line by line
+ // as new nodes.
+ AddUnicodeText(DataObject, Sender as TVirtualStringTree, Mode);
+ LogListBox.Items.Add('+ Unicode accepted');
+ FormatAccepted := True;
+ end;
+ end;
+ else
+ if Formats[I] = CF_VIRTUALTREE then
+ begin
+ // this is our native tree format
+ LogListBox.Items.Add(' - native Virtual Treeview data');
+
+ if not FormatAccepted then
+ begin
+ Sender.ProcessDrop(DataObject, Sender.DropTargetNode, Effect, Mode);
+ LogListBox.Items.Add('+ native Virtual Treeview data accepted');
+ // Indicate that we found a format we accepted so the data is not used twice.
+ FormatAccepted := True;
+ end;
+ end
+ else
+ if Formats[I] = CF_VTREFERENCE then
+ LogListBox.Items.Add(' - Virtual Treeview reference')
+ else
+ begin
+ // Predefined, shell specific, MIME specific or application specific clipboard data.
+ LogListBox.Items.Add(FindCPFormatDescription(Formats[I]));
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/OLE.dpr
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/OLE/OLE.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/OLE/OLE.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,14 @@
+program OLE;
+
+uses
+ Forms,
+ Main in 'Main.pas' {MainForm};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.Title := 'OLE Drag''n drop and cut''n paste demo';
+ Application.CreateForm(TMainForm, MainForm);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/OLE.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/OLE.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Res/Extra.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Res/Extra.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Res/Text.rtf
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Res/Text.rtf 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/OLE/Res/Text.rtf 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,26 @@
+{\rtf1\fbidis\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\fswiss\fprq2\fcharset0 Arial;}{\f1\fswiss\fcharset0 Arial;}{\f2\froman\fprq2\fcharset128 MS PMincho;}{\f3\froman\fprq2\fcharset0 MS PMincho;}{\f4\fswiss\fprq2\fcharset178 Arial;}}
+{\colortbl ;\red0\green0\blue255;\red255\green0\blue0;}
+{\stylesheet{ Normal;}{\s1 heading 1;}{\s2 heading 2;}{\s3 heading 3;}{\s4 heading 4;}}
+\viewkind4\uc1\pard\ltrpar\s1\sb100\sa100\lang2057\kerning36\b\f0\fs24 Execution\lang1024 \fs20 \lang2057\fs48\par
+\pard\ltrpar\lang1031\kerning0\b0\f1\fs20{\pict\wmetafile8\picw1764\pich882\picwgoal8160\pichgoal15
+010009000003310000000000070000000000050000000b0200000000050000000c02f401e80307
+0000001b04f401e8030000000005000000140200000000050000001302f401e803050000001402
+f40100000500000013020000e803030000000000
+}\f0\fs24\par
+\cf1\lang2057\b\i\fs15 Send feedback\cf0\b0 to MSDN.\i0\fs24 \cf1\b\i\fs15 Look here\cf0\b0\par
+\pard\ltrpar\sa240\i0\fs24\line\cf2\i\fs15 This is preliminary documentation and subject to change.\cf0\i0\fs24 \line\cf1\b\i\fs15 Send feedback\b0 \cf0 on this topic.\i0\fs24 \par
+\pard\ltrpar\fs20 The common language runtime provides the infrastructure that enables managed\line execution to take place as well as a variety of services that can be used during \line execution. Before a method can be executed, it must be compiled to processor-specific \line code. Each method for which Microsoft intermediate language (MSIL) has been \line generated is JIT-compiled when it is called for the first time, then executed. The next \line time the method is executed, the existing JIT-compiled native code is executed. \line The process of JIT compiling and then executing the code is repeated until execution \line is complete. During execution, managed code receives services such as automatic \line memory management, security, interoperability with unmanaged code, cross-language \line debugging support, and enhanced deployment and versioning support.\fs24\par
+\pard\ltrpar\s4\sb100\sa100\b See Also\par
+\pard\ltrpar\cf1\b0\fs20 Managed Execution Process\cf0 | \cf1 Securing Your Application\cf0 \cf1 | Interoperating with \line Unmanaged Code\cf0 | \cf1 Deploying .NET Framework Applications\cf0\fs24\par
+\par
+\par
+\fs20 Excerpt from the book "Analects":\par
+\fs24\par
+\lang1031\f2\'81\'77\lang2057\'82\'50\lang1031\'81\'78\'8e\'71\'9e\'48\lang2057\'81\'46\lang1031\'81\'75\'9b\'7b\'8e\'a7\'8e\'9e\'8f\'4b\'94\'56\lang2057\'81\'43\lang1031\'95\'73\'96\'92\u35498?\'8c\'c1\lang2057\'81\'48\lang1031\'97\'4c\'95\'fc\'8e\'a9\'89\'93\'95\'fb\'98\'d2\lang2057\'81\'43\lang1031\'95\'73\'96\'92\'9e\'d9\'8c\'c1\lang2057\'81\'48\lang1031\'90\'6c\'95\'73\'92\'6d\'8e\'a7\'95\'73\'9c\'b0\lang2057\'81\'43\lang1031\'95\'73\'96\'92\'8c\'4e\'8e\'71\'8c\'c1\lang2057\'81\'48\lang1031\'81\'76\lang2057\f3\u8233?\u8233?\f2\par
+\lang1031\'81\'77\lang2057\'82\'51\lang1031\'81\'78\'97\'4c\'8e\'71\'9e\'48\lang2057\'81\'46\lang1031\'81\'75\'91\'b4\'88\'d7\'90\'6c\'96\'e7\'8d\'46\'92\'ed\lang2057\'81\'43\lang1031\'8e\'a7\'8d\'44\'94\'c6\'8f\'e3\'8e\'d2\lang2057\'81\'43\lang1031\'91\'4e\'e1\'e1\lang2057\'81\'47\lang1031\'95\'73\'8d\'44\'94\'c6\'8f\'e3\lang2057\'81\'43\lang1031\'8e\'a7\'8d\'44\'8d\'ec\'98\'aa\'8e\'d2\lang2057\'81\'43\lang1031\'96\'a2\'94\'56\'97\'4c\'96\'e7\'81\'42\'8c\'4e\'8e\'71\'96\'b1\'96\'7b\'81\'43\'96\'7b\'97\'a7\'8e\'a7\'93\'b9\'90\'b6\'81\'42\'8d\'46\'92\'ed\'96\'e7\'8e\'d2\'81\'43\'91\'b4\'88\'d7\'90\'6d\'94\'56\'96\'7b\'e4\'6f\'81\'49\'81\'76\f3\u8233?\u8233?\f2\par
+\'81\'77\'82\'52\'81\'78\'8e\'71\'9e\'48\'81\'46\'81\'75\'8d\'49\'8c\'be\'97\'df\'90\'46\'81\'43\'91\'4e\'e1\'e1\'90\'6d\'81\'49\'81\'76\f3\u8233?\u8233?\f0\fs20\par
+\par
+Arabic text "Wisdom is simple, but hard to find.":\par
+\f4\rtlch\fs32\'c7\'e1\'cd\'df\'e3\'c9 \'c8\'d3\'ed\'d8\'c9 \'e6 \'d3\'e5\'e1\'c9\'a1\'c7\'e1\'d5\'da\'c8 \'e5\'e6 \'c7\'ed\'cc\'c7\'cf\'e5\'c7\f0\ltrch\fs20\par
+}
+
\ No newline at end of file
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemo.dpr
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemo.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemo.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,23 @@
+program MVCDemo;
+
+{ (c) 2000 Marian Aldenhövel
+ Hainstraße 8
+ 53121 Bonn
+ +49 228 6203366
+ Fax: +49 228 624031
+ marian at mba-software.de
+
+ Free: You may use this code in every way you find it useful or fun. }
+
+uses
+ Forms,
+ MVCDemoMain in 'MVCDemoMain.pas' {fmMVCDemo},
+ MVCPanel in 'MVCPanel.pas';
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TfmMVCDemo,fmMVCDemo);
+ Application.Run;
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemo.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemo.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemoMain.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemoMain.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemoMain.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemoMain.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCDemoMain.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,213 @@
+unit MVCDemoMain;
+
+{ (c) 2000 Marian Aldenhövel
+ Hainstraße 8
+ 53121 Bonn
+ +49 228 6203366
+ Fax: +49 228 624031
+ marian at mba-software.de
+
+ Free: You may use this code in every way you find it useful or fun.
+
+ Main form for the MVCDemo-Project. See MVCTypes.pas for Details. }
+
+interface
+
+uses Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,
+ MVCTypes,MVCPanel,StdCtrls,ExtCtrls,ImgList,VirtualTrees,ComCtrls,
+ Buttons;
+
+type TfmMVCDemo=class(TForm)
+ pnlControls:TPanel;
+ ImageList1:TImageList;
+ edCaption:TEdit;
+ Label1:TLabel;
+ Label2:TLabel;
+ edSubcaption:TEdit;
+ Label3:TLabel;
+ edIncidence: TEdit;
+ Label4: TLabel;
+ UpDown1: TUpDown;
+ btnAdd: TButton;
+ btnDelete: TButton;
+ cbLive: TCheckBox;
+ timLive: TTimer;
+ procedure FormCreate(Sender:TObject);
+ procedure edCaptionChange(Sender:TObject);
+ procedure TreeViewChange(Sender:TBaseVirtualTree;Node:PVirtualNode);
+ procedure edIncidenceKeyPress(Sender:TObject;var Key:Char);
+ procedure edSubcaptionChange(Sender:TObject);
+ procedure edIncidenceChange(Sender:TObject);
+ procedure btnAddClick(Sender:TObject);
+ procedure btnDeleteClick(Sender: TObject);
+ procedure cbLiveClick(Sender: TObject);
+ procedure timLiveTimer(Sender: TObject);
+ private
+ P:TMVCPanel;
+ FTree:TMVCTree;
+ procedure UpdateFromNode;
+ function FocusedNode:TMVCNode;
+ function CreateDefaultTree:TMVCTree;
+ end;
+
+var fmMVCDemo:TfmMVCDemo;
+
+implementation
+
+{$R *.DFM}
+
+function TfmMVCDemo.CreateDefaultTree:TMVCTree;
+{ recurse and curse :-) }
+var i,j,k:integer;
+begin
+ Result:=TMVCTree.Create;
+ for i:=0 to 2 do
+ with Result.Root.CreateChild do
+ begin
+ Caption:='Root';
+ SubCaption:='Number '+IntToStr(i);
+ Incidence:=5+random(30);
+ for j:=0 to 2 do
+ with CreateChild do
+ begin
+ Caption:='Child';
+ SubCaption:='Number '+IntToStr(j);
+ Incidence:=random(64);
+ for k:=0 to 1 do
+ with CreateChild do
+ begin
+ Caption:='Grandchild';
+ SubCaption:='Number '+IntToStr(k);
+ Incidence:=random(64);
+ end;
+ end;
+ end;
+end;
+
+procedure TfmMVCDemo.FormCreate(Sender: TObject);
+begin
+ P:=TMVCPanel.Create(Self);
+ with P do
+ begin
+ Parent:=Self;
+ Align:=alClient;
+ TreeView.Images:=ImageList1;
+ { Now this is what it's all about:
+ You have a structure - represented here by a call that creates
+ a tree. All you do is assign it to a property of the Viewer,
+ bingo. }
+ FTree:=CreateDefaultTree;
+ Tree:=FTree;
+ P.TreeView.OnChange:=TreeViewChange;
+ P.TreeView.FullExpand(NIL);
+ UpdateFromNode;
+ end;
+end;
+
+procedure TfmMVCDemo.TreeViewChange(Sender:TBaseVirtualTree;Node:PVirtualNode);
+begin
+ UpdateFromNode;
+end;
+
+procedure TfmMVCDemo.UpdateFromNode;
+begin
+ if FocusedNode=NIL
+ then
+ begin
+ edCaption.Text:= '';
+ edCaption.Enabled:= False;
+ edSubCaption.Text:= '';
+ edSubCaption.Enabled:=False;
+ edIncidence.Text:= '';
+ edIncidence.Enabled:= False;
+ btnDelete.Enabled:=False;
+ end
+ else
+ begin
+ edCaption.Text:= FocusedNode.Caption;
+ edCaption.Enabled:= True;
+ edSubCaption.Text:= FocusedNode.SubCaption;
+ edSubCaption.Enabled:=True;
+ edIncidence.Text:= IntToStr(FocusedNode.Incidence);
+ edIncidence.Enabled:= True;
+ btnDelete.Enabled:= True;
+ end;
+end;
+
+function TfmMVCDemo.FocusedNode:TMVCNode;
+begin
+ with P.TreeView do
+ if FocusedNode<>NIL
+ then Result:=MVCNode[FocusedNode]
+ else Result:=NIL;
+end;
+
+procedure TfmMVCDemo.edIncidenceKeyPress(Sender:TObject;var Key:Char);
+begin
+ if not(Key in ['0'..'9',#8]) then Key:=#0;
+end;
+
+procedure TfmMVCDemo.edSubcaptionChange(Sender:TObject);
+begin
+ if FocusedNode<>NIL
+ then FocusedNode.SubCaption:=edSubCaption.Text;
+end;
+
+procedure TfmMVCDemo.edCaptionChange(Sender:TObject);
+begin
+ if FocusedNode<>NIL then FocusedNode.Caption:=edCaption.Text;
+end;
+
+procedure TfmMVCDemo.edIncidenceChange(Sender:TObject);
+begin
+ try
+ if FocusedNode<>NIL then
+ if edIncidence.Text=''
+ then FocusedNode.Incidence:=0
+ else FocusedNode.Incidence:=StrToInt(edIncidence.Text);
+ except
+ ShowMessage('Enter a number between 0 and 63');
+ end;
+end;
+
+procedure TfmMVCDemo.btnAddClick(Sender:TObject);
+var R:TMVCNode;
+begin
+ if FocusedNode<>NIL
+ then R:=FocusedNode
+ else R:=FTree.Root;
+ with R do
+ begin
+ R:=CreateChild;
+ R.Caption:='New';
+ end;
+end;
+
+procedure TfmMVCDemo.btnDeleteClick(Sender: TObject);
+begin
+ FocusedNode.Free;
+end;
+
+procedure TfmMVCDemo.cbLiveClick(Sender: TObject);
+begin
+ timLive.Enabled:=cbLive.Checked;
+end;
+
+procedure TfmMVCDemo.timLiveTimer(Sender: TObject);
+var N:TMVCNode;
+begin
+ { Change the Incidence-Field of one node on every
+ level in one branch of the tree. }
+ N:=FTree.Root;
+ while Assigned(N) do
+ begin
+ N.Incidence:=5+random(63);
+ if N.ChildCount>0
+ then N:=N.Child[random(N.ChildCount)]
+ else N:=NIL;
+ end;
+end;
+
+initialization
+ Randomize;
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCPanel.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCPanel.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCPanel.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,125 @@
+unit MVCPanel;
+
+{ (c) 2000 Marian Aldenhövel
+ Hainstraße 8
+ 53121 Bonn
+ +49 228 6203366
+ Fax: +49 228 624031
+ marian at mba-software.de
+
+ Free: You may use this code in every way you find it useful or fun.
+
+ This declares a Panel that hold another Panel and a TMVCTreeView. In
+ this Application is not at all useful, you could just as well create the
+ components at designtime.
+
+ The reason why the component is here is because it hints at the
+ possibility to use a TMVCTreeView in a hypothetical compound component
+ TMVMTreeEditor that adds more controls that modify the same structure.
+
+ It also shows how to initialize the Columns of a runtime-created
+ TVirtualTree.
+}
+
+interface
+
+uses Windows,Controls,Graphics,SysUtils,Classes,ExtCtrls,StdCtrls,
+ MVCTypes,VirtualTrees;
+
+type TMVCPanel=class(TCustomPanel)
+ private
+ FpnlTop:TPanel;
+ FTrvItems:TMVCTreeView;
+ procedure SetItems(aTree:TMVCTree);
+ function GetItems:TMVCTree;
+ protected
+ procedure CreateWnd; override;
+ public
+ constructor Create(aOwner:TComponent); override;
+
+ property TreeView:TMVCTreeView read FtrvItems;
+ property Tree:TMVCTree read GetItems write SetItems;
+ end;
+
+implementation
+
+procedure TMVCPanel.SetItems(aTree:TMVCTree);
+begin
+ { Just link the Items to the TreeView, no processing of our own. }
+ FtrvItems.Tree:=aTree;
+end;
+
+function TMVCPanel.GetItems:TMVCTree;
+begin
+ Result:=FtrvItems.Tree;
+end;
+
+constructor TMVCPanel.Create(aOwner:TComponent);
+begin
+ inherited Create(aOwner);
+ BevelOuter:=bvNone;
+ Caption:=' ';
+
+ FpnlTop:=TPanel.Create(Self);
+ with FpnlTop do
+ begin
+ Parent:=Self;
+ Align:=alTop;
+ Height:=30;
+ Caption:='SomePanel';
+ BevelOuter:=bvNone;
+ BevelInner:=bvLowered;
+ end;
+
+ FtrvItems:=TMVCTreeView.Create(Self);
+ with FtrvItems do
+ begin
+ Parent:=Self;
+ Align:=alClient;
+ end;
+end;
+
+procedure TMVCPanel.CreateWnd;
+begin
+ inherited CreateWnd;
+
+ with FtrvItems, TreeOptions do
+ begin
+ PaintOptions:=PaintOptions+[toShowButtons, // display collapse/expand
+ toShowHorzGridLines, // display horizontal lines
+ toShowRoot, // show lines also at root level
+ toShowTreeLines, // display tree lines to show
+ // hierarchy of nodes
+ // buttons left to a node
+ toShowVertGridLines]; // display vertical lines
+ // (depending on columns) to
+ // simulate a grid
+ MiscOptions := MiscOptions+[toEditable];
+ SelectionOptions := SelectionOptions+[toExtendedFocus];
+ // to simulate a grid
+ with Header do
+ begin
+ Height:=18;
+ Options:=Options+[hoVisible];
+ Background:=clBtnFace;
+ AutoSize:=True;
+ with Columns.Add do
+ begin
+ Text:='Caption';
+ Width:=300;
+ end;
+ with Columns.Add do
+ begin
+ Text:='SubCaption';
+ Width:=100;
+ end;
+ with Columns.Add do
+ begin
+ Text:='Incidence';
+ Width:=100;
+ end;
+ end;
+ end;
+end;
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCTypes.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCTypes.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Demo/Objects/MVCTypes.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1038 @@
+unit MVCTypes;
+
+{ (c) 2000 Marian Aldenhövel
+ Hainstraße 8
+ 53121 Bonn
+ +49 228 6203366
+ Fax: +49 228 624031
+ marian at mba-software.de
+
+ Free: You may use this code in every way you find it useful or fun.
+
+ Say you have a hierarchical (a flat list is a special case of such
+ a hierarchy :-)) structure in memory or a file. Now you need to
+ visualize that structure or give the user the ability to edit it.
+
+ Traditionally you have two options:
+
+ 1) Store the hierarchy in a TTreeView and should you need more
+ data than a simple hierarchy store pointers to that data in the
+ Data-property of the TTreeNode.
+
+ This is an indecent mix of structure and visualization. The minute
+ you need to access and process that structure whithout displaying
+ it you either need to duplicate it or find yourself using
+ invisible TTreeView - so called TTreeViewNotViews :-).
+
+ 2) Fill a TreeView with your Data and take very good care to
+ propagate each and every change and edit from the TTreeView to
+ your Data.
+
+ This is a real pain in many parts of the body.
+
+ Using Mike Lischkes fantastic virtual tree you can use a more modern
+ approach:
+
+ Make a descendant of the Treeview that "knows" about your structure.
+ The Tree can be linked to your data and will now automatically
+ follow changes and vice-versa. I call this the "assign-and-forget"-
+ Method.
+
+ This demo ist a simplified version of a component I use in one of my
+ current projects. Read the code to find out about it.
+
+ Note that in this demo the definition and implementation of both
+ Structure and Tree are kept in a single unit. This is just for
+ ease of reading and distribution - in a real-world project it is
+ a good idea to keep them separate even if it means exposing fields
+ of the Nodes you would not need to expose otherwise. That way it
+ is easier to replace the visualization or change the implementation
+ of the structure without compromising the system.
+
+ }
+
+
+interface
+
+uses Windows,Messages,SysUtils,Graphics,VirtualTrees,Classes,StdCtrls,
+ Controls,Forms,ImgList;
+
+type { TMVCNode is the encapsulation of a single Node in the structure.
+ This implementation is a bit bloated because in my project
+ everything is in memory at all times.
+ In such an implementation there is not much "virtual" about the
+ tree anymore - still it's of incredible usefulness as you will
+ see. }
+ TMVCNode=class(TObject)
+ private
+ { Here's the data associated with a single Node in the
+ tree. This structure defines a caption and a subcaption, add
+ whatever defines your data completely. }
+ FParent:TMVCNode;
+ FChildren:TList;
+ FCheckState:TCheckState;
+ FCaption,FSubCaption:string;
+ { The FIncidence-Field is special in the way that it's
+ value is never displayed directly but used to
+ graphically alter the node's display. In my project it
+ is a "weight" showing the number of hits from a
+ database. Here it is displayed next to the caption
+ as a colored speck. }
+ FIncidence:integer;
+
+ { Here's where we start to think of visualization. This
+ field points to the VirtualNode in a virtual tree that
+ is associated with the Node - if there is one,
+ otherwise it is NIL, there may be no virtual node
+ allocated for the TMVCNode or no tree linked. }
+ FVirtualNode:PVirtualNode;
+
+ { Here are reader/writer-methods for the properties that
+ define our data. We need set-properties because we want
+ to update linked nodes directly. }
+ procedure SetCaption(aCaption:string);
+ procedure SetSubCaption(aSubCaption:string);
+ procedure SetCheckState(aCheckState:TCheckState);
+ procedure SetIncidence(aValue:integer);
+ function GetChildCount:integer;
+ function GetChild(n:integer):TMVCNode;
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ { Take a look at our data and pick an icon from the
+ Imagelist to be displayed in the tree. }
+ function GetImageIndex:integer; virtual;
+ { Tell the tree to invalidate the node it displayes the
+ information for this Node in. It will be repainted
+ next }
+ procedure InvalidateVirtualNode;
+
+ { properties exposing our internal data to the world.
+ set-methods are given so the Node can always invalidate
+ its node. }
+ property CheckState:TCheckState read FCheckState write SetCheckState;
+ property Caption:string read FCaption write SetCaption;
+ property SubCaption:string read FSubCaption write SetSubCaption;
+ property Incidence:integer read FIncidence write SetIncidence;
+
+ property Parent:TMVCNode read FParent;
+ property ChildCount:integer read GetChildCount;
+ property Child[n:integer]:TMVCNode read GetChild;
+ function CreateChild:TMVCNode;
+ procedure RemoveChild(n:integer);
+ procedure DestroyChild(n:integer);
+
+ { This field is only exposed because I advise you to put
+ the Tree-Code in a separate unit and then you won't get
+ far privatizing it. Allowing public write-access to it
+ is a bit hairy though, you should never write to the
+ field outside of this or the Tree-unit.
+ This is where a friend-declaration is missing from OP}
+ property VirtualNode:PVirtualNode read FVirtualNode write FVirtualNode;
+ end;
+
+ { TMVCTree keeps the TMVCNodes. It also maintains the link to a
+ virtual treeview. }
+ TMVCTree=class
+ private
+ { This is the Root of the Tree. In this Demo that Root is there
+ purely to hold the structure together, it is never displayed -
+ just like TVirtualTrees own Root. }
+ FRoot:TMVCNode;
+
+ { The Viewer-Field points to any component or object
+ used to visualize or edit this structure. It is
+ not really used in this demo, in a real application
+ you will find situations where you have to find out
+ whether you are linked and if so where to.
+
+ Why is the Viewer declared as TObject and not as
+ the specific class? Two reasons:
+
+ 1) The viewer should be implemented in a different
+ unit, either there or here you will have to
+ cast or you will build a circular reference. I
+ choose to cast here because
+
+ 2) You may want to have _different_ viewers for
+ the same structure. Keeping that in mind you
+ may even want to change the declaration to
+ a list of linked viewers... }
+ FSettingViewer:integer;
+ FViewer:TObject;
+
+ { Access-methods to expose the list in a type safe
+ way. }
+
+ { A set-method that updates the link to a viewer. }
+ procedure SetViewer(aViewer:TObject);
+
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ property Root:TMVCNode read FRoot;
+
+ { Assign to this to create or break the link with
+ a viewer. If you are about to add, remove or edit
+ a zillion Nodes you can call BeginUpdate and
+ EndUpdate. In this demo they just do the same for
+ any assigned viewer - Caution: The demo does not
+ make provisions for the case where you call
+ BeginUpdate and then switch to another viewer! }
+ property Viewer:TObject read FViewer write SetViewer;
+ procedure BeginUpdate;
+ procedure EndUpdate;
+ end;
+
+ { Here's the Viewer. I have descended from the base class to maximize
+ the functionality that is moved to our code, should you be happy
+ with any of the predeclared descendants use of them. }
+ TMVCEditLink=class;
+ TMVCTreeView=class(TBaseVirtualTree)
+ private
+ { This is a pointer to the structure associated with
+ this viewer. }
+ FTree:TMVCTree;
+ FInternalDataOffset: Cardinal; // offset to the internal data
+
+ { Make and break the link with a list }
+ procedure SetTree(aTree:TMVCTree);
+
+ { These are for direct access to our structure
+ through the viewer. You can use them to find
+ the TMVCNode that corresponds to a selected
+ VirtualNode for instance. }
+ function GetMVCNode(VirtualNode:PVirtualNode):TMVCNode;
+ procedure SetMVCNode(VirtualNode:PVirtualNode; aNode:TMVCNode);
+
+ function GetOptions: TVirtualTreeOptions;
+ procedure SetOptions(const Value: TVirtualTreeOptions);
+ protected
+ { Overridden methods of the tree, see their implementation for
+ details on what they do and why they are overridden. }
+ function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer; override;
+ procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
+ procedure DoInitChildren(Node:PVirtualNode;var ChildCount:Cardinal); override;
+ procedure DoInitNode(aParent,aNode:PVirtualNode;
+ var aInitStates:TVirtualNodeInitStates); override;
+ procedure DoFreeNode(aNode:PVirtualNode); override;
+ procedure DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer); override;
+ procedure DoChecked(aNode:PVirtualNode); override;
+ function DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; override;
+ function InternalData(Node: PVirtualNode): Pointer;
+ function InternalDataSize: Cardinal;
+
+ function GetOptionsClass: TTreeOptionsClass; override;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ { Properties for the link to a list and the individual Node.
+ these form the interface to the application. See the main form
+ to check it out. }
+ property Tree:TMVCTree read FTree write SetTree;
+ property MVCNode[VirtualNode:PVirtualNode]:TMVCNode read GetMVCNode;
+
+ function GetNodeText(aNode:TMVCNode;
+ aColumn:integer):string;
+ procedure SetNodeText(aNode:TMVCNode;
+ aColumn:integer;
+ aText:string);
+ published
+ { We descend from the base class, publish whatever you want to.
+ The demo only needs the Header, it is initialized in the fixed
+ panel-code. }
+ property TreeOptions: TVirtualTreeOptions read GetOptions write SetOptions;
+ property Header;
+ property Images;
+ property OnChange;
+ end;
+
+ TMVCEdit=class(TCustomEdit)
+ private
+ FLink:TMVCEditLink;
+ procedure WMChar(var Message: TWMChar); message WM_CHAR;
+ procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
+ procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
+ protected
+ procedure AutoAdjustSize;
+ procedure CreateParams(var Params:TCreateParams); override;
+ public
+ constructor Create(Link:TMVCEditLink); reintroduce;
+ end;
+
+ TMVCEditLink=class(TInterfacedObject,IVTEditLink)
+ private
+ FEdit:TMVCEdit; // a normal custom edit control
+ FTree:TMVCTreeView; // a back reference to the tree calling
+ FNode:PVirtualNode; // the node to be edited
+ FColumn:Integer; // the column of the node
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ function BeginEdit: Boolean; stdcall;
+ function CancelEdit: Boolean; stdcall;
+ function EndEdit: Boolean; stdcall;
+ function GetBounds: TRect; stdcall;
+ function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
+ procedure ProcessMessage(var Message: TMessage); stdcall;
+ procedure SetBounds(R:TRect); stdcall;
+
+ property Tree:TMVCTreeView read FTree;
+ end;
+
+
+implementation
+
+{ Let's go }
+
+{ *********************************************************************** }
+
+constructor TMVCNode.Create;
+begin
+ inherited Create;
+ FChildren:=TList.Create;
+end;
+
+destructor TMVCNode.Destroy;
+begin
+ if Assigned(FParent) then
+ with FParent do
+ RemoveChild(FChildren.IndexOf(Self));
+ { When destroying free all children. }
+ while ChildCount>0 do DestroyChild(0);
+
+ inherited Destroy;
+end;
+
+function TMVCNode.GetImageIndex:integer;
+begin
+ { Take a close look at your data and return the index of whatever image
+ you want next to it. Here we base the choice on the length of the
+ caption. No caption, no icon. }
+ if Caption=''
+ then Result:=-1 else Result:=(Length(Caption) mod 4);
+end;
+
+procedure TMVCNode.InvalidateVirtualNode;
+var T:TBaseVirtualTree;
+begin
+ { If the tree has a node that displays this Node then invalidate it. }
+ if Assigned(FVirtualNode) then
+ begin
+ T := TreeFromNode(FVirtualNode);
+ T.InvalidateNode(FVirtualNode);
+ end;
+end;
+
+procedure TMVCNode.SetCheckState(aCheckState:TCheckState);
+begin
+ { Update the checkstate that is stored in our Node. If the tree has a
+ node for the Node then invalidate it. }
+ if aCheckState=FCheckstate then exit;
+ FCheckState:=aCheckState;
+ if Assigned(FVirtualNode) then FVirtualNode.CheckState:=aCheckState;
+ InvalidateVirtualNode;
+end;
+
+procedure TMVCNode.SetIncidence(aValue:integer);
+begin
+ { Set the Nodes property Incidence and invalidate the node in the tree
+ if there is one. We fix the value into its valid range. }
+ if aValue=FIncidence then exit;
+ FIncidence:=aValue;
+ if FIncidence<0
+ then FIncidence:=0
+ else
+ if FIncidence>63
+ then FIncidence:=63;
+ InvalidateVirtualNode;
+end;
+
+procedure TMVCNode.SetCaption(aCaption:string);
+begin
+ { Set the Nodes property Caption and invalidate the node in the tree
+ if there is one. }
+ if aCaption=FCaption then exit;
+ FCaption:=aCaption;
+ InvalidateVirtualNode;
+end;
+
+procedure TMVCNode.SetSubCaption(aSubCaption:string);
+begin
+ { Set the Nodes property Subcaption and invalidate the node in the tree
+ if there is one. }
+ if aSubCaption=FSubCaption then exit;
+ FSubCaption:=aSubCaption;
+ InvalidateVirtualNode;
+end;
+
+function TMVCNode.GetChildCount:integer;
+begin
+ Result:=FChildren.Count;
+end;
+
+function TMVCNode.GetChild(n:integer):TMVCNode;
+begin
+ Result:=TMVCNode(FChildren[n]);
+end;
+
+function TMVCNode.CreateChild:TMVCNode;
+begin
+ Result:=TMVCNode.Create;
+ Result.FParent:=Self;
+ FChildren.Add(Result);
+ if Assigned(FVirtualNode) then
+ with TreeFromNode(FVirtualNode) do
+ begin
+ ReinitNode(FVirtualNode,False);
+ InvalidateToBottom(FVirtualNode);
+ end;
+end;
+
+procedure TMVCNode.RemoveChild(n:integer);
+var C:TMVCNode;
+begin
+ { Remove Child number n from our Children-List and the tree }
+ C:=Child[n];
+ C.FParent:=NIL;
+ FChildren.Delete(n);
+ if Assigned(C.FVirtualNode) then
+ TreeFromNode(C.FVirtualNode).DeleteNode(C.FVirtualNode);
+end;
+
+procedure TMVCNode.DestroyChild(n:integer);
+var C:TMVCNode;
+begin
+ C:=Child[n];
+ RemoveChild(n);
+ C.Free;
+end;
+
+{*************************************************************************}
+
+constructor TMVCTree.Create;
+begin
+ inherited Create;
+ FRoot:=TMVCNode.Create;
+end;
+
+destructor TMVCTree.Destroy;
+begin
+ { Upon destruction we need to break the link to the Viewer and free
+ all our Nodes and last the list itself. }
+ Viewer:=NIL;
+ FRoot.Free;
+ FRoot:=NIL;
+ inherited Destroy;
+end;
+
+procedure TMVCTree.SetViewer(aViewer:TObject);
+begin
+ { Assign a viewer, De-Assign a viewer (by passing NIL) and assigning
+ a different viewer than the one that is already linked. }
+
+ { Prevent recursion when the viewer itself sets this property. }
+ if FSettingViewer>0 then exit;
+
+ inc(FSettingViewer);
+ try
+ { First de-assign any viewer that is already linked. }
+ if Assigned(FViewer) then TMVCTreeView(FViewer).Tree:=NIL;
+ { Set our field to point to the new viewer. }
+ FViewer:=aViewer;
+ { Now assign this List to the new viewer. }
+ if Assigned(FViewer) then TMVCTreeView(FViewer).Tree:=Self;
+ finally
+ dec(FSettingViewer);
+ end;
+end;
+
+procedure TMVCTree.BeginUpdate;
+begin
+ if Assigned(FViewer) then TMVCTreeView(FViewer).BeginUpdate;
+end;
+
+procedure TMVCTree.EndUpdate;
+begin
+ if Assigned(FViewer) then TMVCTreeView(FViewer).EndUpdate;
+end;
+
+{ *********************************************************************** }
+
+{ Now the tree. }
+
+{ The internal node-data assigned to every virtual node consist only of
+ a reference to an instance of TMVCNode. }
+type PMyNodeData=^TMyNodeData;
+ TMyNodeData=packed record Node:TMVCNode end;
+
+destructor TMVCTreeView.Destroy;
+begin
+ { When destroying the tree, break the link with the list. Note that
+ we do NOT set FNodes:=NIL. By using the Set-Method it is made sure
+ that the List gets notified of our demise and sets its own reference
+ to NIL too. }
+ Tree:=NIL;
+ inherited Destroy;
+end;
+
+procedure TMVCTreeView.SetTree(aTree:TMVCTree);
+begin
+ if FTree=aTree then exit;
+
+ { If we already have a list, break the link to it. }
+ if Assigned(FTree) then FTree.Viewer:=NIL;
+
+ { Now make a link to the new structure: }
+ FTree:=aTree;
+ if Assigned(FTree)
+ then
+ begin
+ FTree.Viewer:=Self;
+ RootNodeCount:=FTree.Root.ChildCount;
+ if FTree.Root.ChildCount>0 then ValidateNode(GetFirst, False);
+ end
+ else RootNodeCount:=0;
+end;
+
+function TMVCTreeView.GetMVCNode(VirtualNode:PVirtualNode):TMVCNode;
+begin
+ { Return the reference to the TMVCNode that is represented by
+ Virtualnode }
+ if VirtualNode=NIL
+ then Result:=NIL
+ else Result:=PMyNodeData(InternalData(VirtualNode)).Node;
+end;
+
+procedure TMVCTreeView.SetMVCNode(VirtualNode:PVirtualNode;aNode:TMVCNode);
+begin
+ { Note the relationship between a VirtualNode and the TMVCNode it
+ represents in the Nodes data. }
+ PMyNodeData(InternalData(VirtualNode)).Node:=aNode;
+end;
+
+function TMVCTreeView.DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink;
+var Link:TMVCEditLink;
+begin
+ Result:=inherited DoCreateEditor(Node,Column);
+ if Result=nil then
+ begin
+ Link:=TMVCEditLink.Create;
+ Result:=Link;
+ end;
+end;
+
+function TMVCTreeView.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;
+{ How wide is the the node in pixels. This is interesting if the graphic
+ representation includes elements that are not text and whose width needs
+ to be calculated. Here we draw a bar whose width corresponds to the
+ value of the Incidence-property of the MVCNode. }
+var N:TMVCNode;
+ Text: string;
+begin
+ N:=GetMVCNode(Node);
+ if Canvas = nil then
+ Canvas := Self.Canvas;
+ if not Assigned(N)
+ then Result:=0
+ else
+ begin
+ Text:=GetNodeText(N, Column);
+ Result:=Canvas.TextWidth(Text);
+ if Column + 1 in [0, 1] then
+ Result := Result + 8 + N.Incidence;
+ end;
+end;
+
+function TMVCTreeView.GetNodeText(aNode:TMVCNode;aColumn:integer):string;
+{ This method returns the text that is to be displayed in aColumn for
+ the Node aNode. It is in a separate function so that it can be used
+ for the calculation of width and for the actual drawing. You could
+ also process the data from the actual Node as stored in your structure
+ to give some other text as shown here for the third column. }
+begin
+ case aColumn of
+ -1,0:Result:=aNode.Caption;
+ 1:Result:=aNode.SubCaption;
+ 2:case aNode.Incidence of
+ 0..5:Result:='under 6';
+ 6..20:Result:='6 to 21';
+ 21..62:Result:='21 or above';
+ 63:Result:='Max.';
+ else Result:='What?';
+ end; (* of case Incidence *)
+ else Result:='What *"§ added columns without giving data?';
+ end; (* of case aColumn *)
+end;
+
+procedure TMVCTreeView.SetNodeText(aNode:TMVCNode;aColumn:integer;aText:string);
+{ Set the text for the node and column. This is called by the editor when
+ editing has finished. }
+begin
+ case aColumn of
+ -1,0:aNode.Caption:=aText;
+ 1:aNode.SubCaption:=aText;
+ else { Error, this column should not / cannot be edited }
+ end; (* of case aColumn *)
+end;
+
+procedure TMVCTreeView.DoPaintNode(var PaintInfo: TVTPaintInfo);
+{ Here we actually draw the graphical representation of the node. It is
+ drawn one cell, i.e. Node/Column at a time. All relevant data is either
+ passed as a parameter or we look it up in our TMVCNode-Structure that
+ is linked to the Node via the internal data. }
+
+var N:TMVCNode;
+ SaveFontColor:TColor;
+ Flags:Integer;
+ TxtRect:TRect;
+ NodeText:string;
+ OldBrushColor,OldPenColor:TColor;
+
+ procedure SaveDC;
+ begin
+ OldBrushColor:=PaintInfo.Canvas.Brush.Color;
+ OldPenColor:=PaintInfo.Canvas.Pen.Color;
+ end;
+
+ procedure RestoreDC;
+ begin
+ PaintInfo.Canvas.Brush.Color:=OldBrushColor;
+ PaintInfo.Canvas.Pen.Color:=OldPenColor;
+ end;
+
+begin
+ SaveDC; { No-brainer: We save and restore every canvas-setting, we _ever_
+ change in this method. So initial and final state
+ of the canvas are of no concern. }
+ try
+ with PaintInfo, Canvas do
+ begin
+ Font:=Self.Font;
+
+ { Get a reference to our data. If this fails bail out - this
+ should not happen anyway. If it does you will notice on screen.
+ Paranoics add assertions as you like. }
+ N:=MVCNode[Node]; if N=NIL then exit;
+
+ { Get the text-string to be displayed in the column. }
+ NodeText:=GetNodeText(N, Column);
+
+ { Some shuffling of feet and rectangles. Try for yourself what
+ happens here be adding offsets, changing colors etc.. }
+ if (toHotTrack in Self.TreeOptions.PaintOptions) and
+ (Node=HotNode)
+ then Font.Style:=Font.Style+[fsUnderline]
+ else Font.Style:=Font.Style-[fsUnderline];
+
+ if vsSelected in Node.States
+ then
+ begin
+ if Focused
+ then (* Selected, focused *)
+ begin
+ Brush.Color:=clHighLight;
+ Font.Color:=clWhite;
+ end
+ else (* Selected, non-focused *)
+ begin
+ Brush.Color:=clBtnFace;
+ Font.Color:=Self.Font.Color;
+ end;
+ { Fill out the entire rectangle }
+ FillRect(ContentRect);
+ end
+ else (* not selected, see Mikes samples on what is going on... *)
+ if Node=DropTargetNode
+ then
+ begin
+ if LastDropMode=dmOnNode
+ then
+ begin
+ Brush.Color:=clHighLight;
+ Font.Color:=clWhite;
+ end
+ else
+ begin
+ Brush.Style:=bsClear;
+ Font.Color:=Self.Font.Color;
+ end;
+ FillRect(ContentRect);
+ end;
+
+ if Focused
+ and (FocusedNode=Node) and
+ not(toFullRowSelect in Self.TreeOptions.SelectionOptions)
+ then
+ begin
+ if Self.Color=clGray
+ then Brush.Color:=clWhite
+ else Brush.Color:=clBlack;
+ SaveFontColor:=Font.Color;
+ Font.Color:=Self.Color;
+ Windows.DrawFocusRect(Handle,ContentRect);
+ Font.Color:=SaveFontColor;
+ end;
+
+ { Disabled node color overrides all other variants }
+ if vsDisabled in Node.States then Font.Color:=clBtnShadow;
+
+ if Column+1 in [0,1] then
+ begin
+ { Draw the Incidence-Bar }
+ Pen.Color:=clBlack;
+ Brush.Style:=bsSolid;
+ { Mix a color for an incidence-value }
+ Brush.Color:= RGB(4 * N.Incidence, 128, 255 - 4 * N.Incidence);
+ Rectangle(ContentRect.Left+2,
+ ContentRect.Top+2,
+ ContentRect.Left+2+N.Incidence,
+ ContentRect.Bottom-2);
+ end;
+
+ { Paint corresponding text }
+ Brush.Color:=Color;
+ SetBkMode(Handle,TRANSPARENT);
+
+ TxtRect.Left:= ContentRect.Left;
+ TxtRect.Top:= ContentRect.Top;
+ TxtRect.Right:= ContentRect.Right;
+ TxtRect.Bottom:=ContentRect.Bottom;
+ if Column+1 in [0,1]
+ then TxtRect.Left:=TxtRect.Left+6+N.Incidence;
+ Flags:=DT_LEFT or DT_SINGLELINE or DT_VCENTER;
+ DrawText(Handle,PChar(NodeText),Length(NodeText),TxtRect,Flags);
+ end; { of with Canvas }
+ finally
+ RestoreDC;
+ end;
+end;
+
+procedure TMVCTreeView.DoFreeNode(aNode:PVirtualNode);
+{ A virtual node is being freed by the tree. Make sure the associated Node
+ loses its pointer to the node. }
+var N:TMVCNode;
+begin
+ N:=MVCNode[aNode];
+ if Assigned(N) then
+ begin
+ N.VirtualNode:=NIL;
+ SetMVCNode(aNode,NIL);
+ end;
+ inherited DoFreeNode(aNode);
+end;
+
+procedure TMVCTreeView.DoInitChildren(Node:PVirtualNode;var ChildCount:Cardinal);
+begin
+ inherited DoInitChildren(Node,ChildCount);
+ ChildCount:=MVCNode[Node].ChildCount;
+end;
+
+procedure TMVCTreeView.DoInitNode(aParent,aNode:PVirtualNode;
+ var aInitStates:TVirtualNodeInitStates);
+{ The tree has just allocated a new virtual node. Link it to the TMVCNode
+ it is to represent. }
+var P,I:TMVCNode;
+begin
+ inherited DoInitNode(aParent,aNode,aInitStates);
+ with aNode^ do
+ begin
+ { Wich MVCNode corresponds to the virtual node being initialized?
+ Find the Parent-MVCNode via the Parent-VirtualNode }
+ if (aParent=RootNode) or (aParent=NIL)
+ then P:=FTree.Root
+ else P:=MVCNode[aParent];
+ { MVCNode we are looking for is child number aIndex. }
+ I:=P.Child[Index];
+
+ { Now set all the data the Treeview needs plus our link to the node }
+ SetMVCNode(aNode,I);
+ I.VirtualNode:=aNode;
+
+ if I.ChildCount>0
+ then Include(aInitStates,ivsHasChildren)
+ else Exclude(aInitStates,ivsHasChildren);
+ CheckState:=I.CheckState;
+ end;
+end;
+
+procedure TMVCTreeView.DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer);
+{ The tree requests the image-index for a Node and column. }
+var N:TMVCNode;
+begin
+ case Column of
+ -1,0:begin
+ { We only want Icons in the first column. Ask the node which
+ one it wants. }
+ N:=MVCNode[Node];
+ if N=NIL { No node assigned, this should not happen. }
+ then Index:=-1
+ else Index:=N.GetImageIndex;
+ end;
+ else Index:=-1;
+ end;
+end;
+
+procedure TMVCTreeView.DoChecked(aNode:PVirtualNode);
+{ In the tree a node has been checked, unchecked or whatever change to
+ the CheckState happens. Propagate that to the TMVCNode. }
+var N:TMVCNode;
+begin
+ if Assigned(FTree) then
+ begin
+ N:=MVCNode[aNode];
+ if Assigned(N) then N.CheckState:=aNode^.CheckState;
+ end;
+ inherited DoChecked(aNode);
+end;
+
+function TMVCTreeView.InternalData(Node: PVirtualNode): Pointer;
+
+begin
+ if (Node = RootNode) or (Node = nil) then
+ Result := nil
+ else
+ Result := PChar(Node) + FInternalDataOffset;
+end;
+
+function TMVCTreeView.InternalDataSize: Cardinal;
+
+begin
+ // The size of the internal data this tree class needs.
+ Result := SizeOf(TMyNodeData);
+end;
+
+constructor TMVCEditLink.Create;
+begin
+ inherited;
+ FEdit := TMVCEdit.Create(Self);
+ with FEdit do
+ begin
+ Visible := False;
+ Ctl3D := False;
+ BorderStyle := bsSingle;
+ AutoSize := False;
+ end;
+end;
+
+destructor TMVCEditLink.Destroy;
+begin
+ FEdit.Free;
+ inherited;
+end;
+
+function TMVCEditLink.BeginEdit: Boolean;
+begin
+ Result := True;
+ FEdit.Show;
+ FEdit.SetFocus;
+end;
+
+function TMVCEditLink.CancelEdit: Boolean;
+begin
+ Result := True;
+ // to show the kill focus handler that we don't need a second notification for the tree
+ FTree:=nil;
+ FEdit.Hide;
+end;
+
+function TMVCEditLink.EndEdit: Boolean;
+var LastTree:TMVCTreeView;
+ MVCNode:TMVCNode;
+begin
+ Result := True;
+ try
+ if Assigned(FTree) then
+ begin
+ if FEdit.Modified then
+ begin
+ MVCNode:=FTree.MVCNode[FNode];
+ // keep tree reference because the application might want to change the focuse while
+ // processing the NewText event
+ LastTree:=FTree;
+ FTree:=nil;
+
+ LastTree.SetNodeText(MVCNode,FColumn,FEdit.Caption);
+ end;
+ FTree:=nil;
+ end;
+ finally
+ FEdit.Hide;
+ end;
+end;
+
+function TMVCEditLink.GetBounds: TRect;
+begin
+ Result:=FEdit.BoundsRect;
+end;
+
+function TMVCEditLink.PrepareEdit(Tree:TBaseVirtualTree;Node:PVirtualNode;Column:TColumnIndex): Boolean;
+// retrieves the true text bounds from the owner tree
+var R:TRect;
+ MVCNode:TMVCNode;
+begin
+ Result := True;
+ FTree:=Tree as TMVCTreeView;
+
+ FNode:=Node;
+ FColumn:=Column;
+
+ MVCNode:=FTree.MVCNode[Node];
+
+ FEdit.Caption:=FTree.GetNodeText(MVCNode,Column);
+ FEdit.Parent:=Tree;
+ R:=FTree.GetDisplayRect(Node,Column,True);
+
+ { In the primary column there is the "Incidence-Bar". Adjust the left
+ side of the rect to exclude it }
+ if Column+1 in [0,1] then R.Left:=R.Left+MVCNode.Incidence;
+
+ with R do
+ begin
+ // set the edit's bounds but make sure there's a minimum width and the right border does not
+ // extend beyond the parent's right border
+ if Right-Left<50 then Right:=Left+50;
+ if Right>FTree.Width then Right:=FTree.Width;
+ FEdit.SetBounds(Left,Top,Right-Left,Bottom-Top);
+ FEdit.Font:=FTree.Font;
+ end;
+end;
+
+procedure TMVCEditLink.SetBounds(R: TRect);
+begin
+ // ignore this one as we get here the entire node rect but want the minimal text bounds
+end;
+
+constructor TMVCEdit.Create(Link:TMVCEditLink);
+begin
+ inherited Create(nil);
+ ShowHint:=False;
+ ParentShowHint:=False;
+ FLink:=Link;
+end;
+
+procedure TMVCEdit.WMChar(var Message: TWMChar);
+// handle character keys
+begin
+ // avoid beep
+ if Message.CharCode <> VK_ESCAPE then
+ begin
+ inherited;
+ if Message.CharCode > $20 then AutoAdjustSize;
+ end;
+end;
+
+procedure TMVCEdit.WMKeyDown(var Message: TWMKeyDown);
+// handles some control keys (either redirection to tree, edit window size or clipboard handling)
+begin
+ case Message.CharCode of
+ // pretend these keycodes were send to the tree
+ VK_ESCAPE,
+ VK_UP,
+ VK_DOWN:
+ FLink.FTree.WndProc(TMessage(Message));
+ VK_RETURN:
+ FLink.FTree.DoEndEdit;
+ // standard clipboard actions,
+ // Caution: to make these work you must not use default TAction classes like TEditPaste etc. in the application!
+ Ord('C'):
+ if (Message.KeyData and MK_CONTROL) <> 0 then CopyToClipboard;
+ Ord('X'):
+ if (Message.KeyData and MK_CONTROL) <> 0 then
+ begin
+ CutToClipboard;
+ AutoAdjustSize;
+ end;
+ Ord('V'):
+ if (Message.KeyData and MK_CONTROL) <> 0 then
+ begin
+ PasteFromClipboard;
+ AutoAdjustSize;
+ end;
+ else
+ inherited;
+ // second level for keys to be passed to its target
+ case Message.CharCode of
+ VK_BACK,
+ VK_DELETE:
+ AutoAdjustSize;
+ end;
+ end;
+end;
+
+procedure TMVCEdit.WMKillFocus(var Msg: TWMKillFocus);
+begin
+ inherited;
+ // FLink.FTree is set to nil if the link doesn't need to notify the tree (e.g. hiding the edit causes
+ // a kill focus message)
+ if Assigned(FLink.FTree) then FLink.FTree.DoCancelEdit;
+end;
+
+procedure TMVCEdit.AutoAdjustSize;
+var
+ DC: HDC;
+ Size: TSize;
+ EditRect,
+ TreeRect: TRect;
+begin
+ DC := GetDc(Handle);
+ GetTextExtentPoint32(DC, PChar(Text), Length(Text), Size);
+ // determine minimum and maximum sizes
+ if Size.cx < 50 then Size.cx := 50;
+ EditRect := ClientRect;
+ MapWindowPoints(Handle, HWND_DESKTOP, EditRect, 2);
+ TreeRect := FLink.FTree.ClientRect;
+ MapWindowPoints(FLink.FTree.Handle, HWND_DESKTOP, TreeRect, 2);
+ if (EditRect.Left + Size.cx) > TreeRect.Right then Size.cx := TreeRect.Right - EditRect.Left;
+ SetWindowPos(Handle, 0, 0, 0, Size.cx, Height, SWP_NOMOVE or SWP_NOOWNERZORDER or SWP_NOZORDER);
+ ReleaseDC(Handle, DC);
+end;
+
+procedure TMVCEdit.CreateParams(var Params:TCreateParams);
+begin
+ Ctl3D := False;
+ inherited;
+end;
+
+procedure TMVCEditLink.ProcessMessage(var Message: TMessage);
+begin
+ // nothing to do
+end;
+
+constructor TMVCTreeView.Create(AOwner: TComponent);
+begin
+ inherited;
+ FInternalDataOffset := AllocateInternalDataArea(SizeOf(Cardinal));
+end;
+
+function TMVCTreeView.GetOptions: TVirtualTreeOptions;
+
+begin
+ Result := inherited TreeOptions as TVirtualTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TMVCTreeView.SetOptions(const Value: TVirtualTreeOptions);
+
+begin
+ TreeOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TMVCTreeView.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TVirtualTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Design/CheckDark.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/CheckDark.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/CheckFlat.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/CheckFlat.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/CheckLight.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/CheckLight.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveAll.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveAll.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveAll.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveAll.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveE.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveE.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveEW.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveEW.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveEW.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveEW.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveN.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveN.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveNE.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveNE.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveNS.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveNS.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveNS.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveNS.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveNW.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveNW.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveS.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveS.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveSE.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveSE.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveSW.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveSW.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/MoveW.cur
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/MoveW.cur
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/TickDark.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/TickDark.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/TickLight.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/TickLight.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Design/XP.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Design/XP.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Help/Virtual Tree.chm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Help/Virtual Tree.chm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/StrEditD4.dfm
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/StrEditD4.dfm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/StrEditD4.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/StrEditD4.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/StrEditD4.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,70 @@
+unit StrEditD4;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ StdCtrls, ExtCtrls, ComCtrls, dsgnintf;
+
+type
+ TStrEditDlg = class(TForm)
+ Bevel1: TBevel;
+ btnOk: TButton;
+ btnCancel: TButton;
+ Editor: TRichEdit;
+ StatusBar: TStatusBar;
+ procedure EditorChange(Sender: TObject);
+ procedure EditorKeyDown(Sender: TObject; var Key: Word;
+ Shift: TShiftState);
+ private
+ FModified: Boolean;
+ public
+ { Public declarations }
+ end;
+
+ TStringListProperty = class(TClassProperty)
+ public
+ function GetAttributes: TPropertyAttributes; override;
+ procedure Edit; override;
+ end;
+
+implementation
+
+{$R *.DFM}
+
+procedure TStrEditDlg.EditorChange(Sender: TObject);
+begin
+ if Sender = Editor then
+ FModified := True;
+ StatusBar.SimpleText := Format ('%d lines.', [Editor.Lines.Count]);
+end;
+
+procedure TStrEditDlg.EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
+begin
+ if Key = VK_ESCAPE then
+ ModalResult := mrCancel;
+end;
+
+{ TStringListProperty }
+
+procedure TStringListProperty.Edit;
+begin
+ with TStrEditDlg.Create(Application) do
+ try
+ Editor.Lines := TStrings(GetOrdValue);
+ EditorChange (nil);
+ FModified := False;
+ ActiveControl := Editor;
+ if ShowModal = mrOk then
+ SetOrdValue(LongInt(Editor.Lines));
+ finally
+ Free;
+ end;
+end;
+
+function TStringListProperty.GetAttributes: TPropertyAttributes;
+begin
+ Result := inherited GetAttributes + [paDialog] - [paSubProperties];
+end;
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTrees.dcr
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTrees.dcr
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4.dpk
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,39 @@
+package VirtualTreesD4;
+
+{$R *.RES}
+{$ALIGN ON}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$REFERENCEINFO OFF}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Virtual Treeview (run time)'}
+{$RUNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl40,
+ dclstd40,
+ ThemeManager4;
+
+contains
+ VirtualTrees in '..\VirtualTrees.pas',
+ VTHeaderPopup in '..\VTHeaderPopup.pas';
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4D.dpk
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4D.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4D.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,39 @@
+package VirtualTreesD4D;
+
+{$R *.RES}
+{$R VirtualTrees.dcr}
+{$ALIGN ON}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$REFERENCEINFO OFF}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Virtual Treeview (design time)'}
+{$DESIGNONLY}
+
+requires
+ vcl40,
+ dclstd40,
+ VirtualTreesD4;
+
+contains
+ VirtualTreesReg in 'VirtualTreesReg.pas',
+ StrEditD4 in 'StrEditD4.pas';
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4D.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD4D.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.dpk
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,39 @@
+package VirtualTreesD5;
+
+{$R *.RES}
+{$ALIGN ON}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$REFERENCEINFO OFF}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Virtual Treeview (run time)'}
+{$RUNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl50,
+ dclstd50,
+ ThemeManager5;
+
+contains
+ VirtualTrees in '..\VirtualTrees.pas',
+ VTHeaderPopup in '..\VTHeaderPopup.pas';
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.cfg
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.cfg 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.cfg 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,35 @@
+-$A+
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J-
+-$K-
+-$L+
+-$M-
+-$N+
+-$O-
+-$P+
+-$Q+
+-$R+
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$Y-
+-$Z1
+-cg
+-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+-H+
+-W+
+-M
+-$M16384,1048576
+-K$00400000
+-LE"c:\programme\borland\delphi5\Projects\Bpl"
+-LN"c:\programme\borland\delphi5\Projects\Bpl"
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dof
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dof 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dof 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,78 @@
+[Compiler]
+A=1
+B=0
+C=1
+D=1
+E=0
+F=0
+G=1
+H=1
+I=1
+J=0
+K=0
+L=1
+M=0
+N=1
+O=0
+P=1
+Q=1
+R=1
+S=0
+T=0
+U=0
+V=1
+W=0
+X=1
+Y=0
+Z=1
+ShowHints=1
+ShowWarnings=1
+UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+[Linker]
+MapFile=0
+OutputObjs=0
+ConsoleApp=1
+DebugInfo=0
+RemoteSymbols=0
+MinStackSize=16384
+MaxStackSize=1048576
+ImageBase=4194304
+ExeDescription=Virtual Treeview (design time)
+[Directories]
+OutputDir=
+UnitOutputDir=
+PackageDLLOutputDir=
+PackageDCPOutputDir=
+SearchPath=
+Packages=
+Conditionals=
+DebugSourceDirs=
+UsePackages=0
+[Parameters]
+RunParams=
+HostApplication=
+[Version Info]
+IncludeVerInfo=1
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1031
+CodePage=1252
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dpk
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,39 @@
+package VirtualTreesD5D;
+
+{$R *.RES}
+{$R 'VirtualTrees.dcr'}
+{$ALIGN ON}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$REFERENCEINFO OFF}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DESCRIPTION 'Virtual Treeview (design time)'}
+{$DESIGNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl50,
+ dclstd50,
+ VirtualTreesD5;
+
+contains
+ VirtualTreesReg in 'VirtualTreesReg.pas';
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD5D.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6.dpk
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,39 @@
+package VirtualTreesD6;
+
+{$R *.res}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$REFERENCEINFO OFF}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $30400000}
+{$DESCRIPTION 'Virtual Treeview'}
+{$RUNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl,
+ vclx,
+ ThemeManager6;
+
+contains
+ VirtualTrees in '..\VirtualTrees.pas',
+ VTHeaderPopup in '..\VTHeaderPopup.pas';
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6D.dpk
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6D.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6D.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,38 @@
+package VirtualTreesD6D;
+
+{$R *.res}
+{$R 'VirtualTrees.dcr'}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$REFERENCEINFO OFF}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $30400000}
+{$DESCRIPTION 'Virtual Treeview'}
+{$DESIGNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ dclstd,
+ VirtualTreesD6;
+
+contains
+ VirtualTreesReg in 'VirtualTreesReg.pas';
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6D.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD6D.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.dpk
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,38 @@
+package VirtualTreesD7;
+
+{$R *.res}
+{$ALIGN 8}
+{$ASSERTIONS OFF}
+{$BOOLEVAL OFF}
+{$DEBUGINFO OFF}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS OFF}
+{$LOCALSYMBOLS OFF}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION ON}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO OFF}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $30400000}
+{$DESCRIPTION 'Virtual Treeview'}
+{$RUNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ vcl,
+ vclx;
+
+contains
+ VirtualTrees in '..\VirtualTrees.pas',
+ VTHeaderPopup in '..\VTHeaderPopup.pas';
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.dpk
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.dpk 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.dpk 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,38 @@
+package VirtualTreesD7D;
+
+{$R *.res}
+{$R 'VirtualTrees.dcr'}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$REFERENCEINFO OFF}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES OFF}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $30400000}
+{$DESCRIPTION 'Virtual Treeview'}
+{$DESIGNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ dclstd,
+ VirtualTreesD7;
+
+contains
+ VirtualTreesReg in 'VirtualTreesReg.pas';
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesD7D.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesReg.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesReg.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesReg.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesReg.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/Packages/VirtualTreesReg.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,509 @@
+unit VirtualTreesReg;
+
+// This unit is an addendum to VirtualTrees.pas and contains code of design time editors as well as
+// for theirs and the tree's registration.
+
+interface
+
+{$include Compilers.inc}
+
+uses
+ Windows, Classes,
+ {$ifdef COMPILER_6_UP}
+ DesignIntf, DesignEditors, VCLEditors, PropertyCategories,
+ {$else}
+ DsgnIntf,
+ {$endif}
+ ColnEdit,
+ VirtualTrees, VTHeaderPopup;
+
+type
+ TVirtualTreeEditor = class (TDefaultEditor)
+ public
+ procedure Edit; override;
+ end;
+
+procedure Register;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ {$ifdef COMPILER_5_UP}
+ StrEdit,
+ {$else}
+ StrEditD4,
+ {$endif COMPILER_5_UP}
+ Dialogs, TypInfo, SysUtils, Graphics;
+
+type
+ // The usual trick to make a protected property accessible in the ShowCollectionEditor call below.
+ TVirtualTreeCast = class(TBaseVirtualTree);
+
+ TClipboardElement = class(TNestedProperty {$ifdef COMPILER_6_UP}, ICustomPropertyDrawing {$endif COMPILER_6_UP})
+ private
+ FElement: string;
+ protected
+ constructor Create(Parent: TPropertyEditor; AElement: string); reintroduce;
+ public
+ function AllEqual: Boolean; override;
+ function GetAttributes: TPropertyAttributes; override;
+ function GetName: string; override;
+ function GetValue: string; override;
+ procedure GetValues(Proc: TGetStrProc); override;
+ procedure SetValue(const Value: string); override;
+
+ {$ifdef COMPILER_5_UP}
+ {$ifdef COMPILER_6_UP}
+ procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+ {$endif COMPILER_6_UP}
+ procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+ {$ifndef COMPILER_6_UP} override; {$endif COMPILER_6_UP}
+ {$endif COMPILER_5_UP}
+ end;
+
+ // This is a special property editor to make the strings in the clipboard format string list
+ // being shown as subproperties in the object inspector. This way it is shown what formats are actually available
+ // and the user can pick them with a simple yes/no choice.
+
+ {$ifdef COMPILER_6_UP}
+ TGetPropEditProc = TGetPropProc;
+ {$endif}
+
+ TClipboardFormatsProperty = class(TStringListProperty {$ifdef COMPILER_6_UP}, ICustomPropertyDrawing {$endif COMPILER_6_UP})
+ public
+ function GetAttributes: TPropertyAttributes; override;
+ procedure GetProperties(Proc: TGetPropEditProc); override;
+ {$ifdef COMPILER_5_UP}
+ procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+ {$ifndef COMPILER_6_UP} override; {$endif}
+ procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+ {$ifndef COMPILER_6_UP} override; {$endif}
+ {$endif}
+ end;
+
+ // Property categories. They are defined this way only for Delphi 5 & BCB 5.
+ {$ifdef COMPILER_5}
+ TVTHeaderCategory = class(TPropertyCategory)
+ public
+ class function Name: string; override;
+ class function Description: string; override;
+ end;
+
+ TVTPaintingCategory = class(TPropertyCategory)
+ public
+ class function Name: string; override;
+ class function Description: string; override;
+ end;
+
+ TVTIncrementalSearchCategory = class(TPropertyCategory)
+ public
+ class function Name: string; override;
+ class function Description: string; override;
+ end;
+ {$endif COMPILER_5}
+
+ {$ifdef COMPILER_6_UP}
+ resourcestring
+ sVTHeaderCategoryName = 'Header';
+ sVTPaintingCategoryName = 'Custom painting';
+ sVTIncremenalCategoryName = 'Incremental search';
+ {$endif}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeEditor.Edit;
+
+begin
+ ShowCollectionEditor(Designer, Component, TVirtualTreeCast(Component).Header.Columns, 'Columns');
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+constructor TClipboardElement.Create(Parent: TPropertyEditor; AElement: string);
+
+begin
+ inherited Create(Parent);
+ FElement := AElement;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardElement.AllEqual: Boolean;
+
+// Determines if this element is included or excluded in all selected components it belongs to.
+
+var
+ I, Index: Integer;
+ List: TClipboardFormats;
+ V: Boolean;
+
+begin
+ Result := False;
+ if PropCount > 1 then
+ begin
+ List := TClipboardFormats(GetOrdValue);
+ V := List.Find(FElement, Index);
+ for I := 1 to PropCount - 1 do
+ begin
+ List := TClipboardFormats(GetOrdValue);
+ if List.Find(FElement, Index) <> V then
+ Exit;
+ end;
+ end;
+ Result := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardElement.GetAttributes: TPropertyAttributes;
+
+begin
+ Result := [paMultiSelect, paValueList, paSortList];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardElement.GetName: string;
+
+begin
+ Result := FElement;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardElement.GetValue: string;
+
+var
+ List: TClipboardFormats;
+
+begin
+ List := TClipboardFormats(GetOrdValue);
+ Result := BooleanIdents[List.IndexOf(FElement) > -1];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardElement.GetValues(Proc: TGetStrProc);
+
+begin
+ Proc(BooleanIdents[False]);
+ Proc(BooleanIdents[True]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardElement.SetValue(const Value: string);
+
+var
+ List: TClipboardFormats;
+ I, Index: Integer;
+
+begin
+ if CompareText(Value, 'True') = 0 then
+ begin
+ for I := 0 to PropCount - 1 do
+ begin
+ List := TClipboardFormats(GetOrdValueAt(I));
+ List.Add(FElement);
+ end;
+ end
+ else
+ begin
+ for I := 0 to PropCount - 1 do
+ begin
+ List := TClipboardFormats(GetOrdValueAt(I));
+ if List.Find(FElement, Index) then
+ List.Delete(Index);
+ end;
+ end;
+ Modified;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+{$ifdef COMPILER_5_UP}
+
+ procedure DrawBoolean(Checked: Boolean; ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+
+ var
+ BoxSize,
+ EntryWidth: Integer;
+ R: TRect;
+ State: Cardinal;
+
+ begin
+ with ACanvas do
+ begin
+ FillRect(ARect);
+
+ BoxSize := ARect.Bottom - ARect.Top;
+ EntryWidth := ARect.Right - ARect.Left;
+
+ R := Rect(ARect.Left + (EntryWidth - BoxSize) div 2, ARect.Top, ARect.Left + (EntryWidth + BoxSize) div 2,
+ ARect.Bottom);
+ InflateRect(R, -1, -1);
+ State := DFCS_BUTTONCHECK;
+ if Checked then
+ State := State or DFCS_CHECKED;
+ DrawFrameControl(Handle, R, DFC_BUTTON, State);
+ end;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+ {$ifdef COMPILER_6_UP}
+
+ procedure TClipboardElement.PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+
+ begin
+ DefaultPropertyDrawName(Self, ACanvas, ARect);
+ end;
+
+ {$endif COMPILER_6_UP}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+ procedure TClipboardElement.PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+
+ begin
+ DrawBoolean(CompareText(GetVisualValue, 'True') = 0, ACanvas, ARect, ASelected);
+ end;
+
+{$endif COMPILER_5_UP}
+
+//----------------- TClipboardFormatsProperty --------------------------------------------------------------------------
+
+function TClipboardFormatsProperty.GetAttributes: TPropertyAttributes;
+
+begin
+ Result := inherited GetAttributes + [paSubProperties {$ifdef COMPILER_5_UP}, paFullWidthName {$endif COMPILER_5_UP}];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatsProperty.GetProperties(Proc: TGetPropEditProc);
+
+var
+ List: TStringList;
+ I: Integer;
+ Tree: TBaseVirtualTree;
+
+begin
+ List := TStringList.Create;
+ Tree := TClipboardFormats(GetOrdValue).Owner;
+ EnumerateVTClipboardFormats(TVirtualTreeClass(Tree.ClassType), List);
+ for I := 0 to List.Count - 1 do
+ Proc(TClipboardElement.Create(Self, List[I]));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+{$ifdef COMPILER_5_UP}
+
+ procedure TClipboardFormatsProperty.PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+
+ var
+ S: string;
+ Width: Integer;
+ R: TRect;
+
+ begin
+ with ACanvas do
+ begin
+ Font.Name := 'Arial';
+ R := ARect;
+ Font.Color := clBlack;
+ S := GetName;
+ Width := TextWidth(S);
+ TextRect(R, R.Left + 1, R.Top + 1, S);
+
+ Inc(R.Left, Width + 8);
+ Font.Height := 14;
+ Font.Color := clBtnHighlight;
+ S := '(OLE drag and clipboard)';
+ SetBkMode(Handle, TRANSPARENT);
+ ExtTextOut(Handle, R.Left + 1, R.Top + 1, ETO_CLIPPED, @R, PChar(S), Length(S), nil);
+ Font.Color := clBtnShadow;
+ ExtTextOut(Handle, R.Left, R.Top, ETO_CLIPPED, @R, PChar(S), Length(S), nil);
+ end;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+ procedure TClipboardFormatsProperty.PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean);
+
+ begin
+ // Nothing to do here.
+ end;
+
+{$endif COMPILER_5_UP}
+
+{$ifdef COMPILER_5}
+
+//----------------- TVTPaintingCategory --------------------------------------------------------------------------------
+
+ class function TVTPaintingCategory.Name: string;
+
+ begin
+ Result := 'Custom Painting';
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+ class function TVTPaintingCategory.Description: string;
+
+ begin
+ Result := 'Custom Painting';
+ end;
+
+//----------------- TVTHeaderCategory ----------------------------------------------------------------------------------
+
+ class function TVTHeaderCategory.Name: string;
+
+ begin
+ Result := 'Header';
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+ class function TVTHeaderCategory.Description: string;
+
+ begin
+ Result := 'Header';
+ end;
+
+//----------------- TVTIncrementalSearchCategory -----------------------------------------------------------------------
+
+ class function TVTIncrementalSearchCategory.Name: string;
+
+ begin
+ Result := 'Incremental Search';
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+ class function TVTIncrementalSearchCategory.Description: string;
+
+ begin
+ Result := 'Incremental Search';
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+{$endif COMPILER_5}
+
+procedure Register;
+
+begin
+ RegisterComponents('Virtual Controls', [TVirtualStringTree, TVirtualDrawTree, TVTHeaderPopupMenu]);
+ RegisterComponentEditor(TVirtualStringTree, TVirtualTreeEditor);
+ RegisterComponentEditor(TVirtualDrawTree, TVirtualTreeEditor);
+ RegisterPropertyEditor(TypeInfo(TClipboardFormats), nil, '', TClipboardFormatsProperty);
+
+ // Categories:
+ {$ifdef COMPILER_5_UP}
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TActionCategory, {$endif} {$ifdef COMPILER_6_UP} sActionCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['ChangeDelay',
+ 'EditDelay']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TDataCategory, {$endif} {$ifdef COMPILER_6_UP} sDataCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['NodeDataSize',
+ 'RootNodeCount',
+ 'OnCompareNodes',
+ 'OnGetNodeDataSize',
+ 'OnInitNode',
+ 'OnInitChildren',
+ 'OnFreeNode',
+ 'OnGetNodeWidth',
+ 'OnGetPopupMenu',
+ 'OnLoadNode',
+ 'OnSaveNode',
+ 'OnResetNode',
+ 'OnNodeMov*',
+ 'OnStructureChange',
+ 'OnUpdating',
+ 'OnGetText',
+ 'OnNewText',
+ 'OnShortenString']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TLayoutCategory, {$endif} {$ifdef COMPILER_6_UP} slayoutCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['AnimationDuration',
+ 'AutoExpandDelay',
+ 'AutoScroll*',
+ 'ButtonStyle',
+ 'DefaultNodeHeight',
+ '*Images*', 'OnGetImageIndex',
+ 'Header',
+ 'Indent',
+ 'LineStyle', 'OnGetLineStyle',
+ 'CheckImageKind',
+ 'Options',
+ 'Margin',
+ 'NodeAlignment',
+ 'ScrollBarOptions',
+ 'SelectionCurveRadius',
+ 'TextMargin']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TVisualCategory, {$endif} {$ifdef COMPILER_6_UP} sVisualCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['Background*',
+ 'ButtonFillMode',
+ 'CustomCheckimages',
+ 'Colors',
+ 'LineMode']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} THelpCategory, {$endif} {$ifdef COMPILER_6_UP} sHelpCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['Hint*', 'On*Hint*', 'On*Help*']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TDragNDropCategory, {$endif} {$ifdef COMPILER_6_UP} sDragNDropCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['ClipboardFormats',
+ 'DefaultPasteMode',
+ 'OnCreateDataObject',
+ 'OnCreateDragManager',
+ 'OnGetUserClipboardFormats',
+ 'OnNodeCop*',
+ 'OnDragAllowed',
+ 'OnRenderOLEData']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TInputCategory, {$endif} {$ifdef COMPILER_6_UP} sInputCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['DefaultText',
+ 'DrawSelectionMode',
+ 'WantTabs',
+ 'OnChang*',
+ 'OnCollaps*',
+ 'OnExpand*',
+ 'OnCheck*',
+ 'OnEdit*',
+ 'On*Click',
+ 'OnFocus*',
+ 'OnCreateEditor',
+ 'OnScroll',
+ 'OnHotChange']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TVTHeaderCategory, {$endif} {$ifdef COMPILER_6_UP} sVTHeaderCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['OnHeader*', 'OnGetHeader*']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TVTPaintingCategory, {$endif} {$ifdef COMPILER_6_UP} sVTPaintingCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['On*Paint*',
+ 'OnDraw*',
+ 'On*Erase*']);
+
+ RegisterPropertiesInCategory({$ifdef COMPILER_5} TVTIncrementalSearchCategory, {$endif} {$ifdef COMPILER_6_UP} sVTIncremenalCategoryName, {$endif COMPILER_6_UP}
+ TBaseVirtualTree,
+ ['*Incremental*']);
+ {$endif COMPILER_5_UP}
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
Added: trunk/WPGM/Components/VirtualTreeview/VTHeaderPopup.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/VTHeaderPopup.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/VTHeaderPopup.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/VTHeaderPopup.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/VTHeaderPopup.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,188 @@
+unit VTHeaderPopup;
+
+//----------------------------------------------------------------------------------------------------------------------
+// The contents of this file are subject to the Mozilla Public License
+// Version 1.1 (the "License"); you may not use this file except in
+// compliance with the License. You may obtain a copy of the License at
+// http://www.mozilla.org/MPL/
+//
+// Alternatively, you may redistribute this library, use and/or modify it under the terms of the
+// GNU Lesser General Public License as published by the Free Software Foundation;
+// either version 2.1 of the License, or (at your option) any later version.
+// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/.
+//
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+// License for the specific language governing rights and limitations
+// under the License.
+//
+// The Original Code is VTHeaderPopup.pas.
+//
+// The Initial Developer of the Original Code is Ralf Junker <delphi at zeitungsjunge.de>. All Rights Reserved.
+//
+// Modified 17 Feb 2002 by Jim Kueneman <jimdk at mindspring.com>.
+// Added the event to filter the items as they are added to the menu.
+//
+// Modified 23 Feb 2002 by Ralf Junker <delphi at zeitungsjunge.de>.
+// Added option to show menu items in the same order as the columns or in original order.
+// Added option to prevent the user to hide all columns.
+//
+// Modified 24 Feb 2002 by Ralf Junker <delphi at zeitungsjunge.de>.
+// Fixed a bug where the OnAddHeaderPopupItem would interfere with poAllowHideAll options.
+// All column indexes now consistently use TColumnIndex (instead of Integer).
+//
+// Modified 20 Oct 2002 by Borut Maricic <borut.maricic at pobox.com>.
+// Added the possibility to use Troy Wolbrink's Unicode aware popup menu. Define the compiler symbol TNT to enable it.
+// You can get Troy's Unicode controls collection from http://home.ccci.org/wolbrink/tnt/delphi_unicode_controls.htm).
+//----------------------------------------------------------------------------------------------------------------------
+
+{$I Compilers.inc}
+
+interface
+
+uses
+ {$ifdef TNT}
+ TntMenus,
+ {$else}
+ Menus,
+ {$endif TNT}
+ VirtualTrees;
+
+type
+ TVTHeaderPopupOption = (
+ poOriginalOrder, // Show menu items in original column order as they were added to the tree.
+ poAllowHideAll // Allows to hide all columns, including the last one.
+ );
+ TVTHeaderPopupOptions = set of TVTHeaderPopupOption;
+
+ TAddPopupItemType = (
+ apNormal,
+ apDisabled,
+ apHidden
+ );
+
+ TOnAddHeaderPopupItem = procedure(const Sender: TBaseVirtualTree; const Column: TColumnIndex; var Cmd: TAddPopupItemType) of object;
+
+ TVTHeaderPopupMenu = class({$ifdef TNT} TTntPopupMenu {$else} TPopupMenu {$endif})
+ private
+ FOnAddHeaderPopupItem: TOnAddHeaderPopupItem;
+ FOptions: TVTHeaderPopupOptions;
+ protected
+ procedure DoAddHeaderPopupItem(const Column: TColumnIndex; out Cmd: TAddPopupItemType);
+ procedure OnMenuItemClick(Sender: TObject);
+ public
+ procedure Popup(x, y: Integer); override;
+ published
+ property OnAddHeaderPopupItem: TOnAddHeaderPopupItem read FOnAddHeaderPopupItem write FOnAddHeaderPopupItem;
+ property Options: TVTHeaderPopupOptions read FOptions write FOptions;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+uses
+ {$ifdef TNT}
+ TnTClasses
+ {$else}
+ Classes
+ {$endif TNT};
+
+type
+ TVirtualTreeCast = class(TBaseVirtualTree); // Necessary to make the header accessible.
+
+//----------------- TVTHeaderPopupMenu ---------------------------------------------------------------------------------
+
+procedure TVTHeaderPopupMenu.DoAddHeaderPopupItem(const Column: TColumnIndex; out Cmd: TAddPopupItemType);
+
+begin
+ Cmd := apNormal;
+ if Assigned(FOnAddHeaderPopupItem) then
+ FOnAddHeaderPopupItem(TVirtualTreeCast(PopupComponent), Column, Cmd);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeaderPopupMenu.OnMenuItemClick(Sender: TObject);
+
+begin
+ if PopupComponent = nil then
+ Exit;
+
+ with {$ifdef TNT} TTntMenuItem {$else} TMenuItem {$endif}(Sender), TVirtualTreeCast(PopupComponent).Header.Columns.Items[Tag] do
+ if Checked then
+ Options := Options - [coVisible]
+ else
+ Options := Options + [coVisible];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeaderPopupMenu.Popup(x, y: Integer);
+
+var
+ i: Integer;
+ ColPos: TColumnPosition;
+ ColIdx: TColumnIndex;
+
+ NewMenuItem: {$ifdef TNT} TTntMenuItem {$else} TMenuItem {$endif};
+ Cmd: TAddPopupItemType;
+
+ VisibleCounter: Cardinal;
+ VisibleItem: {$ifdef TNT} TTntMenuItem {$else} TMenuItem {$endif};
+
+begin
+ if PopupComponent = nil then Exit;
+
+ // Delete existing menu items.
+ i := Items.Count;
+ while i > 0 do begin
+ Dec(i);
+ Items[i].Free;
+ end;
+
+ // Add column menu items.
+ with TVirtualTreeCast(PopupComponent).Header do
+ begin
+ if hoShowImages in Options then Self.Images := Images;
+ VisibleItem := nil;
+ VisibleCounter := 0;
+ for ColPos := 0 to Columns.Count - 1 do
+ begin
+ if poOriginalOrder in FOptions then
+ ColIdx := ColPos
+ else
+ ColIdx := Columns.ColumnFromPosition(ColPos);
+ with Columns[ColIdx] do
+ begin
+ if coVisible in Options then Inc(VisibleCounter);
+ DoAddHeaderPopupItem(ColIdx, Cmd);
+ if Cmd <> apHidden then
+ begin
+ NewMenuItem := {$ifdef TNT} TTntMenuItem {$else} TMenuItem {$endif}.Create(Self);
+ NewMenuItem.Tag := ColIdx;
+ NewMenuItem.Caption := Text;
+ NewMenuItem.Hint := Hint;
+ NewMenuItem.ImageIndex := ImageIndex;
+ NewMenuItem.Checked := coVisible in Options;
+ NewMenuItem.OnClick := OnMenuItemClick;
+ if Cmd = apDisabled then
+ NewMenuItem.Enabled := False
+ else
+ if coVisible in Options then VisibleItem := NewMenuItem;
+ Items.Add(NewMenuItem);
+ end;
+ end;
+ end;
+ // Conditionally disable menu item of last enabled column.
+ if (VisibleCounter = 1) and (VisibleItem <> nil) and not (poAllowHideAll in FOptions) then
+ VisibleItem.Enabled := False;
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+end.
+
Added: trunk/WPGM/Components/VirtualTreeview/VirtualTrees.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/VirtualTrees.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/VirtualTrees.pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/VirtualTrees.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/VirtualTrees.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,29873 @@
+unit VirtualTrees;
+
+// Version 3.8.3
+//
+// The contents of this file are subject to the Mozilla Public License
+// Version 1.1 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+//
+// Alternatively, you may redistribute this library, use and/or modify it under the terms of the
+// GNU Lesser General Public License as published by the Free Software Foundation;
+// either version 2.1 of the License, or (at your option) any later version.
+// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/.
+//
+// Software distributed under the License is distributed on an "AS IS" basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
+// specific language governing rights and limitations under the License.
+//
+// The original code is VirtualTrees.pas, released September 30, 2000.
+//
+// The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de),
+// written by Dipl. Ing. Mike Lischke (public at lischke-online.de, www.lischke-online.de).
+//
+// Portions created by digital publishing AG are Copyright
+// (C) 1999-2001 digital publishing AG. All Rights Reserved.
+//----------------------------------------------------------------------------------------------------------------------
+//
+// For full document history see help file.
+//
+// Credits for their valuable assistance and code donations go to:
+// Freddy Ertl, Marian Aldenhövel, Thomas Bogenrieder, Jim Kuenemann, Werner Lehmann, Jens Treichler,
+// Paul Gallagher (IBO tree), Ondrej Kelle, Ronaldo Melo Ferraz, Heri Bender, Roland Bedürftig (BCB)
+// Anthony Mills, Alexander Egorushkin (BCB), Mathias Torell (BCB), Frank van den Bergh, Vadim Sedulin, Peter Evans,
+// Milan Vandrovec (BCB), Steve Moss (system check images), Joe White, David Clark (local node memory manager),
+// Anders Thomsen, Igor Afanasyev
+// Beta testers:
+// Freddy Ertl, Hans-Jürgen Schnorrenberg, Werner Lehmann, Jim Kueneman, Vadim Sedulin, Moritz Franckenstein,
+// Wim van der Vegt, Franc v/d Westelaken
+// Indirect contribution (via publicly accessible work of those persons):
+// Alex Denissov, Hiroyuki Hori (MMXAsm expert)
+// Documentation:
+// Markus Spoettl and toolsfactory GbR (http://www.doc-o-matic.com/, sponsoring Virtual Treeview
+// with a free copy of the Doc-O-Matic help authoring system), Sven H. (Step by step tutorial)
+// CLX:
+// Dmitri Dmitrienko (initial developer)
+//----------------------------------------------------------------------------------------------------------------------
+
+interface
+
+{$BOOLEVAL OFF} // Use fastest possible boolean evaluation.
+
+{$I Compilers.inc}
+{.$define UseFlatScrollbars}
+{.$define ReverseFullExpandHotKey} // Used to define Ctrl+'+' instead of Ctrl+Shift+'+' for full expand (and similar for collapsing).
+{$define ThemeSupport}
+
+// Virtual Treeview can use a tiny but very effective local memory manager for node allocation.
+// The local memory manager was implemented by David Clark from Caelo Software Inc.
+// See below for more info about it.
+{.$define UseLocalMemoryManager}
+
+{.$define TntSupport} // Added by Igor Afanasyev to support unicode-aware inplace editor. This implementation uses
+ // Troy Wolbrink's TNT controls, which can be found at:
+ // http://home.ccci.org/wolbrink/tnt/delphi_unicode_controls.htm.
+
+{$HPPEMIT '#include <objidl.h>'}
+{$HPPEMIT '#include <oleidl.h>'} // Necessary for BCB 6 SP 2.
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ImgList, ActiveX, StdCtrls, Menus, Printers,
+ SyncObjs // critical sections
+ {$ifdef ThemeSupport}
+ {$ifndef COMPILER_7_UP}
+ , ThemeSrv, TMSchema, UxTheme // Windows XP themes support. Get these units from www.delphi-gems.com.
+ {$else}
+ , Themes, UxTheme
+ {$endif COMPILE_7_UP}
+ {$endif ThemeSupport}
+ {$ifdef TntSupport}
+ , TntStdCtrls // Unicode aware inplace editor.
+ {$endif TntSupport}
+ ;
+
+const
+ VTVersion = '3.8.3';
+ VTTreeStreamVersion = 2;
+ VTHeaderStreamVersion = 2; // The header needs an own stream version to indicate changes only relevant to the header.
+
+ CacheThreshold = 2000; // Number of nodes a tree must at least have to start caching and at the same
+ // time the maximum number of nodes between two cache entries.
+ FadeAnimationStepCount = 255; // Number of animation steps for hint fading (0..255).
+ ShadowSize = 5; // Size in pixels of the hint shadow. This value has no influence on Win2K and XP systems
+ // as those OSes have native shadow support.
+
+ // Special identifiers for columns.
+ NoColumn = -1;
+ InvalidColumn = -2;
+
+ // Indices for check state images used for checking.
+ ckEmpty = 0; // an empty image used as place holder
+ // radio buttons
+ ckRadioUncheckedNormal = 1;
+ ckRadioUncheckedHot = 2;
+ ckRadioUncheckedPressed = 3;
+ ckRadioUncheckedDisabled = 4;
+ ckRadioCheckedNormal = 5;
+ ckRadioCheckedHot = 6;
+ ckRadioCheckedPressed = 7;
+ ckRadioCheckedDisabled = 8;
+ // check boxes
+ ckCheckUncheckedNormal = 9;
+ ckCheckUncheckedHot = 10;
+ ckCheckUncheckedPressed = 11;
+ ckCheckUncheckedDisabled = 12;
+ ckCheckCheckedNormal = 13;
+ ckCheckCheckedHot = 14;
+ ckCheckCheckedPressed = 15;
+ ckCheckCheckedDisabled = 16;
+ ckCheckMixedNormal = 17;
+ ckCheckMixedHot = 18;
+ ckCheckMixedPressed = 19;
+ ckCheckMixedDisabled = 20;
+ // simple button
+ ckButtonNormal = 21;
+ ckButtonHot = 22;
+ ckButtonPressed = 23;
+ ckButtonDisabled = 24;
+
+ // Instead using a TTimer class for each of the various events I use Windows timers with messages
+ // as this is more economical.
+ ExpandTimer = 1;
+ EditTimer = 2;
+ HeaderTimer = 3;
+ ScrollTimer = 4;
+ ChangeTimer = 5;
+ StructureChangeTimer = 6;
+ SearchTimer = 7;
+
+ // Need to use this message to release the edit link interface asynchronly.
+ WM_RELEASEEDITLINK = WM_APP + 31;
+ WM_CHANGESTATE = WM_APP + 32;
+
+ // Virtual Treeview does not need to be subclass by an eventual Theme Manager class as it handles
+ // Windows XP theme painting itself. Hence the special non-subclass message is used to prevent subclassing.
+ CM_DENYSUBCLASSING = CM_BASE + 2000;
+
+ // Decoupling message for auto-adjusting the internal edit window.
+ CM_AUTOADJUST = CM_BASE + 2005;
+
+ // VT's own clipboard formats,
+ // Note: The reference format is used internally to allow to link to a tree reference
+ // to implement optimized moves and other back references.
+ CFSTR_VIRTUALTREE = 'Virtual Tree Data';
+ CFSTR_VTREFERENCE = 'Virtual Tree Reference';
+ CFSTR_HTML = 'HTML Format';
+ CFSTR_RTF = 'Rich Text Format';
+ CFSTR_RTFNOOBJS = 'Rich Text Format Without Objects';
+ CFSTR_CSV = 'CSV';
+
+ // Drag image helpers for Windows 2000 and up.
+ IID_IDropTargetHelper: TGUID = (D1: $4657278B; D2: $411B; D3: $11D2; D4: ($83, $9A, $00, $C0, $4F, $D9, $18, $D0));
+ IID_IDragSourceHelper: TGUID = (D1: $DE5BF786; D2: $477A; D3: $11D2; D4: ($83, $9D, $00, $C0, $4F, $D9, $18, $D0));
+ IID_IDropTarget: TGUID = (D1: $00000122; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00, $00, $00, $46));
+ CLSID_DragDropHelper: TGUID = (D1: $4657278A; D2: $411B; D3: $11D2; D4: ($83, $9A, $00, $C0, $4F, $D9, $18, $D0));
+
+ SID_IDropTargetHelper = '{4657278B-411B-11D2-839A-00C04FD918D0}';
+ SID_IDragSourceHelper = '{DE5BF786-477A-11D2-839D-00C04FD918D0}';
+ SID_IDropTarget = '{00000122-0000-0000-C000-000000000046}';
+
+ // Help identifiers for exceptions. Application developers are responsible to link them with actual help topics.
+ hcTFEditLinkIsNil = 2000;
+ hcTFWrongMoveError = 2001;
+ hcTFWrongStreamFormat = 2002;
+ hcTFWrongStreamVersion = 2003;
+ hcTFStreamTooSmall = 2004;
+ hcTFCorruptStream1 = 2005;
+ hcTFCorruptStream2 = 2006;
+ hcTFClipboardFailed = 2007;
+ hcTFCannotSetUserData = 2008;
+
+ // Header standard split cursor.
+ crHeaderSplit = TCursor(100);
+
+ UtilityImageSize = 16; // Needed by descentants for hittests.
+
+var // Clipboard format IDs used in OLE drag'n drop and clipboard transfers.
+ CF_VIRTUALTREE,
+ CF_VTREFERENCE,
+ CF_VRTF,
+ CF_VRTFNOOBJS, // Unfortunately CF_RTF* is already defined as being
+ // registration strings so I have to use different identifiers.
+ CF_HTML,
+ CF_CSV: Word;
+
+ MMXAvailable: Boolean; // necessary to know because the blend code uses MMX instructions
+
+{$MinEnumSize 1, make enumerations as small as possible}
+
+type
+ // The exception used by the trees.
+ EVirtualTreeError = class(Exception);
+
+
+
+ PCardinal = ^Cardinal;
+
+ // Limits the speed interval which can be used for auto scrolling (milliseconds).
+ TAutoScrollInterval = 1..1000;
+
+ // Need to declare the correct WMNCPaint record as the VCL (D5-) doesn't.
+ TRealWMNCPaint = packed record
+ Msg: Cardinal;
+ Rgn: HRGN;
+ lParam: Integer;
+ Result: Integer;
+ end;
+
+ // The next two message records are not declared in Delphi 6 and lower.
+ TWMPrint = packed record
+ Msg: Cardinal;
+ DC: HDC;
+ Flags: Cardinal;
+ Result: Integer;
+ end;
+
+ TWMPrintClient = TWMPrint;
+
+ {$ifndef COMPILER_5_UP}
+ TWMContextMenu = TWMMouse;
+ {$endif COMPILER_5_UP}
+
+ // Be careful when adding new states as this might change the size of the type which in turn
+ // changes the alignment in the node record as well as the stream chunks.
+ // Do not reorder the states and always add new states at the end of this enumeration in order to avoid
+ // breaking existing code.
+ TVirtualNodeState = (
+ vsInitialized, // Set after the node has been initialized.
+ vsChecking, // Node's check state is changing, avoid propagation.
+ vsCutOrCopy, // Node is selected as cut or copy and paste source.
+ vsDisabled, // Set if node is disabled.
+ vsDeleting, // Set when the node is about to be freed.
+ vsExpanded, // Set if the node is expanded.
+ vsHasChildren, // Indicates the presence of child nodes without actually setting them.
+ vsVisible, // Indicate whether the node is visible or not (independant of the expand states of its parents).
+ vsSelected, // Set if the node is in the current selection.
+ vsInitialUserData, // Set if (via AddChild or InsertNode) initial user data has been set which requires OnFreeNode.
+ vsAllChildrenHidden, // Set if vsHasChildren is set and no child node has the vsVisible flag set.
+ vsClearing, // A node's children are being deleted. Don't register structure change event.
+ vsMultiline // Node text is wrapped at the cell boundaries instead of being shorted.
+ );
+ TVirtualNodeStates = set of TVirtualNodeState;
+
+ // States used in InitNode to indicate states a node shall initially have.
+ TVirtualNodeInitState = (
+ ivsDisabled,
+ ivsExpanded,
+ ivsHasChildren,
+ ivsMultiline,
+ ivsSelected
+ );
+ TVirtualNodeInitStates = set of TVirtualNodeInitState;
+
+ TScrollBarStyle = (
+ sbmRegular,
+ sbmFlat,
+ sbm3D
+ );
+
+ // options per column
+ TVTColumnOption = (
+ coAllowClick,
+ coDraggable,
+ coEnabled,
+ coParentBidiMode,
+ coParentColor,
+ coResizable,
+ coShowDropMark,
+ coVisible
+ );
+ TVTColumnOptions = set of TVTColumnOption;
+
+ // These flags are returned by the hit test method.
+ THitPosition = (
+ hiAbove, // above the client area (if relative) or the absolute tree area
+ hiBelow, // below the client area (if relative) or the absolute tree area
+ hiNowhere, // no node is involved (possible only if the tree is not as tall as the client area)
+ hiOnItem, // on the bitmaps/buttons or label associated with an item
+ hiOnItemButton, // on the button associated with an item
+ hiOnItemCheckbox, // on the checkbox if enabled
+ hiOnItemIndent, // in the indentation area in front of a node
+ hiOnItemLabel, // on the normal text area associated with an item
+ hiOnItemLeft, // in the area to the left of a node's text area (e.g. when right aligned or centered)
+ hiOnItemRight, // in the area to the right of a node's text area (e.g. if left aligned or centered)
+ hiOnNormalIcon, // on the "normal" image
+ hiOnStateIcon, // on the state image
+ hiToLeft, // to the left of the client area (if relative) or the absolute tree area
+ hiToRight // to the right of the client area (if relative) or the absolute tree area
+ );
+ THitPositions = set of THitPosition;
+
+ TCheckType = (
+ ctNone,
+ ctTriStateCheckBox,
+ ctCheckBox,
+ ctRadioButton,
+ ctButton
+ );
+
+ // The check states include both, transient and fluent (temporary) states. The only temporary state defined so
+ // far is the pressed state.
+ TCheckState = (
+ csUncheckedNormal, // unchecked and not pressed
+ csUncheckedPressed, // unchecked and pressed
+ csCheckedNormal, // checked and not pressed
+ csCheckedPressed, // checked and pressed
+ csMixedNormal, // 3-state check box and not pressed
+ csMixedPressed // 3-state check box and pressed
+ );
+
+ TCheckImageKind = (
+ ckLightCheck, // gray cross
+ ckDarkCheck, // black cross
+ ckLightTick, // gray tick mark
+ ckDarkTick, // black tick mark
+ ckFlat, // flat images (no 3D border)
+ ckXP, // Windows XP style
+ ckCustom, // application defined check images
+ ckSystem, // System defined check images.
+ ckSystemFlat // Flat system defined check images.
+ );
+
+ // mode to describe a move action
+ TVTNodeAttachMode = (
+ amNoWhere, // just for simplified tests, means to ignore the Add/Insert command
+ amInsertBefore, // insert node just before destination (as sibling of destination)
+ amInsertAfter, // insert node just after destionation (as sibling of destination)
+ amAddChildFirst, // add node as first child of destination
+ amAddChildLast // add node as last child of destination
+ );
+
+ // modes to determine drop position further
+ TDropMode = (
+ dmNowhere,
+ dmAbove,
+ dmOnNode,
+ dmBelow
+ );
+
+ // operations basically allowed during drag'n drop
+ TDragOperation = (
+ doCopy,
+ doMove,
+ doLink
+ );
+ TDragOperations = set of TDragOperation;
+
+ TVTImageKind = (
+ ikNormal,
+ ikSelected,
+ ikState,
+ ikOverlay
+ );
+
+ TVTHintMode = (
+ hmDefault, // show the hint of the control
+ hmHint, // show node specific hint string returned by the application
+ hmHintAndDefault, // same as hmHint but show the control's hint if no node is concerned
+ hmTooltip // show the text of the node if it isn't already fully shown
+ );
+
+ TMouseButtons = set of TMouseButton;
+
+ // Used to describe the action to do when using the OnBeforeItemErase event.
+ TItemEraseAction = (
+ eaColor, // use the provided color to erase the background instead the one of the tree
+ eaDefault // the tree should erase the item's background (bitmap or solid)
+ );
+
+
+ // There is a heap of switchable behavior in the tree. Since published properties may never exceed 4 bytes,
+ // which limits sets to at most 32 members, and because for better overview tree options are splitted
+ // in various sub-options and are held in a commom options class.
+ //
+ // Options to customize tree appearance:
+ TVTPaintOption = (
+ toHideFocusRect, // Avoid drawing the dotted rectangle around the currently focused node.
+ toHideSelection, // Selected nodes are drawn as unselected nodes if the tree is unfocused.
+ toHotTrack, // Track which node is under the mouse cursor.
+ toPopupMode, // Paint tree as would it always have the focus (useful for tree combo boxes etc.)
+ toShowBackground, // Use the background image if there's one.
+ toShowButtons, // Display collapse/expand buttons left to a node.
+ toShowDropmark, // Show the dropmark during drag'n drop operations.
+ toShowHorzGridLines, // Display horizontal lines to simulate a grid.
+ toShowRoot, // Show lines also at top level (does not show the hidden/internal root node).
+ toShowTreeLines, // Display tree lines to show hierarchy of nodes.
+ toShowVertGridLines, // Display vertical lines (depending on columns) to simulate a grid.
+ toThemeAware, // Draw UI elements (header, tree buttons etc.) according to the current theme if
+ // enabled (Windows XP+ only, application must be themed).
+ toUseBlendedImages, // Enable alpha blending for ghosted nodes or those which are being cut/copied.
+ toGhostedIfUnfocused // Ghosted images are still shown as ghosted if unfocused (otherwise the become non-ghosted
+ // images).
+ );
+ TVTPaintOptions = set of TVTPaintOption;
+
+ // Options to toggle animation support:
+ TVTAnimationOption = (
+ toAnimatedToggle // Expanding and collapsing a node is animated (quick window scroll).
+ );
+ TVTAnimationOptions = set of TVTAnimationOption;
+
+ // Options which toggle automatic handling of certain situations:
+ TVTAutoOption = (
+ toAutoDropExpand, // Expand node if it is the drop target for more than certain time.
+ toAutoExpand, // Nodes are expanded (collapsed) when getting (losing) the focus.
+ toAutoScroll, // Scroll if mouse is near the border while dragging or selecting.
+ toAutoScrollOnExpand, // Scroll as many child nodes in view as possible after expanding a node.
+ toAutoSort, // Sort tree when Header.SortColumn or Header.SortDirection change or sort node if
+ // child nodes are added.
+ toAutoSpanColumns, // Large entries continue into next column(s) if there's no text in them (no clipping).
+ toAutoTristateTracking, // Checkstates are automatically propagated for tri state check boxes.
+ toAutoHideButtons, // Node buttons are hidden when there are child nodes, but all are invisible.
+ toAutoDeleteMovedNodes, // Delete nodes which where moved in a drag operation (if not directed otherwise).
+ toDisableAutoscrollOnFocus,// Disable scrolling a column entirely into view if it gets focused.
+ toAutoChangeScale, // Change default node height automatically if the system's font scale is set to big fonts.
+ toAutoFreeOnCollapse // Frees any child node after a node has been collapsed (HasChildren flag stays there).
+ );
+ TVTAutoOptions = set of TVTAutoOption;
+
+ // Options which determine the tree's behavior when selecting nodes:
+ TVTSelectionOption = (
+ toDisableDrawSelection, // Prevent user from selecting with the selection rectangle in multiselect mode.
+ toExtendedFocus, // Entries other than in the main column can be selected, edited etc.
+ toFullRowSelect, // Hit test as well as selection highlight are not constrained to the text of a node.
+ toLevelSelectConstraint, // Constrain selection to the same level as the selection anchor.
+ toMiddleClickSelect, // Allow selection, dragging etc. with the middle mouse button. This and toWheelPanning
+ // are mutual exclusive.
+ toMultiSelect, // Allow more than one node to be selected.
+ toRightClickSelect, // Allow selection, dragging etc. with the right mouse button.
+ toSiblingSelectConstraint, // constrain selection to nodes with same parent
+ toCenterScrollIntoView // Center nodes vertically in the client area when scrolling into view.
+ );
+ TVTSelectionOptions = set of TVTSelectionOption;
+
+ // Options which do not fit into any of the other groups:
+ TVTMiscOption = (
+ toAcceptOLEDrop, // Register tree as OLE accepting drop target
+ toCheckSupport, // Show checkboxes/radio buttons.
+ toEditable, // Node captions can be edited.
+ toFullRepaintOnResize, // Fully invalidate the tree when its window is resized (CS_HREDRAW/CS_VREDRAW).
+ toGridExtensions, // Use some special enhancements to simulate and support grid behavior.
+ toInitOnSave, // Initialize nodes when saving a tree to a stream.
+ toReportMode, // Tree behaves like TListView in report mode.
+ toToggleOnDblClick, // Toggle node expansion state when it is double clicked.
+ toWheelPanning, // Support for mouse panning (wheel mice only). This option and toMiddleClickSelect are
+ // mutal exclusive, where panning has precedence.
+ toReadOnly // The tree does not allow to be modified in any way. No action is executed and
+ // node editing is not possible.
+ );
+ TVTMiscOptions = set of TVTMiscOption;
+
+const
+ DefaultPaintOptions = [toShowButtons, toShowButtons, toShowDropmark, toShowTreeLines, toShowRoot, toThemeAware,
+ toUseBlendedImages];
+ DefaultAnimationOptions = [];
+ DefaultAutoOptions = [toAutoDropExpand, toAutoTristateTracking, toAutoScrollOnExpand, toAutoDeleteMovedNodes];
+ DefaultSelectionOptions = [];
+ DefaultMiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning];
+ DefaultColumnOptions = [coAllowClick, coDraggable, coEnabled, coParentColor, coParentBidiMode, coResizable,
+ coShowDropmark, coVisible];
+
+type
+ TBaseVirtualTree = class;
+ TVirtualTreeClass = class of TBaseVirtualTree;
+
+ PVirtualNode = ^TVirtualNode;
+
+ TColumnIndex = type Integer;
+ TColumnPosition = type Cardinal;
+
+ // This record must already be defined here and not later because otherwise BCB users will not be able
+ // to compile (conversion done by BCB is wrong).
+ TCacheEntry = record
+ Node: PVirtualNode;
+ AbsoluteTop: Cardinal;
+ end;
+
+ TCache = array of TCacheEntry;
+ TNodeArray = array of PVirtualNode;
+
+ TCustomVirtualTreeOptions = class(TPersistent)
+ private
+ FOwner: TBaseVirtualTree;
+ FPaintOptions: TVTPaintOptions;
+ FAnimationOptions: TVTAnimationOptions;
+ FAutoOptions: TVTAutoOptions;
+ FSelectionOptions: TVTSelectionOptions;
+ FMiscOptions: TVTMiscOptions;
+ procedure SetAnimationOptions(const Value: TVTAnimationOptions);
+ procedure SetAutoOptions(const Value: TVTAutoOptions);
+ procedure SetMiscOptions(const Value: TVTMiscOptions);
+ procedure SetPaintOptions(const Value: TVTPaintOptions);
+ procedure SetSelectionOptions(const Value: TVTSelectionOptions);
+ protected
+ property AnimationOptions: TVTAnimationOptions read FAnimationOptions write SetAnimationOptions
+ default DefaultAnimationOptions;
+ property AutoOptions: TVTAutoOptions read FAutoOptions write SetAutoOptions default DefaultAutoOptions;
+ property MiscOptions: TVTMiscOptions read FMiscOptions write SetMiscOptions default DefaultMiscOptions;
+ property PaintOptions: TVTPaintOptions read FPaintOptions write SetPaintOptions default DefaultPaintOptions;
+ property SelectionOptions: TVTSelectionOptions read FSelectionOptions write SetSelectionOptions
+ default DefaultSelectionOptions;
+ public
+ constructor Create(AOwner: TBaseVirtualTree); virtual;
+
+ procedure AssignTo(Dest: TPersistent); override;
+
+ property Owner: TBaseVirtualTree read FOwner;
+ end;
+
+ TTreeOptionsClass = class of TCustomVirtualTreeOptions;
+
+ TVirtualTreeOptions = class(TCustomVirtualTreeOptions)
+ published
+ property AnimationOptions;
+ property AutoOptions;
+ property MiscOptions;
+ property PaintOptions;
+ property SelectionOptions;
+ end;
+
+ // Used in the CF_VTREFERENCE clipboard format.
+ PVTReference = ^TVTReference;
+ TVTReference = record
+ Process: Cardinal;
+ Tree: TBaseVirtualTree;
+ end;
+
+ TVirtualNode = packed record
+ Index, // index of node with regard to its parent
+ ChildCount: Cardinal; // number of child nodes
+ NodeHeight: Word; // height in pixels
+ States: TVirtualNodeStates; // states describing various properties of the node (expanded, initialized etc.)
+ Align: Byte; // line/button alignment
+ CheckState: TCheckState; // indicates the current check state (e.g. checked, pressed etc.)
+ CheckType: TCheckType; // indicates which check type shall be used for this node
+ Dummy: Byte; // dummy value to fill DWORD boundary
+ TotalCount, // sum of this node, all of its child nodes and their child nodes etc.
+ TotalHeight: Cardinal; // height in pixels this node covers on screen including the height of all of its
+ // children
+ // Note: Some copy routines require that all pointers (as well as the data area) in a node are
+ // located at the end of the node! Hence if you want to add new member fields (except pointers to internal
+ // data) then put them before field Parent.
+ Parent, // reference to the node's parent (for the root this contains the treeview)
+ PrevSibling, // link to the node's previous sibling or nil if it is the first node
+ NextSibling, // link to the node's next sibling or nil if it is the last node
+ FirstChild, // link to the node's first child...
+ LastChild: PVirtualNode; // link to the node's last child...
+ Data: record end; // this is a placeholder, each node gets extra data determined by NodeDataSize
+ end;
+
+ // TVTNodeMemoryManager is a high-performance local memory manager for allocating TVirtualNode structures.
+ // It is not thread-safe in itself, because it assumes that the virtual tree is being used within a single
+ // thread. The local memory manager supports only fixed-length allocation requests - all requests must be of
+ // the same size. The performance improvements are a result of TVTNodeMemoryManager getting 16K blocks
+ // of memory from the Delphi memory manager and then managing them in a highly efficient manner.
+ // A consequence is that node memory allocations/deallocations are not visible to memory debugging tools.
+ //
+ // The local memory manager is disabled by default - to enable it {$define UseLocalMemoryManager}. For smaller trees,
+ // say less than 10,000 nodes, there is really no major performance benefit in using the local memory manager.
+ {$ifdef UseLocalMemoryManager}
+ TVTNodeMemoryManager = class
+ private
+ FAllocSize: Cardinal; // The memory allocated for each node
+ FBlockList: TList; // List of allocated blocks
+ FBytesAvailable: Cardinal; // Bytes available in current block
+ FNext: PVirtualNode; // Pointer to next available node in current block
+ FFreeSpace: PVirtualNode; // Pointer to free space chain
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ function AllocNode(const Size: Cardinal): PVirtualNode;
+ procedure FreeNode(const Node: PVirtualNode);
+ procedure Clear;
+ end;
+ {$endif UseLocalMemoryManager}
+
+ // structure used when info about a certain position in the tree is needed
+ THitInfo = record
+ HitNode: PVirtualNode;
+ HitPositions: THitPositions;
+ HitColumn: TColumnIndex;
+ end;
+
+ // auto scroll directions
+ TScrollDirections = set of (
+ sdLeft,
+ sdUp,
+ sdRight,
+ sdDown
+ );
+
+ // OLE drag'n drop support
+ TFormatEtcArray = array of TFormatEtc;
+ TFormatArray = array of Word;
+
+ // IDataObject.SetData support
+ TInternalStgMedium = packed record
+ Format: TClipFormat;
+ Medium: TStgMedium;
+ end;
+ TInternalStgMediumArray = array of TInternalStgMedium;
+
+ TEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc)
+ private
+ FTree: TBaseVirtualTree;
+ FFormatEtcArray: TFormatEtcArray;
+ FCurrentIndex: Integer;
+ public
+ constructor Create(Tree: TBaseVirtualTree; AFormatEtcArray: TFormatEtcArray);
+
+ function Clone(out Enum: IEnumFormatEtc): HResult; stdcall;
+ function Next(celt: Integer; out elt; pceltFetched: PLongint): HResult; stdcall;
+ function Reset: HResult; stdcall;
+ function Skip(celt: Integer): HResult; stdcall;
+ end;
+
+ // ----- OLE drag'n drop handling
+ IDropTargetHelper = interface(IUnknown)
+ [SID_IDropTargetHelper]
+ function DragEnter(hwndTarget: HWND; pDataObject: IDataObject; var ppt: TPoint; dwEffect: Integer): HRESULT; stdcall;
+ function DragLeave: HRESULT; stdcall;
+ function DragOver(var ppt: TPoint; dwEffect: Integer): HRESULT; stdcall;
+ function Drop(pDataObject: IDataObject; var ppt: TPoint; dwEffect: Integer): HRESULT; stdcall;
+ function Show(fShow: Boolean): HRESULT; stdcall;
+ end;
+
+ PSHDragImage = ^TSHDragImage;
+ TSHDragImage = packed record
+ sizeDragImage: TSize;
+ ptOffset: TPoint;
+ hbmpDragImage: HBITMAP;
+ ColorRef: TColorRef;
+ end;
+
+ IDragSourceHelper = interface(IUnknown)
+ [SID_IDragSourceHelper]
+ function InitializeFromBitmap(var SHDragImage: TSHDragImage; pDataObject: IDataObject): HRESULT; stdcall;
+ function InitializeFromWindow(Window: HWND; var ppt: TPoint; pDataObject: IDataObject): HRESULT; stdcall;
+ end;
+
+ IVTDragManager = interface(IUnknown)
+ ['{C4B25559-14DA-446B-8901-0C879000EB16}']
+ procedure ForceDragLeave; stdcall;
+ function GetDataObject: IDataObject; stdcall;
+ function GetDragSource: TBaseVirtualTree; stdcall;
+ function GetDropTargetHelperSupported: Boolean; stdcall;
+ function GetIsDropTarget: Boolean; stdcall;
+
+ property DataObject: IDataObject read GetDataObject;
+ property DragSource: TBaseVirtualTree read GetDragSource;
+ property DropTargetHelperSupported: Boolean read GetDropTargetHelperSupported;
+ property IsDropTarget: Boolean read GetIsDropTarget;
+ end;
+
+ // This data object is used in two different places. One is for clipboard operations and the other while dragging.
+ TVTDataObject = class(TInterfacedObject, IDataObject)
+ private
+ FOwner: TBaseVirtualTree; // The tree which provides clipboard or drag data.
+ FForClipboard: Boolean; // Determines which data to render with GetData.
+ FFormatEtcArray: TFormatEtcArray;
+ FInternalStgMediumArray: TInternalStgMediumArray; // The available formats in the DataObject
+ FAdviseHolder: IDataAdviseHolder; // Reference to an OLE supplied implementation for advising.
+ protected
+ function CanonicalIUnknown(TestUnknown: IUnknown): IUnknown;
+ function EqualFormatEtc(FormatEtc1, FormatEtc2: TFormatEtc): Boolean;
+ function FindFormatEtc(TestFormatEtc: TFormatEtc; const FormatEtcArray: TFormatEtcArray): integer;
+ function FindInternalStgMedium(Format: TClipFormat): PStgMedium;
+ function HGlobalClone(HGlobal: THandle): THandle;
+ function RenderInternalOLEData(const FormatEtcIn: TFormatEtc; var Medium: TStgMedium; var OLEResult: HResult): Boolean;
+ function StgMediumIncRef(const InStgMedium: TStgMedium; var OutStgMedium: TStgMedium;
+ CopyInMedium: Boolean; DataObject: IDataObject): HRESULT;
+
+ property ForClipboard: Boolean read FForClipboard;
+ property FormatEtcArray: TFormatEtcArray read FFormatEtcArray write FFormatEtcArray;
+ property InternalStgMediumArray: TInternalStgMediumArray read FInternalStgMediumArray write FInternalStgMediumArray;
+ property Owner: TBaseVirtualTree read FOwner;
+ public
+ constructor Create(AOwner: TBaseVirtualTree; ForClipboard: Boolean); virtual;
+ destructor Destroy; override;
+
+ function DAdvise(const FormatEtc: TFormatEtc; advf: Integer; const advSink: IAdviseSink; out dwConnection: Integer):
+ HResult; virtual; stdcall;
+ function DUnadvise(dwConnection: Integer): HResult; virtual; stdcall;
+ function EnumDAdvise(out enumAdvise: IEnumStatData): HResult; virtual; stdcall;
+ function EnumFormatEtc(Direction: Integer; out EnumFormatEtc: IEnumFormatEtc): HResult; virtual; stdcall;
+ function GetCanonicalFormatEtc(const FormatEtc: TFormatEtc; out FormatEtcOut: TFormatEtc): HResult; virtual; stdcall;
+ function GetData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium): HResult; virtual; stdcall;
+ function GetDataHere(const FormatEtc: TFormatEtc; out Medium: TStgMedium): HResult; virtual; stdcall;
+ function QueryGetData(const FormatEtc: TFormatEtc): HResult; virtual; stdcall;
+ function SetData(const FormatEtc: TFormatEtc; var Medium: TStgMedium; DoRelease: BOOL): HResult; virtual; stdcall;
+ end;
+
+ // TVTDragManager is a class to manage drag and drop in a Virtual Treeview.
+ TVTDragManager = class(TInterfacedObject, IVTDragManager, IDropSource, IDropTarget)
+ private
+ FOwner, // The tree which is responsible for drag management.
+ FDragSource: TBaseVirtualTree; // Reference to the source tree if the source was a VT, might be different than
+ // the owner tree.
+ FIsDropTarget: Boolean; // True if the owner is currently the drop target.
+ FDataObject: IDataObject; // A reference to the data object passed in by DragEnter (only used when the owner
+ // tree is the current drop target).
+ FDropTargetHelper: IDropTargetHelper; // Win2k > Drag image support
+ FFullDragging: BOOL; // True, if full dragging is currently enabled in the system.
+
+ function GetDataObject: IDataObject; stdcall;
+ function GetDragSource: TBaseVirtualTree; stdcall;
+ function GetDropTargetHelperSupported: Boolean; stdcall;
+ function GetIsDropTarget: Boolean; stdcall;
+ public
+ constructor Create(AOwner: TBaseVirtualTree); virtual;
+ destructor Destroy; override;
+
+ function DragEnter(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult; stdcall;
+ function DragLeave: HResult; stdcall;
+ function DragOver(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult; stdcall;
+ function Drop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult; stdcall;
+ procedure ForceDragLeave; stdcall;
+ function GiveFeedback(Effect: Integer): HResult; stdcall;
+ function QueryContinueDrag(EscapePressed: BOOL; KeyState: Integer): HResult; stdcall;
+ end;
+
+ PVTHintData = ^TVTHintData;
+ TVTHintData = record
+ Tree: TBaseVirtualTree;
+ Node: PVirtualNode;
+ Column: TColumnIndex;
+ HintRect: TRect; // used for draw trees only, string trees get the size from the hint string
+ DefaultHint: WideString; // used only if there is no node specific hint string available
+ // or a header hint is about to appear
+ HintText: WideString; // set when size of the hint window is calculated
+ BidiMode: TBidiMode;
+ Alignment: TAlignment;
+ end;
+
+ // Determines the kind of animation when a hint is activated.
+ THintAnimationType = (
+ hatNone, // no animation at all, just display hint/tooltip
+ hatFade, // fade in the hint/tooltip, like in Windows 2000
+ hatSlide, // slide in the hint/tooltip, like in Windows 98
+ hatSystemDefault // use what the system is using (slide for Win9x, slide/fade for Win2K+, depends on settings)
+ );
+
+ // The trees need an own hint window class because of Unicode output and adjusted font.
+ TVirtualTreeHintWindow = class(THintWindow)
+ private
+ FHintData: TVTHintData;
+ FBackground,
+ FDrawBuffer,
+ FTarget: TBitmap;
+ FTextHeight: Integer;
+ function AnimationCallback(Step, StepSize: Integer; Data: Pointer): Boolean;
+ procedure InternalPaint(Step, StepSize: Integer);
+ procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
+ procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
+ procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
+ procedure WMShowWindow(var Message: TWMShowWindow); message WM_SHOWWINDOW;
+ protected
+ procedure CreateParams(var Params: TCreateParams); override;
+
+ procedure Paint; override;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ procedure ActivateHint(Rect: TRect; const AHint: string); override;
+ function CalcHintRect(MaxWidth: Integer; const AHint: string; AData: Pointer): TRect; override;
+ function IsHintMsg(var Msg: TMsg): Boolean; override;
+ end;
+
+ // Drag image support for the tree.
+ TVTTransparency = 0..255;
+ TVTBias = -128..127;
+
+ // Simple move limitation for the drag image.
+ TVTDragMoveRestriction = (
+ dmrNone,
+ dmrHorizontalOnly,
+ dmrVerticalOnly
+ );
+
+ TVTDragImageStates = set of (
+ disHidden, // Internal drag image is currently hidden (always hidden if drag image helper interfaces are used).
+ disInDrag, // Drag image class is currently being used.
+ disPrepared, // Drag image class is prepared.
+ disSystemSupport // Running on Windows 2000 or higher. System supports drag images natively.
+ );
+
+ // Class to manage header and tree drag image during a drag'n drop operation.
+ TVTDragImage = class
+ private
+ FOwner: TBaseVirtualTree;
+ FBackImage, // backup of overwritten screen area
+ FAlphaImage, // target for alpha blending
+ FDragImage: TBitmap; // the actual drag image to blend to screen
+ FImagePosition, // position of image (upper left corner) in screen coordinates
+ FLastPosition: TPoint; // last mouse position in screen coordinates
+ FTransparency: TVTTransparency; // alpha value of the drag image (0 - fully transparent, 255 - fully opaque)
+ FPreBlendBias, // value to darken or lighten the drag image before it is blended
+ FPostBlendBias: TVTBias; // value to darken or lighten the alpha blend result
+ FFade: Boolean; // determines whether to fade the drag image from center to borders or not
+ FRestriction: TVTDragMoveRestriction; // determines in which directions the drag image can be moved
+ FColorKey: TColor; // color to make fully transparent regardless of any other setting
+ FStates: TVTDragImageStates; // Determines the states of the drag image class.
+ function GetVisible: Boolean; // True if the drag image is currently hidden (used only when dragging)
+ protected
+ procedure InternalShowDragImage(ScreenDC: HDC);
+ procedure MakeAlphaChannel(Source, Target: TBitmap);
+ public
+ constructor Create(AOwner: TBaseVirtualTree);
+ destructor Destroy; override;
+
+ function DragTo(P: TPoint; ForceRepaint: Boolean): Boolean;
+ procedure EndDrag;
+ function GetDragImageRect: TRect;
+ procedure HideDragImage;
+ procedure PrepareDrag(DragImage: TBitmap; ImagePosition, HotSpot: TPoint; const DataObject: IDataObject);
+ procedure RecaptureBackground(Tree: TBaseVirtualTree; R: TRect; VisibleRegion: HRGN; CaptureNCArea,
+ ReshowDragImage: Boolean);
+ procedure ShowDragImage;
+ function WillMove(P: TPoint): Boolean;
+
+ property ColorKey: TColor read FColorKey write FColorKey default clWindow;
+ property Fade: Boolean read FFade write FFade default False;
+ property MoveRestriction: TVTDragMoveRestriction read FRestriction write FRestriction default dmrNone;
+ property PostBlendBias: TVTBias read FPostBlendBias write FPostBlendBias default 0;
+ property PreBlendBias: TVTBias read FPreBlendBias write FPreBlendBias default 0;
+ property Transparency: TVTTransparency read FTransparency write FTransparency default 128;
+ property Visible: Boolean read GetVisible;
+ end;
+
+ // tree columns implementation
+ TVirtualTreeColumns = class;
+ TVTHeader = class;
+
+ TVirtualTreeColumnStyle = (
+ vsText,
+ vsOwnerDraw
+ );
+
+ {$ifndef COMPILER_5_UP}
+ TImageIndex = Integer;
+ {$endif COMPILER_5_UP}
+
+ TVTHeaderColumnLayout = (
+ blGlyphLeft,
+ blGlyphRight,
+ blGlyphTop,
+ blGlyphBottom
+ );
+
+ TVirtualTreeColumn = class(TCollectionItem)
+ private
+ FText,
+ FHint: WideString;
+ FLeft,
+ FWidth: Integer;
+ FPosition: TColumnPosition;
+ FMinWidth: Integer;
+ FMaxWidth: Integer;
+ FStyle: TVirtualTreeColumnStyle;
+ FImageIndex: TImageIndex;
+ FBiDiMode: TBiDiMode;
+ FLayout: TVTHeaderColumnLayout;
+ FMargin,
+ FSpacing: Integer;
+ FOptions: TVTColumnOptions;
+ FTag: Integer;
+ FAlignment: TAlignment;
+ FLastWidth: Integer;
+ FColor: TColor;
+ function GetLeft: Integer;
+ function IsBiDiModeStored: Boolean;
+ function IsColorStored: Boolean;
+ procedure SetAlignment(const Value: TAlignment);
+ procedure SetBiDiMode(Value: TBiDiMode);
+ procedure SetColor(const Value: TColor);
+ procedure SetImageIndex(Value: TImageIndex);
+ procedure SetLayout(Value: TVTHeaderColumnLayout);
+ procedure SetMargin(Value: Integer);
+ procedure SetMaxWidth(Value: Integer);
+ procedure SetMinWidth(Value: Integer);
+ procedure SetOptions(Value: TVTColumnOptions);
+ procedure SetPosition(Value: TColumnPosition);
+ procedure SetSpacing(Value: Integer);
+ procedure SetStyle(Value: TVirtualTreeColumnStyle);
+ procedure SetText(const Value: WideString);
+ procedure SetWidth(Value: Integer);
+ protected
+ procedure ComputeHeaderLayout(DC: HDC; const Client: TRect; UseHeaderGlyph, UseSortGlyph: Boolean;
+ var HeaderGlyphPos, SortGlyphPos: TPoint; var TextBounds: TRect);
+ procedure DefineProperties(Filer: TFiler); override;
+ procedure GetAbsoluteBounds(var Left, Right: Integer);
+ function GetDisplayName: string; override;
+ function GetOwner: TVirtualTreeColumns; reintroduce;
+ procedure ReadHint(Reader: TReader);
+ procedure ReadText(Reader: TReader);
+ procedure SetIndex(Value: Integer); override;
+ procedure WriteHint(Writer: TWriter);
+ procedure WriteText(Writer: TWriter);
+ public
+ constructor Create(Collection: TCollection); override;
+ destructor Destroy; override;
+
+ procedure Assign(Source: TPersistent); override;
+ function Equals(OtherColumn: TVirtualTreeColumn): Boolean; virtual;
+ function GetRect: TRect;
+ procedure LoadFromStream(const Stream: TStream; Version: Integer);
+ procedure ParentBiDiModeChanged;
+ procedure ParentColorChanged;
+ procedure RestoreLastWidth;
+ procedure SaveToStream(const Stream: TStream);
+ function UseRightToLeftReading: Boolean;
+
+ property Left: Integer read GetLeft;
+ property Owner: TVirtualTreeColumns read GetOwner;
+ published
+ property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
+ property BiDiMode: TBiDiMode read FBiDiMode write SetBiDiMode stored IsBiDiModeStored default bdLeftToRight;
+ property Color: TColor read FColor write SetColor stored IsColorStored default clWindow;
+ property Hint: WideString read FHint write FHint stored False;
+ property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;
+ property Layout: TVTHeaderColumnLayout read FLayout write SetLayout default blGlyphLeft;
+ property Margin: Integer read FMargin write SetMargin default 4;
+ property MaxWidth: Integer read FMaxWidth write SetMaxWidth default 10000;
+ property MinWidth: Integer read FMinWidth write SetMinWidth default 10;
+ property Options: TVTColumnOptions read FOptions write SetOptions default DefaultColumnOptions;
+ property Position: TColumnPosition read FPosition write SetPosition;
+ property Spacing: Integer read FSpacing write SetSpacing default 4;
+ property Style: TVirtualTreeColumnStyle read FStyle write SetStyle default vsText;
+ property Tag: Integer read FTag write FTag default 0;
+ property Text: WideString read FText write SetText stored False; // Never let the VCL store the wide string,
+ // it is simply unable to write it correctly.
+ // We use DefineProperties here.
+ property Width: Integer read FWidth write SetWidth default 50;
+ end;
+
+ TVirtualTreeColumnClass = class of TVirtualTreeColumn;
+
+ TColumnsArray = array of TVirtualTreeColumn;
+ TCardinalArray = array of Cardinal;
+ TIndexArray = array of TColumnIndex;
+
+ TVirtualTreeColumns = class(TCollection)
+ private
+ FHeader: TVTHeader;
+ FHeaderBitmap: TBitmap; // backbuffer for drawing
+ FHoverIndex, // currently "hot" column
+ FDownIndex, // Column on which a mouse button is held down.
+ FTrackIndex: TColumnIndex; // Index of column which is currently being resized
+ FClickIndex: TColumnIndex; // last clicked column
+ FPositionToIndex: TIndexArray;
+ FNeedPositionsFix: Boolean; // True if FixPositions must still be called after DFM loading.
+ FClearing: Boolean; // True if columns are being deleted entirely.
+
+ // drag support
+ FDragIndex: TColumnIndex; // index of column currently being dragged
+ FDropTarget: TColumnIndex; // current target column (index) while dragging
+ FDropBefore: Boolean; // True if drop position is in the left half of a column, False for the right
+ // side to drop the dragged column to
+ procedure DrawButtonText(DC: HDC; Caption: WideString; Bounds: TRect; Enabled, Hot: Boolean; DrawFormat: Cardinal);
+ function GetItem(Index: TColumnIndex): TVirtualTreeColumn;
+ function GetNewIndex(P: TPoint; var OldIndex: TColumnIndex): Boolean;
+ procedure SetItem(Index: TColumnIndex; Value: TVirtualTreeColumn);
+ protected
+ procedure AdjustAutoSize(CurrentIndex: TColumnIndex; Force: Boolean = False);
+ function AdjustDownColumn(P: TPoint): TColumnIndex;
+ function AdjustHoverColumn(P: TPoint): Boolean;
+ procedure AdjustPosition(Column: TVirtualTreeColumn; Position: Cardinal);
+ procedure FixPositions;
+ function GetColumnAndBounds(P: TPoint; var ColumnLeft, ColumnRight: Integer; Relative: Boolean = True): Integer;
+ function GetOwner: TPersistent; override;
+ procedure HandleClick(P: TPoint; Button: TMouseButton; Force, DblClick: Boolean);
+ procedure IndexChanged(OldIndex, NewIndex: Integer);
+ procedure InitializePositionArray;
+ procedure Update(Item: TCollectionItem); override;
+ procedure UpdatePositions(Force: Boolean = False);
+
+ property HeaderBitmap: TBitmap read FHeaderBitmap;
+ property PositionToIndex: TIndexArray read FPositionToIndex;
+ public
+ constructor Create(AOwner: TVTHeader);
+ destructor Destroy; override;
+
+ function Add: TVirtualTreeColumn; virtual;
+ procedure AnimatedResize(Column: TColumnIndex; NewWidth: Integer);
+ procedure Assign(Source: TPersistent); override;
+ procedure Clear; virtual;
+ function ColumnFromPosition(P: TPoint; Relative: Boolean = True): TColumnIndex; overload; virtual;
+ function ColumnFromPosition(PositionIndex: TColumnPosition): TColumnIndex; overload; virtual;
+ function Equals(OtherColumns: TVirtualTreeColumns): Boolean;
+ procedure GetColumnBounds(Column: TColumnIndex; var Left, Right: Integer);
+ function GetFirstVisibleColumn: TColumnIndex;
+ function GetLastVisibleColumn: TColumnIndex;
+ function GetNextColumn(Column: TColumnIndex): TColumnIndex;
+ function GetNextVisibleColumn(Column: TColumnIndex): TColumnIndex;
+ function GetPreviousColumn(Column: TColumnIndex): TColumnIndex;
+ function GetPreviousVisibleColumn(Column: TColumnIndex): TColumnIndex;
+ function GetVisibleColumns: TColumnsArray;
+ function IsValidColumn(Column: TColumnIndex): Boolean;
+ procedure LoadFromStream(const Stream: TStream; Version: Integer);
+ procedure PaintHeader(DC: HDC; R: TRect; HOffset: Integer; VOffset: Integer = 0); virtual;
+ procedure SaveToStream(const Stream: TStream);
+ function TotalWidth: Integer;
+
+ property ClickIndex: TColumnIndex read FClickIndex;
+ property Items[Index: TColumnIndex]: TVirtualTreeColumn read GetItem write SetItem; default;
+ property Header: TVTHeader read FHeader;
+ property TrackIndex: TColumnIndex read FTrackIndex;
+ end;
+
+ TVirtualTreeColumnsClass = class of TVirtualTreeColumns;
+
+ TVTHeaderStyle = (
+ hsThickButtons, // TButton look and feel
+ hsFlatButtons, // flatter look than hsThickButton, like an always raised flat TToolButton
+ hsPlates, // flat TToolButton look and feel (raise on hover etc.)
+ hsXPStyle // Windows XP style
+ );
+
+ TVTHeaderOption = (
+ hoAutoResize, // adjust a column so that the header never exceeds client width of owner control
+ hoColumnResize, // resizing columns is allowed
+ hoDblClickResize, // allows a column to resize itself to its largest entry
+ hoDrag, // dragging columns is allowed
+ hoHotTrack, // header captions are highlighted when mouse is over a particular column
+ hoOwnerDraw, // header items with the owner draw style can be drawn by the application via event
+ hoRestrictDrag, // header can only be dragged horizontally
+ hoShowHint, // show application defined header hint
+ hoShowImages, // show images
+ hoShowSortGlyphs, // allow visible sort glyphs
+ hoVisible // header is visible
+ );
+ TVTHeaderOptions = set of TVTHeaderOption;
+
+ THeaderState = (
+ hsAutoSizing, // auto size chain is in progess, do not trigger again on WM_SIZE
+ hsDragging, // header dragging is in progress (only if enabled)
+ hsDragPending, // left button is down, user might want to start dragging a column
+ hsLoading, // The header currently loads from stream, so updates are not necessary.
+ hsTracking, // column resizing is in progress
+ hsTrackPending // left button is down, user might want to start resize a column
+ );
+ THeaderStates = set of THeaderState;
+
+ TSortDirection = (
+ sdAscending,
+ sdDescending
+ );
+
+ // desribes what made a structure change event happen
+ TChangeReason = (
+ crIgnore, // used as placeholder
+ crAccumulated, // used for delayed changes
+ crChildAdded, // one or more child nodes have been added
+ crChildDeleted, // one or more child nodes have been deleted
+ crNodeAdded, // a node has been added
+ crNodeCopied, // a node has been duplicated
+ crNodeMoved // a node has been moved to a new place
+ );
+
+ TVTHeader = class(TPersistent)
+ private
+ FOwner: TBaseVirtualTree;
+ FColumns: TVirtualTreeColumns;
+ FHeight: Cardinal;
+ FFont: TFont;
+ FOptions: TVTHeaderOptions;
+ FStates: THeaderStates; // used to keep track of internal states the header can enter
+ FLeftTrackPos: Integer; // left border of this column to quickly calculate its width on resize
+ FStyle: TVTHeaderStyle; // button style
+ FBackground: TColor;
+ FAutoSizeIndex: TColumnIndex;
+ FPopupMenu: TPopupMenu;
+ FMainColumn: TColumnIndex; // the column which holds the tree
+ FImages: TImageList;
+ FImageChangeLink: TChangeLink; // connections to the image list to get notified about changes
+ FSortColumn: TColumnIndex;
+ FSortDirection: TSortDirection;
+ FTrackStart: TPoint; // client coordinates of the tracking start point
+ FDragStart: TPoint; // initial mouse drag position
+ FDragImage: TVTDragImage; // drag image management during header drag
+ procedure FontChanged(Sender: TObject);
+ function GetMainColumn: TColumnIndex;
+ function GetUseColumns: Boolean;
+ procedure SetAutoSizeIndex(Value: TColumnIndex);
+ procedure SetBackground(Value: TColor);
+ procedure SetColumns(Value: TVirtualTreeColumns);
+ procedure SetFont(const Value: TFont);
+ procedure SetHeight(Value: Cardinal);
+ procedure SetImages(const Value: TImageList);
+ procedure SetMainColumn(Value: TColumnIndex);
+ procedure SetOptions(Value: TVTHeaderOptions);
+ procedure SetSortColumn(Value: TColumnIndex);
+ procedure SetSortDirection(const Value: TSortDirection);
+ procedure SetStyle(Value: TVTHeaderStyle);
+ protected
+ function CanWriteColumns: Boolean; virtual;
+ procedure ChangeScale(M, D: Integer); virtual;
+ function DetermineSplitterIndex(P: TPoint): Boolean; virtual;
+ procedure DragTo(P: TPoint);
+ function GetColumnsClass: TVirtualTreeColumnsClass; virtual;
+ function GetOwner: TPersistent; override;
+ function GetShiftState: TShiftState;
+ function HandleHeaderMouseMove(var Message: TWMMouseMove): Boolean;
+ function HandleMessage(var Message: TMessage): Boolean; virtual;
+ procedure ImageListChange(Sender: TObject);
+ procedure PrepareDrag(P, Start: TPoint);
+ procedure ReadColumns(Reader: TReader);
+ procedure RecalculateHeader; virtual;
+ procedure UpdateMainColumn;
+ procedure WriteColumns(Writer: TWriter);
+ public
+ constructor Create(AOwner: TBaseVirtualTree); virtual;
+ destructor Destroy; override;
+
+ procedure Assign(Source: TPersistent); override;
+ procedure AutoFitColumns;
+ function InHeader(P: TPoint): Boolean; virtual;
+ procedure Invalidate(Column: TVirtualTreeColumn; ExpandToRight: Boolean = False);
+ procedure LoadFromStream(const Stream: TStream); virtual;
+ procedure RestoreColumns;
+ procedure SaveToStream(const Stream: TStream); virtual;
+
+ property DragImage: TVTDragImage read FDragImage;
+ property States: THeaderStates read FStates;
+ property Treeview: TBaseVirtualTree read FOwner;
+ property UseColumns: Boolean read GetUseColumns;
+ published
+ property AutoSizeIndex: TColumnIndex read FAutoSizeIndex write SetAutoSizeIndex;
+ property Background: TColor read FBackground write SetBackground default clBtnFace;
+ property Columns: TVirtualTreeColumns read FColumns write SetColumns stored False; // Stored by the owner tree to
+ // support VFI.
+ property Font: TFont read FFont write SetFont;
+ property Height: Cardinal read FHeight write SetHeight default 17;
+ property Images: TImageList read FImages write SetImages;
+ property MainColumn: TColumnIndex read GetMainColumn write SetMainColumn default 0;
+ property Options: TVTHeaderOptions read FOptions write SetOptions default [hoColumnResize, hoDrag, hoShowSortGlyphs];
+ property PopupMenu: TPopupMenu read FPopupMenu write FPopUpMenu;
+ property SortColumn: TColumnIndex read FSortColumn write SetSortColumn default NoColumn;
+ property SortDirection: TSortDirection read FSortDirection write SetSortDirection default sdAscending;
+ property Style: TVTHeaderStyle read FStyle write SetStyle default hsThickButtons;
+ end;
+
+ TVTHeaderClass = class of TVTHeader;
+
+ // Communication interface between a tree editor and the tree itself (declared as using stdcall in case it
+ // is implemented in a (C/C++) DLL). The GUID is not nessecary in Delphi but important for BCB users
+ // to allow QueryInterface and _uuidof calls.
+ IVTEditLink = interface
+ ['{2BE3EAFA-5ACB-45B4-9D9A-B58BCC496E17}']
+ function BeginEdit: Boolean; stdcall; // called when editing actually starts
+ function CancelEdit: Boolean; stdcall; // called when editing has been cancelled by the tree
+ function EndEdit: Boolean; stdcall; // called when editing has been finished by the tree
+ function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
+ // called after creation to allow a setup
+ function GetBounds: TRect; stdcall; // called to get the current size of the edit window
+ // (only important if the edit resizes itself)
+ procedure ProcessMessage(var Message: TMessage); stdcall;
+ // used to forward messages to the edit window(s)
+ procedure SetBounds(R: TRect); stdcall; // called to place the editor
+ end;
+
+ // Indicates in the OnUpdating event what state the tree is currently in.
+ TVTUpdateState = (
+ usBegin, // The tree just entered the update state (BeginUpdate call for the first time).
+ usBeginSynch, // The tree just entered the synch update state (BeginSynch call for the first time).
+ usSynch, // Begin/EndSynch has been called but the tree did not change the update state.
+ usUpdate, // Begin/EndUpdate has been called but the tree did not change the update state.
+ usEnd, // The tree just left the update state (EndUpdate called for the last level).
+ usEndSynch // The tree just left the synch update state (EndSynch called for the last level).
+ );
+
+ // Used during owner draw of the header to indicate which drop mark for the column must be drawn.
+ TVTDropMarkMode = (
+ dmmNone,
+ dmmLeft,
+ dmmRight
+ );
+
+ // This structure carries all important information about header painting and is used in the advanced header painting.
+ THeaderPaintInfo = record
+ TargetCanvas: TCanvas;
+ Column: TVirtualTreeColumn;
+ PaintRectangle: TRect;
+ TextRectangle: TRect;
+ IsHoverIndex,
+ IsDownIndex,
+ IsEnabled,
+ ShowHeaderGlyph,
+ ShowSortGlyph,
+ ShowRightBorder: Boolean;
+ DropMark: TVTDropMarkMode;
+ GlyphPos,
+ SortGlyphPos: TPoint;
+ end;
+
+ // These elements are used both to query the application, which of them it wants to draw itself and to tell it during
+ // painting, which elements must be drawn during the advanced custom draw events.
+ THeaderPaintElements = set of (
+ hpeBackground,
+ hpeDropMark,
+ hpeHeaderGlyph,
+ hpeSortGlyph,
+ hpeText
+ );
+
+ // Various events must be handled at different places than they were initiated or need
+ // a persistent storage until they are reset.
+ TVirtualTreeStates = set of (
+ tsChangePending, // A selection change is pending.
+ tsCollapsing, // A full collapse operation is in progress.
+ tsClearFocusedSelection, // Node selection was modifed using Ctrl-click. Change selection state on next mouse up.
+ tsClearPending, // Need to clear the current selection on next mouse move.
+ tsClipboardFlushing, // Set during flushing the clipboard to avoid freeing the content.
+ tsCopyPending, // Indicates a pending copy operation which needs to be finished.
+ tsCutPending, // Indicates a pending cut operation which needs to be finished.
+ tsDrawSelPending, // Multiselection only. User held down the left mouse button on a free
+ // area and might want to start draw selection.
+ tsDrawSelecting, // Multiselection only. Draw selection has actually started.
+ tsEditing, // Indicates that an edit operation is currently in progress.
+ tsEditPending, // An mouse up start edit if dragging has not started.
+ tsExpanding, // A full expand operation is in progress.
+ tsHint, // Set when our hint is visible or soon will be.
+ tsInAnimation, // Set if the tree is currently in an animation loop.
+ tsIncrementalSearching, // Set when the user starts incremental search.
+ tsIncrementalSearchPending, // Set in WM_KEYDOWN to tell to use the char in WM_CHAR for incremental search.
+ tsIterating, // Set when IterateSubtree is currently in progress.
+ tsKeyCheckPending, // A check operation is under way, initiated by a key press (space key). Ignore mouse.
+ tsLeftButtonDown, // Set when the left mouse button is down.
+ tsMouseCheckPending, // A check operation is under way, initiated by a mouse click. Ignore space key.
+ tsMiddleButtonDown, // Set when the middle mouse button is down.
+ tsNeedScale, // On next ChangeScale scale the default node height.
+ tsNeedRootCountUpdate, // Set if while loading a root node count is set.
+ tsOLEDragging, // OLE dragging in progress.
+ tsOLEDragPending, // User has requested to start delayed dragging.
+ tsPainting, // The tree is currently painting itself.
+ tsRightButtonDown, // Set when the right mouse button is down.
+ tsScrolling, // Set when autoscrolling is active.
+ tsScrollPending, // Set when waiting for the scroll delay time to elapse.
+ tsSizing, // Set when the tree window is being resized. This is used to prevent recursive calls
+ // due to setting the scrollbars when sizing.
+ tsStopValidation, // Cache validation can be stopped (usually because a change has occured meanwhile).
+ tsStructureChangePending, // The structure of the tree has been changed while the update was locked.
+ tsSynchMode, // Set when the tree is in synch mode, where no timer events are triggered.
+ tsThumbTracking, // Stop updating the horizontal scroll bar while dragging the vertical thumb and vice versa.
+ tsUpdateHiddenChildrenNeeded, // Pending update for the hidden children flag after massive visibility changes.
+ tsUpdating, // The tree does currently not update its window because a BeginUpdate has not yet ended.
+ tsUseCache, // The tree's node caches are validated and non-empty.
+ tsUserDragObject, // Signals that the application created an own drag object in OnStartDrag.
+ tsUseThemes, // The tree runs under WinXP+, is theme aware and themes are enabled.
+ tsValidating, // The tree's node caches are currently validated.
+ tsValidationNeeded, // Something in the structure of the tree has changed. The cache needs validation.
+ tsVCLDragging, // VCL drag'n drop in progress.
+ tsVCLDragPending, // One-shot flag to avoid clearing the current selection on implicit mouse up for VCL drag.
+ tsWheelPanning, // Wheel mouse panning is active or soon will be.
+ tsWheelScrolling, // Wheel mouse scrolling is active or soon will be.
+ tsWindowCreating // set during window handle creation to avoid frequent unnecessary updates
+ );
+
+ TChangeStates = set of (
+ csStopValidation, // Cache validation can be stopped (usually because a change has occured meanwhile).
+ csUseCache, // The tree's node caches are validated and non-empty.
+ csValidating, // The tree's node caches are currently validated.
+ csValidationNeeded // Something in the structure of the tree has changed. The cache needs validation.
+ );
+
+ // determines whether and how the drag image is to show
+ TVTDragImageKind = (
+ diComplete, // show a complete drag image with all columns, only visible columns are shown
+ diMainColumnOnly, // show only the main column (the tree column)
+ diNoImage // don't show a drag image at all
+ );
+
+ // Switch for OLE and VCL drag'n drop. Because it is not possible to have both simultanously.
+ TVTDragType = (
+ dtOLE,
+ dtVCL
+ );
+
+ // options which determine what to draw in PaintTree
+ TVTInternalPaintOption = (
+ poBackground, // draw background image if there is any and it is enabled
+ poColumnColor, // erase node's background with the column's color
+ poDrawFocusRect, // draw focus rectangle around the focused node
+ poDrawSelection, // draw selected nodes with the normal selection color
+ poDrawDropMark, // draw drop mark if a node is currently the drop target
+ poGridLines, // draw grid lines if enabled
+ poMainOnly, // draw only the main column
+ poSelectedOnly // draw only selected nodes
+ );
+ TVTInternalPaintOptions = set of TVTInternalPaintOption;
+
+ // Determines the look of a tree's lines.
+ TVTLineStyle = (
+ lsCustomStyle, // application provides a line pattern
+ lsDotted, // usual dotted lines (default)
+ lsSolid // simple solid lines
+ );
+
+ // TVTLineType is used during painting a tree
+ TVTLineType = (
+ ltNone, // no line at all
+ ltBottomRight, // a line from bottom to the center and from there to the right
+ ltTopDown, // a line from top to bottom
+ ltTopDownRight, // a line from top to bottom and from center to the right
+ ltRight, // a line from center to the right
+ ltTopRight, // a line from bottom to center and from there to the right
+ // special styles for alternative drawings of tree lines
+ ltLeft, // a line from top to bottom at the left
+ ltLeftBottom // a combination of ltLeft and a line at the bottom from left to right
+ );
+
+ // Determines how to draw tree lines.
+ TVTLineMode = (
+ lmNormal, // usual tree lines (as in TTreeview)
+ lmBands // looks similar to a Nassi-Schneidermann diagram
+ );
+
+ // A collection of line type IDs which is used while painting a node.
+ TLineImage = array of TVTLineType;
+
+ TVTScrollIncrement = 1..10000;
+
+ // A class to manage scroll bar aspects.
+ TScrollBarOptions = class(TPersistent)
+ private
+ FAlwaysVisible: Boolean;
+ FOwner: TBaseVirtualTree;
+ FScrollBars: TScrollStyle; // used to hide or show vertical and/or horizontal scrollbar
+ FScrollBarStyle: TScrollBarStyle; // kind of scrollbars to use
+ FIncrementX,
+ FIncrementY: TVTScrollIncrement; // number of pixels to scroll in one step (when auto scrolling)
+ procedure SetAlwaysVisible(Value: Boolean);
+ procedure SetScrollBars(Value: TScrollStyle);
+ procedure SetScrollBarStyle(Value: TScrollBarStyle);
+ protected
+ function GetOwner: TPersistent; override;
+ public
+ constructor Create(AOwner: TBaseVirtualTree);
+
+ procedure Assign(Source: TPersistent); override;
+ published
+ property AlwaysVisible: Boolean read FAlwaysVisible write SetAlwaysVisible default False;
+ property HorizontalIncrement: TVTScrollIncrement read FIncrementX write FIncrementX default 20;
+ property ScrollBars: TScrollStyle read FScrollbars write SetScrollBars default ssBoth;
+ property ScrollBarStyle: TScrollBarStyle read FScrollBarStyle write SetScrollBarStyle default sbmRegular;
+ property VerticalIncrement: TVTScrollIncrement read FIncrementY write FIncrementY default 20;
+ end;
+
+ // class to collect all switchable colors into one place
+ TVTColors = class(TPersistent)
+ private
+ FOwner: TBaseVirtualTree;
+ FColors: array[0..13] of TColor;
+ function GetColor(const Index: Integer): TColor;
+ procedure SetColor(const Index: Integer; const Value: TColor);
+ public
+ constructor Create(AOwner: TBaseVirtualTree);
+
+ procedure Assign(Source: TPersistent); override;
+ published
+ property BorderColor: TColor index 7 read GetColor write SetColor default clBtnFace;
+ property DisabledColor: TColor index 0 read GetColor write SetColor default clBtnShadow;
+ property DropMarkColor: TColor index 1 read GetColor write SetColor default clHighlight;
+ property DropTargetColor: TColor index 2 read GetColor write SetColor default clHighLight;
+ property DropTargetBorderColor: TColor index 11 read GetColor write SetColor default clHighLight;
+ property FocusedSelectionColor: TColor index 3 read GetColor write SetColor default clHighLight;
+ property FocusedSelectionBorderColor: TColor index 9 read GetColor write SetColor default clHighLight;
+ property GridLineColor: TColor index 4 read GetColor write SetColor default clBtnFace;
+ property HotColor: TColor index 8 read GetColor write SetColor default clWindowText;
+ property SelectionRectangleBlendColor: TColor index 12 read GetColor write SetColor default clHighlight;
+ property SelectionRectangleBorderColor: TColor index 13 read GetColor write SetColor default clHighlight;
+ property TreeLineColor: TColor index 5 read GetColor write SetColor default clBtnShadow;
+ property UnfocusedSelectionColor: TColor index 6 read GetColor write SetColor default clBtnFace;
+ property UnfocusedSelectionBorderColor: TColor index 10 read GetColor write SetColor default clBtnFace;
+ end;
+
+ // For painting a node and its columns/cells a lot of information must be passed frequently to
+ // the paint methode.
+ TVTImageInfo = record
+ Index: Integer; // index in the associated image list
+ XPos, // horizontal position in the current target canvas
+ YPos: Integer; // vertical position in the current target canvas
+ Ghosted: Boolean; // flag to indicate that the image must be drawn slightly lighter
+ end;
+
+ TVTImageInfoIndex = (
+ iiNormal,
+ iiState,
+ iiCheck
+ );
+
+ // Options which are used when modifying the scroll offsets.
+ TScrollUpdateOptions = set of (
+ suoRepaintHeader, // if suoUpdateNCArea is also set then invalidate the header
+ suoRepaintScrollbars, // if suoUpdateNCArea is also set then repaint both scrollbars after updating them
+ suoScrollClientArea, // scroll and invalidate the proper part of the client area
+ suoUpdateNCArea // update non-client area (scrollbars, header)
+ );
+
+ // Determines the look of a tree's buttons.
+ TVTButtonStyle = (
+ bsRectangle, // traditional Windows look (plus/minus buttons)
+ bsTriangle // traditional Macintosh look
+ );
+
+ // TButtonFillMode is only used when the button style is bsRectangle and determines how to fill the interior.
+ TVTButtonFillMode = (
+ fmTreeColor, // solid color, uses the tree's background color
+ fmWindowColor, // solid color, uses clWindow
+ fmShaded, // color gradient, Windows XP style (legacy code, use toThemeAware on Windows XP instead)
+ fmTransparent // transparent color, use the item's background color
+ );
+
+ TVTPaintInfo = record
+ Canvas: TCanvas; // the canvas to paint on
+ PaintOptions: TVTInternalPaintOptions; // a copy of the paint options passed to PaintTree
+ Node: PVirtualNode; // the node to paint
+ Column: TColumnIndex; // the node's column index to paint
+ Position: TColumnPosition; // the column position of the node
+ CellRect, // the node cell
+ ContentRect: TRect; // the area of the cell used for the node's content
+ NodeWidth: Integer; // the actual node width
+ Alignment: TAlignment; // how to align within the node rectangle
+ BidiMode: TBidiMode; // directionality to be used for painting
+ BrushOrigin: TPoint; // the alignment for the brush used to draw dotted lines
+ ImageInfo: array[TVTImageInfoIndex] of TVTImageInfo; // info about each possible node image
+ end;
+
+ // Method called by the Animate routine for each animation step.
+ TVTAnimationCallback = function(Step, StepSize: Integer; Data: Pointer): Boolean of object;
+
+ TVTIncrementalSearch = (
+ isAll, // search every node in tree, initialize if necessary
+ isNone, // disable incremental search
+ isInitializedOnly, // search only initialized nodes, skip others
+ isVisibleOnly // search only visible nodes, initialize if necessary
+ );
+
+ // Determines which direction to use when advancing nodes during an incremental search.
+ TVTSearchDirection = (
+ sdForward,
+ sdBackward
+ );
+
+ // Determines where to start incremental searching for each key press.
+ TVTSearchStart = (
+ ssAlwaysStartOver, // always use the first/last node (depending on direction) to search from
+ ssLastHit, // use the last found node
+ ssFocusedNode // use the currently focused node
+ );
+
+ // Determines how to use the align member of a node.
+ TVTNodeAlignment = (
+ naFromBottom, // the align member specifies amount of units (usually pixels) from top border of the node
+ naFromTop, // align is to be measured from bottom
+ naProportional // align is to be measure in percent of the entire node height and relative to top
+ );
+
+ // Determines how to draw the selection rectangle used for draw selection.
+ TVTDrawSelectionMode = (
+ smDottedRectangle, // same as DrawFocusRect
+ smBlendedRectangle // alpha blending, uses special colors (see TVTColors)
+ );
+
+ TClipboardFormats = class(TStringList)
+ private
+ FOwner: TBaseVirtualTree;
+ public
+ constructor Create(AOwner: TBaseVirtualTree); virtual;
+
+ function Add(const S: string): Integer; override;
+ procedure Insert(Index: Integer; const S: string); override;
+ property Owner: TBaseVirtualTree read FOwner;
+ end;
+
+ // ----- Event prototypes:
+
+ // node enumeration
+ TVTGetNodeProc = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean) of object;
+
+ // node events
+ TVTChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var Allowed: Boolean) of object;
+ TVTCheckChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var NewState: TCheckState;
+ var Allowed: Boolean) of object;
+ TVTChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object;
+ TVTStructureChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Reason: TChangeReason) of object;
+ TVTEditCancelEvent = procedure(Sender: TBaseVirtualTree; Column: TColumnIndex) of object;
+ TVTEditChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var Allowed: Boolean) of object;
+ TVTEditChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object;
+ TVTFreeNodeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object;
+ TVTFocusChangingEvent = procedure(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn,
+ NewColumn: TColumnIndex; var Allowed: Boolean) of object;
+ TVTFocusChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object;
+ TVTGetImageEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var ImageIndex: Integer) of object;
+ TVTHotNodeChangeEvent = procedure(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode) of object;
+ TVTInitChildrenEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal) of object;
+ TVTInitNodeEvent = procedure(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates) of object;
+ TVTPopupEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; const P: TPoint;
+ var AskParent: Boolean; var PopupMenu: TPopupMenu) of object;
+ TVTHelpContextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var HelpContext: Integer) of object;
+ TVTCreateEditorEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ out EditLink: IVTEditLink) of object;
+ TVTSaveNodeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Stream: TStream) of object;
+
+ // header/column events
+ TVTHeaderClickEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer) of object;
+ TVTHeaderMouseEvent = procedure(Sender: TVTHeader; Button: TMouseButton; Shift: TShiftState; X, Y: Integer) of object;
+ TVTHeaderMouseMoveEvent = procedure(Sender: TVTHeader; Shift: TShiftState; X, Y: Integer) of object;
+ TVTHeaderNotifyEvent = procedure(Sender: TVTHeader; Column: TColumnIndex) of object;
+ TVTHeaderDraggingEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; var Allowed: Boolean) of object;
+ TVTHeaderDraggedEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; OldPosition: Integer) of object;
+ TVTHeaderDraggedOutEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; DropPosition: TPoint) of object;
+ TVTHeaderPaintEvent = procedure(Sender: TVTHeader; HeaderCanvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover,
+ Pressed: Boolean; DropMark: TVTDropMarkMode) of object;
+ TVTHeaderPaintQueryElementsEvent = procedure(Sender: TVTHeader; var PaintInfo: THeaderPaintInfo;
+ var Elements: THeaderPaintElements) of object;
+ TVTAdvancedHeaderPaintEvent = procedure(Sender: TVTHeader; var PaintInfo: THeaderPaintInfo;
+ const Elements: THeaderPaintElements) of object;
+ TVTColumnClickEvent = procedure (Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState) of object;
+ TVTColumnDblClickEvent = procedure (Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState) of object;
+ TVTGetHeaderCursorEvent = procedure(Sender: TVTHeader; var Cursor: HCURSOR) of object;
+
+ // move and copy events
+ TVTNodeMovedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object;
+ TVTNodeMovingEvent = procedure(Sender: TBaseVirtualTree; Node, Target: PVirtualNode;
+ var Allowed: Boolean) of object;
+ TVTNodeCopiedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object;
+ TVTNodeCopyingEvent = procedure(Sender: TBaseVirtualTree; Node, Target: PVirtualNode;
+ var Allowed: Boolean) of object;
+
+ // drag'n drop/OLE events
+ TVTCreateDragManagerEvent = procedure(Sender: TBaseVirtualTree; out DragManager: IVTDragManager) of object;
+ TVTCreateDataObjectEvent = procedure(Sender: TBaseVirtualTree; out IDataObject: IDataObject) of object;
+ TVTDragAllowedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var Allowed: Boolean) of object;
+ TVTDragOverEvent = procedure(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState;
+ Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean) of object;
+ TVTDragDropEvent = procedure(Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject;
+ Formats: TFormatArray; Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode) of object;
+ TVTRenderOLEDataEvent = procedure(Sender: TBaseVirtualTree; const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean; var Result: HRESULT) of object;
+ TVTGetUserClipboardFormatsEvent = procedure(Sender: TBaseVirtualTree; var Formats: TFormatEtcArray) of object;
+
+ // paint events
+ TVTBeforeItemEraseEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
+ var ItemColor: TColor; var EraseAction: TItemEraseAction) of object;
+ TVTAfterItemEraseEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ ItemRect: TRect) of object;
+ TVTBeforeItemPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ ItemRect: TRect; var CustomDraw: Boolean) of object;
+ TVTAfterItemPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ ItemRect: TRect) of object;
+ TVTBeforeCellPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; CellRect: TRect) of object;
+ TVTAfterCellPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; CellRect: TRect) of object;
+ TVTPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas) of object;
+ TVTBackgroundPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; R: TRect;
+ var Handled: Boolean) of object;
+ TVTGetLineStyleEvent = procedure(Sender: TBaseVirtualTree; var Bits: Pointer) of object;
+
+ // search, sort
+ TVTCompareEvent = procedure(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex;
+ var Result: Integer) of object;
+ TVTIncrementalSearchEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; const SearchText: WideString;
+ var Result: Integer) of object;
+
+ // miscellaneous
+ TVTGetNodeDataSizeEvent = procedure(Sender: TBaseVirtualTree; var NodeDataSize: Integer) of object;
+ TVTKeyActionEvent = procedure(Sender: TBaseVirtualTree; var CharCode: Word; var Shift: TShiftState;
+ var DoDefault: Boolean) of object;
+ TVTScrollEvent = procedure(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer) of object;
+ TVTUpdatingEvent = procedure(Sender: TBaseVirtualTree; State: TVTUpdateState) of object;
+ TVTGetCursorEvent = procedure(Sender: TBaseVirtualTree; var Cursor: TCursor) of object;
+ TVTStateChangeEvent = procedure(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates) of object;
+
+ // Helper types for node iterations.
+ TGetFirstNodeProc = function: PVirtualNode of object;
+ TGetNextNodeProc = function(Node: PVirtualNode): PVirtualNode of object;
+
+ // ----- TBaseVirtualTree
+ TBaseVirtualTree = class(TCustomControl)
+ private
+ FBorderStyle: TBorderStyle;
+ FHeader: TVTHeader;
+ FRoot: PVirtualNode;
+ FDefaultNodeHeight,
+ FIndent: Cardinal;
+ FOptions: TCustomVirtualTreeOptions;
+ FUpdateCount: Cardinal; // update stopper, updates of the tree control are only done if = 0
+ FSynchUpdateCount: Cardinal; // synchronizer, causes all events which are usually done via timers
+ // to happen immediately, regardless of the normal update state
+ FNodeDataSize: Integer; // number of bytes to allocate with each node (in addition to its base
+ // structure and the internal data), if -1 then do callback
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager: TVTNodeMemoryManager; // High-performance local memory manager.
+ {$endif UseLocalMemoryManager}
+ FStates: TVirtualTreeStates; // various active/pending states the tree needs to consider
+ FLastSelected,
+ FFocusedNode: PVirtualNode;
+ FEditColumn, // column to be edited (focused node)
+ FFocusedColumn: TColumnIndex; // NoColumn if no columns are active otherwise the last hit column of
+ // the currently focused node
+ FScrollDirections: TScrollDirections; // directions to scroll client area into depending on mouse position
+ FLastStructureChangeReason: TChangeReason; // used for delayed structur change event
+ FLastStructureChangeNode, // dito
+ FLastChangedNode, // used for delayed change event
+ FCurrentHotNode: PVirtualNode; // Node over which the mouse is hovering.
+ FLastSelRect,
+ FNewSelRect: TRect; // used while doing draw selection
+ FHotCursor: TCursor; // can be set to additionally indicate the current hot node
+ FAnimationType: THintAnimationType; // none, fade in, slide in animation (just like those animations used
+ // in Win98 (slide) and Windows 2000 (fade))
+ FHintMode: TVTHintMode; // determines the kind of the hint window
+ FHintData: TVTHintData; // used while preparing the hint window
+ FChangeDelay: Cardinal; // used to delay OnChange event
+ FEditDelay: Cardinal; // determines time to elapse before a node goes into edit mode
+ FPositionCache: TCache; // array which stores node references ordered by vertical positions
+ // (see also DoValidateCache for more information)
+ FVisibleCount: Cardinal; // number of currently visible nodes
+ FStartIndex: Cardinal; // index to start validating cache from
+ FSelection: TNodeArray; // list of currently selected nodes
+ FSelectionCount: Integer; // number of currently selected nodes (size of FSelection might differ)
+ FRangeAnchor: PVirtualNode; // anchor node for selection with the keyboard, determines start of a
+ // selection range
+ FCheckNode: PVirtualNode; // node which "captures" an check event
+ FPendingCheckState: TCheckState; // the new state the check node will get if all wents fine
+ FLastSelectionLevel: Integer; // keeps the last node level for constrained multiselection
+ FDrawSelShiftState: TShiftState; // keeps the initial shift state when the user starts selection with
+ // the mouse
+ FEditLink: IVTEditLink; // used to comunicate with an application defined editor
+ FTempNodeCache: TNodeArray; // used at various places to hold temporarily a bunch of node refs.
+ FTempNodeCount: Cardinal; // number of nodes in FTempNodeCache
+ FBackground: TPicture; // a background image loadable at design time
+ FMargin: Integer; // horizontal border distance
+ FTextMargin: Integer; // space between the node's text and its horizontal bounds
+ FBackgroundOffsetX,
+ FBackgroundOffsetY: Integer; // used to fine tune the position of the background image
+ FAnimationDuration: Cardinal; // specifies how long an animation shall take (expanding, hint)
+ FWantTabs: Boolean; // If True then the tree also consumes the tab key.
+ FNodeAlignment: TVTNodeAlignment; // determines how to interpret the align member of a node
+ FHeaderRect: TRect; // Space which the header currently uses in the control (window coords).
+ FLastHintRect: TRect; // Area which the must must leave to reshow a hint.
+ FUpdateRect: TRect;
+ FChangeLock: TCriticalSection; // To sync the change events from both VT and the worker thread.
+
+ // paint support and images
+ FPlusBM,
+ FMinusBM: TBitmap; // small bitmaps used for tree buttons
+ FImages, // normal images in the tree
+ FStateImages, // state images in the tree
+ FCustomCheckImages: TCustomImageList; // application defined check images
+ FCheckImageKind: TCheckImageKind; // light or dark, cross marks or tick marks
+ FCheckImages: TCustomImageList; // Reference to global image list to be used for the check images.
+ FImageChangeLink,
+ FStateChangeLink,
+ FCustomCheckChangeLink: TChangeLink; // connections to the image lists
+ FOldFontChange: TNotifyEvent; // helper method pointer for tracking font changes in the off screen buffer
+ FFontChanged: Boolean; // flag for keeping informed about font changes in the off screen buffer
+ FColors: TVTColors; // class comprising all customizable colors in the tree
+ FButtonStyle: TVTButtonStyle; // style of the tree buttons
+ FButtonFillMode: TVTButtonFillMode; // for rectangular tree buttons only: how to fill them
+ FLineStyle: TVTLineStyle; // style of the tree lines
+ FLineMode: TVTLineMode; // tree lines or bands etc.
+ FDottedBrush: HBRUSH; // used to paint dotted lines without special pens
+ FSelectionCurveRadius: Cardinal; // radius for rounded selection rectangles
+ FSelectionBlendFactor: Byte; // Determines the factor by which the selection rectangle is to be
+ // faded if enabled.
+ FDrawSelectionMode: TVTDrawSelectionMode; // determines the paint mode for draw selection
+
+ // alignment and directionality support
+ FAlignment: TAlignment; // default alignment of the tree if no columns are shown
+
+ // drag'n drop and clipboard support
+ FDragImageKind: TVTDragImageKind; // determines whether or not and what to show in the drag image
+ FDragOperations: TDragOperations; // determines which operations are allowed during drag'n drop
+ FDragThreshold: Integer; // used to determine when to actually start a drag'n drop operation
+ FDragManager: IVTDragManager; // drag'n drop, cut'n paste
+ FDropTargetNode: PVirtualNode; // node currently selected as drop target
+ FLastDropMode: TDropMode; // set while dragging and used to track changes
+ FDragSelection: TNodeArray; // temporary copy of FSelection used during drag'n drop
+ FDragType: TVTDragType; // used to switch between OLE and VCL drag'n drop
+ FDragImage: TVTDragImage; // drag image management
+ FDragWidth,
+ FDragHeight: Integer; // size of the drag image, the larger the more CPU power is needed
+ FClipboardFormats: TClipboardFormats; // a list of clipboard format descriptions enabled for this tree
+ FLastVCLDragTarget: PVirtualNode; // A node cache for VCL drag'n drop (keywords: DragLeave on DragDrop).
+ FVCLDragEffect: Integer; // A cache for VCL drag'n drop to keep the current drop effect.
+
+ // scroll support
+ FScrollBarOptions: TScrollBarOptions; // common properties of horizontal and vertical scrollbar
+ FAutoScrollInterval: TAutoScrollInterval; // determines speed of auto scrolling
+ FAutoScrollDelay: Cardinal; // amount of milliseconds to wait until autoscrolling becomes active
+ FAutoExpandDelay: Cardinal; // amount of milliseconds to wait until a node is expanded if it is the
+ // drop target
+ FOffsetX,
+ FOffsetY: Integer; // determines left and top scroll offset
+ FRangeX,
+ FRangeY: Cardinal; // current virtual width and height of the tree
+
+ FDefaultPasteMode: TVTNodeAttachMode; // Used to determine where to add pasted nodes to.
+ FSingletonNodeArray: TNodeArray; // Contains only one element for quick addition of single nodes
+ // to the selection.
+ FDragScrollStart: Cardinal; // Contains the start time when a tree does auto scrolling as drop target.
+
+ // search
+ FIncrementalSearch: TVTIncrementalSearch; // Used to determine whether and how incremental search is to be used.
+ FSearchTimeout: Cardinal; // Number of milliseconds after which to stop incremental searching.
+ FSearchBuffer: WideString; // Collects a sequence of keypresses used to do incremental searching.
+ FLastSearchNode: PVirtualNode; // Reference to node which was last found as search fit.
+ FSearchDirection: TVTSearchDirection; // Direction to incrementally search the tree.
+ FSearchStart: TVTSearchStart; // Where to start iteration on each key press.
+
+ // miscellanous
+ FTotalInternalDataSize: Cardinal; // Cache of the sum of the necessary internal data size for all tree
+ // classes derived from this base class.
+ FPanningWindow: HWND; // Helper window for wheel panning
+ FPanningCursor: HCURSOR; // Current wheel panning cursor.
+ FPanningImage: TBitmap; // A little 32x32 bitmap to indicate the panning reference point.
+ FLastClickPos: TPoint; // Used for retained drag start and wheel mouse scrolling.
+
+ // common events
+ FOnChange: TVTChangeEvent; // selection change
+ FOnStructureChange: TVTStructureChangeEvent; // structural change like adding nodes etc.
+ FOnInitChildren: TVTInitChildrenEvent; // called when a node's children are needed (expanding etc.)
+ FOnInitNode: TVTInitNodeEvent; // called when a node needs to be initialized (child count etc.)
+ FOnFreeNode: TVTFreeNodeEvent; // called when a node is about to be destroyed, user data can and should
+ // be freed in this event
+ FOnGetImage: TVTGetImageEvent; // used to retrieve the image index of a given node
+ FOnHotChange: TVTHotNodeChangeEvent; // called when the current "hot" node (that is, the node under the mouse)
+ // changes and hot tracking is enabled
+ FOnExpanding, // called just before a node is expanded
+ FOnCollapsing: TVTChangingEvent; // called just before a node is collapsed
+ FOnChecking: TVTCheckChangingEvent; // called just before a node's check state is changed
+ FOnExpanded, // called after a node has been expanded
+ FOnCollapsed, // called after a node has been collapsed
+ FOnChecked: TVTChangeEvent; // called after a node's check state has been changed
+ FOnResetNode: TVTChangeEvent; // called when a node is set to be uninitialized
+ FOnNodeMoving: TVTNodeMovingEvent; // called just before a node is moved from one parent node to another
+ // (this can be cancelled)
+ FOnNodeMoved: TVTNodeMovedEvent; // called after a node and its children have been moved to another
+ // parent node (probably another tree, but within the same application)
+ FOnNodeCopying: TVTNodeCopyingEvent; // called when an node is copied to another parent node (probably in
+ // another tree, but within the same application, can be cancelled)
+ FOnNodeCopied: TVTNodeCopiedEvent; // call after a node has been copied
+ FOnEditing: TVTEditChangingEvent; // called just before a node goes into edit mode
+ FOnEditCancelled: TVTEditCancelEvent; // called when editing has been cancelled
+ FOnEdited: TVTEditChangeEvent; // called when editing has successfully been finished
+ FOnFocusChanging: TVTFocusChangingEvent; // called when the focus is about to go to a new node and/or column
+ // (can be cancelled)
+ FOnFocusChanged: TVTFocusChangeEvent; // called when the focus goes to a new node and/or column
+ FOnGetPopupMenu: TVTPopupEvent; // called when the popup for a node needs to be shown
+ FOnGetHelpContext: TVTHelpContextEvent; // called when a node specific help theme should be called
+ FOnCreateEditor: TVTCreateEditorEvent; // called when a node goes into edit mode, this allows applications
+ // to supply their own editor
+ FOnLoadNode, // called after a node has been loaded from a stream (file, clipboard,
+ // OLE drag'n drop) to allow an application to load their own data
+ // saved in OnSaveNode
+ FOnSaveNode: TVTSaveNodeEvent; // called when a node needs to be serialized into a stream
+ // (see OnLoadNode) to give the application the opportunity to save
+ // their node specific, persistent data (note: never save memory
+ // references)
+
+ // header/column mouse events
+ FOnHeaderClick, // mouse events for the header, just like those for a control
+ FOnHeaderDblClick: TVTHeaderClickEvent;
+ FOnHeaderMouseDown,
+ FOnHeaderMouseUp: TVTHeaderMouseEvent;
+ FOnHeaderMouseMove: TVTHeaderMouseMoveEvent;
+ FOnColumnClick: TVTColumnClickEvent;
+ FOnColumnDblClick: TVTColumnDblClickEvent;
+ FOnColumnResize: TVTHeaderNotifyEvent;
+ FOnGetHeaderCursor: TVTGetHeaderCursorEvent; // triggered to allow the app. to use customized cursors for the header
+
+ // paint events
+ FOnAfterPaint, // triggered when the tree has entirely been painted
+ FOnBeforePaint: TVTPaintEvent; // triggered when the tree is about to be painted
+ FOnAfterItemPaint: TVTAfterItemPaintEvent; // triggered after an item has been painted
+ FOnBeforeItemPaint: TVTBeforeItemPaintEvent; // triggered when an item is about to be painted
+ FOnBeforeItemErase: TVTBeforeItemEraseEvent; // triggered when an item's background is about to be erased
+ FOnAfterItemErase: TVTAfterItemEraseEvent; // triggered after an item's background has been erased
+ FOnAfterCellPaint: TVTAfterCellPaintEvent; // triggered after a column of an item has been painted
+ FOnBeforeCellPaint: TVTBeforeCellPaintEvent; // triggered when a column of an item is about to be painted
+ FOnHeaderDraw: TVTHeaderPaintEvent; // Used when owner draw is enabled for the header and a column is set
+ // to owner draw mode.
+ FOnHeaderDrawQueryElements: TVTHeaderPaintQueryElementsEvent; // Used for advanced header painting to query the
+ // application for the elements, which are drawn by it and which should
+ // be drawn by the tree.
+ FOnAdvancedHeaderDraw: TVTAdvancedHeaderPaintEvent; // Used when owner draw is enabled for the header and a column
+ // is set to owner draw mode. But only if OnHeaderDrawQueryElements
+ // returns at least one element to be drawn by the application.
+ // In this case OnHeaderDraw is not used.
+ FOnGetLineStyle: TVTGetLineStyleEvent; // triggered when a custom line style is used and the pattern brush
+ // needs to be build
+ FOnPaintBackground: TVTBackgroundPaintEvent; // triggered if a part of the tree's background must be erased which is
+ // not covered by any node
+
+ // drag'n drop events
+ FOnCreateDragManager: TVTCreateDragManagerEvent; // called to allow for app./descendant defined drag managers
+ FOnCreateDataObject: TVTCreateDataObjectEvent; // called to allow for app./descentant defined data objects
+ FOnDragAllowed: TVTDragAllowedEvent; // used to get permission for manual drag in mouse down
+ FOnDragOver: TVTDragOverEvent; // called for every mouse move
+ FOnDragDrop: TVTDragDropEvent; // called on release of mouse button (if drop was allowed)
+ FOnHeaderDragged: TVTHeaderDraggedEvent; // header (column) drag'n drop
+ FOnHeaderDraggedOut: TVTHeaderDraggedOutEvent; // header (column) drag'n drop, which did not result in a valid drop.
+ FOnHeaderDragging: TVTHeaderDraggingEvent; // header (column) drag'n drop
+ FOnRenderOLEData: TVTRenderOLEDataEvent; // application/descendant defined clipboard formats
+ FOnGetUserClipboardFormats: TVTGetUserClipboardFormatsEvent; // gives application/descentants the opportunity to
+ // add own clipboard formats on the fly
+
+ // miscellanous events
+ FOnGetNodeDataSize: TVTGetNodeDataSizeEvent; // called if NodeDataSize is -1
+ FOnKeyAction: TVTKeyActionEvent; // used to selectively prevent key actions (full expand on Ctrl+'+' etc.)
+ FOnScroll: TVTScrollEvent; // called when one or both paint offsets changed
+ FOnUpdating: TVTUpdatingEvent; // called from BeginUpdate, EndUpdate, BeginSynch and EndSynch
+ FOnGetCursor: TVTGetCursorEvent; // called to allow the app. to set individual cursors
+ FOnStateChange: TVTStateChangeEvent; // Called whenever a state in the tree changes.
+
+ // search, sort
+ FOnCompareNodes: TVTCompareEvent; // used during sort
+ FOnIncrementalSearch: TVTIncrementalSearchEvent; // triggered on every key press (not key down)
+
+ procedure AdjustCoordinatesByIndent(var PaintInfo: TVTPaintInfo; Indent: Integer);
+ procedure AdjustImageBorder(Images: TCustomImageList; BidiMode: TBidiMode; VAlign: Integer; var R: TRect;
+ var ImageInfo: TVTImageInfo);
+ procedure AdjustTotalCount(Node: PVirtualNode; Value: Integer; relative: Boolean = False);
+ procedure AdjustTotalHeight(Node: PVirtualNode; Value: Integer; relative: Boolean = False);
+ function CalculateCacheEntryCount: Integer;
+ procedure CalculateVerticalAlignments(ShowImages, ShowStateImages: Boolean; Node: PVirtualNode; var VAlign,
+ VButtonAlign: Integer);
+ function ChangeCheckState(Node: PVirtualNode; Value: TCheckState): Boolean;
+ function CollectSelectedNodesLTR(MainColumn, NodeLeft, NodeRight: Integer; Alignment: TAlignment; OldRect,
+ NewRect: TRect): Boolean;
+ function CollectSelectedNodesRTL(MainColumn, NodeLeft, NodeRight: Integer; Alignment: TAlignment; OldRect,
+ NewRect: TRect): Boolean;
+ procedure ClearNodeBackground(const PaintInfo: TVTPaintInfo; UseBackground, Floating: Boolean; R: TRect);
+ function CompareNodePositions(Node1, Node2: PVirtualNode): Integer;
+ procedure DrawLineImage(const PaintInfo: TVTPaintInfo; X, Y, H, VAlign: Integer; Style: TVTLineType; Reverse: Boolean);
+ function FindInPositionCache(Node: PVirtualNode; var CurrentPos: Cardinal): PVirtualNode; overload;
+ function FindInPositionCache(Position: Cardinal; var CurrentPos: Cardinal): PVirtualNode; overload;
+ function GetCheckState(Node: PVirtualNode): TCheckState;
+ function GetCheckType(Node: PVirtualNode): TCheckType;
+ function GetChildCount(Node: PVirtualNode): Cardinal;
+ function GetChildrenInitialized(Node: PVirtualNode): Boolean;
+ function GetDisabled(Node: PVirtualNode): Boolean;
+ function GetDragManager: IVTDragManager;
+ function GetExpanded(Node: PVirtualNode): Boolean;
+ function GetFullyVisible(Node: PVirtualNode): Boolean;
+ function GetHasChildren(Node: PVirtualNode): Boolean;
+ function GetMultiline(Node: PVirtualNode): Boolean;
+ function GetNodeHeight(Node: PVirtualNode): Cardinal;
+ function GetNodeParent(Node: PVirtualNode): PVirtualNode;
+ function GetOffsetXY: TPoint;
+ function GetRootNodeCount: Cardinal;
+ function GetSelected(Node: PVirtualNode): Boolean;
+ function GetTopNode: PVirtualNode;
+ function GetTotalCount: Cardinal;
+ function GetVerticalAlignment(Node: PVirtualNode): Byte;
+ function GetVisible(Node: PVirtualNode): Boolean;
+ function GetVisiblePath(Node: PVirtualNode): Boolean;
+ procedure HandleClickSelection(LastFocused, NewNode: PVirtualNode; Shift: TShiftState);
+ function HandleDrawSelection(X, Y: Integer): Boolean;
+ function HasVisibleNextSibling(Node: PVirtualNode): Boolean;
+ procedure ImageListChange(Sender: TObject);
+ procedure InitializeFirstColumnValues(var PaintInfo: TVTPaintInfo);
+ function InitializeLineImageAndSelectLevel(Node: PVirtualNode; var LineImage: TLineImage): Integer;
+ procedure InitRootNode(OldSize: Cardinal = 0);
+ procedure InterruptValidation;
+ function IsFirstVisibleChild(Parent, Node: PVirtualNode): Boolean;
+ function IsLastVisibleChild(Parent, Node: PVirtualNode): Boolean;
+ procedure LimitPaintingToArea(Canvas: TCanvas; ClipRect: TRect; VisibleRegion: HRGN = 0);
+ function MakeNewNode: PVirtualNode;
+ procedure OriginalWMNCPaint(DC: HDC);
+ function PackArray(TheArray: TNodeArray; Count: Integer): Integer;
+ procedure PrepareBitmaps(NeedButtons, NeedLines: Boolean);
+ procedure PrepareCell(var PaintInfo: TVTPaintInfo);
+ procedure ReadOldOptions(Reader: TReader);
+ procedure SetAlignment(const Value: TAlignment);
+ procedure SetAnimationDuration(const Value: Cardinal);
+ procedure SetBackground(const Value: TPicture);
+ procedure SetBackgroundOffset(const Index, Value: Integer);
+ procedure SetBorderStyle(Value: TBorderStyle);
+ procedure SetButtonFillMode(const Value: TVTButtonFillMode);
+ procedure SetButtonStyle(const Value: TVTButtonStyle);
+ procedure SetCheckImageKind(Value: TCheckImageKind);
+ procedure SetCheckState(Node: PVirtualNode; Value: TCheckState);
+ procedure SetCheckType(Node: PVirtualNode; Value: TCheckType);
+ procedure SetChildCount(Node: PVirtualNode; NewChildCount: Cardinal);
+ procedure SetClipboardFormats(const Value: TClipboardFormats);
+ procedure SetColors(const Value: TVTColors);
+ procedure SetCustomCheckImages(const Value: TCustomImageList);
+ procedure SetDefaultNodeHeight(Value: Cardinal);
+ procedure SetDisabled(Node: PVirtualNode; Value: Boolean);
+ procedure SetExpanded(Node: PVirtualNode; Value: Boolean);
+ procedure SetFocusedColumn(Value: TColumnIndex);
+ procedure SetFocusedNode(Value: PVirtualNode);
+ procedure SetFullyVisible(Node: PVirtualNode; Value: Boolean);
+ procedure SetHasChildren(Node: PVirtualNode; Value: Boolean);
+ procedure SetHeader(const Value: TVTHeader);
+ procedure SetImages(const Value: TCustomImageList);
+ procedure SetIndent(Value: Cardinal);
+ procedure SetLineMode(const Value: TVTLineMode);
+ procedure SetLineStyle(const Value: TVTLineStyle);
+ procedure SetMargin(Value: Integer);
+ procedure SetMultiline(Node: PVirtualNode; const Value: Boolean);
+ procedure SetNodeAlignment(const Value: TVTNodeAlignment);
+ procedure SetNodeDataSize(Value: Integer);
+ procedure SetNodeHeight(Node: PVirtualNode; Value: Cardinal);
+ procedure SetNodeParent(Node: PVirtualNode; const Value: PVirtualNode);
+ procedure SetOffsetX(const Value: Integer);
+ procedure SetOffsetXY(const Value: TPoint);
+ procedure SetOffsetY(const Value: Integer);
+ procedure SetOptions(const Value: TCustomVirtualTreeOptions);
+ procedure SetRootNodeCount(Value: Cardinal);
+ procedure SetScrollBarOptions(Value: TScrollBarOptions);
+ procedure SetSearchOption(const Value: TVTIncrementalSearch);
+ procedure SetSelected(Node: PVirtualNode; Value: Boolean);
+ procedure SetSelectionCurveRadius(const Value: Cardinal);
+ procedure SetStateImages(const Value: TCustomImageList);
+ procedure SetTextMargin(Value: Integer);
+ procedure SetTopNode(Node: PVirtualNode);
+ procedure SetUpdateState(Updating: Boolean);
+ procedure SetVerticalAlignment(Node: PVirtualNode; Value: Byte);
+ procedure SetVisible(Node: PVirtualNode; Value: Boolean);
+ procedure SetVisiblePath(Node: PVirtualNode; Value: Boolean);
+ procedure StopTimer(ID: Integer);
+ procedure TileBackground(Source: TBitmap; Target: TCanvas; Offset: TPoint; R: TRect);
+ function ToggleCallback(Step, StepSize: Integer; Data: Pointer): Boolean;
+
+ procedure CMColorChange(var Message: TMessage); message CM_COLORCHANGED;
+ procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
+ procedure CMDenySubclassing(var Message: TMessage); message CM_DENYSUBCLASSING;
+ procedure CMDrag(var Message: TCMDrag); message CM_DRAG;
+ procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
+ procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
+ procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
+ procedure CMHintShowPause(var Message: TCMHintShowPause); message CM_HINTSHOWPAUSE;
+ procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
+ procedure CMMouseWheel(var Message: TCMMouseWheel); message CM_MOUSEWHEEL;
+ procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
+ procedure WMCancelMode(var Message: TWMCancelMode); message WM_CANCELMODE;
+ procedure WMChangeState(var Message: TMessage); message WM_CHANGESTATE;
+ procedure WMChar(var Message: TWMChar); message WM_CHAR;
+ procedure WMContextMenu(var Message: TWMContextMenu); message WM_CONTEXTMENU;
+ procedure WMCopy(var Message: TWMCopy); message WM_COPY;
+ procedure WMCut(var Message: TWMCut); message WM_CUT;
+ procedure WMEnable(var Message: TWMEnable); message WM_ENABLE;
+ procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
+ procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
+ procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
+ procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
+ procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP;
+ procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
+ procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
+ procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
+ procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
+ procedure WMMButtonDblClk(var Message: TWMMButtonDblClk); message WM_MBUTTONDBLCLK;
+ procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN;
+ procedure WMMButtonUp(var Message: TWMMButtonUp); message WM_MBUTTONUP;
+ procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
+ procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY;
+ procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
+ procedure WMNCPaint(var Message: TRealWMNCPaint); message WM_NCPAINT;
+ procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
+ procedure WMPaste(var Message: TWMPaste); message WM_PASTE;
+ procedure WMPrint(var Message: TWMPrint); message WM_PRINT;
+ procedure WMPrintClient(var Message: TWMPrintClient); message WM_PRINTCLIENT;
+ procedure WMRButtonDblClk(var Message: TWMRButtonDblClk); message WM_RBUTTONDBLCLK;
+ procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
+ procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
+ procedure WMReleaseEditLink(var Message: TMessage); message WM_RELEASEEDITLINK;
+ procedure WMSetCursor(var Message: TWMSetCursor); message WM_SETCURSOR;
+ procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
+ procedure WMSize(var Message: TWMSize); message WM_SIZE;
+ procedure WMTimer(var Message: TWMTimer); message WM_TIMER;
+ procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
+ protected
+ procedure AddToSelection(Node: PVirtualNode); overload;
+ procedure AddToSelection(const NewItems: TNodeArray; NewLength: Integer; ForceInsert: Boolean = False); overload;
+ procedure AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex); virtual;
+ procedure AdjustPanningCursor(X, Y: Integer);
+ procedure AdviseChangeEvent(StructureChange: Boolean; Node: PVirtualNode; Reason: TChangeReason);
+ function AllocateInternalDataArea(Size: Cardinal): Cardinal;
+ procedure Animate(Steps, Duration: Cardinal; Callback: TVTAnimationCallback; Data: Pointer);
+ function CalculateSelectionRect(X, Y: Integer): Boolean;
+ function CanAutoScroll: Boolean; virtual;
+ function CanEdit(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual;
+ function CanShowDragImage: Boolean; virtual;
+ procedure Change(Node: PVirtualNode);
+ procedure ChangeScale(M, D: Integer); override;
+ function CheckParentCheckState(Node: PVirtualNode; NewCheckState: TCheckState): Boolean;
+ procedure ClearTempCache;
+ function ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual;
+ function CountLevelDifference(Node1, Node2: PVirtualNode): Integer;
+ function CountVisibleChildren(Node: PVirtualNode): Cardinal;
+ procedure CreateParams(var Params: TCreateParams); override;
+ procedure CreateWnd; override;
+ procedure DefineProperties(Filer: TFiler); override;
+ procedure DetermineHiddenChildrenFlag(Node: PVirtualNode);
+ procedure DetermineHiddenChildrenFlagAllNodes;
+ procedure DetermineHitPositionLTR(var HitInfo: THitInfo; Offset, Right: Integer; Alignment: TAlignment); virtual;
+ procedure DetermineHitPositionRTL(var HitInfo: THitInfo; Offset, Right: Integer; Alignment: TAlignment); virtual;
+ function DetermineNextCheckState(CheckType: TCheckType; CheckState: TCheckState): TCheckState; virtual;
+ function DetermineScrollDirections(X, Y: Integer): TScrollDirections;
+ procedure DoAdvancedHeaderDraw(var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements); virtual;
+ procedure DoAfterCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); virtual;
+ procedure DoAfterItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); virtual;
+ procedure DoAfterItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); virtual;
+ procedure DoAfterPaint(Canvas: TCanvas); virtual;
+ procedure DoAutoScroll(X, Y: Integer); virtual;
+ function DoBeforeDrag(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual;
+ procedure DoBeforeCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); virtual;
+ procedure DoBeforeItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect; var Color: TColor;
+ var EraseAction: TItemEraseAction); virtual;
+ function DoBeforeItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect): Boolean; virtual;
+ procedure DoBeforePaint(Canvas: TCanvas); virtual;
+ function DoCancelEdit: Boolean; virtual;
+ procedure DoCanEdit(Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); virtual;
+ procedure DoChange(Node: PVirtualNode); virtual;
+ procedure DoCheckClick(Node: PVirtualNode; NewCheckState: TCheckState); virtual;
+ procedure DoChecked(Node: PVirtualNode); virtual;
+ function DoChecking(Node: PVirtualNode; var NewCheckState: TCheckState): Boolean; virtual;
+ procedure DoCollapsed(Node: PVirtualNode); virtual;
+ function DoCollapsing(Node: PVirtualNode): Boolean; virtual;
+ procedure DoColumnClick(Column: TColumnIndex; Shift: TShiftState); virtual;
+ procedure DoColumnDblClick(Column: TColumnIndex; Shift: TShiftState); virtual;
+ procedure DoColumnResize(Column: TColumnIndex); virtual;
+ function DoCompare(Node1, Node2: PVirtualNode; Column: TColumnIndex): Integer; virtual;
+ function DoCreateDataObject: IDataObject; virtual;
+ function DoCreateDragManager: IVTDragManager; virtual;
+ function DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; virtual;
+ procedure DoDragging(P: TPoint);
+ procedure DoDragExpand;
+ function DoDragOver(Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode;
+ var Effect: Integer): Boolean; virtual;
+ procedure DoDragDrop(Source: TObject; DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState; Pt: TPoint;
+ var Effect: Integer; Mode: TDropMode); virtual;
+ procedure DoEdit; virtual;
+ procedure DoEndDrag(Target: TObject; X, Y: Integer); override;
+ function DoEndEdit: Boolean; virtual;
+ procedure DoExpanded(Node: PVirtualNode); virtual;
+ function DoExpanding(Node: PVirtualNode): Boolean; virtual;
+ procedure DoFocusChange(Node: PVirtualNode; Column: TColumnIndex); virtual;
+ function DoFocusChanging(OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex): Boolean; virtual;
+ procedure DoFocusNode(Node: PVirtualNode; Ask: Boolean); virtual;
+ procedure DoFreeNode(Node: PVirtualNode); virtual;
+ function DoGetAnimationType: THintAnimationType; virtual;
+ procedure DoGetCursor(var Cursor: TCursor); virtual;
+ procedure DoGetHeaderCursor(var Cursor: HCURSOR); virtual;
+ procedure DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer); virtual;
+ procedure DoGetLineStyle(var Bits: Pointer); virtual;
+ function DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex): WideString; virtual;
+ function DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex): WideString; virtual;
+ function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer; virtual;
+ function DoGetPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint): TPopupMenu; virtual;
+ procedure DoGetUserClipboardFormats(var Formats: TFormatEtcArray); virtual;
+ procedure DoHeaderClick(Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHeaderDblClick(Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHeaderDragged(Column: TColumnIndex; OldPosition: TColumnPosition); virtual;
+ procedure DoHeaderDraggedOut(Column: TColumnIndex; DropPosition: TPoint); virtual;
+ function DoHeaderDragging(Column: TColumnIndex): Boolean; virtual;
+ procedure DoHeaderDraw(Canvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover, Pressed: Boolean;
+ DropMark: TVTDropMarkMode); virtual;
+ procedure DoHeaderDrawQueryElements(var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements); virtual;
+ procedure DoHeaderMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHeaderMouseMove(Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHeaderMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHotChange(Old, New: PVirtualNode); virtual;
+ function DoIncrementalSearch(Node: PVirtualNode; const Text: WideString): Integer; virtual;
+ procedure DoInitChildren(Node: PVirtualNode; var ChildCount: Cardinal); virtual;
+ procedure DoInitNode(Parent, Node: PVirtualNode; var InitStates: TVirtualNodeInitStates); virtual;
+ function DoKeyAction(var CharCode: Word; var Shift: TShiftState): Boolean; virtual;
+ procedure DoLoadUserData(Node: PVirtualNode; Stream: TStream); virtual;
+ procedure DoNodeCopied(Node: PVirtualNode); virtual;
+ function DoNodeCopying(Node, NewParent: PVirtualNode): Boolean; virtual;
+ procedure DoNodeMoved(Node: PVirtualNode); virtual;
+ function DoNodeMoving(Node, NewParent: PVirtualNode): Boolean; virtual;
+ function DoPaintBackground(Canvas: TCanvas; R: TRect): Boolean; virtual;
+ procedure DoPaintDropMark(Canvas: TCanvas; Node: PVirtualNode; R: TRect); virtual;
+ procedure DoPaintNode(var PaintInfo: TVTPaintInfo); virtual;
+ procedure DoPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint); virtual;
+ function DoRenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean): HRESULT; virtual;
+ procedure DoReset(Node: PVirtualNode); virtual;
+ procedure DoSaveUserData(Node: PVirtualNode; Stream: TStream); virtual;
+ procedure DoScroll(DeltaX, DeltaY: Integer); virtual;
+ function DoSetOffsetXY(Value: TPoint; Options: TScrollUpdateOptions; ClipRect: PRect = nil): Boolean; virtual;
+ procedure DoStartDrag(var DragObject: TDragObject); override;
+ procedure DoStateChange(Enter: TVirtualTreeStates; Leave: TVirtualTreeStates = []); virtual;
+ procedure DoStructureChange(Node: PVirtualNode; Reason: TChangeReason); virtual;
+ procedure DoTimerScroll;
+ procedure DoUpdating(State: TVTUpdateState); virtual;
+ function DoValidateCache: Boolean;
+ procedure DragCanceled; override;
+ function DragDrop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult; reintroduce; virtual;
+ function DragEnter(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult; virtual;
+ procedure DragFinished;
+ procedure DragLeave; virtual;
+ function DragOver(Source: TObject; KeyState: Integer; DragState: TDragState; Pt: TPoint;
+ var Effect: Integer): HResult; reintroduce; virtual;
+ procedure DrawDottedHLine(const PaintInfo: TVTPaintInfo; Left, Right, Top: Integer);
+ procedure DrawDottedVLine(const PaintInfo: TVTPaintInfo; Top, Bottom, Left: Integer);
+ function FindNodeInSelection(P: PVirtualNode; var Index: Integer; LowBound, HighBound: Integer): Boolean;
+ procedure FinishChunkHeader(Stream: TStream; StartPos, EndPos: Integer);
+ procedure FontChanged(AFont: TObject);
+ function GetCheckImage(Node: PVirtualNode): Integer; virtual;
+ function GetColumnClass: TVirtualTreeColumnClass; virtual;
+ function GetHeaderClass: TVTHeaderClass; virtual;
+ function GetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean): Integer;
+ function GetMaxRightExtend: Cardinal;
+ procedure GetNativeClipboardFormats(var Formats: TFormatEtcArray); virtual;
+ function GetOptionsClass: TTreeOptionsClass; virtual;
+ procedure GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect;
+ var Text: WideString); virtual;
+ function GetTreeFromDataObject(const DataObject: IDataObject): TBaseVirtualTree;
+ procedure HandleHotTrack(X, Y: Integer);
+ procedure HandleIncrementalSearch(CharCode: Word);
+ procedure HandleMouseDblClick(var Message: TWMMouse; const HitInfo: THitInfo);
+ procedure HandleMouseDown(var Message: TWMMouse; const HitInfo: THitInfo);
+ procedure HandleMouseUp(var Message: TWMMouse; const HitInfo: THitInfo);
+ function HasPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Pos: TPoint): Boolean; virtual;
+ procedure InitChildren(Node: PVirtualNode);
+ procedure InitNode(Node: PVirtualNode);
+ procedure InternalAddFromStream(Stream: TStream; Version: Integer; Node: PVirtualNode);
+ function InternalAddToSelection(Node: PVirtualNode; ForceInsert: Boolean): Boolean; overload;
+ function InternalAddToSelection(const NewItems: TNodeArray; NewLength: Integer;
+ ForceInsert: Boolean): Boolean; overload;
+ procedure InternalCacheNode(Node: PVirtualNode);
+ procedure InternalClearSelection;
+ procedure InternalConnectNode(Node, Destination: PVirtualNode; Target: TBaseVirtualTree; Mode: TVTNodeAttachMode);
+ function InternalData(Node: PVirtualNode): Pointer;
+ procedure InternalDisconnectNode(Node: PVirtualNode; KeepFocus: Boolean; Reindex: Boolean = True);
+ procedure InternalRemoveFromSelection(Node: PVirtualNode);
+ procedure InvalidateCache;
+ procedure Loaded; override;
+ procedure MainColumnChanged; virtual;
+ procedure MarkCutCopyNodes;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
+ procedure Notification(AComponent: TComponent; Operation: TOperation); override;
+ procedure Paint; override;
+ procedure PaintCheckImage(const PaintInfo: TVTPaintInfo); virtual;
+ procedure PaintImage(const PaintInfo: TVTPaintInfo; ImageInfoIndex: TVTImageInfoIndex; Images: TCustomImageList;
+ DoOverlay: Boolean); virtual;
+ procedure PaintNodeButton(Canvas: TCanvas; Node: PVirtualNode; const R: TRect; ButtonX, ButtonY: Integer;
+ BidiMode: TBiDiMode); virtual;
+ procedure PaintTreeLines(const PaintInfo: TVTPaintInfo; VAlignment, IndentSize: Integer;
+ LineImage: TLineImage); virtual;
+ procedure PaintSelectionRectangle(Target: TCanvas; WindowOrgX: Integer; const SelectionRect: TRect;
+ TargetRect: TRect);
+ procedure PanningWindowProc(var Message: TMessage);
+ function ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType,
+ ChunkSize: Integer): Boolean; virtual;
+ procedure ReadNode(Stream: TStream; Version: Integer; Node: PVirtualNode); virtual;
+ procedure RedirectFontChangeEvent(Canvas: TCanvas);
+ procedure RemoveFromSelection(Node: PVirtualNode);
+ function RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HResult; virtual;
+ procedure ResetRangeAnchor;
+ procedure RestoreFontChangeEvent(Canvas: TCanvas);
+ procedure SelectNodes(StartNode, EndNode: PVirtualNode; AddOnly: Boolean);
+ procedure SetBiDiMode(Value: TBiDiMode); override;
+ procedure SkipNode(Stream: TStream); virtual;
+ procedure StartWheelPanning(Position: TPoint);
+ procedure StopWheelPanning;
+ procedure StructureChange(Node: PVirtualNode; Reason: TChangeReason);
+ function SuggestDropEffect(Source: TObject; Shift: TShiftState; Pt: TPoint; AllowedEffects: Integer): Integer; virtual;
+ procedure ToggleSelection(StartNode, EndNode: PVirtualNode);
+ procedure UnselectNodes(StartNode, EndNode: PVirtualNode);
+ procedure UpdateDesigner;
+ procedure UpdateEditBounds;
+ procedure UpdateHeaderRect;
+ procedure UpdateWindowAndDragImage(const Tree: TBaseVirtualTree; TreeRect: TRect; UpdateNCArea,
+ ReshowDragImage: Boolean);
+ procedure ValidateCache;
+ procedure ValidateNodeDataSize(var Size: Integer); virtual;
+ procedure WndProc(var Message: TMessage); override;
+ procedure WriteChunks(Stream: TStream; Node: PVirtualNode); virtual;
+ procedure WriteNode(Stream: TStream; Node: PVirtualNode);
+
+ property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
+ property AnimationDuration: Cardinal read FAnimationDuration write SetAnimationDuration default 200;
+ property AutoExpandDelay: Cardinal read FAutoExpandDelay write FAutoExpandDelay default 1000;
+ property AutoScrollDelay: Cardinal read FAutoScrollDelay write FAutoScrollDelay default 1000;
+ property AutoScrollInterval: TAutoScrollInterval read FAutoScrollInterval write FAutoScrollInterval default 1;
+ property Background: TPicture read FBackground write SetBackground;
+ property BackgroundOffsetX: Integer index 0 read FBackgroundOffsetX write SetBackgroundOffset default 0;
+ property BackgroundOffsetY: Integer index 1 read FBackgroundOffsetY write SetBackgroundOffset default 0;
+ property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
+ property ButtonFillMode: TVTButtonFillMode read FButtonFillMode write SetButtonFillMode default fmTreeColor;
+ property ButtonStyle: TVTButtonStyle read FButtonStyle write SetButtonStyle default bsRectangle;
+ property ChangeDelay: Cardinal read FChangeDelay write FChangeDelay default 0;
+ property CheckImageKind: TCheckImageKind read FCheckImageKind write SetCheckImageKind default ckLightCheck;
+ property ClipboardFormats: TClipboardFormats read FClipboardFormats write SetClipboardFormats;
+ property Colors: TVTColors read FColors write SetColors;
+ property CustomCheckImages: TCustomImageList read FCustomCheckImages write SetCustomCheckImages;
+ property DefaultNodeHeight: Cardinal read FDefaultNodeHeight write SetDefaultNodeHeight default 18;
+ property DefaultPasteMode: TVTNodeAttachMode read FDefaultPasteMode write FDefaultPasteMode default amAddChildLast;
+ property DragHeight: Integer read FDragHeight write FDragHeight default 350;
+ property DragImageKind: TVTDragImageKind read FDragImageKind write FDragImageKind default diComplete;
+ property DragOperations: TDragOperations read FDragOperations write FDragOperations default [doCopy, doMove];
+ property DragSelection: TNodeArray read FDragSelection;
+ property DragType: TVTDragType read FDragType write FDragType default dtOLE;
+ property DragWidth: Integer read FDragWidth write FDragWidth default 200;
+ property DrawSelectionMode: TVTDrawSelectionMode read FDrawSelectionMode write FDrawSelectionMode
+ default smDottedRectangle;
+ property EditDelay: Cardinal read FEditDelay write FEditDelay default 1000;
+ property Header: TVTHeader read FHeader write SetHeader;
+ property HeaderRect: TRect read FHeaderRect;
+ property HintAnimation: THintAnimationType read FAnimationType write FAnimationType default hatSystemDefault;
+ property HintMode: TVTHintMode read FHintMode write FHintMode default hmDefault;
+ property HotCursor: TCursor read FHotCursor write FHotCursor default crDefault;
+ property Images: TCustomImageList read FImages write SetImages;
+ property IncrementalSearch: TVTIncrementalSearch read FIncrementalSearch write SetSearchOption default isNone;
+ property IncrementalSearchDirection: TVTSearchDirection read FSearchDirection write FSearchDirection default sdForward;
+ property IncrementalSearchStart: TVTSearchStart read FSearchStart write FSearchStart default ssFocusedNode;
+ property IncrementalSearchTimeout: Cardinal read FSearchTimeout write FSearchTimeout default 1000;
+ property Indent: Cardinal read FIndent write SetIndent default 18;
+ property LastDropMode: TDropMode read FLastDropMode write FlastDropMode;
+ property LineMode: TVTLineMode read FLineMode write SetLineMode default lmNormal;
+ property LineStyle: TVTLineStyle read FLineStyle write SetLineStyle default lsDotted;
+ property Margin: Integer read FMargin write SetMargin default 4;
+ property NodeAlignment: TVTNodeAlignment read FNodeAlignment write SetNodeAlignment default naProportional;
+ property NodeDataSize: Integer read FNodeDataSize write SetNodeDataSize default -1;
+ property RootNodeCount: Cardinal read GetRootNodeCount write SetRootNodeCount default 0;
+ property ScrollBarOptions: TScrollBarOptions read FScrollBarOptions write SetScrollBarOptions;
+ property SelectionBlendFactor: Byte read FSelectionBlendFactor write FSelectionBlendFactor default 128;
+ property SelectionCurveRadius: Cardinal read FSelectionCurveRadius write SetSelectionCurveRadius default 0;
+ property StateImages: TCustomImageList read FStateImages write SetStateImages;
+ property TextMargin: Integer read FTextMargin write SetTextMargin default 4;
+ property TotalInternalDataSize: Cardinal read FTotalInternalDataSize;
+ property TreeOptions: TCustomVirtualTreeOptions read FOptions write SetOptions;
+ property WantTabs: Boolean read FWantTabs write FWantTabs default False;
+
+ property OnAdvancedHeaderDraw: TVTAdvancedHeaderPaintEvent read FOnAdvancedHeaderDraw write FOnAdvancedHeaderDraw;
+ property OnAfterCellPaint: TVTAfterCellPaintEvent read FOnAfterCellPaint write FOnAfterCellPaint;
+ property OnAfterItemErase: TVTAfterItemEraseEvent read FOnAfterItemErase write FOnAfterItemErase;
+ property OnAfterItemPaint: TVTAfterItemPaintEvent read FOnAfterItemPaint write FOnAfterItemPaint;
+ property OnAfterPaint: TVTPaintEvent read FOnAfterPaint write FOnAfterPaint;
+ property OnBeforeCellPaint: TVTBeforeCellPaintEvent read FOnBeforeCellPaint write FOnBeforeCellPaint;
+ property OnBeforeItemErase: TVTBeforeItemEraseEvent read FOnBeforeItemErase write FOnBeforeItemErase;
+ property OnBeforeItemPaint: TVTBeforeItemPaintEvent read FOnBeforeItemPaint write FOnBeforeItemPaint;
+ property OnBeforePaint: TVTPaintEvent read FOnBeforePaint write FOnBeforePaint;
+ property OnChange: TVTChangeEvent read FOnChange write FOnChange;
+ property OnChecked: TVTChangeEvent read FOnChecked write FOnChecked;
+ property OnChecking: TVTCheckChangingEvent read FOnChecking write FOnChecking;
+ property OnCollapsed: TVTChangeEvent read FOnCollapsed write FOnCollapsed;
+ property OnCollapsing: TVTChangingEvent read FOnCollapsing write FOnCollapsing;
+ property OnColumnClick: TVTColumnClickEvent read FOnColumnClick write FOnColumnClick;
+ property OnColumnDblClick: TVTColumnDblClickEvent read FOnColumnDblClick write FOnColumnDblClick;
+ property OnColumnResize: TVTHeaderNotifyEvent read FOnColumnResize write FOnColumnResize;
+ property OnCompareNodes: TVTCompareEvent read FOnCompareNodes write FOnCompareNodes;
+ property OnCreateDataObject: TVTCreateDataObjectEvent read FOnCreateDataObject write FOnCreateDataObject;
+ property OnCreateDragManager: TVTCreateDragManagerEvent read FOnCreateDragManager write FOnCreateDragManager;
+ property OnCreateEditor: TVTCreateEditorEvent read FOnCreateEditor write FOnCreateEditor;
+ property OnDragAllowed: TVTDragAllowedEvent read FOnDragAllowed write FOnDragAllowed;
+ property OnDragOver: TVTDragOverEvent read FOnDragOver write FOnDragOver;
+ property OnDragDrop: TVTDragDropEvent read FOnDragDrop write FOnDragDrop;
+ property OnEditCancelled: TVTEditCancelEvent read FOnEditCancelled write FOnEditCancelled;
+ property OnEditing: TVTEditChangingEvent read FOnEditing write FOnEditing;
+ property OnEdited: TVTEditChangeEvent read FOnEdited write FOnEdited;
+ property OnExpanded: TVTChangeEvent read FOnExpanded write FOnExpanded;
+ property OnExpanding: TVTChangingEvent read FOnExpanding write FOnExpanding;
+ property OnFocusChanged: TVTFocusChangeEvent read FOnFocusChanged write FOnFocusChanged;
+ property OnFocusChanging: TVTFocusChangingEvent read FOnFocusChanging write FOnFocusChanging;
+ property OnFreeNode: TVTFreeNodeEvent read FOnFreeNode write FOnFreeNode;
+ property OnGetCursor: TVTGetCursorEvent read FOnGetCursor write FOnGetCursor;
+ property OnGetHeaderCursor: TVTGetHeaderCursorEvent read FOnGetHeaderCursor write FOnGetHeaderCursor;
+ property OnGetHelpContext: TVTHelpContextEvent read FOnGetHelpContext write FOnGetHelpContext;
+ property OnGetImageIndex: TVTGetImageEvent read FOnGetImage write FOnGetImage;
+ property OnGetLineStyle: TVTGetLineStyleEvent read FOnGetLineStyle write FOnGetLineStyle;
+ property OnGetNodeDataSize: TVTGetNodeDataSizeEvent read FOnGetNodeDataSize write FOnGetNodeDataSize;
+ property OnGetPopupMenu: TVTPopupEvent read FOnGetPopupMenu write FOnGetPopupMenu;
+ property OnGetUserClipboardFormats: TVTGetUserClipboardFormatsEvent read FOnGetUserClipboardFormats
+ write FOnGetUserClipboardFormats;
+ property OnHeaderClick: TVTHeaderClickEvent read FOnHeaderClick write FOnHeaderClick;
+ property OnHeaderDblClick: TVTHeaderClickEvent read FOnHeaderDblClick write FOnHeaderDblClick;
+ property OnHeaderDragged: TVTHeaderDraggedEvent read FOnHeaderDragged write FOnHeaderDragged;
+ property OnHeaderDraggedOut: TVTHeaderDraggedOutEvent read FOnHeaderDraggedOut write FOnHeaderDraggedOut;
+ property OnHeaderDragging: TVTHeaderDraggingEvent read FOnHeaderDragging write FOnHeaderDragging;
+ property OnHeaderDraw: TVTHeaderPaintEvent read FOnHeaderDraw write FOnHeaderDraw;
+ property OnHeaderDrawQueryElements: TVTHeaderPaintQueryElementsEvent read FOnHeaderDrawQueryElements
+ write FOnHeaderDrawQueryElements;
+ property OnHeaderMouseDown: TVTHeaderMouseEvent read FOnHeaderMouseDown write FOnHeaderMouseDown;
+ property OnHeaderMouseMove: TVTHeaderMouseMoveEvent read FOnHeaderMouseMove write FOnHeaderMouseMove;
+ property OnHeaderMouseUp: TVTHeaderMouseEvent read FOnHeaderMouseUp write FOnHeaderMouseUp;
+ property OnHotChange: TVTHotNodeChangeEvent read FOnHotChange write FOnHotChange;
+ property OnIncrementalSearch: TVTIncrementalSearchEvent read FOnIncrementalSearch write FOnIncrementalSearch;
+ property OnInitChildren: TVTInitChildrenEvent read FOnInitChildren write FOnInitChildren;
+ property OnInitNode: TVTInitNodeEvent read FOnInitNode write FOnInitNode;
+ property OnKeyAction: TVTKeyActionEvent read FOnKeyAction write FOnKeyAction;
+ property OnLoadNode: TVTSaveNodeEvent read FOnLoadNode write FOnLoadNode;
+ property OnNodeCopied: TVTNodeCopiedEvent read FOnNodeCopied write FOnNodeCopied;
+ property OnNodeCopying: TVTNodeCopyingEvent read FOnNodeCopying write FOnNodeCopying;
+ property OnNodeMoved: TVTNodeMovedEvent read FOnNodeMoved write FOnNodeMoved;
+ property OnNodeMoving: TVTNodeMovingEvent read FOnNodeMoving write FOnNodeMoving;
+ property OnPaintBackground: TVTBackgroundPaintEvent read FOnPaintBackground write FOnPaintBackground;
+ property OnRenderOLEData: TVTRenderOLEDataEvent read FOnRenderOLEData write FOnRenderOLEData;
+ property OnResetNode: TVTChangeEvent read FOnResetNode write FOnResetNode;
+ property OnSaveNode: TVTSaveNodeEvent read FOnSaveNode write FOnSaveNode;
+ property OnScroll: TVTScrollEvent read FOnScroll write FOnScroll;
+ property OnStateChange: TVTStateChangeEvent read FOnStateChange write FOnStateChange;
+ property OnStructureChange: TVTStructureChangeEvent read FOnStructureChange write FOnStructureChange;
+ property OnUpdating: TVTUpdatingEvent read FOnUpdating write FOnUpdating;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ function AbsoluteIndex(Node: PVirtualNode): Cardinal;
+ function AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode;
+ procedure AddFromStream(Stream: TStream; TargetNode: PVirtualNode);
+ procedure AfterConstruction; override;
+ procedure Assign(Source: TPersistent); override;
+ procedure BeginDrag(Immediate: Boolean; Threshold: Integer = -1);
+ procedure BeginSynch;
+ procedure BeginUpdate;
+ procedure CancelCutOrCopy;
+ function CancelEditNode: Boolean;
+ function CanFocus: Boolean; {$ifdef COMPILER_5_UP} override;{$endif}
+ procedure Clear; virtual;
+ procedure ClearSelection;
+ function CopyTo(Source: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean): PVirtualNode; overload;
+ function CopyTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean): PVirtualNode; overload;
+ procedure CopyToClipBoard; virtual;
+ procedure CutToClipBoard; virtual;
+ procedure DeleteChildren(Node: PVirtualNode; ResetHasChildren: Boolean = False);
+ procedure DeleteNode(Node: PVirtualNode; Reindex: Boolean = True);
+ procedure DeleteSelectedNodes; virtual;
+ function Dragging: Boolean;
+ function EditNode(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual;
+ function EndEditNode: Boolean;
+ procedure EndSynch;
+ procedure EndUpdate;
+ function ExecuteAction(Action: TBasicAction): Boolean; override;
+ procedure FinishCutOrCopy;
+ procedure FlushClipboard;
+ procedure FullCollapse(Node: PVirtualNode = nil); virtual;
+ procedure FullExpand(Node: PVirtualNode = nil); virtual;
+ function GetControlsAlignment: TAlignment; override;
+ function GetDisplayRect(Node: PVirtualNode; Column: TColumnIndex; TextOnly: Boolean; Unclipped: Boolean = False): TRect;
+ function GetFirst: PVirtualNode;
+ function GetFirstChild(Node: PVirtualNode): PVirtualNode;
+ function GetFirstCutCopy: PVirtualNode;
+ function GetFirstInitialized: PVirtualNode;
+ function GetFirstNoInit: PVirtualNode;
+ function GetFirstSelected: PVirtualNode;
+ function GetFirstVisible: PVirtualNode;
+ function GetFirstVisibleChild(Node: PVirtualNode): PVirtualNode;
+ function GetFirstVisibleChildNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetFirstVisibleNoInit: PVirtualNode;
+ procedure GetHitTestInfoAt(X, Y: Integer; Relative: Boolean; var HitInfo: THitInfo);
+ function GetLast(Node: PVirtualNode = nil): PVirtualNode;
+ function GetLastInitialized(Node: PVirtualNode = nil): PVirtualNode;
+ function GetLastNoInit(Node: PVirtualNode = nil): PVirtualNode;
+ function GetLastChild(Node: PVirtualNode): PVirtualNode;
+ function GetLastChildNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetLastVisible(Node: PVirtualNode = nil): PVirtualNode;
+ function GetLastVisibleChild(Node: PVirtualNode): PVirtualNode;
+ function GetLastVisibleChildNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetLastVisibleNoInit(Node: PVirtualNode = nil): PVirtualNode;
+ function GetMaxColumnWidth(Column: TColumnIndex): Integer;
+ function GetNext(Node: PVirtualNode): PVirtualNode;
+ function GetNextCutCopy(Node: PVirtualNode): PVirtualNode;
+ function GetNextInitialized(Node: PVirtualNode): PVirtualNode;
+ function GetNextNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetNextSelected(Node: PVirtualNode): PVirtualNode;
+ function GetNextSibling(Node: PVirtualNode): PVirtualNode;
+ function GetNextVisible(Node: PVirtualNode): PVirtualNode;
+ function GetNextVisibleNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetNextVisibleSibling(Node: PVirtualNode): PVirtualNode;
+ function GetNextVisibleSiblingNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetNodeAt(X, Y: Integer): PVirtualNode; overload;
+ function GetNodeAt(X, Y: Integer; Relative: Boolean; var NodeTop: Integer): PVirtualNode; overload;
+ function GetNodeData(Node: PVirtualNode): Pointer;
+ function GetNodeLevel(Node: PVirtualNode): Cardinal;
+ function GetPrevious(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousInitialized(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousSibling(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousVisible(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousVisibleNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousVisibleSibling(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousVisibleSiblingNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetSortedCutCopySet(Resolve: Boolean): TNodeArray;
+ function GetSortedSelection(Resolve: Boolean): TNodeArray;
+ function GetTreeRect: TRect;
+ function GetVisibleParent(Node: PVirtualNode): PVirtualNode;
+ function HasAsParent(Node, PotentialParent: PVirtualNode): Boolean;
+ function InsertNode(Node: PVirtualNode; Mode: TVTNodeAttachMode; UserData: Pointer = nil): PVirtualNode;
+ procedure InvalidateChildren(Node: PVirtualNode; Recursive: Boolean);
+ procedure InvalidateColumn(Column: TColumnIndex);
+ function InvalidateNode(Node: PVirtualNode): TRect; virtual;
+ procedure InvalidateToBottom(Node: PVirtualNode);
+ procedure InvertSelection(VisibleOnly: Boolean);
+ function IsEditing: Boolean;
+ function IsMouseSelecting: Boolean;
+ function IterateSubtree(Node: PVirtualNode; Callback: TVTGetNodeProc; Data: Pointer; Filter: TVirtualNodeStates = [];
+ DoInit: Boolean = False; ChildNodesOnly: Boolean = False): PVirtualNode;
+ procedure LoadFromFile(const FileName: TFileName); virtual;
+ procedure LoadFromStream(Stream: TStream); virtual;
+ procedure MoveTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; ChildrenOnly: Boolean); overload;
+ procedure MoveTo(Node: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean); overload;
+ procedure PaintTree(TargetCanvas: TCanvas; Window: TRect; Target: TPoint; PaintOptions: TVTInternalPaintOptions);
+ function PasteFromClipboard: Boolean; virtual;
+ procedure PrepareDragImage(HotSpot: TPoint; const DataObject: IDataObject);
+ procedure Print(Printer: TPrinter; PrintHeader: Boolean);
+ function ProcessDrop(DataObject: IDataObject; TargetNode: PVirtualNode; var Effect: Integer; Mode:
+ TVTNodeAttachMode): Boolean;
+ function ProcessOLEData(Source: TBaseVirtualTree; DataObject: IDataObject; TargetNode: PVirtualNode;
+ Mode: TVTNodeAttachMode; Optimized: Boolean): Boolean;
+ procedure RepaintNode(Node: PVirtualNode);
+ procedure ReinitChildren(Node: PVirtualNode; Recursive: Boolean); virtual;
+ procedure ReinitNode(Node: PVirtualNode; Recursive: Boolean); virtual;
+ procedure ResetNode(Node: PVirtualNode); virtual;
+ procedure SaveToFile(const FileName: TFileName);
+ procedure SaveToStream(Stream: TStream; Node: PVirtualNode = nil); virtual;
+ function ScrollIntoView(Node: PVirtualNode; Center: Boolean; Horizontally: Boolean = False): Boolean;
+ procedure SelectAll(VisibleOnly: Boolean);
+ procedure Sort(Node: PVirtualNode; Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True); virtual;
+ procedure SortTree(Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True);
+ procedure ToggleNode(Node: PVirtualNode);
+ function UpdateAction(Action: TBasicAction): Boolean; override;
+ procedure UpdateHorizontalScrollBar(DoRepaint: Boolean);
+ procedure UpdateScrollBars(DoRepaint: Boolean); virtual;
+ procedure UpdateVerticalScrollBar(DoRepaint: Boolean);
+ function UseRightToLeftReading: Boolean;
+ procedure ValidateChildren(Node: PVirtualNode; Recursive: Boolean);
+ procedure ValidateNode(Node: PVirtualNode; Recursive: Boolean);
+
+ property CheckState[Node: PVirtualNode]: TCheckState read GetCheckState write SetCheckState;
+ property CheckType[Node: PVirtualNode]: TCheckType read GetCheckType write SetCheckType;
+ property ChildCount[Node: PVirtualNode]: Cardinal read GetChildCount write SetChildCount;
+ property ChildrenInitialized[Node: PVirtualNode]: Boolean read GetChildrenInitialized;
+ property DragImage: TVTDragImage read FDragImage;
+ property DragManager: IVTDragManager read GetDragManager;
+ property DropTargetNode: PVirtualNode read FDropTargetNode;
+ property EditLink: IVTEditLink read FEditLink;
+ property Expanded[Node: PVirtualNode]: Boolean read GetExpanded write SetExpanded;
+ property FocusedColumn: TColumnIndex read FFocusedColumn write SetFocusedColumn default InvalidColumn;
+ property FocusedNode: PVirtualNode read FFocusedNode write SetFocusedNode;
+ property Font;
+ property FullyVisible[Node: PVirtualNode]: Boolean read GetFullyVisible write SetFullyVisible;
+ property HasChildren[Node: PVirtualNode]: Boolean read GetHasChildren write SetHasChildren;
+ property HotNode: PVirtualNode read FCurrentHotNode;
+ property IsDisabled[Node: PVirtualNode]: Boolean read GetDisabled write SetDisabled;
+ property IsVisible[Node: PVirtualNode]: Boolean read GetVisible write SetVisible;
+ property MultiLine[Node: PVirtualNode]: Boolean read GetMultiline write SetMultiline;
+ property NodeHeight[Node: PVirtualNode]: Cardinal read GetNodeHeight write SetNodeHeight;
+ property NodeParent[Node: PVirtualNode]: PVirtualNode read GetNodeParent write SetNodeParent;
+ property OffsetX: Integer read FOffsetX write SetOffsetX;
+ property OffsetXY: TPoint read GetOffsetXY write SetOffsetXY;
+ property OffsetY: Integer read FOffsetY write SetOffsetY;
+ property RootNode: PVirtualNode read FRoot;
+ property SearchBuffer: WideString read FSearchBuffer;
+ property Selected[Node: PVirtualNode]: Boolean read GetSelected write SetSelected;
+ property TotalCount: Cardinal read GetTotalCount;
+ property TreeStates: TVirtualTreeStates read FStates write FStates;
+ property SelectedCount: Integer read FSelectionCount;
+ property TopNode: PVirtualNode read GetTopNode write SetTopNode;
+ property VerticalAlignment[Node: PVirtualNode]: Byte read GetVerticalAlignment write SetVerticalAlignment;
+ property VisibleCount: Cardinal read FVisibleCount;
+ property VisiblePath[Node: PVirtualNode]: Boolean read GetVisiblePath write SetVisiblePath;
+ end;
+
+
+ // --------- TCustomVirtualStringTree
+
+ // Options regarding strings (useful only for the string tree and descentants):
+ TVTStringOption = (
+ toSaveCaptions, // If set then the caption is automatically saved with the tree node, regardless of what is
+ // saved in the user data.
+ toShowStaticText, // Show static text in a caption which can be differently formatted than the caption
+ // but cannot be edited.
+ toAutoAcceptEditChange // Automatically accept changes during edit if the user finishes editing other then
+ // VK_RETURN or ESC. If not set then changes are cancelled.
+ );
+ TVTStringOptions = set of TVTStringOption;
+
+const
+ DefaultStringOptions = [toSaveCaptions, toAutoAcceptEditChange];
+
+type
+ TCustomStringTreeOptions = class(TCustomVirtualTreeOptions)
+ private
+ FStringOptions: TVTStringOptions;
+ procedure SetStringOptions(const Value: TVTStringOptions);
+ protected
+ property StringOptions: TVTStringOptions read FStringOptions write SetStringOptions default DefaultStringOptions;
+ public
+ constructor Create(AOwner: TBaseVirtualTree); override;
+
+ procedure AssignTo(Dest: TPersistent); override;
+ end;
+
+ TStringTreeOptions = class(TCustomStringTreeOptions)
+ published
+ property AnimationOptions;
+ property AutoOptions;
+ property MiscOptions;
+ property PaintOptions;
+ property SelectionOptions;
+ property StringOptions;
+ end;
+
+ TCustomVirtualStringTree = class;
+
+ // Edit support classes.
+ TStringEditLink = class;
+
+ {$ifdef TntSupport}
+ TVTEdit = class(TTntEdit)
+ {$else}
+ TVTEdit = class(TCustomEdit)
+ {$endif TntSupport}
+ private
+ FLink: TStringEditLink;
+ procedure CMAutoAdjust(var Message: TMessage); message CM_AUTOADJUST;
+ procedure CMExit(var Message: TMessage); message CM_EXIT;
+ procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
+ procedure WMChar(var Message: TWMChar); message WM_CHAR;
+ procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
+ procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
+ procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
+ protected
+ procedure AutoAdjustSize;
+ procedure CreateParams(var Params: TCreateParams); override;
+ public
+ constructor Create(Link: TStringEditLink); reintroduce;
+
+ property AutoSelect;
+ property AutoSize;
+ property BorderStyle;
+ property CharCase;
+ property HideSelection;
+ property MaxLength;
+ property OEMConvert;
+ property PasswordChar;
+ end;
+
+ TStringEditLink = class(TInterfacedObject, IVTEditLink)
+ private
+ FEdit: TVTEdit; // A normal custom edit control.
+ FTree: TCustomVirtualStringTree; // A back reference to the tree calling.
+ FNode: PVirtualNode; // The node to be edited.
+ FColumn: TColumnIndex; // The column of the node.
+ FAlignment: TAlignment;
+ FTextBounds: TRect; // Smallest rectangle around the text.
+ FStopping: Boolean; // Set to True when the edit link requests stopping the edit action.
+ procedure SetEdit(const Value: TVTEdit);
+ protected
+ property Edit: TVTEdit read FEdit write SetEdit;
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ function BeginEdit: Boolean; virtual; stdcall;
+ function CancelEdit: Boolean; virtual; stdcall;
+ function EndEdit: Boolean; virtual; stdcall;
+ function GetBounds: TRect; virtual; stdcall;
+ function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; stdcall;
+ procedure ProcessMessage(var Message: TMessage); virtual; stdcall;
+ procedure SetBounds(R: TRect); virtual; stdcall;
+ end;
+
+ // Describes the type of text to return in the text and draw info retrival events.
+ TVSTTextType = (
+ ttNormal, // normal label of the node, this is also the text which can be edited
+ ttStatic // static (non-editable) text after the normal text
+ );
+
+ // Describes the source to use when converting a string tree into a string for clipboard etc.
+ TVSTTextSourceType = (
+ tstAll, // All nodes are rendered. Initialization is done on the fly.
+ tstInitialized, // Only initialized nodes are rendered.
+ tstSelected, // Only selected nodes are rendered.
+ tstCutCopySet, // Only nodes currently marked as being in the cut/copy clipboard set are rendered.
+ tstVisible // Only visible nodes are rendered.
+ );
+
+ TVTPaintText = procedure(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType) of object;
+ TVSTGetTextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var CellText: WideString) of object;
+ // New text can only be set for variable caption.
+ TVSTNewTextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ NewText: WideString) of object;
+ TVSTShortenStringEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; const S: WideString; TextSpace: Integer; RightToLeft: Boolean; var Result: WideString;
+ var Done: Boolean) of object;
+
+ TCustomVirtualStringTree = class(TBaseVirtualTree)
+ private
+ FDefaultText: WideString; // text to show if there's no OnGetText event handler (e.g. at design time)
+ FTextHeight: Integer; // true size of the font
+ FEllipsisWidth: Integer; // width of '...' for the current font
+ FInternalDataOffset: Cardinal; // offset to the internal data of the string tree
+
+ FOnPaintText: TVTPaintText; // triggered before either normal or fixed text is painted to allow
+ // even finer customization (kind of sub cell painting)
+ FOnGetText, // used to retrieve the string to be displayed for a specific node
+ FOnGetHint: TVSTGetTextEvent; // used to retrieve the hint to be displayed for a specific node
+ FOnNewText: TVSTNewTextEvent; // used to notify the application about an edited node caption
+ FOnShortenString: TVSTShortenStringEvent; // used to allow the application a customized string shortage
+
+ procedure GetRenderStartValues(Source: TVSTTextSourceType; var Node: PVirtualNode;
+ var NextNodeProc: TGetNextNodeProc);
+ function GetOptions: TCustomStringTreeOptions;
+ function GetText(Node: PVirtualNode; Column: TColumnIndex): WideString;
+ procedure InitializeTextProperties(const Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex);
+ procedure PaintNormalText(var PaintInfo: TVTPaintInfo; TextOutFlags: Integer; Text: WideString);
+ procedure PaintStaticText(const PaintInfo: TVTPaintInfo; TextOutFlags: Integer; const Text: WideString);
+ procedure ReadText(Reader: TReader);
+ procedure SetDefaultText(const Value: WideString);
+ procedure SetOptions(const Value: TCustomStringTreeOptions);
+ procedure SetText(Node: PVirtualNode; Column: TColumnIndex; const Value: WideString);
+ procedure WriteText(Writer: TWriter);
+
+ procedure WMSetFont(var Msg: TWMSetFont); message WM_SETFONT;
+ protected
+ procedure AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex); override;
+ function CalculateTextWidth(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; Text: WideString): Integer; virtual;
+ function ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean; override;
+ procedure DefineProperties(Filer: TFiler); override;
+ function DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; override;
+ function DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex): WideString; override;
+ function DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex): WideString; override;
+ function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer; override;
+ procedure DoGetText(Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString); virtual;
+ function DoIncrementalSearch(Node: PVirtualNode; const Text: WideString): Integer; override;
+ procedure DoNewText(Node: PVirtualNode; Column: TColumnIndex; Text: WideString); virtual;
+ procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
+ procedure DoPaintText(Node: PVirtualNode; const Canvas: TCanvas; Column: TColumnIndex;
+ TextType: TVSTTextType); virtual;
+ function DoShortenString(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const S: WideString; Width: Integer;
+ RightToLeft: Boolean; EllipsisWidth: Integer = 0): WideString; virtual;
+ function GetOptionsClass: TTreeOptionsClass; override;
+ procedure GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect;
+ var Text: WideString); override;
+ function InternalData(Node: PVirtualNode): Pointer;
+ procedure MainColumnChanged; override;
+ function ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType,
+ ChunkSize: Integer): Boolean; override;
+ procedure ReadOldStringOptions(Reader: TReader);
+ function RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HResult; override;
+ procedure WriteChunks(Stream: TStream; Node: PVirtualNode); override;
+
+ property DefaultText: WideString read FDefaultText write SetDefaultText stored False;
+ property EllipsisWidth: Integer read FEllipsisWidth;
+ property TreeOptions: TCustomStringTreeOptions read GetOptions write SetOptions;
+
+ property OnGetHint: TVSTGettextEvent read FOnGetHint write FOnGetHint;
+ property OnGetText: TVSTGetTextEvent read FOnGetText write FOnGetText;
+ property OnNewText: TVSTNewTextEvent read FOnNewText write FOnNewText;
+ property OnPaintText: TVTPaintText read FOnPaintText write FOnPaintText;
+ property OnShortenString: TVSTShortenStringEvent read FOnShortenString write FOnShortenString;
+ public
+ constructor Create(AOwner: TComponent); override;
+
+ function ContentToClipboard(Format: Word; Source: TVSTTextSourceType): HGLOBAL;
+ function ContentToHTML(Source: TVSTTextSourceType; Caption: WideString = ''): string;
+ function ContentToRTF(Source: TVSTTextSourceType): string;
+ function ContentToText(Source: TVSTTextSourceType; Separator: Char): string;
+ function ContentToUnicode(Source: TVSTTextSourceType; Separator: WideChar): WideString;
+ function InvalidateNode(Node: PVirtualNode): TRect; override;
+ function Path(Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; Delimiter: WideChar): WideString;
+ procedure ReinitNode(Node: PVirtualNode; Recursive: Boolean); override;
+
+ property Text[Node: PVirtualNode; Column: TColumnIndex]: WideString read GetText write SetText;
+ end;
+
+ TVirtualStringTree = class(TCustomVirtualStringTree)
+ private
+ function GetOptions: TStringTreeOptions;
+ procedure SetOptions(const Value: TStringTreeOptions);
+ protected
+ function GetOptionsClass: TTreeOptionsClass; override;
+ public
+ property Canvas;
+ published
+ property Action;
+ property Align;
+ property Alignment;
+ property Anchors;
+ property AnimationDuration;
+ property AutoExpandDelay;
+ property AutoScrollDelay;
+ property AutoScrollInterval;
+ property Background;
+ property BackgroundOffsetX;
+ property BackgroundOffsetY;
+ property BiDiMode;
+ property BevelEdges;
+ property BevelInner;
+ property BevelOuter;
+ property BevelKind;
+ property BevelWidth;
+ property BorderStyle;
+ property ButtonFillMode;
+ property ButtonStyle;
+ property BorderWidth;
+ property ChangeDelay;
+ property CheckImageKind;
+ property ClipboardFormats;
+ property Color;
+ property Colors;
+ property Constraints;
+ property Ctl3D;
+ property CustomCheckImages;
+ property DefaultNodeHeight;
+ property DefaultPasteMode;
+ property DefaultText;
+ property DragCursor;
+ property DragHeight;
+ property DragKind;
+ property DragImageKind;
+ property DragMode;
+ property DragOperations;
+ property DragType;
+ property DragWidth;
+ property DrawSelectionMode;
+ property EditDelay;
+ property Enabled;
+ property Font;
+ property Header;
+ property HintAnimation;
+ property HintMode;
+ property HotCursor;
+ property Images;
+ property IncrementalSearch;
+ property IncrementalSearchDirection;
+ property IncrementalSearchStart;
+ property IncrementalSearchTimeout;
+ property Indent;
+ property LineMode;
+ property LineStyle;
+ property Margin;
+ property NodeAlignment;
+ property NodeDataSize;
+ property ParentBiDiMode;
+ property ParentColor default False;
+ property ParentCtl3D;
+ property ParentFont;
+ property ParentShowHint;
+ property PopupMenu;
+ property RootNodeCount;
+ property ScrollBarOptions;
+ property SelectionBlendFactor;
+ property SelectionCurveRadius;
+ property ShowHint;
+ property StateImages;
+ property TabOrder;
+ property TabStop default True;
+ property TextMargin;
+ property TreeOptions: TStringTreeOptions read GetOptions write SetOptions;
+ property Visible;
+ property WantTabs;
+
+ property OnAdvancedHeaderDraw;
+ property OnAfterCellPaint;
+ property OnAfterItemErase;
+ property OnAfterItemPaint;
+ property OnAfterPaint;
+ property OnBeforeCellPaint;
+ property OnBeforeItemErase;
+ property OnBeforeItemPaint;
+ property OnBeforePaint;
+ property OnChange;
+ property OnChecked;
+ property OnChecking;
+ property OnClick;
+ property OnCollapsed;
+ property OnCollapsing;
+ property OnColumnClick;
+ property OnColumnDblClick;
+ property OnColumnResize;
+ property OnCompareNodes;
+ {$ifdef COMPILER_5_UP}
+ property OnContextPopup;
+ {$endif COMPILER_5_UP}
+ property OnCreateDataObject;
+ property OnCreateDragManager;
+ property OnCreateEditor;
+ property OnDblClick;
+ property OnDragAllowed;
+ property OnDragOver;
+ property OnDragDrop;
+ property OnEditCancelled;
+ property OnEdited;
+ property OnEditing;
+ property OnEndDock;
+ property OnEndDrag;
+ property OnEnter;
+ property OnExit;
+ property OnExpanded;
+ property OnExpanding;
+ property OnFocusChanged;
+ property OnFocusChanging;
+ property OnFreeNode;
+ property OnGetCursor;
+ property OnGetHeaderCursor;
+ property OnGetText;
+ property OnPaintText;
+ property OnGetHelpContext;
+ property OnGetImageIndex;
+ property OnGetHint;
+ property OnGetLineStyle;
+ property OnGetNodeDataSize;
+ property OnGetPopupMenu;
+ property OnGetUserClipboardFormats;
+ property OnHeaderClick;
+ property OnHeaderDblClick;
+ property OnHeaderDragged;
+ property OnHeaderDraggedOut;
+ property OnHeaderDragging;
+ property OnHeaderDraw;
+ property OnHeaderDrawQueryElements;
+ property OnHeaderMouseDown;
+ property OnHeaderMouseMove;
+ property OnHeaderMouseUp;
+ property OnHotChange;
+ property OnIncrementalSearch;
+ property OnInitChildren;
+ property OnInitNode;
+ property OnKeyAction;
+ property OnKeyDown;
+ property OnKeyPress;
+ property OnKeyUp;
+ property OnLoadNode;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnNewText;
+ property OnNodeCopied;
+ property OnNodeCopying;
+ property OnNodeMoved;
+ property OnNodeMoving;
+ property OnPaintBackground;
+ property OnRenderOLEData;
+ property OnResetNode;
+ property OnResize;
+ property OnSaveNode;
+ property OnScroll;
+ property OnShortenString;
+ property OnStartDock;
+ property OnStartDrag;
+ property OnStateChange;
+ property OnStructureChange;
+ property OnUpdating;
+ end;
+
+ TVTDrawHintEvent = procedure(Sender: TBaseVirtualTree; HintCanvas: TCanvas; Node: PVirtualNode; R: TRect;
+ Column: TColumnIndex) of object;
+ TVTDrawNodeEvent = procedure(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo) of object;
+ TVTGetNodeWidthEvent = procedure(Sender: TBaseVirtualTree; HintCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; var NodeWidth: Integer) of object;
+ TVTGetHintSizeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var R: TRect) of object;
+
+ // Tree descendant to let an application draw its stuff itself.
+ TCustomVirtualDrawTree = class(TBaseVirtualTree)
+ private
+ FOnDrawNode: TVTDrawNodeEvent;
+ FOnGetNodeWidth: TVTGetNodeWidthEvent;
+ FOnGetHintSize: TVTGetHintSizeEvent;
+ FOnDrawHint: TVTDrawHintEvent;
+ protected
+ procedure DoDrawHint(Canvas: TCanvas; Node: PVirtualNode; R: TRect; Column: TColumnIndex);
+ procedure DoGetHintSize(Node: PVirtualNode; Column: TColumnIndex; var R: TRect); virtual;
+ function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer; override;
+ procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
+
+ property OnDrawHint: TVTDrawHintEvent read FOnDrawHint write FOnDrawHint;
+ property OnDrawNode: TVTDrawNodeEvent read FOnDrawNode write FOnDrawNode;
+ property OnGetHintSize: TVTGetHintSizeEvent read FOnGetHintSize write FOnGetHintSize;
+ property OnGetNodeWidth: TVTGetNodeWidthEvent read FOnGetNodeWidth write FOnGetNodeWidth;
+ end;
+
+ TVirtualDrawTree = class(TCustomVirtualDrawTree)
+ private
+ function GetOptions: TVirtualTreeOptions;
+ procedure SetOptions(const Value: TVirtualTreeOptions);
+ protected
+ function GetOptionsClass: TTreeOptionsClass; override;
+ public
+ property Canvas;
+ published
+ property Action;
+ property Align;
+ property Alignment;
+ property Anchors;
+ property AnimationDuration;
+ property AutoExpandDelay;
+ property AutoScrollDelay;
+ property AutoScrollInterval;
+ property Background;
+ property BackgroundOffsetX;
+ property BackgroundOffsetY;
+ property BiDiMode;
+ property BevelEdges;
+ property BevelInner;
+ property BevelOuter;
+ property BevelKind;
+ property BevelWidth;
+ property BorderStyle;
+ property ButtonFillMode;
+ property ButtonStyle;
+ property BorderWidth;
+ property ChangeDelay;
+ property CheckImageKind;
+ property ClipboardFormats;
+ property Color;
+ property Colors;
+ property Constraints;
+ property Ctl3D;
+ property CustomCheckImages;
+ property DefaultNodeHeight;
+ property DefaultPasteMode;
+ property DragCursor;
+ property DragHeight;
+ property DragKind;
+ property DragImageKind;
+ property DragMode;
+ property DragOperations;
+ property DragType;
+ property DragWidth;
+ property DrawSelectionMode;
+ property EditDelay;
+ property Enabled;
+ property Font;
+ property Header;
+ property HintAnimation;
+ property HintMode;
+ property HotCursor;
+ property Images;
+ property IncrementalSearch;
+ property IncrementalSearchDirection;
+ property IncrementalSearchStart;
+ property IncrementalSearchTimeout;
+ property Indent;
+ property LineMode;
+ property LineStyle;
+ property Margin;
+ property NodeAlignment;
+ property NodeDataSize;
+ property ParentBiDiMode;
+ property ParentColor default False;
+ property ParentCtl3D;
+ property ParentFont;
+ property ParentShowHint;
+ property PopupMenu;
+ property RootNodeCount;
+ property ScrollBarOptions;
+ property SelectionBlendFactor;
+ property SelectionCurveRadius;
+ property ShowHint;
+ property StateImages;
+ property TabOrder;
+ property TabStop default True;
+ property TextMargin;
+ property TreeOptions: TVirtualTreeOptions read GetOptions write SetOptions;
+ property Visible;
+ property WantTabs;
+
+ property OnAfterCellPaint;
+ property OnAfterItemErase;
+ property OnAfterItemPaint;
+ property OnAfterPaint;
+ property OnBeforeCellPaint;
+ property OnBeforeItemErase;
+ property OnBeforeItemPaint;
+ property OnBeforePaint;
+ property OnChange;
+ property OnChecked;
+ property OnChecking;
+ property OnClick;
+ property OnCollapsed;
+ property OnCollapsing;
+ property OnColumnClick;
+ property OnColumnDblClick;
+ property OnColumnResize;
+ property OnCompareNodes;
+ {$ifdef COMPILER_5_UP}
+ property OnContextPopup;
+ {$endif COMPILER_5_UP}
+ property OnCreateDataObject;
+ property OnCreateDragManager;
+ property OnCreateEditor;
+ property OnDblClick;
+ property OnDragAllowed;
+ property OnDragOver;
+ property OnDragDrop;
+ property OnDrawHint;
+ property OnDrawNode;
+ property OnEdited;
+ property OnEditing;
+ property OnEndDock;
+ property OnEndDrag;
+ property OnEnter;
+ property OnExit;
+ property OnExpanded;
+ property OnExpanding;
+ property OnFocusChanged;
+ property OnFocusChanging;
+ property OnFreeNode;
+ property OnGetCursor;
+ property OnGetHeaderCursor;
+ property OnGetHelpContext;
+ property OnGetHintSize;
+ property OnGetImageIndex;
+ property OnGetLineStyle;
+ property OnGetNodeDataSize;
+ property OnGetNodeWidth;
+ property OnGetPopupMenu;
+ property OnGetUserClipboardFormats;
+ property OnHeaderClick;
+ property OnHeaderDblClick;
+ property OnHeaderDragged;
+ property OnHeaderDraggedOut;
+ property OnHeaderDragging;
+ property OnHeaderDraw;
+ property OnHeaderMouseDown;
+ property OnHeaderMouseMove;
+ property OnHeaderMouseUp;
+ property OnHotChange;
+ property OnIncrementalSearch;
+ property OnInitChildren;
+ property OnInitNode;
+ property OnKeyAction;
+ property OnKeyDown;
+ property OnKeyPress;
+ property OnKeyUp;
+ property OnLoadNode;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnNodeCopied;
+ property OnNodeCopying;
+ property OnNodeMoved;
+ property OnNodeMoving;
+ property OnPaintBackground;
+ property OnRenderOLEData;
+ property OnResetNode;
+ property OnResize;
+ property OnSaveNode;
+ property OnScroll;
+ property OnStartDock;
+ property OnStateChange;
+ property OnStructureChange;
+ property OnUpdating;
+ end;
+
+type
+ // Describes the mode how to blend pixels.
+ TBlendMode = (
+ bmConstantAlpha, // apply given constant alpha
+ bmPerPixelAlpha, // use alpha value of the source pixel
+ bmMasterAlpha, // use alpha value of source pixel and multiply it with the constant alpha value
+ bmConstantAlphaAndColor // blend the destination color with the given constant color und the constant alpha value
+ );
+
+// OLE Clipboard and drag'n drop helper
+procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; const List: TStrings); overload;
+procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray); overload;
+function GetVTClipboardFormatDescription(AFormat: Word): string;
+procedure RegisterVTClipboardFormat(AFormat: Word; TreeClass: TVirtualTreeClass; Priority: Cardinal); overload;
+function RegisterVTClipboardFormat(Description: string; TreeClass: TVirtualTreeClass; Priority: Cardinal;
+ tymed: Integer = TYMED_HGLOBAL; ptd: PDVTargetDevice = nil; dwAspect: Integer = DVASPECT_CONTENT;
+ lindex: Integer = -1): Word; overload;
+
+// utility routines
+procedure AlphaBlend(Source, Destination: HDC; R: TRect; Target: TPoint; Mode: TBlendMode; ConstantAlpha, Bias: Integer);
+procedure DrawTextW(DC: HDC; lpString: PWideChar; nCount: Integer; var lpRect: TRect; uFormat: Cardinal;
+ AdjustRight: Boolean);
+function ShortenString(DC: HDC; const S: WideString; Width: Integer; RTL: Boolean;
+ EllipsisWidth: Integer = 0): WideString;
+function TreeFromNode(Node: PVirtualNode): TBaseVirtualTree;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+{$R VirtualTrees.res}
+
+uses
+ Consts, Math,
+ AxCtrls, // TOLEStream
+ CommCtrl, // image list stuff
+ {$ifdef UseFlatScrollbars}
+ FlatSB, // wrapper for systems without flat SB support
+ {$endif UseFlatScrollbars}
+ MMSystem, // for animation timer (does not include further resources)
+ TypInfo, // for migration stuff
+ ActnList,
+ StdActns; // for standard action support
+
+resourcestring
+ // Localizable strings.
+ SEditLinkIsNil = 'Edit link must not be nil.';
+ SWrongMoveError = 'Target node cannot be a child node of the node to be moved.';
+ SWrongStreamFormat = 'Unable to load tree structure, the format is wrong.';
+ SWrongStreamVersion = 'Unable to load tree structure, the version is unknown.';
+ SStreamTooSmall = 'Unable to load tree structure, not enough data available.';
+ SCorruptStream1 = 'Stream data corrupt. A node''s anchor chunk is missing.';
+ SCorruptStream2 = 'Stream data corrupt. Unexpected data after node''s end position.';
+ SClipboardFailed = 'Clipboard operation failed.';
+ SCannotSetUserData = 'Cannot set initial user data because there is not enough user data space allocated.';
+
+const
+ ClipboardStates = [tsCopyPending, tsCutPending];
+ DefaultScrollUpdateFlags = [suoRepaintHeader, suoRepaintScrollbars, suoScrollClientArea, suoUpdateNCArea];
+ MinimumTimerInterval = 1; // minimum resolution for timeGetTime
+ TreeNodeSize = (SizeOf(TVirtualNode) + 3) and not 3; // used for node allocation and access to internal data
+
+ // Lookup to quickly convert a specific check state into its pressed counterpart and vice versa.
+ PressedState: array[TCheckState] of TCheckState = (
+ csUncheckedPressed, csUncheckedPressed, csCheckedPressed, csCheckedPressed, csMixedPressed, csMixedPressed
+ );
+ UnpressedState: array[TCheckState] of TCheckState = (
+ csUncheckedNormal, csUncheckedNormal, csCheckedNormal, csCheckedNormal, csMixedNormal, csMixedNormal
+ );
+ MouseButtonDown = [tsLeftButtonDown, tsMiddleButtonDown, tsRightButtonDown];
+
+ // Do not modify the copyright in any way! Usage of this unit is prohibited without the copyright notice
+ // in the compiled binary file.
+ Copyright: string = 'Virtual Treeview © 1999, 2003 Mike Lischke';
+
+var
+ StandardOLEFormat: TFormatEtc = (
+ // Format must later be set.
+ cfFormat: 0;
+ // No specific target device to render on.
+ ptd: nil;
+ // Normal content to render.
+ dwAspect: DVASPECT_CONTENT;
+ // No specific page of multipage data (we don't use multipage data by default).
+ lindex: -1;
+ // Acceptable storage formats are IStream and global memory. The first is preferred.
+ tymed: TYMED_ISTREAM or TYMED_HGLOBAL;
+ );
+
+
+type // streaming support
+ TMagicID = array[0..5] of WideChar;
+
+ TChunkHeader = record
+ ChunkType,
+ ChunkSize: Integer; // contains the size of the chunk excluding the header
+ end;
+
+ // base information about a node
+ TBaseChunkBody = packed record
+ ChildCount,
+ NodeHeight: Cardinal;
+ States: TVirtualNodeStates;
+ Align: Byte;
+ CheckState: TCheckState;
+ CheckType: TCheckType;
+ Reserved: Cardinal;
+ end;
+
+ TBaseChunk = packed record
+ Header: TChunkHeader;
+ Body: TBaseChunkBody;
+ end;
+
+ // Internally used data for animations.
+ TToggleAnimationData = record
+ Expand: Boolean; // if true then expanding is in progress
+ Window: HWND; // copy of the tree's window handle
+ DC: HDC; // the DC of the window to erase unconvered parts
+ Brush: HBRUSH; // the brush to be used to erase uncovered parts
+ R: TRect; // the scroll rectangle
+ end;
+
+const
+ MagicID: TMagicID = (#$2045, 'V', 'T', WideChar(VTTreeStreamVersion), ' ', #$2046);
+
+ // chunk IDs
+ NodeChunk = 1;
+ BaseChunk = 2; // chunk containing node state, check state, child node count etc.
+ // this chunk is immediately followed by all child nodes
+ CaptionChunk = 3; // used by the string tree to store a node's caption
+ UserChunk = 4; // used for data supplied by the application
+
+ {$ifdef UseFlatScrollbars}
+ ScrollBarProp: array[TScrollBarStyle] of Integer = (
+ FSB_REGULAR_MODE,
+ FSB_FLAT_MODE,
+ FSB_ENCARTA_MODE
+ );
+ {$endif}
+
+ RTLFlag: array[Boolean] of Integer = (0, ETO_RTLREADING);
+ AlignmentToDrawFlag: array[TAlignment] of Cardinal = (DT_LEFT, DT_RIGHT, DT_CENTER);
+
+ WideNull = WideChar(#0);
+ WideCR = WideChar(#13);
+ WideLF = WideChar(#10);
+ WideLineSeparator = WideChar(#2028);
+
+type
+ // internal worker thread
+ TWorkerThread = class(TThread)
+ private
+ FCurrentTree: TBaseVirtualTree;
+ FWaiterList: TThreadList;
+ FRefCount: Cardinal;
+ protected
+ procedure ChangeTreeStates(EnterStates, LeaveStates: TChangeStates);
+ procedure Execute; override;
+ public
+ constructor Create(CreateSuspended: Boolean);
+ destructor Destroy; override;
+
+ procedure AddTree(Tree: TBaseVirtualTree);
+ procedure RemoveTree(Tree: TBaseVirtualTree);
+ end;
+
+ // Helper classes to speed up rendering text formats for clipboard and drag'n drop transfers.
+ TBufferedString = class
+ private
+ FStart,
+ FPosition,
+ FEnd: PChar;
+ function GetAsString: string;
+ public
+ destructor Destroy; override;
+
+ procedure Add(const S: string);
+ procedure AddNewLine;
+
+ property AsString: string read GetAsString;
+ end;
+
+ TWideBufferedString = class
+ private
+ FStart,
+ FPosition,
+ FEnd: PWideChar;
+ function GetAsString: WideString;
+ public
+ destructor Destroy; override;
+
+ procedure Add(const S: WideString);
+ procedure AddNewLine;
+
+ property AsString: WideString read GetAsString;
+ end;
+
+var
+ WorkerThread: TWorkerThread;
+ WorkEvent: THandle;
+ Watcher: TCriticalSection;
+ LightCheckImages, // global light check images
+ DarkCheckImages, // global heavy check images
+ LightTickImages, // global light tick images
+ DarkTickImages, // global heavy check images
+ FlatImages, // global flat check images
+ XPImages, // global XP style check images
+ UtilityImages, // some small additional images (e.g for header dragging)
+ SystemCheckImages, // global system check images
+ SystemFlatCheckImages: TImageList; // global flat system check images
+ IsWinNT: Boolean; // Necessary to fix bugs in Win95/WinME (non-client area region intersection, edit resize)
+ // and to allow for check of system dependent hint animation.
+ IsWin2K: Boolean; // Nessary to provide correct string shortage
+ IsWinXP: Boolean;
+ Initialized: Boolean; // True if global structures have been initialized.
+ NeedToUnitialize: Boolean; // True if the OLE subsystem could be initialized successfully.
+
+ {$ifndef COMPILER_5_UP}
+ HintFont: TFont; // In Delphi 4 there is no TScreen.HintFont yet.
+ {$endif COMPILER_5_UP}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+{$ifndef COMPILER_6_UP}
+
+ procedure RaiseLastOSError;
+
+ begin
+ RaiseLastWin32Error;
+ end;
+
+{$endif COMPILER_6_UP}
+
+//----------------- TClipboardFormats ----------------------------------------------------------------------------------
+
+type
+ PClipboardFormatListEntry = ^TClipboardFormatListEntry;
+ TClipboardFormatListEntry = record
+ Description: string; // The string used to register the format with Windows.
+ TreeClass: TVirtualTreeClass; // The tree class which supports rendering this format.
+ Priority: Cardinal; // Number which determines the order of formats used in IDataObject.
+ FormatEtc: TFormatEtc; // The definition of the format in the IDataObject.
+ end;
+
+ TClipboardFormatList = class
+ private
+ FList: TList;
+ procedure Sort;
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ procedure Add(FormatString: string; AClass: TVirtualTreeClass; Priority: Cardinal; AFormatEtc: TFormatEtc);
+ procedure Clear;
+ procedure EnumerateFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray;
+ const AllowedFormats: TClipboardFormats = nil); overload;
+ procedure EnumerateFormats(TreeClass: TVirtualTreeClass; const Formats: TStrings); overload;
+ function FindFormat(FormatString: string): PClipboardFormatListEntry; overload;
+ function FindFormat(FormatString: string; var Fmt: Word): TVirtualTreeClass; overload;
+ function FindFormat(Fmt: Word; var Description: string): TVirtualTreeClass; overload;
+ end;
+
+var
+ InternalClipboardFormats: TClipboardFormatList;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+constructor TClipboardFormatList.Create;
+
+begin
+ FList := TList.Create;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TClipboardFormatList.Destroy;
+
+begin
+ Clear;
+ FList.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.Sort;
+
+// Sorts all entry for priority (increasing priority value).
+
+ //--------------- local function --------------------------------------------
+
+ procedure QuickSort(L, R: Integer);
+
+ var
+ I, J: Integer;
+ P, T: PClipboardFormatListEntry;
+
+ begin
+ repeat
+ I := L;
+ J := R;
+ P := FList[(L + R) shr 1];
+ repeat
+ while PClipboardFormatListEntry(FList[I]).Priority < P.Priority do
+ Inc(I);
+ while PClipboardFormatListEntry(Flist[J]).Priority > P.Priority do
+ Dec(J);
+ if I <= J then
+ begin
+ T := Flist[I];
+ FList[I] := FList[J];
+ FList[J] := T;
+ Inc(I);
+ Dec(J);
+ end;
+ until I > J;
+ if L < J then
+ QuickSort(L, J);
+ L := I;
+ until I >= R;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+begin
+ if FList.Count > 1 then
+ QuickSort(0, FList.Count - 1);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.Add(FormatString: string; AClass: TVirtualTreeClass; Priority: Cardinal;
+ AFormatEtc: TFormatEtc);
+
+// Adds the given data to the internal list. The priority value is used to sort formats for importance. Larger priority
+// values mean less priority.
+
+var
+ Entry: PClipboardFormatListEntry;
+
+begin
+ New(Entry);
+ Entry.Description := FormatString;
+ Entry.TreeClass := AClass;
+ Entry.Priority := Priority;
+ Entry.FormatEtc := AFormatEtc;
+ FList.Add(Entry);
+
+ Sort;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.Clear;
+
+var
+ I: Integer;
+
+begin
+ for I := 0 to FList.Count - 1 do
+ Dispose(PClipboardFormatListEntry(FList[I]));
+ FList.Clear;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.EnumerateFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray;
+ const AllowedFormats: TClipboardFormats = nil);
+
+// Returns a list of format records for the given class. If assigned the AllowedFormats is used to limit the
+// enumerated formats to those described in the list.
+
+var
+ I, Count: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ SetLength(Formats, FList.Count);
+ Count := 0;
+ for I := 0 to FList.Count - 1 do
+ begin
+ Entry := FList[I];
+ // Does the tree class support this clipboard format?
+ if TreeClass.InheritsFrom(Entry.TreeClass) then
+ begin
+ // Is this format allowed to be included?
+ if (AllowedFormats = nil) or (AllowedFormats.IndexOf(Entry.Description) > -1) then
+ begin
+ // The list could change before we use the FormatEtc so it is best not to pass a pointer to the true FormatEtc
+ // structure. Instead make a copy and send that.
+ Formats[Count] := Entry.FormatEtc;
+ Inc(Count);
+ end;
+ end;
+ end;
+ SetLength(Formats, Count);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.EnumerateFormats(TreeClass: TVirtualTreeClass; const Formats: TStrings);
+
+// Returns a list of format descriptions for the given class.
+
+var
+ I: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ for I := 0 to FList.Count - 1 do
+ begin
+ Entry := FList[I];
+ if TreeClass.InheritsFrom(Entry.TreeClass) then
+ Formats.Add(Entry.Description);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardFormatList.FindFormat(FormatString: string): PClipboardFormatListEntry;
+
+var
+ I: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ Result := nil;
+ for I := FList.Count - 1 downto 0 do
+ begin
+ Entry := FList[I];
+ if CompareText(Entry.Description, FormatString) = 0 then
+ begin
+ Result := Entry;
+ Break;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardFormatList.FindFormat(FormatString: string; var Fmt: Word): TVirtualTreeClass;
+
+var
+ I: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ Result := nil;
+ for I := FList.Count - 1 downto 0 do
+ begin
+ Entry := FList[I];
+ if CompareText(Entry.Description, FormatString) = 0 then
+ begin
+ Result := Entry.TreeClass;
+ Fmt := Entry.FormatEtc.cfFormat;
+ Break;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardFormatList.FindFormat(Fmt: Word; var Description: string): TVirtualTreeClass;
+
+var
+ I: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ Result := nil;
+ for I := FList.Count - 1 downto 0 do
+ begin
+ Entry := FList[I];
+ if Entry.FormatEtc.cfFormat = Fmt then
+ begin
+ Result := Entry.TreeClass;
+ Description := Entry.Description;
+ Break;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ TClipboardFormatEntry = record
+ ID: Word;
+ Description: string;
+ end;
+
+var
+ ClipboardDescriptions: array [1..CF_MAX - 1] of TClipboardFormatEntry = (
+ (ID: CF_TEXT; Description: 'Plain text'),
+ (ID: CF_BITMAP; Description: 'Windows bitmap'),
+ (ID: CF_METAFILEPICT; Description: 'Windows metafile'),
+ (ID: CF_SYLK; Description: 'Symbolic link'),
+ (ID: CF_DIF; Description: 'Data interchange format'),
+ (ID: CF_TIFF; Description: 'Tiff image'),
+ (ID: CF_OEMTEXT; Description: 'OEM text'),
+ (ID: CF_DIB; Description: 'DIB image'),
+ (ID: CF_PALETTE; Description: 'Palette data'),
+ (ID: CF_PENDATA; Description: 'Pen data'),
+ (ID: CF_RIFF; Description: 'Riff audio data'),
+ (ID: CF_WAVE; Description: 'Wav audio data'),
+ (ID: CF_UNICODETEXT; Description: 'Unicode text'),
+ (ID: CF_ENHMETAFILE; Description: 'Enhanced metafile image'),
+ (ID: CF_HDROP; Description: 'File name(s)'),
+ (ID: CF_LOCALE; Description: 'Locale descriptor')
+ );
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; const List: TStrings);
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+ InternalClipboardFormats.EnumerateFormats(TreeClass, List);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray);
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+ InternalClipboardFormats.EnumerateFormats(TreeClass, Formats);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function GetVTClipboardFormatDescription(AFormat: Word): string;
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+ if InternalClipboardFormats.FindFormat(AFormat, Result) = nil then
+ Result := '';
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure RegisterVTClipboardFormat(AFormat: Word; TreeClass: TVirtualTreeClass; Priority: Cardinal);
+
+// Registers the given clipboard format for the given TreeClass.
+
+var
+ I: Integer;
+ Buffer: array[0..2048] of Char;
+ FormatEtc: TFormatEtc;
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+
+ // Assumes a HGlobal format.
+ FormatEtc.cfFormat := AFormat;
+ FormatEtc.ptd := nil;
+ FormatEtc.dwAspect := DVASPECT_CONTENT;
+ FormatEtc.lindex := -1;
+ FormatEtc.tymed := TYMED_HGLOBAL;
+
+ // Determine description string of the given format. For predefined formats we need the lookup table because they
+ // don't have a description string. For registered formats the description string is the string which was used
+ // to register them.
+ if AFormat < CF_MAX then
+ begin
+ for I := 1 to High(ClipboardDescriptions) do
+ if ClipboardDescriptions[I].ID = AFormat then
+ begin
+ InternalClipboardFormats.Add(ClipboardDescriptions[I].Description, TreeClass, Priority, FormatEtc);
+ Break;
+ end;
+ end
+ else
+ begin
+ GetClipboardFormatName(AFormat, Buffer, Length(Buffer));
+ InternalClipboardFormats.Add(Buffer, TreeClass, Priority, FormatEtc);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function RegisterVTClipboardFormat(Description: string; TreeClass: TVirtualTreeClass; Priority: Cardinal;
+ tymed: Integer = TYMED_HGLOBAL; ptd: PDVTargetDevice = nil; dwAspect: Integer = DVASPECT_CONTENT;
+ lindex: Integer = -1): Word;
+
+// Alternative method to register a certain clipboard format for a given tree class. Registration with the
+// clipboard is done here too and the assigned ID returned by the function.
+// tymed may contain or'ed TYMED constants which allows to register several storage formats for one clipboard format.
+
+var
+ FormatEtc: TFormatEtc;
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+ Result := RegisterClipboardFormat(PChar(Description));
+ FormatEtc.cfFormat := Result;
+ FormatEtc.ptd := ptd;
+ FormatEtc.dwAspect := dwAspect;
+ FormatEtc.lindex := lindex;
+ FormatEtc.tymed := tymed;
+ InternalClipboardFormats.Add(Description, TreeClass, Priority, FormatEtc);
+end;
+
+//----------------- utility functions ----------------------------------------------------------------------------------
+
+procedure ShowError(Msg: WideString; HelpContext: Integer);
+
+begin
+ raise EVirtualTreeError.CreateHelp(Msg, HelpContext);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TreeFromNode(Node: PVirtualNode): TBaseVirtualTree;
+
+// Returns the tree the node currently belongs to or nil if the node is not attached to a tree.
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+
+ // The root node is marked by having its NextSibling (and PrevSibling) pointing to itself.
+ while Assigned(Node) and (Node.NextSibling <> Node) do
+ Node := Node.Parent;
+ if Assigned(Node) then
+ Result := TBaseVirtualTree(Node.Parent)
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function OrderRect(const R: TRect): TRect;
+
+// Converts the incoming rectangle so that left and top are always less than or equal to right and bottom.
+
+begin
+ if R.Left < R.Right then
+ begin
+ Result.Left := R.Left;
+ Result.Right := R.Right;
+ end
+ else
+ begin
+ Result.Left := R.Right;
+ Result.Right := R.Left;
+ end;
+ if R.Top < R.Bottom then
+ begin
+ Result.Top := R.Top;
+ Result.Bottom := R.Bottom;
+ end
+ else
+ begin
+ Result.Top := R.Bottom;
+ Result.Bottom := R.Top;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure QuickSort(const TheArray: TNodeArray; L, R: Integer);
+
+var
+ I, J: Integer;
+ P, T: Pointer;
+
+begin
+ repeat
+ I := L;
+ J := R;
+ P := TheArray[(L + R) shr 1];
+ repeat
+ while Cardinal(TheArray[I]) < Cardinal(P) do
+ Inc(I);
+ while Cardinal(TheArray[J]) > Cardinal(P) do
+ Dec(J);
+ if I <= J then
+ begin
+ T := TheArray[I];
+ TheArray[I] := TheArray[J];
+ TheArray[J] := T;
+ Inc(I);
+ Dec(J);
+ end;
+ until I > J;
+ if L < J then
+ QuickSort(TheArray, L, J);
+ L := I;
+ until I >= R;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure DrawTextW(DC: HDC; lpString: PWideChar; nCount: Integer; var lpRect: TRect; uFormat: Cardinal;
+ AdjustRight: Boolean);
+
+// This procedure implements a subset of Window's DrawText API for Unicode which is not available for
+// Windows 9x. For a description of the parameters see DrawText in the online help.
+// Supported flags are currently:
+// - DT_LEFT
+// - DT_TOP
+// - DT_CALCRECT
+// - DT_NOCLIP
+// - DT_RTLREADING
+// - DT_SINGLELINE
+// - DT_VCENTER
+// Differences to the DrawTextW Windows API:
+// - The additional parameter AdjustRight determines whether to adjust the right border of the given rectangle to
+// accomodate the largest line in the text. It has only a meaning if also DT_CALCRECT is specified.
+
+var
+ Head, Tail: PWideChar;
+ Size: TSize;
+ MaxWidth: Integer;
+ TextOutFlags: Integer;
+ TextAlign,
+ OldTextAlign: Cardinal;
+ TM: TTextMetric;
+ TextHeight: Integer;
+ LineRect: TRect;
+ TextPosY,
+ TextPosX: Integer;
+
+ CalculateRect: Boolean;
+
+begin
+ // Prepare some work variables.
+ MaxWidth := 0;
+ Head := lpString;
+ GetTextMetrics(DC, TM);
+ TextHeight := TM.tmHeight;
+ if uFormat and DT_SINGLELINE <> 0 then
+ LineRect := lpRect
+ else
+ LineRect := Rect(lpRect.Left, lpRect.Top, lpRect.Right, lpRect.Top + TextHeight);
+
+ CalculateRect := uFormat and DT_CALCRECT <> 0;
+
+ // Prepare text output.
+ TextOutFlags := 0;
+ if uFormat and DT_NOCLIP = 0 then
+ TextOutFlags := TextOutFlags or ETO_CLIPPED;
+ if uFormat and DT_RTLREADING <> 0 then
+ TextOutFlags := TextOutFlags or ETO_RTLREADING;
+
+ // Determine horizontal and vertical text alignment.
+ OldTextAlign := GetTextAlign(DC);
+ TextAlign := TA_LEFT or TA_TOP;
+ TextPosX := lpRect.Left;
+ if uFormat and DT_RIGHT <> 0 then
+ begin
+ TextAlign := TextAlign or TA_RIGHT and not TA_LEFT;
+ TextPosX := lpRect.Right;
+ end
+ else
+ if uFormat and DT_CENTER <> 0 then
+ begin
+ TextAlign := TextAlign or TA_CENTER and not TA_LEFT;
+ TextPosX := (lpRect.Left + lpRect.Right) div 2;
+ end;
+
+ TextPosY := lpRect.Top;
+ if uFormat and DT_VCENTER <> 0 then
+ begin
+ // Note: vertical alignment does only work with single line text ouput!
+ TextPosY := (lpRect.Top + lpRect.Bottom - TextHeight) div 2;
+ end;
+ SetTextAlign(DC, TextAlign);
+
+ if uFormat and DT_SINGLELINE <> 0 then
+ begin
+ if CalculateRect then
+ begin
+ GetTextExtentPoint32W(DC, Head, nCount, Size);
+ if Size.cx > MaxWidth then
+ MaxWidth := Size.cx;
+ end
+ else
+ ExtTextOutW(DC, TextPosX, TextPosY, TextOutFlags, @LineRect, Head, nCount, nil);
+ OffsetRect(LineRect, 0, TextHeight);
+ end
+ else
+ begin
+ while (nCount > 0) and (Head^ <> WideNull) do
+ begin
+ Tail := Head;
+ // Look for the end of the current line. A line is finished either by the string end or a line break.
+ while (nCount > 0) and not (Tail^ in [WideNull, WideCR, WideLF]) and (Tail^ <> WideLineSeparator) do
+ begin
+ Inc(Tail);
+ Dec(nCount);
+ end;
+
+ if CalculateRect then
+ begin
+ GetTextExtentPoint32W(DC, Head, Tail - Head, Size);
+ if Size.cx > MaxWidth then
+ MaxWidth := Size.cx;
+ end
+ else
+ ExtTextOutW(DC, TextPosX, LineRect.Top, TextOutFlags, @LineRect, Head, Tail - Head, nil);
+ OffsetRect(LineRect, 0, TextHeight);
+
+ // Get out of the loop if the rectangle is filled up.
+ if (nCount = 0) or (not CalculateRect and (LineRect.Top >= lpRect.Bottom)) then
+ Break;
+
+ if (nCount > 0) and (Tail^ = WideCR) or (Tail^ = WideLineSeparator) then
+ begin
+ Inc(Tail);
+ Dec(nCount);
+ end;
+
+ if (nCount > 0) and (Tail^ = WideLF) then
+ begin
+ Inc(Tail);
+ Dec(nCount);
+ end;
+ Head := Tail;
+ end;
+ end;
+
+ SetTextAlign(DC, OldTextAlign);
+ if CalculateRect then
+ begin
+ if AdjustRight then
+ lpRect.Right := lpRect.Left + MaxWidth;
+ lpRect.Bottom := LineRect.Top;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function ShortenString(DC: HDC; const S: WideString; Width: Integer; RTL: Boolean;
+ EllipsisWidth: Integer = 0): WideString;
+
+// Adjusts the given string S so that it fits into the given width. EllipsisWidth gives the width of
+// the three points to be added to the shorted string. If this value is 0 then it will be determined implicitely.
+// For higher speed (and multiple entries to be shorted) specify this value explicitely.
+// RTL determines if right-to-left reading is active, which is needed to put the ellipsisis on the correct side.
+// Note: It is assumed that the string really needs shortage. Check this in advance.
+
+var
+ Size: TSize;
+ Len: Integer;
+ L, H, N, W: Integer;
+
+begin
+ Len := Length(S);
+ if (Len = 0) or (Width <= 0) then
+ Result := ''
+ else
+ begin
+ // Determine width of triple point using the current DC settings (if not already done).
+ if EllipsisWidth = 0 then
+ begin
+ GetTextExtentPoint32W(DC, '...', 3, Size);
+ EllipsisWidth := Size.cx;
+ end;
+
+ if Width <= EllipsisWidth then
+ Result := ''
+ else
+ begin
+ // Do a binary search for the optimal string length which fits into the given width.
+ L := 0;
+ H := Len;
+ while L < H do
+ begin
+ N := (L + H + 1) shr 1;
+ GetTextExtentPoint32W(DC, PWideChar(S), N, Size);
+ W := Size.cx + EllipsisWidth;
+ if W <= Width then
+ L := N
+ else
+ H := N - 1;
+ end;
+
+ // Windows 2000/XP automatically switches the order in the string. For every other system we have to take care.
+ if IsWin2K or IsWinXP or not RTL then
+ Result := Copy(S, 1, L) + '...'
+ else
+ Result := '...' + Copy(S, 1, L);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure FillDragRectangles(DragWidth, DragHeight, DeltaX, DeltaY: Integer; var RClip, RScroll, RSamp1, RSamp2, RDraw1,
+ RDraw2: TRect);
+
+// Fills the given rectangles with values which can be used while dragging around an image
+// (used in DragMove of the drag manager and DragTo of the header columns).
+
+begin
+ // ScrollDC limits
+ RClip := Rect(0, 0, DragWidth, DragHeight);
+ if DeltaX > 0 then
+ begin
+ // move to the left
+ if DeltaY = 0 then
+ begin
+ // move only to the left
+ // background movement
+ RScroll := Rect(0, 0, DragWidth - DeltaX, DragHeight);
+ RSamp1 := Rect(0, 0, DeltaX, DragHeight);
+ RDraw1 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight);
+ end
+ else
+ if DeltaY < 0 then
+ begin
+ // move to bottom left
+ RScroll := Rect(0, -DeltaY, DragWidth - DeltaX, DragHeight);
+ RSamp1 := Rect(0, 0, DeltaX, DragHeight);
+ RSamp2 := Rect(DeltaX, DragHeight + DeltaY, DragWidth - DeltaX, -DeltaY);
+ RDraw1 := Rect(0, 0, DragWidth - DeltaX, -DeltaY);
+ RDraw2 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight);
+ end
+ else
+ begin
+ // move to upper left
+ RScroll := Rect(0, 0, DragWidth - DeltaX, DragHeight - DeltaY);
+ RSamp1 := Rect(0, 0, DeltaX, DragHeight);
+ RSamp2 := Rect(DeltaX, 0, DragWidth - DeltaX, DeltaY);
+ RDraw1 := Rect(0, DragHeight - DeltaY, DragWidth - DeltaX, DeltaY);
+ RDraw2 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight);
+ end;
+ end
+ else
+ if DeltaX = 0 then
+ begin
+ // vertical movement only
+ if DeltaY < 0 then
+ begin
+ // move downwards
+ RScroll := Rect(0, -DeltaY, DragWidth, DragHeight);
+ RSamp2 := Rect(0, DragHeight + DeltaY, DragWidth, -DeltaY);
+ RDraw2 := Rect(0, 0, DragWidth, -DeltaY);
+ end
+ else
+ begin
+ // move upwards
+ RScroll := Rect(0, 0, DragWidth, DragHeight - DeltaY);
+ RSamp2 := Rect(0, 0, DragWidth, DeltaY);
+ RDraw2 := Rect(0, DragHeight - DeltaY, DragWidth, DeltaY);
+ end;
+ end
+ else
+ begin
+ // move to the right
+ if DeltaY > 0 then
+ begin
+ // move up right
+ RScroll := Rect(-DeltaX, 0, DragWidth, DragHeight);
+ RSamp1 := Rect(0, 0, DragWidth + DeltaX, DeltaY);
+ RSamp2 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight);
+ RDraw1 := Rect(0, 0, -DeltaX, DragHeight);
+ RDraw2 := Rect(-DeltaX, DragHeight - DeltaY, DragWidth + DeltaX, DeltaY);
+ end
+ else
+ if DeltaY = 0 then
+ begin
+ // to the right only
+ RScroll := Rect(-DeltaX, 0, DragWidth, DragHeight);
+ RSamp1 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight);
+ RDraw1 := Rect(0, 0, -DeltaX, DragHeight);
+ end
+ else
+ begin
+ // move down right
+ RScroll := Rect(-DeltaX, -DeltaY, DragWidth, DragHeight);
+ RSamp1 := Rect(0, DragHeight + DeltaY, DragWidth + DeltaX, -DeltaY);
+ RSamp2 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight);
+ RDraw1 := Rect(0, 0, -DeltaX, DragHeight);
+ RDraw2 := Rect(-DeltaX, 0, DragWidth + DeltaX, -DeltaY);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlendLineConstant(Source, Destination: Pointer; Count: Integer; ConstantAlpha, Bias: Integer);
+
+// Blends a line of Count pixels from Source to Destination using a constant alpha value.
+// The layout of a pixel must be BGRA where A is ignored (but is calculated as the other components).
+// ConstantAlpha must be in the range 0..255 where 0 means totally transparent (destination pixel only)
+// and 255 totally opaque (source pixel only).
+// Bias is an additional value which gets added to every component and must be in the range -128..127
+//
+// EAX contains Source
+// EDX contains Destination
+// ECX contains Count
+// ConstantAlpha and Bias are on the stack
+
+asm
+ PUSH ESI // save used registers
+ PUSH EDI
+
+ MOV ESI, EAX // ESI becomes the actual source pointer
+ MOV EDI, EDX // EDI becomes the actual target pointer
+
+ // Load MM6 with the constant alpha value (replicate it for every component).
+ // Expand it to word size.
+ MOV EAX, [ConstantAlpha]
+ DB $0F, $6E, $F0 /// MOVD MM6, EAX
+ DB $0F, $61, $F6 /// PUNPCKLWD MM6, MM6
+ DB $0F, $62, $F6 /// PUNPCKLDQ MM6, MM6
+
+ // Load MM5 with the bias value.
+ MOV EAX, [Bias]
+ DB $0F, $6E, $E8 /// MOVD MM5, EAX
+ DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
+ DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
+
+ // Load MM4 with 128 to allow for saturated biasing.
+ MOV EAX, 128
+ DB $0F, $6E, $E0 /// MOVD MM4, EAX
+ DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
+ DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
+
+ at 1: // The pixel loop calculates an entire pixel in one run.
+ // Note: The pixel byte values are expanded into the higher bytes of a word due
+ // to the way unpacking works. We compensate for this with an extra shift.
+ DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
+ DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
+ DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
+ DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
+ DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
+ DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
+
+ // calculation is: target = (alpha * (source - target) + 256 * target) / 256
+ DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
+ DB $0F, $D5, $C6 /// PMULLW MM0, MM6, alpha * (source - target)
+ DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
+
+ // Bias is accounted for by conversion of range 0..255 to -128..127,
+ // doing a saturated add and convert back to 0..255.
+ DB $0F, $F9, $C4 /// PSUBW MM0, MM4
+ DB $0F, $ED, $C5 /// PADDSW MM0, MM5
+ DB $0F, $FD, $C4 /// PADDW MM0, MM4
+ DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
+ DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
+ at 3:
+ ADD ESI, 4
+ ADD EDI, 4
+ DEC ECX
+ JNZ @1
+ POP EDI
+ POP ESI
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlendLinePerPixel(Source, Destination: Pointer; Count, Bias: Integer);
+
+// Blends a line of Count pixels from Source to Destination using the alpha value of the source pixels.
+// The layout of a pixel must be BGRA.
+// Bias is an additional value which gets added to every component and must be in the range -128..127
+//
+// EAX contains Source
+// EDX contains Destination
+// ECX contains Count
+// Bias is on the stack
+
+asm
+ PUSH ESI // save used registers
+ PUSH EDI
+
+ MOV ESI, EAX // ESI becomes the actual source pointer
+ MOV EDI, EDX // EDI becomes the actual target pointer
+
+ // Load MM5 with the bias value.
+ MOV EAX, [Bias]
+ DB $0F, $6E, $E8 /// MOVD MM5, EAX
+ DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
+ DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
+
+ // Load MM4 with 128 to allow for saturated biasing.
+ MOV EAX, 128
+ DB $0F, $6E, $E0 /// MOVD MM4, EAX
+ DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
+ DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
+
+ at 1: // The pixel loop calculates an entire pixel in one run.
+ // Note: The pixel byte values are expanded into the higher bytes of a word due
+ // to the way unpacking works. We compensate for this with an extra shift.
+ DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
+ DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
+ DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
+ DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
+ DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
+ DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
+
+ // Load MM6 with the source alpha value (replicate it for every component).
+ // Expand it to word size.
+ DB $0F, $6F, $F0 /// MOVQ MM6, MM0
+ DB $0F, $69, $F6 /// PUNPCKHWD MM6, MM6
+ DB $0F, $6A, $F6 /// PUNPCKHDQ MM6, MM6
+
+ // calculation is: target = (alpha * (source - target) + 256 * target) / 256
+ DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
+ DB $0F, $D5, $C6 /// PMULLW MM0, MM6, alpha * (source - target)
+ DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
+
+ // Bias is accounted for by conversion of range 0..255 to -128..127,
+ // doing a saturated add and convert back to 0..255.
+ DB $0F, $F9, $C4 /// PSUBW MM0, MM4
+ DB $0F, $ED, $C5 /// PADDSW MM0, MM5
+ DB $0F, $FD, $C4 /// PADDW MM0, MM4
+ DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
+ DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
+ at 3:
+ ADD ESI, 4
+ ADD EDI, 4
+ DEC ECX
+ JNZ @1
+ POP EDI
+ POP ESI
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlendLineMaster(Source, Destination: Pointer; Count: Integer; ConstantAlpha, Bias: Integer);
+
+// Blends a line of Count pixels from Source to Destination using the source pixel and a constant alpha value.
+// The layout of a pixel must be BGRA.
+// ConstantAlpha must be in the range 0..255.
+// Bias is an additional value which gets added to every component and must be in the range -128..127
+//
+// EAX contains Source
+// EDX contains Destination
+// ECX contains Count
+// ConstantAlpha and Bias are on the stack
+
+asm
+ PUSH ESI // save used registers
+ PUSH EDI
+
+ MOV ESI, EAX // ESI becomes the actual source pointer
+ MOV EDI, EDX // EDI becomes the actual target pointer
+
+ // Load MM6 with the constant alpha value (replicate it for every component).
+ // Expand it to word size.
+ MOV EAX, [ConstantAlpha]
+ DB $0F, $6E, $F0 /// MOVD MM6, EAX
+ DB $0F, $61, $F6 /// PUNPCKLWD MM6, MM6
+ DB $0F, $62, $F6 /// PUNPCKLDQ MM6, MM6
+
+ // Load MM5 with the bias value.
+ MOV EAX, [Bias]
+ DB $0F, $6E, $E8 /// MOVD MM5, EAX
+ DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
+ DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
+
+ // Load MM4 with 128 to allow for saturated biasing.
+ MOV EAX, 128
+ DB $0F, $6E, $E0 /// MOVD MM4, EAX
+ DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
+ DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
+
+ at 1: // The pixel loop calculates an entire pixel in one run.
+ // Note: The pixel byte values are expanded into the higher bytes of a word due
+ // to the way unpacking works. We compensate for this with an extra shift.
+ DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
+ DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
+ DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
+ DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
+ DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
+ DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
+
+ // Load MM7 with the source alpha value (replicate it for every component).
+ // Expand it to word size.
+ DB $0F, $6F, $F8 /// MOVQ MM7, MM0
+ DB $0F, $69, $FF /// PUNPCKHWD MM7, MM7
+ DB $0F, $6A, $FF /// PUNPCKHDQ MM7, MM7
+ DB $0F, $D5, $FE /// PMULLW MM7, MM6, source alpha * master alpha
+ DB $0F, $71, $D7, $08 /// PSRLW MM7, 8, divide by 256
+
+ // calculation is: target = (alpha * master alpha * (source - target) + 256 * target) / 256
+ DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
+ DB $0F, $D5, $C7 /// PMULLW MM0, MM7, alpha * (source - target)
+ DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
+
+ // Bias is accounted for by conversion of range 0..255 to -128..127,
+ // doing a saturated add and convert back to 0..255.
+ DB $0F, $F9, $C4 /// PSUBW MM0, MM4
+ DB $0F, $ED, $C5 /// PADDSW MM0, MM5
+ DB $0F, $FD, $C4 /// PADDW MM0, MM4
+ DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
+ DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
+ at 3:
+ ADD ESI, 4
+ ADD EDI, 4
+ DEC ECX
+ JNZ @1
+ POP EDI
+ POP ESI
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlendLineMasterAndColor(Destination: Pointer; Count: Integer; ConstantAlpha, Color: Integer);
+
+// Blends a line of Count pixels in Destination against the given color using a constant alpha value.
+// The layout of a pixel must be BGRA and Color must be rrggbb00 (as stored by a COLORREF).
+// ConstantAlpha must be in the range 0..255.
+//
+// EAX contains Destination
+// EDX contains Count
+// ECX contains ConstantAlpha
+// Color is passed on the stack
+
+asm
+ // The used formula is: target = (alpha * color + (256 - alpha) * target) / 256.
+ // alpha * color (factor 1) and 256 - alpha (factor 2) are constant values which can be calculated in advance.
+ // The remaining calculation is therefore: target = (F1 + F2 * target) / 256
+
+ // Load MM3 with the constant alpha value (replicate it for every component).
+ // Expand it to word size. (Every calculation here works on word sized operands.)
+ DB $0F, $6E, $D9 /// MOVD MM3, ECX
+ DB $0F, $61, $DB /// PUNPCKLWD MM3, MM3
+ DB $0F, $62, $DB /// PUNPCKLDQ MM3, MM3
+
+ // Calculate factor 2.
+ MOV ECX, $100
+ DB $0F, $6E, $D1 /// MOVD MM2, ECX
+ DB $0F, $61, $D2 /// PUNPCKLWD MM2, MM2
+ DB $0F, $62, $D2 /// PUNPCKLDQ MM2, MM2
+ DB $0F, $F9, $D3 /// PSUBW MM2, MM3 // MM2 contains now: 255 - alpha = F2
+
+ // Now calculate factor 1. Alpha is still in MM3, but the r and b components of Color must be swapped.
+ MOV ECX, [Color]
+ BSWAP ECX
+ ROR ECX, 8
+ DB $0F, $6E, $C9 /// MOVD MM1, ECX // Load the color and convert to word sized values.
+ DB $0F, $EF, $E4 /// PXOR MM4, MM4
+ DB $0F, $60, $CC /// PUNPCKLBW MM1, MM4
+ DB $0F, $D5, $CB /// PMULLW MM1, MM3 // MM1 contains now: color * alpha = F1
+
+ at 1: // The pixel loop calculates an entire pixel in one run.
+ DB $0F, $6E, $00 /// MOVD MM0, [EAX]
+ DB $0F, $60, $C4 /// PUNPCKLBW MM0, MM4
+
+ DB $0F, $D5, $C2 /// PMULLW MM0, MM2 // calculate F1 + F2 * target
+ DB $0F, $FD, $C1 /// PADDW MM0, MM1
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8 // divide by 256
+
+ DB $0F, $67, $C0 /// PACKUSWB MM0, MM0 // convert words to bytes with saturation
+ DB $0F, $7E, $00 /// MOVD [EAX], MM0 // store the result
+
+ ADD EAX, 4
+ DEC EDX
+ JNZ @1
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure EMMS;
+
+// Reset MMX state to use the FPU for other tasks again.
+
+asm
+ DB $0F, $77 /// EMMS
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function GetBitmapBitsFromDeviceContext(DC: HDC; var Width, Height: Integer): Pointer;
+
+// Helper function used to retrieve the bitmap selected into the given device context. If there is a bitmap then
+// the function will return a pointer to its bits otherwise nil is returned.
+// Additionally the dimensions of the bitmap are returned.
+
+var
+ Bitmap: HBITMAP;
+ DIB: TDIBSection;
+
+begin
+ Result := nil;
+ Width := 0;
+ Height := 0;
+
+ Bitmap := GetCurrentObject(DC, OBJ_BITMAP);
+ if Bitmap <> 0 then
+ begin
+ if GetObject(Bitmap, SizeOf(DIB), @DIB) = SizeOf(DIB) then
+ begin
+ Assert(DIB.dsBm.bmPlanes * DIB.dsBm.bmBitsPixel = 32, 'Alpha blending error: bitmap must use 32 bpp.');
+ Result := DIB.dsBm.bmBits;
+ Width := DIB.dsBmih.biWidth;
+ Height := DIB.dsBmih.biHeight;
+ end;
+ end;
+ Assert(Result <> nil, 'Alpha blending DC error: no bitmap available.');
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function CalculateScanline(Bits: Pointer; Width, Height, Row: Integer): Pointer;
+
+// Helper function to calculate the start address for the given row.
+
+begin
+ if Height > 0 then // bottom-up DIB
+ Row := Height - Row - 1;
+ // Return DWORD aligned address of the requested scanline.
+ Integer(Result) := Integer(Bits) + Row * ((Width * 32 + 31) and not 31) div 8;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlend(Source, Destination: HDC; R: TRect; Target: TPoint; Mode: TBlendMode; ConstantAlpha, Bias: Integer);
+
+// Optimized alpha blend procedure using MMX instructions to perform as quick as possible.
+// For this procedure to work properly it is important that both source and target bitmap use the 32 bit color format.
+// R describes the source rectangle to work on.
+// Target is the place (upper left corner) in the target bitmap where to blend to. Note that source width + X offset
+// must be less or equal to the target width. Similar for the height.
+// If Mode is bmConstantAlpha then the blend operation uses the given ConstantAlpha value for all pixels.
+// If Mode is bmPerPixelAlpha then each pixel is blended using its individual alpha value (the alpha value of the source).
+// If Mode is bmMasterAlpha then each pixel is blended using its individual alpha value multiplied by ConstantAlpha.
+// If Mode is bmConstantAlphaAndColor then each destination pixel is blended using ConstantAlpha but also a constant
+// color which will be obtained from Bias. In this case no offset value is added, otherwise Bias is used as offset.
+// Blending of a color into target only (bmConstantAlphaAndColor) ignores Source (the DC) and Target (the position).
+// CAUTION: This procedure does not check whether MMX instructions are actually available! Call it only if MMX is really
+// usable.
+
+var
+ Y: Integer;
+ SourceRun,
+ TargetRun: PByte;
+
+ SourceBits,
+ DestBits: Pointer;
+ SourceWidth,
+ SourceHeight,
+ DestWidth,
+ DestHeight: Integer;
+
+begin
+ if not IsRectEmpty(R) then
+ begin
+ // Note: it is tempting to optimize the special cases for constant alpha 0 and 255 by just ignoring soure
+ // (alpha = 0) or simply do a blit (alpha = 255). But this does not take the bias into account.
+ case Mode of
+ bmConstantAlpha:
+ begin
+ // Get a pointer to the bitmap bits for the source and target device contexts.
+ // Note: this supposes that both contexts do actually have bitmaps assigned!
+ SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
+ DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
+ if Assigned(SourceBits) and Assigned(DestBits) then
+ begin
+ for Y := 0 to R.Bottom - R.Top - 1 do
+ begin
+ SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
+ Inc(SourceRun, 4 * R.Left);
+ TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
+ Inc(TargetRun, 4 * Target.X);
+ AlphaBlendLineConstant(SourceRun, TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
+ end;
+ end;
+ EMMS;
+ end;
+ bmPerPixelAlpha:
+ begin
+ SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
+ DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
+ if Assigned(SourceBits) and Assigned(DestBits) then
+ begin
+ for Y := 0 to R.Bottom - R.Top - 1 do
+ begin
+ SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
+ Inc(SourceRun, 4 * R.Left);
+ TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
+ Inc(TargetRun, 4 * Target.X);
+ AlphaBlendLinePerPixel(SourceRun, TargetRun, R.Right - R.Left, Bias);
+ end;
+ end;
+ EMMS;
+ end;
+ bmMasterAlpha:
+ begin
+ SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
+ DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
+ if Assigned(SourceBits) and Assigned(DestBits) then
+ begin
+ for Y := 0 to R.Bottom - R.Top - 1 do
+ begin
+ SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
+ Inc(SourceRun, 4 * Target.X);
+ TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
+ AlphaBlendLineMaster(SourceRun, TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
+ end;
+ end;
+ EMMS;
+ end;
+ bmConstantAlphaAndColor:
+ begin
+ // Source is ignored since there is a constant color value.
+ DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
+ if Assigned(DestBits) then
+ begin
+ for Y := 0 to R.Bottom - R.Top - 1 do
+ begin
+ TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + R.Top);
+ Inc(TargetRun, 4 * R.Left);
+ AlphaBlendLineMasterAndColor(TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
+ end;
+ end;
+ EMMS;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function GetRGBColor(Value: TColor): DWORD;
+
+// Little helper to convert a Delphi color to an image list color.
+
+begin
+ Result := ColorToRGB(Value);
+ case Result of
+ clNone:
+ Result := CLR_NONE;
+ clDefault:
+ Result := CLR_DEFAULT;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+const
+ Grays: array[0..3] of TColor = (clWhite, clSilver, clGray, clBlack);
+ SysGrays: array[0..3] of TColor = (clWindow, clBtnFace, clBtnShadow, clBtnText);
+
+procedure ConvertImageList(IL: TImageList; const ImageName: string; ColorRemapping: Boolean = True);
+
+// Loads a bunch of images given by ImageName into IL. If ColorRemapping = True then a mapping of gray values to
+// system colors is performed.
+
+var
+ Images,
+ OneImage: TBitmap;
+ I: Integer;
+ MaskColor: TColor;
+ Source,
+ Dest: TRect;
+
+begin
+ Watcher.Enter;
+ try
+ // Since we want the image list appearing in the correct system colors, we have to remap its colors.
+ Images := TBitmap.Create;
+ OneImage := TBitmap.Create;
+ if ColorRemapping then
+ Images.Handle := CreateMappedRes(FindClassHInstance(TBaseVirtualTree), PChar(ImageName), Grays, SysGrays)
+ else
+ Images.Handle := LoadBitmap(FindClassHInstance(TBaseVirtualTree), PChar(ImageName));
+
+ try
+ Assert(Images.Height > 0, 'Internal image "' + ImageName + '" is missing or corrupt.');
+
+ // It is assumed that the image height determines also the width of one entry in the image list.
+ IL.Clear;
+ IL.Height := Images.Height;
+ IL.Width := Images.Height;
+ OneImage.Width := IL.Width;
+ OneImage.Height := IL.Height;
+ MaskColor := Images.Canvas.Pixels[0, 0]; // this is usually clFuchsia
+ Dest := Rect(0, 0, IL.Width, IL.Height);
+ for I := 0 to (Images.Width div Images.Height) - 1 do
+ begin
+ Source := Rect(I * IL.Width, 0, (I + 1) * IL.Width, IL.Height);
+ OneImage.Canvas.CopyRect(Dest, Images.Canvas, Source);
+ IL.AddMasked(OneImage, MaskColor);
+ end;
+ finally
+ Images.Free;
+ OneImage.Free;
+ end;
+ finally
+ Watcher.Leave;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure CreateSystemImageSet(var IL: TImageList; Flags: Cardinal; Flat: Boolean);
+
+// Creates a system check image set.
+// Note: the DarkCheckImages image list must already be filled, as some images from it are copied here.
+
+const
+ MaskColor: TColor = clFuchsia;
+
+ //--------------- local functions -------------------------------------------
+
+ procedure AddNodeImages(IL: TImageList);
+
+ var
+ BM: TBitmap;
+ I: Integer;
+ OffsetX,
+ OffsetY: Integer;
+
+ begin
+ BM := TBitmap.Create;
+ // Make the bitmap the same size as the image list has to avoid problems when adding.
+ BM.Width := IL.Width;
+ BM.Height := IL.Height;
+ // The offsets are used to center the node images in case the sizes differ.
+ OffsetX := (IL.Width - DarkCheckImages.Width) div 2;
+ OffsetY := (IL.Height - DarkCheckImages.Height) div 2;
+ try
+ for I := 20 to 23 do
+ begin
+ DarkCheckImages.Draw(BM.Canvas, OffsetX, OffsetY, I);
+ IL.AddMasked(BM, DarkCheckImages.BkColor);
+ end;
+ finally
+ BM.Free;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure AddSystemImage(IL: TImageList; Flat: Boolean; Index: Integer);
+
+ var
+ BM: TBitmap;
+ ButtonState: Cardinal;
+ ButtonType: Cardinal;
+
+ begin
+ BM := TBitmap.Create;
+ try
+ BM.Width := IL.Width;
+ BM.Height := IL.Height;
+ BM.Canvas.Brush.Color := MaskColor;
+ BM.Canvas.Brush.Style := bsSolid;
+ BM.Canvas.FillRect(Rect(0, 0, BM.Width, BM.Height));
+ BM.Canvas.Brush.Style := bsClear;
+ if Index <= 8 then
+ ButtonType := DFCS_BUTTONRADIO
+ else
+ ButtonType := DFCS_BUTTONCHECK;
+ if Index >= 17 then
+ ButtonType := ButtonType or DFCS_BUTTON3STATE or DFCS_INACTIVE;
+
+ case Index mod 4 of
+ 1:
+ ButtonState := 0;
+ 2:
+ ButtonState := DFCS_HOT;
+ 3:
+ ButtonState := DFCS_PUSHED;
+ else
+ ButtonState := DFCS_INACTIVE;
+ end;
+ if Index in [5..8, 13..16] then
+ ButtonState := ButtonState or DFCS_CHECKED;
+ if Flat then
+ ButtonState := ButtonState or DFCS_FLAT;
+ DrawFrameControl(BM.Canvas.Handle, Rect(1, 2, BM.Width - 2, BM.Height - 1), DFC_BUTTON, ButtonType or ButtonState);
+ IL.AddMasked(BM, MaskColor);
+ finally
+ BM.Free
+ end;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ I, Width, Height: Integer;
+
+begin
+ Width := GetSystemMetrics(SM_CXMENUCHECK) + 3;
+ Height := GetSystemMetrics(SM_CYMENUCHECK) + 3;
+ IL := TImageList.CreateSize(Width, Height);
+ with IL do
+ Handle := ImageList_Create(Width, Height, Flags, 0, AllocBy);
+ IL.Masked := True;
+ // Add the 20 system checkbox and radiobutton images.
+ for I := 0 to 19 do
+ AddSystemImage(IL, Flat, I);
+ // Add the 4 node images from the dark check set.
+ AddNodeImages(IL);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function HasMMX: Boolean;
+
+// Helper method to determine whether the current processor supports MMX.
+
+asm
+ PUSH EBX
+ XOR EAX, EAX // Result := False
+ PUSHFD // determine if the processor supports the CPUID command
+ POP EDX
+ MOV ECX, EDX
+ XOR EDX, $200000
+ PUSH EDX
+ POPFD
+ PUSHFD
+ POP EDX
+ XOR ECX, EDX
+ JZ @1 // no CPUID support so we can't even get to the feature information
+ PUSH EDX
+ POPFD
+
+ MOV EAX, 1
+ DW $A20F // CPUID, EAX contains now version info and EDX feature information
+ MOV EBX, EAX // free EAX to get the result value
+ XOR EAX, EAX // Result := False
+ CMP EBX, $50
+ JB @1 // if processor family is < 5 then it is not a Pentium class processor
+ TEST EDX, $800000
+ JZ @1 // if the MMX bit is not set then we don't have MMX
+ INC EAX // Result := True
+ at 1:
+ POP EBX
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure PrtStretchDrawDIB(Canvas: TCanvas; DestRect: TRect; ABitmap: TBitmap);
+
+// Stretch draw on to the new canvas.
+
+var
+ Header,
+ Bits: Pointer;
+ HeaderSize,
+ BitsSize: Cardinal;
+
+begin
+ GetDIBSizes(ABitmap.Handle, HeaderSize, BitsSize);
+
+ GetMem(Header, HeaderSize);
+ GetMem(Bits, BitsSize);
+ try
+ GetDIB(ABitmap.Handle, ABitmap.Palette, Header^, Bits^);
+ StretchDIBits(Canvas.Handle, DestRect.Left, DestRect.Top, DestRect.Right - DestRect.Left, DestRect.Bottom -
+ DestRect.Top, 0, 0, ABitmap.Width, ABitmap.Height, Bits, TBitmapInfo(Header^), DIB_RGB_COLORS, SRCCOPY);
+ finally
+ FreeMem(Header);
+ FreeMem(Bits);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure InitializeGlobalStructures;
+
+// initialization of stuff global to the unit
+
+var
+ {$ifndef COMPILER_5_UP}
+ NonClientMetrics: TNonClientMetrics;
+ {$endif COMPILER_5_UP}
+ Flags: Cardinal;
+
+begin
+ Initialized := True;
+
+ // For the drag image a fast MMX blend routine is used. We have to make sure MMX is available.
+ MMXAvailable := HasMMX;
+
+ // There is a bug in Win95 and WinME (and potentially in Win98 too) regarding GetDCEx which causes sometimes
+ // serious trouble within GDI (see method WMNCPaint).
+ IsWinNT := (Win32Platform and VER_PLATFORM_WIN32_NT) <> 0;
+ IsWin2K := (Win32MajorVersion = 5) and (Win32MinorVersion = 0);
+ IsWinXP := (Win32MajorVersion = 5) and (Win32MinorVersion = 1);
+
+ // Initialize OLE subsystem for drag'n drop and clipboard operations.
+ NeedToUnitialize := Succeeded(OleInitialize(nil));
+
+ // Register the tree reference clipboard format. Others will be handled in InternalClipboarFormats.
+ CF_VTREFERENCE := RegisterClipboardFormat(CFSTR_VTREFERENCE);
+
+ // Load all internal image lists and convert their colors to current desktop color scheme.
+ // In order to use high color images we have to create the image list handle ourselves.
+ if IsWinNT then
+ Flags := ILC_COLOR32 or ILC_MASK
+ else
+ Flags := ILC_COLOR16 or ILC_MASK;
+ LightCheckImages := TImageList.Create(nil);
+ with LightCheckImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(LightCheckImages, 'VT_CHECK_LIGHT');
+
+ DarkCheckImages := TImageList.CreateSize(16, 16);
+ with DarkCheckImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(DarkCheckImages, 'VT_CHECK_DARK');
+
+ LightTickImages := TImageList.CreateSize(16, 16);
+ with LightTickImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(LightTickImages, 'VT_TICK_LIGHT');
+
+ DarkTickImages := TImageList.CreateSize(16, 16);
+ with DarkTickImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(DarkTickImages, 'VT_TICK_DARK');
+
+ FlatImages := TImageList.CreateSize(16, 16);
+ with FlatImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(FlatImages, 'VT_FLAT');
+
+ XPImages := TImageList.CreateSize(16, 16);
+ with XPImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(XPImages, 'VT_XP', False);
+
+ UtilityImages := TImageList.CreateSize(UtilityImageSize, UtilityImageSize);
+ with UtilityImages do
+ Handle := ImageList_Create(UtilityImageSize, UtilityImageSize, Flags, 0, AllocBy);
+ ConvertImageList(UtilityImages, 'VT_UTILITIES');
+
+ CreateSystemImageSet(SystemCheckImages, Flags, False);
+ CreateSystemImageSet(SystemFlatCheckImages, Flags, True);
+
+ {$ifndef COMPILER_5_UP}
+ // In Delphi 4 there is no TScreen.HintFont hence we have to manage this manually.
+ HintFont := TFont.Create;
+ NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
+ if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
+ HintFont.Handle := CreateFontIndirect(NonClientMetrics.lfStatusFont)
+ else
+ HintFont.Size := 8;
+ {$endif COMPILER_5_UP}
+
+ // Specify an useful timer resolution for timeGetTime.
+ timeBeginPeriod(MinimumTimerInterval);
+
+ // Delphi (at least version 6 and lower) does not provide a standard split cursor.
+ // Hence we have to load our own.
+ Screen.Cursors[crHeaderSplit] := LoadCursor(HInstance, 'VT_HEADERSPLIT');
+
+ // Clipboard format registration.
+ // Native clipboard format. Needs a new identifier and has an average priority to allow other formats to take over.
+ // This format is supposed to use the IStream storage format but unfortunately this does not work when
+ // OLEFlushClipboard is used. Hence it is disabled until somebody finds a solution.
+ CF_VIRTUALTREE := RegisterVTClipboardFormat(CFSTR_VIRTUALTREE, TBaseVirtualTree, 50, TYMED_HGLOBAL {or TYMED_ISTREAM});
+ // Specialized string tree formats.
+ CF_HTML := RegisterVTClipboardFormat(CFSTR_HTML, TCustomVirtualStringTree, 80);
+ CF_VRTFNOOBJS := RegisterVTClipboardFormat(CFSTR_RTFNOOBJS, TCustomVirtualStringTree, 84);
+ CF_VRTF := RegisterVTClipboardFormat(CFSTR_RTF, TCustomVirtualStringTree, 85);
+ CF_CSV := RegisterVTClipboardFormat(CFSTR_CSV, TCustomVirtualStringTree, 90);
+ // Predefined clipboard formats. Just add them to the internal list.
+ RegisterVTClipboardFormat(CF_TEXT, TCustomVirtualStringTree, 100);
+ RegisterVTClipboardFormat(CF_UNICODETEXT, TCustomVirtualStringTree, 95);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure FinalizeGlobalStructures;
+
+var
+ HintWasEnabled: Boolean;
+
+begin
+ timeEndPeriod(MinimumTimerInterval);
+ {$ifndef COMPILER_5_UP}
+ HintFont.Free;
+ {$endif COMPILER_5_UP}
+
+ LightCheckImages.Free;
+ DarkCheckImages.Free;
+ LightTickImages.Free;
+ DarkTickImages.Free;
+ FlatImages.Free;
+ XPImages.Free;
+ UtilityImages.Free;
+ SystemCheckImages.Free;
+ SystemFlatCheckImages.Free;
+
+ if NeedToUnitialize then
+ OleUninitialize;
+
+ // If VT is used in a package and its special hint window was used then the last instance of this
+ // window is not freed correctly (bug in the VCL). We explicitely tell the application to free it
+ // otherwise an AV is raised due to access to an invalid memory area.
+ if ModuleIsPackage then
+ begin
+ HintWasEnabled := Application.ShowHint;
+ Application.ShowHint := False;
+ if HintWasEnabled then
+ Application.ShowHint := True;
+ end;
+end;
+
+//----------------- TWorkerThread --------------------------------------------------------------------------------------
+
+procedure AddThreadReference;
+
+begin
+ if WorkerThread = nil then
+ begin
+ // Create an event used to trigger our worker thread when something is to do.
+ WorkEvent := CreateEvent(nil, False, False, nil);
+ if WorkEvent = 0 then
+ RaiseLastOSError;
+
+ // Create worker thread, initialize it and send it to its wait loop.
+ WorkerThread := TWorkerThread.Create(False);
+ end;
+ Inc(WorkerThread.FRefCount);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure ReleaseThreadReference(Tree: TBaseVirtualTree);
+
+begin
+ if Assigned(WorkerThread) then
+ begin
+ Dec(WorkerThread.FRefCount);
+
+ // Make sure there is no reference remaining to the releasing tree.
+ Tree.InterruptValidation;
+
+ if WorkerThread.FRefCount = 0 then
+ begin
+ with WorkerThread do
+ begin
+ Terminate;
+ SetEvent(WorkEvent);
+
+ // The following work around is no longer necessary with Delphi 6 and up.
+ {$ifndef COMPILER_6_UP}
+ // There is a problem when the thread is freed in the exit code of a DLL. This can happen when a tree is
+ // destroyed on unload of a DLL (e.g. control panel applet). In this case only the main thread will get
+ // CPU time, other threads will never awake again. The VCL however waits for a thread when freeing it
+ // which will result in a deadlock (the WaitFor call does not return because the thread does not get CPU time).
+ // If a thread is however suspended then the VCL does not wait and all is fine.
+ if IsLibrary then
+ Suspend;
+ {$endif COMPILER_6_UP}
+
+ WorkerThread.Free;
+ end;
+ WorkerThread := nil;
+ CloseHandle(WorkEvent);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+constructor TWorkerThread.Create(CreateSuspended: Boolean);
+
+begin
+ inherited Create(CreateSuspended);
+ FWaiterList := TThreadList.Create;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TWorkerThread.Destroy;
+
+begin
+ FWaiterList.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWorkerThread.ChangeTreeStates(EnterStates, LeaveStates: TChangeStates);
+
+begin
+ if Assigned(FCurrentTree) and (FCurrentTree.HandleAllocated) then
+ PostMessage(FCurrentTree.Handle, WM_CHANGESTATE, Byte(EnterStates), Byte(LeaveStates));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWorkerThread.Execute;
+
+// Does some background tasks, like validating tree caches.
+
+var
+ EnterStates,
+ LeaveStates: TChangeStates;
+
+begin
+ while not Terminated do
+ begin
+ WaitForSingleObject(WorkEvent, INFINITE);
+ if not Terminated then
+ begin
+ // Get the next waiting tree.
+ with FWaiterList.LockList do
+ try
+ if Count > 0 then
+ begin
+ FCurrentTree := Items[0];
+ // Remove this tree from waiter list.
+ Delete(0);
+ end
+ else
+ FCurrentTree := nil;
+ finally
+ FWaiterList.UnlockList;
+ end;
+
+ // Something to do?
+ try
+ if Assigned(FCurrentTree) and not (tsStopValidation in FCurrentTree.FStates) then
+ begin
+ ChangeTreeStates([csValidating], [csUseCache]);
+ EnterStates := [];
+ if FCurrentTree.DoValidateCache then
+ EnterStates := [csUseCache];
+ end;
+ finally
+ LeaveStates := [csValidating, csStopValidation];
+ if csUseCache in EnterStates then
+ Include(LeaveStates, csValidationNeeded);
+ ChangeTreeStates(EnterStates, LeaveStates);
+ FCurrentTree := nil;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWorkerThread.AddTree(Tree: TBaseVirtualTree);
+
+begin
+ Assert(Assigned(Tree), 'Tree must not be nil.');
+
+ with FWaiterList.LockList do
+ try
+ if IndexOf(Tree) = -1 then
+ Add(Tree);
+ finally
+ FWaiterList.UnlockList;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWorkerThread.RemoveTree(Tree: TBaseVirtualTree);
+
+begin
+ Assert(Assigned(Tree), 'Tree must not be nil.');
+
+ if FCurrentTree = Tree then
+ FCurrentTree := nil;
+
+ with FWaiterList.LockList do
+ try
+ Remove(Tree);
+ finally
+ FWaiterList.UnlockList;
+ end;
+end;
+
+//----------------- TBufferedString ------------------------------------------------------------------------------------
+
+const
+ AllocIncrement = 4096;
+
+destructor TBufferedString.Destroy;
+
+begin
+ FreeMem(FStart);
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBufferedString.GetAsString: string;
+
+begin
+ SetString(Result, FStart, FPosition - FStart);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBufferedString.Add(const S: string);
+
+var
+ LastLen,
+ LastOffset,
+ Len: Integer;
+
+begin
+ Len := Length(S);
+ // Make room for the new string.
+ if FEnd - FPosition <= Len then
+ begin
+ // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned.
+ LastLen := FEnd - FStart;
+ LastOffset := FPosition - FStart;
+ ReallocMem(FStart, FEnd - FStart + AllocIncrement);
+ FPosition := FStart + LastOffset;
+ FEnd := FStart + LastLen + AllocIncrement;
+ end;
+ Move(PChar(S)^, FPosition^, Len);
+ Inc(FPosition, Len);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBufferedString.AddNewLine;
+
+var
+ LastLen,
+ LastOffset: Integer;
+
+begin
+ // Make room for the CR/LF characters.
+ if FEnd - FPosition <= 2 then
+ begin
+ // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned.
+ LastLen := FEnd - FStart;
+ LastOffset := FPosition - FStart;
+ ReallocMem(FStart, FEnd - FStart + AllocIncrement);
+ FPosition := FStart + LastOffset;
+ FEnd := FStart + LastLen + AllocIncrement;
+ end;
+ FPosition^ := #13;
+ Inc(FPosition);
+ FPosition^ := #10;
+ Inc(FPosition);
+end;
+
+//----------------- TWideBufferedString --------------------------------------------------------------------------------
+
+destructor TWideBufferedString.Destroy;
+
+begin
+ FreeMem(FStart);
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TWideBufferedString.GetAsString: WideString;
+
+begin
+ SetString(Result, FStart, FPosition - FStart);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWideBufferedString.Add(const S: WideString);
+
+var
+ LastLen,
+ LastOffset,
+ Len: Integer;
+
+begin
+ Len := Length(S);
+ // Make room for the new string.
+ if FEnd - FPosition <= Len then
+ begin
+ // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned.
+ LastLen := FEnd - FStart;
+ LastOffset := FPosition - FStart;
+ ReallocMem(FStart, 2 * (FEnd - FStart + AllocIncrement));
+ FPosition := FStart + LastOffset;
+ FEnd := FStart + LastLen + AllocIncrement;
+ end;
+ Move(PWideChar(S)^, FPosition^, 2 * Len);
+ Inc(FPosition, Len);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWideBufferedString.AddNewLine;
+
+var
+ LastLen,
+ LastOffset: Integer;
+
+begin
+ // Make room for the CR/LF characters.
+ if FEnd - FPosition <= 4 then
+ begin
+ // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned.
+ LastLen := FEnd - FStart;
+ LastOffset := FPosition - FStart;
+ ReallocMem(FStart, 2 * (FEnd - FStart + AllocIncrement));
+ FPosition := FStart + LastOffset;
+ FEnd := FStart + LastLen + AllocIncrement;
+ end;
+ FPosition^ := #13;
+ Inc(FPosition);
+ FPosition^ := #10;
+ Inc(FPosition);
+end;
+
+//----------------- TCustomVirtualTreeOptions --------------------------------------------------------------------------
+
+constructor TCustomVirtualTreeOptions.Create(AOwner: TBaseVirtualTree);
+
+begin
+ FOwner := AOwner;
+
+ FPaintOptions := DefaultPaintOptions;
+ FAnimationOptions := DefaultAnimationOptions;
+ FAutoOptions := DefaultAutoOptions;
+ FSelectionOptions := DefaultSelectionOptions;
+ FMiscOptions := DefaultMiscOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetAnimationOptions(const Value: TVTAnimationOptions);
+
+begin
+ FAnimationOptions := Value;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetAutoOptions(const Value: TVTAutoOptions);
+
+var
+ ChangedOptions: TVTAutoOptions;
+
+begin
+ if FAutoOptions <> Value then
+ begin
+ // Exclusive ORing to get all entries wich are in either set but not in both.
+ ChangedOptions := FAutoOptions + Value - (FAutoOptions * Value);
+ FAutoOptions := Value;
+ with FOwner do
+ if (toAutoSpanColumns in ChangedOptions) and not (csLoading in ComponentState) and HandleAllocated then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetMiscOptions(const Value: TVTMiscOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTMiscOptions;
+
+begin
+ if FMiscOptions <> Value then
+ begin
+ ToBeSet := Value - FMiscOptions;
+ ToBeCleared := FMiscOptions - Value;
+ FMiscOptions := Value;
+
+ with FOwner do
+ if not (csLoading in ComponentState) and HandleAllocated then
+ begin
+ if toCheckSupport in ToBeSet + ToBeCleared then
+ Invalidate;
+ if not (csDesigning in ComponentState) then
+ begin
+ if toFullRepaintOnResize in TobeSet + ToBeCleared then
+ RecreateWnd;
+ if toAcceptOLEDrop in ToBeSet then
+ RegisterDragDrop(Handle, DragManager as IDropTarget);
+ if toAcceptOLEDrop in ToBeCleared then
+ RevokeDragDrop(Handle);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetPaintOptions(const Value: TVTPaintOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTPaintOptions;
+
+begin
+ if FPaintOptions <> Value then
+ begin
+ ToBeSet := Value - FPaintOptions;
+ ToBeCleared := FPaintOptions - Value;
+ FPaintOptions := Value;
+ with FOwner do
+ if not (csLoading in ComponentState) and HandleAllocated then
+ begin
+ {$ifdef ThemeSupport}
+ if toThemeAware in ToBeSet + ToBeCleared then
+ begin
+ if (toThemeAware in ToBeSet) and ThemeServices.ThemesEnabled then
+ DoStateChange([tsUseThemes])
+ else
+ DoStateChange([], [tsUseThemes]);
+ PrepareBitmaps(True, False);
+ RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_VALIDATE or RDW_FRAME);
+ end
+ else
+ {$endif ThemeSupport}
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetSelectionOptions(const Value: TVTSelectionOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTSelectionOptions;
+
+begin
+ if FSelectionOptions <> Value then
+ begin
+ ToBeSet := Value - FSelectionOptions;
+ ToBeCleared := FSelectionOptions - Value;
+ FSelectionOptions := Value;
+
+ with FOwner do
+ begin
+ if (toMultiSelect in (ToBeCleared + ToBeSet)) or
+ ([toLevelSelectConstraint, toSiblingSelectConstraint] * ToBeSet <> []) then
+ ClearSelection;
+
+ if (toExtendedFocus in ToBeCleared) and (FFocusedColumn > 0) and HandleAllocated then
+ begin
+ FFocusedColumn := FHeader.MainColumn;
+ Invalidate;
+ end;
+
+ if not (toExtendedFocus in FSelectionOptions) then
+ FFocusedColumn := FHeader.MainColumn;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.AssignTo(Dest: TPersistent);
+
+begin
+ if Dest is TCustomVirtualTreeOptions then
+ begin
+ with Dest as TCustomVirtualTreeOptions do
+ begin
+ PaintOptions := Self.PaintOptions;
+ AnimationOptions := Self.AnimationOptions;
+ AutoOptions := Self.AutoOptions;
+ SelectionOptions := Self.SelectionOptions;
+ MiscOptions := Self.MiscOptions;
+ end;
+ end
+ else
+ inherited;
+end;
+
+//----------------- TVTNodeMemoryManager -------------------------------------------------------------------------------
+
+{$ifdef UseLocalMemoryManager}
+
+ const
+ NodeMemoryGuard: PVirtualNode = PVirtualNode($FEEFEFFE);
+
+ constructor TVTNodeMemoryManager.Create;
+
+ begin
+ FBlockList := TList.Create;
+ end;
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ destructor TVTNodeMemoryManager.Destroy;
+
+ begin
+ Clear;
+ FBlockList.Free;
+ end;
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ function TVTNodeMemoryManager.AllocNode(const Size: Cardinal): PVirtualNode;
+
+ // Allocates memory for a node using the local memory manager.
+
+ const
+ BlockSize = (16 * 1024); // Blocks larger than 16K offer no significant performance improvement.
+
+ begin
+ if FAllocSize = 0 then
+ // Recalculate allocation size first time after a clear.
+ FAllocSize := (Size + 3) and not 3 // Force alignment on 32-bit boundaries.
+ else
+ // Allocation size cannot be increased unless Memory Manager is explicitly cleared.
+ Assert(Size <= FAllocSize, 'Node memory manager allocation size cannot be increased.');
+
+ if Assigned(FFreeSpace) then
+ begin
+ // Assign node from free-space chain.
+ Assert(FFreeSpace.NextSibling = NodeMemoryGuard, 'Memory overwrite in node memory manager free space chain.');
+ Result := FFreeSpace; // Assign node
+ FFreeSpace := Result.PrevSibling; // Point to prev node in free-space chain
+ end
+ else
+ begin
+ if FBytesAvailable < FAllocSize then
+ begin
+ // Get another block from the Delphi memory manager.
+ GetMem(FNext, BlockSize);
+ FBytesAvailable := BlockSize;
+ FBlockList.Add(FNext);
+ end;
+ // Assign node from current block.
+ Result := FNext;
+ Inc(PChar(FNext), FAllocSize);
+ Dec(FBytesAvailable, FAllocSize);
+ end;
+
+ // Clear the memory.
+ FillChar(Result^, FAllocSize, 0);
+ end;
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ procedure TVTNodeMemoryManager.Clear;
+
+ // Releases all memory held by the local memory manager.
+
+ var
+ I: Integer;
+
+ begin
+ for I := 0 to FBlockList.Count - 1 do
+ FreeMem(FBlockList[I]);
+ FBlockList.Clear;
+ FFreeSpace := nil;
+ FBytesAvailable := 0;
+ FAllocSize := 0;
+ end;
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ procedure TVTNodeMemoryManager.FreeNode(const Node: PVirtualNode);
+
+ // Frees node memory that was allocated using the local memory manager.
+
+ begin
+ Node.PrevSibling := FFreeSpace; // Point to previous free node.
+ Node.NextSibling := NodeMemoryGuard; // Memory guard to detect overwrites.
+ FFreeSpace := Node; // Point Free chain pointer to me.
+ end;
+
+{$endif UseLocalMemoryManager}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+// OLE drag and drop support classes
+// This is quite heavy stuff (compared with the VCL implementation) but is much better suited to fit the needs
+// of DD'ing various kinds of virtual data and works also between applications.
+
+//----------------- TEnumFormatEtc -------------------------------------------------------------------------------------
+
+constructor TEnumFormatEtc.Create(Tree: TBaseVirtualTree; AFormatEtcArray: TFormatEtcArray);
+
+var
+ I: Integer;
+
+begin
+ inherited Create;
+
+ FTree := Tree;
+ // Make a local copy of the format data.
+ SetLength(FFormatEtcArray, Length(AFormatEtcArray));
+ for I := 0 to High(AFormatEtcArray) do
+ FFormatEtcArray[I] := AFormatEtcArray[I];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TEnumFormatEtc.Clone(out Enum: IEnumFormatEtc): HResult;
+
+var
+ AClone: TEnumFormatEtc;
+
+begin
+ Result := S_OK;
+ try
+ AClone := TEnumFormatEtc.Create(nil, FFormatEtcArray);
+ AClone.FCurrentIndex := FCurrentIndex;
+ Enum := AClone as IEnumFormatEtc;
+ except
+ Result := E_FAIL;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TEnumFormatEtc.Next(celt: Integer; out elt; pceltFetched: PLongint): HResult;
+
+var
+ CopyCount: Integer;
+
+begin
+ Result := S_FALSE;
+ CopyCount := Length(FFormatEtcArray) - FCurrentIndex;
+ if celt < CopyCount then
+ CopyCount := celt;
+ if CopyCount > 0 then
+ begin
+ Move(FFormatEtcArray[FCurrentIndex], elt, CopyCount * SizeOf(TFormatEtc));
+ Inc(FCurrentIndex, CopyCount);
+ Result := S_OK;
+ end;
+ if Assigned(pceltFetched) then
+ pceltFetched^ := CopyCount;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TEnumFormatEtc.Reset: HResult;
+
+begin
+ FCurrentIndex := 0;
+ Result := S_OK;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TEnumFormatEtc.Skip(celt: Integer): HResult;
+
+begin
+ if FCurrentIndex + celt < High(FFormatEtcArray) then
+ begin
+ Inc(FCurrentIndex, celt);
+ Result := S_Ok;
+ end
+ else
+ Result := S_FALSE;
+end;
+
+//----------------- TVTDataObject --------------------------------------------------------------------------------------
+
+constructor TVTDataObject.Create(AOwner: TBaseVirtualTree; ForClipboard: Boolean);
+
+begin
+ inherited Create;
+
+ FOwner := AOwner;
+ FForClipboard := ForClipboard;
+ FOwner.GetNativeClipboardFormats(FFormatEtcArray);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVTDataObject.Destroy;
+
+var
+ I: Integer;
+ StgMedium: PStgMedium;
+
+begin
+ // Cancel a pending clipboard operation if this data object was created for the clipboard and
+ // is freed because something else is placed there.
+ if FForClipboard and not (tsClipboardFlushing in FOwner.FStates) then
+ FOwner.CancelCutOrCopy;
+
+ // Release any internal clipboard formats
+ for I := 0 to High(FormatEtcArray) do
+ begin
+ StgMedium := FindInternalStgMedium(FormatEtcArray[I].cfFormat);
+ if Assigned(StgMedium) then
+ ReleaseStgMedium(StgMedium^);
+ end;
+
+ FormatEtcArray := nil;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.CanonicalIUnknown(TestUnknown: IUnknown): IUnknown;
+
+// Uses COM object identity: An explicit call to the IUnknown::QueryInterface method, requesting the IUnknown
+// interface, will always return the same pointer.
+
+begin
+ if Assigned(TestUnknown) then
+ begin
+ if TestUnknown.QueryInterface(IUnknown, Result) = 0 then
+ Result._Release // Don't actually need it just need the pointer value
+ else
+ Result := TestUnknown
+ end
+ else
+ Result := TestUnknown
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.EqualFormatEtc(FormatEtc1, FormatEtc2: TFormatEtc): Boolean;
+
+begin
+ Result := (FormatEtc1.cfFormat = FormatEtc2.cfFormat) and (FormatEtc1.ptd = FormatEtc2.ptd) and
+ (FormatEtc1.dwAspect = FormatEtc2.dwAspect) and (FormatEtc1.lindex = FormatEtc2.lindex) and
+ (FormatEtc1.tymed and FormatEtc2.tymed <> 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.FindFormatEtc(TestFormatEtc: TFormatEtc; const FormatEtcArray: TFormatEtcArray): integer;
+
+var
+ I: integer;
+
+begin
+ Result := -1;
+ for I := 0 to High(FormatEtcArray) do
+ begin
+ if EqualFormatEtc(TestFormatEtc, FormatEtcArray[I]) then
+ begin
+ Result := I;
+ Break;
+ end
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.FindInternalStgMedium(Format: TClipFormat): PStgMedium;
+
+var
+ I: integer;
+begin
+ Result := nil;
+ for I := 0 to High(InternalStgMediumArray) do
+ begin
+ if Format = InternalStgMediumArray[I].Format then
+ begin
+ Result := @InternalStgMediumArray[I].Medium;
+ Break;
+ end
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.HGlobalClone(HGlobal: THandle): THandle;
+
+// Returns a global memory block that is a copy of the passed memory block.
+
+var
+ Size: Cardinal;
+ Data,
+ NewData: PChar;
+
+begin
+ Size := GlobalSize(HGlobal);
+ Result := GlobalAlloc(GPTR, Size);
+ Data := GlobalLock(hGlobal);
+ try
+ NewData := GlobalLock(Result);
+ try
+ Move(Data^, NewData^, Size);
+ finally
+ GlobalUnLock(Result);
+ end
+ finally
+ GlobalUnLock(hGlobal);
+ end
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.RenderInternalOLEData(const FormatEtcIn: TFormatEtc; var Medium: TStgMedium;
+ var OLEResult: HResult): Boolean;
+
+// Tries to render one of the formats which have been stored via the SetData method.
+// Since this data is already there it is just copied or its reference count is increased (depending on storage medium).
+
+var
+ InternalMedium: PStgMedium;
+
+begin
+ Result := True;
+ InternalMedium := FindInternalStgMedium(FormatEtcIn.cfFormat);
+ if Assigned(InternalMedium) then
+ OLEResult := StgMediumIncRef(InternalMedium^, Medium, False, Self as IDataObject)
+ else
+ Result := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.StgMediumIncRef(const InStgMedium: TStgMedium; var OutStgMedium: TStgMedium;
+ CopyInMedium: Boolean; DataObject: IDataObject): HRESULT;
+
+// InStgMedium is the data that is requested, OutStgMedium is the data that we are to return either a copy of or
+// increase the IDataObject's reference and send ourselves back as the data (unkForRelease). The InStgMedium is usually
+// the result of a call to find a particular FormatEtc that has been stored locally through a call to SetData.
+// If CopyInMedium is not true we already have a local copy of the data when the SetData function was called (during
+// that call the CopyInMedium must be true). Then as the caller asks for the data through GetData we do not have to make
+// copy of the data for the caller only to have them destroy it then need us to copy it again if necessary.
+// This way we increase the reference count to ourselves and pass the STGMEDIUM structure initially stored in SetData.
+// This way when the caller frees the structure it sees the unkForRelease is not nil and calls Release on the object
+// instead of destroying the actual data.
+
+var
+ Len: Integer;
+
+begin
+ Result := S_OK;
+
+ // Simply copy all fields to start with.
+ OutStgMedium := InStgMedium;
+ // The data handled here always results from a call of SetData we got. This ensures only one storage format
+ // is indicated and hence the case statement below is safe (IDataObject.GetData can optionally use several
+ // storage formats).
+ case InStgMedium.tymed of
+ TYMED_HGLOBAL:
+ begin
+ if CopyInMedium then
+ begin
+ // Generate a unique copy of the data passed
+ OutStgMedium.hGlobal := HGlobalClone(InStgMedium.hGlobal);
+ if OutStgMedium.hGlobal = 0 then
+ Result := E_OUTOFMEMORY
+ end
+ else
+ // Don't generate a copy just use ourselves and the copy previously saved.
+ OutStgMedium.unkForRelease := Pointer(DataObject); // Does not increase RefCount.
+ end;
+ TYMED_FILE:
+ begin
+ Len := lstrLenW(InStgMedium.lpszFileName) + 1; // Don'nt forget the terminating null character.
+ OutStgMedium.lpszFileName := CoTaskMemAlloc(2 * Len);
+ Move(InStgMedium.lpszFileName^, OutStgMedium.lpszFileName^, 2 * Len);
+ end;
+ TYMED_ISTREAM:
+ IUnknown(OutStgMedium.stm)._AddRef;
+ TYMED_ISTORAGE:
+ IUnknown(OutStgMedium.stg)._AddRef;
+ TYMED_GDI:
+ if not CopyInMedium then
+ // Don't generate a copy just use ourselves and the copy previously saved data.
+ OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount.
+ else
+ Result := DV_E_TYMED; // Don't know how to copy GDI objects right now.
+ TYMED_MFPICT:
+ if not CopyInMedium then
+ // Don't generate a copy just use ourselves and the copy previously saved data.
+ OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount.
+ else
+ Result := DV_E_TYMED; // Don't know how to copy MetaFile objects right now.
+ TYMED_ENHMF:
+ if not CopyInMedium then
+ // Don't generate a copy just use ourselves and the copy previously saved data.
+ OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount.
+ else
+ Result := DV_E_TYMED; // Don't know how to copy enhanced metafiles objects right now.
+ else
+ Result := DV_E_TYMED;
+ end;
+
+ if (Result = S_OK) and Assigned(OutStgMedium.unkForRelease) then
+ IUnknown(OutStgMedium.unkForRelease)._AddRef;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.DAdvise(const FormatEtc: TFormatEtc; advf: Integer; const advSink: IAdviseSink;
+ out dwConnection: Integer): HResult;
+
+// Advise sink management is greatly simplified by the IDataAdviseHolder interface.
+// We use this interface and forward all concerning calls to it.
+
+begin
+ Result := S_OK;
+ if FAdviseHolder = nil then
+ Result := CreateDataAdviseHolder(FAdviseHolder);
+ if Result = S_OK then
+ Result := FAdviseHolder.Advise(Self as IDataObject, FormatEtc, advf, advSink, dwConnection);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.DUnadvise(dwConnection: Integer): HResult;
+
+begin
+ if FAdviseHolder = nil then
+ Result := E_NOTIMPL
+ else
+ Result := FAdviseHolder.Unadvise(dwConnection);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.EnumDAdvise(out enumAdvise: IEnumStatData): HResult;
+
+begin
+ if FAdviseHolder = nil then
+ Result := OLE_E_ADVISENOTSUPPORTED
+ else
+ Result := FAdviseHolder.EnumAdvise(enumAdvise);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.EnumFormatEtc(Direction: Integer; out EnumFormatEtc: IEnumFormatEtc): HResult;
+
+var
+ NewList: TEnumFormatEtc;
+
+begin
+ Result := E_FAIL;
+ if Direction = DATADIR_GET then
+ begin
+ NewList := TEnumFormatEtc.Create(FOwner, FormatEtcArray);
+ EnumFormatEtc := NewList as IEnumFormatEtc;
+ Result := S_OK;
+ end
+ else
+ EnumFormatEtc := nil;
+ if EnumFormatEtc = nil then
+ Result := OLE_S_USEREG;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.GetCanonicalFormatEtc(const FormatEtc: TFormatEtc; out FormatEtcOut: TFormatEtc): HResult;
+
+begin
+ Result := DATA_S_SAMEFORMATETC;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.GetData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium): HResult;
+
+// Data is requested by clipboard or drop target. This method dispatchs the call
+// depending on the data being requested.
+
+var
+ I: Integer;
+ Data: PVTReference;
+
+begin
+ // The tree reference format is always supported and returned from here.
+ if FormatEtcIn.cfFormat = CF_VTREFERENCE then
+ begin
+ // Note: this format is not used while flushing the clipboard to avoid a dangling reference
+ // when the owner tree is destroyed before the clipboard data is replaced with something else.
+ if tsClipboardFlushing in FOwner.FStates then
+ Result := E_FAIL
+ else
+ begin
+ Medium.hGlobal := GlobalAlloc(GHND or GMEM_SHARE, SizeOf(TVTReference));
+ Data := GlobalLock(Medium.hGlobal);
+ Data.Process := GetCurrentProcessID;
+ Data.Tree := FOwner;
+ GlobalUnlock(Medium.hGlobal);
+ Medium.tymed := TYMED_HGLOBAL;
+ Medium.unkForRelease := nil;
+ Result := S_OK;
+ end;
+ end
+ else
+ begin
+ try
+ // See if we accept this type and if not get the correct return value.
+ Result := QueryGetData(FormatEtcIn);
+ if Result = S_OK then
+ begin
+ for I := 0 to High(FormatEtcArray) do
+ begin
+ if EqualFormatEtc(FormatEtcIn, FormatEtcArray[I]) then
+ begin
+ if not RenderInternalOLEData(FormatEtcIn, Medium, Result) then
+ Result := FOwner.RenderOLEData(FormatEtcIn, Medium, FForClipboard);
+ Break;
+ end;
+ end
+ end
+ except
+ FillChar(Medium, SizeOf(Medium), #0);
+ Result := E_FAIL;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.GetDataHere(const FormatEtc: TFormatEtc; out Medium: TStgMedium): HResult;
+
+begin
+ Result := E_NOTIMPL;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.QueryGetData(const FormatEtc: TFormatEtc): HResult;
+
+var
+ I: Integer;
+
+begin
+ Result := DV_E_CLIPFORMAT;
+ for I := 0 to High(FFormatEtcArray) do
+ begin
+ if FormatEtc.cfFormat = FFormatEtcArray[I].cfFormat then
+ begin
+ if (FormatEtc.tymed and FFormatEtcArray[I].tymed) <> 0 then
+ begin
+ if FormatEtc.dwAspect = FFormatEtcArray[I].dwAspect then
+ begin
+ if FormatEtc.lindex = FFormatEtcArray[I].lindex then
+ begin
+ Result := S_OK;
+ Break;
+ end
+ else
+ Result := DV_E_LINDEX;
+ end
+ else
+ Result := DV_E_DVASPECT;
+ end
+ else
+ Result := DV_E_TYMED;
+ end;
+ end
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.SetData(const FormatEtc: TFormatEtc; var Medium: TStgMedium; DoRelease: BOOL): HResult;
+
+// Allows dynamic adding to the IDataObject during its existance. Most noteably it is used to implement
+// IDropSourceHelper and allows to set a special format for optimized moves during a shell transfer.
+
+var
+ Index: integer;
+ LocalStgMedium: PStgMedium;
+
+begin
+ // See if we already have a format of that type available.
+ Index := FindFormatEtc(FormatEtc, FormatEtcArray);
+ if Index > - 1 then
+ begin
+ // Just use the TFormatEct in the Array after releasing the data.
+ LocalStgMedium := FindInternalStgMedium(FormatEtcArray[Index].cfFormat);
+ if Assigned(LocalStgMedium) then
+ begin
+ ReleaseStgMedium(LocalStgMedium^);
+ FillChar(LocalStgMedium^, SizeOf(LocalStgMedium^), #0);
+ end;
+ end
+ else
+ begin
+ // It is a new format so create a new TFormatCollectionItem, copy the
+ // FormatEtc parameter into the new object and and put it in the list.
+ SetLength(FFormatEtcArray, Length(FormatEtcArray) + 1);
+ FormatEtcArray[High(FormatEtcArray)] := FormatEtc;
+
+ // Create a new InternalStgMedium and initialize it and associate it with the format.
+ SetLength(FInternalStgMediumArray, Length(InternalStgMediumArray) + 1);
+ InternalStgMediumArray[High(InternalStgMediumArray)].Format := FormatEtc.cfFormat;
+ LocalStgMedium := @InternalStgMediumArray[High(InternalStgMediumArray)].Medium;
+ FillChar(LocalStgMedium^, SizeOf(LocalStgMedium^), #0);
+ end;
+
+ if DoRelease then
+ begin
+ // We are simply being given the data and we take control of it.
+ LocalStgMedium^ := Medium;
+ Result := S_OK
+ end
+ else
+ begin
+ // We need to reference count or copy the data and keep our own references to it.
+ Result := StgMediumIncRef(Medium, LocalStgMedium^, True, Self as IDataObject);
+
+ // Can get a circular reference if the client calls GetData then calls SetData with the same StgMedium.
+ // Because the unkForRelease for the IDataObject can be marshalled it is necessary to get pointers that
+ // can be correctly compared. See the IDragSourceHelper article by Raymond Chen at MSDN.
+ if Assigned(LocalStgMedium.unkForRelease) then
+ begin
+ if CanonicalIUnknown(Self) = CanonicalIUnknown(IUnknown(LocalStgMedium.unkForRelease)) then
+ IUnknown(LocalStgMedium.unkForRelease) := nil; // release the interface
+ end;
+ end;
+
+ // Tell all registered advice sinks about the data change.
+ if Assigned(FAdviseHolder) then
+ FAdviseHolder.SendOnDataChange(Self as IDataObject, 0, 0);
+end;
+
+//----------------- TVTDragManager -------------------------------------------------------------------------------------
+
+constructor TVTDragManager.Create(AOwner: TBaseVirtualTree);
+
+begin
+ inherited Create;
+ FOwner := AOwner;
+
+ // Create an instance of the drop target helper interface. This will fail but not harm on systems which do
+ // not support this interface (everything below Windows 2000);
+ CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, FDropTargetHelper);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVTDragManager.Destroy;
+
+begin
+ // Set the owner's reference to us to nil otherwise it will access an invalid pointer
+ // after our desctruction is complete.
+ Pointer(FOwner.FDragManager) := nil;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GetDataObject: IDataObject;
+
+begin
+ // When the owner tree starts a drag operation then it gets a data object here to pass it to the OLE subsystem.
+ // In this case there is no local reference to a data object and one is created (but not stored).
+ // If there is a local reference then the owner tree is currently the drop target and the stored interface is
+ // that of the drag initiator.
+ if Assigned(FDataObject) then
+ Result := FDataObject
+ else
+ begin
+ Result := FOwner.DoCreateDataObject;
+ if Result = nil then
+ Result := TVTDataObject.Create(FOwner, False) as IDataObject;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GetDragSource: TBaseVirtualTree;
+
+begin
+ Result := FDragSource;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GetDropTargetHelperSupported: Boolean;
+
+begin
+ Result := Assigned(FDropTargetHelper);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GetIsDropTarget: Boolean;
+
+begin
+ Result := FIsDropTarget;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.DragEnter(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult;
+
+begin
+ FDataObject := DataObject;
+ FIsDropTarget := True;
+
+ SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, @FFullDragging, 0);
+ // If full dragging of window contents is disabled in the system then our tree windows will be locked
+ // and cannot be updated during a drag operation. With the following call painting is again enabled.
+ if not FFullDragging then
+ LockWindowUpdate(0);
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.DragEnter(FOwner.Handle, DataObject, Pt, Effect);
+
+ FDragSource := FOwner.GetTreeFromDataObject(DataObject);
+ Result := FOwner.DragEnter(KeyState, Pt, Effect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.DragLeave: HResult;
+
+begin
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.DragLeave;
+
+ FOwner.DragLeave;
+ FIsDropTarget := False;
+ FDragSource := nil;
+ FDataObject := nil;
+ Result := NOERROR;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.DragOver(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult;
+
+begin
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.DragOver(Pt, Effect);
+
+ Result := FOwner.DragOver(FDragSource, KeyState, dsDragMove, Pt, Effect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.Drop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult;
+
+begin
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.Drop(DataObject, Pt, Effect);
+
+ Result := FOwner.DragDrop(DataObject, KeyState, Pt, Effect);
+ FIsDropTarget := False;
+ FDataObject := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragManager.ForceDragLeave;
+
+// It has been reported that under some circumstances a drag image remains on screen. Unfortunately, nobody could
+// come up with a list of steps-to-reproduce. So we can only fix the result instead the cause.
+// This method calls the drop target helper's DragLeave method to ensure it removes the drag image from screen.
+
+begin
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.DragLeave;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GiveFeedback(Effect: Integer): HResult;
+
+begin
+ Result := DRAGDROP_S_USEDEFAULTCURSORS;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.QueryContinueDrag(EscapePressed: BOOL; KeyState: Integer): HResult;
+
+var
+ RButton,
+ LButton: Boolean;
+
+begin
+ LButton := (KeyState and MK_LBUTTON) <> 0;
+ RButton := (KeyState and MK_RBUTTON) <> 0;
+
+ // Drag'n drop canceled by pressing both mouse buttons or Esc?
+ if (LButton and RButton) or EscapePressed then
+ Result := DRAGDROP_S_CANCEL
+ else
+ // drag'n drop finished?
+ if not (LButton or RButton) then
+ Result := DRAGDROP_S_DROP
+ else
+ Result := S_OK;
+end;
+
+//----------------- TVirtualTreeHintWindow -----------------------------------------------------------------------------
+
+var
+ // This variable is necessary to coordinate the complex interaction between different hints in the application
+ // and animated hints in our own class. Under certain conditions it can happen that our hint window is destroyed
+ // while it is still in the animation loop.
+ HintWindowDestroyed: Boolean = True;
+
+constructor TVirtualTreeHintWindow.Create(AOwner: TComponent);
+
+begin
+ inherited;
+
+ FBackground := TBitmap.Create;
+ FBackground.PixelFormat := pf32Bit;
+ FDrawBuffer := TBitmap.Create;
+ FDrawBuffer.PixelFormat := pf32Bit;
+ FTarget := TBitmap.Create;
+ FTarget.PixelFormat := pf32Bit;
+
+ DoubleBuffered := False; // we do our own buffering
+ HintWindowDestroyed := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVirtualTreeHintWindow.Destroy;
+
+begin
+ HintWindowDestroyed := True;
+
+ FTarget.Free;
+ FDrawBuffer.Free;
+ FBackground.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeHintWindow.AnimationCallback(Step, StepSize: Integer; Data: Pointer): Boolean;
+
+begin
+ Result := not HintWindowDestroyed and IsWindowVisible(Handle);
+ if Result then
+ begin
+ InternalPaint(Step, StepSize);
+ // We have to allow certain messages to be processed normally for various reasons.
+ // This introduces another problem however if this hint window is destroyed
+ // while it is still in the animation loop. A global variable keeps track of
+ // that case. This is reliable because we can only have one (internal) hint window.
+ Application.ProcessMessages;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.InternalPaint(Step, StepSize: Integer);
+
+ //--------------- local functions -------------------------------------------
+
+ procedure DoShadowBlend(DC: HDC; R: TRect; Alpha: Integer);
+
+ // Helper routine for shadow blending to shorten the parameter list in frequent calls.
+
+ begin
+ AlphaBlend(0, DC, R, Point(0, 0), bmConstantAlphaAndColor, Alpha, clBlack);
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure DrawHintShadow(Canvas: TCanvas; ShadowSize: Integer);
+
+ var
+ R: TRect;
+
+ begin
+ // Bottom shadow.
+ R := Rect(ShadowSize, Height - ShadowSize, Width, Height);
+ DoShadowBlend(Canvas.Handle, R, 5);
+ Inc(R.Left);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ DoShadowBlend(Canvas.Handle, R, 10);
+ Inc(R.Left);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ DoShadowBlend(Canvas.Handle, R, 20);
+ Inc(R.Left);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ DoShadowBlend(Canvas.Handle, R, 35);
+ Inc(R.Left);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ DoShadowBlend(Canvas.Handle, R, 50);
+ // Right shadow.
+ R := Rect(Width - ShadowSize, ShadowSize, Width, Height - ShadowSize);
+ DoShadowBlend(Canvas.Handle, R, 5);
+ Inc(R.Top);
+ Dec(R.Right);
+ DoShadowBlend(Canvas.Handle, R, 10);
+ Inc(R.Top);
+ Dec(R.Right);
+ DoShadowBlend(Canvas.Handle, R, 20);
+ Inc(R.Top);
+ Dec(R.Right);
+ DoShadowBlend(Canvas.Handle, R, 35);
+ Inc(R.Top);
+ Dec(R.Right);
+ DoShadowBlend(Canvas.Handle, R, 50);
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ R: TRect;
+ Y: Integer;
+ S: WideString;
+ DrawFormat: Cardinal;
+ Shadow: Integer;
+
+begin
+ {$ifndef COMPILER_7_UP}
+ if MMXAvailable then
+ Shadow := ShadowSize
+ else
+ {$endif COMPILER_7_UP}
+ Shadow := 0;
+
+ with FHintData, FDrawBuffer do
+ begin
+ // Do actual painting only in the very first run.
+ if Step = 0 then
+ begin
+ // If the given node is nil then we have to display a header hint.
+ if (Node = nil) or (Tree.FHintMode <> hmToolTip) then
+ begin
+ {$ifndef COMPILER_5_UP}
+ Canvas.Font := HintFont;
+ {$else}
+ Canvas.Font := Screen.HintFont;
+ {$endif COMPILER_5_UP}
+ Y := 2;
+ end
+ else
+ begin
+ Tree.GetTextInfo(Node, Column, Canvas.Font, R, S);
+ if vsMultiline in Node.States then
+ Y := Tree.TextMargin + 1
+ else
+ Y := (R.Top - R.Bottom - Shadow + Self.Height) div 2;
+ end;
+
+ with ClientRect do
+ R := Rect(0, 0, Width - Shadow, Height - Shadow);
+
+ if (Tree is TCustomVirtualDrawTree) and Assigned(Node) then
+ begin
+ // The draw tree has by default no hint text so let it draw the hint itself.
+ (Tree as TCustomVirtualDrawTree).DoDrawHint(Canvas, Node, R, Column);
+ end
+ else
+ with Canvas do
+ begin
+ // Still force tooltip back and text color.
+ Font.Color := clInfoText;
+ Pen.Color := clBlack;
+ Brush.Color := clInfoBk;
+ {$ifdef COMPILER_5_UP}
+ Rectangle(R);
+ {$else}
+ with R do
+ Rectangle(Left, Top, Right, Bottom);
+ {$endif COMPILER_5_UP}
+
+ // Determine text position and don't forget the border.
+ InflateRect(R, -Tree.FTextMargin - 1, -1);
+ DrawFormat := DT_TOP or DT_NOPREFIX;
+ if BidiMode <> bdLeftToRight then
+ begin
+ DrawFormat := DrawFormat or DT_RIGHT or DT_RTLREADING;
+ Inc(R.Right);
+ end
+ else
+ DrawFormat := DrawFormat or DT_LEFT;
+ SetBkMode(Handle, Windows.TRANSPARENT);
+ R.Top := Y;
+ if Assigned(Node) and (vsMultiline in Node.States) then
+ DrawFormat := DrawFormat or DT_WORDBREAK;
+ if IsWinNT then
+ Windows.DrawTextW(Handle, PWideChar(HintText), Length(HintText), R, DrawFormat)
+ else
+ DrawTextW(Handle, PWideChar(HintText), Length(HintText), R, DrawFormat, False);
+ end;
+ end;
+ end;
+
+ if StepSize > 0 then
+ begin
+ if FHintData.Tree.DoGetAnimationType = hatFade then
+ begin
+ with FTarget do
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FBackground.Canvas.Handle, 0, 0, SRCCOPY);
+ // Main image.
+ AlphaBlend(FDrawBuffer.Canvas.Handle, FTarget.Canvas.Handle, Rect(0, 0, Width - Shadow, Height - Shadow),
+ Point(0, 0), bmConstantAlpha, MulDiv(Step, 256, FadeAnimationStepCount), 0);
+
+ if Shadow > 0 then
+ DrawHintShadow(FTarget.Canvas, Shadow);
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FTarget.Canvas.Handle, 0, 0, SRCCOPY);
+ end
+ else
+ begin
+ // Slide is done by blitting "step" lines of the lower part of the hint window
+ // and fill the rest with the screen background.
+
+ // 1) blit hint bitmap to the hint canvas
+ BitBlt(Canvas.Handle, 0, 0, Width - Shadow, Step, FDrawBuffer.Canvas.Handle, 0, Height - Step, SRCCOPY);
+ // 2) blit background rest to hint canvas
+ if Step <= Shadow then
+ Step := 0
+ else
+ Dec(Step, Shadow);
+ BitBlt(Canvas.Handle, 0, Step, Width, Height - Step, FBackground.Canvas.Handle, 0, Step, SRCCOPY);
+ end;
+ end
+ else
+ // Last step during slide or the only step without animation.
+ if FHintData.Tree.DoGetAnimationType <> hatFade then
+ begin
+ if Shadow > 0 then
+ begin
+ with FBackground do
+ BitBlt(Canvas.Handle, 0, 0, Width - Shadow, Height - Shadow, FDrawBuffer.Canvas.Handle, 0, 0, SRCCOPY);
+
+ DrawHintShadow(FBackground.Canvas, Shadow);
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FBackground.Canvas.Handle, 0, 0, SRCCOPY);
+ end
+ else
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FDrawBuffer.Canvas.Handle, 0, 0, SRCCOPY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.CMTextChanged(var Message: TMessage);
+
+begin
+ // swallow this message to prevent the ancestor from resizing the window (we don't use the caption anyway)
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.WMEraseBkgnd(var Message: TWMEraseBkgnd);
+
+// The control is fully painted by own code so don't erase its background as this causes flickering.
+
+begin
+ Message.Result := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.WMNCPaint(var Message: TMessage);
+
+// The control is fully painted by own code so don't paint any borders.
+
+begin
+ Message.Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.WMShowWindow(var Message: TWMShowWindow);
+
+// Clear hint data when the window becomes hidden.
+
+begin
+ if not Message.Show then
+ begin
+ Finalize(FHintData);
+ FillChar(FHintData, SizeOf(FHintData), 0);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.CreateParams(var Params: TCreateParams);
+
+begin
+ inherited CreateParams(Params);
+
+ with Params do
+ begin
+ Style := WS_POPUP;
+ ExStyle := ExStyle and not WS_EX_CLIENTEDGE;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.Paint;
+
+begin
+ InternalPaint(0, 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.ActivateHint(Rect: TRect; const AHint: string);
+
+var
+ DC: HDC;
+
+begin
+ // Do not allow to enter the animation loop recursively.
+ if (tsInAnimation in FHintData.Tree.FStates) or IsRectEmpty(Rect) then
+ Application.CancelHint
+ else
+ begin
+ SetWindowPos(Handle, 0, Rect.Left, Rect.Top, Width, Height, SWP_HIDEWINDOW or SWP_NOACTIVATE or SWP_NOZORDER);
+ UpdateBoundsRect(Rect);
+
+ if Rect.Top + Height > Screen.DesktopHeight then
+ Rect.Top := Screen.DesktopHeight - Height;
+ if Rect.Top < Screen.DesktopTop then
+ Rect.Top := Screen.DesktopTop;
+ if Rect.Left + Width > Screen.DesktopWidth then
+ Rect.Left := Screen.DesktopWidth - Width;
+ if Rect.Left < Screen.DesktopLeft then
+ Rect.Left := Screen.DesktopLeft;
+
+ // adjust sizes of bitmaps
+ FDrawBuffer.Width := Width;
+ FDrawBuffer.Height := Height;
+ FBackground.Width := Width;
+ FBackground.Height := Height;
+ FTarget.Width := Width;
+ FTarget.Height := Height;
+
+ FHintData.Tree.Update;
+
+ // capture screen
+ DC := GetDC(0);
+ try
+ with Rect do
+ BitBlt(FBackground.Canvas.Handle, 0, 0, Width, Height, DC, Left, Top, SRCCOPY);
+ finally
+ ReleaseDC(0, DC);
+ end;
+
+ SetWindowPos(Handle, HWND_TOPMOST, Rect.Left, Rect.Top, Width, Height, SWP_SHOWWINDOW or SWP_NOACTIVATE);
+ with FHintData.Tree do
+ case DoGetAnimationType of
+ hatNone:
+ InvalidateRect(Self.Handle, nil, False);
+ hatFade:
+ begin
+ // Make sure the window is not drawn unanimated.
+ ValidateRect(Self.Handle, nil);
+ // Empirically determined animation duration shows that fading needs about twice as much time as
+ // sliding to show a comparable visual effect.
+ Animate(FadeAnimationStepCount, 2 * FAnimationDuration, AnimationCallback, nil);
+ end;
+ hatSlide:
+ begin
+ // Make sure the window is not drawn unanimated.
+ ValidateRect(Self.Handle, nil);
+ Animate(Self.Height, FAnimationDuration, AnimationCallback, nil);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string; AData: Pointer): TRect;
+
+var
+ TM: TTextMetric;
+ R: TRect;
+
+begin
+ // The hint window does not need any bidi mode setting but the caller of this method (TApplication.ActivateHint)
+ // does some unneccessary actions if the hint window is not left-to-right.
+ // The text alignment is based on the bidi mode passed in the hint data, hence we can
+ // simply set the window's mode to left-to-right (it might have been modified by the caller, if the
+ // tree window is right-to-left aligned).
+ BidiMode := bdLeftToRight;
+
+ FHintData := PVTHintData(AData)^;
+
+ with FHintData do
+ begin
+ // The draw tree gets its hint size by the application (but only if not a header hint is about to show).
+ // This size has already been determined in CMHintShow.
+ if (Tree is TCustomVirtualDrawTree) and Assigned(Node) then
+ Result := HintRect
+ else
+ begin
+ if Column <= NoColumn then
+ begin
+ BidiMode := Tree.BidiMode;
+ Alignment := Tree.Alignment;
+ end
+ else
+ begin
+ BidiMode := Tree.Header.Columns[Column].BidiMode;
+ Alignment := Tree.Header.Columns[Column].Alignment;
+ end;
+
+ if BidiMode <> bdLeftToRight then
+ ChangeBidiModeAlignment(Alignment);
+
+ if (Node = nil) or (Tree.FHintMode <> hmToolTip) then
+ begin
+ {$ifndef COMPILER_5_UP}
+ Canvas.Font := HintFont
+ {$else}
+ Canvas.Font := Screen.HintFont
+ {$endif COMPILER_5_UP}
+ end
+ else
+ begin
+ Canvas.Font := Tree.Font;
+ if Tree is TCustomVirtualStringTree then
+ with TCustomVirtualStringTree(Tree) do
+ DoPaintText(Node, Self.Canvas, Column, ttNormal);
+ end;
+
+ GetTextMetrics(Canvas.Handle, TM);
+ FTextHeight := TM.tmHeight;
+
+ if Length(DefaultHint) > 0 then
+ HintText := DefaultHint
+ else
+ if Tree.HintMode = hmToolTip then
+ HintText := Tree.DoGetNodeToolTip(Node, Column)
+ else
+ HintText := Tree.DoGetNodeHint(Node, Column);
+
+ if Length(HintText) = 0 then
+ Result := Rect(0, 0, 0, 0)
+ else
+ begin
+ if Assigned(Node) and (Tree.FHintMode = hmToolTip) then
+ begin
+ // Hint for a node.
+ if vsMultiline in Node.States then
+ begin
+ // Multiline tooltips use the columns width but extend the bottom border to fit the whole caption.
+ Result := Tree.GetDisplayRect(Node, Column, True, False);
+ // On Windows NT the behavior of the tooltip is slightly different to that on Windows 9x/Me.
+ // We don't have Unicode word wrap on the latter so the tooltip gets as wide as the largest line
+ // in the caption (limited by carriage return), which results in unoptimal overlay of the tooltip.
+ // On Windows NT the tooltip exactly overlays the node text.
+ if IsWinNT then
+ begin
+ // DT_CALCRECT sometimes also modifies the right border. But we are only interested in the bottom border.
+ R := Result;
+ Windows.DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), R, DT_CALCRECT or DT_WORDBREAK);
+ Result.Bottom := R.Bottom;
+ end
+ else
+ DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), Result, DT_CALCRECT, True);
+
+ // Adjust for text margin.
+ InflateRect(Result, 0, Tree.TextMargin);
+ Inc(Result.Right);
+ // If the node height is already large enough to cover the entire text, then we don't need the hint, though.
+ // However if the text is partially scrolled out of the client area then a hint is useful as well.
+ if ((Node.NodeHeight + 2) >= (Result.Bottom - Result.Top)) and not
+ ((Result.Left < 0) or (Result.Right > Tree.ClientWidth) or
+ (Result.Top < 0) or (Result.Bottom > Tree.ClientHeight)) then
+ begin
+ Result := Rect(0, 0, 0, 0);
+ Exit;
+ end;
+ end
+ else
+ begin
+ Result := Tree.GetDisplayRect(Node, Column, True, True);
+ if toShowHorzGridLines in Tree.TreeOptions.PaintOptions then
+ Dec(Result.Bottom);
+ end;
+ // Include a one pixel border.
+ InflateRect(Result, 1, 1);
+ // Make the coordinates relative. They will again be offset by the caller code.
+ OffsetRect(Result, -Result.Left - 1, -Result.Top - 1);
+ end
+ else
+ begin
+ // Hint for a header.
+ // Start with the base size of the hint in client coordinates.
+ Result := Rect(0, 0, MaxWidth, FTextHeight);
+ // Calculate the true size of the text rectangle.
+ DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), Result, DT_CALCRECT, True);
+ // The height of the text plus 2 pixels vertical margin plus the border determine the hint window height.
+ Inc(Result.Bottom, 6);
+ // The text is centered horizontally with usual text margin for left and right borders (plus border).
+ Inc(Result.Right, 2 * Tree.FTextMargin + 2);
+ end;
+
+ {$ifndef COMPILER_7_UP}
+ // Add some pixels for the shadow if MMX is available for blending.
+ if MMXAvailable then
+ begin
+ Inc(Result.Right, ShadowSize);
+ Inc(Result.Bottom, ShadowSize);
+ end;
+ {$endif COMPILER_7_UP}
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeHintWindow.IsHintMsg(var Msg: TMsg): Boolean;
+
+// The VCL is a bit too generous when telling that an existing hint can be cancelled. Need to specify further here.
+
+begin
+ Result := inherited IsHintMsg(Msg) and HandleAllocated and IsWindowVisible(Handle);
+ if Result and (Msg.Message = WM_NCMOUSEMOVE) then
+ Result := False
+ else
+ // Work around problems with keypresses while doing hint animation.
+ if HandleAllocated and IsWindowVisible(Handle) and (Msg.Message >= WM_KEYFIRST) and (Msg.Message <= WM_KEYLAST) and
+ (tsInAnimation in FHintData.Tree.FStates) and TranslateMessage(Msg) then
+ DispatchMessage(Msg);
+end;
+
+//----------------- TVTDragImage ---------------------------------------------------------------------------------------
+
+constructor TVTDragImage.Create(AOwner: TBaseVirtualTree);
+
+begin
+ FOwner := AOwner;
+ FTransparency := 128;
+ FPreBlendBias := 0;
+ FPostBlendBias := 0;
+ FFade := False;
+ FRestriction := dmrNone;
+ FColorKey := clNone;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVTDragImage.Destroy;
+
+begin
+ EndDrag;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragImage.GetVisible: Boolean;
+
+// Returns True if the internal drag image is used (i.e. the system does not natively support drag images) and
+// the internal image is currently visible on screen.
+
+begin
+ Result := FStates * [disHidden, disInDrag, disPrepared, disSystemSupport] = [disInDrag, disPrepared];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.InternalShowDragImage(ScreenDC: HDC);
+
+// Frequently called helper routine to actually do the blend and put it onto the screen.
+// Only used if the system does not support drag images.
+
+var
+ BlendMode: TBlendMode;
+
+begin
+ with FAlphaImage do
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FBackImage.Canvas.Handle, 0, 0, SRCCOPY);
+ if not FFade and (FColorKey = clNone) then
+ BlendMode := bmConstantAlpha
+ else
+ BlendMode := bmMasterAlpha;
+ with FDragImage do
+ AlphaBlend(Canvas.Handle, FAlphaImage.Canvas.Handle, Rect(0, 0, Width, Height), Point(0, 0), BlendMode,
+ FTransparency, FPostBlendBias);
+
+ with FAlphaImage do
+ BitBlt(ScreenDC, FImagePosition.X, FImagePosition.Y, Width, Height, Canvas.Handle, 0, 0, SRCCOPY);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.MakeAlphaChannel(Source, Target: TBitmap);
+
+// Helper method to create a proper alpha channel in Target (which must be in 32 bit pixel format), depending
+// on the settings for the drag image and the color values in Source.
+// Only used if the system does not support drag images.
+
+type
+ PBGRA = ^TBGRA;
+ TBGRA = packed record
+ case Boolean of
+ False:
+ (Color: Cardinal);
+ True:
+ (BGR: array[0..2] of Byte;
+ Alpha: Byte);
+ end;
+
+var
+ Color,
+ ColorKeyRef: COLORREF;
+ UseColorKey: Boolean;
+ SourceRun,
+ TargetRun: PBGRA;
+ X, Y,
+ MaxDimension,
+ HalfWidth,
+ HalfHeight: Integer;
+ T: Extended;
+
+begin
+ UseColorKey := ColorKey <> clNone;
+ ColorKeyRef := ColorToRGB(ColorKey) and $FFFFFF;
+ // Color values are in the form BGR (red on LSB) while bitmap colors are in the form ARGB (blue on LSB)
+ // hence we have to swap red and blue in the color key.
+ with TBGRA(ColorKeyRef) do
+ begin
+ X := BGR[0];
+ BGR[0] := BGR[2];
+ BGR[2] := X;
+ end;
+
+ with Target do
+ begin
+ MaxDimension := Max(Width, Height);
+
+ HalfWidth := Width div 2;
+ HalfHeight := Height div 2;
+ for Y := 0 to Height - 1 do
+ begin
+ TargetRun := Scanline[Y];
+ SourceRun := Source.Scanline[Y];
+ for X := 0 to Width - 1 do
+ begin
+ Color := SourceRun.Color and $FFFFFF;
+ if UseColorKey and (Color = ColorKeyRef) then
+ TargetRun.Alpha := 0
+ else
+ begin
+ // If the color is not the given color key (or none is used) then do full calculation of a bell curve.
+ T := exp(-8 * Sqrt(Sqr((X - HalfWidth) / MaxDimension) + Sqr((Y - HalfHeight) / MaxDimension)));
+ TargetRun.Alpha := Round(255 * T);
+ end;
+ Inc(SourceRun);
+ Inc(TargetRun);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragImage.DragTo(P: TPoint; ForceRepaint: Boolean): Boolean;
+
+// Moves the drag image to a new position, which is determined from the passed point P and the previous
+// mouse position.
+// ForceRepaint is True if something on the screen changed and the back image must be refreshed.
+
+var
+ ScreenDC: HDC;
+ DeltaX,
+ DeltaY: Integer;
+
+ // optimized drag image move support
+ RSamp1,
+ RSamp2, // newly added parts from screen which will be overwritten
+ RDraw1,
+ RDraw2, // parts to be restored to screen
+ RScroll,
+ RClip: TRect; // ScrollDC of the existent background
+
+begin
+ // Determine distances to move the drag image. Take care for restrictions.
+ case FRestriction of
+ dmrHorizontalOnly:
+ begin
+ DeltaX := FLastPosition.X - P.X;
+ DeltaY := 0;
+ end;
+ dmrVerticalOnly:
+ begin
+ DeltaX := 0;
+ DeltaY := FLastPosition.Y - P.Y;
+ end;
+ else // dmrNone
+ DeltaX := FLastPosition.X - P.X;
+ DeltaY := FLastPosition.Y - P.Y;
+ end;
+
+ Result := (DeltaX <> 0) or (DeltaY <> 0) or ForceRepaint;
+ if Result then
+ begin
+ if Visible then
+ begin
+ // All this stuff is only called if we have to handle the drag image ourselves. If the system supports
+ // drag image then this is all never executed.
+ ScreenDC := GetDC(0);
+ try
+ if (Abs(DeltaX) >= FDragImage.Width) or (Abs(DeltaY) >= FDragImage.Height) or ForceRepaint then
+ begin
+ // If moved more than image size then just restore old screen and blit image to new position.
+ BitBlt(ScreenDC, FImagePosition.X, FImagePosition.Y, FBackImage.Width, FBackImage.Height,
+ FBackImage.Canvas.Handle, 0, 0, SRCCOPY);
+
+ if ForceRepaint then
+ UpdateWindow(FOwner.Handle);
+
+ Inc(FImagePosition.X, -DeltaX);
+ Inc(FImagePosition.Y, -DeltaY);
+
+ BitBlt(FBackImage.Canvas.Handle, 0, 0, FBackImage.Width, FBackImage.Height, ScreenDC, FImagePosition.X,
+ FImagePosition.Y, SRCCOPY);
+ end
+ else
+ begin
+ // overlapping copy
+ FillDragRectangles(FDragImage.Width, FDragImage.Height, DeltaX, DeltaY, RClip, RScroll, RSamp1, RSamp2, RDraw1,
+ RDraw2);
+
+ with FBackImage.Canvas do
+ begin
+ // restore uncovered areas of the screen
+ if DeltaX = 0 then
+ begin
+ with RDraw2 do
+ BitBlt(ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top, Right, Bottom, Handle, Left, Top,
+ SRCCOPY);
+ end
+ else
+ begin
+ if DeltaY = 0 then
+ begin
+ with RDraw1 do
+ BitBlt(ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top, Right, Bottom, Handle, Left, Top,
+ SRCCOPY);
+ end
+ else
+ begin
+ with RDraw1 do
+ BitBlt(ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top, Right, Bottom, Handle, Left, Top,
+ SRCCOPY);
+ with RDraw2 do
+ BitBlt(ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top, Right, Bottom, Handle, Left, Top,
+ SRCCOPY);
+ end;
+ end;
+
+ // move existent background
+ ScrollDC(Handle, DeltaX, DeltaY, RScroll, RClip, 0, nil);
+
+ Inc(FImagePosition.X, -DeltaX);
+ Inc(FImagePosition.Y, -DeltaY);
+
+ // Get first and second additional rectangle from screen.
+ if DeltaX = 0 then
+ begin
+ with RSamp2 do
+ BitBlt(Handle, Left, Top, Right, Bottom, ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top,
+ SRCCOPY);
+ end
+ else
+ if DeltaY = 0 then
+ begin
+ with RSamp1 do
+ BitBlt(Handle, Left, Top, Right, Bottom, ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top,
+ SRCCOPY);
+ end
+ else
+ begin
+ with RSamp1 do
+ BitBlt(Handle, Left, Top, Right, Bottom, ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top,
+ SRCCOPY);
+ with RSamp2 do
+ BitBlt(Handle, Left, Top, Right, Bottom, ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top,
+ SRCCOPY);
+ end;
+ end;
+ end;
+ InternalShowDragImage(ScreenDC);
+ finally
+ ReleaseDC(0, ScreenDC);
+ end;
+ end;
+ FLastPosition.X := P.X;
+ FLastPosition.Y := P.Y;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.EndDrag;
+
+begin
+ HideDragImage;
+ FStates := FStates - [disInDrag, disPrepared];
+
+ FBackImage.Free;
+ FBackImage := nil;
+ FDragImage.Free;
+ FDragImage := nil;
+ FAlphaImage.Free;
+ FAlphaImage := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragImage.GetDragImageRect: TRect;
+
+// Returns the current size and position of the drag image (screen coordinates).
+
+begin
+ if Visible then
+ begin
+ with FBackImage do
+ Result := Rect(FImagePosition.X, FImagePosition.Y, FImagePosition.X + Width, FImagePosition.Y + Height);
+ end
+ else
+ Result := Rect(0, 0, 0, 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.HideDragImage;
+
+var
+ ScreenDC: HDC;
+
+begin
+ if Visible then
+ begin
+ Include(FStates, disHidden);
+ ScreenDC := GetDC(0);
+ try
+ // restore screen
+ with FBackImage do
+ BitBlt(ScreenDC, FImagePosition.X, FImagePosition.Y, Width, Height, Canvas.Handle, 0, 0, SRCCOPY);
+ finally
+ ReleaseDC(0, ScreenDC);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.PrepareDrag(DragImage: TBitmap; ImagePosition, HotSpot: TPoint; const DataObject: IDataObject);
+
+// Creates all necessary structures to do alpha blended dragging using the given image.
+// ImagePostion and Hotspot are given in screen coordinates. The first determines where to place the drag image while
+// the second is the initial mouse position.
+// This method also determines whether the system supports drag images natively. If so then only minimal structures
+// are created.
+
+var
+ Width,
+ Height: Integer;
+ DragSourceHelper: IDragSourceHelper;
+ DragInfo: TSHDragImage;
+
+begin
+ Width := DragImage.Width;
+ Height := DragImage.Height;
+
+ // Determine whether the system supports the drag helper interfaces.
+ if Assigned(DataObject) and Succeeded(CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER,
+ IID_IDragSourceHelper, DragSourceHelper)) then
+ begin
+ Include(FStates, disSystemSupport);
+
+ // Supply the drag source helper with our drag image.
+ DragInfo.sizeDragImage.cx := Width;
+ DragInfo.sizeDragImage.cy := Height;
+ DragInfo.ptOffset.x := Width div 2;
+ DragInfo.ptOffset.y := Height div 2;
+ DragInfo.hbmpDragImage := CopyImage(DragImage.Handle, IMAGE_BITMAP, Width, Height, LR_COPYRETURNORG);
+ DragInfo.ColorRef := ColorToRGB(FColorKey);
+ if not Succeeded(DragSourceHelper.InitializeFromBitmap(DragInfo, DataObject)) then
+ begin
+ DeleteObject(DragInfo.hbmpDragImage);
+ Exclude(FStates, disSystemSupport);
+ end;
+ end
+ else
+ Exclude(FStates, disSystemSupport);
+
+ if MMXAvailable and not (disSystemSupport in FStates) then
+ begin
+ FLastPosition := HotSpot;
+
+ FDragImage := TBitmap.Create;
+ FDragImage.PixelFormat := pf32Bit;
+ FDragImage.Width := Width;
+ FDragImage.Height := Height;
+
+ FAlphaImage := TBitmap.Create;
+ FAlphaImage.PixelFormat := pf32Bit;
+ FAlphaImage.Width := Width;
+ FAlphaImage.Height := Height;
+
+ FBackImage := TBitmap.Create;
+ FBackImage.PixelFormat := pf32Bit;
+ FBackImage.Width := Width;
+ FBackImage.Height := Height;
+
+ // Copy the given drag image and apply pre blend bias if required.
+ if FPreBlendBias = 0 then
+ with FDragImage do
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, DragImage.Canvas.Handle, 0, 0, SRCCOPY)
+ else
+ AlphaBlend(DragImage.Canvas.Handle, FDragImage.Canvas.Handle, Rect(0, 0, Width, Height), Point(0, 0),
+ bmConstantAlpha, 255, FPreBlendBias);
+
+ // Create a proper alpha channel also if no fading is required (transparent parts).
+ MakeAlphaChannel(DragImage, FDragImage);
+
+ FImagePosition := ImagePosition;
+
+ // Initially the drag image is hidden and will be shown during the immediately following DragEnter event.
+ FStates := FStates + [disInDrag, disHidden, disPrepared];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.RecaptureBackground(Tree: TBaseVirtualTree; R: TRect; VisibleRegion: HRGN;
+ CaptureNCArea, ReshowDragImage: Boolean);
+
+// Notification by the drop target tree to update the background image because something in the tree has changed.
+// Note: The passed rectangle is given in client coordinates of the current drop target tree (given in Tree).
+// The caller does not check if the given rectangle is actually within the drag image. Hence this method must do
+// all the checks.
+// This method does nothing if the system manages the drag image.
+
+var
+ DragRect,
+ ClipRect: TRect;
+ PaintTarget: TPoint;
+ PaintOptions: TVTInternalPaintOptions;
+ ScreenDC: HDC;
+
+begin
+ // Recapturing means we want the tree to paint the new part into our back bitmap instead to the screen.
+ if Visible then
+ begin
+ // Create the minimum rectangle to be recaptured.
+ MapWindowPoints(Tree.Handle, 0, R, 2);
+ DragRect := GetDragImageRect;
+ IntersectRect(R, R, DragRect);
+
+ OffsetRgn(VisibleRegion, -DragRect.Left, -DragRect.Top);
+
+ // The target position for painting in the drag image is relative and can be determined from screen coordinates too.
+ PaintTarget.X := R.Left - DragRect.Left;
+ PaintTarget.Y := R.Top - DragRect.Top;
+
+ // The source rectangle is determined by the offsets in the tree.
+ MapWindowPoints(0, Tree.Handle, R, 2);
+ OffsetRect(R, -Tree.FOffsetX, -Tree.FOffsetY);
+
+ // Finally let the tree paint the relevant part and upate the drag image on screen.
+ PaintOptions := [poBackground, poColumnColor, poDrawFocusRect, poDrawDropMark, poDrawSelection, poGridLines];
+ with FBackImage do
+ begin
+ ClipRect.TopLeft := PaintTarget;
+ ClipRect.Right := ClipRect.Left + R.Right - R.Left;
+ ClipRect.Bottom := ClipRect.Top + R.Bottom - R.Top;
+ Tree.LimitPaintingToArea(Canvas, ClipRect, VisibleRegion);
+ Tree.PaintTree(Canvas, R, PaintTarget, PaintOptions);
+
+ if CaptureNCArea then
+ begin
+ // For the non-client area we only need the visible region of the window as limit for painting.
+ SelectClipRgn(Canvas.Handle, VisibleRegion);
+ // Since WM_PRINT cannot be given a position where to draw we simply move the window origin and
+ // get the same effect.
+ GetWindowRect(Tree.Handle, ClipRect);
+ SetWindowOrgEx(Canvas.Handle, DragRect.Left - ClipRect.Left, DragRect.Top - ClipRect.Top, nil);
+ Tree.Perform(WM_PRINT, Integer(Canvas.Handle), PRF_NONCLIENT);
+ SetWindowOrgEx(Canvas.Handle, 0, 0, nil);
+ end;
+ SelectClipRgn(Canvas.Handle, 0);
+
+ if ReshowDragImage then
+ begin
+ GDIFlush;
+ ScreenDC := GetDC(0);
+ try
+ InternalShowDragImage(ScreenDC);
+ finally
+ ReleaseDC(0, ScreenDC);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.ShowDragImage;
+
+// Shows the drag image after it has been hidden by HideDragImage.
+// Note: there might be a new background now.
+// Also this method does nothing if the system manages the drag image.
+
+var
+ ScreenDC: HDC;
+
+begin
+ if FStates * [disInDrag, disHidden, disPrepared, disSystemSupport] = [disInDrag, disHidden, disPrepared] then
+ begin
+ Exclude(FStates, disHidden);
+
+ GDIFlush;
+ ScreenDC := GetDC(0);
+ try
+ BitBlt(FBackImage.Canvas.Handle, 0, 0, FBackImage.Width, FBackImage.Height, ScreenDC, FImagePosition.X,
+ FImagePosition.Y, SRCCOPY);
+
+ InternalShowDragImage(ScreenDC);
+ finally
+ ReleaseDC(0, ScreenDC);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragImage.WillMove(P: TPoint): Boolean;
+
+// This method determines whether the drag image would "physically" move when DragTo would be called with the same
+// target point.
+// Always returns False if the system drag image support is available.
+
+var
+ DeltaX,
+ DeltaY: Integer;
+
+begin
+ Result := Visible;
+ if Result then
+ begin
+ // Determine distances to move the drag image. Take care for restrictions.
+ case FRestriction of
+ dmrHorizontalOnly:
+ begin
+ DeltaX := FLastPosition.X - P.X;
+ DeltaY := 0;
+ end;
+ dmrVerticalOnly:
+ begin
+ DeltaX := 0;
+ DeltaY := FLastPosition.Y - P.Y;
+ end;
+ else // dmrNone
+ DeltaX := FLastPosition.X - P.X;
+ DeltaY := FLastPosition.Y - P.Y;
+ end;
+
+ Result := (DeltaX <> 0) or (DeltaY <> 0);
+ end;
+end;
+
+//----------------- TVirtualTreeColumn ---------------------------------------------------------------------------------
+
+constructor TVirtualTreeColumn.Create(Collection: TCollection);
+
+begin
+ FWidth := 50;
+ FLastWidth := 50;
+ FMinWidth := 10;
+ FMaxWidth := 10000;
+ FImageIndex := -1;
+ FMargin := 4;
+ FSpacing := 4;
+ FText := '';
+ FOptions := DefaultColumnOptions;
+ FAlignment := taLeftJustify;
+ FBidiMode := bdLeftToRight;
+ FColor := clWindow;
+ FLayout := blGlyphLeft;
+
+ inherited Create(Collection);
+
+ FPosition := Owner.Count - 1;
+ // Read parent bidi mode and color values as default values.
+ ParentBiDiModeChanged;
+ ParentColorChanged;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVirtualTreeColumn.Destroy;
+
+var
+ I: Integer;
+
+begin
+ // Check if this column is somehow referenced by its collection parent or the header.
+ with Owner do
+ begin
+ // If the columns collection object is currently deleting all columns
+ // then we don't need to check the various cached indices individually.
+ if not FClearing then
+ begin
+ IndexChanged(Index, -1);
+
+ if Index = FHoverIndex then
+ FHoverIndex := NoColumn;
+ if Index = FDownIndex then
+ FDownIndex := NoColumn;
+ if Index = FTrackIndex then
+ FTrackIndex := NoColumn;
+ if Index = FClickIndex then
+ FClickIndex := NoColumn;
+
+ with Header do
+ begin
+ if Index = FAutoSizeIndex then
+ FAutoSizeIndex := NoColumn;
+ if Index = FMainColumn then
+ begin
+ // If the current main column is about to be destroyed then we have to find a new main column.
+ FMainColumn := NoColumn;
+ for I := 0 to Count - 1 do
+ if I <> Index then
+ begin
+ FMainColumn := I;
+ Break;
+ end;
+ end;
+ if Index = FSortColumn then
+ FSortColumn := NoColumn;
+ end;
+ end;
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.GetLeft: Integer;
+
+begin
+ Result := FLeft + Owner.Header.Treeview.FOffsetX;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.IsBiDiModeStored: Boolean;
+
+begin
+ Result := not (coParentBiDiMode in FOptions);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.IsColorStored: Boolean;
+
+begin
+ Result := not (coParentColor in FOptions);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetAlignment(const Value: TAlignment);
+
+begin
+ if FAlignment <> Value then
+ begin
+ FAlignment := Value;
+ Changed(False);
+ // Setting the alignment affects also the tree, hence invalidate it too.
+ Owner.Header.TreeView.Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetBiDiMode(Value: TBiDiMode);
+
+begin
+ if Value <> FBiDiMode then
+ begin
+ FBiDiMode := Value;
+ Exclude(FOptions, coParentBiDiMode);
+ Changed(False);
+ // Setting the alignment affects also the tree, hence invalidate it too.
+ Owner.Header.TreeView.Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetColor(const Value: TColor);
+
+begin
+ if FColor <> Value then
+ begin
+ FColor := Value;
+ Exclude(FOptions, coParentColor);
+ Changed(False);
+ Owner.Header.TreeView.Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetImageIndex(Value: TImageIndex);
+
+begin
+ if Value <> FImageIndex then
+ begin
+ FImageIndex := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetLayout(Value: TVTHeaderColumnLayout);
+
+begin
+ if FLayout <> Value then
+ begin
+ FLayout := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetMargin(Value: Integer);
+
+begin
+ // Compatibility setting for -1.
+ if Value < 0 then
+ Value := 4;
+ if FMargin <> Value then
+ begin
+ FMargin := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetMaxWidth(Value: Integer);
+
+begin
+ if Value < FMinWidth then
+ Value := FMinWidth;
+ if Value > 10000 then
+ Value := 10000;
+ FMaxWidth := Value;
+ SetWidth(FWidth);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetMinWidth(Value: Integer);
+
+begin
+ if Value < 0 then
+ Value := 0;
+ if Value > FMaxWidth then
+ Value := FMaxWidth;
+ FMinWidth := Value;
+ SetWidth(FWidth);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetOptions(Value: TVTColumnOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTColumnOptions;
+ VisibleChanged,
+ ColorChanged: Boolean;
+
+begin
+ if FOptions <> Value then
+ begin
+ ToBeCleared := FOptions - Value;
+ ToBeSet := Value - FOptions;
+
+ FOptions := Value;
+
+ VisibleChanged := coVisible in (ToBeSet + ToBeCleared);
+ ColorChanged := coParentColor in ToBeSet;
+
+ if coParentBidiMode in ToBeSet then
+ ParentBiDiModeChanged;
+ if ColorChanged then
+ ParentColorChanged;
+
+ Changed(False);
+ // Need to repaint and adjust the owner tree too.
+ with Owner, Header.Treeview do
+ if not (csLoading in ComponentState) and (VisibleChanged or ColorChanged) and (UpdateCount = 0) then
+ begin
+ Invalidate;
+ if VisibleChanged then
+ UpdateHorizontalScrollBar(False);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetPosition(Value: TColumnPosition);
+
+begin
+ if csLoading in Owner.Header.Treeview.ComponentState then
+ // Only cache the position for final fixup when loading from DFM.
+ FPosition := Value
+ else
+ begin
+ if Value >= TColumnPosition(Collection.Count) then
+ Value := Collection.Count - 1;
+ if FPosition <> Value then
+ with Owner do
+ begin
+ InitializePositionArray;
+ // need to repaint and adjust the owner tree too
+ with Header do
+ begin
+ if not (csLoading in Treeview.ComponentState) and (UpdateCount = 0) then
+ begin
+ AdjustPosition(Self, Value);
+ UpdatePositions;
+ Treeview.CancelEditNode;
+ Invalidate(Self);
+ Treeview.Invalidate;
+ Treeview.UpdateHorizontalScrollBar(False);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetSpacing(Value: Integer);
+
+begin
+ if FSpacing <> Value then
+ begin
+ FSpacing := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetStyle(Value: TVirtualTreeColumnStyle);
+
+begin
+ if FStyle <> Value then
+ begin
+ FStyle := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetText(const Value: WideString);
+
+begin
+ if FText <> Value then
+ begin
+ FText := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetWidth(Value: Integer);
+
+begin
+ if Value < FMinWidth then
+ Value := FMinWidth;
+ if Value > FMaxWidth then
+ Value := FMaxWidth;
+
+ if FWidth <> Value then
+ begin
+ FLastWidth := FWidth;
+ with Owner, Header do
+ begin
+ if not (hoAutoResize in FOptions) or (Index <> FAutoSizeIndex) then
+ begin
+ FWidth := Value;
+ UpdatePositions;
+ end;
+ if not (csLoading in Treeview.ComponentState) and (UpdateCount = 0) then
+ begin
+ if hoAutoResize in FOptions then
+ AdjustAutoSize(Index);
+ Treeview.DoColumnResize(Index);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ComputeHeaderLayout(DC: HDC; const Client: TRect; UseHeaderGlyph, UseSortGlyph: Boolean;
+ var HeaderGlyphPos, SortGlyphPos: TPoint; var TextBounds: TRect);
+
+// The layout of a column header is determined by a lot of factors. This method takes them all into account and
+// determines all necessary positions and bounds:
+// - for the header text
+// - the header glyph
+// - the sort glyph
+
+var
+ TextSize: TSize;
+ TextPos,
+ ClientSize,
+ HeaderGlyphSize,
+ SortGlyphSize: TPoint;
+ CurrentAlignment: TAlignment;
+ MinLeft,
+ MaxRight,
+ TextSpacing: Integer;
+ UseText: Boolean;
+
+begin
+ UseText := Length(FText) > 0;
+ // If nothing is to show then don't waste time with useless preparation.
+ if not (UseText or UseHeaderGlyph or UseSortGlyph) then
+ Exit;
+
+ CurrentAlignment := FAlignment;
+ if FBidiMode <> bdLeftToRight then
+ ChangeBiDiModeAlignment(CurrentAlignment);
+
+ // Calculate sizes of the involved items.
+ ClientSize := Point(Client.Right - Client.Left, Client.Bottom - Client.Top);
+ with Owner, Header do
+ begin
+ if UseHeaderGlyph then
+ HeaderGlyphSize := Point(FImages.Width, FImages.Height)
+ else
+ HeaderGlyphSize := Point(0, 0);
+ if UseSortGlyph then
+ begin
+ SortGlyphSize := Point(UtilityImages.Width, UtilityImages.Height);
+ // In any case, the sort glyph is vertically centered.
+ SortGlyphPos.Y := (ClientSize.Y - SortGlyphSize.Y) div 2;
+ end
+ else
+ SortGlyphSize := Point(0, 0);
+ end;
+
+ if UseText then
+ begin
+ GetTextExtentPoint32W(DC, PWideChar(FText), Length(FText), TextSize);
+ Inc(TextSize.cx, 2);
+ TextBounds := Rect(0, 0, TextSize.cx, TextSize.cy);
+ TextSpacing := FSpacing;
+ end
+ else
+ begin
+ TextSpacing := 0;
+ TextSize.cx := 0;
+ TextSize.cy := 0;
+ end;
+
+ // Check first for the special case where nothing is shown except the sort glyph.
+ if UseSortGlyph and not (UseText or UseHeaderGlyph) then
+ begin
+ // Center the sort glyph in the available area if nothing else is there.
+ SortGlyphPos := Point((ClientSize.X - SortGlyphSize.X) div 2, (ClientSize.Y - SortGlyphSize.Y) div 2);
+ end
+ else
+ begin
+ // Determine extents of text and glyph and calculate positions which are clear from the layout.
+ if (Layout in [blGlyphLeft, blGlyphRight]) or not UseHeaderGlyph then
+ begin
+ HeaderGlyphPos.Y := (ClientSize.Y - HeaderGlyphSize.Y) div 2;
+ TextPos.Y := (ClientSize.Y - TextSize.cy) div 2;
+ end
+ else
+ begin
+ if Layout = blGlyphTop then
+ begin
+ HeaderGlyphPos.Y := (ClientSize.Y - HeaderGlyphSize.Y - TextSize.cy - TextSpacing) div 2;
+ TextPos.Y := HeaderGlyphPos.Y + HeaderGlyphSize.Y + TextSpacing;
+ end
+ else
+ begin
+ TextPos.Y := (ClientSize.Y - HeaderGlyphSize.Y - TextSize.cy - TextSpacing) div 2;
+ HeaderGlyphPos.Y := TextPos.Y + TextSize.cy + TextSpacing;
+ end;
+ end;
+
+ // Each alignment needs special consideration.
+ case CurrentAlignment of
+ taLeftJustify:
+ begin
+ MinLeft := FMargin;
+ if UseSortGlyph and (FBidiMode <> bdLeftToRight) then
+ begin
+ // In RTL context is the sort glyph placed on the left hand side.
+ SortGlyphPos.X := MinLeft;
+ Inc(MinLeft, SortGlyphSize.X + FSpacing);
+ end;
+ if Layout in [blGlyphTop, blGlyphBottom] then
+ begin
+ // Header glyph is above or below text, so both must be considered when calculating
+ // the left positition of the sort glyph (if it is on the right hand side).
+ TextPos.X := MinLeft;
+ if UseHeaderGlyph then
+ begin
+ HeaderGlyphPos.X := (ClientSize.X - HeaderGlyphSize.X) div 2;
+ if HeaderGlyphPos.X < MinLeft then
+ HeaderGlyphPos.X := MinLeft;
+ MinLeft := Max(TextPos.X + TextSize.cx + TextSpacing, HeaderGlyphPos.X + HeaderGlyphSize.X + FSpacing);
+ end
+ else
+ MinLeft := TextPos.X + TextSize.cx + TextSpacing;
+ end
+ else
+ begin
+ // Everything is lined up. TextSpacing might be 0 if there is no text.
+ // This simplifies the calculation because no extra tests are necessary.
+ if UseHeaderGlyph and (Layout = blGlyphLeft) then
+ begin
+ HeaderGlyphPos.X := MinLeft;
+ Inc(MinLeft, HeaderGlyphSize.X + FSpacing);
+ end;
+ TextPos.X := MinLeft;
+ Inc(MinLeft, TextSize.cx + TextSpacing);
+ if UseHeaderGlyph and (Layout = blGlyphRight) then
+ begin
+ HeaderGlyphPos.X := MinLeft;
+ Inc(MinLeft, HeaderGlyphSize.X + FSpacing);
+ end;
+ end;
+ if UseSortGlyph and (FBidiMode = bdLeftToRight) then
+ SortGlyphPos.X := MinLeft;
+ end;
+ taCenter:
+ begin
+ if Layout in [blGlyphTop, blGlyphBottom] then
+ begin
+ HeaderGlyphPos.X := (ClientSize.X - HeaderGlyphSize.X) div 2;
+ TextPos.X := (ClientSize.X - TextSize.cx) div 2;
+ if UseSortGlyph then
+ Dec(TextPos.X, SortGlyphSize.X div 2);
+ end
+ else
+ begin
+ MinLeft := (ClientSize.X - HeaderGlyphSize.X - TextSpacing - TextSize.cx) div 2;
+ if UseHeaderGlyph and (Layout = blGlyphLeft) then
+ begin
+ HeaderGlyphPos.X := MinLeft;
+ Inc(MinLeft, HeaderGlyphSize.X + TextSpacing);
+ end;
+ TextPos.X := MinLeft;
+ Inc(MinLeft, TextSize.cx + TextSpacing);
+ if UseHeaderGlyph and (Layout = blGlyphRight) then
+ HeaderGlyphPos.X := MinLeft;
+ end;
+ if UseHeaderGlyph then
+ begin
+ MinLeft := Min(HeaderGlyphPos.X, TextPos.X);
+ MaxRight := Max(HeaderGlyphPos.X + HeaderGlyphSize.X, TextPos.X + TextSize.cx);
+ end
+ else
+ begin
+ MinLeft := TextPos.X;
+ MaxRight := TextPos.X + TextSize.cx;
+ end;
+ // Place the sort glyph directly to the left or right of the larger item.
+ if UseSortGlyph then
+ if FBidiMode = bdLeftToRight then
+ begin
+ // Sort glyph on the right hand side.
+ SortGlyphPos.X := MaxRight + FSpacing;
+ end
+ else
+ begin
+ // Sort glyph on the left hand side.
+ SortGlyphPos.X := MinLeft - FSpacing - SortGlyphSize.X;
+ end;
+ end;
+ else
+ // taRightJustify
+ MaxRight := ClientSize.X - FMargin;
+ if UseSortGlyph and (FBidiMode = bdLeftToRight) then
+ begin
+ // In LTR context is the sort glyph placed on the right hand side.
+ Dec(MaxRight, SortGlyphSize.X);
+ SortGlyphPos.X := MaxRight;
+ Dec(MaxRight, FSpacing);
+ end;
+ if Layout in [blGlyphTop, blGlyphBottom] then
+ begin
+ TextPos.X := MaxRight - TextSize.cx;
+ if UseHeaderGlyph then
+ begin
+ HeaderGlyphPos.X := (ClientSize.X - HeaderGlyphSize.X) div 2;
+ if HeaderGlyphPos.X + HeaderGlyphSize.X + FSpacing > MaxRight then
+ HeaderGlyphPos.X := MaxRight - HeaderGlyphSize.X - FSpacing;
+ MaxRight := Min(TextPos.X - TextSpacing, HeaderGlyphPos.X - FSpacing);
+ end
+ else
+ MaxRight := TextPos.X - TextSpacing;
+ end
+ else
+ begin
+ // Everything is lined up. TextSpacing might be 0 if there is no text.
+ // This simplifies the calculation because no extra tests are necessary.
+ if UseHeaderGlyph and (Layout = blGlyphRight) then
+ begin
+ HeaderGlyphPos.X := MaxRight - HeaderGlyphSize.X;
+ MaxRight := HeaderGlyphPos.X - FSpacing;
+ end;
+ TextPos.X := MaxRight - TextSize.cx;
+ MaxRight := TextPos.X - TextSpacing;
+ if UseHeaderGlyph and (Layout = blGlyphLeft) then
+ begin
+ HeaderGlyphPos.X := MaxRight - HeaderGlyphSize.X;
+ MaxRight := HeaderGlyphPos.X - FSpacing;
+ end;
+ end;
+ if UseSortGlyph and (FBidiMode <> bdLeftToRight) then
+ SortGlyphPos.X := MaxRight - SortGlyphSize.X;
+ end;
+ end;
+
+ // Once the position of each element is determined there remains only one but important step.
+ // The horizontal positions of every element must be adjusted so that it always fits into the
+ // given header area. This is accomplished by shorten the text appropriately.
+
+ // These are the maximum bounds. Nothing goes beyond them.
+ MinLeft := FMargin;
+ MaxRight := ClientSize.X - FMargin;
+ if UseSortGlyph then
+ begin
+ if FBidiMode = bdLeftToRight then
+ begin
+ // Sort glyph on the right hand side.
+ if SortGlyphPos.X + SortGlyphSize.X > MaxRight then
+ SortGlyphPos.X := MaxRight - SortGlyphSize.X;
+ MaxRight := SortGlyphPos.X - FSpacing;
+ end;
+
+ // Consider also the left side of the sort glyph regardless of the bidi mode.
+ if SortGlyphPos.X < MinLeft then
+ SortGlyphPos.X := MinLeft;
+ // Left border needs only adjustment if the sort glyph marks the left border.
+ if FBidiMode <> bdLeftToRight then
+ MinLeft := SortGlyphPos.X + SortGlyphSize.X + FSpacing;
+
+ // Finally transform sort glyph to its actual position.
+ with SortGlyphPos do
+ begin
+ Inc(X, Client.Left);
+ Inc(Y, Client.Top);
+ end;
+ end;
+ if UseHeaderGlyph then
+ begin
+ if HeaderGlyphPos.X + HeaderGlyphSize.X > MaxRight then
+ HeaderGlyphPos.X := MaxRight - HeaderGlyphSize.X;
+ if Layout = blGlyphRight then
+ MaxRight := HeaderGlyphPos.X - FSpacing;
+ if HeaderGlyphPos.X < MinLeft then
+ HeaderGlyphPos.X := MinLeft;
+ if Layout = blGlyphLeft then
+ MinLeft := HeaderGlyphPos.X + HeaderGlyphSize.X + FSpacing;
+ // Finally transform header glyph to its actual position.
+ with HeaderGlyphPos do
+ begin
+ Inc(X, Client.Left);
+ Inc(Y, Client.Top);
+ end;
+ end;
+ if UseText then
+ begin
+ if TextPos.X < MinLeft then
+ TextPos.X := MinLeft;
+ OffsetRect(TextBounds, TextPos.X, TextPos.Y);
+ if TextBounds.Right > MaxRight then
+ TextBounds.Right := MaxRight;
+ OffsetRect(TextBounds, Client.Left, Client.Top);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.DefineProperties(Filer: TFiler);
+
+begin
+ inherited;
+
+ // Must define a new name for the properties otherwise the VCL will try to load the wide string
+ // without asking us and screws it completely up.
+ Filer.DefineProperty('WideText', ReadText, WriteText, FText <> '');
+ Filer.DefineProperty('WideHint', ReadHint, WriteHint, FHint <> '');
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.GetAbsoluteBounds(var Left, Right: Integer);
+
+// Returns the column's left and right bounds in header coordinates, that is, independant of the scrolling position.
+
+begin
+ Left := FLeft;
+ Right := FLeft + FWidth;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.GetDisplayName: string;
+
+// Returns the column text if it only contains ANSI characters, otherwise the column id is returned because the IDE
+// still cannot handle Unicode strings.
+
+var
+ I: Integer;
+
+begin
+ // Check if the text of the column contains characters > 255
+ I := 1;
+ while I <= Length(FText) do
+ begin
+ if Ord(FText[I]) > 255 then
+ Break;
+ Inc(I);
+ end;
+
+ if I > Length(FText) then
+ Result := FText // implicit conversion
+ else
+ Result := Format('Column %d', [Index]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.GetOwner: TVirtualTreeColumns;
+
+begin
+ Result := Collection as TVirtualTreeColumns;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ReadText(Reader: TReader);
+
+begin
+ case Reader.NextValue of
+ vaLString, vaString:
+ SetText(Reader.ReadString);
+ else
+ SetText(Reader.ReadWideString);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetIndex(Value: Integer);
+
+begin
+ if Index <> Value then
+ begin
+ // Tell the columns collection about the index change. Its position array must be updated.
+ Owner.IndexChanged(Index, Value);
+
+ inherited;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ReadHint(Reader: TReader);
+
+begin
+ case Reader.NextValue of
+ vaLString, vaString:
+ FHint := Reader.ReadString;
+ else
+ FHint := Reader.ReadWideString;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.WriteHint(Writer: TWriter);
+
+begin
+ Writer.WriteWideString(FHint);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.WriteText(Writer: TWriter);
+
+begin
+ Writer.WriteWideString(FText);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.Assign(Source: TPersistent);
+
+var
+ OldOptions: TVTColumnOptions;
+
+begin
+ if Source is TVirtualTreeColumn then
+ begin
+ OldOptions := FOptions;
+ FOptions := [];
+
+ BiDiMode := TVirtualTreeColumn(Source).BiDiMode;
+ ImageIndex := TVirtualTreeColumn(Source).ImageIndex;
+ Layout := TVirtualTreeColumn(Source).Layout;
+ Margin := TVirtualTreeColumn(Source).Margin;
+ MaxWidth := TVirtualTreeColumn(Source).MaxWidth;
+ MinWidth := TVirtualTreeColumn(Source).MinWidth;
+ Position := TVirtualTreeColumn(Source).Position;
+ Spacing := TVirtualTreeColumn(Source).Spacing;
+ Style := TVirtualTreeColumn(Source).Style;
+ Text := TVirtualTreeColumn(Source).Text;
+ Hint := TVirtualTreeColumn(Source).Hint;
+ Width := TVirtualTreeColumn(Source).Width;
+ Alignment := TVirtualTreeColumn(Source).Alignment;
+ Color := TVirtualTreeColumn(Source).Color;
+ Tag := TVirtualTreeColumn(Source).Tag;
+
+ // Order is important. Assign options last.
+ FOptions := OldOptions;
+ Options := TVirtualTreeColumn(Source).Options;
+
+ Changed(False);
+ end
+ else
+ inherited Assign(Source);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.Equals(OtherColumn: TVirtualTreeColumn): Boolean;
+
+begin
+ Result := (BiDiMode = OtherColumn.BiDiMode) and
+ (ImageIndex = OtherColumn.ImageIndex) and
+ (Layout = OtherColumn.Layout) and
+ (Margin = OtherColumn.Margin) and
+ (MaxWidth = OtherColumn.MaxWidth) and
+ (MinWidth = OtherColumn.MinWidth) and
+ (Position = OtherColumn.Position) and
+ (Spacing = OtherColumn.Spacing) and
+ (Style = OtherColumn.Style) and
+ (Text = OtherColumn.Text) and
+ (Hint = OtherColumn.Hint) and
+ (Width = OtherColumn.Width) and
+ (Alignment = OtherColumn.Alignment) and
+ (Color = OtherColumn.Color) and
+ (Tag = OtherColumn.Tag) and
+ (Options = OtherColumn.Options);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.GetRect: TRect;
+
+// Returns the rectangle this column occupies in the header (relative to (0, 0) of the non-client area).
+
+begin
+ with TVirtualTreeColumns(GetOwner).FHeader do
+ Result := Treeview.FHeaderRect;
+ Inc(Result.Left, FLeft);
+ Result.Right := Result.Left + FWidth;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.LoadFromStream(const Stream: TStream; Version: Integer);
+
+ //--------------- local function --------------------------------------------
+
+ function ConvertOptions(Value: Cardinal): TVTColumnOptions;
+
+ // Converts the given raw value which represents column options for possibly older
+ // formats to the current format.
+
+ begin
+ if Version > 1 then
+ Result := TVTColumnOptions(Byte(Value))
+ else
+ begin
+ // In version 2 coParentColor has been added. This needs an option shift for older stream formats.
+ // The first (lower) 4 options remain as they are.
+ Result := TVTColumnOptions(Byte(Value) and $F);
+ Value := (Value and not $F) shl 1;
+ Result := Result + TVTColumnOptions(Byte(Value));
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ Dummy: Integer;
+ S: WideString;
+
+begin
+ with Stream do
+ begin
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SetLength(S, Dummy);
+ ReadBuffer(PWideChar(S)^, 2 * Dummy);
+ Text := S;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SetLength(FHint, Dummy);
+ ReadBuffer(PWideChar(FHint)^, 2 * Dummy);
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Width := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ MinWidth := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ MaxWidth := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Style := TVirtualTreeColumnStyle(Dummy);
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ ImageIndex := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Layout := TVTHeaderColumnLayout(Dummy);
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Margin := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Spacing := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ BiDiMode := TBiDiMode(Dummy);
+
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Options := ConvertOptions(Dummy);
+
+ if Version > 0 then
+ begin
+ // Parts which have been introduced/changed with header stream version 1+.
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Tag := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Alignment := TAlignment(Dummy);
+
+ if Version > 1 then
+ begin
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Color := TColor(Dummy);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ParentBiDiModeChanged;
+
+var
+ Columns: TVirtualTreeColumns;
+
+begin
+ if coParentBiDiMode in FOptions then
+ begin
+ Columns := GetOwner as TVirtualTreeColumns;
+ if Assigned(Columns) and (FBidiMode <> Columns.FHeader.Treeview.BiDiMode) then
+ begin
+ FBiDiMode := Columns.FHeader.Treeview.BiDiMode;
+ Changed(False);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ParentColorChanged;
+
+var
+ Columns: TVirtualTreeColumns;
+
+begin
+ if coParentColor in FOptions then
+ begin
+ Columns := GetOwner as TVirtualTreeColumns;
+ if Assigned(Columns) and (FColor <> Columns.FHeader.Treeview.Color) then
+ begin
+ FColor := Columns.FHeader.Treeview.Color;
+ Changed(False);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.RestoreLastWidth;
+
+begin
+ TVirtualTreeColumns(GetOwner).AnimatedResize(Index, FLastWidth);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SaveToStream(const Stream: TStream);
+
+var
+ Dummy: Integer;
+
+begin
+ with Stream do
+ begin
+ Dummy := Length(FText);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ WriteBuffer(PWideChar(FText)^, 2 * Dummy);
+ Dummy := Length(FHint);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ WriteBuffer(PWideChar(FHint)^, 2 * Dummy);
+ WriteBuffer(FWidth, SizeOf(FWidth));
+ WriteBuffer(FMinWidth, SizeOf(FMinWidth));
+ WriteBuffer(FMaxWidth, SizeOf(FMaxWidth));
+ Dummy := Ord(FStyle);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := FImageIndex;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Ord(FLayout);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ WriteBuffer(FMargin, SizeOf(FMargin));
+ WriteBuffer(FSpacing, SizeOf(FSpacing));
+ Dummy := Ord(FBiDiMode);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Byte(FOptions);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+
+ // parts introduce with stream version 1
+ WriteBuffer(FTag, SizeOf(Dummy));
+ Dummy := Cardinal(FAlignment);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+
+ // parts introduce with stream version 2
+ Dummy := Integer(FColor);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.UseRightToLeftReading: Boolean;
+
+begin
+ Result := FBiDiMode <> bdLeftToRight;
+end;
+
+//----------------- TVirtualTreeColumns --------------------------------------------------------------------------------
+
+constructor TVirtualTreeColumns.Create(AOwner: TVTHeader);
+
+var
+ ColumnClass: TVirtualTreeColumnClass;
+
+begin
+ FHeader := AOwner;
+
+ // Determine column class to be used in the header.
+ ColumnClass := AOwner.FOwner.GetColumnClass;
+ // The owner tree always returns the default tree column class if not changed by application/descentants.
+ inherited Create(ColumnClass);
+
+ FHeaderBitmap := TBitmap.Create;
+ FHeaderBitmap.PixelFormat := pf32Bit;
+
+ FHoverIndex := NoColumn;
+ FDownIndex := NoColumn;
+ FClickIndex := NoColumn;
+ FDropTarget := NoColumn;
+ FTrackIndex := NoColumn;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVirtualTreeColumns.Destroy;
+
+begin
+ FHeaderBitmap.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.DrawButtonText(DC: HDC; Caption: WideString; Bounds: TRect; Enabled, Hot: Boolean;
+ DrawFormat: Cardinal);
+
+var
+ TextSpace: Integer;
+ Size: TSize;
+
+begin
+ // Do we need to shorten the caption due to limited space?
+ GetTextExtentPoint32W(DC, PWideChar(Caption), Length(Caption), Size);
+ TextSpace := Bounds.Right - Bounds.Left;
+ if TextSpace < Size.cx then
+ Caption := ShortenString(DC, Caption, TextSpace, DT_RTLREADING and DrawFormat <> 0);
+
+ SetBkMode(DC, TRANSPARENT);
+ if not Enabled then
+ begin
+ OffsetRect(Bounds, 1, 1);
+ SetTextColor(DC, ColorToRGB(clBtnHighlight));
+ if IsWinNT then
+ Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat)
+ else
+ DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat, False);
+ OffsetRect(Bounds, -1, -1);
+ SetTextColor(DC, ColorToRGB(clBtnShadow));
+ if IsWinNT then
+ Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat)
+ else
+ DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat, False);
+ end
+ else
+ begin
+ if Hot then
+ SetTextColor(DC, ColorToRGB(clBtnShadow))
+ else
+ SetTextColor(DC, ColorToRGB(FHeader.FFont.Color));
+ if IsWinNT then
+ Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat)
+ else
+ DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetItem(Index: TColumnIndex): TVirtualTreeColumn;
+
+begin
+ Result := TVirtualTreeColumn(inherited GetItem(Index));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetNewIndex(P: TPoint; var OldIndex: TColumnIndex): Boolean;
+
+var
+ NewIndex: Integer;
+
+begin
+ Result := False;
+ // convert to local coordinates
+ Inc(P.Y, FHeader.FHeight);
+ NewIndex := ColumnFromPosition(P);
+ if NewIndex <> OldIndex then
+ begin
+ if OldIndex > NoColumn then
+ FHeader.Invalidate(Items[OldIndex]);
+ OldIndex := NewIndex;
+ if OldIndex > NoColumn then
+ FHeader.Invalidate(Items[OldIndex]);
+ Result := True;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.SetItem(Index: TColumnIndex; Value: TVirtualTreeColumn);
+
+begin
+ inherited SetItem(Index, Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.AdjustAutoSize(CurrentIndex: TColumnIndex; Force: Boolean = False);
+
+// Called only if the header is in auto-size mode which means a column needs to be so large
+// that it fills all the horizontal space not occupied by the other columns.
+// CurrentIndex (if not InvalidColumn) describes which column has just been resized.
+
+var
+ NewValue,
+ AutoIndex,
+ Index,
+ RestWidth: Integer;
+
+begin
+ if Count > 0 then
+ begin
+ // Determine index to be used for auto resizing. This is usually given by the owner's AutoSizeIndex, but
+ // could be different if the column whose resize caused the invokation here is either the auto column itself
+ // or visually to the right of the auto size column.
+ AutoIndex := FHeader.FAutoSizeIndex;
+ if (AutoIndex < 0) or (AutoIndex >= Count) then
+ AutoIndex := Count - 1;
+ if (CurrentIndex > NoColumn) and
+ (Items[CurrentIndex].Position >= Items[AutoIndex].Position) then
+ begin
+ // The given index is the either the auto size column itself or visually to its right.
+ // Use the next column instead if there is one.
+ AutoIndex := GetNextVisibleColumn(CurrentIndex);
+ end;
+
+ if AutoIndex >= 0 then
+ begin
+ with FHeader.Treeview do
+ begin
+ if HandleAllocated then
+ RestWidth := ClientWidth
+ else
+ RestWidth := Width;
+ end;
+
+ // go through all columns and calculate the rest space remaining
+ for Index := 0 to Count - 1 do
+ if (Index <> AutoIndex) and (coVisible in Items[Index].FOptions) then
+ Dec(RestWidth, Items[Index].Width);
+
+ with Items[AutoIndex] do
+ begin
+ NewValue := Max(MinWidth, Min(MaxWidth, RestWidth));
+ if Force or (FWidth <> NewValue) then
+ begin
+ FWidth := NewValue;
+ UpdatePositions;
+ FHeader.Treeview.DoColumnResize(AutoIndex);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.AdjustDownColumn(P: TPoint): TColumnIndex;
+
+// Determines the column from the given position and returns it. If this column is allowed to be clicked then
+// it is also kept for later use.
+
+begin
+ // Convert to local coordinates.
+ Inc(P.Y, FHeader.FHeight);
+ Result := ColumnFromPosition(P);
+ if (Result > NoColumn) and (Result <> FDownIndex) and (coAllowClick in Items[Result].FOptions) and
+ (coEnabled in Items[Result].FOptions) then
+ begin
+ if FDownIndex > NoColumn then
+ FHeader.Invalidate(Items[FDownIndex]);
+ FDownIndex := Result;
+ FHeader.Invalidate(Items[FDownIndex]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.AdjustHoverColumn(P: TPoint): Boolean;
+
+// Determines the new hover column index and returns True if the index actually changed else False.
+
+begin
+ Result := GetNewIndex(P, FHoverIndex);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.AdjustPosition(Column: TVirtualTreeColumn; Position: Cardinal);
+
+// Reorders the column position array so that the given column gets the given position.
+
+var
+ OldPosition: Cardinal;
+
+begin
+ OldPosition := Column.Position;
+ if OldPosition <> Position then
+ begin
+ if OldPosition < Position then
+ begin
+ // column will be moved up so move down other entries
+ Move(FPositionToIndex[OldPosition + 1], FPositionToIndex[OldPosition], (Position - OldPosition) * SizeOf(Cardinal));
+ end
+ else
+ begin
+ // column will be moved down so move up other entries
+ Move(FPositionToIndex[Position], FPositionToIndex[Position + 1], (OldPosition - Position) * SizeOf(Cardinal));
+ end;
+ FPositionToIndex[Position] := Column.Index;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.FixPositions;
+
+// Fixes column positions after loading from DFM.
+
+var
+ I: Integer;
+
+begin
+ for I := 0 to Count - 1 do
+ FPositionToIndex[Items[I].Position] := I;
+ FNeedPositionsFix := False;
+ UpdatePositions(True);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetColumnAndBounds(P: TPoint; var ColumnLeft, ColumnRight: Integer;
+ Relative: Boolean = True): Integer;
+
+// Returns the column where the mouse is currently in as well as the left and right bound of
+// this column (Left and Right are undetermined if no column is involved).
+
+var
+ I: Integer;
+
+begin
+ Result := InvalidColumn;
+ if Relative then
+ ColumnLeft := FHeader.Treeview.FOffsetX
+ else
+ ColumnLeft := 0;
+ for I := 0 to Count - 1 do
+ with Items[FPositionToIndex[I]] do
+ if coVisible in FOptions then
+ begin
+ ColumnRight := ColumnLeft + FWidth;
+ if P.X < ColumnRight then
+ begin
+ Result := FPositionToIndex[I];
+ Exit;
+ end;
+ ColumnLeft := ColumnRight;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetOwner: TPersistent;
+
+begin
+ Result := FHeader;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.HandleClick(P: TPoint; Button: TMouseButton; Force, DblClick: Boolean);
+
+// Generates a click event if the mouse button has been released over the same column it was pressed first.
+// Alternatively, Force might be set to True to indicate that the down index does not matter (right, middle and
+// double click).
+
+var
+ NewClickIndex: Integer;
+ Shift: TShiftState;
+
+begin
+ // convert to local coordinates
+ Inc(P.Y, FHeader.FHeight);
+ NewClickIndex := ColumnFromPosition(P);
+ if (NewClickIndex > NoColumn) and (coAllowClick in Items[NewClickIndex].FOptions) and
+ ((NewClickIndex = FDownIndex) or Force) then
+ begin
+ FClickIndex := NewClickIndex;
+ Shift := FHeader.GetShiftState;
+ if DblClick then
+ Shift := Shift + [ssDouble];
+ FHeader.Treeview.DoHeaderClick(NewClickIndex, Button, Shift, P.X, P.Y);
+ FHeader.Invalidate(Items[NewClickIndex]);
+ end
+ else
+ FClickIndex := NoColumn;
+
+ if (FClickIndex > NoColumn) and (FClickIndex <> NewClickIndex) then
+ FHeader.Invalidate(Items[FClickIndex]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.IndexChanged(OldIndex, NewIndex: Integer);
+
+// Called by a column when its index in the collection changes. If NewIndex is -1 then the column is
+// about to be removed, otherwise it is moved to a new index.
+// The method will then update the position array to reflect the change.
+
+var
+ I: Integer;
+ Increment: Integer;
+ Lower,
+ Upper: Integer;
+
+begin
+ if NewIndex = -1 then
+ begin
+ // Find position in the array with the old index.
+ Upper := High(FPositionToIndex);
+ for I := 0 to Upper do
+ begin
+ if FPositionToIndex[I] = OldIndex then
+ begin
+ // Index found. Move all higher entries one step down and remove the last entry.
+ if I < Upper then
+ Move(FPositionToIndex[I + 1], FPositionToIndex[I], (Upper - I) * SizeOf(Integer));
+ end;
+ // Decrease all indices, which are greater than the index to be deleted.
+ if FPositionToIndex[I] > OldIndex then
+ Dec(FPositionToIndex[I]);
+ end;
+ SetLength(FPositionToIndex, High(FPositionToIndex));
+ end
+ else
+ begin
+ if OldIndex < NewIndex then
+ Increment := -1
+ else
+ Increment := 1;
+
+ Lower := Min(OldIndex, NewIndex);
+ Upper := Max(OldIndex, NewIndex);
+ for I := 0 to High(FPositionToIndex) do
+ begin
+ if (FPositionToIndex[I] >= Lower) and (FPositionToIndex[I] < Upper) then
+ Inc(FPositionToIndex[I], Increment)
+ else
+ if FPositionToIndex[I] = OldIndex then
+ FPositionToIndex[I] := NewIndex;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.InitializePositionArray;
+
+// Ensures that the column position array contains as much entries as columns are defined.
+// The array is resized and initialized with default values if needed.
+
+var
+ I, OldSize: Integer;
+ Changed: Boolean;
+
+begin
+ if Count <> Length(FPositionToIndex) then
+ begin
+ OldSize := Length(FPositionToIndex);
+ SetLength(FPositionToIndex, Count);
+ if Count > OldSize then
+ begin
+ // New items have been added, just set their position to the same as their index.
+ for I := OldSize to Count - 1 do
+ FPositionToIndex[I] := I;
+ end
+ else
+ begin
+ // Items have been deleted, so reindex remaining entries by decrementing values larger than the highest
+ // possible index until no entry is higher than this limit.
+ repeat
+ Changed := False;
+ for I := 0 to Count - 1 do
+ if FPositionToIndex[I] >= Count then
+ begin
+ Dec(FPositionToIndex[I]);
+ Changed := True;
+ end;
+ until not Changed;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.Update(Item: TCollectionItem);
+
+begin
+ // This is the only place which gets notified when a new column has been added or removed
+ // and we need this event to adjust the column position array.
+ InitializePositionArray;
+ if csLoading in Header.Treeview.ComponentState then
+ FNeedPositionsFix := True
+ else
+ UpdatePositions;
+
+ // The first column which is created is by definition also the main column.
+ if (Count > 0) and (Header.FMainColumn < 0) then
+ FHeader.FMainColumn := 0;
+
+ if not (csLoading in Header.Treeview.ComponentState) and not (hsLoading in FHeader.FStates) then
+ begin
+ with FHeader do
+ begin
+ if hoAutoResize in FOptions then
+ AdjustAutoSize(InvalidColumn);
+ if Assigned(Item) then
+ Invalidate(Item as TVirtualTreeColumn)
+ else
+ if Treeview.HandleAllocated then
+ begin
+ Treeview.UpdateHorizontalScrollBar(False);
+ Invalidate(nil);
+ Treeview.Invalidate;
+ end;
+ // This is mainly to let the designer know when a change occurs at design time which
+ // doesn't involve the object inspector (like column resizing with the mouse).
+ // This does NOT include design time code as the comunication is done via an interface.
+ Treeview.UpdateDesigner;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.UpdatePositions(Force: Boolean = False);
+
+// Recalculates the left border of every column and updates their position property according to the
+// PostionToIndex array which primarily determines where each column is placed visually.
+
+var
+ I, LeftPos: Integer;
+
+begin
+ if not FNeedPositionsFix and (Force or (UpdateCount = 0)) then
+ begin
+ LeftPos := 0;
+ for I := 0 to High(FPositionToIndex) do
+ with Items[FPositionToIndex[I]] do
+ begin
+ FPosition := I;
+ FLeft := LeftPos;
+ if coVisible in FOptions then
+ Inc(LeftPos, FWidth);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.Add: TVirtualTreeColumn;
+
+begin
+ Result := TVirtualTreeColumn(inherited Add);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.AnimatedResize(Column: TColumnIndex; NewWidth: Integer);
+
+// Resizes the given column animated by scrolling the window DC.
+
+var
+ OldWidth: Integer;
+ DC: HDC;
+ I,
+ Steps,
+ DX: Integer;
+ HeaderScrollRect,
+ ScrollRect,
+ R: TRect;
+
+ NewBrush,
+ LastBrush: HBRUSH;
+
+begin
+ // Make sure the width constrains are considered.
+ if NewWidth < Items[Column].FMinWidth then
+ NewWidth := Items[Column].FMinWidth;
+ if NewWidth > Items[Column].FMaxWidth then
+ NewWidth := Items[Column].FMaxWidth;
+
+ OldWidth := Items[Column].Width;
+ // Nothing to do if the width is the same.
+ if OldWidth <> NewWidth then
+ begin
+ DC := GetWindowDC(FHeader.Treeview.Handle);
+ with FHeader.Treeview do
+ try
+ Steps := 32;
+ DX := (NewWidth - OldWidth) div Steps;
+
+ // Determination of the scroll rectangle is a bit complicated since we neither want
+ // to scroll the scrollbars nor the border of the treeview window.
+ HeaderScrollRect := FHeaderRect;
+ ScrollRect := HeaderScrollRect;
+ // Exclude the header itself from scrolling.
+ ScrollRect.Top := ScrollRect.Bottom;
+ ScrollRect.Bottom := ScrollRect.Top + ClientHeight;
+ ScrollRect.Right := ScrollRect.Left + ClientWidth;
+ with Items[Column] do
+ Inc(ScrollRect.Left, FLeft + FWidth);
+ HeaderScrollRect.Left := ScrollRect.Left;
+ HeaderScrollRect.Right := ScrollRect.Right;
+
+ // When the new width is larger then avoid artefacts on the left hand side
+ // by deleting a small stripe
+ if NewWidth > OldWidth then
+ begin
+ R := ScrollRect;
+ NewBrush := CreateSolidBrush(ColorToRGB(Color));
+ LastBrush := SelectObject(DC, NewBrush);
+ R.Right := R.Left + DX;
+ FillRect(DC, R, NewBrush);
+ SelectObject(DC, LastBrush);
+ DeleteObject(NewBrush);
+ end
+ else
+ begin
+ Inc(HeaderScrollRect.Left, DX);
+ Inc(ScrollRect.Left, DX);
+ end;
+
+ for I := 0 to Steps - 1 do
+ begin
+ ScrollDC(DC, DX, 0, HeaderScrollRect, HeaderScrollRect, 0, nil);
+ Inc(HeaderScrollRect.Left, DX);
+ ScrollDC(DC, DX, 0, ScrollRect, ScrollRect, 0, nil);
+ Inc(ScrollRect.Left, DX);
+ Sleep(1);
+ end;
+ finally
+ ReleaseDC(Handle, DC);
+ end;
+ Items[Column].Width := NewWidth;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.Assign(Source: TPersistent);
+
+begin
+ // Let the collection class assign the items.
+ inherited;
+
+ if Source is TVirtualTreeColumns then
+ begin
+ // Copying the position array is the only needed task here.
+ FPositionToIndex := Copy(TVirtualTreeColumns(Source).FPositionToIndex, 0, MaxInt);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.Clear;
+
+begin
+ FClearing := True;
+ try
+ // Since we're freeing all columns, the following have to be true when we're done.
+ FHoverIndex := NoColumn;
+ FDownIndex := NoColumn;
+ FTrackIndex := NoColumn;
+ FClickIndex := NoColumn;
+
+ with Header do
+ if not (hsLoading in FStates) then
+ begin
+ FAutoSizeIndex := NoColumn;
+ FMainColumn := NoColumn;
+ FSortColumn := NoColumn;
+ end;
+
+ inherited Clear;
+ finally
+ FClearing := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.ColumnFromPosition(P: TPoint; Relative: Boolean = True): TColumnIndex;
+
+// Determines the current column based on the position passed in P.
+
+var
+ I, Sum: Integer;
+
+begin
+ Result := InvalidColumn;
+ // The position must be within the header area, but we extend the vertical bounds to the entire treeview area.
+ if (P.X >= 0) and (P.Y >= 0) and (P.Y <= Integer(FHeader.TreeView.Height)) then
+ begin
+ if Relative then
+ Sum := FHeader.Treeview.FOffsetX
+ else
+ Sum := 0;
+ for I := 0 to Count - 1 do
+ if coVisible in Items[FPositionToIndex[I]].FOptions then
+ begin
+ Inc(Sum, Items[FPositionToIndex[I]].Width);
+ if P.X < Sum then
+ begin
+ Result := FPositionToIndex[I];
+ Break;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.ColumnFromPosition(PositionIndex: TColumnPosition): TColumnIndex;
+
+// Returns the index of the column at the given position.
+
+begin
+ if Integer(PositionIndex) < Length(FPositionToIndex) then
+ Result := FPositionToIndex[PositionIndex]
+ else
+ Result := NoColumn;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.Equals(OtherColumns: TVirtualTreeColumns): Boolean;
+
+// Compares itself with the given set of columns and returns True if all published properties are the same
+// (including column order), otherwise False is returned.
+
+var
+ I: Integer;
+
+begin
+ // Same number of columns?
+ Result := OtherColumns.Count = Count;
+ if Result then
+ begin
+ // Same order of columns?
+ Result := CompareMem(Pointer(FPositionToIndex), Pointer(OtherColumns.FPositionToIndex),
+ Length(FPositionToIndex) * SizeOf(TColumnIndex));
+ if Result then
+ begin
+ for I := 0 to Count - 1 do
+ if not Items[I].Equals(OtherColumns[I]) then
+ begin
+ Result := False;
+ Break;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.GetColumnBounds(Column: TColumnIndex; var Left, Right: Integer);
+
+// Returns the left and right bound of the given column. If Column is NoColumn then the entire client width is returned.
+
+begin
+ if Column = NoColumn then
+ begin
+ Left := 0;
+ Right := FHeader.Treeview.ClientWidth;
+ end
+ else
+ begin
+ Left := Items[Column].Left;
+ Right := Left + Items[Column].Width;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetFirstVisibleColumn: TColumnIndex;
+
+// Returns the index of the first visible column or "InvalidColumn" if either no columns are defined or
+// all columns are hidden.
+
+var
+ I: Integer;
+
+begin
+ Result := InvalidColumn;
+ for I := 0 to Count - 1 do
+ if coVisible in Items[FPositionToIndex[I]].FOptions then
+ begin
+ Result := FPositionToIndex[I];
+ Break;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetLastVisibleColumn: TColumnIndex;
+
+// Returns the index of the last visible column or "InvalidColumn" if either no columns are defined or
+// all columns are hidden.
+
+var
+ I: Integer;
+
+begin
+ Result := InvalidColumn;
+ for I := Count - 1 downto 0 do
+ if coVisible in Items[FPositionToIndex[I]].FOptions then
+ begin
+ Result := FPositionToIndex[I];
+ Break;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetNextColumn(Column: TColumnIndex): TColumnIndex;
+
+// Returns the next column in display order. Column is the index of an item in the collection (a column).
+
+var
+ Position: Integer;
+
+begin
+ if Column < 0 then
+ Result := InvalidColumn
+ else
+ begin
+ Position := Items[Column].Position;
+ if Position < Count - 1 then
+ Result := FPositionToIndex[Position + 1]
+ else
+ Result := InvalidColumn;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetNextVisibleColumn(Column: TColumnIndex): TColumnIndex;
+
+// Returns the next visible column in display order, Column is an index into the columns list.
+
+begin
+ Result := Column;
+ repeat
+ Result := GetNextColumn(Result);
+ until (Result = InvalidColumn) or (coVisible in Items[Result].FOptions);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetPreviousColumn(Column: TColumnIndex): TColumnIndex;
+
+// Returns the previous column in display order, Column is an index into the columns list.
+
+var
+ Position: Integer;
+
+begin
+ if Column < 0 then
+ Result := InvalidColumn
+ else
+ begin
+ Position := Items[Column].Position;
+ if Position > 0 then
+ Result := FPositionToIndex[Position - 1]
+ else
+ Result := InvalidColumn;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetPreviousVisibleColumn(Column: TColumnIndex): TColumnIndex;
+
+// Returns the previous column in display order, Column is an index into the columns list.
+
+begin
+ Result := Column;
+ repeat
+ Result := GetPreviousColumn(Result);
+ until (Result = InvalidColumn) or (coVisible in Items[Result].FOptions);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetVisibleColumns: TColumnsArray;
+
+// Returns a list of all currently visible columns in actual order.
+
+var
+ I, Counter: Integer;
+
+begin
+ SetLength(Result, Count);
+ Counter := 0;
+
+ for I := 0 to Count - 1 do
+ if coVisible in Items[FPositionToIndex[I]].FOptions then
+ begin
+ Result[Counter] := Items[FPositionToIndex[I]];
+ Inc(Counter);
+ end;
+ // Set result length to actual visible count.
+ SetLength(Result, Counter);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.IsValidColumn(Column: TColumnIndex): Boolean;
+
+// Determines whether the given column is valid or not, that is, whether it is one of the current columns.
+
+begin
+ Result := (Column > NoColumn) and (Column < Count);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.LoadFromStream(const Stream: TStream; Version: Integer);
+
+var
+ I,
+ ItemCount: Integer;
+
+begin
+ Clear;
+ Stream.ReadBuffer(ItemCount, SizeOf(ItemCount));
+ // number of columns
+ if ItemCount > 0 then
+ begin
+ BeginUpdate;
+ try
+ for I := 0 to ItemCount - 1 do
+ Add.LoadFromStream(Stream, Version);
+ SetLength(FPositionToIndex, ItemCount);
+ Stream.ReadBuffer(FPositionToIndex[0], ItemCount * SizeOf(Cardinal));
+ UpdatePositions(True);
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+// XP style header button legacy code. This procedure is only used on non-XP systems to simulate the themed
+// header style.
+// Note: the theme elements displayed here only correspond to the standard themes of Windows XP
+
+const
+ XPMainHeaderColorUp = $DBEAEB; // Main background color of the header if drawn as being not pressed.
+ XPMainHeaderColorDown = $D8DFDE; // Main background color of the header if drawn as being pressed.
+ XPMainHeaderColorHover = $F3F8FA; // Main background color of the header if drawn as being under the mouse pointer.
+ XPDarkSplitBarColor = $B2C5C7; // Dark color of the splitter bar.
+ XPLightSplitBarColor = $FFFFFF; // Light color of the splitter bar.
+ XPDarkGradientColor = $B8C7CB; // Darkest color in the bottom gradient. Other colors will be interpolated.
+ XPDownOuterLineColor = $97A5A5; // Down state border color.
+ XPDownMiddleLineColor = $B8C2C1; // Down state border color.
+ XPDownInnerLineColor = $C9D1D0; // Down state border color.
+
+procedure DrawXPButton(DC: HDC; ButtonR: TRect; DrawSplitter, Down, Hover: Boolean);
+
+// Helper procedure to draw an Windows XP like header button.
+
+var
+ PaintBrush: HBRUSH;
+ Pen,
+ OldPen: HPEN;
+ PenColor,
+ FillColor: COLORREF;
+ dRed, dGreen, dBlue: Single;
+ Width,
+ XPos: Integer;
+
+begin
+ if Down then
+ FillColor := XPMainHeaderColorDown
+ else
+ if Hover then
+ FillColor := XPMainHeaderColorHover
+ else
+ FillColor := XPMainHeaderColorUp;
+ PaintBrush := CreateSolidBrush(FillColor);
+ FillRect(DC, ButtonR, PaintBrush);
+ DeleteObject(PaintBrush);
+
+ if DrawSplitter and not (Down or Hover) then
+ begin
+ // One solid pen for the dark line...
+ Pen := CreatePen(PS_SOLID, 1, XPDarkSplitBarColor);
+ OldPen := SelectObject(DC, Pen);
+ MoveToEx(DC, ButtonR.Right - 2, ButtonR.Top + 3, nil);
+ LineTo(DC, ButtonR.Right - 2, ButtonR.Bottom - 5);
+ // ... and one solid pen for the light line.
+ Pen := CreatePen(PS_SOLID, 1, XPLightSplitBarColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Right - 1, ButtonR.Top + 3, nil);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Bottom - 5);
+ SelectObject(DC, OldPen);
+ DeleteObject(Pen);
+ end;
+
+ if Down then
+ begin
+ // Down state. Three lines to draw.
+ // First one is the outer line, drawn at left, bottom and right.
+ Pen := CreatePen(PS_SOLID, 1, XPDownOuterLineColor);
+ OldPen := SelectObject(DC, Pen);
+ MoveToEx(DC, ButtonR.Left, ButtonR.Top, nil);
+ LineTo(DC, ButtonR.Left, ButtonR.Bottom - 1);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Bottom - 1);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Top - 1);
+
+ // Second one is the middle line, which is a bit lighter.
+ Pen := CreatePen(PS_SOLID, 1, XPDownMiddleLineColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Left + 1, ButtonR.Bottom - 2, nil);
+ LineTo(DC, ButtonR.Left + 1, ButtonR.Top);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Top);
+
+ // Third line is the inner line, which is even lighter than the middle line.
+ Pen := CreatePen(PS_SOLID, 1, XPDownInnerLineColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Left + 2, ButtonR.Bottom - 2, nil);
+ LineTo(DC, ButtonR.Left + 2, ButtonR.Top + 1);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Top + 1);
+
+ // Housekeeping:
+ SelectObject(DC, OldPen);
+ DeleteObject(Pen);
+ end
+ else
+ if Hover then
+ begin
+ // Hover state. There are three lines at the bottom border, but they are rendered in a way which
+ // requires expensive construction.
+ Width := ButtonR.Right - ButtonR.Left;
+ if Width <= 32 then
+ begin
+ ImageList_DrawEx(UtilityImages.Handle, 8, DC, ButtonR.Right - 16, ButtonR.Bottom - 3, 16, 3, CLR_NONE, CLR_NONE,
+ ILD_NORMAL);
+ ImageList_DrawEx(UtilityImages.Handle, 6, DC, ButtonR.Left, ButtonR.Bottom - 3, Width div 2, 3, CLR_NONE,
+ CLR_NONE, ILD_NORMAL);
+ end
+ else
+ begin
+ ImageList_DrawEx(UtilityImages.Handle, 6, DC, ButtonR.Left, ButtonR.Bottom - 3, 16, 3, CLR_NONE, CLR_NONE,
+ ILD_NORMAL);
+ // Replicate inner part as many times as need to fill up the button rectangle.
+ XPos := ButtonR.Left + 16;
+ repeat
+ ImageList_DrawEx(UtilityImages.Handle, 7, DC, XPos, ButtonR.Bottom - 3, 16, 3, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ Inc(XPos, 16);
+ until XPos + 16 >= ButtonR.Right;
+ ImageList_DrawEx(UtilityImages.Handle, 8, DC, ButtonR.Right - 16, ButtonR.Bottom - 3, 16, 3, CLR_NONE, CLR_NONE,
+ ILD_NORMAL);
+ end;
+ end
+ else
+ begin
+ // There is a three line gradient near the bottom border which transforms from the button color to a dark,
+ // clBtnFace like color (here XPDarkGradientColor).
+ PenColor := XPMainHeaderColorUp;
+ dRed := ((PenColor and $FF) - (XPDarkGradientColor and $FF)) / 3;
+ dGreen := (((PenColor shr 8) and $FF) - ((XPDarkGradientColor shr 8) and $FF)) / 3;
+ dBlue := (((PenColor shr 16) and $FF) - ((XPDarkGradientColor shr 16) and $FF)) / 3;
+
+ // First line:
+ PenColor := PenColor - Round(dRed) - Round(dGreen) shl 8 - Round(dBlue) shl 16;
+ Pen := CreatePen(PS_SOLID, 1, PenColor);
+ OldPen := SelectObject(DC, Pen);
+ MoveToEx(DC, ButtonR.Left, ButtonR.Bottom - 3, nil);
+ LineTo(DC, ButtonR.Right, ButtonR.Bottom - 3);
+
+ // Second line:
+ PenColor := PenColor - Round(dRed) - Round(dGreen) shl 8 - Round(dBlue) shl 16;
+ Pen := CreatePen(PS_SOLID, 1, PenColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Left, ButtonR.Bottom - 2, nil);
+ LineTo(DC, ButtonR.Right, ButtonR.Bottom - 2);
+
+ // Third line:
+ Pen := CreatePen(PS_SOLID, 1, XPDarkGradientColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Left, ButtonR.Bottom - 1, nil);
+ LineTo(DC, ButtonR.Right, ButtonR.Bottom - 1);
+
+ // Housekeeping:
+ DeleteObject(SelectObject(DC, OldPen));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.PaintHeader(DC: HDC; R: TRect; HOffset: Integer; VOffset: Integer = 0);
+
+// Main paint method to draw the header.
+
+const
+ SortGlyphs: array[TSortDirection, Boolean] of Integer = ( // ascending/descending, normal/XP style
+ (3, 5) {ascending}, (2, 4) {descending}
+ );
+
+var
+ I, Y,
+ SortIndex: Integer;
+ Run: TRect;
+ RightBorderFlag,
+ NormalButtonStyle,
+ NormalButtonFlags,
+ PressedButtonStyle,
+ PressedButtonFlags,
+ RaisedButtonStyle,
+ RaisedButtonFlags: Cardinal;
+ DrawFormat: Cardinal;
+ Images: TImageList;
+ ButtonRgn: HRGN;
+ OwnerDraw,
+ AdvancedOwnerDraw: Boolean;
+ {$ifdef ThemeSupport}
+ Details: TThemedElementDetails;
+ {$endif ThemeSupport}
+
+ PaintInfo: THeaderPaintInfo;
+ RequestedElements,
+ ActualElements: THeaderPaintElements;
+
+ SavedDC: Integer;
+
+begin
+ Run := FHeader.Treeview.FHeaderRect;
+ FHeaderBitmap.Width := Max(Run.Right, R.Right - R.Left);
+ FHeaderBitmap.Height := Run.Bottom;
+ OwnerDraw := (hoOwnerDraw in FHeader.FOptions) and Assigned(FHeader.Treeview.FOnHeaderDraw) and
+ not (csDesigning in FHeader.Treeview.ComponentState);
+ AdvancedOwnerDraw := (hoOwnerDraw in FHeader.FOptions) and Assigned(FHeader.Treeview.FOnAdvancedHeaderDraw) and
+ Assigned(FHeader.Treeview.FOnHeaderDrawQueryElements) and not (csDesigning in FHeader.Treeview.ComponentState);
+ // If both draw posibillities are specified then prefer the advanced way.
+ if AdvancedOwnerDraw then
+ OwnerDraw := False;
+
+ ZeroMemory(@PaintInfo, SizeOf(PaintInfo));
+ PaintInfo.TargetCanvas := FHeaderBitmap.Canvas;
+
+ with PaintInfo, TargetCanvas do
+ begin
+ Font := FHeader.FFont;
+
+ RaisedButtonStyle := 0;
+ RaisedButtonFlags := 0;
+ case FHeader.Style of
+ hsThickButtons:
+ begin
+ NormalButtonStyle := BDR_RAISEDINNER or BDR_RAISEDOUTER;
+ NormalButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_SOFT or BF_ADJUST;
+ PressedButtonStyle := BDR_RAISEDINNER or BDR_RAISEDOUTER;
+ PressedButtonFlags := NormalButtonFlags or BF_RIGHT or BF_FLAT or BF_ADJUST;
+ end;
+ hsFlatButtons:
+ begin
+ NormalButtonStyle := BDR_RAISEDINNER;
+ NormalButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_ADJUST;
+ PressedButtonStyle := BDR_SUNKENOUTER;
+ PressedButtonFlags := BF_RECT or BF_MIDDLE or BF_ADJUST;
+ end;
+ else
+ // hsPlates or hsXPStyle, values are not used in the latter case
+ begin
+ NormalButtonStyle := BDR_RAISEDINNER;
+ NormalButtonFlags := BF_RECT or BF_MIDDLE or BF_SOFT or BF_ADJUST;
+ PressedButtonStyle := BDR_SUNKENOUTER;
+ PressedButtonFlags := BF_RECT or BF_MIDDLE or BF_ADJUST;
+ RaisedButtonStyle := BDR_RAISEDINNER;
+ RaisedButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_ADJUST;
+ end;
+ end;
+
+ // Use shortcut for the images.
+ Images := FHeader.FImages;
+
+ // Consider right-to-left directionality.
+ with FHeader.Treeview do
+ if (BidiMode <> bdLeftToRight) and (Integer(FRangeY) > ClientHeight) then
+ Inc(HOffset, GetSystemMetrics(SM_CXVSCROLL));
+
+ // Erase background of the header.
+ // See if the application wants to do that on its own.
+ RequestedElements := [];
+ if AdvancedOwnerDraw then
+ begin
+ PaintInfo.PaintRectangle := R;
+ PaintInfo.Column := nil;
+ FHeader.Treeview.DoHeaderDrawQueryElements(PaintInfo, RequestedElements);
+ end;
+
+ if hpeBackground in RequestedElements then
+ begin
+ FHeader.Treeview.DoAdvancedHeaderDraw(PaintInfo, [hpeBackground]);
+ end
+ else
+ begin
+ {$ifdef ThemeSupport}
+ if tsUseThemes in FHeader.Treeview.FStates then
+ begin
+ Details := ThemeServices.GetElementDetails(thHeaderItemRightNormal);
+ ThemeServices.DrawElement(Handle, Details, R, @R);
+ end
+ else
+ {$endif ThemeSupport}
+ if FHeader.Style = hsXPStyle then
+ DrawXPButton(Handle, Run, False, False, False)
+ else
+ begin
+ Brush.Color := FHeader.FBackground;
+ FillRect(R);
+ end;
+ end;
+
+ Run.Top := R.Top;
+ Run.Right := R.Left + HOffset;
+ Run.Bottom := R.Bottom;
+ // Run.Left is set in the loop
+
+ ShowRightBorder := (FHeader.Style = hsThickButtons) or not (hoAutoResize in FHeader.FOptions) or
+ (FHeader.Treeview.BevelKind = bkNone);
+
+ // now go for each button
+ for I := 0 to Count - 1 do
+ with Items[FPositionToIndex[I]] do
+ if coVisible in FOptions then
+ begin
+ Run.Left := Run.Right;
+ Inc(Run.Right, Width);
+ // Skip columns which are not visible at all.
+ if Run.Right > R.Left then
+ begin
+ // Stop painting if the rectangle is filled.
+ if Run.Left > R.Right then
+ Break;
+
+ IsHoverIndex := (Integer(FPositionToIndex[I]) = FHoverIndex) and (hoHotTrack in FHeader.FOptions) and
+ (coEnabled in FOptions);
+ IsDownIndex := Integer(FPositionToIndex[I]) = FDownIndex;
+ if (coShowDropMark in FOptions) and (Integer(FPositionToIndex[I]) = FDropTarget) and
+ (Integer(FPositionToIndex[I]) <> FDragIndex) then
+ begin
+ if FDropBefore then
+ DropMark := dmmLeft
+ else
+ DropMark := dmmRight;
+ end
+ else
+ DropMark := dmmNone;
+ IsEnabled := (coEnabled in FOptions) and (FHeader.Treeview.Enabled);
+ ShowHeaderGlyph := (hoShowImages in FHeader.FOptions) and Assigned(Images) and (FImageIndex > -1);
+ ShowSortGlyph := (Integer(FPositionToIndex[I]) = FHeader.FSortColumn) and (hoShowSortGlyphs in FHeader.FOptions);
+
+ PaintRectangle := Run;
+
+ // This path for text columns or advanced owner draw.
+ if (Style = vsText) or not OwnerDraw or AdvancedOwnerDraw then
+ begin
+ // See if the application wants to draw part of the header itself.
+ RequestedElements := [];
+ if AdvancedOwnerDraw then
+ begin
+ PaintInfo.Column := Items[FPositionToIndex[I]];
+ FHeader.Treeview.DoHeaderDrawQueryElements(PaintInfo, RequestedElements);
+ end;
+
+ if ShowRightBorder or (I < Count - 1) then
+ RightBorderFlag := BF_RIGHT
+ else
+ RightBorderFlag := 0;
+
+ if hpeBackground in RequestedElements then
+ FHeader.Treeview.DoAdvancedHeaderDraw(PaintInfo, [hpeBackground])
+ else
+ begin
+ // Draw button first before setting the clip region.
+ {$ifdef ThemeSupport}
+ if tsUseThemes in FHeader.Treeview.FStates then
+ begin
+ if IsDownIndex then
+ Details := ThemeServices.GetElementDetails(thHeaderItemPressed)
+ else
+ if IsHoverIndex then
+ Details := ThemeServices.GetElementDetails(thHeaderItemHot)
+ else
+ Details := ThemeServices.GetElementDetails(thHeaderItemNormal);
+ ThemeServices.DrawElement(Handle, Details, PaintRectangle, @PaintRectangle);
+ end
+ else
+ {$endif ThemeSupport}
+ begin
+ if FHeader.Style = hsXPStyle then
+ DrawXPButton(Handle, PaintRectangle, RightBorderFlag <> 0, IsDownIndex, IsHoverIndex)
+ else
+ if IsDownIndex then
+ DrawEdge(Handle, PaintRectangle, PressedButtonStyle, PressedButtonFlags)
+ else
+ // Plates have the special case of raising on mouse over.
+ if (FHeader.Style = hsPlates) and IsHoverIndex and
+ (coAllowClick in FOptions) and (coEnabled in FOptions) then
+ DrawEdge(Handle, PaintRectangle, RaisedButtonStyle, RaisedButtonFlags or RightBorderFlag)
+ else
+ DrawEdge(Handle, PaintRectangle, NormalButtonStyle, NormalButtonFlags or RightBorderFlag);
+ end;
+ end;
+ end;
+
+ // Create a clip region to avoid overpainting any other area which does not belong to this column.
+ if PaintRectangle.Right > R.Right then
+ PaintRectangle.Right := R.Right;
+ if PaintRectangle.Left < R.Left then
+ PaintRectangle.Left := R.Left;
+ ButtonRgn := CreateRectRgnIndirect(PaintRectangle);
+ SelectClipRgn(Handle, ButtonRgn);
+ DeleteObject(ButtonRgn);
+
+ PaintRectangle := Run;
+ if (Style = vsText) or not OwnerDraw or AdvancedOwnerDraw then
+ begin
+ // calculate text and glyph position
+ InflateRect(PaintRectangle, -2, -2);
+ DrawFormat := DT_LEFT or DT_TOP;
+ if UseRightToLeftReading then
+ DrawFormat := DrawFormat + DT_RTLREADING;
+ ComputeHeaderLayout(Handle, PaintRectangle, ShowHeaderGlyph, ShowSortGlyph, GlyphPos, SortGlyphPos,
+ TextRectangle);
+
+ // Move glyph and text one pixel to the right and down to simulate a pressed button.
+ if IsDownIndex then
+ begin
+ OffsetRect(TextRectangle, 1, 1);
+ Inc(GlyphPos.X);
+ Inc(GlyphPos.Y);
+ Inc(SortGlyphPos.X);
+ Inc(SortGlyphPos.Y);
+ end;
+
+ // Advanced owner draw allows to paint elements, which would normally not be painted (because of space
+ // limitations, empty captions etc.).
+ ActualElements := RequestedElements * [hpeHeaderGlyph, hpeSortGlyph, hpeDropMark, hpeText];
+
+ // main glyph
+ if not (hpeHeaderGlyph in ActualElements) and ShowHeaderGlyph and
+ (not ShowSortGlyph or (FBidiMode <> bdLeftToRight) or (GlyphPos.X + Images.Width <= SortGlyphPos.X)) then
+ Images.Draw(FHeaderBitmap.Canvas, GlyphPos.X, GlyphPos.Y, FImageIndex, IsEnabled);
+
+ // caption
+ if not (hpeText in ActualElements) and (Length(Text) > 0) then
+ DrawButtonText(Handle, Text, TextRectangle, IsEnabled, IsHoverIndex and (hoHotTrack in FHeader.FOptions) and
+ not (tsUseThemes in FHeader.Treeview.FStates), DrawFormat);
+
+ // sort glyph
+ if not (hpeSortGlyph in ActualElements) and ShowSortGlyph then
+ begin
+ SortIndex := SortGlyphs[FHeader.FSortDirection, tsUseThemes in FHeader.Treeview.FStates];
+ UtilityImages.Draw(FHeaderBitmap.Canvas, SortGlyphPos.X, SortGlyphPos.Y, SortIndex);
+ end;
+
+ // Show an indication if this column is the current drop target in a header drag operation.
+ if not (hpeDropMark in ActualElements) and (DropMark <> dmmNone) then
+ begin
+ Y := (PaintRectangle.Top + PaintRectangle.Bottom - UtilityImages.Height) div 2;
+ if DropMark = dmmLeft then
+ UtilityImages.Draw(FHeaderBitmap.Canvas, PaintRectangle.Left, Y, 0)
+ else
+ UtilityImages.Draw(FHeaderBitmap.Canvas, PaintRectangle.Right - 16 , Y, 1);
+ end;
+
+ if ActualElements <> [] then
+ begin
+ SavedDC := SaveDC(Handle);
+ FHeader.Treeview.DoAdvancedHeaderDraw(PaintInfo, ActualElements);
+ RestoreDC(Handle, SavedDC);
+ end;
+ end
+ else // Let application draw the header.
+ FHeader.Treeview.DoHeaderDraw(FHeaderBitmap.Canvas, Items[FPositionToIndex[I]], PaintRectangle, IsHoverIndex,
+ IsDownIndex, DropMark);
+ SelectClipRgn(Handle, 0);
+ end;
+ end;
+
+ // Blit the result to target.
+ with R do
+ BitBlt(DC, Left, Top, Right - Left, Bottom - Top, Handle, Left, Top, SRCCOPY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.SaveToStream(const Stream: TStream);
+
+var
+ I: Integer;
+
+begin
+ I := Count;
+ Stream.WriteBuffer(I, SizeOf(I));
+ if I > 0 then
+ begin
+ for I := 0 to Count - 1 do
+ TVirtualTreeColumn(Items[I]).SaveToStream(Stream);
+
+ Stream.WriteBuffer(FPositionToIndex[0], Count * SizeOf(Cardinal));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.TotalWidth: Integer;
+
+var
+ LastColumn: TColumnIndex;
+
+begin
+ if Count = 0 then
+ Result := 0
+ else
+ begin
+ LastColumn := FPositionToIndex[Count - 1];
+ if not (coVisible in Items[LastColumn].FOptions) then
+ LastColumn := GetPreviousVisibleColumn(LastColumn);
+ if LastColumn > NoColumn then
+ with Items[LastColumn] do
+ Result := FLeft + FWidth
+ else
+ Result := 0;
+ end;
+end;
+
+//----------------- TVTHeader -----------------------------------------------------------------------------------------
+
+constructor TVTHeader.Create(AOwner: TBaseVirtualTree);
+
+begin
+ inherited Create;
+ FOwner := AOwner;
+ FColumns := GetColumnsClass.Create(Self);
+ FHeight := 17;
+ FFont := TFont.Create;
+ FFont.OnChange := FontChanged;
+ FBackground := clBtnFace;
+ FOptions := [hoColumnResize, hoDrag];
+
+ FImageChangeLink := TChangeLink.Create;
+ FImageChangeLink.OnChange := ImageListChange;
+
+ FSortColumn := NoColumn;
+ FSortDirection := sdAscending;
+ FMainColumn := NoColumn;
+
+ FDragImage := TVTDragImage.Create(AOwner);
+ with FDragImage do
+ begin
+ Fade := False;
+ PostBlendBias := 0;
+ PreBlendBias := -50;
+ Transparency := 140;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVTHeader.Destroy;
+
+begin
+ FDragImage.Free;
+ FImageChangeLink.Free;
+ FFont.Free;
+ FColumns.Clear; // TCollection's Clear method is not virtual, so we have to call our own Clear method manually.
+ FColumns.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.FontChanged(Sender: TObject);
+
+begin
+ Invalidate(nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetMainColumn: TColumnIndex;
+
+begin
+ if FColumns.Count > 0 then
+ Result := FMainColumn
+ else
+ Result := NoColumn;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetUseColumns: Boolean;
+
+begin
+ Result := FColumns.Count > 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetAutoSizeIndex(Value: TColumnIndex);
+
+begin
+ if FAutoSizeIndex <> Value then
+ begin
+ FAutoSizeIndex := Value;
+ if hoAutoResize in FOptions then
+ Columns.AdjustAutoSize(InvalidColumn);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetBackground(Value: TColor);
+
+begin
+ if FBackground <> Value then
+ begin
+ FBackground := Value;
+ Invalidate(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetColumns(Value: TVirtualTreeColumns);
+
+begin
+ FColumns.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetFont(const Value: TFont);
+
+begin
+ FFont.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetHeight(Value: Cardinal);
+
+begin
+ if FHeight <> Value then
+ begin
+ FHeight := Value;
+ if not (csLoading in Treeview.ComponentState) then
+ RecalculateHeader;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetImages(const Value: TImageList);
+
+begin
+ if FImages <> Value then
+ begin
+ if Assigned(FImages) then
+ begin
+ FImages.UnRegisterChanges(FImageChangeLink);
+ {$ifdef COMPILER_5_UP}
+ FImages.RemoveFreeNotification(FOwner);
+ {$endif COMPILER_5_UP}
+ end;
+ FImages := Value;
+ if Assigned(FImages) then
+ begin
+ FImages.RegisterChanges(FImageChangeLink);
+ FImages.FreeNotification(FOwner);
+ end;
+ if not (csLoading in Treeview.ComponentState) then
+ Invalidate(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetMainColumn(Value: TColumnIndex);
+
+begin
+ if csLoading in Treeview.ComponentState then
+ FMainColumn := Value
+ else
+ begin
+ if Value < 0 then
+ Value := 0;
+ if Value > FColumns.Count - 1 then
+ Value := FColumns.Count - 1;
+ if Value <> FMainColumn then
+ begin
+ FMainColumn := Value;
+ if not (csLoading in Treeview.ComponentState) then
+ begin
+ Treeview.MainColumnChanged;
+ if not (toExtendedFocus in Treeview.FOptions.FSelectionOptions) then
+ Treeview.FocusedColumn := FMainColumn;
+ Treeview.Invalidate;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetOptions(Value: TVTHeaderOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTHeaderOptions;
+
+begin
+ ToBeSet := Value - FOptions;
+ ToBeCleared := FOptions - Value;
+ FOptions := Value;
+
+ if (hoAutoResize in (ToBeSet + ToBeCleared)) and (FColumns.Count > 0) then
+ begin
+ FColumns.AdjustAutoSize(InvalidColumn);
+ if Treeview.HandleAllocated then
+ begin
+ Treeview.UpdateHorizontalScrollBar(False);
+ if hoAutoResize in ToBeSet then
+ Treeview.Invalidate;
+ end;
+ end;
+
+ if not (csLoading in Treeview.ComponentState) and Treeview.HandleAllocated then
+ begin
+ if hoVisible in (ToBeSet + ToBeCleared) then
+ RecalculateHeader;
+ Invalidate(nil);
+ Treeview.Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetSortColumn(Value: TColumnIndex);
+
+begin
+ if csLoading in Treeview.ComponentState then
+ FSortColumn := Value
+ else
+ begin
+ if Value < NoColumn then
+ Value := NoColumn;
+ if Value > Columns.Count - 1 then
+ Value := Columns.Count - 1;
+ if FSortColumn <> Value then
+ begin
+ if FSortColumn > NoColumn then
+ Invalidate(Columns[FSortColumn]);
+ FSortColumn := Value;
+ if FSortColumn > NoColumn then
+ Invalidate(Columns[FSortColumn]);
+ if (toAutoSort in Treeview.FOptions.FAutoOptions) and (Treeview.FUpdateCount = 0) then
+ Treeview.SortTree(FSortColumn, FSortDirection, True);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetSortDirection(const Value: TSortDirection);
+
+begin
+ if Value <> FSortDirection then
+ begin
+ FSortDirection := Value;
+ Invalidate(nil);
+ if (toAutoSort in Treeview.FOptions.FAutoOptions) and (Treeview.FUpdateCount = 0) then
+ Treeview.SortTree(FSortColumn, FSortDirection, True);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetStyle(Value: TVTHeaderStyle);
+
+begin
+ if FStyle <> Value then
+ begin
+ FStyle := Value;
+ if not (csLoading in Treeview.ComponentState) then
+ Invalidate(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.CanWriteColumns: Boolean;
+
+// Descentants may override this to optionally prevent column writing (e.g. if they are build dynamically).
+
+begin
+ Result := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.ChangeScale(M, D: Integer);
+
+begin
+ FFont.Size := MulDiv(FFont.Size, M, D);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.DetermineSplitterIndex(P: TPoint): Boolean;
+
+// Tries to find the index of that column whose right border corresponds to P.
+// Result is True if column border was hit (with -3..+5 pixels tolerance).
+// For continuous resizing the current track index and the column's left border are set.
+// Note: The hit test is checking from right to left to make enlarging of zero-sized columns possible.
+
+var
+ I,
+ SplitPoint: Integer;
+
+begin
+ Result := False;
+ FColumns.FTrackIndex := NoColumn;
+
+ if FColumns.Count > 0 then
+ begin
+ SplitPoint := Treeview.FOffsetX + Integer(Treeview.FRangeX);
+
+ for I := FColumns.Count - 1 downto 0 do
+ with FColumns, Items[FPositionToIndex[I]] do
+ if coVisible in FOptions then
+ begin
+ if (P.X < SplitPoint + 5) and (P.X > SplitPoint - 3) then
+ begin
+ if coResizable in FOptions then
+ begin
+ Result := True;
+ FTrackIndex := FPositionToIndex[I];
+ FLeftTrackPos := SplitPoint - FWidth;
+ end;
+ Break;
+ end;
+ Dec(SplitPoint, FWidth);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.DragTo(P: TPoint);
+
+// Moves the drag image to a new position, which is determined from the passed point P and the previous
+// mouse position.
+
+var
+ I,
+ NewTarget: Integer;
+ // optimized drag image move support
+ ClientP: TPoint;
+ Left,
+ Right: Integer;
+ NeedRepaint: Boolean; // True if the screen needs an update (changed drop target or drop side)
+
+begin
+ // Determine new drop target and which side of it is prefered.
+ ClientP := Treeview.ScreenToClient(P);
+ // Make coordinates relative to (0, 0) of the non-client area.
+ Inc(ClientP.Y, FHeight);
+ NewTarget := FColumns.ColumnFromPosition(ClientP);
+ NeedRepaint := (NewTarget <> InvalidColumn) and (NewTarget <> FColumns.FDropTarget);
+ if NewTarget >= 0 then
+ begin
+ FColumns.GetColumnBounds(NewTarget, Left, Right);
+ if (ClientP.X < ((Left + Right) div 2)) <> FColumns.FDropBefore then
+ begin
+ NeedRepaint := True;
+ FColumns.FDropBefore := not FColumns.FDropBefore;
+ end;
+ end;
+
+ if NeedRepaint then
+ begin
+ // Invalidate columns which need a repaint.
+ if FColumns.FDropTarget > NoColumn then
+ begin
+ I := FColumns.FDropTarget;
+ FColumns.FDropTarget := NoColumn;
+ Invalidate(FColumns.Items[I]);
+ end;
+ if (NewTarget > NoColumn) and (NewTarget <> FColumns.FDropTarget) then
+ begin
+ Invalidate(FColumns.Items[NewTarget]);
+ FColumns.FDropTarget := NewTarget;
+ end;
+ end;
+
+ FDragImage.DragTo(P, NeedRepaint);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetColumnsClass: TVirtualTreeColumnsClass;
+
+// Returns the class to be used for the actual column implementation. Descentants may optionally override this and
+// return their own class.
+
+begin
+ Result := TVirtualTreeColumns;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetOwner: TPersistent;
+
+begin
+ Result := FOwner;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetShiftState: TShiftState;
+
+begin
+ Result := [];
+ if GetKeyState(VK_SHIFT) < 0 then
+ Include(Result, ssShift);
+ if GetKeyState(VK_CONTROL) < 0 then
+ Include(Result, ssCtrl);
+ if GetKeyState(VK_MENU) < 0 then
+ Include(Result, ssAlt);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.HandleHeaderMouseMove(var Message: TWMMouseMove): Boolean;
+
+var
+ P: TPoint;
+ I: Integer;
+
+begin
+ Result := False;
+ with Message do
+ begin
+ P := Point(XPos, YPos);
+ if hsTrackPending in FStates then
+ begin
+ Treeview.StopTimer(HeaderTimer);
+ FStates := FStates - [hsTrackPending] + [hsTracking];
+ HandleHeaderMouseMove := True;
+ Result := 0;
+ end
+ else
+ if hsTracking in FStates then
+ begin
+ FColumns[FColumns.FTrackIndex].Width := XPos - FLeftTrackPos;
+ HandleHeaderMouseMove := True;
+ Result := 0;
+ end
+ else
+ begin
+ if hsDragPending in FStates then
+ begin
+ P := Treeview.ClientToScreen(P);
+ // start actual dragging if allowed
+ if (hoDrag in FOptions) and Treeview.DoHeaderDragging(FColumns.FDownIndex) then
+ begin
+ if ((Abs(FDragStart.X - P.X) > Mouse.DragThreshold) or
+ (Abs(FDragStart.Y - P.Y) > Mouse.DragThreshold)) then
+ begin
+ Treeview.StopTimer(HeaderTimer);
+ I := FColumns.FDownIndex;
+ FColumns.FDownIndex := NoColumn;
+ FColumns.FHoverIndex := NoColumn;
+ if I > NoColumn then
+ Invalidate(FColumns[I]);
+ PrepareDrag(P, FDragStart);
+ FStates := FStates - [hsDragPending] + [hsDragging];
+ HandleHeaderMouseMove := True;
+ Result := 0;
+ end;
+ end;
+ end
+ else
+ if hsDragging in FStates then
+ begin
+ DragTo(Treeview.ClientToScreen(Point(XPos, YPos)));
+ HandleHeaderMouseMove := True;
+ Result := 0;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.HandleMessage(var Message: TMessage): Boolean;
+
+// The header gets here the opportunity to handle certain messages before they reach the tree. This is important
+// because the tree needs to handle various non-client area messages for the header as well as some dragging/tracking
+// events.
+// By returning True the message will not be handled further, otherwise the message is then dispatched
+// to the proper message handlers.
+
+var
+ P: TPoint;
+ R: TRect;
+ I: Integer;
+ OldPosition: Integer;
+ HitIndex: TColumnIndex;
+ NewCursor: HCURSOR;
+ Button: TMouseButton;
+
+begin
+ Result := False;
+ case Message.Msg of
+ WM_SIZE:
+ begin
+ if (hoAutoResize in FOptions) and not (hsAutoSizing in FStates) and
+ not (tsWindowCreating in FOwner.FStates) then
+ begin
+ FColumns.AdjustAutoSize(InvalidColumn);
+ Invalidate(nil);
+ end;
+ end;
+ CM_BIDIMODECHANGED:
+ for I := 0 to FColumns.Count - 1 do
+ if coParentBiDiMode in FColumns[I].FOptions then
+ FColumns[I].ParentBiDiModeChanged;
+ WM_NCMBUTTONDOWN:
+ begin
+ with TWMNCMButtonDown(Message) do
+ P := Treeview.ScreenToClient(Point(XCursor, YCursor));
+ if InHeader(P) then
+ FOwner.DoHeaderMouseDown(mbMiddle, GetShiftState, P.X, P.Y + Integer(FHeight));
+ end;
+ WM_NCMBUTTONUP:
+ begin
+ with TWMNCMButtonUp(Message) do
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ if InHeader(P) then
+ begin
+ FColumns.HandleClick(P, mbMiddle, True, False);
+ FOwner.DoHeaderMouseUp(mbMiddle, GetShiftState, P.X, P.Y + Integer(FHeight));
+ FColumns.FDownIndex := NoColumn;
+ end;
+ end;
+ WM_NCLBUTTONDBLCLK,
+ WM_NCMBUTTONDBLCLK,
+ WM_NCRBUTTONDBLCLK:
+ begin
+ with TWMNCLButtonDblClk(Message) do
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ // If the click was on a splitter then resize column do smallest width.
+ if InHeader(P) then
+ begin
+ case Message.Msg of
+ WM_NCMBUTTONDBLCLK:
+ Button := mbMiddle;
+ WM_NCRBUTTONDBLCLK:
+ Button := mbRight;
+ else
+ // WM_NCLBUTTONDBLCLK
+ Button := mbLeft;
+ end;
+ if (hoDblClickResize in FOptions) and (FColumns.FTrackIndex > NoColumn) then
+ begin
+ with FColumns do
+ AnimatedResize(FTrackIndex, Max(FColumns[FTrackIndex].MinWidth, Treeview.GetMaxColumnWidth(FTrackIndex)));
+ end
+ else
+ FColumns.HandleClick(P, Button, True, True);
+ FOwner.DoHeaderDblClick(FColumns.FClickIndex, Button, GetShiftState + [ssDouble], P.X, P.Y + Integer(FHeight));
+ end;
+ end;
+ WM_NCLBUTTONDOWN:
+ begin
+ Application.CancelHint;
+
+ // make sure no auto scrolling is active...
+ Treeview.StopTimer(ScrollTimer);
+ Treeview.DoStateChange([], [tsScrollPending, tsScrolling]);
+ // ... pending editing is cancelled (actual editing remains active)
+ Treeview.StopTimer(EditTimer);
+ Treeview.DoStateChange([], [tsEditPending]);
+
+ with TWMNCLButtonDown(Message) do
+ begin
+ // want the drag start point in screen coordinates
+ FDragStart := Point(XCursor, YCursor);
+ P := Treeview.ScreenToClient(FDragStart);
+ end;
+
+ if InHeader(P) then
+ begin
+ // This is a good opportunity to notify the application.
+ FOwner.DoHeaderMouseDown(mbLeft, GetShiftState, P.X, P.Y + Integer(FHeight));
+
+ if DetermineSplitterIndex(P) and (hoColumnResize in FOptions) then
+ begin
+ FColumns.FHoverIndex := NoColumn;
+ FTrackStart := P;
+ Include(FStates, hsTrackPending);
+ SetCapture(Treeview.Handle);
+ Result := True;
+ Message.Result := 0;
+ end
+ else
+ begin
+ HitIndex := Columns.AdjustDownColumn(P);
+ if (hoDrag in FOptions) and (HitIndex > NoColumn) and (coDraggable in FColumns[HitIndex].FOptions) then
+ begin
+ // Show potential drag operation.
+ // Disabled columns do not start a drag operation because they can't be clicked.
+ Include(FStates, hsDragPending);
+ SetCapture(Treeview.Handle);
+ Result := True;
+ Message.Result := 0;
+ end;
+ end;
+ end;
+ end;
+ WM_NCRBUTTONDOWN:
+ begin
+ with TWMNCRButtonDown(Message) do
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ if InHeader(P) then
+ FOwner.DoHeaderMouseDown(mbRight, GetShiftState, P.X, P.Y + Integer(FHeight));
+ end;
+ WM_NCRBUTTONUP:
+ if not (csDesigning in FOwner.ComponentState) then
+ with TWMNCRButtonUp(Message) do
+ begin
+ Application.CancelHint;
+
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ if InHeader(P) then
+ begin
+ FColumns.HandleClick(P, mbRight, True, False);
+ FOwner.DoHeaderMouseUp(mbRight, GetShiftState, P.X, P.Y + Integer(FHeight));
+ FColumns.FDownIndex := NoColumn;
+ FColumns.FTrackIndex := NoColumn;
+
+ // Trigger header popup if there's one.
+ if Assigned(FPopupMenu) then
+ begin
+ Treeview.StopTimer(ScrollTimer);
+ Treeview.StopTimer(HeaderTimer);
+ FColumns.FHoverIndex := NoColumn;
+ Treeview.DoStateChange([], [tsScrollPending, tsScrolling]);
+ FPopupMenu.PopupComponent := Treeview;
+ FPopupMenu.Popup(XCursor, YCursor);
+ HandleMessage := True;
+ end;
+ end;
+ end;
+ // When the tree window has an active mouse capture then we only get "client-area" messages.
+ WM_LBUTTONUP,
+ WM_NCLBUTTONUP:
+ begin
+ Application.CancelHint;
+
+ if FStates <> [] then
+ begin
+ ReleaseCapture;
+ if hsDragging in FStates then
+ begin
+ // successfull dragging moves columns
+ with TWMLButtonUp(Message) do
+ P := Treeview.ClientToScreen(Point(XPos, YPos));
+ GetWindowRect(Treeview.Handle, R);
+ with FColumns do
+ begin
+ FDragImage.EndDrag;
+ if (FDropTarget > -1) and (FDropTarget <> FDragIndex) and PtInRect(R, P) then
+ begin
+ OldPosition := FColumns[FDragIndex].Position;
+ if FColumns.FDropBefore then
+ begin
+ if FColumns[FDragIndex].Position < FColumns[FDropTarget].Position then
+ FColumns[FDragIndex].Position := Max(0, FColumns[FDropTarget].Position - 1)
+ else
+ FColumns[FDragIndex].Position := FColumns[FDropTarget].Position;
+ end
+ else
+ begin
+ if FColumns[FDragIndex].Position < FColumns[FDropTarget].Position then
+ FColumns[FDragIndex].Position := FColumns[FDropTarget].Position
+ else
+ FColumns[FDragIndex].Position := FColumns[FDropTarget].Position + 1;
+ end;
+ Treeview.DoHeaderDragged(FDragIndex, OldPosition);
+ end
+ else
+ Treeview.DoHeaderDraggedOut(FDragIndex, P);
+ FDropTarget := NoColumn;
+ end;
+ Invalidate(nil);
+ end;
+ Result := True;
+ Message.Result := 0;
+ end;
+
+ case Message.Msg of
+ WM_LBUTTONUP:
+ with TWMLButtonUp(Message) do
+ begin
+ if FColumns.FDownIndex > NoColumn then
+ FColumns.HandleClick(Point(XPos, YPos), mbLeft, False, False);
+ if FStates <> [] then
+ FOwner.DoHeaderMouseUp(mbLeft, KeysToShiftState(Keys), XPos, YPos);
+ end;
+ WM_NCLBUTTONUP:
+ with TWMNCLButtonUp(Message) do
+ begin
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ FColumns.HandleClick(P, mbLeft, False, False);
+ FOwner.DoHeaderMouseUp(mbLeft, GetShiftState, P.X, P.Y + Integer(FHeight));
+ end;
+ end;
+
+ if FColumns.FTrackIndex > NoColumn then
+ begin
+ Invalidate(Columns[FColumns.FTrackIndex]);
+ FColumns.FTrackIndex := NoColumn;
+ end;
+ if FColumns.FDownIndex > NoColumn then
+ begin
+ Invalidate(Columns[FColumns.FDownIndex]);
+ FColumns.FDownIndex := NoColumn;
+ end;
+ FStates := FStates - [hsDragging, hsDragPending, hsTracking, hsTrackPending];
+ end;
+ // hovering, mouse leave detection
+ WM_NCMOUSEMOVE:
+ with TWMNCMouseMove(Message), FColumns do
+ begin
+ P := Treeview.ScreenToClient(Point(XCursor, YCursor));
+ Treeview.DoHeaderMouseMove(GetShiftState, P.X, P.Y + Integer(FHeight));
+ if InHeader(P) and ((AdjustHoverColumn(P)) or ((FDownIndex >= 0) and (FHoverIndex <> FDownIndex))) then
+ begin
+ // We need a mouse leave detection from here for the non client area. The best solution available would be the
+ // TrackMouseEvent API. Unfortunately, it leaves Win95 totally and WinNT4 for non-client stuff out and
+ // currently I cannot ignore these systems. Hence I go the only other reliable way and use a timer
+ // (although, I don't like it...).
+ Treeview.StopTimer(HeaderTimer);
+ SetTimer(Treeview.Handle, HeaderTimer, 50, nil);
+ // use Delphi's internal hint handling for header hints too
+ if hoShowHint in FOptions then
+ begin
+ // client coordinates!
+ XCursor := P.x;
+ YCursor := P.y + Integer(FHeight);
+ Application.HintMouseMessage(Treeview, Message);
+ end;
+ end
+ end;
+ WM_TIMER:
+ if TWMTimer(Message).TimerID = HeaderTimer then
+ begin
+ // determine current mouse position to check if it left the window
+ GetCursorPos(P);
+ P := Treeview.ScreenToClient(P);
+ with FColumns do
+ begin
+ if not InHeader(P) or ((FDownIndex > NoColumn) and (FHoverIndex <> FDownIndex)) then
+ begin
+ Treeview.StopTimer(HeaderTimer);
+ FHoverIndex := NoColumn;
+ FClickIndex := NoColumn;
+ FDownIndex := NoColumn;
+ Result := True;
+ Message.Result := 0;
+ Invalidate(nil);
+ end;
+ end;
+ end;
+ WM_MOUSEMOVE: // mouse capture and general message redirection
+ Result := HandleHeaderMouseMove(TWMMouseMove(Message));
+ WM_SETCURSOR:
+ if FStates = [] then
+ begin
+ // Retrieve last cursor position (GetMessagePos does not work here, I don't know why).
+ GetCursorPos(P);
+ // Is the mouse in the header rectangle?
+ P := Treeview.ScreenToClient(P);
+ if InHeader(P) then
+ begin
+ NewCursor := Screen.Cursors[crDefault];
+ if hoColumnResize in FOptions then
+ begin
+ if DetermineSplitterIndex(P) then
+ NewCursor := Screen.Cursors[crHeaderSplit];
+
+ Treeview.DoGetHeaderCursor(NewCursor);
+ Result := NewCursor <> Screen.Cursors[crDefault];
+ if Result then
+ begin
+ Windows.SetCursor(NewCursor);
+ Message.Result := 1;
+ end
+ end;
+ end;
+ end
+ else
+ begin
+ Message.Result := 1;
+ Result := True;
+ end;
+ WM_KEYDOWN,
+ WM_KILLFOCUS:
+ if (Message.Msg = WM_KILLFOCUS) or
+ (TWMKeyDown(Message).CharCode = VK_ESCAPE) then
+ begin
+ if hsDragging in FStates then
+ begin
+ ReleaseCapture;
+ FDragImage.EndDrag;
+ Exclude(FStates, hsDragging);
+ FColumns.FDropTarget := NoColumn;
+ Invalidate(nil);
+ Result := True;
+ Message.Result := 0;
+ end
+ else
+ if hsTracking in FStates then
+ begin
+ ReleaseCapture;
+ Exclude(FStates, hsTracking);
+ Result := True;
+ Message.Result := 0;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.ImageListChange(Sender: TObject);
+
+begin
+ if not (csDestroying in Treeview.ComponentState) then
+ Invalidate(nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.PrepareDrag(P, Start: TPoint);
+
+// Initializes dragging of the header, P is the current mouse postion and Start the initial mouse position.
+
+var
+ ColumnR,
+ HeaderR: TRect;
+ Image: TBitmap;
+ ImagePos: TPoint;
+
+begin
+ // Determine initial position of drag image (screen coordinates).
+ FColumns.FDropTarget := NoColumn;
+ Start := Treeview.ScreenToClient(Start);
+ Inc(Start.Y, FHeight);
+ FColumns.FDragIndex := FColumns.ColumnFromPosition(Start);
+ ColumnR := FColumns[FColumns.FDragIndex].GetRect;
+
+ HeaderR := Treeview.FHeaderRect;
+ // Set right border of the header rectangle to the maximum extent.
+ HeaderR.Right := FColumns.TotalWidth;
+
+ // Take out influence of border since we need a seamless drag image.
+ OffsetRect(ColumnR, -HeaderR.Left + Treeview.FOffsetX, -HeaderR.Top);
+
+ Image := TBitmap.Create;
+ with Image do
+ try
+ PixelFormat := pf32Bit;
+ Width := ColumnR.Right - ColumnR.Left + HeaderR.Left;
+ Height := ColumnR.Bottom - ColumnR.Top + HeaderR.Top;
+
+ HeaderR.Left := 0;
+ HeaderR.Top := 0;
+
+ // Erase the entire image with the color key value, for the case not everything
+ // in the image is covered by the header image.
+ Canvas.Brush.Color := clBtnFace;
+ Canvas.FillRect(Rect(0, 0, Width, Height));
+
+ FColumns.PaintHeader(Canvas.Handle, HeaderR, -ColumnR.Left + Treeview.FOffsetX, -ColumnR.Top);
+
+ ImagePos := Treeview.ClientToScreen(ColumnR.TopLeft);
+ // Column rectangles are given in local window coordinates not client coordinates.
+ Dec(ImagePos.Y, FHeight);
+
+ if hoRestrictDrag in FOptions then
+ FDragImage.MoveRestriction := dmrHorizontalOnly
+ else
+ FDragImage.MoveRestriction := dmrNone;
+ FDragImage.PrepareDrag(Image, ImagePos, P, nil);
+ FDragImage.ShowDragImage;
+ finally
+ Image.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.ReadColumns(Reader: TReader);
+
+begin
+ Include(FStates, hsLoading);
+ Columns.Clear;
+ Reader.ReadValue;
+ Reader.ReadCollection(Columns);
+ Exclude(FStates, hsLoading);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.RecalculateHeader;
+
+// Initiate a recalculation of the non-client area of the owner tree.
+
+begin
+ if Treeview.HandleAllocated then
+ begin
+ Treeview.UpdateHeaderRect;
+ SetWindowPos(Treeview.Handle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or
+ SWP_NOSENDCHANGING or SWP_NOSIZE or SWP_NOZORDER);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.UpdateMainColumn;
+
+// Called once the load process of the owner tree is done.
+
+begin
+ if FMainColumn < 0 then
+ FMainColumn := 0;
+ if FMainColumn > FColumns.Count - 1 then
+ FMainColumn := FColumns.Count - 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.WriteColumns(Writer: TWriter);
+
+begin
+ Writer.WriteCollection(Columns);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.Assign(Source: TPersistent);
+
+begin
+ if Source is TVTHeader then
+ begin
+ AutoSizeIndex := TVTHeader(Source).AutoSizeIndex;
+ Background := TVTHeader(Source).Background;
+ Columns := TVTHeader(Source).Columns;
+ Font := TVTHeader(Source).Font;
+ Height := TVTHeader(Source).Height;
+ Options := TVTHeader(Source).Options;
+ PopupMenu := TVTHeader(Source).PopupMenu;
+ Style := TVTHeader(Source).Style;
+ end
+ else
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.AutoFitColumns;
+
+var
+ I: Integer;
+
+begin
+ with FColumns do
+ for I := 0 to Count - 1 do
+ if [coResizable, coVisible] * Items[FPositionToIndex[I]].FOptions = [coResizable, coVisible] then
+ AnimatedResize(FPositionToIndex[I], Treeview.GetMaxColumnWidth(FPositionToIndex[I]))
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.InHeader(P: TPoint): Boolean;
+
+// Determines whether the given point (client coordinates!) is within the header rectangle (non-client coordinates).
+
+var
+ R, RW: TRect;
+
+begin
+ R := Treeview.FHeaderRect;
+ // current position of the owner in screen coordinates
+ GetWindowRect(Treeview.Handle, RW);
+ // convert to client coordinates
+ MapWindowPoints(0, Treeview.Handle, RW, 2);
+ // consider the header within this rectangle
+ OffsetRect(R, RW.Left, RW.Top);
+ Result := PtInRect(R, P);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.Invalidate(Column: TVirtualTreeColumn; ExpandToRight: Boolean = False);
+
+// Because the header is in the non-client area of the tree it needs some special handling in order to initiate its
+// repainting.
+// If ExpandToRight is True then not only the given column but everything to its right will be invalidated (useful for
+// resizing). This makes only sense when a column is given.
+
+var
+ R, RW: TRect;
+
+begin
+ if (hoVisible in FOptions) and Treeview.HandleAllocated then
+ begin
+ if Column = nil then
+ R := Treeview.FHeaderRect
+ else
+ begin
+ R := Column.GetRect;
+ OffsetRect(R, Treeview.FOffsetX, 0);
+ if ExpandToRight then
+ R.Right := Treeview.FHeaderRect.Right;
+ end;
+
+ // Current position of the owner in screen coordinates.
+ GetWindowRect(Treeview.Handle, RW);
+ // Consider the header within this rectangle.
+ OffsetRect(R, RW.Left, RW.Top);
+ // Expressed in client coordinates (because RedrawWindow wants them so, they will actually become negative).
+ MapWindowPoints(0, Treeview.Handle, R, 2);
+ RedrawWindow(Treeview.Handle, @R, 0, RDW_FRAME or RDW_INVALIDATE or RDW_VALIDATE or RDW_NOINTERNALPAINT or
+ RDW_NOERASE or RDW_NOCHILDREN);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.LoadFromStream(const Stream: TStream);
+
+// restore the state of the header from the given stream
+
+var
+ Dummy,
+ Version: Integer;
+ S: string;
+ OldOptions: TVTHeaderOptions;
+
+begin
+ Include(FStates, hsLoading);
+ with Stream do
+ try
+ // switch off all options which could influence loading the columns (they will be later set again)
+ OldOptions := FOptions;
+ FOptions := [];
+
+ // determine whether the stream contains data without a version number
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ if Dummy > -1 then
+ begin
+ // seek back to undo read operation if this is an old stream format
+ Seek(-SizeOf(Dummy), soFromCurrent);
+ Version := -1;
+ end
+ else // read version number if this is a "versionized" format
+ ReadBuffer(Version, SizeOf(Version));
+ Columns.LoadFromStream(Stream, Version);
+
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ AutoSizeIndex := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Background := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Height := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ FOptions := OldOptions;
+ Options := TVTHeaderOptions(Word(Dummy));
+ // PopupMenu is neither saved nor restored
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Style := TVTHeaderStyle(Dummy);
+ // TFont has no own save routine so we do it manually
+ with Font do
+ begin
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Color := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Height := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SetLength(S, Dummy);
+ ReadBuffer(PChar(S)^, Dummy);
+ Name := S;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Pitch := TFontPitch(Dummy);
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Style := TFontStyles(Byte(Dummy));
+ end;
+
+ // read data introduced by stream version 1+
+ if Version > 0 then
+ begin
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ MainColumn := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SortColumn := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SortDirection := TSortDirection(Byte(Dummy));
+ end;
+ finally
+ Exclude(FStates, hsLoading);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.RestoreColumns;
+
+// Restores all columns to their width which they had before they have been auto fitted.
+
+var
+ I: Integer;
+
+begin
+ with FColumns do
+ for I := Count - 1 downto 0 do
+ if [coResizable, coVisible] * Items[FPositionToIndex[I]].FOptions = [coResizable, coVisible] then
+ Items[I].RestoreLastWidth;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SaveToStream(const Stream: TStream);
+
+// Saves the complete state of the header into the provided stream.
+
+var
+ Dummy: Integer;
+
+begin
+ with Stream do
+ begin
+ // In previous version of VT was no header stream version defined.
+ // For feature enhancements it is necessary, however, to know which stream
+ // format we are trying to load.
+ // In order to distict from non-version streams an indicator is inserted.
+ Dummy := -1;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ // Write current stream version number, nothing more is required at the time being.
+ Dummy := VTHeaderStreamVersion;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+
+ // Save columns in case they depend on certain options (like auto size).
+ Columns.SaveToStream(Stream);
+
+ Dummy := FAutoSizeIndex;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := FBackground;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := FHeight;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Word(FOptions);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ // PopupMenu is neither saved nor restored
+ Dummy := Ord(FStyle);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ // TFont has no own save routine so we do it manually
+ with Font do
+ begin
+ Dummy := Color;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Height;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Length(Name);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ WriteBuffer(PChar(Name)^, Dummy);
+ Dummy := Ord(Pitch);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ // need only to write one: size or height, I decided to write height
+ Dummy := Byte(Style);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ end;
+
+ // data introduced by stream version 1
+ Dummy := FMainColumn;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := FSortColumn;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Byte(FSortDirection);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ end;
+end;
+
+//----------------- TScrollBarOptions ----------------------------------------------------------------------------------
+
+constructor TScrollBarOptions.Create(AOwner: TBaseVirtualTree);
+
+begin
+ inherited Create;
+
+ FOwner := AOwner;
+ FAlwaysVisible := False;
+ FScrollBarStyle := sbmRegular;
+ FScrollBars := ssBoth;
+ FIncrementX := 20;
+ FIncrementY := 20;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TScrollBarOptions.SetAlwaysVisible(Value: Boolean);
+
+begin
+ if FAlwaysVisible <> Value then
+ begin
+ FAlwaysVisible := Value;
+ if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then
+ FOwner.RecreateWnd;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TScrollBarOptions.SetScrollBars(Value: TScrollStyle);
+
+begin
+ if FScrollbars <> Value then
+ begin
+ FScrollBars := Value;
+ if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then
+ FOwner.RecreateWnd;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TScrollBarOptions.SetScrollBarStyle(Value: TScrollBarStyle);
+
+begin
+ {$ifndef UseFlatScrollbars}
+ Assert(Value = sbmRegular, 'Flat scrollbars styles are disabled. Enable UseFlatScrollbars in VirtualTrees.pas for' +
+ 'flat scrollbar support.');
+ {$endif UseFlatScrollbars}
+
+ if FScrollBarStyle <> Value then
+ begin
+ FScrollBarStyle := Value;
+ {$ifdef UseFlatScrollbars}
+ if FOwner.HandleAllocated then
+ begin
+ // If set to regular style then don't use the emulation mode of the FlatSB APIs but the original APIs.
+ // This is necessary because the FlatSB APIs don't respect NC paint request with limited update region
+ // (which is necessary for the transparent drag image).
+ FOwner.RecreateWnd;
+ end;
+ {$endif UseFlatScrollbars}
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TScrollBarOptions.GetOwner: TPersistent;
+
+begin
+ Result := FOwner;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TScrollBarOptions.Assign(Source: TPersistent);
+
+begin
+ if Source is TScrollBarOptions then
+ begin
+ AlwaysVisible := TScrollBarOptions(Source).AlwaysVisible;
+ HorizontalIncrement := TScrollBarOptions(Source).HorizontalIncrement;
+ ScrollBars := TScrollBarOptions(Source).ScrollBars;
+ ScrollBarStyle := TScrollBarOptions(Source).ScrollBarStyle;
+ VerticalIncrement := TScrollBarOptions(Source).VerticalIncrement;
+ end
+ else
+ inherited;
+end;
+
+//----------------- TVTColors ------------------------------------------------------------------------------------------
+
+constructor TVTColors.Create(AOwner: TBaseVirtualTree);
+
+begin
+ FOwner := AOwner;
+ FColors[0] := clBtnShadow; // DisabledColor
+ FColors[1] := clHighlight; // DropMarkColor
+ FColors[2] := clHighLight; // DropTargetColor
+ FColors[3] := clHighLight; // FocusedSelectionColor
+ FColors[4] := clBtnFace; // GridLineColor
+ FColors[5] := clBtnShadow; // TreeLineColor
+ FColors[6] := clBtnFace; // UnfocusedSelectionColor
+ FColors[7] := clBtnFace; // BorderColor
+ FColors[8] := clWindowText; // HotColor
+ FColors[9] := clHighLight; // FocusedSelectionBorderColor
+ FColors[10] := clBtnFace; // UnfocusedSelectionBorderColor
+ FColors[11] := clHighlight; // DropTargetBorderColor
+ FColors[12] := clHighlight; // SelectionRectangleBlendColor
+ FColors[13] := clHighlight; // SelectionRectangleBorderColor
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTColors.GetColor(const Index: Integer): TColor;
+
+begin
+ Result := FColors[Index];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTColors.SetColor(const Index: Integer; const Value: TColor);
+
+begin
+ if FColors[Index] <> Value then
+ begin
+ FColors[Index] := Value;
+ // Cause helper bitmap rebuild for grid and tree line colors.
+ if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then
+ begin
+ FOwner.Invalidate;
+ if Index = 7 then
+ RedrawWindow(FOwner.Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTColors.Assign(Source: TPersistent);
+
+begin
+ if Source is TVTColors then
+ begin
+ FColors := TVTColors(Source).FColors;
+ if FOwner.FUpdateCount = 0 then
+ FOwner.Invalidate;
+ end
+ else
+ inherited;
+end;
+
+//----------------- TClipboardFormats ----------------------------------------------------------------------------------
+
+constructor TClipboardFormats.Create(AOwner: TBaseVirtualTree);
+
+begin
+ FOwner := AOwner;
+ Sorted := True;
+ Duplicates := dupIgnore;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardFormats.Add(const S: string): Integer;
+
+// Restrict additions to the clipbard formats to only those which are registered with the owner tree or one of its
+// ancestors.
+
+var
+ Format: Word;
+ RegisteredClass: TVirtualTreeClass;
+
+begin
+ RegisteredClass := InternalClipboardFormats.FindFormat(S, Format);
+ if Assigned(RegisteredClass) and FOwner.ClassType.InheritsFrom(RegisteredClass) then
+ Result := inherited Add(S)
+ else
+ Result := -1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormats.Insert(Index: Integer; const S: string);
+
+// Restrict additions to the clipbard formats to only those which are registered with the owner tree or one of its
+// ancestors.
+
+var
+ Format: Word;
+ RegisteredClass: TVirtualTreeClass;
+
+begin
+ RegisteredClass := InternalClipboardFormats.FindFormat(S, Format);
+ if Assigned(RegisteredClass) and FOwner.ClassType.InheritsFrom(RegisteredClass) then
+ inherited Insert(Index, S);
+end;
+
+//----------------- TBaseVirtualTree -----------------------------------------------------------------------------------
+
+constructor TBaseVirtualTree.Create(AOwner: TComponent);
+
+begin
+ if not Initialized then
+ InitializeGlobalStructures;
+
+ inherited;
+
+ ControlStyle := ControlStyle - [csSetCaption] + [csCaptureMouse, csOpaque, csReplicatable, csDisplayDragImage,
+ csReflector];
+ FTotalInternalDataSize := 0;
+ FNodeDataSize := -1;
+ Width := 200;
+ Height := 100;
+ TabStop := True;
+ ParentColor := False;
+ FDefaultNodeHeight := 18;
+ FDragOperations := [doCopy, doMove];
+ FHotCursor := crDefault;
+ FScrollBarOptions := TScrollBarOptions.Create(Self);
+ FFocusedColumn := NoColumn;
+ FDragImageKind := diComplete;
+ FLastSelectionLevel := -1;
+ FAnimationType := hatSystemDefault;
+ FSelectionBlendFactor := 128;
+
+ FIndent := 18;
+
+ FPlusBM := TBitmap.Create;
+ FMinusBM := TBitmap.Create;
+
+ FBorderStyle := bsSingle;
+ FButtonStyle := bsRectangle;
+ FButtonFillMode := fmTreeColor;
+
+ FHeader := GetHeaderClass.Create(Self);
+
+ // we have an own double buffer handling
+ DoubleBuffered := False;
+
+ FCheckImageKind := ckLightCheck;
+ FCheckImages := LightCheckImages;
+
+ FImageChangeLink := TChangeLink.Create;
+ FImageChangeLink.OnChange := ImageListChange;
+ FStateChangeLink := TChangeLink.Create;
+ FStateChangeLink.OnChange := ImageListChange;
+ FCustomCheckChangeLink := TChangeLink.Create;
+ FCustomCheckChangeLink.OnChange := ImageListChange;
+
+ FAutoExpandDelay := 1000;
+ FAutoScrollDelay := 1000;
+ FAutoScrollInterval := 1;
+
+ FBackground := TPicture.Create;
+
+ FDefaultPasteMode := amAddChildLast;
+ FMargin := 4;
+ FTextMargin := 4;
+ FDragType := dtOLE;
+ FDragHeight := 350;
+ FDragWidth := 200;
+
+ FColors := TVTColors.Create(Self);
+ FEditDelay := 1000;
+
+ FDragImage := TVTDragImage.Create(Self);
+ with FDragImage do
+ begin
+ Fade := True;
+ PostBlendBias := 0;
+ PreBlendBias := 0;
+ Transparency := 200;
+ end;
+
+ SetLength(FSingletonNodeArray, 1);
+ FAnimationDuration := 200;
+ FSearchTimeout := 1000;
+ FSearchStart := ssFocusedNode;
+ FNodeAlignment := naProportional;
+ FLineStyle := lsDotted;
+ FIncrementalSearch := isNone;
+ FClipboardFormats := TClipboardFormats.Create(Self);
+ FOptions := GetOptionsClass.Create(Self);
+ FChangeLock := TCriticalSection.Create;
+
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager := TVTNodeMemoryManager.Create;
+ {$endif UseLocalMemoryManager}
+
+ AddThreadReference;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TBaseVirtualTree.Destroy;
+
+begin
+ Exclude(FOptions.FMiscOptions, toReadOnly);
+ InterruptValidation;
+ StopWheelPanning;
+ CancelEditNode;
+
+ // Just in case it didn't happen already release the edit link.
+ FEditLink := nil;
+ FClipboardFormats.Free;
+ // Clear will also free the drag manager if it is still alive.
+ Clear;
+ FDragImage.Free;
+ FColors.Free;
+ FBackground.Free;
+ FImageChangeLink.Free;
+ FStateChangeLink.Free;
+ FCustomCheckChangeLink.Free;
+ FScrollBarOptions.Free;
+ FOptions.Free;
+
+ // The window handle must be destroyed before the header is freed because it is needed in WM_NCDESTROY.
+ if HandleAllocated then
+ DestroyWindowHandle;
+ FHeader.Free;
+
+ FreeMem(FRoot);
+
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager.Free;
+ {$endif UseLocalMemoryManager}
+ FPlusBM.Free;
+ FMinusBM.Free;
+ FChangeLock.Free;
+ ReleaseThreadReference(Self);
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustCoordinatesByIndent(var PaintInfo: TVTPaintInfo; Indent: Integer);
+
+// During painting of the main column some coordinates must be adjusted due to the tree lines.
+// The offset resulting from the tree lines and indentation level is given in Indent.
+
+var
+ Offset: Integer;
+
+begin
+ with PaintInfo do
+ begin
+ Offset := Indent * Integer(FIndent);
+ if BidiMode = bdLeftToRight then
+ begin
+ Inc(ContentRect.Left, Offset);
+ Inc(ImageInfo[iiNormal].XPos, Offset);
+ Inc(ImageInfo[iiState].XPos, Offset);
+ Inc(ImageInfo[iiCheck].XPos, Offset);
+ end
+ else
+ begin
+ Dec(ContentRect.Right, Offset);
+ Dec(ImageInfo[iiNormal].XPos, Offset);
+ Dec(ImageInfo[iiState].XPos, Offset);
+ Dec(ImageInfo[iiCheck].XPos, Offset);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustImageBorder(Images: TCustomImageList; BidiMode: TBidiMode; VAlign: Integer; var R: TRect;
+ var ImageInfo: TVTImageInfo);
+
+// Depending on the width of the image list as well as the given bidi mode R must be adjusted.
+
+begin
+ if BidiMode = bdLeftToRight then
+ begin
+ ImageInfo.XPos := R.Left;
+ Inc(R.Left, Images.Width + 2);
+ end
+ else
+ begin
+ ImageInfo.XPos := R.Right - Images.Width;
+ Dec(R.Right, Images.Width + 2);
+ end;
+ ImageInfo.YPos := R.Top + VAlign - Images.Height div 2;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustTotalCount(Node: PVirtualNode; Value: Integer; relative: Boolean = False);
+
+// Sets a node's total count to the given value and recursively adjusts the parent's total count
+// (actually, the adjustment is done iteratively to avoid function call overheads).
+
+var
+ Difference: Integer;
+ Run: PVirtualNode;
+
+begin
+ if relative then
+ Difference := Value
+ else
+ Difference := Integer(Value) - Integer(Node.TotalCount);
+ if Difference <> 0 then
+ begin
+ Run := Node;
+ // root node has as parent the tree view
+ while Assigned(Run) and (Run <> Pointer(Self)) do
+ begin
+ Inc(Integer(Run.TotalCount), Difference);
+ Run := Run.Parent;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustTotalHeight(Node: PVirtualNode; Value: Integer; relative: Boolean = False);
+
+// Sets a node's total height to the given value and recursively adjusts the parent's total height.
+
+var
+ Difference: Integer;
+ Run: PVirtualNode;
+
+begin
+ if relative then
+ Difference := Value
+ else
+ Difference := Integer(Value) - Integer(Node.TotalHeight);
+ if Difference <> 0 then
+ begin
+ Run := Node;
+ repeat
+ Inc(Integer(Run.TotalHeight), Difference);
+ // If the node is not visible or the parent node is not expanded or we are already at the top
+ // then nothing more remains to do.
+ if not (vsVisible in Run.States) or (Run = FRoot) or
+ (Run.Parent = nil) or not (vsExpanded in Run.Parent.States) then
+ Break;
+
+ Run := Run.Parent;
+ until False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CalculateCacheEntryCount: Integer;
+
+// Calculates the size of the position cache.
+
+begin
+ if FVisibleCount > 1 then
+ Result := Ceil(FVisibleCount / CacheThreshold)
+ else
+ Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CalculateVerticalAlignments(ShowImages, ShowStateImages: Boolean; Node: PVirtualNode;
+ var VAlign, VButtonAlign: Integer);
+
+// Calculates the vertical alignment of the given node and its associated expand/collapse button during
+// a node paint cycle depending on the required node alignment style.
+
+begin
+ // For absolute alignment the caluclation is trivial.
+ case FNodeAlignment of
+ naFromTop:
+ VAlign := Node.Align;
+ naFromBottom:
+ VAlign := Node.NodeHeight - Node.Align;
+ else // naProportional
+ // Consider button and line alignment, but make sure neither the image nor the button (whichever is taller)
+ // go out of the entire node height (100% means bottom alignment to the node's bounds).
+ if ShowImages or ShowStateImages then
+ begin
+ if ShowImages then
+ VAlign := FImages.Height
+ else
+ VAlign := FStateImages.Height;
+ VAlign := MulDiv((Node.NodeHeight - VAlign), Node.Align, 100) + VAlign div 2;
+ end
+ else
+ if toShowButtons in FOptions.FPaintOptions then
+ VAlign := MulDiv((Node.NodeHeight - FPlusBM.Height), Node.Align, 100) + FPlusBM.Height div 2
+ else
+ VAlign := MulDiv(Node.NodeHeight, Node.Align, 100);
+ end;
+
+ VButtonAlign := VAlign - FPlusBM.Height div 2;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ChangeCheckState(Node: PVirtualNode; Value: TCheckState): Boolean;
+
+// Sets the check state of the node according to the given value and the node's check type.
+// If the check state must be propagated to the parent nodes and one of them refuses to change then
+// nothing happens and False is returned, otherwise True.
+
+var
+ Run: PVirtualNode;
+ CheckCount: Cardinal;
+
+begin
+ with Node^ do
+ begin
+ Include(States, vsChecking);
+
+ // Do actions which are associated with the given check state.
+ case CheckType of
+ // Check state change with additional consequences for check states of the children.
+ ctTriStateCheckBox:
+ begin
+ // propagate state down to the children
+ if toAutoTristateTracking in FOptions.FAutoOptions then
+ case Value of
+ csUncheckedNormal:
+ begin
+ Run := FirstChild;
+ CheckCount := 0;
+ while Assigned(Run) do
+ begin
+ if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
+ begin
+ SetCheckState(Run, csUncheckedNormal);
+ // Check if the new child state was set successfully, otherwise we have to adjust the
+ // node's new check state accordingly.
+ if Run.CheckState = csUncheckedNormal then
+ Inc(CheckCount);
+ end;
+ Run := Run.NextSibling;
+ end;
+ if Node.ChildCount > 0 then
+ begin
+ if CheckCount = 0 then
+ Value := csCheckedNormal
+ else
+ if CheckCount < Node.ChildCount then
+ Value := csMixedNormal;
+ end;
+ end;
+ csCheckedNormal:
+ begin
+ Run := FirstChild;
+ CheckCount := 0;
+ while Assigned(Run) do
+ begin
+ if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
+ begin
+ SetCheckState(Run, csCheckedNormal);
+ // Check if the new child state was set successfully, otherwise we have to adjust the
+ // node's new check state accordingly.
+ if Run.CheckState = csCheckedNormal then
+ Inc(CheckCount);
+ end;
+ Run := Run.NextSibling;
+ end;
+ if Node.ChildCount > 0 then
+ begin
+ if CheckCount = 0 then
+ Value := csUncheckedNormal
+ else
+ if CheckCount < Node.ChildCount then
+ Value := csMixedNormal;
+ end;
+ end;
+ end;
+ end;
+ // radio button check state change
+ ctRadioButton:
+ if Value = csCheckedNormal then
+ begin
+ Value := csCheckedNormal;
+ // Make sure only this node is checked.
+ Run := Parent.FirstChild;
+ while Assigned(Run) do
+ begin
+ if Run.CheckType = ctRadioButton then
+ Run.CheckState := csUncheckedNormal;
+ Run := Run.NextSibling;
+ end;
+ Invalidate;
+ end;
+ end;
+
+ // Propagate state up to the parent.
+ if not (vsInitialized in Parent.States) then
+ InitNode(Parent);
+ if (toAutoTristateTracking in FOptions.FAutoOptions) and ([vsChecking, vsDisabled] * Parent.States = []) and
+ (CheckType in [ctCheckBox, ctTriStateCheckBox]) and (Parent <> FRoot) and
+ (Parent.CheckType = ctTriStateCheckBox) then
+ Result := CheckParentCheckState(Node, Value)
+ else
+ Result := True;
+
+ if Result then
+ CheckState := Value // Set new check state
+ else
+ CheckState := UnpressedState[CheckState]; // Reset dynmic check state.
+ InvalidateNode(Node);
+ Exclude(States, vsChecking);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CollectSelectedNodesLTR(MainColumn, NodeLeft, NodeRight: Integer; Alignment: TAlignment;
+ OldRect, NewRect: TRect): Boolean;
+
+// Helper routine used when a draw selection takes place. This version handles left-to-right directionality.
+// In the process of adding or removing nodes the current selection is modified which requires to pack it after
+// the function returns. Another side effect of this method is that a temporary list of nodes will be created
+// (see also InternalCacheNode) which must be inserted into the current selection by the caller.
+
+var
+ Run,
+ NextNode: PVirtualNode;
+ TextRight,
+ TextLeft,
+ CheckOffset,
+ CurrentTop,
+ CurrentRight,
+ NextTop,
+ NextColumn,
+ NodeWidth,
+ Dummy: Integer;
+ MinY, MaxY: Integer;
+ ImageOffset,
+ StateImageOffset: Integer;
+ IsInOldRect,
+ IsInNewRect: Boolean;
+
+ // quick check variables for various parameters
+ WithCheck,
+ WithImages,
+ WithStateImages,
+ DoSwitch,
+ AutoSpan,
+ Ghosted: Boolean;
+
+begin
+ // a priory nothing changes
+ Result := False;
+
+ // Determine minimum and maximum vertical coordinates to limit iteration to.
+ MinY := Min(OldRect.Top, NewRect.Top);
+ MaxY := Max(OldRect.Bottom, NewRect.Bottom);
+
+ // Initialize short hand variables to speed up tests below.
+ DoSwitch := ssCtrl in FDrawSelShiftState;
+ WithCheck := (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages);
+ // Don't check the events here as descendant trees might have overriden the DoGetImageIndex method.
+ WithImages := Assigned(FImages);
+ if WithImages then
+ ImageOffset := FImages.Width + 2
+ else
+ ImageOffset := 0;
+ WithStateImages := Assigned(FStateImages);
+ if WithStateImages then
+ StateImageOffset := FStateImages.Width + 2
+ else
+ StateImageOffset := 0;
+ if WithCheck then
+ CheckOffset := FCheckImages.Width + 2
+ else
+ CheckOffset := 0;
+ AutoSpan := FHeader.UseColumns and (toAutoSpanColumns in FOptions.FAutoOptions);
+
+ // This is the node to start with.
+ Run := GetNodeAt(0, MinY, False, CurrentTop);
+
+ if Assigned(Run) then
+ begin
+ // The initial minimal left border is determined by the identation level of the node and is dynamically adjusted.
+ if toShowRoot in FOptions.FPaintOptions then
+ Inc(NodeLeft, Integer((GetNodeLevel(Run) + 1) * FIndent) + FMargin)
+ else
+ Inc(NodeLeft, Integer(GetNodeLevel(Run) * FIndent) + FMargin);
+
+ // ----- main loop
+ // Change selection depending on the node's rectangle being in the selection rectangle or not, but
+ // touch only those nodes which overlap either the old selection rectangle or the new one but not both.
+ repeat
+ // Collect offsets for check, normal and state images.
+ TextLeft := NodeLeft;
+ if WithCheck and (Run.CheckType <> ctNone) then
+ Inc(TextLeft, CheckOffset);
+ if WithImages and (GetImageIndex(Run, ikNormal, MainColumn, Ghosted) > -1) then
+ Inc(TextLeft, ImageOffset);
+ if WithStateImages and (GetImageIndex(Run, ikState, MainColumn, Ghosted) > -1) then
+ Inc(TextLeft, StateImageOffset);
+
+ NextTop := CurrentTop + Run.NodeHeight;
+
+ // The right column border might be extended if column spanning is enabled.
+ if AutoSpan then
+ begin
+ with FHeader.FColumns do
+ begin
+ NextColumn := MainColumn;
+ repeat
+ Dummy := GetNextVisibleColumn(NextColumn);
+ if (Dummy = InvalidColumn) or not ColumnIsEmpty(Run, Dummy) or
+ (Items[Dummy].BidiMode <> bdLeftToRight) then
+ Break;
+ NextColumn := Dummy;
+ until False;
+ if NextColumn = MainColumn then
+ CurrentRight := NodeRight
+ else
+ GetColumnBounds(NextColumn, Dummy, CurrentRight);
+ end;
+ end
+ else
+ CurrentRight := NodeRight;
+
+ // Check if we need the node's width. This is the case when the node is not left aligned or the
+ // left border of the selection rectangle is to the right of the left node border.
+ if (TextLeft < OldRect.Left) or (TextLeft < NewRect.Left) or (Alignment <> taLeftJustify) then
+ begin
+ NodeWidth := DoGetNodeWidth(Run, MainColumn);
+ if NodeWidth >= (CurrentRight - TextLeft) then
+ TextRight := CurrentRight
+ else
+ case Alignment of
+ taLeftJustify:
+ TextRight := TextLeft + NodeWidth;
+ taCenter:
+ begin
+ TextLeft := (TextLeft + CurrentRight - NodeWidth) div 2;
+ TextRight := TextLeft + NodeWidth;
+ end;
+ else
+ // taRightJustify
+ TextRight := CurrentRight;
+ TextLeft := TextRight - NodeWidth;
+ end;
+ end
+ else
+ TextRight := CurrentRight;
+
+ // Now determine whether we need to change the state.
+ IsInOldRect := (OldRect.Left <= TextRight) and (OldRect.Right >= TextLeft) and
+ (NextTop > OldRect.Top) and (CurrentTop < OldRect.Bottom);
+ IsInNewRect := (NewRect.Left <= TextRight) and (NewRect.Right >= TextLeft) and
+ (NextTop > NewRect.Top) and (CurrentTop < NewRect.Bottom);
+
+ if IsInOldRect xor IsInNewRect then
+ begin
+ Result := True;
+ if DoSwitch then
+ begin
+ if vsSelected in Run.States then
+ InternalRemoveFromSelection(Run)
+ else
+ InternalCacheNode(Run);
+ end
+ else
+ begin
+ if IsInNewRect then
+ InternalCacheNode(Run)
+ else
+ InternalRemoveFromSelection(Run);
+ end;
+ end;
+
+ CurrentTop := NextTop;
+ // Get next visible node and update left node position.
+ NextNode := GetNextVisibleNoInit(Run);
+ if NextNode = nil then
+ Break;
+ Inc(NodeLeft, CountLevelDifference(Run, NextNode) * Integer(FIndent));
+ Run := NextNode;
+ until CurrentTop > MaxY;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CollectSelectedNodesRTL(MainColumn, NodeLeft, NodeRight: Integer; Alignment: TAlignment;
+ OldRect, NewRect: TRect): Boolean;
+
+// Helper routine used when a draw selection takes place. This version handles right-to-left directionality.
+// See also comments in CollectSelectedNodesLTR.
+
+var
+ Run,
+ NextNode: PVirtualNode;
+ TextRight,
+ TextLeft,
+ CheckOffset,
+ CurrentTop,
+ CurrentLeft,
+ NextTop,
+ NextColumn,
+ NodeWidth,
+ Dummy: Integer;
+ MinY, MaxY: Integer;
+ ImageOffset,
+ StateImageOffset: Integer;
+ IsInOldRect,
+ IsInNewRect: Boolean;
+
+ // quick check variables for various parameters
+ WithCheck,
+ WithImages,
+ WithStateImages,
+ DoSwitch,
+ AutoSpan,
+ Ghosted: Boolean;
+
+begin
+ // A priori nothing changes.
+ Result := False;
+ // Switch the alignment to the opposite value in RTL context.
+ ChangeBiDiModeAlignment(Alignment);
+
+ // Determine minimum and maximum vertical coordinates to limit iteration to.
+ MinY := Min(OldRect.Top, NewRect.Top);
+ MaxY := Max(OldRect.Bottom, NewRect.Bottom);
+
+ // Initialize short hand variables to speed up tests below.
+ DoSwitch := ssCtrl in FDrawSelShiftState;
+ WithCheck := (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages);
+ // Don't check the events here as descendant trees might have overriden the DoGetImageIndex method.
+ WithImages := Assigned(FImages);
+ if WithImages then
+ ImageOffset := FImages.Width + 2
+ else
+ ImageOffset := 0;
+ WithStateImages := Assigned(FStateImages);
+ if WithStateImages then
+ StateImageOffset := FStateImages.Width + 2
+ else
+ StateImageOffset := 0;
+ if WithCheck then
+ CheckOffset := FCheckImages.Width + 2
+ else
+ CheckOffset := 0;
+ AutoSpan := FHeader.UseColumns and (toAutoSpanColumns in FOptions.FAutoOptions);
+
+ // This is the node to start with.
+ Run := GetNodeAt(0, MinY, False, CurrentTop);
+
+ if Assigned(Run) then
+ begin
+ // The initial minimal left border is determined by the identation level of the node and is dynamically adjusted.
+ if toShowRoot in FOptions.FPaintOptions then
+ Dec(NodeRight, Integer((GetNodeLevel(Run) + 1) * FIndent) + FMargin)
+ else
+ Dec(NodeRight, Integer(GetNodeLevel(Run) * FIndent) + FMargin);
+
+ // ----- main loop
+ // Change selection depending on the node's rectangle being in the selection rectangle or not, but
+ // touch only those nodes which overlap either the old selection rectangle or the new one but not both.
+ repeat
+ // Collect offsets for check, normal and state images.
+ TextRight := NodeRight;
+ if WithCheck and (Run.CheckType <> ctNone) then
+ Dec(TextRight, CheckOffset);
+ if WithImages and (GetImageIndex(Run, ikNormal, MainColumn, Ghosted) > -1) then
+ Dec(TextRight, ImageOffset);
+ if WithStateImages and (GetImageIndex(Run, ikState, MainColumn, Ghosted) > -1) then
+ Dec(TextRight, StateImageOffset);
+
+ NextTop := CurrentTop + Run.NodeHeight;
+
+ // The left column border might be extended if column spanning is enabled.
+ if AutoSpan then
+ begin
+ NextColumn := MainColumn;
+ repeat
+ Dummy := FHeader.FColumns.GetPreviousVisibleColumn(NextColumn);
+ if (Dummy = InvalidColumn) or not ColumnIsEmpty(Run, Dummy) or
+ (FHeader.FColumns[Dummy].BiDiMode = bdLeftToRight) then
+ Break;
+ NextColumn := Dummy;
+ until False;
+ if NextColumn = MainColumn then
+ CurrentLeft := NodeLeft
+ else
+ FHeader.FColumns.GetColumnBounds(NextColumn, CurrentLeft, Dummy);
+ end
+ else
+ CurrentLeft := NodeLeft;
+
+ // Check if we need the node's width. This is the case when the node is not left aligned (in RTL context this
+ // means actually right aligned) or the right border of the selection rectangle is to the left
+ // of the right node border.
+ if (TextRight > OldRect.Right) or (TextRight > NewRect.Right) or (Alignment <> taRightJustify) then
+ begin
+ NodeWidth := DoGetNodeWidth(Run, MainColumn);
+ if NodeWidth >= (TextRight - CurrentLeft) then
+ TextLeft := CurrentLeft
+ else
+ case Alignment of
+ taLeftJustify:
+ begin
+ TextLeft := CurrentLeft;
+ TextRight := TextLeft + NodeWidth;
+ end;
+ taCenter:
+ begin
+ TextLeft := (TextRight + CurrentLeft - NodeWidth) div 2;
+ TextRight := TextLeft + NodeWidth;
+ end;
+ else
+ // taRightJustify
+ TextLeft := TextRight - NodeWidth;
+ end;
+ end
+ else
+ TextLeft := CurrentLeft;
+
+ // Now determine whether we need to change the state.
+ IsInOldRect := (OldRect.Right >= TextLeft) and (OldRect.Left <= TextRight) and
+ (NextTop > OldRect.Top) and (CurrentTop < OldRect.Bottom);
+ IsInNewRect := (NewRect.Right >= TextLeft) and (NewRect.Left <= TextRight) and
+ (NextTop > NewRect.Top) and (CurrentTop < NewRect.Bottom);
+
+ if IsInOldRect xor IsInNewRect then
+ begin
+ Result := True;
+ if DoSwitch then
+ begin
+ if vsSelected in Run.States then
+ InternalRemoveFromSelection(Run)
+ else
+ InternalCacheNode(Run);
+ end
+ else
+ begin
+ if IsInNewRect then
+ InternalCacheNode(Run)
+ else
+ InternalRemoveFromSelection(Run);
+ end;
+ end;
+
+ CurrentTop := NextTop;
+ // Get next visible node and update left node position.
+ NextNode := GetNextVisibleNoInit(Run);
+ if NextNode = nil then
+ Break;
+ Dec(NodeRight, CountLevelDifference(Run, NextNode) * Integer(FIndent));
+ Run := NextNode;
+ until CurrentTop > MaxY;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ClearNodeBackground(const PaintInfo: TVTPaintInfo; UseBackground, Floating: Boolean;
+ R: TRect);
+
+// Erases a nodes background depending on what the application decides to do.
+// UseBackground determines whether or not to use the background picture, while Floating indicates
+// that R is given in coordinates of the small node bitmap or the superordinated target bitmap used in PaintTree.
+
+var
+ BackColor: TColor;
+ EraseAction: TItemEraseAction;
+ Offset: TPoint;
+
+begin
+ with PaintInfo do
+ begin
+ EraseAction := eaDefault;
+ BackColor := Color;
+ DoBeforeItemErase(Canvas, Node, R, Backcolor, EraseAction);
+ if Floating then
+ begin
+ Offset := Point(FOffsetX, R.Top);
+ OffsetRect(R, 0, -Offset.Y);
+ end
+ else
+ Offset := Point(0, 0);
+
+ with Canvas do
+ begin
+ case EraseAction of
+ eaColor:
+ begin
+ // user has given a new background color
+ Brush.Color := BackColor;
+ FillRect(R);
+ DoAfterItemErase(Canvas, Node, R);
+ end;
+ else // eaDefault
+ if UseBackground then
+ TileBackground(FBackground.Bitmap, Canvas, Offset, R)
+ else
+ begin
+ if (poDrawSelection in PaintOptions) and (toFullRowSelect in FOptions.FSelectionOptions) and
+ (vsSelected in Node.States) then
+ begin
+ if toShowHorzGridLines in FOptions.PaintOptions then
+ Dec(R.Bottom);
+ if Focused or (toPopupMode in FOptions.FPaintOptions)then
+ begin
+ Brush.Color := FColors.FocusedSelectionColor;
+ Pen.Color := FColors.FocusedSelectionBorderColor;
+ end
+ else
+ begin
+ Brush.Color := FColors.UnfocusedSelectionColor;
+ Pen.Color := FColors.UnfocusedSelectionBorderColor;
+ end;
+ with R do
+ RoundRect(Left, Top, Right, Bottom, FSelectionCurveRadius, FSelectionCurveRadius);
+ end
+ else
+ begin
+ Brush.Color := Color;
+ FillRect(R);
+ end;
+ end;
+ DoAfterItemErase(Canvas, Node, R);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CompareNodePositions(Node1, Node2: PVirtualNode): Integer;
+
+// Tries hard and smart to quickly determine whether Node1's structural position is before Node2's position
+// Returns 0 if Node1 = Node2, < 0 if Node1 is located before Node2 else > 0.
+
+var
+ Run1,
+ Run2: PVirtualNode;
+ Level1,
+ Level2: Cardinal;
+
+begin
+ Assert(Assigned(Node1) and Assigned(Node2), 'Nodes must never be nil.');
+
+ if Node1 = Node2 then
+ Result := 0
+ else
+ begin
+ if HasAsParent(Node1, Node2) then
+ Result := 1
+ else
+ if HasAsParent(Node2, Node1) then
+ Result := -1
+ else
+ begin
+ // the given nodes are neither equal nor are they parents of each other, so go up to FRoot
+ // for each node and compare the child indices of the top level parents
+ // Note: neither Node1 nor Node2 can be FRoot at this point as this (a bit strange) circumstance would
+ // be caught by the previous code.
+
+ // start lookup at the same level
+ Level1 := GetNodeLevel(Node1);
+ Level2 := GetNodeLevel(Node2);
+ Run1 := Node1;
+ while Level1 > Level2 do
+ begin
+ Run1 := Run1.Parent;
+ Dec(Level1);
+ end;
+ Run2 := Node2;
+ while Level2 > Level1 do
+ begin
+ Run2 := Run2.Parent;
+ Dec(Level2);
+ end;
+
+ // now go up until we find a common parent node (loop will safely stop at FRoot if the nodes
+ // don't share a common parent)
+ while Run1.Parent <> Run2.Parent do
+ begin
+ Run1 := Run1.Parent;
+ Run2 := Run2.Parent;
+ end;
+ Result := Integer(Run1.Index) - Integer(Run2.Index);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DrawLineImage(const PaintInfo: TVTPaintInfo; X, Y, H, VAlign: Integer; Style: TVTLineType;
+ Reverse: Boolean);
+
+// Draws (depending on Style) one of the 5 line types of the tree.
+// If Reverse is True then a right-to-left column is being drawn, hence horizontal lines must be mirrored.
+// X and Y describe the left upper corner of the line image rectangle, while H denotes its height (and width).
+
+var
+ HalfWidth,
+ TargetX: Integer;
+
+begin
+ HalfWidth := Integer(FIndent) div 2;
+ if Reverse then
+ TargetX := 0
+ else
+ TargetX := FIndent;
+
+ with PaintInfo.Canvas do
+ begin
+ case Style of
+ ltBottomRight:
+ begin
+ DrawDottedVLine(PaintInfo, Y + VAlign, Y + H, X + HalfWidth);
+ DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign);
+ end;
+ ltTopDown:
+ DrawDottedVLine(PaintInfo, Y, Y + H, X + HalfWidth);
+ ltTopDownRight:
+ begin
+ DrawDottedVLine(PaintInfo, Y, Y + H, X + HalfWidth);
+ DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign);
+ end;
+ ltRight:
+ DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign);
+ ltTopRight:
+ begin
+ DrawDottedVLine(PaintInfo, Y, Y + VAlign, X + HalfWidth);
+ DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign);
+ end;
+ ltLeft: // left can also mean right for RTL context
+ if Reverse then
+ DrawDottedVLine(PaintInfo, Y, Y + H, X + Integer(FIndent))
+ else
+ DrawDottedVLine(PaintInfo, Y, Y + H, X);
+ ltLeftBottom:
+ if Reverse then
+ begin
+ DrawDottedVLine(PaintInfo, Y, Y + H, X + Integer(FIndent));
+ DrawDottedHLine(PaintInfo, X, X + Integer(FIndent), Y + H);
+ end
+ else
+ begin
+ DrawDottedVLine(PaintInfo, Y, Y + H, X);
+ DrawDottedHLine(PaintInfo, X, X + Integer(FIndent), Y + H);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.FindInPositionCache(Node: PVirtualNode; var CurrentPos: Cardinal): PVirtualNode;
+
+// Looks through the position cache and returns the node whose top position is the largest one which is smaller or equal
+// to the position of the given node.
+
+var
+ L, H, I: Integer;
+
+begin
+ L := 0;
+ H := High(FPositionCache);
+ while L <= H do
+ begin
+ I := (L + H) shr 1;
+ if CompareNodePositions(FPositionCache[I].Node, Node) <= 0 then
+ L := I + 1
+ else
+ H := I - 1;
+ end;
+ Result := FPositionCache[L - 1].Node;
+ CurrentPos := FPositionCache[L - 1].AbsoluteTop;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.FindInPositionCache(Position: Cardinal; var CurrentPos: Cardinal): PVirtualNode;
+
+// Looks through the position cache and returns the node whose top position is the largest one which is smaller or equal
+// to the given vertical position.
+// The returned node does not necessarily occupy the given position but is the nearest one to start
+// iterating from to approach the real node for a given position. CurrentPos receives the actual position of the found
+// node which is needed for further iteration.
+
+var
+ L, H, I: Integer;
+
+begin
+ L := 0;
+ H := High(FPositionCache);
+ while L <= H do
+ begin
+ I := (L + H) shr 1;
+ if FPositionCache[I].AbsoluteTop <= Position then
+ L := I + 1
+ else
+ H := I - 1;
+ end;
+ Result := FPositionCache[L - 1].Node;
+ CurrentPos := FPositionCache[L - 1].AbsoluteTop;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetCheckState(Node: PVirtualNode): TCheckState;
+
+begin
+ Result := Node.CheckState;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetCheckType(Node: PVirtualNode): TCheckType;
+
+begin
+ Result := Node.CheckType;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetChildCount(Node: PVirtualNode): Cardinal;
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.ChildCount
+ else
+ Result := Node.ChildCount;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetChildrenInitialized(Node: PVirtualNode): Boolean;
+
+begin
+ Result := not (vsHasChildren in Node.States) or (Node.ChildCount > 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetDisabled(Node: PVirtualNode): Boolean;
+
+begin
+ Result := Assigned(Node) and (vsDisabled in Node.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetDragManager: IVTDragManager;
+
+// Returns the internal drag manager interface. If this does not yet exist then it is created here.
+
+begin
+ if FDragManager = nil then
+ begin
+ FDragManager := DoCreateDragManager;
+ if FDragManager = nil then
+ FDragManager := TVTDragManager.Create(Self);
+ end;
+
+ Result := FDragManager;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetExpanded(Node: PVirtualNode): Boolean;
+
+begin
+ if Assigned(Node) then
+ Result := vsExpanded in Node.States
+ else
+ Result := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFullyVisible(Node: PVirtualNode): Boolean;
+
+// Determines whether the given node has the visibility flag set as well as all its parents are expanded.
+
+begin
+ Assert(Assigned(Node), 'Invalid parameter.');
+ Result := vsVisible in Node.States;
+ if Result and (Node <> FRoot) then
+ Result := VisiblePath[Node];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetHasChildren(Node: PVirtualNode): Boolean;
+
+begin
+ if Assigned(Node) then
+ Result := vsHasChildren in Node.States
+ else
+ Result := vsHasChildren in FRoot.States;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetMultiline(Node: PVirtualNode): Boolean;
+
+begin
+ Result := Assigned(Node) and (Node <> FRoot) and (vsMultiline in Node.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeHeight(Node: PVirtualNode): Cardinal;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ Result := Node.NodeHeight
+ else
+ Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeParent(Node: PVirtualNode): PVirtualNode;
+
+begin
+ if Assigned(Node) and (Node.Parent <> FRoot) then
+ Result := Node.Parent
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetOffsetXY: TPoint;
+
+begin
+ Result := Point(FOffsetX, FOffsetY);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetRootNodeCount: Cardinal;
+
+begin
+ Result := FRoot.ChildCount;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetSelected(Node: PVirtualNode): Boolean;
+
+begin
+ Result := Assigned(Node) and (vsSelected in Node.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetTopNode: PVirtualNode;
+
+var
+ Dummy: Integer;
+
+begin
+ Result := GetNodeAt(0, 0, True, Dummy);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetTotalCount: Cardinal;
+
+begin
+ Inc(FUpdateCount);
+ try
+ ValidateNode(FRoot, True);
+ finally
+ Dec(FUpdateCount);
+ end;
+ // The root node itself doesn't count as node.
+ Result := FRoot.TotalCount - 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetVerticalAlignment(Node: PVirtualNode): Byte;
+
+begin
+ Result := Node.Align;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetVisible(Node: PVirtualNode): Boolean;
+
+// Determines if the given node marked as being visible.
+
+begin
+ if Node = nil then
+ Node := FRoot;
+
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ Result := vsVisible in Node.States;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetVisiblePath(Node: PVirtualNode): Boolean;
+
+// Determines if all parents of the given node are expanded and have the visibility flag set.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameters.');
+
+ // FRoot is always expanded
+ repeat
+ Node := Node.Parent;
+ until (Node = FRoot) or not (vsExpanded in Node.States) or not (vsVisible in Node.States);
+
+ Result := Node = FRoot;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleClickSelection(LastFocused, NewNode: PVirtualNode; Shift: TShiftState);
+
+// Handles multi-selection with mouse click.
+
+begin
+ // Ctrl key down
+ if ssCtrl in Shift then
+ begin
+ if ssShift in Shift then
+ begin
+ SelectNodes(FRangeAnchor, NewNode, True);
+ Invalidate;
+ end
+ else
+ begin
+ if not (toSiblingSelectConstraint in FOptions.SelectionOptions) then
+ FRangeAnchor := NewNode;
+ DoStateChange([tsClearFocusedSelection])
+ end;
+ end
+ else
+ // Shift key down
+ if ssShift in Shift then
+ begin
+ if FRangeAnchor = nil then
+ FRangeAnchor := FRoot.FirstChild;
+
+ // select node range
+ if Assigned(FRangeAnchor) then
+ begin
+ SelectNodes(FRangeAnchor, NewNode, False);
+ Invalidate;
+ end;
+ end
+ else
+ begin
+ // any other case
+ if not (vsSelected in NewNode.States) then
+ begin
+ AddToSelection(NewNode);
+ InvalidateNode(NewNode);
+ end;
+ // assign new reference item
+ FRangeAnchor := NewNode;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.HandleDrawSelection(X, Y: Integer): Boolean;
+
+// Handles multi-selection with a focus rectangle.
+// Result is True if something changed in selection.
+
+var
+ OldRect,
+ NewRect: TRect;
+ MainColumn: TColumnIndex;
+ MaxValue: Integer;
+
+ // limits of a node and its text
+ NodeLeft,
+ NodeRight: Integer;
+
+ // alignment and directionality
+ CurrentBidiMode: TBidiMode;
+ CurrentAlignment: TAlignment;
+
+begin
+ Result := False;
+
+ // Selection changes are only done if the user drew a selection rectangle large
+ // enough to exceed the threshold.
+ if (FRoot.TotalCount > 1) and (tsDrawSelecting in FStates) then
+ begin
+ // Effective handling of node selection is done by using two rectangles stored in FSelectRec.
+ OldRect := OrderRect(FLastSelRect);
+ NewRect := OrderRect(FNewSelRect);
+ ClearTempCache;
+
+ MainColumn := FHeader.MainColumn;
+
+ // Alignment and bidi mode determine where the node text is located within a node.
+ if MainColumn = NoColumn then
+ begin
+ CurrentBidiMode := BidiMode;
+ CurrentAlignment := Alignment;
+ end
+ else
+ begin
+ CurrentBidiMode := FHeader.FColumns[MainColumn].BidiMode;
+ CurrentAlignment := FHeader.FColumns[MainColumn].Alignment;
+ end;
+
+ // Determine initial left border of first node (take column reordering into account).
+ if FHeader.UseColumns then
+ begin
+ // The mouse coordinates don't include any horizontal scrolling hence take this also
+ // out from the returned column position.
+ NodeLeft := FHeader.FColumns[MainColumn].Left - FOffsetX;
+ NodeRight := NodeLeft + FHeader.FColumns[MainColumn].Width;
+ end
+ else
+ begin
+ NodeLeft := 0;
+ NodeRight := ClientWidth;
+ end;
+ if CurrentBidiMode = bdLeftToRight then
+ Result := CollectSelectedNodesLTR(MainColumn, NodeLeft, NodeRight, CurrentAlignment, OldRect, NewRect)
+ else
+ Result := CollectSelectedNodesRTL(MainColumn, NodeLeft, NodeRight, CurrentAlignment, OldRect, NewRect);
+ end;
+
+ if Result then
+ begin
+ // Do some housekeeping if there was a change.
+ MaxValue := PackArray(FSelection, FSelectionCount);
+ if MaxValue > -1 then
+ begin
+ FSelectionCount := MaxValue;
+ SetLength(FSelection, FSelectionCount);
+ end;
+ if FTempNodeCount > 0 then
+ begin
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+ end;
+
+ Change(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.HasVisibleNextSibling(Node: PVirtualNode): Boolean;
+
+// Helper method to determine if the given node has a visible sibling. This is needed to
+// draw correct tree lines.
+
+begin
+ // Check if there is a sibling at all.
+ Result := Assigned(Node.NextSibling);
+
+ if Result then
+ begin
+ repeat
+ Node := Node.NextSibling;
+ Result := vsVisible in Node.States;
+ until Result or (Node.NextSibling = nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ImageListChange(Sender: TObject);
+
+begin
+ if not (csDestroying in ComponentState) then
+ Invalidate;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InitializeFirstColumnValues(var PaintInfo: TVTPaintInfo);
+
+// Determines initial index, position and cell size of the first visible column.
+
+begin
+ PaintInfo.Column := FHeader.FColumns.GetFirstVisibleColumn;
+ with FHeader.FColumns, PaintInfo do
+ begin
+ if Column > NoColumn then
+ begin
+ CellRect.Right := CellRect.Left + Items[Column].Width;
+ Position := Items[Column].Position;
+ end
+ else
+ Position := 0;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InitializeLineImageAndSelectLevel(Node: PVirtualNode; var LineImage: TLineImage): Integer;
+
+// This method is used during paint cycles and initializes an array of line type IDs. These IDs are used to paint
+// the tree lines in front of the given node.
+// Additionally an initial count of selected parents is determined and returned which is used for specific painting.
+
+var
+ X: Integer;
+ Run: PVirtualNode;
+
+begin
+ Result := 0;
+ if toShowRoot in FOptions.FPaintOptions then
+ X := 1
+ else
+ X := 0;
+ Run := Node;
+ // Determine indentation level of top node.
+ while Run.Parent <> FRoot do
+ begin
+ Inc(X);
+ Run := Run.Parent;
+ // Count selected nodes (FRoot is never selected).
+ if vsSelected in Run.States then
+ Inc(Result);
+ end;
+
+ // Set initial size of line index array, this will automatically initialized all entries to ltNone.
+ SetLength(LineImage, X);
+
+ // Only use lines if requested.
+ if toShowTreeLines in FOptions.FPaintOptions then
+ begin
+ // Start over parent traversal if necessary.
+ Run := Node;
+ if Run.Parent <> FRoot then
+ begin
+ // The very last image (the one immediately before the item label) is different.
+ if HasVisibleNextSibling(Run) then
+ LineImage[X - 1] := ltTopDownRight
+ else
+ LineImage[X - 1] := ltTopRight;
+ Run := Run.Parent;
+
+ // Now go up all parents.
+ repeat
+ if Run.Parent = FRoot then
+ Break;
+ Dec(X);
+ if HasVisibleNextSibling(Run) then
+ LineImage[X - 1] := ltTopDown
+ else
+ LineImage[X - 1] := ltNone;
+ Run := Run.Parent;
+ until False;
+ end;
+
+ // Prepare root level. Run points at this stage to a top level node.
+ if (toShowRoot in FOptions.FPaintOptions) and (toShowTreeLines in FOptions.FPaintOptions) then
+ begin
+ // Is the top node a root node?
+ if Run = Node then
+ begin
+ // First child gets the bottom-right bitmap if it isn't also the only child.
+ if IsFirstVisibleChild(FRoot, Run) then
+ // Is it the only child?
+ if IsLastVisibleChild(FRoot, Run) then
+ LineImage[0] := ltRight
+ else
+ LineImage[0] := ltBottomRight
+ else
+ // real last child
+ if IsLastVisibleChild(FRoot, Run) then
+ LineImage[0] := ltTopRight
+ else
+ LineImage[0] := ltTopDownRight;
+ end
+ else
+ begin
+ // No, top node is not a top level node. So we need different painting.
+ if HasVisibleNextSibling(Run) then
+ LineImage[0] := ltTopDown
+ else
+ LineImage[0] := ltNone;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InitRootNode(OldSize: Cardinal = 0);
+
+// Reinitializes the root node.
+
+var
+ NewSize: Cardinal;
+
+begin
+ NewSize := TreeNodeSize + FTotalInternalDataSize;
+ if FRoot = nil then
+ FRoot := AllocMem(NewSize)
+ else
+ begin
+ ReallocMem(FRoot, NewSize);
+ ZeroMemory(PChar(FRoot) + OldSize, NewSize - OldSize);
+ end;
+
+ with FRoot^ do
+ begin
+ // Indication that this node is the root node.
+ PrevSibling := FRoot;
+ NextSibling := FRoot;
+ Parent := Pointer(Self);
+ States := [vsInitialized, vsExpanded, vsHasChildren, vsVisible];
+ TotalHeight := FDefaultNodeHeight;
+ TotalCount := 1;
+ TotalHeight := FDefaultNodeHeight;
+ NodeHeight := FDefaultNodeHeight;
+ Align := 50;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InterruptValidation;
+
+// Waits until the worker thread has stopped validating the caches of this tree.
+
+begin
+ if tsValidating in FStates then
+ begin
+ DoStateChange([tsStopValidation], [tsUseCache]);
+ // Make a hard break until the worker thread has stopped validation.
+ while (tsValidating in FStates) and (WorkerThread.FCurrentTree = Self) and not Application.Terminated do
+ Sleep(100);
+ DoStateChange([tsValidationNeeded]);
+ end
+ else // Remove any pending validation.
+ WorkerThread.RemoveTree(Self);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IsFirstVisibleChild(Parent, Node: PVirtualNode): Boolean;
+
+// Helper method to check if Node is the same as the first visible child of Parent.
+
+var
+ Run: PVirtualNode;
+
+begin
+ // Find first visible child.
+ Run := Parent.FirstChild;
+ while Assigned(Run) and not (vsVisible in Run.States) do
+ Run := Run.NextSibling;
+
+ Result := Assigned(Run) and (Run = Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IsLastVisibleChild(Parent, Node: PVirtualNode): Boolean;
+
+// Helper method to check if Node is the same as the last visible child of Parent.
+
+var
+ Run: PVirtualNode;
+
+begin
+ // Find last visible child.
+ Run := Parent.LastChild;
+ while Assigned(Run) and not (vsVisible in Run.States) do
+ Run := Run.PrevSibling;
+
+ Result := Assigned(Run) and (Run = Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.LimitPaintingToArea(Canvas: TCanvas; ClipRect: TRect; VisibleRegion: HRGN = 0);
+
+// Limits further painting onto the given canvas to the given rectangle.
+// VisibleRegion is an optional region which can be used to limit drawing further.
+
+var
+ ClipRegion: HRGN;
+
+begin
+ // Regions expect their coordinates in device coordinates, hence we have to transform the region rectangle.
+ LPtoDP(Canvas.Handle, ClipRect, 2);
+ ClipRegion := CreateRectRgnIndirect(ClipRect);
+ if VisibleRegion <> 0 then
+ CombineRgn(ClipRegion, ClipRegion, VisibleRegion, RGN_AND);
+ SelectClipRgn(Canvas.Handle, ClipRegion);
+ DeleteObject(ClipRegion);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.MakeNewNode: PVirtualNode;
+
+var
+ Size: Cardinal;
+
+begin
+ Size := TreeNodeSize;
+ if not (csDesigning in ComponentState) then
+ begin
+ // Make sure FNodeDataSize is valid.
+ if FNodeDataSize = -1 then
+ ValidateNodeDataSize(FNodeDataSize);
+
+ // Take record alignment into account.
+ Inc(Size, FNodeDataSize);
+ end;
+
+ {$ifdef UseLocalMemoryManager}
+ Result := FNodeMemoryManager.AllocNode(Size + FTotalInternalDataSize);
+ {$else}
+ Result := AllocMem(Size + FTotalInternalDataSize);
+ {$endif UseLocalMemoryManager}
+
+ // Fill in some default values.
+ with Result^ do
+ begin
+ TotalCount := 1;
+ TotalHeight := FDefaultNodeHeight;
+ NodeHeight := FDefaultNodeHeight;
+ States := [vsVisible];
+ Align := 50;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.OriginalWMNCPaint(DC: HDC);
+
+// Unfortunately, the painting for the non-client area in TControl is not always correct and does also not consider
+// existing clipping regions, so it has been modified here to take this into account.
+
+const
+ InnerStyles: array[TBevelCut] of Integer = (0, BDR_SUNKENINNER, BDR_RAISEDINNER, 0);
+ OuterStyles: array[TBevelCut] of Integer = (0, BDR_SUNKENOUTER, BDR_RAISEDOUTER, 0);
+ EdgeStyles: array[TBevelKind] of Integer = (0, 0, BF_SOFT, BF_FLAT);
+ Ctl3DStyles: array[Boolean] of Integer = (BF_MONO, 0);
+
+var
+ RC, RW: TRect;
+ EdgeSize: Integer;
+ Styles: Integer;
+
+begin
+ if (BevelKind <> bkNone) or (BorderWidth > 0) then
+ begin
+ RC := Rect(0, 0, Width, Height);
+ Styles := GetWindowLong(Handle, GWL_STYLE);
+ if (Styles and WS_BORDER) <> 0 then
+ InflateRect(RC, -1, -1);
+ if (Styles and WS_THICKFRAME) <> 0 then
+ InflateRect(RC, -3, -3);
+ Styles := GetWindowLong(Handle, GWL_EXSTYLE);
+ if (Styles and WS_EX_CLIENTEDGE) <> 0 then
+ InflateRect(RC, -2, -2);
+
+ RW := RC;
+
+ if BevelKind <> bkNone then
+ begin
+ DrawEdge(DC, RC, InnerStyles[BevelInner] or OuterStyles[BevelOuter], Byte(BevelEdges) or EdgeStyles[BevelKind] or
+ Ctl3DStyles[Ctl3D]);
+
+ EdgeSize := 0;
+ if BevelInner <> bvNone then
+ Inc(EdgeSize, BevelWidth);
+ if BevelOuter <> bvNone then
+ Inc(EdgeSize, BevelWidth);
+ with RC do
+ begin
+ if beLeft in BevelEdges then
+ Inc(Left, EdgeSize);
+ if beTop in BevelEdges then
+ Inc(Top, EdgeSize);
+ if beRight in BevelEdges then
+ Dec(Right, EdgeSize);
+ if beBottom in BevelEdges then
+ Dec(Bottom, EdgeSize);
+ end;
+ end;
+
+ // Repaint only the part in the original clipping region and not yet drawn parts.
+ IntersectClipRect(DC, RC.Left, RC.Top, RC.Right, RC.Bottom);
+
+ // Determine inner rectangle to exclude (RC corresponds then to the client area).
+ InflateRect(RC, -BorderWidth, -BorderWidth);
+
+ // Remove the inner rectangle.
+ ExcludeClipRect(DC, RC.Left, RC.Top, RC.Right, RC.Bottom);
+
+ // Erase parts not drawn.
+ Brush.Color := FColors.BorderColor;
+ Windows.FillRect(DC, RW, Brush.Handle);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.PackArray(TheArray: TNodeArray; Count: Integer): Integer; assembler;
+
+// Removes all entries from the selection array which are no longer in use. The selection array must be sorted for this
+// algo to work. Values which must be removed are marked with bit 0 (LSB) set. This little trick works because memory
+// is always allocated DWORD aligned. Since the selection array must be sorted while determining the entries to be
+// removed it is much more efficient to increment the entry in question instead of setting it to nil (which would break
+// the ordered appearance of the list).
+//
+// On enter EAX contains self reference, EDX the address to TheArray and ECX Count
+// The returned value is the number of remaining entries in the array, so the caller can reallocate (shorten)
+// the selection array if needed or -1 if nothing needs to be changed.
+
+asm
+ PUSH EBX
+ PUSH EDI
+ PUSH ESI
+ MOV ESI, EDX
+ MOV EDX, -1
+ JCXZ @@Finish // Empty list?
+ INC EDX // init remaining entries counter
+ MOV EDI, ESI // source and destination point to the list memory
+ MOV EBX, 1 // use a register instead of immediate operant to check against
+@@PreScan:
+ TEST [ESI], EBX // do the fastest scan possible to find the first entry
+ // which must be removed
+ JNZ @@DoMainLoop
+ INC EDX
+ ADD ESI, 4
+ DEC ECX
+ JNZ @@PreScan
+ JMP @@Finish
+
+@@DoMainLoop:
+ MOV EDI, ESI
+@@MainLoop:
+ TEST [ESI], EBX // odd entry?
+ JNE @@Skip // yes, so skip this one
+ MOVSD // else move the entry to new location
+ INC EDX // count the moved entries
+ DEC ECX
+ JNZ @@MainLoop // do it until all entries are processed
+ JMP @@Finish
+
+@@Skip:
+ ADD ESI, 4 // point to the next entry
+ DEC ECX
+ JNZ @@MainLoop // do it until all entries are processed
+@@Finish:
+ MOV EAX, EDX // prepare return value
+ POP ESI
+ POP EDI
+ POP EBX
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PrepareBitmaps(NeedButtons, NeedLines: Boolean);
+
+// initializes the contents of the internal bitmaps
+
+const
+ LineBitsDotted: array [0..8] of Word = ($55, $AA, $55, $AA, $55, $AA, $55, $AA, $55);
+ LineBitsSolid: array [0..7] of Word = (0, 0, 0, 0, 0, 0, 0, 0);
+
+var
+ PatternBitmap: HBITMAP;
+ Bits: Pointer;
+ {$ifdef ThemeSupport}
+ Details: TThemedElementDetails;
+ {$endif ThemeSupport}
+
+begin
+ if NeedButtons then
+ begin
+ with FMinusBM, Canvas do
+ begin
+ // box is always of odd size
+ Width := 9;
+ Height := Width;
+ Transparent := True;
+ TransparentColor := clFuchsia;
+ Brush.Color := clFuchsia;
+ FillRect(Rect(0, 0, Width, Height));
+ if FButtonStyle = bsTriangle then
+ begin
+ Brush.Color := clBlack;
+ Pen.Color := clBlack;
+ Polygon([Point(0, 2), Point(8, 2), Point(4, 6)]);
+ end
+ else
+ begin
+ // Button style is rectangular. Now ButtonFillMode determines how to fill the interior.
+ if FButtonFillMode in [fmTreeColor, fmWindowColor, fmTransparent] then
+ begin
+ case FButtonFillMode of
+ fmTreeColor:
+ Brush.Color := Self.Color;
+ fmWindowColor:
+ Brush.Color := clWindow;
+ end;
+ Pen.Color := FColors.TreeLineColor;
+ Rectangle(0, 0, Width, Height);
+ Pen.Color := Self.Font.Color;
+ MoveTo(2, Width div 2);
+ LineTo(Width - 2 , Width div 2);
+ end
+ else
+ FMinusBM.Handle := LoadBitmap(HInstance, 'VT_XPBUTTONMINUS');
+ end;
+ end;
+
+ with FPlusBM, Canvas do
+ begin
+ Width := 9;
+ Height := Width;
+ Transparent := True;
+ TransparentColor := clFuchsia;
+ Brush.Color := clFuchsia;
+ FillRect(Rect(0, 0, Width, Height));
+ if FButtonStyle = bsTriangle then
+ begin
+ Brush.Color := clBlack;
+ Pen.Color := clBlack;
+ Polygon([Point(2, 0), Point(6, 4), Point(2, 8)]);
+ end
+ else
+ begin
+ // Button style is rectangular. Now ButtonFillMode determines how to fill the interior.
+ if FButtonFillMode in [fmTreeColor, fmWindowColor, fmTransparent] then
+ begin
+ case FButtonFillMode of
+ fmTreeColor:
+ Brush.Color := Self.Color;
+ fmWindowColor:
+ Brush.Color := clWindow;
+ end;
+
+ Pen.Color := FColors.TreeLineColor;
+ Rectangle(0, 0, Width, Height);
+ Pen.Color := Self.Font.Color;
+ MoveTo(2, Width div 2);
+ LineTo(Width - 2 , Width div 2);
+ MoveTo(Width div 2, 2);
+ LineTo(Width div 2, Width - 2);
+ end
+ else
+ FPlusBM.Handle := LoadBitmap(HInstance, 'VT_XPBUTTONPLUS');
+ end;
+ end;
+
+ {$ifdef ThemeSupport}
+ // Overwrite glyph images if theme is active.
+ if tsUseThemes in FStates then
+ begin
+ Details := ThemeServices.GetElementDetails(ttGlyphClosed);
+ ThemeServices.DrawElement(FPlusBM.Canvas.Handle, Details, Rect(0, 0, 9, 9));
+ Details := ThemeServices.GetElementDetails(ttGlyphOpened);
+ ThemeServices.DrawElement(FMinusBM.Canvas.Handle, Details, Rect(0, 0, 9, 9));
+ end;
+ {$endif ThemeSupport}
+ end;
+
+ if NeedLines then
+ begin
+ if FDottedBrush <> 0 then
+ DeleteObject(FDottedBrush);
+
+ case FLineStyle of
+ lsDotted:
+ Bits := @LineBitsDotted;
+ lsSolid:
+ Bits := @LineBitsSolid;
+ else // lsCustomStyle
+ Bits := @LineBitsDotted;
+ DoGetLineStyle(Bits);
+ end;
+ PatternBitmap := CreateBitmap(8, 8, 1, 1, Bits);
+ FDottedBrush := CreatePatternBrush(PatternBitmap);
+ DeleteObject(PatternBitmap);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PrepareCell(var PaintInfo: TVTPaintInfo);
+
+// This method is called immediately before a cell's content is drawn und is responsible to paint selection colors etc.
+
+var
+ TextColorBackup,
+ BackColorBackup: COLORREF;
+ InnerRect: TRect;
+
+begin
+ with PaintInfo, Canvas do
+ begin
+ InnerRect := ContentRect;
+
+ // Fill cell background if its color differs from tree background.
+ with FHeader.FColumns do
+ if poColumnColor in PaintOptions then
+ begin
+ Brush.Color := Items[Column].Color;
+ FillRect(CellRect);
+ end;
+
+ // Let the application customize the cell background.
+ DoBeforeCellPaint(Canvas, Node, Column, CellRect);
+
+ if (Column = FFocusedColumn) or (toFullRowSelect in FOptions.FSelectionOptions) then
+ begin
+ // The selection rectangle depends on alignment.
+ if not (toGridExtensions in FOptions.FMiscOptions) then
+ begin
+ case Alignment of
+ taLeftJustify:
+ with InnerRect do
+ if Left + NodeWidth < Right then
+ Right := Left + NodeWidth;
+ taCenter:
+ with InnerRect do
+ if (Right - Left) > NodeWidth then
+ begin
+ Left := (Left + Right - NodeWidth) div 2;
+ Right := Left + NodeWidth;
+ end;
+ taRightJustify:
+ with InnerRect do
+ if (Right - Left) > NodeWidth then
+ Left := Right - NodeWidth;
+ end;
+ end;
+
+ // Fill the selection rectangle.
+ if poDrawSelection in PaintOptions then
+ begin
+ if Node = FDropTargetNode then
+ begin
+ if (FLastDropMode = dmOnNode) or (vsSelected in Node.States) then
+ begin
+ Brush.Color := FColors.DropTargetColor;
+ Pen.Color := FColors.DropTargetBorderColor;
+
+ if (toGridExtensions in FOptions.FMiscOptions) or
+ (toFullRowSelect in FOptions.FSelectionOptions) then
+ InnerRect := CellRect;
+ if not IsRectEmpty(InnerRect) then
+ with InnerRect do
+ RoundRect(Left, Top, Right, Bottom, FSelectionCurveRadius, FSelectionCurveRadius);
+ end
+ else
+ begin
+ Brush.Style := bsClear;
+ end;
+ end
+ else
+ if vsSelected in Node.States then
+ begin
+ if Focused or (toPopupMode in FOptions.FPaintOptions) then
+ begin
+ Brush.Color := FColors.FocusedSelectionColor;
+ Pen.Color := FColors.FocusedSelectionBorderColor;
+ end
+ else
+ begin
+ Brush.Color := FColors.UnfocusedSelectionColor;
+ Pen.Color := FColors.UnfocusedSelectionBorderColor;
+ end;
+
+ if (toGridExtensions in FOptions.FMiscOptions) or (toFullRowSelect in FOptions.FSelectionOptions) then
+ InnerRect := CellRect;
+ if not IsRectEmpty(InnerRect) then
+ with InnerRect do
+ RoundRect(Left, Top, Right, Bottom, FSelectionCurveRadius, FSelectionCurveRadius);
+ end;
+ end;
+
+ // draw focus rect
+ if (poDrawFocusRect in PaintOptions) and (Column = FFocusedColumn) and
+ (Focused or (toPopupMode in FOptions.FPaintOptions)) and (FFocusedNode = Node) then
+ begin
+ TextColorBackup := GetTextColor(Handle);
+ SetTextColor(Handle, $FFFFFF);
+ BackColorBackup := GetBkColor(Handle);
+ SetBkColor(Handle, 0);
+
+ if toGridExtensions in FOptions.FMiscOptions then
+ Windows.DrawFocusRect(Handle, CellRect)
+ else
+ Windows.DrawFocusRect(Handle, InnerRect);
+
+ SetTextColor(Handle, TextColorBackup);
+ SetBkColor(Handle, BackColorBackup);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ TOldVTOption = (voAcceptOLEDrop, voAnimatedToggle, voAutoDropExpand, voAutoExpand, voAutoScroll,
+ voAutoSort, voAutoSpanColumns, voAutoTristateTracking, voCheckSupport, voDisableDrawSelection, voEditable,
+ voExtendedFocus, voFullRowSelect, voGridExtensions, voHideFocusRect, voHideSelection, voHotTrack, voInitOnSave,
+ voLevelSelectConstraint, voMiddleClickSelect, voMultiSelect, voRightClickSelect, voPopupMode, voShowBackground,
+ voShowButtons, voShowDropmark, voShowHorzGridLines, voShowRoot, voShowTreeLines, voShowVertGridLines,
+ voSiblingSelectConstraint, voToggleOnDblClick);
+
+const
+ OptionMap: array[TOldVTOption] of Integer = (
+ Ord(toAcceptOLEDrop), Ord(toAnimatedToggle), Ord(toAutoDropExpand), Ord(toAutoExpand), Ord(toAutoScroll),
+ Ord(toAutoSort), Ord(toAutoSpanColumns), Ord(toAutoTristateTracking), Ord(toCheckSupport), Ord(toDisableDrawSelection),
+ Ord(toEditable), Ord(toExtendedFocus), Ord(toFullRowSelect), Ord(toGridExtensions), Ord(toHideFocusRect),
+ Ord(toHideSelection), Ord(toHotTrack), Ord(toInitOnSave), Ord(toLevelSelectConstraint), Ord(toMiddleClickSelect),
+ Ord(toMultiSelect), Ord(toRightClickSelect), Ord(toPopupMode), Ord(toShowBackground),
+ Ord(toShowButtons), Ord(toShowDropmark), Ord(toShowHorzGridLines), Ord(toShowRoot), Ord(toShowTreeLines),
+ Ord(toShowVertGridLines), Ord(toSiblingSelectConstraint), Ord(toToggleOnDblClick)
+ );
+
+procedure TBaseVirtualTree.ReadOldOptions(Reader: TReader);
+
+// Migration helper routine to silently convert forms containing the old tree options member into the new
+// sub-options structure.
+
+var
+ OldOption: TOldVTOption;
+ EnumName: string;
+
+begin
+ // If we are at design time currently then let the designer know we changed something.
+ UpdateDesigner;
+
+ // It should never happen at this place that there is something different than the old set.
+ if Reader.ReadValue = vaSet then
+ begin
+ // Remove all default values set by the constructor.
+ FOptions.AnimationOptions := [];
+ FOptions.AutoOptions := [];
+ FOptions.MiscOptions := [];
+ FOptions.PaintOptions := [];
+ FOptions.SelectionOptions := [];
+
+ while True do
+ begin
+ // Sets are stored with their members as simple strings. Read them one by one and map them to the new option
+ // in the correct sub-option set.
+ EnumName := Reader.ReadStr;
+ if EnumName = '' then
+ Break;
+ OldOption := TOldVTOption(GetEnumValue(TypeInfo(TOldVTOption), EnumName));
+ case OldOption of
+ voAcceptOLEDrop, voCheckSupport, voEditable, voGridExtensions, voInitOnSave, voToggleOnDblClick:
+ FOptions.MiscOptions := FOptions.FMiscOptions + [TVTMiscOption(OptionMap[OldOption])];
+ voAnimatedToggle:
+ FOptions.AnimationOptions := FOptions.FAnimationOptions + [TVTAnimationOption(OptionMap[OldOption])];
+ voAutoDropExpand, voAutoExpand, voAutoScroll, voAutoSort, voAutoSpanColumns, voAutoTristateTracking:
+ FOptions.AutoOptions := FOptions.FAutoOptions + [TVTAutoOption(OptionMap[OldOption])];
+ voDisableDrawSelection, voExtendedFocus, voFullRowSelect, voLevelSelectConstraint,
+ voMiddleClickSelect, voMultiSelect, voRightClickSelect, voSiblingSelectConstraint:
+ FOptions.SelectionOptions := FOptions.FSelectionOptions + [TVTSelectionOption(OptionMap[OldOption])];
+ voHideFocusRect, voHideSelection, voHotTrack, voPopupMode, voShowBackground, voShowButtons,
+ voShowDropmark, voShowHorzGridLines, voShowRoot, voShowTreeLines, voShowVertGridLines:
+ FOptions.PaintOptions := FOptions.FPaintOptions + [TVTPaintOption(OptionMap[OldOption])];
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetAlignment(const Value: TAlignment);
+
+begin
+ if FAlignment <> Value then
+ begin
+ FAlignment := Value;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetAnimationDuration(const Value: Cardinal);
+
+begin
+ FAnimationDuration := Value;
+ if FAnimationDuration = 0 then
+ Exclude(FOptions.FAnimationOptions, toAnimatedToggle)
+ else
+ Include(FOptions.FAnimationOptions, toAnimatedToggle);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetBackground(const Value: TPicture);
+
+begin
+ FBackground.Assign(Value);
+ Invalidate;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetBackgroundOffset(const Index, Value: Integer);
+
+begin
+ case Index of
+ 0:
+ if FBackgroundOffsetX <> Value then
+ begin
+ FBackgroundOffsetX := Value;
+ Invalidate;
+ end;
+ 1:
+ if FBackgroundOffsetY <> Value then
+ begin
+ FBackgroundOffsetY := Value;
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetBorderStyle(Value: TBorderStyle);
+
+begin
+ if FBorderStyle <> Value then
+ begin
+ FBorderStyle := Value;
+ RecreateWnd;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetButtonFillMode(const Value: TVTButtonFillMode);
+
+begin
+ if FButtonFillMode <> Value then
+ begin
+ FButtonFillMode := Value;
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(True, False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetButtonStyle(const Value: TVTButtonStyle);
+
+begin
+ if FButtonStyle <> Value then
+ begin
+ FButtonStyle := Value;
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(True, False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetCheckImageKind(Value: TCheckImageKind);
+
+begin
+ if FCheckImageKind <> Value then
+ begin
+ FCheckImageKind := Value;
+ case Value of
+ ckDarkCheck:
+ FCheckImages := DarkCheckImages;
+ ckLightTick:
+ FCheckImages := LightTickImages;
+ ckDarkTick:
+ FCheckImages := DarkTickImages;
+ ckLightCheck:
+ FCheckImages := LightCheckImages;
+ ckFlat:
+ FCheckImages := FlatImages;
+ ckXP:
+ FCheckImages := XPImages;
+ ckSystem:
+ FCheckImages := SystemCheckImages;
+ ckSystemFlat:
+ FCheckImages := SystemFlatCheckImages;
+ else
+ FCheckImages := FCustomCheckImages;
+ end;
+ if HandleAllocated and (FUpdateCount = 0) and not (csLoading in ComponentState) then
+ InvalidateRect(Handle, nil, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetCheckState(Node: PVirtualNode; Value: TCheckState);
+
+begin
+ if (Node.CheckState <> Value) and not (vsDisabled in Node.States) and DoChecking(Node, Value) then
+ DoCheckClick(Node, Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetCheckType(Node: PVirtualNode; Value: TCheckType);
+
+begin
+ if (Node.CheckType <> Value) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Node.CheckType := Value;
+ Node.CheckState := csUncheckedNormal;
+ // For check boxes with tri-state check box parents we have to initialize differently.
+ if (toAutoTriStateTracking in FOptions.FAutoOptions) and (Value in [ctCheckBox, ctTriStateCheckBox]) and
+ (Node.Parent <> FRoot) then
+ begin
+ if not (vsInitialized in Node.Parent.States) then
+ InitNode(Node.Parent);
+ if (Node.Parent.CheckType = ctTriStateCheckBox) and
+ (Node.Parent.CheckState in [csUncheckedNormal, csCheckedNormal]) then
+ CheckState[Node] := Node.Parent.CheckState;
+ end;
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetChildCount(Node: PVirtualNode; NewChildCount: Cardinal);
+
+// Changes a node's child structure to accomodate the new child count. This is used to add or delete
+// child nodes to/from the end of the node's child list. To insert or delete a specific node a separate
+// routine is used.
+
+var
+ Count: Integer;
+ Index: Cardinal;
+ Child: PVirtualNode;
+ C: Integer;
+ NewHeight: Integer;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ if Node = nil then
+ Node := FRoot;
+
+ if NewChildCount = 0 then
+ DeleteChildren(Node)
+ else
+ begin
+ Count := Integer(NewChildCount) - Integer(Node.ChildCount);
+
+ // If nothing changed then do nothing.
+ if Count <> 0 then
+ begin
+ InterruptValidation;
+
+ C := Count;
+ NewHeight := 0;
+
+ if Count > 0 then
+ begin
+ // New nodes to add.
+ if Assigned(Node.LastChild) then
+ Index := Node.LastChild.Index + 1
+ else
+ begin
+ Index := 0;
+ Include(Node.States, vsHasChildren);
+ end;
+
+ // New nodes are by default always visible, so we don't need to check the visibility.
+ while Count > 0 do
+ begin
+ Child := MakeNewNode;
+ Child.Index := Index;
+ Child.PrevSibling := Node.LastChild;
+ if Assigned(Node.LastChild) then
+ Node.LastChild.NextSibling := Child;
+ Child.Parent := Node;
+ Node.LastChild := Child;
+ if Node.FirstChild = nil then
+ Node.FirstChild := Child;
+ Dec(Count);
+ Inc(Index);
+ Inc(NewHeight, Child.NodeHeight);
+ end;
+
+ if vsExpanded in Node.States then
+ begin
+ AdjustTotalHeight(Node, NewHeight, True);
+ if FullyVisible[Node] then
+ Inc(Integer(FVisibleCount), C);
+ end;
+
+ AdjustTotalCount(Node, C, True);
+ Node.ChildCount := NewChildCount;
+ if (FUpdateCount = 0) and (toAutoSort in FOptions.FAutoOptions) and (FHeader.FSortColumn > InvalidColumn) then
+ Sort(Node, FHeader.FSortColumn, FHeader.FSortDirection, True);
+
+ InvalidateCache;
+ end
+ else
+ begin
+ // Nodes have to be deleted.
+ while Count < 0 do
+ begin
+ DeleteNode(Node.LastChild);
+ Inc(Count);
+ end;
+ end;
+
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ Invalidate;
+ end;
+
+ if Node = FRoot then
+ StructureChange(nil, crChildAdded)
+ else
+ StructureChange(Node, crChildAdded);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetClipboardFormats(const Value: TClipboardFormats);
+
+var
+ I: Integer;
+
+begin
+ // Add string by string instead doing an Assign or AddStrings because the list may return -1 for
+ // invalid entries which cause trouble for the standard implementation.
+ FClipboardFormats.Clear;
+ for I := 0 to Value.Count - 1 do
+ FClipboardFormats.Add(Value[I]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetColors(const Value: TVTColors);
+
+begin
+ FColors.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetCustomCheckImages(const Value: TCustomImageList);
+
+begin
+ if FCustomCheckImages <> Value then
+ begin
+ if Assigned(FCustomCheckImages) then
+ begin
+ FCustomCheckImages.UnRegisterChanges(FCustomCheckChangeLink);
+ {$ifdef COMPILER_5_UP}
+ FCustomCheckImages.RemoveFreeNotification(Self);
+ {$endif COMPILER_5_UP}
+ // Reset the internal check image list reference too, if necessary.
+ if FCheckImages = FCustomCheckImages then
+ FCheckImages := nil;
+ end;
+ FCustomCheckImages := Value;
+ if Assigned(FCustomCheckImages) then
+ begin
+ FCustomCheckImages.RegisterChanges(FCustomCheckChangeLink);
+ FCustomCheckImages.FreeNotification(Self);
+ end;
+ // Check if currently custom check images are active.
+ if FCheckImageKind = ckCustom then
+ FCheckImages := Value;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetDefaultNodeHeight(Value: Cardinal);
+
+begin
+ if Value = 0 then
+ Value := 18;
+ if FDefaultNodeHeight <> Value then
+ begin
+ DoStateChange([tsNeedScale]);
+ Inc(Integer(FRoot.TotalHeight), Integer(Value) - Integer(FDefaultNodeHeight));
+ Inc(SmallInt(FRoot.NodeHeight), Integer(Value) - Integer(FDefaultNodeHeight));
+ FDefaultNodeHeight := Value;
+ InvalidateCache;
+ if (FUpdateCount = 0) and HandleAllocated and not (csLoading in ComponentState) then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions, True);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetDisabled(Node: PVirtualNode; Value: Boolean);
+
+begin
+ if Assigned(Node) and (Value xor (vsDisabled in Node.States)) then
+ begin
+ if Value then
+ Include(Node.States, vsDisabled)
+ else
+ Exclude(Node.States, vsDisabled);
+
+ if FUpdateCount = 0 then
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetExpanded(Node: PVirtualNode; Value: Boolean);
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and (Value xor (vsExpanded in Node.States)) then
+ ToggleNode(Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetFocusedColumn(Value: TColumnIndex);
+
+begin
+ if (FFocusedColumn <> Value) and
+ DoFocusChanging(FFocusedNode, FFocusedNode, FFocusedColumn, Value) then
+ begin
+ CancelEditNode;
+ FFocusedColumn := Value;
+ if Assigned(FFocusedNode) then
+ begin
+ ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions,
+ not (toDisableAutoscrollOnFocus in FOptions.FAutoOptions));
+ InvalidateNode(FFocusedNode);
+ end;
+
+ DoFocusChange(FFocusedNode, FFocusedColumn);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetFocusedNode(Value: PVirtualNode);
+
+var
+ WasDifferent: Boolean;
+
+begin
+ WasDifferent := Value <> FFocusedNode;
+ DoFocusNode(Value, True);
+ // Do change event only if there was actually a change.
+ if WasDifferent and (FFocusedNode = Value) then
+ DoFocusChange(FFocusedNode, FFocusedColumn);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetFullyVisible(Node: PVirtualNode; Value: Boolean);
+
+// This method ensures that a node is visible and all its parent nodes are expanded and also visible
+// if Value is True. Otherwise the visibility flag of the node is reset but the expand state
+// of the parent nodes stays untouched.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter');
+
+ IsVisible[Node] := Value;
+ if Value then
+ begin
+ repeat
+ Node := Node.Parent;
+ if Node = FRoot then
+ Break;
+ if not (vsExpanded in Node.States) then
+ ToggleNode(Node);
+ if not (vsVisible in Node.States) then
+ IsVisible[Node] := True;
+ until False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetHasChildren(Node: PVirtualNode; Value: Boolean);
+
+begin
+ if Assigned(Node) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ if Value then
+ Include(Node.States, vsHasChildren)
+ else
+ begin
+ Exclude(Node.States, vsHasChildren);
+ DeleteChildren(Node);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetHeader(const Value: TVTHeader);
+
+begin
+ FHeader.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetImages(const Value: TCustomImageList);
+
+begin
+ if FImages <> Value then
+ begin
+ if Assigned(FImages) then
+ begin
+ FImages.UnRegisterChanges(FImageChangeLink);
+ {$ifdef COMPILER_5_UP}
+ FImages.RemoveFreeNotification(Self);
+ {$endif COMPILER_5_UP}
+ end;
+ FImages := Value;
+ if Assigned(FImages) then
+ begin
+ FImages.RegisterChanges(FImageChangeLink);
+ FImages.FreeNotification(Self);
+ end;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetIndent(Value: Cardinal);
+
+begin
+ if FIndent <> Value then
+ begin
+ FIndent := Value;
+ if not (csLoading in ComponentState) and (FUpdateCount = 0) and HandleAllocated then
+ begin
+ UpdateScrollBars(True);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetLineMode(const Value: TVTLineMode);
+
+begin
+ if FLineMode <> Value then
+ begin
+ FLineMode := Value;
+ if HandleAllocated and not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetLineStyle(const Value: TVTLineStyle);
+
+begin
+ if FLineStyle <> Value then
+ begin
+ FLineStyle := Value;
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(False, True);
+ if HandleAllocated then
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetMargin(Value: Integer);
+
+begin
+ if FMargin <> Value then
+ begin
+ FMargin := Value;
+ if HandleAllocated and not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetMultiline(Node: PVirtualNode; const Value: Boolean);
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ if Value <> (vsMultiline in Node.States) then
+ begin
+ if Value then
+ Include(Node.States, vsMultiline)
+ else
+ Exclude(Node.States, vsMultiline);
+
+ if FUpdateCount = 0 then
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetNodeAlignment(const Value: TVTNodeAlignment);
+
+begin
+ if FNodeAlignment <> Value then
+ begin
+ FNodeAlignment := Value;
+ if HandleAllocated and not (csReading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetNodeDataSize(Value: Integer);
+
+var
+ LastRootCount: Cardinal;
+
+begin
+ if Value < -1 then
+ Value := -1;
+ if FNodeDataSize <> Value then
+ begin
+ FNodeDataSize := Value;
+ if not (csLoading in ComponentState) and not (csDesigning in ComponentState) then
+ begin
+ LastRootCount := FRoot.ChildCount;
+ Clear;
+ SetRootNodeCount(LastRootCount);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetNodeHeight(Node: PVirtualNode; Value: Cardinal);
+
+var
+ Difference: Integer;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and (Node.NodeHeight <> Value) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Difference := Integer(Value) - Integer(Node.NodeHeight);
+ Node.NodeHeight := Value;
+ AdjustTotalHeight(Node, Difference, True);
+ if FullyVisible[Node] then
+ begin
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ InvalidateToBottom(Node);
+ UpdateScrollBars(True);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetNodeParent(Node: PVirtualNode; const Value: PVirtualNode);
+
+begin
+ if Assigned(Node) and Assigned(Value) and (Node.Parent <> Value) then
+ MoveTo(Node, Value, amAddChildLast, False);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetOffsetX(const Value: Integer);
+
+begin
+ DoSetOffsetXY(Point(Value, FOffsetY), DefaultScrollUpdateFlags);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetOffsetXY(const Value: TPoint);
+
+begin
+ DoSetOffsetXY(Value, DefaultScrollUpdateFlags);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetOffsetY(const Value: Integer);
+
+begin
+ DoSetOffsetXY(Point(FOffsetX, Value), DefaultScrollUpdateFlags);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetOptions(const Value: TCustomVirtualTreeOptions);
+
+begin
+ FOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetRootNodeCount(Value: Cardinal);
+
+begin
+ // Don't set the root node count until all other properties (in particular the OnInitNode event) have been set.
+ if csLoading in ComponentState then
+ begin
+ FRoot.ChildCount := Value;
+ DoStateChange([tsNeedRootCountUpdate]);
+ end
+ else
+ if FRoot.ChildCount <> Value then
+ begin
+ BeginUpdate;
+ InterruptValidation;
+ SetChildCount(FRoot, Value);
+ EndUpdate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetScrollBarOptions(Value: TScrollBarOptions);
+
+begin
+ FScrollBarOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetSearchOption(const Value: TVTIncrementalSearch);
+
+begin
+ if FIncrementalSearch <> Value then
+ begin
+ FIncrementalSearch := Value;
+ if FIncrementalSearch = isNone then
+ begin
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetSelected(Node: PVirtualNode; Value: Boolean);
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and (Value xor (vsSelected in Node.States)) then
+ begin
+ if Value then
+ begin
+ if FSelectionCount = 0 then
+ FRangeAnchor := Node
+ else
+ if not (toMultiSelect in FOptions.FSelectionOptions) then
+ ClearSelection;
+
+ AddToSelection(Node);
+
+ // Make sure there is a valid column selected (if there are columns at all).
+ if ((FFocusedColumn < 0) or not (coVisible in FHeader.Columns[FFocusedColumn].Options)) and
+ (FHeader.MainColumn > NoColumn) then
+ if coVisible in FHeader.Columns[FHeader.MainColumn].Options then
+ FFocusedColumn := FHeader.MainColumn
+ else
+ FFocusedColumn := FHeader.Columns.GetFirstVisibleColumn;
+ if FRangeAnchor = nil then
+ FRangeAnchor := Node;
+ end
+ else
+ begin
+ RemoveFromSelection(Node);
+ if FSelectionCount = 0 then
+ ResetRangeAnchor;
+ end;
+ if FullyVisible[Node] then
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetSelectionCurveRadius(const Value: Cardinal);
+
+begin
+ if FSelectionCurveRadius <> Value then
+ begin
+ FSelectionCurveRadius := Value;
+ if HandleAllocated and not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetStateImages(const Value: TCustomImageList);
+
+begin
+ if FStateImages <> Value then
+ begin
+ if Assigned(FStateImages) then
+ begin
+ FStateImages.UnRegisterChanges(FStateChangeLink);
+ {$ifdef COMPILER_5_UP}
+ FStateImages.RemoveFreeNotification(Self);
+ {$endif COMPILER_5_UP}
+ end;
+ FStateImages := Value;
+ if Assigned(FStateImages) then
+ begin
+ FStateImages.RegisterChanges(FStateChangeLink);
+ FStateImages.FreeNotification(Self);
+ end;
+ if HandleAllocated and not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetTextMargin(Value: Integer);
+
+begin
+ if FTextMargin <> Value then
+ begin
+ FTextMargin := Value;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetTopNode(Node: PVirtualNode);
+
+var
+ R: TRect;
+ Run: PVirtualNode;
+
+begin
+ if Assigned(Node) then
+ begin
+ // make sure all parents of the node are expanded
+ Run := Node.Parent;
+ while Run <> FRoot do
+ begin
+ if not (vsExpanded in Run.States) then
+ ToggleNode(Run);
+ Run := Run.Parent;
+ end;
+ R := GetDisplayRect(Node, FHeader.MainColumn, True);
+ SetOffsetY(FOffsetY - R.Top);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetUpdateState(Updating: Boolean);
+
+begin
+ // The check for visibility is necessary otherwise the tree is automatically shown when
+ // updating is allowed. As this happens internally the VCL does not get notified and
+ // still assumes the control is hidden. This results in weird "cannot focus invisble control" errors.
+ if Visible and HandleAllocated then
+ SendMessage(Handle, WM_SETREDRAW, Ord(not Updating), 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetVerticalAlignment(Node: PVirtualNode; Value: Byte);
+
+begin
+ if Value > 100 then
+ Value := 100;
+ if Node.Align <> Value then
+ begin
+ Node.Align := Value;
+ if FullyVisible[Node] and (FUpdateCount = 0) then
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetVisible(Node: PVirtualNode; Value: Boolean);
+
+// Sets the visibility style of the given node according to Value.
+
+var
+ NeedUpdate: Boolean;
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ if Value <> (vsVisible in Node.States) then
+ begin
+ InterruptValidation;
+ NeedUpdate := False;
+ if Value then
+ begin
+ Include(Node.States, vsVisible);
+ if vsExpanded in Node.Parent.States then
+ AdjustTotalHeight(Node.Parent, Node.TotalHeight, True);
+ if VisiblePath[Node] then
+ begin
+ Inc(FVisibleCount, 1 + CountVisibleChildren(Node));
+ NeedUpdate := True;
+ end;
+
+ // Update the hidden children flag of the parent.
+ // Since this node is now visible we simply have to remove the flag.
+ Exclude(Node.Parent.States, vsAllChildrenHidden);
+ end
+ else
+ begin
+ Exclude(Node.States, vsVisible);
+ if vsExpanded in Node.Parent.States then
+ AdjustTotalHeight(Node.Parent, -Integer(Node.TotalHeight), True);
+ if VisiblePath[Node] then
+ begin
+ Dec(FVisibleCount, 1 + CountVisibleChildren(Node));
+ NeedUpdate := True;
+ end;
+
+ if FUpdateCount = 0 then
+ DetermineHiddenChildrenFlag(Node.Parent)
+ else
+ Include(FStates, tsUpdateHiddenChildrenNeeded)
+ end;
+
+ InvalidateCache;
+ if NeedUpdate and (FUpdateCount = 0) then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetVisiblePath(Node: PVirtualNode; Value: Boolean);
+
+// If Value is True then all parent nodes of Node are expanded.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ if Value then
+ begin
+ repeat
+ Node := Node.Parent;
+ if Node = FRoot then
+ Break;
+ if not (vsExpanded in Node.States) then
+ ToggleNode(Node);
+ until False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.StopTimer(ID: Integer);
+
+begin
+ if HandleAllocated then
+ KillTimer(Handle, ID);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.TileBackground(Source: TBitmap; Target: TCanvas; Offset: TPoint; R: TRect);
+
+// Draws the given source graphic so that it tiles into the given rectangle which is relative to the target bitmap.
+// The graphic is aligned so that it always starts at the upper left corner of the target canvas.
+// Offset gives the position of the target window in an possible superordinated surface.
+
+var
+ SourceX,
+ SourceY,
+ TargetX,
+
+ DeltaY: Integer;
+
+begin
+ with Target do
+ begin
+ SourceY := (R.Top + Offset.Y + FBackgroundOffsetY) mod Source.Height;
+ // Always wrap the source coordinates into positive range.
+ if SourceY < 0 then
+ SourceY := Source.Height + SourceY;
+
+ // Tile image vertically until target rect is filled.
+ while R.Top < R.Bottom do
+ begin
+ SourceX := (R.Left + Offset.X + FBackgroundOffsetX) mod Source.Width;
+ // always wrap the source coordinates into positive range
+ if SourceX < 0 then
+ SourceX := Source.Width + SourceX;
+
+ TargetX := R.Left;
+ // height of strip to draw
+ DeltaY := Min(R.Bottom - R.Top, Source.Height - SourceY);
+
+ // tile the image horizontally
+ while TargetX < R.Right do
+ begin
+ BitBlt(Handle, TargetX, R.Top, Min(R.Right - TargetX, Source.Width - SourceX), DeltaY,
+ Source.Canvas.Handle, SourceX, SourceY, SRCCOPY);
+ Inc(TargetX, Source.Width - SourceX);
+ SourceX := 0;
+ end;
+ Inc(R.Top, Source.Height - SourceY);
+ SourceY := 0;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ToggleCallback(Step, StepSize: Integer; Data: Pointer): Boolean;
+
+var
+ ScrollRect: TRect;
+ Column: TColumnIndex;
+ Run: TRect;
+
+ //--------------- local function --------------------------------------------
+
+ procedure EraseLine;
+
+ var
+ LocalBrush: HBRUSH;
+
+ begin
+ with TToggleAnimationData(Data^), FHeader.FColumns do
+ begin
+ // Iterate through all columns and erase background in their local color.
+ // LocalBrush is a brush in the color of the particular column.
+ Column := ColumnFromPosition(Run.TopLeft);
+ while (Column > InvalidColumn) and (Run.Left < ClientWidth) do
+ begin
+ GetColumnBounds(Column, Run.Left, Run.Right);
+ if coParentColor in Items[Column].FOptions then
+ FillRect(DC, Run, Brush)
+ else
+ begin
+ LocalBrush := CreateSolidBrush(ColorToRGB(Items[Column].Color));
+ FillRect(DC, Run, LocalBrush);
+ DeleteObject(LocalBrush);
+ end;
+ Column := GetNextVisibleColumn(Column);
+ end;
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+begin
+ Result := True;
+ if StepSize > 0 then
+ begin
+ with TToggleAnimationData(Data^) do
+ begin
+ ScrollRect := R;
+ if Expand then
+ begin
+ ScrollDC(DC, 0, StepSize, ScrollRect, ScrollRect, 0, nil);
+
+ // In the first step the background must be cleared (only a small stripe) to avoid artefacts.
+ if Step = 0 then
+ if not FHeader.UseColumns then
+ FillRect(DC, Rect(R.Left, R.Top, R.Right, R.Top + StepSize + 1), Brush)
+ else
+ begin
+ Run := Rect(R.Left, R.Top, R.Right, R.Top + StepSize + 1);
+ EraseLine;
+ end;
+ end
+ else
+ begin
+ // Collapse branch.
+ ScrollDC(DC, 0, -StepSize, ScrollRect, ScrollRect, 0, nil);
+
+ if Step = 0 then
+ if not FHeader.UseColumns then
+ FillRect(DC, Rect(R.Left, R.Bottom - StepSize - 1, R.Right, R.Bottom), Brush)
+ else
+ begin
+ Run := Rect(R.Left, R.Bottom - StepSize - 1, R.Right, R.Bottom);
+ EraseLine;
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMColorChange(var Message: TMessage);
+
+begin
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(True, False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMCtl3DChanged(var Message: TMessage);
+
+begin
+ inherited;
+ if FBorderStyle = bsSingle then
+ RecreateWnd;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMDenySubclassing(var Message: TMessage);
+
+// If a Windows XP Theme Manager component is used in the application it will try to subclass all controls which do not
+// explicitly deny this. Virtual Treeview knows how to handle XP themes so it does not need subclassing.
+
+begin
+ Message.Result := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMDrag(var Message: TCMDrag);
+
+var
+ S: TObject;
+ ShiftState: Integer;
+ P: TPoint;
+ Formats: TFormatArray;
+
+begin
+ with Message, DragRec^ do
+ begin
+ S := Source;
+ Formats := nil;
+
+ // Let the ancestor handle dock operations.
+ if S is TDragDockObject then
+ inherited
+ else
+ begin
+ // We need an extra check for the control drag object as there might be other objects not derived from
+ // this class (e.g. TActionDragObject).
+ if not (tsUserDragObject in FStates) and (S is TBaseDragControlObject) then
+ S := (S as TBaseDragControlObject).Control;
+ case DragMessage of
+ dmDragEnter, dmDragLeave, dmDragMove:
+ begin
+ if DragMessage = dmDragEnter then
+ DoStateChange([tsVCLDragging]);
+ if DragMessage = dmDragLeave then
+ DoStateChange([], [tsVCLDragging]);
+
+ if DragMessage = dmDragMove then
+ with ScreenToClient(Pos) do
+ DoAutoScroll(X, Y);
+
+ ShiftState := 0;
+ // Alt key will be queried by the KeysToShiftState function in DragOver.
+ if GetKeyState(VK_SHIFT) < 0 then
+ ShiftState := ShiftState or MK_SHIFT;
+ if GetKeyState(VK_CONTROL) < 0 then
+ ShiftState := ShiftState or MK_CONTROL;
+
+ // Allowed drop effects are simulated for VCL dd.
+ Result := DROPEFFECT_MOVE or DROPEFFECT_COPY;
+ DragOver(S, ShiftState, TDragState(DragMessage), Pos, Result);
+ FLastVCLDragTarget := FDropTargetNode;
+ FVCLDragEffect := Result;
+ if (DragMessage = dmDragLeave) and Assigned(FDropTargetNode) then
+ begin
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := nil;
+ end;
+ end;
+ dmDragDrop:
+ begin
+ ShiftState := 0;
+ // Alt key will be queried by the KeysToShiftState function in DragOver
+ if GetKeyState(VK_SHIFT) < 0 then
+ ShiftState := ShiftState or MK_SHIFT;
+ if GetKeyState(VK_CONTROL) < 0 then
+ ShiftState := ShiftState or MK_CONTROL;
+
+ // allowed drop effects are simulated for VCL dd,
+ // replace target node with cached node from other VCL dd messages
+ if Assigned(FDropTargetNode) then
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := FLastVCLDragTarget;
+ P := Point(Pos.X, Pos.Y);
+ P := ScreenToClient(P);
+ DoDragDrop(S, nil, Formats, KeysToShiftState(ShiftState), P, FVCLDragEffect, FLastDropMode);
+ if Assigned(FDropTargetNode) then
+ begin
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := nil;
+ end;
+ end;
+ dmFindTarget:
+ begin
+ Result := Integer(ControlAtPos(ScreenToClient(Pos), False));
+ if Result = 0 then
+ Result := Integer(Self);
+
+ // This is a reliable place to check whether VCL drag has
+ // really begun.
+ if tsVCLDragPending in FStates then
+ DoStateChange([tsVCLDragging], [tsVCLDragPending, tsEditPending, tsClearPending]);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMEnabledChanged(var Message: TMessage);
+
+begin
+ inherited;
+
+ // Need to invalidate the non-client area as well, since the header must be redrawn too.
+ if csDesigning in ComponentState then
+ RedrawWindow(Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMFontChanged(var Message: TMessage);
+
+begin
+ inherited;
+
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(True, False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMHintShow(var Message: TCMHintShow);
+
+// Determines hint message (tooltip) and out-of-hint rect.
+// Note: A special handling is needed here because we cannot pass wide strings back to the caller.
+// I had to introduce the hint data record anyway so we can use this to pass the hint string.
+// We still need to set a dummy hint string in the message to make the VCL showing the hint window.
+
+var
+ NodeRect: TRect;
+ SpanColumn,
+ Dummy,
+ ColLeft,
+ ColRight: Integer;
+ HitInfo: THitInfo;
+ ShowOwnHint: Boolean;
+ IsFocusedOrEditing: Boolean;
+ ParentForm: TCustomForm;
+
+begin
+ with Message do
+ begin
+ Result := 1;
+
+ if PtInRect(FLastHintRect, HintInfo.CursorPos) then
+ Exit;
+ // Determine node for which to show hint/tooltip.
+ with HintInfo^ do
+ GetHitTestInfoAt(CursorPos.X, CursorPos.Y, True, HitInfo);
+
+ // Make sure a hint is only shown if the tree or at least its parent form is active.
+ // Active editing is ok too as long as we don't want the hint for the current edit node.
+ if IsEditing then
+ IsFocusedOrEditing := HitInfo.HitNode <> FFocusedNode
+ else
+ begin
+ IsFocusedOrEditing := Focused;
+ ParentForm := GetParentForm(Self);
+ if Assigned(ParentForm) then
+ IsFocusedOrEditing := ParentForm.Focused or Application.Active;
+ end;
+
+ if (GetCapture = 0) and ShowHint and not (Dragging or IsMouseSelecting) and ([tsScrolling] * FStates = []) and
+ (FHeader.States = []) and IsFocusedOrEditing then
+ begin
+ with HintInfo^ do
+ begin
+ Result := 0;
+ ShowOwnHint := False;
+ // Assign a dummy string otherwise the VCL will not show the hint window.
+ HintStr := ' ';
+
+ // First check whether there is a header hint to show.
+ if FHeader.UseColumns and (hoShowHint in FHeader.FOptions) and FHeader.InHeader(CursorPos) then
+ begin
+ CursorRect := FHeaderRect;
+ // Convert the cursor rectangle into real client coordinates.
+ OffsetRect(CursorRect, 0, -Integer(FHeader.FHeight));
+ HitInfo.HitColumn := FHeader.FColumns.GetColumnAndBounds(CursorPos, CursorRect.Left, CursorRect.Right);
+ // align the vertical hint position on the bottom bound of the header, but
+ // avoid overlapping of mouse cursor and hint
+ HintPos.Y := Max(HintPos.Y, ClientToScreen(Point(0, CursorRect.Bottom)).Y);
+ // Note: the test for the left mouse button in ControlState might cause problems whenever the VCL does not
+ // realize when the button is released. This, for instance, happens when doing OLE drag'n drop and
+ // cancel this with ESC.
+ if (HitInfo.HitColumn > -1) and not (csLButtonDown in ControlState) then
+ begin
+ FHintData.DefaultHint := FHeader.FColumns[HitInfo.HitColumn].FHint;
+ if FHintData.DefaultHint <> '' then
+ ShowOwnHint := True
+ else
+ Result := 1;
+ end
+ else
+ Result := 1;
+ end
+ else
+ begin
+ // Default mode is handled as would the tree be a usual VCL control (no own hint window necessary).
+ if FHintMode = hmDefault then
+ HintStr := GetShortHint(Hint)
+ else
+ begin
+ if Assigned(HitInfo.HitNode) and (HitInfo.HitColumn > InvalidColumn) then
+ begin
+ // A draw tree should only display a hint when at least its OnGetHintSize
+ // event handler is assigned.
+ if Self is TCustomVirtualDrawTree then
+ begin
+ FHintData.HintRect := Rect(0, 0, 0, 0);
+ with Self as TCustomVirtualDrawTree do
+ DoGetHintSize(HitInfo.HitNode, HitInfo.HitColumn, FHintData.HintRect);
+ ShowOwnHint := not IsRectEmpty(FHintData.HintRect);
+ end
+ else
+ // For string trees a decision about showing the hint or not is based
+ // on the hint string (if it is empty then no hint is shown).
+ ShowOwnHint := True;
+
+ if ShowOwnHint then
+ begin
+ if HitInfo.HitColumn > NoColumn then
+ begin
+ FHeader.FColumns.GetColumnBounds(HitInfo.HitColumn, ColLeft, ColRight);
+ // The right column border might be extended if column spanning is enabled.
+ if toAutoSpanColumns in FOptions.FAutoOptions then
+ begin
+ SpanColumn := HitInfo.HitColumn;
+ repeat
+ Dummy := FHeader.FColumns.GetNextVisibleColumn(SpanColumn);
+ if (Dummy = InvalidColumn) or not ColumnIsEmpty(HitInfo.HitNode, Dummy) then
+ Break;
+ SpanColumn := Dummy;
+ until False;
+ if SpanColumn <> HitInfo.HitColumn then
+ FHeader.FColumns.GetColumnBounds(SpanColumn, Dummy, ColRight);
+ end;
+ end
+ else
+ begin
+ ColLeft := 0;
+ ColRight := ClientWidth;
+ end;
+
+ FHintData.DefaultHint := '';
+ if FHintMode <> hmTooltip then
+ begin
+ // Node specific hint text.
+ CursorRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, False);
+ // Align the vertical hint position on the bottom bound of the node, but
+ // avoid overlapping of mouse cursor and hint.
+ HintPos.Y := Max(HintPos.Y, ClientToScreen(CursorRect.BottomRight).Y) + 2;
+ end
+ else
+ begin
+ // Tool tip to show. This means the full caption of the node must be displayed.
+ if vsMultiline in HitInfo.HitNode.States then
+ begin
+ ShowOwnHint := True;
+ NodeRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, True, False);
+ end
+ else
+ begin
+ NodeRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, True, True);
+ ShowOwnHint := (HitInfo.HitColumn > InvalidColumn) and PtInRect(NodeRect, CursorPos) and
+ (CursorPos.X <= ColRight) and (CursorPos.X >= ColLeft) and
+ ((NodeRect.Right > Min(ColRight, ClientWidth)) or (NodeRect.Left < Max(ColLeft, 0)));
+ end;
+
+ if ShowOwnHint then
+ begin
+ // Node specific hint text given will be retrieved when needed.
+ FHintData.DefaultHint := '';
+ HintPos := ClientToScreen(Point(NodeRect.Left, NodeRect.Top));
+ CursorRect := NodeRect;
+ end
+ else
+ // nothing to show
+ Result := 1;
+ end;
+ end
+ else
+ Result := 1; // Avoid hint if this is a draw tree returning an empty hint rectangle.
+ end
+ else
+ begin
+ // No node so fall back to control's hint (if indicated) or show nothing.
+ if FHintMode = hmHintAndDefault then
+ begin
+ FHintData.DefaultHint := GetShortHint(Hint);
+ if Length(FHintData.DefaultHint) = 0 then
+ Result := 1
+ else
+ ShowOwnHint := True;
+ end
+ else
+ Result := 1;
+ end;
+ end;
+ end;
+
+ // Set our own hint window class and prepare structure to be passed to the hint window.
+ if ShowOwnHint and (Result = 0) then
+ begin
+ HintWindowClass := TVirtualTreeHintWindow;
+
+ FHintData.Tree := Self;
+ FHintData.Column := HitInfo.HitColumn;
+ FHintData.Node := HitInfo.HitNode;
+ FLastHintRect := CursorRect;
+ HintData := @FHintData;
+ end
+ else
+ FLastHintRect := Rect(0, 0, 0, 0);
+ end;
+
+ // Remind that a hint is about to show.
+ if Result = 0 then
+ DoStateChange([tsHint])
+ else
+ DoStateChange([], [tsHint]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMHintShowPause(var Message: TCMHintShowPause);
+
+// Tells the application that the tree (and only the tree) does not want a delayed tool tip.
+// Normal hints / header hints use the default delay (except the first time).
+
+var
+ P: TPoint;
+
+begin
+ // A little workaround is needed here to make the application class using the correct hint window class.
+ // Once the application gets ShowHint set to true (which is the case when we want to show hints in the tree) then
+ // an internal hint window will be created which is not our own class (because we don't set an application wide
+ // hint window class but only one for the tree). Unfortunately, this default hint window class will prevent
+ // hints for the non-client area to show up (e.g. for the header) by calling CancelHint whenever certain messages
+ // arrive. By setting the hint show pause to 0 if our hint class was not used recently we make sure
+ // that the hint timer (in Forms.pas) is not used and our class is created immediately.
+ if HintWindowDestroyed then
+ begin
+ GetCursorPos(P);
+ // Check if the mouse is in the header or tool tips are enabled, which must be shown without delay anyway.
+ if FHeader.UseColumns and (hoShowHint in FHeader.FOptions) and FHeader.InHeader(ScreenToClient(P)) or
+ (FHintMode = hmToolTip) then
+ Message.Pause^ := 0
+ end
+ else
+ if (FHintMode = hmToolTip) then
+ Message.Pause^ := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMMouseLeave(var Message: TMessage);
+
+var
+ LeaveStates: TVirtualTreeStates;
+
+begin
+ LeaveStates := [tsHint];
+ if [tsWheelPanning, tsWheelScrolling] * FStates = [] then
+ begin
+ StopTimer(ScrollTimer);
+ LeaveStates := LeaveStates + [tsScrollPending, tsScrolling];
+ end;
+ DoStateChange([], LeaveStates);
+ if Assigned(FCurrentHotNode) then
+ begin
+ DoHotChange(FCurrentHotNode, nil);
+ InvalidateNode(FCurrentHotNode);
+ FCurrentHotNode := nil;
+ end;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMMouseWheel(var Message: TCMMouseWheel);
+
+var
+ ScrollCount: Integer;
+ ScrollLines: Integer;
+
+begin
+ StopWheelPanning;
+
+ inherited;
+
+ if Message.Result = 0 then
+ begin
+ with Message do
+ begin
+ Result := 1;
+ if FRangeY > Cardinal(ClientHeight) then
+ begin
+ // Scroll vertically if there's something to scroll...
+ if ssCtrl in ShiftState then
+ ScrollCount := WheelDelta div WHEEL_DELTA * (ClientHeight div Integer(FDefaultNodeHeight))
+ else
+ begin
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, @ScrollLines, 0);
+ ScrollCount := ScrollLines * WheelDelta div WHEEL_DELTA;
+ end;
+ SetOffsetY(FOffsetY + ScrollCount * Integer(FDefaultNodeHeight));
+ end
+ else
+ begin
+ // ...else scroll horizontally.
+ if ssCtrl in ShiftState then
+ ScrollCount := WheelDelta div WHEEL_DELTA * ClientWidth
+ else
+ ScrollCount := WheelDelta div WHEEL_DELTA;
+ SetOffsetX(FOffsetX + ScrollCount * Integer(FIndent));
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMSysColorChange(var Message: TMessage);
+
+begin
+ inherited;
+
+ ConvertImageList(LightCheckImages, 'VT_CHECK_LIGHT');
+ ConvertImageList(DarkCheckImages, 'VT_CHECK_DARK');
+ ConvertImageList(LightTickImages, 'VT_TICK_LIGHT');
+ ConvertImageList(DarkTickImages, 'VT_TICK_DARK');
+ ConvertImageList(FlatImages, 'VT_FLAT');
+ ConvertImageList(UtilityImages, 'VT_UTILITIES');
+ // XP images do not need to be converted.
+ // System check images do not need to be converted.
+ Message.Msg := WM_SYSCOLORCHANGE;
+ DefaultHandler(Message);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMCancelMode(var Message: TWMCancelMode);
+
+begin
+ // Clear any transient state.
+ StopTimer(ExpandTimer);
+ StopTimer(EditTimer);
+ StopTimer(HeaderTimer);
+ StopTimer(ScrollTimer);
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+
+ DoStateChange([], [tsClearPending, tsEditPending, tsOLEDragPending, tsVCLDragPending, tsDrawSelecting,
+ tsDrawSelPending, tsIncrementalSearching]);
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMChangeState(var Message: TMessage);
+
+var
+ EnterStates,
+ LeaveStates: TVirtualTreeStates;
+
+begin
+ EnterStates := [];
+ if csStopValidation in TChangeStates(Byte(Message.WParam)) then
+ Include(EnterStates, tsStopValidation);
+ if csUseCache in TChangeStates(Byte(Message.WParam)) then
+ Include(EnterStates, tsUseCache);
+ if csValidating in TChangeStates(Byte(Message.WParam)) then
+ Include(EnterStates, tsValidating);
+ if csValidationNeeded in TChangeStates(Byte(Message.WParam)) then
+ Include(EnterStates, tsValidationNeeded);
+
+ LeaveStates := [];
+ if csStopValidation in TChangeStates(Byte(Message.LParam)) then
+ Include(LeaveStates, tsStopValidation);
+ if csUseCache in TChangeStates(Byte(Message.LParam)) then
+ Include(LeaveStates, tsUseCache);
+ if csValidating in TChangeStates(Byte(Message.LParam)) then
+ Include(LeaveStates, tsValidating);
+ if csValidationNeeded in TChangeStates(Byte(Message.LParam)) then
+ Include(LeaveStates, tsValidationNeeded);
+
+ DoStateChange(EnterStates, LeaveStates);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMChar(var Message: TWMChar);
+
+begin
+ if tsIncrementalSearchPending in FStates then
+ begin
+ HandleIncrementalSearch(Message.CharCode);
+ DoStateChange([], [tsIncrementalSearchPending]);
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMContextMenu(var Message: TWMContextMenu);
+
+// This method is called when a popup menu is about to be displayed.
+// We have to cancel some pending states here to avoid interferences.
+
+begin
+ DoStateChange([], [tsClearPending, tsEditPending, tsOLEDragPending, tsVCLDragPending]);
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMCopy(var Message: TWMCopy);
+
+begin
+ CopyToClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMCut(var Message: TWMCut);
+
+begin
+ CutToClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMEnable(var Message: TWMEnable);
+
+begin
+ inherited;
+ RedrawWindow(Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMEraseBkgnd(var Message: TWMEraseBkgnd);
+
+begin
+ Message.Result := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMGetDlgCode(var Message: TWMGetDlgCode);
+
+begin
+ Message.Result := DLGC_WANTCHARS or DLGC_WANTARROWS;
+ if FWantTabs then
+ Message.Result := Message.Result or DLGC_WANTTAB;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMHScroll(var Message: TWMHScroll);
+
+ //--------------- local functions -------------------------------------------
+
+ function GetRealScrollPosition: Integer;
+
+ var
+ SI: TScrollInfo;
+ Code: Integer;
+
+ begin
+ SI.cbSize := SizeOf(TScrollInfo);
+ SI.fMask := SIF_TRACKPOS;
+ Code := SB_HORZ;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_GetScrollInfo(Handle, Code, SI);
+ {$else}
+ GetScrollInfo(Handle, Code, SI);
+ {$endif UseFlatScrollbars}
+ Result := SI.nTrackPos;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+begin
+ case Message.ScrollCode of
+ SB_BOTTOM:
+ SetOffsetX(-Integer(FRangeX));
+ SB_ENDSCROLL:
+ begin
+ DoStateChange([], [tsThumbTracking]);
+ // avoiding to adjust the vertical scroll position while tracking makes it much smoother
+ // but we need to adjust the final position here then
+ UpdateHorizontalScrollBar(False);
+ end;
+ SB_LINELEFT:
+ SetOffsetX(FOffsetX + FScrollBarOptions.FIncrementX);
+ SB_LINERIGHT:
+ SetOffsetX(FOffsetX - FScrollBarOptions.FIncrementX);
+ SB_PAGELEFT:
+ SetOffsetX(FOffsetX + ClientWidth);
+ SB_PAGERIGHT:
+ SetOffsetX(FOffsetX - ClientWidth);
+ SB_THUMBPOSITION,
+ SB_THUMBTRACK:
+ begin
+ DoStateChange([tsThumbTracking]);
+ SetOffsetX(-GetRealScrollPosition);
+ end;
+ SB_TOP:
+ SetOffsetX(0);
+ end;
+
+ Message.Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMKeyDown(var Message: TWMKeyDown);
+
+// Keyboard event handling for node focus, selection, node specific popup menus and help invokation.
+// For a detailed description of every action done here read the help.
+
+var
+ Shift: TShiftState;
+ Node, Temp,
+ LastFocused: PVirtualNode;
+ Offset: Integer;
+ ClearPending,
+ NeedInvalidate,
+ DoRangeSelect,
+ HandleMultiSelect: Boolean;
+ Context: Integer;
+ ParentControl: TWinControl;
+ R: TRect;
+ NewCheckState: TCheckState;
+ NewColumn: TColumnIndex;
+ ActAsGrid: Boolean;
+
+ // for tabulator handling
+ GetStartColumn: function: TColumnIndex of object;
+ GetNextColumn: function(Column: TColumnIndex): TColumnIndex of object;
+ GetNextNode: TGetNextNodeProc;
+
+ KeyState: TKeyboardState;
+ Buffer: array[0..1] of Char;
+
+begin
+ // Make form key preview work and let application modify the key if it wants this.
+ inherited;
+
+ with Message do
+ begin
+ Shift := KeyDataToShiftState(KeyData);
+ // Ask the application if the default key handling is desired.
+ if DoKeyAction(CharCode, Shift) then
+ begin
+ if (tsKeyCheckPending in FStates) and (CharCode <> VK_SPACE) then
+ begin
+ DoStateChange([], [tskeyCheckPending]);
+ FCheckNode.CheckState := UnpressedState[FCheckNode.CheckState];
+ RepaintNode(FCheckNode);
+ FCheckNode := nil;
+ end;
+
+ if CharCode in [VK_HOME, VK_END, VK_PRIOR, VK_NEXT, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_BACK, VK_TAB] then
+ begin
+ HandleMultiSelect := (ssShift in Shift) and (toMultiSelect in FOptions.FSelectionOptions) and not IsEditing;
+
+ // Flag to avoid range selection in case of single node advance.
+ DoRangeSelect := (CharCode in [VK_HOME, VK_END, VK_PRIOR, VK_NEXT]) and HandleMultiSelect and not IsEditing;
+
+ NeedInvalidate := DoRangeSelect or (FSelectionCount > 1);
+ ActAsGrid := toGridExtensions in FOptions.FMiscOptions;
+ ClearPending := (Shift = []) or (ActAsGrid and not (ssShift in Shift)) or
+ not (toMultiSelect in FOptions.FSelectionOptions) or (CharCode in [VK_TAB, VK_BACK]);
+
+ // Keep old focused node for range selection. Use a default node if none was focused until now.
+ LastFocused := FFocusedNode;
+ if (LastFocused = nil) and (Shift <> []) then
+ LastFocused := GetFirstVisible;
+
+ // Set an initial range anchor if there is not yet one.
+ if FRangeAnchor = nil then
+ FRangeAnchor := GetFirstSelected;
+ if FRangeAnchor = nil then
+ FRangeAnchor := GetFirst;
+
+ // Determine new focused node.
+ case CharCode of
+ VK_HOME, VK_END:
+ begin
+ if CharCode = VK_END then
+ begin
+ GetStartColumn := FHeader.FColumns.GetLastVisibleColumn;
+ GetNextColumn := FHeader.FColumns.GetPreviousVisibleColumn;
+ GetNextNode := GetPreviousVisible;
+ Node := GetLastVisible;
+ end
+ else
+ begin
+ GetStartColumn := FHeader.FColumns.GetFirstVisibleColumn;
+ GetNextColumn := FHeader.FColumns.GetNextVisibleColumn;
+ GetNextNode := GetNextVisible;
+ Node := GetFirstVisible;
+ end;
+
+ // Advance to next/previous visible column.
+ if FHeader.UseColumns then
+ NewColumn := GetStartColumn
+ else
+ NewColumn := NoColumn;
+ // Find a column for the new/current node which can be focused.
+ while (NewColumn > NoColumn) and not DoFocusChanging(FFocusedNode, Node, FFocusedColumn, NewColumn) do
+ NewColumn := GetNextColumn(NewColumn);
+ if NewColumn > InvalidColumn then
+ begin
+ if (Shift = [ssCtrl]) and not ActAsGrid then
+ begin
+ ScrollIntoView(Node, toCenterScrollIntoView in FOptions.SelectionOptions,
+ not (toDisableAutoscrollOnFocus in FOptions.FAutoOptions));
+ if CharCode = VK_HOME then
+ SetOffsetX(0)
+ else
+ SetOffsetX(-MaxInt);
+ end
+ else
+ begin
+ if not ActAsGrid or (ssCtrl in Shift) then
+ FocusedNode := Node;
+ if ActAsGrid and not (toFullRowSelect in FOptions.FSelectionOptions) then
+ FocusedColumn := NewColumn;
+ end;
+ end;
+ end;
+ VK_PRIOR:
+ if ssCtrl in Shift then
+ SetOffsetY(FOffsetY + ClientHeight)
+ else
+ begin
+ Offset := 0;
+ // If there's no focused node then just take the very first visible one.
+ if FFocusedNode = nil then
+ Node := GetFirstVisible
+ else
+ begin
+ // Go up as many nodes as comprise together a size of ClientHeight.
+ Node := FFocusedNode;
+ while Offset < ClientHeight do
+ begin
+ Temp := GetPreviousVisible(Node);
+ if Temp = nil then
+ Break;
+ Node := Temp;
+ Inc(Offset, Node.NodeHeight);
+ end;
+ end;
+ FocusedNode := Node;
+ end;
+ VK_NEXT:
+ if ssCtrl in Shift then
+ SetOffsetY(FOffsetY - ClientHeight)
+ else
+ begin
+ Offset := 0;
+ // If there's no focused node then just take the very last one.
+ if FFocusedNode = nil then
+ Node := GetLastVisible
+ else
+ begin
+ // Go up as many nodes as comprise together a size of ClientHeight.
+ Node := FFocusedNode;
+ while Offset < ClientHeight do
+ begin
+ Temp := GetNextVisible(Node);
+ if Temp = nil then
+ Break;
+ Node := Temp;
+ Inc(Offset, Node.NodeHeight);
+ end;
+ end;
+ FocusedNode := Node;
+ end;
+ VK_UP:
+ begin
+ // scrolling without selection change
+ if ssCtrl in Shift then
+ SetOffsetY(FOffsetY + Integer(FDefaultNodeHeight))
+ else
+ begin
+ if FFocusedNode = nil then
+ Node := GetLastVisible
+ else
+ Node := GetPreviousVisible(FFocusedNode);
+
+ if Assigned(Node) then
+ begin
+ EndEditNode;
+ if HandleMultiSelect and (CompareNodePositions(LastFocused, FRangeAnchor) > 0) and
+ Assigned(FFocusedNode) then
+ RemoveFromSelection(FFocusedNode);
+ if FFocusedColumn = NoColumn then
+ FFocusedColumn := FHeader.MainColumn;
+ FocusedNode := Node;
+ end
+ else
+ if Assigned(FFocusedNode) then
+ InvalidateNode(FFocusedNode);
+ end;
+ end;
+ VK_DOWN:
+ begin
+ // scrolling without selection change
+ if ssCtrl in Shift then
+ SetOffsetY(FOffsetY - Integer(FDefaultNodeHeight))
+ else
+ begin
+ if FFocusedNode = nil then
+ Node := GetFirstVisible
+ else
+ Node := GetNextVisible(FFocusedNode);
+
+ if Assigned(Node) then
+ begin
+ EndEditNode;
+ if HandleMultiSelect and (CompareNodePositions(LastFocused, FRangeAnchor) < 0) and
+ Assigned(FFocusedNode) then
+ RemoveFromSelection(FFocusedNode);
+ if FFocusedColumn = NoColumn then
+ FFocusedColumn := FHeader.MainColumn;
+ FocusedNode := Node;
+ end
+ else
+ if Assigned(FFocusedNode) then
+ InvalidateNode(FFocusedNode);
+ end;
+ end;
+ VK_LEFT:
+ begin
+ // special handling
+ if ssCtrl in Shift then
+ SetOffsetX(FOffsetX + Integer(FIndent))
+ else
+ begin
+ // other special cases
+ Context := NoColumn;
+ if (toExtendedFocus in FOptions.FSelectionOptions) and (toGridExtensions in FOptions.FMiscOptions) then
+ begin
+ Context := FHeader.Columns.GetPreviousVisibleColumn(FFocusedColumn);
+ if Context > -1 then
+ FocusedColumn := Context
+ end
+ else
+ if Assigned(FFocusedNode) and (vsExpanded in FFocusedNode.States) and
+ (Shift = []) and (vsHasChildren in FFocusedNode.States) then
+ ToggleNode(FFocusedNode)
+ else
+ begin
+ if FFocusedNode = nil then
+ FocusedNode := GetFirstVisible
+ else
+ begin
+ if FFocusedNode.Parent <> FRoot then
+ Node := FFocusedNode.Parent
+ else
+ Node := nil;
+ if Assigned(Node) then
+ begin
+ if HandleMultiSelect then
+ begin
+ // and a third special case
+ if FFocusedNode.Index > 0 then
+ DoRangeSelect := True
+ else
+ if CompareNodePositions(Node, FRangeAnchor) > 0 then
+ RemoveFromSelection(FFocusedNode);
+ end;
+ FocusedNode := Node;
+ end;
+ end;
+ end;
+ end;
+ end;
+ VK_RIGHT:
+ begin
+ // special handling
+ if ssCtrl in Shift then
+ SetOffsetX(FOffsetX - Integer(FIndent))
+ else
+ begin
+ // other special cases
+ Context := NoColumn;
+ if (toExtendedFocus in FOptions.FSelectionOptions) and (toGridExtensions in FOptions.FMiscOptions) then
+ begin
+ Context := FHeader.Columns.GetNextVisibleColumn(FFocusedColumn);
+ if Context > -1 then
+ FocusedColumn := Context;
+ end
+ else
+ if Assigned(FFocusedNode) and not (vsExpanded in FFocusedNode.States) and
+ (Shift = []) and (vsHasChildren in FFocusedNode.States) then
+ ToggleNode(FFocusedNode)
+ else
+ begin
+ if FFocusedNode = nil then
+ FocusedNode := GetFirstVisible
+ else
+ begin
+ Node := GetFirstVisibleChild(FFocusedNode);
+ if Assigned(Node) then
+ begin
+ if HandleMultiSelect and (CompareNodePositions(Node, FRangeAnchor) < 0) then
+ RemoveFromSelection(FFocusedNode);
+ FocusedNode := Node;
+ end;
+ end;
+ end;
+ end;
+ end;
+ VK_BACK:
+ if tsIncrementalSearching in FStates then
+ DoStateChange([tsIncrementalSearchPending])
+ else
+ if Assigned(FFocusedNode) and (FFocusedNode.Parent <> FRoot) then
+ FocusedNode := FocusedNode.Parent;
+ VK_TAB:
+ if (toExtendedFocus in FOptions.FSelectionOptions) and FHeader.UseColumns then
+ begin
+ // In order to avoid duplicating source code just to change the direction
+ // we use function variables.
+ if ssShift in Shift then
+ begin
+ GetStartColumn := FHeader.FColumns.GetLastVisibleColumn;
+ GetNextColumn := FHeader.FColumns.GetPreviousVisibleColumn;
+ GetNextNode := GetPreviousVisible;
+ end
+ else
+ begin
+ GetStartColumn := FHeader.FColumns.GetFirstVisibleColumn;
+ GetNextColumn := FHeader.FColumns.GetNextVisibleColumn;
+ GetNextNode := GetNextVisible;
+ end;
+
+ // Advance to next/previous visible column/node.
+ Node := FFocusedNode;
+ NewColumn := GetNextColumn(FFocusedColumn);
+ repeat
+ // Find a column for the current node which can be focused.
+ while (NewColumn > NoColumn) and not DoFocusChanging(FFocusedNode, Node, FFocusedColumn, NewColumn) do
+ NewColumn := GetNextColumn(NewColumn);
+
+ if NewColumn > NoColumn then
+ begin
+ FocusedNode := Node;
+ FocusedColumn := NewColumn;
+ Break;
+ end;
+
+ // No next column was accepted for the current node. So advance to next node and try again.
+ Node := GetNextNode(Node);
+ NewColumn := GetStartColumn;
+ until Node = nil;
+ end;
+ end;
+
+ // Clear old selection if required but take care about change events.
+ if ClearPending then
+ if (LastFocused = FFocusedNode) and (FSelectionCount <= 1) then
+ InternalClearSelection
+ else
+ ClearSelection;
+
+ // Determine new selection anchor.
+ if Shift = [] then
+ begin
+ FRangeAnchor := FFocusedNode;
+ FLastSelectionLevel := GetNodeLevel(FFocusedNode);
+ end;
+ // Finally change the selection for a specific range of nodes.
+ if DoRangeSelect then
+ ToggleSelection(LastFocused, FFocusedNode);
+
+ // Make sure the new focused node is also selected.
+ // Avoid change event if this node was already the only selected node.
+ if Assigned(FFocusedNode) then
+ if LastFocused = FFocusedNode then
+ InternalAddToSelection(FFocusedNode, False)
+ else
+ AddToSelection(FFocusedNode);
+
+ // If a repaint is needed then paint the entire tree because of the ClearSelection call,
+ if NeedInvalidate then
+ Invalidate;
+ end
+ else
+ begin
+ // Second chance for keys not directly concerned with selection changes.
+
+ // For +, -, /, * keys on the main keyboard (not numpad) there is no virtual key code defined.
+ // We have to do special processing to get them working too.
+ GetKeyboardState(KeyState);
+ // Avoid conversion to control characters. We have captured the control key state already in Shift.
+ KeyState[VK_CONTROL] := 0;
+ if ToASCII(Message.CharCode, (Message.KeyData shr 16) and 7, KeyState, Buffer, 0) > 0 then
+ begin
+ case Buffer[0] of
+ '*':
+ CharCode := VK_MULTIPLY;
+ '+':
+ CharCode := VK_ADD;
+ '/':
+ CharCode := VK_DIVIDE;
+ '-':
+ CharCode := VK_SUBTRACT;
+ end;
+ end;
+
+ case CharCode of
+ VK_F2:
+ if (Shift = []) and Assigned(FFocusedNode) and CanEdit(FFocusedNode, FFocusedColumn) then
+ begin
+ FEditColumn := FFocusedColumn;
+ DoEdit;
+ end;
+ VK_ADD:
+ if not (tsIncrementalSearching in FStates) then
+ begin
+ if ssCtrl in Shift then
+ if {$ifdef ReverseFullExpandHotKey} not {$endif ReverseFullExpandHotKey} (ssShift in Shift) then
+ FullExpand
+ else
+ FHeader.AutoFitColumns
+ else
+ if Assigned(FFocusedNode) and not (vsExpanded in FFocusedNode.States) then
+ ToggleNode(FFocusedNode);
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_SUBTRACT:
+ if not (tsIncrementalSearching in FStates) then
+ begin
+ if ssCtrl in Shift then
+ if {$ifdef ReverseFullExpandHotKey} not {$endif ReverseFullExpandHotKey} (ssShift in Shift) then
+ FullCollapse
+ else
+ FHeader.RestoreColumns
+ else
+ if Assigned(FFocusedNode) and (vsExpanded in FFocusedNode.States) then
+ ToggleNode(FFocusedNode);
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_MULTIPLY:
+ if not (tsIncrementalSearching in FStates) then
+ begin
+ if Assigned(FFocusedNode) then
+ FullExpand(FFocusedNode);
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_DIVIDE:
+ if not (tsIncrementalSearching in FStates) then
+ begin
+ if Assigned(FFocusedNode) then
+ FullCollapse(FFocusedNode);
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_ESCAPE: // cancel actions currently in progress
+ begin
+ if IsMouseSelecting then
+ begin
+ DoStateChange([], [tsDrawSelecting, tsDrawSelPending]);
+ Invalidate;
+ end
+ else
+ if IsEditing then
+ CancelEditNode;
+ end;
+ VK_SPACE:
+ if (toCheckSupport in FOptions.MiscOptions) and Assigned(FFocusedNode) and
+ (FFocusedNode.CheckType <> ctNone) then
+ begin
+ if (FStates * [tsKeyCheckPending, tsMouseCheckPending] = []) and Assigned(FFocusedNode) and
+ not (vsDisabled in FFocusedNode.States) then
+ begin
+ with FFocusedNode^ do
+ NewCheckState := DetermineNextCheckState(CheckType, CheckState);
+ if DoChecking(FFocusedNode, NewCheckState) then
+ begin
+ DoStateChange([tsKeyCheckPending]);
+ FCheckNode := FFocusedNode;
+ FPendingCheckState := NewCheckState;
+ FCheckNode.CheckState := PressedState[FCheckNode.CheckState];
+ RepaintNode(FCheckNode);
+ end;
+ end;
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_F1:
+ if Assigned(FOnGetHelpContext) then
+ begin
+ Context := 0;
+ if Assigned(FFocusedNode) then
+ begin
+ Node := FFocusedNode;
+ // Traverse the tree structure up to the root.
+ repeat
+ FOnGetHelpContext(Self, Node, 0, Context);
+ Node := Node.Parent;
+ until (Node = FRoot) or (Context <> 0);
+ end;
+
+ // If no help context could be found try the tree's one or its parent's contexts.
+ ParentControl := Self;
+ while Assigned(ParentControl) and (Context = 0) do
+ begin
+ Context := ParentControl.HelpContext;
+ ParentControl := ParentControl.Parent;
+ end;
+ if Context <> 0 then
+ Application.HelpContext(Context);
+ end;
+ VK_APPS:
+ if Assigned(FFocusedNode) then
+ begin
+ R := GetDisplayRect(FFocusedNode, FFocusedColumn, True);
+ Offset := DoGetNodeWidth(FFocusedNode, FFocusedColumn);
+ if FFocusedColumn >= 0 then
+ begin
+ if Offset > FHeader.Columns[FFocusedColumn].Width then
+ Offset := FHeader.Columns[FFocusedColumn].Width;
+ end
+ else
+ begin
+ if Offset > ClientWidth then
+ Offset := ClientWidth;
+ end;
+ DoPopupMenu(FFocusedNode, FFocusedColumn, Point(R.Left + Offset div 2, (R.Top + R.Bottom) div 2));
+ end;
+ Ord('a'), Ord('A'):
+ if ssCtrl in Shift then
+ SelectAll(True)
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ else
+ begin
+ // Use the key for incremental search.
+ // Since we are dealing with Unicode all the time there should be a more sophisticated way
+ // of checking for valid characters for incremental search.
+ // This is available but would require to include a significant amount of Unicode character
+ // properties, so we stick with the simple space check.
+ if (Shift * [ssCtrl, ssAlt] = []) and (CharCode >= 32) then
+ DoStateChange([tsIncrementalSearchPending]);
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMKeyUp(var Message: TWMKeyUp);
+
+begin
+ inherited;
+
+ case Message.CharCode of
+ VK_SPACE:
+ if tsKeyCheckPending in FStates then
+ begin
+ DoStateChange([], [tskeyCheckPending]);
+ if FCheckNode = FFocusedNode then
+ DoCheckClick(FCheckNode, FPendingCheckState);
+ InvalidateNode(FCheckNode);
+ FCheckNode := nil;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMKillFocus(var Msg: TWMKillFocus);
+
+var
+ Form: TCustomForm;
+ Control: TWinControl;
+ Pos: TSmallPoint;
+ Unknown: IUnknown;
+
+begin
+ inherited;
+
+ // Stop wheel panning if active.
+ StopWheelPanning;
+
+ // Don't let any timer continue if the tree is no longer the active control (except change timers).
+ StopTimer(ExpandTimer);
+ StopTimer(EditTimer);
+ StopTimer(HeaderTimer);
+ StopTimer(ScrollTimer);
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+
+ DoStateChange([], [tsScrollPending, tsScrolling, tsEditPending, tsLeftButtonDown, tsRightButtonDown,
+ tsMiddleButtonDown, tsOLEDragPending, tsVCLDragPending, tsIncrementalSearching]);
+
+ if (FSelectionCount > 0) or not (toGhostedIfUnfocused in FOptions.FPaintOptions) then
+ Invalidate
+ else
+ if Assigned(FFocusedNode) then
+ InvalidateNode(FFocusedNode);
+
+ // Workaround for wrapped non-VCL controls (like TWebBrowser), which do not use VCL mechanisms and
+ // leave the ActiveControl property in the wrong state, which causes trouble when the control is refocused.
+ Form := GetParentForm(Self);
+ if Assigned(Form) and (Form.ActiveControl = Self) then
+ begin
+ Cardinal(Pos) := GetMessagePos;
+ Control := FindVCLWindow(SmallPointToPoint(Pos));
+ // Every control derived from TOleControl has potentially the focus problem. In order to avoid including
+ // the OleCtrls unit (which will, among others, include Variants), which would allow to test for the TOleControl
+ // class, the IOleClientSite interface is used for the test, which is supported by TOleControl and a good indicator.
+ if Assigned(Control) and Control.GetInterface(IOleClientSite, Unknown) then
+ Form.ActiveControl := nil;
+
+ // For other classes the active control should not be modified. Otherwise you need two clicks to select it.
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMLButtonDblClk(var Message: TWMLButtonDblClk);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ inherited;
+
+ // get information about the hit
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDblClick(Message, HitInfo);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMLButtonDown(var Message: TWMLButtonDown);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([tsLeftButtonDown]);
+ inherited;
+
+ // get information about the hit
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDown(Message, HitInfo);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMLButtonUp(var Message: TWMLButtonUp);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([], [tsLeftButtonDown]);
+
+ // get information about the hit
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseUp(Message, HitInfo);
+
+ inherited;
+
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMMButtonDblClk(var Message: TWMMButtonDblClk);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ inherited;
+
+ // get information about the hit
+ if toMiddleClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDblClick(Message, HitInfo);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMMButtonDown(var Message: TWMMButtonDown);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([tsMiddleButtonDown]);
+
+ if FHeader.FStates = [] then
+ begin
+ inherited;
+
+ // Start wheel panning or scrolling if not already active, allowed and scrolling is useful at all.
+ if (toWheelPanning in FOptions.FMiscOptions) and ([tsWheelScrolling, tsWheelPanning] * FStates = []) and
+ ((Integer(FRangeX) > ClientWidth) or (Integer(FRangeY) > ClientHeight)) then
+ begin
+ FLastClickPos := SmallPointToPoint(Message.Pos);
+ StartWheelPanning(FLastClickPos);
+ end
+ else
+ begin
+ StopWheelPanning;
+
+ // Get information about the hit.
+ if toMiddleClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDown(Message, HitInfo);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMMButtonUp(var Message: TWMMButtonUp);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([], [tsMiddleButtonDown]);
+
+ // If wheel panning/scrolling is active and the mouse has not yet been moved then the user starts wheel auto scrolling.
+ // Indicate this by removing the panning flag. Otherwise (the mouse has moved meanwhile) stop panning.
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ if tsWheelScrolling in FStates then
+ DoStateChange([], [tsWheelPanning])
+ else
+ StopWheelPanning;
+ end
+ else
+ if FHeader.FStates = [] then
+ begin
+ inherited;
+
+ // get information about the hit
+ if toMiddleClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseUp(Message, HitInfo);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMNCCalcSize(var Message: TWMNCCalcSize);
+
+begin
+ inherited;
+
+ with FHeader do
+ if hoVisible in FHeader.FOptions then
+ with Message.CalcSize_Params^ do
+ Inc(rgrc[0].Top, FHeight);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMNCDestroy(var Message: TWMNCDestroy);
+
+// Used to release a reference of the drag manager. This is the only reliable way we get notified about
+// window destruction, because of the automatic release of a window if its parent window is freed.
+
+begin
+ StopTimer(ChangeTimer);
+ StopTimer(StructureChangeTimer);
+
+ if not (csDesigning in ComponentState) and (toAcceptOLEDrop in FOptions.FMiscOptions) then
+ RevokeDragDrop(Handle);
+
+ // Clean up other stuff.
+ DeleteObject(FDottedBrush);
+ FDottedBrush := 0;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMNCHitTest(var Message: TWMNCHitTest);
+
+begin
+ inherited;
+ if not (csDesigning in ComponentState) and (hoVisible in FHeader.FOptions) and
+ FHeader.InHeader(ScreenToClient(SmallPointToPoint(Message.Pos))) then
+ Message.Result := HTBORDER;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMNCPaint(var Message: TRealWMNCPaint);
+
+var
+ DC: HDC;
+ R: TRect;
+ Flags: DWORD;
+
+begin
+ DefaultHandler(Message);
+
+ // If the tree is themed then the border which is drawn by the default handler will be overpainted here.
+ // This will, when resizing columns, cause a bit flicker, but since I found nowhwere documentation about
+ // how to do it right I have to live with that for the time being.
+ Flags := DCX_CACHE or DCX_CLIPSIBLINGS or DCX_WINDOW or DCX_VALIDATE;
+
+ if True or (Message.Rgn = 1) or not IsWinNT then
+ DC := GetDCEx(Handle, 0, Flags)
+ else
+ DC := GetDCEx(Handle, Message.Rgn, Flags or DCX_INTERSECTRGN);
+
+ if DC <> 0 then
+ begin
+ if hoVisible in FHeader.FOptions then
+ begin
+ R := FHeaderRect;
+ FHeader.FColumns.PaintHeader(DC, R, FOffsetX);
+ end;
+ OriginalWMNCPaint(DC);
+ ReleaseDC(Handle, DC);
+ end;
+ {$ifdef ThemeSupport}
+ if tsUseThemes in FStates then
+ ThemeServices.PaintBorder(Self, False);
+ {$endif ThemeSupport}
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMPaint(var Message: TWMPaint);
+
+begin
+ if tsVCLDragging in FStates then
+ ImageList_DragShowNolock(False);
+ GetUpdateRect(Handle, FUpdateRect, True);
+ inherited;
+ if tsVCLDragging in FStates then
+ ImageList_DragShowNolock(True);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMPaste(var Message: TWMPaste);
+
+begin
+ PasteFromClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMPrint(var Message: TWMPrint);
+
+// This message is sent to request that the tree draws itself to a given device context. This includes not only
+// the client area but also the non-client area (header!).
+
+begin
+ // Draw only if the window is visible or visibility is not required.
+ if ((Message.Flags and PRF_CHECKVISIBLE) = 0) or IsWindowVisible(Handle) then
+ Header.Columns.PaintHeader(Message.DC, FHeaderRect, FOffsetX);
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMPrintClient(var Message: TWMPrintClient);
+
+var
+ Window: TRect;
+ Target: TPoint;
+ Canvas: TCanvas;
+
+begin
+ // Draw only if the window is visible or visibility is not required.
+ if ((Message.Flags and PRF_CHECKVISIBLE) = 0) or IsWindowVisible(Handle) then
+ begin
+ // Determine area of the entire tree to be displayed in the control.
+ Window := ClientRect;
+ Target := Window.TopLeft;
+
+ // The Window rectangle is given in client coordinates. We have to convert it into
+ // a sliding window of the tree image.
+ OffsetRect(Window, -FOffsetX, -FOffsetY);
+
+ Canvas := TCanvas.Create;
+ try
+ Canvas.Handle := Message.DC;
+ PaintTree(Canvas, Window, Target, [poBackground, poDrawFocusRect, poDrawDropMark, poDrawSelection, poGridLines]);
+ finally
+ Canvas.Handle := 0;
+ Canvas.Free;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMRButtonDblClk(var Message: TWMRButtonDblClk);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ inherited;
+
+ // get information about the hit
+ if toMiddleClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDblClick(Message, HitInfo);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMRButtonDown(var Message: TWMRButtonDown);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([tsRightButtonDown]);
+
+ if FHeader.FStates = [] then
+ begin
+ inherited;
+
+ // get information about the hit
+ if toRightClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDown(Message, HitInfo);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMRButtonUp(var Message: TWMRButtonUp);
+
+// handle right click selection and node specific popup menu
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([], [tsRightButtonDown]);
+
+ if FHeader.FStates = [] then
+ begin
+ Application.CancelHint;
+
+ if IsMouseSelecting and Assigned(PopupMenu) then
+ begin
+ // Reset selection state already here, before the inherited handler opens the default menu.
+ DoStateChange([], [tsDrawSelecting, tsDrawSelPending]);
+ Invalidate;
+ end;
+
+ inherited;
+
+ // get information about the hit
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+
+ if toRightClickSelect in FOptions.FSelectionOptions then
+ HandleMouseUp(Message, HitInfo);
+
+ if not Assigned(PopupMenu) then
+ DoPopupMenu(HitInfo.HitNode, HitInfo.HitColumn, Point(Message.XPos, Message.YPos));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMReleaseEditLink(var Message: TMessage);
+
+begin
+ // Finally free edit link memory after editing has been finished.
+ if not IsEditing then
+ FEditLink := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMSetCursor(var Message: TWMSetCursor);
+
+// Sets the hot node mouse cursor for the tree. Cursor changes for the header are handled in Header.HandleMessage.
+
+var
+ NewCursor: TCursor;
+
+begin
+ with Message do
+ begin
+ if (CursorWnd = Handle) and not (csDesigning in ComponentState) then
+ begin
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ Beep;
+ end
+ else
+ if not FHeader.HandleMessage(TMessage(Message)) then
+ begin
+ // Apply own cursors only if there is no global cursor set.
+ if Screen.Cursor = crDefault then
+ begin
+ if (toHotTrack in FOptions.PaintOptions) and Assigned(FCurrentHotNode) then
+ NewCursor := FHotCursor
+ else
+ NewCursor := Cursor;
+
+ DoGetCursor(NewCursor);
+ Windows.SetCursor(Screen.Cursors[NewCursor]);
+ Message.Result := 1;
+ end
+ else
+ inherited;
+ end;
+ end
+ else
+ inherited;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMSetFocus(var Msg: TWMSetFocus);
+
+begin
+ inherited;
+ if (FSelectionCount > 0) or not (toGhostedIfUnfocused in FOptions.FPaintOptions) then
+ Invalidate;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMSize(var Message: TWMSize);
+
+begin
+ inherited;
+
+ // Need to update scroll bars here. This will cause a recursion because of the change of the client area
+ // when changing a scrollbar. Usually this is no problem since with the second level recursion no change of the
+ // window size happens (the same values for the scrollbars are set, which shouldn't cause a window size change).
+ // Appearently, this applies not to all systems, however.
+ if HandleAllocated and ([tsSizing, tsWindowCreating] * FStates = []) and (ClientHeight > 0) then
+ try
+ DoStateChange([tsSizing]);
+ // This call will invalidate the entire non-client area which needs recalculation on resize.
+ FHeader.RecalculateHeader;
+ UpdateScrollBars(True);
+
+ if (tsEditing in FStates) and not FHeader.UseColumns then
+ UpdateEditBounds;
+ finally
+ DoStateChange([], [tsSizing]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMTimer(var Message: TWMTimer);
+
+// centralized timer handling happens here
+
+begin
+ with Message do
+ begin
+ case TimerID of
+ ExpandTimer:
+ DoDragExpand;
+ EditTimer:
+ DoEdit;
+ ScrollTimer:
+ begin
+ if tsScrollPending in FStates then
+ begin
+ Application.CancelHint;
+ // Scroll delay has elapsed, set to normal scroll interval now.
+ SetTimer(Handle, ScrollTimer, FAutoScrollInterval, nil);
+ DoStateChange([tsScrolling], [tsScrollPending]);
+ end;
+ DoTimerScroll;
+ end;
+ ChangeTimer:
+ DoChange(FLastChangedNode);
+ StructureChangeTimer:
+ DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason);
+ SearchTimer:
+ begin
+ // When this event triggers then the user did not pressed any key for the specified timeout period.
+ // Hence incremental searching is stopped.
+ DoStateChange([], [tsIncrementalSearching]);
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMVScroll(var Message: TWMVScroll);
+
+ //--------------- local functions -------------------------------------------
+
+ function GetRealScrollPosition: Integer;
+
+ var
+ SI: TScrollInfo;
+ Code: Integer;
+
+ begin
+ SI.cbSize := SizeOf(TScrollInfo);
+ SI.fMask := SIF_TRACKPOS;
+ Code := SB_VERT;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_GetScrollInfo(Handle, Code, SI);
+ {$else}
+ GetScrollInfo(Handle, Code, SI);
+ {$endif UseFlatScrollbars}
+ Result := SI.nTrackPos;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+begin
+ case Message.ScrollCode of
+ SB_BOTTOM:
+ SetOffsetY(-Integer(FRoot.TotalHeight));
+ SB_ENDSCROLL:
+ begin
+ DoStateChange([], [tsThumbTracking]);
+ // Avoiding to adjust the horizontal scroll position while tracking makes scrolling much smoother
+ // but we need to adjust the final position here then.
+ UpdateScrollBars(True);
+ // Really weird invalidation needed here (and I do it only because it happens so rarely), because
+ // when showing the horizontal scrollbar while scrolling down using the down arrow button,
+ // the button will be repainted on mouse up (at the wrong place in the far right lower corner)...
+ RedrawWindow(Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN);
+ end;
+ SB_LINEUP:
+ SetOffsetY(FOffsetY + FScrollBarOptions.FIncrementY);
+ SB_LINEDOWN:
+ SetOffsetY(FOffsetY - FScrollBarOptions.FIncrementY);
+ SB_PAGEUP:
+ SetOffsetY(FOffsetY + ClientHeight);
+ SB_PAGEDOWN:
+ SetOffsetY(FOffsetY - ClientHeight);
+
+ SB_THUMBPOSITION,
+ SB_THUMBTRACK:
+ begin
+ DoStateChange([tsThumbTracking]);
+ SetOffsetY(-GetRealScrollPosition);
+ end;
+ SB_TOP:
+ SetOffsetY(0);
+ end;
+ Message.Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AddToSelection(Node: PVirtualNode);
+
+var
+ Changed: Boolean;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil!');
+ FSingletonNodeArray[0] := Node;
+ Changed := InternalAddToSelection(FSingletonNodeArray, 1, False);
+ if Changed then
+ Change(Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AddToSelection(const NewItems: TNodeArray; NewLength: Integer; ForceInsert: Boolean = False);
+
+// Adds the given items all at once into the current selection array. NewLength is the amount of
+// nodes to add (necessary to allow NewItems to be larger than the actual used entries).
+// ForceInsert is True if nodes must be inserted without consideration of level select constraint or
+// already set selected flags (e.g. when loading from stream).
+// Note: In the case ForceInsert is True the caller is responsible for making sure the new nodes aren't already in the
+// selection array!
+
+var
+ Changed: Boolean;
+
+begin
+ Changed := InternalAddToSelection(NewItems, NewLength, ForceInsert);
+ if Changed then
+ begin
+ if NewLength = 1 then
+ Change(NewItems[0])
+ else
+ Change(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex);
+
+// Used in descentants to modify the clip rectangle of the current column while painting a certain node.
+
+begin
+ // Since cells are always drawn from left to right the next column index is independent of the
+ // bidi mode, but not the column borders which might change depending on the cell's content.
+ NextNonEmpty := FHeader.FColumns.GetNextVisibleColumn(PaintInfo.Column);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustPanningCursor(X, Y: Integer);
+
+// Triggered by a mouse move when wheel panning/scrolling is active.
+// Loads the proper cursor which indicates into which direction scrolling is done.
+
+var
+ Name: string;
+ NewCursor: HCURSOR;
+ ScrollHorizontal,
+ ScrollVertical: Boolean;
+
+begin
+ ScrollHorizontal := Integer(FRangeX) > ClientWidth;
+ ScrollVertical := Integer(FRangeY) > ClientHeight;
+
+ if (Abs(X - FLastClickPos.X) < 8) and (Abs(Y - FLastClickPos.Y) < 8) then
+ begin
+ // Mouse is in the neutral zone.
+ if ScrollHorizontal then
+ begin
+ if ScrollVertical then
+ Name := 'VT_MOVEALL'
+ else
+ Name := 'VT_MOVEEW'
+ end
+ else
+ Name := 'VT_MOVENS';
+ end
+ else
+ begin
+ // One of 8 directions applies: north, north-east, east, south-east, south, south-west, west and north-west.
+ // Check also if scrolling in the particular direction is possible.
+ if ScrollVertical and ScrollHorizontal then
+ begin
+ // All directions allowed.
+ if X - FlastClickPos.X < -8 then
+ begin
+ // Left hand side.
+ if Y - FLastClickPos.Y < -8 then
+ Name := 'VT_MOVENW'
+ else
+ if Y - FLastClickPos.Y > 8 then
+ Name := 'VT_MOVESW'
+ else
+ Name := 'VT_MOVEW';
+ end
+ else
+ if X - FLastClickPos.X > 8 then
+ begin
+ // Right hand side.
+ if Y - FLastClickPos.Y < -8 then
+ Name := 'VT_MOVENE'
+ else
+ if Y - FLastClickPos.Y > 8 then
+ Name := 'VT_MOVESE'
+ else
+ Name := 'VT_MOVEE';
+ end
+ else
+ begin
+ // Up or down.
+ if Y < FLastClickPos.Y then
+ Name := 'VT_MOVEN'
+ else
+ Name := 'VT_MOVES';
+ end;
+ end
+ else
+ if ScrollHorizontal then
+ begin
+ // Only horizontal movement allowed.
+ if X < FlastClickPos.X then
+ Name := 'VT_MOVEW'
+ else
+ Name := 'VT_MOVEE';
+ end
+ else
+ begin
+ // Only vertical movement allowed.
+ if Y < FlastClickPos.Y then
+ Name := 'VT_MOVEN'
+ else
+ Name := 'VT_MOVES';
+ end;
+ end;
+
+ // Now load the cursor and apply it.
+ NewCursor := LoadCursor(HInstance, PChar(Name));
+ if FPanningCursor <> NewCursor then
+ begin
+ DeleteObject(FPanningCursor);
+ FPanningCursor := NewCursor;
+ Windows.SetCursor(FPanningCursor);
+ end
+ else
+ DeleteObject(NewCursor);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdviseChangeEvent(StructureChange: Boolean; Node: PVirtualNode; Reason: TChangeReason);
+
+// Used to register a delayed change event. If StructureChange is False then we have a selection change event (without
+// a specific reason) otherwise it is a structure change.
+
+begin
+ if StructureChange then
+ begin
+ if tsStructureChangePending in FStates then
+ StopTimer(StructureChangeTimer)
+ else
+ DoStateChange([tsStructureChangePending]);
+
+ FLastStructureChangeNode := Node;
+ if FLastStructureChangeReason = crIgnore then
+ FLastStructureChangeReason := Reason
+ else
+ if Reason <> crIgnore then
+ FLastStructureChangeReason := crAccumulated;
+ end
+ else
+ begin
+ if tsChangePending in FStates then
+ StopTimer(ChangeTimer)
+ else
+ DoStateChange([tsChangePending]);
+
+ FLastChangedNode := Node;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.AllocateInternalDataArea(Size: Cardinal): Cardinal;
+
+// Simple registration method to be called by each descendant to claim their internal data area.
+// Result is the offset from the begin of the node to the internal data area of the calling tree class.
+
+begin
+ Assert((FRoot = nil) or (FRoot.ChildCount = 0), 'Internal data allocation must be done before any node is created.');
+
+ Result := TreeNodeSize + FTotalInternalDataSize;
+ Inc(FTotalInternalDataSize, (Size + 3) and not 3);
+ InitRootNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Animate(Steps, Duration: Cardinal; Callback: TVTAnimationCallback; Data: Pointer);
+
+// This method does the calculation part of an animation as used for node toggling and hint animations.
+// Steps is the maximum amount of animation steps to do and Duration determines the milliseconds the animation
+// has to run. Callback is a task specific method which is called in the loop for every step and Data is simply
+// something to pass on to the callback.
+// The callback is called with the current step, the current step size and the Data parameter. Since the step amount
+// as well as the step size are possibly adjusted during the animation, it is impossible to determine if the current
+// step is the last step, even if the original step amount is known. To solve this problem the callback will be
+// called after the loop has finished with a step size of 0 indicating so to execute any post processing.
+
+var
+ StepSize,
+ RemainingTime,
+ RemainingSteps,
+ NextTimeStep,
+ CurrentStep,
+ StartTime,
+ CurrentTime: Cardinal;
+
+begin
+ if not (tsInAnimation in FStates) and (Duration > 0) then
+ begin
+ DoStateChange([tsInAnimation]);
+ try
+ RemainingTime := Duration;
+ RemainingSteps := Steps;
+
+ // Determine the initial step size which is either 1 if the needed steps are less than the number of
+ // steps possible given by the duration or > 1 otherwise.
+ StepSize := Round(Max(1, RemainingSteps / Duration));
+ RemainingSteps := RemainingSteps div StepSize;
+ CurrentStep := 0;
+
+ while (RemainingSteps > 0) and (RemainingTime > 0) and not Application.Terminated do
+ begin
+ StartTime := timeGetTime;
+ NextTimeStep := StartTime + RemainingTime div RemainingSteps;
+ if not Callback(CurrentStep, StepSize, Data) then
+ Break;
+
+ // Keep duration for this step for rest calculation.
+ CurrentTime := timeGetTime;
+ // Wait until the calculated time has been reached.
+ while CurrentTime < NextTimeStep do
+ CurrentTime := timeGetTime;
+
+ // Subtract the time this step really needed.
+ if RemainingTime >= CurrentTime - StartTime then
+ begin
+ Dec(RemainingTime, CurrentTime - StartTime);
+ Dec(RemainingSteps);
+ end
+ else
+ begin
+ RemainingTime := 0;
+ RemainingSteps := 0;
+ end;
+ // If the remaining time per step is less than one time step then we have to decrease the
+ // step count and increase the step size.
+ if (RemainingSteps > 0) and ((RemainingTime div RemainingSteps) < 1) then
+ begin
+ repeat
+ Inc(StepSize);
+ RemainingSteps := RemainingTime div StepSize;
+ until (RemainingSteps <= 0) or ((RemainingTime div RemainingSteps) >= 1);
+ end;
+ CurrentStep := Cardinal(Steps) - RemainingSteps;
+ end;
+
+ if not Application.Terminated then
+ Callback(0, 0, Data);
+ finally
+ DoStateChange([], [tsInAnimation]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CalculateSelectionRect(X, Y: Integer): Boolean;
+
+// Recalculates old and new selection rectangle given that X, Y are new mouse coordinates.
+// Returns True if there was a change since the last call.
+
+var
+ MaxValue: Integer;
+
+begin
+ if tsDrawSelecting in FStates then
+ FLastSelRect := FNewSelRect;
+ FNewSelRect.BottomRight := Point(X - FOffsetX, Y - FOffsetY);
+ if FNewSelRect.Right < 0 then
+ FNewSelRect.Right := 0;
+ if FNewSelRect.Bottom < 0 then
+ FNewSelRect.Bottom := 0;
+ MaxValue := ClientWidth;
+ if FRangeX > Cardinal(MaxValue) then
+ MaxValue := FRangeX;
+ if FNewSelRect.Right > MaxValue then
+ FNewSelRect.Right := MaxValue;
+ MaxValue := ClientHeight;
+ if FRangeY > Cardinal(MaxValue) then
+ MaxValue := FRangeY;
+ if FNewSelRect.Bottom > MaxValue then
+ FNewSelRect.Bottom := MaxValue;
+
+ Result := not CompareMem(@FLastSelRect, @FNewSelRect, SizeOf(FNewSelRect));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CanAutoScroll: Boolean;
+
+// Determines if auto scrolling is currently allowed.
+
+begin
+ // Don't scroll the client area if the header is currently doing tracking or dragging.
+ // Do auto scroll only if there is a draw selection in progress or the tree is the current drop target or
+ // wheel panning/scrolling is active.
+ Result := (toAutoScroll in FOptions.FAutoOptions) and (FHeader.FStates = []) and
+ (([tsDrawSelPending, tsDrawSelecting] * FStates <> []) or (Assigned(FDragManager) and DragManager.IsDropTarget) or
+ (tsVCLDragging in FStates) or
+ ([tsWheelPanning, tsWheelScrolling] * FStates <> []));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CanEdit(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// Returns True if the given node can be edited.
+
+begin
+ Result := (toEditable in FOptions.FMiscOptions) and Enabled and not (toReadOnly in FOptions.FMiscOptions);
+ DoCanEdit(Node, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CanShowDragImage: Boolean;
+
+// Determines whether a drag image should be shown.
+
+begin
+ Result := FDragImageKind <> diNoImage;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Change(Node: PVirtualNode);
+
+begin
+ AdviseChangeEvent(False, Node, crIgnore);
+
+ if FUpdateCount = 0 then
+ begin
+ if (FChangeDelay > 0) and not (tsSynchMode in FStates) then
+ SetTimer(Handle, ChangeTimer, FChangeDelay, nil)
+ else
+ DoChange(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ChangeScale(M, D: Integer);
+
+var
+ DoScale: Boolean;
+
+begin
+ inherited;
+
+ if (M <> D) and (toAutoChangeScale in FOptions.FAutoOptions) then
+ begin
+ if (csLoading in ComponentState) then
+ DoScale := tsNeedScale in FStates
+ else
+ DoScale := True;
+ if DoScale then
+ begin
+ FDefaultNodeHeight := MulDiv(FDefaultNodeHeight, M, D);
+ FHeader.ChangeScale(M, D);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CheckParentCheckState(Node: PVirtualNode; NewCheckState: TCheckState): Boolean;
+
+// Checks all siblings of node to determine which check state Node's parent must get.
+
+var
+ CheckCount,
+ BoxCount: Cardinal;
+ PartialCheck: Boolean;
+ Run: PVirtualNode;
+
+begin
+ CheckCount := 0;
+ BoxCount := 0;
+ PartialCheck := False;
+ Run := Node.Parent.FirstChild;
+ while Assigned(Run) do
+ begin
+ if Run = Node then
+ begin
+ // The given node cannot be checked because it does not yet have its new check state (as this depends
+ // on the outcome of this method). Instead NewCheckState is used as this contains the new state the node
+ // will get if this method returns True.
+ if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
+ begin
+ Inc(BoxCount);
+ if NewCheckState in [csCheckedNormal, csCheckedPressed] then
+ Inc(CheckCount);
+ PartialCheck := PartialCheck or (NewCheckState = csMixedNormal);
+ end;
+ end
+ else
+ if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
+ begin
+ Inc(BoxCount);
+ if Run.CheckState in [csCheckedNormal, csCheckedPressed] then
+ Inc(CheckCount);
+ PartialCheck := PartialCheck or (Run.CheckState = csMixedNormal);
+ end;
+ Run := Run.NextSibling;
+ end;
+
+ if (CheckCount = 0) and not PartialCheck then
+ NewCheckState := csUncheckedNormal
+ else
+ if CheckCount < BoxCount then
+ NewCheckState := csMixedNormal
+ else
+ NewCheckState := csCheckedNormal;
+
+ Node := Node.Parent;
+ Result := DoChecking(Node, NewCheckState);
+ if Result then
+ begin
+ DoCheckClick(Node, NewCheckState);
+ // Recursively adjust parent of parent.
+ with Node^ do
+ begin
+ if not (vsInitialized in Parent.States) then
+ InitNode(Parent);
+ if ([vsChecking, vsDisabled] * Parent.States = []) and (Parent <> FRoot) and
+ (Parent.CheckType = ctTriStateCheckBox) then
+ Result := CheckParentCheckState(Node, NewCheckState);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ClearTempCache;
+
+// make sure the temporary node cache is in a reliable state
+
+begin
+ FTempNodeCache := nil;
+ FTempNodeCount := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// Returns True if the given column is to be considered as being empty. This will usually be determined by
+// descentants as the base tree implementation has not enough information to decide.
+
+begin
+ Result := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CountLevelDifference(Node1, Node2: PVirtualNode): Integer;
+
+// This method counts how many indentation levels the given nodes are apart. If both nodes have the same parent then the
+// difference is 0 otherwise the result is basically GetNodeLevel(Node2) - GetNodeLevel(Node1), but with sign.
+// If the result is negative then Node2 is less intended than Node1.
+
+var
+ Level1, Level2: Integer;
+
+begin
+ Assert(Assigned(Node1) and Assigned(Node2), 'Both nodes must be Assigned.');
+
+ Level1 := 0;
+ while Node1.Parent <> FRoot do
+ begin
+ Inc(Level1);
+ Node1 := Node1.Parent;
+ end;
+
+ Level2 := 0;
+ while Node2.Parent <> FRoot do
+ begin
+ Inc(Level2);
+ Node2 := Node2.Parent;
+ end;
+
+ Result := Level2 - Level1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CountVisibleChildren(Node: PVirtualNode): Cardinal;
+
+// Returns the number of visible child nodes of the given node.
+
+begin
+ Result := 0;
+ // its direct children
+ if vsExpanded in Node.States then
+ begin
+ // and their children
+ Node := Node.FirstChild;
+ while Assigned(Node) do
+ begin
+ if vsVisible in Node.States then
+ Inc(Result, CountVisibleChildren(Node) + 1);
+ Node := Node.NextSibling;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CreateParams(var Params: TCreateParams);
+
+const
+ ScrollBar: array[TScrollStyle] of Cardinal = (0, WS_HSCROLL, WS_VSCROLL, WS_HSCROLL or WS_VSCROLL);
+
+begin
+ inherited CreateParams(Params);
+
+ with Params do
+ begin
+ Style := Style or WS_CLIPCHILDREN or WS_CLIPSIBLINGS or ScrollBar[ScrollBarOptions.FScrollBars];
+ if toFullRepaintOnResize in FOptions.MiscOptions then
+ WindowClass.style := WindowClass.style or CS_HREDRAW or CS_VREDRAW
+ else
+ WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
+ if FBorderStyle = bsSingle then
+ begin
+ if Ctl3D then
+ begin
+ ExStyle := ExStyle or WS_EX_CLIENTEDGE;
+ Style := Style and not WS_BORDER;
+ end
+ else
+ Style := Style or WS_BORDER;
+ end
+ else
+ Style := Style and not WS_BORDER;
+
+ // Left scrollbars can be used with Win2K and up, regardless of the system locale.
+ if BidiMode <> bdLeftToRight then
+ ExStyle := ExStyle or WS_EX_LEFTSCROLLBAR;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CreateWnd;
+
+// Initializes data which depends on a valid window handle.
+
+begin
+ DoStateChange([tsWindowCreating]);
+ inherited;
+ DoStateChange([], [tsWindowCreating]);
+
+ {$ifdef ThemeSupport}
+ if ThemeServices.ThemesEnabled and (toThemeAware in TreeOptions.PaintOptions) then
+ DoStateChange([tsUseThemes])
+ else
+ {$endif ThemeSupport}
+ DoStateChange([], [tsUseThemes]);
+
+ // Because of the special recursion and update stopper when creating the window (or resizing it)
+ // we have to manually trigger the auto size calculation here.
+ if hoAutoResize in FHeader.FOptions then
+ FHeader.FColumns.AdjustAutoSize(InvalidColumn);
+
+ // Initialize flat scroll bar library if required.
+ {$ifdef UseFlatScrollbars}
+ if FScrollBarOptions.FScrollBarStyle <> sbmRegular then
+ begin
+ InitializeFlatSB(Handle);
+ FlatSB_SetScrollProp(Handle, WSB_PROP_HSTYLE, ScrollBarProp[FScrollBarOptions.ScrollBarStyle], False);
+ FlatSB_SetScrollProp(Handle, WSB_PROP_VSTYLE, ScrollBarProp[FScrollBarOptions.ScrollBarStyle], False);
+ end;
+ {$endif UseFlatScrollbars}
+
+ PrepareBitmaps(True, True);
+
+ // Register tree as OLE drop target.
+ if not (csDesigning in ComponentState) and (toAcceptOLEDrop in FOptions.FMiscOptions) then
+ RegisterDragDrop(Handle, DragManager as IDropTarget);
+
+ UpdateScrollBars(True);
+ UpdateHeaderRect;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DefineProperties(Filer: TFiler);
+
+// There were heavy changes in some properties during development of VT. This method helps to make migration easier
+// by reading old properties manually and put them into the new properties as appropriate.
+// Note: these old properties are never written again and silently disappear.
+// June 2002: Meanwhile another task is done here too: working around the problem that TCollection is not streamed
+// correctly when using Visual Form Inheritance (VFI).
+
+var
+ StoreIt: Boolean;
+
+begin
+ inherited;
+
+ // The header can prevent writing columns altogether.
+ if FHeader.CanWriteColumns then
+ begin
+ // Check if we inherit from an ancestor form (Visual Form Inheritance).
+ StoreIt := Filer.Ancestor = nil;
+ // If there is an ancestor then save columns only if they are different to the base set.
+ if not StoreIt then
+ StoreIt := not FHeader.Columns.Equals(TBaseVirtualTree(Filer.Ancestor).FHeader.Columns);
+ end
+ else
+ StoreIt := False;
+
+ Filer.DefineProperty('Columns', FHeader.ReadColumns, FHeader.WriteColumns, StoreIt);
+ Filer.DefineProperty('Options', ReadOldOptions, nil, False);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DetermineHiddenChildrenFlag(Node: PVirtualNode);
+
+// Update the hidden children flag of the given node.
+
+var
+ Run: PVirtualNode;
+
+begin
+ // Iterate through all siblings and stop when one visible is found.
+ Run := Node.FirstChild;
+ while Assigned(Run) and not (vsVisible in Run.States) do
+ Run := Run.NextSibling;
+ if Assigned(Run) then
+ Exclude(Node.States, vsAllChildrenHidden)
+ else
+ Include(Node.States, vsAllChildrenHidden);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DetermineHiddenChildrenFlagAllNodes;
+
+var
+ Run: PVirtualNode;
+
+begin
+ Run := GetFirstNoInit;
+ while Assigned(Run) do
+ begin
+ DetermineHiddenChildrenFlag(Run);
+ Run := GetNextNoInit(Run);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DetermineHitPositionLTR(var HitInfo: THitInfo; Offset, Right: Integer;
+ Alignment: TAlignment);
+
+// This method determines the hit position within a node with left-to-right orientation.
+
+var
+ MainColumnHit,
+ Ghosted: Boolean;
+ Run: PVirtualNode;
+ Indent,
+ TextWidth,
+ ImageOffset: Integer;
+
+begin
+ MainColumnHit := HitInfo.HitColumn = FHeader.MainColumn;
+ Indent := 0;
+
+ // If columns are not used or the main column is hit then the tree indentation must be considered too.
+ if MainColumnHit then
+ begin
+ Run := HitInfo.HitNode;
+ while (Run.Parent <> FRoot) do
+ begin
+ Inc(Indent, FIndent);
+ Run := Run.Parent;
+ end;
+ if toShowRoot in FOptions.FPaintOptions then
+ Inc(Indent, FIndent);
+ end;
+
+ if Offset < Indent then
+ begin
+ // Position is to the left of calculated indentation which can only happen for the main column.
+ // Check whether it corresponds to a button/checkbox.
+ if (toShowButtons in FOptions.FPaintOptions) and (vsHasChildren in HitInfo.HitNode.States) then
+ begin
+ // Position of button is interpreted very generously to avoid forcing the user
+ // to click exactly into the 9x9 pixels area. The entire node height and one full
+ // indentation level is accepted as button hit.
+ if Offset >= Indent - Integer(FIndent) then
+ Include(HitInfo.HitPositions, hiOnItemButton);
+ end;
+ // no button hit so position is on indent
+ if HitInfo.HitPositions = [] then
+ Include(HitInfo.HitPositions, hiOnItemIndent);
+ end
+ else
+ begin
+ // The next hit positions can be:
+ // - on the check box
+ // - on the state image
+ // - on the normal image
+ // - to the left of the text area
+ // - on the label or
+ // - to the right of the text area
+ // (in this order).
+
+ // In report mode no hit other than in the main column is possible.
+ if MainColumnHit or not (toReportMode in FOptions.FMiscOptions) then
+ begin
+ ImageOffset := Indent + FMargin;
+
+ // Check support is only available for the main column.
+ if MainColumnHit and (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages) and
+ (HitInfo.HitNode.CheckType <> ctNone) then
+ Inc(ImageOffset, FCheckImages.Width + 2);
+
+ if MainColumnHit and (Offset < ImageOffset) then
+ HitInfo.HitPositions := [hiOnItem, hiOnItemCheckBox]
+ else
+ begin
+ if Assigned(FStateImages) and (GetImageIndex(HitInfo.HitNode, ikState, HitInfo.HitColumn, Ghosted) > -1) then
+ Inc(ImageOffset, FStateImages.Width + 2);
+ if Offset < ImageOffset then
+ Include(HitInfo.HitPositions, hiOnStateIcon)
+ else
+ begin
+ if Assigned(FImages) and (GetImageIndex(HitInfo.HitNode, ikNormal, HitInfo.HitColumn, Ghosted) > -1) then
+ Inc(ImageOffset, FImages.Width + 2);
+ if Offset < ImageOffset then
+ Include(HitInfo.HitPositions, hiOnNormalIcon)
+ else
+ begin
+ // ImageOffset contains now the left border of the node label area. This is used to calculate the
+ // correct alignment in the column.
+ TextWidth := DoGetNodeWidth(HitInfo.HitNode, HitInfo.HitColumn);
+
+ // Check if the text can be aligned at all. This is only possible if there is enough room
+ // in the remaining text rectangle.
+ if TextWidth > Right - ImageOffset then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ begin
+ case Alignment of
+ taCenter:
+ begin
+ Indent := (ImageOffset + Right - TextWidth) div 2;
+ if Offset < Indent then
+ Include(HitInfo.HitPositions, hiOnItemLeft)
+ else
+ if Offset < Indent + TextWidth then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ Include(HitInfo.HitPositions, hiOnItemRight)
+ end;
+ taRightJustify:
+ begin
+ Indent := Right - TextWidth;
+ if Offset < Indent then
+ Include(HitInfo.HitPositions, hiOnItemLeft)
+ else
+ Include(HitInfo.HitPositions, hiOnItemLabel);
+ end;
+ else // taLeftJustify
+ if Offset < ImageOffset + TextWidth then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ Include(HitInfo.HitPositions, hiOnItemRight);
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DetermineHitPositionRTL(var HitInfo: THitInfo; Offset, Right: Integer; Alignment: TAlignment);
+
+// This method determines the hit position within a node with right-to-left orientation.
+
+var
+ MainColumnHit,
+ Ghosted: Boolean;
+ Run: PVirtualNode;
+ Indent,
+ TextWidth,
+ ImageOffset: Integer;
+
+begin
+ MainColumnHit := HitInfo.HitColumn = FHeader.MainColumn;
+
+ // If columns are not used or the main column is hit then the tree indentation must be considered too.
+ if MainColumnHit then
+ begin
+ Run := HitInfo.HitNode;
+ while (Run.Parent <> FRoot) do
+ begin
+ Dec(Right, FIndent);
+ Run := Run.Parent;
+ end;
+ if toShowRoot in FOptions.FPaintOptions then
+ Dec(Right, FIndent);
+ end;
+
+ if Offset >= Right then
+ begin
+ // Position is to the right of calculated indentation which can only happen for the main column.
+ // Check whether it corresponds to a button/checkbox.
+ if (toShowButtons in FOptions.FPaintOptions) and (vsHasChildren in HitInfo.HitNode.States) then
+ begin
+ // Position of button is interpreted very generously to avoid forcing the user
+ // to click exactly into the 9x9 pixels area. The entire node height and one full
+ // indentation level is accepted as button hit.
+ if Offset <= Right + Integer(FIndent) then
+ Include(HitInfo.HitPositions, hiOnItemButton);
+ end;
+ // no button hit so position is on indent
+ if HitInfo.HitPositions = [] then
+ Include(HitInfo.HitPositions, hiOnItemIndent);
+ end
+ else
+ begin
+ // The next hit positions can be:
+ // - on the check box
+ // - on the state image
+ // - on the normal image
+ // - to the left of the text area
+ // - on the label or
+ // - to the right of the text area
+ // (in this order).
+
+ // In report mode no hit other than in the main column is possible.
+ if MainColumnHit or not (toReportMode in FOptions.FMiscOptions) then
+ begin
+ ImageOffset := Right - FMargin;
+
+ // Check support is only available for the main column.
+ if MainColumnHit and (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages) and
+ (HitInfo.HitNode.CheckType <> ctNone) then
+ Dec(ImageOffset, FCheckImages.Width + 2);
+
+ if MainColumnHit and (Offset > ImageOffset) then
+ HitInfo.HitPositions := [hiOnItem, hiOnItemCheckBox]
+ else
+ begin
+ if Assigned(FStateImages) and (GetImageIndex(HitInfo.HitNode, ikState, HitInfo.HitColumn, Ghosted) > -1) then
+ Dec(ImageOffset, FStateImages.Width + 2);
+ if Offset > ImageOffset then
+ Include(HitInfo.HitPositions, hiOnStateIcon)
+ else
+ begin
+ if Assigned(FImages) and (GetImageIndex(HitInfo.HitNode, ikNormal, HitInfo.HitColumn, Ghosted) > -1) then
+ Dec(ImageOffset, FImages.Width + 2);
+ if Offset > ImageOffset then
+ Include(HitInfo.HitPositions, hiOnNormalIcon)
+ else
+ begin
+ // ImageOffset contains now the right border of the node label area. This is used to calculate the
+ // correct alignment in the column.
+ TextWidth := DoGetNodeWidth(HitInfo.HitNode, HitInfo.HitColumn);
+
+ // Check if the text can be aligned at all. This is only possible if there is enough room
+ // in the remaining text rectangle.
+ if TextWidth > ImageOffset then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ begin
+ // Consider bidi mode here. In RTL context does left alignment actually mean right alignment
+ // and vice versa.
+ ChangeBiDiModeAlignment(Alignment);
+
+ case Alignment of
+ taCenter:
+ begin
+ Indent := (ImageOffset - TextWidth) div 2;
+ if Offset < Indent then
+ Include(HitInfo.HitPositions, hiOnItemLeft)
+ else
+ if Offset < Indent + TextWidth then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ Include(HitInfo.HitPositions, hiOnItemRight)
+ end;
+ taRightJustify:
+ begin
+ Indent := ImageOffset - TextWidth;
+ if Offset < Indent then
+ Include(HitInfo.HitPositions, hiOnItemLeft)
+ else
+ Include(HitInfo.HitPositions, hiOnItemLabel);
+ end;
+ else // taLeftJustify
+ if Offset > TextWidth then
+ Include(HitInfo.HitPositions, hiOnItemRight)
+ else
+ Include(HitInfo.HitPositions, hiOnItemLabel);
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DetermineNextCheckState(CheckType: TCheckType; CheckState: TCheckState): TCheckState;
+
+// Determines the next check state in case the user click the check image or pressed the space key.
+
+begin
+ case CheckType of
+ ctTriStateCheckBox,
+ ctCheckBox:
+ if CheckState = csCheckedNormal then
+ Result := csUncheckedNormal
+ else
+ Result := csCheckedNormal;
+ ctRadioButton:
+ Result := csCheckedNormal;
+ ctButton:
+ Result := csUncheckedNormal;
+ else
+ Result := csMixedNormal;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DetermineScrollDirections(X, Y: Integer): TScrollDirections;
+
+// Determines which direction the client area must be scrolled depending on the given position.
+
+begin
+ Result:= [];
+
+ if CanAutoScroll then
+ begin
+ // Calculation for wheel panning/scrolling is a bit different to normal auto scroll.
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ if (X - FLastClickPos.X) < -8 then
+ Include(Result, sdLeft);
+ if (X - FLastClickPos.X) > 8 then
+ Include(Result, sdRight);
+
+ if (Y - FLastClickPos.Y) < -8 then
+ Include(Result, sdUp);
+ if (Y - FLastClickPos.Y) > 8 then
+ Include(Result, sdDown);
+ end
+ else
+ begin
+ if (X < Integer(FDefaultNodeHeight)) and (FOffsetX <> 0) then
+ Include(Result, sdLeft);
+ if (ClientWidth - FOffsetX < Integer(FRangeX)) and (X > ClientWidth - Integer(FDefaultNodeHeight)) then
+ Include(Result, sdRight);
+
+ if (Y < Integer(FDefaultNodeHeight)) and (FOffsetY <> 0) then
+ Include(Result, sdUp);
+ if (ClientHeight - FOffsetY < Integer(FRangeY)) and (Y > ClientHeight - Integer(FDefaultNodeHeight)) then
+ Include(Result, sdDown);
+
+ // Since scrolling during dragging is not handled via the timer we do a check here whether the auto
+ // scroll timeout already has elapsed or not.
+ if (Result <> []) and
+ ((Assigned(FDragManager) and DragManager.IsDropTarget) or
+ (FindDragTarget(Point(X, Y), False) = Self)) then
+ begin
+ if FDragScrollStart = 0 then
+ FDragScrollStart := timeGetTime;
+ // Reset any scroll direction to avoid scroll in the case the user is dragging and the auto scroll time has not
+ // yet elapsed.
+ if ((timeGetTime - FDragScrollStart) < FAutoScrollDelay) then
+ Result := [];
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAdvancedHeaderDraw(var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements);
+
+begin
+ if Assigned(FOnAdvancedHeaderDraw) then
+ FOnAdvancedHeaderDraw(FHeader, PaintInfo, Elements);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAfterCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect);
+
+begin
+ if Assigned(FOnAfterCellPaint) then
+ FOnAfterCellPaint(Self, Canvas, Node, Column, CellRect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAfterItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
+
+begin
+ if Assigned(FOnAfterItemErase) then
+ FOnAfterItemErase(Self, Canvas, Node, ItemRect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAfterItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
+
+begin
+ if Assigned(FOnAfterItemPaint) then
+ FOnAfterItemPaint(Self, Canvas, Node, ItemRect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAfterPaint(Canvas: TCanvas);
+
+begin
+ if Assigned(FOnAfterPaint) then
+ FOnAfterPaint(Self, Canvas);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAutoScroll(X, Y: Integer);
+
+begin
+ FScrollDirections := DetermineScrollDirections(X, Y);
+
+ if FStates * [tsWheelPanning, tsWheelScrolling] = [] then
+ begin
+ if FScrollDirections = [] then
+ begin
+ if ((FStates * [tsScrollPending, tsScrolling]) <> []) then
+ begin
+ StopTimer(ScrollTimer);
+ DoStateChange([], [tsScrollPending, tsScrolling]);
+ end;
+ end
+ else
+ begin
+ // start auto scroll if not yet done
+ if (FStates * [tsScrollPending, tsScrolling]) = [] then
+ begin
+ DoStateChange([tsScrollPending]);
+ SetTimer(Handle, ScrollTimer, FAutoScrollDelay, nil);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoBeforeDrag(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+begin
+ Result := False;
+ if Assigned(FOnDragAllowed) then
+ FOnDragAllowed(Self, Node, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoBeforeCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect);
+
+begin
+ if Assigned(FOnBeforeCellPaint) then
+ FOnBeforeCellPaint(Self, Canvas, Node, Column, CellRect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoBeforeItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect; var Color: TColor;
+ var EraseAction: TItemEraseAction);
+
+begin
+ if Assigned(FOnBeforeItemErase) then
+ FOnBeforeItemErase(Self, Canvas, Node, ItemRect, Color, EraseAction);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoBeforeItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect): Boolean;
+
+begin
+ // By default custom draw will not be used, so the tree handles drawing the node.
+ Result := False;
+ if Assigned(FOnBeforeItemPaint) then
+ FOnBeforeItemPaint(Self, Canvas, Node, ItemRect, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoBeforePaint(Canvas: TCanvas);
+
+begin
+ if Assigned(FOnBeforePaint) then
+ FOnBeforePaint(Self, Canvas);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCancelEdit: Boolean;
+
+// Called when the current edit action or a pending edit must be cancelled.
+
+begin
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ Result := (tsEditing in FStates) and FEditLink.CancelEdit;
+ if Result then
+ begin
+ DoStateChange([], [tsEditing]);
+ if Assigned(FOnEditCancelled) then
+ FOnEditCancelled(Self, FEditColumn);
+ if not (csDestroying in ComponentState) then
+ // Asynchroniously release edit link.
+ PostMessage(Handle, WM_RELEASEEDITLINK, 0, 0);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoCanEdit(Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
+
+begin
+ if Assigned(FOnEditing) then
+ FOnEditing(Self, Node, Column, Allowed);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoChange(Node: PVirtualNode);
+
+begin
+ StopTimer(ChangeTimer);
+ if Assigned(FOnChange) then
+ FOnChange(Self, Node);
+
+ // This is a good place to reset the cached node. This is the same as the node passed in here.
+ // This is necessary to allow descentants to override this method and get the node then.
+ DoStateChange([], [tsChangePending]);
+ FLastChangedNode := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoCheckClick(Node: PVirtualNode; NewCheckState: TCheckState);
+
+begin
+ if ChangeCheckState(Node, NewCheckState) then
+ DoChecked(Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoChecked(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnChecked) then
+ FOnChecked(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoChecking(Node: PVirtualNode; var NewCheckState: TCheckState): Boolean;
+
+// Determines if a node is allowed to change its check state to NewCheckState.
+
+begin
+ if toReadOnly in FOptions.FMiscOptions then
+ Result := False
+ else
+ begin
+ Result := True;
+ if Assigned(FOnChecking) then
+ FOnChecking(Self, Node, NewCheckState, Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoCollapsed(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnCollapsed) then
+ FOnCollapsed(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCollapsing(Node: PVirtualNode): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnCollapsing) then
+ FOnCollapsing(Self, Node, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoColumnClick(Column: TColumnIndex; Shift: TShiftState);
+
+begin
+ if Assigned(FOnColumnClick) then
+ FOnColumnClick(Self, Column, Shift);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoColumnDblClick(Column: TColumnIndex; Shift: TShiftState);
+
+begin
+ if Assigned(FOnColumnDblClick) then
+ FOnColumnDblClick(Self, Column, Shift);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoColumnResize(Column: TColumnIndex);
+
+var
+ R: TRect;
+
+begin
+ if not (csLoading in ComponentState) and HandleAllocated then
+ begin
+ UpdateHorizontalScrollBar(True);
+ // Invalidate client area from the current column all to the right.
+ R := ClientRect;
+ if not (toAutoSpanColumns in FOptions.FAutoOptions) then
+ R.Left := FHeader.Columns[Column].Left;
+ InvalidateRect(Handle, @R, False);
+ FHeader.Invalidate(FHeader.Columns[Column], True);
+ if hsTracking in FHeader.States then
+ UpdateWindow(Handle);
+
+ UpdateDesigner; // design time only
+
+ if Assigned(FOnColumnResize) then
+ FOnColumnResize(FHeader, Column);
+
+ // If the tree is currently in edit state then notify edit link.
+ if tsEditing in FStates then
+ UpdateEditBounds;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCompare(Node1, Node2: PVirtualNode; Column: TColumnIndex): Integer;
+
+begin
+ Result := 0;
+ if Assigned(FOnCompareNodes) then
+ FOnCompareNodes(Self, Node1, Node2, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCreateDataObject: IDataObject;
+
+begin
+ Result := nil;
+ if Assigned(FOnCreateDataObject) then
+ FOnCreateDataObject(Self, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCreateDragManager: IVTDragManager;
+
+begin
+ Result := nil;
+ if Assigned(FOnCreateDragManager) then
+ FOnCreateDragManager(Self, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink;
+
+begin
+ Result := nil;
+ if Assigned(FOnCreateEditor) then
+ begin
+ FOnCreateEditor(Self, Node, Column, Result);
+ if Result = nil then
+ ShowError(SEditLinkIsNil, hcTFEditLinkIsNil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoDragging(P: TPoint);
+
+// Initiates finally the drag'n drop operation and returns after DD is finished.
+
+ //--------------- local function --------------------------------------------
+
+ function GetDragOperations: Integer;
+
+ begin
+ if FDragOperations = [] then
+ Result := DROPEFFECT_COPY or DROPEFFECT_MOVE or DROPEFFECT_LINK
+ else
+ begin
+ Result := 0;
+ if doCopy in FDragOperations then
+ Result := Result or DROPEFFECT_COPY;
+ if doLink in FDragOperations then
+ Result := Result or DROPEFFECT_LINK;
+ if doMove in FDragOperations then
+ Result := Result or DROPEFFECT_MOVE;
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ I,
+ DragEffect,
+ AllowedEffects: Integer;
+ DragObject: TDragObject;
+
+ DataObject: IDataObject;
+
+begin
+ DataObject := nil;
+ // Dragging is dragging, nothing else.
+ DoCancelEdit;
+
+ if Assigned(FCurrentHotNode) then
+ begin
+ InvalidateNode(FCurrentHotNode);
+ FCurrentHotNode := nil;
+ end;
+ // Select the focused node if not already done.
+ if Assigned(FFocusedNode) and not (vsSelected in FFocusedNode.States) then
+ begin
+ InternalAddToSelection(FFocusedNode, False);
+ InvalidateNode(FFocusedNode);
+ end;
+
+ UpdateWindow(Handle);
+
+ // Keep a list of all currently selected nodes as this list might change,
+ // but we have probably to delete currently selected nodes.
+ FDragSelection := GetSortedSelection(True);
+ try
+ DoStateChange([tsOLEDragging], [tsOLEDragPending, tsClearPending]);
+
+ // An application might create a drag object like used during VCL dd. This is not required for OLE dd but
+ // required as parameter.
+ DragObject := nil;
+ DoStartDrag(DragObject);
+ DragObject.Free;
+
+ DataObject := DragManager.DataObject;
+ PrepareDragImage(P, DataObject);
+
+ FLastDropMode := dmOnNode;
+ // Don't forget to initialize the result. It might never be touched.
+ DragEffect := DROPEFFECT_NONE;
+ AllowedEffects := GetDragOperations;
+ try
+ ActiveX.DoDragDrop(DataObject, DragManager as IDropSource, AllowedEffects, DragEffect);
+ DragManager.ForceDragLeave;
+ finally
+ GetCursorPos(P);
+ P := ScreenToClient(P);
+ DoEndDrag(Self, P.X, P.Y);
+
+ FDragImage.EndDrag;
+
+ // Finish the operation.
+ if (DragEffect = DROPEFFECT_MOVE) and (toAutoDeleteMovedNodes in TreeOptions.AutoOptions) then
+ begin
+ // The operation was a move so delete the previously selected nodes.
+ BeginUpdate;
+ try
+ // The list of selected nodes was retrieved in resolved state. That means there can never be a node
+ // in the list whose parent (or its parent etc.) is also selected.
+ for I := 0 to High(FDragSelection) do
+ DeleteNode(FDragSelection[I]);
+ finally
+ EndUpdate;
+ end;
+ end;
+
+ DoStateChange([], [tsOLEDragging]);
+ end;
+ finally
+ FDragSelection := nil;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoDragExpand;
+
+var
+ SourceTree: TBaseVirtualTree;
+
+begin
+ StopTimer(ExpandTimer);
+ if Assigned(FDropTargetNode) and (vsHasChildren in FDropTargetNode.States) and
+ not (vsExpanded in FDropTargetNode.States) then
+ begin
+ if Assigned(FDragManager) then
+ SourceTree := DragManager.DragSource
+ else
+ SourceTree := nil;
+
+ if not DragManager.DropTargetHelperSupported and Assigned(SourceTree) then
+ SourceTree.FDragImage.HideDragImage;
+ ToggleNode(FDropTargetNode);
+ UpdateWindow(Handle);
+ if not DragManager.DropTargetHelperSupported and Assigned(SourceTree) then
+ SourceTree.FDragImage.ShowDragImage;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoDragOver(Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode;
+ var Effect: Integer): Boolean;
+
+begin
+ Result := False;
+ if Assigned(FOnDragOver) then
+ FOnDragOver(Self, Source, Shift, State, Pt, Mode, Effect, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoDragDrop(Source: TObject; DataObject: IDataObject; Formats: TFormatArray;
+ Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode);
+
+begin
+ if Assigned(FOnDragDrop) then
+ FOnDragDrop(Self, Source, DataObject, Formats, Shift, Pt, Effect, Mode);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoEdit;
+
+begin
+ Application.CancelHint;
+ StopTimer(ScrollTimer);
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ if Assigned(FFocusedNode) and not (vsDisabled in FFocusedNode.States) and
+ not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ FEditLink := DoCreateEditor(FFocusedNode, FEditColumn);
+ if Assigned(FEditLink) then
+ begin
+ DoStateChange([tsEditing], [tsDrawSelecting, tsDrawSelPending, tsClearFocusedSelection, tsOLEDragPending,
+ tsOLEDragging, tsClearPending, tsDrawSelPending, tsScrollPending, tsScrolling, tsMouseCheckPending]);
+ ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions, True);
+ if FEditLink.PrepareEdit(Self, FFocusedNode, FEditColumn) then
+ begin
+ UpdateEditBounds;
+ // Node needs repaint because the selection rectangle and static text must disappear.
+ InvalidateNode(FFocusedNode);
+ if not FEditLink.BeginEdit then
+ DoStateChange([], [tsEditing]);
+ end
+ else
+ DoStateChange([], [tsEditing]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoEndDrag(Target: TObject; X, Y: Integer);
+
+// Does some housekeeping for VCL drag'n drop;
+
+begin
+ inherited;
+
+ DragFinished;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoEndEdit: Boolean;
+
+begin
+ Result := (tsEditing in FStates) and FEditLink.EndEdit;
+ if Result then
+ begin
+ DoStateChange([], [tsEditing]);
+ // Asynchronously release edit link.
+ PostMessage(Handle, WM_RELEASEEDITLINK, 0, 0);
+ if Assigned(FOnEdited) then
+ FOnEdited(Self, FFocusedNode, FEditColumn);
+ end;
+ DoStateChange([], [tsEditPending]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoExpanded(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnExpanded) then
+ FOnExpanded(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoExpanding(Node: PVirtualNode): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnExpanding) then
+ FOnExpanding(Self, Node, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoFocusChange(Node: PVirtualNode; Column: TColumnIndex);
+
+begin
+ if Assigned(FOnFocusChanged) then
+ FOnFocusChanged(Self, Node, Column);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoFocusChanging(OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnFocusChanging) then
+ FOnFocusChanging(Self, OldNode, NewNode, OldColumn, NewColumn, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoFocusNode(Node: PVirtualNode; Ask: Boolean);
+
+begin
+ if not (tsEditing in FStates) or EndEditNode then
+ begin
+ if Node = FRoot then
+ Node := nil;
+ if (FFocusedNode <> Node) and (not Ask or DoFocusChanging(FFocusedNode, Node, FFocusedColumn, FFocusedColumn)) then
+ begin
+ if Assigned(FFocusedNode) then
+ begin
+ // Do automatic collapsing of last focused node if enabled. This is however only done if
+ // old and new focused node have a common parent node.
+ if (toAutoExpand in FOptions.FAutoOptions) and Assigned(Node) and (Node.Parent = FFocusedNode.Parent) and
+ (vsExpanded in FFocusedNode.States) then
+ ToggleNode(FFocusedNode)
+ else
+ InvalidateNode(FFocusedNode);
+ end;
+ FFocusedNode := Node;
+ end;
+
+ // Have to scroll the node into view, even it is the same node as before.
+ if Assigned(FFocusedNode) then
+ begin
+ // Make sure a valid column is set if columns are used and no column has currently the focus.
+ if FHeader.UseColumns and (FFocusedColumn < 0) then
+ FFocusedColumn := 0;
+ // Do automatic expansion of the newly focused node if enabled.
+ if (toAutoExpand in FOptions.FAutoOptions) and not (vsExpanded in FFocusedNode.States) then
+ ToggleNode(FFocusedNode);
+ InvalidateNode(FFocusedNode);
+ if FUpdateCount = 0 then
+ ScrollIntoView(FFocusedNode, (toCenterScrollIntoView in FOptions.SelectionOptions) and
+ (MouseButtonDown * FStates = []), not (toDisableAutoscrollOnFocus in FOptions.FAutoOptions));
+ end;
+
+ // Reset range anchor if necessary.
+ if FSelectionCount = 0 then
+ ResetRangeAnchor;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoFreeNode(Node: PVirtualNode);
+
+begin
+ if Node = FCurrentHotNode then
+ FCurrentHotNode := nil;
+ if Assigned(FOnFreeNode) and ([vsInitialized, vsInitialUserData] * Node.States <> []) then
+ FOnFreeNode(Self, Node);
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager.FreeNode(Node);
+ {$else}
+ FreeMem(Node);
+ {$endif UseLocalMemoryManager}
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+// These constants are defined in the platform SDK for W2K/XP, but not yet in Delphi.
+const
+ SPI_GETTOOLTIPANIMATION = $1016;
+ SPI_GETTOOLTIPFADE = $1018;
+
+function TBaseVirtualTree.DoGetAnimationType: THintAnimationType;
+
+// Determines (depending on the properties settings and the system) which hint
+// animation type is to be used.
+
+var
+ Animation: BOOL;
+
+begin
+ Result := FAnimationType;
+ if Result = hatSystemDefault then
+ begin
+ if not IsWinNT then
+ Result := hatSlide
+ else
+ begin
+ SystemParametersInfo(SPI_GETTOOLTIPANIMATION, 0, @Animation, 0);
+ if not Animation then
+ Result := hatNone
+ else
+ begin
+ SystemParametersInfo(SPI_GETTOOLTIPFADE, 0, @Animation, 0);
+ if Animation then
+ Result := hatFade
+ else
+ Result := hatSlide;
+ end;
+ end;
+ end;
+
+ // Check availability of MMX if fading is requested.
+ if not MMXAvailable and (Result = hatFade) then
+ Result := hatSlide;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetCursor(var Cursor: TCursor);
+
+begin
+ if Assigned(FOnGetCursor) then
+ FOnGetCursor(Self, Cursor);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetHeaderCursor(var Cursor: HCURSOR);
+
+begin
+ if Assigned(FOnGetHeaderCursor) then
+ FOnGetHeaderCursor(FHeader, Cursor);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer);
+
+begin
+ if Assigned(FOnGetImage) then
+ FOnGetImage(Self, Node, Kind, Column, Ghosted, Index);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetLineStyle(var Bits: Pointer);
+
+begin
+ if Assigned(FOnGetLineStyle) then
+ FOnGetLineStyle(Self, Bits);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Result := Hint;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Result := Hint;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;
+
+begin
+ Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoGetPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint): TPopupMenu;
+
+// Queries the application whether there is a node specific popup menu.
+
+var
+ Run: PVirtualNode;
+ AskParent: Boolean;
+
+begin
+ Result := nil;
+ if Assigned(FOnGetPopupMenu) then
+ begin
+ Run := Node;
+
+ if Assigned(Run) then
+ begin
+ AskParent := True;
+ repeat
+ FOnGetPopupMenu(Self, Run, Column, Position, AskParent, Result);
+ Run := Run.Parent;
+ until (Run = FRoot) or Assigned(Result) or not AskParent;
+ end
+ else
+ FOnGetPopupMenu(Self, nil, -1, Position, AskParent, Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetUserClipboardFormats(var Formats: TFormatEtcArray);
+
+begin
+ if Assigned(FOnGetUserClipboardFormats) then
+ FOnGetUserClipboardFormats(Self, Formats);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderClick(Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderClick) then
+ FOnHeaderClick(FHeader, Column, Button, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDblClick(Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderDblClick) then
+ FOnHeaderDblClick(FHeader, Column, Button, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDragged(Column: TColumnIndex; OldPosition: TColumnPosition);
+
+begin
+ if Assigned(FOnHeaderDragged) then
+ FOnHeaderDragged(FHeader, Column, OldPosition);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDraggedOut(Column: TColumnIndex; DropPosition: TPoint);
+
+begin
+ if Assigned(FOnHeaderDraggedOut) then
+ FOnHeaderDraggedOut(FHeader, Column, DropPosition);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoHeaderDragging(Column: TColumnIndex): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnHeaderDragging) then
+ FOnHeaderDragging(FHeader, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDraw(Canvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover, Pressed: Boolean;
+ DropMark: TVTDropMarkMode);
+
+begin
+ if Assigned(FOnHeaderDraw) then
+ FOnHeaderDraw(FHeader, Canvas, Column, R, Hover, Pressed, DropMark);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDrawQueryElements(var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements);
+
+begin
+ if Assigned(FOnHeaderDrawQueryElements) then
+ FOnHeaderDrawQueryElements(FHeader, PaintInfo, Elements);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderMouseDown) then
+ FOnHeaderMouseDown(FHeader, Button, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderMouseMove(Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderMouseMove) then
+ FOnHeaderMouseMove(FHeader, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderMouseUp) then
+ FOnHeaderMouseUp(FHeader, Button, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHotChange(Old, New: PVirtualNode);
+
+begin
+ if Assigned(FOnHotChange) then
+ FOnHotChange(Self, Old, New);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoIncrementalSearch(Node: PVirtualNode; const Text: WideString): Integer;
+
+begin
+ Result := 0;
+ if Assigned(FOnIncrementalSearch) then
+ FOnIncrementalSearch(Self, Node, Text, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoInitChildren(Node: PVirtualNode; var ChildCount: Cardinal);
+
+begin
+ if Assigned(FOnInitChildren) then
+ FOnInitChildren(Self, Node, ChildCount);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoInitNode(Parent, Node: PVirtualNode; var InitStates: TVirtualNodeInitStates);
+
+begin
+ if Assigned(FOnInitNode) then
+ FOnInitNode(Self, Parent, Node, InitStates);
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoKeyAction(var CharCode: Word; var Shift: TShiftState): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnKeyAction) then
+ FOnKeyAction(Self, CharCode, Shift, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoLoadUserData(Node: PVirtualNode; Stream: TStream);
+
+begin
+ if Assigned(FOnLoadNode) then
+ if Node = FRoot then
+ FOnLoadNode(Self, nil, Stream)
+ else
+ FOnLoadNode(Self, Node, Stream);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoNodeCopied(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnNodeCopied) then
+ FOnNodeCopied(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoNodeCopying(Node, NewParent: PVirtualNode): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnNodeCopying) then
+ FOnNodeCopying(Self, Node, NewParent, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoNodeMoved(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnNodeMoved) then
+ FOnNodeMoved(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoNodeMoving(Node, NewParent: PVirtualNode): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnNodeMoving) then
+ FOnNodeMoving(Self, Node, NewParent, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoPaintBackground(Canvas: TCanvas; R: TRect): Boolean;
+
+begin
+ Result := False;
+ if Assigned(FOnPaintBackground) then
+ FOnPaintBackground(Self, Canvas, R, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoPaintDropMark(Canvas: TCanvas; Node: PVirtualNode; R: TRect);
+
+// draws the drop mark into the given rectangle
+// Note: Changed properties of the given canvas should be reset to their previous values.
+
+var
+ SaveBrushColor: TColor;
+ SavePenStyle: TPenStyle;
+
+begin
+ if FLastDropMode in [dmAbove, dmBelow] then
+ with Canvas do
+ begin
+ SavePenStyle := Pen.Style;
+ Pen.Style := psClear;
+ SaveBrushColor := Brush.Color;
+ Brush.Color := FColors.DropMarkColor;
+
+ if FLastDropMode = dmAbove then
+ begin
+ Polygon([Point(R.Left + 2, R.Top),
+ Point(R.Right - 2, R.Top),
+ Point(R.Right - 2, R.Top + 6),
+ Point(R.Right - 6, R.Top + 2),
+ Point(R.Left + 6 , R.Top + 2),
+ Point(R.Left + 2, R.Top + 6)
+ ]);
+ end
+ else
+ Polygon([Point(R.Left + 2, R.Bottom - 1),
+ Point(R.Right - 2, R.Bottom - 1),
+ Point(R.Right - 2, R.Bottom - 8),
+ Point(R.Right - 7, R.Bottom - 3),
+ Point(R.Left + 7 , R.Bottom - 3),
+ Point(R.Left + 2, R.Bottom - 8)
+ ]);
+ Brush.Color := SaveBrushColor;
+ Pen.Style := SavePenStyle;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoPaintNode(var PaintInfo: TVTPaintInfo);
+
+begin
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint);
+
+// Support for node dependent popup menus.
+
+var
+ Menu: TPopupMenu;
+
+begin
+ Menu := DoGetPopupMenu(Node, Column, Position);
+
+ if Assigned(Menu) then
+ begin
+ StopTimer(EditTimer);
+ Menu.PopupComponent := Self;
+ with ClientToScreen(Position) do
+ Menu.Popup(X, Y);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoRenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean): HRESULT;
+
+begin
+ Result := E_FAIL;
+ if Assigned(FOnRenderOLEData) then
+ FOnRenderOLEData(Self, FormatEtcIn, Medium, ForClipboard, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoReset(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnResetNode) then
+ FOnResetNode(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoSaveUserData(Node: PVirtualNode; Stream: TStream);
+
+begin
+ if Assigned(FOnSaveNode) then
+ if Node = FRoot then
+ FOnSaveNode(Self, nil, Stream)
+ else
+ FOnSaveNode(Self, Node, Stream);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoScroll(DeltaX, DeltaY: Integer);
+
+begin
+ if Assigned(FOnScroll) then
+ FOnScroll(Self, DeltaX, DeltaY);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoSetOffsetXY(Value: TPoint; Options: TScrollUpdateOptions; ClipRect: PRect = nil): Boolean;
+
+// Actual offset setter used to scroll the client area, update scroll bars and invalidating the header (all optional).
+// Returns True if the offset really changed otherwise False is returned.
+
+var
+ DeltaX: Integer;
+ DeltaY: Integer;
+ DWPStructure: HDWP;
+ I: Integer;
+ P: TPoint;
+
+begin
+ // Range check, order is important here.
+ if Value.X < (ClientWidth - Integer(FRangeX)) then
+ Value.X := ClientWidth - Integer(FRangeX);
+ if Value.X > 0 then
+ Value.X := 0;
+ DeltaX := Value.X - FOffsetX;
+ if Value.Y < (ClientHeight - Integer(FRangeY)) then
+ Value.Y := ClientHeight - Integer(FRangeY);
+ if Value.Y > 0 then
+ Value.Y := 0;
+ DeltaY := Value.Y - FOffsetY;
+
+ Result := (DeltaX <> 0) or (DeltaY <> 0);
+ if Result then
+ begin
+ FOffsetX := Value.X;
+ FOffsetY := Value.Y;
+ Result := True;
+
+ if FUpdateCount = 0 then
+ begin
+ // The drag image from VCL controls need special consideration.
+ if tsVCLDragging in FStates then
+ ImageList_DragShowNolock(False);
+
+ if suoScrollClientArea in Options then
+ begin
+ // Have to invalidate the entire window if there's a background.
+ if (toShowBackground in FOptions.FPaintOptions) and (FBackground.Graphic is TBitmap) then
+ begin
+ // Since we don't use ScrollWindow here we have to move all client windows ourselves.
+ DWPStructure := BeginDeferWindowPos(ControlCount);
+ for I := 0 to ControlCount - 1 do
+ if Controls[I] is TWinControl then
+ begin
+ with Controls[I] as TWinControl do
+ DWPStructure := DeferWindowPos(DWPStructure, Handle, 0, Left + DeltaX, Top + DeltaY, 0, 0,
+ SWP_NOZORDER or SWP_NOACTIVATE or SWP_NOSIZE);
+ if DWPStructure = 0 then
+ Break;
+ end;
+ if DWPStructure <> 0 then
+ EndDeferWindowPos(DWPStructure);
+ InvalidateRect(Handle, nil, False);
+ end
+ else
+ ScrollWindow(Handle, DeltaX, DeltaY, ClipRect, ClipRect);
+ end;
+
+ if suoUpdateNCArea in Options then
+ begin
+ if DeltaX <> 0 then
+ begin
+ if (suoRepaintHeader in Options) and (hoVisible in FHeader.FOptions) then
+ FHeader.Invalidate(nil);
+ if not (tsSizing in FStates) and (FScrollBarOptions.ScrollBars in [ssHorizontal, ssBoth]) then
+ UpdateHorizontalScrollBar(suoRepaintScrollbars in Options);
+ end;
+
+ if (DeltaY <> 0) and ([tsThumbTracking, tsSizing] * FStates = []) then
+ begin
+ UpdateVerticalScrollBar(suoRepaintScrollbars in Options);
+ if not (FHeader.UseColumns or IsMouseSelecting) and
+ (FScrollBarOptions.ScrollBars in [ssHorizontal, ssBoth]) then
+ UpdateHorizontalScrollBar(suoRepaintScrollbars in Options);
+ end;
+ end;
+
+ if tsVCLDragging in FStates then
+ ImageList_DragShowNolock(True);
+ end;
+
+ // Finally update "hot" node if hot tracking is activated
+ GetCursorPos(P);
+ P := ScreenToClient(P);
+ if PtInRect(ClientRect, P) then
+ HandleHotTrack(P.X, P.Y);
+
+ DoScroll(DeltaX, DeltaY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoStartDrag(var DragObject: TDragObject);
+
+begin
+ inherited;
+
+ // Check if the application created an own drag object. This is needed to pass the correct source in
+ // OnDragOver and OnDragDrop.
+ if Assigned(DragObject) then
+ DoStateChange([tsUserDragObject]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoStateChange(Enter: TVirtualTreeStates; Leave: TVirtualTreeStates = []);
+
+var
+ ActualEnter,
+ ActualLeave: TVirtualTreeStates;
+
+begin
+ if Assigned(FOnStateChange) then
+ begin
+ ActualEnter := Enter - FStates;
+ ActualLeave := FStates * Leave;
+ if (ActualEnter + ActualLeave) <> [] then
+ FOnStateChange(Self, Enter, Leave);
+ end;
+ FStates := FStates + Enter - Leave;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoStructureChange(Node: PVirtualNode; Reason: TChangeReason);
+
+begin
+ StopTimer(StructureChangeTimer);
+ if Assigned(FOnStructureChange) then
+ FOnStructureChange(Self, Node, Reason);
+
+ // This is a good place to reset the cached node and reason. These are the same as the values passed in here.
+ // This is necessary to allow descentants to override this method and get them.
+ DoStateChange([], [tsStructureChangePending]);
+ FLastStructureChangeNode := nil;
+ FLastStructureChangeReason := crIgnore;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoTimerScroll;
+
+var
+ P,
+ ClientP: TPoint;
+ InRect,
+ Panning: Boolean;
+ R,
+ ClipRect: TRect;
+ DeltaX,
+ DeltaY: Integer;
+
+begin
+ GetCursorPos(P);
+ R := ClientRect;
+ ClipRect := R;
+ MapWindowPoints(Handle, 0, R, 2);
+ InRect := PtInRect(R, P);
+ ClientP := ScreenToClient(P);
+ Panning := [tsWheelPanning, tsWheelScrolling] * FStates <> [];
+
+ if IsMouseSelecting or InRect or ([tsWheelPanning, tsWheelScrolling] * FStates <> []) then
+ begin
+ DeltaX := 0;
+ DeltaY := 0;
+ if sdUp in FScrollDirections then
+ begin
+ if Panning then
+ DeltaY := FLastClickPos.Y - ClientP.Y - 8
+ else
+ if InRect then
+ DeltaY := Min(FScrollBarOptions.FIncrementY, ClientHeight)
+ else
+ DeltaY := Min(FScrollBarOptions.FIncrementY, ClientHeight) * Abs(R.Top - P.Y);
+ if FOffsetY = 0 then
+ Exclude(FScrollDirections, sdUp);
+ end;
+
+ if sdDown in FScrollDirections then
+ begin
+ if Panning then
+ DeltaY := FLastClickPos.Y - ClientP.Y + 8
+ else
+ if InRect then
+ DeltaY := -Min(FScrollBarOptions.FIncrementY, ClientHeight)
+ else
+ DeltaY := -Min(FScrollBarOptions.FIncrementY, ClientHeight) * Abs(P.Y - R.Bottom);
+ if (ClientHeight - FOffsetY) = Integer(FRangeY) then
+ Exclude(FScrollDirections, sdDown);
+ end;
+
+ if sdLeft in FScrollDirections then
+ begin
+ if Panning then
+ DeltaX := FLastClickPos.X - ClientP.X - 8
+ else
+ if InRect then
+ DeltaX := FScrollBarOptions.FIncrementX
+ else
+ DeltaX := FScrollBarOptions.FIncrementX * Abs(R.Left - P.X);
+ if FOffsetX = 0 then
+ Exclude(FScrollDirections, sdleft);
+ end;
+
+ if sdRight in FScrollDirections then
+ begin
+ if Panning then
+ DeltaX := FLastClickPos.X - ClientP.X + 8
+ else
+ if InRect then
+ DeltaX := -FScrollBarOptions.FIncrementX
+ else
+ DeltaX := -FScrollBarOptions.FIncrementX * Abs(P.X - R.Right);
+
+ if (ClientWidth - FOffsetX) = Integer(FRangeX) then
+ Exclude(FScrollDirections, sdRight);
+ end;
+
+ if IsMouseSelecting then
+ begin
+ // In order to avoid scrolling the area which needs a repaint due to the changed selection rectangle
+ // we limit the scroll area explicitely.
+ OffsetRect(ClipRect, DeltaX, DeltaY);
+ DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), DefaultScrollUpdateFlags, @ClipRect);
+ // When selecting with the mouse then either update only the parts of the window which have been uncovered
+ // by the scroll operation if no change in the selection happend or invalidate and redraw the entire
+ // client area otherwise (to avoid the time consuming task of determining the display rectangles of every
+ // changed node).
+ if CalculateSelectionRect(ClientP.X, ClientP.Y) and HandleDrawSelection(ClientP.X, ClientP.Y) then
+ InvalidateRect(Handle, nil, False)
+ else
+ begin
+ // The selection did not change so invalidate only the part of the window which really needs an update.
+ // 1) Invalidate the parts uncovered by the scroll operation. Add another offset range, we have to
+ // scroll only one stripe but have to update two.
+ OffsetRect(ClipRect, DeltaX, DeltaY);
+ SubtractRect(ClipRect, ClientRect, ClipRect);
+ InvalidateRect(Handle, @ClipRect, False);
+
+ // 2) Invalidate the selection rectangles.
+ UnionRect(ClipRect, OrderRect(FNewSelRect), OrderRect(FLastSelRect));
+ OffsetRect(ClipRect, FOffsetX, FOffsetY);
+ InvalidateRect(Handle, @ClipRect, False);
+ end;
+ end
+ else
+ begin
+ // Scroll only if there is no drag'n drop in progress. Drag'n drop scrolling is handled in DragOver.
+ if ((FDragManager = nil) or not DragManager.IsDropTarget) and ((DeltaX <> 0) or (DeltaY <> 0)) then
+ DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), DefaultScrollUpdateFlags, nil);
+ end;
+ UpdateWindow(Handle);
+
+ if (FScrollDirections = []) and ([tsWheelPanning, tsWheelScrolling] * FStates = []) then
+ begin
+ StopTimer(ScrollTimer);
+ DoStateChange([], [tsScrollPending, tsScrolling]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoUpdating(State: TVTUpdateState);
+
+begin
+ if Assigned(FOnUpdating) then
+ FOnUpdating(Self, State);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoValidateCache: Boolean;
+
+// This method fills the caches used in various situations to speed up search for nodes.
+// The strategy is simple: Take the current number of visible nodes and distribute evenly a number of marks
+// (which are stored in FPositionCache) so that iterating through the tree doesn't cost too much time.
+// If there are less than 'CacheThreshold' nodes in the tree then the cache remains empty.
+// Result is True if the cache was filled without interruption, otherwise False.
+// Note: You can adjust the maximum number of nodes between two cache entries by changing CacheThreshold.
+
+var
+ EntryCount,
+ CurrentTop,
+ Index: Cardinal;
+ CurrentNode,
+ Temp: PVirtualNode;
+
+begin
+ EntryCount := 0;
+ if not (tsStopValidation in FStates) then
+ begin
+ if FStartIndex = 0 then
+ FPositionCache := nil;
+
+ if FVisibleCount > CacheThreshold then
+ begin
+ EntryCount := CalculateCacheEntryCount;
+ SetLength(FPositionCache, EntryCount);
+ if FStartIndex > EntryCount then
+ FStartIndex := EntryCount;
+
+ // Optimize validation by starting with FStartIndex if set.
+ if (FStartIndex > 0) and Assigned(FPositionCache[FStartIndex - 1].Node) then
+ begin
+ // Index is the current entry in FPositionCache.
+ Index := FStartIndex - 1;
+ // Running term for absolute top value.
+ CurrentTop := FPositionCache[Index].AbsoluteTop;
+ // Running node pointer.
+ CurrentNode := FPositionCache[Index].Node;
+ end
+ else
+ begin
+ // Index is the current entry in FPositionCache.
+ Index := 0;
+ // Running term for absolute top value.
+ CurrentTop := 0;
+ // Running node pointer.
+ CurrentNode := GetFirstVisibleNoInit;
+ end;
+
+ // EntryCount serves as counter for processed nodes here. This value can always start at 0 as
+ // the validation either starts also at index 0 or an index which is always a multiple of CacheThreshold
+ // and EntryCount is only used with modulo CacheThreshold.
+ EntryCount := 0;
+ if Assigned(CurrentNode) then
+ begin
+ while not (tsStopValidation in FStates) do
+ begin
+ if (EntryCount mod CacheThreshold) = 0 then
+ begin
+ // New cache entry to set up.
+ with FPositionCache[Index] do
+ begin
+ Node := CurrentNode;
+ AbsoluteTop := CurrentTop;
+ end;
+ Inc(Index);
+ end;
+
+ Inc(CurrentTop, CurrentNode.NodeHeight);
+ // Advance to next visible node.
+ Temp := GetNextVisibleNoInit(CurrentNode);
+ // If there is no further node or the cache is full then stop the loop.
+ if (Temp = nil) or (Integer(Index) = Length(FPositionCache)) then
+ Break;
+
+ CurrentNode := Temp;
+ Inc(EntryCount);
+ end;
+ end;
+ // Finalize the position cache so no nil entry remains there.
+ if not (tsStopValidation in FStates) and (Integer(Index) <= High(FPositionCache)) then
+ begin
+ SetLength(FPositionCache, Index + 1);
+ with FPositionCache[Index] do
+ begin
+ Node := CurrentNode;
+ AbsoluteTop := CurrentTop;
+ end;
+ end;
+ end;
+ end;
+
+ Result := EntryCount > 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DragCanceled;
+
+// Does some housekeeping for VCL drag'n drop;
+
+begin
+ inherited;
+
+ DragFinished;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DragDrop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult;
+
+var
+ Shift: TShiftState;
+ EnumFormat: IEnumFormatEtc;
+ Fetched: Integer;
+ OLEFormat: TFormatEtc;
+ Formats: TFormatArray;
+
+begin
+ StopTimer(ExpandTimer);
+ StopTimer(ScrollTimer);
+ DoStateChange([], [tsScrollPending, tsScrolling]);
+ Formats := nil;
+
+ // Ask explicitly again whether the action is allowed. Otherwise we may accept a drop which is intentionally not
+ // allowed but cannot be prevented by the application because when the tree was scrolling while dropping
+ // no DragOver event is created by the OLE subsystem.
+ Result := DragOver(DragManager.DragSource, KeyState, dsDragMove, Pt, Effect);
+ try
+ if (Result <> NOERROR) or ((Effect and not DROPEFFECT_SCROLL) = DROPEFFECT_NONE) then
+ Result := E_FAIL
+ else
+ begin
+ try
+ Shift := KeysToShiftState(KeyState);
+ Pt := ScreenToClient(Pt);
+ // Determine which formats we can get and pass them along with the data object to the drop handler.
+ Result := DataObject.EnumFormatEtc(DATADIR_GET, EnumFormat);
+ if Failed(Result) then
+ Abort;
+ Result := EnumFormat.Reset;
+ if Failed(Result) then
+ Abort;
+ // create a list of available formats
+ while EnumFormat.Next(1, OLEFormat, @Fetched) = S_OK do
+ begin
+ SetLength(Formats, Length(Formats) + 1);
+ Formats[High(Formats)] := OLEFormat.cfFormat;
+ end;
+ DoDragDrop(DragManager.DragSource, DataObject, Formats, Shift, Pt, Effect, FLastDropMode);
+ except
+ Result := E_UNEXPECTED;
+ raise;
+ end;
+ end;
+ finally
+ if Assigned(FDropTargetNode) then
+ begin
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := nil;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DragEnter(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult;
+
+// callback routine for the drop target interface
+
+var
+ Shift: TShiftState;
+ Accept: Boolean;
+ R: TRect;
+ HitInfo: THitInfo;
+
+begin
+ try
+ // Determine acceptance of drag operation and reset scroll start time.
+ FDragScrollStart := 0;
+
+ Shift := KeysToShiftState(KeyState);
+ Pt := ScreenToClient(Pt);
+ Effect := SuggestDropEffect(DragManager.DragSource, Shift, Pt, Effect);
+ Accept := DoDragOver(DragManager.DragSource, Shift, dsDragEnter, Pt, FLastDropMode, Effect);
+ if not Accept then
+ Effect := DROPEFFECT_NONE
+ else
+ begin
+ // Set initial drop target node and drop mode.
+ GetHitTestInfoAt(Pt.X, Pt.Y, True, HitInfo);
+ if Assigned(HitInfo.HitNode) then
+ begin
+ FDropTargetNode := HitInfo.HitNode;
+ R := GetDisplayRect(HitInfo.HitNode, FHeader.MainColumn, False);
+ if hiOnItemLabel in HitInfo.HitPositions then
+ FLastDropMode := dmOnNode
+ else
+ if ((R.Top + R.Bottom) div 2) > Pt.Y then
+ FLastDropMode := dmAbove
+ else
+ FLastDropMode := dmBelow;
+ end
+ else
+ FLastDropMode := dmNowhere;
+ end;
+
+ // If the drag source is a virtual tree then we know how to control the drag image
+ // and can show it even if the source is not the target tree.
+ // This is only necessary if we cannot use the drag image helper interfaces.
+ if not DragManager.DropTargetHelperSupported and Assigned(DragManager.DragSource) then
+ DragManager.DragSource.FDragImage.ShowDragImage;
+ Result := NOERROR;
+ except
+ Result := E_UNEXPECTED;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DragFinished;
+
+// Called by DragCancelled or EndDrag to make up for the still missing mouse button up messages.
+// These are important for such important things like popup menus.
+
+var
+ P: TPoint;
+
+begin
+ GetCursorPos(P);
+ P := ScreenToClient(P);
+ if tsRightButtonDown in FStates then
+ Perform(WM_RBUTTONUP, 0, Longint(PointToSmallPoint(P)))
+ else
+ if tsMiddleButtonDown in FStates then
+ Perform(WM_MBUTTONUP, 0, Longint(PointToSmallPoint(P)))
+ else
+ Perform(WM_LBUTTONUP, 0, Longint(PointToSmallPoint(P)));
+ DoStateChange([], [tsVCLDragPending, tsVCLDragging, tsUserDragObject]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DragLeave;
+
+var
+ Effect: Integer;
+
+begin
+ StopTimer(ExpandTimer);
+
+ if not DragManager.DropTargetHelperSupported and Assigned(DragManager.DragSource) then
+ DragManager.DragSource.FDragImage.HideDragImage;
+
+ if Assigned(FDropTargetNode) then
+ begin
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := nil;
+ end;
+ UpdateWindow(Handle);
+
+ Effect := 0;
+ DoDragOver(nil, [], dsDragLeave, Point(0, 0), FLastDropMode, Effect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DragOver(Source: TObject; KeyState: Integer; DragState: TDragState; Pt: TPoint;
+ var Effect: Integer): HResult;
+
+// callback routine for the drop target interface
+
+var
+ Shift: TShiftState;
+ Accept,
+ DragImageWillMove,
+ WindowScrolled: Boolean;
+ OldR, R: TRect;
+ NewDropMode: TDropMode;
+ HitInfo: THitInfo;
+ ImageHit: Boolean;
+ LabelHit: Boolean;
+ DragPos: TPoint;
+ Tree: TBaseVirtualTree;
+ LastNode: PVirtualNode;
+
+ DeltaX,
+ DeltaY: Integer;
+ ScrollOptions: TScrollUpdateOptions;
+
+begin
+ if not DragManager.DropTargetHelperSupported and (Source is TBaseVirtualTree) then
+ begin
+ Tree := Source as TBaseVirtualTree;
+ ScrollOptions := [suoUpdateNCArea];
+ end
+ else
+ begin
+ Tree := nil;
+ ScrollOptions := DefaultScrollUpdateFlags;
+ end;
+
+ try
+ DragPos := Pt;
+ Pt := ScreenToClient(Pt);
+
+ // Check if we have to scroll the client area.
+ FScrollDirections := DetermineScrollDirections(Pt.X, Pt.Y);
+ DeltaX := 0;
+ DeltaY := 0;
+ if FScrollDirections <> [] then
+ begin
+ // Determine amount to scroll.
+ if sdUp in FScrollDirections then
+ begin
+ DeltaY := Min(FScrollBarOptions.FIncrementY, ClientHeight);
+ if FOffsetY = 0 then
+ Exclude(FScrollDirections, sdUp);
+ end;
+ if sdDown in FScrollDirections then
+ begin
+ DeltaY := -Min(FScrollBarOptions.FIncrementY, ClientHeight);
+ if (ClientHeight - FOffsetY) = Integer(FRangeY) then
+ Exclude(FScrollDirections, sdDown);
+ end;
+ if sdLeft in FScrollDirections then
+ begin
+ DeltaX := FScrollBarOptions.FIncrementX;
+ if FOffsetX = 0 then
+ Exclude(FScrollDirections, sdleft);
+ end;
+ if sdRight in FScrollDirections then
+ begin
+ DeltaX := -FScrollBarOptions.FIncrementX;
+ if (ClientWidth - FOffsetX) = Integer(FRangeX) then
+ Exclude(FScrollDirections, sdRight);
+ end;
+ WindowScrolled := DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), ScrollOptions, nil);
+ end
+ else
+ WindowScrolled := False;
+
+ // Determine acceptance of drag operation as well as drag target.
+ Shift := KeysToShiftState(KeyState);
+ GetHitTestInfoAt(Pt.X, Pt.Y, True, HitInfo);
+ ImageHit := HitInfo.HitPositions * [hiOnNormalIcon, hiOnStateIcon] <> [];
+ LabelHit := hiOnItemLabel in HitInfo.HitPositions;
+ // In report mode only direct hits of the node captions/images in the main column are accepted as hits.
+ if (toReportMode in FOptions.MiscOptions) and not ((LabelHit or ImageHit) and
+ (HitInfo.HitColumn = FHeader.MainColumn)) then
+ HitInfo.HitNode := nil;
+
+ if Assigned(HitInfo.HitNode) then
+ begin
+ R := GetDisplayRect(HitInfo.HitNode, NoColumn, False);
+ if LabelHit or ImageHit or not (toShowDropmark in FOptions.FPaintOptions) then
+ NewDropMode := dmOnNode
+ else
+ if ((R.Top + R.Bottom) div 2) > Pt.Y then
+ NewDropMode := dmAbove
+ else
+ NewDropMode := dmBelow;
+ end
+ else
+ begin
+ NewDropMode := dmNowhere;
+ R := Rect(0, 0, 0, 0);
+ end;
+
+ if Assigned(Tree) then
+ DragImageWillMove := Tree.FDragImage.WillMove(DragPos)
+ else
+ DragImageWillMove := False;
+
+ if (HitInfo.HitNode <> FDropTargetNode) or (FLastDropMode <> NewDropMode) then
+ begin
+ // Something in the tree will change. This requires to update the screen and/or the drag image.
+ FLastDropMode := NewDropMode;
+ if HitInfo.HitNode <> FDropTargetNode then
+ begin
+ StopTimer(ExpandTimer);
+ // The last target node is needed for the rectangle determination but must already be set for
+ // the recapture call, hence it must be stored somewhere.
+ LastNode := FDropTargetNode;
+ FDropTargetNode := HitInfo.HitNode;
+ // In order to show a selection rectangle a column must be focused.
+ if FFocusedColumn = NoColumn then
+ FFocusedColumn := FHeader.MainColumn;
+
+ if Assigned(LastNode) and Assigned(FDropTargetNode) then
+ begin
+ // Optimize the case that the selection moved between two nodes.
+ OldR := GetDisplayRect(LastNode, NoColumn, False);
+ UnionRect(R, R, OldR);
+ if Assigned(Tree) then
+ begin
+ if WindowScrolled then
+ UpdateWindowAndDragImage(Tree, ClientRect, True, not DragImageWillMove)
+ else
+ UpdateWindowAndDragImage(Tree, R, False, not DragImageWillMove);
+ end
+ else
+ InvalidateRect(Handle, @R, False);
+ end
+ else
+ begin
+ if Assigned(LastNode) then
+ begin
+ // Repaint last target node.
+ OldR := GetDisplayRect(LastNode, NoColumn, False);
+ if Assigned(Tree) then
+ begin
+ if WindowScrolled then
+ UpdateWindowAndDragImage(Tree, ClientRect, WindowScrolled, not DragImageWillMove)
+ else
+ UpdateWindowAndDragImage(Tree, OldR, False, not DragImageWillMove);
+ end
+ else
+ InvalidateRect(Handle, @OldR, False);
+ end
+ else
+ begin
+ if Assigned(Tree) then
+ begin
+ if WindowScrolled then
+ UpdateWindowAndDragImage(Tree, ClientRect, WindowScrolled, not DragImageWillMove)
+ else
+ UpdateWindowAndDragImage(Tree, R, False, not DragImageWillMove);
+ end
+ else
+ InvalidateRect(Handle, @R, False);
+ end;
+ end;
+
+ // Start auto expand timer if necessary.
+ if (toAutoDropExpand in FOptions.FAutoOptions) and Assigned(FDropTargetNode) and
+ (vsHasChildren in FDropTargetNode.States) then
+ SetTimer(Handle, ExpandTimer, FAutoExpandDelay, nil);
+ end
+ else
+ begin
+ // Only the drop mark position changed so invalidate the current drop target node.
+ if Assigned(Tree) then
+ begin
+ if WindowScrolled then
+ UpdateWindowAndDragImage(Tree, ClientRect, WindowScrolled, not DragImageWillMove)
+ else
+ UpdateWindowAndDragImage(Tree, R, False, not DragImageWillMove);
+ end
+ else
+ InvalidateRect(Handle, @R, False);
+ end;
+ end
+ else
+ begin
+ // No change in the current drop target or drop mode. This might still mean horizontal or vertical scrolling.
+ if Assigned(Tree) and ((DeltaX <> 0) or (DeltaY <> 0)) then
+ UpdateWindowAndDragImage(Tree, ClientRect, WindowScrolled, not DragImageWillMove);
+ end;
+
+ Update;
+
+ if Assigned(Tree) and DragImageWillMove then
+ Tree.FDragImage.DragTo(DragPos, False);
+
+ Effect := SuggestDropEffect(Source, Shift, Pt, Effect);
+ Accept := DoDragOver(Source, Shift, DragState, Pt, FLastDropMode, Effect);
+ if not Accept then
+ Effect := DROPEFFECT_NONE;
+ if WindowScrolled then
+ Effect := Effect or Integer(DROPEFFECT_SCROLL);
+ Result := NOERROR;
+ except
+ Result := E_UNEXPECTED;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DrawDottedHLine(const PaintInfo: TVTPaintInfo; Left, Right, Top: Integer);
+
+// Draws a horizontal line with alternating pixels (this style is not supported for pens under Win9x).
+
+var
+ R: TRect;
+
+begin
+ with PaintInfo, Canvas do
+ begin
+ Brush.Color := Color;
+ R := Rect(Min(Left, Right), Top, Max(Left, Right) + 1, Top + 1);
+ Windows.FillRect(Handle, R, FDottedBrush);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DrawDottedVLine(const PaintInfo: TVTPaintInfo; Top, Bottom, Left: Integer);
+
+// Draws a horizontal line with alternating pixels (this style is not supported for pens under Win9x).
+
+var
+ R: TRect;
+
+begin
+ with PaintInfo, Canvas do
+ begin
+ Brush.Color := Color;
+ R := Rect(Left, Min(Top, Bottom), Left + 1, Max(Top, Bottom) + 1);
+ Windows.FillRect(Handle, R, FDottedBrush);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.FindNodeInSelection(P: PVirtualNode; var Index: Integer; LowBound,
+ HighBound: Integer): Boolean;
+
+// Search routine to find a specific node in the selection array.
+// LowBound and HighBound determine the range in which to search the node.
+// Either value can be -1 to denote the maximum range otherwise LowBound must be less or equal HighBound.
+
+var
+ L, H,
+ I, C: Integer;
+
+begin
+ Result := False;
+ L := 0;
+ if LowBound >= 0 then
+ L := LowBound;
+ H := FSelectionCount - 1;
+ if HighBound >= 0 then
+ H := HighBound;
+ while L <= H do
+ begin
+ I := (L + H) shr 1;
+ C := Integer(FSelection[I]) - Integer(P);
+ if C < 0 then
+ L := I + 1
+ else
+ begin
+ H := I - 1;
+ if C = 0 then
+ begin
+ Result := True;
+ L := I;
+ end;
+ end;
+ end;
+ Index := L;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FinishChunkHeader(Stream: TStream; StartPos, EndPos: Integer);
+
+// used while streaming out a node to finally write out the size of the chunk
+
+var
+ Size: Integer;
+
+begin
+ // seek back to the second entry in the chunk header
+ Stream.Position := StartPos + SizeOf(Integer);
+ // determine size of chunk without the chunk header
+ Size := EndPos - StartPos - SizeOf(TChunkHeader);
+ // write the size...
+ Stream.Write(Size, SizeOf(Size));
+ // ... and seek to the last endposition
+ Stream.Position := EndPos;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FontChanged(AFont: TObject);
+
+// Little helper function for font changes (as they are not tracked in TBitmap/TCanvas.OnChange).
+
+begin
+ FFontChanged := True;
+ FOldFontChange(AFont);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetCheckImage(Node: PVirtualNode): Integer;
+
+// Determines the index into the check image list for the given node depending on the check type
+// and enabled state.
+
+const
+ // Four dimensional array consisting of image indices for the check type, the check state, the enabled state and the
+ // hot state.
+ CheckStateToCheckImage: array[ctCheckBox..ctButton, csUncheckedNormal..csMixedPressed, Boolean, Boolean] of Integer = (
+ // ctCheckBox, ctTriStateCheckBox
+ (
+ // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckCheckUncheckedDisabled, ckCheckUncheckedDisabled), (ckCheckUncheckedNormal, ckCheckUncheckedHot)),
+ // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckCheckUncheckedDisabled, ckCheckUncheckedDisabled), (ckCheckUncheckedPressed, ckCheckUncheckedPressed)),
+ // csCheckedNormal
+ ((ckCheckCheckedDisabled, ckCheckCheckedDisabled), (ckCheckCheckedNormal, ckCheckCheckedHot)),
+ // csCheckedPressed
+ ((ckCheckCheckedDisabled, ckCheckCheckedDisabled), (ckCheckCheckedPressed, ckCheckCheckedPressed)),
+ // csMixedNormal
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)),
+ // csMixedPressed
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed))
+ ),
+ // ctRadioButton
+ (
+ // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckRadioUncheckedDisabled, ckRadioUncheckedDisabled), (ckRadioUncheckedNormal, ckRadioUncheckedHot)),
+ // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckRadioUncheckedDisabled, ckRadioUncheckedDisabled), (ckRadioUncheckedPressed, ckRadioUncheckedPressed)),
+ // csCheckedNormal
+ ((ckRadioCheckedDisabled, ckRadioCheckedDisabled), (ckRadioCheckedNormal, ckRadioCheckedHot)),
+ // csCheckedPressed
+ ((ckRadioCheckedDisabled, ckRadioCheckedDisabled), (ckRadioCheckedPressed, ckRadioCheckedPressed)),
+ // csMixedNormal (should never appear with ctRadioButton)
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)),
+ // csMixedPressed (should never appear with ctRadioButton)
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed))
+ ),
+ // ctButton
+ (
+ // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckButtonDisabled, ckButtonDisabled), (ckButtonNormal, ckButtonHot)),
+ // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckButtonDisabled, ckButtonDisabled), (ckButtonPressed, ckButtonPressed)),
+ // csCheckedNormal
+ ((ckButtonDisabled, ckButtonDisabled), (ckButtonNormal, ckButtonHot)),
+ // csCheckedPressed
+ ((ckButtonDisabled, ckButtonDisabled), (ckButtonPressed, ckButtonPressed)),
+ // csMixedNormal (should never appear with ctButton)
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)),
+ // csMixedPressed (should never appear with ctButton)
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed))
+ )
+ );
+
+var
+ AType: TCheckType;
+
+begin
+ if Node.CheckType = ctNone then
+ Result := -1
+ else
+ begin
+ AType := Node.CheckType;
+ if AType = ctTriStateCheckBox then
+ AType := ctCheckBox;
+ Result := CheckStateToCheckImage[AType, Node.CheckState, not (vsDisabled in Node.States) and Enabled,
+ Node = FCurrentHotNode];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetColumnClass: TVirtualTreeColumnClass;
+
+begin
+ Result := TVirtualTreeColumn;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetHeaderClass: TVTHeaderClass;
+
+begin
+ Result := TVTHeader;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean): Integer;
+
+begin
+ Result := -1;
+ Ghosted := False;
+ DoGetImageIndex(Node, Kind, Column, Ghosted, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetMaxRightExtend: Cardinal;
+
+// Determines the maximum with of the currently visible part of the tree, depending on the length
+// of the node texts. This method is used for determining the horizontal scroll range if no columns are used.
+
+var
+ Node,
+ NextNode: PVirtualNode;
+ TopPosition: Integer;
+ NodeLeft,
+ CurrentWidth: Integer;
+ WithCheck: Boolean;
+ CheckOffset: Integer;
+
+begin
+ Node := GetNodeAt(0, 0, True, TopPosition);
+ Result := 0;
+ if toShowRoot in FOptions.FPaintOptions then
+ NodeLeft := (GetNodeLevel(Node) + 1) * FIndent
+ else
+ NodeLeft := GetNodeLevel(Node) * FIndent;
+
+ if Assigned(FStateImages) then
+ Inc(NodeLeft, FStateImages.Width + 2);
+ if Assigned(FImages) then
+ Inc(NodeLeft, FImages.Width + 2);
+ WithCheck := (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages);
+ if WithCheck then
+ CheckOffset := FCheckImages.Width + 2
+ else
+ CheckOffset := 0;
+
+ while Assigned(Node) do
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ if WithCheck and (Node.CheckType <> ctNone) then
+ Inc(NodeLeft, CheckOffset);
+ CurrentWidth := DoGetNodeWidth(Node, NoColumn);
+ if Integer(Result) < (NodeLeft + CurrentWidth) then
+ Result := NodeLeft + CurrentWidth;
+ Inc(TopPosition, Node.NodeHeight);
+ if TopPosition > Height then
+ Break;
+
+ if WithCheck and (Node.CheckType <> ctNone) then
+ Dec(NodeLeft, CheckOffset);
+
+ // Get next visible node and update left node position.
+ NextNode := GetNextVisible(Node);
+ if NextNode = nil then
+ Break;
+ Inc(NodeLeft, CountLevelDifference(Node, NextNode) * Integer(FIndent));
+ Node := NextNode;
+ end;
+
+ Inc(Result, 2 * FMargin);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.GetNativeClipboardFormats(var Formats: TFormatEtcArray);
+
+// Returns the supported clipboard formats of the tree.
+
+begin
+ InternalClipboardFormats.EnumerateFormats(TVirtualTreeClass(ClassType), Formats, FClipboardFormats);
+ // Ask application/descentants for self defined formats.
+ DoGetUserClipboardFormats(Formats);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TCustomVirtualTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect;
+ var Text: WideString);
+
+// Generic base method for editors, hint windows etc. to get some info about a node.
+
+begin
+ R := Rect(0, 0, 0, 0);
+ Text := '';
+ AFont.Assign(Font);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetTreeFromDataObject(const DataObject: IDataObject): TBaseVirtualTree;
+
+// Returns the owner/sender of the given data object by means of a special clipboard format
+// or nil if the sender is in another process or no virtual tree at all.
+
+var
+ Medium: TStgMedium;
+ Data: PVTReference;
+
+begin
+ Result := nil;
+ if Assigned(DataObject) then
+ begin
+ StandardOLEFormat.cfFormat := CF_VTREFERENCE;
+ if DataObject.GetData(StandardOLEFormat, Medium) = S_OK then
+ begin
+ Data := GlobalLock(Medium.hGlobal);
+ if Assigned(Data) then
+ begin
+ if Data.Process = GetCurrentProcessID then
+ Result := Data.Tree;
+ GlobalUnlock(Medium.hGlobal);
+ end;
+ ReleaseStgMedium(Medium);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleHotTrack(X, Y: Integer);
+
+// Updates the current "hot" node.
+
+var
+ HitInfo: THitInfo;
+ DoInvalidate: Boolean;
+
+begin
+ // Get information about the hit.
+ GetHitTestInfoAt(X, Y, True, HitInfo);
+ // Only make the new node being "hot" if its label is hit or full row selection is enabled.
+ if ([hiOnItemLabel, hiOnItemCheckbox] * HitInfo.HitPositions = []) and
+ not (toFullRowSelect in FOptions.FSelectionOptions) then
+ HitInfo.HitNode := nil;
+ if HitInfo.HitNode <> FCurrentHotNode then
+ begin
+ DoInvalidate := (toHotTrack in FOptions.PaintOptions) or (toCheckSupport in FOptions.MiscOptions);
+ DoHotChange(FCurrentHotNode, HitInfo.HitNode);
+ if Assigned(FCurrentHotNode) and DoInvalidate then
+ InvalidateNode(FCurrentHotNode);
+ FCurrentHotNode := HitInfo.HitNode;
+ if Assigned(FCurrentHotNode) and DoInvalidate then
+ InvalidateNode(FCurrentHotNode);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleIncrementalSearch(CharCode: Word);
+
+var
+ Run, Stop: PVirtualNode;
+ GetNextNode: TGetNextNodeProc;
+ NewSearchText: WideString;
+ SingleLetter,
+ PreviousSearch: Boolean; // True if VK_BACK was sent.
+ SearchDirection: TVTSearchDirection;
+
+ //--------------- local functions -------------------------------------------
+
+ procedure SetupNavigation;
+
+ // If the search buffer is empty then we start searching with the next node after the last one, otherwise
+ // we continue with the last one. Node navigation function is set up too here, to avoid frequent checks.
+
+ var
+ FindNextNode: Boolean;
+
+ begin
+ FindNextNode := (Length(FSearchBuffer) = 0) or (Run = nil) or SingleLetter or PreviousSearch;
+ case FIncrementalSearch of
+ isVisibleOnly:
+ if SearchDirection = sdForward then
+ begin
+ GetNextNode := GetNextVisible;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetFirstVisible
+ else
+ begin
+ Run := GetNextVisible(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetFirstVisible;
+ end;
+ end;
+ end
+ else
+ begin
+ GetNextNode := GetPreviousVisible;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetLastVisible
+ else
+ begin
+ Run := GetPreviousVisible(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetLastVisible;
+ end;
+ end;
+ end;
+ isInitializedOnly:
+ if SearchDirection = sdForward then
+ begin
+ GetNextNode := GetNextNoInit;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetFirstNoInit
+ else
+ begin
+ Run := GetNextNoInit(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetFirstNoInit;
+ end;
+ end;
+ end
+ else
+ begin
+ GetNextNode := GetPreviousNoInit;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetLastNoInit
+ else
+ begin
+ Run := GetPreviousNoInit(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetLastNoInit;
+ end;
+ end;
+ end;
+ else
+ // isAll
+ if SearchDirection = sdForward then
+ begin
+ GetNextNode := GetNext;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetFirst
+ else
+ begin
+ Run := GetNext(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetFirst;
+ end;
+ end;
+ end
+ else
+ begin
+ GetNextNode := GetPrevious;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetLast
+ else
+ begin
+ Run := GetPrevious(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetLast;
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function CodePageFromLocale(Language: LCID): Integer;
+
+ // Determines the code page for a given locale.
+ // Unfortunately there is no easier way than this, currently.
+
+ var
+ Buf: array[0..6] of Char;
+
+ begin
+ GetLocaleInfo(Language, LOCALE_IDEFAULTANSICODEPAGE, Buf, 6);
+ Result := StrToIntDef(Buf, GetACP);
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function KeyUnicode(C: Char): WideChar;
+
+ // Converts the given character into its corresponding Unicode character
+ // depending on the active keyboard layout.
+
+ begin
+ MultiByteToWideChar(CodePageFromLocale(GetKeyboardLayout(0) and $FFFF),
+ MB_USEGLYPHCHARS, @C, 1, @Result, 1);
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ FoundMatch: Boolean;
+ NewChar: WideChar;
+
+begin
+ StopTimer(SearchTimer);
+
+ if FIncrementalSearch <> isNone then
+ begin
+ if CharCode <> 0 then
+ begin
+ DoStateChange([tsIncrementalSearching]);
+
+ // Convert the given virtual key code into a Unicode character based on the current locale.
+ NewChar := KeyUnicode(Char(CharCode));
+ PreviousSearch := NewChar = WideChar(VK_BACK);
+ // We cannot do a search with an empty search buffer.
+ if not PreviousSearch or (Length(FSearchBuffer) > 1) then
+ begin
+ // Determine which method to use to advance nodes and the start node to search from.
+ case FSearchStart of
+ ssAlwaysStartOver:
+ Run := nil;
+ ssFocusedNode:
+ Run := FFocusedNode;
+ else // ssLastHit
+ Run := FLastSearchNode;
+ end;
+
+ // Make sure the start node corresponds to the search criterion.
+ if Assigned(Run) then
+ begin
+ case FIncrementalSearch of
+ isInitializedOnly:
+ if not (vsInitialized in Run.States) then
+ Run := nil;
+ isVisibleOnly:
+ if not FullyVisible[Run] then
+ Run := nil;
+ end;
+ end;
+ Stop := Run;
+
+ // VK_BACK temporarily changes search direction to opposite mode.
+ if PreviousSearch then
+ begin
+ if SearchDirection = sdBackward then
+ SearchDirection := sdForward
+ else
+ SearchDirection := sdBackward
+ end
+ else
+ SearchDirection := FSearchDirection;
+ // The "single letter mode" is used to advance quickly from node to node when pressing the same key several times.
+ SingleLetter := (Length(FSearchBuffer) = 1) and not PreviousSearch and (FSearchBuffer[1] = NewChar);
+ SetupNavigation;
+ FoundMatch := False;
+
+ if Assigned(Run) then
+ begin
+ if SingleLetter then
+ NewSearchText := FSearchBuffer
+ else
+ if PreviousSearch then
+ begin
+ SetLength(FSearchBuffer, Length(FSearchBuffer) - 1);
+ NewSearchText := FSearchBuffer;
+ end
+ else
+ NewSearchText := FSearchBuffer + NewChar;
+
+ repeat
+ if DoIncrementalSearch(Run, NewSearchText) = 0 then
+ begin
+ FoundMatch := True;
+ Break;
+ end;
+
+ // Advance to next node if we have not found a match.
+ Run := GetNextNode(Run);
+ // Do wrap around start or end of tree.
+ if (Run <> Stop) and (Run = nil) then
+ SetupNavigation;
+ until Run = Stop;
+ end;
+
+ if FoundMatch then
+ begin
+ ClearSelection;
+ FSearchBuffer := NewSearchText;
+ FLastSearchNode := Run;
+ FocusedNode := Run;
+ Selected[Run] := True;
+ FLastSearchNode := Run;
+ end
+ else
+ // Play an acoustic signal if nothing could be found but don't beep if only the currently
+ // focused node matches.
+ if Assigned(Run) and (DoIncrementalSearch(Run, NewSearchText) <> 0) then
+ Beep;
+ end;
+ end;
+
+ // Restart search timeout interval.
+ SetTimer(Handle, SearchTimer, FSearchTimeout, nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleMouseDblClick(var Message: TWMMouse; const HitInfo: THitInfo);
+
+var
+ NewCheckState: TCheckState;
+
+begin
+ if tsEditPending in FStates then
+ begin
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ end;
+
+ if not (tsEditing in FStates) or DoEndEdit then
+ begin
+ if HitInfo.HitColumn = FHeader.FColumns.FClickIndex then
+ DoColumnDblClick(HitInfo.HitColumn, KeysToShiftState(Message.Keys));
+
+ if hiOnItemCheckBox in HitInfo.HitPositions then
+ begin
+ if (FStates * [tsMouseCheckPending, tsKeyCheckPending] = []) and not (vsDisabled in HitInfo.HitNode.States) then
+ begin
+ with HitInfo.HitNode^ do
+ NewCheckState := DetermineNextCheckState(CheckType, CheckState);
+ if DoChecking(HitInfo.HitNode, NewCheckState) then
+ begin
+ DoStateChange([tsMouseCheckPending]);
+ FCheckNode := HitInfo.HitNode;
+ FPendingCheckState := NewCheckState;
+ FCheckNode.CheckState := PressedState[FCheckNode.CheckState];
+ InvalidateNode(HitInfo.HitNode);
+ end;
+ end;
+ end
+ else
+ begin
+ if hiOnItemButton in HitInfo.HitPositions then
+ ToggleNode(HitInfo.HitNode)
+ else
+ begin
+ if toToggleOnDblClick in FOptions.FMiscOptions then
+ begin
+ if ((([hiOnItemButton, hiOnItemLabel, hiOnNormalIcon, hiOnStateIcon] * HitInfo.HitPositions) <> []) or
+ ((toFullRowSelect in FOptions.FSelectionOptions) and Assigned(HitInfo.HitNode))) then
+ ToggleNode(HitInfo.HitNode);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleMouseDown(var Message: TWMMouse; const HitInfo: THitInfo);
+
+// centralized mouse button down handling
+
+var
+ LastFocused: PVirtualNode;
+ Column: TColumnIndex;
+ ShiftState: TShiftState;
+
+ // helper variables to shorten boolean equations/expressions
+ AutoDrag, // automatic (or allowed) drag start
+ IsHit, // the node's caption or images are hit
+ IsCellHit, // for grid extension or full row select (but not check box, button)
+ IsAnyHit, // either IsHit or IsCellHit
+ MultiSelect, // multiselection is enabled
+ ShiftEmpty, // ShiftState = []
+ NodeSelected: Boolean; // the new node (if any) is selected
+ NewColumn: Boolean; // column changed
+ NeedChange: Boolean; // change event is required for selection change
+ CanClear: Boolean;
+ NewCheckState: TCheckState;
+
+begin
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ StopWheelPanning;
+ Exit;
+ end;
+
+ if tsEditPending in FStates then
+ begin
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ end;
+
+ if not (tsEditing in FStates) or DoEndEdit then
+ begin
+ // Keep clicked column in case the application needs it.
+ FHeader.FColumns.FClickIndex := HitInfo.HitColumn;
+
+ // Change column only if we have hit the node label.
+ if (hiOnItemLabel in HitInfo.HitPositions) or
+ (toFullRowSelect in FOptions.FSelectionOptions) or
+ (toGridExtensions in FOptions.FMiscOptions) then
+ begin
+ NewColumn := FFocusedColumn <> HitInfo.HitColumn;
+ if toExtendedFocus in FOptions.FSelectionOptions then
+ Column := HitInfo.HitColumn
+ else
+ Column := FHeader.MainColumn;
+ end
+ else
+ begin
+ NewColumn := False;
+ Column := FFocusedColumn;
+ end;
+
+ // Translate keys and filter out shift and control key.
+ ShiftState := KeysToShiftState(Message.Keys) * [ssShift, ssCtrl];
+
+ // Various combinations determine what states the tree enters now.
+ // We initialize shorthand variables to avoid the following expressions getting too large
+ // and to avoid repeative expensive checks.
+ IsHit := (hiOnItemLabel in HitInfo.HitPositions) or (hiOnNormalIcon in HitInfo.HitPositions);
+ IsCellHit := not IsHit and Assigned(HitInfo.HitNode) and
+ ([hiOnItemButton, hiOnItemCheckBox] * HitInfo.HitPositions = []) and
+ ((toFullRowSelect in FOptions.FSelectionOptions) or (toGridExtensions in FOptions.FMiscOptions));
+ IsAnyHit := IsHit or IsCellHit;
+ MultiSelect := toMultiSelect in FOptions.FSelectionOptions;
+ ShiftEmpty := ShiftState = [];
+ NodeSelected := IsAnyHit and (vsSelected in HitInfo.HitNode.States);
+
+ // Dragging might be started in the inherited handler manually (which is discouraged for stability reasons)
+ // the test for manual mode is done below (after the focused node is set).
+ AutoDrag := ((DragMode = dmAutomatic) or Dragging) and not IsCellHit;
+
+ // Query the application to learn if dragging may start now (if set to dmManual).
+ if Assigned(HitInfo.HitNode) and not AutoDrag and (DragMode = dmManual) then
+ AutoDrag := DoBeforeDrag(HitInfo.HitNode, Column) and not IsCellHit;
+
+ // handle button clicks
+ if (hiOnItemButton in HitInfo.HitPositions) and (vsHasChildren in HitInfo.HitNode.States) then
+ begin
+ ToggleNode(HitInfo.HitNode);
+ Exit;
+ end;
+
+ // check event
+ if hiOnItemCheckBox in HitInfo.HitPositions then
+ begin
+ if (FStates * [tsMouseCheckPending, tsKeyCheckPending] = []) and not (vsDisabled in HitInfo.HitNode.States) then
+ begin
+ with HitInfo.HitNode^ do
+ NewCheckState := DetermineNextCheckState(CheckType, CheckState);
+ if DoChecking(HitInfo.HitNode, NewCheckState) then
+ begin
+ DoStateChange([tsMouseCheckPending]);
+ FCheckNode := HitInfo.HitNode;
+ FPendingCheckState := NewCheckState;
+ FCheckNode.CheckState := PressedState[FCheckNode.CheckState];
+ InvalidateNode(HitInfo.HitNode);
+ end;
+ end;
+ Exit;
+ end;
+
+ // Keep this node's level in case we need it for constraint selection.
+ if (FRoot.ChildCount > 0) and ShiftEmpty or (FSelectionCount = 0) then
+ if Assigned(HitInfo.HitNode) then
+ FLastSelectionLevel := GetNodeLevel(HitInfo.HitNode)
+ else
+ FLastSelectionLevel := GetNodeLevel(GetLastVisibleNoInit);
+
+ // pending clearance
+ if MultiSelect and ShiftEmpty and not (hiOnItemCheckbox in HitInfo.HitPositions) and
+ (IsHit and ShiftEmpty and AutoDrag and NodeSelected) then
+ DoStateChange([tsClearPending]);
+
+ // immediate clearance
+ // Determine for the right mouse button if there is a popup menu. In this case and if drag'n drop is pending
+ // the current selection has to stay as it is.
+ with HitInfo, Message do
+ CanClear := not AutoDrag and
+ (not (tsRightButtonDown in FStates) or not HasPopupMenu(HitNode, HitColumn, Point(XPos, YPos)));
+ if (not IsAnyHit and MultiSelect and ShiftEmpty) or
+ (IsAnyHit and (not NodeSelected or (NodeSelected and CanClear)) and (ShiftEmpty or not MultiSelect)) then
+ begin
+ Assert(not (tsClearPending in FStates), 'Pending and direct clearance are mutual exclusive!');
+ if NodeSelected then
+ begin
+ // If the currently hit node is (also) selected then we have to reselect it again but without
+ // a change event if it is the only selected node.
+ NeedChange := FSelectionCount > 1;
+ InternalClearSelection;
+ InternalAddToSelection(HitInfo.HitNode, True);
+ if NeedChange then
+ begin
+ Invalidate;
+ Change(nil);
+ end;
+ end
+ else
+ ClearSelection;
+ end;
+
+ // pending node edit
+ if Focused and
+ ((hiOnItemLabel in HitInfo.HitPositions) or ((toGridExtensions in FOptions.FMiscOptions) and
+ (hiOnItem in HitInfo.HitPositions))) and NodeSelected and not NewColumn and ShiftEmpty then
+ DoStateChange([tsEditPending]);
+
+ // focus change
+ if not Focused and CanFocus then
+ SetFocus;
+
+ // User starts a selection with a selection rectangle.
+ if not (toDisableDrawSelection in FOptions.FSelectionOptions) and not IsHit and MultiSelect then
+ begin
+ SetCapture(Handle);
+ DoStateChange([tsDrawSelPending]);
+ FDrawSelShiftState := ShiftState;
+ FNewSelRect := Rect(Message.XPos - FOffsetX, Message.YPos - FOffsetY, Message.XPos - FOffsetX,
+ Message.YPos - FOffsetY);
+ FLastSelRect := FNewSelRect;
+ if not IsCellHit then
+ Exit;
+ end;
+
+ // Keep current mouse position.
+ FLastClickPos := Point(Message.XPos, Message.YPos);
+
+ // Handle selection and node focus change.
+ if (IsHit or IsCellHit) and
+ DoFocusChanging(FFocusedNode, HitInfo.HitNode, FFocusedColumn, Column) then
+ begin
+ if NewColumn then
+ begin
+ InvalidateColumn(FFocusedColumn);
+ InvalidateColumn(Column);
+ FFocusedColumn := Column;
+ end;
+ if DragKind = dkDock then
+ begin
+ StopTimer(ScrollTimer);
+ DoStateChange([], [tsScrollPending, tsScrolling]);
+ end;
+ // Get the currently focused node to make multiple multi-selection blocks possible.
+ LastFocused := FFocusedNode;
+ DoFocusNode(HitInfo.HitNode, False);
+
+ if MultiSelect and not Dragging and not ShiftEmpty then
+ HandleClickSelection(LastFocused, HitInfo.HitNode, ShiftState)
+ else
+ begin
+ if ShiftEmpty then
+ FRangeAnchor := HitInfo.HitNode;
+
+ // If the hit node is not yet selected then do it now.
+ if not NodeSelected then
+ AddToSelection(HitInfo.HitNode);
+ end;
+
+ DoFocusChange(FFocusedNode, FFocusedColumn);
+
+ // Drag'n drop initiation
+ // If we lost focus in the interim the button states would be cleared in WM_KILLFOCUS.
+ if AutoDrag and (FStates * [tsLeftButtonDown, tsRightButtonDown, tsMiddleButtonDown] <> []) then
+ BeginDrag(False);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleMouseUp(var Message: TWMMouse; const HitInfo: THitInfo);
+
+// Counterpart to the mouse down handler.
+
+var
+ ReselectFocusedNode: Boolean;
+
+begin
+ ReleaseCapture;
+
+ if not (tsVCLDragPending in FStates) then
+ begin
+ // reset pending or persistent states
+ if IsMouseSelecting then
+ begin
+ DoStateChange([], [tsDrawSelecting, tsDrawSelPending]);
+ Invalidate;
+ end;
+
+ if tsClearPending in FStates then
+ begin
+ ReselectFocusedNode := Assigned(FFocusedNode) and (vsSelected in FFocusedNode.States);
+ ClearSelection;
+ if ReselectFocusedNode then
+ AddToSelection(FFocusedNode);
+ end;
+
+ if (tsClearFocusedSelection in FStates) and Assigned(HitInfo.HitNode) then
+ begin
+ if vsSelected in HitInfo.HitNode.States then
+ RemoveFromSelection(HitInfo.HitNode)
+ else
+ AddToSelection(HitInfo.HitNode);
+ InvalidateNode(HitInfo.HitNode);
+ end;
+
+ DoStateChange([], [tsOLEDragPending, tsOLEDragging, tsClearPending, tsDrawSelPending, tsScrollPending,
+ tsScrolling, tsClearFocusedSelection]);
+ StopTimer(ScrollTimer);
+
+ if tsMouseCheckPending in FStates then
+ begin
+ DoStateChange([], [tsMouseCheckPending]);
+ // Is the mouse still over the same node?
+ if (HitInfo.HitNode = FCheckNode) and (hiOnItem in HitInfo.HitPositions) then
+ begin
+ ChangeCheckState(FCheckNode, FPendingCheckState);
+ DoCheckClick(FCheckNode, FPendingCheckState);
+ end
+ else
+ FCheckNode.CheckState := UnpressedState[FCheckNode.CheckState];
+ InvalidateNode(FCheckNode);
+ FCheckNode := nil;
+ end;
+
+ if (FHeader.FColumns.FClickIndex > NoColumn) and (FHeader.FColumns.FClickIndex = HitInfo.HitColumn) then
+ DoColumnClick(HitInfo.HitColumn, KeysToShiftState(Message.Keys));
+
+ // handle a pending edit event
+ if tsEditPending in FStates then
+ begin
+ // Is the mouse still over the same node?
+ if (HitInfo.HitNode = FFocusedNode) and (hiOnItem in HitInfo.HitPositions) and
+ CanEdit(FFocusedNode, HitInfo.HitColumn) then
+ begin
+ FEditColumn := FFocusedColumn;
+ SetTimer(Handle, EditTimer, FEditDelay, nil);
+ end
+ else
+ DoStateChange([], [tsEditPending]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.HasPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Pos: TPoint): Boolean;
+
+// Determines whether the tree got a popup menu, either in its PopupMenu property, via the OnGetPopupMenu event or
+// through inheritannce. The latter case must be checked by the descendant which must override this method.
+
+begin
+ Result := Assigned(PopupMenu) or Assigned(DoGetPopupMenu(Node, Column, Pos));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InitChildren(Node: PVirtualNode);
+
+// Initiates the initialization of the child number of the given node.
+
+var
+ Count: Cardinal;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and (vsHasChildren in Node.States) then
+ begin
+ Count := Node.ChildCount;
+ DoInitChildren(Node, Count);
+ if Count = 0 then
+ begin
+ // Remove any child node which is already there.
+ DeleteChildren(Node);
+ Exclude(Node.States, vsHasChildren);
+ end
+ else
+ SetChildCount(Node, Count);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InitNode(Node: PVirtualNode);
+
+// Initiates the initialization of the given node to allow the application to load needed data for it.
+
+var
+ InitStates: TVirtualNodeInitStates;
+
+begin
+ with Node^ do
+ begin
+ InitStates := [];
+ if Parent = FRoot then
+ DoInitNode(nil, Node, InitStates)
+ else
+ DoInitNode(Parent, Node, InitStates);
+ Include(States, vsInitialized);
+ if ivsDisabled in InitStates then
+ Include(States, vsDisabled);
+ if ivsHasChildren in InitStates then
+ Include(States, vsHasChildren);
+ if ivsSelected in InitStates then
+ begin
+ FSingletonNodeArray[0] := Node;
+ InternalAddToSelection(FSingletonNodeArray, 1, False);
+ end;
+ if ivsMultiline in InitStates then
+ Include(States, vsMultiline);
+
+ // Expanded may already be set (when called from ReinitNode) or be set in DoInitNode, allow both.
+ if (vsExpanded in Node.States) xor (ivsExpanded in InitStates) then
+ begin
+ // Expand node if not yet done (this will automatically initialize child nodes).
+ if ivsExpanded in InitStates then
+ ToggleNode(Node)
+ else
+ // If the node already was expanded then explicitly trigger child initialization.
+ if vsHasChildren in Node.States then
+ InitChildren(Node);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalAddFromStream(Stream: TStream; Version: Integer; Node: PVirtualNode);
+
+// Loads nodes from the given stream and adds them as children to Node.
+// Because the new nodes might be selected this method also fixes the selection array.
+
+var
+ Stop: PVirtualNode;
+ LastVisibleCount: Cardinal;
+ Index: Integer;
+
+begin
+ if Node = nil then
+ Node := FRoot;
+
+ // Read in the new nodes, keep number of visible nodes for a correction.
+ LastVisibleCount := FVisibleCount;
+ ReadNode(Stream, Version, Node);
+
+ // I need to fix the visible count here because of the hierarchical load procedure.
+ if (Node = FRoot) or ([vsExpanded, vsVisible] * Node.Parent.States = [vsExpanded, vsVisible]) then
+ FVisibleCount := LastVisibleCount + CountVisibleChildren(Node)
+ else
+ FVisibleCount := LastVisibleCount;
+
+ // Fix selection array.
+ ClearTempCache;
+ if Node = FRoot then
+ Stop := nil
+ else
+ Stop := Node.NextSibling;
+
+ if toMultiSelect in FOptions.FSelectionOptions then
+ begin
+ // Add all nodes which were selected before to the current selection (unless they are already there).
+ while Node <> Stop do
+ begin
+ if (vsSelected in Node.States) and not FindNodeInSelection(Node, Index, 0, High(FSelection)) then
+ InternalCacheNode(Node);
+ Node := GetNextNoInit(Node);
+ end;
+ if FTempNodeCount > 0 then
+ AddToSelection(FTempNodeCache, FTempNodeCount, True);
+ ClearTempCache;
+ end
+ else // No further selected nodes allowed so delete the corresponding flag in all new nodes.
+ while Node <> Stop do
+ begin
+ Exclude(Node.States, vsSelected);
+ Node := GetNextNoInit(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InternalAddToSelection(Node: PVirtualNode; ForceInsert: Boolean): Boolean;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil!');
+ FSingletonNodeArray[0] := Node;
+ Result := InternalAddToSelection(FSingletonNodeArray, 1, ForceInsert);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InternalAddToSelection(const NewItems: TNodeArray; NewLength: Integer;
+ ForceInsert: Boolean): Boolean;
+
+// Internal version of method AddToSelection which does not trigger OnChange events
+
+var
+ I, J: Integer;
+ CurrentEnd: Integer;
+ Constrained,
+ SiblingConstrained: Boolean;
+
+begin
+ // The idea behind this code is to use a kind of reverse merge sort. QuickSort is quite fast
+ // and would do the job here too but has a serious problem with already sorted lists like FSelection.
+
+ // 1) Remove already selected items, mark all other as being selected.
+ if ForceInsert then
+ begin
+ for I := 0 to NewLength - 1 do
+ Include(NewItems[I].States, vsSelected);
+ end
+ else
+ begin
+ Constrained := toLevelSelectConstraint in FOptions.FSelectionOptions;
+ if Constrained and (FLastSelectionLevel = -1) then
+ FLastSelectionLevel := GetNodeLevel(NewItems[0]);
+ SiblingConstrained := toSiblingSelectConstraint in FOptions.FSelectionOptions;
+ if SiblingConstrained and (FRangeAnchor = nil) then
+ FRangeAnchor := NewItems[0];
+
+ for I := 0 to NewLength - 1 do
+ if ([vsSelected, vsDisabled] * NewItems[I].States <> []) or
+ (Constrained and (Cardinal(FLastSelectionLevel) <> GetNodeLevel(NewItems[I]))) or
+ (SiblingConstrained and (FRangeAnchor.Parent <> NewItems[I].Parent)) then
+ Inc(Cardinal(NewItems[I]))
+ else
+ Include(NewItems[I].States, vsSelected);
+ end;
+
+ I := PackArray(NewItems, NewLength);
+ if I > -1 then
+ NewLength := I;
+
+ Result := NewLength > 0;
+ if Result then
+ begin
+ // 2) Sort the new item list so we can easily traverse it.
+ if NewLength > 1 then
+ QuickSort(NewItems, 0, NewLength - 1);
+ // 3) Make room in FSelection for the new items.
+ if FSelectionCount + NewLength >= Length(FSelection) then
+ SetLength(FSelection, FSelectionCount + NewLength);
+
+ // 4) Merge in new items
+ J := NewLength - 1;
+ CurrentEnd := FSelectionCount - 1;
+
+ while J >= 0 do
+ begin
+ // First insert all new entries which are greater than the greatest entry in the old list.
+ // If the current end marker is < 0 then there's nothing more to move in the selection
+ // array and only the remaining new items must be inserted.
+ if CurrentEnd >= 0 then
+ begin
+ while (J >= 0) and (Cardinal(NewItems[J]) > Cardinal(FSelection[CurrentEnd])) do
+ begin
+ FSelection[CurrentEnd + J + 1] := NewItems[J];
+ Dec(J);
+ end;
+ // early out if nothing more needs to be copied
+ if J < 0 then
+ Break;
+ end
+ else
+ begin
+ // insert remaining new entries at position 0
+ Move(NewItems[0], FSelection[0], (J + 1) * SizeOf(Pointer));
+ // nothing more to do so exit main loop
+ Break;
+ end;
+
+ // find the last entry in the remaining selection list which is smaller then the largest
+ // entry in the remaining new items list
+ FindNodeInSelection(NewItems[J], I, 0, CurrentEnd);
+ Dec(I);
+ // move all entries which are greater than the greatest entry in the new items list up
+ // so the remaining gap travels down to where new items must be inserted
+ Move(FSelection[I + 1], FSelection[I + J + 2], (CurrentEnd - I) * SizeOf(Pointer));
+ CurrentEnd := I;
+ end;
+
+ Inc(FSelectionCount, NewLength);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalCacheNode(Node: PVirtualNode);
+
+// Adds the given node to the temporary node cache (used when collecting possibly large amounts of nodes).
+
+var
+ Len: Cardinal;
+
+begin
+ Len := Length(FTempNodeCache);
+ if FTempNodeCount = Len then
+ begin
+ if Len < 100 then
+ Len := 100
+ else
+ Len := Len + Len div 10;
+ SetLength(FTempNodeCache, Len);
+ end;
+ FTempNodeCache[FTempNodeCount] := Node;
+ Inc(FTempNodeCount);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalClearSelection;
+
+var
+ Count: Integer;
+
+begin
+ // It is possible that there are invalid node references in the selection array
+ // if the tree update is locked and changes in the structure were made.
+ // Handle this potentially dangerous situation by packing the selection array explicitely.
+ if FUpdateCount > 0 then
+ begin
+ Count := PackArray(FSelection, FSelectionCount);
+ if Count > -1 then
+ begin
+ FSelectionCount := Count;
+ SetLength(FSelection, FSelectionCount);
+ end;
+ end;
+
+ while FSelectionCount > 0 do
+ begin
+ Dec(FSelectionCount);
+ Exclude(FSelection[FSelectionCount].States, vsSelected);
+ end;
+ ResetRangeAnchor;
+ FSelection := nil;
+ DoStateChange([], [tsClearPending]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalConnectNode(Node, Destination: PVirtualNode; Target: TBaseVirtualTree;
+ Mode: TVTNodeAttachMode);
+
+// Connects Node with Destination depending on Mode.
+// No error checking takes place. Node as well as Destination must be valid. Node must never be a root node and
+// Destination must not be a root node if Mode is amInsertBefore or amInsertAfter.
+
+var
+ Run: PVirtualNode;
+
+begin
+ // Keep in mind that the destination node might belong to another tree.
+ with Target do
+ begin
+ case Mode of
+ amInsertBefore:
+ begin
+ Node.PrevSibling := Destination.PrevSibling;
+ Destination.PrevSibling := Node;
+ Node.NextSibling := Destination;
+ Node.Parent := Destination.Parent;
+ Node.Index := Destination.Index;
+ if Node.PrevSibling = nil then
+ Node.Parent.FirstChild := Node
+ else
+ Node.PrevSibling.NextSibling := Node;
+
+ // reindex all following nodes
+ Run := Destination;
+ while Assigned(Run) do
+ begin
+ Inc(Run.Index);
+ Run := Run.NextSibling;
+ end;
+
+ Inc(Destination.Parent.ChildCount);
+ Include(Destination.Parent.States, vsHasChildren);
+ AdjustTotalCount(Destination.Parent, Node.TotalCount, True);
+
+ // Add the new node's height only if its parent is expanded.
+ if vsExpanded in Destination.Parent.States then
+ AdjustTotalHeight(Destination.Parent, Node.TotalHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node) + 1);
+ end;
+ amInsertAfter:
+ begin
+ Node.NextSibling := Destination.NextSibling;
+ Destination.NextSibling := Node;
+ Node.PrevSibling := Destination;
+ Node.Parent := Destination.Parent;
+ if Node.NextSibling = nil then
+ Node.Parent.LastChild := Node
+ else
+ Node.NextSibling.PrevSibling := Node;
+ Node.Index := Destination.Index;
+
+ // reindex all following nodes
+ Run := Node;
+ while Assigned(Run) do
+ begin
+ Inc(Run.Index);
+ Run := Run.NextSibling;
+ end;
+
+ Inc(Destination.Parent.ChildCount);
+ Include(Destination.Parent.States, vsHasChildren);
+ AdjustTotalCount(Destination.Parent, Node.TotalCount, True);
+ // Add the new node's height only if its parent is expanded.
+ if vsExpanded in Destination.Parent.States then
+ AdjustTotalHeight(Destination.Parent, Node.TotalHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node) + 1);
+ end;
+ amAddChildFirst:
+ begin
+ if Assigned(Destination.FirstChild) then
+ begin
+ // If there's a first child then there must also be a last child.
+ Destination.FirstChild.PrevSibling := Node;
+ Node.NextSibling := Destination.FirstChild;
+ Destination.FirstChild := Node;
+ end
+ else
+ begin
+ // First child node at this location.
+ Destination.FirstChild := Node;
+ Destination.LastChild := Node;
+ Node.NextSibling := nil;
+ end;
+ Node.PrevSibling := nil;
+ Node.Parent := Destination;
+ Node.Index := 0;
+ // reindex all following nodes
+ Run := Node.NextSibling;
+ while Assigned(Run) do
+ begin
+ Inc(Run.Index);
+ Run := Run.NextSibling;
+ end;
+
+ Inc(Destination.ChildCount);
+ Include(Destination.States, vsHasChildren);
+ AdjustTotalCount(Destination, Node.TotalCount, True);
+ // add the new node's height only if its parent is expanded (visibility is handled elsewhere)
+ if vsExpanded in Destination.States then
+ AdjustTotalHeight(Destination, Node.TotalHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node) + 1);
+ end;
+ amAddChildLast:
+ begin
+ if Assigned(Destination.LastChild) then
+ begin
+ // If there's a last child then there must also be a first child.
+ Destination.LastChild.NextSibling := Node;
+ Node.PrevSibling := Destination.LastChild;
+ Destination.LastChild := Node;
+ end
+ else
+ begin
+ // first child node at this location
+ Destination.FirstChild := Node;
+ Destination.LastChild := Node;
+ Node.PrevSibling := nil;
+ end;
+ Node.NextSibling := nil;
+ Node.Parent := Destination;
+ if Assigned(Node.PrevSibling) then
+ Node.Index := Node.PrevSibling.Index + 1
+ else
+ Node.Index := 0;
+ Inc(Destination.ChildCount);
+ Include(Destination.States, vsHasChildren);
+ AdjustTotalCount(Destination, Node.TotalCount, True);
+ // Add the new node's height only if its parent is expanded (visibility is handled elsewhere).
+ if vsExpanded in Destination.States then
+ AdjustTotalHeight(Destination, Node.TotalHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node) + 1);
+ end;
+ else
+ // amNoWhere: do nothing
+ end;
+
+ // Update the hidden children flag of the parent.
+ if (Mode <> amNoWhere) and (Node.Parent <> FRoot) then
+ begin
+ // If we have added a visible node then simply remove the all-children-hidden flag.
+ if vsVisible in Node.States then
+ Exclude(Node.Parent.States, vsAllChildrenHidden)
+ else
+ // If we have added an invisible node and this is the only child node then
+ // make sure the all-children-hidden flag is in a determined state.
+ // If there were child nodes before then no action is needed.
+ if Node.Parent.ChildCount = 1 then
+ Include(Node.Parent.States, vsAllChildrenHidden);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InternalData(Node: PVirtualNode): Pointer;
+
+begin
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalDisconnectNode(Node: PVirtualNode; KeepFocus: Boolean; Reindex: Boolean = True);
+
+// Disconnects the given node from its parent and siblings. The node's pointer are not reset so they can still be used
+// after return from this method (probably a very short time only!).
+// If KeepFocus is True then the focused node is not reset. This is useful if the given node is reconnected to the tree
+// immediately after return of this method and should stay being the focused node if it was it before.
+// Note: Node must not be nil or the root node.
+
+var
+ Parent,
+ Run: PVirtualNode;
+ Index: Integer;
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Node must neither be nil nor the root node.');
+
+ if (Node = FFocusedNode) and not KeepFocus then
+ begin
+ DoFocusNode(nil, False);
+ DoFocusChange(FFocusedNode, FFocusedColumn);
+ end;
+
+ if Node = FRangeAnchor then
+ ResetRangeAnchor;
+
+ // Update the hidden children flag of the parent.
+ if (Node.Parent <> FRoot) and not (vsClearing in Node.Parent.States) then
+ DetermineHiddenChildrenFlag(Node.Parent);
+
+ if not (vsDeleting in Node.States) then
+ begin
+ // Some states are only temporary so take them out.
+ Node.States := Node.States - [vsChecking];
+ Parent := Node.Parent;
+ Dec(Parent.ChildCount);
+ if Parent.ChildCount = 0 then
+ Exclude(Parent.States, vsHasChildren);
+ AdjustTotalCount(Parent, -Integer(Node.TotalCount), True);
+ if vsExpanded in Parent.States then
+ AdjustTotalHeight(Parent, -Integer(Node.TotalHeight), True);
+ if FullyVisible[Node] then
+ Dec(FVisibleCount, CountVisibleChildren(Node) + 1);
+ if Assigned(Node.PrevSibling) then
+ Node.PrevSibling.NextSibling := Node.NextSibling
+ else
+ Parent.FirstChild := Node.NextSibling;
+
+ if Assigned(Node.NextSibling) then
+ begin
+ Node.NextSibling.PrevSibling := Node.PrevSibling;
+ // Reindex all following nodes.
+ if Reindex then
+ begin
+ Run := Node.NextSibling;
+ Index := Node.Index;
+ while Assigned(Run) do
+ begin
+ Run.Index := Index;
+ Inc(Index);
+ Run := Run.NextSibling;
+ end;
+ end;
+ end
+ else
+ Parent.LastChild := Node.PrevSibling;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalRemoveFromSelection(Node: PVirtualNode);
+
+// Special version to mark a node to be no longer in the current selection. PackArray must
+// be used to remove finally those entries.
+
+var
+ Index: Integer;
+
+begin
+ // Because pointers are always DWORD aligned we can simply increment all those
+ // which we want to have removed (see also PackArray) and still have the
+ // order in the list preserved.
+ if FindNodeInSelection(Node, Index, -1, -1) then
+ begin
+ Exclude(Node.States, vsSelected);
+ Inc(Cardinal(FSelection[Index]));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvalidateCache;
+
+// Marks the cache as invalid.
+
+begin
+ DoStateChange([tsValidationNeeded], [tsUseCache]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MarkCutCopyNodes;
+
+// Sets the vsCutOrCopy style in every currently selected but not disabled node to indicate it is
+// now part of a clipboard operation.
+
+var
+ Nodes: TNodeArray;
+ I: Integer;
+
+begin
+ Nodes := nil;
+ if FSelectionCount > 0 then
+ begin
+ // need the current selection sorted to exclude selected nodes which are children, grandchildren etc. of
+ // already selected nodes
+ Nodes := GetSortedSelection(False);
+ for I := 0 to High(Nodes) do
+ with Nodes[I]^ do
+ if not (vsDisabled in States) then
+ Include(States, vsCutOrCopy);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Loaded;
+
+var
+ LastRootCount: Cardinal;
+ IsReadOnly: Boolean;
+
+begin
+ inherited;
+
+ // If a root node count has been set during load of the tree then update its child structure now
+ // as this hasn't been done yet in this case.
+ if (tsNeedRootCountUpdate in FStates) and (FRoot.ChildCount > 0) then
+ begin
+ DoStateChange([], [tsNeedRootCountUpdate]);
+ IsReadOnly := toReadOnly in FOptions.FMiscOptions;
+ Exclude(FOptions.FMiscOptions, toReadOnly);
+ LastRootCount := FRoot.ChildCount;
+ FRoot.ChildCount := 0;
+ BeginUpdate;
+ SetChildCount(FRoot, LastRootCount);
+ EndUpdate;
+ if IsReadOnly then
+ Include(FOptions.FMiscOptions, toReadOnly);
+ end;
+
+ // Prevent the object inspector at design time from marking the header as being modified
+ // when auto resize is enabled.
+ Updating;
+ try
+ FHeader.UpdateMainColumn;
+ FHeader.FColumns.FixPositions;
+ FHeader.RecalculateHeader;
+ if hoAutoResize in FHeader.FOptions then
+ FHeader.FColumns.AdjustAutoSize(InvalidColumn, True);
+ finally
+ Updated;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MainColumnChanged;
+
+begin
+ DoCancelEdit;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MouseMove(Shift: TShiftState; X, Y: Integer);
+
+var
+ R: TRect;
+
+begin
+ // Remove current selection in case the user clicked somewhere in the window (but not a node)
+ // and moved the mouse.
+ if tsDrawSelPending in FStates then
+ begin
+ if CalculateSelectionRect(X, Y) then
+ begin
+ InvalidateRect(Handle, @FNewSelRect, False);
+ UpdateWindow(Handle);
+ if (Abs(FNewSelRect.Right - FNewSelRect.Left) > Mouse.DragThreshold) or
+ (Abs(FNewSelRect.Bottom - FNewSelRect.Top) > Mouse.DragThreshold) then
+ begin
+ if tsClearPending in FStates then
+ begin
+ DoStateChange([], [tsClearPending]);
+ ClearSelection;
+ end;
+ DoStateChange([tsDrawSelecting], [tsDrawSelPending]);
+ // reset to main column for multiselection
+ FocusedColumn := FHeader.MainColumn;
+
+ // The current rectangle may already include some node captions. Handle this.
+ if HandleDrawSelection(X, Y) then
+ InvalidateRect(Handle, nil, False);
+ end;
+ end;
+ end
+ else
+ begin
+ // If both wheel panning and auto scrolling are pending then the user moved the mouse while holding down the
+ // middle mouse button. This means panning is being used, hence remove the autoscroll flag.
+ if [tsWheelPanning, tsWheelScrolling] * FStates = [tsWheelPanning, tsWheelScrolling] then
+ begin
+ if ((Abs(FLastClickPos.X - X) >= Mouse.DragThreshold) or (Abs(FLastClickPos.Y - Y) >= Mouse.DragThreshold)) then
+ DoStateChange([], [tsWheelScrolling]);
+ end;
+
+ // Really start dragging if the mouse has been moved more than the threshold.
+ if (tsOLEDragPending in FStates) and ((Abs(FLastClickPos.X - X) >= FDragThreshold) or
+ (Abs(FLastClickPos.Y - Y) >= FDragThreshold)) then
+ DoDragging(FLastClickPos)
+ else
+ begin
+ if CanAutoScroll then
+ DoAutoScroll(X, Y);
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ AdjustPanningCursor(X, Y);
+ if not IsMouseSelecting then
+ begin
+ HandleHotTrack(X, Y);
+ inherited MouseMove(Shift, X, Y);
+ end
+ else
+ begin
+ // Handle draw selection if required, but don't do the work twice if the
+ // auto scrolling code already cares about the selection.
+ if not (tsScrolling in FStates) and CalculateSelectionRect(X, Y) then
+ begin
+ // If something in the selection changed then invalidate the entire
+ // tree instead trying to figure out the display rects of all changed nodes.
+ if HandleDrawSelection(X, Y) then
+ InvalidateRect(Handle, nil, False)
+ else
+ begin
+ UnionRect(R, OrderRect(FNewSelRect), OrderRect(FLastSelRect));
+ OffsetRect(R, FOffsetX, FOffsetY);
+ InvalidateRect(Handle, @R, False);
+ end;
+ UpdateWindow(Handle);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Notification(AComponent: TComponent; Operation: TOperation);
+
+begin
+ if (AComponent <> Self) and (Operation = opRemove) then
+ begin
+ // Check for components linked to the tree.
+ if AComponent = FImages then
+ begin
+ Images := nil;
+ if not (csDestroying in ComponentState) then
+ Invalidate;
+ end
+ else
+ if AComponent = FStateImages then
+ begin
+ StateImages := nil;
+ if not (csDestroying in ComponentState) then
+ Invalidate;
+ end
+ else
+ if AComponent = FCustomCheckImages then
+ begin
+ CustomCheckImages := nil;
+ FCheckImageKind := ckLightCheck;
+ if not (csDestroying in ComponentState) then
+ Invalidate;
+ end
+ else
+ if AComponent = PopupMenu then
+ PopupMenu := nil
+ else
+ // Check for components linked to the header.
+ if AComponent = FHeader.FImages then
+ FHeader.Images := nil
+ else
+ if AComponent = FHeader.PopupMenu then
+ FHeader.PopupMenu := nil;
+ end;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Paint;
+
+// Window paint routine. Used when the tree window needs to be updated.
+
+var
+ Window: TRect;
+ Target: TPoint;
+
+begin
+ // The update rect has already been filled in WMPaint, as it is the window's update rect, which gets
+ // reset when BeginPaint is called (in the ancestor).
+ // The difference to the DC's clipbox is that it is also valid with internal paint operations used
+ // e.g. by the Explorer while dragging, but show window content while dragging is disabled.
+ if not IsRectEmpty(FUpdateRect) then
+ begin
+ Window := FUpdateRect;
+ Target := Window.TopLeft;
+
+ // The clipping rectangle is given in client coordinates of the window. We have to convert it into
+ // a sliding window of the tree image.
+ OffsetRect(Window, -FOffsetX, -FOffsetY);
+ PaintTree(Canvas, Window, Target, [poBackground, poColumnColor, poDrawFocusRect, poDrawDropMark, poDrawSelection,
+ poGridLines]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintCheckImage(const PaintInfo: TVTPaintInfo);
+
+var
+ ForegroundColor: COLORREF;
+ {$ifdef ThemeSupport}
+ R: TRect;
+ Details: TThemedElementDetails;
+ {$endif ThemeSupport}
+
+begin
+ with PaintInfo, ImageInfo[iiCheck] do
+ begin
+ {$ifdef ThemeSupport}
+ if (tsUseThemes in FStates) and (FCheckImageKind <> ckCustom) then
+ begin
+ R := Rect(XPos - 1, YPos, XPos + 16, YPos + 16);
+ Details.Element := teButton;
+ case Index of
+ 0..8: // radio buttons
+ begin
+ Details.Part := BP_RADIOBUTTON;
+ Details.State := Index;
+ end;
+ 9..20: // check boxes
+ begin
+ Details.Part := BP_CHECKBOX;
+ Details.State := Index - 8;
+ end;
+ 21..24: // buttons
+ begin
+ Details.Part := BP_PUSHBUTTON;
+ Details.State := Index - 20;
+ end;
+ else
+ Details.Part := 0;
+ Details.State := 0;
+ end;
+ ThemeServices.DrawElement(Canvas.Handle, Details, R);
+ if Index in [21..24] then
+ UtilityImages.Draw(Canvas, XPos - 1, YPos, 4);
+ end
+ else
+ {$endif ThemeSupport}
+ with FCheckImages do
+ begin
+ if (vsSelected in Node.States) and not Ghosted then
+ begin
+ if Focused or (toPopupMode in FOptions.FPaintOptions) then
+ ForegroundColor := ColorToRGB(FColors.FocusedSelectionColor)
+ else
+ ForegroundColor := ColorToRGB(FColors.UnfocusedSelectionColor);
+ end
+ else
+ ForegroundColor := GetRGBColor(BlendColor);
+
+ ImageList_DrawEx(Handle, Index, Canvas.Handle, XPos, YPos, 0, 0, GetRGBColor(BkColor), ForegroundColor,
+ ILD_TRANSPARENT);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintImage(const PaintInfo: TVTPaintInfo; ImageInfoIndex: TVTImageInfoIndex;
+ Images: TCustomImageList; DoOverlay: Boolean);
+
+const
+ Style: array[TImageType] of Cardinal = (0, ILD_MASK);
+
+var
+ OverlayImage: Integer;
+ OverlayGhosted: Boolean;
+ ExtraStyle: Cardinal;
+ ForegroundColor: COLORREF;
+ CutNode: Boolean;
+ PaintFocused: Boolean;
+
+begin
+ with PaintInfo, ImageInfo[ImageInfoIndex], Images do
+ begin
+ CutNode := (vsCutOrCopy in Node.States) and (tsCutPending in FStates);
+ PaintFocused := Focused or (toGhostedIfUnfocused in FOptions.FPaintOptions);
+
+ if (vsSelected in Node.States) and not (Ghosted or CutNode) then
+ begin
+ if PaintFocused or (toPopupMode in FOptions.FPaintOptions) then
+ ForegroundColor := ColorToRGB(FColors.FocusedSelectionColor)
+ else
+ ForegroundColor := ColorToRGB(FColors.UnfocusedSelectionColor);
+ end
+ else
+ ForegroundColor := GetRGBColor(Color);
+
+ // Since the overlay image must be specified together with the image to draw
+ // it is meaningfull to retrieve it in advance.
+ if DoOverlay then
+ OverlayImage := GetImageIndex(PaintInfo.Node, ikOverlay, PaintInfo.Column, OverlayGhosted)
+ else
+ OverlayImage := -1;
+ if (vsDisabled in Node.States) or not Enabled then
+ begin
+ // The internal handling for disabled images in TImageList destroys the forground color on Windows API level.
+ // Hence the canvas does not recognize the change and we have to restore the color manually.
+ ForegroundColor := ColorToRGB(Canvas.Font.Color);
+
+ // If the tree or the current node is disabled then let the VCL draw the image as it already
+ // contains code to convert the image to the system colors.
+ if OverlayImage > -1 then
+ Images.DrawOverlay(Canvas, XPos, YPos, Index, OverlayImage, False)
+ else
+ Images.Draw(Canvas, XPos, YPos, Index, False);
+
+ SetTextColor(Canvas.Handle, ForegroundColor);
+ end
+ else
+ begin
+ if OverlayImage > -1 then
+ ExtraStyle := ILD_TRANSPARENT or ILD_OVERLAYMASK and IndexToOverlayMask(OverlayImage + 1)
+ else
+ ExtraStyle := ILD_TRANSPARENT;
+
+ // Blend image if enabled and the tree has the focus (or ghosted images must be drawn also if unfocused) ...
+ if (toUseBlendedImages in FOptions.FPaintOptions) and PaintFocused
+ // ... and the image is ghosted...
+ and (Ghosted or
+ // ... or it is not the check image and the node is selected (but selection is not for the entire row)...
+ ((vsSelected in Node.States) and
+ not (toFullRowSelect in FOptions.FSelectionOptions) and
+ not (toGridExtensions in FOptions.FMiscOptions)) or
+ // ... or the node must be shown in cut mode.
+ CutNode) then
+ ExtraStyle := ExtraStyle or ILD_BLEND50;
+
+ ImageList_DrawEx(Handle, Index, Canvas.Handle, XPos, YPos, 0, 0, GetRGBColor(BkColor), ForegroundColor,
+ Style[ImageType] or ExtraStyle);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintNodeButton(Canvas: TCanvas; Node: PVirtualNode; const R: TRect; ButtonX,
+ ButtonY: Integer; BidiMode: TBiDiMode);
+
+var
+ Bitmap: TBitmap;
+ XPos: Integer;
+
+begin
+ if vsExpanded in Node.States then
+ Bitmap := FMinusBM
+ else
+ Bitmap := FPlusBM;
+
+ // Draw the node's plus/minus button according to the directionality.
+ if BidiMode = bdLeftToRight then
+ XPos := R.Left + ButtonX
+ else
+ XPos := R.Right - ButtonX - Bitmap.Width;
+
+ // Need to draw this masked.
+ Canvas.Draw(XPos, R.Top + ButtonY, Bitmap);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintTreeLines(const PaintInfo: TVTPaintInfo; VAlignment, IndentSize: Integer;
+ LineImage: TLineImage);
+
+var
+ I: Integer;
+ XPos,
+ Offset: Integer;
+ NewStyles: TLineImage;
+
+begin
+ NewStyles := nil;
+
+ with PaintInfo do
+ begin
+ if BidiMode = bdLeftToRight then
+ begin
+ XPos := CellRect.Left;
+ Offset := FIndent;
+ end
+ else
+ begin
+ Offset := -Integer(FIndent);
+ XPos := CellRect.Right + Offset;
+ end;
+
+ case FLineMode of
+ lmBands:
+ if poGridLines in PaintInfo.PaintOptions then
+ begin
+ // Convert the line images in correct bands.
+ SetLength(NewStyles, Length(LineImage));
+ for I := IndentSize - 1 downto 0 do
+ begin
+ if vsExpanded in Node.States then
+ NewStyles[I] := ltLeft
+ else
+ case LineImage[I] of
+ ltRight,
+ ltBottomRight,
+ ltTopDownRight,
+ ltTopRight:
+ NewStyles[I] := ltLeftBottom;
+ ltNone:
+ // Have to take over the image to the right of this one. A no line entry can never appear as
+ // last entry so I don't need an end check here.
+ if LineImage[I + 1] in [ltNone, ltTopRight] then
+ NewStyles[I] := NewStyles[I + 1]
+ else
+ NewStyles[I] := ltLeft;
+ ltTopDown:
+ // Have to check the image to the right of this one. A top down line can never appear as
+ // last entry so I don't need an end check here.
+ if LineImage[I + 1] in [ltNone, ltTopRight] then
+ NewStyles[I] := NewStyles[I + 1]
+ else
+ NewStyles[I] := ltLeft;
+ end;
+ end;
+
+ PaintInfo.Canvas.Font.Color := FColors.GridLineColor;
+ for I := 0 to IndentSize - 1 do
+ begin
+ DrawLineImage(PaintInfo, XPos, CellRect.Top, Node.NodeHeight - 1, VAlignment, NewStyles[I],
+ BidiMode <> bdLeftToRight);
+ Inc(XPos, Offset);
+ end;
+ end;
+ else // lmNormal
+ PaintInfo.Canvas.Font.Color := FColors.TreeLineColor;
+ for I := 0 to IndentSize - 1 do
+ begin
+ DrawLineImage(PaintInfo, XPos, CellRect.Top, Node.NodeHeight, VAlignment, LineImage[I],
+ BidiMode <> bdLeftToRight);
+ Inc(XPos, Offset);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintSelectionRectangle(Target: TCanvas; WindowOrgX: Integer; const SelectionRect: TRect;
+ TargetRect: TRect);
+
+// Helper routine to draw a selection rectangle in the mode determined by DrawSelectionMode.
+
+var
+ BlendRect: TRect;
+ TextColorBackup,
+ BackColorBackup: COLORREF; // used to restore forground and background colors when drawing a selection rectangle
+
+begin
+ if ((FDrawSelectionMode = smDottedRectangle) and not (tsUseThemes in FStates)) or
+ not MMXAvailable then
+ begin
+ // Classical selection rectangle using dotted borderlines.
+ TextColorBackup := GetTextColor(Target.Handle);
+ SetTextColor(Target.Handle, $FFFFFF);
+ BackColorBackup := GetBkColor(Target.Handle);
+ SetBkColor(Target.Handle, 0);
+ Target.DrawFocusRect(SelectionRect);
+ SetTextColor(Target.Handle, TextColorBackup);
+ SetBkColor(Target.Handle, BackColorBackup);
+ end
+ else
+ begin
+ // Modern alpha blended style.
+ OffsetRect(TargetRect, WindowOrgX, 0);
+ if IntersectRect(BlendRect, OrderRect(SelectionRect), TargetRect) then
+ begin
+ OffsetRect(BlendRect, -WindowOrgX, 0);
+ AlphaBlend(0, Target.Handle, BlendRect, Point(0, 0), bmConstantAlphaAndColor, FSelectionBlendFactor,
+ ColorToRGB(FColors.SelectionRectangleBlendColor));
+
+ Target.Brush.Color := FColors.SelectionRectangleBorderColor;
+ Target.FrameRect(SelectionRect);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PanningWindowProc(var Message: TMessage);
+
+var
+ PS: TPaintStruct;
+ Canvas: TCanvas;
+
+begin
+ if Message.Msg = WM_PAINT then
+ begin
+ BeginPaint(FPanningWindow, PS);
+ Canvas := TCanvas.Create;
+ Canvas.Handle := PS.hdc;
+ try
+ Canvas.Draw(0, 0, FPanningImage);
+ finally
+ Canvas.Handle := 0;
+ Canvas.Free;
+ EndPaint(FPanningWindow, PS);
+ end;
+ Message.Result := 0;
+ end
+ else
+ with Message do
+ Result := DefWindowProc(FPanningWindow, Msg, wParam, lParam);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType,
+ ChunkSize: Integer): Boolean;
+
+// Called while loading a tree structure, Node is already valid (allocated) at this point.
+// The function handles the base and user chunks, any other chunk is marked as being unknown (result becomes False)
+// and skipped. Descentants may handle them by overriding this method.
+// Returns True if the chunk could be handled, otherwise False.
+
+var
+ ChunkBody: TBaseChunkBody;
+ Run: PVirtualNode;
+ LastPosition: Integer;
+
+begin
+ case ChunkType of
+ BaseChunk:
+ begin
+ // Load base chunk's body (chunk header has already been consumed).
+ if Version > 1 then
+ Stream.Read(ChunkBody, SizeOf(ChunkBody))
+ else
+ begin
+ with ChunkBody do
+ begin
+ // In version prior to 2 there was a smaller chunk body. Hence we have to read it entry by entry now.
+ Stream.Read(ChildCount, SizeOf(ChildCount));
+ Stream.Read(NodeHeight, SizeOf(NodeHeight));
+ // TVirtualNodeStates was a byte sized type in version 1
+ States := [];
+ Stream.Read(States, SizeOf(Byte));
+ // vsVisible is now in the place where vsSelected was before, but every node was visible in the old version
+ // so we need to fix this too.
+ if vsVisible in States then
+ Include(States, vsSelected)
+ else
+ Include(States, vsVisible);
+ Stream.Read(Align, SizeOf(Align));
+ Stream.Read(CheckState, SizeOf(CheckState));
+ Stream.Read(CheckType, SizeOf(CheckType));
+ end;
+ end;
+
+ with Node^ do
+ begin
+ // Set states first, in case the node is invisble.
+ States := ChunkBody.States;
+
+ NodeHeight := ChunkBody.NodeHeight;
+ AdjustTotalHeight(Node, NodeHeight);
+
+ Align := ChunkBody.Align;
+ CheckState := ChunkBody.CheckState;
+ CheckType := ChunkBody.CheckType;
+
+ // Create and read child nodes.
+ while ChunkBody.ChildCount > 0 do
+ begin
+ Run := MakeNewNode;
+ InternalConnectNode(Run, Node, Self, amAddChildLast);
+ ReadNode(Stream, Version, Run);
+ Dec(ChunkBody.ChildCount);
+ end;
+ end;
+ Result := True;
+ end;
+ UserChunk:
+ if ChunkSize > 0 then
+ begin
+ // need to know whether the data was read
+ LastPosition := Stream.Position;
+ DoLoadUserData(Node, Stream);
+ // compare stream position to learn whether the data was read
+ Result := Stream.Position > LastPosition;
+ // Improve stability by advancing the stream to the chunk's real end if
+ // the application did not read what has been written.
+ if not Result or (Stream.Position <> (LastPosition + ChunkSize)) then
+ Stream.Position := LastPosition + ChunkSize;
+ end
+ else
+ Result := True;
+ else
+ // unknown chunk, skip it
+ Stream.Position := Stream.Position + ChunkSize;
+ Result := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ReadNode(Stream: TStream; Version: Integer; Node: PVirtualNode);
+
+// Reads the anchor chunk of each node and initiates reading the sub chunks for this node
+
+var
+ Header: TChunkHeader;
+ EndPosition: Integer;
+
+begin
+ with Stream do
+ begin
+ // Read anchor chunk of the node.
+ Stream.Read(Header, SizeOf(Header));
+ if Header.ChunkType = NodeChunk then
+ begin
+ EndPosition := Stream.Position + Header.ChunkSize;
+ // Read all subchunks until the indicated chunk end position is reached in the stream.
+ while Position < EndPosition do
+ begin
+ // Read new chunk header.
+ Stream.Read(Header, SizeOf(Header));
+ ReadChunk(Stream, Version, Node, Header.ChunkType, Header.ChunkSize);
+ end;
+ // If the last chunk does not end at the given end position then there is something wrong.
+ if Position <> EndPosition then
+ ShowError(SCorruptStream2, hcTFCorruptStream2);
+ end
+ else
+ ShowError(SCorruptStream1, hcTFCorruptStream1);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.RedirectFontChangeEvent(Canvas: TCanvas);
+
+begin
+ if @Canvas.Font.OnChange <> @FOldFontChange then
+ begin
+ FOldFontChange := Canvas.Font.OnChange;
+ Canvas.Font.OnChange := FontChanged;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.RemoveFromSelection(Node: PVirtualNode);
+
+var
+ Index: Integer;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil!');
+ if vsSelected in Node.States then
+ begin
+ Exclude(Node.States, vsSelected);
+ if FindNodeInSelection(Node, Index, -1, -1) and (Index < FSelectionCount - 1) then
+ Move(FSelection[Index + 1], FSelection[Index], (FSelectionCount - Index - 1) * 4);
+ if FSelectionCount > 0 then
+ Dec(FSelectionCount);
+ SetLength(FSelection, FSelectionCount);
+
+ if FSelectionCount = 0 then
+ ResetRangeAnchor;
+
+ Change(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean): HResult;
+
+// Returns a memory expression of all currently selected nodes in the Medium structure.
+// Note: The memory requirement of this method might be very high. This depends however on the requested storage format.
+// For HGlobal (a global memory block) we need to render first all nodes to local memory and copy this then to
+// the global memory in Medium. This is necessary because we have first to determine how much
+// memory is needed before we can allocate it. Hence for a short moment we need twice the space as used by the
+// nodes alone (plus the amount the nodes need in the tree anyway)!
+// With IStream this does not happen. We directly stream out the nodes and pass the constructed stream along.
+
+ //--------------- local function --------------------------------------------
+
+ procedure WriteNodes(Stream: TStream);
+
+ var
+ Selection: TNodeArray;
+ I: Integer;
+
+ begin
+ if ForClipboard then
+ Selection := GetSortedCutCopySet(True)
+ else
+ Selection := GetSortedSelection(True);
+ for I := 0 to High(Selection) do
+ WriteNode(Stream, Selection[I]);
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ Data: PCardinal;
+ ResPointer: Pointer;
+ ResSize: Integer;
+ OLEStream: IStream;
+ VCLStream: TStream;
+
+begin
+ FillChar(Medium, SizeOf(Medium), 0);
+
+ // We can render the native clipboard format in two different storage media.
+ if (FormatEtcIn.cfFormat = CF_VIRTUALTREE) and (FormatEtcIn.tymed and (TYMED_HGLOBAL or TYMED_ISTREAM) <> 0) then
+ begin
+ VCLStream := nil;
+ try
+ Medium.unkForRelease := nil;
+ // Return data in one of the supported storage formats, prefer IStream.
+ if FormatEtcIn.tymed and TYMED_ISTREAM <> 0 then
+ begin
+ // Create an IStream on a memory handle (here it is 0 which indicates to implicitely allocated a handle).
+ // Do not use TStreamAdapter as it is not compatible with OLE (when flushing the clipboard OLE wants the HGlobal
+ // back which is not supported by TStreamAdapater).
+ CreateStreamOnHGlobal(0, True, OLEStream);
+ VCLStream := TOLEStream.Create(OLEStream);
+ WriteNodes(VCLStream);
+ // Rewind stream.
+ VCLStream.Position := 0;
+ Medium.tymed := TYMED_ISTREAM;
+ IUnknown(Medium.stm) := OLEStream;
+ Result := S_OK;
+ end
+ else
+ begin
+ VCLStream := TMemoryStream.Create;
+ WriteNodes(VCLStream);
+ ResPointer := TMemoryStream(VCLStream).Memory;
+ ResSize := VCLStream.Position;
+
+ // Allocate memory to hold the string.
+ if ResSize > 0 then
+ begin
+ Medium.hGlobal := GlobalAlloc(GHND or GMEM_SHARE, ResSize + SizeOf(Cardinal));
+ Data := GlobalLock(Medium.hGlobal);
+ // Store the size of the data too, for easy retrival.
+ Data^ := ResSize;
+ Inc(Data);
+ Move(ResPointer^, Data^, ResSize);
+ GlobalUnlock(Medium.hGlobal);
+ Medium.tymed := TYMED_HGLOBAL;
+
+ Result := S_OK;
+ end
+ else
+ Result := E_FAIL;
+ end;
+ finally
+ // We can free the VCL stream here since it was either a pure memory stream or only a wrapper around
+ // the OLEStream which exists independently.
+ VCLStream.Free;
+ end;
+ end
+ else // Ask application descentants to render self defined formats.
+ Result := DoRenderOLEData(FormatEtcIn, Medium, ForClipboard);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ResetRangeAnchor;
+
+// Called when there is no selected node anymore and the selection range anchor needs a new value.
+
+begin
+ FRangeAnchor := FFocusedNode;
+ FLastSelectionLevel := -1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.RestoreFontChangeEvent(Canvas: TCanvas);
+
+begin
+ Canvas.Font.OnChange := FOldFontChange;
+ FOldFontChange := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SelectNodes(StartNode, EndNode: PVirtualNode; AddOnly: Boolean);
+
+// Selects a range of nodes and unselects all other eventually selected nodes which are not in this range if
+// AddOnly is False.
+// EndNode must be visible while StartNode does not necessarily as in the case where the last focused node is the start
+// node but it is a child of a node which has been collapsed previously. In this case the first visible parent node
+// is used as start node. StartNode can be nil in which case the very first node in the tree is used.
+
+var
+ NodeFrom,
+ NodeTo,
+ LastAnchor: PVirtualNode;
+ Index: Integer;
+
+begin
+ Assert(Assigned(EndNode), 'EndNode must not be nil!');
+ ClearTempCache;
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ else
+ if not FullyVisible[StartNode] then
+ begin
+ StartNode := GetPreviousVisible(StartNode);
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ end;
+
+ if CompareNodePositions(StartNode, EndNode) < 0 then
+ begin
+ NodeFrom := StartNode;
+ NodeTo := EndNode;
+ end
+ else
+ begin
+ NodeFrom := EndNode;
+ NodeTo := StartNode;
+ end;
+
+ // The range anchor will be reset by the following call.
+ LastAnchor := FRangeAnchor;
+ if not AddOnly then
+ InternalClearSelection;
+
+ while NodeFrom <> NodeTo do
+ begin
+ InternalCacheNode(NodeFrom);
+ NodeFrom := GetNextVisible(NodeFrom);
+ end;
+ // select last node too
+ InternalCacheNode(NodeFrom);
+ // now add them all in "one" step
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+ if Assigned(LastAnchor) and FindNodeInSelection(LastAnchor, Index, -1, -1) then
+ FRangeAnchor := LastAnchor;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetBiDiMode(Value: TBiDiMode);
+
+begin
+ inherited;
+
+ RecreateWnd;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SkipNode(Stream: TStream);
+
+// Skips the data for the next node in the given stream (including the child nodes).
+
+var
+ Header: TChunkHeader;
+
+begin
+ with Stream do
+ begin
+ // read achor chunk of the node
+ Stream.Read(Header, SizeOf(Header));
+ if Header.ChunkType = NodeChunk then
+ Stream.Position := Stream.Position + Header.ChunkSize
+ else
+ ShowError(SCorruptStream1, hcTFCorruptStream1);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+var
+ PanningWindowClass: TWndClass = (
+ style: 0;
+ lpfnWndProc: @DefWindowProc;
+ cbClsExtra: 0;
+ cbWndExtra: 0;
+ hInstance: 0;
+ hIcon: 0;
+ hCursor: 0;
+ hbrBackground: 0;
+ lpszMenuName: nil;
+ lpszClassName: 'VTPanningWindow'
+ );
+
+procedure TBaseVirtualTree.StartWheelPanning(Position: TPoint);
+
+// Called when wheel panning should start. A little helper window is created to indicate the reference position,
+// which determines in which direction and how far wheel panning/scrolling will happen.
+
+ //--------------- local function --------------------------------------------
+
+ function CreateClipRegion: HRGN;
+
+ // In order to avoid doing all the transparent drawing ourselves we use a
+ // window region for the wheel window.
+ // Since we only work on a very small image (32x32 pixels) this is acceptable.
+
+ var
+ Start, X, Y: Integer;
+ Temp: HRGN;
+
+ begin
+ Assert(not FPanningImage.Empty, 'Invalid wheel panning image.');
+
+ // Create an initial region on which we operate.
+ Result := CreateRectRgn(0, 0, 0, 0);
+ with FPanningImage, Canvas do
+ begin
+ for Y := 0 to Height - 1 do
+ begin
+ Start := -1;
+ for X := 0 to Width - 1 do
+ begin
+ // Start a new span if we found a non-transparent pixel and no span is currently started.
+ if (Start = -1) and (Pixels[X, Y] <> clFuchsia) then
+ Start := X
+ else
+ if (Start > -1) and (Pixels[X, Y] = clFuchsia) then
+ begin
+ // A non-transparent span is finished. Add it to the result region.
+ Temp := CreateRectRgn(Start, Y, X, Y + 1);
+ CombineRgn(Result, Result, Temp, RGN_OR);
+ DeleteObject(Temp);
+ Start := -1;
+ end;
+ end;
+ // If there is an open span then add this also to the result region.
+ if Start > -1 then
+ begin
+ Temp := CreateRectRgn(Start, Y, Width, Y + 1);
+ CombineRgn(Result, Result, Temp, RGN_OR);
+ DeleteObject(Temp);
+ end;
+ end;
+ end;
+ // The resulting region is used as window region so we must not delete it.
+ // Windows will own it after the assignment below.
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ TempClass: TWndClass;
+ ClassRegistered: Boolean;
+ ImageName: string;
+
+begin
+ // Set both panning and scrolling flag. One will be removed shortly depending on whether the middle mouse button is
+ // released before the mouse is moved or vice versa. The first case is referred to as wheel scrolling while the
+ // latter is called wheel panning.
+ StopTimer(ScrollTimer);
+ DoStateChange([tsWheelPanning, tsWheelScrolling]);
+
+ // Register the helper window class.
+ PanningWindowClass.hInstance := HInstance;
+ ClassRegistered := GetClassInfo(HInstance, PanningWindowClass.lpszClassName, TempClass);
+ if not ClassRegistered or (TempClass.lpfnWndProc <> @DefWindowProc) then
+ begin
+ if ClassRegistered then
+ Windows.UnregisterClass(PanningWindowClass.lpszClassName, HInstance);
+ Windows.RegisterClass(PanningWindowClass);
+ end;
+ // Create the helper window and show at the given position without activating it.
+ with ClientToScreen(Position) do
+ FPanningWindow := CreateWindowEx(WS_EX_TOOLWINDOW, PanningWindowClass.lpszClassName, nil, WS_POPUP, X - 16, Y - 16,
+ 32, 32, Handle, 0, HInstance, nil);
+
+ FPanningImage := TBitmap.Create;
+ if Integer(FRangeX) > ClientWidth then
+ begin
+ if Integer(FRangeY) > ClientHeight then
+ ImageName := 'VT_MOVEALL'
+ else
+ ImageName := 'VT_MOVEEW'
+ end
+ else
+ ImageName := 'VT_MOVENS';
+ FPanningImage.LoadFromResourceName(HInstance, ImageName);
+ SetWindowRgn(FPanningWindow, CreateClipRegion, False);
+
+ {$ifdef COMPILER_6_UP}
+ SetWindowLong(FPanningWindow, GWL_WNDPROC, Integer(Classes.MakeObjectInstance(PanningWindowProc)));
+ {$else}
+ SetWindowLong(FPanningWindow, GWL_WNDPROC, Integer(MakeObjectInstance(PanningWindowProc)));
+ {$endif}
+ ShowWindow(FPanningWindow, SW_SHOWNOACTIVATE);
+
+ // Setup the panscroll timer and capture all mouse input.
+ SetFocus;
+ SetCapture(Handle);
+ SetTimer(Handle, ScrollTimer, 20, nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.StopWheelPanning;
+
+// Stops panning if currently active and destroys the helper window.
+
+var
+ Instance: Pointer;
+
+begin
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ // Release the mouse capture and stop the panscroll timer.
+ StopTimer(ScrollTimer);
+ ReleaseCapture;
+ DoStateChange([], [tsWheelPanning, tsWheelScrolling]);
+
+ // Destroy the helper window.
+ Instance := Pointer(GetWindowLong(FPanningWindow, GWL_WNDPROC));
+ DestroyWindow(FPanningWindow);
+ if Instance <> @DefWindowProc then
+ {$ifdef COMPILER_6_UP}
+ Classes.FreeObjectInstance(Instance);
+ {$else}
+ FreeObjectInstance(Instance);
+ {$endif}
+ FPanningWindow := 0;
+ FPanningImage.Free;
+ FPanningImage := nil;
+ DeleteObject(FPanningCursor);
+ FPanningCursor := 0;
+ Windows.SetCursor(Screen.Cursors[Cursor]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.StructureChange(Node: PVirtualNode; Reason: TChangeReason);
+
+begin
+ AdviseChangeEvent(True, Node, Reason);
+
+ if FUpdateCount = 0 then
+ begin
+ if (FChangeDelay > 0) and not (tsSynchMode in FStates) then
+ SetTimer(Handle, StructureChangeTimer, FChangeDelay, nil)
+ else
+ DoStructureChange(Node, Reason);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.SuggestDropEffect(Source: TObject; Shift: TShiftState; Pt: TPoint;
+ AllowedEffects: Integer): Integer;
+
+// determines the drop action to take if the drag'n drop operation ends on this tree
+// Note: Source can be any Delphi object not just a virtual tree
+
+begin
+ Result := AllowedEffects;
+
+ // prefer MOVE if source and target are the same control, otherwise whatever is allowed as initial value
+ if Assigned(Source) and (Source = Self) then
+ if (AllowedEffects and DROPEFFECT_MOVE) <> 0 then
+ Result := DROPEFFECT_MOVE
+ else // no change
+ else
+ // drag between different applicatons
+ if (AllowedEffects and DROPEFFECT_COPY) <> 0 then
+ Result := DROPEFFECT_COPY;
+
+ // consider modifier keys and what is allowed at the moment, if none of the following conditions apply then
+ // the initial value just set is used
+ if ssCtrl in Shift then
+ begin
+ // copy or link
+ if ssShift in Shift then
+ begin
+ // link
+ if (AllowedEffects and DROPEFFECT_LINK) <> 0 then
+ Result := DROPEFFECT_LINK;
+ end
+ else
+ begin
+ // copy
+ if (AllowedEffects and DROPEFFECT_COPY) <> 0 then
+ Result := DROPEFFECT_COPY;
+ end;
+ end
+ else
+ begin
+ // move, link or default
+ if ssShift in Shift then
+ begin
+ // move
+ if (AllowedEffects and DROPEFFECT_MOVE) <> 0 then
+ Result := DROPEFFECT_MOVE;
+ end
+ else
+ begin
+ // link or default
+ if ssAlt in Shift then
+ begin
+ // link
+ if (AllowedEffects and DROPEFFECT_LINK) <> 0 then
+ Result := DROPEFFECT_LINK;
+ end;
+ // else default
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ToggleSelection(StartNode, EndNode: PVirtualNode);
+
+// Switchs the selection state of a range of nodes.
+// Note: This method is specifically designed to help selecting ranges with the keyboard and considers therefore
+// the range anchor.
+
+var
+ NodeFrom,
+ NodeTo: PVirtualNode;
+ NewSize: Integer;
+ Position: Integer;
+
+begin
+ Assert(Assigned(EndNode), 'EndNode must not be nil!');
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ else
+ if not FullyVisible[StartNode] then
+ StartNode := GetPreviousVisible(StartNode);
+
+ Position := CompareNodePositions(StartNode, EndNode);
+ // nothing to do if start and end node are the same
+ if Position <> 0 then
+ begin
+ if Position < 0 then
+ begin
+ NodeFrom := StartNode;
+ NodeTo := EndNode;
+ end
+ else
+ begin
+ NodeFrom := EndNode;
+ NodeTo := StartNode;
+ end;
+
+ ClearTempCache;
+
+ // 1) toggle the start node if it is before the range anchor
+ if CompareNodePositions(NodeFrom, FRangeAnchor) < 0 then
+ if not (vsSelected in NodeFrom.States) then
+ InternalCacheNode(NodeFrom)
+ else
+ InternalRemoveFromSelection(NodeFrom);
+
+ // 2) toggle all nodes within the range
+ NodeFrom := GetNextVisible(NodeFrom);
+ while NodeFrom <> NodeTo do
+ begin
+ if not (vsSelected in NodeFrom.States) then
+ InternalCacheNode(NodeFrom)
+ else
+ InternalRemoveFromSelection(NodeFrom);
+ NodeFrom := GetNextVisible(NodeFrom);
+ end;
+
+ // 3) toggle end node if it is after the range anchor
+ if CompareNodePositions(NodeFrom, FRangeAnchor) > 0 then
+ if not (vsSelected in NodeFrom.States) then
+ InternalCacheNode(NodeFrom)
+ else
+ InternalRemoveFromSelection(NodeFrom);
+
+ // Do some housekeeping if there was a change.
+ NewSize := PackArray(FSelection, FSelectionCount);
+ if NewSize > -1 then
+ begin
+ FSelectionCount := NewSize;
+ SetLength(FSelection, FSelectionCount);
+ end;
+ // If the range went over the anchor then we need to reselect it.
+ if not (vsSelected in FRangeAnchor.States) then
+ InternalCacheNode(FRangeAnchor);
+ if FTempNodeCount > 0 then
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UnselectNodes(StartNode, EndNode: PVirtualNode);
+
+// Deselects a range of nodes.
+// EndNode must be visible while StartNode must not as in the case where the last focused node is the start node
+// but it is a child of a node which has been collapsed previously. In this case the first visible parent node
+// is used as start node. StartNode can be nil in which case the very first node in the tree is used.
+
+var
+ NodeFrom,
+ NodeTo: PVirtualNode;
+ NewSize: Integer;
+
+begin
+ Assert(Assigned(EndNode), 'EndNode must not be nil!');
+
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ else
+ if not FullyVisible[StartNode] then
+ begin
+ StartNode := GetPreviousVisible(StartNode);
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ end;
+
+ if CompareNodePositions(StartNode, EndNode) < 0 then
+ begin
+ NodeFrom := StartNode;
+ NodeTo := EndNode;
+ end
+ else
+ begin
+ NodeFrom := EndNode;
+ NodeTo := StartNode;
+ end;
+
+ while NodeFrom <> NodeTo do
+ begin
+ InternalRemoveFromSelection(NodeFrom);
+ NodeFrom := GetNextVisible(NodeFrom);
+ end;
+ // Deselect last node too.
+ InternalRemoveFromSelection(NodeFrom);
+
+ // Do some housekeeping.
+ NewSize := PackArray(FSelection, FSelectionCount);
+ if NewSize > -1 then
+ begin
+ FSelectionCount := NewSize;
+ SetLength(FSelection, FSelectionCount);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateDesigner;
+
+var
+ ParentForm: TCustomForm;
+
+begin
+ if (csDesigning in ComponentState) and not (csUpdating in ComponentState) then
+ begin
+ ParentForm := GetParentForm(Self);
+ if Assigned(ParentForm) and Assigned(ParentForm.Designer) then
+ ParentForm.Designer.Modified;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateHeaderRect;
+
+// Calculates the rectangle the header occupies in non-client area.
+// These coordinates are in window rectangle.
+
+var
+ OffsetX,
+ OffsetY: Integer;
+ EdgeSize: Integer;
+ Styles: Integer;
+
+begin
+ FHeaderRect := Rect(0, 0, Width, Height);
+
+ // Consider borders...
+ Styles := GetWindowLong(Handle, GWL_STYLE);
+ if (Styles and WS_BORDER) <> 0 then
+ InflateRect(FHeaderRect, -1, -1);
+ if (Styles and WS_THICKFRAME) <> 0 then
+ InflateRect(FHeaderRect, -3, -3);
+
+ Styles := GetWindowLong(Handle, GWL_EXSTYLE);
+ if (Styles and WS_EX_CLIENTEDGE) <> 0 then
+ InflateRect(FHeaderRect, -2, -2);
+
+ // ... and bevels.
+ OffsetX := BorderWidth;
+ OffsetY := BorderWidth;
+ if BevelKind <> bkNone then
+ begin
+ EdgeSize := 0;
+ if BevelInner <> bvNone then
+ Inc(EdgeSize, BevelWidth);
+ if BevelOuter <> bvNone then
+ Inc(EdgeSize, BevelWidth);
+ if beLeft in BevelEdges then
+ Inc(OffsetX, EdgeSize);
+ if beTop in BevelEdges then
+ Inc(OffsetY, EdgeSize);
+ end;
+
+ InflateRect(FHeaderRect, -OffsetX, -OffsetY);
+
+ if hoVisible in FHeader.FOptions then
+ begin
+ if FHeaderRect.Left <= FHeaderRect.Right then
+ FHeaderRect.Bottom := FHeaderRect.Top + Integer(FHeader.FHeight)
+ else
+ FHeaderRect := Rect(0, 0, 0, 0);
+ end
+ else
+ FHeaderRect.Bottom := FHeaderRect.Top;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateEditBounds;
+
+// Used to update the bounds of the current node editor if editing is currently active.
+
+var
+ R: TRect;
+ Dummy: Integer;
+ BidiMode: TBidiMode;
+
+begin
+ if tsEditing in FStates then
+ begin
+ if vsMultiline in FFocusedNode.States then
+ R := GetDisplayRect(FFocusedNode, FEditColumn, True, False)
+ else
+ R := GetDisplayRect(FFocusedNode, FEditColumn, True, True);
+ if (toGridExtensions in FOptions.MiscOptions) then
+ begin
+ // Consider visible tree lines, check boxes or images here. Do not forget about bidi.
+ if FEditColumn = NoColumn then
+ BidiMode := Self.BidiMode
+ else
+ BidiMode := FHeader.Columns[FEditColumn].FBiDiMode;
+ if BiDiMode = bdLeftToRight then
+ FHeader.Columns.GetColumnBounds(FEditColumn, Dummy, R.Right)
+ else
+ FHeader.Columns.GetColumnBounds(FEditColumn, R.Left, Dummy);
+ end;
+ if toShowHorzGridLines in TreeOptions.PaintOptions then
+ Dec(R.Bottom);
+ FEditLink.SetBounds(R);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+const
+ ScrollMasks: array[Boolean] of Cardinal = (0, SIF_DISABLENOSCROLL);
+
+const // Region identifiers for GetRandomRgn
+ CLIPRGN = 1;
+ METARGN = 2;
+ APIRGN = 3;
+ SYSRGN = 4;
+
+function GetRandomRgn(DC: HDC; Rgn: HRGN; iNum: Integer): Integer; stdcall; external 'GDI32.DLL';
+
+procedure TBaseVirtualTree.UpdateWindowAndDragImage(const Tree: TBaseVirtualTree; TreeRect: TRect; UpdateNCArea,
+ ReshowDragImage: Boolean);
+
+// Method to repaint part of the window area which is not covered by the drag image and to initiate a recapture
+// of the drag image.
+// Note: This method must only be called during a drag operation and the tree passed in is the one managing the current
+// drag image (so it is the actual drag source).
+
+var
+ DragRegion, // the region representing the drag image
+ UpdateRegion, // the unclipped region within the tree to be updated
+ NCRegion: HRGN; // the region representing the non-client area of the tree
+ DragRect,
+ NCRect: TRect;
+ RedrawFlags: Cardinal;
+
+ VisibleTreeRegion: HRGN;
+
+ DC: HDC;
+
+begin
+ if IntersectRect(TreeRect, TreeRect, ClientRect) then
+ begin
+ // Retrieve the visible region of the window. This is important to avoid overpainting parts of other windows
+ // which overlap this one.
+ VisibleTreeRegion := CreateRectRgn(0, 0, 1, 1);
+ DC := GetDCEx(Handle, 0, DCX_CACHE or DCX_WINDOW or DCX_CLIPSIBLINGS or DCX_CLIPCHILDREN);
+ GetRandomRgn(DC, VisibleTreeRegion, SYSRGN);
+ ReleaseDC(Handle, DC);
+
+ // In Win9x the returned visible region is given in client coordinates. We need it in screen coordinates, though.
+ if not IsWinNT then
+ with ClientToScreen(Point(0, 0)) do
+ OffsetRgn(VisibleTreeRegion, X, Y);
+
+ // The drag image will figure out itself what part of the rectangle can be recaptured.
+ // Recapturing is not done by taking a snapshot of the screen, but by letting the tree draw itself
+ // into the back bitmap of the drag image. So the order here is unimportant.
+ Tree.FDragImage.RecaptureBackground(Self, TreeRect, VisibleTreeRegion, UpdateNCArea, ReshowDragImage);
+
+ // Calculate the screen area not covered by the drag image and which needs an update.
+ DragRect := Tree.FDragImage.GetDragImageRect;
+ MapWindowPoints(0, Handle, DragRect, 2);
+ DragRegion := CreateRectRgnIndirect(DragRect);
+
+ // Start with non-client area if requested.
+ if UpdateNCArea then
+ begin
+ // Compute the part of the non-client area which must be updated.
+
+ // Determine the outer rectangle of the entire tree window.
+ GetWindowRect(Handle, NCRect);
+ // Express the tree window rectangle in client coordinates (because RedrawWindow wants them so).
+ MapWindowPoints(0, Handle, NCRect, 2);
+ NCRegion := CreateRectRgnIndirect(NCRect);
+ // Determine client rect in screen coordinates and create another region for it.
+ UpdateRegion := CreateRectRgnIndirect(ClientRect);
+ // Create a region which only contains the NC part by subtracting out the client area.
+ CombineRgn(NCRegion, NCRegion, UpdateRegion, RGN_DIFF);
+ // Subtract also out what is hidden by the drag image.
+ CombineRgn(NCRegion, NCRegion, DragRegion, RGN_DIFF);
+ RedrawWindow(Handle, nil, NCRegion, RDW_FRAME or RDW_NOERASE or RDW_NOCHILDREN or RDW_INVALIDATE or RDW_VALIDATE or
+ RDW_UPDATENOW);
+ DeleteObject(NCRegion);
+ DeleteObject(UpdateRegion);
+ end;
+
+ UpdateRegion := CreateRectRgnIndirect(TreeRect);
+ RedrawFlags := RDW_INVALIDATE or RDW_VALIDATE or RDW_UPDATENOW or RDW_NOERASE or RDW_NOCHILDREN;
+ // Remove the part of the update region which is covered by the drag image.
+ CombineRgn(UpdateRegion, UpdateRegion, DragRegion, RGN_DIFF);
+ RedrawWindow(Handle, nil, UpdateRegion, RedrawFlags);
+ DeleteObject(UpdateRegion);
+ DeleteObject(DragRegion);
+ DeleteObject(VisibleTreeRegion);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ValidateCache;
+
+// Starts cache validation if not already done by adding this instance to the worker thread's waiter list
+// (if not already there) and signalling the thread it can start validating.
+
+begin
+ // Wait for thread to stop validation if it is currently validating this tree's cache.
+ InterruptValidation;
+
+ FStartIndex := 0;
+ if tsValidationNeeded in FStates then
+ begin
+ // Tell the thread this tree needs actually something to do.
+ WorkerThread.AddTree(Self);
+ SetEvent(WorkEvent);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ValidateNodeDataSize(var Size: Integer);
+
+begin
+ Size := 0;
+ if Assigned(FOnGetNodeDataSize) then
+ FOnGetNodeDataSize(Self, Size);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WndProc(var Message: TMessage);
+
+var
+ Handled: Boolean;
+
+begin
+ Handled := False;
+
+ // Try the header whether it needs to take this message.
+ if Assigned(FHeader) and (FHeader.FStates <> []) then
+ Handled := FHeader.HandleMessage(Message);
+ if not Handled then
+ begin
+ // For auto drag mode, let tree handle itself, instead of TControl.
+ if not (csDesigning in ComponentState) and
+ ((Message.Msg = WM_LBUTTONDOWN) or (Message.Msg = WM_LBUTTONDBLCLK)) then
+ begin
+ if (DragMode = dmAutomatic) and (DragKind = dkDrag) then
+ begin
+ if IsControlMouseMsg(TWMMouse(Message)) then
+ Handled := True;
+ if not Handled then
+ begin
+ ControlState := ControlState + [csLButtonDown];
+ Dispatch(Message); // overrides TControl's BeginDrag
+ Handled := True;
+ end;
+ end;
+ end;
+
+ if not Handled and Assigned(FHeader) then
+ Handled := FHeader.HandleMessage(Message);
+
+ if not Handled then
+ begin
+ if (Message.Msg in [WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN, WM_NCMBUTTONDOWN]) and not Focused and CanFocus then
+ SetFocus;
+ inherited;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WriteChunks(Stream: TStream; Node: PVirtualNode);
+
+// writes the core chunks for Node into the stream
+// Node: Descentants can optionally override this method to add other node specific chunks.
+// Keep in mind that this method is also called for the root node. Using this fact in descentants you can
+// create a kind of "global" chunks not directly bound to a specific node.
+
+var
+ Header: TChunkHeader;
+ LastPosition,
+ ChunkSize: Integer;
+ Chunk: TBaseChunk;
+ Run: PVirtualNode;
+
+begin
+ with Stream do
+ begin
+ // 1. The base chunk...
+ LastPosition := Position;
+ Chunk.Header.ChunkType := BaseChunk;
+ with Node^, Chunk do
+ begin
+ Body.ChildCount := ChildCount;
+ Body.NodeHeight := NodeHeight;
+ // some states are only temporary so take them out as they make no sense at the new location
+ Body.States := States - [vsChecking, vsCutOrCopy, vsDeleting, vsInitialUserData];
+ Body.Align := Align;
+ Body.CheckState := CheckState;
+ Body.CheckType := CheckType;
+ Body.Reserved := 0;
+ end;
+ // write the base chunk
+ Write(Chunk, SizeOf(Chunk));
+
+ // 2. ... directly followed by the child node chunks (actually they are child chunks of
+ // the base chunk)
+ if vsInitialized in Node.States then
+ begin
+ Run := Node.FirstChild;
+ while Assigned(Run) do
+ begin
+ WriteNode(Stream, Run);
+ Run := Run.NextSibling;
+ end;
+ end;
+
+ FinishChunkHeader(Stream, LastPosition, Position);
+
+ // 3. write user data
+ LastPosition := Position;
+ Header.ChunkType := UserChunk;
+ Write(Header, SizeOf(Header));
+ DoSaveUserData(Node, Stream);
+ // check if the application actually wrote data
+ ChunkSize := Position - LastPosition - SizeOf(TChunkHeader);
+ // seek back to start of chunk if nothing has been written
+ if ChunkSize = 0 then
+ begin
+ Position := LastPosition;
+ Size := Size - SizeOf(Header);
+ end
+ else
+ FinishChunkHeader(Stream, LastPosition, Position);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WriteNode(Stream: TStream; Node: PVirtualNode);
+
+// Writes the "cover" chunk for Node to Stream and initiates writing child nodes and chunks.
+
+var
+ LastPosition: Integer;
+ Header: TChunkHeader;
+
+begin
+ // Initialize the node first if necessary and wanted.
+ if toInitOnSave in FOptions.FMiscOptions then
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+ end;
+
+ with Stream do
+ begin
+ LastPosition := Position;
+ // Emit the anchor chunk.
+ Header.ChunkType := NodeChunk;
+ Write(Header, SizeOf(Header));
+ // Write other chunks to stream taking their size into this chunk's size.
+ WriteChunks(Stream, Node);
+
+ // Update chunk size.
+ FinishChunkHeader(Stream, LastPosition, Position);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.AbsoluteIndex(Node: PVirtualNode): Cardinal;
+
+begin
+ Result := 0;
+ while Assigned(Node) and (Node <> FRoot) do
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if Assigned(Node.PrevSibling) then
+ begin
+ // if there's a previous sibling then add its total count to the result
+ Node := Node.PrevSibling;
+ Inc(Result, Node.TotalCount);
+ end
+ else
+ begin
+ Node := Node.Parent;
+ if Node <> FRoot then
+ Inc(Result);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode;
+
+// Adds a new node to the given parent node. This is simply done by increasing the child count of the
+// parent node. If Parent is nil then the new node is added as (last) top level node.
+// UserData can be used to set the first 4 bytes of the user data area to an initial value which can be used
+// in OnInitNode and will also cause to trigger the OnFreeNode event (if <> nil) even if the node is not yet
+// "officially" initialized.
+// AddChild is a compatibility method and will implicitly validate the parent node. This is however
+// against the virtual paradigm and hence I dissuade from its usage.
+
+var
+ NodeData: ^Pointer;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ CancelEditNode;
+
+ if Parent = nil then
+ Parent := FRoot;
+ if not (vsInitialized in Parent.States) then
+ InitNode(Parent);
+
+ // Locally stop updates of the tree in order to avoid usage of the new node before it is correctly set up.
+ // If the update count was 0 on enter then there will be a correct update at the end of this method.
+ Inc(FUpdateCount);
+ try
+ SetChildCount(Parent, Parent.ChildCount + 1);
+ // Update the hidden children flag of the parent. Nodes are added as being visible by default.
+ Exclude(Parent.States, vsAllChildrenHidden);
+ finally
+ Dec(FUpdateCount);
+ end;
+ Result := Parent.LastChild;
+
+ // Check if there is initial user data and there is also enough user data space allocated.
+ if Assigned(UserData) then
+ if FNodeDataSize >= 4 then
+ begin
+ NodeData := Pointer(PChar(@Result.Data) + FTotalInternalDataSize);
+ NodeData^ := UserData;
+ Include(Result.States, vsInitialUserData);
+ end
+ else
+ ShowError(SCannotSetUserData, hcTFCannotSetUserData);
+
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ if tsStructureChangePending in FStates then
+ begin
+ if Parent = FRoot then
+ StructureChange(nil, crChildAdded)
+ else
+ StructureChange(Parent, crChildAdded);
+ end;
+
+ if (toAutoSort in FOptions.FAutoOptions) and (FHeader.FSortColumn > InvalidColumn) then
+ Sort(Parent, FHeader.FSortColumn, FHeader.FSortDirection, True);
+
+ InvalidateToBottom(Parent);
+ UpdateScrollbars(True);
+ end;
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AddFromStream(Stream: TStream; TargetNode: PVirtualNode);
+
+// loads nodes from the given stream and adds them to TargetNode
+// the current content is not cleared before the load process starts (see also LoadFromStream)
+
+var
+ ThisID: TMagicID;
+ Version,
+ Count: Cardinal;
+ Node: PVirtualNode;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ // check first whether this is a stream we can read
+ Stream.ReadBuffer(ThisID, SizeOf(TMagicID));
+ if (ThisID[0] = MagicID[0]) and
+ (ThisID[1] = MagicID[1]) and
+ (ThisID[2] = MagicID[2]) and
+ (ThisID[5] = MagicID[5]) then
+ begin
+ Version := Word(ThisID[3]);
+ if Version <= VTTreeStreamVersion then
+ begin
+ BeginUpdate;
+ try
+ if Version < 2 then
+ Count := MaxInt
+ else
+ Stream.ReadBuffer(Count, SizeOf(Count));
+
+ while (Stream.Position < Stream.Size) and (Count > 0) do
+ begin
+ Dec(Count);
+ Node := MakeNewNode;
+ InternalConnectNode(Node, TargetNode, Self, amAddChildLast);
+ InternalAddFromStream(Stream, Version, Node);
+ end;
+ if TargetNode = FRoot then
+ DoNodeCopied(nil)
+ else
+ DoNodeCopied(TargetNode);
+ finally
+ EndUpdate;
+ end;
+ end
+ else
+ ShowError(SWrongStreamVersion, hcTFWrongStreamVersion);
+ end
+ else
+ ShowError(SWrongStreamVersion, hcTFWrongStreamVersion);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AfterConstruction;
+
+begin
+ inherited;
+
+ if FRoot = nil then
+ InitRootNode;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Assign(Source: TPersistent);
+
+begin
+ if (Source is TBaseVirtualTree) and not (toReadOnly in FOptions.FMiscOptions) then
+ with Source as TBaseVirtualTree do
+ begin
+ Self.Align := Align;
+ Self.Anchors := Anchors;
+ Self.AutoScrollDelay := AutoScrollDelay;
+ Self.AutoScrollInterval := AutoScrollInterval;
+ Self.AutoSize := AutoSize;
+ Self.Background := Background;
+ Self.BevelEdges := BevelEdges;
+ Self.BevelInner := BevelInner;
+ Self.BevelKind := BevelKind;
+ Self.BevelOuter := BevelOuter;
+ Self.BevelWidth := BevelWidth;
+ Self.BiDiMode := BiDiMode;
+ Self.BorderStyle := BorderStyle;
+ Self.BorderWidth := BorderWidth;
+ Self.ChangeDelay := ChangeDelay;
+ Self.CheckImageKind := CheckImageKind;
+ Self.Color := Color;
+ Self.Colors.Assign(Colors);
+ Self.Constraints.Assign(Constraints);
+ Self.Ctl3D := Ctl3D;
+ Self.DefaultNodeHeight := DefaultNodeHeight;
+ Self.DefaultPasteMode := DefaultPasteMode;
+ Self.DragCursor := DragCursor;
+ Self.DragImageKind := DragImageKind;
+ Self.DragKind := DragKind;
+ Self.DragMode := DragMode;
+ Self.Enabled := Enabled;
+ Self.Font := Font;
+ Self.Header := Header;
+ Self.HintAnimation := HintAnimation;
+ Self.HintMode := HintMode;
+ Self.HotCursor := HotCursor;
+ Self.Images := Images;
+ Self.ImeMode := ImeMode;
+ Self.ImeName := ImeName;
+ Self.Indent := Indent;
+ Self.Margin := Margin;
+ Self.NodeAlignment := NodeAlignment;
+ Self.NodeDataSize := NodeDataSize;
+ Self.TreeOptions := TreeOptions;
+ Self.ParentBiDiMode := ParentBiDiMode;
+ Self.ParentColor := ParentColor;
+ Self.ParentCtl3D := ParentCtl3D;
+ Self.ParentFont := ParentFont;
+ Self.ParentShowHint := ParentShowHint;
+ Self.PopupMenu := PopupMenu;
+ Self.RootNodeCount := RootNodeCount;
+ Self.ScrollBarOptions := ScrollBarOptions;
+ Self.ShowHint := ShowHint;
+ Self.StateImages := StateImages;
+ Self.TabOrder := TabOrder;
+ Self.TabStop := TabStop;
+ Self.Visible := Visible;
+ Self.SelectionCurveRadius := SelectionCurveRadius;
+ Self.SelectionBlendFactor := SelectionBlendFactor;
+ end
+ else
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.BeginDrag(Immediate: Boolean; Threshold: Integer);
+
+// Reintroduced method to allow to start OLE drag'n drop as well as VCL drag'n drop.
+
+begin
+ if FDragType = dtVCL then
+ begin
+ DoStateChange([tsVCLDragPending]);
+ inherited;
+ end
+ else
+ if (FStates * [tsOLEDragPending, tsOLEDragging]) = [] then
+ begin
+ // Drag start position has already been recorded in WMMouseDown.
+ if Threshold < 0 then
+ FDragThreshold := Mouse.DragThreshold
+ else
+ FDragThreshold := Threshold;
+ if Immediate then
+ DoDragging(FLastClickPos)
+ else
+ DoStateChange([tsOLEDragPending]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.BeginSynch;
+
+// Starts the synchronous update mode (if not already active).
+
+begin
+ if not (csDestroying in ComponentState) then
+ begin
+ if FSynchUpdateCount = 0 then
+ begin
+ DoUpdating(usBeginSynch);
+
+ // Stop all timers...
+ StopTimer(ChangeTimer);
+ StopTimer(StructureChangeTimer);
+ StopTimer(ExpandTimer);
+ StopTimer(EditTimer);
+ StopTimer(HeaderTimer);
+ StopTimer(ScrollTimer);
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+ DoStateChange([], [tsEditPending, tsScrollPending, tsScrolling, tsIncrementalSearching]);
+
+ // ...and trigger pending update states.
+ if tsStructureChangePending in FStates then
+ DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason);
+ if tsChangePending in FStates then
+ DoChange(FLastChangedNode);
+ end
+ else
+ DoUpdating(usSynch);
+ end;
+ Inc(FSynchUpdateCount);
+ DoStateChange([tsSynchMode]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.BeginUpdate;
+
+begin
+ if not (csDestroying in ComponentState) then
+ begin
+ if FUpdateCount = 0 then
+ begin
+ DoUpdating(usBegin);
+ SetUpdateState(True);
+ end
+ else
+ DoUpdating(usUpdate);
+ end;
+ Inc(FUpdateCount);
+ DoStateChange([tsUpdating]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CancelCutOrCopy;
+
+// Resets nodes which are marked as being cut.
+
+var
+ Run: PVirtualNode;
+
+begin
+ if ([tsCutPending, tsCopyPending] * FStates) <> [] then
+ begin
+ Run := FRoot.FirstChild;
+ while Assigned(Run) do
+ begin
+ if vsCutOrCopy in Run.States then
+ Exclude(Run.States, vsCutOrCopy);
+ Run := GetNextNoInit(Run);
+ end;
+ end;
+ DoStateChange([], [tsCutPending, tsCopyPending]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CancelEditNode: Boolean;
+
+// Called by the application or the current edit link to cancel the edit action.
+
+begin
+ if HandleAllocated and ([tsEditing, tsEditPending] * FStates <> []) then
+ Result := DoCancelEdit
+ else
+ Result := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CanFocus: Boolean;
+
+var
+ Form: TCustomForm;
+
+begin
+ {$ifdef COMPILER_5_UP}
+ Result := inherited CanFocus;
+ {$else}
+ Result := True;
+ {$endif}
+
+ if Result then
+ begin
+ Form := GetParentForm(Self);
+ Result := (Form = nil) or (Form.Enabled and Form.Visible);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Clear;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) or (csDestroying in ComponentState) then
+ begin
+ BeginUpdate;
+ try
+ InterruptValidation;
+ if IsEditing then
+ CancelEditNode;
+
+ if ClipboardStates * FStates <> [] then
+ begin
+ OleSetClipBoard(nil);
+ DoStateChange([], ClipboardStates);
+ end;
+ ClearSelection;
+ FFocusedNode := nil;
+ FLastSelected := nil;
+ FCurrentHotNode := nil;
+ DeleteChildren(FRoot, True);
+ FVisibleCount := 0;
+ FOffsetX := 0;
+ FOffsetY := 0;
+
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager.Clear;
+ {$endif UseLocalMemoryManager}
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ClearSelection;
+
+var
+ Node: PVirtualNode;
+ Dummy: Integer;
+ R: TRect;
+ Counter: Integer;
+
+begin
+ if (FSelectionCount > 0) and not (csDestroying in ComponentState) then
+ begin
+ if (FUpdateCount = 0) and HandleAllocated and (FVisibleCount > 0) then
+ begin
+ // Iterate through nodes currently visible in the client area and invalidate them.
+ Node := GetNodeAt(0, 0, True, Dummy);
+ if Assigned(Node) then
+ R := GetDisplayRect(Node, NoColumn, False);
+ Counter := FSelectionCount;
+
+ while Assigned(Node) do
+ begin
+ R.Bottom := R.Top + Node.NodeHeight;
+ if vsSelected in Node.States then
+ begin
+ InvalidateRect(Handle, @R, False);
+ Dec(Counter);
+ // Only try as many nodes as are selected.
+ if Counter = 0 then
+ Break;
+ end;
+ R.Top := R.Bottom;
+ if R.Top > ClientHeight then
+ Break;
+ Node := GetNextVisibleNoInit(Node);
+ end;
+ end;
+
+ InternalClearSelection;
+ Change(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CopyTo(Source: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean): PVirtualNode;
+
+// A simplified CopyTo method to allow to copy nodes to the root of another tree.
+
+begin
+ Result := CopyTo(Source, Tree.FRoot, Mode, ChildrenOnly);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CopyTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean): PVirtualNode;
+
+// Copies Source and all its child nodes to Target.
+// Mode is used to specify further where to add the new node actually (as sibling of Target or as child of Target).
+// Result is the newly created node to which source has been copied if ChildrenOnly is False or just contains Target
+// in the other case.
+// ChildrenOnly determines whether to copy also the source node or only its child nodes.
+
+var
+ TargetTree: TBaseVirtualTree;
+ Stream: TMemoryStream;
+
+begin
+ Assert(TreeFromNode(Source) = Self, 'The source tree must contain the source node.');
+
+ Result := nil;
+ if (Mode <> amNoWhere) and Assigned(Source) and (Source <> FRoot) then
+ begin
+ // Assume that an empty destination means the root in this (the source) tree.
+ if Target = nil then
+ begin
+ TargetTree := Self;
+ Target := FRoot;
+ Mode := amAddChildFirst;
+ end
+ else
+ TargetTree := TreeFromNode(Target);
+
+ if not (toReadOnly in TargetTree.FOptions.FMiscOptions) then
+ begin
+ if Target = TargetTree.FRoot then
+ begin
+ case Mode of
+ amInsertBefore:
+ Mode := amAddChildFirst;
+ amInsertAfter:
+ Mode := amAddChildLast;
+ end;
+ end;
+
+ Stream := TMemoryStream.Create;
+ try
+ // Write all nodes into a temprary stream depending on the ChildrenOnly flag.
+ if not ChildrenOnly then
+ WriteNode(Stream, Source)
+ else
+ begin
+ Source := Source.FirstChild;
+ while Assigned(Source) do
+ begin
+ WriteNode(Stream, Source);
+ Source := Source.NextSibling;
+ end;
+ end;
+ // Now load the serialized nodes into the target node (tree).
+ TargetTree.BeginUpdate;
+ try
+ Stream.Position := 0;
+ while Stream.Position < Stream.Size do
+ begin
+ Result := TargetTree.MakeNewNode;
+ InternalConnectNode(Result, Target, TargetTree, Mode);
+ TargetTree.InternalAddFromStream(Stream, VTTreeStreamVersion, Result);
+ if not DoNodeCopying(Result, Target) then
+ begin
+ TargetTree.DeleteNode(Result);
+ Result := nil;
+ end
+ else
+ DoNodeCopied(Result);
+ end;
+ if ChildrenOnly then
+ Result := Target;
+ finally
+ TargetTree.EndUpdate;
+ end;
+ finally
+ Stream.Free;
+ end;
+
+ with TargetTree do
+ begin
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ Invalidate;
+ end;
+ StructureChange(Source, crNodeCopied);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CopyToClipBoard;
+
+var
+ DataObject: IDataObject;
+
+begin
+ if FSelectionCount > 0 then
+ begin
+ DataObject := TVTDataObject.Create(Self, True) as IDataObject;
+ if OleSetClipBoard(DataObject) = S_OK then
+ begin
+ MarkCutCopyNodes;
+ DoStateChange([tsCopyPending]);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CutToClipBoard;
+
+var
+ DataObject: IDataObject;
+
+begin
+ if (FSelectionCount > 0) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ DataObject := TVTDataObject.Create(Self, True) as IDataObject;
+ if OleSetClipBoard(DataObject) = S_OK then
+ begin
+ MarkCutCopyNodes;
+ DoStateChange([tsCutPending]);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DeleteChildren(Node: PVirtualNode; ResetHasChildren: Boolean = False);
+
+// Removes all children and their children from memory without changing the vsHasChildren style by default.
+
+var
+ Run,
+ Mark: PVirtualNode;
+ LastTop,
+ LastLeft: Integer;
+ ParentVisible: Boolean;
+
+begin
+ if (Node.ChildCount > 0) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Assert(not (tsIterating in FStates), 'Deleting nodes during tree iteration leads to invalid pointers.');
+
+ // The code below uses some flags for speed improvements which may cause invalid pointers if updates of
+ // the tree happen. Hence switch updates off until we have finished the operation.
+ Inc(FUpdateCount);
+ try
+ InterruptValidation;
+ LastLeft := FOffsetX;
+ LastTop := FOffsetY;
+
+ // Make a local copy of the visibility state of this node to speed up
+ // adjusting the visible nodes count.
+ ParentVisible := Node = FRoot;
+ if not ParentVisible then
+ ParentVisible := FullyVisible[Node] and (vsExpanded in Node.States);
+
+ // Show that we are clearing the child list, to avoid registering structure change events.
+ Include(Node.States, vsClearing);
+ Run := Node.LastChild;
+ while Assigned(Run) do
+ begin
+ if ParentVisible and (vsVisible in Run.States) then
+ Dec(FVisibleCount);
+
+ Include(Run.States, vsDeleting);
+ Mark := Run;
+ Run := Run.PrevSibling;
+ // Important, to avoid exchange of invalid pointers while disconnecting the node.
+ if Assigned(Run) then
+ Run.NextSibling := nil;
+ DeleteNode(Mark);
+ end;
+ Exclude(Node.States, vsClearing);
+ if ResetHasChildren then
+ Exclude(Node.States, vsHasChildren);
+ if Node <> FRoot then
+ Exclude(Node.States, vsExpanded);
+ Node.ChildCount := 0;
+ if (Node = FRoot) or (vsDeleting in Node.States) then
+ begin
+ Node.TotalHeight := Node.NodeHeight;
+ Node.TotalCount := 1;
+ end
+ else
+ begin
+ AdjustTotalHeight(Node, Node.NodeHeight);
+ AdjustTotalCount(Node, 1);
+ end;
+ Node.FirstChild := nil;
+ Node.LastChild := nil;
+ finally
+ Dec(FUpdateCount);
+ end;
+
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ UpdateScrollbars(True);
+ // Invalidate entire tree if it scrolled e.g. to make the last node also the
+ // bottom node in the treeview.
+ if (LastLeft <> FOffsetX) or (LastTop <> FOffsetY) then
+ Invalidate
+ else
+ InvalidateToBottom(Node);
+ end;
+ StructureChange(Node, crChildDeleted);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DeleteNode(Node: PVirtualNode; Reindex: Boolean = True);
+
+var
+ LastTop,
+ LastLeft: Integer;
+ LastParent: PVirtualNode;
+ WasInSynchMode: Boolean;
+ ParentClearing: Boolean;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Assert(not (tsIterating in FStates), 'Deleting nodes during tree iteration leads to invalid pointers.');
+
+ // Determine parent node for structure change notification.
+ ParentClearing := vsClearing in Node.Parent.States;
+ LastParent := Node.Parent;
+
+ if not ParentClearing then
+ begin
+ if LastParent = FRoot then
+ StructureChange(nil, crChildDeleted)
+ else
+ StructureChange(LastParent, crChildDeleted);
+ end;
+
+ LastLeft := FOffsetX;
+ LastTop := FOffsetY;
+
+ if vsSelected in Node.States then
+ begin
+ if FUpdateCount = 0 then
+ begin
+ // Go temporarily into sync mode to avoid a delayed change event for the node
+ // when unselecting.
+ WasInSynchMode := tsSynchMode in FStates;
+ Include(FStates, tsSynchMode);
+ RemoveFromSelection(Node);
+ if not WasInSynchMode then
+ Exclude(FStates, tsSynchMode);
+ InvalidateToBottom(LastParent);
+ end
+ else
+ InternalRemoveFromSelection(Node);
+ end
+ else
+ InvalidateToBottom(LastParent);
+
+ if tsHint in FStates then
+ begin
+ Application.CancelHint;
+ DoStateChange([], [tsHint]);
+ end;
+
+ DeleteChildren(Node);
+ InternalDisconnectNode(Node, False, Reindex);
+ DoFreeNode(Node);
+
+ if not ParentClearing then
+ begin
+ DetermineHiddenChildrenFlag(LastParent);
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ UpdateScrollbars(True);
+ // Invalidate entire tree if it scrolled e.g. to make the last node also the
+ // bottom node in the treeview.
+ if (LastLeft <> FOffsetX) or (LastTop <> FOffsetY) then
+ Invalidate;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DeleteSelectedNodes;
+
+// Deletes all currently selected nodes (including their child nodes).
+
+var
+ Nodes: TNodeArray;
+ I: Integer;
+ LevelChange: Boolean;
+
+begin
+ Nodes := nil;
+ if (FSelectionCount > 0) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ BeginUpdate;
+ try
+ Nodes := GetSortedSelection(True);
+ for I := High(Nodes) downto 1 do
+ begin
+ LevelChange := Nodes[I].Parent <> Nodes[I - 1].Parent;
+ DeleteNode(Nodes[I], LevelChange);
+ end;
+ DeleteNode(Nodes[0]);
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.Dragging: Boolean;
+
+begin
+ // Check for both OLE drag'n drop as well as VCL drag'n drop.
+ Result := ([tsOLEDragPending, tsOLEDragging] * FStates <> []) or inherited Dragging;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.EditNode(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// Application triggered edit event for the given node.
+// Returns True if the tree started editing otherwise False.
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+ Assert((Column > InvalidColumn) and (Column < FHeader.Columns.Count),
+ 'Column must be a valid column index (-1 if no header is shown).');
+
+ Result := tsEditing in FStates;
+ // If the tree is already editing then we don't disrupt this.
+ if not Result and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ FocusedNode := Node;
+ if Assigned(FFocusedNode) and (Node = FFocusedNode) and CanEdit(FFocusedNode, Column) then
+ begin
+ FEditColumn := Column;
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ DoEdit;
+ Result := tsEditing in FStates;
+ end
+ else
+ Result := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.EndEditNode: Boolean;
+
+// Called by the application or the current edit link to finish the edit action.
+
+begin
+ if [tsEditing, tsEditPending] * FStates <> [] then
+ Result := DoEndEdit
+ else
+ Result := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.EndSynch;
+
+begin
+ if FSynchUpdateCount > 0 then
+ Dec(FSynchUpdateCount);
+
+ if not (csDestroying in ComponentState) then
+ begin
+ if FSynchUpdateCount = 0 then
+ begin
+ DoStateChange([], [tsSynchMode]);
+ DoUpdating(usEndSynch);
+ end
+ else
+ DoUpdating(usSynch);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.EndUpdate;
+
+var
+ NewSize: Integer;
+
+begin
+ if FUpdateCount > 0 then
+ Dec(FUpdateCount);
+
+ if not (csDestroying in ComponentState) then
+ begin
+ if (FUpdateCount = 0) and (tsUpdating in FStates) then
+ begin
+ if tsUpdateHiddenChildrenNeeded in FStates then
+ begin
+ DetermineHiddenChildrenFlagAllNodes;
+ Exclude(FStates, tsUpdateHiddenChildrenNeeded);
+ end;
+
+ DoStateChange([], [tsUpdating]);
+
+ NewSize := PackArray(FSelection, FSelectionCount);
+ if NewSize > -1 then
+ begin
+ FSelectionCount := NewSize;
+ SetLength(FSelection, FSelectionCount);
+ end;
+ ValidateCache;
+ if HandleAllocated then
+ UpdateScrollBars(True);
+
+ if tsStructureChangePending in FStates then
+ DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason);
+ if tsChangePending in FStates then
+ DoChange(FLastChangedNode);
+
+ if toAutoSort in FOptions.FAutoOptions then
+ SortTree(FHeader.FSortColumn, FHeader.FSortDirection, True);
+
+ SetUpdateState(False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+
+ if FUpdateCount = 0 then
+ DoUpdating(usEnd)
+ else
+ DoUpdating(usUpdate);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ExecuteAction(Action: TBasicAction): Boolean;
+
+// Some support for standard actions.
+
+begin
+ Result := inherited ExecuteAction(Action);
+
+ if not Result and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Result := Action is TEditCut;
+ if Result then
+ CutToClipboard
+ else
+ begin
+ Result := Action is TEditCopy;
+ if Result then
+ CopyToClipboard
+ else
+ begin
+ Result := Action is TEditPaste;
+ if Result then
+ PasteFromClipboard
+ {$ifdef COMPILER_5_UP}
+ else
+ begin
+ Result := Action is TEditDelete;
+ if Result then
+ DeleteSelectedNodes
+ else
+ begin
+ Result := Action is TEditSelectAll;
+ if Result then
+ SelectAll(False);
+ end;
+ end;
+ {$endif COMPILER_5_UP}
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FinishCutOrCopy;
+
+// Deletes nodes which are marked as being cutted.
+
+var
+ Run: PVirtualNode;
+
+begin
+ if tsCutPending in FStates then
+ begin
+ Run := FRoot.FirstChild;
+ while Assigned(Run) do
+ begin
+ if vsCutOrCopy in Run.States then
+ DeleteNode(Run);
+ Run := GetNextNoInit(Run);
+ end;
+ DoStateChange([], [tsCutPending]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FlushClipboard;
+
+// Used to render the data which is currently on the clipboard (finishes delayed rendering).
+
+begin
+ if ClipboardStates * FStates <> [] then
+ begin
+ DoStateChange([tsClipboardFlushing]);
+ OleFlushClipboard;
+ CancelCutOrCopy;
+ DoStateChange([], [tsClipboardFlushing]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FullCollapse(Node: PVirtualNode = nil);
+
+// This routine collapses all expanded nodes in the subtree given by Node or the whole tree if Node is FRoot or nil.
+// Only nodes which are expanded will be collapsed. This excludes uninitialized nodes but nodes marked as visible
+// will still be collapsed if they are expanded.
+
+var
+ Stop: PVirtualNode;
+
+begin
+ if FRoot.TotalCount > 1 then
+ begin
+ if Node = FRoot then
+ Node := nil;
+
+ DoStateChange([tsCollapsing]);
+ BeginUpdate;
+ try
+ Stop := Node;
+ Node := GetLastVisibleNoInit(Node);
+
+ if Assigned(Node) then
+ begin
+ repeat
+ if [vsHasChildren, vsExpanded] * Node.States = [vsHasChildren, vsExpanded] then
+ ToggleNode(Node);
+ Node := GetPreviousNoInit(Node);
+ until Node = Stop;
+
+ // Collapse the start node too.
+ if Assigned(Node) and ([vsHasChildren, vsExpanded] * Node.States = [vsHasChildren, vsExpanded]) then
+ ToggleNode(Node);
+ end;
+ finally
+ EndUpdate;
+ DoStateChange([], [tsCollapsing]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FullExpand(Node: PVirtualNode = nil);
+
+// This routine expands all collapsed nodes in the subtree given by Node or the whole tree if Node is FRoot or nil.
+// All nodes on the way down are initialized so this procedure might take a long time.
+// Since all nodes are validated, the tree cannot make use of optimatizations. Hence it is counter productive and you
+// should consider avoiding its use.
+
+var
+ Stop: PVirtualNode;
+
+begin
+ if FRoot.TotalCount > 1 then
+ begin
+ DoStateChange([tsExpanding]);
+ BeginUpdate;
+ try
+ if Node = nil then
+ begin
+ Node := FRoot.FirstChild;
+ Stop := nil;
+ end
+ else
+ begin
+ Stop := Node.NextSibling;
+ if Stop = nil then
+ begin
+ Stop := Node;
+ repeat
+ Stop := Stop.Parent;
+ until (Stop = FRoot) or Assigned(Stop.NextSibling);
+ if Stop = FRoot then
+ Stop := nil
+ else
+ Stop := Stop.NextSibling;
+ end;
+ end;
+
+ // Initialize the start node. Others will be initialized in GetNext.
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ repeat
+ if not (vsExpanded in Node.States) then
+ ToggleNode(Node);
+ Node := GetNext(Node);
+ until Node = Stop;
+ finally
+ EndUpdate;
+ DoStateChange([], [tsExpanding]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetControlsAlignment: TAlignment;
+
+begin
+ Result := FAlignment;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetDisplayRect(Node: PVirtualNode; Column: TColumnIndex; TextOnly: Boolean;
+ Unclipped: Boolean = False): TRect;
+
+// Determines the client coordinates the given node covers, depending on scrolling, expand state etc.
+// If the given node cannot be found (because one of its parents is collapsed or it is invisible) then an empty
+// rectangle is returned.
+// If TextOnly is True then only the text bounds are returned, that is, the resulting rectangle's left and right border
+// are updated according to bidi mode, alignment and text width of the node.
+// If Unclipped is True (which only makes sense if also TextOnly is True) then the calculated text rectangle is
+// not clipped if the text does not entirely fit into the text space. This is special handling needed for hints.
+// If Column is -1 then the entire client width is used before determining the node's width otherwise the bounds of the
+// particular column are used.
+// Note: Column must be a valid column and is used independent of whether the header is visible or not.
+
+var
+ Temp: PVirtualNode;
+ Offset: Cardinal;
+ Indent,
+ TextWidth: Integer;
+ MainColumnHit,
+ Ghosted: Boolean;
+ CurrentBidiMode: TBidiMode;
+ CurrentAlignment: TAlignment;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+ Assert(Node <> FRoot, 'Node must not be the hidden root node.');
+
+ MainColumnHit := (Column + 1) in [0, FHeader.MainColumn + 1];
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ Result := Rect(0, 0, 0, 0);
+
+ // Check whether the node is visible (determine indentation level btw.).
+ Temp := Node;
+ Indent := 0;
+ while Temp <> FRoot do
+ begin
+ if not (vsVisible in Temp.States) or not (vsExpanded in Temp.Parent.States) then
+ Exit;
+ Temp := Temp.Parent;
+ if MainColumnHit and (Temp <> FRoot) then
+ Inc(Indent, FIndent);
+ end;
+
+ // Here we know the node is visible.
+ Offset := 0;
+ if tsUseCache in FStates then
+ begin
+ // If we can use the position cache then do a binary search to find a cached node which is as close as possible
+ // to the current node. Iterate then through all following and visible nodes and sum up their heights.
+ Temp := FindInPositionCache(Node, Offset);
+ while Assigned(Temp) and (Temp <> Node) do
+ begin
+ Inc(Offset, Temp.NodeHeight);
+ Temp := GetNextVisibleNoInit(Temp);
+ end;
+ end
+ else
+ begin
+ // If the cache is not available then go straight through all nodes up to the root and sum up their heights.
+ Temp := Node;
+ repeat
+ Temp := GetPreviousVisibleNoInit(Temp);
+ if Temp = nil then
+ Break;
+ Inc(Offset, Temp.NodeHeight);
+ until False;
+ end;
+
+ Result := Rect(0, Offset, Max(FRangeX, ClientWidth), Offset + Node.NodeHeight);
+
+ // Limit left and right bounds to the given column (if any) and move bounds according to current scroll state.
+ if Column > NoColumn then
+ begin
+ FHeader.FColumns.GetColumnBounds(Column, Result.Left, Result.Right);
+ // The right column border is not part of this cell.
+ Dec(Result.Right);
+ OffsetRect(Result, 0, FOffsetY);
+ end
+ else
+ OffsetRect(Result, FOffsetX, FOffsetY);
+
+ // Limit left and right bounds further if only the text area is required.
+ if TextOnly then
+ begin
+ // Start with the offset of the text in the column and consider the indentation level too.
+ Offset := FMargin + Indent;
+ // If the text of a node is involved then we have to consider directionality and alignment too.
+ if Column = NoColumn then
+ begin
+ CurrentBidiMode := BidiMode;
+ CurrentAlignment := Alignment;
+ end
+ else
+ begin
+ CurrentBidiMode := FHeader.FColumns[Column].BidiMode;
+ CurrentAlignment := FHeader.FColumns[Column].Alignment;
+ end;
+
+ TextWidth := DoGetNodeWidth(Node, Column);
+
+ if MainColumnHit then
+ begin
+ if toShowRoot in FOptions.FPaintOptions then
+ Inc(Offset, FIndent);
+ if (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages) and (Node.CheckType <> ctNone) then
+ Inc(Offset, FCheckImages.Width + 2);
+ end;
+ // Consider associated images.
+ if Assigned(FStateImages) and (GetImageIndex(Node, ikState, Column, Ghosted) > -1) then
+ Inc(Offset, FStateImages.Width + 2);
+ if Assigned(FImages) and (GetImageIndex(Node, ikNormal, Column, Ghosted) > -1) then
+ Inc(Offset, FImages.Width + 2);
+
+ // Offset contains now the distance from the left or right border of the rectangle (depending on bidi mode).
+ // Now consider the alignment too and calculate the final result.
+ if CurrentBidiMode = bdLeftToRight then
+ begin
+ Inc(Result.Left, Offset);
+ // Left-to-right reading does not need any special adjustment of the alignment.
+ end
+ else
+ begin
+ Dec(Result.Right, Offset);
+
+ // Consider bidi mode here. In RTL context does left alignment actually mean right alignment and vice versa.
+ ChangeBiDiModeAlignment(CurrentAlignment);
+ end;
+
+ if Unclipped then
+ begin
+ // The caller requested the text coordinates unclipped. This means they must be calculated so as would
+ // there be enough space, regardless of column bounds etc.
+ // The layout still depends on the available space too, because this determines the position
+ // of the unclipped text rectangle.
+ if Result.Right - Result.Left < TextWidth then
+ if CurrentBidiMode = bdLeftToRight then
+ CurrentAlignment := taLeftJustify
+ else
+ CurrentAlignment := taRightJustify;
+
+ case CurrentAlignment of
+ taCenter:
+ begin
+ Result.Left := (Result.Left + Result.Right - TextWidth) div 2;
+ Result.Right := Result.Left + TextWidth;
+ end;
+ taRightJustify:
+ Result.Left := Result.Right - TextWidth;
+ else // taLeftJustify
+ Result.Right := Result.Left + TextWidth;
+ end;
+ end
+ else
+ // Modify rectangle only if the text fits entirely into the given room.
+ if Result.Right - Result.Left > TextWidth then
+ case CurrentAlignment of
+ taCenter:
+ begin
+ Result.Left := (Result.Left + Result.Right - TextWidth) div 2;
+ Result.Right := Result.Left + TextWidth;
+ end;
+ taRightJustify:
+ Result.Left := Result.Right - TextWidth;
+ else // taLeftJustify
+ Result.Right := Result.Left + TextWidth;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirst: PVirtualNode;
+
+// Returns the first node in the tree.
+
+begin
+ Result := FRoot.FirstChild;
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstChild(Node: PVirtualNode): PVirtualNode;
+
+// Returns the first child of the given node. The result node is initialized before exit.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.FirstChild
+ else
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if vsHasChildren in Node.States then
+ begin
+ if Node.ChildCount = 0 then
+ InitChildren(Node);
+ Result := Node.FirstChild;
+ end
+ else
+ Result := nil;
+ end;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstCutCopy: PVirtualNode;
+
+// Returns the first node in the tree which is currently marked for a clipboard operation.
+// See also GetNextCutCopy for comments on initialization.
+
+begin
+ Result := GetNextCutCopy(nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstInitialized: PVirtualNode;
+
+// Returns the first node which is already initialized.
+
+begin
+ Result := FRoot.FirstChild;
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ Result := GetNextInitialized(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstNoInit: PVirtualNode;
+
+begin
+ Result := FRoot.FirstChild;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstSelected: PVirtualNode;
+
+// Returns the first node in the current selection.
+
+begin
+ Result := GetNextSelected(nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstVisible: PVirtualNode;
+
+// Returns the first visible node in the tree. If necessary nodes are initialized on demand.
+
+begin
+ if vsHasChildren in FRoot.States then
+ begin
+ Result := FRoot;
+
+ if Result.ChildCount = 0 then
+ InitChildren(Result);
+
+ // Child nodes are the first choice if possible.
+ if Assigned(Result.FirstChild) then
+ begin
+ Result := GetFirstChild(Result);
+
+ // If there are no children or the first child is not visible then search the sibling nodes or traverse parents.
+ if not (vsVisible in Result.States) then
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ // The visible state can be removed during initialization so init the node first.
+ if not (vsInitialized in Result.States) then
+ InitNode(Result);
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end
+ else
+ Result := nil;
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstVisibleChild(Node: PVirtualNode): PVirtualNode;
+
+// Returns the first visible child node of Node. If necessary nodes are initialized on demand.
+
+begin
+ Result := GetFirstChild(Node);
+ if Assigned(Result) and not (vsVisible in Result.States) then
+ Result := GetNextVisibleSibling(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstVisibleChildNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the first visible child node of Node.
+
+begin
+ if Node = nil then
+ Node := FRoot;
+ Result := Node.FirstChild;
+ if Assigned(Result) and not (vsVisible in Result.States) then
+ Result := GetNextVisibleSiblingNoInit(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstVisibleNoInit: PVirtualNode;
+
+// Returns the first visible node in the tree. No initialization is performed.
+
+begin
+ if vsHasChildren in FRoot.States then
+ begin
+ Result := FRoot;
+
+ // Child nodes are the first choice if possible.
+ if Assigned(Result.FirstChild) then
+ begin
+ Result := Result.FirstChild;
+
+ // If there are no children or the first child is not visible then search the sibling nodes or traverse parents.
+ if not (vsVisible in Result.States) then
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end
+ else
+ Result := nil;
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.GetHitTestInfoAt(X, Y: Integer; Relative: Boolean; var HitInfo: THitInfo);
+
+// Determines the node that occupies the specified point or nil if there's none. The parameter Relative determines
+// whether to consider X and Y as being client coordinates (if True) or as being absolute tree coordinates.
+// HitInfo is filled with flags describing the hit further.
+
+var
+ ColLeft,
+ ColRight: Integer;
+ NodeTop: Integer;
+ InitialColumn,
+ NextColumn: TColumnIndex;
+ CurrentBidiMode: TBidiMode;
+ CurrentAlignment: TAlignment;
+
+begin
+ HitInfo.HitNode := nil;
+ HitInfo.HitPositions := [];
+ HitInfo.HitColumn := NoColumn;
+
+ // Determine if point lies in the tree's client area.
+ if X < 0 then
+ Include(HitInfo.HitPositions, hiToLeft)
+ else
+ if X > Max(FRangeX, ClientWidth) then
+ Include(HitInfo.HitPositions, hiToRight);
+
+ if Y < 0 then
+ Include(HitInfo.HitPositions, hiAbove)
+ else
+ if Y > Max(FRangeY, ClientHeight) then
+ Include(HitInfo.HitPositions, hiBelow);
+
+ // Convert position into absolute coordinate if necessary.
+ if Relative then
+ begin
+ Inc(X, -FOffsetX);
+ Inc(Y, -FOffsetY);
+ end;
+
+ // If the point is in the tree area then check the nodes.
+ if HitInfo.HitPositions = [] then
+ begin
+ HitInfo.HitNode := GetNodeAt(X, Y, False, NodeTop);
+ if HitInfo.HitNode = nil then
+ Include(HitInfo.HitPositions, hiNowhere)
+ else
+ begin
+ // At this point we need some info about the node, so it must be initialized.
+ if not (vsInitialized in HitInfo.HitNode.States) then
+ InitNode(HitInfo.HitNode);
+
+ if FHeader.UseColumns then
+ begin
+ HitInfo.HitColumn := FHeader.Columns.GetColumnAndBounds(Point(X, Y), ColLeft, ColRight, False);
+ // If auto column spanning is enabled then look for the last non empty column.
+ if toAutoSpanColumns in FOptions.FAutoOptions then
+ begin
+ InitialColumn := HitInfo.HitColumn;
+ // Search to the left of the hit column for empty columns.
+ while (HitInfo.HitColumn > NoColumn) and ColumnIsEmpty(HitInfo.HitNode, HitInfo.HitColumn) do
+ begin
+ NextColumn := FHeader.FColumns.GetPreviousVisibleColumn(HitInfo.HitColumn);
+ if NextColumn = InvalidColumn then
+ Break;
+ HitInfo.HitColumn := NextColumn;
+ Dec(ColLeft, FHeader.FColumns[NextColumn].Width);
+ end;
+ // Search to the right of the hit column for empty columns.
+ repeat
+ InitialColumn := FHeader.FColumns.GetNextVisibleColumn(InitialColumn);
+ if (InitialColumn = InvalidColumn) or not ColumnIsEmpty(HitInfo.HitNode, InitialColumn) then
+ Break;
+ Inc(ColRight, FHeader.FColumns[InitialColumn].Width);
+ until False;
+ end;
+ // Make the X position and the right border relative to the start of the column.
+ Dec(X, ColLeft);
+ Dec(ColRight, ColLeft);
+ end
+ else
+ begin
+ HitInfo.HitColumn := NoColumn;
+ ColRight := Max(FRangeX, ClientWidth);
+ end;
+ ColLeft := 0;
+
+ if HitInfo.HitColumn = InvalidColumn then
+ Include(HitInfo.HitPositions, hiNowhere)
+ else
+ begin
+ // From now on X is in "column" coordinates (relative to the left column border).
+ HitInfo.HitPositions := [hiOnItem];
+ if HitInfo.HitColumn = NoColumn then
+ begin
+ CurrentBidiMode := BidiMode;
+ CurrentAlignment := Alignment;
+ end
+ else
+ begin
+ CurrentBidiMode := FHeader.FColumns[HitInfo.HitColumn].BidiMode;
+ CurrentAlignment := FHeader.FColumns[HitInfo.HitColumn].Alignment;
+ end;
+
+ if CurrentBidiMode = bdLeftToRight then
+ DetermineHitPositionLTR(HitInfo, X, ColRight, CurrentAlignment)
+ else
+ DetermineHitPositionRTL(HitInfo, X, ColRight, CurrentAlignment);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLast(Node: PVirtualNode = nil): PVirtualNode;
+
+// Returns the very last node in the tree branch given by Node and initializes the nodes all the way down including the
+// result. By using Node = nil the very last node in the tree is returned.
+
+var
+ Next: PVirtualNode;
+
+begin
+ Result := GetLastChild(Node);
+ while Assigned(Result) do
+ begin
+ // Test if there is a next last child. If not keep the node from the last run.
+ // Otherwise use the next last child.
+ Next := GetLastChild(Result);
+ if Next = nil then
+ Break;
+ Result := Next;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastInitialized(Node: PVirtualNode): PVirtualNode;
+
+// Returns the very last initialized child node in the tree branch given by Node.
+
+begin
+ Result := GetLastNoInit(Node);
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ Result := GetPreviousInitialized(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastNoInit(Node: PVirtualNode = nil): PVirtualNode;
+
+// Returns the very last node in the tree branch given by Node without initialization.
+
+var
+ Next: PVirtualNode;
+
+begin
+ Result := GetLastChildNoInit(Node);
+ while Assigned(Result) do
+ begin
+ // Test if there is a next last child. If not keep the node from the last run.
+ // Otherwise use the next last child.
+ Next := GetLastChildNoInit(Result);
+ if Next = nil then
+ Break;
+ Result := Next;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastChild(Node: PVirtualNode): PVirtualNode;
+
+// Determines the last child of the given node and initializes it if there is one.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.LastChild
+ else
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if vsHasChildren in Node.States then
+ begin
+ if Node.ChildCount = 0 then
+ InitChildren(Node);
+ Result := Node.LastChild;
+ end
+ else
+ Result := nil;
+ end;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastChildNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Determines the last child of the given node but does not initialize it.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.LastChild
+ else
+ begin
+ if vsHasChildren in Node.States then
+ Result := Node.LastChild
+ else
+ Result := nil;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastVisible(Node: PVirtualNode = nil): PVirtualNode;
+
+// Returns the very last visible node in the tree and initializes nodes all the way down including the result node.
+
+var
+ Next: PVirtualNode;
+
+begin
+ Result := GetLastVisibleChild(Node);
+ while Assigned(Result) do
+ begin
+ // Test if there is a next last visible child. If not keep the node from the last run.
+ // Otherwise use the next last visible child.
+ Next := GetLastVisibleChild(Result);
+ if Next = nil then
+ Break;
+ Result := Next;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastVisibleChild(Node: PVirtualNode): PVirtualNode;
+
+// Determines the last visible child of the given node and initializes it if necessary.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := GetLastChild(FRoot)
+ else
+ if FullyVisible[Node] and (vsExpanded in Node.States) then
+ Result := GetLastChild(Node)
+ else
+ Result := nil;
+
+ if Assigned(Result) and not (vsVisible in Result.States) then
+ Result := GetPreviousVisibleSibling(Result);
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastVisibleChildNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Determines the last visible child of the given node without initialization.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := GetLastChildNoInit(FRoot)
+ else
+ if FullyVisible[Node] and (vsExpanded in Node.States) then
+ Result := GetLastChildNoInit(Node)
+ else
+ Result := nil;
+
+ if Assigned(Result) and not (vsVisible in Result.States) then
+ Result := GetPreviousVisibleSiblingNoInit(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastVisibleNoInit(Node: PVirtualNode = nil): PVirtualNode;
+
+// Returns the very last visible node in the tree without initialization.
+
+var
+ Next: PVirtualNode;
+
+begin
+ Result := GetLastVisibleChildNoInit(Node);
+ while Assigned(Result) do
+ begin
+ // Test if there is a next last visible child. If not keep the node from the last run.
+ // Otherwise use the next last visible child.
+ Next := GetLastVisibleChildNoInit(Result);
+ if Next = nil then
+ Break;
+ Result := Next;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetMaxColumnWidth(Column: TColumnIndex): Integer;
+
+// This method determines the width of the largest node in the given column.
+// Note: Every visible node in the tree will be initialized contradicting so the virtual paradigm.
+
+var
+ Run,
+ NextNode: PVirtualNode;
+ NodeLeft,
+ TextLeft,
+ CurrentWidth: Integer;
+ WithCheck,
+ WithImages,
+ WithStateImages,
+ Ghosted: Boolean;
+ CheckOffset,
+ ImageOffset,
+ StateImageOffset: Integer;
+
+begin
+ Result := 0;
+
+ // Don't check the event here as descendant trees might have overriden the DoGetImageIndex method.
+ WithImages := Assigned(FImages);
+ if WithImages then
+ ImageOffset := FImages.Width + 2
+ else
+ ImageOffset := 0;
+ WithStateImages := Assigned(FStateImages);
+ if WithStateImages then
+ StateImageOffset := FStateImages.Width + 2
+ else
+ StateImageOffset := 0;
+ if Assigned(FCheckImages) then
+ CheckOffset := FCheckImages.Width + 2
+ else
+ CheckOffset := 0;
+
+ Run := GetFirstVisible;
+ if Column = FHeader.MainColumn then
+ begin
+ if toShowRoot in FOptions.FPaintOptions then
+ NodeLeft := Integer((GetNodeLevel(Run) + 1) * FIndent)
+ else
+ NodeLeft := Integer(GetNodeLevel(Run) * FIndent);
+
+ WithCheck := (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages);
+ end
+ else
+ begin
+ NodeLeft := 0;
+ WithCheck := False;
+ end;
+
+ // Leave a margin at both sides of the nodes.
+ Inc(NodeLeft, 2 * FMargin);
+
+ while Assigned(Run) do
+ begin
+ TextLeft := NodeLeft;
+ if WithCheck and (Run.CheckType <> ctNone) then
+ Inc(TextLeft, CheckOffset);
+ if WithImages and (GetImageIndex(Run, ikNormal, Column, Ghosted) > -1) then
+ Inc(TextLeft, ImageOffset);
+ if WithStateImages and (GetImageIndex(Run, ikState, Column, Ghosted) > -1) then
+ Inc(TextLeft, StateImageOffset);
+
+ CurrentWidth := DoGetNodeWidth(Run, Column);
+
+ if Result < (TextLeft + CurrentWidth) then
+ Result := TextLeft + CurrentWidth;
+
+ // Get next visible node and update left node position if needed.
+ NextNode := GetNextVisible(Run);
+ if NextNode = nil then
+ Break;
+ if Column = Header.MainColumn then
+ Inc(NodeLeft, CountLevelDifference(Run, NextNode) * Integer(FIndent));
+ Run := NextNode;
+ end;
+ if toShowVertGridLines in FOptions.FPaintOptions then
+ Inc(Result)
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNext(Node: PVirtualNode): PVirtualNode;
+
+// Returns next node in tree (advances to next sibling of the node's parent or its parent, if necessary).
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // Has this node got children?
+ if vsHasChildren in Result.States then
+ begin
+ // Yes, there are child nodes. Initialize them if necessary.
+ if Result.ChildCount = 0 then
+ InitChildren(Result);
+ end;
+
+ // if there is no child node try siblings
+ if Assigned(Result.FirstChild) then
+ Result := Result.FirstChild
+ else
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextCutCopy(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next node in the tree which is currently marked for a clipboard operation. Since only visible nodes can
+// be marked (or they are hidden after they have been marked) it is not necessary to initialize nodes to check for
+// child nodes. The result, however, is initialized if necessary.
+
+begin
+ if ClipboardStates * FStates <> [] then
+ begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.FirstChild
+ else
+ Result := GetNextNoInit(Node);
+ while Assigned(Result) and not (vsCutOrCopy in Result.States) do
+ Result := GetNextNoInit(Result);
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextInitialized(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next node in tree which is initialized.
+
+begin
+ Result := Node;
+ repeat
+ Result := GetNextNoInit(Result);
+ until (Result = nil) or (vsInitialized in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextNoInit(Node: PVirtualNode): PVirtualNode;
+
+// optimized variant of GetNext, no initialization of nodes is performed (if a node is not initialized
+// then it is considered as not being there)
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // if there is no child node try siblings
+ if Assigned(Result.FirstChild) then
+ Result := Result.FirstChild
+ else
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextSelected(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next node in the tree which is currently selected. Since children of unitialized nodes cannot be
+// in the current selection (because they simply do not exist yet) it is not necessary to initialize nodes here.
+// The result however is initialized if necessary.
+
+begin
+ if FSelectionCount > 0 then
+ begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.FirstChild
+ else
+ Result := GetNextNoInit(Node);
+ while Assigned(Result) and not (vsSelected in Result.States) do
+ Result := GetNextNoInit(Result);
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextSibling(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next sibling of Node and initializes it if necessary.
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ Result := Node.NextSibling;
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextVisible(Node: PVirtualNode): PVirtualNode;
+
+// Returns next node in tree, with regard to Node, which is visible.
+// Nodes which need an initialization (including the result) are initialized.
+
+var
+ ForceSearch: Boolean;
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // If the given node is not visible then look for a parent node which is visible, otherwise we will
+ // likely go unnecessarily through a whole bunch of invisible nodes.
+ if not FullyVisible[Result] then
+ Result := GetVisibleParent(Result);
+
+ // Has this node got children?
+ if [vsHasChildren, vsExpanded] * Result.States = [vsHasChildren, vsExpanded] then
+ begin
+ // Yes, there are child nodes. Initialize them if necessary.
+ if Result.ChildCount = 0 then
+ InitChildren(Result);
+ end;
+
+ // Child nodes are the first choice if possible.
+ if (vsExpanded in Result.States) and Assigned(Result.FirstChild) then
+ begin
+ Result := GetFirstChild(Result);
+ ForceSearch := False;
+ end
+ else
+ ForceSearch := True;
+
+ // If there are no children or the first child is not visible then search the sibling nodes or traverse parents.
+ if Assigned(Result) and (ForceSearch or not (vsVisible in Result.States)) then
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ if not (vsInitialized in Result.States) then
+ InitNode(Result);
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextVisibleNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next node in tree, with regard to Node, which is visible.
+// No initialization is done.
+
+var
+ ForceSearch: Boolean;
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // If the given node is not visible then look for a parent node which is visible, otherwise we will
+ // likely go unnecessarily through a whole bunch of invisible nodes.
+ if not FullyVisible[Result] then
+ Result := GetVisibleParent(Result);
+
+ // Child nodes are the first choice if possible.
+ if (vsExpanded in Result.States) and Assigned(Result.FirstChild) then
+ begin
+ Result := Result.FirstChild;
+ ForceSearch := False;
+ end
+ else
+ ForceSearch := True;
+
+ // If there are no children or the first child is not visible then search the sibling nodes or traverse parents.
+ if ForceSearch or not (vsVisible in Result.States) then
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextVisibleSibling(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next visible sibling after Node. Initialization is done implicitly.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ Result := Node;
+ repeat
+ Result := GetNextSibling(Result);
+ until (Result = nil) or (vsVisible in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextVisibleSiblingNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next visible sibling after Node.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ Result := Node;
+ repeat
+ Result := Result.NextSibling;
+ until (Result = nil) or (vsVisible in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeAt(X, Y: Integer): PVirtualNode;
+
+// Overloaded variant of GetNodeAt to easy life of application developers which do not need to have the exact
+// top position returned and always use client coordinates.
+
+var
+ Dummy: Integer;
+
+begin
+ Result := GetNodeAt(X, Y, True, Dummy);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeAt(X, Y: Integer; Relative: Boolean; var NodeTop: Integer): PVirtualNode;
+
+// This method returns the node that occupies the specified point, or nil if there's none.
+// If Releative is True then X and Y are given in client coordinates otherwise they are considered as being
+// absolute values into the virtual tree image (regardless of the current offsets in the tree window).
+// NodeTop gets the absolute or relative top position of the node returned or is untouched if no node
+// could be found.
+
+var
+ AbsolutePos,
+ CurrentPos: Cardinal;
+
+begin
+ if Y < 0 then
+ Y := 0;
+
+ AbsolutePos := Y;
+ if Relative then
+ Inc(AbsolutePos, -FOffsetY);
+
+ // CurrentPos tracks a running term of the current position to test for.
+ // It corresponds always to the top position of the currently considered node.
+ CurrentPos := 0;
+
+ // If the cache is available then use it.
+ if tsUseCache in FStates then
+ Result := FindInPositionCache(AbsolutePos, CurrentPos)
+ else
+ Result := GetFirstVisibleNoInit;
+
+ // Determine node, of which position and height corresponds to the scroll position most closely.
+ while Assigned(Result) and (Result <> FRoot) do
+ begin
+ if (vsVisible in Result.States) and (AbsolutePos < (CurrentPos + Result.TotalHeight)) then
+ begin
+ // Found a node which covers the given position. Now go down one level
+ // and search its children (if any, otherwise stop looking).
+ if (AbsolutePos >= CurrentPos + Result.NodeHeight) and Assigned(Result.FirstChild) and
+ (vsExpanded in Result.States) then
+ begin
+ Inc(CurrentPos, Result.NodeHeight);
+ Result := Result.FirstChild;
+ Continue;
+ end
+ else
+ Break;
+ end
+ else
+ begin
+ // Advance current position to after the current node, if the node is visible.
+ if vsVisible in Result.States then
+ Inc(CurrentPos, Result.TotalHeight);
+ // Find following node not being a child of the currently considered node (e.g. a sibling or parent).
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end;
+
+ if Result = FRoot then
+ Result := nil;
+
+ // Since the given vertical position is likely not the same as the top position
+ // of the found node this top position is returned.
+ if Assigned(Result) then
+ begin
+ NodeTop := CurrentPos;
+ if Relative then
+ Inc(NodeTop, FOffsetY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeData(Node: PVirtualNode): Pointer;
+
+// Returns the address of the user defined data area in the node.
+
+begin
+ Assert(FNodeDataSize > 0, 'NodeDataSize not initialized.');
+
+ if (FNodeDataSize <= 0) or (Node = nil) or (Node = FRoot) then
+ Result := nil
+ else
+ Result := PChar(@Node.Data) + FTotalInternalDataSize;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeLevel(Node: PVirtualNode): Cardinal;
+
+// returns the level of the given node
+
+var
+ Run: PVirtualNode;
+
+begin
+ Result := 0;
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ Run := Node.Parent;
+ while Run <> FRoot do
+ begin
+ Run := Run.Parent;
+ Inc(Result);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPrevious(Node: PVirtualNode): PVirtualNode;
+
+// Resturns previous node in tree with regard to Node. The result node is initialized if necessary.
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(vsInitialized in Result.States, 'Node must already be initialized.');
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // Is there a previous sibling?
+ if Assigned(Node.PrevSibling) then
+ begin
+ // Go down and find the last child node.
+ Result := GetLast(Node.PrevSibling);
+ if Result = nil then
+ Result := Node.PrevSibling;
+ end
+ else
+ // no previous sibling so the parent of the node is the previous visible node
+ if Node.Parent <> FRoot then
+ Result := Node.Parent
+ else
+ Result := nil;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousInitialized(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous node in tree which is initialized.
+
+begin
+ Result := Node;
+ repeat
+ Result := GetPreviousNoInit(Result);
+ until (Result = nil) or (vsInitialized in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous node in the tree with regard to Node. No initialization in done, hence this
+// method might be faster than GetPrevious. Not yet initialized nodes are ignored during search.
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // Is there a previous sibling?
+ if Assigned(Node.PrevSibling) then
+ begin
+ // Go down and find the last child node.
+ Result := GetLastNoInit(Node.PrevSibling);
+ if Result = nil then
+ Result := Node.PrevSibling;
+ end
+ else
+ // No previous sibling so the parent of the node is the previous node.
+ if Node.Parent <> FRoot then
+ Result := Node.Parent
+ else
+ Result := nil
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousSibling(Node: PVirtualNode): PVirtualNode;
+
+// get next sibling of Node, initialize it if necessary
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ Result := Node.PrevSibling;
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousVisible(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous node in tree, with regard to Node, which is visible.
+// Nodes which need an initialization (including the result) are initialized.
+
+var
+ Marker: PVirtualNode;
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(vsInitialized in Result.States, 'Node must already be initialized.');
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // If the given node is not visible then look for a parent node which is visible and use its last visible
+ // child or the parent node (if there is no visible child) as result.
+ if not FullyVisible[Result] then
+ begin
+ Result := GetVisibleParent(Result);
+ if Result = FRoot then
+ Result := nil;
+ Marker := GetLastVisible(Result);
+ if Assigned(Marker) then
+ Result := Marker;
+ end
+ else
+ begin
+ repeat
+ // Is there a previous sibling node?
+ if Assigned(Result.PrevSibling) then
+ begin
+ Result := Result.PrevSibling;
+ // Initialize the new node and check its visibility.
+ if not (vsInitialized in Result.States) then
+ InitNode(Result);
+ if vsVisible in Result.States then
+ begin
+ // If there are visible child nodes then use the last one.
+ Marker := GetLastVisible(Result);
+ if Assigned(Marker) then
+ Result := Marker;
+ Break;
+ end;
+ end
+ else
+ begin
+ // No previous sibling there so the parent node is the nearest previous node.
+ Result := Result.Parent;
+ if Result = FRoot then
+ Result := nil;
+ Break;
+ end;
+ until False;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousVisibleNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous node in tree, with regard to Node, which is visible.
+
+var
+ Marker: PVirtualNode;
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // If the given node is not visible then look for a parent node which is visible and use its last visible
+ // child or the parent node (if there is no visible child) as result.
+ if not FullyVisible[Result] then
+ begin
+ Result := GetVisibleParent(Result);
+ if Result = FRoot then
+ Result := nil;
+ Marker := GetLastVisibleNoInit(Result);
+ if Assigned(Marker) then
+ Result := Marker;
+ end
+ else
+ begin
+ repeat
+ // Is there a previous sibling node?
+ if Assigned(Result.PrevSibling) then
+ begin
+ Result := Result.PrevSibling;
+ if vsVisible in Result.States then
+ begin
+ // If there are visible child nodes then use the last one.
+ Marker := GetLastVisibleNoInit(Result);
+ if Assigned(Marker) then
+ Result := Marker;
+ Break;
+ end;
+ end
+ else
+ begin
+ // No previous sibling there so the parent node is the nearest previous node.
+ Result := Result.Parent;
+ if Result = FRoot then
+ Result := nil;
+ Break;
+ end;
+ until False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousVisibleSibling(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous visible sibling before Node. Initialization is done implicitly.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ Result := Node;
+ repeat
+ Result := GetPreviousSibling(Result);
+ until (Result = nil) or (vsVisible in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousVisibleSiblingNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous visible sibling before Node.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ Result := Node;
+ repeat
+ Result := Result.PrevSibling;
+ until (Result = nil) or (vsVisible in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetSortedCutCopySet(Resolve: Boolean): TNodeArray;
+
+// Same as GetSortedSelection but with nodes marked as being part in the current cut/copy set (e.g. for clipboard).
+
+var
+ Run: PVirtualNode;
+ Counter: Cardinal;
+
+ //--------------- local function --------------------------------------------
+
+ procedure IncludeThisNode(Node: PVirtualNode);
+
+ // adds the given node to the result
+
+ var
+ Len: Cardinal;
+
+ begin
+ Len := Length(Result);
+ if Counter = Len then
+ begin
+ if Len < 100 then
+ Len := 100
+ else
+ Len := Len + Len div 10;
+ SetLength(Result, Len);
+ end;
+ Result[Counter] := Node;
+ Inc(Counter);
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+begin
+ Run := FRoot.FirstChild;
+ Counter := 0;
+ if Resolve then
+ begin
+ // Resolving is actually easy: just find the first cutted node in logical order
+ // and then never go deeper in level than this node as long as there's a sibling node.
+ // Restart the search for a cutted node (at any level) if there are no further siblings.
+ while Assigned(Run) do
+ begin
+ if vsCutOrCopy in Run.States then
+ begin
+ IncludeThisNode(Run);
+ if Assigned(Run.NextSibling) then
+ Run := Run.NextSibling
+ else
+ begin
+ // If there are no further siblings then go up one or more levels until a node is
+ // found or all nodes have been processed. Although we consider here only initialized
+ // nodes we don't need to make any special checks as only initialized nodes can also be selected.
+ repeat
+ Run := Run.Parent;
+ until (Run = FRoot) or Assigned(Run.NextSibling);
+ if Run = FRoot then
+ Break
+ else
+ Run := Run.NextSibling;
+ end;
+ end
+ else
+ Run := GetNextNoInit(Run);
+ end;
+ end
+ else
+ while Assigned(Run) do
+ begin
+ if vsCutOrCopy in Run.States then
+ IncludeThisNode(Run);
+ Run := GetNextNoInit(Run);
+ end;
+
+ // set the resulting array to its real length
+ SetLength(Result, Counter);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetSortedSelection(Resolve: Boolean): TNodeArray;
+
+// Returns a list of selected nodes sorted in logical order, that is, as they appear in the tree.
+// If Resolve is True then nodes which are children of other selected nodes are not put into the new array.
+// This feature is in particuar important when doing drag'n drop as in this case all selected node plus their children
+// need to be considered. A selected node which is child (grand child etc.) of another selected node is then
+// automatically included and doesn't need to be explicitely mentioned in the returned selection array.
+//
+// Note: The caller is responsible for freeing the array. Allocation is done here. Usually, though, freeing the array
+// doesn't need additional attention as it is automatically freed by Delphi when it gets out of scope.
+
+var
+ Run: PVirtualNode;
+ Counter: Cardinal;
+
+begin
+ SetLength(Result, FSelectionCount);
+ if FSelectionCount > 0 then
+ begin
+ Run := FRoot.FirstChild;
+ Counter := 0;
+ if Resolve then
+ begin
+ // Resolving is actually easy: just find the first selected node in logical order
+ // and then never go deeper in level than this node as long as there's a sibling node.
+ // Restart the search for a selected node (at any level) if there are no further siblings.
+ while Assigned(Run) do
+ begin
+ if vsSelected in Run.States then
+ begin
+ Result[Counter] := Run;
+ Inc(Counter);
+ if Assigned(Run.NextSibling) then
+ Run := Run.NextSibling
+ else
+ begin
+ // If there are no further siblings then go up one or more levels until a node is
+ // found or all nodes have been processed. Although we consider here only initialized
+ // nodes we don't need to make any special checks as only initialized nodes can also be selected.
+ repeat
+ Run := Run.Parent;
+ until (Run = FRoot) or Assigned(Run.NextSibling);
+ if Run = FRoot then
+ Break
+ else
+ Run := Run.NextSibling;
+ end;
+ end
+ else
+ Run := GetNextNoInit(Run);
+ end;
+ end
+ else
+ while Assigned(Run) do
+ begin
+ if vsSelected in Run.States then
+ begin
+ Result[Counter] := Run;
+ Inc(Counter);
+ end;
+ Run := GetNextNoInit(Run);
+ end;
+
+ // Since we may have skipped some nodes the result array is likely to be smaller than the
+ // selection array, hence shorten the result to true length.
+ if Integer(Counter) < Length(Result) then
+ SetLength(Result, Counter);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetTreeRect: TRect;
+
+// Returns the true size of the tree in pixels. This size is at least ClientHeight x ClientWidth and depends on
+// the expand state, header size etc.
+// Note: if no columns are used then the width of the tree is determined by the largest node which is currently in the
+// client area. This might however not be the largest node in the entire tree.
+
+begin
+ Result := Rect(0, 0, Max(FRangeX, ClientWidth), Max(FRangeY, ClientHeight));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetVisibleParent(Node: PVirtualNode): PVirtualNode;
+
+// Returns the first (nearest) parent node of Node which is visible.
+// This method is one of the seldom cases where the hidden root node could be returned.
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+
+ Result := Node;
+ while Result <> FRoot do
+ begin
+ // FRoot is always expanded hence the loop will safely stop there if no other node is expanded
+ repeat
+ Result := Result.Parent;
+ until vsExpanded in Result.States;
+
+ if (Result = FRoot) or FullyVisible[Result] then
+ Break;
+
+ // if there is still a collapsed parent node then advance to it and repeat the entire loop
+ while (Result <> FRoot) and (vsExpanded in Result.Parent.States) do
+ Result := Result.Parent;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.HasAsParent(Node, PotentialParent: PVirtualNode): Boolean;
+
+// Determines whether Node has got PotentialParent as one of its parents.
+
+var
+ Run: PVirtualNode;
+
+begin
+ Result := Assigned(Node) and Assigned(PotentialParent) and (Node <> PotentialParent);
+ if Result then
+ begin
+ Run := Node;
+ while (Run <> FRoot) and (Run <> PotentialParent) do
+ Run := Run.Parent;
+ Result := Run = PotentialParent;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InsertNode(Node: PVirtualNode; Mode: TVTNodeAttachMode; UserData: Pointer = nil): PVirtualNode;
+
+// Adds a new node relative to Node. The final position is determined by Mode.
+// UserData can be used to set the first 4 bytes of the user data area to an initial value which can be used
+// in OnInitNode and will also cause to trigger the OnFreeNode event (if <> nil) even if the node is not yet
+// "officially" initialized.
+// InsertNode is a compatibility method and will implicitly validate the given node if the new node
+// is to be added as child node. This is however against the virtual paradigm and hence I dissuade from its usage.
+
+var
+ NodeData: ^Pointer;
+
+begin
+ if Mode <> amNoWhere then
+ begin
+ CancelEditNode;
+
+ if Node = nil then
+ Node := FRoot;
+ // we need a new node...
+ Result := MakeNewNode;
+ // avoid erronous attach modes
+ if Node = FRoot then
+ begin
+ case Mode of
+ amInsertBefore:
+ Mode := amAddChildFirst;
+ amInsertAfter:
+ Mode := amAddChildLast;
+ end;
+ end;
+
+ // Validate given node in case the new node becomes its child.
+ if (Mode in [amAddChildFirst, amAddChildLast]) and not (vsInitialized in Node.States) then
+ InitNode(Node);
+ InternalConnectNode(Result, Node, Self, Mode);
+
+ // Check if there is initial user data and there is also enough user data space allocated.
+ if Assigned(UserData) then
+ if FNodeDataSize >= 4 then
+ begin
+ NodeData := Pointer(PChar(@Result.Data) + FTotalInternalDataSize);
+ NodeData^ := UserData;
+ Include(Result.States, vsInitialUserData);
+ end
+ else
+ ShowError(SCannotSetUserData, hcTFCannotSetUserData);
+
+ if FUpdateCount = 0 then
+ begin
+ // If auto sort is enabled then sort the node or its parent (depending on the insert mode).
+ if (toAutoSort in FOptions.FAutoOptions) and (FHeader.FSortColumn > InvalidColumn) then
+ case Mode of
+ amInsertBefore,
+ amInsertAfter:
+ // Here no initialization is necessary because *if* a node has already got children then it
+ // must also be initialized.
+ // Note: Node can never be FRoot at this point.
+ Sort(Node.Parent, FHeader.FSortColumn, FHeader.FSortDirection, True);
+ amAddChildFirst,
+ amAddChildLast:
+ Sort(Node, FHeader.FSortColumn, FHeader.FSortDirection, True);
+ end;
+
+ UpdateScrollbars(True);
+ if Mode = amInsertBefore then
+ InvalidateToBottom(Result)
+ else
+ InvalidateToBottom(Node);
+ end;
+ StructureChange(Result, crNodeAdded);
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvalidateChildren(Node: PVirtualNode; Recursive: Boolean);
+
+// Invalidates Node and its immediate children.
+// If Recursive is True then all grandchildren are invalidated as well.
+// The node itself is initialized if necessary and its child nodes are created (and initialized too if
+// Recursive is True).
+
+var
+ Run: PVirtualNode;
+
+begin
+ if Assigned(Node) then
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ InvalidateNode(Node);
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+ Run := Node.FirstChild;
+ end
+ else
+ Run := FRoot.FirstChild;
+
+ while Assigned(Run) do
+ begin
+ InvalidateNode(Run);
+ if Recursive then
+ InvalidateChildren(Run, True);
+ Run := Run.NextSibling;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvalidateColumn(Column: TColumnIndex);
+
+// Invalidates the client area part of a column.
+
+var
+ R: TRect;
+
+begin
+ if (FUpdateCount = 0) and FHeader.Columns.IsValidColumn(Column) then
+ begin
+ R := ClientRect;
+ FHeader.Columns.GetColumnBounds(Column, R.Left, R.Right);
+ InvalidateRect(Handle, @R, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InvalidateNode(Node: PVirtualNode): TRect;
+
+// Initiates repaint of the given node and returns the just invalidated rectangle.
+
+begin
+ if (FUpdateCount = 0) and HandleAllocated then
+ begin
+ Result := GetDisplayRect(Node, NoColumn, False);
+ InvalidateRect(Handle, @Result, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvalidateToBottom(Node: PVirtualNode);
+
+// Initiates repaint of client area starting at given node. If this node is not visible or not yet initialized
+// then nothing happens.
+
+var
+ R: TRect;
+
+begin
+ if FUpdateCount = 0 then
+ begin
+ if (Node = nil) or (Node = FRoot) then
+ Invalidate
+ else
+ if [vsInitialized, vsVisible] * Node.States = [vsInitialized, vsVisible] then
+ begin
+ R := GetDisplayRect(Node, -1, False);
+ if R.Top < ClientHeight then
+ begin
+ R.Bottom := ClientHeight;
+ InvalidateRect(Handle, @R, False);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvertSelection(VisibleOnly: Boolean);
+
+// Inverts the current selection (so nodes which are selected become unselected and vice versa).
+// If VisibleOnly is True then only visible nodes are considered.
+
+var
+ Run: PVirtualNode;
+ NewSize: Integer;
+ NextFunction: function(Node: PVirtualNode): PVirtualNode of object;
+ TriggerChange: Boolean;
+
+begin
+ if toMultiSelect in FOptions.FSelectionOptions then
+ begin
+ Run := FRoot.FirstChild;
+ ClearTempCache;
+ if VisibleOnly then
+ NextFunction := GetNextVisibleNoInit
+ else
+ NextFunction := GetNextNoInit;
+ while Assigned(Run) do
+ begin
+ if vsSelected in Run.States then
+ InternalRemoveFromSelection(Run)
+ else
+ InternalCacheNode(Run);
+ Run := NextFunction(Run);
+ end;
+
+ // do some housekeeping
+ // Need to trigger the OnChange event from here if nodes were only deleted but not added.
+ TriggerChange := False;
+ NewSize := PackArray(FSelection, FSelectionCount);
+ if NewSize > -1 then
+ begin
+ FSelectionCount := NewSize;
+ SetLength(FSelection, FSelectionCount);
+ TriggerChange := True;
+ end;
+ if FTempNodeCount > 0 then
+ begin
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+ TriggerChange := False;
+ end;
+ Invalidate;
+ if TriggerChange then
+ Change(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IsEditing: Boolean;
+
+begin
+ Result := tsEditing in FStates;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IsMouseSelecting: Boolean;
+
+begin
+ Result := (tsDrawSelPending in FStates) or (tsDrawSelecting in FStates);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IterateSubtree(Node: PVirtualNode; Callback: TVTGetNodeProc; Data: Pointer;
+ Filter: TVirtualNodeStates = []; DoInit: Boolean = False; ChildNodesOnly: Boolean = False): PVirtualNode;
+
+// Iterates through the all children and grandchildren etc. of Node (or the entire tree if Node = nil)
+// and calls for each node the provided callback method (which must not be empty).
+// Filter determines which nodes to consider (an empty set denotes all nodes).
+// If DoInit is True then nodes which aren't initialized yet will be initialized.
+// Note: During execution of the callback the application can set Abort to True. In this case the iteration is stopped
+// and the last accessed node (the one on which the callback set Abort to True) is returned to the caller.
+// Otherwise (no abort) nil is returned.
+
+var
+ Stop: PVirtualNode;
+ Abort: Boolean;
+ GetNextNode: TGetNextNodeProc;
+ WasIterating: Boolean;
+
+begin
+ Assert(Node <> FRoot, 'Node must not be the hidden root node.');
+
+ WasIterating := tsIterating in FStates;
+ DoStateChange([tsIterating]);
+ try
+ // prepare function to be used when advancing
+ if DoInit then
+ GetNextNode := GetNext
+ else
+ GetNextNode := GetNextNoInit;
+
+ Abort := False;
+ if Node = nil then
+ Stop := nil
+ else
+ begin
+ if not (vsInitialized in Node.States) and DoInit then
+ InitNode(Node);
+
+ // The stopper does not need to be initialized since it is not taken into the enumeration.
+ Stop := Node.NextSibling;
+ if Stop = nil then
+ begin
+ Stop := Node;
+ repeat
+ Stop := Stop.Parent;
+ until (Stop = FRoot) or Assigned(Stop.NextSibling);
+ if Stop = FRoot then
+ Stop := nil
+ else
+ Stop := Stop.NextSibling;
+ end;
+ end;
+
+ // Use first node if we start with the root.
+ if Node = nil then
+ Node := GetFirstNoInit;
+
+ if Assigned(Node) then
+ begin
+ if not (vsInitialized in Node.States) and DoInit then
+ InitNode(Node);
+
+ // Skip given node if only the child nodes are requested.
+ if ChildNodesOnly then
+ begin
+ if Node.ChildCount = 0 then
+ Node := nil
+ else
+ Node := GetNextNode(Node);
+ end;
+
+ if Filter = [] then
+ begin
+ // unfiltered loop
+ while Assigned(Node) and (Node <> Stop) do
+ begin
+ Callback(Self, Node, Data, Abort);
+ if Abort then
+ Break;
+ Node := GetNextNode(Node);
+ end;
+ end
+ else
+ begin
+ // filtered loop
+ while Assigned(Node) and (Node <> Stop) do
+ begin
+ if Node.States * Filter = Filter then
+ Callback(Self, Node, Data, Abort);
+ if Abort then
+ Break;
+ Node := GetNextNode(Node)
+ end;
+ end;
+ end;
+
+ if Abort then
+ Result := Node
+ else
+ Result := nil;
+ finally
+ if not WasIterating then
+ DoStateChange([], [tsIterating]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.LoadFromFile(const FileName: TFileName);
+
+var
+ FileStream: TFileStream;
+
+begin
+ FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ LoadFromStream(FileStream);
+ finally
+ FileStream.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.LoadFromStream(Stream: TStream);
+
+// Clears the current content of the tree and loads a new structure from the given stream.
+
+var
+ ThisID: TMagicID;
+ Version,
+ Count: Cardinal;
+ Node: PVirtualNode;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Clear;
+ // Check first whether this is a stream we can read.
+ if Stream.Read(ThisID, SizeOf(TMagicID)) < SizeOf(TMagicID) then
+ ShowError(SStreamTooSmall, hcTFStreamTooSmall);
+
+ if (ThisID[0] = MagicID[0]) and (ThisID[1] = MagicID[1]) and (ThisID[2] = MagicID[2]) and
+ (ThisID[5] = MagicID[5]) then
+ begin
+ Version := Word(ThisID[3]);
+ if Version <= VTTreeStreamVersion then
+ begin
+ BeginUpdate;
+ try
+ if Version < 2 then
+ Count := MaxInt
+ else
+ Stream.ReadBuffer(Count, SizeOf(Count));
+
+ while (Stream.Position < Stream.Size) and (Count > 0) do
+ begin
+ Dec(Count);
+ Node := MakeNewNode;
+ InternalConnectNode(Node, FRoot, Self, amAddChildLast);
+ InternalAddFromStream(Stream, Version, Node);
+ end;
+ DoNodeCopied(nil);
+ finally
+ EndUpdate;
+ end;
+ end
+ else
+ ShowError(SWrongStreamVersion, hcTFWrongStreamVersion);
+ end
+ else
+ ShowError(SWrongStreamFormat, hcTFWrongStreamFormat);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MoveTo(Node: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean);
+
+// A simplified method to allow to move nodes to the root of another tree.
+
+begin
+ MoveTo(Node, Tree.FRoot, Mode, ChildrenOnly);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MoveTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; ChildrenOnly: Boolean);
+
+// Moves the given node (and all its children) to Target. Source must belong to the tree instance which calls this
+// MoveTo method. Mode determines how to connect Source to Target.
+// This method might involve a change of the tree if Target belongs to a different tree than Source.
+
+var
+ TargetTree: TBaseVirtualTree;
+ Allowed: Boolean;
+ NewNode: PVirtualNode;
+ Stream: TMemoryStream;
+
+begin
+ Assert(TreeFromNode(Source) = Self, 'The source tree must contain the source node.');
+
+ // When moving nodes then source and target must not be the same node unless only the source's children are
+ // moved and they are inserted before or after the node itself.
+ Allowed := (Source <> Target) or ((Mode in [amInsertBefore, amInsertAfter]) and ChildrenOnly);
+
+ if Allowed and (Mode <> amNoWhere) and Assigned(Source) and (Source <> FRoot) and
+ not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ // Assume that an empty destination means the root in this (the source) tree.
+ if Target = nil then
+ begin
+ TargetTree := Self;
+ Target := FRoot;
+ Mode := amAddChildFirst;
+ end
+ else
+ TargetTree := TreeFromNode(Target);
+
+ if Target = TargetTree.FRoot then
+ begin
+ case Mode of
+ amInsertBefore:
+ Mode := amAddChildFirst;
+ amInsertAfter:
+ Mode := amAddChildLast;
+ end;
+ end;
+
+ if TargetTree = Self then
+ begin
+ // Simple case: move node(s) within the same tree.
+ if Target = FRoot then
+ Allowed := DoNodeMoving(Source, nil)
+ else
+ Allowed := DoNodeMoving(Source, Target);
+ if Allowed then
+ begin
+ // Check first that Source is not added as new child to a target node which
+ // is already a child of Source.
+ // Consider the case Source and Target are the same node, but only child nodes are moved.
+ if (Source <> Target) and HasAsParent(Target, Source) then
+ ShowError(SWrongMoveError, hcTFWrongMoveError);
+
+ if not ChildrenOnly then
+ begin
+ // Disconnect from old location.
+ InternalDisconnectNode(Source, True);
+ // Connect to new location.
+ InternalConnectNode(Source, Target, Self, Mode);
+ DoNodeMoved(Source);
+ end
+ else
+ begin
+ // Only child nodes should be moved.
+ Source := Source.LastChild;
+ while Assigned(Source) do
+ begin
+ NewNode := Source.PrevSibling;
+ // Disconnect from old location.
+ InternalDisconnectNode(Source, True, False);
+ // Connect to new location.
+ InternalConnectNode(Source, Target, Self, Mode);
+ DoNodeMoved(Source);
+ Source := NewNode;
+ end;
+ end;
+ end;
+ end
+ else
+ begin
+ // Difficult case: move node(s) to another tree.
+ // In opposition to node copying we ask only once if moving is allowed because
+ // we cannot take back a move once done.
+ if Target = TargetTree.FRoot then
+ Allowed := DoNodeMoving(Source, nil)
+ else
+ Allowed := DoNodeMoving(Source, Target);
+
+ if Allowed then
+ begin
+ Stream := TMemoryStream.Create;
+ try
+ // Write all nodes into a temporary stream depending on the ChildrenOnly flag.
+ if not ChildrenOnly then
+ WriteNode(Stream, Source)
+ else
+ begin
+ Source := Source.FirstChild;
+ while Assigned(Source) do
+ begin
+ WriteNode(Stream, Source);
+ Source := Source.NextSibling;
+ end;
+ end;
+ // Now load the serialized nodes into the target node (tree).
+ TargetTree.BeginUpdate;
+ try
+ Stream.Position := 0;
+ while Stream.Position < Stream.Size do
+ begin
+ NewNode := TargetTree.MakeNewNode;
+ InternalConnectNode(NewNode, Target, TargetTree, Mode);
+ TargetTree.InternalAddFromStream(Stream, VTTreeStreamVersion, NewNode);
+ DoNodeMoved(NewNode);
+ end;
+ finally
+ TargetTree.EndUpdate;
+ end;
+ finally
+ Stream.Free;
+ end;
+ // finally delete original nodes
+ BeginUpdate;
+ try
+ if ChildrenOnly then
+ DeleteChildren(Source)
+ else
+ DeleteNode(Source);
+ finally
+ EndUpdate;
+ end;
+ end;
+ end;
+
+ InvalidateCache;
+ if (FUpdateCount = 0) and Allowed then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ Invalidate;
+ if TargetTree <> Self then
+ TargetTree.Invalidate;
+ end;
+ StructureChange(Source, crNodeMoved);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintTree(TargetCanvas: TCanvas; Window: TRect; Target: TPoint;
+ PaintOptions: TVTInternalPaintOptions);
+
+// This is the core paint routine of the tree. It is responsible for maintaining the paint cycles per node as well
+// as coordinating drawing of the various parts of the tree image.
+// TargetCanvas is the canvas to which to draw the tree image. This is usually the tree window itself but could well
+// be a bitmap or printer canvas.
+// Window determines which part of the entire tree image to draw. The full size of the virtual image is determined
+// by GetTreeRect.
+// Target is the position in TargetCanvas where to draw the tree part specified by Window.
+// PaintOptions determines what of the tree to draw. For different tasks usually different parts need to be drawn, with
+// a full image in the window, selected only nodes for a drag image etc.
+
+const
+ ImageKind: array[Boolean] of TVTImageKind = (ikNormal, ikSelected);
+
+var
+ DrawSelectionRect,
+ UseBackground,
+ ShowImages,
+ ShowStateImages,
+ ShowCheckImages,
+ UseColumns,
+ IsMainColumn: Boolean;
+
+ VAlign,
+ IndentSize,
+ ButtonX,
+ ButtonY: Integer;
+ Temp: PVirtualNode;
+ LineImage: TLineImage;
+ PaintInfo: TVTPaintInfo; // all necessary information about a node to pass to the paint routines
+
+ R, // the area of an entire node in its local coordinate
+ TargetRect, // the area of a node (part) in the target canvas
+ SelectionRect: TRect; // ordered rectangle used for drawing the selection focus rect
+ NextColumn: TColumnIndex;
+ BaseOffset: Integer; // top position of the top node to draw given in absolute tree coordinates
+ NodeBitmap: TBitmap; // small buffer to draw flicker free
+ MaximumRight, // maximum horizontal target position
+ MaximumBottom: Integer; // maximum vertical target position
+ SelectLevel: Integer; // > 0 if current node is selected or child/grandchild etc. of a selected node
+ FirstColumn: TColumnIndex; // index of first column which is at least partially visible in the given window
+
+begin
+ DoStateChange([tsPainting]);
+
+ DoBeforePaint(TargetCanvas);
+
+ // Create small bitmaps and initialize default values.
+ // The bitmaps are used to paint one node at a time and to draw the result to the target (e.g. screen) in one step,
+ // to prevent flickering.
+ NodeBitmap := TBitmap.Create;
+ // For alpha blending we need the 32 bit pixel format.
+ if MMXAvailable and ((FDrawSelectionMode = smBlendedRectangle) or (tsUseThemes in FStates)) then
+ NodeBitmap.PixelFormat := pf32Bit;
+
+ // Prepare paint info structure and lock the back bitmap canvas to avoid that it gets freed on the way.
+ FillChar(PaintInfo, SizeOf(PaintInfo), 0);
+ PaintInfo.Canvas := NodeBitmap.Canvas;
+ NodeBitmap.Canvas.Lock;
+ try
+ // Prepare the current selection rectangle once. The corner points are absolute tree coordinates.
+ SelectionRect := OrderRect(FNewSelRect);
+ DrawSelectionRect := IsMouseSelecting and not IsRectEmpty(SelectionRect);
+
+ // R represents an entire node (all columns), but is a bit unprecise when it comes to
+ // trees without any column defined, because FRangeX only represents the maximum width of all
+ // nodes in the client area (not all defined nodes). There might be, however, wider nodes somewhere. Without full
+ // validation I cannot better determine the width, though. By using at least the control's width it is ensured
+ // that the tree is fully displayed on screen.
+ R := Rect(0, 0, Max(FRangeX, ClientWidth), 0);
+ NodeBitmap.Width := Window.Right - Window.Left;
+
+ // Make sure the buffer bitmap and target bitmap use the same transformation mode.
+ SetMapMode(NodeBitmap.Canvas.Handle, GetMapMode(TargetCanvas.Handle));
+
+ // For quick checks some intermediate variables are used.
+ UseBackground := (toShowBackground in FOptions.FPaintOptions) and (FBackground.Graphic is TBitmap) and
+ (poBackground in PaintOptions);
+ ShowImages := Assigned(FImages);
+ ShowStateImages := Assigned(FStateImages);
+ ShowCheckImages := Assigned(FCheckImages) and (toCheckSupport in FOptions.FMiscOptions);
+ UseColumns := FHeader.UseColumns;
+
+ // Adjust paint options to tree settings.
+ if not Focused and (toHideSelection in FOptions.FPaintOptions) then
+ Exclude(PaintOptions, poDrawSelection);
+ if toHideFocusRect in FOptions.FPaintOptions then
+ Exclude(PaintOptions, poDrawFocusRect);
+
+ // Determine node to start drawing with.
+ BaseOffset := 0;
+ PaintInfo.Node := GetNodeAt(0, Window.Top, False, BaseOffset);
+
+ // Transform selection rectangle into node bitmap coordinates.
+ if DrawSelectionRect then
+ OffsetRect(SelectionRect, 0, -BaseOffset);
+
+ // The target rectangle holds the coordinates of the exact area to blit in target canvas coordinates.
+ // It is usually smaller than an entire node and wanders while the paint loop advances.
+ MaximumRight := Target.X + (Window.Right - Window.Left);
+ MaximumBottom := Target.Y + (Window.Bottom - Window.Top);
+
+ TargetRect := Rect(Target.X, Target.Y - (Window.Top - BaseOffset), MaximumRight, 0);
+ TargetRect.Bottom := TargetRect.Top;
+
+ // This marker gets the index of the first column which is visible in the given window.
+ // This is needed for column based background colors.
+ FirstColumn := InvalidColumn;
+
+ if Assigned(PaintInfo.Node) then
+ begin
+ SelectLevel := InitializeLineImageAndSelectLevel(PaintInfo.Node, LineImage);
+ IndentSize := Length(LineImage);
+
+ // Precalculate horizontal position of buttons relative to the column start.
+ ButtonX := (Length(LineImage) * Integer(FIndent)) + Round((Integer(FIndent) - FPlusBM.Width) / 2) - FIndent;
+
+ // ----- main node paint loop
+ while Assigned(PaintInfo.Node) do
+ begin
+ // Initialize node if not already done.
+ if not (vsInitialized in PaintInfo.Node.States) then
+ InitNode(PaintInfo.Node);
+ if vsSelected in PaintInfo.Node.States then
+ Inc(SelectLevel);
+
+ // Adjust the brush origin for dotted lines depending on the current source position.
+ // It is applied some lines later, as the canvas might get reallocated, when changing the node bitmap.
+ PaintInfo.BrushOrigin := Point(Window.Left and 1, BaseOffset and 1);
+ Inc(BaseOffset, PaintInfo.Node.NodeHeight);
+
+ TargetRect.Bottom := TargetRect.Top + PaintInfo.Node.NodeHeight;
+
+ // If poSelectedOnly is active then do the following stuff only for selected nodes or nodes
+ // which are children of selected nodes.
+ if (SelectLevel > 0) or not (poSelectedOnly in PaintOptions) then
+ begin
+ // Adjust height of temporary node bitmap.
+ with NodeBitmap do
+ begin
+ if Height <> PaintInfo.Node.NodeHeight then
+ begin
+ // Avoid that the VCL copies the bitmap while changing its height.
+ Height := 0;
+ Height := PaintInfo.Node.NodeHeight;
+ SetWindowOrgEx(Canvas.Handle, Window.Left, 0, nil);
+ R.Bottom := PaintInfo.Node.NodeHeight;
+ end;
+ // Set the origin of the canvas' brush. This depends on the node heights.
+ with PaintInfo do
+ SetBrushOrgEx(Canvas.Handle, BrushOrigin.X, BrushOrigin.Y, nil);
+ end;
+ CalculateVerticalAlignments(ShowImages, ShowStateImages, PaintInfo.Node, VAlign, ButtonY);
+
+ // Let application decide whether the node should normally be drawn or by the application itself.
+ if not DoBeforeItemPaint(PaintInfo.Canvas, PaintInfo.Node, R) then
+ begin
+ // Init paint options for the background painting.
+ PaintInfo.PaintOptions := PaintOptions;
+
+ // The node background can contain a single color, a bitmap or can be drawn by the application.
+ ClearNodeBackground(PaintInfo, UseBackground, True, Rect(Window.Left, TargetRect.Top, Window.Right,
+ TargetRect.Bottom));
+
+ // Prepare column, position and node clipping rectangle.
+ PaintInfo.CellRect := R;
+ if UseColumns then
+ InitializeFirstColumnValues(PaintInfo);
+
+ // Now go through all visible columns (there's still one run if columns aren't used).
+ with FHeader.FColumns do
+ begin
+ while ((PaintInfo.Column > InvalidColumn) or not UseColumns)
+ and (PaintInfo.CellRect.Left < Window.Right) do
+ begin
+ if UseColumns then
+ begin
+ PaintInfo.Column := FPositionToIndex[PaintInfo.Position];
+ if FirstColumn = InvalidColumn then
+ FirstColumn := PaintInfo.Column;
+ PaintInfo.BidiMode := Items[PaintInfo.Column].FBiDiMode;
+ PaintInfo.Alignment := Items[PaintInfo.Column].FAlignment;
+ end
+ else
+ begin
+ PaintInfo.Column := NoColumn;
+ PaintInfo.BidiMode := BidiMode;
+ PaintInfo.Alignment := FAlignment;
+ end;
+
+ PaintInfo.PaintOptions := PaintOptions;
+ with PaintInfo do
+ begin
+ if (tsEditing in FStates) and (Node = FFocusedNode) and
+ ((Column = FEditColumn) or not UseColumns) then
+ Exclude(PaintOptions, poDrawSelection);
+ if not UseColumns or
+ ((vsSelected in Node.States) and (toFullRowSelect in FOptions.FSelectionOptions) and
+ (poDrawSelection in PaintOptions)) or
+ (coParentColor in Items[PaintInfo.Column].Options) then
+ Exclude(PaintOptions, poColumnColor);
+ end;
+ IsMainColumn := PaintInfo.Column = FHeader.MainColumn;
+
+ // Consider bidi mode here. In RTL context means left alignment actually right alignment and vice versa.
+ if PaintInfo.BidiMode <> bdLeftToRight then
+ ChangeBiDiModeAlignment(PaintInfo.Alignment);
+
+ // Paint the current cell if it is marked as being visible or columns aren't used and
+ // if this cell belongs to the main column if only the main column should be drawn.
+ if (not UseColumns or (coVisible in Items[PaintInfo.Column].FOptions)) and
+ (not (poMainOnly in PaintOptions) or IsMainColumn) then
+ begin
+ AdjustPaintCellRect(PaintInfo, NextColumn);
+
+ // Paint the cell only if it is in the current window.
+ if PaintInfo.CellRect.Right > Window.Left then
+ begin
+ with PaintInfo do
+ begin
+ // Fill in remaining values in the paint info structure.
+ NodeWidth := DoGetNodeWidth(Node, Column, Canvas);
+ // Not the entire cell is covered by text. Hence we need a running rectangle to follow up.
+ ContentRect := CellRect;
+ // Set up the distance from column border (margin).
+ if BidiMode <> bdLeftToRight then
+ Dec(ContentRect.Right, FMargin)
+ else
+ Inc(ContentRect.Left, FMargin);
+
+ if ShowCheckImages and IsMainColumn then
+ begin
+ ImageInfo[iiCheck].Index := GetCheckImage(Node);
+ if ImageInfo[iiCheck].Index > -1 then
+ begin
+ AdjustImageBorder(FCheckImages, BidiMode, VAlign, ContentRect, ImageInfo[iiCheck]);
+ ImageInfo[iiCheck].Ghosted := False;
+ end;
+ end
+ else
+ ImageInfo[iiCheck].Index := -1;
+ if ShowStateImages then
+ begin
+ ImageInfo[iiState].Index := GetImageIndex(Node, ikState, Column, ImageInfo[iiState].Ghosted);
+ if ImageInfo[iiState].Index > -1 then
+ AdjustImageBorder(FStateImages, BidiMode, VAlign, ContentRect, ImageInfo[iiState]);
+ end
+ else
+ ImageInfo[iiState].Index := -1;
+ if ShowImages then
+ begin
+ ImageInfo[iiNormal].Index := GetImageIndex(Node, ImageKind[vsSelected in Node.States], Column,
+ ImageInfo[iiNormal].Ghosted);
+ if ImageInfo[iiNormal].Index > -1 then
+ AdjustImageBorder(FImages, BidiMode, VAlign, ContentRect, ImageInfo[iiNormal]);
+ end
+ else
+ ImageInfo[iiNormal].Index := -1;
+
+ // Take the space for the tree lines into account.
+ if IsMainColumn then
+ AdjustCoordinatesByIndent(PaintInfo, IndentSize);
+
+ if UseColumns then
+ LimitPaintingToArea(Canvas, CellRect);
+
+ // Paint the horizontal grid line.
+ if (poGridLines in PaintOptions) and (toShowHorzGridLines in FOptions.FPaintOptions) then
+ begin
+ Canvas.Font.Color := FColors.GridLineColor;
+ if IsMainColumn and (FLineMode = lmBands) then
+ begin
+ if BidiMode = bdLeftToRight then
+ begin
+ DrawDottedHLine(PaintInfo, CellRect.Left + IndentSize * Integer(FIndent), CellRect.Right - 1,
+ CellRect.Bottom - 1);
+ end
+ else
+ begin
+ DrawDottedHLine(PaintInfo, CellRect.Left, CellRect.Right - IndentSize * Integer(FIndent) - 1,
+ CellRect.Bottom - 1);
+ end;
+ end
+ else
+ DrawDottedHLine(PaintInfo, CellRect.Left, CellRect.Right, CellRect.Bottom - 1);
+ Dec(CellRect.Bottom);
+ Dec(ContentRect.Bottom);
+ end;
+
+ if UseColumns then
+ begin
+ // Paint vertical grid line.
+ // Don't draw if this is the last column and the header is in autosize mode.
+ if (poGridLines in PaintOptions) and (toShowVertGridLines in FOptions.FPaintOptions) and
+ (not (hoAutoResize in FHeader.FOptions) or (Position < TColumnPosition(Count - 1))) then
+ begin
+ if (BidiMode = bdLeftToRight) or not ColumnIsEmpty(Node, Column) then
+ begin
+ Canvas.Font.Color := FColors.GridLineColor;
+ DrawDottedVLine(PaintInfo, CellRect.Top, CellRect.Bottom, CellRect.Right - 1);
+ end;
+ Dec(CellRect.Right);
+ Dec(ContentRect.Right);
+ end;
+ end;
+
+ // Prepare background and focus rect for the current cell.
+ PrepareCell(PaintInfo);
+
+ // Some parts are only drawn for the main column.
+ if IsMainColumn then
+ begin
+ if toShowTreeLines in FOptions.FPaintOptions then
+ PaintTreeLines(PaintInfo, VAlign, IndentSize, LineImage);
+ // Show node button if allowed, if there child nodes and at least one of the child
+ // nodes is visible or auto button hiding is disabled.
+ if (toShowButtons in FOptions.FPaintOptions) and (vsHasChildren in Node.States) and
+ not ((vsAllChildrenHidden in Node.States) and
+ (toAutoHideButtons in TreeOptions.FAutoOptions)) then
+ PaintNodeButton(Canvas, Node, CellRect, ButtonX, ButtonY, BidiMode);
+
+ if ImageInfo[iiCheck].Index > -1 then
+ PaintCheckImage(PaintInfo);
+ end;
+
+ if ImageInfo[iiState].Index > -1 then
+ PaintImage(PaintInfo, iiState, FStateImages, False);
+ if ImageInfo[iiNormal].Index > -1 then
+ PaintImage(PaintInfo, iiNormal, FImages, True);
+
+ // Now let descendants or applications draw whatever they want,
+ // but don't draw the node if it is currently being edited.
+ if not ((tsEditing in FStates) and (Node = FFocusedNode) and
+ ((Column = FEditColumn) or not UseColumns)) then
+ DoPaintNode(PaintInfo);
+
+ DoAfterCellPaint(Canvas, Node, Column, CellRect);
+ end;
+ end;
+
+ // leave after first run if columns aren't used
+ if not UseColumns then
+ Break;
+ end
+ else
+ NextColumn := GetNextVisibleColumn(PaintInfo.Column);
+
+ SelectClipRgn(PaintInfo.Canvas.Handle, 0);
+ // Stop column loop if there are no further columns in the given window.
+ if (PaintInfo.CellRect.Left >= Window.Right) or (NextColumn = InvalidColumn) then
+ Break;
+
+ // Move on to next column which might not be the one immediately following the current one
+ // because of auto span feature.
+ PaintInfo.Position := Items[NextColumn].Position;
+
+ // Move clip rectangle and continue.
+ if coVisible in Items[NextColumn].FOptions then
+ with PaintInfo do
+ begin
+ Items[NextColumn].GetAbsoluteBounds(CellRect.Left, CellRect.Right);
+ CellRect.Bottom := Node.NodeHeight;
+ ContentRect.Bottom := Node.NodeHeight;
+ end;
+ end;
+ end;
+
+ // This node is finished, notify descentants/application.
+ with PaintInfo do
+ begin
+ DoAfterItemPaint(Canvas, Node, R);
+
+ // Final touch for this node: mark it if it is the current drop target node.
+ if (Node = FDropTargetNode) and (toShowDropmark in FOptions.FPaintOptions) and
+ (poDrawDropMark in PaintOptions) then
+ DoPaintDropMark(Canvas, Node, R);
+ end;
+ end;
+
+ with PaintInfo.Canvas do
+ begin
+ if DrawSelectionRect then
+ begin
+ PaintSelectionRectangle(PaintInfo.Canvas, Window.Left, SelectionRect, Rect(0, 0, NodeBitmap.Width,
+ NodeBitmap.Height));
+ end;
+
+ // Put the constructed node image onto the target canvas.
+ with TargetRect, NodeBitmap do
+ BitBlt(TargetCanvas.Handle, Left, Top, Width, Height, Canvas.Handle, Window.Left, 0, SRCCOPY);
+ end;
+ end;
+
+ Inc(TargetRect.Top, PaintInfo.Node.NodeHeight);
+ if TargetRect.Top >= MaximumBottom then
+ Break;
+
+ // Keep selection rectangle coordinates in sync.
+ if DrawSelectionRect then
+ OffsetRect(SelectionRect, 0, -PaintInfo.Node.NodeHeight);
+
+ // Advance to next visible node.
+ Temp := GetNextVisible(PaintInfo.Node);
+ if Assigned(Temp) then
+ begin
+ // Adjust line bitmap (and so also indentation level).
+ if Temp.Parent = PaintInfo.Node then
+ begin
+ // New node is a child node. Need to adjust previous bitmap level.
+ if IndentSize > 0 then
+ if HasVisibleNextSibling(PaintInfo.Node) then
+ LineImage[IndentSize - 1] := ltTopDown
+ else
+ LineImage[IndentSize - 1] := ltNone;
+ // Enhance line type array if necessary.
+ Inc(IndentSize);
+ if Length(LineImage) <= IndentSize then
+ SetLength(LineImage, IndentSize + 8);
+ Inc(ButtonX, FIndent);
+ end
+ else
+ begin
+ // New node is at the same or higher tree level.
+ // Take back select level increase if the node was selected
+ if vsSelected in PaintInfo.Node.States then
+ Dec(SelectLevel);
+ if PaintInfo.Node.Parent <> Temp.Parent then
+ begin
+ // We went up one or more levels. Determine how many levels it was actually.
+ while PaintInfo.Node.Parent <> Temp.Parent do
+ begin
+ Dec(IndentSize);
+ Dec(ButtonX, FIndent);
+ PaintInfo.Node := PaintInfo.Node.Parent;
+ // Take back one selection level increase for every step up.
+ if vsSelected in PaintInfo.Node.States then
+ Dec(SelectLevel);
+ end;
+ end;
+ end;
+
+ // Set new image in front of the new node.
+ if IndentSize > 0 then
+ if HasVisibleNextSibling(Temp) then
+ LineImage[IndentSize - 1] := ltTopDownRight
+ else
+ LineImage[IndentSize - 1] := ltTopRight;
+ end;
+
+ PaintInfo.Node := Temp;
+ end;
+ end;
+
+ // Erase rest of window not covered by a node.
+ if TargetRect.Top < MaximumBottom then
+ begin
+ // Keep the horizontal target position to determine the selection rectangle offset later (if necessary).
+ BaseOffset := Target.X;
+ Target := TargetRect.TopLeft;
+ R := Rect(TargetRect.Left, 0, MaximumRight, MaximumBottom - Target.Y);
+ TargetRect := Rect(0, 0, MaximumRight - Target.X, MaximumBottom - Target.Y);
+ // Avoid unnecessary copying of bitmap content. This will destroy the DC handle too.
+ NodeBitmap.Height := 0;
+ NodeBitmap.PixelFormat := pf32Bit;
+ NodeBitmap.Width := TargetRect.Right - TargetRect.Left + 1;
+ NodeBitmap.Height := TargetRect.Bottom - TargetRect.Top + 1;
+
+ // Call back application/descentants whether they want to erase this area.
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, Target.X, 0, nil);
+ if not DoPaintBackground(NodeBitmap.Canvas, TargetRect) then
+ begin
+ if UseBackground then
+ begin
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, 0, 0, nil);
+ TileBackground(FBackground.Bitmap, NodeBitmap.Canvas, Target, TargetRect);
+ end
+ else
+ begin
+ // Consider here also colors of the columns.
+ if UseColumns then
+ begin
+ with FHeader.FColumns do
+ begin
+ // If there is no content in the tree then the first column has not yet been determined.
+ if FirstColumn = InvalidColumn then
+ begin
+ FirstColumn := GetFirstVisibleColumn;
+ repeat
+ if FirstColumn <> InvalidColumn then
+ begin
+ R.Left := Items[FirstColumn].Left;
+ R.Right := R.Left + Items[FirstColumn].FWidth;
+ if R.Right > TargetRect.Left then
+ Break;
+ FirstColumn := GetNextVisibleColumn(FirstColumn);
+ end;
+ until FirstColumn = InvalidColumn;
+ end
+ else
+ begin
+ R.Left := Items[FirstColumn].Left;
+ R.Right := R.Left + Items[FirstColumn].FWidth;
+ end;
+
+ while (FirstColumn <> InvalidColumn) and (R.Left < TargetRect.Right + Target.X) do
+ begin
+ if not (coParentColor in Items[FirstColumn].FOptions) then
+ NodeBitmap.Canvas.Brush.Color := Items[FirstColumn].FColor
+ else
+ NodeBitmap.Canvas.Brush.Color := Color;
+
+ NodeBitmap.Canvas.FillRect(R);
+ FirstColumn := GetNextVisibleColumn(FirstColumn);
+ if FirstColumn <> InvalidColumn then
+ begin
+ R.Left := Items[FirstColumn].Left;
+ R.Right := R.Left + Items[FirstColumn].FWidth;
+ end;
+ end;
+ // Erase also the part of the tree not covert by a column.
+ if R.Right < TargetRect.Right + Target.X then
+ begin
+ R.Left := R.Right;
+ R.Right := TargetRect.Right + Target.X;
+ NodeBitmap.Canvas.Brush.Color := Color;
+ NodeBitmap.Canvas.FillRect(R);
+ end;
+ end;
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, 0, 0, nil);
+ end
+ else
+ begin
+ // No columns nor bitmap background. Simply erase it with the tree color.
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, 0, 0, nil);
+ NodeBitmap.Canvas.Brush.Color := Color;
+ NodeBitmap.Canvas.FillRect(TargetRect);
+ end;
+ end;
+ end;
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, 0, 0, nil);
+
+ if DrawSelectionRect then
+ begin
+ R := OrderRect(FNewSelRect);
+ // Remap the selection rectangle to the current window of the tree.
+ // Since Target has been used for other tasks BaseOffset got the left extent of the target position here.
+ OffsetRect(R, -Target.X + BaseOffset - Window.Left, -Target.Y);
+ SetBrushOrgEx(NodeBitmap.Canvas.Handle, 0, Target.X and 1, nil);
+ PaintSelectionRectangle(NodeBitmap.Canvas, 0, R, TargetRect);
+ end;
+ with Target, NodeBitmap do
+ BitBlt(TargetCanvas.Handle, X, Y, Width, Height, Canvas.Handle, 0, 0, SRCCOPY);
+ end;
+ finally
+ NodeBitmap.Canvas.Unlock;
+ NodeBitmap.Free;
+ end;
+ DoAfterPaint(TargetCanvas);
+ DoStateChange([], [tsPainting]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.PasteFromClipboard: Boolean;
+
+// Reads what is currently on the clipboard into the tree (if the format is supported).
+// Note: If the application wants to have text or special formats to be inserted then it must implement
+// its own code (OLE). Here only the native tree format is accepted.
+
+var
+ Data: IDataObject;
+ Source: TBaseVirtualTree;
+
+begin
+ Result := False;
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ if OleGetClipboard(Data) <> S_OK then
+ ShowError(SClipboardFailed, hcTFClipboardFailed)
+ else
+ try
+ // Try to get the source tree of the operation to optimize the operation.
+ Source := GetTreeFromDataObject(Data);
+ Result := ProcessOLEData(Source, Data, FFocusedNode, FDefaultPasteMode, Assigned(Source) and
+ (tsCutPending in Source.FStates));
+ if Assigned(Source) and (Source <> Self) then
+ Source.FinishCutOrCopy;
+ finally
+ Data := nil;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PrepareDragImage(Hotspot: TPoint; const DataObject: IDataObject);
+
+// Initiates an image drag operation. Hotspot is the position of the mouse in client coordinates.
+
+var
+ PaintOptions: TVTInternalPaintOptions;
+ TreeRect,
+ PaintRect: TRect;
+ LocalSpot,
+ ImagePos,
+ PaintTarget: TPoint;
+ Image: TBitmap;
+
+begin
+ if CanShowDragImage then
+ begin
+ // Determine the drag rectangle which is a square around the hot spot. Operate in virtual tree space.
+ LocalSpot := HotSpot;
+ Dec(LocalSpot.X, FOffsetX);
+ Dec(LocalSpot.Y, FOffsetY);
+ TreeRect := Rect(LocalSpot.X - FDragWidth div 2, LocalSpot.Y - FDragHeight div 2, LocalSpot.X + FDragWidth div 2,
+ LocalSpot.Y + FDragHeight div 2);
+
+ // Check that we have a valid rectangle.
+ with TreeRect do
+ begin
+ PaintRect := TreeRect;
+ if Left < 0 then
+ begin
+ PaintTarget.X := -Left;
+ PaintRect.Left := 0;
+ end
+ else
+ PaintTarget.X := 0;
+ if Top < 0 then
+ begin
+ PaintTarget.Y := -Top;
+ PaintRect.Top := 0;
+ end
+ else
+ PaintTarget.Y := 0;
+ end;
+
+ Image := TBitmap.Create;
+ with Image do
+ try
+ PixelFormat := pf32Bit;
+ Width := TreeRect.Right - TreeRect.Left;
+ Height := TreeRect.Bottom - TreeRect.Top;
+ // Erase the entire image with the color key value, for the case not everything
+ // in the image is covered by the tree image.
+ Canvas.Brush.Color := Color;
+ Canvas.FillRect(Rect(0, 0, Width, Height));
+
+ PaintOptions := [poDrawSelection, poSelectedOnly];
+ if FDragImageKind = diMainColumnOnly then
+ Include(PaintOptions, poMainOnly);
+ PaintTree(Image.Canvas, PaintRect, PaintTarget, PaintOptions);
+
+ // Once we have got the drag image we can convert all necessary coordinates into screen space.
+ OffsetRect(TreeRect, FOffsetX, FOffsetY);
+ ImagePos := ClientToScreen(TreeRect.TopLeft);
+ HotSpot := ClientToScreen(HotSpot);
+
+ FDragImage.ColorKey := Color;
+ FDragImage.PrepareDrag(Image, ImagePos, HotSpot, DataObject);
+ finally
+ Image.Free;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Print(Printer: TPrinter; PrintHeader: Boolean);
+
+var
+ SaveTreeFont: TFont; // Remembers the tree's current font.
+ SaveHeaderFont: TFont; // Remembers the header's current font.
+ ImgRect, // Describes the dimensions of Image.
+ TreeRect, // The total VTree dimensions.
+ DestRect, // Dimensions of PrinterImage.
+ SrcRect: TRect; // Clip dimensions from Image -> PrinterImage
+ P: TPoint; // Used by PaintTree.
+ Options: TVTInternalPaintOptions; // Used by PaintTree.
+ Image, // Complete Tree is drawn to this image.
+ PrinterImage: TBitmap; // This is the image that gets printed.
+ SaveColor: TColor; // Remembers the VTree Color.
+ pTxtHeight, // Height of font in the TPrinter.Canvas
+ vTxtHeight, // Height of font in the VTree Canvas
+ vPageWidth,
+ vPageHeight, // Printer height in VTree resolution
+ xPageNum, yPageNum, // # of pages (except the occasional last one)
+ xPage, yPage: Integer; // Loop counter
+ Scale: Extended; // Scale factor between Printer Canvas and VTree Canvas
+ LogFont: TLogFont;
+
+begin
+ if Assigned(Printer) then
+ begin
+ BeginUpdate;
+
+ // Grid lines are the only parts which are desirable when printing.
+ Options := [poGridLines];
+
+ // Remember the tree font.
+ SaveTreeFont := TFont.Create;
+ SaveTreeFont.Assign(Font);
+ // Create a new font for printing which does not use clear type output (but is antialiased, if possible)
+ // and which has the highest possible quality.
+ GetObject(Font.Handle, SizeOf(TLogFont), @LogFont);
+ LogFont.lfQuality := ANTIALIASED_QUALITY;
+ Font.Handle := CreateFontIndirect(LogFont);
+
+ // Create an image that will hold the complete VTree
+ Image := TBitmap.Create;
+ Image.PixelFormat := pf32Bit;
+ PrinterImage := nil;
+ try
+ TreeRect := GetTreeRect;
+
+ Image.Width := TreeRect.Right - TreeRect.Left;
+ P := Point(0, 0);
+ if (hoVisible in FHeader.Options) and PrintHeader then
+ begin
+ Inc(TreeRect.Bottom, FHeader.Height);
+ Inc(P.Y, FHeader.Height);
+ end;
+ Image.Height := TreeRect.Bottom - TreeRect.Top;
+
+ ImgRect.Left := 0;
+ ImgRect.Top := 0;
+ ImgRect.Right := Image.Width;
+
+ // Force the background to white color during the rendering.
+ SaveColor := Color;
+ Color := clWhite;
+ // Print header if it is visible.
+ if (hoVisible in FHeader.Options) and PrintHeader then
+ begin
+ SaveHeaderFont := TFont.Create;
+ try
+ SaveHeaderFont.Assign(FHeader.Font);
+ // Create a new font for printing which does not use clear type output (but is antialiased, if possible)
+ // and which has the highest possible quality.
+ GetObject(FHeader.Font.Handle, SizeOf(TLogFont), @LogFont);
+ LogFont.lfQuality := ANTIALIASED_QUALITY;
+ FHeader.Font.Handle := CreateFontIndirect(LogFont);
+ ImgRect.Bottom := FHeader.Height;
+ FHeader.FColumns.PaintHeader(Image.Canvas.Handle, ImgRect, 0);
+ FHeader.Font := SaveHeaderFont;
+ finally
+ SaveHeaderFont.Free;
+ end;
+ end;
+ // The image's height is already adjusted for the header if it is visible.
+ ImgRect.Bottom := Image.Height;
+
+ PaintTree(Image.Canvas, ImgRect, P, Options);
+ Color := SaveColor;
+
+ // Activate the printer
+ Printer.BeginDoc;
+ Printer.Canvas.Font := Font;
+
+ // Now we can calculate the scaling :
+ pTxtHeight := Printer.Canvas.TextHeight('Tj');
+ vTxtHeight := Canvas.TextHeight('Tj');
+
+ Scale := pTxtHeight / vTxtHeight;
+
+ // Create an Image that has the same dimensions as the printer canvas but
+ // scaled to the VTree resolution:
+ PrinterImage := TBitmap.Create;
+
+ vPageHeight := Round(Printer.PageHeight / Scale);
+ vPageWidth := Round(Printer.PageWidth / Scale);
+
+ // We do a minumum of one page.
+ xPageNum := Trunc(Image.Width / vPageWidth);
+ yPageNum := Trunc(Image.Height / vPageHeight);
+
+ PrinterImage.Width := vPageWidth;
+ PrinterImage.Height := vPageHeight;
+
+ // Split vertically:
+ for yPage := 0 to yPageNum do
+ begin
+ DestRect.Left := 0;
+ DestRect.Top := 0;
+ DestRect.Right := PrinterImage.Width;
+ DestRect.Bottom := PrinterImage.Height;
+
+ // Split horizontally:
+ for xPage := 0 to xPageNum do
+ begin
+ SrcRect.Left := vPageWidth * xPage;
+ SrcRect.Top := vPageHeight * yPage;
+ SrcRect.Right := vPageWidth * xPage + PrinterImage.Width;
+ SrcRect.Bottom := SrcRect.Top + vPageHeight;
+
+ // Clear the image
+ PrinterImage.Canvas.Brush.Color := clWhite;
+ PrinterImage.Canvas.FillRect(Rect(0, 0, PrinterImage.Width, PrinterImage.Height));
+ PrinterImage.Canvas.CopyRect(DestRect, Image.Canvas, SrcRect);
+ PrtStretchDrawDIB(Printer.Canvas, Rect(0, 0, Printer.PageWidth, Printer.PageHeight - 1), PrinterImage);
+ if xPage <> xPageNum then
+ Printer.NewPage;
+ end;
+ if yPage <> yPageNum then
+ Printer.NewPage;
+ end;
+
+ // Restore tree font.
+ Font := SaveTreeFont;
+ SaveTreeFont.Free;
+ Printer.EndDoc;
+ finally
+ PrinterImage.Free;
+ Image.Free;
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ProcessDrop(DataObject: IDataObject; TargetNode: PVirtualNode; var Effect: Integer;
+ Mode: TVTNodeAttachMode): Boolean;
+
+// Recreates the (sub) tree structure serialized into memory and provided by DataObject. The new nodes are attached to
+// the passed node or FRoot if TargetNode is nil.
+// Returns True on success, i.e. the CF_VIRTUALTREE format is supported by the data object and the structure could be
+// recreated, otherwise False.
+
+var
+ Source: TBaseVirtualTree;
+
+begin
+ Result := False;
+ if Mode = amNoWhere then
+ Effect := DROPEFFECT_NONE
+ else
+ begin
+ BeginUpdate;
+ // try to get the source tree of the operation
+ Source := GetTreeFromDataObject(DataObject);
+ if Assigned(Source) then
+ Source.BeginUpdate;
+ try
+ try
+ // Before adding the new nodes try to optimize the operation if source and target tree reside in
+ // the same application and operation is a move.
+ if ((Effect and DROPEFFECT_MOVE) <> 0) and Assigned(Source) then
+ begin
+ // If both copy and move are specified then prefer a copy because this is not destructing.
+ Result := ProcessOLEData(Source, DataObject, TargetNode, Mode, (Effect and DROPEFFECT_COPY) = 0);
+ // Since we made an optimized move or a copy there's no reason to act further after DoDragging returns.
+ Effect := DROPEFFECT_NONE;
+ end
+ else
+ // Act only if move or copy operation is requested.
+ if (Effect and (DROPEFFECT_MOVE or DROPEFFECT_COPY)) <> 0 then
+ Result := ProcessOLEData(Source, DataObject, TargetNode, Mode, False)
+ else
+ Result := False;
+ except
+ Effect := DROPEFFECT_NONE;
+ end;
+ finally
+ if Assigned(Source) then
+ Source.EndUpdate;
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ // needed to handle OLE global memory objects
+ TOLEMemoryStream = class(TCustomMemoryStream)
+ public
+ function Write(const Buffer; Count: Integer): Longint; override;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TOLEMemoryStream.Write(const Buffer; Count: Integer): Integer;
+
+begin
+ {$ifdef COMPILER_5_UP}
+ raise EStreamError.CreateRes(PResStringRec(@SCantWriteResourceStreamError));
+ {$else}
+ raise EStreamError.Create(SCantWriteResourceStreamError);
+ {$endif COMPILER_5_UP}
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ProcessOLEData(Source: TBaseVirtualTree; DataObject: IDataObject; TargetNode: PVirtualNode;
+ Mode: TVTNodeAttachMode; Optimized: Boolean): Boolean;
+
+// Recreates the (sub) tree structure serialized into memory and provided by DataObject. The new nodes are attached to
+// the passed node or FRoot if TargetNode is nil according to Mode. Optimized can be set to True if the entire operation
+// happens within the same process (i.e. sender and receiver of the OLE operation are located in the same process).
+// Optimize = True makes only sense if the operation to carry out is a move hence it is also the indication of the
+// operation to be done here. Source is the source of the OLE data and only of use (and usually assigned) when
+// an OLE operation takes place in the same application.
+// Returns True on success, i.e. the CF_VIRTUALTREE format is supported by the data object and the structure could be
+// recreated, otherwise False.
+
+var
+ Medium: TStgMedium;
+ Stream: TStream;
+ Data: Pointer;
+ Node: PVirtualNode;
+ Nodes: TNodeArray;
+ I: Integer;
+ Res: HRESULT;
+ ChangeReason: TChangeReason;
+
+begin
+ Nodes := nil;
+ // Check the data format available by the data object.
+ with StandardOLEFormat do
+ begin
+ // Read best format.
+ cfFormat := CF_VIRTUALTREE;
+ end;
+ Result := DataObject.QueryGetData(StandardOLEFormat) = S_OK;
+ if Result and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ BeginUpdate;
+ Result := False;
+ try
+ if TargetNode = nil then
+ TargetNode := FRoot;
+ if TargetNode = FRoot then
+ begin
+ case Mode of
+ amInsertBefore:
+ Mode := amAddChildFirst;
+ amInsertAfter:
+ Mode := amAddChildLast;
+ end;
+ end;
+
+ // Optimized means source is known and in the same process so we can access its pointers, which avoids duplicating
+ // the data while doing a serialization. Can only be used with cut'n paste and drag'n drop with move effect.
+ if Optimized then
+ begin
+ if tsOLEDragging in Source.FStates then
+ Nodes := Source.FDragSelection
+ else
+ Nodes := Source.GetSortedCutCopySet(True);
+
+ if Mode in [amInsertBefore,amAddChildLast] then
+ begin
+ for I := 0 to High(Nodes) do
+ if not HasAsParent(TargetNode, Nodes[I]) then
+ Source.MoveTo(Nodes[I], TargetNode, Mode, False);
+ end
+ else
+ begin
+ for I := High(Nodes) downto 0 do
+ if not HasAsParent(TargetNode, Nodes[I]) then
+ Source.MoveTo(Nodes[I], TargetNode, Mode, False);
+ end;
+ Result := True;
+ end
+ else
+ begin
+ if Source = Self then
+ ChangeReason := crNodeCopied
+ else
+ ChangeReason := crNodeAdded;
+ Res := DataObject.GetData(StandardOLEFormat, Medium);
+ if Res = S_OK then
+ begin
+ case Medium.tymed of
+ TYMED_ISTREAM, // IStream interface
+ TYMED_HGLOBAL: // global memory block
+ begin
+ Stream := nil;
+ if Medium.tymed = TYMED_ISTREAM then
+ Stream := TOLEStream.Create(IUnknown(Medium.stm) as IStream)
+ else
+ begin
+ Data := GlobalLock(Medium.hGlobal);
+ if Assigned(Data) then
+ begin
+ // Get the total size of data to retrieve.
+ I := PCardinal(Data)^;
+ Inc(PCardinal(Data));
+ Stream := TOLEMemoryStream.Create;
+ TOLEMemoryStream(Stream).SetPointer(Data, I);
+ end;
+ end;
+
+ if Assigned(Stream) then
+ try
+ while Stream.Position < Stream.Size do
+ begin
+ Node := MakeNewNode;
+ InternalConnectNode(Node, TargetNode, Self, Mode);
+ InternalAddFromStream(Stream, VTTreeStreamVersion, Node);
+ // This seems a bit strange because of the callback for granting to add the node
+ // which actually comes after the node has been added. The reason is that the node must
+ // contain valid data otherwise I don't see how the application can make a funded decision.
+ if not DoNodeCopying(Node, TargetNode) then
+ DeleteNode(Node)
+ else
+ DoNodeCopied(Node);
+ StructureChange(Node, ChangeReason);
+ end;
+ Result := True;
+ finally
+ Stream.Free;
+ if Medium.tymed = TYMED_HGLOBAL then
+ GlobalUnlock(Medium.hGlobal);
+ end;
+ end;
+ end;
+ ReleaseStgMedium(Medium);
+ end;
+ end;
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ReinitChildren(Node: PVirtualNode; Recursive: Boolean);
+
+// Forces all child nodes of Node to be reinitialized.
+// If Recursive is True then also the grandchildren are reinitialized.
+
+var
+ Run: PVirtualNode;
+
+begin
+ if Assigned(Node) then
+ begin
+ InitChildren(Node);
+ Run := Node.FirstChild;
+ end
+ else
+ begin
+ InitChildren(FRoot);
+ Run := FRoot.FirstChild;
+ end;
+
+ while Assigned(Run) do
+ begin
+ ReinitNode(Run, recursive);
+ Run := Run.NextSibling;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ReinitNode(Node: PVirtualNode; Recursive: Boolean);
+
+// Forces the given node and all its children (if recursive is True) to be initialized again without
+// modifying any data in the nodes nor deleting children (unless the application requests a different amount).
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ // remove dynamic styles
+ Node.States := Node.States - [vsChecking, vsCutOrCopy, vsDeleting];
+ InitNode(Node);
+ end;
+
+ if Recursive then
+ ReinitChildren(Node, True);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.RepaintNode(Node: PVirtualNode);
+
+// Causes an immediate repaint of the given node.
+
+var
+ R: Trect;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ R := GetDisplayRect(Node, -1, False);
+ RedrawWindow(Handle, @R, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE or RDW_VALIDATE or RDW_NOCHILDREN);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ResetNode(Node: PVirtualNode);
+
+// Deletes all children of the given node and marks it as being uninitialized.
+
+begin
+ DoCancelEdit;
+ if (Node = nil) or (Node = FRoot) then
+ Clear
+ else
+ begin
+ DoReset(Node);
+ DeleteChildren(Node);
+ // Remove initialized and other dynamic styles, keep persistent styles.
+ Node.States := Node.States - [vsInitialized, vsChecking, vsCutOrCopy, vsDeleting, vsHasChildren, vsExpanded];
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SaveToFile(const FileName: TFileName);
+
+// Saves the entire content of the tree into a file (see further notes in SaveToStream).
+
+var
+ FileStream: TFileStream;
+
+begin
+ FileStream := TFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(FileStream);
+ finally
+ FileStream.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SaveToStream(Stream: TStream; Node: PVirtualNode = nil);
+
+// Saves Node and all its children to Stream. If Node is nil then all top level nodes will be stored.
+// Note: You should be careful about assuming what is actually saved. The problem here is that we are dealing with
+// virtual data. The tree can so not know what it has to save. The only fact we reliably know is the tree's
+// structure. To be flexible for future enhancements as well as unknown content (unknown to the tree class which
+// is saving/loading the stream) a chunk based approach is used here. Every tree class handles only those
+// chunks which are not handled by an anchestor class and are known by the class.
+//
+// The base tree class saves only the structure of the tree along with application provided data. Descentants may
+// optionally add their own chunks to store additional information. See: WriteChunks.
+
+var
+ Count: Cardinal;
+
+begin
+ Stream.Write(MagicID, SizeOf(MagicID));
+ if Node = nil then
+ begin
+ // Keep number of top level nodes for easy restauration.
+ Count := FRoot.ChildCount;
+ Stream.WriteBuffer(Count, SizeOf(Count));
+
+ // Save entire tree here.
+ Node := FRoot.FirstChild;
+ while Assigned(Node) do
+ begin
+ WriteNode(Stream, Node);
+ Node := Node.NextSibling;
+ end;
+ end
+ else
+ begin
+ Count := 1;
+ Stream.WriteBuffer(Count, SizeOf(Count));
+ WriteNode(Stream, Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ScrollIntoView(Node: PVirtualNode; Center: Boolean; Horizontally: Boolean = False): Boolean;
+
+// Scrolls the tree so that the given node is in the client area and returns True if the tree really has been
+// scrolled (e.g. to avoid further updates) else returns False. If extened focus is enabled then the tree will also
+// be horizontally scrolled if needed.
+// Note: All collapsed parents of the node are expanded.
+
+var
+ MidPoint: Integer;
+ R: TRect;
+ Run: PVirtualNode;
+ UseColumns,
+ HScrollBarVisible: Boolean;
+
+begin
+ Result := False;
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ // Make sure all parents of the node are expanded.
+ Run := Node.Parent;
+ while Run <> FRoot do
+ begin
+ if not (vsExpanded in Run.States) then
+ ToggleNode(Run);
+ Run := Run.Parent;
+ end;
+ UseColumns := FHeader.UseColumns;
+ if UseColumns then
+ R := GetDisplayRect(Node, FFocusedColumn, not (toGridExtensions in FOptions.FMiscOptions))
+ else
+ R := GetDisplayRect(Node, NoColumn, not (toGridExtensions in FOptions.FMiscOptions));
+
+ // The returned rectangle can never be empty after the expand code above.
+ // 1) scroll vertically
+ if R.Top < 0 then
+ begin
+ if Center then
+ SetOffsetY(FOffsetY - R.Top + ClientHeight div 2)
+ else
+ SetOffsetY(FOffsetY - R.Top);
+ Result := True;
+ end
+ else
+ if (R.Bottom > ClientHeight) or Center then
+ begin
+ HScrollBarVisible := (ScrollBarOptions.ScrollBars in [ssBoth, ssHorizontal]) and
+ (ScrollBarOptions.AlwaysVisible or (Integer(FRangeX) > ClientWidth));
+ if Center then
+ SetOffsetY(FOffsetY - R.Bottom + ClientHeight div 2)
+ else
+ SetOffsetY(FOffsetY - R.Bottom + ClientHeight);
+ // When scrolling up and the horizontal scroll appears because of the operation
+ // then we have to move up the node the horizontal scrollbar's height too
+ // in order to avoid that the scroll bar hides the node which we wanted to have in view.
+ if not UseColumns and not HScrollBarVisible and (Integer(FRangeX) > ClientWidth) then
+ SetOffsetY(FOffsetY - GetSystemMetrics(SM_CYHSCROLL));
+ Result := True;
+ end;
+
+ if Horizontally then
+ begin
+ // 2) scroll horizontally
+ if (R.Right > ClientWidth) or (R.Left < 0) then
+ begin
+ MidPoint := -FOffsetX + (R.Left + R.Right) div 2;
+ SetOffsetX((ClientWidth div 2) - MidPoint);
+ Result := True;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SelectAll(VisibleOnly: Boolean);
+
+// Select all nodes in the tree.
+// If VisibleOnly is True then only visible nodes are selected.
+
+var
+ Run: PVirtualNode;
+ NextFunction: function(Node: PVirtualNode): PVirtualNode of object;
+
+begin
+ if toMultiSelect in FOptions.FSelectionOptions then
+ begin
+ ClearTempCache;
+ if VisibleOnly then
+ begin
+ Run := GetFirstVisible;
+ NextFunction := GetNextVisible;
+ end
+ else
+ begin
+ Run := GetFirst;
+ NextFunction := GetNext;
+ end;
+
+ while Assigned(Run) do
+ begin
+ if not(vsSelected in Run.States) then
+ InternalCacheNode(Run);
+ Run := NextFunction(Run);
+ end;
+ if FTempNodeCount > 0 then
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Sort(Node: PVirtualNode; Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True);
+
+// Sorts the given node. The application is queried about how to sort via the OnCompareNodes event.
+// Column is simply passed to the the compare function so the application can also sort in a particular column.
+// In order to free the application from taking care about the sort direction the parameter Direction is used.
+// This way the application can always sort in increasing order, while this method reorders nodes according to this flag.
+
+ //--------------- local functions -------------------------------------------
+
+ function MergeAscending(A, B: PVirtualNode): PVirtualNode;
+
+ // Merges A and B (which both must be sorted via Compare) into one list.
+
+ var
+ Dummy: TVirtualNode;
+
+ begin
+ // This avoids checking for Result = nil in the loops.
+ Result := @Dummy;
+ while Assigned(A) and Assigned(B) do
+ begin
+ if DoCompare(A, B, Column) <= 0 then
+ begin
+ Result.NextSibling := A;
+ Result := A;
+ A := A.NextSibling;
+ end
+ else
+ begin
+ Result.NextSibling := B;
+ Result := B;
+ B := B.NextSibling;
+ end;
+ end;
+
+ // Just append the list which is not nil (or set end of result list to nil if both lists are nil).
+ if Assigned(A) then
+ Result.NextSibling := A
+ else
+ Result.NextSibling := B;
+ // return start of the new merged list
+ Result := Dummy.NextSibling;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function MergeDescending(A, B: PVirtualNode): PVirtualNode;
+
+ // Merges A and B (which both must be sorted via Compare) into one list.
+
+ var
+ Dummy: TVirtualNode;
+
+ begin
+ // this avoids checking for Result = nil in the loops
+ Result := @Dummy;
+ while Assigned(A) and Assigned(B) do
+ begin
+ if DoCompare(A, B, Column) >= 0 then
+ begin
+ Result.NextSibling := A;
+ Result := A;
+ A := A.NextSibling;
+ end
+ else
+ begin
+ Result.NextSibling := B;
+ Result := B;
+ B := B.NextSibling;
+ end;
+ end;
+
+ // Just append the list which is not nil (or set end of result list to nil if both lists are nil).
+ if Assigned(A) then
+ Result.NextSibling := A
+ else
+ Result.NextSibling := B;
+ // Return start of the newly merged list.
+ Result := Dummy.NextSibling;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function MergeSortAscending(var Node: PVirtualNode; N: Cardinal): PVirtualNode;
+
+ // Sorts the list of nodes given by Node (which must not be nil).
+
+ var
+ A, B: PVirtualNode;
+
+ begin
+ if N > 1 then
+ begin
+ A := MergeSortAscending(Node, N div 2);
+ B := MergeSortAscending(Node, (N + 1) div 2);
+ Result := MergeAscending(A, B);
+ end
+ else
+ begin
+ Result := Node;
+ Node := Node.NextSibling;
+ Result.NextSibling := nil;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function MergeSortDescending(var Node: PVirtualNode; N: Cardinal): PVirtualNode;
+
+ // Sorts the list of nodes given by Node (which must not be nil).
+
+ var
+ A, B: PVirtualNode;
+
+ begin
+ if N > 1 then
+ begin
+ A := MergeSortDescending(Node, N div 2);
+ B := MergeSortDescending(Node, (N + 1) div 2);
+ Result := MergeDescending(A, B);
+ end
+ else
+ begin
+ Result := Node;
+ Node := Node.NextSibling;
+ Result.NextSibling := nil;
+ end;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ Run: PVirtualNode;
+ Index: Cardinal;
+
+begin
+ InterruptValidation;
+ if tsEditPending in FStates then
+ begin
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ end;
+
+ if not (tsEditing in FStates) or DoEndEdit then
+ begin
+ if Node = nil then
+ Node := FRoot;
+ if vsHasChildren in Node.States then
+ begin
+ if (Node.ChildCount = 0) and DoInit then
+ InitChildren(Node);
+ // Make sure the children are valid, so they can be sorted at all.
+ if DoInit and (Node.ChildCount > 1) then
+ ValidateChildren(Node, False);
+ // Child count might have changed.
+ if Node.ChildCount > 1 then
+ begin
+ // Sort the linked list, check direction flag only once.
+ if Direction = sdAscending then
+ Node.FirstChild := MergeSortAscending(Node.FirstChild, Node.ChildCount)
+ else
+ Node.FirstChild := MergeSortDescending(Node.FirstChild, Node.ChildCount);
+ // Consolidate the child list finally.
+ Run := Node.FirstChild;
+ Run.PrevSibling := nil;
+ Index := 0;
+ repeat
+ Run.Index := Index;
+ Inc(Index);
+ if Run.NextSibling = nil then
+ Break;
+ Run.NextSibling.PrevSibling := Run;
+ Run := Run.NextSibling;
+ until False;
+ Node.LastChild := Run;
+
+ InvalidateCache;
+ end;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ Invalidate;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SortTree(Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True);
+
+ //--------------- local function --------------------------------------------
+
+ procedure DoSort(Node: PVirtualNode);
+
+ // Recursively sorts Node and its child nodes.
+
+ var
+ Run: PVirtualNode;
+
+ begin
+ Sort(Node, Column, Direction, DoInit);
+
+ Run := Node.FirstChild;
+ while Assigned(Run) do
+ begin
+ if DoInit and not (vsInitialized in Run.States) then
+ InitNode(Run);
+ if vsInitialized in Run.States then
+ DoSort(Run);
+ Run := Run.NextSibling;
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+begin
+ // Instead of wrapping the sort using BeginUpdate/EndUpdate simply the update counter
+ // is modified. Otherwise the EndUpdate call will recurse here.
+ Inc(FUpdateCount);
+ try
+ if Column > InvalidColumn then
+ DoSort(FRoot);
+ InvalidateCache;
+ finally
+ if FUpdateCount > 0 then
+ Dec(FUpdateCount);
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ToggleNode(Node: PVirtualNode);
+
+// Changes a node's expand state to the opposite state.
+
+var
+ LastTopNode,
+ Child: PVirtualNode;
+ NewHeight: Integer;
+ NeedUpdate: Boolean;
+ ToggleData: TToggleAnimationData;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+ NeedUpdate := False;
+
+ // We don't need to switch the expand state if the node is being deleted otherwise some
+ // updates (e.g. visible node count) are done twice with disasterous results).
+ if not (vsDeleting in Node.States) then
+ begin
+ // LastTopNode is needed to know when the entire tree scrolled during toggling.
+ // It is of course only needed when we also update the display here.
+ if FUpdateCount = 0 then
+ LastTopNode := GetTopNode
+ else
+ LastTopNode := nil;
+
+ if vsExpanded in Node.States then
+ begin
+ if DoCollapsing(Node) then
+ begin
+ NeedUpdate := True;
+
+ if (FUpdateCount = 0) and (toAnimatedToggle in FOptions.FAnimationOptions) and not (tsCollapsing in FStates) then
+ begin
+ Application.CancelHint;
+ UpdateWindow(Handle);
+
+ // animated collapsing
+ with ToggleData do
+ begin
+ Expand := False;
+ R := GetDisplayRect(Node, NoColumn, False);
+ R.Bottom := ClientHeight;
+ Inc(R.Top, Node.NodeHeight);
+ Window := Handle;
+ DC := GetDC(Handle);
+ Self.Brush.Color := Color;
+ Brush := Self.Brush.Handle;
+ try
+ Animate(Min(R.Bottom - R.Top + 1, Node.TotalHeight - Node.NodeHeight), FAnimationDuration, ToggleCallback,
+ @ToggleData);
+ finally
+ ReleaseDC(Window, DC);
+ end;
+ end;
+ end;
+
+ // collapse the node
+ AdjustTotalHeight(Node, Node.NodeHeight);
+ if FullyVisible[Node] then
+ Dec(FVisibleCount, CountVisibleChildren(Node));
+ Exclude(Node.States, vsExpanded);
+ DoCollapsed(Node);
+
+ // Remove child nodes now, if enabled.
+ if (toAutoFreeOnCollapse in FOptions.FAutoOptions) and (Node.ChildCount > 0) then
+ begin
+ DeleteChildren(Node);
+ Include(Node.States, vsHasChildren);
+ end;
+ end;
+ end
+ else
+ if DoExpanding(Node) then
+ begin
+ NeedUpdate := True;
+ // expand the node, need to adjust the height
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+
+ // Avoid setting the vsExpanded style if there are no child nodes.
+ if Node.ChildCount > 0 then
+ begin
+ // Iterate through the child nodes without initializing them. We have to determine the entire height.
+ NewHeight := 0;
+ Child := Node.FirstChild;
+ repeat
+ if vsVisible in Child.States then
+ Inc(NewHeight, Child.TotalHeight);
+ Child := Child.NextSibling;
+ until Child = nil;
+
+ if FUpdateCount = 0 then
+ begin
+ ToggleData.R := GetDisplayRect(Node, NoColumn, False);
+
+ // Do animated expanding if enabled and it is not the last visible node to be expanded.
+ if (ToggleData.R.Top < ClientHeight) and ([tsPainting, tsExpanding] * FStates = []) and
+ (toAnimatedToggle in FOptions.FAnimationOptions) and (GetNextVisibleNoInit(Node) <> nil) then
+ begin
+ Application.CancelHint;
+ UpdateWindow(Handle);
+ // animated expanding
+ with ToggleData do
+ begin
+ Inc(R.Top, Node.NodeHeight);
+ R.Bottom := ClientHeight;
+ if R.Bottom > R.Top then
+ begin
+ Expand := True;
+ Window := Handle;
+ DC := GetDC(Handle);
+
+ Self.Brush.Color := Color;
+ Brush := Self.Brush.Handle;
+ try
+ Animate(Min(R.Bottom - R.Top + 1, NewHeight), FAnimationDuration, ToggleCallback, @ToggleData);
+ finally
+ ReleaseDC(Window, DC);
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ Include(Node.States, vsExpanded);
+ AdjustTotalHeight(Node, NewHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node));
+
+ DoExpanded(Node);
+ end;
+ end;
+
+ if NeedUpdate then
+ begin
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ if Node.ChildCount > 0 then
+ begin
+ ValidateCache;
+ UpdateScrollbars(True);
+ // Scroll as much child nodes into view as possible if the node has been expanded.
+ if (toAutoScrollOnExpand in FOptions.FAutoOptions) and (vsExpanded in Node.States) then
+ begin
+ if Integer(Node.TotalHeight) <= ClientHeight then
+ ScrollIntoView(GetLastChild(Node), toCenterScrollIntoView in FOptions.SelectionOptions)
+ else
+ TopNode := Node;
+ end;
+
+ // Check for automatically scrolled tree.
+ if LastTopNode <> GetTopNode then
+ Invalidate
+ else
+ InvalidateToBottom(Node);
+ end
+ else
+ InvalidateNode(Node);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.UpdateAction(Action: TBasicAction): Boolean;
+
+// Support for standard actions.
+
+begin
+ if not Focused then
+ Result := inherited UpdateAction(Action)
+ else
+ begin
+ Result := (Action is TEditCut) or (Action is TEditCopy)
+ {$ifdef COMPILER_5_UP} or (Action is TEditDelete) {$endif COMPILER_5_UP};
+
+ if Result then
+ TAction(Action).Enabled := (FSelectionCount > 0) and
+ ({$ifdef COMPILER_5_UP} (Action is TEditDelete) or {$endif COMPILER_5_UP} (FClipboardFormats.Count > 0))
+ else
+ begin
+ Result := Action is TEditPaste;
+ if Result then
+ TAction(Action).Enabled := True
+ else
+ begin
+ {$ifdef COMPILER_5_UP}
+ Result := Action is TEditSelectAll;
+ if Result then
+ TAction(Action).Enabled := (toMultiSelect in FOptions.FSelectionOptions) and (FVisibleCount > 0)
+ else
+ {$endif COMPILER_5_UP}
+ Result := inherited UpdateAction(Action);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateHorizontalScrollBar(DoRepaint: Boolean);
+
+var
+ ScrollInfo: TScrollInfo;
+
+begin
+ if FHeader.UseColumns then
+ FRangeX := FHeader.FColumns.TotalWidth
+ else
+ FRangeX := GetMaxRightExtend;
+
+ if FScrollBarOptions.ScrollBars in [ssHorizontal, ssBoth] then
+ begin
+ FillChar(ScrollInfo, SizeOf(ScrollInfo), 0);
+ ScrollInfo.cbSize := SizeOf(ScrollInfo);
+ ScrollInfo.fMask := SIF_ALL;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_GetScrollInfo(Handle, SB_HORZ, ScrollInfo);
+ {$else}
+ GetScrollInfo(Handle, SB_HORZ, ScrollInfo);
+ {$endif UseFlatScrollbars}
+
+ if (Integer(FRangeX) > ClientWidth) or FScrollBarOptions.AlwaysVisible then
+ begin
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_HORZ, True);
+ {$else}
+ ShowScrollBar(Handle, SB_HORZ, True);
+ {$endif UseFlatScrollbars}
+
+ ScrollInfo.nMin := 0;
+ ScrollInfo.nMax := FRangeX;
+ ScrollInfo.nPos := -FOffsetX;
+ ScrollInfo.nPage := Max(0, ClientWidth + 1);
+
+ ScrollInfo.fMask := SIF_ALL or ScrollMasks[FScrollBarOptions.AlwaysVisible];
+ {$ifdef UseFlatScrollbars}
+ FlatSB_SetScrollInfo(Handle, SB_HORZ, ScrollInfo, DoRepaint);
+ {$else}
+ SetScrollInfo(Handle, SB_HORZ, ScrollInfo, DoRepaint);
+ {$endif UseFlatScrollbars}
+ end
+ else
+ begin
+ ScrollInfo.nMin := 0;
+ ScrollInfo.nMax := 0;
+ ScrollInfo.nPos := 0;
+ ScrollInfo.nPage := 0;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_HORZ, False);
+ FlatSB_SetScrollInfo(Handle, SB_HORZ, ScrollInfo, False);
+ {$else}
+ ShowScrollBar(Handle, SB_HORZ, False);
+ SetScrollInfo(Handle, SB_HORZ, ScrollInfo, False);
+ {$endif UseFlatScrollbars}
+ end;
+
+ // Since the position is automatically changed if it doesn't meet the range
+ // we better read the current position back to stay synchronized.
+ {$ifdef UseFlatScrollbars}
+ SetOffsetX(-FlatSB_GetScrollPos(Handle, SB_HORZ));
+ {$else}
+ SetOffsetX(-GetScrollPos(Handle, SB_HORZ));
+ {$endif UseFlatScrollbars}
+ end
+ else
+ begin
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_HORZ, False);
+ {$else}
+ ShowScrollBar(Handle, SB_HORZ, False);
+ {$endif UseFlatScrollbars}
+
+ // Reset the current horizontal offset to account for window resize etc.
+ SetOffsetX(FOffsetX);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateScrollBars(DoRepaint: Boolean);
+
+// adjusts scrollbars to reflect current size and paint offset of the tree
+
+begin
+ if HandleAllocated then
+ begin
+ UpdateHorizontalScrollBar(DoRepaint);
+ UpdateVerticalScrollBar(DoRepaint);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateVerticalScrollBar(DoRepaint: Boolean);
+
+var
+ ScrollInfo: TScrollInfo;
+
+begin
+ // total node height includes the height of the invisble root node
+ if FRoot.TotalHeight < FDefaultNodeHeight then
+ FRoot.TotalHeight := FDefaultNodeHeight;
+ FRangeY := FRoot.TotalHeight - FRoot.NodeHeight;
+
+ if FScrollBarOptions.ScrollBars in [ssVertical, ssBoth] then
+ begin
+ ScrollInfo.cbSize := SizeOf(ScrollInfo);
+ ScrollInfo.fMask := SIF_ALL;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_GetScrollInfo(Handle, SB_VERT, ScrollInfo);
+ {$else}
+ GetScrollInfo(Handle, SB_VERT, ScrollInfo);
+ {$endif UseFlatScrollbars}
+
+ if (Integer(FRangeY) > ClientHeight) or FScrollBarOptions.AlwaysVisible then
+ begin
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_VERT, True);
+ {$else}
+ ShowScrollBar(Handle, SB_VERT, True);
+ {$endif UseFlatScrollbars}
+
+ ScrollInfo.nMin := 0;
+ ScrollInfo.nMax := FRangeY;
+ ScrollInfo.nPos := -FOffsetY;
+ ScrollInfo.nPage := Max(0, ClientHeight + 1);
+
+ ScrollInfo.fMask := SIF_ALL or ScrollMasks[FScrollBarOptions.AlwaysVisible];
+ {$ifdef UseFlatScrollbars}
+ FlatSB_SetScrollInfo(Handle, SB_VERT, ScrollInfo, DoRepaint);
+ {$else}
+ SetScrollInfo(Handle, SB_VERT, ScrollInfo, DoRepaint);
+ {$endif UseFlatScrollbars}
+ end
+ else
+ begin
+ ScrollInfo.nMin := 0;
+ ScrollInfo.nMax := 0;
+ ScrollInfo.nPos := 0;
+ ScrollInfo.nPage := 0;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_VERT, False);
+ FlatSB_SetScrollInfo(Handle, SB_VERT, ScrollInfo, False);
+ {$else}
+ ShowScrollBar(Handle, SB_VERT, False);
+ SetScrollInfo(Handle, SB_VERT, ScrollInfo, False);
+ {$endif UseFlatScrollbars}
+ end;
+
+ // Since the position is automatically changed if it doesn't meet the range
+ // we better read the current position back to stay synchronized.
+ {$ifdef UseFlatScrollbars}
+ SetOffsetY(-FlatSB_GetScrollPos(Handle, SB_VERT));
+ {$else}
+ SetOffsetY(-GetScrollPos(Handle, SB_VERT));
+ {$endif UseFlatScrollBars}
+ end
+ else
+ begin
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_VERT, False);
+ {$else}
+ ShowScrollBar(Handle, SB_VERT, False);
+ {$endif UseFlatScrollbars}
+
+ // Reset the current vertical offset to account for window resize etc.
+ SetOffsetY(FOffsetY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.UseRightToLeftReading: Boolean;
+
+// The tree can handle right-to-left reading also on non-middle-east systems, so we cannot use the same function as
+// it is implemented in TControl.
+
+begin
+ Result := BiDiMode <> bdLeftToRight;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ValidateChildren(Node: PVirtualNode; Recursive: Boolean);
+
+// Ensures that the children of the given node (and all their children, if Recursive is True) are initialized.
+// Node must already be initialized
+
+var
+ Child: PVirtualNode;
+
+begin
+ if Node = nil then
+ Node := FRoot;
+
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+ Child := Node.FirstChild;
+ while Assigned(Child) do
+ begin
+ ValidateNode(Child, Recursive);
+ Child := Child.NextSibling;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ValidateNode(Node: PVirtualNode; Recursive: Boolean);
+
+// Ensures that the given node (and all its children, if Recursive is True) are initialized.
+
+var
+ Child: PVirtualNode;
+
+begin
+ if Node = nil then
+ Node := FRoot
+ else
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ if Recursive then
+ begin
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+ Child := Node.FirstChild;
+ while Assigned(Child) do
+ begin
+ ValidateNode(Child, recursive);
+ Child := Child.NextSibling;
+ end;
+ end;
+end;
+
+//----------------- TCustomStringTreeOptions ---------------------------------------------------------------------------
+
+constructor TCustomStringTreeOptions.Create(AOwner: TBaseVirtualTree);
+
+begin
+ inherited;
+
+ FStringOptions := DefaultStringOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomStringTreeOptions.SetStringOptions(const Value: TVTStringOptions);
+
+var
+ ChangedOptions: TVTStringOptions;
+
+begin
+ if FStringOptions <> Value then
+ begin
+ // Exclusive ORing to get all entries wich are in either set but not in both.
+ ChangedOptions := FStringOptions + Value - (FStringOptions * Value);
+ FStringOptions := Value;
+ with FOwner do
+ if (toShowStaticText in ChangedOptions) and not (csLoading in ComponentState) and HandleAllocated then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomStringTreeOptions.AssignTo(Dest: TPersistent);
+
+begin
+ if Dest is TCustomStringTreeOptions then
+ begin
+ with Dest as TCustomStringTreeOptions do
+ StringOptions := Self.StringOptions;
+ end;
+
+ // Let ancestors assign their options to the destination class.
+ inherited;
+end;
+
+//----------------- TVTEdit --------------------------------------------------------------------------------------------
+
+// Implementation of a generic node caption editor.
+
+constructor TVTEdit.Create(Link: TStringEditLink);
+
+begin
+ inherited Create(nil);
+ ShowHint := False;
+ ParentShowHint := False;
+ FLink := Link;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.CMAutoAdjust(var Message: TMessage);
+
+begin
+ AutoAdjustSize;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.CMExit(var Message: TMessage);
+
+begin
+ if not FLink.FStopping then
+ with FLink, FTree do
+ begin
+ if (toAutoAcceptEditChange in TreeOptions.StringOptions) then
+ FLink.FTree.DoEndEdit
+ else
+ FLink.FTree.DoCancelEdit;
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.CNCommand(var Message: TWMCommand);
+
+begin
+ if Assigned(FLink) and Assigned(FLink.FTree) and (Message.NotifyCode = EN_UPDATE) and
+ not (toGridExtensions in FLink.FTree.FOptions.MiscOptions) and
+ not (vsMultiline in FLink.FNode.States) then
+ // Instead directly calling AutoAdjustSize it is necessary on Win9x/Me to decouple this notification message
+ // and eventual resizing. Hence we use a message to accomplish that.
+ if IsWinNT then
+ AutoAdjustSize
+ else
+ PostMessage(Handle, CM_AUTOADJUST, 0, 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.WMChar(var Message: TWMChar);
+
+begin
+ if not (Message.CharCode in [VK_ESCAPE, VK_TAB]) then
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.WMDestroy(var Message: TWMDestroy);
+
+begin
+ // If editing stopped by other means than accept or cancel then we have to do default processing for
+ // pending changes.
+ if not FLink.FStopping then
+ with FLink, FTree do
+ begin
+ if (toAutoAcceptEditChange in TreeOptions.StringOptions) and Modified then
+ DoNewText(FNode, FColumn, FEdit.Caption);
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.WMGetDlgCode(var Message: TWMGetDlgCode);
+
+begin
+ inherited;
+
+ Message.Result := Message.Result or DLGC_WANTALLKEYS;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.WMKeyDown(var Message: TWMKeyDown);
+
+// Handles some control keys.
+
+var
+ Shift: TShiftState;
+ EndEdit: Boolean;
+
+begin
+ case Message.CharCode of
+ // Pretend these keycodes were send to the tree.
+ VK_ESCAPE:
+ begin
+ FLink.FTree.DoCancelEdit;
+ // Set focus back to tree.
+ FLink.FTree.SetFocus;
+ end;
+ VK_RETURN:
+ begin
+ EndEdit := not (vsMultiline in FLink.FNode.States);
+ if not EndEdit then
+ begin
+ // If a multiline node is being edited the finish editing only if Ctrl+Enter was pressed,
+ // otherwise allow to insert line breaks into the text.
+ Shift := KeyDataToShiftState(Message.KeyData);
+ EndEdit := ssCtrl in Shift;
+ end;
+ if EndEdit then
+ begin
+ FLink.FTree.InvalidateNode(FLink.FNode);
+ FLink.FTree.DoEndEdit;
+ // Set focus back to tree.
+ FLink.FTree.SetFocus;
+ end;
+ end;
+ VK_UP:
+ begin
+ if not (vsMultiline in FLink.FNode.States) then
+ Message.CharCode := VK_LEFT;
+ inherited;
+ end;
+ VK_DOWN:
+ begin
+ if not (vsMultiline in FLink.FNode.States) then
+ Message.CharCode := VK_RIGHT;
+ inherited;
+ end;
+ else
+ inherited;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.AutoAdjustSize;
+
+// Changes the size of the edit to accomodate as much as possible of its text within its container window.
+// NewChar describes the next character which will be added to the edit's text.
+
+var
+ DC: HDC;
+ Size: TSize;
+ LastFont: THandle;
+
+begin
+ if not (vsMultiline in FLink.FNode.States) then
+ begin
+ // avoid flicker
+ SendMessage(Handle, WM_SETREDRAW, 0, 0);
+
+ DC := GetDC(Handle);
+ LastFont := SelectObject(DC, Font.Handle);
+ try
+ // Read needed space for the current text.
+ {$ifdef TntSupport}
+ GetTextExtentPoint32W(DC, PWideChar(Text), Length(Text), Size);
+ {$else}
+ GetTextExtentPoint32(DC, PChar(Text), Length(Text), Size);
+ {$endif TntSupport}
+ Inc(Size.cx, 2 * FLink.FTree.FTextMargin);
+
+ // Repaint associated node if the edit becomes smaller.
+ if Size.cx < Width then
+ FLink.FTree.InvalidateNode(FLink.FNode);
+
+ if FLink.FAlignment = taRightJustify then
+ FLink.SetBounds(Rect(Left + Width - Size.cx, Top, Left + Width, Top + Height))
+ else
+ FLink.SetBounds(Rect(Left, Top, Left + Size.cx, Top + Height));
+ finally
+ SelectObject(DC, LastFont);
+ ReleaseDC(Handle, DC);
+ SendMessage(Handle, WM_SETREDRAW, 1, 0);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.CreateParams(var Params: TCreateParams);
+
+begin
+ inherited;
+
+ // Only with multiline style we can use the text formatting rectangle.
+ // This does not harm formatting as single line control, if we don't use word wrapping.
+ with Params do
+ begin
+ Style := Style or ES_MULTILINE;
+ if vsMultiline in FLink.FNode.States then
+ Style := Style and not (ES_AUTOHSCROLL or WS_HSCROLL) or WS_VSCROLL or ES_AUTOVSCROLL;
+ if tsUseThemes in FLink.FTree.FStates then
+ begin
+ Style := Style and not WS_BORDER;
+ ExStyle := ExStyle or WS_EX_CLIENTEDGE;
+ end
+ else
+ begin
+ Style := Style or WS_BORDER;
+ ExStyle := ExStyle and not WS_EX_CLIENTEDGE;
+ end;
+ end;
+end;
+
+//----------------- TStringEditLink ------------------------------------------------------------------------------------
+
+constructor TStringEditLink.Create;
+
+begin
+ inherited;
+ FEdit := TVTEdit.Create(Self);
+ with FEdit do
+ begin
+ Visible := False;
+ BorderStyle := bsSingle;
+ AutoSize := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TStringEditLink.Destroy;
+
+begin
+ FEdit.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.BeginEdit: Boolean;
+
+// Notifies the edit link that editing can start now. Descentants may cancel node edit
+// by returning False.
+
+begin
+ Result := not FStopping;
+ if Result then
+ begin
+ FEdit.Show;
+ FEdit.SelectAll;
+ FEdit.SetFocus;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TStringEditLink.SetEdit(const Value: TVTEdit);
+
+begin
+ if Assigned(FEdit) then
+ FEdit.Free;
+ FEdit := Value;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.CancelEdit: Boolean;
+
+begin
+ Result := not FStopping;
+ if Result then
+ begin
+ FStopping := True;
+ FEdit.Hide;
+ FTree.CancelEditNode;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.EndEdit: Boolean;
+
+begin
+ Result := not FStopping;
+ if Result then
+ try
+ FStopping := True;
+ if FEdit.Modified then
+ FTree.DoNewText(FNode, FColumn, FEdit.Text);
+ FEdit.Hide;
+ except
+ FStopping := False;
+ raise;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.GetBounds: TRect;
+
+begin
+ Result := FEdit.BoundsRect;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// Retrieves the true text bounds from the owner tree.
+
+var
+ Text: WideString;
+
+begin
+ Result := Tree is TCustomVirtualStringTree;
+ if Result then
+ begin
+ FTree := Tree as TCustomVirtualStringTree;
+ FNode := Node;
+ FColumn := Column;
+ // Initial size, font and text of the node.
+ FTree.GetTextInfo(Node, Column, FEdit.Font, FTextBounds, Text);
+ FEdit.Font.Color := clBlack;
+ FEdit.Parent := Tree;
+ FEdit.RecreateWnd;
+ FEdit.HandleNeeded;
+ {$ifdef TntSupport}
+ FEdit.Text := Text;
+ {$else}
+ FEdit.Caption := Text;
+ {$endif}
+
+ if Column <= NoColumn then
+ begin
+ FEdit.BidiMode := FTree.BidiMode;
+ FAlignment := FTree.Alignment;
+ end
+ else
+ begin
+ FEdit.BidiMode := FTree.Header.Columns[Column].BidiMode;
+ FAlignment := FTree.Header.Columns[Column].Alignment;
+ end;
+
+ if FEdit.BidiMode <> bdLeftToRight then
+ ChangeBidiModeAlignment(FAlignment);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TStringEditLink.ProcessMessage(var Message: TMessage);
+
+begin
+ FEdit.WindowProc(Message);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TStringEditLink.SetBounds(R: TRect);
+
+// Sets the outer bounds of the edit control and the actual edit area in the control.
+
+var
+ Offset: Integer;
+
+begin
+ if not FStopping then
+ begin
+ with R do
+ begin
+ // Set the edit's bounds but make sure there's a minimum width and the right border does not
+ // extend beyond the parent's left/right border.
+ if Left < 0 then
+ Left := 0;
+ if Right - Left < 30 then
+ begin
+ if FAlignment = taRightJustify then
+ Left := Right - 30
+ else
+ Right := Left + 30;
+ end;
+ if Right > FTree.ClientWidth then
+ Right := FTree.ClientWidth;
+ FEdit.BoundsRect := R;
+
+ // The selected text shall exclude the text margins and be centered vertically.
+ // We have to take out the two pixel border of the edit control as well as a one pixel "edit border" the
+ // control leaves around the (selected) text.
+ R := FEdit.ClientRect;
+ Offset := 2;
+ if tsUseThemes in FTree.FStates then
+ Inc(Offset);
+ if vsMultiline in FNode.States then
+ InflateRect(R, -FTree.FTextMargin + Offset, -FTree.FTextMargin + Offset)
+ else
+ begin
+ InflateRect(R, -FTree.FTextMargin + Offset, Offset);
+ OffsetRect(R, 0, FTextBounds.Top - FEdit.Top);
+ end;
+
+ SendMessage(FEdit.Handle, EM_SETRECTNP, 0, Integer(@R));
+ end;
+ end;
+end;
+
+//----------------- TCustomVirtualString -------------------------------------------------------------------------------
+
+constructor TCustomVirtualStringTree.Create(AOwner: TComponent);
+
+begin
+ inherited;
+
+ FDefaultText := 'Node';
+ FInternalDataOffset := AllocateInternalDataArea(SizeOf(Cardinal));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.GetRenderStartValues(Source: TVSTTextSourceType; var Node: PVirtualNode;
+ var NextNodeProc: TGetNextNodeProc);
+
+begin
+ case Source of
+ tstInitialized:
+ begin
+ Node := GetFirstInitialized;
+ NextNodeProc := GetNextInitialized;
+ end;
+ tstSelected:
+ begin
+ Node := GetFirstSelected;
+ NextNodeProc := GetNextSelected;
+ end;
+ tstCutCopySet:
+ begin
+ Node := GetFirstCutCopy;
+ NextNodeProc := GetNextCutCopy;
+ end;
+ tstVisible:
+ begin
+ Node := GetFirstVisible;
+ NextNodeProc := GetNextVisible;
+ end;
+ else // tstAll
+ Node := GetFirst;
+ NextNodeProc := GetNext;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.GetOptions: TCustomStringTreeOptions;
+
+begin
+ Result := FOptions as TCustomStringTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.GetText(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ Result := FDefaultText;
+
+ DoGetText(Node, Column, ttNormal, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.InitializeTextProperties(const Canvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex);
+
+// Initializes default values for customization in PaintNormalText.
+
+begin
+ Canvas.Font := Font;
+
+ if (toHotTrack in FOptions.FPaintOptions) and (Node = FCurrentHotNode) then
+ begin
+ Canvas.Font.Style := Canvas.Font.Style + [fsUnderline];
+ Canvas.Font.Color := FColors.HotColor;
+ end;
+
+ if (Column = FFocusedColumn) or (toFullRowSelect in FOptions.FSelectionOptions) then
+ begin
+ if Node = FDropTargetNode then
+ begin
+ if (FLastDropMode = dmOnNode) or (vsSelected in Node.States)then
+ Canvas.Font.Color := clHighlightText
+ else
+ Canvas.Font.Color := Font.Color;
+ end
+ else
+ if vsSelected in Node.States then
+ begin
+ if Focused or (toPopupMode in FOptions.FPaintOptions) then
+ Canvas.Font.Color := clHighlightText
+ else
+ Canvas.Font.Color := Font.Color;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.PaintNormalText(var PaintInfo: TVTPaintInfo; TextOutFlags: Integer;
+ Text: WideString);
+
+// This method is responsible for painting the given test to target canvas (under consideration of the given rectangles).
+// The text drawn here is considered as the normal text in a node.
+// Note: NodeWidth is the actual width of the text to be drawn. This does not necessarily correspond to the width of
+// the node rectangle. The clipping rectangle comprises the entire node (including tree lines, buttons etc.).
+
+var
+ TripleWidth: Integer;
+ R: TRect;
+ DrawFormat: Cardinal;
+ Size: TSize;
+
+begin
+ with PaintInfo do
+ begin
+ InitializeTextProperties(Canvas, Node, Column);
+
+ R := ContentRect;
+ Canvas.TextFlags := 0;
+
+ // Multiline nodes don't need special font handling or text manipulation.
+ // Note: multiline support requires the Unicode version of DrawText, which is able to do word breaking.
+ // The emulation in this unit does not support this so we have to use the OS version. However
+ // DrawTextW is only available on NT/2000/XP and up. Hence there is only partial multiline support
+ // for 9x/Me.
+ if vsMultiline in Node.States then
+ begin
+ InflateRect(R, -FTextMargin, -FTextMargin);
+ DoPaintText(Node, Canvas, Column, ttNormal);
+ // Disabled node color overrides all other variants.
+ if (vsDisabled in Node.States) or not Enabled then
+ Canvas.Font.Color := FColors.DisabledColor;
+
+ // The edit control flag will ensure that no partial line is displayed, that is, only lines
+ // which are (vertically) fully visible are drawn.
+ DrawFormat := DT_NOPREFIX or DT_WORDBREAK or DT_END_ELLIPSIS or DT_EDITCONTROL or AlignmentToDrawFlag[Alignment];
+ if BidiMode <> bdLeftToRight then
+ DrawFormat := DrawFormat or DT_RTLREADING;
+ end
+ else
+ begin
+ InflateRect(R, -FTextMargin, 0);
+ FFontChanged := False;
+ TripleWidth := FEllipsisWidth;
+ DoPaintText(Node, Canvas, Column, ttNormal);
+ if FFontChanged then
+ begin
+ // If the font has been changed then the ellipsis width must be recalculated.
+ TripleWidth := 0;
+ // Recalculate also the width of the normal text.
+ GetTextExtentPoint32W(Canvas.Handle, PWideChar(Text), Length(Text), Size);
+ NodeWidth := Size.cx + 2 * FTextMargin;
+ end;
+
+ // Disabled node color overrides all other variants.
+ if (vsDisabled in Node.States) or not Enabled then
+ Canvas.Font.Color := FColors.DisabledColor;
+
+ DrawFormat := DT_NOPREFIX or DT_VCENTER or DT_SINGLELINE;
+ if BidiMode <> bdLeftToRight then
+ DrawFormat := DrawFormat or DT_RTLREADING;
+ // Check if the text must be shortend.
+ if (Column > -1) and ((NodeWidth - 2 * FTextMargin) > R.Right - R.Left) then
+ begin
+ Text := DoShortenString(Canvas, Node, Column, Text, R.Right - R.Left, BidiMode <> bdLeftToRight, TripleWidth);
+ if Alignment = taRightJustify then
+ DrawFormat := DrawFormat or DT_RIGHT
+ else
+ DrawFormat := DrawFormat or DT_LEFT;
+ end
+ else
+ DrawFormat := DrawFormat or AlignmentToDrawFlag[Alignment];
+ end;
+
+ if Canvas.TextFlags and ETO_OPAQUE = 0 then
+ SetBkMode(Canvas.Handle, TRANSPARENT)
+ else
+ SetBkMode(Canvas.Handle, OPAQUE);
+ if IsWinNT then
+ Windows.DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat)
+ else
+ DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.PaintStaticText(const PaintInfo: TVTPaintInfo; TextOutFlags: Integer;
+ const Text: WideString);
+
+// This method retrives and draws the static text bound to a particular node.
+
+var
+ R: TRect;
+ DrawFormat: Cardinal;
+
+begin
+ with PaintInfo do
+ begin
+ Canvas.Font := Font;
+ if toFullRowSelect in FOptions.FSelectionOptions then
+ begin
+ if Node = FDropTargetNode then
+ begin
+ if (FLastDropMode = dmOnNode) or (vsSelected in Node.States)then
+ Canvas.Font.Color := clHighlightText
+ else
+ Canvas.Font.Color := Font.Color;
+ end
+ else
+ if vsSelected in Node.States then
+ begin
+ if Focused or (toPopupMode in FOptions.FPaintOptions) then
+ Canvas.Font.Color := clHighlightText
+ else
+ Canvas.Font.Color := Font.Color;
+ end;
+ end;
+
+ DrawFormat := DT_VCENTER or DT_SINGLELINE;
+ Canvas.TextFlags := 0;
+ DoPaintText(Node, Canvas, Column, ttStatic);
+
+ // Disabled node color overrides all other variants.
+ if (vsDisabled in Node.States) or not Enabled then
+ Canvas.Font.Color := FColors.DisabledColor;
+
+ R := ContentRect;
+ if Alignment = taRightJustify then
+ Dec(R.Right, NodeWidth + FTextMargin)
+ else
+ Inc(R.Left, NodeWidth + FTextMargin);
+
+ if Canvas.TextFlags and ETO_OPAQUE = 0 then
+ SetBkMode(Canvas.Handle, TRANSPARENT)
+ else
+ SetBkMode(Canvas.Handle, OPAQUE);
+ if IsWinNT then
+ Windows.DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat)
+ else
+ DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.ReadText(Reader: TReader);
+
+begin
+ case Reader.NextValue of
+ vaLString, vaString:
+ SetDefaultText(Reader.ReadString);
+ else
+ SetDefaultText(Reader.ReadWideString);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.SetDefaultText(const Value: WideString);
+
+begin
+ if FDefaultText <> Value then
+ begin
+ FDefaultText := Value;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.SetOptions(const Value: TCustomStringTreeOptions);
+
+begin
+ FOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.SetText(Node: PVirtualNode; Column: TColumnIndex; const Value: WideString);
+
+begin
+ DoNewText(Node, Column, Value);
+ InvalidateNode(Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.WriteText(Writer: TWriter);
+
+begin
+ Writer.WriteWideString(FDefaultText);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.WMSetFont(var Msg: TWMSetFont);
+
+// Whenever a new font is applied to the tree some default values are determined to avoid frequent
+// determination of the same value.
+
+var
+ MemDC: HDC;
+ Run: PVirtualNode;
+ TM: TTextMetric;
+ Size: TSize;
+
+begin
+ inherited;
+
+ MemDC := CreateCompatibleDC(0);
+ try
+ SelectObject(MemDC, Msg.Font);
+ GetTextMetrics(MemDC, TM);
+ FTextHeight := TM.tmHeight;
+
+ GetTextExtentPoint32W(MemDC, '...', 3, Size);
+ FEllipsisWidth := Size.cx;
+ finally
+ DeleteDC(MemDC);
+ end;
+
+ // Have to reset all node widths.
+ Run := FRoot.FirstChild;
+ while Assigned(Run) do
+ begin
+ PInteger(InternalData(Run))^ := 0;
+ Run := GetNextNoInit(Run);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex);
+
+// In the case a node spans several columns (if enabled) we need to determine how many columns.
+// Note: the autospan feature can only be used with left-to-right layout.
+
+begin
+ if (toAutoSpanColumns in FOptions.FAutoOptions) and FHeader.UseColumns and (PaintInfo.BidiMode = bdLeftToRight) then
+ with FHeader.FColumns, PaintInfo do
+ begin
+ // Start with the directly following column.
+ NextNonEmpty := GetNextVisibleColumn(Column);
+
+ // Auto spanning columns can only be used for left-to-right directionality because the tree is drawn
+ // from left to right. For RTL directionality it would be necessary to draw it from right to left.
+ // While this could be managed, it becomes impossible when directionality is mixed.
+ repeat
+ if (NextNonEmpty = InvalidColumn) or not ColumnIsEmpty(Node, NextNonEmpty) or
+ (Items[NextNonEmpty].BidiMode <> bdLeftToRight) then
+ Break;
+ Inc(CellRect.Right, Items[NextNonEmpty].Width);
+ NextNonEmpty := GetNextVisibleColumn(NextNonEmpty);
+ until False;
+ end
+ else
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.CalculateTextWidth(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ Text: WideString): Integer;
+
+// determines the width of the given text
+
+var
+ Size: TSize;
+
+begin
+ Result := 2 * FTextMargin;
+ if Length(Text) > 0 then
+ begin
+ Canvas.Font := Font;
+ DoPaintText(Node, Canvas, Column, ttNormal);
+
+ GetTextExtentPoint32W(Canvas.Handle, PWideChar(Text), Length(Text), Size);
+ Inc(Result, Size.cx);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// For hit tests it is necessary to consider cases where columns are empty and automatic column spanning is enabled.
+// This method simply checks the given column's text and if this is empty then the column is considered as being empty.
+
+begin
+ Result := Length(Text[Node, Column]) = 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DefineProperties(Filer: TFiler);
+
+begin
+ inherited;
+
+ // Delphi still cannot handle wide strings properly while streaming
+ Filer.DefineProperty('WideDefaultText', ReadText, WriteText, FDefaultText <> 'Node');
+ Filer.DefineProperty('StringOptions', ReadOldStringOptions, nil, False);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink;
+
+begin
+ Result := inherited DoCreateEditor(Node, Column);
+ // Enable generic label editing support if the application does not have own editors.
+ if Result = nil then
+ Result := TStringEditLink.Create;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Result := inherited DoGetNodeHint(Node, Column);
+ if Assigned(FOnGetHint) then
+ FOnGetHint(Self, Node, Column, ttNormal, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Result := Hint;
+ Result := Text[Node, Column];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;
+
+// Returns the text width of the given node in pixels.
+// This width is stored in the node's data member to increase access speed.
+
+var
+ Data: PInteger;
+
+begin
+ if (Column > NoColumn) and (vsMultiline in Node.States) then
+ Result := FHeader.Columns[Column].Width
+ else
+ begin
+ if Canvas = nil then
+ Canvas := Self.Canvas;
+
+ if Column = FHeader.MainColumn then
+ begin
+ // primary column or no columns
+ Data := InternalData(Node);
+ Result := Data^;
+ if Result = 0 then
+ begin
+ Data^ := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]);
+ Result := Data^;
+ end;
+ end
+ else
+ // any other column
+ Result := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DoGetText(Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+
+begin
+ if Assigned(FOnGetText) then
+ FOnGetText(Self, Node, Column, TextType, Text);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoIncrementalSearch(Node: PVirtualNode; const Text: WideString): Integer;
+
+// Since the string tree has access to node text it can do incremental search on its own. Use the event to
+// override the default behavior.
+
+begin
+ Result := 0;
+ if Assigned(FOnIncrementalSearch) then
+ FOnIncrementalSearch(Self, Node, Text, Result)
+ else
+ // Default behavior is to match the search string with the start of the node text.
+ if Pos(Text, GetText(Node, FocusedColumn)) <> 1 then
+ Result := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DoNewText(Node: PVirtualNode; Column: TColumnIndex; Text: WideString);
+
+begin
+ if Assigned(FOnNewText) then
+ FOnNewText(Self, Node, Column, Text);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DoPaintNode(var PaintInfo: TVTPaintInfo);
+
+// Main output routine to print the text of the given node using the space provided in PaintInfo.ContentRect.
+
+var
+ S: WideString;
+ TextOutFlags: Integer;
+
+begin
+ // Set a new OnChange event for the canvas' font so we know if the application changes it in the callbacks.
+ // This long winded procedure is necessary because font changes (as well as brush and pen changes) are
+ // unfortunately not announced via the Canvas.OnChange event.
+ RedirectFontChangeEvent(PaintInfo.Canvas);
+
+ // Determine main text direction as well as other text properties.
+ TextOutFlags := ETO_CLIPPED or RTLFlag[PaintInfo.BidiMode <> bdLeftToRight];
+ S := Text[PaintInfo.Node, PaintInfo.Column];
+
+ // Paint the normal text first...
+ if Length(S) > 0 then
+ PaintNormalText(PaintInfo, TextOutFlags, S);
+
+ // ... and afterwards the static text if not centered and the node is not multiline enabled.
+ if (Alignment <> taCenter) and not (vsMultiline in PaintInfo.Node.States) and (toShowStaticText in TreeOptions.FStringOptions) then
+ begin
+ S := '';
+ with PaintInfo do
+ DoGetText(Node, Column, ttStatic, S);
+ if Length(S) > 0 then
+ PaintStaticText(PaintInfo, TextOutFlags, S);
+ end;
+ RestoreFontChangeEvent(PaintInfo.Canvas);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DoPaintText(Node: PVirtualNode; const Canvas: TCanvas; Column: TColumnIndex;
+ TextType: TVSTTextType);
+
+begin
+ if Assigned(FOnPaintText) then
+ FOnPaintText(Self, Canvas, Node, Column, TextType);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoShortenString(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ const S: WideString; Width: Integer; RightToLeft: Boolean; EllipsisWidth: Integer = 0): WideString;
+
+var
+ Done: Boolean;
+
+begin
+ Done := False;
+ if Assigned(FOnShortenString) then
+ FOnShortenString(Self, Canvas, Node, Column, S, Width, RightToLeft, Result, Done);
+ if not Done then
+ Result := ShortenString(Canvas.Handle, S, Width, RightToLeft, EllipsisWidth);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TCustomStringTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect;
+ var Text: WideString);
+
+// Returns the font, the text and its bounding rectangle to the caller. R is returned as the closest
+// bounding rectangle around Text.
+
+var
+ NewHeight: Integer;
+ TM: TTextMetric;
+
+begin
+ // Get default font and initialize the other parameters.
+ inherited GetTextInfo(Node, Column, AFont, R, Text);
+
+ Canvas.Font := AFont;
+
+ FFontChanged := False;
+ RedirectFontChangeEvent(Canvas);
+ DoPaintText(Node, Canvas, Column, ttNormal);
+ if FFontChanged then
+ begin
+ AFont.Assign(Canvas.Font);
+ GetTextMetrics(Canvas.Handle, TM);
+ NewHeight := TM.tmHeight;
+ end
+ else // Otherwise the correct font is already there and we only need to set the correct height.
+ NewHeight := FTextHeight;
+ RestoreFontChangeEvent(Canvas);
+
+ // Alignment to the actual text.
+ Text := Self.Text[Node, Column];
+ R := GetDisplayRect(Node, Column, True, not (vsMultiline in Node.States));
+ if toShowHorzGridLines in TreeOptions.PaintOptions then
+ Dec(R.Bottom);
+ InflateRect(R, 0, -(R.Bottom - R.Top - NewHeight) div 2);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
+
+begin
+ if (Node = FRoot) or (Node = nil) then
+ Result := nil
+ else
+ Result := PChar(Node) + FInternalDataOffset;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.MainColumnChanged;
+
+var
+ Run: PVirtualNode;
+
+begin
+ inherited;
+
+ // Have to reset all node widths.
+ Run := FRoot.FirstChild;
+ while Assigned(Run) do
+ begin
+ PInteger(InternalData(Run))^ := 0;
+ Run := GetNextNoInit(Run);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType,
+ ChunkSize: Integer): Boolean;
+
+// read in the caption chunk if there is one
+
+var
+ NewText: WideString;
+
+begin
+ case ChunkType of
+ CaptionChunk:
+ begin
+ NewText := '';
+ if ChunkSize > 0 then
+ begin
+ SetLength(NewText, ChunkSize div 2);
+ Stream.Read(PWideChar(NewText)^, ChunkSize);
+ end;
+ // Do a new text event regardless of the caption content to allow removing the default string.
+ DoNewText(Node, FHeader.MainColumn, NewText);
+ Result := True;
+ end;
+ else
+ Result := inherited ReadChunk(Stream, Version, Node, ChunkType, ChunkSize);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ TOldVTStringOption = (soSaveCaptions, soShowStaticText);
+
+procedure TCustomVirtualStringTree.ReadOldStringOptions(Reader: TReader);
+
+// Migration helper routine to silently convert forms containing the old tree options member into the new
+// sub-options structure.
+
+var
+ OldOption: TOldVTStringOption;
+ EnumName: string;
+
+begin
+ // If we are at design time currently then let the designer know we changed something.
+ UpdateDesigner;
+
+ // It should never happen at this place that there is something different than the old set.
+ if Reader.ReadValue = vaSet then
+ with TreeOptions do
+ begin
+ // Remove all default values set by the constructor.
+ StringOptions := [];
+
+ while True do
+ begin
+ // Sets are stored with their members as simple strings. Read them one by one and map them to the new option
+ // in the correct sub-option set.
+ EnumName := Reader.ReadStr;
+ if EnumName = '' then
+ Break;
+ OldOption := TOldVTStringOption(GetEnumValue(TypeInfo(TOldVTStringOption), EnumName));
+ case OldOption of
+ soSaveCaptions:
+ StringOptions := FStringOptions + [toSaveCaptions];
+ soShowStaticText:
+ StringOptions := FStringOptions + [toShowStaticText];
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean): HResult;
+
+// Returns string expressions of all currently selected nodes in the Medium structure.
+
+begin
+ Result := inherited RenderOLEData(FormatEtcIn, Medium, ForClipboard);
+ if Failed(Result) then
+ try
+ if ForClipboard then
+ Medium.hGlobal := ContentToClipboard(FormatEtcIn.cfFormat, tstCutCopySet)
+ else
+ Medium.hGlobal := ContentToClipboard(FormatEtcIn.cfFormat, tstSelected);
+
+ // Fill rest of the Medium structure if rendering went fine.
+ if Medium.hGlobal <> 0 then
+ begin
+ Medium.tymed := TYMED_HGLOBAL;
+ Medium.unkForRelease := nil;
+
+ Result := S_OK;
+ end;
+ except
+ Result := E_FAIL;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.WriteChunks(Stream: TStream; Node: PVirtualNode);
+
+// Adds another sibling chunk for Node storing the label if the node is initialized.
+// Note: If the application stores a node's caption in the node's data member (which will be quite common) and needs to
+// store more node specific data then it should use the OnSaveNode event rather than the caption autosave function
+// (take out soSaveCaption from StringOptions). Otherwise the caption is unnecessarily stored twice.
+
+var
+ Header: TChunkHeader;
+ S: WideString;
+ Len: Integer;
+
+begin
+ inherited;
+ if (toSaveCaptions in TreeOptions.FStringOptions) and (Node <> FRoot) and
+ (vsInitialized in Node.States) then
+ with Stream do
+ begin
+ // Read the node's caption (primary column only).
+ S := Text[Node, FHeader.MainColumn];
+ Len := 2 * Length(S);
+ if Len > 0 then
+ begin
+ // Write a new sub chunk.
+ Header.ChunkType := CaptionChunk;
+ Header.ChunkSize := Len;
+ Write(Header, SizeOf(Header));
+ Write(PWideChar(S)^, Len);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToClipboard(Format: Word; Source: TVSTTextSourceType): HGLOBAL;
+
+// This method constructs a shareable memory object filled with string data in the required format. Supported are:
+// CF_TEXT - plain ANSI text (Unicode text is converted using the user's current locale)
+// CF_UNICODETEXT - plain Unicode text
+// CF_CSV - comma separated plain ANSI text
+// CF_VRTF + CF_RTFNOOBS - rich text (plain ANSI)
+// CF_HTML - HTML text encoded using UTF-8
+//
+// Result is the handle to a globally allocated memory block which can directly be used for clipboard and drag'n drop
+// transfers. The caller is responsible for freeing the memory. If for some reason the content could not be rendered
+// the Result is 0.
+
+ //--------------- local function --------------------------------------------
+
+ procedure MakeFragment(var HTML: string);
+
+ // Helper routine to build a properly-formatted HTML fragment.
+
+ const
+ Version = 'Version:1.0'#13#10;
+ StartHTML = 'StartHTML:';
+ EndHTML = 'EndHTML:';
+ StartFragment = 'StartFragment:';
+ EndFragment = 'EndFragment:';
+ DocType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">';
+ HTMLIntro = '<html><head><META http-equiv=Content-Type content="text/html; charset=utf-8">' +
+ '</head><body><!--StartFragment-->';
+ HTMLExtro = '<!--EndFragment--></body></html>';
+ NumberLengthAndCR = 10;
+
+ // Let the compiler determine the description length.
+ DescriptionLength = Length(Version) + Length(StartHTML) + Length(EndHTML) + Length(StartFragment) +
+ Length(EndFragment) + 4 * NumberLengthAndCR;
+
+ var
+ Description: string;
+ StartHTMLIndex,
+ EndHTMLIndex,
+ StartFragmentIndex,
+ EndFragmentIndex: Integer;
+
+ begin
+ // The HTML clipboard format is defined by using byte positions in the entire block where HTML text and
+ // fragments start and end. These positions are written in a description. Unfortunately the positions depend on the
+ // length of the description but the description may change with varying positions.
+ // To solve this dilemma the offsets are converted into fixed length strings which makes it possible to know
+ // the description length in advance.
+ StartHTMLIndex := DescriptionLength; // position 0 after the description
+ StartFragmentIndex := StartHTMLIndex + Length(DocType) + Length(HTMLIntro);
+ EndFragmentIndex := StartFragmentIndex + Length(HTML);
+ EndHTMLIndex := EndFragmentIndex + Length(HTMLExtro);
+
+ Description := Version +
+ SysUtils.Format('%s%.8d', [StartHTML, StartHTMLIndex]) + #13#10 +
+ SysUtils.Format('%s%.8d', [EndHTML, EndHTMLIndex]) + #13#10 +
+ SysUtils.Format('%s%.8d', [StartFragment, StartFragmentIndex]) + #13#10 +
+ SysUtils.Format('%s%.8d', [EndFragment, EndFragmentIndex]) + #13#10;
+ HTML := Description + DocType + HTMLIntro + HTML + HTMLExtro;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ Data: Pointer;
+ DataSize: Cardinal;
+ S: string;
+ WS: WideString;
+ P: Pointer;
+
+begin
+ Result := 0;
+ case Format of
+ CF_TEXT:
+ begin
+ S := ContentToText(Source, #9) + #0;
+ Data := PChar(S);
+ DataSize := Length(S);
+ end;
+ CF_UNICODETEXT:
+ begin
+ WS := ContentToUnicode(Source, #9) + #0;
+ Data := PWideChar(WS);
+ DataSize := 2 * Length(WS);
+ end;
+ else
+ if Format = CF_CSV then
+ S := ContentToText(Source, ListSeparator) + #0
+ else
+ if (Format = CF_VRTF) or (Format = CF_VRTFNOOBJS) then
+ S := ContentToRTF(Source) + #0
+ else
+ if Format = CF_HTML then
+ begin
+ S := ContentToHTML(Source);
+ // Build a valid HTML clipboard fragment.
+ MakeFragment(S);
+ S := S + #0;
+ end;
+ Data := PChar(S);
+ DataSize := Length(S);
+ end;
+
+ if DataSize > 0 then
+ begin
+ Result := GlobalAlloc(GHND or GMEM_SHARE, DataSize);
+ P := GlobalLock(Result);
+ Move(Data^, P^, DataSize);
+ GlobalUnlock(Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToHTML(Source: TVSTTextSourceType; Caption: WideString = ''): string;
+
+// Renders the current tree content (depending on Source) as HTML text encoded in UTF-8.
+// If Caption is not empty then it is used to create and fill the header for the table built here.
+// Based on ideas and code from Frank van den Bergh and Andreas Hörstemeier.
+
+type
+ UCS2 = Word;
+ UCS4 = Cardinal;
+
+const
+ MaximumUCS4: UCS4 = $7FFFFFFF;
+ ReplacementCharacter: UCS4 = $0000FFFD;
+
+var
+ Buffer: TBufferedString;
+
+ //--------------- local functions -------------------------------------------
+
+ function ConvertSurrogate(S1, S2: UCS2): UCS4;
+
+ // Converts a pair of high and low surrogate into the corresponding UCS4 character.
+
+ const
+ SurrogateOffset = ($D800 shl 10) + $DC00 - $10000;
+
+ begin
+ Result := Word(S1) shl 10 + Word(S2) - SurrogateOffset;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function UTF16ToUTF8(const S: WideString): string;
+
+ // Converts the given Unicode text (which may contain surrogates) into
+ // the UTF-8 encoding used for the HTML clipboard format.
+
+ const
+ FirstByteMark: array[0..6] of Byte = ($00, $00, $C0, $E0, $F0, $F8, $FC);
+
+ var
+ Ch: UCS4;
+ I, J, T: Integer;
+ BytesToWrite: Cardinal;
+
+ begin
+ if Length(S) = 0 then
+ Result := ''
+ else
+ begin
+ // Make room for the result. Assume worst case, there are only short texts to convert.
+ SetLength(Result, 6 * Length(S));
+ T := 1;
+ I := 1;
+ while I <= Length(S) do
+ begin
+ Ch := UCS4(S[I]);
+
+ // Is the character a surrogate?
+ if (Ch and $FFFFF800) = $D800 then
+ begin
+ Inc(I);
+ // Check the following char whether it forms a valid surrogate pair with the first character.
+ if (I <= Length(S)) and ((UCS4(S[I]) and $FFFFFC00) = $DC00) then
+ Ch := ConvertSurrogate(UCS2(Ch), UCS2(S[I]))
+ else // Skip invalid surrogate value.
+ Continue;
+ end;
+
+ if Ch < $80 then
+ BytesToWrite := 1
+ else
+ if Ch < $800 then
+ BytesToWrite := 2
+ else
+ if Ch < $10000 then
+ BytesToWrite := 3
+ else
+ if Ch < $200000 then
+ BytesToWrite := 4
+ else
+ if Ch < $4000000 then
+ BytesToWrite := 5
+ else
+ if Ch <= MaximumUCS4 then
+ BytesToWrite := 6
+ else
+ begin
+ BytesToWrite := 2;
+ Ch := ReplacementCharacter;
+ end;
+
+ for J := BytesToWrite downto 2 do
+ begin
+ Result[T + J - 1] := Char((Ch or $80) and $BF);
+ Ch := Ch shr 6;
+ end;
+ Result[T] := Char(Ch or FirstByteMark[BytesToWrite]);
+ Inc(T, BytesToWrite);
+
+ Inc(I);
+ end;
+ SetLength(Result, T - 1); // set to actual length
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure WriteColorAsHex(Color: TColor);
+
+ var
+ WinColor: COLORREF;
+ I: Integer;
+ Component,
+ Value: Byte;
+
+ begin
+ Buffer.Add('#');
+ WinColor := ColorToRGB(Color);
+ I := 1;
+ while I <= 6 do
+ begin
+ Component := WinColor and $FF;
+
+ Value := 48 + (Component shr 4);
+ if Value > $39 then
+ Inc(Value, 7);
+ Buffer.Add(Char(Value));
+ Inc(I);
+
+ Value := 48 + (Component and $F);
+ if Value > $39 then
+ Inc(Value, 7);
+ Buffer.Add(Char(Value));
+ Inc(I);
+
+ WinColor := WinColor shr 8;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure WriteStyle(Name: string; Font: TFont);
+
+ // Creates a CSS style entry with the given name for the given font.
+ // If Name is empty then the entry is created as inline style.
+
+ begin
+ if Length(Name) = 0 then
+ Buffer.Add(' style="{font:')
+ else
+ begin
+ Buffer.Add('.');
+ Buffer.Add(Name);
+ Buffer.Add('{font:');
+ end;
+ if fsUnderline in Font.Style then
+ Buffer.Add(' underline');
+ if fsItalic in Font.Style then
+ Buffer.Add(' italic');
+ if fsBold in Font.Style then
+ Buffer.Add(' bold');
+ Buffer.Add(Format(' %dpt "%s";', [Font.Size, Font.Name]));
+ Buffer.Add('color:');
+ WriteColorAsHex(Font.Color);
+ Buffer.Add(';}');
+ if Length(Name) = 0 then
+ Buffer.Add('"');
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ I, J : Integer;
+ Level, MaxLevel: Cardinal;
+ AddHeader: string;
+ Save, Run: PVirtualNode;
+ GetNextNode: TGetNextNodeProc;
+ Text: WideString;
+
+ RenderColumns: Boolean;
+ Columns: TColumnsArray;
+ ColumnColors: array of string;
+ Index: Integer;
+ IndentWidth,
+ LineStyleText: string;
+ Alignment: TAlignment;
+ BidiMode: TBidiMode;
+
+ CellPadding: string;
+
+begin
+ Buffer := TBufferedString.Create;
+ try
+ // For customization by the application or descentants we use again the redirected font change event.
+ RedirectFontChangeEvent(Canvas);
+
+ CellPadding := Format('padding-left:%dpx;padding-right:%0:dpx;', [FMargin]);
+
+ IndentWidth := IntToStr(FIndent);
+ AddHeader := ' ';
+ // Add title if adviced so by giving a caption.
+ if Length(Caption) > 0 then
+ AddHeader := AddHeader + 'caption="' + UTF16ToUTF8(Caption) + '"';
+ if Borderstyle <> bsNone then
+ AddHeader := AddHeader + Format('border="%d" frame=box', [BorderWidth + 1]);
+
+ // Create HTML table based on the tree structure. To simplify formatting we use styles defined in a small CSS area.
+ Buffer.Add('<style type="text/css">');
+ Buffer.AddnewLine;
+ WriteStyle('default', Font);
+ Buffer.AddNewLine;
+ WriteStyle('header', FHeader.Font);
+ Buffer.AddNewLine;
+
+ // Determine grid/table lines and create CSS for it.
+ // Vertical and/or horizontal border to show.
+ if FLineStyle = lsSolid then
+ LineStyleText := 'solid;'
+ else
+ LineStyleText := 'dotted;';
+ if toShowHorzGridLines in FOptions.FPaintOptions then
+ begin
+ Buffer.Add('.noborder{border-style:');
+ Buffer.Add(LineStyleText);
+ Buffer.Add(' border-bottom:1;border-left:0;border-right:0; border-top:0;');
+ Buffer.Add(CellPadding);
+ Buffer.Add('}');
+ end
+ else
+ begin
+ Buffer.Add('.noborder{border-style:none;');
+ Buffer.Add(CellPadding);
+ Buffer.Add('}');
+ end;
+ Buffer.AddNewLine;
+
+ Buffer.Add('.normalborder {border-top:none; border-left:none; ');
+ if toShowVertGridLines in FOptions.FPaintOptions then
+ Buffer.Add('border-right:1 ' + LineStyleText)
+ else
+ Buffer.Add('border-right:none;');
+ if toShowHorzGridLines in FOptions.FPaintOptions then
+ Buffer.Add('border-bottom:1 ' + LineStyleText)
+ else
+ Buffer.Add('border-bottom:none;');
+ Buffer.Add(CellPadding);
+ Buffer.Add('}');
+ Buffer.Add('</style>');
+ Buffer.AddNewLine;
+
+ // General table properties.
+ Buffer.Add('<table class="default" bgcolor=');
+ WriteColorAsHex(Color);
+ Buffer.Add(AddHeader);
+ Buffer.Add(' cellspacing="0" cellpadding=');
+ Buffer.Add(IntToStr(FMargin) + '>');
+ Buffer.AddNewLine;
+
+ Columns := nil;
+ ColumnColors := nil;
+ RenderColumns := FHeader.UseColumns;
+ if RenderColumns then
+ begin
+ Columns := FHeader.FColumns.GetVisibleColumns;
+ SetLength(ColumnColors, Length(Columns));
+ end;
+
+ GetRenderStartValues(Source, Run, GetNextNode);
+ Save := Run;
+
+ MaxLevel := 0;
+ // The table consists of visible columns and rows as used in the tree, but the main tree column is splitted
+ // into several HTML columns to accomodate the indentation.
+ while Assigned(Run) do
+ begin
+ Level := GetNodeLevel(Run);
+ If Level > MaxLevel then
+ MaxLevel := Level;
+ Run := GetNextNode(Run);
+ end;
+
+ if RenderColumns then
+ begin
+ Buffer.Add('<tr class="header" style="');
+ Buffer.Add(CellPadding);
+ Buffer.Add('">');
+ Buffer.AddNewLine;
+ // Make the first row in the HTML table an image of the tree header.
+ for I := 0 to High(Columns) do
+ begin
+ Buffer.Add('<th height="');
+ Buffer.Add(IntToStr(FHeader.FHeight));
+ Buffer.Add('px"');
+ Alignment := Columns[I].Alignment;
+ // Consider directionality.
+ if Columns[I].FBiDiMode <> bdLeftToRight then
+ begin
+ ChangeBidiModeAlignment(Alignment);
+ Buffer.Add(' dir="rtl"');
+ end;
+
+ // Consider aligment.
+ case Alignment of
+ taRightJustify:
+ Buffer.Add(' align=right');
+ taCenter:
+ Buffer.Add(' align=center');
+ else
+ Buffer.Add(' align=left');
+ end;
+
+ Index := Columns[I].Index;
+ // Merge cells of the header emulation in the main column.
+ if (MaxLevel > 0) and (Index = Header.MainColumn) then
+ begin
+ Buffer.Add(' colspan="');
+ Buffer.Add(IntToStr(MaxLevel + 1));
+ Buffer.Add('"');
+ end;
+
+ // The color of the header is usually clBtnFace.
+ Buffer.Add(' bgcolor=');
+ WriteColorAsHex(clBtnFace);
+
+ // Set column width in pixels.
+ Buffer.Add(' width="');
+ Buffer.Add(IntToStr(Columns[I].Width));
+ Buffer.Add('px">');
+
+ if Length(Columns[I].Text) > 0 then
+ Buffer.Add(UTF16ToUTF8(Columns[I].Text));
+ Buffer.Add('</th>');
+ end;
+ Buffer.Add('</tr>');
+ Buffer.AddNewLine;
+ end;
+
+ // Now go through the tree.
+ Run := Save;
+ while Assigned(Run) do
+ begin
+ Level := GetNodeLevel(Run);
+ Buffer.Add(' <tr class="default">');
+ Buffer.AddNewLine;
+
+ I := 0;
+ while (I < Length(Columns)) or not RenderColumns do
+ begin
+ if RenderColumns then
+ Index := Columns[I].Index
+ else
+ Index := NoColumn;
+
+ if not RenderColumns or (coVisible in Columns[I].FOptions) then
+ begin
+ // Call back the application to know about font customization.
+ Canvas.Font := Font;
+ FFontChanged := False;
+ DoPaintText(Run, Canvas, Index, ttNormal);
+
+ if Index = Header.MainColumn then
+ begin
+ // Create a cell for each indentation level.
+ if RenderColumns and not (coParentColor in Columns[I].FOptions) then
+ begin
+ for J := 1 to Level do
+ begin
+ Buffer.Add('<td class="noborder" width="');
+ Buffer.Add(IndentWidth);
+ Buffer.Add('" height="');
+ Buffer.Add(IntToStr(Run.NodeHeight));
+ Buffer.Add('px"');
+ if not (coParentColor in Columns[I].FOptions) then
+ begin
+ Buffer.Add(' bgcolor=');
+ WriteColorAsHex(Columns[I].Color);
+ end;
+ Buffer.Add('> </td>');
+ end;
+ end
+ else
+ begin
+ for J := 1 to Level do
+ if J = 1 then
+ begin
+ Buffer.Add(' <td height="');
+ Buffer.Add(IntToStr(Run.NodeHeight));
+ Buffer.Add('px"> </td>');
+ end
+ else
+ Buffer.Add(' <td> </td>');
+ end;
+ end;
+
+ if FFontChanged then
+ begin
+ Buffer.Add(' <td class="normalborder" ');
+ WriteStyle('', Canvas.Font);
+ Buffer.Add(' height="');
+ Buffer.Add(IntToStr(Run.NodeHeight));
+ Buffer.Add('px"');
+ end
+ else
+ begin
+ Buffer.Add(' <td class="normalborder" height="');
+ Buffer.Add(IntToStr(Run.NodeHeight));
+ Buffer.Add('px"');
+ end;
+
+ if RenderColumns then
+ begin
+ Alignment := Columns[I].Alignment;
+ BidiMode := Columns[I].BidiMode;
+ end
+ else
+ begin
+ Alignment := Self.Alignment;
+ BidiMode := Self.BidiMode;
+ end;
+ // Consider directionality.
+ if BiDiMode <> bdLeftToRight then
+ begin
+ ChangeBidiModeAlignment(Alignment);
+ Buffer.Add(' dir="rtl"');
+ end;
+
+ // Consider aligment.
+ case Alignment of
+ taRightJustify:
+ Buffer.Add(' align=right');
+ taCenter:
+ Buffer.Add(' align=center');
+ else
+ Buffer.Add(' align=left');
+ end;
+ // Merge cells in the main column.
+ if (MaxLevel > 0) and (Index = FHeader.MainColumn) and (Level < MaxLevel) then
+ begin
+ Buffer.Add(' colspan="');
+ Buffer.Add(IntToStr(MaxLevel - Level + 1));
+ Buffer.Add('"');
+ end;
+ if RenderColumns and not (coParentColor in Columns[I].FOptions) then
+ begin
+ Buffer.Add(' bgcolor=');
+ WriteColorAsHex(Columns[I].Color);
+ end;
+ Buffer.Add('>');
+ Text := Self.Text[Run, Index];
+ if Length(Text) > 0 then
+ begin
+ Text := UTF16ToUTF8(Text);
+ Buffer.Add(Text);
+ end;
+ Buffer.Add('</td>');
+ end;
+
+ if not RenderColumns then
+ Break;
+ Inc(I);
+ end;
+ Run := GetNextNode(Run);
+ Buffer.Add(' </tr>');
+ Buffer.AddNewLine;
+ end;
+ Buffer.Add('</table>');
+
+ RestoreFontChangeEvent(Canvas);
+
+ Result := Buffer.AsString;
+ finally
+ Buffer.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToRTF(Source: TVSTTextSourceType): string;
+
+// Renders the current tree content (depending on Source) as RTF (rich text).
+// Based on ideas and code from Frank van den Bergh and Andreas Hörstemeier.
+
+var
+ Fonts: TStringList;
+ Colors: TList;
+ CurrentFontIndex,
+ CurrentFontColor,
+ CurrentFontSize: Integer;
+ Buffer: TBufferedString;
+
+ //--------------- local functions -------------------------------------------
+
+ procedure SelectFont(Font: string);
+
+ var
+ I: Integer;
+
+ begin
+ I := Fonts.IndexOf(Font);
+ if I > -1 then
+ begin
+ // Font has already been used
+ if I <> CurrentFontIndex then
+ begin
+ Buffer.Add('\f');
+ Buffer.Add(IntToStr(I));
+ CurrentFontIndex := I;
+ end;
+ end
+ else
+ begin
+ I := Fonts.Add(Font);
+ Buffer.Add('\f');
+ Buffer.Add(IntToStr(I));
+ CurrentFontIndex := I;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure SelectColor(Color: TColor);
+
+ var
+ I: Integer;
+
+ begin
+ I := Colors.IndexOf(Pointer(Color));
+ if I > -1 then
+ begin
+ // Color has already been used
+ if I <> CurrentFontColor then
+ begin
+ Buffer.Add('\cf');
+ Buffer.Add(IntToStr(I + 1));
+ CurrentFontColor := I;
+ end;
+ end
+ else
+ begin
+ I := Colors.Add(Pointer(Color));
+ Buffer.Add('\cf');
+ Buffer.Add(IntToStr(I + 1));
+ CurrentFontColor := I;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure TextPlusFont(Text: WideString; Font: TFont);
+
+ var
+ UseUnderline,
+ UseItalic,
+ UseBold: Boolean;
+ I: Integer;
+
+ begin
+ if Length(Text) > 0 then
+ begin
+ UseUnderline := fsUnderline in Font.Style;
+ if UseUnderline then
+ Buffer.Add('\ul');
+ UseItalic := fsItalic in Font.Style;
+ if UseItalic then
+ Buffer.Add('\i');
+ UseBold := fsBold in Font.Style;
+ if UseBold then
+ Buffer.Add('\b');
+ SelectFont(Font.Name);
+ SelectColor(Font.Color);
+ if Font.Size <> CurrentFontSize then
+ begin
+ // Font size must be given in half points.
+ Buffer.Add('\fs');
+ Buffer.Add(IntToStr(2 * Font.Size));
+ CurrentFontSize := Font.Size;
+ end;
+ // Use escape sequences to note Unicode text.
+ Buffer.Add(' ');
+ // Note: Unicode values > 32767 must be expressed as negative numbers. This is implicitly done
+ // by interpreting the wide chars (word values) as small integers.
+ for I := 1 to Length(Text) do
+ Buffer.Add(Format('\u%d\''3f', [SmallInt(Text[I])]));
+ if UseUnderline then
+ Buffer.Add('\ul0');
+ if UseItalic then
+ Buffer.Add('\i0');
+ if UseBold then
+ Buffer.Add('\b0');
+ end;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ Level, LastLevel: Integer;
+ I, J: Integer;
+ Save, Run: PVirtualNode;
+ GetNextNode: TGetNextNodeProc;
+ S, Tabs : string;
+ Text: WideString;
+ Twips: Integer;
+
+ RenderColumns: Boolean;
+ Columns: TColumnsArray;
+ Index: Integer;
+ Alignment: TAlignment;
+ BidiMode: TBidiMode;
+
+begin
+ Buffer := TBufferedString.Create;
+ try
+ // For customization by the application or descentants we use again the redirected font change event.
+ RedirectFontChangeEvent(Canvas);
+
+ Fonts := TStringList.Create;
+ Colors := TList.Create;
+ CurrentFontIndex := -1;
+ CurrentFontColor := -1;
+ CurrentFontSize := -1;
+
+ Columns := nil;
+ Tabs := '';
+ LastLevel := 0;
+
+ RenderColumns := FHeader.UseColumns;
+ if RenderColumns then
+ Columns := FHeader.FColumns.GetVisibleColumns;
+
+ GetRenderStartValues(Source, Run, GetNextNode);
+ Save := Run;
+
+ // First make a table structure. The \rtf and other header stuff is included
+ // when the font and color tables are created.
+ Buffer.Add('\uc1\trowd\trgaph70');
+ J := 0;
+ if RenderColumns then
+ begin
+ for I := 0 to High(Columns) do
+ begin
+ Inc(J, Columns[I].Width);
+ // This value must be expressed in twips (1 inch = 1440 twips).
+ Twips := Round(1440 * J / Screen.PixelsPerInch);
+ Buffer.Add('\cellx');
+ Buffer.Add(IntToStr(Twips));
+ end;
+ end
+ else
+ begin
+ Twips := Round(1440 * ClientWidth / Screen.PixelsPerInch);
+ Buffer.Add('\cellx');
+ Buffer.Add(IntToStr(Twips));
+ end;
+
+ // Fill table header.
+ if RenderColumns then
+ begin
+ Buffer.Add('\pard\intbl');
+ for I := 0 to High(Columns) do
+ begin
+ Alignment := Columns[I].Alignment;
+ BidiMode := Columns[I].BidiMode;
+
+ // Alignment is not supported with older RTF formats, however it will be ignored.
+ if BidiMode <> bdLeftToRight then
+ ChangeBidiModeAlignment(Alignment);
+ case Alignment of
+ taRightJustify:
+ Buffer.Add('\qr');
+ taCenter:
+ Buffer.Add('\qc');
+ end;
+
+ TextPlusFont(Columns[I].Text, Header.Font);
+ Buffer.Add('\cell');
+ end;
+ Buffer.Add('\row');
+ end;
+
+ // Now write the contents.
+ Run := Save;
+ while Assigned(Run) do
+ begin
+ I := 0;
+ while not RenderColumns or (I < Length(Columns)) do
+ begin
+ if RenderColumns then
+ begin
+ Index := Columns[I].Index;
+ Alignment := Columns[I].Alignment;
+ BidiMode := Columns[I].BidiMode;
+ end
+ else
+ begin
+ Index := NoColumn;
+ Alignment := FAlignment;
+ BidiMode := Self.BidiMode;
+ end;
+
+ if not RenderColumns or (coVisible in Columns[I].Options) then
+ begin
+ Text := Self.Text[Run, Index];
+ Buffer.Add('\pard\intbl');
+
+ // Alignment is not supported with older RTF formats, however it will be ignored.
+ if BidiMode <> bdLeftToRight then
+ ChangeBidiModeAlignment(Alignment);
+ case Alignment of
+ taRightJustify:
+ Buffer.Add('\qr');
+ taCenter:
+ Buffer.Add('\qc');
+ end;
+
+ // Call back the application to know about font customization.
+ Canvas.Font := Font;
+ FFontChanged := False;
+ DoPaintText(Run, Canvas, Index, ttNormal);
+
+ if Index = Header.MainColumn then
+ begin
+ Level := GetNodeLevel(Run);
+ if Level <> LastLevel then
+ begin
+ LastLevel := Level;
+ Tabs := '';
+ for J := 0 to Level - 1 do
+ Tabs := Tabs + '\tab';
+ end;
+ if Level > 0 then
+ begin
+ Buffer.Add(Tabs);
+ Buffer.Add(' ');
+ TextPlusFont(Text, Canvas.Font);
+ Buffer.Add('\cell');
+ end
+ else
+ begin
+ TextPlusFont(Text, Canvas.Font);
+ Buffer.Add('\cell');
+ end;
+ end
+ else
+ begin
+ TextPlusFont(Text, Canvas.Font);
+ Buffer.Add('\cell');
+ end;
+ end;
+
+ if not RenderColumns then
+ Break;
+ Inc(I);
+ end;
+ Buffer.Add('\row');
+ Run := GetNextNode(Run);
+ end;
+
+ Buffer.Add('\pard\par');
+
+ // Build lists with fonts and colors. They have to be at the start of the document.
+ S := '{\rtf1\ansi\ansicpg1252\deff0\deflang1043{\fonttbl';
+ for I := 0 to Fonts.Count - 1 do
+ S := S + Format('{\f%d %s;}', [I, Fonts[I]]);
+ S := S + '}';
+
+ S := S + '{\colortbl;';
+ for I := 0 to Colors.Count - 1 do
+ begin
+ J := ColorToRGB(TColor(Colors[I]));
+ S := S + Format('\red%d\green%d\blue%d;', [J and $FF, (J shr 8) and $FF, (J shr 16) and $FF]);
+ end;
+ S := S + '}';
+
+ Result := S + Buffer.AsString + '}';
+ Fonts.Free;
+ Colors.Free;
+
+ RestoreFontChangeEvent(Canvas);
+ finally
+ Buffer.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToText(Source: TVSTTextSourceType; Separator: Char): string;
+
+// Renders the current tree content (depending on Source) as plain ANSI text.
+// Note: Unicode strings are implicitely converted to ANSI strings based on the currently active user locale.
+
+var
+ RenderColumns: Boolean;
+ Tabs: string;
+ GetNextNode: TGetNextNodeProc;
+ Run, Save: PVirtualNode;
+ Level, MaxLevel: Cardinal;
+ Columns: TColumnsArray;
+ LastColumn: TVirtualTreeColumn;
+ Index,
+ I: Integer;
+ Text: string;
+ Buffer: TBufferedString;
+
+begin
+ Columns := nil;
+ Buffer := TBufferedString.Create;
+ try
+ RenderColumns := FHeader.UseColumns;
+ if RenderColumns then
+ Columns := FHeader.FColumns.GetVisibleColumns;
+
+ GetRenderStartValues(Source, Run, GetNextNode);
+ Save := Run;
+
+ // The text consists of visible groups representing the columns, which are separated by one or more separator
+ // characters. There are always MaxLevel separator chars in a line (main column only). Either before the caption
+ // to ident it or after the caption to make the following column aligned.
+ MaxLevel := 0;
+ while Assigned(Run) do
+ begin
+ Level := GetNodeLevel(Run);
+ If Level > MaxLevel then
+ MaxLevel := Level;
+ Run := GetNextNode(Run);
+ end;
+
+ SetLength(Tabs, MaxLevel);
+ FillChar(PChar(Tabs)^, MaxLevel, Separator);
+
+ // First line is always the header if used.
+ if RenderColumns then
+ begin
+ LastColumn := Columns[High(Columns)];
+ for I := 0 to High(Columns) do
+ begin
+ Buffer.Add(Columns[I].Text);
+ if Columns[I] <> LastColumn then
+ begin
+ if Columns[I].Index = Header.MainColumn then
+ begin
+ Buffer.Add(Tabs);
+ Buffer.Add(Separator);
+ end
+ else
+ Buffer.Add(Separator);
+ end;
+ end;
+ Buffer.AddNewLine;
+ end
+ else
+ LastColumn := nil;
+
+ Run := Save;
+ if RenderColumns then
+ begin
+ while Assigned(Run) do
+ begin
+ for I := 0 to High(Columns) do
+ begin
+ if coVisible in Columns[I].Options then
+ begin
+ Index := Columns[I].Index;
+ // This line implicitly converts the Unicode text to ANSI.
+ Text := Self.Text[Run, Index];
+ if Index = Header.MainColumn then
+ begin
+ Level := GetNodeLevel(Run);
+ Buffer.Add(Copy(Tabs, 1, Level));
+ Buffer.Add(Text);
+ Buffer.Add(Copy(Tabs, 1, MaxLevel - Level));
+ end
+ else
+ Buffer.Add(Text);
+
+ if Columns[I] <> LastColumn then
+ Buffer.Add(Separator);
+ end;
+ end;
+ Run := GetNextNode(Run);
+ Buffer.AddNewLine;
+ end;
+ end
+ else
+ begin
+ while Assigned(Run) do
+ begin
+ // This line implicitly converts the Unicode text to ANSI.
+ Text := Self.Text[Run, NoColumn];
+ Level := GetNodeLevel(Run);
+ Buffer.Add(Copy(Tabs, 1, Level));
+ Buffer.Add(Text);
+ Buffer.AddNewLine;
+
+ Run := GetNextNode(Run);
+ end;
+ end;
+
+ Result := Buffer.AsString;
+ finally
+ Buffer.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToUnicode(Source: TVSTTextSourceType; Separator: WideChar): WideString;
+
+// Renders the current tree content (depending on Source) as Unicode text.
+
+const
+ WideCRLF: WideString = #13#10;
+
+var
+ RenderColumns: Boolean;
+ Tabs: WideString;
+ GetNextNode: TGetNextNodeProc;
+ Run, Save: PVirtualNode;
+
+ Columns: TColumnsArray;
+ LastColumn: TVirtualTreeColumn;
+ Level, MaxLevel: Cardinal;
+ Index,
+ I: Integer;
+ Text: WideString;
+ Buffer: TWideBufferedString;
+
+begin
+ Columns := nil;
+
+ Buffer := TWideBufferedString.Create;
+ try
+ RenderColumns := FHeader.UseColumns;
+ if RenderColumns then
+ Columns := FHeader.FColumns.GetVisibleColumns;
+
+ GetRenderStartValues(Source, Run, GetNextNode);
+ Save := Run;
+
+ // The text consists of visible groups representing the columns, which are separated by one or more separator
+ // characters. There are always MaxLevel separator chars in a line (main column only). Either before the caption
+ // to ident it or after the caption to make the following column aligned.
+ MaxLevel := 0;
+ while Assigned(Run) do
+ begin
+ Level := GetNodeLevel(Run);
+ If Level > MaxLevel then
+ MaxLevel := Level;
+ Run := GetNextNode(Run);
+ end;
+
+ SetLength(Tabs, MaxLevel);
+ for I := 1 to MaxLevel do
+ Tabs[I] := Separator;
+
+ // First line is always the header if used.
+ if RenderColumns then
+ begin
+ LastColumn := Columns[High(Columns)];
+ for I := 0 to High(Columns) do
+ begin
+ Buffer.Add(Columns[I].Text);
+ if Columns[I] <> LastColumn then
+ begin
+ if Columns[I].Index = Header.MainColumn then
+ begin
+ Buffer.Add(Tabs);
+ Buffer.Add(Separator);
+ end
+ else
+ Buffer.Add(Separator);
+ end;
+ end;
+ Buffer.AddNewLine;
+ end
+ else
+ LastColumn := nil;
+
+ Run := Save;
+ if RenderColumns then
+ begin
+ while Assigned(Run) do
+ begin
+ for I := 0 to High(Columns) do
+ begin
+ if coVisible in Columns[I].Options then
+ begin
+ Index := Columns[I].Index;
+ Text := Self.Text[Run, Index];
+ if Index = Header.MainColumn then
+ begin
+ Level := GetNodeLevel(Run);
+ Buffer.Add(Copy(Tabs, 1, Level));
+ Buffer.Add(Text);
+ Buffer.Add(Copy(Tabs, 1, MaxLevel - Level));
+ end
+ else
+ Buffer.Add(Text);
+
+ if Columns[I] <> LastColumn then
+ Buffer.Add(Separator);
+ end;
+ end;
+ Run := GetNextNode(Run);
+ Buffer.AddNewLine;
+ end;
+ end
+ else
+ begin
+ while Assigned(Run) do
+ begin
+ Text := Self.Text[Run, NoColumn];
+ Level := GetNodeLevel(Run);
+ Buffer.Add(Copy(Tabs, 1, Level));
+ Buffer.Add(Text);
+ Buffer.AddNewLine;
+
+ Run := GetNextNode(Run);
+ end;
+ end;
+ Result := Buffer.AsString;
+ finally
+ Buffer.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.InvalidateNode(Node: PVirtualNode): TRect;
+
+var
+ Data: PInteger;
+
+begin
+ Result := inherited InvalidateNode(Node);
+ // Reset node width so changed text attributes are applied correctly.
+ Data := InternalData(Node);
+ if Assigned(Data) then
+ Data^ := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.Path(Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ Delimiter: WideChar): WideString;
+
+// Constructs a string containing the node and all its parents. The last character in the returned path is always the
+// given delimiter.
+
+var
+ S: WideString;
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := Delimiter
+ else
+ begin
+ Result := '';
+ while Node <> FRoot do
+ begin
+ DoGetText(Node, Column, TextType, S);
+ Result := S + Delimiter + Result;
+ Node := Node.Parent;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.ReinitNode(Node: PVirtualNode; Recursive: Boolean);
+
+begin
+ inherited;
+ // Reset node width so changed text attributes are applied correctly.
+ if Assigned(Node) and (Node <> FRoot) then
+ PInteger(InternalData(Node))^ := 0;
+end;
+
+//----------------- TVirtualStringTree ---------------------------------------------------------------------------------
+
+function TVirtualStringTree.GetOptions: TStringTreeOptions;
+
+begin
+ Result := FOptions as TStringTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualStringTree.SetOptions(const Value: TStringTreeOptions);
+
+begin
+ FOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualStringTree.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TStringTreeOptions;
+end;
+
+//----------------- TCustomVirtualDrawTree -----------------------------------------------------------------------------
+
+procedure TCustomVirtualDrawTree.DoDrawHint(Canvas: TCanvas; Node: PVirtualNode; R: TRect; Column: TColumnIndex);
+
+begin
+ if Assigned(FOnDrawHint) then
+ FOnDrawHint(Self, Canvas, Node, R, Column);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualDrawTree.DoGetHintSize(Node: PVirtualNode; Column: TColumnIndex; var R: TRect);
+
+begin
+ if Assigned(FOnGetHintSize) then
+ FOnGetHintSize(Self, Node, Column, R);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualDrawTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;
+
+begin
+ Result := 2 * FTextMargin;
+ if Canvas = nil then
+ Canvas := Self.Canvas;
+
+ if Assigned(FOnGetNodeWidth) then
+ FOnGetNodeWidth(Self, Canvas, Node, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualDrawTree.DoPaintNode(var PaintInfo: TVTPaintInfo);
+
+begin
+ if Assigned(FOnDrawNode) then
+ FOnDrawNode(Self, PaintInfo);
+end;
+
+//----------------- TVirtualDrawTree -----------------------------------------------------------------------------------
+
+function TVirtualDrawTree.GetOptions: TVirtualTreeOptions;
+
+begin
+ Result := FOptions as TVirtualTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualDrawTree.SetOptions(const Value: TVirtualTreeOptions);
+
+begin
+ FOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualDrawTree.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TVirtualTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+initialization
+ // This watcher is used whenever a global structure could be modified by more than one thread.
+ Watcher := TCriticalSection.Create;
+finalization
+ if Initialized then
+ FinalizeGlobalStructures;
+
+ InternalClipboardFormats.Free;
+ Watcher.Free;
+end.
Added: trunk/WPGM/Components/VirtualTreeview/VirtualTrees.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Components/VirtualTreeview/VirtualTrees.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Components/VirtualTreeview/VirtualTrees.~pas
===================================================================
--- trunk/WPGM/Components/VirtualTreeview/VirtualTrees.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Components/VirtualTreeview/VirtualTrees.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,29873 @@
+unit VirtualTrees;
+
+// Version 3.8.3
+//
+// The contents of this file are subject to the Mozilla Public License
+// Version 1.1 (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+//
+// Alternatively, you may redistribute this library, use and/or modify it under the terms of the
+// GNU Lesser General Public License as published by the Free Software Foundation;
+// either version 2.1 of the License, or (at your option) any later version.
+// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/.
+//
+// Software distributed under the License is distributed on an "AS IS" basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
+// specific language governing rights and limitations under the License.
+//
+// The original code is VirtualTrees.pas, released September 30, 2000.
+//
+// The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de),
+// written by Dipl. Ing. Mike Lischke (public at lischke-online.de, www.lischke-online.de).
+//
+// Portions created by digital publishing AG are Copyright
+// (C) 1999-2001 digital publishing AG. All Rights Reserved.
+//----------------------------------------------------------------------------------------------------------------------
+//
+// For full document history see help file.
+//
+// Credits for their valuable assistance and code donations go to:
+// Freddy Ertl, Marian Aldenhövel, Thomas Bogenrieder, Jim Kuenemann, Werner Lehmann, Jens Treichler,
+// Paul Gallagher (IBO tree), Ondrej Kelle, Ronaldo Melo Ferraz, Heri Bender, Roland Bedürftig (BCB)
+// Anthony Mills, Alexander Egorushkin (BCB), Mathias Torell (BCB), Frank van den Bergh, Vadim Sedulin, Peter Evans,
+// Milan Vandrovec (BCB), Steve Moss (system check images), Joe White, David Clark (local node memory manager),
+// Anders Thomsen, Igor Afanasyev
+// Beta testers:
+// Freddy Ertl, Hans-Jürgen Schnorrenberg, Werner Lehmann, Jim Kueneman, Vadim Sedulin, Moritz Franckenstein,
+// Wim van der Vegt, Franc v/d Westelaken
+// Indirect contribution (via publicly accessible work of those persons):
+// Alex Denissov, Hiroyuki Hori (MMXAsm expert)
+// Documentation:
+// Markus Spoettl and toolsfactory GbR (http://www.doc-o-matic.com/, sponsoring Virtual Treeview
+// with a free copy of the Doc-O-Matic help authoring system), Sven H. (Step by step tutorial)
+// CLX:
+// Dmitri Dmitrienko (initial developer)
+//----------------------------------------------------------------------------------------------------------------------
+
+interface
+
+{$BOOLEVAL OFF} // Use fastest possible boolean evaluation.
+
+{$I Compilers.inc}
+{.$define UseFlatScrollbars}
+{.$define ReverseFullExpandHotKey} // Used to define Ctrl+'+' instead of Ctrl+Shift+'+' for full expand (and similar for collapsing).
+{$define ThemeSupport}
+
+// Virtual Treeview can use a tiny but very effective local memory manager for node allocation.
+// The local memory manager was implemented by David Clark from Caelo Software Inc.
+// See below for more info about it.
+{.$define UseLocalMemoryManager}
+
+{.$define TntSupport} // Added by Igor Afanasyev to support unicode-aware inplace editor. This implementation uses
+ // Troy Wolbrink's TNT controls, which can be found at:
+ // http://home.ccci.org/wolbrink/tnt/delphi_unicode_controls.htm.
+
+{$HPPEMIT '#include <objidl.h>'}
+{$HPPEMIT '#include <oleidl.h>'} // Necessary for BCB 6 SP 2.
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, ImgList, ActiveX, StdCtrls, Menus, Printers,
+ SyncObjs // critical sections
+ {$ifdef ThemeSupport}
+ {$ifndef COMPILER_7_UP}
+ , ThemeSrv, TMSchema, UxTheme // Windows XP themes support. Get these units from www.delphi-gems.com.
+ {$else}
+ , Themes, UxTheme
+ {$endif COMPILE_7_UP}
+ {$endif ThemeSupport}
+ {$ifdef TntSupport}
+ , TntStdCtrls // Unicode aware inplace editor.
+ {$endif TntSupport}
+ ;
+
+const
+ VTVersion = '3.8.3';
+ VTTreeStreamVersion = 2;
+ VTHeaderStreamVersion = 2; // The header needs an own stream version to indicate changes only relevant to the header.
+
+ CacheThreshold = 2000; // Number of nodes a tree must at least have to start caching and at the same
+ // time the maximum number of nodes between two cache entries.
+ FadeAnimationStepCount = 255; // Number of animation steps for hint fading (0..255).
+ ShadowSize = 5; // Size in pixels of the hint shadow. This value has no influence on Win2K and XP systems
+ // as those OSes have native shadow support.
+
+ // Special identifiers for columns.
+ NoColumn = -1;
+ InvalidColumn = -2;
+
+ // Indices for check state images used for checking.
+ ckEmpty = 0; // an empty image used as place holder
+ // radio buttons
+ ckRadioUncheckedNormal = 1;
+ ckRadioUncheckedHot = 2;
+ ckRadioUncheckedPressed = 3;
+ ckRadioUncheckedDisabled = 4;
+ ckRadioCheckedNormal = 5;
+ ckRadioCheckedHot = 6;
+ ckRadioCheckedPressed = 7;
+ ckRadioCheckedDisabled = 8;
+ // check boxes
+ ckCheckUncheckedNormal = 9;
+ ckCheckUncheckedHot = 10;
+ ckCheckUncheckedPressed = 11;
+ ckCheckUncheckedDisabled = 12;
+ ckCheckCheckedNormal = 13;
+ ckCheckCheckedHot = 14;
+ ckCheckCheckedPressed = 15;
+ ckCheckCheckedDisabled = 16;
+ ckCheckMixedNormal = 17;
+ ckCheckMixedHot = 18;
+ ckCheckMixedPressed = 19;
+ ckCheckMixedDisabled = 20;
+ // simple button
+ ckButtonNormal = 21;
+ ckButtonHot = 22;
+ ckButtonPressed = 23;
+ ckButtonDisabled = 24;
+
+ // Instead using a TTimer class for each of the various events I use Windows timers with messages
+ // as this is more economical.
+ ExpandTimer = 1;
+ EditTimer = 2;
+ HeaderTimer = 3;
+ ScrollTimer = 4;
+ ChangeTimer = 5;
+ StructureChangeTimer = 6;
+ SearchTimer = 7;
+
+ // Need to use this message to release the edit link interface asynchronly.
+ WM_RELEASEEDITLINK = WM_APP + 31;
+ WM_CHANGESTATE = WM_APP + 32;
+
+ // Virtual Treeview does not need to be subclass by an eventual Theme Manager class as it handles
+ // Windows XP theme painting itself. Hence the special non-subclass message is used to prevent subclassing.
+ CM_DENYSUBCLASSING = CM_BASE + 2000;
+
+ // Decoupling message for auto-adjusting the internal edit window.
+ CM_AUTOADJUST = CM_BASE + 2005;
+
+ // VT's own clipboard formats,
+ // Note: The reference format is used internally to allow to link to a tree reference
+ // to implement optimized moves and other back references.
+ CFSTR_VIRTUALTREE = 'Virtual Tree Data';
+ CFSTR_VTREFERENCE = 'Virtual Tree Reference';
+ CFSTR_HTML = 'HTML Format';
+ CFSTR_RTF = 'Rich Text Format';
+ CFSTR_RTFNOOBJS = 'Rich Text Format Without Objects';
+ CFSTR_CSV = 'CSV';
+
+ // Drag image helpers for Windows 2000 and up.
+ IID_IDropTargetHelper: TGUID = (D1: $4657278B; D2: $411B; D3: $11D2; D4: ($83, $9A, $00, $C0, $4F, $D9, $18, $D0));
+ IID_IDragSourceHelper: TGUID = (D1: $DE5BF786; D2: $477A; D3: $11D2; D4: ($83, $9D, $00, $C0, $4F, $D9, $18, $D0));
+ IID_IDropTarget: TGUID = (D1: $00000122; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00, $00, $00, $46));
+ CLSID_DragDropHelper: TGUID = (D1: $4657278A; D2: $411B; D3: $11D2; D4: ($83, $9A, $00, $C0, $4F, $D9, $18, $D0));
+
+ SID_IDropTargetHelper = '{4657278B-411B-11D2-839A-00C04FD918D0}';
+ SID_IDragSourceHelper = '{DE5BF786-477A-11D2-839D-00C04FD918D0}';
+ SID_IDropTarget = '{00000122-0000-0000-C000-000000000046}';
+
+ // Help identifiers for exceptions. Application developers are responsible to link them with actual help topics.
+ hcTFEditLinkIsNil = 2000;
+ hcTFWrongMoveError = 2001;
+ hcTFWrongStreamFormat = 2002;
+ hcTFWrongStreamVersion = 2003;
+ hcTFStreamTooSmall = 2004;
+ hcTFCorruptStream1 = 2005;
+ hcTFCorruptStream2 = 2006;
+ hcTFClipboardFailed = 2007;
+ hcTFCannotSetUserData = 2008;
+
+ // Header standard split cursor.
+ crHeaderSplit = TCursor(100);
+
+ UtilityImageSize = 16; // Needed by descentants for hittests.
+
+var // Clipboard format IDs used in OLE drag'n drop and clipboard transfers.
+ CF_VIRTUALTREE,
+ CF_VTREFERENCE,
+ CF_VRTF,
+ CF_VRTFNOOBJS, // Unfortunately CF_RTF* is already defined as being
+ // registration strings so I have to use different identifiers.
+ CF_HTML,
+ CF_CSV: Word;
+
+ MMXAvailable: Boolean; // necessary to know because the blend code uses MMX instructions
+
+{$MinEnumSize 1, make enumerations as small as possible}
+
+type
+ // The exception used by the trees.
+ EVirtualTreeError = class(Exception);
+
+
+
+ PCardinal = ^Cardinal;
+
+ // Limits the speed interval which can be used for auto scrolling (milliseconds).
+ TAutoScrollInterval = 1..1000;
+
+ // Need to declare the correct WMNCPaint record as the VCL (D5-) doesn't.
+ TRealWMNCPaint = packed record
+ Msg: Cardinal;
+ Rgn: HRGN;
+ lParam: Integer;
+ Result: Integer;
+ end;
+
+ // The next two message records are not declared in Delphi 6 and lower.
+ TWMPrint = packed record
+ Msg: Cardinal;
+ DC: HDC;
+ Flags: Cardinal;
+ Result: Integer;
+ end;
+
+ TWMPrintClient = TWMPrint;
+
+ {$ifndef COMPILER_5_UP}
+ TWMContextMenu = TWMMouse;
+ {$endif COMPILER_5_UP}
+
+ // Be careful when adding new states as this might change the size of the type which in turn
+ // changes the alignment in the node record as well as the stream chunks.
+ // Do not reorder the states and always add new states at the end of this enumeration in order to avoid
+ // breaking existing code.
+ TVirtualNodeState = (
+ vsInitialized, // Set after the node has been initialized.
+ vsChecking, // Node's check state is changing, avoid propagation.
+ vsCutOrCopy, // Node is selected as cut or copy and paste source.
+ vsDisabled, // Set if node is disabled.
+ vsDeleting, // Set when the node is about to be freed.
+ vsExpanded, // Set if the node is expanded.
+ vsHasChildren, // Indicates the presence of child nodes without actually setting them.
+ vsVisible, // Indicate whether the node is visible or not (independant of the expand states of its parents).
+ vsSelected, // Set if the node is in the current selection.
+ vsInitialUserData, // Set if (via AddChild or InsertNode) initial user data has been set which requires OnFreeNode.
+ vsAllChildrenHidden, // Set if vsHasChildren is set and no child node has the vsVisible flag set.
+ vsClearing, // A node's children are being deleted. Don't register structure change event.
+ vsMultiline // Node text is wrapped at the cell boundaries instead of being shorted.
+ );
+ TVirtualNodeStates = set of TVirtualNodeState;
+
+ // States used in InitNode to indicate states a node shall initially have.
+ TVirtualNodeInitState = (
+ ivsDisabled,
+ ivsExpanded,
+ ivsHasChildren,
+ ivsMultiline,
+ ivsSelected
+ );
+ TVirtualNodeInitStates = set of TVirtualNodeInitState;
+
+ TScrollBarStyle = (
+ sbmRegular,
+ sbmFlat,
+ sbm3D
+ );
+
+ // options per column
+ TVTColumnOption = (
+ coAllowClick,
+ coDraggable,
+ coEnabled,
+ coParentBidiMode,
+ coParentColor,
+ coResizable,
+ coShowDropMark,
+ coVisible
+ );
+ TVTColumnOptions = set of TVTColumnOption;
+
+ // These flags are returned by the hit test method.
+ THitPosition = (
+ hiAbove, // above the client area (if relative) or the absolute tree area
+ hiBelow, // below the client area (if relative) or the absolute tree area
+ hiNowhere, // no node is involved (possible only if the tree is not as tall as the client area)
+ hiOnItem, // on the bitmaps/buttons or label associated with an item
+ hiOnItemButton, // on the button associated with an item
+ hiOnItemCheckbox, // on the checkbox if enabled
+ hiOnItemIndent, // in the indentation area in front of a node
+ hiOnItemLabel, // on the normal text area associated with an item
+ hiOnItemLeft, // in the area to the left of a node's text area (e.g. when right aligned or centered)
+ hiOnItemRight, // in the area to the right of a node's text area (e.g. if left aligned or centered)
+ hiOnNormalIcon, // on the "normal" image
+ hiOnStateIcon, // on the state image
+ hiToLeft, // to the left of the client area (if relative) or the absolute tree area
+ hiToRight // to the right of the client area (if relative) or the absolute tree area
+ );
+ THitPositions = set of THitPosition;
+
+ TCheckType = (
+ ctNone,
+ ctTriStateCheckBox,
+ ctCheckBox,
+ ctRadioButton,
+ ctButton
+ );
+
+ // The check states include both, transient and fluent (temporary) states. The only temporary state defined so
+ // far is the pressed state.
+ TCheckState = (
+ csUncheckedNormal, // unchecked and not pressed
+ csUncheckedPressed, // unchecked and pressed
+ csCheckedNormal, // checked and not pressed
+ csCheckedPressed, // checked and pressed
+ csMixedNormal, // 3-state check box and not pressed
+ csMixedPressed // 3-state check box and pressed
+ );
+
+ TCheckImageKind = (
+ ckLightCheck, // gray cross
+ ckDarkCheck, // black cross
+ ckLightTick, // gray tick mark
+ ckDarkTick, // black tick mark
+ ckFlat, // flat images (no 3D border)
+ ckXP, // Windows XP style
+ ckCustom, // application defined check images
+ ckSystem, // System defined check images.
+ ckSystemFlat // Flat system defined check images.
+ );
+
+ // mode to describe a move action
+ TVTNodeAttachMode = (
+ amNoWhere, // just for simplified tests, means to ignore the Add/Insert command
+ amInsertBefore, // insert node just before destination (as sibling of destination)
+ amInsertAfter, // insert node just after destionation (as sibling of destination)
+ amAddChildFirst, // add node as first child of destination
+ amAddChildLast // add node as last child of destination
+ );
+
+ // modes to determine drop position further
+ TDropMode = (
+ dmNowhere,
+ dmAbove,
+ dmOnNode,
+ dmBelow
+ );
+
+ // operations basically allowed during drag'n drop
+ TDragOperation = (
+ doCopy,
+ doMove,
+ doLink
+ );
+ TDragOperations = set of TDragOperation;
+
+ TVTImageKind = (
+ ikNormal,
+ ikSelected,
+ ikState,
+ ikOverlay
+ );
+
+ TVTHintMode = (
+ hmDefault, // show the hint of the control
+ hmHint, // show node specific hint string returned by the application
+ hmHintAndDefault, // same as hmHint but show the control's hint if no node is concerned
+ hmTooltip // show the text of the node if it isn't already fully shown
+ );
+
+ TMouseButtons = set of TMouseButton;
+
+ // Used to describe the action to do when using the OnBeforeItemErase event.
+ TItemEraseAction = (
+ eaColor, // use the provided color to erase the background instead the one of the tree
+ eaDefault // the tree should erase the item's background (bitmap or solid)
+ );
+
+
+ // There is a heap of switchable behavior in the tree. Since published properties may never exceed 4 bytes,
+ // which limits sets to at most 32 members, and because for better overview tree options are splitted
+ // in various sub-options and are held in a commom options class.
+ //
+ // Options to customize tree appearance:
+ TVTPaintOption = (
+ toHideFocusRect, // Avoid drawing the dotted rectangle around the currently focused node.
+ toHideSelection, // Selected nodes are drawn as unselected nodes if the tree is unfocused.
+ toHotTrack, // Track which node is under the mouse cursor.
+ toPopupMode, // Paint tree as would it always have the focus (useful for tree combo boxes etc.)
+ toShowBackground, // Use the background image if there's one.
+ toShowButtons, // Display collapse/expand buttons left to a node.
+ toShowDropmark, // Show the dropmark during drag'n drop operations.
+ toShowHorzGridLines, // Display horizontal lines to simulate a grid.
+ toShowRoot, // Show lines also at top level (does not show the hidden/internal root node).
+ toShowTreeLines, // Display tree lines to show hierarchy of nodes.
+ toShowVertGridLines, // Display vertical lines (depending on columns) to simulate a grid.
+ toThemeAware, // Draw UI elements (header, tree buttons etc.) according to the current theme if
+ // enabled (Windows XP+ only, application must be themed).
+ toUseBlendedImages, // Enable alpha blending for ghosted nodes or those which are being cut/copied.
+ toGhostedIfUnfocused // Ghosted images are still shown as ghosted if unfocused (otherwise the become non-ghosted
+ // images).
+ );
+ TVTPaintOptions = set of TVTPaintOption;
+
+ // Options to toggle animation support:
+ TVTAnimationOption = (
+ toAnimatedToggle // Expanding and collapsing a node is animated (quick window scroll).
+ );
+ TVTAnimationOptions = set of TVTAnimationOption;
+
+ // Options which toggle automatic handling of certain situations:
+ TVTAutoOption = (
+ toAutoDropExpand, // Expand node if it is the drop target for more than certain time.
+ toAutoExpand, // Nodes are expanded (collapsed) when getting (losing) the focus.
+ toAutoScroll, // Scroll if mouse is near the border while dragging or selecting.
+ toAutoScrollOnExpand, // Scroll as many child nodes in view as possible after expanding a node.
+ toAutoSort, // Sort tree when Header.SortColumn or Header.SortDirection change or sort node if
+ // child nodes are added.
+ toAutoSpanColumns, // Large entries continue into next column(s) if there's no text in them (no clipping).
+ toAutoTristateTracking, // Checkstates are automatically propagated for tri state check boxes.
+ toAutoHideButtons, // Node buttons are hidden when there are child nodes, but all are invisible.
+ toAutoDeleteMovedNodes, // Delete nodes which where moved in a drag operation (if not directed otherwise).
+ toDisableAutoscrollOnFocus,// Disable scrolling a column entirely into view if it gets focused.
+ toAutoChangeScale, // Change default node height automatically if the system's font scale is set to big fonts.
+ toAutoFreeOnCollapse // Frees any child node after a node has been collapsed (HasChildren flag stays there).
+ );
+ TVTAutoOptions = set of TVTAutoOption;
+
+ // Options which determine the tree's behavior when selecting nodes:
+ TVTSelectionOption = (
+ toDisableDrawSelection, // Prevent user from selecting with the selection rectangle in multiselect mode.
+ toExtendedFocus, // Entries other than in the main column can be selected, edited etc.
+ toFullRowSelect, // Hit test as well as selection highlight are not constrained to the text of a node.
+ toLevelSelectConstraint, // Constrain selection to the same level as the selection anchor.
+ toMiddleClickSelect, // Allow selection, dragging etc. with the middle mouse button. This and toWheelPanning
+ // are mutual exclusive.
+ toMultiSelect, // Allow more than one node to be selected.
+ toRightClickSelect, // Allow selection, dragging etc. with the right mouse button.
+ toSiblingSelectConstraint, // constrain selection to nodes with same parent
+ toCenterScrollIntoView // Center nodes vertically in the client area when scrolling into view.
+ );
+ TVTSelectionOptions = set of TVTSelectionOption;
+
+ // Options which do not fit into any of the other groups:
+ TVTMiscOption = (
+ toAcceptOLEDrop, // Register tree as OLE accepting drop target
+ toCheckSupport, // Show checkboxes/radio buttons.
+ toEditable, // Node captions can be edited.
+ toFullRepaintOnResize, // Fully invalidate the tree when its window is resized (CS_HREDRAW/CS_VREDRAW).
+ toGridExtensions, // Use some special enhancements to simulate and support grid behavior.
+ toInitOnSave, // Initialize nodes when saving a tree to a stream.
+ toReportMode, // Tree behaves like TListView in report mode.
+ toToggleOnDblClick, // Toggle node expansion state when it is double clicked.
+ toWheelPanning, // Support for mouse panning (wheel mice only). This option and toMiddleClickSelect are
+ // mutal exclusive, where panning has precedence.
+ toReadOnly // The tree does not allow to be modified in any way. No action is executed and
+ // node editing is not possible.
+ );
+ TVTMiscOptions = set of TVTMiscOption;
+
+const
+ DefaultPaintOptions = [toShowButtons, toShowButtons, toShowDropmark, toShowTreeLines, toShowRoot, toThemeAware,
+ toUseBlendedImages];
+ DefaultAnimationOptions = [];
+ DefaultAutoOptions = [toAutoDropExpand, toAutoTristateTracking, toAutoScrollOnExpand, toAutoDeleteMovedNodes];
+ DefaultSelectionOptions = [];
+ DefaultMiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning];
+ DefaultColumnOptions = [coAllowClick, coDraggable, coEnabled, coParentColor, coParentBidiMode, coResizable,
+ coShowDropmark, coVisible];
+
+type
+ TBaseVirtualTree = class;
+ TVirtualTreeClass = class of TBaseVirtualTree;
+
+ PVirtualNode = ^TVirtualNode;
+
+ TColumnIndex = type Integer;
+ TColumnPosition = type Cardinal;
+
+ // This record must already be defined here and not later because otherwise BCB users will not be able
+ // to compile (conversion done by BCB is wrong).
+ TCacheEntry = record
+ Node: PVirtualNode;
+ AbsoluteTop: Cardinal;
+ end;
+
+ TCache = array of TCacheEntry;
+ TNodeArray = array of PVirtualNode;
+
+ TCustomVirtualTreeOptions = class(TPersistent)
+ private
+ FOwner: TBaseVirtualTree;
+ FPaintOptions: TVTPaintOptions;
+ FAnimationOptions: TVTAnimationOptions;
+ FAutoOptions: TVTAutoOptions;
+ FSelectionOptions: TVTSelectionOptions;
+ FMiscOptions: TVTMiscOptions;
+ procedure SetAnimationOptions(const Value: TVTAnimationOptions);
+ procedure SetAutoOptions(const Value: TVTAutoOptions);
+ procedure SetMiscOptions(const Value: TVTMiscOptions);
+ procedure SetPaintOptions(const Value: TVTPaintOptions);
+ procedure SetSelectionOptions(const Value: TVTSelectionOptions);
+ protected
+ property AnimationOptions: TVTAnimationOptions read FAnimationOptions write SetAnimationOptions
+ default DefaultAnimationOptions;
+ property AutoOptions: TVTAutoOptions read FAutoOptions write SetAutoOptions default DefaultAutoOptions;
+ property MiscOptions: TVTMiscOptions read FMiscOptions write SetMiscOptions default DefaultMiscOptions;
+ property PaintOptions: TVTPaintOptions read FPaintOptions write SetPaintOptions default DefaultPaintOptions;
+ property SelectionOptions: TVTSelectionOptions read FSelectionOptions write SetSelectionOptions
+ default DefaultSelectionOptions;
+ public
+ constructor Create(AOwner: TBaseVirtualTree); virtual;
+
+ procedure AssignTo(Dest: TPersistent); override;
+
+ property Owner: TBaseVirtualTree read FOwner;
+ end;
+
+ TTreeOptionsClass = class of TCustomVirtualTreeOptions;
+
+ TVirtualTreeOptions = class(TCustomVirtualTreeOptions)
+ published
+ property AnimationOptions;
+ property AutoOptions;
+ property MiscOptions;
+ property PaintOptions;
+ property SelectionOptions;
+ end;
+
+ // Used in the CF_VTREFERENCE clipboard format.
+ PVTReference = ^TVTReference;
+ TVTReference = record
+ Process: Cardinal;
+ Tree: TBaseVirtualTree;
+ end;
+
+ TVirtualNode = packed record
+ Index, // index of node with regard to its parent
+ ChildCount: Cardinal; // number of child nodes
+ NodeHeight: Word; // height in pixels
+ States: TVirtualNodeStates; // states describing various properties of the node (expanded, initialized etc.)
+ Align: Byte; // line/button alignment
+ CheckState: TCheckState; // indicates the current check state (e.g. checked, pressed etc.)
+ CheckType: TCheckType; // indicates which check type shall be used for this node
+ Dummy: Byte; // dummy value to fill DWORD boundary
+ TotalCount, // sum of this node, all of its child nodes and their child nodes etc.
+ TotalHeight: Cardinal; // height in pixels this node covers on screen including the height of all of its
+ // children
+ // Note: Some copy routines require that all pointers (as well as the data area) in a node are
+ // located at the end of the node! Hence if you want to add new member fields (except pointers to internal
+ // data) then put them before field Parent.
+ Parent, // reference to the node's parent (for the root this contains the treeview)
+ PrevSibling, // link to the node's previous sibling or nil if it is the first node
+ NextSibling, // link to the node's next sibling or nil if it is the last node
+ FirstChild, // link to the node's first child...
+ LastChild: PVirtualNode; // link to the node's last child...
+ Data: record end; // this is a placeholder, each node gets extra data determined by NodeDataSize
+ end;
+
+ // TVTNodeMemoryManager is a high-performance local memory manager for allocating TVirtualNode structures.
+ // It is not thread-safe in itself, because it assumes that the virtual tree is being used within a single
+ // thread. The local memory manager supports only fixed-length allocation requests - all requests must be of
+ // the same size. The performance improvements are a result of TVTNodeMemoryManager getting 16K blocks
+ // of memory from the Delphi memory manager and then managing them in a highly efficient manner.
+ // A consequence is that node memory allocations/deallocations are not visible to memory debugging tools.
+ //
+ // The local memory manager is disabled by default - to enable it {$define UseLocalMemoryManager}. For smaller trees,
+ // say less than 10,000 nodes, there is really no major performance benefit in using the local memory manager.
+ {$ifdef UseLocalMemoryManager}
+ TVTNodeMemoryManager = class
+ private
+ FAllocSize: Cardinal; // The memory allocated for each node
+ FBlockList: TList; // List of allocated blocks
+ FBytesAvailable: Cardinal; // Bytes available in current block
+ FNext: PVirtualNode; // Pointer to next available node in current block
+ FFreeSpace: PVirtualNode; // Pointer to free space chain
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ function AllocNode(const Size: Cardinal): PVirtualNode;
+ procedure FreeNode(const Node: PVirtualNode);
+ procedure Clear;
+ end;
+ {$endif UseLocalMemoryManager}
+
+ // structure used when info about a certain position in the tree is needed
+ THitInfo = record
+ HitNode: PVirtualNode;
+ HitPositions: THitPositions;
+ HitColumn: TColumnIndex;
+ end;
+
+ // auto scroll directions
+ TScrollDirections = set of (
+ sdLeft,
+ sdUp,
+ sdRight,
+ sdDown
+ );
+
+ // OLE drag'n drop support
+ TFormatEtcArray = array of TFormatEtc;
+ TFormatArray = array of Word;
+
+ // IDataObject.SetData support
+ TInternalStgMedium = packed record
+ Format: TClipFormat;
+ Medium: TStgMedium;
+ end;
+ TInternalStgMediumArray = array of TInternalStgMedium;
+
+ TEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc)
+ private
+ FTree: TBaseVirtualTree;
+ FFormatEtcArray: TFormatEtcArray;
+ FCurrentIndex: Integer;
+ public
+ constructor Create(Tree: TBaseVirtualTree; AFormatEtcArray: TFormatEtcArray);
+
+ function Clone(out Enum: IEnumFormatEtc): HResult; stdcall;
+ function Next(celt: Integer; out elt; pceltFetched: PLongint): HResult; stdcall;
+ function Reset: HResult; stdcall;
+ function Skip(celt: Integer): HResult; stdcall;
+ end;
+
+ // ----- OLE drag'n drop handling
+ IDropTargetHelper = interface(IUnknown)
+ [SID_IDropTargetHelper]
+ function DragEnter(hwndTarget: HWND; pDataObject: IDataObject; var ppt: TPoint; dwEffect: Integer): HRESULT; stdcall;
+ function DragLeave: HRESULT; stdcall;
+ function DragOver(var ppt: TPoint; dwEffect: Integer): HRESULT; stdcall;
+ function Drop(pDataObject: IDataObject; var ppt: TPoint; dwEffect: Integer): HRESULT; stdcall;
+ function Show(fShow: Boolean): HRESULT; stdcall;
+ end;
+
+ PSHDragImage = ^TSHDragImage;
+ TSHDragImage = packed record
+ sizeDragImage: TSize;
+ ptOffset: TPoint;
+ hbmpDragImage: HBITMAP;
+ ColorRef: TColorRef;
+ end;
+
+ IDragSourceHelper = interface(IUnknown)
+ [SID_IDragSourceHelper]
+ function InitializeFromBitmap(var SHDragImage: TSHDragImage; pDataObject: IDataObject): HRESULT; stdcall;
+ function InitializeFromWindow(Window: HWND; var ppt: TPoint; pDataObject: IDataObject): HRESULT; stdcall;
+ end;
+
+ IVTDragManager = interface(IUnknown)
+ ['{C4B25559-14DA-446B-8901-0C879000EB16}']
+ procedure ForceDragLeave; stdcall;
+ function GetDataObject: IDataObject; stdcall;
+ function GetDragSource: TBaseVirtualTree; stdcall;
+ function GetDropTargetHelperSupported: Boolean; stdcall;
+ function GetIsDropTarget: Boolean; stdcall;
+
+ property DataObject: IDataObject read GetDataObject;
+ property DragSource: TBaseVirtualTree read GetDragSource;
+ property DropTargetHelperSupported: Boolean read GetDropTargetHelperSupported;
+ property IsDropTarget: Boolean read GetIsDropTarget;
+ end;
+
+ // This data object is used in two different places. One is for clipboard operations and the other while dragging.
+ TVTDataObject = class(TInterfacedObject, IDataObject)
+ private
+ FOwner: TBaseVirtualTree; // The tree which provides clipboard or drag data.
+ FForClipboard: Boolean; // Determines which data to render with GetData.
+ FFormatEtcArray: TFormatEtcArray;
+ FInternalStgMediumArray: TInternalStgMediumArray; // The available formats in the DataObject
+ FAdviseHolder: IDataAdviseHolder; // Reference to an OLE supplied implementation for advising.
+ protected
+ function CanonicalIUnknown(TestUnknown: IUnknown): IUnknown;
+ function EqualFormatEtc(FormatEtc1, FormatEtc2: TFormatEtc): Boolean;
+ function FindFormatEtc(TestFormatEtc: TFormatEtc; const FormatEtcArray: TFormatEtcArray): integer;
+ function FindInternalStgMedium(Format: TClipFormat): PStgMedium;
+ function HGlobalClone(HGlobal: THandle): THandle;
+ function RenderInternalOLEData(const FormatEtcIn: TFormatEtc; var Medium: TStgMedium; var OLEResult: HResult): Boolean;
+ function StgMediumIncRef(const InStgMedium: TStgMedium; var OutStgMedium: TStgMedium;
+ CopyInMedium: Boolean; DataObject: IDataObject): HRESULT;
+
+ property ForClipboard: Boolean read FForClipboard;
+ property FormatEtcArray: TFormatEtcArray read FFormatEtcArray write FFormatEtcArray;
+ property InternalStgMediumArray: TInternalStgMediumArray read FInternalStgMediumArray write FInternalStgMediumArray;
+ property Owner: TBaseVirtualTree read FOwner;
+ public
+ constructor Create(AOwner: TBaseVirtualTree; ForClipboard: Boolean); virtual;
+ destructor Destroy; override;
+
+ function DAdvise(const FormatEtc: TFormatEtc; advf: Integer; const advSink: IAdviseSink; out dwConnection: Integer):
+ HResult; virtual; stdcall;
+ function DUnadvise(dwConnection: Integer): HResult; virtual; stdcall;
+ function EnumDAdvise(out enumAdvise: IEnumStatData): HResult; virtual; stdcall;
+ function EnumFormatEtc(Direction: Integer; out EnumFormatEtc: IEnumFormatEtc): HResult; virtual; stdcall;
+ function GetCanonicalFormatEtc(const FormatEtc: TFormatEtc; out FormatEtcOut: TFormatEtc): HResult; virtual; stdcall;
+ function GetData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium): HResult; virtual; stdcall;
+ function GetDataHere(const FormatEtc: TFormatEtc; out Medium: TStgMedium): HResult; virtual; stdcall;
+ function QueryGetData(const FormatEtc: TFormatEtc): HResult; virtual; stdcall;
+ function SetData(const FormatEtc: TFormatEtc; var Medium: TStgMedium; DoRelease: BOOL): HResult; virtual; stdcall;
+ end;
+
+ // TVTDragManager is a class to manage drag and drop in a Virtual Treeview.
+ TVTDragManager = class(TInterfacedObject, IVTDragManager, IDropSource, IDropTarget)
+ private
+ FOwner, // The tree which is responsible for drag management.
+ FDragSource: TBaseVirtualTree; // Reference to the source tree if the source was a VT, might be different than
+ // the owner tree.
+ FIsDropTarget: Boolean; // True if the owner is currently the drop target.
+ FDataObject: IDataObject; // A reference to the data object passed in by DragEnter (only used when the owner
+ // tree is the current drop target).
+ FDropTargetHelper: IDropTargetHelper; // Win2k > Drag image support
+ FFullDragging: BOOL; // True, if full dragging is currently enabled in the system.
+
+ function GetDataObject: IDataObject; stdcall;
+ function GetDragSource: TBaseVirtualTree; stdcall;
+ function GetDropTargetHelperSupported: Boolean; stdcall;
+ function GetIsDropTarget: Boolean; stdcall;
+ public
+ constructor Create(AOwner: TBaseVirtualTree); virtual;
+ destructor Destroy; override;
+
+ function DragEnter(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult; stdcall;
+ function DragLeave: HResult; stdcall;
+ function DragOver(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult; stdcall;
+ function Drop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult; stdcall;
+ procedure ForceDragLeave; stdcall;
+ function GiveFeedback(Effect: Integer): HResult; stdcall;
+ function QueryContinueDrag(EscapePressed: BOOL; KeyState: Integer): HResult; stdcall;
+ end;
+
+ PVTHintData = ^TVTHintData;
+ TVTHintData = record
+ Tree: TBaseVirtualTree;
+ Node: PVirtualNode;
+ Column: TColumnIndex;
+ HintRect: TRect; // used for draw trees only, string trees get the size from the hint string
+ DefaultHint: WideString; // used only if there is no node specific hint string available
+ // or a header hint is about to appear
+ HintText: WideString; // set when size of the hint window is calculated
+ BidiMode: TBidiMode;
+ Alignment: TAlignment;
+ end;
+
+ // Determines the kind of animation when a hint is activated.
+ THintAnimationType = (
+ hatNone, // no animation at all, just display hint/tooltip
+ hatFade, // fade in the hint/tooltip, like in Windows 2000
+ hatSlide, // slide in the hint/tooltip, like in Windows 98
+ hatSystemDefault // use what the system is using (slide for Win9x, slide/fade for Win2K+, depends on settings)
+ );
+
+ // The trees need an own hint window class because of Unicode output and adjusted font.
+ TVirtualTreeHintWindow = class(THintWindow)
+ private
+ FHintData: TVTHintData;
+ FBackground,
+ FDrawBuffer,
+ FTarget: TBitmap;
+ FTextHeight: Integer;
+ function AnimationCallback(Step, StepSize: Integer; Data: Pointer): Boolean;
+ procedure InternalPaint(Step, StepSize: Integer);
+ procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
+ procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
+ procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;
+ procedure WMShowWindow(var Message: TWMShowWindow); message WM_SHOWWINDOW;
+ protected
+ procedure CreateParams(var Params: TCreateParams); override;
+
+ procedure Paint; override;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ procedure ActivateHint(Rect: TRect; const AHint: string); override;
+ function CalcHintRect(MaxWidth: Integer; const AHint: string; AData: Pointer): TRect; override;
+ function IsHintMsg(var Msg: TMsg): Boolean; override;
+ end;
+
+ // Drag image support for the tree.
+ TVTTransparency = 0..255;
+ TVTBias = -128..127;
+
+ // Simple move limitation for the drag image.
+ TVTDragMoveRestriction = (
+ dmrNone,
+ dmrHorizontalOnly,
+ dmrVerticalOnly
+ );
+
+ TVTDragImageStates = set of (
+ disHidden, // Internal drag image is currently hidden (always hidden if drag image helper interfaces are used).
+ disInDrag, // Drag image class is currently being used.
+ disPrepared, // Drag image class is prepared.
+ disSystemSupport // Running on Windows 2000 or higher. System supports drag images natively.
+ );
+
+ // Class to manage header and tree drag image during a drag'n drop operation.
+ TVTDragImage = class
+ private
+ FOwner: TBaseVirtualTree;
+ FBackImage, // backup of overwritten screen area
+ FAlphaImage, // target for alpha blending
+ FDragImage: TBitmap; // the actual drag image to blend to screen
+ FImagePosition, // position of image (upper left corner) in screen coordinates
+ FLastPosition: TPoint; // last mouse position in screen coordinates
+ FTransparency: TVTTransparency; // alpha value of the drag image (0 - fully transparent, 255 - fully opaque)
+ FPreBlendBias, // value to darken or lighten the drag image before it is blended
+ FPostBlendBias: TVTBias; // value to darken or lighten the alpha blend result
+ FFade: Boolean; // determines whether to fade the drag image from center to borders or not
+ FRestriction: TVTDragMoveRestriction; // determines in which directions the drag image can be moved
+ FColorKey: TColor; // color to make fully transparent regardless of any other setting
+ FStates: TVTDragImageStates; // Determines the states of the drag image class.
+ function GetVisible: Boolean; // True if the drag image is currently hidden (used only when dragging)
+ protected
+ procedure InternalShowDragImage(ScreenDC: HDC);
+ procedure MakeAlphaChannel(Source, Target: TBitmap);
+ public
+ constructor Create(AOwner: TBaseVirtualTree);
+ destructor Destroy; override;
+
+ function DragTo(P: TPoint; ForceRepaint: Boolean): Boolean;
+ procedure EndDrag;
+ function GetDragImageRect: TRect;
+ procedure HideDragImage;
+ procedure PrepareDrag(DragImage: TBitmap; ImagePosition, HotSpot: TPoint; const DataObject: IDataObject);
+ procedure RecaptureBackground(Tree: TBaseVirtualTree; R: TRect; VisibleRegion: HRGN; CaptureNCArea,
+ ReshowDragImage: Boolean);
+ procedure ShowDragImage;
+ function WillMove(P: TPoint): Boolean;
+
+ property ColorKey: TColor read FColorKey write FColorKey default clWindow;
+ property Fade: Boolean read FFade write FFade default False;
+ property MoveRestriction: TVTDragMoveRestriction read FRestriction write FRestriction default dmrNone;
+ property PostBlendBias: TVTBias read FPostBlendBias write FPostBlendBias default 0;
+ property PreBlendBias: TVTBias read FPreBlendBias write FPreBlendBias default 0;
+ property Transparency: TVTTransparency read FTransparency write FTransparency default 128;
+ property Visible: Boolean read GetVisible;
+ end;
+
+ // tree columns implementation
+ TVirtualTreeColumns = class;
+ TVTHeader = class;
+
+ TVirtualTreeColumnStyle = (
+ vsText,
+ vsOwnerDraw
+ );
+
+ {$ifndef COMPILER_5_UP}
+ TImageIndex = Integer;
+ {$endif COMPILER_5_UP}
+
+ TVTHeaderColumnLayout = (
+ blGlyphLeft,
+ blGlyphRight,
+ blGlyphTop,
+ blGlyphBottom
+ );
+
+ TVirtualTreeColumn = class(TCollectionItem)
+ private
+ FText,
+ FHint: WideString;
+ FLeft,
+ FWidth: Integer;
+ FPosition: TColumnPosition;
+ FMinWidth: Integer;
+ FMaxWidth: Integer;
+ FStyle: TVirtualTreeColumnStyle;
+ FImageIndex: TImageIndex;
+ FBiDiMode: TBiDiMode;
+ FLayout: TVTHeaderColumnLayout;
+ FMargin,
+ FSpacing: Integer;
+ FOptions: TVTColumnOptions;
+ FTag: Integer;
+ FAlignment: TAlignment;
+ FLastWidth: Integer;
+ FColor: TColor;
+ function GetLeft: Integer;
+ function IsBiDiModeStored: Boolean;
+ function IsColorStored: Boolean;
+ procedure SetAlignment(const Value: TAlignment);
+ procedure SetBiDiMode(Value: TBiDiMode);
+ procedure SetColor(const Value: TColor);
+ procedure SetImageIndex(Value: TImageIndex);
+ procedure SetLayout(Value: TVTHeaderColumnLayout);
+ procedure SetMargin(Value: Integer);
+ procedure SetMaxWidth(Value: Integer);
+ procedure SetMinWidth(Value: Integer);
+ procedure SetOptions(Value: TVTColumnOptions);
+ procedure SetPosition(Value: TColumnPosition);
+ procedure SetSpacing(Value: Integer);
+ procedure SetStyle(Value: TVirtualTreeColumnStyle);
+ procedure SetText(const Value: WideString);
+ procedure SetWidth(Value: Integer);
+ protected
+ procedure ComputeHeaderLayout(DC: HDC; const Client: TRect; UseHeaderGlyph, UseSortGlyph: Boolean;
+ var HeaderGlyphPos, SortGlyphPos: TPoint; var TextBounds: TRect);
+ procedure DefineProperties(Filer: TFiler); override;
+ procedure GetAbsoluteBounds(var Left, Right: Integer);
+ function GetDisplayName: string; override;
+ function GetOwner: TVirtualTreeColumns; reintroduce;
+ procedure ReadHint(Reader: TReader);
+ procedure ReadText(Reader: TReader);
+ procedure SetIndex(Value: Integer); override;
+ procedure WriteHint(Writer: TWriter);
+ procedure WriteText(Writer: TWriter);
+ public
+ constructor Create(Collection: TCollection); override;
+ destructor Destroy; override;
+
+ procedure Assign(Source: TPersistent); override;
+ function Equals(OtherColumn: TVirtualTreeColumn): Boolean; virtual;
+ function GetRect: TRect;
+ procedure LoadFromStream(const Stream: TStream; Version: Integer);
+ procedure ParentBiDiModeChanged;
+ procedure ParentColorChanged;
+ procedure RestoreLastWidth;
+ procedure SaveToStream(const Stream: TStream);
+ function UseRightToLeftReading: Boolean;
+
+ property Left: Integer read GetLeft;
+ property Owner: TVirtualTreeColumns read GetOwner;
+ published
+ property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
+ property BiDiMode: TBiDiMode read FBiDiMode write SetBiDiMode stored IsBiDiModeStored default bdLeftToRight;
+ property Color: TColor read FColor write SetColor stored IsColorStored default clWindow;
+ property Hint: WideString read FHint write FHint stored False;
+ property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;
+ property Layout: TVTHeaderColumnLayout read FLayout write SetLayout default blGlyphLeft;
+ property Margin: Integer read FMargin write SetMargin default 4;
+ property MaxWidth: Integer read FMaxWidth write SetMaxWidth default 10000;
+ property MinWidth: Integer read FMinWidth write SetMinWidth default 10;
+ property Options: TVTColumnOptions read FOptions write SetOptions default DefaultColumnOptions;
+ property Position: TColumnPosition read FPosition write SetPosition;
+ property Spacing: Integer read FSpacing write SetSpacing default 4;
+ property Style: TVirtualTreeColumnStyle read FStyle write SetStyle default vsText;
+ property Tag: Integer read FTag write FTag default 0;
+ property Text: WideString read FText write SetText stored False; // Never let the VCL store the wide string,
+ // it is simply unable to write it correctly.
+ // We use DefineProperties here.
+ property Width: Integer read FWidth write SetWidth default 50;
+ end;
+
+ TVirtualTreeColumnClass = class of TVirtualTreeColumn;
+
+ TColumnsArray = array of TVirtualTreeColumn;
+ TCardinalArray = array of Cardinal;
+ TIndexArray = array of TColumnIndex;
+
+ TVirtualTreeColumns = class(TCollection)
+ private
+ FHeader: TVTHeader;
+ FHeaderBitmap: TBitmap; // backbuffer for drawing
+ FHoverIndex, // currently "hot" column
+ FDownIndex, // Column on which a mouse button is held down.
+ FTrackIndex: TColumnIndex; // Index of column which is currently being resized
+ FClickIndex: TColumnIndex; // last clicked column
+ FPositionToIndex: TIndexArray;
+ FNeedPositionsFix: Boolean; // True if FixPositions must still be called after DFM loading.
+ FClearing: Boolean; // True if columns are being deleted entirely.
+
+ // drag support
+ FDragIndex: TColumnIndex; // index of column currently being dragged
+ FDropTarget: TColumnIndex; // current target column (index) while dragging
+ FDropBefore: Boolean; // True if drop position is in the left half of a column, False for the right
+ // side to drop the dragged column to
+ procedure DrawButtonText(DC: HDC; Caption: WideString; Bounds: TRect; Enabled, Hot: Boolean; DrawFormat: Cardinal);
+ function GetItem(Index: TColumnIndex): TVirtualTreeColumn;
+ function GetNewIndex(P: TPoint; var OldIndex: TColumnIndex): Boolean;
+ procedure SetItem(Index: TColumnIndex; Value: TVirtualTreeColumn);
+ protected
+ procedure AdjustAutoSize(CurrentIndex: TColumnIndex; Force: Boolean = False);
+ function AdjustDownColumn(P: TPoint): TColumnIndex;
+ function AdjustHoverColumn(P: TPoint): Boolean;
+ procedure AdjustPosition(Column: TVirtualTreeColumn; Position: Cardinal);
+ procedure FixPositions;
+ function GetColumnAndBounds(P: TPoint; var ColumnLeft, ColumnRight: Integer; Relative: Boolean = True): Integer;
+ function GetOwner: TPersistent; override;
+ procedure HandleClick(P: TPoint; Button: TMouseButton; Force, DblClick: Boolean);
+ procedure IndexChanged(OldIndex, NewIndex: Integer);
+ procedure InitializePositionArray;
+ procedure Update(Item: TCollectionItem); override;
+ procedure UpdatePositions(Force: Boolean = False);
+
+ property HeaderBitmap: TBitmap read FHeaderBitmap;
+ property PositionToIndex: TIndexArray read FPositionToIndex;
+ public
+ constructor Create(AOwner: TVTHeader);
+ destructor Destroy; override;
+
+ function Add: TVirtualTreeColumn; virtual;
+ procedure AnimatedResize(Column: TColumnIndex; NewWidth: Integer);
+ procedure Assign(Source: TPersistent); override;
+ procedure Clear; virtual;
+ function ColumnFromPosition(P: TPoint; Relative: Boolean = True): TColumnIndex; overload; virtual;
+ function ColumnFromPosition(PositionIndex: TColumnPosition): TColumnIndex; overload; virtual;
+ function Equals(OtherColumns: TVirtualTreeColumns): Boolean;
+ procedure GetColumnBounds(Column: TColumnIndex; var Left, Right: Integer);
+ function GetFirstVisibleColumn: TColumnIndex;
+ function GetLastVisibleColumn: TColumnIndex;
+ function GetNextColumn(Column: TColumnIndex): TColumnIndex;
+ function GetNextVisibleColumn(Column: TColumnIndex): TColumnIndex;
+ function GetPreviousColumn(Column: TColumnIndex): TColumnIndex;
+ function GetPreviousVisibleColumn(Column: TColumnIndex): TColumnIndex;
+ function GetVisibleColumns: TColumnsArray;
+ function IsValidColumn(Column: TColumnIndex): Boolean;
+ procedure LoadFromStream(const Stream: TStream; Version: Integer);
+ procedure PaintHeader(DC: HDC; R: TRect; HOffset: Integer; VOffset: Integer = 0); virtual;
+ procedure SaveToStream(const Stream: TStream);
+ function TotalWidth: Integer;
+
+ property ClickIndex: TColumnIndex read FClickIndex;
+ property Items[Index: TColumnIndex]: TVirtualTreeColumn read GetItem write SetItem; default;
+ property Header: TVTHeader read FHeader;
+ property TrackIndex: TColumnIndex read FTrackIndex;
+ end;
+
+ TVirtualTreeColumnsClass = class of TVirtualTreeColumns;
+
+ TVTHeaderStyle = (
+ hsThickButtons, // TButton look and feel
+ hsFlatButtons, // flatter look than hsThickButton, like an always raised flat TToolButton
+ hsPlates, // flat TToolButton look and feel (raise on hover etc.)
+ hsXPStyle // Windows XP style
+ );
+
+ TVTHeaderOption = (
+ hoAutoResize, // adjust a column so that the header never exceeds client width of owner control
+ hoColumnResize, // resizing columns is allowed
+ hoDblClickResize, // allows a column to resize itself to its largest entry
+ hoDrag, // dragging columns is allowed
+ hoHotTrack, // header captions are highlighted when mouse is over a particular column
+ hoOwnerDraw, // header items with the owner draw style can be drawn by the application via event
+ hoRestrictDrag, // header can only be dragged horizontally
+ hoShowHint, // show application defined header hint
+ hoShowImages, // show images
+ hoShowSortGlyphs, // allow visible sort glyphs
+ hoVisible // header is visible
+ );
+ TVTHeaderOptions = set of TVTHeaderOption;
+
+ THeaderState = (
+ hsAutoSizing, // auto size chain is in progess, do not trigger again on WM_SIZE
+ hsDragging, // header dragging is in progress (only if enabled)
+ hsDragPending, // left button is down, user might want to start dragging a column
+ hsLoading, // The header currently loads from stream, so updates are not necessary.
+ hsTracking, // column resizing is in progress
+ hsTrackPending // left button is down, user might want to start resize a column
+ );
+ THeaderStates = set of THeaderState;
+
+ TSortDirection = (
+ sdAscending,
+ sdDescending
+ );
+
+ // desribes what made a structure change event happen
+ TChangeReason = (
+ crIgnore, // used as placeholder
+ crAccumulated, // used for delayed changes
+ crChildAdded, // one or more child nodes have been added
+ crChildDeleted, // one or more child nodes have been deleted
+ crNodeAdded, // a node has been added
+ crNodeCopied, // a node has been duplicated
+ crNodeMoved // a node has been moved to a new place
+ );
+
+ TVTHeader = class(TPersistent)
+ private
+ FOwner: TBaseVirtualTree;
+ FColumns: TVirtualTreeColumns;
+ FHeight: Cardinal;
+ FFont: TFont;
+ FOptions: TVTHeaderOptions;
+ FStates: THeaderStates; // used to keep track of internal states the header can enter
+ FLeftTrackPos: Integer; // left border of this column to quickly calculate its width on resize
+ FStyle: TVTHeaderStyle; // button style
+ FBackground: TColor;
+ FAutoSizeIndex: TColumnIndex;
+ FPopupMenu: TPopupMenu;
+ FMainColumn: TColumnIndex; // the column which holds the tree
+ FImages: TImageList;
+ FImageChangeLink: TChangeLink; // connections to the image list to get notified about changes
+ FSortColumn: TColumnIndex;
+ FSortDirection: TSortDirection;
+ FTrackStart: TPoint; // client coordinates of the tracking start point
+ FDragStart: TPoint; // initial mouse drag position
+ FDragImage: TVTDragImage; // drag image management during header drag
+ procedure FontChanged(Sender: TObject);
+ function GetMainColumn: TColumnIndex;
+ function GetUseColumns: Boolean;
+ procedure SetAutoSizeIndex(Value: TColumnIndex);
+ procedure SetBackground(Value: TColor);
+ procedure SetColumns(Value: TVirtualTreeColumns);
+ procedure SetFont(const Value: TFont);
+ procedure SetHeight(Value: Cardinal);
+ procedure SetImages(const Value: TImageList);
+ procedure SetMainColumn(Value: TColumnIndex);
+ procedure SetOptions(Value: TVTHeaderOptions);
+ procedure SetSortColumn(Value: TColumnIndex);
+ procedure SetSortDirection(const Value: TSortDirection);
+ procedure SetStyle(Value: TVTHeaderStyle);
+ protected
+ function CanWriteColumns: Boolean; virtual;
+ procedure ChangeScale(M, D: Integer); virtual;
+ function DetermineSplitterIndex(P: TPoint): Boolean; virtual;
+ procedure DragTo(P: TPoint);
+ function GetColumnsClass: TVirtualTreeColumnsClass; virtual;
+ function GetOwner: TPersistent; override;
+ function GetShiftState: TShiftState;
+ function HandleHeaderMouseMove(var Message: TWMMouseMove): Boolean;
+ function HandleMessage(var Message: TMessage): Boolean; virtual;
+ procedure ImageListChange(Sender: TObject);
+ procedure PrepareDrag(P, Start: TPoint);
+ procedure ReadColumns(Reader: TReader);
+ procedure RecalculateHeader; virtual;
+ procedure UpdateMainColumn;
+ procedure WriteColumns(Writer: TWriter);
+ public
+ constructor Create(AOwner: TBaseVirtualTree); virtual;
+ destructor Destroy; override;
+
+ procedure Assign(Source: TPersistent); override;
+ procedure AutoFitColumns;
+ function InHeader(P: TPoint): Boolean; virtual;
+ procedure Invalidate(Column: TVirtualTreeColumn; ExpandToRight: Boolean = False);
+ procedure LoadFromStream(const Stream: TStream); virtual;
+ procedure RestoreColumns;
+ procedure SaveToStream(const Stream: TStream); virtual;
+
+ property DragImage: TVTDragImage read FDragImage;
+ property States: THeaderStates read FStates;
+ property Treeview: TBaseVirtualTree read FOwner;
+ property UseColumns: Boolean read GetUseColumns;
+ published
+ property AutoSizeIndex: TColumnIndex read FAutoSizeIndex write SetAutoSizeIndex;
+ property Background: TColor read FBackground write SetBackground default clBtnFace;
+ property Columns: TVirtualTreeColumns read FColumns write SetColumns stored False; // Stored by the owner tree to
+ // support VFI.
+ property Font: TFont read FFont write SetFont;
+ property Height: Cardinal read FHeight write SetHeight default 17;
+ property Images: TImageList read FImages write SetImages;
+ property MainColumn: TColumnIndex read GetMainColumn write SetMainColumn default 0;
+ property Options: TVTHeaderOptions read FOptions write SetOptions default [hoColumnResize, hoDrag, hoShowSortGlyphs];
+ property PopupMenu: TPopupMenu read FPopupMenu write FPopUpMenu;
+ property SortColumn: TColumnIndex read FSortColumn write SetSortColumn default NoColumn;
+ property SortDirection: TSortDirection read FSortDirection write SetSortDirection default sdAscending;
+ property Style: TVTHeaderStyle read FStyle write SetStyle default hsThickButtons;
+ end;
+
+ TVTHeaderClass = class of TVTHeader;
+
+ // Communication interface between a tree editor and the tree itself (declared as using stdcall in case it
+ // is implemented in a (C/C++) DLL). The GUID is not nessecary in Delphi but important for BCB users
+ // to allow QueryInterface and _uuidof calls.
+ IVTEditLink = interface
+ ['{2BE3EAFA-5ACB-45B4-9D9A-B58BCC496E17}']
+ function BeginEdit: Boolean; stdcall; // called when editing actually starts
+ function CancelEdit: Boolean; stdcall; // called when editing has been cancelled by the tree
+ function EndEdit: Boolean; stdcall; // called when editing has been finished by the tree
+ function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
+ // called after creation to allow a setup
+ function GetBounds: TRect; stdcall; // called to get the current size of the edit window
+ // (only important if the edit resizes itself)
+ procedure ProcessMessage(var Message: TMessage); stdcall;
+ // used to forward messages to the edit window(s)
+ procedure SetBounds(R: TRect); stdcall; // called to place the editor
+ end;
+
+ // Indicates in the OnUpdating event what state the tree is currently in.
+ TVTUpdateState = (
+ usBegin, // The tree just entered the update state (BeginUpdate call for the first time).
+ usBeginSynch, // The tree just entered the synch update state (BeginSynch call for the first time).
+ usSynch, // Begin/EndSynch has been called but the tree did not change the update state.
+ usUpdate, // Begin/EndUpdate has been called but the tree did not change the update state.
+ usEnd, // The tree just left the update state (EndUpdate called for the last level).
+ usEndSynch // The tree just left the synch update state (EndSynch called for the last level).
+ );
+
+ // Used during owner draw of the header to indicate which drop mark for the column must be drawn.
+ TVTDropMarkMode = (
+ dmmNone,
+ dmmLeft,
+ dmmRight
+ );
+
+ // This structure carries all important information about header painting and is used in the advanced header painting.
+ THeaderPaintInfo = record
+ TargetCanvas: TCanvas;
+ Column: TVirtualTreeColumn;
+ PaintRectangle: TRect;
+ TextRectangle: TRect;
+ IsHoverIndex,
+ IsDownIndex,
+ IsEnabled,
+ ShowHeaderGlyph,
+ ShowSortGlyph,
+ ShowRightBorder: Boolean;
+ DropMark: TVTDropMarkMode;
+ GlyphPos,
+ SortGlyphPos: TPoint;
+ end;
+
+ // These elements are used both to query the application, which of them it wants to draw itself and to tell it during
+ // painting, which elements must be drawn during the advanced custom draw events.
+ THeaderPaintElements = set of (
+ hpeBackground,
+ hpeDropMark,
+ hpeHeaderGlyph,
+ hpeSortGlyph,
+ hpeText
+ );
+
+ // Various events must be handled at different places than they were initiated or need
+ // a persistent storage until they are reset.
+ TVirtualTreeStates = set of (
+ tsChangePending, // A selection change is pending.
+ tsCollapsing, // A full collapse operation is in progress.
+ tsClearFocusedSelection, // Node selection was modifed using Ctrl-click. Change selection state on next mouse up.
+ tsClearPending, // Need to clear the current selection on next mouse move.
+ tsClipboardFlushing, // Set during flushing the clipboard to avoid freeing the content.
+ tsCopyPending, // Indicates a pending copy operation which needs to be finished.
+ tsCutPending, // Indicates a pending cut operation which needs to be finished.
+ tsDrawSelPending, // Multiselection only. User held down the left mouse button on a free
+ // area and might want to start draw selection.
+ tsDrawSelecting, // Multiselection only. Draw selection has actually started.
+ tsEditing, // Indicates that an edit operation is currently in progress.
+ tsEditPending, // An mouse up start edit if dragging has not started.
+ tsExpanding, // A full expand operation is in progress.
+ tsHint, // Set when our hint is visible or soon will be.
+ tsInAnimation, // Set if the tree is currently in an animation loop.
+ tsIncrementalSearching, // Set when the user starts incremental search.
+ tsIncrementalSearchPending, // Set in WM_KEYDOWN to tell to use the char in WM_CHAR for incremental search.
+ tsIterating, // Set when IterateSubtree is currently in progress.
+ tsKeyCheckPending, // A check operation is under way, initiated by a key press (space key). Ignore mouse.
+ tsLeftButtonDown, // Set when the left mouse button is down.
+ tsMouseCheckPending, // A check operation is under way, initiated by a mouse click. Ignore space key.
+ tsMiddleButtonDown, // Set when the middle mouse button is down.
+ tsNeedScale, // On next ChangeScale scale the default node height.
+ tsNeedRootCountUpdate, // Set if while loading a root node count is set.
+ tsOLEDragging, // OLE dragging in progress.
+ tsOLEDragPending, // User has requested to start delayed dragging.
+ tsPainting, // The tree is currently painting itself.
+ tsRightButtonDown, // Set when the right mouse button is down.
+ tsScrolling, // Set when autoscrolling is active.
+ tsScrollPending, // Set when waiting for the scroll delay time to elapse.
+ tsSizing, // Set when the tree window is being resized. This is used to prevent recursive calls
+ // due to setting the scrollbars when sizing.
+ tsStopValidation, // Cache validation can be stopped (usually because a change has occured meanwhile).
+ tsStructureChangePending, // The structure of the tree has been changed while the update was locked.
+ tsSynchMode, // Set when the tree is in synch mode, where no timer events are triggered.
+ tsThumbTracking, // Stop updating the horizontal scroll bar while dragging the vertical thumb and vice versa.
+ tsUpdateHiddenChildrenNeeded, // Pending update for the hidden children flag after massive visibility changes.
+ tsUpdating, // The tree does currently not update its window because a BeginUpdate has not yet ended.
+ tsUseCache, // The tree's node caches are validated and non-empty.
+ tsUserDragObject, // Signals that the application created an own drag object in OnStartDrag.
+ tsUseThemes, // The tree runs under WinXP+, is theme aware and themes are enabled.
+ tsValidating, // The tree's node caches are currently validated.
+ tsValidationNeeded, // Something in the structure of the tree has changed. The cache needs validation.
+ tsVCLDragging, // VCL drag'n drop in progress.
+ tsVCLDragPending, // One-shot flag to avoid clearing the current selection on implicit mouse up for VCL drag.
+ tsWheelPanning, // Wheel mouse panning is active or soon will be.
+ tsWheelScrolling, // Wheel mouse scrolling is active or soon will be.
+ tsWindowCreating // set during window handle creation to avoid frequent unnecessary updates
+ );
+
+ TChangeStates = set of (
+ csStopValidation, // Cache validation can be stopped (usually because a change has occured meanwhile).
+ csUseCache, // The tree's node caches are validated and non-empty.
+ csValidating, // The tree's node caches are currently validated.
+ csValidationNeeded // Something in the structure of the tree has changed. The cache needs validation.
+ );
+
+ // determines whether and how the drag image is to show
+ TVTDragImageKind = (
+ diComplete, // show a complete drag image with all columns, only visible columns are shown
+ diMainColumnOnly, // show only the main column (the tree column)
+ diNoImage // don't show a drag image at all
+ );
+
+ // Switch for OLE and VCL drag'n drop. Because it is not possible to have both simultanously.
+ TVTDragType = (
+ dtOLE,
+ dtVCL
+ );
+
+ // options which determine what to draw in PaintTree
+ TVTInternalPaintOption = (
+ poBackground, // draw background image if there is any and it is enabled
+ poColumnColor, // erase node's background with the column's color
+ poDrawFocusRect, // draw focus rectangle around the focused node
+ poDrawSelection, // draw selected nodes with the normal selection color
+ poDrawDropMark, // draw drop mark if a node is currently the drop target
+ poGridLines, // draw grid lines if enabled
+ poMainOnly, // draw only the main column
+ poSelectedOnly // draw only selected nodes
+ );
+ TVTInternalPaintOptions = set of TVTInternalPaintOption;
+
+ // Determines the look of a tree's lines.
+ TVTLineStyle = (
+ lsCustomStyle, // application provides a line pattern
+ lsDotted, // usual dotted lines (default)
+ lsSolid // simple solid lines
+ );
+
+ // TVTLineType is used during painting a tree
+ TVTLineType = (
+ ltNone, // no line at all
+ ltBottomRight, // a line from bottom to the center and from there to the right
+ ltTopDown, // a line from top to bottom
+ ltTopDownRight, // a line from top to bottom and from center to the right
+ ltRight, // a line from center to the right
+ ltTopRight, // a line from bottom to center and from there to the right
+ // special styles for alternative drawings of tree lines
+ ltLeft, // a line from top to bottom at the left
+ ltLeftBottom // a combination of ltLeft and a line at the bottom from left to right
+ );
+
+ // Determines how to draw tree lines.
+ TVTLineMode = (
+ lmNormal, // usual tree lines (as in TTreeview)
+ lmBands // looks similar to a Nassi-Schneidermann diagram
+ );
+
+ // A collection of line type IDs which is used while painting a node.
+ TLineImage = array of TVTLineType;
+
+ TVTScrollIncrement = 1..10000;
+
+ // A class to manage scroll bar aspects.
+ TScrollBarOptions = class(TPersistent)
+ private
+ FAlwaysVisible: Boolean;
+ FOwner: TBaseVirtualTree;
+ FScrollBars: TScrollStyle; // used to hide or show vertical and/or horizontal scrollbar
+ FScrollBarStyle: TScrollBarStyle; // kind of scrollbars to use
+ FIncrementX,
+ FIncrementY: TVTScrollIncrement; // number of pixels to scroll in one step (when auto scrolling)
+ procedure SetAlwaysVisible(Value: Boolean);
+ procedure SetScrollBars(Value: TScrollStyle);
+ procedure SetScrollBarStyle(Value: TScrollBarStyle);
+ protected
+ function GetOwner: TPersistent; override;
+ public
+ constructor Create(AOwner: TBaseVirtualTree);
+
+ procedure Assign(Source: TPersistent); override;
+ published
+ property AlwaysVisible: Boolean read FAlwaysVisible write SetAlwaysVisible default False;
+ property HorizontalIncrement: TVTScrollIncrement read FIncrementX write FIncrementX default 20;
+ property ScrollBars: TScrollStyle read FScrollbars write SetScrollBars default ssBoth;
+ property ScrollBarStyle: TScrollBarStyle read FScrollBarStyle write SetScrollBarStyle default sbmRegular;
+ property VerticalIncrement: TVTScrollIncrement read FIncrementY write FIncrementY default 20;
+ end;
+
+ // class to collect all switchable colors into one place
+ TVTColors = class(TPersistent)
+ private
+ FOwner: TBaseVirtualTree;
+ FColors: array[0..13] of TColor;
+ function GetColor(const Index: Integer): TColor;
+ procedure SetColor(const Index: Integer; const Value: TColor);
+ public
+ constructor Create(AOwner: TBaseVirtualTree);
+
+ procedure Assign(Source: TPersistent); override;
+ published
+ property BorderColor: TColor index 7 read GetColor write SetColor default clBtnFace;
+ property DisabledColor: TColor index 0 read GetColor write SetColor default clBtnShadow;
+ property DropMarkColor: TColor index 1 read GetColor write SetColor default clHighlight;
+ property DropTargetColor: TColor index 2 read GetColor write SetColor default clHighLight;
+ property DropTargetBorderColor: TColor index 11 read GetColor write SetColor default clHighLight;
+ property FocusedSelectionColor: TColor index 3 read GetColor write SetColor default clHighLight;
+ property FocusedSelectionBorderColor: TColor index 9 read GetColor write SetColor default clHighLight;
+ property GridLineColor: TColor index 4 read GetColor write SetColor default clBtnFace;
+ property HotColor: TColor index 8 read GetColor write SetColor default clWindowText;
+ property SelectionRectangleBlendColor: TColor index 12 read GetColor write SetColor default clHighlight;
+ property SelectionRectangleBorderColor: TColor index 13 read GetColor write SetColor default clHighlight;
+ property TreeLineColor: TColor index 5 read GetColor write SetColor default clBtnShadow;
+ property UnfocusedSelectionColor: TColor index 6 read GetColor write SetColor default clBtnFace;
+ property UnfocusedSelectionBorderColor: TColor index 10 read GetColor write SetColor default clBtnFace;
+ end;
+
+ // For painting a node and its columns/cells a lot of information must be passed frequently to
+ // the paint methode.
+ TVTImageInfo = record
+ Index: Integer; // index in the associated image list
+ XPos, // horizontal position in the current target canvas
+ YPos: Integer; // vertical position in the current target canvas
+ Ghosted: Boolean; // flag to indicate that the image must be drawn slightly lighter
+ end;
+
+ TVTImageInfoIndex = (
+ iiNormal,
+ iiState,
+ iiCheck
+ );
+
+ // Options which are used when modifying the scroll offsets.
+ TScrollUpdateOptions = set of (
+ suoRepaintHeader, // if suoUpdateNCArea is also set then invalidate the header
+ suoRepaintScrollbars, // if suoUpdateNCArea is also set then repaint both scrollbars after updating them
+ suoScrollClientArea, // scroll and invalidate the proper part of the client area
+ suoUpdateNCArea // update non-client area (scrollbars, header)
+ );
+
+ // Determines the look of a tree's buttons.
+ TVTButtonStyle = (
+ bsRectangle, // traditional Windows look (plus/minus buttons)
+ bsTriangle // traditional Macintosh look
+ );
+
+ // TButtonFillMode is only used when the button style is bsRectangle and determines how to fill the interior.
+ TVTButtonFillMode = (
+ fmTreeColor, // solid color, uses the tree's background color
+ fmWindowColor, // solid color, uses clWindow
+ fmShaded, // color gradient, Windows XP style (legacy code, use toThemeAware on Windows XP instead)
+ fmTransparent // transparent color, use the item's background color
+ );
+
+ TVTPaintInfo = record
+ Canvas: TCanvas; // the canvas to paint on
+ PaintOptions: TVTInternalPaintOptions; // a copy of the paint options passed to PaintTree
+ Node: PVirtualNode; // the node to paint
+ Column: TColumnIndex; // the node's column index to paint
+ Position: TColumnPosition; // the column position of the node
+ CellRect, // the node cell
+ ContentRect: TRect; // the area of the cell used for the node's content
+ NodeWidth: Integer; // the actual node width
+ Alignment: TAlignment; // how to align within the node rectangle
+ BidiMode: TBidiMode; // directionality to be used for painting
+ BrushOrigin: TPoint; // the alignment for the brush used to draw dotted lines
+ ImageInfo: array[TVTImageInfoIndex] of TVTImageInfo; // info about each possible node image
+ end;
+
+ // Method called by the Animate routine for each animation step.
+ TVTAnimationCallback = function(Step, StepSize: Integer; Data: Pointer): Boolean of object;
+
+ TVTIncrementalSearch = (
+ isAll, // search every node in tree, initialize if necessary
+ isNone, // disable incremental search
+ isInitializedOnly, // search only initialized nodes, skip others
+ isVisibleOnly // search only visible nodes, initialize if necessary
+ );
+
+ // Determines which direction to use when advancing nodes during an incremental search.
+ TVTSearchDirection = (
+ sdForward,
+ sdBackward
+ );
+
+ // Determines where to start incremental searching for each key press.
+ TVTSearchStart = (
+ ssAlwaysStartOver, // always use the first/last node (depending on direction) to search from
+ ssLastHit, // use the last found node
+ ssFocusedNode // use the currently focused node
+ );
+
+ // Determines how to use the align member of a node.
+ TVTNodeAlignment = (
+ naFromBottom, // the align member specifies amount of units (usually pixels) from top border of the node
+ naFromTop, // align is to be measured from bottom
+ naProportional // align is to be measure in percent of the entire node height and relative to top
+ );
+
+ // Determines how to draw the selection rectangle used for draw selection.
+ TVTDrawSelectionMode = (
+ smDottedRectangle, // same as DrawFocusRect
+ smBlendedRectangle // alpha blending, uses special colors (see TVTColors)
+ );
+
+ TClipboardFormats = class(TStringList)
+ private
+ FOwner: TBaseVirtualTree;
+ public
+ constructor Create(AOwner: TBaseVirtualTree); virtual;
+
+ function Add(const S: string): Integer; override;
+ procedure Insert(Index: Integer; const S: string); override;
+ property Owner: TBaseVirtualTree read FOwner;
+ end;
+
+ // ----- Event prototypes:
+
+ // node enumeration
+ TVTGetNodeProc = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean) of object;
+
+ // node events
+ TVTChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var Allowed: Boolean) of object;
+ TVTCheckChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var NewState: TCheckState;
+ var Allowed: Boolean) of object;
+ TVTChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object;
+ TVTStructureChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Reason: TChangeReason) of object;
+ TVTEditCancelEvent = procedure(Sender: TBaseVirtualTree; Column: TColumnIndex) of object;
+ TVTEditChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var Allowed: Boolean) of object;
+ TVTEditChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object;
+ TVTFreeNodeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object;
+ TVTFocusChangingEvent = procedure(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn,
+ NewColumn: TColumnIndex; var Allowed: Boolean) of object;
+ TVTFocusChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object;
+ TVTGetImageEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var ImageIndex: Integer) of object;
+ TVTHotNodeChangeEvent = procedure(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode) of object;
+ TVTInitChildrenEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal) of object;
+ TVTInitNodeEvent = procedure(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
+ var InitialStates: TVirtualNodeInitStates) of object;
+ TVTPopupEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; const P: TPoint;
+ var AskParent: Boolean; var PopupMenu: TPopupMenu) of object;
+ TVTHelpContextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var HelpContext: Integer) of object;
+ TVTCreateEditorEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ out EditLink: IVTEditLink) of object;
+ TVTSaveNodeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Stream: TStream) of object;
+
+ // header/column events
+ TVTHeaderClickEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer) of object;
+ TVTHeaderMouseEvent = procedure(Sender: TVTHeader; Button: TMouseButton; Shift: TShiftState; X, Y: Integer) of object;
+ TVTHeaderMouseMoveEvent = procedure(Sender: TVTHeader; Shift: TShiftState; X, Y: Integer) of object;
+ TVTHeaderNotifyEvent = procedure(Sender: TVTHeader; Column: TColumnIndex) of object;
+ TVTHeaderDraggingEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; var Allowed: Boolean) of object;
+ TVTHeaderDraggedEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; OldPosition: Integer) of object;
+ TVTHeaderDraggedOutEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; DropPosition: TPoint) of object;
+ TVTHeaderPaintEvent = procedure(Sender: TVTHeader; HeaderCanvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover,
+ Pressed: Boolean; DropMark: TVTDropMarkMode) of object;
+ TVTHeaderPaintQueryElementsEvent = procedure(Sender: TVTHeader; var PaintInfo: THeaderPaintInfo;
+ var Elements: THeaderPaintElements) of object;
+ TVTAdvancedHeaderPaintEvent = procedure(Sender: TVTHeader; var PaintInfo: THeaderPaintInfo;
+ const Elements: THeaderPaintElements) of object;
+ TVTColumnClickEvent = procedure (Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState) of object;
+ TVTColumnDblClickEvent = procedure (Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState) of object;
+ TVTGetHeaderCursorEvent = procedure(Sender: TVTHeader; var Cursor: HCURSOR) of object;
+
+ // move and copy events
+ TVTNodeMovedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object;
+ TVTNodeMovingEvent = procedure(Sender: TBaseVirtualTree; Node, Target: PVirtualNode;
+ var Allowed: Boolean) of object;
+ TVTNodeCopiedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object;
+ TVTNodeCopyingEvent = procedure(Sender: TBaseVirtualTree; Node, Target: PVirtualNode;
+ var Allowed: Boolean) of object;
+
+ // drag'n drop/OLE events
+ TVTCreateDragManagerEvent = procedure(Sender: TBaseVirtualTree; out DragManager: IVTDragManager) of object;
+ TVTCreateDataObjectEvent = procedure(Sender: TBaseVirtualTree; out IDataObject: IDataObject) of object;
+ TVTDragAllowedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var Allowed: Boolean) of object;
+ TVTDragOverEvent = procedure(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState;
+ Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean) of object;
+ TVTDragDropEvent = procedure(Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject;
+ Formats: TFormatArray; Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode) of object;
+ TVTRenderOLEDataEvent = procedure(Sender: TBaseVirtualTree; const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean; var Result: HRESULT) of object;
+ TVTGetUserClipboardFormatsEvent = procedure(Sender: TBaseVirtualTree; var Formats: TFormatEtcArray) of object;
+
+ // paint events
+ TVTBeforeItemEraseEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect;
+ var ItemColor: TColor; var EraseAction: TItemEraseAction) of object;
+ TVTAfterItemEraseEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ ItemRect: TRect) of object;
+ TVTBeforeItemPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ ItemRect: TRect; var CustomDraw: Boolean) of object;
+ TVTAfterItemPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ ItemRect: TRect) of object;
+ TVTBeforeCellPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; CellRect: TRect) of object;
+ TVTAfterCellPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; CellRect: TRect) of object;
+ TVTPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas) of object;
+ TVTBackgroundPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; R: TRect;
+ var Handled: Boolean) of object;
+ TVTGetLineStyleEvent = procedure(Sender: TBaseVirtualTree; var Bits: Pointer) of object;
+
+ // search, sort
+ TVTCompareEvent = procedure(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex;
+ var Result: Integer) of object;
+ TVTIncrementalSearchEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; const SearchText: WideString;
+ var Result: Integer) of object;
+
+ // miscellaneous
+ TVTGetNodeDataSizeEvent = procedure(Sender: TBaseVirtualTree; var NodeDataSize: Integer) of object;
+ TVTKeyActionEvent = procedure(Sender: TBaseVirtualTree; var CharCode: Word; var Shift: TShiftState;
+ var DoDefault: Boolean) of object;
+ TVTScrollEvent = procedure(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer) of object;
+ TVTUpdatingEvent = procedure(Sender: TBaseVirtualTree; State: TVTUpdateState) of object;
+ TVTGetCursorEvent = procedure(Sender: TBaseVirtualTree; var Cursor: TCursor) of object;
+ TVTStateChangeEvent = procedure(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates) of object;
+
+ // Helper types for node iterations.
+ TGetFirstNodeProc = function: PVirtualNode of object;
+ TGetNextNodeProc = function(Node: PVirtualNode): PVirtualNode of object;
+
+ // ----- TBaseVirtualTree
+ TBaseVirtualTree = class(TCustomControl)
+ private
+ FBorderStyle: TBorderStyle;
+ FHeader: TVTHeader;
+ FRoot: PVirtualNode;
+ FDefaultNodeHeight,
+ FIndent: Cardinal;
+ FOptions: TCustomVirtualTreeOptions;
+ FUpdateCount: Cardinal; // update stopper, updates of the tree control are only done if = 0
+ FSynchUpdateCount: Cardinal; // synchronizer, causes all events which are usually done via timers
+ // to happen immediately, regardless of the normal update state
+ FNodeDataSize: Integer; // number of bytes to allocate with each node (in addition to its base
+ // structure and the internal data), if -1 then do callback
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager: TVTNodeMemoryManager; // High-performance local memory manager.
+ {$endif UseLocalMemoryManager}
+ FStates: TVirtualTreeStates; // various active/pending states the tree needs to consider
+ FLastSelected,
+ FFocusedNode: PVirtualNode;
+ FEditColumn, // column to be edited (focused node)
+ FFocusedColumn: TColumnIndex; // NoColumn if no columns are active otherwise the last hit column of
+ // the currently focused node
+ FScrollDirections: TScrollDirections; // directions to scroll client area into depending on mouse position
+ FLastStructureChangeReason: TChangeReason; // used for delayed structur change event
+ FLastStructureChangeNode, // dito
+ FLastChangedNode, // used for delayed change event
+ FCurrentHotNode: PVirtualNode; // Node over which the mouse is hovering.
+ FLastSelRect,
+ FNewSelRect: TRect; // used while doing draw selection
+ FHotCursor: TCursor; // can be set to additionally indicate the current hot node
+ FAnimationType: THintAnimationType; // none, fade in, slide in animation (just like those animations used
+ // in Win98 (slide) and Windows 2000 (fade))
+ FHintMode: TVTHintMode; // determines the kind of the hint window
+ FHintData: TVTHintData; // used while preparing the hint window
+ FChangeDelay: Cardinal; // used to delay OnChange event
+ FEditDelay: Cardinal; // determines time to elapse before a node goes into edit mode
+ FPositionCache: TCache; // array which stores node references ordered by vertical positions
+ // (see also DoValidateCache for more information)
+ FVisibleCount: Cardinal; // number of currently visible nodes
+ FStartIndex: Cardinal; // index to start validating cache from
+ FSelection: TNodeArray; // list of currently selected nodes
+ FSelectionCount: Integer; // number of currently selected nodes (size of FSelection might differ)
+ FRangeAnchor: PVirtualNode; // anchor node for selection with the keyboard, determines start of a
+ // selection range
+ FCheckNode: PVirtualNode; // node which "captures" an check event
+ FPendingCheckState: TCheckState; // the new state the check node will get if all wents fine
+ FLastSelectionLevel: Integer; // keeps the last node level for constrained multiselection
+ FDrawSelShiftState: TShiftState; // keeps the initial shift state when the user starts selection with
+ // the mouse
+ FEditLink: IVTEditLink; // used to comunicate with an application defined editor
+ FTempNodeCache: TNodeArray; // used at various places to hold temporarily a bunch of node refs.
+ FTempNodeCount: Cardinal; // number of nodes in FTempNodeCache
+ FBackground: TPicture; // a background image loadable at design time
+ FMargin: Integer; // horizontal border distance
+ FTextMargin: Integer; // space between the node's text and its horizontal bounds
+ FBackgroundOffsetX,
+ FBackgroundOffsetY: Integer; // used to fine tune the position of the background image
+ FAnimationDuration: Cardinal; // specifies how long an animation shall take (expanding, hint)
+ FWantTabs: Boolean; // If True then the tree also consumes the tab key.
+ FNodeAlignment: TVTNodeAlignment; // determines how to interpret the align member of a node
+ FHeaderRect: TRect; // Space which the header currently uses in the control (window coords).
+ FLastHintRect: TRect; // Area which the must must leave to reshow a hint.
+ FUpdateRect: TRect;
+ FChangeLock: TCriticalSection; // To sync the change events from both VT and the worker thread.
+
+ // paint support and images
+ FPlusBM,
+ FMinusBM: TBitmap; // small bitmaps used for tree buttons
+ FImages, // normal images in the tree
+ FStateImages, // state images in the tree
+ FCustomCheckImages: TCustomImageList; // application defined check images
+ FCheckImageKind: TCheckImageKind; // light or dark, cross marks or tick marks
+ FCheckImages: TCustomImageList; // Reference to global image list to be used for the check images.
+ FImageChangeLink,
+ FStateChangeLink,
+ FCustomCheckChangeLink: TChangeLink; // connections to the image lists
+ FOldFontChange: TNotifyEvent; // helper method pointer for tracking font changes in the off screen buffer
+ FFontChanged: Boolean; // flag for keeping informed about font changes in the off screen buffer
+ FColors: TVTColors; // class comprising all customizable colors in the tree
+ FButtonStyle: TVTButtonStyle; // style of the tree buttons
+ FButtonFillMode: TVTButtonFillMode; // for rectangular tree buttons only: how to fill them
+ FLineStyle: TVTLineStyle; // style of the tree lines
+ FLineMode: TVTLineMode; // tree lines or bands etc.
+ FDottedBrush: HBRUSH; // used to paint dotted lines without special pens
+ FSelectionCurveRadius: Cardinal; // radius for rounded selection rectangles
+ FSelectionBlendFactor: Byte; // Determines the factor by which the selection rectangle is to be
+ // faded if enabled.
+ FDrawSelectionMode: TVTDrawSelectionMode; // determines the paint mode for draw selection
+
+ // alignment and directionality support
+ FAlignment: TAlignment; // default alignment of the tree if no columns are shown
+
+ // drag'n drop and clipboard support
+ FDragImageKind: TVTDragImageKind; // determines whether or not and what to show in the drag image
+ FDragOperations: TDragOperations; // determines which operations are allowed during drag'n drop
+ FDragThreshold: Integer; // used to determine when to actually start a drag'n drop operation
+ FDragManager: IVTDragManager; // drag'n drop, cut'n paste
+ FDropTargetNode: PVirtualNode; // node currently selected as drop target
+ FLastDropMode: TDropMode; // set while dragging and used to track changes
+ FDragSelection: TNodeArray; // temporary copy of FSelection used during drag'n drop
+ FDragType: TVTDragType; // used to switch between OLE and VCL drag'n drop
+ FDragImage: TVTDragImage; // drag image management
+ FDragWidth,
+ FDragHeight: Integer; // size of the drag image, the larger the more CPU power is needed
+ FClipboardFormats: TClipboardFormats; // a list of clipboard format descriptions enabled for this tree
+ FLastVCLDragTarget: PVirtualNode; // A node cache for VCL drag'n drop (keywords: DragLeave on DragDrop).
+ FVCLDragEffect: Integer; // A cache for VCL drag'n drop to keep the current drop effect.
+
+ // scroll support
+ FScrollBarOptions: TScrollBarOptions; // common properties of horizontal and vertical scrollbar
+ FAutoScrollInterval: TAutoScrollInterval; // determines speed of auto scrolling
+ FAutoScrollDelay: Cardinal; // amount of milliseconds to wait until autoscrolling becomes active
+ FAutoExpandDelay: Cardinal; // amount of milliseconds to wait until a node is expanded if it is the
+ // drop target
+ FOffsetX,
+ FOffsetY: Integer; // determines left and top scroll offset
+ FRangeX,
+ FRangeY: Cardinal; // current virtual width and height of the tree
+
+ FDefaultPasteMode: TVTNodeAttachMode; // Used to determine where to add pasted nodes to.
+ FSingletonNodeArray: TNodeArray; // Contains only one element for quick addition of single nodes
+ // to the selection.
+ FDragScrollStart: Cardinal; // Contains the start time when a tree does auto scrolling as drop target.
+
+ // search
+ FIncrementalSearch: TVTIncrementalSearch; // Used to determine whether and how incremental search is to be used.
+ FSearchTimeout: Cardinal; // Number of milliseconds after which to stop incremental searching.
+ FSearchBuffer: WideString; // Collects a sequence of keypresses used to do incremental searching.
+ FLastSearchNode: PVirtualNode; // Reference to node which was last found as search fit.
+ FSearchDirection: TVTSearchDirection; // Direction to incrementally search the tree.
+ FSearchStart: TVTSearchStart; // Where to start iteration on each key press.
+
+ // miscellanous
+ FTotalInternalDataSize: Cardinal; // Cache of the sum of the necessary internal data size for all tree
+ // classes derived from this base class.
+ FPanningWindow: HWND; // Helper window for wheel panning
+ FPanningCursor: HCURSOR; // Current wheel panning cursor.
+ FPanningImage: TBitmap; // A little 32x32 bitmap to indicate the panning reference point.
+ FLastClickPos: TPoint; // Used for retained drag start and wheel mouse scrolling.
+
+ // common events
+ FOnChange: TVTChangeEvent; // selection change
+ FOnStructureChange: TVTStructureChangeEvent; // structural change like adding nodes etc.
+ FOnInitChildren: TVTInitChildrenEvent; // called when a node's children are needed (expanding etc.)
+ FOnInitNode: TVTInitNodeEvent; // called when a node needs to be initialized (child count etc.)
+ FOnFreeNode: TVTFreeNodeEvent; // called when a node is about to be destroyed, user data can and should
+ // be freed in this event
+ FOnGetImage: TVTGetImageEvent; // used to retrieve the image index of a given node
+ FOnHotChange: TVTHotNodeChangeEvent; // called when the current "hot" node (that is, the node under the mouse)
+ // changes and hot tracking is enabled
+ FOnExpanding, // called just before a node is expanded
+ FOnCollapsing: TVTChangingEvent; // called just before a node is collapsed
+ FOnChecking: TVTCheckChangingEvent; // called just before a node's check state is changed
+ FOnExpanded, // called after a node has been expanded
+ FOnCollapsed, // called after a node has been collapsed
+ FOnChecked: TVTChangeEvent; // called after a node's check state has been changed
+ FOnResetNode: TVTChangeEvent; // called when a node is set to be uninitialized
+ FOnNodeMoving: TVTNodeMovingEvent; // called just before a node is moved from one parent node to another
+ // (this can be cancelled)
+ FOnNodeMoved: TVTNodeMovedEvent; // called after a node and its children have been moved to another
+ // parent node (probably another tree, but within the same application)
+ FOnNodeCopying: TVTNodeCopyingEvent; // called when an node is copied to another parent node (probably in
+ // another tree, but within the same application, can be cancelled)
+ FOnNodeCopied: TVTNodeCopiedEvent; // call after a node has been copied
+ FOnEditing: TVTEditChangingEvent; // called just before a node goes into edit mode
+ FOnEditCancelled: TVTEditCancelEvent; // called when editing has been cancelled
+ FOnEdited: TVTEditChangeEvent; // called when editing has successfully been finished
+ FOnFocusChanging: TVTFocusChangingEvent; // called when the focus is about to go to a new node and/or column
+ // (can be cancelled)
+ FOnFocusChanged: TVTFocusChangeEvent; // called when the focus goes to a new node and/or column
+ FOnGetPopupMenu: TVTPopupEvent; // called when the popup for a node needs to be shown
+ FOnGetHelpContext: TVTHelpContextEvent; // called when a node specific help theme should be called
+ FOnCreateEditor: TVTCreateEditorEvent; // called when a node goes into edit mode, this allows applications
+ // to supply their own editor
+ FOnLoadNode, // called after a node has been loaded from a stream (file, clipboard,
+ // OLE drag'n drop) to allow an application to load their own data
+ // saved in OnSaveNode
+ FOnSaveNode: TVTSaveNodeEvent; // called when a node needs to be serialized into a stream
+ // (see OnLoadNode) to give the application the opportunity to save
+ // their node specific, persistent data (note: never save memory
+ // references)
+
+ // header/column mouse events
+ FOnHeaderClick, // mouse events for the header, just like those for a control
+ FOnHeaderDblClick: TVTHeaderClickEvent;
+ FOnHeaderMouseDown,
+ FOnHeaderMouseUp: TVTHeaderMouseEvent;
+ FOnHeaderMouseMove: TVTHeaderMouseMoveEvent;
+ FOnColumnClick: TVTColumnClickEvent;
+ FOnColumnDblClick: TVTColumnDblClickEvent;
+ FOnColumnResize: TVTHeaderNotifyEvent;
+ FOnGetHeaderCursor: TVTGetHeaderCursorEvent; // triggered to allow the app. to use customized cursors for the header
+
+ // paint events
+ FOnAfterPaint, // triggered when the tree has entirely been painted
+ FOnBeforePaint: TVTPaintEvent; // triggered when the tree is about to be painted
+ FOnAfterItemPaint: TVTAfterItemPaintEvent; // triggered after an item has been painted
+ FOnBeforeItemPaint: TVTBeforeItemPaintEvent; // triggered when an item is about to be painted
+ FOnBeforeItemErase: TVTBeforeItemEraseEvent; // triggered when an item's background is about to be erased
+ FOnAfterItemErase: TVTAfterItemEraseEvent; // triggered after an item's background has been erased
+ FOnAfterCellPaint: TVTAfterCellPaintEvent; // triggered after a column of an item has been painted
+ FOnBeforeCellPaint: TVTBeforeCellPaintEvent; // triggered when a column of an item is about to be painted
+ FOnHeaderDraw: TVTHeaderPaintEvent; // Used when owner draw is enabled for the header and a column is set
+ // to owner draw mode.
+ FOnHeaderDrawQueryElements: TVTHeaderPaintQueryElementsEvent; // Used for advanced header painting to query the
+ // application for the elements, which are drawn by it and which should
+ // be drawn by the tree.
+ FOnAdvancedHeaderDraw: TVTAdvancedHeaderPaintEvent; // Used when owner draw is enabled for the header and a column
+ // is set to owner draw mode. But only if OnHeaderDrawQueryElements
+ // returns at least one element to be drawn by the application.
+ // In this case OnHeaderDraw is not used.
+ FOnGetLineStyle: TVTGetLineStyleEvent; // triggered when a custom line style is used and the pattern brush
+ // needs to be build
+ FOnPaintBackground: TVTBackgroundPaintEvent; // triggered if a part of the tree's background must be erased which is
+ // not covered by any node
+
+ // drag'n drop events
+ FOnCreateDragManager: TVTCreateDragManagerEvent; // called to allow for app./descendant defined drag managers
+ FOnCreateDataObject: TVTCreateDataObjectEvent; // called to allow for app./descentant defined data objects
+ FOnDragAllowed: TVTDragAllowedEvent; // used to get permission for manual drag in mouse down
+ FOnDragOver: TVTDragOverEvent; // called for every mouse move
+ FOnDragDrop: TVTDragDropEvent; // called on release of mouse button (if drop was allowed)
+ FOnHeaderDragged: TVTHeaderDraggedEvent; // header (column) drag'n drop
+ FOnHeaderDraggedOut: TVTHeaderDraggedOutEvent; // header (column) drag'n drop, which did not result in a valid drop.
+ FOnHeaderDragging: TVTHeaderDraggingEvent; // header (column) drag'n drop
+ FOnRenderOLEData: TVTRenderOLEDataEvent; // application/descendant defined clipboard formats
+ FOnGetUserClipboardFormats: TVTGetUserClipboardFormatsEvent; // gives application/descentants the opportunity to
+ // add own clipboard formats on the fly
+
+ // miscellanous events
+ FOnGetNodeDataSize: TVTGetNodeDataSizeEvent; // called if NodeDataSize is -1
+ FOnKeyAction: TVTKeyActionEvent; // used to selectively prevent key actions (full expand on Ctrl+'+' etc.)
+ FOnScroll: TVTScrollEvent; // called when one or both paint offsets changed
+ FOnUpdating: TVTUpdatingEvent; // called from BeginUpdate, EndUpdate, BeginSynch and EndSynch
+ FOnGetCursor: TVTGetCursorEvent; // called to allow the app. to set individual cursors
+ FOnStateChange: TVTStateChangeEvent; // Called whenever a state in the tree changes.
+
+ // search, sort
+ FOnCompareNodes: TVTCompareEvent; // used during sort
+ FOnIncrementalSearch: TVTIncrementalSearchEvent; // triggered on every key press (not key down)
+
+ procedure AdjustCoordinatesByIndent(var PaintInfo: TVTPaintInfo; Indent: Integer);
+ procedure AdjustImageBorder(Images: TCustomImageList; BidiMode: TBidiMode; VAlign: Integer; var R: TRect;
+ var ImageInfo: TVTImageInfo);
+ procedure AdjustTotalCount(Node: PVirtualNode; Value: Integer; relative: Boolean = False);
+ procedure AdjustTotalHeight(Node: PVirtualNode; Value: Integer; relative: Boolean = False);
+ function CalculateCacheEntryCount: Integer;
+ procedure CalculateVerticalAlignments(ShowImages, ShowStateImages: Boolean; Node: PVirtualNode; var VAlign,
+ VButtonAlign: Integer);
+ function ChangeCheckState(Node: PVirtualNode; Value: TCheckState): Boolean;
+ function CollectSelectedNodesLTR(MainColumn, NodeLeft, NodeRight: Integer; Alignment: TAlignment; OldRect,
+ NewRect: TRect): Boolean;
+ function CollectSelectedNodesRTL(MainColumn, NodeLeft, NodeRight: Integer; Alignment: TAlignment; OldRect,
+ NewRect: TRect): Boolean;
+ procedure ClearNodeBackground(const PaintInfo: TVTPaintInfo; UseBackground, Floating: Boolean; R: TRect);
+ function CompareNodePositions(Node1, Node2: PVirtualNode): Integer;
+ procedure DrawLineImage(const PaintInfo: TVTPaintInfo; X, Y, H, VAlign: Integer; Style: TVTLineType; Reverse: Boolean);
+ function FindInPositionCache(Node: PVirtualNode; var CurrentPos: Cardinal): PVirtualNode; overload;
+ function FindInPositionCache(Position: Cardinal; var CurrentPos: Cardinal): PVirtualNode; overload;
+ function GetCheckState(Node: PVirtualNode): TCheckState;
+ function GetCheckType(Node: PVirtualNode): TCheckType;
+ function GetChildCount(Node: PVirtualNode): Cardinal;
+ function GetChildrenInitialized(Node: PVirtualNode): Boolean;
+ function GetDisabled(Node: PVirtualNode): Boolean;
+ function GetDragManager: IVTDragManager;
+ function GetExpanded(Node: PVirtualNode): Boolean;
+ function GetFullyVisible(Node: PVirtualNode): Boolean;
+ function GetHasChildren(Node: PVirtualNode): Boolean;
+ function GetMultiline(Node: PVirtualNode): Boolean;
+ function GetNodeHeight(Node: PVirtualNode): Cardinal;
+ function GetNodeParent(Node: PVirtualNode): PVirtualNode;
+ function GetOffsetXY: TPoint;
+ function GetRootNodeCount: Cardinal;
+ function GetSelected(Node: PVirtualNode): Boolean;
+ function GetTopNode: PVirtualNode;
+ function GetTotalCount: Cardinal;
+ function GetVerticalAlignment(Node: PVirtualNode): Byte;
+ function GetVisible(Node: PVirtualNode): Boolean;
+ function GetVisiblePath(Node: PVirtualNode): Boolean;
+ procedure HandleClickSelection(LastFocused, NewNode: PVirtualNode; Shift: TShiftState);
+ function HandleDrawSelection(X, Y: Integer): Boolean;
+ function HasVisibleNextSibling(Node: PVirtualNode): Boolean;
+ procedure ImageListChange(Sender: TObject);
+ procedure InitializeFirstColumnValues(var PaintInfo: TVTPaintInfo);
+ function InitializeLineImageAndSelectLevel(Node: PVirtualNode; var LineImage: TLineImage): Integer;
+ procedure InitRootNode(OldSize: Cardinal = 0);
+ procedure InterruptValidation;
+ function IsFirstVisibleChild(Parent, Node: PVirtualNode): Boolean;
+ function IsLastVisibleChild(Parent, Node: PVirtualNode): Boolean;
+ procedure LimitPaintingToArea(Canvas: TCanvas; ClipRect: TRect; VisibleRegion: HRGN = 0);
+ function MakeNewNode: PVirtualNode;
+ procedure OriginalWMNCPaint(DC: HDC);
+ function PackArray(TheArray: TNodeArray; Count: Integer): Integer;
+ procedure PrepareBitmaps(NeedButtons, NeedLines: Boolean);
+ procedure PrepareCell(var PaintInfo: TVTPaintInfo);
+ procedure ReadOldOptions(Reader: TReader);
+ procedure SetAlignment(const Value: TAlignment);
+ procedure SetAnimationDuration(const Value: Cardinal);
+ procedure SetBackground(const Value: TPicture);
+ procedure SetBackgroundOffset(const Index, Value: Integer);
+ procedure SetBorderStyle(Value: TBorderStyle);
+ procedure SetButtonFillMode(const Value: TVTButtonFillMode);
+ procedure SetButtonStyle(const Value: TVTButtonStyle);
+ procedure SetCheckImageKind(Value: TCheckImageKind);
+ procedure SetCheckState(Node: PVirtualNode; Value: TCheckState);
+ procedure SetCheckType(Node: PVirtualNode; Value: TCheckType);
+ procedure SetChildCount(Node: PVirtualNode; NewChildCount: Cardinal);
+ procedure SetClipboardFormats(const Value: TClipboardFormats);
+ procedure SetColors(const Value: TVTColors);
+ procedure SetCustomCheckImages(const Value: TCustomImageList);
+ procedure SetDefaultNodeHeight(Value: Cardinal);
+ procedure SetDisabled(Node: PVirtualNode; Value: Boolean);
+ procedure SetExpanded(Node: PVirtualNode; Value: Boolean);
+ procedure SetFocusedColumn(Value: TColumnIndex);
+ procedure SetFocusedNode(Value: PVirtualNode);
+ procedure SetFullyVisible(Node: PVirtualNode; Value: Boolean);
+ procedure SetHasChildren(Node: PVirtualNode; Value: Boolean);
+ procedure SetHeader(const Value: TVTHeader);
+ procedure SetImages(const Value: TCustomImageList);
+ procedure SetIndent(Value: Cardinal);
+ procedure SetLineMode(const Value: TVTLineMode);
+ procedure SetLineStyle(const Value: TVTLineStyle);
+ procedure SetMargin(Value: Integer);
+ procedure SetMultiline(Node: PVirtualNode; const Value: Boolean);
+ procedure SetNodeAlignment(const Value: TVTNodeAlignment);
+ procedure SetNodeDataSize(Value: Integer);
+ procedure SetNodeHeight(Node: PVirtualNode; Value: Cardinal);
+ procedure SetNodeParent(Node: PVirtualNode; const Value: PVirtualNode);
+ procedure SetOffsetX(const Value: Integer);
+ procedure SetOffsetXY(const Value: TPoint);
+ procedure SetOffsetY(const Value: Integer);
+ procedure SetOptions(const Value: TCustomVirtualTreeOptions);
+ procedure SetRootNodeCount(Value: Cardinal);
+ procedure SetScrollBarOptions(Value: TScrollBarOptions);
+ procedure SetSearchOption(const Value: TVTIncrementalSearch);
+ procedure SetSelected(Node: PVirtualNode; Value: Boolean);
+ procedure SetSelectionCurveRadius(const Value: Cardinal);
+ procedure SetStateImages(const Value: TCustomImageList);
+ procedure SetTextMargin(Value: Integer);
+ procedure SetTopNode(Node: PVirtualNode);
+ procedure SetUpdateState(Updating: Boolean);
+ procedure SetVerticalAlignment(Node: PVirtualNode; Value: Byte);
+ procedure SetVisible(Node: PVirtualNode; Value: Boolean);
+ procedure SetVisiblePath(Node: PVirtualNode; Value: Boolean);
+ procedure StopTimer(ID: Integer);
+ procedure TileBackground(Source: TBitmap; Target: TCanvas; Offset: TPoint; R: TRect);
+ function ToggleCallback(Step, StepSize: Integer; Data: Pointer): Boolean;
+
+ procedure CMColorChange(var Message: TMessage); message CM_COLORCHANGED;
+ procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
+ procedure CMDenySubclassing(var Message: TMessage); message CM_DENYSUBCLASSING;
+ procedure CMDrag(var Message: TCMDrag); message CM_DRAG;
+ procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
+ procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
+ procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW;
+ procedure CMHintShowPause(var Message: TCMHintShowPause); message CM_HINTSHOWPAUSE;
+ procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
+ procedure CMMouseWheel(var Message: TCMMouseWheel); message CM_MOUSEWHEEL;
+ procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
+ procedure WMCancelMode(var Message: TWMCancelMode); message WM_CANCELMODE;
+ procedure WMChangeState(var Message: TMessage); message WM_CHANGESTATE;
+ procedure WMChar(var Message: TWMChar); message WM_CHAR;
+ procedure WMContextMenu(var Message: TWMContextMenu); message WM_CONTEXTMENU;
+ procedure WMCopy(var Message: TWMCopy); message WM_COPY;
+ procedure WMCut(var Message: TWMCut); message WM_CUT;
+ procedure WMEnable(var Message: TWMEnable); message WM_ENABLE;
+ procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
+ procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
+ procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
+ procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
+ procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP;
+ procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
+ procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
+ procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
+ procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
+ procedure WMMButtonDblClk(var Message: TWMMButtonDblClk); message WM_MBUTTONDBLCLK;
+ procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN;
+ procedure WMMButtonUp(var Message: TWMMButtonUp); message WM_MBUTTONUP;
+ procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
+ procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY;
+ procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST;
+ procedure WMNCPaint(var Message: TRealWMNCPaint); message WM_NCPAINT;
+ procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
+ procedure WMPaste(var Message: TWMPaste); message WM_PASTE;
+ procedure WMPrint(var Message: TWMPrint); message WM_PRINT;
+ procedure WMPrintClient(var Message: TWMPrintClient); message WM_PRINTCLIENT;
+ procedure WMRButtonDblClk(var Message: TWMRButtonDblClk); message WM_RBUTTONDBLCLK;
+ procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
+ procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
+ procedure WMReleaseEditLink(var Message: TMessage); message WM_RELEASEEDITLINK;
+ procedure WMSetCursor(var Message: TWMSetCursor); message WM_SETCURSOR;
+ procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
+ procedure WMSize(var Message: TWMSize); message WM_SIZE;
+ procedure WMTimer(var Message: TWMTimer); message WM_TIMER;
+ procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
+ protected
+ procedure AddToSelection(Node: PVirtualNode); overload;
+ procedure AddToSelection(const NewItems: TNodeArray; NewLength: Integer; ForceInsert: Boolean = False); overload;
+ procedure AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex); virtual;
+ procedure AdjustPanningCursor(X, Y: Integer);
+ procedure AdviseChangeEvent(StructureChange: Boolean; Node: PVirtualNode; Reason: TChangeReason);
+ function AllocateInternalDataArea(Size: Cardinal): Cardinal;
+ procedure Animate(Steps, Duration: Cardinal; Callback: TVTAnimationCallback; Data: Pointer);
+ function CalculateSelectionRect(X, Y: Integer): Boolean;
+ function CanAutoScroll: Boolean; virtual;
+ function CanEdit(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual;
+ function CanShowDragImage: Boolean; virtual;
+ procedure Change(Node: PVirtualNode);
+ procedure ChangeScale(M, D: Integer); override;
+ function CheckParentCheckState(Node: PVirtualNode; NewCheckState: TCheckState): Boolean;
+ procedure ClearTempCache;
+ function ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual;
+ function CountLevelDifference(Node1, Node2: PVirtualNode): Integer;
+ function CountVisibleChildren(Node: PVirtualNode): Cardinal;
+ procedure CreateParams(var Params: TCreateParams); override;
+ procedure CreateWnd; override;
+ procedure DefineProperties(Filer: TFiler); override;
+ procedure DetermineHiddenChildrenFlag(Node: PVirtualNode);
+ procedure DetermineHiddenChildrenFlagAllNodes;
+ procedure DetermineHitPositionLTR(var HitInfo: THitInfo; Offset, Right: Integer; Alignment: TAlignment); virtual;
+ procedure DetermineHitPositionRTL(var HitInfo: THitInfo; Offset, Right: Integer; Alignment: TAlignment); virtual;
+ function DetermineNextCheckState(CheckType: TCheckType; CheckState: TCheckState): TCheckState; virtual;
+ function DetermineScrollDirections(X, Y: Integer): TScrollDirections;
+ procedure DoAdvancedHeaderDraw(var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements); virtual;
+ procedure DoAfterCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); virtual;
+ procedure DoAfterItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); virtual;
+ procedure DoAfterItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); virtual;
+ procedure DoAfterPaint(Canvas: TCanvas); virtual;
+ procedure DoAutoScroll(X, Y: Integer); virtual;
+ function DoBeforeDrag(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual;
+ procedure DoBeforeCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); virtual;
+ procedure DoBeforeItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect; var Color: TColor;
+ var EraseAction: TItemEraseAction); virtual;
+ function DoBeforeItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect): Boolean; virtual;
+ procedure DoBeforePaint(Canvas: TCanvas); virtual;
+ function DoCancelEdit: Boolean; virtual;
+ procedure DoCanEdit(Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); virtual;
+ procedure DoChange(Node: PVirtualNode); virtual;
+ procedure DoCheckClick(Node: PVirtualNode; NewCheckState: TCheckState); virtual;
+ procedure DoChecked(Node: PVirtualNode); virtual;
+ function DoChecking(Node: PVirtualNode; var NewCheckState: TCheckState): Boolean; virtual;
+ procedure DoCollapsed(Node: PVirtualNode); virtual;
+ function DoCollapsing(Node: PVirtualNode): Boolean; virtual;
+ procedure DoColumnClick(Column: TColumnIndex; Shift: TShiftState); virtual;
+ procedure DoColumnDblClick(Column: TColumnIndex; Shift: TShiftState); virtual;
+ procedure DoColumnResize(Column: TColumnIndex); virtual;
+ function DoCompare(Node1, Node2: PVirtualNode; Column: TColumnIndex): Integer; virtual;
+ function DoCreateDataObject: IDataObject; virtual;
+ function DoCreateDragManager: IVTDragManager; virtual;
+ function DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; virtual;
+ procedure DoDragging(P: TPoint);
+ procedure DoDragExpand;
+ function DoDragOver(Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode;
+ var Effect: Integer): Boolean; virtual;
+ procedure DoDragDrop(Source: TObject; DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState; Pt: TPoint;
+ var Effect: Integer; Mode: TDropMode); virtual;
+ procedure DoEdit; virtual;
+ procedure DoEndDrag(Target: TObject; X, Y: Integer); override;
+ function DoEndEdit: Boolean; virtual;
+ procedure DoExpanded(Node: PVirtualNode); virtual;
+ function DoExpanding(Node: PVirtualNode): Boolean; virtual;
+ procedure DoFocusChange(Node: PVirtualNode; Column: TColumnIndex); virtual;
+ function DoFocusChanging(OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex): Boolean; virtual;
+ procedure DoFocusNode(Node: PVirtualNode; Ask: Boolean); virtual;
+ procedure DoFreeNode(Node: PVirtualNode); virtual;
+ function DoGetAnimationType: THintAnimationType; virtual;
+ procedure DoGetCursor(var Cursor: TCursor); virtual;
+ procedure DoGetHeaderCursor(var Cursor: HCURSOR); virtual;
+ procedure DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer); virtual;
+ procedure DoGetLineStyle(var Bits: Pointer); virtual;
+ function DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex): WideString; virtual;
+ function DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex): WideString; virtual;
+ function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer; virtual;
+ function DoGetPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint): TPopupMenu; virtual;
+ procedure DoGetUserClipboardFormats(var Formats: TFormatEtcArray); virtual;
+ procedure DoHeaderClick(Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHeaderDblClick(Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHeaderDragged(Column: TColumnIndex; OldPosition: TColumnPosition); virtual;
+ procedure DoHeaderDraggedOut(Column: TColumnIndex; DropPosition: TPoint); virtual;
+ function DoHeaderDragging(Column: TColumnIndex): Boolean; virtual;
+ procedure DoHeaderDraw(Canvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover, Pressed: Boolean;
+ DropMark: TVTDropMarkMode); virtual;
+ procedure DoHeaderDrawQueryElements(var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements); virtual;
+ procedure DoHeaderMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHeaderMouseMove(Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHeaderMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual;
+ procedure DoHotChange(Old, New: PVirtualNode); virtual;
+ function DoIncrementalSearch(Node: PVirtualNode; const Text: WideString): Integer; virtual;
+ procedure DoInitChildren(Node: PVirtualNode; var ChildCount: Cardinal); virtual;
+ procedure DoInitNode(Parent, Node: PVirtualNode; var InitStates: TVirtualNodeInitStates); virtual;
+ function DoKeyAction(var CharCode: Word; var Shift: TShiftState): Boolean; virtual;
+ procedure DoLoadUserData(Node: PVirtualNode; Stream: TStream); virtual;
+ procedure DoNodeCopied(Node: PVirtualNode); virtual;
+ function DoNodeCopying(Node, NewParent: PVirtualNode): Boolean; virtual;
+ procedure DoNodeMoved(Node: PVirtualNode); virtual;
+ function DoNodeMoving(Node, NewParent: PVirtualNode): Boolean; virtual;
+ function DoPaintBackground(Canvas: TCanvas; R: TRect): Boolean; virtual;
+ procedure DoPaintDropMark(Canvas: TCanvas; Node: PVirtualNode; R: TRect); virtual;
+ procedure DoPaintNode(var PaintInfo: TVTPaintInfo); virtual;
+ procedure DoPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint); virtual;
+ function DoRenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean): HRESULT; virtual;
+ procedure DoReset(Node: PVirtualNode); virtual;
+ procedure DoSaveUserData(Node: PVirtualNode; Stream: TStream); virtual;
+ procedure DoScroll(DeltaX, DeltaY: Integer); virtual;
+ function DoSetOffsetXY(Value: TPoint; Options: TScrollUpdateOptions; ClipRect: PRect = nil): Boolean; virtual;
+ procedure DoStartDrag(var DragObject: TDragObject); override;
+ procedure DoStateChange(Enter: TVirtualTreeStates; Leave: TVirtualTreeStates = []); virtual;
+ procedure DoStructureChange(Node: PVirtualNode; Reason: TChangeReason); virtual;
+ procedure DoTimerScroll;
+ procedure DoUpdating(State: TVTUpdateState); virtual;
+ function DoValidateCache: Boolean;
+ procedure DragCanceled; override;
+ function DragDrop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult; reintroduce; virtual;
+ function DragEnter(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult; virtual;
+ procedure DragFinished;
+ procedure DragLeave; virtual;
+ function DragOver(Source: TObject; KeyState: Integer; DragState: TDragState; Pt: TPoint;
+ var Effect: Integer): HResult; reintroduce; virtual;
+ procedure DrawDottedHLine(const PaintInfo: TVTPaintInfo; Left, Right, Top: Integer);
+ procedure DrawDottedVLine(const PaintInfo: TVTPaintInfo; Top, Bottom, Left: Integer);
+ function FindNodeInSelection(P: PVirtualNode; var Index: Integer; LowBound, HighBound: Integer): Boolean;
+ procedure FinishChunkHeader(Stream: TStream; StartPos, EndPos: Integer);
+ procedure FontChanged(AFont: TObject);
+ function GetCheckImage(Node: PVirtualNode): Integer; virtual;
+ function GetColumnClass: TVirtualTreeColumnClass; virtual;
+ function GetHeaderClass: TVTHeaderClass; virtual;
+ function GetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean): Integer;
+ function GetMaxRightExtend: Cardinal;
+ procedure GetNativeClipboardFormats(var Formats: TFormatEtcArray); virtual;
+ function GetOptionsClass: TTreeOptionsClass; virtual;
+ procedure GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect;
+ var Text: WideString); virtual;
+ function GetTreeFromDataObject(const DataObject: IDataObject): TBaseVirtualTree;
+ procedure HandleHotTrack(X, Y: Integer);
+ procedure HandleIncrementalSearch(CharCode: Word);
+ procedure HandleMouseDblClick(var Message: TWMMouse; const HitInfo: THitInfo);
+ procedure HandleMouseDown(var Message: TWMMouse; const HitInfo: THitInfo);
+ procedure HandleMouseUp(var Message: TWMMouse; const HitInfo: THitInfo);
+ function HasPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Pos: TPoint): Boolean; virtual;
+ procedure InitChildren(Node: PVirtualNode);
+ procedure InitNode(Node: PVirtualNode);
+ procedure InternalAddFromStream(Stream: TStream; Version: Integer; Node: PVirtualNode);
+ function InternalAddToSelection(Node: PVirtualNode; ForceInsert: Boolean): Boolean; overload;
+ function InternalAddToSelection(const NewItems: TNodeArray; NewLength: Integer;
+ ForceInsert: Boolean): Boolean; overload;
+ procedure InternalCacheNode(Node: PVirtualNode);
+ procedure InternalClearSelection;
+ procedure InternalConnectNode(Node, Destination: PVirtualNode; Target: TBaseVirtualTree; Mode: TVTNodeAttachMode);
+ function InternalData(Node: PVirtualNode): Pointer;
+ procedure InternalDisconnectNode(Node: PVirtualNode; KeepFocus: Boolean; Reindex: Boolean = True);
+ procedure InternalRemoveFromSelection(Node: PVirtualNode);
+ procedure InvalidateCache;
+ procedure Loaded; override;
+ procedure MainColumnChanged; virtual;
+ procedure MarkCutCopyNodes;
+ procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
+ procedure Notification(AComponent: TComponent; Operation: TOperation); override;
+ procedure Paint; override;
+ procedure PaintCheckImage(const PaintInfo: TVTPaintInfo); virtual;
+ procedure PaintImage(const PaintInfo: TVTPaintInfo; ImageInfoIndex: TVTImageInfoIndex; Images: TCustomImageList;
+ DoOverlay: Boolean); virtual;
+ procedure PaintNodeButton(Canvas: TCanvas; Node: PVirtualNode; const R: TRect; ButtonX, ButtonY: Integer;
+ BidiMode: TBiDiMode); virtual;
+ procedure PaintTreeLines(const PaintInfo: TVTPaintInfo; VAlignment, IndentSize: Integer;
+ LineImage: TLineImage); virtual;
+ procedure PaintSelectionRectangle(Target: TCanvas; WindowOrgX: Integer; const SelectionRect: TRect;
+ TargetRect: TRect);
+ procedure PanningWindowProc(var Message: TMessage);
+ function ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType,
+ ChunkSize: Integer): Boolean; virtual;
+ procedure ReadNode(Stream: TStream; Version: Integer; Node: PVirtualNode); virtual;
+ procedure RedirectFontChangeEvent(Canvas: TCanvas);
+ procedure RemoveFromSelection(Node: PVirtualNode);
+ function RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HResult; virtual;
+ procedure ResetRangeAnchor;
+ procedure RestoreFontChangeEvent(Canvas: TCanvas);
+ procedure SelectNodes(StartNode, EndNode: PVirtualNode; AddOnly: Boolean);
+ procedure SetBiDiMode(Value: TBiDiMode); override;
+ procedure SkipNode(Stream: TStream); virtual;
+ procedure StartWheelPanning(Position: TPoint);
+ procedure StopWheelPanning;
+ procedure StructureChange(Node: PVirtualNode; Reason: TChangeReason);
+ function SuggestDropEffect(Source: TObject; Shift: TShiftState; Pt: TPoint; AllowedEffects: Integer): Integer; virtual;
+ procedure ToggleSelection(StartNode, EndNode: PVirtualNode);
+ procedure UnselectNodes(StartNode, EndNode: PVirtualNode);
+ procedure UpdateDesigner;
+ procedure UpdateEditBounds;
+ procedure UpdateHeaderRect;
+ procedure UpdateWindowAndDragImage(const Tree: TBaseVirtualTree; TreeRect: TRect; UpdateNCArea,
+ ReshowDragImage: Boolean);
+ procedure ValidateCache;
+ procedure ValidateNodeDataSize(var Size: Integer); virtual;
+ procedure WndProc(var Message: TMessage); override;
+ procedure WriteChunks(Stream: TStream; Node: PVirtualNode); virtual;
+ procedure WriteNode(Stream: TStream; Node: PVirtualNode);
+
+ property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
+ property AnimationDuration: Cardinal read FAnimationDuration write SetAnimationDuration default 200;
+ property AutoExpandDelay: Cardinal read FAutoExpandDelay write FAutoExpandDelay default 1000;
+ property AutoScrollDelay: Cardinal read FAutoScrollDelay write FAutoScrollDelay default 1000;
+ property AutoScrollInterval: TAutoScrollInterval read FAutoScrollInterval write FAutoScrollInterval default 1;
+ property Background: TPicture read FBackground write SetBackground;
+ property BackgroundOffsetX: Integer index 0 read FBackgroundOffsetX write SetBackgroundOffset default 0;
+ property BackgroundOffsetY: Integer index 1 read FBackgroundOffsetY write SetBackgroundOffset default 0;
+ property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
+ property ButtonFillMode: TVTButtonFillMode read FButtonFillMode write SetButtonFillMode default fmTreeColor;
+ property ButtonStyle: TVTButtonStyle read FButtonStyle write SetButtonStyle default bsRectangle;
+ property ChangeDelay: Cardinal read FChangeDelay write FChangeDelay default 0;
+ property CheckImageKind: TCheckImageKind read FCheckImageKind write SetCheckImageKind default ckLightCheck;
+ property ClipboardFormats: TClipboardFormats read FClipboardFormats write SetClipboardFormats;
+ property Colors: TVTColors read FColors write SetColors;
+ property CustomCheckImages: TCustomImageList read FCustomCheckImages write SetCustomCheckImages;
+ property DefaultNodeHeight: Cardinal read FDefaultNodeHeight write SetDefaultNodeHeight default 18;
+ property DefaultPasteMode: TVTNodeAttachMode read FDefaultPasteMode write FDefaultPasteMode default amAddChildLast;
+ property DragHeight: Integer read FDragHeight write FDragHeight default 350;
+ property DragImageKind: TVTDragImageKind read FDragImageKind write FDragImageKind default diComplete;
+ property DragOperations: TDragOperations read FDragOperations write FDragOperations default [doCopy, doMove];
+ property DragSelection: TNodeArray read FDragSelection;
+ property DragType: TVTDragType read FDragType write FDragType default dtOLE;
+ property DragWidth: Integer read FDragWidth write FDragWidth default 200;
+ property DrawSelectionMode: TVTDrawSelectionMode read FDrawSelectionMode write FDrawSelectionMode
+ default smDottedRectangle;
+ property EditDelay: Cardinal read FEditDelay write FEditDelay default 1000;
+ property Header: TVTHeader read FHeader write SetHeader;
+ property HeaderRect: TRect read FHeaderRect;
+ property HintAnimation: THintAnimationType read FAnimationType write FAnimationType default hatSystemDefault;
+ property HintMode: TVTHintMode read FHintMode write FHintMode default hmDefault;
+ property HotCursor: TCursor read FHotCursor write FHotCursor default crDefault;
+ property Images: TCustomImageList read FImages write SetImages;
+ property IncrementalSearch: TVTIncrementalSearch read FIncrementalSearch write SetSearchOption default isNone;
+ property IncrementalSearchDirection: TVTSearchDirection read FSearchDirection write FSearchDirection default sdForward;
+ property IncrementalSearchStart: TVTSearchStart read FSearchStart write FSearchStart default ssFocusedNode;
+ property IncrementalSearchTimeout: Cardinal read FSearchTimeout write FSearchTimeout default 1000;
+ property Indent: Cardinal read FIndent write SetIndent default 18;
+ property LastDropMode: TDropMode read FLastDropMode write FlastDropMode;
+ property LineMode: TVTLineMode read FLineMode write SetLineMode default lmNormal;
+ property LineStyle: TVTLineStyle read FLineStyle write SetLineStyle default lsDotted;
+ property Margin: Integer read FMargin write SetMargin default 4;
+ property NodeAlignment: TVTNodeAlignment read FNodeAlignment write SetNodeAlignment default naProportional;
+ property NodeDataSize: Integer read FNodeDataSize write SetNodeDataSize default -1;
+ property RootNodeCount: Cardinal read GetRootNodeCount write SetRootNodeCount default 0;
+ property ScrollBarOptions: TScrollBarOptions read FScrollBarOptions write SetScrollBarOptions;
+ property SelectionBlendFactor: Byte read FSelectionBlendFactor write FSelectionBlendFactor default 128;
+ property SelectionCurveRadius: Cardinal read FSelectionCurveRadius write SetSelectionCurveRadius default 0;
+ property StateImages: TCustomImageList read FStateImages write SetStateImages;
+ property TextMargin: Integer read FTextMargin write SetTextMargin default 4;
+ property TotalInternalDataSize: Cardinal read FTotalInternalDataSize;
+ property TreeOptions: TCustomVirtualTreeOptions read FOptions write SetOptions;
+ property WantTabs: Boolean read FWantTabs write FWantTabs default False;
+
+ property OnAdvancedHeaderDraw: TVTAdvancedHeaderPaintEvent read FOnAdvancedHeaderDraw write FOnAdvancedHeaderDraw;
+ property OnAfterCellPaint: TVTAfterCellPaintEvent read FOnAfterCellPaint write FOnAfterCellPaint;
+ property OnAfterItemErase: TVTAfterItemEraseEvent read FOnAfterItemErase write FOnAfterItemErase;
+ property OnAfterItemPaint: TVTAfterItemPaintEvent read FOnAfterItemPaint write FOnAfterItemPaint;
+ property OnAfterPaint: TVTPaintEvent read FOnAfterPaint write FOnAfterPaint;
+ property OnBeforeCellPaint: TVTBeforeCellPaintEvent read FOnBeforeCellPaint write FOnBeforeCellPaint;
+ property OnBeforeItemErase: TVTBeforeItemEraseEvent read FOnBeforeItemErase write FOnBeforeItemErase;
+ property OnBeforeItemPaint: TVTBeforeItemPaintEvent read FOnBeforeItemPaint write FOnBeforeItemPaint;
+ property OnBeforePaint: TVTPaintEvent read FOnBeforePaint write FOnBeforePaint;
+ property OnChange: TVTChangeEvent read FOnChange write FOnChange;
+ property OnChecked: TVTChangeEvent read FOnChecked write FOnChecked;
+ property OnChecking: TVTCheckChangingEvent read FOnChecking write FOnChecking;
+ property OnCollapsed: TVTChangeEvent read FOnCollapsed write FOnCollapsed;
+ property OnCollapsing: TVTChangingEvent read FOnCollapsing write FOnCollapsing;
+ property OnColumnClick: TVTColumnClickEvent read FOnColumnClick write FOnColumnClick;
+ property OnColumnDblClick: TVTColumnDblClickEvent read FOnColumnDblClick write FOnColumnDblClick;
+ property OnColumnResize: TVTHeaderNotifyEvent read FOnColumnResize write FOnColumnResize;
+ property OnCompareNodes: TVTCompareEvent read FOnCompareNodes write FOnCompareNodes;
+ property OnCreateDataObject: TVTCreateDataObjectEvent read FOnCreateDataObject write FOnCreateDataObject;
+ property OnCreateDragManager: TVTCreateDragManagerEvent read FOnCreateDragManager write FOnCreateDragManager;
+ property OnCreateEditor: TVTCreateEditorEvent read FOnCreateEditor write FOnCreateEditor;
+ property OnDragAllowed: TVTDragAllowedEvent read FOnDragAllowed write FOnDragAllowed;
+ property OnDragOver: TVTDragOverEvent read FOnDragOver write FOnDragOver;
+ property OnDragDrop: TVTDragDropEvent read FOnDragDrop write FOnDragDrop;
+ property OnEditCancelled: TVTEditCancelEvent read FOnEditCancelled write FOnEditCancelled;
+ property OnEditing: TVTEditChangingEvent read FOnEditing write FOnEditing;
+ property OnEdited: TVTEditChangeEvent read FOnEdited write FOnEdited;
+ property OnExpanded: TVTChangeEvent read FOnExpanded write FOnExpanded;
+ property OnExpanding: TVTChangingEvent read FOnExpanding write FOnExpanding;
+ property OnFocusChanged: TVTFocusChangeEvent read FOnFocusChanged write FOnFocusChanged;
+ property OnFocusChanging: TVTFocusChangingEvent read FOnFocusChanging write FOnFocusChanging;
+ property OnFreeNode: TVTFreeNodeEvent read FOnFreeNode write FOnFreeNode;
+ property OnGetCursor: TVTGetCursorEvent read FOnGetCursor write FOnGetCursor;
+ property OnGetHeaderCursor: TVTGetHeaderCursorEvent read FOnGetHeaderCursor write FOnGetHeaderCursor;
+ property OnGetHelpContext: TVTHelpContextEvent read FOnGetHelpContext write FOnGetHelpContext;
+ property OnGetImageIndex: TVTGetImageEvent read FOnGetImage write FOnGetImage;
+ property OnGetLineStyle: TVTGetLineStyleEvent read FOnGetLineStyle write FOnGetLineStyle;
+ property OnGetNodeDataSize: TVTGetNodeDataSizeEvent read FOnGetNodeDataSize write FOnGetNodeDataSize;
+ property OnGetPopupMenu: TVTPopupEvent read FOnGetPopupMenu write FOnGetPopupMenu;
+ property OnGetUserClipboardFormats: TVTGetUserClipboardFormatsEvent read FOnGetUserClipboardFormats
+ write FOnGetUserClipboardFormats;
+ property OnHeaderClick: TVTHeaderClickEvent read FOnHeaderClick write FOnHeaderClick;
+ property OnHeaderDblClick: TVTHeaderClickEvent read FOnHeaderDblClick write FOnHeaderDblClick;
+ property OnHeaderDragged: TVTHeaderDraggedEvent read FOnHeaderDragged write FOnHeaderDragged;
+ property OnHeaderDraggedOut: TVTHeaderDraggedOutEvent read FOnHeaderDraggedOut write FOnHeaderDraggedOut;
+ property OnHeaderDragging: TVTHeaderDraggingEvent read FOnHeaderDragging write FOnHeaderDragging;
+ property OnHeaderDraw: TVTHeaderPaintEvent read FOnHeaderDraw write FOnHeaderDraw;
+ property OnHeaderDrawQueryElements: TVTHeaderPaintQueryElementsEvent read FOnHeaderDrawQueryElements
+ write FOnHeaderDrawQueryElements;
+ property OnHeaderMouseDown: TVTHeaderMouseEvent read FOnHeaderMouseDown write FOnHeaderMouseDown;
+ property OnHeaderMouseMove: TVTHeaderMouseMoveEvent read FOnHeaderMouseMove write FOnHeaderMouseMove;
+ property OnHeaderMouseUp: TVTHeaderMouseEvent read FOnHeaderMouseUp write FOnHeaderMouseUp;
+ property OnHotChange: TVTHotNodeChangeEvent read FOnHotChange write FOnHotChange;
+ property OnIncrementalSearch: TVTIncrementalSearchEvent read FOnIncrementalSearch write FOnIncrementalSearch;
+ property OnInitChildren: TVTInitChildrenEvent read FOnInitChildren write FOnInitChildren;
+ property OnInitNode: TVTInitNodeEvent read FOnInitNode write FOnInitNode;
+ property OnKeyAction: TVTKeyActionEvent read FOnKeyAction write FOnKeyAction;
+ property OnLoadNode: TVTSaveNodeEvent read FOnLoadNode write FOnLoadNode;
+ property OnNodeCopied: TVTNodeCopiedEvent read FOnNodeCopied write FOnNodeCopied;
+ property OnNodeCopying: TVTNodeCopyingEvent read FOnNodeCopying write FOnNodeCopying;
+ property OnNodeMoved: TVTNodeMovedEvent read FOnNodeMoved write FOnNodeMoved;
+ property OnNodeMoving: TVTNodeMovingEvent read FOnNodeMoving write FOnNodeMoving;
+ property OnPaintBackground: TVTBackgroundPaintEvent read FOnPaintBackground write FOnPaintBackground;
+ property OnRenderOLEData: TVTRenderOLEDataEvent read FOnRenderOLEData write FOnRenderOLEData;
+ property OnResetNode: TVTChangeEvent read FOnResetNode write FOnResetNode;
+ property OnSaveNode: TVTSaveNodeEvent read FOnSaveNode write FOnSaveNode;
+ property OnScroll: TVTScrollEvent read FOnScroll write FOnScroll;
+ property OnStateChange: TVTStateChangeEvent read FOnStateChange write FOnStateChange;
+ property OnStructureChange: TVTStructureChangeEvent read FOnStructureChange write FOnStructureChange;
+ property OnUpdating: TVTUpdatingEvent read FOnUpdating write FOnUpdating;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+
+ function AbsoluteIndex(Node: PVirtualNode): Cardinal;
+ function AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode;
+ procedure AddFromStream(Stream: TStream; TargetNode: PVirtualNode);
+ procedure AfterConstruction; override;
+ procedure Assign(Source: TPersistent); override;
+ procedure BeginDrag(Immediate: Boolean; Threshold: Integer = -1);
+ procedure BeginSynch;
+ procedure BeginUpdate;
+ procedure CancelCutOrCopy;
+ function CancelEditNode: Boolean;
+ function CanFocus: Boolean; {$ifdef COMPILER_5_UP} override;{$endif}
+ procedure Clear; virtual;
+ procedure ClearSelection;
+ function CopyTo(Source: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean): PVirtualNode; overload;
+ function CopyTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean): PVirtualNode; overload;
+ procedure CopyToClipBoard; virtual;
+ procedure CutToClipBoard; virtual;
+ procedure DeleteChildren(Node: PVirtualNode; ResetHasChildren: Boolean = False);
+ procedure DeleteNode(Node: PVirtualNode; Reindex: Boolean = True);
+ procedure DeleteSelectedNodes; virtual;
+ function Dragging: Boolean;
+ function EditNode(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual;
+ function EndEditNode: Boolean;
+ procedure EndSynch;
+ procedure EndUpdate;
+ function ExecuteAction(Action: TBasicAction): Boolean; override;
+ procedure FinishCutOrCopy;
+ procedure FlushClipboard;
+ procedure FullCollapse(Node: PVirtualNode = nil); virtual;
+ procedure FullExpand(Node: PVirtualNode = nil); virtual;
+ function GetControlsAlignment: TAlignment; override;
+ function GetDisplayRect(Node: PVirtualNode; Column: TColumnIndex; TextOnly: Boolean; Unclipped: Boolean = False): TRect;
+ function GetFirst: PVirtualNode;
+ function GetFirstChild(Node: PVirtualNode): PVirtualNode;
+ function GetFirstCutCopy: PVirtualNode;
+ function GetFirstInitialized: PVirtualNode;
+ function GetFirstNoInit: PVirtualNode;
+ function GetFirstSelected: PVirtualNode;
+ function GetFirstVisible: PVirtualNode;
+ function GetFirstVisibleChild(Node: PVirtualNode): PVirtualNode;
+ function GetFirstVisibleChildNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetFirstVisibleNoInit: PVirtualNode;
+ procedure GetHitTestInfoAt(X, Y: Integer; Relative: Boolean; var HitInfo: THitInfo);
+ function GetLast(Node: PVirtualNode = nil): PVirtualNode;
+ function GetLastInitialized(Node: PVirtualNode = nil): PVirtualNode;
+ function GetLastNoInit(Node: PVirtualNode = nil): PVirtualNode;
+ function GetLastChild(Node: PVirtualNode): PVirtualNode;
+ function GetLastChildNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetLastVisible(Node: PVirtualNode = nil): PVirtualNode;
+ function GetLastVisibleChild(Node: PVirtualNode): PVirtualNode;
+ function GetLastVisibleChildNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetLastVisibleNoInit(Node: PVirtualNode = nil): PVirtualNode;
+ function GetMaxColumnWidth(Column: TColumnIndex): Integer;
+ function GetNext(Node: PVirtualNode): PVirtualNode;
+ function GetNextCutCopy(Node: PVirtualNode): PVirtualNode;
+ function GetNextInitialized(Node: PVirtualNode): PVirtualNode;
+ function GetNextNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetNextSelected(Node: PVirtualNode): PVirtualNode;
+ function GetNextSibling(Node: PVirtualNode): PVirtualNode;
+ function GetNextVisible(Node: PVirtualNode): PVirtualNode;
+ function GetNextVisibleNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetNextVisibleSibling(Node: PVirtualNode): PVirtualNode;
+ function GetNextVisibleSiblingNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetNodeAt(X, Y: Integer): PVirtualNode; overload;
+ function GetNodeAt(X, Y: Integer; Relative: Boolean; var NodeTop: Integer): PVirtualNode; overload;
+ function GetNodeData(Node: PVirtualNode): Pointer;
+ function GetNodeLevel(Node: PVirtualNode): Cardinal;
+ function GetPrevious(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousInitialized(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousSibling(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousVisible(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousVisibleNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousVisibleSibling(Node: PVirtualNode): PVirtualNode;
+ function GetPreviousVisibleSiblingNoInit(Node: PVirtualNode): PVirtualNode;
+ function GetSortedCutCopySet(Resolve: Boolean): TNodeArray;
+ function GetSortedSelection(Resolve: Boolean): TNodeArray;
+ function GetTreeRect: TRect;
+ function GetVisibleParent(Node: PVirtualNode): PVirtualNode;
+ function HasAsParent(Node, PotentialParent: PVirtualNode): Boolean;
+ function InsertNode(Node: PVirtualNode; Mode: TVTNodeAttachMode; UserData: Pointer = nil): PVirtualNode;
+ procedure InvalidateChildren(Node: PVirtualNode; Recursive: Boolean);
+ procedure InvalidateColumn(Column: TColumnIndex);
+ function InvalidateNode(Node: PVirtualNode): TRect; virtual;
+ procedure InvalidateToBottom(Node: PVirtualNode);
+ procedure InvertSelection(VisibleOnly: Boolean);
+ function IsEditing: Boolean;
+ function IsMouseSelecting: Boolean;
+ function IterateSubtree(Node: PVirtualNode; Callback: TVTGetNodeProc; Data: Pointer; Filter: TVirtualNodeStates = [];
+ DoInit: Boolean = False; ChildNodesOnly: Boolean = False): PVirtualNode;
+ procedure LoadFromFile(const FileName: TFileName); virtual;
+ procedure LoadFromStream(Stream: TStream); virtual;
+ procedure MoveTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; ChildrenOnly: Boolean); overload;
+ procedure MoveTo(Node: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean); overload;
+ procedure PaintTree(TargetCanvas: TCanvas; Window: TRect; Target: TPoint; PaintOptions: TVTInternalPaintOptions);
+ function PasteFromClipboard: Boolean; virtual;
+ procedure PrepareDragImage(HotSpot: TPoint; const DataObject: IDataObject);
+ procedure Print(Printer: TPrinter; PrintHeader: Boolean);
+ function ProcessDrop(DataObject: IDataObject; TargetNode: PVirtualNode; var Effect: Integer; Mode:
+ TVTNodeAttachMode): Boolean;
+ function ProcessOLEData(Source: TBaseVirtualTree; DataObject: IDataObject; TargetNode: PVirtualNode;
+ Mode: TVTNodeAttachMode; Optimized: Boolean): Boolean;
+ procedure RepaintNode(Node: PVirtualNode);
+ procedure ReinitChildren(Node: PVirtualNode; Recursive: Boolean); virtual;
+ procedure ReinitNode(Node: PVirtualNode; Recursive: Boolean); virtual;
+ procedure ResetNode(Node: PVirtualNode); virtual;
+ procedure SaveToFile(const FileName: TFileName);
+ procedure SaveToStream(Stream: TStream; Node: PVirtualNode = nil); virtual;
+ function ScrollIntoView(Node: PVirtualNode; Center: Boolean; Horizontally: Boolean = False): Boolean;
+ procedure SelectAll(VisibleOnly: Boolean);
+ procedure Sort(Node: PVirtualNode; Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True); virtual;
+ procedure SortTree(Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True);
+ procedure ToggleNode(Node: PVirtualNode);
+ function UpdateAction(Action: TBasicAction): Boolean; override;
+ procedure UpdateHorizontalScrollBar(DoRepaint: Boolean);
+ procedure UpdateScrollBars(DoRepaint: Boolean); virtual;
+ procedure UpdateVerticalScrollBar(DoRepaint: Boolean);
+ function UseRightToLeftReading: Boolean;
+ procedure ValidateChildren(Node: PVirtualNode; Recursive: Boolean);
+ procedure ValidateNode(Node: PVirtualNode; Recursive: Boolean);
+
+ property CheckState[Node: PVirtualNode]: TCheckState read GetCheckState write SetCheckState;
+ property CheckType[Node: PVirtualNode]: TCheckType read GetCheckType write SetCheckType;
+ property ChildCount[Node: PVirtualNode]: Cardinal read GetChildCount write SetChildCount;
+ property ChildrenInitialized[Node: PVirtualNode]: Boolean read GetChildrenInitialized;
+ property DragImage: TVTDragImage read FDragImage;
+ property DragManager: IVTDragManager read GetDragManager;
+ property DropTargetNode: PVirtualNode read FDropTargetNode;
+ property EditLink: IVTEditLink read FEditLink;
+ property Expanded[Node: PVirtualNode]: Boolean read GetExpanded write SetExpanded;
+ property FocusedColumn: TColumnIndex read FFocusedColumn write SetFocusedColumn default InvalidColumn;
+ property FocusedNode: PVirtualNode read FFocusedNode write SetFocusedNode;
+ property Font;
+ property FullyVisible[Node: PVirtualNode]: Boolean read GetFullyVisible write SetFullyVisible;
+ property HasChildren[Node: PVirtualNode]: Boolean read GetHasChildren write SetHasChildren;
+ property HotNode: PVirtualNode read FCurrentHotNode;
+ property IsDisabled[Node: PVirtualNode]: Boolean read GetDisabled write SetDisabled;
+ property IsVisible[Node: PVirtualNode]: Boolean read GetVisible write SetVisible;
+ property MultiLine[Node: PVirtualNode]: Boolean read GetMultiline write SetMultiline;
+ property NodeHeight[Node: PVirtualNode]: Cardinal read GetNodeHeight write SetNodeHeight;
+ property NodeParent[Node: PVirtualNode]: PVirtualNode read GetNodeParent write SetNodeParent;
+ property OffsetX: Integer read FOffsetX write SetOffsetX;
+ property OffsetXY: TPoint read GetOffsetXY write SetOffsetXY;
+ property OffsetY: Integer read FOffsetY write SetOffsetY;
+ property RootNode: PVirtualNode read FRoot;
+ property SearchBuffer: WideString read FSearchBuffer;
+ property Selected[Node: PVirtualNode]: Boolean read GetSelected write SetSelected;
+ property TotalCount: Cardinal read GetTotalCount;
+ property TreeStates: TVirtualTreeStates read FStates write FStates;
+ property SelectedCount: Integer read FSelectionCount;
+ property TopNode: PVirtualNode read GetTopNode write SetTopNode;
+ property VerticalAlignment[Node: PVirtualNode]: Byte read GetVerticalAlignment write SetVerticalAlignment;
+ property VisibleCount: Cardinal read FVisibleCount;
+ property VisiblePath[Node: PVirtualNode]: Boolean read GetVisiblePath write SetVisiblePath;
+ end;
+
+
+ // --------- TCustomVirtualStringTree
+
+ // Options regarding strings (useful only for the string tree and descentants):
+ TVTStringOption = (
+ toSaveCaptions, // If set then the caption is automatically saved with the tree node, regardless of what is
+ // saved in the user data.
+ toShowStaticText, // Show static text in a caption which can be differently formatted than the caption
+ // but cannot be edited.
+ toAutoAcceptEditChange // Automatically accept changes during edit if the user finishes editing other then
+ // VK_RETURN or ESC. If not set then changes are cancelled.
+ );
+ TVTStringOptions = set of TVTStringOption;
+
+const
+ DefaultStringOptions = [toSaveCaptions, toAutoAcceptEditChange];
+
+type
+ TCustomStringTreeOptions = class(TCustomVirtualTreeOptions)
+ private
+ FStringOptions: TVTStringOptions;
+ procedure SetStringOptions(const Value: TVTStringOptions);
+ protected
+ property StringOptions: TVTStringOptions read FStringOptions write SetStringOptions default DefaultStringOptions;
+ public
+ constructor Create(AOwner: TBaseVirtualTree); override;
+
+ procedure AssignTo(Dest: TPersistent); override;
+ end;
+
+ TStringTreeOptions = class(TCustomStringTreeOptions)
+ published
+ property AnimationOptions;
+ property AutoOptions;
+ property MiscOptions;
+ property PaintOptions;
+ property SelectionOptions;
+ property StringOptions;
+ end;
+
+ TCustomVirtualStringTree = class;
+
+ // Edit support classes.
+ TStringEditLink = class;
+
+ {$ifdef TntSupport}
+ TVTEdit = class(TTntEdit)
+ {$else}
+ TVTEdit = class(TCustomEdit)
+ {$endif TntSupport}
+ private
+ FLink: TStringEditLink;
+ procedure CMAutoAdjust(var Message: TMessage); message CM_AUTOADJUST;
+ procedure CMExit(var Message: TMessage); message CM_EXIT;
+ procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
+ procedure WMChar(var Message: TWMChar); message WM_CHAR;
+ procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
+ procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
+ procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
+ protected
+ procedure AutoAdjustSize;
+ procedure CreateParams(var Params: TCreateParams); override;
+ public
+ constructor Create(Link: TStringEditLink); reintroduce;
+
+ property AutoSelect;
+ property AutoSize;
+ property BorderStyle;
+ property CharCase;
+ property HideSelection;
+ property MaxLength;
+ property OEMConvert;
+ property PasswordChar;
+ end;
+
+ TStringEditLink = class(TInterfacedObject, IVTEditLink)
+ private
+ FEdit: TVTEdit; // A normal custom edit control.
+ FTree: TCustomVirtualStringTree; // A back reference to the tree calling.
+ FNode: PVirtualNode; // The node to be edited.
+ FColumn: TColumnIndex; // The column of the node.
+ FAlignment: TAlignment;
+ FTextBounds: TRect; // Smallest rectangle around the text.
+ FStopping: Boolean; // Set to True when the edit link requests stopping the edit action.
+ procedure SetEdit(const Value: TVTEdit);
+ protected
+ property Edit: TVTEdit read FEdit write SetEdit;
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ function BeginEdit: Boolean; virtual; stdcall;
+ function CancelEdit: Boolean; virtual; stdcall;
+ function EndEdit: Boolean; virtual; stdcall;
+ function GetBounds: TRect; virtual; stdcall;
+ function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; stdcall;
+ procedure ProcessMessage(var Message: TMessage); virtual; stdcall;
+ procedure SetBounds(R: TRect); virtual; stdcall;
+ end;
+
+ // Describes the type of text to return in the text and draw info retrival events.
+ TVSTTextType = (
+ ttNormal, // normal label of the node, this is also the text which can be edited
+ ttStatic // static (non-editable) text after the normal text
+ );
+
+ // Describes the source to use when converting a string tree into a string for clipboard etc.
+ TVSTTextSourceType = (
+ tstAll, // All nodes are rendered. Initialization is done on the fly.
+ tstInitialized, // Only initialized nodes are rendered.
+ tstSelected, // Only selected nodes are rendered.
+ tstCutCopySet, // Only nodes currently marked as being in the cut/copy clipboard set are rendered.
+ tstVisible // Only visible nodes are rendered.
+ );
+
+ TVTPaintText = procedure(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType) of object;
+ TVSTGetTextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ TextType: TVSTTextType; var CellText: WideString) of object;
+ // New text can only be set for variable caption.
+ TVSTNewTextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ NewText: WideString) of object;
+ TVSTShortenStringEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; const S: WideString; TextSpace: Integer; RightToLeft: Boolean; var Result: WideString;
+ var Done: Boolean) of object;
+
+ TCustomVirtualStringTree = class(TBaseVirtualTree)
+ private
+ FDefaultText: WideString; // text to show if there's no OnGetText event handler (e.g. at design time)
+ FTextHeight: Integer; // true size of the font
+ FEllipsisWidth: Integer; // width of '...' for the current font
+ FInternalDataOffset: Cardinal; // offset to the internal data of the string tree
+
+ FOnPaintText: TVTPaintText; // triggered before either normal or fixed text is painted to allow
+ // even finer customization (kind of sub cell painting)
+ FOnGetText, // used to retrieve the string to be displayed for a specific node
+ FOnGetHint: TVSTGetTextEvent; // used to retrieve the hint to be displayed for a specific node
+ FOnNewText: TVSTNewTextEvent; // used to notify the application about an edited node caption
+ FOnShortenString: TVSTShortenStringEvent; // used to allow the application a customized string shortage
+
+ procedure GetRenderStartValues(Source: TVSTTextSourceType; var Node: PVirtualNode;
+ var NextNodeProc: TGetNextNodeProc);
+ function GetOptions: TCustomStringTreeOptions;
+ function GetText(Node: PVirtualNode; Column: TColumnIndex): WideString;
+ procedure InitializeTextProperties(const Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex);
+ procedure PaintNormalText(var PaintInfo: TVTPaintInfo; TextOutFlags: Integer; Text: WideString);
+ procedure PaintStaticText(const PaintInfo: TVTPaintInfo; TextOutFlags: Integer; const Text: WideString);
+ procedure ReadText(Reader: TReader);
+ procedure SetDefaultText(const Value: WideString);
+ procedure SetOptions(const Value: TCustomStringTreeOptions);
+ procedure SetText(Node: PVirtualNode; Column: TColumnIndex; const Value: WideString);
+ procedure WriteText(Writer: TWriter);
+
+ procedure WMSetFont(var Msg: TWMSetFont); message WM_SETFONT;
+ protected
+ procedure AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex); override;
+ function CalculateTextWidth(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; Text: WideString): Integer; virtual;
+ function ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean; override;
+ procedure DefineProperties(Filer: TFiler); override;
+ function DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; override;
+ function DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex): WideString; override;
+ function DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex): WideString; override;
+ function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer; override;
+ procedure DoGetText(Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString); virtual;
+ function DoIncrementalSearch(Node: PVirtualNode; const Text: WideString): Integer; override;
+ procedure DoNewText(Node: PVirtualNode; Column: TColumnIndex; Text: WideString); virtual;
+ procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
+ procedure DoPaintText(Node: PVirtualNode; const Canvas: TCanvas; Column: TColumnIndex;
+ TextType: TVSTTextType); virtual;
+ function DoShortenString(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const S: WideString; Width: Integer;
+ RightToLeft: Boolean; EllipsisWidth: Integer = 0): WideString; virtual;
+ function GetOptionsClass: TTreeOptionsClass; override;
+ procedure GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect;
+ var Text: WideString); override;
+ function InternalData(Node: PVirtualNode): Pointer;
+ procedure MainColumnChanged; override;
+ function ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType,
+ ChunkSize: Integer): Boolean; override;
+ procedure ReadOldStringOptions(Reader: TReader);
+ function RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HResult; override;
+ procedure WriteChunks(Stream: TStream; Node: PVirtualNode); override;
+
+ property DefaultText: WideString read FDefaultText write SetDefaultText stored False;
+ property EllipsisWidth: Integer read FEllipsisWidth;
+ property TreeOptions: TCustomStringTreeOptions read GetOptions write SetOptions;
+
+ property OnGetHint: TVSTGettextEvent read FOnGetHint write FOnGetHint;
+ property OnGetText: TVSTGetTextEvent read FOnGetText write FOnGetText;
+ property OnNewText: TVSTNewTextEvent read FOnNewText write FOnNewText;
+ property OnPaintText: TVTPaintText read FOnPaintText write FOnPaintText;
+ property OnShortenString: TVSTShortenStringEvent read FOnShortenString write FOnShortenString;
+ public
+ constructor Create(AOwner: TComponent); override;
+
+ function ContentToClipboard(Format: Word; Source: TVSTTextSourceType): HGLOBAL;
+ function ContentToHTML(Source: TVSTTextSourceType; Caption: WideString = ''): string;
+ function ContentToRTF(Source: TVSTTextSourceType): string;
+ function ContentToText(Source: TVSTTextSourceType; Separator: Char): string;
+ function ContentToUnicode(Source: TVSTTextSourceType; Separator: WideChar): WideString;
+ function InvalidateNode(Node: PVirtualNode): TRect; override;
+ function Path(Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; Delimiter: WideChar): WideString;
+ procedure ReinitNode(Node: PVirtualNode; Recursive: Boolean); override;
+
+ property Text[Node: PVirtualNode; Column: TColumnIndex]: WideString read GetText write SetText;
+ end;
+
+ TVirtualStringTree = class(TCustomVirtualStringTree)
+ private
+ function GetOptions: TStringTreeOptions;
+ procedure SetOptions(const Value: TStringTreeOptions);
+ protected
+ function GetOptionsClass: TTreeOptionsClass; override;
+ public
+ property Canvas;
+ published
+ property Action;
+ property Align;
+ property Alignment;
+ property Anchors;
+ property AnimationDuration;
+ property AutoExpandDelay;
+ property AutoScrollDelay;
+ property AutoScrollInterval;
+ property Background;
+ property BackgroundOffsetX;
+ property BackgroundOffsetY;
+ property BiDiMode;
+ property BevelEdges;
+ property BevelInner;
+ property BevelOuter;
+ property BevelKind;
+ property BevelWidth;
+ property BorderStyle;
+ property ButtonFillMode;
+ property ButtonStyle;
+ property BorderWidth;
+ property ChangeDelay;
+ property CheckImageKind;
+ property ClipboardFormats;
+ property Color;
+ property Colors;
+ property Constraints;
+ property Ctl3D;
+ property CustomCheckImages;
+ property DefaultNodeHeight;
+ property DefaultPasteMode;
+ property DefaultText;
+ property DragCursor;
+ property DragHeight;
+ property DragKind;
+ property DragImageKind;
+ property DragMode;
+ property DragOperations;
+ property DragType;
+ property DragWidth;
+ property DrawSelectionMode;
+ property EditDelay;
+ property Enabled;
+ property Font;
+ property Header;
+ property HintAnimation;
+ property HintMode;
+ property HotCursor;
+ property Images;
+ property IncrementalSearch;
+ property IncrementalSearchDirection;
+ property IncrementalSearchStart;
+ property IncrementalSearchTimeout;
+ property Indent;
+ property LineMode;
+ property LineStyle;
+ property Margin;
+ property NodeAlignment;
+ property NodeDataSize;
+ property ParentBiDiMode;
+ property ParentColor default False;
+ property ParentCtl3D;
+ property ParentFont;
+ property ParentShowHint;
+ property PopupMenu;
+ property RootNodeCount;
+ property ScrollBarOptions;
+ property SelectionBlendFactor;
+ property SelectionCurveRadius;
+ property ShowHint;
+ property StateImages;
+ property TabOrder;
+ property TabStop default True;
+ property TextMargin;
+ property TreeOptions: TStringTreeOptions read GetOptions write SetOptions;
+ property Visible;
+ property WantTabs;
+
+ property OnAdvancedHeaderDraw;
+ property OnAfterCellPaint;
+ property OnAfterItemErase;
+ property OnAfterItemPaint;
+ property OnAfterPaint;
+ property OnBeforeCellPaint;
+ property OnBeforeItemErase;
+ property OnBeforeItemPaint;
+ property OnBeforePaint;
+ property OnChange;
+ property OnChecked;
+ property OnChecking;
+ property OnClick;
+ property OnCollapsed;
+ property OnCollapsing;
+ property OnColumnClick;
+ property OnColumnDblClick;
+ property OnColumnResize;
+ property OnCompareNodes;
+ {$ifdef COMPILER_5_UP}
+ property OnContextPopup;
+ {$endif COMPILER_5_UP}
+ property OnCreateDataObject;
+ property OnCreateDragManager;
+ property OnCreateEditor;
+ property OnDblClick;
+ property OnDragAllowed;
+ property OnDragOver;
+ property OnDragDrop;
+ property OnEditCancelled;
+ property OnEdited;
+ property OnEditing;
+ property OnEndDock;
+ property OnEndDrag;
+ property OnEnter;
+ property OnExit;
+ property OnExpanded;
+ property OnExpanding;
+ property OnFocusChanged;
+ property OnFocusChanging;
+ property OnFreeNode;
+ property OnGetCursor;
+ property OnGetHeaderCursor;
+ property OnGetText;
+ property OnPaintText;
+ property OnGetHelpContext;
+ property OnGetImageIndex;
+ property OnGetHint;
+ property OnGetLineStyle;
+ property OnGetNodeDataSize;
+ property OnGetPopupMenu;
+ property OnGetUserClipboardFormats;
+ property OnHeaderClick;
+ property OnHeaderDblClick;
+ property OnHeaderDragged;
+ property OnHeaderDraggedOut;
+ property OnHeaderDragging;
+ property OnHeaderDraw;
+ property OnHeaderDrawQueryElements;
+ property OnHeaderMouseDown;
+ property OnHeaderMouseMove;
+ property OnHeaderMouseUp;
+ property OnHotChange;
+ property OnIncrementalSearch;
+ property OnInitChildren;
+ property OnInitNode;
+ property OnKeyAction;
+ property OnKeyDown;
+ property OnKeyPress;
+ property OnKeyUp;
+ property OnLoadNode;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnNewText;
+ property OnNodeCopied;
+ property OnNodeCopying;
+ property OnNodeMoved;
+ property OnNodeMoving;
+ property OnPaintBackground;
+ property OnRenderOLEData;
+ property OnResetNode;
+ property OnResize;
+ property OnSaveNode;
+ property OnScroll;
+ property OnShortenString;
+ property OnStartDock;
+ property OnStartDrag;
+ property OnStateChange;
+ property OnStructureChange;
+ property OnUpdating;
+ end;
+
+ TVTDrawHintEvent = procedure(Sender: TBaseVirtualTree; HintCanvas: TCanvas; Node: PVirtualNode; R: TRect;
+ Column: TColumnIndex) of object;
+ TVTDrawNodeEvent = procedure(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo) of object;
+ TVTGetNodeWidthEvent = procedure(Sender: TBaseVirtualTree; HintCanvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex; var NodeWidth: Integer) of object;
+ TVTGetHintSizeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
+ var R: TRect) of object;
+
+ // Tree descendant to let an application draw its stuff itself.
+ TCustomVirtualDrawTree = class(TBaseVirtualTree)
+ private
+ FOnDrawNode: TVTDrawNodeEvent;
+ FOnGetNodeWidth: TVTGetNodeWidthEvent;
+ FOnGetHintSize: TVTGetHintSizeEvent;
+ FOnDrawHint: TVTDrawHintEvent;
+ protected
+ procedure DoDrawHint(Canvas: TCanvas; Node: PVirtualNode; R: TRect; Column: TColumnIndex);
+ procedure DoGetHintSize(Node: PVirtualNode; Column: TColumnIndex; var R: TRect); virtual;
+ function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer; override;
+ procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override;
+
+ property OnDrawHint: TVTDrawHintEvent read FOnDrawHint write FOnDrawHint;
+ property OnDrawNode: TVTDrawNodeEvent read FOnDrawNode write FOnDrawNode;
+ property OnGetHintSize: TVTGetHintSizeEvent read FOnGetHintSize write FOnGetHintSize;
+ property OnGetNodeWidth: TVTGetNodeWidthEvent read FOnGetNodeWidth write FOnGetNodeWidth;
+ end;
+
+ TVirtualDrawTree = class(TCustomVirtualDrawTree)
+ private
+ function GetOptions: TVirtualTreeOptions;
+ procedure SetOptions(const Value: TVirtualTreeOptions);
+ protected
+ function GetOptionsClass: TTreeOptionsClass; override;
+ public
+ property Canvas;
+ published
+ property Action;
+ property Align;
+ property Alignment;
+ property Anchors;
+ property AnimationDuration;
+ property AutoExpandDelay;
+ property AutoScrollDelay;
+ property AutoScrollInterval;
+ property Background;
+ property BackgroundOffsetX;
+ property BackgroundOffsetY;
+ property BiDiMode;
+ property BevelEdges;
+ property BevelInner;
+ property BevelOuter;
+ property BevelKind;
+ property BevelWidth;
+ property BorderStyle;
+ property ButtonFillMode;
+ property ButtonStyle;
+ property BorderWidth;
+ property ChangeDelay;
+ property CheckImageKind;
+ property ClipboardFormats;
+ property Color;
+ property Colors;
+ property Constraints;
+ property Ctl3D;
+ property CustomCheckImages;
+ property DefaultNodeHeight;
+ property DefaultPasteMode;
+ property DragCursor;
+ property DragHeight;
+ property DragKind;
+ property DragImageKind;
+ property DragMode;
+ property DragOperations;
+ property DragType;
+ property DragWidth;
+ property DrawSelectionMode;
+ property EditDelay;
+ property Enabled;
+ property Font;
+ property Header;
+ property HintAnimation;
+ property HintMode;
+ property HotCursor;
+ property Images;
+ property IncrementalSearch;
+ property IncrementalSearchDirection;
+ property IncrementalSearchStart;
+ property IncrementalSearchTimeout;
+ property Indent;
+ property LineMode;
+ property LineStyle;
+ property Margin;
+ property NodeAlignment;
+ property NodeDataSize;
+ property ParentBiDiMode;
+ property ParentColor default False;
+ property ParentCtl3D;
+ property ParentFont;
+ property ParentShowHint;
+ property PopupMenu;
+ property RootNodeCount;
+ property ScrollBarOptions;
+ property SelectionBlendFactor;
+ property SelectionCurveRadius;
+ property ShowHint;
+ property StateImages;
+ property TabOrder;
+ property TabStop default True;
+ property TextMargin;
+ property TreeOptions: TVirtualTreeOptions read GetOptions write SetOptions;
+ property Visible;
+ property WantTabs;
+
+ property OnAfterCellPaint;
+ property OnAfterItemErase;
+ property OnAfterItemPaint;
+ property OnAfterPaint;
+ property OnBeforeCellPaint;
+ property OnBeforeItemErase;
+ property OnBeforeItemPaint;
+ property OnBeforePaint;
+ property OnChange;
+ property OnChecked;
+ property OnChecking;
+ property OnClick;
+ property OnCollapsed;
+ property OnCollapsing;
+ property OnColumnClick;
+ property OnColumnDblClick;
+ property OnColumnResize;
+ property OnCompareNodes;
+ {$ifdef COMPILER_5_UP}
+ property OnContextPopup;
+ {$endif COMPILER_5_UP}
+ property OnCreateDataObject;
+ property OnCreateDragManager;
+ property OnCreateEditor;
+ property OnDblClick;
+ property OnDragAllowed;
+ property OnDragOver;
+ property OnDragDrop;
+ property OnDrawHint;
+ property OnDrawNode;
+ property OnEdited;
+ property OnEditing;
+ property OnEndDock;
+ property OnEndDrag;
+ property OnEnter;
+ property OnExit;
+ property OnExpanded;
+ property OnExpanding;
+ property OnFocusChanged;
+ property OnFocusChanging;
+ property OnFreeNode;
+ property OnGetCursor;
+ property OnGetHeaderCursor;
+ property OnGetHelpContext;
+ property OnGetHintSize;
+ property OnGetImageIndex;
+ property OnGetLineStyle;
+ property OnGetNodeDataSize;
+ property OnGetNodeWidth;
+ property OnGetPopupMenu;
+ property OnGetUserClipboardFormats;
+ property OnHeaderClick;
+ property OnHeaderDblClick;
+ property OnHeaderDragged;
+ property OnHeaderDraggedOut;
+ property OnHeaderDragging;
+ property OnHeaderDraw;
+ property OnHeaderMouseDown;
+ property OnHeaderMouseMove;
+ property OnHeaderMouseUp;
+ property OnHotChange;
+ property OnIncrementalSearch;
+ property OnInitChildren;
+ property OnInitNode;
+ property OnKeyAction;
+ property OnKeyDown;
+ property OnKeyPress;
+ property OnKeyUp;
+ property OnLoadNode;
+ property OnMouseDown;
+ property OnMouseMove;
+ property OnMouseUp;
+ property OnNodeCopied;
+ property OnNodeCopying;
+ property OnNodeMoved;
+ property OnNodeMoving;
+ property OnPaintBackground;
+ property OnRenderOLEData;
+ property OnResetNode;
+ property OnResize;
+ property OnSaveNode;
+ property OnScroll;
+ property OnStartDock;
+ property OnStateChange;
+ property OnStructureChange;
+ property OnUpdating;
+ end;
+
+type
+ // Describes the mode how to blend pixels.
+ TBlendMode = (
+ bmConstantAlpha, // apply given constant alpha
+ bmPerPixelAlpha, // use alpha value of the source pixel
+ bmMasterAlpha, // use alpha value of source pixel and multiply it with the constant alpha value
+ bmConstantAlphaAndColor // blend the destination color with the given constant color und the constant alpha value
+ );
+
+// OLE Clipboard and drag'n drop helper
+procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; const List: TStrings); overload;
+procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray); overload;
+function GetVTClipboardFormatDescription(AFormat: Word): string;
+procedure RegisterVTClipboardFormat(AFormat: Word; TreeClass: TVirtualTreeClass; Priority: Cardinal); overload;
+function RegisterVTClipboardFormat(Description: string; TreeClass: TVirtualTreeClass; Priority: Cardinal;
+ tymed: Integer = TYMED_HGLOBAL; ptd: PDVTargetDevice = nil; dwAspect: Integer = DVASPECT_CONTENT;
+ lindex: Integer = -1): Word; overload;
+
+// utility routines
+procedure AlphaBlend(Source, Destination: HDC; R: TRect; Target: TPoint; Mode: TBlendMode; ConstantAlpha, Bias: Integer);
+procedure DrawTextW(DC: HDC; lpString: PWideChar; nCount: Integer; var lpRect: TRect; uFormat: Cardinal;
+ AdjustRight: Boolean);
+function ShortenString(DC: HDC; const S: WideString; Width: Integer; RTL: Boolean;
+ EllipsisWidth: Integer = 0): WideString;
+function TreeFromNode(Node: PVirtualNode): TBaseVirtualTree;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+implementation
+
+{$R VirtualTrees.res}
+
+uses
+ Consts, Math,
+ AxCtrls, // TOLEStream
+ CommCtrl, // image list stuff
+ {$ifdef UseFlatScrollbars}
+ FlatSB, // wrapper for systems without flat SB support
+ {$endif UseFlatScrollbars}
+ MMSystem, // for animation timer (does not include further resources)
+ TypInfo, // for migration stuff
+ ActnList,
+ StdActns; // for standard action support
+
+resourcestring
+ // Localizable strings.
+ SEditLinkIsNil = 'Edit link must not be nil.';
+ SWrongMoveError = 'Target node cannot be a child node of the node to be moved.';
+ SWrongStreamFormat = 'Unable to load tree structure, the format is wrong.';
+ SWrongStreamVersion = 'Unable to load tree structure, the version is unknown.';
+ SStreamTooSmall = 'Unable to load tree structure, not enough data available.';
+ SCorruptStream1 = 'Stream data corrupt. A node''s anchor chunk is missing.';
+ SCorruptStream2 = 'Stream data corrupt. Unexpected data after node''s end position.';
+ SClipboardFailed = 'Clipboard operation failed.';
+ SCannotSetUserData = 'Cannot set initial user data because there is not enough user data space allocated.';
+
+const
+ ClipboardStates = [tsCopyPending, tsCutPending];
+ DefaultScrollUpdateFlags = [suoRepaintHeader, suoRepaintScrollbars, suoScrollClientArea, suoUpdateNCArea];
+ MinimumTimerInterval = 1; // minimum resolution for timeGetTime
+ TreeNodeSize = (SizeOf(TVirtualNode) + 3) and not 3; // used for node allocation and access to internal data
+
+ // Lookup to quickly convert a specific check state into its pressed counterpart and vice versa.
+ PressedState: array[TCheckState] of TCheckState = (
+ csUncheckedPressed, csUncheckedPressed, csCheckedPressed, csCheckedPressed, csMixedPressed, csMixedPressed
+ );
+ UnpressedState: array[TCheckState] of TCheckState = (
+ csUncheckedNormal, csUncheckedNormal, csCheckedNormal, csCheckedNormal, csMixedNormal, csMixedNormal
+ );
+ MouseButtonDown = [tsLeftButtonDown, tsMiddleButtonDown, tsRightButtonDown];
+
+ // Do not modify the copyright in any way! Usage of this unit is prohibited without the copyright notice
+ // in the compiled binary file.
+ Copyright: string = 'Virtual Treeview © 1999, 2003 Mike Lischke';
+
+var
+ StandardOLEFormat: TFormatEtc = (
+ // Format must later be set.
+ cfFormat: 0;
+ // No specific target device to render on.
+ ptd: nil;
+ // Normal content to render.
+ dwAspect: DVASPECT_CONTENT;
+ // No specific page of multipage data (we don't use multipage data by default).
+ lindex: -1;
+ // Acceptable storage formats are IStream and global memory. The first is preferred.
+ tymed: TYMED_ISTREAM or TYMED_HGLOBAL;
+ );
+
+
+type // streaming support
+ TMagicID = array[0..5] of WideChar;
+
+ TChunkHeader = record
+ ChunkType,
+ ChunkSize: Integer; // contains the size of the chunk excluding the header
+ end;
+
+ // base information about a node
+ TBaseChunkBody = packed record
+ ChildCount,
+ NodeHeight: Cardinal;
+ States: TVirtualNodeStates;
+ Align: Byte;
+ CheckState: TCheckState;
+ CheckType: TCheckType;
+ Reserved: Cardinal;
+ end;
+
+ TBaseChunk = packed record
+ Header: TChunkHeader;
+ Body: TBaseChunkBody;
+ end;
+
+ // Internally used data for animations.
+ TToggleAnimationData = record
+ Expand: Boolean; // if true then expanding is in progress
+ Window: HWND; // copy of the tree's window handle
+ DC: HDC; // the DC of the window to erase unconvered parts
+ Brush: HBRUSH; // the brush to be used to erase uncovered parts
+ R: TRect; // the scroll rectangle
+ end;
+
+const
+ MagicID: TMagicID = (#$2045, 'V', 'T', WideChar(VTTreeStreamVersion), ' ', #$2046);
+
+ // chunk IDs
+ NodeChunk = 1;
+ BaseChunk = 2; // chunk containing node state, check state, child node count etc.
+ // this chunk is immediately followed by all child nodes
+ CaptionChunk = 3; // used by the string tree to store a node's caption
+ UserChunk = 4; // used for data supplied by the application
+
+ {$ifdef UseFlatScrollbars}
+ ScrollBarProp: array[TScrollBarStyle] of Integer = (
+ FSB_REGULAR_MODE,
+ FSB_FLAT_MODE,
+ FSB_ENCARTA_MODE
+ );
+ {$endif}
+
+ RTLFlag: array[Boolean] of Integer = (0, ETO_RTLREADING);
+ AlignmentToDrawFlag: array[TAlignment] of Cardinal = (DT_LEFT, DT_RIGHT, DT_CENTER);
+
+ WideNull = WideChar(#0);
+ WideCR = WideChar(#13);
+ WideLF = WideChar(#10);
+ WideLineSeparator = WideChar(#2028);
+
+type
+ // internal worker thread
+ TWorkerThread = class(TThread)
+ private
+ FCurrentTree: TBaseVirtualTree;
+ FWaiterList: TThreadList;
+ FRefCount: Cardinal;
+ protected
+ procedure ChangeTreeStates(EnterStates, LeaveStates: TChangeStates);
+ procedure Execute; override;
+ public
+ constructor Create(CreateSuspended: Boolean);
+ destructor Destroy; override;
+
+ procedure AddTree(Tree: TBaseVirtualTree);
+ procedure RemoveTree(Tree: TBaseVirtualTree);
+ end;
+
+ // Helper classes to speed up rendering text formats for clipboard and drag'n drop transfers.
+ TBufferedString = class
+ private
+ FStart,
+ FPosition,
+ FEnd: PChar;
+ function GetAsString: string;
+ public
+ destructor Destroy; override;
+
+ procedure Add(const S: string);
+ procedure AddNewLine;
+
+ property AsString: string read GetAsString;
+ end;
+
+ TWideBufferedString = class
+ private
+ FStart,
+ FPosition,
+ FEnd: PWideChar;
+ function GetAsString: WideString;
+ public
+ destructor Destroy; override;
+
+ procedure Add(const S: WideString);
+ procedure AddNewLine;
+
+ property AsString: WideString read GetAsString;
+ end;
+
+var
+ WorkerThread: TWorkerThread;
+ WorkEvent: THandle;
+ Watcher: TCriticalSection;
+ LightCheckImages, // global light check images
+ DarkCheckImages, // global heavy check images
+ LightTickImages, // global light tick images
+ DarkTickImages, // global heavy check images
+ FlatImages, // global flat check images
+ XPImages, // global XP style check images
+ UtilityImages, // some small additional images (e.g for header dragging)
+ SystemCheckImages, // global system check images
+ SystemFlatCheckImages: TImageList; // global flat system check images
+ IsWinNT: Boolean; // Necessary to fix bugs in Win95/WinME (non-client area region intersection, edit resize)
+ // and to allow for check of system dependent hint animation.
+ IsWin2K: Boolean; // Nessary to provide correct string shortage
+ IsWinXP: Boolean;
+ Initialized: Boolean; // True if global structures have been initialized.
+ NeedToUnitialize: Boolean; // True if the OLE subsystem could be initialized successfully.
+
+ {$ifndef COMPILER_5_UP}
+ HintFont: TFont; // In Delphi 4 there is no TScreen.HintFont yet.
+ {$endif COMPILER_5_UP}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+{$ifndef COMPILER_6_UP}
+
+ procedure RaiseLastOSError;
+
+ begin
+ RaiseLastWin32Error;
+ end;
+
+{$endif COMPILER_6_UP}
+
+//----------------- TClipboardFormats ----------------------------------------------------------------------------------
+
+type
+ PClipboardFormatListEntry = ^TClipboardFormatListEntry;
+ TClipboardFormatListEntry = record
+ Description: string; // The string used to register the format with Windows.
+ TreeClass: TVirtualTreeClass; // The tree class which supports rendering this format.
+ Priority: Cardinal; // Number which determines the order of formats used in IDataObject.
+ FormatEtc: TFormatEtc; // The definition of the format in the IDataObject.
+ end;
+
+ TClipboardFormatList = class
+ private
+ FList: TList;
+ procedure Sort;
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ procedure Add(FormatString: string; AClass: TVirtualTreeClass; Priority: Cardinal; AFormatEtc: TFormatEtc);
+ procedure Clear;
+ procedure EnumerateFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray;
+ const AllowedFormats: TClipboardFormats = nil); overload;
+ procedure EnumerateFormats(TreeClass: TVirtualTreeClass; const Formats: TStrings); overload;
+ function FindFormat(FormatString: string): PClipboardFormatListEntry; overload;
+ function FindFormat(FormatString: string; var Fmt: Word): TVirtualTreeClass; overload;
+ function FindFormat(Fmt: Word; var Description: string): TVirtualTreeClass; overload;
+ end;
+
+var
+ InternalClipboardFormats: TClipboardFormatList;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+constructor TClipboardFormatList.Create;
+
+begin
+ FList := TList.Create;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TClipboardFormatList.Destroy;
+
+begin
+ Clear;
+ FList.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.Sort;
+
+// Sorts all entry for priority (increasing priority value).
+
+ //--------------- local function --------------------------------------------
+
+ procedure QuickSort(L, R: Integer);
+
+ var
+ I, J: Integer;
+ P, T: PClipboardFormatListEntry;
+
+ begin
+ repeat
+ I := L;
+ J := R;
+ P := FList[(L + R) shr 1];
+ repeat
+ while PClipboardFormatListEntry(FList[I]).Priority < P.Priority do
+ Inc(I);
+ while PClipboardFormatListEntry(Flist[J]).Priority > P.Priority do
+ Dec(J);
+ if I <= J then
+ begin
+ T := Flist[I];
+ FList[I] := FList[J];
+ FList[J] := T;
+ Inc(I);
+ Dec(J);
+ end;
+ until I > J;
+ if L < J then
+ QuickSort(L, J);
+ L := I;
+ until I >= R;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+begin
+ if FList.Count > 1 then
+ QuickSort(0, FList.Count - 1);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.Add(FormatString: string; AClass: TVirtualTreeClass; Priority: Cardinal;
+ AFormatEtc: TFormatEtc);
+
+// Adds the given data to the internal list. The priority value is used to sort formats for importance. Larger priority
+// values mean less priority.
+
+var
+ Entry: PClipboardFormatListEntry;
+
+begin
+ New(Entry);
+ Entry.Description := FormatString;
+ Entry.TreeClass := AClass;
+ Entry.Priority := Priority;
+ Entry.FormatEtc := AFormatEtc;
+ FList.Add(Entry);
+
+ Sort;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.Clear;
+
+var
+ I: Integer;
+
+begin
+ for I := 0 to FList.Count - 1 do
+ Dispose(PClipboardFormatListEntry(FList[I]));
+ FList.Clear;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.EnumerateFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray;
+ const AllowedFormats: TClipboardFormats = nil);
+
+// Returns a list of format records for the given class. If assigned the AllowedFormats is used to limit the
+// enumerated formats to those described in the list.
+
+var
+ I, Count: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ SetLength(Formats, FList.Count);
+ Count := 0;
+ for I := 0 to FList.Count - 1 do
+ begin
+ Entry := FList[I];
+ // Does the tree class support this clipboard format?
+ if TreeClass.InheritsFrom(Entry.TreeClass) then
+ begin
+ // Is this format allowed to be included?
+ if (AllowedFormats = nil) or (AllowedFormats.IndexOf(Entry.Description) > -1) then
+ begin
+ // The list could change before we use the FormatEtc so it is best not to pass a pointer to the true FormatEtc
+ // structure. Instead make a copy and send that.
+ Formats[Count] := Entry.FormatEtc;
+ Inc(Count);
+ end;
+ end;
+ end;
+ SetLength(Formats, Count);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormatList.EnumerateFormats(TreeClass: TVirtualTreeClass; const Formats: TStrings);
+
+// Returns a list of format descriptions for the given class.
+
+var
+ I: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ for I := 0 to FList.Count - 1 do
+ begin
+ Entry := FList[I];
+ if TreeClass.InheritsFrom(Entry.TreeClass) then
+ Formats.Add(Entry.Description);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardFormatList.FindFormat(FormatString: string): PClipboardFormatListEntry;
+
+var
+ I: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ Result := nil;
+ for I := FList.Count - 1 downto 0 do
+ begin
+ Entry := FList[I];
+ if CompareText(Entry.Description, FormatString) = 0 then
+ begin
+ Result := Entry;
+ Break;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardFormatList.FindFormat(FormatString: string; var Fmt: Word): TVirtualTreeClass;
+
+var
+ I: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ Result := nil;
+ for I := FList.Count - 1 downto 0 do
+ begin
+ Entry := FList[I];
+ if CompareText(Entry.Description, FormatString) = 0 then
+ begin
+ Result := Entry.TreeClass;
+ Fmt := Entry.FormatEtc.cfFormat;
+ Break;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardFormatList.FindFormat(Fmt: Word; var Description: string): TVirtualTreeClass;
+
+var
+ I: Integer;
+ Entry: PClipboardFormatListEntry;
+
+begin
+ Result := nil;
+ for I := FList.Count - 1 downto 0 do
+ begin
+ Entry := FList[I];
+ if Entry.FormatEtc.cfFormat = Fmt then
+ begin
+ Result := Entry.TreeClass;
+ Description := Entry.Description;
+ Break;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ TClipboardFormatEntry = record
+ ID: Word;
+ Description: string;
+ end;
+
+var
+ ClipboardDescriptions: array [1..CF_MAX - 1] of TClipboardFormatEntry = (
+ (ID: CF_TEXT; Description: 'Plain text'),
+ (ID: CF_BITMAP; Description: 'Windows bitmap'),
+ (ID: CF_METAFILEPICT; Description: 'Windows metafile'),
+ (ID: CF_SYLK; Description: 'Symbolic link'),
+ (ID: CF_DIF; Description: 'Data interchange format'),
+ (ID: CF_TIFF; Description: 'Tiff image'),
+ (ID: CF_OEMTEXT; Description: 'OEM text'),
+ (ID: CF_DIB; Description: 'DIB image'),
+ (ID: CF_PALETTE; Description: 'Palette data'),
+ (ID: CF_PENDATA; Description: 'Pen data'),
+ (ID: CF_RIFF; Description: 'Riff audio data'),
+ (ID: CF_WAVE; Description: 'Wav audio data'),
+ (ID: CF_UNICODETEXT; Description: 'Unicode text'),
+ (ID: CF_ENHMETAFILE; Description: 'Enhanced metafile image'),
+ (ID: CF_HDROP; Description: 'File name(s)'),
+ (ID: CF_LOCALE; Description: 'Locale descriptor')
+ );
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; const List: TStrings);
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+ InternalClipboardFormats.EnumerateFormats(TreeClass, List);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray);
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+ InternalClipboardFormats.EnumerateFormats(TreeClass, Formats);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function GetVTClipboardFormatDescription(AFormat: Word): string;
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+ if InternalClipboardFormats.FindFormat(AFormat, Result) = nil then
+ Result := '';
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure RegisterVTClipboardFormat(AFormat: Word; TreeClass: TVirtualTreeClass; Priority: Cardinal);
+
+// Registers the given clipboard format for the given TreeClass.
+
+var
+ I: Integer;
+ Buffer: array[0..2048] of Char;
+ FormatEtc: TFormatEtc;
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+
+ // Assumes a HGlobal format.
+ FormatEtc.cfFormat := AFormat;
+ FormatEtc.ptd := nil;
+ FormatEtc.dwAspect := DVASPECT_CONTENT;
+ FormatEtc.lindex := -1;
+ FormatEtc.tymed := TYMED_HGLOBAL;
+
+ // Determine description string of the given format. For predefined formats we need the lookup table because they
+ // don't have a description string. For registered formats the description string is the string which was used
+ // to register them.
+ if AFormat < CF_MAX then
+ begin
+ for I := 1 to High(ClipboardDescriptions) do
+ if ClipboardDescriptions[I].ID = AFormat then
+ begin
+ InternalClipboardFormats.Add(ClipboardDescriptions[I].Description, TreeClass, Priority, FormatEtc);
+ Break;
+ end;
+ end
+ else
+ begin
+ GetClipboardFormatName(AFormat, Buffer, Length(Buffer));
+ InternalClipboardFormats.Add(Buffer, TreeClass, Priority, FormatEtc);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function RegisterVTClipboardFormat(Description: string; TreeClass: TVirtualTreeClass; Priority: Cardinal;
+ tymed: Integer = TYMED_HGLOBAL; ptd: PDVTargetDevice = nil; dwAspect: Integer = DVASPECT_CONTENT;
+ lindex: Integer = -1): Word;
+
+// Alternative method to register a certain clipboard format for a given tree class. Registration with the
+// clipboard is done here too and the assigned ID returned by the function.
+// tymed may contain or'ed TYMED constants which allows to register several storage formats for one clipboard format.
+
+var
+ FormatEtc: TFormatEtc;
+
+begin
+ if InternalClipboardFormats = nil then
+ InternalClipboardFormats := TClipboardFormatList.Create;
+ Result := RegisterClipboardFormat(PChar(Description));
+ FormatEtc.cfFormat := Result;
+ FormatEtc.ptd := ptd;
+ FormatEtc.dwAspect := dwAspect;
+ FormatEtc.lindex := lindex;
+ FormatEtc.tymed := tymed;
+ InternalClipboardFormats.Add(Description, TreeClass, Priority, FormatEtc);
+end;
+
+//----------------- utility functions ----------------------------------------------------------------------------------
+
+procedure ShowError(Msg: WideString; HelpContext: Integer);
+
+begin
+ raise EVirtualTreeError.CreateHelp(Msg, HelpContext);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TreeFromNode(Node: PVirtualNode): TBaseVirtualTree;
+
+// Returns the tree the node currently belongs to or nil if the node is not attached to a tree.
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+
+ // The root node is marked by having its NextSibling (and PrevSibling) pointing to itself.
+ while Assigned(Node) and (Node.NextSibling <> Node) do
+ Node := Node.Parent;
+ if Assigned(Node) then
+ Result := TBaseVirtualTree(Node.Parent)
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function OrderRect(const R: TRect): TRect;
+
+// Converts the incoming rectangle so that left and top are always less than or equal to right and bottom.
+
+begin
+ if R.Left < R.Right then
+ begin
+ Result.Left := R.Left;
+ Result.Right := R.Right;
+ end
+ else
+ begin
+ Result.Left := R.Right;
+ Result.Right := R.Left;
+ end;
+ if R.Top < R.Bottom then
+ begin
+ Result.Top := R.Top;
+ Result.Bottom := R.Bottom;
+ end
+ else
+ begin
+ Result.Top := R.Bottom;
+ Result.Bottom := R.Top;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure QuickSort(const TheArray: TNodeArray; L, R: Integer);
+
+var
+ I, J: Integer;
+ P, T: Pointer;
+
+begin
+ repeat
+ I := L;
+ J := R;
+ P := TheArray[(L + R) shr 1];
+ repeat
+ while Cardinal(TheArray[I]) < Cardinal(P) do
+ Inc(I);
+ while Cardinal(TheArray[J]) > Cardinal(P) do
+ Dec(J);
+ if I <= J then
+ begin
+ T := TheArray[I];
+ TheArray[I] := TheArray[J];
+ TheArray[J] := T;
+ Inc(I);
+ Dec(J);
+ end;
+ until I > J;
+ if L < J then
+ QuickSort(TheArray, L, J);
+ L := I;
+ until I >= R;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure DrawTextW(DC: HDC; lpString: PWideChar; nCount: Integer; var lpRect: TRect; uFormat: Cardinal;
+ AdjustRight: Boolean);
+
+// This procedure implements a subset of Window's DrawText API for Unicode which is not available for
+// Windows 9x. For a description of the parameters see DrawText in the online help.
+// Supported flags are currently:
+// - DT_LEFT
+// - DT_TOP
+// - DT_CALCRECT
+// - DT_NOCLIP
+// - DT_RTLREADING
+// - DT_SINGLELINE
+// - DT_VCENTER
+// Differences to the DrawTextW Windows API:
+// - The additional parameter AdjustRight determines whether to adjust the right border of the given rectangle to
+// accomodate the largest line in the text. It has only a meaning if also DT_CALCRECT is specified.
+
+var
+ Head, Tail: PWideChar;
+ Size: TSize;
+ MaxWidth: Integer;
+ TextOutFlags: Integer;
+ TextAlign,
+ OldTextAlign: Cardinal;
+ TM: TTextMetric;
+ TextHeight: Integer;
+ LineRect: TRect;
+ TextPosY,
+ TextPosX: Integer;
+
+ CalculateRect: Boolean;
+
+begin
+ // Prepare some work variables.
+ MaxWidth := 0;
+ Head := lpString;
+ GetTextMetrics(DC, TM);
+ TextHeight := TM.tmHeight;
+ if uFormat and DT_SINGLELINE <> 0 then
+ LineRect := lpRect
+ else
+ LineRect := Rect(lpRect.Left, lpRect.Top, lpRect.Right, lpRect.Top + TextHeight);
+
+ CalculateRect := uFormat and DT_CALCRECT <> 0;
+
+ // Prepare text output.
+ TextOutFlags := 0;
+ if uFormat and DT_NOCLIP = 0 then
+ TextOutFlags := TextOutFlags or ETO_CLIPPED;
+ if uFormat and DT_RTLREADING <> 0 then
+ TextOutFlags := TextOutFlags or ETO_RTLREADING;
+
+ // Determine horizontal and vertical text alignment.
+ OldTextAlign := GetTextAlign(DC);
+ TextAlign := TA_LEFT or TA_TOP;
+ TextPosX := lpRect.Left;
+ if uFormat and DT_RIGHT <> 0 then
+ begin
+ TextAlign := TextAlign or TA_RIGHT and not TA_LEFT;
+ TextPosX := lpRect.Right;
+ end
+ else
+ if uFormat and DT_CENTER <> 0 then
+ begin
+ TextAlign := TextAlign or TA_CENTER and not TA_LEFT;
+ TextPosX := (lpRect.Left + lpRect.Right) div 2;
+ end;
+
+ TextPosY := lpRect.Top;
+ if uFormat and DT_VCENTER <> 0 then
+ begin
+ // Note: vertical alignment does only work with single line text ouput!
+ TextPosY := (lpRect.Top + lpRect.Bottom - TextHeight) div 2;
+ end;
+ SetTextAlign(DC, TextAlign);
+
+ if uFormat and DT_SINGLELINE <> 0 then
+ begin
+ if CalculateRect then
+ begin
+ GetTextExtentPoint32W(DC, Head, nCount, Size);
+ if Size.cx > MaxWidth then
+ MaxWidth := Size.cx;
+ end
+ else
+ ExtTextOutW(DC, TextPosX, TextPosY, TextOutFlags, @LineRect, Head, nCount, nil);
+ OffsetRect(LineRect, 0, TextHeight);
+ end
+ else
+ begin
+ while (nCount > 0) and (Head^ <> WideNull) do
+ begin
+ Tail := Head;
+ // Look for the end of the current line. A line is finished either by the string end or a line break.
+ while (nCount > 0) and not (Tail^ in [WideNull, WideCR, WideLF]) and (Tail^ <> WideLineSeparator) do
+ begin
+ Inc(Tail);
+ Dec(nCount);
+ end;
+
+ if CalculateRect then
+ begin
+ GetTextExtentPoint32W(DC, Head, Tail - Head, Size);
+ if Size.cx > MaxWidth then
+ MaxWidth := Size.cx;
+ end
+ else
+ ExtTextOutW(DC, TextPosX, LineRect.Top, TextOutFlags, @LineRect, Head, Tail - Head, nil);
+ OffsetRect(LineRect, 0, TextHeight);
+
+ // Get out of the loop if the rectangle is filled up.
+ if (nCount = 0) or (not CalculateRect and (LineRect.Top >= lpRect.Bottom)) then
+ Break;
+
+ if (nCount > 0) and (Tail^ = WideCR) or (Tail^ = WideLineSeparator) then
+ begin
+ Inc(Tail);
+ Dec(nCount);
+ end;
+
+ if (nCount > 0) and (Tail^ = WideLF) then
+ begin
+ Inc(Tail);
+ Dec(nCount);
+ end;
+ Head := Tail;
+ end;
+ end;
+
+ SetTextAlign(DC, OldTextAlign);
+ if CalculateRect then
+ begin
+ if AdjustRight then
+ lpRect.Right := lpRect.Left + MaxWidth;
+ lpRect.Bottom := LineRect.Top;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function ShortenString(DC: HDC; const S: WideString; Width: Integer; RTL: Boolean;
+ EllipsisWidth: Integer = 0): WideString;
+
+// Adjusts the given string S so that it fits into the given width. EllipsisWidth gives the width of
+// the three points to be added to the shorted string. If this value is 0 then it will be determined implicitely.
+// For higher speed (and multiple entries to be shorted) specify this value explicitely.
+// RTL determines if right-to-left reading is active, which is needed to put the ellipsisis on the correct side.
+// Note: It is assumed that the string really needs shortage. Check this in advance.
+
+var
+ Size: TSize;
+ Len: Integer;
+ L, H, N, W: Integer;
+
+begin
+ Len := Length(S);
+ if (Len = 0) or (Width <= 0) then
+ Result := ''
+ else
+ begin
+ // Determine width of triple point using the current DC settings (if not already done).
+ if EllipsisWidth = 0 then
+ begin
+ GetTextExtentPoint32W(DC, '...', 3, Size);
+ EllipsisWidth := Size.cx;
+ end;
+
+ if Width <= EllipsisWidth then
+ Result := ''
+ else
+ begin
+ // Do a binary search for the optimal string length which fits into the given width.
+ L := 0;
+ H := Len;
+ while L < H do
+ begin
+ N := (L + H + 1) shr 1;
+ GetTextExtentPoint32W(DC, PWideChar(S), N, Size);
+ W := Size.cx + EllipsisWidth;
+ if W <= Width then
+ L := N
+ else
+ H := N - 1;
+ end;
+
+ // Windows 2000/XP automatically switches the order in the string. For every other system we have to take care.
+ if IsWin2K or IsWinXP or not RTL then
+ Result := Copy(S, 1, L) + '...'
+ else
+ Result := '...' + Copy(S, 1, L);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure FillDragRectangles(DragWidth, DragHeight, DeltaX, DeltaY: Integer; var RClip, RScroll, RSamp1, RSamp2, RDraw1,
+ RDraw2: TRect);
+
+// Fills the given rectangles with values which can be used while dragging around an image
+// (used in DragMove of the drag manager and DragTo of the header columns).
+
+begin
+ // ScrollDC limits
+ RClip := Rect(0, 0, DragWidth, DragHeight);
+ if DeltaX > 0 then
+ begin
+ // move to the left
+ if DeltaY = 0 then
+ begin
+ // move only to the left
+ // background movement
+ RScroll := Rect(0, 0, DragWidth - DeltaX, DragHeight);
+ RSamp1 := Rect(0, 0, DeltaX, DragHeight);
+ RDraw1 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight);
+ end
+ else
+ if DeltaY < 0 then
+ begin
+ // move to bottom left
+ RScroll := Rect(0, -DeltaY, DragWidth - DeltaX, DragHeight);
+ RSamp1 := Rect(0, 0, DeltaX, DragHeight);
+ RSamp2 := Rect(DeltaX, DragHeight + DeltaY, DragWidth - DeltaX, -DeltaY);
+ RDraw1 := Rect(0, 0, DragWidth - DeltaX, -DeltaY);
+ RDraw2 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight);
+ end
+ else
+ begin
+ // move to upper left
+ RScroll := Rect(0, 0, DragWidth - DeltaX, DragHeight - DeltaY);
+ RSamp1 := Rect(0, 0, DeltaX, DragHeight);
+ RSamp2 := Rect(DeltaX, 0, DragWidth - DeltaX, DeltaY);
+ RDraw1 := Rect(0, DragHeight - DeltaY, DragWidth - DeltaX, DeltaY);
+ RDraw2 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight);
+ end;
+ end
+ else
+ if DeltaX = 0 then
+ begin
+ // vertical movement only
+ if DeltaY < 0 then
+ begin
+ // move downwards
+ RScroll := Rect(0, -DeltaY, DragWidth, DragHeight);
+ RSamp2 := Rect(0, DragHeight + DeltaY, DragWidth, -DeltaY);
+ RDraw2 := Rect(0, 0, DragWidth, -DeltaY);
+ end
+ else
+ begin
+ // move upwards
+ RScroll := Rect(0, 0, DragWidth, DragHeight - DeltaY);
+ RSamp2 := Rect(0, 0, DragWidth, DeltaY);
+ RDraw2 := Rect(0, DragHeight - DeltaY, DragWidth, DeltaY);
+ end;
+ end
+ else
+ begin
+ // move to the right
+ if DeltaY > 0 then
+ begin
+ // move up right
+ RScroll := Rect(-DeltaX, 0, DragWidth, DragHeight);
+ RSamp1 := Rect(0, 0, DragWidth + DeltaX, DeltaY);
+ RSamp2 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight);
+ RDraw1 := Rect(0, 0, -DeltaX, DragHeight);
+ RDraw2 := Rect(-DeltaX, DragHeight - DeltaY, DragWidth + DeltaX, DeltaY);
+ end
+ else
+ if DeltaY = 0 then
+ begin
+ // to the right only
+ RScroll := Rect(-DeltaX, 0, DragWidth, DragHeight);
+ RSamp1 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight);
+ RDraw1 := Rect(0, 0, -DeltaX, DragHeight);
+ end
+ else
+ begin
+ // move down right
+ RScroll := Rect(-DeltaX, -DeltaY, DragWidth, DragHeight);
+ RSamp1 := Rect(0, DragHeight + DeltaY, DragWidth + DeltaX, -DeltaY);
+ RSamp2 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight);
+ RDraw1 := Rect(0, 0, -DeltaX, DragHeight);
+ RDraw2 := Rect(-DeltaX, 0, DragWidth + DeltaX, -DeltaY);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlendLineConstant(Source, Destination: Pointer; Count: Integer; ConstantAlpha, Bias: Integer);
+
+// Blends a line of Count pixels from Source to Destination using a constant alpha value.
+// The layout of a pixel must be BGRA where A is ignored (but is calculated as the other components).
+// ConstantAlpha must be in the range 0..255 where 0 means totally transparent (destination pixel only)
+// and 255 totally opaque (source pixel only).
+// Bias is an additional value which gets added to every component and must be in the range -128..127
+//
+// EAX contains Source
+// EDX contains Destination
+// ECX contains Count
+// ConstantAlpha and Bias are on the stack
+
+asm
+ PUSH ESI // save used registers
+ PUSH EDI
+
+ MOV ESI, EAX // ESI becomes the actual source pointer
+ MOV EDI, EDX // EDI becomes the actual target pointer
+
+ // Load MM6 with the constant alpha value (replicate it for every component).
+ // Expand it to word size.
+ MOV EAX, [ConstantAlpha]
+ DB $0F, $6E, $F0 /// MOVD MM6, EAX
+ DB $0F, $61, $F6 /// PUNPCKLWD MM6, MM6
+ DB $0F, $62, $F6 /// PUNPCKLDQ MM6, MM6
+
+ // Load MM5 with the bias value.
+ MOV EAX, [Bias]
+ DB $0F, $6E, $E8 /// MOVD MM5, EAX
+ DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
+ DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
+
+ // Load MM4 with 128 to allow for saturated biasing.
+ MOV EAX, 128
+ DB $0F, $6E, $E0 /// MOVD MM4, EAX
+ DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
+ DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
+
+ at 1: // The pixel loop calculates an entire pixel in one run.
+ // Note: The pixel byte values are expanded into the higher bytes of a word due
+ // to the way unpacking works. We compensate for this with an extra shift.
+ DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
+ DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
+ DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
+ DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
+ DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
+ DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
+
+ // calculation is: target = (alpha * (source - target) + 256 * target) / 256
+ DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
+ DB $0F, $D5, $C6 /// PMULLW MM0, MM6, alpha * (source - target)
+ DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
+
+ // Bias is accounted for by conversion of range 0..255 to -128..127,
+ // doing a saturated add and convert back to 0..255.
+ DB $0F, $F9, $C4 /// PSUBW MM0, MM4
+ DB $0F, $ED, $C5 /// PADDSW MM0, MM5
+ DB $0F, $FD, $C4 /// PADDW MM0, MM4
+ DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
+ DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
+ at 3:
+ ADD ESI, 4
+ ADD EDI, 4
+ DEC ECX
+ JNZ @1
+ POP EDI
+ POP ESI
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlendLinePerPixel(Source, Destination: Pointer; Count, Bias: Integer);
+
+// Blends a line of Count pixels from Source to Destination using the alpha value of the source pixels.
+// The layout of a pixel must be BGRA.
+// Bias is an additional value which gets added to every component and must be in the range -128..127
+//
+// EAX contains Source
+// EDX contains Destination
+// ECX contains Count
+// Bias is on the stack
+
+asm
+ PUSH ESI // save used registers
+ PUSH EDI
+
+ MOV ESI, EAX // ESI becomes the actual source pointer
+ MOV EDI, EDX // EDI becomes the actual target pointer
+
+ // Load MM5 with the bias value.
+ MOV EAX, [Bias]
+ DB $0F, $6E, $E8 /// MOVD MM5, EAX
+ DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
+ DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
+
+ // Load MM4 with 128 to allow for saturated biasing.
+ MOV EAX, 128
+ DB $0F, $6E, $E0 /// MOVD MM4, EAX
+ DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
+ DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
+
+ at 1: // The pixel loop calculates an entire pixel in one run.
+ // Note: The pixel byte values are expanded into the higher bytes of a word due
+ // to the way unpacking works. We compensate for this with an extra shift.
+ DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
+ DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
+ DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
+ DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
+ DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
+ DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
+
+ // Load MM6 with the source alpha value (replicate it for every component).
+ // Expand it to word size.
+ DB $0F, $6F, $F0 /// MOVQ MM6, MM0
+ DB $0F, $69, $F6 /// PUNPCKHWD MM6, MM6
+ DB $0F, $6A, $F6 /// PUNPCKHDQ MM6, MM6
+
+ // calculation is: target = (alpha * (source - target) + 256 * target) / 256
+ DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
+ DB $0F, $D5, $C6 /// PMULLW MM0, MM6, alpha * (source - target)
+ DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
+
+ // Bias is accounted for by conversion of range 0..255 to -128..127,
+ // doing a saturated add and convert back to 0..255.
+ DB $0F, $F9, $C4 /// PSUBW MM0, MM4
+ DB $0F, $ED, $C5 /// PADDSW MM0, MM5
+ DB $0F, $FD, $C4 /// PADDW MM0, MM4
+ DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
+ DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
+ at 3:
+ ADD ESI, 4
+ ADD EDI, 4
+ DEC ECX
+ JNZ @1
+ POP EDI
+ POP ESI
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlendLineMaster(Source, Destination: Pointer; Count: Integer; ConstantAlpha, Bias: Integer);
+
+// Blends a line of Count pixels from Source to Destination using the source pixel and a constant alpha value.
+// The layout of a pixel must be BGRA.
+// ConstantAlpha must be in the range 0..255.
+// Bias is an additional value which gets added to every component and must be in the range -128..127
+//
+// EAX contains Source
+// EDX contains Destination
+// ECX contains Count
+// ConstantAlpha and Bias are on the stack
+
+asm
+ PUSH ESI // save used registers
+ PUSH EDI
+
+ MOV ESI, EAX // ESI becomes the actual source pointer
+ MOV EDI, EDX // EDI becomes the actual target pointer
+
+ // Load MM6 with the constant alpha value (replicate it for every component).
+ // Expand it to word size.
+ MOV EAX, [ConstantAlpha]
+ DB $0F, $6E, $F0 /// MOVD MM6, EAX
+ DB $0F, $61, $F6 /// PUNPCKLWD MM6, MM6
+ DB $0F, $62, $F6 /// PUNPCKLDQ MM6, MM6
+
+ // Load MM5 with the bias value.
+ MOV EAX, [Bias]
+ DB $0F, $6E, $E8 /// MOVD MM5, EAX
+ DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5
+ DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5
+
+ // Load MM4 with 128 to allow for saturated biasing.
+ MOV EAX, 128
+ DB $0F, $6E, $E0 /// MOVD MM4, EAX
+ DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4
+ DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4
+
+ at 1: // The pixel loop calculates an entire pixel in one run.
+ // Note: The pixel byte values are expanded into the higher bytes of a word due
+ // to the way unpacking works. We compensate for this with an extra shift.
+ DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking
+ DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes
+ DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking
+ DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words
+ DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again
+ DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes
+
+ // Load MM7 with the source alpha value (replicate it for every component).
+ // Expand it to word size.
+ DB $0F, $6F, $F8 /// MOVQ MM7, MM0
+ DB $0F, $69, $FF /// PUNPCKHWD MM7, MM7
+ DB $0F, $6A, $FF /// PUNPCKHDQ MM7, MM7
+ DB $0F, $D5, $FE /// PMULLW MM7, MM6, source alpha * master alpha
+ DB $0F, $71, $D7, $08 /// PSRLW MM7, 8, divide by 256
+
+ // calculation is: target = (alpha * master alpha * (source - target) + 256 * target) / 256
+ DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target
+ DB $0F, $D5, $C7 /// PMULLW MM0, MM7, alpha * (source - target)
+ DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form)
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256
+
+ // Bias is accounted for by conversion of range 0..255 to -128..127,
+ // doing a saturated add and convert back to 0..255.
+ DB $0F, $F9, $C4 /// PSUBW MM0, MM4
+ DB $0F, $ED, $C5 /// PADDSW MM0, MM5
+ DB $0F, $FD, $C4 /// PADDW MM0, MM4
+ DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation
+ DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result
+ at 3:
+ ADD ESI, 4
+ ADD EDI, 4
+ DEC ECX
+ JNZ @1
+ POP EDI
+ POP ESI
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlendLineMasterAndColor(Destination: Pointer; Count: Integer; ConstantAlpha, Color: Integer);
+
+// Blends a line of Count pixels in Destination against the given color using a constant alpha value.
+// The layout of a pixel must be BGRA and Color must be rrggbb00 (as stored by a COLORREF).
+// ConstantAlpha must be in the range 0..255.
+//
+// EAX contains Destination
+// EDX contains Count
+// ECX contains ConstantAlpha
+// Color is passed on the stack
+
+asm
+ // The used formula is: target = (alpha * color + (256 - alpha) * target) / 256.
+ // alpha * color (factor 1) and 256 - alpha (factor 2) are constant values which can be calculated in advance.
+ // The remaining calculation is therefore: target = (F1 + F2 * target) / 256
+
+ // Load MM3 with the constant alpha value (replicate it for every component).
+ // Expand it to word size. (Every calculation here works on word sized operands.)
+ DB $0F, $6E, $D9 /// MOVD MM3, ECX
+ DB $0F, $61, $DB /// PUNPCKLWD MM3, MM3
+ DB $0F, $62, $DB /// PUNPCKLDQ MM3, MM3
+
+ // Calculate factor 2.
+ MOV ECX, $100
+ DB $0F, $6E, $D1 /// MOVD MM2, ECX
+ DB $0F, $61, $D2 /// PUNPCKLWD MM2, MM2
+ DB $0F, $62, $D2 /// PUNPCKLDQ MM2, MM2
+ DB $0F, $F9, $D3 /// PSUBW MM2, MM3 // MM2 contains now: 255 - alpha = F2
+
+ // Now calculate factor 1. Alpha is still in MM3, but the r and b components of Color must be swapped.
+ MOV ECX, [Color]
+ BSWAP ECX
+ ROR ECX, 8
+ DB $0F, $6E, $C9 /// MOVD MM1, ECX // Load the color and convert to word sized values.
+ DB $0F, $EF, $E4 /// PXOR MM4, MM4
+ DB $0F, $60, $CC /// PUNPCKLBW MM1, MM4
+ DB $0F, $D5, $CB /// PMULLW MM1, MM3 // MM1 contains now: color * alpha = F1
+
+ at 1: // The pixel loop calculates an entire pixel in one run.
+ DB $0F, $6E, $00 /// MOVD MM0, [EAX]
+ DB $0F, $60, $C4 /// PUNPCKLBW MM0, MM4
+
+ DB $0F, $D5, $C2 /// PMULLW MM0, MM2 // calculate F1 + F2 * target
+ DB $0F, $FD, $C1 /// PADDW MM0, MM1
+ DB $0F, $71, $D0, $08 /// PSRLW MM0, 8 // divide by 256
+
+ DB $0F, $67, $C0 /// PACKUSWB MM0, MM0 // convert words to bytes with saturation
+ DB $0F, $7E, $00 /// MOVD [EAX], MM0 // store the result
+
+ ADD EAX, 4
+ DEC EDX
+ JNZ @1
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure EMMS;
+
+// Reset MMX state to use the FPU for other tasks again.
+
+asm
+ DB $0F, $77 /// EMMS
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function GetBitmapBitsFromDeviceContext(DC: HDC; var Width, Height: Integer): Pointer;
+
+// Helper function used to retrieve the bitmap selected into the given device context. If there is a bitmap then
+// the function will return a pointer to its bits otherwise nil is returned.
+// Additionally the dimensions of the bitmap are returned.
+
+var
+ Bitmap: HBITMAP;
+ DIB: TDIBSection;
+
+begin
+ Result := nil;
+ Width := 0;
+ Height := 0;
+
+ Bitmap := GetCurrentObject(DC, OBJ_BITMAP);
+ if Bitmap <> 0 then
+ begin
+ if GetObject(Bitmap, SizeOf(DIB), @DIB) = SizeOf(DIB) then
+ begin
+ Assert(DIB.dsBm.bmPlanes * DIB.dsBm.bmBitsPixel = 32, 'Alpha blending error: bitmap must use 32 bpp.');
+ Result := DIB.dsBm.bmBits;
+ Width := DIB.dsBmih.biWidth;
+ Height := DIB.dsBmih.biHeight;
+ end;
+ end;
+ Assert(Result <> nil, 'Alpha blending DC error: no bitmap available.');
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function CalculateScanline(Bits: Pointer; Width, Height, Row: Integer): Pointer;
+
+// Helper function to calculate the start address for the given row.
+
+begin
+ if Height > 0 then // bottom-up DIB
+ Row := Height - Row - 1;
+ // Return DWORD aligned address of the requested scanline.
+ Integer(Result) := Integer(Bits) + Row * ((Width * 32 + 31) and not 31) div 8;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure AlphaBlend(Source, Destination: HDC; R: TRect; Target: TPoint; Mode: TBlendMode; ConstantAlpha, Bias: Integer);
+
+// Optimized alpha blend procedure using MMX instructions to perform as quick as possible.
+// For this procedure to work properly it is important that both source and target bitmap use the 32 bit color format.
+// R describes the source rectangle to work on.
+// Target is the place (upper left corner) in the target bitmap where to blend to. Note that source width + X offset
+// must be less or equal to the target width. Similar for the height.
+// If Mode is bmConstantAlpha then the blend operation uses the given ConstantAlpha value for all pixels.
+// If Mode is bmPerPixelAlpha then each pixel is blended using its individual alpha value (the alpha value of the source).
+// If Mode is bmMasterAlpha then each pixel is blended using its individual alpha value multiplied by ConstantAlpha.
+// If Mode is bmConstantAlphaAndColor then each destination pixel is blended using ConstantAlpha but also a constant
+// color which will be obtained from Bias. In this case no offset value is added, otherwise Bias is used as offset.
+// Blending of a color into target only (bmConstantAlphaAndColor) ignores Source (the DC) and Target (the position).
+// CAUTION: This procedure does not check whether MMX instructions are actually available! Call it only if MMX is really
+// usable.
+
+var
+ Y: Integer;
+ SourceRun,
+ TargetRun: PByte;
+
+ SourceBits,
+ DestBits: Pointer;
+ SourceWidth,
+ SourceHeight,
+ DestWidth,
+ DestHeight: Integer;
+
+begin
+ if not IsRectEmpty(R) then
+ begin
+ // Note: it is tempting to optimize the special cases for constant alpha 0 and 255 by just ignoring soure
+ // (alpha = 0) or simply do a blit (alpha = 255). But this does not take the bias into account.
+ case Mode of
+ bmConstantAlpha:
+ begin
+ // Get a pointer to the bitmap bits for the source and target device contexts.
+ // Note: this supposes that both contexts do actually have bitmaps assigned!
+ SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
+ DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
+ if Assigned(SourceBits) and Assigned(DestBits) then
+ begin
+ for Y := 0 to R.Bottom - R.Top - 1 do
+ begin
+ SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
+ Inc(SourceRun, 4 * R.Left);
+ TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
+ Inc(TargetRun, 4 * Target.X);
+ AlphaBlendLineConstant(SourceRun, TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
+ end;
+ end;
+ EMMS;
+ end;
+ bmPerPixelAlpha:
+ begin
+ SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
+ DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
+ if Assigned(SourceBits) and Assigned(DestBits) then
+ begin
+ for Y := 0 to R.Bottom - R.Top - 1 do
+ begin
+ SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
+ Inc(SourceRun, 4 * R.Left);
+ TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
+ Inc(TargetRun, 4 * Target.X);
+ AlphaBlendLinePerPixel(SourceRun, TargetRun, R.Right - R.Left, Bias);
+ end;
+ end;
+ EMMS;
+ end;
+ bmMasterAlpha:
+ begin
+ SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight);
+ DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
+ if Assigned(SourceBits) and Assigned(DestBits) then
+ begin
+ for Y := 0 to R.Bottom - R.Top - 1 do
+ begin
+ SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top);
+ Inc(SourceRun, 4 * Target.X);
+ TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y);
+ AlphaBlendLineMaster(SourceRun, TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
+ end;
+ end;
+ EMMS;
+ end;
+ bmConstantAlphaAndColor:
+ begin
+ // Source is ignored since there is a constant color value.
+ DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight);
+ if Assigned(DestBits) then
+ begin
+ for Y := 0 to R.Bottom - R.Top - 1 do
+ begin
+ TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + R.Top);
+ Inc(TargetRun, 4 * R.Left);
+ AlphaBlendLineMasterAndColor(TargetRun, R.Right - R.Left, ConstantAlpha, Bias);
+ end;
+ end;
+ EMMS;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function GetRGBColor(Value: TColor): DWORD;
+
+// Little helper to convert a Delphi color to an image list color.
+
+begin
+ Result := ColorToRGB(Value);
+ case Result of
+ clNone:
+ Result := CLR_NONE;
+ clDefault:
+ Result := CLR_DEFAULT;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+const
+ Grays: array[0..3] of TColor = (clWhite, clSilver, clGray, clBlack);
+ SysGrays: array[0..3] of TColor = (clWindow, clBtnFace, clBtnShadow, clBtnText);
+
+procedure ConvertImageList(IL: TImageList; const ImageName: string; ColorRemapping: Boolean = True);
+
+// Loads a bunch of images given by ImageName into IL. If ColorRemapping = True then a mapping of gray values to
+// system colors is performed.
+
+var
+ Images,
+ OneImage: TBitmap;
+ I: Integer;
+ MaskColor: TColor;
+ Source,
+ Dest: TRect;
+
+begin
+ Watcher.Enter;
+ try
+ // Since we want the image list appearing in the correct system colors, we have to remap its colors.
+ Images := TBitmap.Create;
+ OneImage := TBitmap.Create;
+ if ColorRemapping then
+ Images.Handle := CreateMappedRes(FindClassHInstance(TBaseVirtualTree), PChar(ImageName), Grays, SysGrays)
+ else
+ Images.Handle := LoadBitmap(FindClassHInstance(TBaseVirtualTree), PChar(ImageName));
+
+ try
+ Assert(Images.Height > 0, 'Internal image "' + ImageName + '" is missing or corrupt.');
+
+ // It is assumed that the image height determines also the width of one entry in the image list.
+ IL.Clear;
+ IL.Height := Images.Height;
+ IL.Width := Images.Height;
+ OneImage.Width := IL.Width;
+ OneImage.Height := IL.Height;
+ MaskColor := Images.Canvas.Pixels[0, 0]; // this is usually clFuchsia
+ Dest := Rect(0, 0, IL.Width, IL.Height);
+ for I := 0 to (Images.Width div Images.Height) - 1 do
+ begin
+ Source := Rect(I * IL.Width, 0, (I + 1) * IL.Width, IL.Height);
+ OneImage.Canvas.CopyRect(Dest, Images.Canvas, Source);
+ IL.AddMasked(OneImage, MaskColor);
+ end;
+ finally
+ Images.Free;
+ OneImage.Free;
+ end;
+ finally
+ Watcher.Leave;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure CreateSystemImageSet(var IL: TImageList; Flags: Cardinal; Flat: Boolean);
+
+// Creates a system check image set.
+// Note: the DarkCheckImages image list must already be filled, as some images from it are copied here.
+
+const
+ MaskColor: TColor = clFuchsia;
+
+ //--------------- local functions -------------------------------------------
+
+ procedure AddNodeImages(IL: TImageList);
+
+ var
+ BM: TBitmap;
+ I: Integer;
+ OffsetX,
+ OffsetY: Integer;
+
+ begin
+ BM := TBitmap.Create;
+ // Make the bitmap the same size as the image list has to avoid problems when adding.
+ BM.Width := IL.Width;
+ BM.Height := IL.Height;
+ // The offsets are used to center the node images in case the sizes differ.
+ OffsetX := (IL.Width - DarkCheckImages.Width) div 2;
+ OffsetY := (IL.Height - DarkCheckImages.Height) div 2;
+ try
+ for I := 20 to 23 do
+ begin
+ DarkCheckImages.Draw(BM.Canvas, OffsetX, OffsetY, I);
+ IL.AddMasked(BM, DarkCheckImages.BkColor);
+ end;
+ finally
+ BM.Free;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure AddSystemImage(IL: TImageList; Flat: Boolean; Index: Integer);
+
+ var
+ BM: TBitmap;
+ ButtonState: Cardinal;
+ ButtonType: Cardinal;
+
+ begin
+ BM := TBitmap.Create;
+ try
+ BM.Width := IL.Width;
+ BM.Height := IL.Height;
+ BM.Canvas.Brush.Color := MaskColor;
+ BM.Canvas.Brush.Style := bsSolid;
+ BM.Canvas.FillRect(Rect(0, 0, BM.Width, BM.Height));
+ BM.Canvas.Brush.Style := bsClear;
+ if Index <= 8 then
+ ButtonType := DFCS_BUTTONRADIO
+ else
+ ButtonType := DFCS_BUTTONCHECK;
+ if Index >= 17 then
+ ButtonType := ButtonType or DFCS_BUTTON3STATE or DFCS_INACTIVE;
+
+ case Index mod 4 of
+ 1:
+ ButtonState := 0;
+ 2:
+ ButtonState := DFCS_HOT;
+ 3:
+ ButtonState := DFCS_PUSHED;
+ else
+ ButtonState := DFCS_INACTIVE;
+ end;
+ if Index in [5..8, 13..16] then
+ ButtonState := ButtonState or DFCS_CHECKED;
+ if Flat then
+ ButtonState := ButtonState or DFCS_FLAT;
+ DrawFrameControl(BM.Canvas.Handle, Rect(1, 2, BM.Width - 2, BM.Height - 1), DFC_BUTTON, ButtonType or ButtonState);
+ IL.AddMasked(BM, MaskColor);
+ finally
+ BM.Free
+ end;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ I, Width, Height: Integer;
+
+begin
+ Width := GetSystemMetrics(SM_CXMENUCHECK) + 3;
+ Height := GetSystemMetrics(SM_CYMENUCHECK) + 3;
+ IL := TImageList.CreateSize(Width, Height);
+ with IL do
+ Handle := ImageList_Create(Width, Height, Flags, 0, AllocBy);
+ IL.Masked := True;
+ // Add the 20 system checkbox and radiobutton images.
+ for I := 0 to 19 do
+ AddSystemImage(IL, Flat, I);
+ // Add the 4 node images from the dark check set.
+ AddNodeImages(IL);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function HasMMX: Boolean;
+
+// Helper method to determine whether the current processor supports MMX.
+
+asm
+ PUSH EBX
+ XOR EAX, EAX // Result := False
+ PUSHFD // determine if the processor supports the CPUID command
+ POP EDX
+ MOV ECX, EDX
+ XOR EDX, $200000
+ PUSH EDX
+ POPFD
+ PUSHFD
+ POP EDX
+ XOR ECX, EDX
+ JZ @1 // no CPUID support so we can't even get to the feature information
+ PUSH EDX
+ POPFD
+
+ MOV EAX, 1
+ DW $A20F // CPUID, EAX contains now version info and EDX feature information
+ MOV EBX, EAX // free EAX to get the result value
+ XOR EAX, EAX // Result := False
+ CMP EBX, $50
+ JB @1 // if processor family is < 5 then it is not a Pentium class processor
+ TEST EDX, $800000
+ JZ @1 // if the MMX bit is not set then we don't have MMX
+ INC EAX // Result := True
+ at 1:
+ POP EBX
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure PrtStretchDrawDIB(Canvas: TCanvas; DestRect: TRect; ABitmap: TBitmap);
+
+// Stretch draw on to the new canvas.
+
+var
+ Header,
+ Bits: Pointer;
+ HeaderSize,
+ BitsSize: Cardinal;
+
+begin
+ GetDIBSizes(ABitmap.Handle, HeaderSize, BitsSize);
+
+ GetMem(Header, HeaderSize);
+ GetMem(Bits, BitsSize);
+ try
+ GetDIB(ABitmap.Handle, ABitmap.Palette, Header^, Bits^);
+ StretchDIBits(Canvas.Handle, DestRect.Left, DestRect.Top, DestRect.Right - DestRect.Left, DestRect.Bottom -
+ DestRect.Top, 0, 0, ABitmap.Width, ABitmap.Height, Bits, TBitmapInfo(Header^), DIB_RGB_COLORS, SRCCOPY);
+ finally
+ FreeMem(Header);
+ FreeMem(Bits);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure InitializeGlobalStructures;
+
+// initialization of stuff global to the unit
+
+var
+ {$ifndef COMPILER_5_UP}
+ NonClientMetrics: TNonClientMetrics;
+ {$endif COMPILER_5_UP}
+ Flags: Cardinal;
+
+begin
+ Initialized := True;
+
+ // For the drag image a fast MMX blend routine is used. We have to make sure MMX is available.
+ MMXAvailable := HasMMX;
+
+ // There is a bug in Win95 and WinME (and potentially in Win98 too) regarding GetDCEx which causes sometimes
+ // serious trouble within GDI (see method WMNCPaint).
+ IsWinNT := (Win32Platform and VER_PLATFORM_WIN32_NT) <> 0;
+ IsWin2K := (Win32MajorVersion = 5) and (Win32MinorVersion = 0);
+ IsWinXP := (Win32MajorVersion = 5) and (Win32MinorVersion = 1);
+
+ // Initialize OLE subsystem for drag'n drop and clipboard operations.
+ NeedToUnitialize := Succeeded(OleInitialize(nil));
+
+ // Register the tree reference clipboard format. Others will be handled in InternalClipboarFormats.
+ CF_VTREFERENCE := RegisterClipboardFormat(CFSTR_VTREFERENCE);
+
+ // Load all internal image lists and convert their colors to current desktop color scheme.
+ // In order to use high color images we have to create the image list handle ourselves.
+ if IsWinNT then
+ Flags := ILC_COLOR32 or ILC_MASK
+ else
+ Flags := ILC_COLOR16 or ILC_MASK;
+ LightCheckImages := TImageList.Create(nil);
+ with LightCheckImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(LightCheckImages, 'VT_CHECK_LIGHT');
+
+ DarkCheckImages := TImageList.CreateSize(16, 16);
+ with DarkCheckImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(DarkCheckImages, 'VT_CHECK_DARK');
+
+ LightTickImages := TImageList.CreateSize(16, 16);
+ with LightTickImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(LightTickImages, 'VT_TICK_LIGHT');
+
+ DarkTickImages := TImageList.CreateSize(16, 16);
+ with DarkTickImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(DarkTickImages, 'VT_TICK_DARK');
+
+ FlatImages := TImageList.CreateSize(16, 16);
+ with FlatImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(FlatImages, 'VT_FLAT');
+
+ XPImages := TImageList.CreateSize(16, 16);
+ with XPImages do
+ Handle := ImageList_Create(16, 16, Flags, 0, AllocBy);
+ ConvertImageList(XPImages, 'VT_XP', False);
+
+ UtilityImages := TImageList.CreateSize(UtilityImageSize, UtilityImageSize);
+ with UtilityImages do
+ Handle := ImageList_Create(UtilityImageSize, UtilityImageSize, Flags, 0, AllocBy);
+ ConvertImageList(UtilityImages, 'VT_UTILITIES');
+
+ CreateSystemImageSet(SystemCheckImages, Flags, False);
+ CreateSystemImageSet(SystemFlatCheckImages, Flags, True);
+
+ {$ifndef COMPILER_5_UP}
+ // In Delphi 4 there is no TScreen.HintFont hence we have to manage this manually.
+ HintFont := TFont.Create;
+ NonClientMetrics.cbSize := SizeOf(NonClientMetrics);
+ if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
+ HintFont.Handle := CreateFontIndirect(NonClientMetrics.lfStatusFont)
+ else
+ HintFont.Size := 8;
+ {$endif COMPILER_5_UP}
+
+ // Specify an useful timer resolution for timeGetTime.
+ timeBeginPeriod(MinimumTimerInterval);
+
+ // Delphi (at least version 6 and lower) does not provide a standard split cursor.
+ // Hence we have to load our own.
+ Screen.Cursors[crHeaderSplit] := LoadCursor(HInstance, 'VT_HEADERSPLIT');
+
+ // Clipboard format registration.
+ // Native clipboard format. Needs a new identifier and has an average priority to allow other formats to take over.
+ // This format is supposed to use the IStream storage format but unfortunately this does not work when
+ // OLEFlushClipboard is used. Hence it is disabled until somebody finds a solution.
+ CF_VIRTUALTREE := RegisterVTClipboardFormat(CFSTR_VIRTUALTREE, TBaseVirtualTree, 50, TYMED_HGLOBAL {or TYMED_ISTREAM});
+ // Specialized string tree formats.
+ CF_HTML := RegisterVTClipboardFormat(CFSTR_HTML, TCustomVirtualStringTree, 80);
+ CF_VRTFNOOBJS := RegisterVTClipboardFormat(CFSTR_RTFNOOBJS, TCustomVirtualStringTree, 84);
+ CF_VRTF := RegisterVTClipboardFormat(CFSTR_RTF, TCustomVirtualStringTree, 85);
+ CF_CSV := RegisterVTClipboardFormat(CFSTR_CSV, TCustomVirtualStringTree, 90);
+ // Predefined clipboard formats. Just add them to the internal list.
+ RegisterVTClipboardFormat(CF_TEXT, TCustomVirtualStringTree, 100);
+ RegisterVTClipboardFormat(CF_UNICODETEXT, TCustomVirtualStringTree, 95);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure FinalizeGlobalStructures;
+
+var
+ HintWasEnabled: Boolean;
+
+begin
+ timeEndPeriod(MinimumTimerInterval);
+ {$ifndef COMPILER_5_UP}
+ HintFont.Free;
+ {$endif COMPILER_5_UP}
+
+ LightCheckImages.Free;
+ DarkCheckImages.Free;
+ LightTickImages.Free;
+ DarkTickImages.Free;
+ FlatImages.Free;
+ XPImages.Free;
+ UtilityImages.Free;
+ SystemCheckImages.Free;
+ SystemFlatCheckImages.Free;
+
+ if NeedToUnitialize then
+ OleUninitialize;
+
+ // If VT is used in a package and its special hint window was used then the last instance of this
+ // window is not freed correctly (bug in the VCL). We explicitely tell the application to free it
+ // otherwise an AV is raised due to access to an invalid memory area.
+ if ModuleIsPackage then
+ begin
+ HintWasEnabled := Application.ShowHint;
+ Application.ShowHint := False;
+ if HintWasEnabled then
+ Application.ShowHint := True;
+ end;
+end;
+
+//----------------- TWorkerThread --------------------------------------------------------------------------------------
+
+procedure AddThreadReference;
+
+begin
+ if WorkerThread = nil then
+ begin
+ // Create an event used to trigger our worker thread when something is to do.
+ WorkEvent := CreateEvent(nil, False, False, nil);
+ if WorkEvent = 0 then
+ RaiseLastOSError;
+
+ // Create worker thread, initialize it and send it to its wait loop.
+ WorkerThread := TWorkerThread.Create(False);
+ end;
+ Inc(WorkerThread.FRefCount);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure ReleaseThreadReference(Tree: TBaseVirtualTree);
+
+begin
+ if Assigned(WorkerThread) then
+ begin
+ Dec(WorkerThread.FRefCount);
+
+ // Make sure there is no reference remaining to the releasing tree.
+ Tree.InterruptValidation;
+
+ if WorkerThread.FRefCount = 0 then
+ begin
+ with WorkerThread do
+ begin
+ Terminate;
+ SetEvent(WorkEvent);
+
+ // The following work around is no longer necessary with Delphi 6 and up.
+ {$ifndef COMPILER_6_UP}
+ // There is a problem when the thread is freed in the exit code of a DLL. This can happen when a tree is
+ // destroyed on unload of a DLL (e.g. control panel applet). In this case only the main thread will get
+ // CPU time, other threads will never awake again. The VCL however waits for a thread when freeing it
+ // which will result in a deadlock (the WaitFor call does not return because the thread does not get CPU time).
+ // If a thread is however suspended then the VCL does not wait and all is fine.
+ if IsLibrary then
+ Suspend;
+ {$endif COMPILER_6_UP}
+
+ WorkerThread.Free;
+ end;
+ WorkerThread := nil;
+ CloseHandle(WorkEvent);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+constructor TWorkerThread.Create(CreateSuspended: Boolean);
+
+begin
+ inherited Create(CreateSuspended);
+ FWaiterList := TThreadList.Create;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TWorkerThread.Destroy;
+
+begin
+ FWaiterList.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWorkerThread.ChangeTreeStates(EnterStates, LeaveStates: TChangeStates);
+
+begin
+ if Assigned(FCurrentTree) and (FCurrentTree.HandleAllocated) then
+ PostMessage(FCurrentTree.Handle, WM_CHANGESTATE, Byte(EnterStates), Byte(LeaveStates));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWorkerThread.Execute;
+
+// Does some background tasks, like validating tree caches.
+
+var
+ EnterStates,
+ LeaveStates: TChangeStates;
+
+begin
+ while not Terminated do
+ begin
+ WaitForSingleObject(WorkEvent, INFINITE);
+ if not Terminated then
+ begin
+ // Get the next waiting tree.
+ with FWaiterList.LockList do
+ try
+ if Count > 0 then
+ begin
+ FCurrentTree := Items[0];
+ // Remove this tree from waiter list.
+ Delete(0);
+ end
+ else
+ FCurrentTree := nil;
+ finally
+ FWaiterList.UnlockList;
+ end;
+
+ // Something to do?
+ try
+ if Assigned(FCurrentTree) and not (tsStopValidation in FCurrentTree.FStates) then
+ begin
+ ChangeTreeStates([csValidating], [csUseCache]);
+ EnterStates := [];
+ if FCurrentTree.DoValidateCache then
+ EnterStates := [csUseCache];
+ end;
+ finally
+ LeaveStates := [csValidating, csStopValidation];
+ if csUseCache in EnterStates then
+ Include(LeaveStates, csValidationNeeded);
+ ChangeTreeStates(EnterStates, LeaveStates);
+ FCurrentTree := nil;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWorkerThread.AddTree(Tree: TBaseVirtualTree);
+
+begin
+ Assert(Assigned(Tree), 'Tree must not be nil.');
+
+ with FWaiterList.LockList do
+ try
+ if IndexOf(Tree) = -1 then
+ Add(Tree);
+ finally
+ FWaiterList.UnlockList;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWorkerThread.RemoveTree(Tree: TBaseVirtualTree);
+
+begin
+ Assert(Assigned(Tree), 'Tree must not be nil.');
+
+ if FCurrentTree = Tree then
+ FCurrentTree := nil;
+
+ with FWaiterList.LockList do
+ try
+ Remove(Tree);
+ finally
+ FWaiterList.UnlockList;
+ end;
+end;
+
+//----------------- TBufferedString ------------------------------------------------------------------------------------
+
+const
+ AllocIncrement = 4096;
+
+destructor TBufferedString.Destroy;
+
+begin
+ FreeMem(FStart);
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBufferedString.GetAsString: string;
+
+begin
+ SetString(Result, FStart, FPosition - FStart);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBufferedString.Add(const S: string);
+
+var
+ LastLen,
+ LastOffset,
+ Len: Integer;
+
+begin
+ Len := Length(S);
+ // Make room for the new string.
+ if FEnd - FPosition <= Len then
+ begin
+ // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned.
+ LastLen := FEnd - FStart;
+ LastOffset := FPosition - FStart;
+ ReallocMem(FStart, FEnd - FStart + AllocIncrement);
+ FPosition := FStart + LastOffset;
+ FEnd := FStart + LastLen + AllocIncrement;
+ end;
+ Move(PChar(S)^, FPosition^, Len);
+ Inc(FPosition, Len);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBufferedString.AddNewLine;
+
+var
+ LastLen,
+ LastOffset: Integer;
+
+begin
+ // Make room for the CR/LF characters.
+ if FEnd - FPosition <= 2 then
+ begin
+ // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned.
+ LastLen := FEnd - FStart;
+ LastOffset := FPosition - FStart;
+ ReallocMem(FStart, FEnd - FStart + AllocIncrement);
+ FPosition := FStart + LastOffset;
+ FEnd := FStart + LastLen + AllocIncrement;
+ end;
+ FPosition^ := #13;
+ Inc(FPosition);
+ FPosition^ := #10;
+ Inc(FPosition);
+end;
+
+//----------------- TWideBufferedString --------------------------------------------------------------------------------
+
+destructor TWideBufferedString.Destroy;
+
+begin
+ FreeMem(FStart);
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TWideBufferedString.GetAsString: WideString;
+
+begin
+ SetString(Result, FStart, FPosition - FStart);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWideBufferedString.Add(const S: WideString);
+
+var
+ LastLen,
+ LastOffset,
+ Len: Integer;
+
+begin
+ Len := Length(S);
+ // Make room for the new string.
+ if FEnd - FPosition <= Len then
+ begin
+ // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned.
+ LastLen := FEnd - FStart;
+ LastOffset := FPosition - FStart;
+ ReallocMem(FStart, 2 * (FEnd - FStart + AllocIncrement));
+ FPosition := FStart + LastOffset;
+ FEnd := FStart + LastLen + AllocIncrement;
+ end;
+ Move(PWideChar(S)^, FPosition^, 2 * Len);
+ Inc(FPosition, Len);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TWideBufferedString.AddNewLine;
+
+var
+ LastLen,
+ LastOffset: Integer;
+
+begin
+ // Make room for the CR/LF characters.
+ if FEnd - FPosition <= 4 then
+ begin
+ // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned.
+ LastLen := FEnd - FStart;
+ LastOffset := FPosition - FStart;
+ ReallocMem(FStart, 2 * (FEnd - FStart + AllocIncrement));
+ FPosition := FStart + LastOffset;
+ FEnd := FStart + LastLen + AllocIncrement;
+ end;
+ FPosition^ := #13;
+ Inc(FPosition);
+ FPosition^ := #10;
+ Inc(FPosition);
+end;
+
+//----------------- TCustomVirtualTreeOptions --------------------------------------------------------------------------
+
+constructor TCustomVirtualTreeOptions.Create(AOwner: TBaseVirtualTree);
+
+begin
+ FOwner := AOwner;
+
+ FPaintOptions := DefaultPaintOptions;
+ FAnimationOptions := DefaultAnimationOptions;
+ FAutoOptions := DefaultAutoOptions;
+ FSelectionOptions := DefaultSelectionOptions;
+ FMiscOptions := DefaultMiscOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetAnimationOptions(const Value: TVTAnimationOptions);
+
+begin
+ FAnimationOptions := Value;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetAutoOptions(const Value: TVTAutoOptions);
+
+var
+ ChangedOptions: TVTAutoOptions;
+
+begin
+ if FAutoOptions <> Value then
+ begin
+ // Exclusive ORing to get all entries wich are in either set but not in both.
+ ChangedOptions := FAutoOptions + Value - (FAutoOptions * Value);
+ FAutoOptions := Value;
+ with FOwner do
+ if (toAutoSpanColumns in ChangedOptions) and not (csLoading in ComponentState) and HandleAllocated then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetMiscOptions(const Value: TVTMiscOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTMiscOptions;
+
+begin
+ if FMiscOptions <> Value then
+ begin
+ ToBeSet := Value - FMiscOptions;
+ ToBeCleared := FMiscOptions - Value;
+ FMiscOptions := Value;
+
+ with FOwner do
+ if not (csLoading in ComponentState) and HandleAllocated then
+ begin
+ if toCheckSupport in ToBeSet + ToBeCleared then
+ Invalidate;
+ if not (csDesigning in ComponentState) then
+ begin
+ if toFullRepaintOnResize in TobeSet + ToBeCleared then
+ RecreateWnd;
+ if toAcceptOLEDrop in ToBeSet then
+ RegisterDragDrop(Handle, DragManager as IDropTarget);
+ if toAcceptOLEDrop in ToBeCleared then
+ RevokeDragDrop(Handle);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetPaintOptions(const Value: TVTPaintOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTPaintOptions;
+
+begin
+ if FPaintOptions <> Value then
+ begin
+ ToBeSet := Value - FPaintOptions;
+ ToBeCleared := FPaintOptions - Value;
+ FPaintOptions := Value;
+ with FOwner do
+ if not (csLoading in ComponentState) and HandleAllocated then
+ begin
+ {$ifdef ThemeSupport}
+ if toThemeAware in ToBeSet + ToBeCleared then
+ begin
+ if (toThemeAware in ToBeSet) and ThemeServices.ThemesEnabled then
+ DoStateChange([tsUseThemes])
+ else
+ DoStateChange([], [tsUseThemes]);
+ PrepareBitmaps(True, False);
+ RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_VALIDATE or RDW_FRAME);
+ end
+ else
+ {$endif ThemeSupport}
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.SetSelectionOptions(const Value: TVTSelectionOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTSelectionOptions;
+
+begin
+ if FSelectionOptions <> Value then
+ begin
+ ToBeSet := Value - FSelectionOptions;
+ ToBeCleared := FSelectionOptions - Value;
+ FSelectionOptions := Value;
+
+ with FOwner do
+ begin
+ if (toMultiSelect in (ToBeCleared + ToBeSet)) or
+ ([toLevelSelectConstraint, toSiblingSelectConstraint] * ToBeSet <> []) then
+ ClearSelection;
+
+ if (toExtendedFocus in ToBeCleared) and (FFocusedColumn > 0) and HandleAllocated then
+ begin
+ FFocusedColumn := FHeader.MainColumn;
+ Invalidate;
+ end;
+
+ if not (toExtendedFocus in FSelectionOptions) then
+ FFocusedColumn := FHeader.MainColumn;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualTreeOptions.AssignTo(Dest: TPersistent);
+
+begin
+ if Dest is TCustomVirtualTreeOptions then
+ begin
+ with Dest as TCustomVirtualTreeOptions do
+ begin
+ PaintOptions := Self.PaintOptions;
+ AnimationOptions := Self.AnimationOptions;
+ AutoOptions := Self.AutoOptions;
+ SelectionOptions := Self.SelectionOptions;
+ MiscOptions := Self.MiscOptions;
+ end;
+ end
+ else
+ inherited;
+end;
+
+//----------------- TVTNodeMemoryManager -------------------------------------------------------------------------------
+
+{$ifdef UseLocalMemoryManager}
+
+ const
+ NodeMemoryGuard: PVirtualNode = PVirtualNode($FEEFEFFE);
+
+ constructor TVTNodeMemoryManager.Create;
+
+ begin
+ FBlockList := TList.Create;
+ end;
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ destructor TVTNodeMemoryManager.Destroy;
+
+ begin
+ Clear;
+ FBlockList.Free;
+ end;
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ function TVTNodeMemoryManager.AllocNode(const Size: Cardinal): PVirtualNode;
+
+ // Allocates memory for a node using the local memory manager.
+
+ const
+ BlockSize = (16 * 1024); // Blocks larger than 16K offer no significant performance improvement.
+
+ begin
+ if FAllocSize = 0 then
+ // Recalculate allocation size first time after a clear.
+ FAllocSize := (Size + 3) and not 3 // Force alignment on 32-bit boundaries.
+ else
+ // Allocation size cannot be increased unless Memory Manager is explicitly cleared.
+ Assert(Size <= FAllocSize, 'Node memory manager allocation size cannot be increased.');
+
+ if Assigned(FFreeSpace) then
+ begin
+ // Assign node from free-space chain.
+ Assert(FFreeSpace.NextSibling = NodeMemoryGuard, 'Memory overwrite in node memory manager free space chain.');
+ Result := FFreeSpace; // Assign node
+ FFreeSpace := Result.PrevSibling; // Point to prev node in free-space chain
+ end
+ else
+ begin
+ if FBytesAvailable < FAllocSize then
+ begin
+ // Get another block from the Delphi memory manager.
+ GetMem(FNext, BlockSize);
+ FBytesAvailable := BlockSize;
+ FBlockList.Add(FNext);
+ end;
+ // Assign node from current block.
+ Result := FNext;
+ Inc(PChar(FNext), FAllocSize);
+ Dec(FBytesAvailable, FAllocSize);
+ end;
+
+ // Clear the memory.
+ FillChar(Result^, FAllocSize, 0);
+ end;
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ procedure TVTNodeMemoryManager.Clear;
+
+ // Releases all memory held by the local memory manager.
+
+ var
+ I: Integer;
+
+ begin
+ for I := 0 to FBlockList.Count - 1 do
+ FreeMem(FBlockList[I]);
+ FBlockList.Clear;
+ FFreeSpace := nil;
+ FBytesAvailable := 0;
+ FAllocSize := 0;
+ end;
+
+ //----------------------------------------------------------------------------------------------------------------------
+
+ procedure TVTNodeMemoryManager.FreeNode(const Node: PVirtualNode);
+
+ // Frees node memory that was allocated using the local memory manager.
+
+ begin
+ Node.PrevSibling := FFreeSpace; // Point to previous free node.
+ Node.NextSibling := NodeMemoryGuard; // Memory guard to detect overwrites.
+ FFreeSpace := Node; // Point Free chain pointer to me.
+ end;
+
+{$endif UseLocalMemoryManager}
+
+//----------------------------------------------------------------------------------------------------------------------
+
+// OLE drag and drop support classes
+// This is quite heavy stuff (compared with the VCL implementation) but is much better suited to fit the needs
+// of DD'ing various kinds of virtual data and works also between applications.
+
+//----------------- TEnumFormatEtc -------------------------------------------------------------------------------------
+
+constructor TEnumFormatEtc.Create(Tree: TBaseVirtualTree; AFormatEtcArray: TFormatEtcArray);
+
+var
+ I: Integer;
+
+begin
+ inherited Create;
+
+ FTree := Tree;
+ // Make a local copy of the format data.
+ SetLength(FFormatEtcArray, Length(AFormatEtcArray));
+ for I := 0 to High(AFormatEtcArray) do
+ FFormatEtcArray[I] := AFormatEtcArray[I];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TEnumFormatEtc.Clone(out Enum: IEnumFormatEtc): HResult;
+
+var
+ AClone: TEnumFormatEtc;
+
+begin
+ Result := S_OK;
+ try
+ AClone := TEnumFormatEtc.Create(nil, FFormatEtcArray);
+ AClone.FCurrentIndex := FCurrentIndex;
+ Enum := AClone as IEnumFormatEtc;
+ except
+ Result := E_FAIL;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TEnumFormatEtc.Next(celt: Integer; out elt; pceltFetched: PLongint): HResult;
+
+var
+ CopyCount: Integer;
+
+begin
+ Result := S_FALSE;
+ CopyCount := Length(FFormatEtcArray) - FCurrentIndex;
+ if celt < CopyCount then
+ CopyCount := celt;
+ if CopyCount > 0 then
+ begin
+ Move(FFormatEtcArray[FCurrentIndex], elt, CopyCount * SizeOf(TFormatEtc));
+ Inc(FCurrentIndex, CopyCount);
+ Result := S_OK;
+ end;
+ if Assigned(pceltFetched) then
+ pceltFetched^ := CopyCount;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TEnumFormatEtc.Reset: HResult;
+
+begin
+ FCurrentIndex := 0;
+ Result := S_OK;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TEnumFormatEtc.Skip(celt: Integer): HResult;
+
+begin
+ if FCurrentIndex + celt < High(FFormatEtcArray) then
+ begin
+ Inc(FCurrentIndex, celt);
+ Result := S_Ok;
+ end
+ else
+ Result := S_FALSE;
+end;
+
+//----------------- TVTDataObject --------------------------------------------------------------------------------------
+
+constructor TVTDataObject.Create(AOwner: TBaseVirtualTree; ForClipboard: Boolean);
+
+begin
+ inherited Create;
+
+ FOwner := AOwner;
+ FForClipboard := ForClipboard;
+ FOwner.GetNativeClipboardFormats(FFormatEtcArray);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVTDataObject.Destroy;
+
+var
+ I: Integer;
+ StgMedium: PStgMedium;
+
+begin
+ // Cancel a pending clipboard operation if this data object was created for the clipboard and
+ // is freed because something else is placed there.
+ if FForClipboard and not (tsClipboardFlushing in FOwner.FStates) then
+ FOwner.CancelCutOrCopy;
+
+ // Release any internal clipboard formats
+ for I := 0 to High(FormatEtcArray) do
+ begin
+ StgMedium := FindInternalStgMedium(FormatEtcArray[I].cfFormat);
+ if Assigned(StgMedium) then
+ ReleaseStgMedium(StgMedium^);
+ end;
+
+ FormatEtcArray := nil;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.CanonicalIUnknown(TestUnknown: IUnknown): IUnknown;
+
+// Uses COM object identity: An explicit call to the IUnknown::QueryInterface method, requesting the IUnknown
+// interface, will always return the same pointer.
+
+begin
+ if Assigned(TestUnknown) then
+ begin
+ if TestUnknown.QueryInterface(IUnknown, Result) = 0 then
+ Result._Release // Don't actually need it just need the pointer value
+ else
+ Result := TestUnknown
+ end
+ else
+ Result := TestUnknown
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.EqualFormatEtc(FormatEtc1, FormatEtc2: TFormatEtc): Boolean;
+
+begin
+ Result := (FormatEtc1.cfFormat = FormatEtc2.cfFormat) and (FormatEtc1.ptd = FormatEtc2.ptd) and
+ (FormatEtc1.dwAspect = FormatEtc2.dwAspect) and (FormatEtc1.lindex = FormatEtc2.lindex) and
+ (FormatEtc1.tymed and FormatEtc2.tymed <> 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.FindFormatEtc(TestFormatEtc: TFormatEtc; const FormatEtcArray: TFormatEtcArray): integer;
+
+var
+ I: integer;
+
+begin
+ Result := -1;
+ for I := 0 to High(FormatEtcArray) do
+ begin
+ if EqualFormatEtc(TestFormatEtc, FormatEtcArray[I]) then
+ begin
+ Result := I;
+ Break;
+ end
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.FindInternalStgMedium(Format: TClipFormat): PStgMedium;
+
+var
+ I: integer;
+begin
+ Result := nil;
+ for I := 0 to High(InternalStgMediumArray) do
+ begin
+ if Format = InternalStgMediumArray[I].Format then
+ begin
+ Result := @InternalStgMediumArray[I].Medium;
+ Break;
+ end
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.HGlobalClone(HGlobal: THandle): THandle;
+
+// Returns a global memory block that is a copy of the passed memory block.
+
+var
+ Size: Cardinal;
+ Data,
+ NewData: PChar;
+
+begin
+ Size := GlobalSize(HGlobal);
+ Result := GlobalAlloc(GPTR, Size);
+ Data := GlobalLock(hGlobal);
+ try
+ NewData := GlobalLock(Result);
+ try
+ Move(Data^, NewData^, Size);
+ finally
+ GlobalUnLock(Result);
+ end
+ finally
+ GlobalUnLock(hGlobal);
+ end
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.RenderInternalOLEData(const FormatEtcIn: TFormatEtc; var Medium: TStgMedium;
+ var OLEResult: HResult): Boolean;
+
+// Tries to render one of the formats which have been stored via the SetData method.
+// Since this data is already there it is just copied or its reference count is increased (depending on storage medium).
+
+var
+ InternalMedium: PStgMedium;
+
+begin
+ Result := True;
+ InternalMedium := FindInternalStgMedium(FormatEtcIn.cfFormat);
+ if Assigned(InternalMedium) then
+ OLEResult := StgMediumIncRef(InternalMedium^, Medium, False, Self as IDataObject)
+ else
+ Result := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.StgMediumIncRef(const InStgMedium: TStgMedium; var OutStgMedium: TStgMedium;
+ CopyInMedium: Boolean; DataObject: IDataObject): HRESULT;
+
+// InStgMedium is the data that is requested, OutStgMedium is the data that we are to return either a copy of or
+// increase the IDataObject's reference and send ourselves back as the data (unkForRelease). The InStgMedium is usually
+// the result of a call to find a particular FormatEtc that has been stored locally through a call to SetData.
+// If CopyInMedium is not true we already have a local copy of the data when the SetData function was called (during
+// that call the CopyInMedium must be true). Then as the caller asks for the data through GetData we do not have to make
+// copy of the data for the caller only to have them destroy it then need us to copy it again if necessary.
+// This way we increase the reference count to ourselves and pass the STGMEDIUM structure initially stored in SetData.
+// This way when the caller frees the structure it sees the unkForRelease is not nil and calls Release on the object
+// instead of destroying the actual data.
+
+var
+ Len: Integer;
+
+begin
+ Result := S_OK;
+
+ // Simply copy all fields to start with.
+ OutStgMedium := InStgMedium;
+ // The data handled here always results from a call of SetData we got. This ensures only one storage format
+ // is indicated and hence the case statement below is safe (IDataObject.GetData can optionally use several
+ // storage formats).
+ case InStgMedium.tymed of
+ TYMED_HGLOBAL:
+ begin
+ if CopyInMedium then
+ begin
+ // Generate a unique copy of the data passed
+ OutStgMedium.hGlobal := HGlobalClone(InStgMedium.hGlobal);
+ if OutStgMedium.hGlobal = 0 then
+ Result := E_OUTOFMEMORY
+ end
+ else
+ // Don't generate a copy just use ourselves and the copy previously saved.
+ OutStgMedium.unkForRelease := Pointer(DataObject); // Does not increase RefCount.
+ end;
+ TYMED_FILE:
+ begin
+ Len := lstrLenW(InStgMedium.lpszFileName) + 1; // Don'nt forget the terminating null character.
+ OutStgMedium.lpszFileName := CoTaskMemAlloc(2 * Len);
+ Move(InStgMedium.lpszFileName^, OutStgMedium.lpszFileName^, 2 * Len);
+ end;
+ TYMED_ISTREAM:
+ IUnknown(OutStgMedium.stm)._AddRef;
+ TYMED_ISTORAGE:
+ IUnknown(OutStgMedium.stg)._AddRef;
+ TYMED_GDI:
+ if not CopyInMedium then
+ // Don't generate a copy just use ourselves and the copy previously saved data.
+ OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount.
+ else
+ Result := DV_E_TYMED; // Don't know how to copy GDI objects right now.
+ TYMED_MFPICT:
+ if not CopyInMedium then
+ // Don't generate a copy just use ourselves and the copy previously saved data.
+ OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount.
+ else
+ Result := DV_E_TYMED; // Don't know how to copy MetaFile objects right now.
+ TYMED_ENHMF:
+ if not CopyInMedium then
+ // Don't generate a copy just use ourselves and the copy previously saved data.
+ OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount.
+ else
+ Result := DV_E_TYMED; // Don't know how to copy enhanced metafiles objects right now.
+ else
+ Result := DV_E_TYMED;
+ end;
+
+ if (Result = S_OK) and Assigned(OutStgMedium.unkForRelease) then
+ IUnknown(OutStgMedium.unkForRelease)._AddRef;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.DAdvise(const FormatEtc: TFormatEtc; advf: Integer; const advSink: IAdviseSink;
+ out dwConnection: Integer): HResult;
+
+// Advise sink management is greatly simplified by the IDataAdviseHolder interface.
+// We use this interface and forward all concerning calls to it.
+
+begin
+ Result := S_OK;
+ if FAdviseHolder = nil then
+ Result := CreateDataAdviseHolder(FAdviseHolder);
+ if Result = S_OK then
+ Result := FAdviseHolder.Advise(Self as IDataObject, FormatEtc, advf, advSink, dwConnection);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.DUnadvise(dwConnection: Integer): HResult;
+
+begin
+ if FAdviseHolder = nil then
+ Result := E_NOTIMPL
+ else
+ Result := FAdviseHolder.Unadvise(dwConnection);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.EnumDAdvise(out enumAdvise: IEnumStatData): HResult;
+
+begin
+ if FAdviseHolder = nil then
+ Result := OLE_E_ADVISENOTSUPPORTED
+ else
+ Result := FAdviseHolder.EnumAdvise(enumAdvise);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.EnumFormatEtc(Direction: Integer; out EnumFormatEtc: IEnumFormatEtc): HResult;
+
+var
+ NewList: TEnumFormatEtc;
+
+begin
+ Result := E_FAIL;
+ if Direction = DATADIR_GET then
+ begin
+ NewList := TEnumFormatEtc.Create(FOwner, FormatEtcArray);
+ EnumFormatEtc := NewList as IEnumFormatEtc;
+ Result := S_OK;
+ end
+ else
+ EnumFormatEtc := nil;
+ if EnumFormatEtc = nil then
+ Result := OLE_S_USEREG;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.GetCanonicalFormatEtc(const FormatEtc: TFormatEtc; out FormatEtcOut: TFormatEtc): HResult;
+
+begin
+ Result := DATA_S_SAMEFORMATETC;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.GetData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium): HResult;
+
+// Data is requested by clipboard or drop target. This method dispatchs the call
+// depending on the data being requested.
+
+var
+ I: Integer;
+ Data: PVTReference;
+
+begin
+ // The tree reference format is always supported and returned from here.
+ if FormatEtcIn.cfFormat = CF_VTREFERENCE then
+ begin
+ // Note: this format is not used while flushing the clipboard to avoid a dangling reference
+ // when the owner tree is destroyed before the clipboard data is replaced with something else.
+ if tsClipboardFlushing in FOwner.FStates then
+ Result := E_FAIL
+ else
+ begin
+ Medium.hGlobal := GlobalAlloc(GHND or GMEM_SHARE, SizeOf(TVTReference));
+ Data := GlobalLock(Medium.hGlobal);
+ Data.Process := GetCurrentProcessID;
+ Data.Tree := FOwner;
+ GlobalUnlock(Medium.hGlobal);
+ Medium.tymed := TYMED_HGLOBAL;
+ Medium.unkForRelease := nil;
+ Result := S_OK;
+ end;
+ end
+ else
+ begin
+ try
+ // See if we accept this type and if not get the correct return value.
+ Result := QueryGetData(FormatEtcIn);
+ if Result = S_OK then
+ begin
+ for I := 0 to High(FormatEtcArray) do
+ begin
+ if EqualFormatEtc(FormatEtcIn, FormatEtcArray[I]) then
+ begin
+ if not RenderInternalOLEData(FormatEtcIn, Medium, Result) then
+ Result := FOwner.RenderOLEData(FormatEtcIn, Medium, FForClipboard);
+ Break;
+ end;
+ end
+ end
+ except
+ FillChar(Medium, SizeOf(Medium), #0);
+ Result := E_FAIL;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.GetDataHere(const FormatEtc: TFormatEtc; out Medium: TStgMedium): HResult;
+
+begin
+ Result := E_NOTIMPL;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.QueryGetData(const FormatEtc: TFormatEtc): HResult;
+
+var
+ I: Integer;
+
+begin
+ Result := DV_E_CLIPFORMAT;
+ for I := 0 to High(FFormatEtcArray) do
+ begin
+ if FormatEtc.cfFormat = FFormatEtcArray[I].cfFormat then
+ begin
+ if (FormatEtc.tymed and FFormatEtcArray[I].tymed) <> 0 then
+ begin
+ if FormatEtc.dwAspect = FFormatEtcArray[I].dwAspect then
+ begin
+ if FormatEtc.lindex = FFormatEtcArray[I].lindex then
+ begin
+ Result := S_OK;
+ Break;
+ end
+ else
+ Result := DV_E_LINDEX;
+ end
+ else
+ Result := DV_E_DVASPECT;
+ end
+ else
+ Result := DV_E_TYMED;
+ end;
+ end
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDataObject.SetData(const FormatEtc: TFormatEtc; var Medium: TStgMedium; DoRelease: BOOL): HResult;
+
+// Allows dynamic adding to the IDataObject during its existance. Most noteably it is used to implement
+// IDropSourceHelper and allows to set a special format for optimized moves during a shell transfer.
+
+var
+ Index: integer;
+ LocalStgMedium: PStgMedium;
+
+begin
+ // See if we already have a format of that type available.
+ Index := FindFormatEtc(FormatEtc, FormatEtcArray);
+ if Index > - 1 then
+ begin
+ // Just use the TFormatEct in the Array after releasing the data.
+ LocalStgMedium := FindInternalStgMedium(FormatEtcArray[Index].cfFormat);
+ if Assigned(LocalStgMedium) then
+ begin
+ ReleaseStgMedium(LocalStgMedium^);
+ FillChar(LocalStgMedium^, SizeOf(LocalStgMedium^), #0);
+ end;
+ end
+ else
+ begin
+ // It is a new format so create a new TFormatCollectionItem, copy the
+ // FormatEtc parameter into the new object and and put it in the list.
+ SetLength(FFormatEtcArray, Length(FormatEtcArray) + 1);
+ FormatEtcArray[High(FormatEtcArray)] := FormatEtc;
+
+ // Create a new InternalStgMedium and initialize it and associate it with the format.
+ SetLength(FInternalStgMediumArray, Length(InternalStgMediumArray) + 1);
+ InternalStgMediumArray[High(InternalStgMediumArray)].Format := FormatEtc.cfFormat;
+ LocalStgMedium := @InternalStgMediumArray[High(InternalStgMediumArray)].Medium;
+ FillChar(LocalStgMedium^, SizeOf(LocalStgMedium^), #0);
+ end;
+
+ if DoRelease then
+ begin
+ // We are simply being given the data and we take control of it.
+ LocalStgMedium^ := Medium;
+ Result := S_OK
+ end
+ else
+ begin
+ // We need to reference count or copy the data and keep our own references to it.
+ Result := StgMediumIncRef(Medium, LocalStgMedium^, True, Self as IDataObject);
+
+ // Can get a circular reference if the client calls GetData then calls SetData with the same StgMedium.
+ // Because the unkForRelease for the IDataObject can be marshalled it is necessary to get pointers that
+ // can be correctly compared. See the IDragSourceHelper article by Raymond Chen at MSDN.
+ if Assigned(LocalStgMedium.unkForRelease) then
+ begin
+ if CanonicalIUnknown(Self) = CanonicalIUnknown(IUnknown(LocalStgMedium.unkForRelease)) then
+ IUnknown(LocalStgMedium.unkForRelease) := nil; // release the interface
+ end;
+ end;
+
+ // Tell all registered advice sinks about the data change.
+ if Assigned(FAdviseHolder) then
+ FAdviseHolder.SendOnDataChange(Self as IDataObject, 0, 0);
+end;
+
+//----------------- TVTDragManager -------------------------------------------------------------------------------------
+
+constructor TVTDragManager.Create(AOwner: TBaseVirtualTree);
+
+begin
+ inherited Create;
+ FOwner := AOwner;
+
+ // Create an instance of the drop target helper interface. This will fail but not harm on systems which do
+ // not support this interface (everything below Windows 2000);
+ CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, FDropTargetHelper);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVTDragManager.Destroy;
+
+begin
+ // Set the owner's reference to us to nil otherwise it will access an invalid pointer
+ // after our desctruction is complete.
+ Pointer(FOwner.FDragManager) := nil;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GetDataObject: IDataObject;
+
+begin
+ // When the owner tree starts a drag operation then it gets a data object here to pass it to the OLE subsystem.
+ // In this case there is no local reference to a data object and one is created (but not stored).
+ // If there is a local reference then the owner tree is currently the drop target and the stored interface is
+ // that of the drag initiator.
+ if Assigned(FDataObject) then
+ Result := FDataObject
+ else
+ begin
+ Result := FOwner.DoCreateDataObject;
+ if Result = nil then
+ Result := TVTDataObject.Create(FOwner, False) as IDataObject;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GetDragSource: TBaseVirtualTree;
+
+begin
+ Result := FDragSource;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GetDropTargetHelperSupported: Boolean;
+
+begin
+ Result := Assigned(FDropTargetHelper);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GetIsDropTarget: Boolean;
+
+begin
+ Result := FIsDropTarget;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.DragEnter(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult;
+
+begin
+ FDataObject := DataObject;
+ FIsDropTarget := True;
+
+ SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, @FFullDragging, 0);
+ // If full dragging of window contents is disabled in the system then our tree windows will be locked
+ // and cannot be updated during a drag operation. With the following call painting is again enabled.
+ if not FFullDragging then
+ LockWindowUpdate(0);
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.DragEnter(FOwner.Handle, DataObject, Pt, Effect);
+
+ FDragSource := FOwner.GetTreeFromDataObject(DataObject);
+ Result := FOwner.DragEnter(KeyState, Pt, Effect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.DragLeave: HResult;
+
+begin
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.DragLeave;
+
+ FOwner.DragLeave;
+ FIsDropTarget := False;
+ FDragSource := nil;
+ FDataObject := nil;
+ Result := NOERROR;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.DragOver(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult;
+
+begin
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.DragOver(Pt, Effect);
+
+ Result := FOwner.DragOver(FDragSource, KeyState, dsDragMove, Pt, Effect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.Drop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult;
+
+begin
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.Drop(DataObject, Pt, Effect);
+
+ Result := FOwner.DragDrop(DataObject, KeyState, Pt, Effect);
+ FIsDropTarget := False;
+ FDataObject := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragManager.ForceDragLeave;
+
+// It has been reported that under some circumstances a drag image remains on screen. Unfortunately, nobody could
+// come up with a list of steps-to-reproduce. So we can only fix the result instead the cause.
+// This method calls the drop target helper's DragLeave method to ensure it removes the drag image from screen.
+
+begin
+ if Assigned(FDropTargetHelper) and FFullDragging then
+ FDropTargetHelper.DragLeave;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.GiveFeedback(Effect: Integer): HResult;
+
+begin
+ Result := DRAGDROP_S_USEDEFAULTCURSORS;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragManager.QueryContinueDrag(EscapePressed: BOOL; KeyState: Integer): HResult;
+
+var
+ RButton,
+ LButton: Boolean;
+
+begin
+ LButton := (KeyState and MK_LBUTTON) <> 0;
+ RButton := (KeyState and MK_RBUTTON) <> 0;
+
+ // Drag'n drop canceled by pressing both mouse buttons or Esc?
+ if (LButton and RButton) or EscapePressed then
+ Result := DRAGDROP_S_CANCEL
+ else
+ // drag'n drop finished?
+ if not (LButton or RButton) then
+ Result := DRAGDROP_S_DROP
+ else
+ Result := S_OK;
+end;
+
+//----------------- TVirtualTreeHintWindow -----------------------------------------------------------------------------
+
+var
+ // This variable is necessary to coordinate the complex interaction between different hints in the application
+ // and animated hints in our own class. Under certain conditions it can happen that our hint window is destroyed
+ // while it is still in the animation loop.
+ HintWindowDestroyed: Boolean = True;
+
+constructor TVirtualTreeHintWindow.Create(AOwner: TComponent);
+
+begin
+ inherited;
+
+ FBackground := TBitmap.Create;
+ FBackground.PixelFormat := pf32Bit;
+ FDrawBuffer := TBitmap.Create;
+ FDrawBuffer.PixelFormat := pf32Bit;
+ FTarget := TBitmap.Create;
+ FTarget.PixelFormat := pf32Bit;
+
+ DoubleBuffered := False; // we do our own buffering
+ HintWindowDestroyed := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVirtualTreeHintWindow.Destroy;
+
+begin
+ HintWindowDestroyed := True;
+
+ FTarget.Free;
+ FDrawBuffer.Free;
+ FBackground.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeHintWindow.AnimationCallback(Step, StepSize: Integer; Data: Pointer): Boolean;
+
+begin
+ Result := not HintWindowDestroyed and IsWindowVisible(Handle);
+ if Result then
+ begin
+ InternalPaint(Step, StepSize);
+ // We have to allow certain messages to be processed normally for various reasons.
+ // This introduces another problem however if this hint window is destroyed
+ // while it is still in the animation loop. A global variable keeps track of
+ // that case. This is reliable because we can only have one (internal) hint window.
+ Application.ProcessMessages;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.InternalPaint(Step, StepSize: Integer);
+
+ //--------------- local functions -------------------------------------------
+
+ procedure DoShadowBlend(DC: HDC; R: TRect; Alpha: Integer);
+
+ // Helper routine for shadow blending to shorten the parameter list in frequent calls.
+
+ begin
+ AlphaBlend(0, DC, R, Point(0, 0), bmConstantAlphaAndColor, Alpha, clBlack);
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure DrawHintShadow(Canvas: TCanvas; ShadowSize: Integer);
+
+ var
+ R: TRect;
+
+ begin
+ // Bottom shadow.
+ R := Rect(ShadowSize, Height - ShadowSize, Width, Height);
+ DoShadowBlend(Canvas.Handle, R, 5);
+ Inc(R.Left);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ DoShadowBlend(Canvas.Handle, R, 10);
+ Inc(R.Left);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ DoShadowBlend(Canvas.Handle, R, 20);
+ Inc(R.Left);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ DoShadowBlend(Canvas.Handle, R, 35);
+ Inc(R.Left);
+ Dec(R.Right);
+ Dec(R.Bottom);
+ DoShadowBlend(Canvas.Handle, R, 50);
+ // Right shadow.
+ R := Rect(Width - ShadowSize, ShadowSize, Width, Height - ShadowSize);
+ DoShadowBlend(Canvas.Handle, R, 5);
+ Inc(R.Top);
+ Dec(R.Right);
+ DoShadowBlend(Canvas.Handle, R, 10);
+ Inc(R.Top);
+ Dec(R.Right);
+ DoShadowBlend(Canvas.Handle, R, 20);
+ Inc(R.Top);
+ Dec(R.Right);
+ DoShadowBlend(Canvas.Handle, R, 35);
+ Inc(R.Top);
+ Dec(R.Right);
+ DoShadowBlend(Canvas.Handle, R, 50);
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ R: TRect;
+ Y: Integer;
+ S: WideString;
+ DrawFormat: Cardinal;
+ Shadow: Integer;
+
+begin
+ {$ifndef COMPILER_7_UP}
+ if MMXAvailable then
+ Shadow := ShadowSize
+ else
+ {$endif COMPILER_7_UP}
+ Shadow := 0;
+
+ with FHintData, FDrawBuffer do
+ begin
+ // Do actual painting only in the very first run.
+ if Step = 0 then
+ begin
+ // If the given node is nil then we have to display a header hint.
+ if (Node = nil) or (Tree.FHintMode <> hmToolTip) then
+ begin
+ {$ifndef COMPILER_5_UP}
+ Canvas.Font := HintFont;
+ {$else}
+ Canvas.Font := Screen.HintFont;
+ {$endif COMPILER_5_UP}
+ Y := 2;
+ end
+ else
+ begin
+ Tree.GetTextInfo(Node, Column, Canvas.Font, R, S);
+ if vsMultiline in Node.States then
+ Y := Tree.TextMargin + 1
+ else
+ Y := (R.Top - R.Bottom - Shadow + Self.Height) div 2;
+ end;
+
+ with ClientRect do
+ R := Rect(0, 0, Width - Shadow, Height - Shadow);
+
+ if (Tree is TCustomVirtualDrawTree) and Assigned(Node) then
+ begin
+ // The draw tree has by default no hint text so let it draw the hint itself.
+ (Tree as TCustomVirtualDrawTree).DoDrawHint(Canvas, Node, R, Column);
+ end
+ else
+ with Canvas do
+ begin
+ // Still force tooltip back and text color.
+ Font.Color := clInfoText;
+ Pen.Color := clBlack;
+ Brush.Color := clInfoBk;
+ {$ifdef COMPILER_5_UP}
+ Rectangle(R);
+ {$else}
+ with R do
+ Rectangle(Left, Top, Right, Bottom);
+ {$endif COMPILER_5_UP}
+
+ // Determine text position and don't forget the border.
+ InflateRect(R, -Tree.FTextMargin - 1, -1);
+ DrawFormat := DT_TOP or DT_NOPREFIX;
+ if BidiMode <> bdLeftToRight then
+ begin
+ DrawFormat := DrawFormat or DT_RIGHT or DT_RTLREADING;
+ Inc(R.Right);
+ end
+ else
+ DrawFormat := DrawFormat or DT_LEFT;
+ SetBkMode(Handle, Windows.TRANSPARENT);
+ R.Top := Y;
+ if Assigned(Node) and (vsMultiline in Node.States) then
+ DrawFormat := DrawFormat or DT_WORDBREAK;
+ if IsWinNT then
+ Windows.DrawTextW(Handle, PWideChar(HintText), Length(HintText), R, DrawFormat)
+ else
+ DrawTextW(Handle, PWideChar(HintText), Length(HintText), R, DrawFormat, False);
+ end;
+ end;
+ end;
+
+ if StepSize > 0 then
+ begin
+ if FHintData.Tree.DoGetAnimationType = hatFade then
+ begin
+ with FTarget do
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FBackground.Canvas.Handle, 0, 0, SRCCOPY);
+ // Main image.
+ AlphaBlend(FDrawBuffer.Canvas.Handle, FTarget.Canvas.Handle, Rect(0, 0, Width - Shadow, Height - Shadow),
+ Point(0, 0), bmConstantAlpha, MulDiv(Step, 256, FadeAnimationStepCount), 0);
+
+ if Shadow > 0 then
+ DrawHintShadow(FTarget.Canvas, Shadow);
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FTarget.Canvas.Handle, 0, 0, SRCCOPY);
+ end
+ else
+ begin
+ // Slide is done by blitting "step" lines of the lower part of the hint window
+ // and fill the rest with the screen background.
+
+ // 1) blit hint bitmap to the hint canvas
+ BitBlt(Canvas.Handle, 0, 0, Width - Shadow, Step, FDrawBuffer.Canvas.Handle, 0, Height - Step, SRCCOPY);
+ // 2) blit background rest to hint canvas
+ if Step <= Shadow then
+ Step := 0
+ else
+ Dec(Step, Shadow);
+ BitBlt(Canvas.Handle, 0, Step, Width, Height - Step, FBackground.Canvas.Handle, 0, Step, SRCCOPY);
+ end;
+ end
+ else
+ // Last step during slide or the only step without animation.
+ if FHintData.Tree.DoGetAnimationType <> hatFade then
+ begin
+ if Shadow > 0 then
+ begin
+ with FBackground do
+ BitBlt(Canvas.Handle, 0, 0, Width - Shadow, Height - Shadow, FDrawBuffer.Canvas.Handle, 0, 0, SRCCOPY);
+
+ DrawHintShadow(FBackground.Canvas, Shadow);
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FBackground.Canvas.Handle, 0, 0, SRCCOPY);
+ end
+ else
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FDrawBuffer.Canvas.Handle, 0, 0, SRCCOPY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.CMTextChanged(var Message: TMessage);
+
+begin
+ // swallow this message to prevent the ancestor from resizing the window (we don't use the caption anyway)
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.WMEraseBkgnd(var Message: TWMEraseBkgnd);
+
+// The control is fully painted by own code so don't erase its background as this causes flickering.
+
+begin
+ Message.Result := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.WMNCPaint(var Message: TMessage);
+
+// The control is fully painted by own code so don't paint any borders.
+
+begin
+ Message.Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.WMShowWindow(var Message: TWMShowWindow);
+
+// Clear hint data when the window becomes hidden.
+
+begin
+ if not Message.Show then
+ begin
+ Finalize(FHintData);
+ FillChar(FHintData, SizeOf(FHintData), 0);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.CreateParams(var Params: TCreateParams);
+
+begin
+ inherited CreateParams(Params);
+
+ with Params do
+ begin
+ Style := WS_POPUP;
+ ExStyle := ExStyle and not WS_EX_CLIENTEDGE;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.Paint;
+
+begin
+ InternalPaint(0, 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeHintWindow.ActivateHint(Rect: TRect; const AHint: string);
+
+var
+ DC: HDC;
+
+begin
+ // Do not allow to enter the animation loop recursively.
+ if (tsInAnimation in FHintData.Tree.FStates) or IsRectEmpty(Rect) then
+ Application.CancelHint
+ else
+ begin
+ SetWindowPos(Handle, 0, Rect.Left, Rect.Top, Width, Height, SWP_HIDEWINDOW or SWP_NOACTIVATE or SWP_NOZORDER);
+ UpdateBoundsRect(Rect);
+
+ if Rect.Top + Height > Screen.DesktopHeight then
+ Rect.Top := Screen.DesktopHeight - Height;
+ if Rect.Top < Screen.DesktopTop then
+ Rect.Top := Screen.DesktopTop;
+ if Rect.Left + Width > Screen.DesktopWidth then
+ Rect.Left := Screen.DesktopWidth - Width;
+ if Rect.Left < Screen.DesktopLeft then
+ Rect.Left := Screen.DesktopLeft;
+
+ // adjust sizes of bitmaps
+ FDrawBuffer.Width := Width;
+ FDrawBuffer.Height := Height;
+ FBackground.Width := Width;
+ FBackground.Height := Height;
+ FTarget.Width := Width;
+ FTarget.Height := Height;
+
+ FHintData.Tree.Update;
+
+ // capture screen
+ DC := GetDC(0);
+ try
+ with Rect do
+ BitBlt(FBackground.Canvas.Handle, 0, 0, Width, Height, DC, Left, Top, SRCCOPY);
+ finally
+ ReleaseDC(0, DC);
+ end;
+
+ SetWindowPos(Handle, HWND_TOPMOST, Rect.Left, Rect.Top, Width, Height, SWP_SHOWWINDOW or SWP_NOACTIVATE);
+ with FHintData.Tree do
+ case DoGetAnimationType of
+ hatNone:
+ InvalidateRect(Self.Handle, nil, False);
+ hatFade:
+ begin
+ // Make sure the window is not drawn unanimated.
+ ValidateRect(Self.Handle, nil);
+ // Empirically determined animation duration shows that fading needs about twice as much time as
+ // sliding to show a comparable visual effect.
+ Animate(FadeAnimationStepCount, 2 * FAnimationDuration, AnimationCallback, nil);
+ end;
+ hatSlide:
+ begin
+ // Make sure the window is not drawn unanimated.
+ ValidateRect(Self.Handle, nil);
+ Animate(Self.Height, FAnimationDuration, AnimationCallback, nil);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string; AData: Pointer): TRect;
+
+var
+ TM: TTextMetric;
+ R: TRect;
+
+begin
+ // The hint window does not need any bidi mode setting but the caller of this method (TApplication.ActivateHint)
+ // does some unneccessary actions if the hint window is not left-to-right.
+ // The text alignment is based on the bidi mode passed in the hint data, hence we can
+ // simply set the window's mode to left-to-right (it might have been modified by the caller, if the
+ // tree window is right-to-left aligned).
+ BidiMode := bdLeftToRight;
+
+ FHintData := PVTHintData(AData)^;
+
+ with FHintData do
+ begin
+ // The draw tree gets its hint size by the application (but only if not a header hint is about to show).
+ // This size has already been determined in CMHintShow.
+ if (Tree is TCustomVirtualDrawTree) and Assigned(Node) then
+ Result := HintRect
+ else
+ begin
+ if Column <= NoColumn then
+ begin
+ BidiMode := Tree.BidiMode;
+ Alignment := Tree.Alignment;
+ end
+ else
+ begin
+ BidiMode := Tree.Header.Columns[Column].BidiMode;
+ Alignment := Tree.Header.Columns[Column].Alignment;
+ end;
+
+ if BidiMode <> bdLeftToRight then
+ ChangeBidiModeAlignment(Alignment);
+
+ if (Node = nil) or (Tree.FHintMode <> hmToolTip) then
+ begin
+ {$ifndef COMPILER_5_UP}
+ Canvas.Font := HintFont
+ {$else}
+ Canvas.Font := Screen.HintFont
+ {$endif COMPILER_5_UP}
+ end
+ else
+ begin
+ Canvas.Font := Tree.Font;
+ if Tree is TCustomVirtualStringTree then
+ with TCustomVirtualStringTree(Tree) do
+ DoPaintText(Node, Self.Canvas, Column, ttNormal);
+ end;
+
+ GetTextMetrics(Canvas.Handle, TM);
+ FTextHeight := TM.tmHeight;
+
+ if Length(DefaultHint) > 0 then
+ HintText := DefaultHint
+ else
+ if Tree.HintMode = hmToolTip then
+ HintText := Tree.DoGetNodeToolTip(Node, Column)
+ else
+ HintText := Tree.DoGetNodeHint(Node, Column);
+
+ if Length(HintText) = 0 then
+ Result := Rect(0, 0, 0, 0)
+ else
+ begin
+ if Assigned(Node) and (Tree.FHintMode = hmToolTip) then
+ begin
+ // Hint for a node.
+ if vsMultiline in Node.States then
+ begin
+ // Multiline tooltips use the columns width but extend the bottom border to fit the whole caption.
+ Result := Tree.GetDisplayRect(Node, Column, True, False);
+ // On Windows NT the behavior of the tooltip is slightly different to that on Windows 9x/Me.
+ // We don't have Unicode word wrap on the latter so the tooltip gets as wide as the largest line
+ // in the caption (limited by carriage return), which results in unoptimal overlay of the tooltip.
+ // On Windows NT the tooltip exactly overlays the node text.
+ if IsWinNT then
+ begin
+ // DT_CALCRECT sometimes also modifies the right border. But we are only interested in the bottom border.
+ R := Result;
+ Windows.DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), R, DT_CALCRECT or DT_WORDBREAK);
+ Result.Bottom := R.Bottom;
+ end
+ else
+ DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), Result, DT_CALCRECT, True);
+
+ // Adjust for text margin.
+ InflateRect(Result, 0, Tree.TextMargin);
+ Inc(Result.Right);
+ // If the node height is already large enough to cover the entire text, then we don't need the hint, though.
+ // However if the text is partially scrolled out of the client area then a hint is useful as well.
+ if ((Node.NodeHeight + 2) >= (Result.Bottom - Result.Top)) and not
+ ((Result.Left < 0) or (Result.Right > Tree.ClientWidth) or
+ (Result.Top < 0) or (Result.Bottom > Tree.ClientHeight)) then
+ begin
+ Result := Rect(0, 0, 0, 0);
+ Exit;
+ end;
+ end
+ else
+ begin
+ Result := Tree.GetDisplayRect(Node, Column, True, True);
+ if toShowHorzGridLines in Tree.TreeOptions.PaintOptions then
+ Dec(Result.Bottom);
+ end;
+ // Include a one pixel border.
+ InflateRect(Result, 1, 1);
+ // Make the coordinates relative. They will again be offset by the caller code.
+ OffsetRect(Result, -Result.Left - 1, -Result.Top - 1);
+ end
+ else
+ begin
+ // Hint for a header.
+ // Start with the base size of the hint in client coordinates.
+ Result := Rect(0, 0, MaxWidth, FTextHeight);
+ // Calculate the true size of the text rectangle.
+ DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), Result, DT_CALCRECT, True);
+ // The height of the text plus 2 pixels vertical margin plus the border determine the hint window height.
+ Inc(Result.Bottom, 6);
+ // The text is centered horizontally with usual text margin for left and right borders (plus border).
+ Inc(Result.Right, 2 * Tree.FTextMargin + 2);
+ end;
+
+ {$ifndef COMPILER_7_UP}
+ // Add some pixels for the shadow if MMX is available for blending.
+ if MMXAvailable then
+ begin
+ Inc(Result.Right, ShadowSize);
+ Inc(Result.Bottom, ShadowSize);
+ end;
+ {$endif COMPILER_7_UP}
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeHintWindow.IsHintMsg(var Msg: TMsg): Boolean;
+
+// The VCL is a bit too generous when telling that an existing hint can be cancelled. Need to specify further here.
+
+begin
+ Result := inherited IsHintMsg(Msg) and HandleAllocated and IsWindowVisible(Handle);
+ if Result and (Msg.Message = WM_NCMOUSEMOVE) then
+ Result := False
+ else
+ // Work around problems with keypresses while doing hint animation.
+ if HandleAllocated and IsWindowVisible(Handle) and (Msg.Message >= WM_KEYFIRST) and (Msg.Message <= WM_KEYLAST) and
+ (tsInAnimation in FHintData.Tree.FStates) and TranslateMessage(Msg) then
+ DispatchMessage(Msg);
+end;
+
+//----------------- TVTDragImage ---------------------------------------------------------------------------------------
+
+constructor TVTDragImage.Create(AOwner: TBaseVirtualTree);
+
+begin
+ FOwner := AOwner;
+ FTransparency := 128;
+ FPreBlendBias := 0;
+ FPostBlendBias := 0;
+ FFade := False;
+ FRestriction := dmrNone;
+ FColorKey := clNone;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVTDragImage.Destroy;
+
+begin
+ EndDrag;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragImage.GetVisible: Boolean;
+
+// Returns True if the internal drag image is used (i.e. the system does not natively support drag images) and
+// the internal image is currently visible on screen.
+
+begin
+ Result := FStates * [disHidden, disInDrag, disPrepared, disSystemSupport] = [disInDrag, disPrepared];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.InternalShowDragImage(ScreenDC: HDC);
+
+// Frequently called helper routine to actually do the blend and put it onto the screen.
+// Only used if the system does not support drag images.
+
+var
+ BlendMode: TBlendMode;
+
+begin
+ with FAlphaImage do
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, FBackImage.Canvas.Handle, 0, 0, SRCCOPY);
+ if not FFade and (FColorKey = clNone) then
+ BlendMode := bmConstantAlpha
+ else
+ BlendMode := bmMasterAlpha;
+ with FDragImage do
+ AlphaBlend(Canvas.Handle, FAlphaImage.Canvas.Handle, Rect(0, 0, Width, Height), Point(0, 0), BlendMode,
+ FTransparency, FPostBlendBias);
+
+ with FAlphaImage do
+ BitBlt(ScreenDC, FImagePosition.X, FImagePosition.Y, Width, Height, Canvas.Handle, 0, 0, SRCCOPY);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.MakeAlphaChannel(Source, Target: TBitmap);
+
+// Helper method to create a proper alpha channel in Target (which must be in 32 bit pixel format), depending
+// on the settings for the drag image and the color values in Source.
+// Only used if the system does not support drag images.
+
+type
+ PBGRA = ^TBGRA;
+ TBGRA = packed record
+ case Boolean of
+ False:
+ (Color: Cardinal);
+ True:
+ (BGR: array[0..2] of Byte;
+ Alpha: Byte);
+ end;
+
+var
+ Color,
+ ColorKeyRef: COLORREF;
+ UseColorKey: Boolean;
+ SourceRun,
+ TargetRun: PBGRA;
+ X, Y,
+ MaxDimension,
+ HalfWidth,
+ HalfHeight: Integer;
+ T: Extended;
+
+begin
+ UseColorKey := ColorKey <> clNone;
+ ColorKeyRef := ColorToRGB(ColorKey) and $FFFFFF;
+ // Color values are in the form BGR (red on LSB) while bitmap colors are in the form ARGB (blue on LSB)
+ // hence we have to swap red and blue in the color key.
+ with TBGRA(ColorKeyRef) do
+ begin
+ X := BGR[0];
+ BGR[0] := BGR[2];
+ BGR[2] := X;
+ end;
+
+ with Target do
+ begin
+ MaxDimension := Max(Width, Height);
+
+ HalfWidth := Width div 2;
+ HalfHeight := Height div 2;
+ for Y := 0 to Height - 1 do
+ begin
+ TargetRun := Scanline[Y];
+ SourceRun := Source.Scanline[Y];
+ for X := 0 to Width - 1 do
+ begin
+ Color := SourceRun.Color and $FFFFFF;
+ if UseColorKey and (Color = ColorKeyRef) then
+ TargetRun.Alpha := 0
+ else
+ begin
+ // If the color is not the given color key (or none is used) then do full calculation of a bell curve.
+ T := exp(-8 * Sqrt(Sqr((X - HalfWidth) / MaxDimension) + Sqr((Y - HalfHeight) / MaxDimension)));
+ TargetRun.Alpha := Round(255 * T);
+ end;
+ Inc(SourceRun);
+ Inc(TargetRun);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragImage.DragTo(P: TPoint; ForceRepaint: Boolean): Boolean;
+
+// Moves the drag image to a new position, which is determined from the passed point P and the previous
+// mouse position.
+// ForceRepaint is True if something on the screen changed and the back image must be refreshed.
+
+var
+ ScreenDC: HDC;
+ DeltaX,
+ DeltaY: Integer;
+
+ // optimized drag image move support
+ RSamp1,
+ RSamp2, // newly added parts from screen which will be overwritten
+ RDraw1,
+ RDraw2, // parts to be restored to screen
+ RScroll,
+ RClip: TRect; // ScrollDC of the existent background
+
+begin
+ // Determine distances to move the drag image. Take care for restrictions.
+ case FRestriction of
+ dmrHorizontalOnly:
+ begin
+ DeltaX := FLastPosition.X - P.X;
+ DeltaY := 0;
+ end;
+ dmrVerticalOnly:
+ begin
+ DeltaX := 0;
+ DeltaY := FLastPosition.Y - P.Y;
+ end;
+ else // dmrNone
+ DeltaX := FLastPosition.X - P.X;
+ DeltaY := FLastPosition.Y - P.Y;
+ end;
+
+ Result := (DeltaX <> 0) or (DeltaY <> 0) or ForceRepaint;
+ if Result then
+ begin
+ if Visible then
+ begin
+ // All this stuff is only called if we have to handle the drag image ourselves. If the system supports
+ // drag image then this is all never executed.
+ ScreenDC := GetDC(0);
+ try
+ if (Abs(DeltaX) >= FDragImage.Width) or (Abs(DeltaY) >= FDragImage.Height) or ForceRepaint then
+ begin
+ // If moved more than image size then just restore old screen and blit image to new position.
+ BitBlt(ScreenDC, FImagePosition.X, FImagePosition.Y, FBackImage.Width, FBackImage.Height,
+ FBackImage.Canvas.Handle, 0, 0, SRCCOPY);
+
+ if ForceRepaint then
+ UpdateWindow(FOwner.Handle);
+
+ Inc(FImagePosition.X, -DeltaX);
+ Inc(FImagePosition.Y, -DeltaY);
+
+ BitBlt(FBackImage.Canvas.Handle, 0, 0, FBackImage.Width, FBackImage.Height, ScreenDC, FImagePosition.X,
+ FImagePosition.Y, SRCCOPY);
+ end
+ else
+ begin
+ // overlapping copy
+ FillDragRectangles(FDragImage.Width, FDragImage.Height, DeltaX, DeltaY, RClip, RScroll, RSamp1, RSamp2, RDraw1,
+ RDraw2);
+
+ with FBackImage.Canvas do
+ begin
+ // restore uncovered areas of the screen
+ if DeltaX = 0 then
+ begin
+ with RDraw2 do
+ BitBlt(ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top, Right, Bottom, Handle, Left, Top,
+ SRCCOPY);
+ end
+ else
+ begin
+ if DeltaY = 0 then
+ begin
+ with RDraw1 do
+ BitBlt(ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top, Right, Bottom, Handle, Left, Top,
+ SRCCOPY);
+ end
+ else
+ begin
+ with RDraw1 do
+ BitBlt(ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top, Right, Bottom, Handle, Left, Top,
+ SRCCOPY);
+ with RDraw2 do
+ BitBlt(ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top, Right, Bottom, Handle, Left, Top,
+ SRCCOPY);
+ end;
+ end;
+
+ // move existent background
+ ScrollDC(Handle, DeltaX, DeltaY, RScroll, RClip, 0, nil);
+
+ Inc(FImagePosition.X, -DeltaX);
+ Inc(FImagePosition.Y, -DeltaY);
+
+ // Get first and second additional rectangle from screen.
+ if DeltaX = 0 then
+ begin
+ with RSamp2 do
+ BitBlt(Handle, Left, Top, Right, Bottom, ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top,
+ SRCCOPY);
+ end
+ else
+ if DeltaY = 0 then
+ begin
+ with RSamp1 do
+ BitBlt(Handle, Left, Top, Right, Bottom, ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top,
+ SRCCOPY);
+ end
+ else
+ begin
+ with RSamp1 do
+ BitBlt(Handle, Left, Top, Right, Bottom, ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top,
+ SRCCOPY);
+ with RSamp2 do
+ BitBlt(Handle, Left, Top, Right, Bottom, ScreenDC, FImagePosition.X + Left, FImagePosition.Y + Top,
+ SRCCOPY);
+ end;
+ end;
+ end;
+ InternalShowDragImage(ScreenDC);
+ finally
+ ReleaseDC(0, ScreenDC);
+ end;
+ end;
+ FLastPosition.X := P.X;
+ FLastPosition.Y := P.Y;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.EndDrag;
+
+begin
+ HideDragImage;
+ FStates := FStates - [disInDrag, disPrepared];
+
+ FBackImage.Free;
+ FBackImage := nil;
+ FDragImage.Free;
+ FDragImage := nil;
+ FAlphaImage.Free;
+ FAlphaImage := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragImage.GetDragImageRect: TRect;
+
+// Returns the current size and position of the drag image (screen coordinates).
+
+begin
+ if Visible then
+ begin
+ with FBackImage do
+ Result := Rect(FImagePosition.X, FImagePosition.Y, FImagePosition.X + Width, FImagePosition.Y + Height);
+ end
+ else
+ Result := Rect(0, 0, 0, 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.HideDragImage;
+
+var
+ ScreenDC: HDC;
+
+begin
+ if Visible then
+ begin
+ Include(FStates, disHidden);
+ ScreenDC := GetDC(0);
+ try
+ // restore screen
+ with FBackImage do
+ BitBlt(ScreenDC, FImagePosition.X, FImagePosition.Y, Width, Height, Canvas.Handle, 0, 0, SRCCOPY);
+ finally
+ ReleaseDC(0, ScreenDC);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.PrepareDrag(DragImage: TBitmap; ImagePosition, HotSpot: TPoint; const DataObject: IDataObject);
+
+// Creates all necessary structures to do alpha blended dragging using the given image.
+// ImagePostion and Hotspot are given in screen coordinates. The first determines where to place the drag image while
+// the second is the initial mouse position.
+// This method also determines whether the system supports drag images natively. If so then only minimal structures
+// are created.
+
+var
+ Width,
+ Height: Integer;
+ DragSourceHelper: IDragSourceHelper;
+ DragInfo: TSHDragImage;
+
+begin
+ Width := DragImage.Width;
+ Height := DragImage.Height;
+
+ // Determine whether the system supports the drag helper interfaces.
+ if Assigned(DataObject) and Succeeded(CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER,
+ IID_IDragSourceHelper, DragSourceHelper)) then
+ begin
+ Include(FStates, disSystemSupport);
+
+ // Supply the drag source helper with our drag image.
+ DragInfo.sizeDragImage.cx := Width;
+ DragInfo.sizeDragImage.cy := Height;
+ DragInfo.ptOffset.x := Width div 2;
+ DragInfo.ptOffset.y := Height div 2;
+ DragInfo.hbmpDragImage := CopyImage(DragImage.Handle, IMAGE_BITMAP, Width, Height, LR_COPYRETURNORG);
+ DragInfo.ColorRef := ColorToRGB(FColorKey);
+ if not Succeeded(DragSourceHelper.InitializeFromBitmap(DragInfo, DataObject)) then
+ begin
+ DeleteObject(DragInfo.hbmpDragImage);
+ Exclude(FStates, disSystemSupport);
+ end;
+ end
+ else
+ Exclude(FStates, disSystemSupport);
+
+ if MMXAvailable and not (disSystemSupport in FStates) then
+ begin
+ FLastPosition := HotSpot;
+
+ FDragImage := TBitmap.Create;
+ FDragImage.PixelFormat := pf32Bit;
+ FDragImage.Width := Width;
+ FDragImage.Height := Height;
+
+ FAlphaImage := TBitmap.Create;
+ FAlphaImage.PixelFormat := pf32Bit;
+ FAlphaImage.Width := Width;
+ FAlphaImage.Height := Height;
+
+ FBackImage := TBitmap.Create;
+ FBackImage.PixelFormat := pf32Bit;
+ FBackImage.Width := Width;
+ FBackImage.Height := Height;
+
+ // Copy the given drag image and apply pre blend bias if required.
+ if FPreBlendBias = 0 then
+ with FDragImage do
+ BitBlt(Canvas.Handle, 0, 0, Width, Height, DragImage.Canvas.Handle, 0, 0, SRCCOPY)
+ else
+ AlphaBlend(DragImage.Canvas.Handle, FDragImage.Canvas.Handle, Rect(0, 0, Width, Height), Point(0, 0),
+ bmConstantAlpha, 255, FPreBlendBias);
+
+ // Create a proper alpha channel also if no fading is required (transparent parts).
+ MakeAlphaChannel(DragImage, FDragImage);
+
+ FImagePosition := ImagePosition;
+
+ // Initially the drag image is hidden and will be shown during the immediately following DragEnter event.
+ FStates := FStates + [disInDrag, disHidden, disPrepared];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.RecaptureBackground(Tree: TBaseVirtualTree; R: TRect; VisibleRegion: HRGN;
+ CaptureNCArea, ReshowDragImage: Boolean);
+
+// Notification by the drop target tree to update the background image because something in the tree has changed.
+// Note: The passed rectangle is given in client coordinates of the current drop target tree (given in Tree).
+// The caller does not check if the given rectangle is actually within the drag image. Hence this method must do
+// all the checks.
+// This method does nothing if the system manages the drag image.
+
+var
+ DragRect,
+ ClipRect: TRect;
+ PaintTarget: TPoint;
+ PaintOptions: TVTInternalPaintOptions;
+ ScreenDC: HDC;
+
+begin
+ // Recapturing means we want the tree to paint the new part into our back bitmap instead to the screen.
+ if Visible then
+ begin
+ // Create the minimum rectangle to be recaptured.
+ MapWindowPoints(Tree.Handle, 0, R, 2);
+ DragRect := GetDragImageRect;
+ IntersectRect(R, R, DragRect);
+
+ OffsetRgn(VisibleRegion, -DragRect.Left, -DragRect.Top);
+
+ // The target position for painting in the drag image is relative and can be determined from screen coordinates too.
+ PaintTarget.X := R.Left - DragRect.Left;
+ PaintTarget.Y := R.Top - DragRect.Top;
+
+ // The source rectangle is determined by the offsets in the tree.
+ MapWindowPoints(0, Tree.Handle, R, 2);
+ OffsetRect(R, -Tree.FOffsetX, -Tree.FOffsetY);
+
+ // Finally let the tree paint the relevant part and upate the drag image on screen.
+ PaintOptions := [poBackground, poColumnColor, poDrawFocusRect, poDrawDropMark, poDrawSelection, poGridLines];
+ with FBackImage do
+ begin
+ ClipRect.TopLeft := PaintTarget;
+ ClipRect.Right := ClipRect.Left + R.Right - R.Left;
+ ClipRect.Bottom := ClipRect.Top + R.Bottom - R.Top;
+ Tree.LimitPaintingToArea(Canvas, ClipRect, VisibleRegion);
+ Tree.PaintTree(Canvas, R, PaintTarget, PaintOptions);
+
+ if CaptureNCArea then
+ begin
+ // For the non-client area we only need the visible region of the window as limit for painting.
+ SelectClipRgn(Canvas.Handle, VisibleRegion);
+ // Since WM_PRINT cannot be given a position where to draw we simply move the window origin and
+ // get the same effect.
+ GetWindowRect(Tree.Handle, ClipRect);
+ SetWindowOrgEx(Canvas.Handle, DragRect.Left - ClipRect.Left, DragRect.Top - ClipRect.Top, nil);
+ Tree.Perform(WM_PRINT, Integer(Canvas.Handle), PRF_NONCLIENT);
+ SetWindowOrgEx(Canvas.Handle, 0, 0, nil);
+ end;
+ SelectClipRgn(Canvas.Handle, 0);
+
+ if ReshowDragImage then
+ begin
+ GDIFlush;
+ ScreenDC := GetDC(0);
+ try
+ InternalShowDragImage(ScreenDC);
+ finally
+ ReleaseDC(0, ScreenDC);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTDragImage.ShowDragImage;
+
+// Shows the drag image after it has been hidden by HideDragImage.
+// Note: there might be a new background now.
+// Also this method does nothing if the system manages the drag image.
+
+var
+ ScreenDC: HDC;
+
+begin
+ if FStates * [disInDrag, disHidden, disPrepared, disSystemSupport] = [disInDrag, disHidden, disPrepared] then
+ begin
+ Exclude(FStates, disHidden);
+
+ GDIFlush;
+ ScreenDC := GetDC(0);
+ try
+ BitBlt(FBackImage.Canvas.Handle, 0, 0, FBackImage.Width, FBackImage.Height, ScreenDC, FImagePosition.X,
+ FImagePosition.Y, SRCCOPY);
+
+ InternalShowDragImage(ScreenDC);
+ finally
+ ReleaseDC(0, ScreenDC);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTDragImage.WillMove(P: TPoint): Boolean;
+
+// This method determines whether the drag image would "physically" move when DragTo would be called with the same
+// target point.
+// Always returns False if the system drag image support is available.
+
+var
+ DeltaX,
+ DeltaY: Integer;
+
+begin
+ Result := Visible;
+ if Result then
+ begin
+ // Determine distances to move the drag image. Take care for restrictions.
+ case FRestriction of
+ dmrHorizontalOnly:
+ begin
+ DeltaX := FLastPosition.X - P.X;
+ DeltaY := 0;
+ end;
+ dmrVerticalOnly:
+ begin
+ DeltaX := 0;
+ DeltaY := FLastPosition.Y - P.Y;
+ end;
+ else // dmrNone
+ DeltaX := FLastPosition.X - P.X;
+ DeltaY := FLastPosition.Y - P.Y;
+ end;
+
+ Result := (DeltaX <> 0) or (DeltaY <> 0);
+ end;
+end;
+
+//----------------- TVirtualTreeColumn ---------------------------------------------------------------------------------
+
+constructor TVirtualTreeColumn.Create(Collection: TCollection);
+
+begin
+ FWidth := 50;
+ FLastWidth := 50;
+ FMinWidth := 10;
+ FMaxWidth := 10000;
+ FImageIndex := -1;
+ FMargin := 4;
+ FSpacing := 4;
+ FText := '';
+ FOptions := DefaultColumnOptions;
+ FAlignment := taLeftJustify;
+ FBidiMode := bdLeftToRight;
+ FColor := clWindow;
+ FLayout := blGlyphLeft;
+
+ inherited Create(Collection);
+
+ FPosition := Owner.Count - 1;
+ // Read parent bidi mode and color values as default values.
+ ParentBiDiModeChanged;
+ ParentColorChanged;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVirtualTreeColumn.Destroy;
+
+var
+ I: Integer;
+
+begin
+ // Check if this column is somehow referenced by its collection parent or the header.
+ with Owner do
+ begin
+ // If the columns collection object is currently deleting all columns
+ // then we don't need to check the various cached indices individually.
+ if not FClearing then
+ begin
+ IndexChanged(Index, -1);
+
+ if Index = FHoverIndex then
+ FHoverIndex := NoColumn;
+ if Index = FDownIndex then
+ FDownIndex := NoColumn;
+ if Index = FTrackIndex then
+ FTrackIndex := NoColumn;
+ if Index = FClickIndex then
+ FClickIndex := NoColumn;
+
+ with Header do
+ begin
+ if Index = FAutoSizeIndex then
+ FAutoSizeIndex := NoColumn;
+ if Index = FMainColumn then
+ begin
+ // If the current main column is about to be destroyed then we have to find a new main column.
+ FMainColumn := NoColumn;
+ for I := 0 to Count - 1 do
+ if I <> Index then
+ begin
+ FMainColumn := I;
+ Break;
+ end;
+ end;
+ if Index = FSortColumn then
+ FSortColumn := NoColumn;
+ end;
+ end;
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.GetLeft: Integer;
+
+begin
+ Result := FLeft + Owner.Header.Treeview.FOffsetX;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.IsBiDiModeStored: Boolean;
+
+begin
+ Result := not (coParentBiDiMode in FOptions);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.IsColorStored: Boolean;
+
+begin
+ Result := not (coParentColor in FOptions);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetAlignment(const Value: TAlignment);
+
+begin
+ if FAlignment <> Value then
+ begin
+ FAlignment := Value;
+ Changed(False);
+ // Setting the alignment affects also the tree, hence invalidate it too.
+ Owner.Header.TreeView.Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetBiDiMode(Value: TBiDiMode);
+
+begin
+ if Value <> FBiDiMode then
+ begin
+ FBiDiMode := Value;
+ Exclude(FOptions, coParentBiDiMode);
+ Changed(False);
+ // Setting the alignment affects also the tree, hence invalidate it too.
+ Owner.Header.TreeView.Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetColor(const Value: TColor);
+
+begin
+ if FColor <> Value then
+ begin
+ FColor := Value;
+ Exclude(FOptions, coParentColor);
+ Changed(False);
+ Owner.Header.TreeView.Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetImageIndex(Value: TImageIndex);
+
+begin
+ if Value <> FImageIndex then
+ begin
+ FImageIndex := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetLayout(Value: TVTHeaderColumnLayout);
+
+begin
+ if FLayout <> Value then
+ begin
+ FLayout := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetMargin(Value: Integer);
+
+begin
+ // Compatibility setting for -1.
+ if Value < 0 then
+ Value := 4;
+ if FMargin <> Value then
+ begin
+ FMargin := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetMaxWidth(Value: Integer);
+
+begin
+ if Value < FMinWidth then
+ Value := FMinWidth;
+ if Value > 10000 then
+ Value := 10000;
+ FMaxWidth := Value;
+ SetWidth(FWidth);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetMinWidth(Value: Integer);
+
+begin
+ if Value < 0 then
+ Value := 0;
+ if Value > FMaxWidth then
+ Value := FMaxWidth;
+ FMinWidth := Value;
+ SetWidth(FWidth);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetOptions(Value: TVTColumnOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTColumnOptions;
+ VisibleChanged,
+ ColorChanged: Boolean;
+
+begin
+ if FOptions <> Value then
+ begin
+ ToBeCleared := FOptions - Value;
+ ToBeSet := Value - FOptions;
+
+ FOptions := Value;
+
+ VisibleChanged := coVisible in (ToBeSet + ToBeCleared);
+ ColorChanged := coParentColor in ToBeSet;
+
+ if coParentBidiMode in ToBeSet then
+ ParentBiDiModeChanged;
+ if ColorChanged then
+ ParentColorChanged;
+
+ Changed(False);
+ // Need to repaint and adjust the owner tree too.
+ with Owner, Header.Treeview do
+ if not (csLoading in ComponentState) and (VisibleChanged or ColorChanged) and (UpdateCount = 0) then
+ begin
+ Invalidate;
+ if VisibleChanged then
+ UpdateHorizontalScrollBar(False);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetPosition(Value: TColumnPosition);
+
+begin
+ if csLoading in Owner.Header.Treeview.ComponentState then
+ // Only cache the position for final fixup when loading from DFM.
+ FPosition := Value
+ else
+ begin
+ if Value >= TColumnPosition(Collection.Count) then
+ Value := Collection.Count - 1;
+ if FPosition <> Value then
+ with Owner do
+ begin
+ InitializePositionArray;
+ // need to repaint and adjust the owner tree too
+ with Header do
+ begin
+ if not (csLoading in Treeview.ComponentState) and (UpdateCount = 0) then
+ begin
+ AdjustPosition(Self, Value);
+ UpdatePositions;
+ Treeview.CancelEditNode;
+ Invalidate(Self);
+ Treeview.Invalidate;
+ Treeview.UpdateHorizontalScrollBar(False);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetSpacing(Value: Integer);
+
+begin
+ if FSpacing <> Value then
+ begin
+ FSpacing := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetStyle(Value: TVirtualTreeColumnStyle);
+
+begin
+ if FStyle <> Value then
+ begin
+ FStyle := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetText(const Value: WideString);
+
+begin
+ if FText <> Value then
+ begin
+ FText := Value;
+ Changed(False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetWidth(Value: Integer);
+
+begin
+ if Value < FMinWidth then
+ Value := FMinWidth;
+ if Value > FMaxWidth then
+ Value := FMaxWidth;
+
+ if FWidth <> Value then
+ begin
+ FLastWidth := FWidth;
+ with Owner, Header do
+ begin
+ if not (hoAutoResize in FOptions) or (Index <> FAutoSizeIndex) then
+ begin
+ FWidth := Value;
+ UpdatePositions;
+ end;
+ if not (csLoading in Treeview.ComponentState) and (UpdateCount = 0) then
+ begin
+ if hoAutoResize in FOptions then
+ AdjustAutoSize(Index);
+ Treeview.DoColumnResize(Index);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ComputeHeaderLayout(DC: HDC; const Client: TRect; UseHeaderGlyph, UseSortGlyph: Boolean;
+ var HeaderGlyphPos, SortGlyphPos: TPoint; var TextBounds: TRect);
+
+// The layout of a column header is determined by a lot of factors. This method takes them all into account and
+// determines all necessary positions and bounds:
+// - for the header text
+// - the header glyph
+// - the sort glyph
+
+var
+ TextSize: TSize;
+ TextPos,
+ ClientSize,
+ HeaderGlyphSize,
+ SortGlyphSize: TPoint;
+ CurrentAlignment: TAlignment;
+ MinLeft,
+ MaxRight,
+ TextSpacing: Integer;
+ UseText: Boolean;
+
+begin
+ UseText := Length(FText) > 0;
+ // If nothing is to show then don't waste time with useless preparation.
+ if not (UseText or UseHeaderGlyph or UseSortGlyph) then
+ Exit;
+
+ CurrentAlignment := FAlignment;
+ if FBidiMode <> bdLeftToRight then
+ ChangeBiDiModeAlignment(CurrentAlignment);
+
+ // Calculate sizes of the involved items.
+ ClientSize := Point(Client.Right - Client.Left, Client.Bottom - Client.Top);
+ with Owner, Header do
+ begin
+ if UseHeaderGlyph then
+ HeaderGlyphSize := Point(FImages.Width, FImages.Height)
+ else
+ HeaderGlyphSize := Point(0, 0);
+ if UseSortGlyph then
+ begin
+ SortGlyphSize := Point(UtilityImages.Width, UtilityImages.Height);
+ // In any case, the sort glyph is vertically centered.
+ SortGlyphPos.Y := (ClientSize.Y - SortGlyphSize.Y) div 2;
+ end
+ else
+ SortGlyphSize := Point(0, 0);
+ end;
+
+ if UseText then
+ begin
+ GetTextExtentPoint32W(DC, PWideChar(FText), Length(FText), TextSize);
+ Inc(TextSize.cx, 2);
+ TextBounds := Rect(0, 0, TextSize.cx, TextSize.cy);
+ TextSpacing := FSpacing;
+ end
+ else
+ begin
+ TextSpacing := 0;
+ TextSize.cx := 0;
+ TextSize.cy := 0;
+ end;
+
+ // Check first for the special case where nothing is shown except the sort glyph.
+ if UseSortGlyph and not (UseText or UseHeaderGlyph) then
+ begin
+ // Center the sort glyph in the available area if nothing else is there.
+ SortGlyphPos := Point((ClientSize.X - SortGlyphSize.X) div 2, (ClientSize.Y - SortGlyphSize.Y) div 2);
+ end
+ else
+ begin
+ // Determine extents of text and glyph and calculate positions which are clear from the layout.
+ if (Layout in [blGlyphLeft, blGlyphRight]) or not UseHeaderGlyph then
+ begin
+ HeaderGlyphPos.Y := (ClientSize.Y - HeaderGlyphSize.Y) div 2;
+ TextPos.Y := (ClientSize.Y - TextSize.cy) div 2;
+ end
+ else
+ begin
+ if Layout = blGlyphTop then
+ begin
+ HeaderGlyphPos.Y := (ClientSize.Y - HeaderGlyphSize.Y - TextSize.cy - TextSpacing) div 2;
+ TextPos.Y := HeaderGlyphPos.Y + HeaderGlyphSize.Y + TextSpacing;
+ end
+ else
+ begin
+ TextPos.Y := (ClientSize.Y - HeaderGlyphSize.Y - TextSize.cy - TextSpacing) div 2;
+ HeaderGlyphPos.Y := TextPos.Y + TextSize.cy + TextSpacing;
+ end;
+ end;
+
+ // Each alignment needs special consideration.
+ case CurrentAlignment of
+ taLeftJustify:
+ begin
+ MinLeft := FMargin;
+ if UseSortGlyph and (FBidiMode <> bdLeftToRight) then
+ begin
+ // In RTL context is the sort glyph placed on the left hand side.
+ SortGlyphPos.X := MinLeft;
+ Inc(MinLeft, SortGlyphSize.X + FSpacing);
+ end;
+ if Layout in [blGlyphTop, blGlyphBottom] then
+ begin
+ // Header glyph is above or below text, so both must be considered when calculating
+ // the left positition of the sort glyph (if it is on the right hand side).
+ TextPos.X := MinLeft;
+ if UseHeaderGlyph then
+ begin
+ HeaderGlyphPos.X := (ClientSize.X - HeaderGlyphSize.X) div 2;
+ if HeaderGlyphPos.X < MinLeft then
+ HeaderGlyphPos.X := MinLeft;
+ MinLeft := Max(TextPos.X + TextSize.cx + TextSpacing, HeaderGlyphPos.X + HeaderGlyphSize.X + FSpacing);
+ end
+ else
+ MinLeft := TextPos.X + TextSize.cx + TextSpacing;
+ end
+ else
+ begin
+ // Everything is lined up. TextSpacing might be 0 if there is no text.
+ // This simplifies the calculation because no extra tests are necessary.
+ if UseHeaderGlyph and (Layout = blGlyphLeft) then
+ begin
+ HeaderGlyphPos.X := MinLeft;
+ Inc(MinLeft, HeaderGlyphSize.X + FSpacing);
+ end;
+ TextPos.X := MinLeft;
+ Inc(MinLeft, TextSize.cx + TextSpacing);
+ if UseHeaderGlyph and (Layout = blGlyphRight) then
+ begin
+ HeaderGlyphPos.X := MinLeft;
+ Inc(MinLeft, HeaderGlyphSize.X + FSpacing);
+ end;
+ end;
+ if UseSortGlyph and (FBidiMode = bdLeftToRight) then
+ SortGlyphPos.X := MinLeft;
+ end;
+ taCenter:
+ begin
+ if Layout in [blGlyphTop, blGlyphBottom] then
+ begin
+ HeaderGlyphPos.X := (ClientSize.X - HeaderGlyphSize.X) div 2;
+ TextPos.X := (ClientSize.X - TextSize.cx) div 2;
+ if UseSortGlyph then
+ Dec(TextPos.X, SortGlyphSize.X div 2);
+ end
+ else
+ begin
+ MinLeft := (ClientSize.X - HeaderGlyphSize.X - TextSpacing - TextSize.cx) div 2;
+ if UseHeaderGlyph and (Layout = blGlyphLeft) then
+ begin
+ HeaderGlyphPos.X := MinLeft;
+ Inc(MinLeft, HeaderGlyphSize.X + TextSpacing);
+ end;
+ TextPos.X := MinLeft;
+ Inc(MinLeft, TextSize.cx + TextSpacing);
+ if UseHeaderGlyph and (Layout = blGlyphRight) then
+ HeaderGlyphPos.X := MinLeft;
+ end;
+ if UseHeaderGlyph then
+ begin
+ MinLeft := Min(HeaderGlyphPos.X, TextPos.X);
+ MaxRight := Max(HeaderGlyphPos.X + HeaderGlyphSize.X, TextPos.X + TextSize.cx);
+ end
+ else
+ begin
+ MinLeft := TextPos.X;
+ MaxRight := TextPos.X + TextSize.cx;
+ end;
+ // Place the sort glyph directly to the left or right of the larger item.
+ if UseSortGlyph then
+ if FBidiMode = bdLeftToRight then
+ begin
+ // Sort glyph on the right hand side.
+ SortGlyphPos.X := MaxRight + FSpacing;
+ end
+ else
+ begin
+ // Sort glyph on the left hand side.
+ SortGlyphPos.X := MinLeft - FSpacing - SortGlyphSize.X;
+ end;
+ end;
+ else
+ // taRightJustify
+ MaxRight := ClientSize.X - FMargin;
+ if UseSortGlyph and (FBidiMode = bdLeftToRight) then
+ begin
+ // In LTR context is the sort glyph placed on the right hand side.
+ Dec(MaxRight, SortGlyphSize.X);
+ SortGlyphPos.X := MaxRight;
+ Dec(MaxRight, FSpacing);
+ end;
+ if Layout in [blGlyphTop, blGlyphBottom] then
+ begin
+ TextPos.X := MaxRight - TextSize.cx;
+ if UseHeaderGlyph then
+ begin
+ HeaderGlyphPos.X := (ClientSize.X - HeaderGlyphSize.X) div 2;
+ if HeaderGlyphPos.X + HeaderGlyphSize.X + FSpacing > MaxRight then
+ HeaderGlyphPos.X := MaxRight - HeaderGlyphSize.X - FSpacing;
+ MaxRight := Min(TextPos.X - TextSpacing, HeaderGlyphPos.X - FSpacing);
+ end
+ else
+ MaxRight := TextPos.X - TextSpacing;
+ end
+ else
+ begin
+ // Everything is lined up. TextSpacing might be 0 if there is no text.
+ // This simplifies the calculation because no extra tests are necessary.
+ if UseHeaderGlyph and (Layout = blGlyphRight) then
+ begin
+ HeaderGlyphPos.X := MaxRight - HeaderGlyphSize.X;
+ MaxRight := HeaderGlyphPos.X - FSpacing;
+ end;
+ TextPos.X := MaxRight - TextSize.cx;
+ MaxRight := TextPos.X - TextSpacing;
+ if UseHeaderGlyph and (Layout = blGlyphLeft) then
+ begin
+ HeaderGlyphPos.X := MaxRight - HeaderGlyphSize.X;
+ MaxRight := HeaderGlyphPos.X - FSpacing;
+ end;
+ end;
+ if UseSortGlyph and (FBidiMode <> bdLeftToRight) then
+ SortGlyphPos.X := MaxRight - SortGlyphSize.X;
+ end;
+ end;
+
+ // Once the position of each element is determined there remains only one but important step.
+ // The horizontal positions of every element must be adjusted so that it always fits into the
+ // given header area. This is accomplished by shorten the text appropriately.
+
+ // These are the maximum bounds. Nothing goes beyond them.
+ MinLeft := FMargin;
+ MaxRight := ClientSize.X - FMargin;
+ if UseSortGlyph then
+ begin
+ if FBidiMode = bdLeftToRight then
+ begin
+ // Sort glyph on the right hand side.
+ if SortGlyphPos.X + SortGlyphSize.X > MaxRight then
+ SortGlyphPos.X := MaxRight - SortGlyphSize.X;
+ MaxRight := SortGlyphPos.X - FSpacing;
+ end;
+
+ // Consider also the left side of the sort glyph regardless of the bidi mode.
+ if SortGlyphPos.X < MinLeft then
+ SortGlyphPos.X := MinLeft;
+ // Left border needs only adjustment if the sort glyph marks the left border.
+ if FBidiMode <> bdLeftToRight then
+ MinLeft := SortGlyphPos.X + SortGlyphSize.X + FSpacing;
+
+ // Finally transform sort glyph to its actual position.
+ with SortGlyphPos do
+ begin
+ Inc(X, Client.Left);
+ Inc(Y, Client.Top);
+ end;
+ end;
+ if UseHeaderGlyph then
+ begin
+ if HeaderGlyphPos.X + HeaderGlyphSize.X > MaxRight then
+ HeaderGlyphPos.X := MaxRight - HeaderGlyphSize.X;
+ if Layout = blGlyphRight then
+ MaxRight := HeaderGlyphPos.X - FSpacing;
+ if HeaderGlyphPos.X < MinLeft then
+ HeaderGlyphPos.X := MinLeft;
+ if Layout = blGlyphLeft then
+ MinLeft := HeaderGlyphPos.X + HeaderGlyphSize.X + FSpacing;
+ // Finally transform header glyph to its actual position.
+ with HeaderGlyphPos do
+ begin
+ Inc(X, Client.Left);
+ Inc(Y, Client.Top);
+ end;
+ end;
+ if UseText then
+ begin
+ if TextPos.X < MinLeft then
+ TextPos.X := MinLeft;
+ OffsetRect(TextBounds, TextPos.X, TextPos.Y);
+ if TextBounds.Right > MaxRight then
+ TextBounds.Right := MaxRight;
+ OffsetRect(TextBounds, Client.Left, Client.Top);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.DefineProperties(Filer: TFiler);
+
+begin
+ inherited;
+
+ // Must define a new name for the properties otherwise the VCL will try to load the wide string
+ // without asking us and screws it completely up.
+ Filer.DefineProperty('WideText', ReadText, WriteText, FText <> '');
+ Filer.DefineProperty('WideHint', ReadHint, WriteHint, FHint <> '');
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.GetAbsoluteBounds(var Left, Right: Integer);
+
+// Returns the column's left and right bounds in header coordinates, that is, independant of the scrolling position.
+
+begin
+ Left := FLeft;
+ Right := FLeft + FWidth;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.GetDisplayName: string;
+
+// Returns the column text if it only contains ANSI characters, otherwise the column id is returned because the IDE
+// still cannot handle Unicode strings.
+
+var
+ I: Integer;
+
+begin
+ // Check if the text of the column contains characters > 255
+ I := 1;
+ while I <= Length(FText) do
+ begin
+ if Ord(FText[I]) > 255 then
+ Break;
+ Inc(I);
+ end;
+
+ if I > Length(FText) then
+ Result := FText // implicit conversion
+ else
+ Result := Format('Column %d', [Index]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.GetOwner: TVirtualTreeColumns;
+
+begin
+ Result := Collection as TVirtualTreeColumns;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ReadText(Reader: TReader);
+
+begin
+ case Reader.NextValue of
+ vaLString, vaString:
+ SetText(Reader.ReadString);
+ else
+ SetText(Reader.ReadWideString);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SetIndex(Value: Integer);
+
+begin
+ if Index <> Value then
+ begin
+ // Tell the columns collection about the index change. Its position array must be updated.
+ Owner.IndexChanged(Index, Value);
+
+ inherited;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ReadHint(Reader: TReader);
+
+begin
+ case Reader.NextValue of
+ vaLString, vaString:
+ FHint := Reader.ReadString;
+ else
+ FHint := Reader.ReadWideString;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.WriteHint(Writer: TWriter);
+
+begin
+ Writer.WriteWideString(FHint);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.WriteText(Writer: TWriter);
+
+begin
+ Writer.WriteWideString(FText);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.Assign(Source: TPersistent);
+
+var
+ OldOptions: TVTColumnOptions;
+
+begin
+ if Source is TVirtualTreeColumn then
+ begin
+ OldOptions := FOptions;
+ FOptions := [];
+
+ BiDiMode := TVirtualTreeColumn(Source).BiDiMode;
+ ImageIndex := TVirtualTreeColumn(Source).ImageIndex;
+ Layout := TVirtualTreeColumn(Source).Layout;
+ Margin := TVirtualTreeColumn(Source).Margin;
+ MaxWidth := TVirtualTreeColumn(Source).MaxWidth;
+ MinWidth := TVirtualTreeColumn(Source).MinWidth;
+ Position := TVirtualTreeColumn(Source).Position;
+ Spacing := TVirtualTreeColumn(Source).Spacing;
+ Style := TVirtualTreeColumn(Source).Style;
+ Text := TVirtualTreeColumn(Source).Text;
+ Hint := TVirtualTreeColumn(Source).Hint;
+ Width := TVirtualTreeColumn(Source).Width;
+ Alignment := TVirtualTreeColumn(Source).Alignment;
+ Color := TVirtualTreeColumn(Source).Color;
+ Tag := TVirtualTreeColumn(Source).Tag;
+
+ // Order is important. Assign options last.
+ FOptions := OldOptions;
+ Options := TVirtualTreeColumn(Source).Options;
+
+ Changed(False);
+ end
+ else
+ inherited Assign(Source);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.Equals(OtherColumn: TVirtualTreeColumn): Boolean;
+
+begin
+ Result := (BiDiMode = OtherColumn.BiDiMode) and
+ (ImageIndex = OtherColumn.ImageIndex) and
+ (Layout = OtherColumn.Layout) and
+ (Margin = OtherColumn.Margin) and
+ (MaxWidth = OtherColumn.MaxWidth) and
+ (MinWidth = OtherColumn.MinWidth) and
+ (Position = OtherColumn.Position) and
+ (Spacing = OtherColumn.Spacing) and
+ (Style = OtherColumn.Style) and
+ (Text = OtherColumn.Text) and
+ (Hint = OtherColumn.Hint) and
+ (Width = OtherColumn.Width) and
+ (Alignment = OtherColumn.Alignment) and
+ (Color = OtherColumn.Color) and
+ (Tag = OtherColumn.Tag) and
+ (Options = OtherColumn.Options);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.GetRect: TRect;
+
+// Returns the rectangle this column occupies in the header (relative to (0, 0) of the non-client area).
+
+begin
+ with TVirtualTreeColumns(GetOwner).FHeader do
+ Result := Treeview.FHeaderRect;
+ Inc(Result.Left, FLeft);
+ Result.Right := Result.Left + FWidth;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.LoadFromStream(const Stream: TStream; Version: Integer);
+
+ //--------------- local function --------------------------------------------
+
+ function ConvertOptions(Value: Cardinal): TVTColumnOptions;
+
+ // Converts the given raw value which represents column options for possibly older
+ // formats to the current format.
+
+ begin
+ if Version > 1 then
+ Result := TVTColumnOptions(Byte(Value))
+ else
+ begin
+ // In version 2 coParentColor has been added. This needs an option shift for older stream formats.
+ // The first (lower) 4 options remain as they are.
+ Result := TVTColumnOptions(Byte(Value) and $F);
+ Value := (Value and not $F) shl 1;
+ Result := Result + TVTColumnOptions(Byte(Value));
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ Dummy: Integer;
+ S: WideString;
+
+begin
+ with Stream do
+ begin
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SetLength(S, Dummy);
+ ReadBuffer(PWideChar(S)^, 2 * Dummy);
+ Text := S;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SetLength(FHint, Dummy);
+ ReadBuffer(PWideChar(FHint)^, 2 * Dummy);
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Width := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ MinWidth := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ MaxWidth := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Style := TVirtualTreeColumnStyle(Dummy);
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ ImageIndex := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Layout := TVTHeaderColumnLayout(Dummy);
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Margin := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Spacing := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ BiDiMode := TBiDiMode(Dummy);
+
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Options := ConvertOptions(Dummy);
+
+ if Version > 0 then
+ begin
+ // Parts which have been introduced/changed with header stream version 1+.
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Tag := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Alignment := TAlignment(Dummy);
+
+ if Version > 1 then
+ begin
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Color := TColor(Dummy);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ParentBiDiModeChanged;
+
+var
+ Columns: TVirtualTreeColumns;
+
+begin
+ if coParentBiDiMode in FOptions then
+ begin
+ Columns := GetOwner as TVirtualTreeColumns;
+ if Assigned(Columns) and (FBidiMode <> Columns.FHeader.Treeview.BiDiMode) then
+ begin
+ FBiDiMode := Columns.FHeader.Treeview.BiDiMode;
+ Changed(False);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.ParentColorChanged;
+
+var
+ Columns: TVirtualTreeColumns;
+
+begin
+ if coParentColor in FOptions then
+ begin
+ Columns := GetOwner as TVirtualTreeColumns;
+ if Assigned(Columns) and (FColor <> Columns.FHeader.Treeview.Color) then
+ begin
+ FColor := Columns.FHeader.Treeview.Color;
+ Changed(False);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.RestoreLastWidth;
+
+begin
+ TVirtualTreeColumns(GetOwner).AnimatedResize(Index, FLastWidth);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumn.SaveToStream(const Stream: TStream);
+
+var
+ Dummy: Integer;
+
+begin
+ with Stream do
+ begin
+ Dummy := Length(FText);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ WriteBuffer(PWideChar(FText)^, 2 * Dummy);
+ Dummy := Length(FHint);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ WriteBuffer(PWideChar(FHint)^, 2 * Dummy);
+ WriteBuffer(FWidth, SizeOf(FWidth));
+ WriteBuffer(FMinWidth, SizeOf(FMinWidth));
+ WriteBuffer(FMaxWidth, SizeOf(FMaxWidth));
+ Dummy := Ord(FStyle);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := FImageIndex;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Ord(FLayout);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ WriteBuffer(FMargin, SizeOf(FMargin));
+ WriteBuffer(FSpacing, SizeOf(FSpacing));
+ Dummy := Ord(FBiDiMode);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Byte(FOptions);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+
+ // parts introduce with stream version 1
+ WriteBuffer(FTag, SizeOf(Dummy));
+ Dummy := Cardinal(FAlignment);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+
+ // parts introduce with stream version 2
+ Dummy := Integer(FColor);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumn.UseRightToLeftReading: Boolean;
+
+begin
+ Result := FBiDiMode <> bdLeftToRight;
+end;
+
+//----------------- TVirtualTreeColumns --------------------------------------------------------------------------------
+
+constructor TVirtualTreeColumns.Create(AOwner: TVTHeader);
+
+var
+ ColumnClass: TVirtualTreeColumnClass;
+
+begin
+ FHeader := AOwner;
+
+ // Determine column class to be used in the header.
+ ColumnClass := AOwner.FOwner.GetColumnClass;
+ // The owner tree always returns the default tree column class if not changed by application/descentants.
+ inherited Create(ColumnClass);
+
+ FHeaderBitmap := TBitmap.Create;
+ FHeaderBitmap.PixelFormat := pf32Bit;
+
+ FHoverIndex := NoColumn;
+ FDownIndex := NoColumn;
+ FClickIndex := NoColumn;
+ FDropTarget := NoColumn;
+ FTrackIndex := NoColumn;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVirtualTreeColumns.Destroy;
+
+begin
+ FHeaderBitmap.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.DrawButtonText(DC: HDC; Caption: WideString; Bounds: TRect; Enabled, Hot: Boolean;
+ DrawFormat: Cardinal);
+
+var
+ TextSpace: Integer;
+ Size: TSize;
+
+begin
+ // Do we need to shorten the caption due to limited space?
+ GetTextExtentPoint32W(DC, PWideChar(Caption), Length(Caption), Size);
+ TextSpace := Bounds.Right - Bounds.Left;
+ if TextSpace < Size.cx then
+ Caption := ShortenString(DC, Caption, TextSpace, DT_RTLREADING and DrawFormat <> 0);
+
+ SetBkMode(DC, TRANSPARENT);
+ if not Enabled then
+ begin
+ OffsetRect(Bounds, 1, 1);
+ SetTextColor(DC, ColorToRGB(clBtnHighlight));
+ if IsWinNT then
+ Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat)
+ else
+ DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat, False);
+ OffsetRect(Bounds, -1, -1);
+ SetTextColor(DC, ColorToRGB(clBtnShadow));
+ if IsWinNT then
+ Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat)
+ else
+ DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat, False);
+ end
+ else
+ begin
+ if Hot then
+ SetTextColor(DC, ColorToRGB(clBtnShadow))
+ else
+ SetTextColor(DC, ColorToRGB(FHeader.FFont.Color));
+ if IsWinNT then
+ Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat)
+ else
+ DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetItem(Index: TColumnIndex): TVirtualTreeColumn;
+
+begin
+ Result := TVirtualTreeColumn(inherited GetItem(Index));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetNewIndex(P: TPoint; var OldIndex: TColumnIndex): Boolean;
+
+var
+ NewIndex: Integer;
+
+begin
+ Result := False;
+ // convert to local coordinates
+ Inc(P.Y, FHeader.FHeight);
+ NewIndex := ColumnFromPosition(P);
+ if NewIndex <> OldIndex then
+ begin
+ if OldIndex > NoColumn then
+ FHeader.Invalidate(Items[OldIndex]);
+ OldIndex := NewIndex;
+ if OldIndex > NoColumn then
+ FHeader.Invalidate(Items[OldIndex]);
+ Result := True;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.SetItem(Index: TColumnIndex; Value: TVirtualTreeColumn);
+
+begin
+ inherited SetItem(Index, Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.AdjustAutoSize(CurrentIndex: TColumnIndex; Force: Boolean = False);
+
+// Called only if the header is in auto-size mode which means a column needs to be so large
+// that it fills all the horizontal space not occupied by the other columns.
+// CurrentIndex (if not InvalidColumn) describes which column has just been resized.
+
+var
+ NewValue,
+ AutoIndex,
+ Index,
+ RestWidth: Integer;
+
+begin
+ if Count > 0 then
+ begin
+ // Determine index to be used for auto resizing. This is usually given by the owner's AutoSizeIndex, but
+ // could be different if the column whose resize caused the invokation here is either the auto column itself
+ // or visually to the right of the auto size column.
+ AutoIndex := FHeader.FAutoSizeIndex;
+ if (AutoIndex < 0) or (AutoIndex >= Count) then
+ AutoIndex := Count - 1;
+ if (CurrentIndex > NoColumn) and
+ (Items[CurrentIndex].Position >= Items[AutoIndex].Position) then
+ begin
+ // The given index is the either the auto size column itself or visually to its right.
+ // Use the next column instead if there is one.
+ AutoIndex := GetNextVisibleColumn(CurrentIndex);
+ end;
+
+ if AutoIndex >= 0 then
+ begin
+ with FHeader.Treeview do
+ begin
+ if HandleAllocated then
+ RestWidth := ClientWidth
+ else
+ RestWidth := Width;
+ end;
+
+ // go through all columns and calculate the rest space remaining
+ for Index := 0 to Count - 1 do
+ if (Index <> AutoIndex) and (coVisible in Items[Index].FOptions) then
+ Dec(RestWidth, Items[Index].Width);
+
+ with Items[AutoIndex] do
+ begin
+ NewValue := Max(MinWidth, Min(MaxWidth, RestWidth));
+ if Force or (FWidth <> NewValue) then
+ begin
+ FWidth := NewValue;
+ UpdatePositions;
+ FHeader.Treeview.DoColumnResize(AutoIndex);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.AdjustDownColumn(P: TPoint): TColumnIndex;
+
+// Determines the column from the given position and returns it. If this column is allowed to be clicked then
+// it is also kept for later use.
+
+begin
+ // Convert to local coordinates.
+ Inc(P.Y, FHeader.FHeight);
+ Result := ColumnFromPosition(P);
+ if (Result > NoColumn) and (Result <> FDownIndex) and (coAllowClick in Items[Result].FOptions) and
+ (coEnabled in Items[Result].FOptions) then
+ begin
+ if FDownIndex > NoColumn then
+ FHeader.Invalidate(Items[FDownIndex]);
+ FDownIndex := Result;
+ FHeader.Invalidate(Items[FDownIndex]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.AdjustHoverColumn(P: TPoint): Boolean;
+
+// Determines the new hover column index and returns True if the index actually changed else False.
+
+begin
+ Result := GetNewIndex(P, FHoverIndex);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.AdjustPosition(Column: TVirtualTreeColumn; Position: Cardinal);
+
+// Reorders the column position array so that the given column gets the given position.
+
+var
+ OldPosition: Cardinal;
+
+begin
+ OldPosition := Column.Position;
+ if OldPosition <> Position then
+ begin
+ if OldPosition < Position then
+ begin
+ // column will be moved up so move down other entries
+ Move(FPositionToIndex[OldPosition + 1], FPositionToIndex[OldPosition], (Position - OldPosition) * SizeOf(Cardinal));
+ end
+ else
+ begin
+ // column will be moved down so move up other entries
+ Move(FPositionToIndex[Position], FPositionToIndex[Position + 1], (OldPosition - Position) * SizeOf(Cardinal));
+ end;
+ FPositionToIndex[Position] := Column.Index;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.FixPositions;
+
+// Fixes column positions after loading from DFM.
+
+var
+ I: Integer;
+
+begin
+ for I := 0 to Count - 1 do
+ FPositionToIndex[Items[I].Position] := I;
+ FNeedPositionsFix := False;
+ UpdatePositions(True);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetColumnAndBounds(P: TPoint; var ColumnLeft, ColumnRight: Integer;
+ Relative: Boolean = True): Integer;
+
+// Returns the column where the mouse is currently in as well as the left and right bound of
+// this column (Left and Right are undetermined if no column is involved).
+
+var
+ I: Integer;
+
+begin
+ Result := InvalidColumn;
+ if Relative then
+ ColumnLeft := FHeader.Treeview.FOffsetX
+ else
+ ColumnLeft := 0;
+ for I := 0 to Count - 1 do
+ with Items[FPositionToIndex[I]] do
+ if coVisible in FOptions then
+ begin
+ ColumnRight := ColumnLeft + FWidth;
+ if P.X < ColumnRight then
+ begin
+ Result := FPositionToIndex[I];
+ Exit;
+ end;
+ ColumnLeft := ColumnRight;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetOwner: TPersistent;
+
+begin
+ Result := FHeader;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.HandleClick(P: TPoint; Button: TMouseButton; Force, DblClick: Boolean);
+
+// Generates a click event if the mouse button has been released over the same column it was pressed first.
+// Alternatively, Force might be set to True to indicate that the down index does not matter (right, middle and
+// double click).
+
+var
+ NewClickIndex: Integer;
+ Shift: TShiftState;
+
+begin
+ // convert to local coordinates
+ Inc(P.Y, FHeader.FHeight);
+ NewClickIndex := ColumnFromPosition(P);
+ if (NewClickIndex > NoColumn) and (coAllowClick in Items[NewClickIndex].FOptions) and
+ ((NewClickIndex = FDownIndex) or Force) then
+ begin
+ FClickIndex := NewClickIndex;
+ Shift := FHeader.GetShiftState;
+ if DblClick then
+ Shift := Shift + [ssDouble];
+ FHeader.Treeview.DoHeaderClick(NewClickIndex, Button, Shift, P.X, P.Y);
+ FHeader.Invalidate(Items[NewClickIndex]);
+ end
+ else
+ FClickIndex := NoColumn;
+
+ if (FClickIndex > NoColumn) and (FClickIndex <> NewClickIndex) then
+ FHeader.Invalidate(Items[FClickIndex]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.IndexChanged(OldIndex, NewIndex: Integer);
+
+// Called by a column when its index in the collection changes. If NewIndex is -1 then the column is
+// about to be removed, otherwise it is moved to a new index.
+// The method will then update the position array to reflect the change.
+
+var
+ I: Integer;
+ Increment: Integer;
+ Lower,
+ Upper: Integer;
+
+begin
+ if NewIndex = -1 then
+ begin
+ // Find position in the array with the old index.
+ Upper := High(FPositionToIndex);
+ for I := 0 to Upper do
+ begin
+ if FPositionToIndex[I] = OldIndex then
+ begin
+ // Index found. Move all higher entries one step down and remove the last entry.
+ if I < Upper then
+ Move(FPositionToIndex[I + 1], FPositionToIndex[I], (Upper - I) * SizeOf(Integer));
+ end;
+ // Decrease all indices, which are greater than the index to be deleted.
+ if FPositionToIndex[I] > OldIndex then
+ Dec(FPositionToIndex[I]);
+ end;
+ SetLength(FPositionToIndex, High(FPositionToIndex));
+ end
+ else
+ begin
+ if OldIndex < NewIndex then
+ Increment := -1
+ else
+ Increment := 1;
+
+ Lower := Min(OldIndex, NewIndex);
+ Upper := Max(OldIndex, NewIndex);
+ for I := 0 to High(FPositionToIndex) do
+ begin
+ if (FPositionToIndex[I] >= Lower) and (FPositionToIndex[I] < Upper) then
+ Inc(FPositionToIndex[I], Increment)
+ else
+ if FPositionToIndex[I] = OldIndex then
+ FPositionToIndex[I] := NewIndex;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.InitializePositionArray;
+
+// Ensures that the column position array contains as much entries as columns are defined.
+// The array is resized and initialized with default values if needed.
+
+var
+ I, OldSize: Integer;
+ Changed: Boolean;
+
+begin
+ if Count <> Length(FPositionToIndex) then
+ begin
+ OldSize := Length(FPositionToIndex);
+ SetLength(FPositionToIndex, Count);
+ if Count > OldSize then
+ begin
+ // New items have been added, just set their position to the same as their index.
+ for I := OldSize to Count - 1 do
+ FPositionToIndex[I] := I;
+ end
+ else
+ begin
+ // Items have been deleted, so reindex remaining entries by decrementing values larger than the highest
+ // possible index until no entry is higher than this limit.
+ repeat
+ Changed := False;
+ for I := 0 to Count - 1 do
+ if FPositionToIndex[I] >= Count then
+ begin
+ Dec(FPositionToIndex[I]);
+ Changed := True;
+ end;
+ until not Changed;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.Update(Item: TCollectionItem);
+
+begin
+ // This is the only place which gets notified when a new column has been added or removed
+ // and we need this event to adjust the column position array.
+ InitializePositionArray;
+ if csLoading in Header.Treeview.ComponentState then
+ FNeedPositionsFix := True
+ else
+ UpdatePositions;
+
+ // The first column which is created is by definition also the main column.
+ if (Count > 0) and (Header.FMainColumn < 0) then
+ FHeader.FMainColumn := 0;
+
+ if not (csLoading in Header.Treeview.ComponentState) and not (hsLoading in FHeader.FStates) then
+ begin
+ with FHeader do
+ begin
+ if hoAutoResize in FOptions then
+ AdjustAutoSize(InvalidColumn);
+ if Assigned(Item) then
+ Invalidate(Item as TVirtualTreeColumn)
+ else
+ if Treeview.HandleAllocated then
+ begin
+ Treeview.UpdateHorizontalScrollBar(False);
+ Invalidate(nil);
+ Treeview.Invalidate;
+ end;
+ // This is mainly to let the designer know when a change occurs at design time which
+ // doesn't involve the object inspector (like column resizing with the mouse).
+ // This does NOT include design time code as the comunication is done via an interface.
+ Treeview.UpdateDesigner;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.UpdatePositions(Force: Boolean = False);
+
+// Recalculates the left border of every column and updates their position property according to the
+// PostionToIndex array which primarily determines where each column is placed visually.
+
+var
+ I, LeftPos: Integer;
+
+begin
+ if not FNeedPositionsFix and (Force or (UpdateCount = 0)) then
+ begin
+ LeftPos := 0;
+ for I := 0 to High(FPositionToIndex) do
+ with Items[FPositionToIndex[I]] do
+ begin
+ FPosition := I;
+ FLeft := LeftPos;
+ if coVisible in FOptions then
+ Inc(LeftPos, FWidth);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.Add: TVirtualTreeColumn;
+
+begin
+ Result := TVirtualTreeColumn(inherited Add);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.AnimatedResize(Column: TColumnIndex; NewWidth: Integer);
+
+// Resizes the given column animated by scrolling the window DC.
+
+var
+ OldWidth: Integer;
+ DC: HDC;
+ I,
+ Steps,
+ DX: Integer;
+ HeaderScrollRect,
+ ScrollRect,
+ R: TRect;
+
+ NewBrush,
+ LastBrush: HBRUSH;
+
+begin
+ // Make sure the width constrains are considered.
+ if NewWidth < Items[Column].FMinWidth then
+ NewWidth := Items[Column].FMinWidth;
+ if NewWidth > Items[Column].FMaxWidth then
+ NewWidth := Items[Column].FMaxWidth;
+
+ OldWidth := Items[Column].Width;
+ // Nothing to do if the width is the same.
+ if OldWidth <> NewWidth then
+ begin
+ DC := GetWindowDC(FHeader.Treeview.Handle);
+ with FHeader.Treeview do
+ try
+ Steps := 32;
+ DX := (NewWidth - OldWidth) div Steps;
+
+ // Determination of the scroll rectangle is a bit complicated since we neither want
+ // to scroll the scrollbars nor the border of the treeview window.
+ HeaderScrollRect := FHeaderRect;
+ ScrollRect := HeaderScrollRect;
+ // Exclude the header itself from scrolling.
+ ScrollRect.Top := ScrollRect.Bottom;
+ ScrollRect.Bottom := ScrollRect.Top + ClientHeight;
+ ScrollRect.Right := ScrollRect.Left + ClientWidth;
+ with Items[Column] do
+ Inc(ScrollRect.Left, FLeft + FWidth);
+ HeaderScrollRect.Left := ScrollRect.Left;
+ HeaderScrollRect.Right := ScrollRect.Right;
+
+ // When the new width is larger then avoid artefacts on the left hand side
+ // by deleting a small stripe
+ if NewWidth > OldWidth then
+ begin
+ R := ScrollRect;
+ NewBrush := CreateSolidBrush(ColorToRGB(Color));
+ LastBrush := SelectObject(DC, NewBrush);
+ R.Right := R.Left + DX;
+ FillRect(DC, R, NewBrush);
+ SelectObject(DC, LastBrush);
+ DeleteObject(NewBrush);
+ end
+ else
+ begin
+ Inc(HeaderScrollRect.Left, DX);
+ Inc(ScrollRect.Left, DX);
+ end;
+
+ for I := 0 to Steps - 1 do
+ begin
+ ScrollDC(DC, DX, 0, HeaderScrollRect, HeaderScrollRect, 0, nil);
+ Inc(HeaderScrollRect.Left, DX);
+ ScrollDC(DC, DX, 0, ScrollRect, ScrollRect, 0, nil);
+ Inc(ScrollRect.Left, DX);
+ Sleep(1);
+ end;
+ finally
+ ReleaseDC(Handle, DC);
+ end;
+ Items[Column].Width := NewWidth;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.Assign(Source: TPersistent);
+
+begin
+ // Let the collection class assign the items.
+ inherited;
+
+ if Source is TVirtualTreeColumns then
+ begin
+ // Copying the position array is the only needed task here.
+ FPositionToIndex := Copy(TVirtualTreeColumns(Source).FPositionToIndex, 0, MaxInt);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.Clear;
+
+begin
+ FClearing := True;
+ try
+ // Since we're freeing all columns, the following have to be true when we're done.
+ FHoverIndex := NoColumn;
+ FDownIndex := NoColumn;
+ FTrackIndex := NoColumn;
+ FClickIndex := NoColumn;
+
+ with Header do
+ if not (hsLoading in FStates) then
+ begin
+ FAutoSizeIndex := NoColumn;
+ FMainColumn := NoColumn;
+ FSortColumn := NoColumn;
+ end;
+
+ inherited Clear;
+ finally
+ FClearing := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.ColumnFromPosition(P: TPoint; Relative: Boolean = True): TColumnIndex;
+
+// Determines the current column based on the position passed in P.
+
+var
+ I, Sum: Integer;
+
+begin
+ Result := InvalidColumn;
+ // The position must be within the header area, but we extend the vertical bounds to the entire treeview area.
+ if (P.X >= 0) and (P.Y >= 0) and (P.Y <= Integer(FHeader.TreeView.Height)) then
+ begin
+ if Relative then
+ Sum := FHeader.Treeview.FOffsetX
+ else
+ Sum := 0;
+ for I := 0 to Count - 1 do
+ if coVisible in Items[FPositionToIndex[I]].FOptions then
+ begin
+ Inc(Sum, Items[FPositionToIndex[I]].Width);
+ if P.X < Sum then
+ begin
+ Result := FPositionToIndex[I];
+ Break;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.ColumnFromPosition(PositionIndex: TColumnPosition): TColumnIndex;
+
+// Returns the index of the column at the given position.
+
+begin
+ if Integer(PositionIndex) < Length(FPositionToIndex) then
+ Result := FPositionToIndex[PositionIndex]
+ else
+ Result := NoColumn;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.Equals(OtherColumns: TVirtualTreeColumns): Boolean;
+
+// Compares itself with the given set of columns and returns True if all published properties are the same
+// (including column order), otherwise False is returned.
+
+var
+ I: Integer;
+
+begin
+ // Same number of columns?
+ Result := OtherColumns.Count = Count;
+ if Result then
+ begin
+ // Same order of columns?
+ Result := CompareMem(Pointer(FPositionToIndex), Pointer(OtherColumns.FPositionToIndex),
+ Length(FPositionToIndex) * SizeOf(TColumnIndex));
+ if Result then
+ begin
+ for I := 0 to Count - 1 do
+ if not Items[I].Equals(OtherColumns[I]) then
+ begin
+ Result := False;
+ Break;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.GetColumnBounds(Column: TColumnIndex; var Left, Right: Integer);
+
+// Returns the left and right bound of the given column. If Column is NoColumn then the entire client width is returned.
+
+begin
+ if Column = NoColumn then
+ begin
+ Left := 0;
+ Right := FHeader.Treeview.ClientWidth;
+ end
+ else
+ begin
+ Left := Items[Column].Left;
+ Right := Left + Items[Column].Width;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetFirstVisibleColumn: TColumnIndex;
+
+// Returns the index of the first visible column or "InvalidColumn" if either no columns are defined or
+// all columns are hidden.
+
+var
+ I: Integer;
+
+begin
+ Result := InvalidColumn;
+ for I := 0 to Count - 1 do
+ if coVisible in Items[FPositionToIndex[I]].FOptions then
+ begin
+ Result := FPositionToIndex[I];
+ Break;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetLastVisibleColumn: TColumnIndex;
+
+// Returns the index of the last visible column or "InvalidColumn" if either no columns are defined or
+// all columns are hidden.
+
+var
+ I: Integer;
+
+begin
+ Result := InvalidColumn;
+ for I := Count - 1 downto 0 do
+ if coVisible in Items[FPositionToIndex[I]].FOptions then
+ begin
+ Result := FPositionToIndex[I];
+ Break;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetNextColumn(Column: TColumnIndex): TColumnIndex;
+
+// Returns the next column in display order. Column is the index of an item in the collection (a column).
+
+var
+ Position: Integer;
+
+begin
+ if Column < 0 then
+ Result := InvalidColumn
+ else
+ begin
+ Position := Items[Column].Position;
+ if Position < Count - 1 then
+ Result := FPositionToIndex[Position + 1]
+ else
+ Result := InvalidColumn;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetNextVisibleColumn(Column: TColumnIndex): TColumnIndex;
+
+// Returns the next visible column in display order, Column is an index into the columns list.
+
+begin
+ Result := Column;
+ repeat
+ Result := GetNextColumn(Result);
+ until (Result = InvalidColumn) or (coVisible in Items[Result].FOptions);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetPreviousColumn(Column: TColumnIndex): TColumnIndex;
+
+// Returns the previous column in display order, Column is an index into the columns list.
+
+var
+ Position: Integer;
+
+begin
+ if Column < 0 then
+ Result := InvalidColumn
+ else
+ begin
+ Position := Items[Column].Position;
+ if Position > 0 then
+ Result := FPositionToIndex[Position - 1]
+ else
+ Result := InvalidColumn;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetPreviousVisibleColumn(Column: TColumnIndex): TColumnIndex;
+
+// Returns the previous column in display order, Column is an index into the columns list.
+
+begin
+ Result := Column;
+ repeat
+ Result := GetPreviousColumn(Result);
+ until (Result = InvalidColumn) or (coVisible in Items[Result].FOptions);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.GetVisibleColumns: TColumnsArray;
+
+// Returns a list of all currently visible columns in actual order.
+
+var
+ I, Counter: Integer;
+
+begin
+ SetLength(Result, Count);
+ Counter := 0;
+
+ for I := 0 to Count - 1 do
+ if coVisible in Items[FPositionToIndex[I]].FOptions then
+ begin
+ Result[Counter] := Items[FPositionToIndex[I]];
+ Inc(Counter);
+ end;
+ // Set result length to actual visible count.
+ SetLength(Result, Counter);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.IsValidColumn(Column: TColumnIndex): Boolean;
+
+// Determines whether the given column is valid or not, that is, whether it is one of the current columns.
+
+begin
+ Result := (Column > NoColumn) and (Column < Count);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.LoadFromStream(const Stream: TStream; Version: Integer);
+
+var
+ I,
+ ItemCount: Integer;
+
+begin
+ Clear;
+ Stream.ReadBuffer(ItemCount, SizeOf(ItemCount));
+ // number of columns
+ if ItemCount > 0 then
+ begin
+ BeginUpdate;
+ try
+ for I := 0 to ItemCount - 1 do
+ Add.LoadFromStream(Stream, Version);
+ SetLength(FPositionToIndex, ItemCount);
+ Stream.ReadBuffer(FPositionToIndex[0], ItemCount * SizeOf(Cardinal));
+ UpdatePositions(True);
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+// XP style header button legacy code. This procedure is only used on non-XP systems to simulate the themed
+// header style.
+// Note: the theme elements displayed here only correspond to the standard themes of Windows XP
+
+const
+ XPMainHeaderColorUp = $DBEAEB; // Main background color of the header if drawn as being not pressed.
+ XPMainHeaderColorDown = $D8DFDE; // Main background color of the header if drawn as being pressed.
+ XPMainHeaderColorHover = $F3F8FA; // Main background color of the header if drawn as being under the mouse pointer.
+ XPDarkSplitBarColor = $B2C5C7; // Dark color of the splitter bar.
+ XPLightSplitBarColor = $FFFFFF; // Light color of the splitter bar.
+ XPDarkGradientColor = $B8C7CB; // Darkest color in the bottom gradient. Other colors will be interpolated.
+ XPDownOuterLineColor = $97A5A5; // Down state border color.
+ XPDownMiddleLineColor = $B8C2C1; // Down state border color.
+ XPDownInnerLineColor = $C9D1D0; // Down state border color.
+
+procedure DrawXPButton(DC: HDC; ButtonR: TRect; DrawSplitter, Down, Hover: Boolean);
+
+// Helper procedure to draw an Windows XP like header button.
+
+var
+ PaintBrush: HBRUSH;
+ Pen,
+ OldPen: HPEN;
+ PenColor,
+ FillColor: COLORREF;
+ dRed, dGreen, dBlue: Single;
+ Width,
+ XPos: Integer;
+
+begin
+ if Down then
+ FillColor := XPMainHeaderColorDown
+ else
+ if Hover then
+ FillColor := XPMainHeaderColorHover
+ else
+ FillColor := XPMainHeaderColorUp;
+ PaintBrush := CreateSolidBrush(FillColor);
+ FillRect(DC, ButtonR, PaintBrush);
+ DeleteObject(PaintBrush);
+
+ if DrawSplitter and not (Down or Hover) then
+ begin
+ // One solid pen for the dark line...
+ Pen := CreatePen(PS_SOLID, 1, XPDarkSplitBarColor);
+ OldPen := SelectObject(DC, Pen);
+ MoveToEx(DC, ButtonR.Right - 2, ButtonR.Top + 3, nil);
+ LineTo(DC, ButtonR.Right - 2, ButtonR.Bottom - 5);
+ // ... and one solid pen for the light line.
+ Pen := CreatePen(PS_SOLID, 1, XPLightSplitBarColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Right - 1, ButtonR.Top + 3, nil);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Bottom - 5);
+ SelectObject(DC, OldPen);
+ DeleteObject(Pen);
+ end;
+
+ if Down then
+ begin
+ // Down state. Three lines to draw.
+ // First one is the outer line, drawn at left, bottom and right.
+ Pen := CreatePen(PS_SOLID, 1, XPDownOuterLineColor);
+ OldPen := SelectObject(DC, Pen);
+ MoveToEx(DC, ButtonR.Left, ButtonR.Top, nil);
+ LineTo(DC, ButtonR.Left, ButtonR.Bottom - 1);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Bottom - 1);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Top - 1);
+
+ // Second one is the middle line, which is a bit lighter.
+ Pen := CreatePen(PS_SOLID, 1, XPDownMiddleLineColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Left + 1, ButtonR.Bottom - 2, nil);
+ LineTo(DC, ButtonR.Left + 1, ButtonR.Top);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Top);
+
+ // Third line is the inner line, which is even lighter than the middle line.
+ Pen := CreatePen(PS_SOLID, 1, XPDownInnerLineColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Left + 2, ButtonR.Bottom - 2, nil);
+ LineTo(DC, ButtonR.Left + 2, ButtonR.Top + 1);
+ LineTo(DC, ButtonR.Right - 1, ButtonR.Top + 1);
+
+ // Housekeeping:
+ SelectObject(DC, OldPen);
+ DeleteObject(Pen);
+ end
+ else
+ if Hover then
+ begin
+ // Hover state. There are three lines at the bottom border, but they are rendered in a way which
+ // requires expensive construction.
+ Width := ButtonR.Right - ButtonR.Left;
+ if Width <= 32 then
+ begin
+ ImageList_DrawEx(UtilityImages.Handle, 8, DC, ButtonR.Right - 16, ButtonR.Bottom - 3, 16, 3, CLR_NONE, CLR_NONE,
+ ILD_NORMAL);
+ ImageList_DrawEx(UtilityImages.Handle, 6, DC, ButtonR.Left, ButtonR.Bottom - 3, Width div 2, 3, CLR_NONE,
+ CLR_NONE, ILD_NORMAL);
+ end
+ else
+ begin
+ ImageList_DrawEx(UtilityImages.Handle, 6, DC, ButtonR.Left, ButtonR.Bottom - 3, 16, 3, CLR_NONE, CLR_NONE,
+ ILD_NORMAL);
+ // Replicate inner part as many times as need to fill up the button rectangle.
+ XPos := ButtonR.Left + 16;
+ repeat
+ ImageList_DrawEx(UtilityImages.Handle, 7, DC, XPos, ButtonR.Bottom - 3, 16, 3, CLR_NONE, CLR_NONE, ILD_NORMAL);
+ Inc(XPos, 16);
+ until XPos + 16 >= ButtonR.Right;
+ ImageList_DrawEx(UtilityImages.Handle, 8, DC, ButtonR.Right - 16, ButtonR.Bottom - 3, 16, 3, CLR_NONE, CLR_NONE,
+ ILD_NORMAL);
+ end;
+ end
+ else
+ begin
+ // There is a three line gradient near the bottom border which transforms from the button color to a dark,
+ // clBtnFace like color (here XPDarkGradientColor).
+ PenColor := XPMainHeaderColorUp;
+ dRed := ((PenColor and $FF) - (XPDarkGradientColor and $FF)) / 3;
+ dGreen := (((PenColor shr 8) and $FF) - ((XPDarkGradientColor shr 8) and $FF)) / 3;
+ dBlue := (((PenColor shr 16) and $FF) - ((XPDarkGradientColor shr 16) and $FF)) / 3;
+
+ // First line:
+ PenColor := PenColor - Round(dRed) - Round(dGreen) shl 8 - Round(dBlue) shl 16;
+ Pen := CreatePen(PS_SOLID, 1, PenColor);
+ OldPen := SelectObject(DC, Pen);
+ MoveToEx(DC, ButtonR.Left, ButtonR.Bottom - 3, nil);
+ LineTo(DC, ButtonR.Right, ButtonR.Bottom - 3);
+
+ // Second line:
+ PenColor := PenColor - Round(dRed) - Round(dGreen) shl 8 - Round(dBlue) shl 16;
+ Pen := CreatePen(PS_SOLID, 1, PenColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Left, ButtonR.Bottom - 2, nil);
+ LineTo(DC, ButtonR.Right, ButtonR.Bottom - 2);
+
+ // Third line:
+ Pen := CreatePen(PS_SOLID, 1, XPDarkGradientColor);
+ DeleteObject(SelectObject(DC, Pen));
+ MoveToEx(DC, ButtonR.Left, ButtonR.Bottom - 1, nil);
+ LineTo(DC, ButtonR.Right, ButtonR.Bottom - 1);
+
+ // Housekeeping:
+ DeleteObject(SelectObject(DC, OldPen));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.PaintHeader(DC: HDC; R: TRect; HOffset: Integer; VOffset: Integer = 0);
+
+// Main paint method to draw the header.
+
+const
+ SortGlyphs: array[TSortDirection, Boolean] of Integer = ( // ascending/descending, normal/XP style
+ (3, 5) {ascending}, (2, 4) {descending}
+ );
+
+var
+ I, Y,
+ SortIndex: Integer;
+ Run: TRect;
+ RightBorderFlag,
+ NormalButtonStyle,
+ NormalButtonFlags,
+ PressedButtonStyle,
+ PressedButtonFlags,
+ RaisedButtonStyle,
+ RaisedButtonFlags: Cardinal;
+ DrawFormat: Cardinal;
+ Images: TImageList;
+ ButtonRgn: HRGN;
+ OwnerDraw,
+ AdvancedOwnerDraw: Boolean;
+ {$ifdef ThemeSupport}
+ Details: TThemedElementDetails;
+ {$endif ThemeSupport}
+
+ PaintInfo: THeaderPaintInfo;
+ RequestedElements,
+ ActualElements: THeaderPaintElements;
+
+ SavedDC: Integer;
+
+begin
+ Run := FHeader.Treeview.FHeaderRect;
+ FHeaderBitmap.Width := Max(Run.Right, R.Right - R.Left);
+ FHeaderBitmap.Height := Run.Bottom;
+ OwnerDraw := (hoOwnerDraw in FHeader.FOptions) and Assigned(FHeader.Treeview.FOnHeaderDraw) and
+ not (csDesigning in FHeader.Treeview.ComponentState);
+ AdvancedOwnerDraw := (hoOwnerDraw in FHeader.FOptions) and Assigned(FHeader.Treeview.FOnAdvancedHeaderDraw) and
+ Assigned(FHeader.Treeview.FOnHeaderDrawQueryElements) and not (csDesigning in FHeader.Treeview.ComponentState);
+ // If both draw posibillities are specified then prefer the advanced way.
+ if AdvancedOwnerDraw then
+ OwnerDraw := False;
+
+ ZeroMemory(@PaintInfo, SizeOf(PaintInfo));
+ PaintInfo.TargetCanvas := FHeaderBitmap.Canvas;
+
+ with PaintInfo, TargetCanvas do
+ begin
+ Font := FHeader.FFont;
+
+ RaisedButtonStyle := 0;
+ RaisedButtonFlags := 0;
+ case FHeader.Style of
+ hsThickButtons:
+ begin
+ NormalButtonStyle := BDR_RAISEDINNER or BDR_RAISEDOUTER;
+ NormalButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_SOFT or BF_ADJUST;
+ PressedButtonStyle := BDR_RAISEDINNER or BDR_RAISEDOUTER;
+ PressedButtonFlags := NormalButtonFlags or BF_RIGHT or BF_FLAT or BF_ADJUST;
+ end;
+ hsFlatButtons:
+ begin
+ NormalButtonStyle := BDR_RAISEDINNER;
+ NormalButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_ADJUST;
+ PressedButtonStyle := BDR_SUNKENOUTER;
+ PressedButtonFlags := BF_RECT or BF_MIDDLE or BF_ADJUST;
+ end;
+ else
+ // hsPlates or hsXPStyle, values are not used in the latter case
+ begin
+ NormalButtonStyle := BDR_RAISEDINNER;
+ NormalButtonFlags := BF_RECT or BF_MIDDLE or BF_SOFT or BF_ADJUST;
+ PressedButtonStyle := BDR_SUNKENOUTER;
+ PressedButtonFlags := BF_RECT or BF_MIDDLE or BF_ADJUST;
+ RaisedButtonStyle := BDR_RAISEDINNER;
+ RaisedButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_ADJUST;
+ end;
+ end;
+
+ // Use shortcut for the images.
+ Images := FHeader.FImages;
+
+ // Consider right-to-left directionality.
+ with FHeader.Treeview do
+ if (BidiMode <> bdLeftToRight) and (Integer(FRangeY) > ClientHeight) then
+ Inc(HOffset, GetSystemMetrics(SM_CXVSCROLL));
+
+ // Erase background of the header.
+ // See if the application wants to do that on its own.
+ RequestedElements := [];
+ if AdvancedOwnerDraw then
+ begin
+ PaintInfo.PaintRectangle := R;
+ PaintInfo.Column := nil;
+ FHeader.Treeview.DoHeaderDrawQueryElements(PaintInfo, RequestedElements);
+ end;
+
+ if hpeBackground in RequestedElements then
+ begin
+ FHeader.Treeview.DoAdvancedHeaderDraw(PaintInfo, [hpeBackground]);
+ end
+ else
+ begin
+ {$ifdef ThemeSupport}
+ if tsUseThemes in FHeader.Treeview.FStates then
+ begin
+ Details := ThemeServices.GetElementDetails(thHeaderItemRightNormal);
+ ThemeServices.DrawElement(Handle, Details, R, @R);
+ end
+ else
+ {$endif ThemeSupport}
+ if FHeader.Style = hsXPStyle then
+ DrawXPButton(Handle, Run, False, False, False)
+ else
+ begin
+ Brush.Color := FHeader.FBackground;
+ FillRect(R);
+ end;
+ end;
+
+ Run.Top := R.Top;
+ Run.Right := R.Left + HOffset;
+ Run.Bottom := R.Bottom;
+ // Run.Left is set in the loop
+
+ ShowRightBorder := (FHeader.Style = hsThickButtons) or not (hoAutoResize in FHeader.FOptions) or
+ (FHeader.Treeview.BevelKind = bkNone);
+
+ // now go for each button
+ for I := 0 to Count - 1 do
+ with Items[FPositionToIndex[I]] do
+ if coVisible in FOptions then
+ begin
+ Run.Left := Run.Right;
+ Inc(Run.Right, Width);
+ // Skip columns which are not visible at all.
+ if Run.Right > R.Left then
+ begin
+ // Stop painting if the rectangle is filled.
+ if Run.Left > R.Right then
+ Break;
+
+ IsHoverIndex := (Integer(FPositionToIndex[I]) = FHoverIndex) and (hoHotTrack in FHeader.FOptions) and
+ (coEnabled in FOptions);
+ IsDownIndex := Integer(FPositionToIndex[I]) = FDownIndex;
+ if (coShowDropMark in FOptions) and (Integer(FPositionToIndex[I]) = FDropTarget) and
+ (Integer(FPositionToIndex[I]) <> FDragIndex) then
+ begin
+ if FDropBefore then
+ DropMark := dmmLeft
+ else
+ DropMark := dmmRight;
+ end
+ else
+ DropMark := dmmNone;
+ IsEnabled := (coEnabled in FOptions) and (FHeader.Treeview.Enabled);
+ ShowHeaderGlyph := (hoShowImages in FHeader.FOptions) and Assigned(Images) and (FImageIndex > -1);
+ ShowSortGlyph := (Integer(FPositionToIndex[I]) = FHeader.FSortColumn) and (hoShowSortGlyphs in FHeader.FOptions);
+
+ PaintRectangle := Run;
+
+ // This path for text columns or advanced owner draw.
+ if (Style = vsText) or not OwnerDraw or AdvancedOwnerDraw then
+ begin
+ // See if the application wants to draw part of the header itself.
+ RequestedElements := [];
+ if AdvancedOwnerDraw then
+ begin
+ PaintInfo.Column := Items[FPositionToIndex[I]];
+ FHeader.Treeview.DoHeaderDrawQueryElements(PaintInfo, RequestedElements);
+ end;
+
+ if ShowRightBorder or (I < Count - 1) then
+ RightBorderFlag := BF_RIGHT
+ else
+ RightBorderFlag := 0;
+
+ if hpeBackground in RequestedElements then
+ FHeader.Treeview.DoAdvancedHeaderDraw(PaintInfo, [hpeBackground])
+ else
+ begin
+ // Draw button first before setting the clip region.
+ {$ifdef ThemeSupport}
+ if tsUseThemes in FHeader.Treeview.FStates then
+ begin
+ if IsDownIndex then
+ Details := ThemeServices.GetElementDetails(thHeaderItemPressed)
+ else
+ if IsHoverIndex then
+ Details := ThemeServices.GetElementDetails(thHeaderItemHot)
+ else
+ Details := ThemeServices.GetElementDetails(thHeaderItemNormal);
+ ThemeServices.DrawElement(Handle, Details, PaintRectangle, @PaintRectangle);
+ end
+ else
+ {$endif ThemeSupport}
+ begin
+ if FHeader.Style = hsXPStyle then
+ DrawXPButton(Handle, PaintRectangle, RightBorderFlag <> 0, IsDownIndex, IsHoverIndex)
+ else
+ if IsDownIndex then
+ DrawEdge(Handle, PaintRectangle, PressedButtonStyle, PressedButtonFlags)
+ else
+ // Plates have the special case of raising on mouse over.
+ if (FHeader.Style = hsPlates) and IsHoverIndex and
+ (coAllowClick in FOptions) and (coEnabled in FOptions) then
+ DrawEdge(Handle, PaintRectangle, RaisedButtonStyle, RaisedButtonFlags or RightBorderFlag)
+ else
+ DrawEdge(Handle, PaintRectangle, NormalButtonStyle, NormalButtonFlags or RightBorderFlag);
+ end;
+ end;
+ end;
+
+ // Create a clip region to avoid overpainting any other area which does not belong to this column.
+ if PaintRectangle.Right > R.Right then
+ PaintRectangle.Right := R.Right;
+ if PaintRectangle.Left < R.Left then
+ PaintRectangle.Left := R.Left;
+ ButtonRgn := CreateRectRgnIndirect(PaintRectangle);
+ SelectClipRgn(Handle, ButtonRgn);
+ DeleteObject(ButtonRgn);
+
+ PaintRectangle := Run;
+ if (Style = vsText) or not OwnerDraw or AdvancedOwnerDraw then
+ begin
+ // calculate text and glyph position
+ InflateRect(PaintRectangle, -2, -2);
+ DrawFormat := DT_LEFT or DT_TOP;
+ if UseRightToLeftReading then
+ DrawFormat := DrawFormat + DT_RTLREADING;
+ ComputeHeaderLayout(Handle, PaintRectangle, ShowHeaderGlyph, ShowSortGlyph, GlyphPos, SortGlyphPos,
+ TextRectangle);
+
+ // Move glyph and text one pixel to the right and down to simulate a pressed button.
+ if IsDownIndex then
+ begin
+ OffsetRect(TextRectangle, 1, 1);
+ Inc(GlyphPos.X);
+ Inc(GlyphPos.Y);
+ Inc(SortGlyphPos.X);
+ Inc(SortGlyphPos.Y);
+ end;
+
+ // Advanced owner draw allows to paint elements, which would normally not be painted (because of space
+ // limitations, empty captions etc.).
+ ActualElements := RequestedElements * [hpeHeaderGlyph, hpeSortGlyph, hpeDropMark, hpeText];
+
+ // main glyph
+ if not (hpeHeaderGlyph in ActualElements) and ShowHeaderGlyph and
+ (not ShowSortGlyph or (FBidiMode <> bdLeftToRight) or (GlyphPos.X + Images.Width <= SortGlyphPos.X)) then
+ Images.Draw(FHeaderBitmap.Canvas, GlyphPos.X, GlyphPos.Y, FImageIndex, IsEnabled);
+
+ // caption
+ if not (hpeText in ActualElements) and (Length(Text) > 0) then
+ DrawButtonText(Handle, Text, TextRectangle, IsEnabled, IsHoverIndex and (hoHotTrack in FHeader.FOptions) and
+ not (tsUseThemes in FHeader.Treeview.FStates), DrawFormat);
+
+ // sort glyph
+ if not (hpeSortGlyph in ActualElements) and ShowSortGlyph then
+ begin
+ SortIndex := SortGlyphs[FHeader.FSortDirection, tsUseThemes in FHeader.Treeview.FStates];
+ UtilityImages.Draw(FHeaderBitmap.Canvas, SortGlyphPos.X, SortGlyphPos.Y, SortIndex);
+ end;
+
+ // Show an indication if this column is the current drop target in a header drag operation.
+ if not (hpeDropMark in ActualElements) and (DropMark <> dmmNone) then
+ begin
+ Y := (PaintRectangle.Top + PaintRectangle.Bottom - UtilityImages.Height) div 2;
+ if DropMark = dmmLeft then
+ UtilityImages.Draw(FHeaderBitmap.Canvas, PaintRectangle.Left, Y, 0)
+ else
+ UtilityImages.Draw(FHeaderBitmap.Canvas, PaintRectangle.Right - 16 , Y, 1);
+ end;
+
+ if ActualElements <> [] then
+ begin
+ SavedDC := SaveDC(Handle);
+ FHeader.Treeview.DoAdvancedHeaderDraw(PaintInfo, ActualElements);
+ RestoreDC(Handle, SavedDC);
+ end;
+ end
+ else // Let application draw the header.
+ FHeader.Treeview.DoHeaderDraw(FHeaderBitmap.Canvas, Items[FPositionToIndex[I]], PaintRectangle, IsHoverIndex,
+ IsDownIndex, DropMark);
+ SelectClipRgn(Handle, 0);
+ end;
+ end;
+
+ // Blit the result to target.
+ with R do
+ BitBlt(DC, Left, Top, Right - Left, Bottom - Top, Handle, Left, Top, SRCCOPY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualTreeColumns.SaveToStream(const Stream: TStream);
+
+var
+ I: Integer;
+
+begin
+ I := Count;
+ Stream.WriteBuffer(I, SizeOf(I));
+ if I > 0 then
+ begin
+ for I := 0 to Count - 1 do
+ TVirtualTreeColumn(Items[I]).SaveToStream(Stream);
+
+ Stream.WriteBuffer(FPositionToIndex[0], Count * SizeOf(Cardinal));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualTreeColumns.TotalWidth: Integer;
+
+var
+ LastColumn: TColumnIndex;
+
+begin
+ if Count = 0 then
+ Result := 0
+ else
+ begin
+ LastColumn := FPositionToIndex[Count - 1];
+ if not (coVisible in Items[LastColumn].FOptions) then
+ LastColumn := GetPreviousVisibleColumn(LastColumn);
+ if LastColumn > NoColumn then
+ with Items[LastColumn] do
+ Result := FLeft + FWidth
+ else
+ Result := 0;
+ end;
+end;
+
+//----------------- TVTHeader -----------------------------------------------------------------------------------------
+
+constructor TVTHeader.Create(AOwner: TBaseVirtualTree);
+
+begin
+ inherited Create;
+ FOwner := AOwner;
+ FColumns := GetColumnsClass.Create(Self);
+ FHeight := 17;
+ FFont := TFont.Create;
+ FFont.OnChange := FontChanged;
+ FBackground := clBtnFace;
+ FOptions := [hoColumnResize, hoDrag];
+
+ FImageChangeLink := TChangeLink.Create;
+ FImageChangeLink.OnChange := ImageListChange;
+
+ FSortColumn := NoColumn;
+ FSortDirection := sdAscending;
+ FMainColumn := NoColumn;
+
+ FDragImage := TVTDragImage.Create(AOwner);
+ with FDragImage do
+ begin
+ Fade := False;
+ PostBlendBias := 0;
+ PreBlendBias := -50;
+ Transparency := 140;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TVTHeader.Destroy;
+
+begin
+ FDragImage.Free;
+ FImageChangeLink.Free;
+ FFont.Free;
+ FColumns.Clear; // TCollection's Clear method is not virtual, so we have to call our own Clear method manually.
+ FColumns.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.FontChanged(Sender: TObject);
+
+begin
+ Invalidate(nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetMainColumn: TColumnIndex;
+
+begin
+ if FColumns.Count > 0 then
+ Result := FMainColumn
+ else
+ Result := NoColumn;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetUseColumns: Boolean;
+
+begin
+ Result := FColumns.Count > 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetAutoSizeIndex(Value: TColumnIndex);
+
+begin
+ if FAutoSizeIndex <> Value then
+ begin
+ FAutoSizeIndex := Value;
+ if hoAutoResize in FOptions then
+ Columns.AdjustAutoSize(InvalidColumn);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetBackground(Value: TColor);
+
+begin
+ if FBackground <> Value then
+ begin
+ FBackground := Value;
+ Invalidate(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetColumns(Value: TVirtualTreeColumns);
+
+begin
+ FColumns.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetFont(const Value: TFont);
+
+begin
+ FFont.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetHeight(Value: Cardinal);
+
+begin
+ if FHeight <> Value then
+ begin
+ FHeight := Value;
+ if not (csLoading in Treeview.ComponentState) then
+ RecalculateHeader;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetImages(const Value: TImageList);
+
+begin
+ if FImages <> Value then
+ begin
+ if Assigned(FImages) then
+ begin
+ FImages.UnRegisterChanges(FImageChangeLink);
+ {$ifdef COMPILER_5_UP}
+ FImages.RemoveFreeNotification(FOwner);
+ {$endif COMPILER_5_UP}
+ end;
+ FImages := Value;
+ if Assigned(FImages) then
+ begin
+ FImages.RegisterChanges(FImageChangeLink);
+ FImages.FreeNotification(FOwner);
+ end;
+ if not (csLoading in Treeview.ComponentState) then
+ Invalidate(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetMainColumn(Value: TColumnIndex);
+
+begin
+ if csLoading in Treeview.ComponentState then
+ FMainColumn := Value
+ else
+ begin
+ if Value < 0 then
+ Value := 0;
+ if Value > FColumns.Count - 1 then
+ Value := FColumns.Count - 1;
+ if Value <> FMainColumn then
+ begin
+ FMainColumn := Value;
+ if not (csLoading in Treeview.ComponentState) then
+ begin
+ Treeview.MainColumnChanged;
+ if not (toExtendedFocus in Treeview.FOptions.FSelectionOptions) then
+ Treeview.FocusedColumn := FMainColumn;
+ Treeview.Invalidate;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetOptions(Value: TVTHeaderOptions);
+
+var
+ ToBeSet,
+ ToBeCleared: TVTHeaderOptions;
+
+begin
+ ToBeSet := Value - FOptions;
+ ToBeCleared := FOptions - Value;
+ FOptions := Value;
+
+ if (hoAutoResize in (ToBeSet + ToBeCleared)) and (FColumns.Count > 0) then
+ begin
+ FColumns.AdjustAutoSize(InvalidColumn);
+ if Treeview.HandleAllocated then
+ begin
+ Treeview.UpdateHorizontalScrollBar(False);
+ if hoAutoResize in ToBeSet then
+ Treeview.Invalidate;
+ end;
+ end;
+
+ if not (csLoading in Treeview.ComponentState) and Treeview.HandleAllocated then
+ begin
+ if hoVisible in (ToBeSet + ToBeCleared) then
+ RecalculateHeader;
+ Invalidate(nil);
+ Treeview.Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetSortColumn(Value: TColumnIndex);
+
+begin
+ if csLoading in Treeview.ComponentState then
+ FSortColumn := Value
+ else
+ begin
+ if Value < NoColumn then
+ Value := NoColumn;
+ if Value > Columns.Count - 1 then
+ Value := Columns.Count - 1;
+ if FSortColumn <> Value then
+ begin
+ if FSortColumn > NoColumn then
+ Invalidate(Columns[FSortColumn]);
+ FSortColumn := Value;
+ if FSortColumn > NoColumn then
+ Invalidate(Columns[FSortColumn]);
+ if (toAutoSort in Treeview.FOptions.FAutoOptions) and (Treeview.FUpdateCount = 0) then
+ Treeview.SortTree(FSortColumn, FSortDirection, True);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetSortDirection(const Value: TSortDirection);
+
+begin
+ if Value <> FSortDirection then
+ begin
+ FSortDirection := Value;
+ Invalidate(nil);
+ if (toAutoSort in Treeview.FOptions.FAutoOptions) and (Treeview.FUpdateCount = 0) then
+ Treeview.SortTree(FSortColumn, FSortDirection, True);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SetStyle(Value: TVTHeaderStyle);
+
+begin
+ if FStyle <> Value then
+ begin
+ FStyle := Value;
+ if not (csLoading in Treeview.ComponentState) then
+ Invalidate(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.CanWriteColumns: Boolean;
+
+// Descentants may override this to optionally prevent column writing (e.g. if they are build dynamically).
+
+begin
+ Result := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.ChangeScale(M, D: Integer);
+
+begin
+ FFont.Size := MulDiv(FFont.Size, M, D);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.DetermineSplitterIndex(P: TPoint): Boolean;
+
+// Tries to find the index of that column whose right border corresponds to P.
+// Result is True if column border was hit (with -3..+5 pixels tolerance).
+// For continuous resizing the current track index and the column's left border are set.
+// Note: The hit test is checking from right to left to make enlarging of zero-sized columns possible.
+
+var
+ I,
+ SplitPoint: Integer;
+
+begin
+ Result := False;
+ FColumns.FTrackIndex := NoColumn;
+
+ if FColumns.Count > 0 then
+ begin
+ SplitPoint := Treeview.FOffsetX + Integer(Treeview.FRangeX);
+
+ for I := FColumns.Count - 1 downto 0 do
+ with FColumns, Items[FPositionToIndex[I]] do
+ if coVisible in FOptions then
+ begin
+ if (P.X < SplitPoint + 5) and (P.X > SplitPoint - 3) then
+ begin
+ if coResizable in FOptions then
+ begin
+ Result := True;
+ FTrackIndex := FPositionToIndex[I];
+ FLeftTrackPos := SplitPoint - FWidth;
+ end;
+ Break;
+ end;
+ Dec(SplitPoint, FWidth);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.DragTo(P: TPoint);
+
+// Moves the drag image to a new position, which is determined from the passed point P and the previous
+// mouse position.
+
+var
+ I,
+ NewTarget: Integer;
+ // optimized drag image move support
+ ClientP: TPoint;
+ Left,
+ Right: Integer;
+ NeedRepaint: Boolean; // True if the screen needs an update (changed drop target or drop side)
+
+begin
+ // Determine new drop target and which side of it is prefered.
+ ClientP := Treeview.ScreenToClient(P);
+ // Make coordinates relative to (0, 0) of the non-client area.
+ Inc(ClientP.Y, FHeight);
+ NewTarget := FColumns.ColumnFromPosition(ClientP);
+ NeedRepaint := (NewTarget <> InvalidColumn) and (NewTarget <> FColumns.FDropTarget);
+ if NewTarget >= 0 then
+ begin
+ FColumns.GetColumnBounds(NewTarget, Left, Right);
+ if (ClientP.X < ((Left + Right) div 2)) <> FColumns.FDropBefore then
+ begin
+ NeedRepaint := True;
+ FColumns.FDropBefore := not FColumns.FDropBefore;
+ end;
+ end;
+
+ if NeedRepaint then
+ begin
+ // Invalidate columns which need a repaint.
+ if FColumns.FDropTarget > NoColumn then
+ begin
+ I := FColumns.FDropTarget;
+ FColumns.FDropTarget := NoColumn;
+ Invalidate(FColumns.Items[I]);
+ end;
+ if (NewTarget > NoColumn) and (NewTarget <> FColumns.FDropTarget) then
+ begin
+ Invalidate(FColumns.Items[NewTarget]);
+ FColumns.FDropTarget := NewTarget;
+ end;
+ end;
+
+ FDragImage.DragTo(P, NeedRepaint);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetColumnsClass: TVirtualTreeColumnsClass;
+
+// Returns the class to be used for the actual column implementation. Descentants may optionally override this and
+// return their own class.
+
+begin
+ Result := TVirtualTreeColumns;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetOwner: TPersistent;
+
+begin
+ Result := FOwner;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.GetShiftState: TShiftState;
+
+begin
+ Result := [];
+ if GetKeyState(VK_SHIFT) < 0 then
+ Include(Result, ssShift);
+ if GetKeyState(VK_CONTROL) < 0 then
+ Include(Result, ssCtrl);
+ if GetKeyState(VK_MENU) < 0 then
+ Include(Result, ssAlt);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.HandleHeaderMouseMove(var Message: TWMMouseMove): Boolean;
+
+var
+ P: TPoint;
+ I: Integer;
+
+begin
+ Result := False;
+ with Message do
+ begin
+ P := Point(XPos, YPos);
+ if hsTrackPending in FStates then
+ begin
+ Treeview.StopTimer(HeaderTimer);
+ FStates := FStates - [hsTrackPending] + [hsTracking];
+ HandleHeaderMouseMove := True;
+ Result := 0;
+ end
+ else
+ if hsTracking in FStates then
+ begin
+ FColumns[FColumns.FTrackIndex].Width := XPos - FLeftTrackPos;
+ HandleHeaderMouseMove := True;
+ Result := 0;
+ end
+ else
+ begin
+ if hsDragPending in FStates then
+ begin
+ P := Treeview.ClientToScreen(P);
+ // start actual dragging if allowed
+ if (hoDrag in FOptions) and Treeview.DoHeaderDragging(FColumns.FDownIndex) then
+ begin
+ if ((Abs(FDragStart.X - P.X) > Mouse.DragThreshold) or
+ (Abs(FDragStart.Y - P.Y) > Mouse.DragThreshold)) then
+ begin
+ Treeview.StopTimer(HeaderTimer);
+ I := FColumns.FDownIndex;
+ FColumns.FDownIndex := NoColumn;
+ FColumns.FHoverIndex := NoColumn;
+ if I > NoColumn then
+ Invalidate(FColumns[I]);
+ PrepareDrag(P, FDragStart);
+ FStates := FStates - [hsDragPending] + [hsDragging];
+ HandleHeaderMouseMove := True;
+ Result := 0;
+ end;
+ end;
+ end
+ else
+ if hsDragging in FStates then
+ begin
+ DragTo(Treeview.ClientToScreen(Point(XPos, YPos)));
+ HandleHeaderMouseMove := True;
+ Result := 0;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.HandleMessage(var Message: TMessage): Boolean;
+
+// The header gets here the opportunity to handle certain messages before they reach the tree. This is important
+// because the tree needs to handle various non-client area messages for the header as well as some dragging/tracking
+// events.
+// By returning True the message will not be handled further, otherwise the message is then dispatched
+// to the proper message handlers.
+
+var
+ P: TPoint;
+ R: TRect;
+ I: Integer;
+ OldPosition: Integer;
+ HitIndex: TColumnIndex;
+ NewCursor: HCURSOR;
+ Button: TMouseButton;
+
+begin
+ Result := False;
+ case Message.Msg of
+ WM_SIZE:
+ begin
+ if (hoAutoResize in FOptions) and not (hsAutoSizing in FStates) and
+ not (tsWindowCreating in FOwner.FStates) then
+ begin
+ FColumns.AdjustAutoSize(InvalidColumn);
+ Invalidate(nil);
+ end;
+ end;
+ CM_BIDIMODECHANGED:
+ for I := 0 to FColumns.Count - 1 do
+ if coParentBiDiMode in FColumns[I].FOptions then
+ FColumns[I].ParentBiDiModeChanged;
+ WM_NCMBUTTONDOWN:
+ begin
+ with TWMNCMButtonDown(Message) do
+ P := Treeview.ScreenToClient(Point(XCursor, YCursor));
+ if InHeader(P) then
+ FOwner.DoHeaderMouseDown(mbMiddle, GetShiftState, P.X, P.Y + Integer(FHeight));
+ end;
+ WM_NCMBUTTONUP:
+ begin
+ with TWMNCMButtonUp(Message) do
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ if InHeader(P) then
+ begin
+ FColumns.HandleClick(P, mbMiddle, True, False);
+ FOwner.DoHeaderMouseUp(mbMiddle, GetShiftState, P.X, P.Y + Integer(FHeight));
+ FColumns.FDownIndex := NoColumn;
+ end;
+ end;
+ WM_NCLBUTTONDBLCLK,
+ WM_NCMBUTTONDBLCLK,
+ WM_NCRBUTTONDBLCLK:
+ begin
+ with TWMNCLButtonDblClk(Message) do
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ // If the click was on a splitter then resize column do smallest width.
+ if InHeader(P) then
+ begin
+ case Message.Msg of
+ WM_NCMBUTTONDBLCLK:
+ Button := mbMiddle;
+ WM_NCRBUTTONDBLCLK:
+ Button := mbRight;
+ else
+ // WM_NCLBUTTONDBLCLK
+ Button := mbLeft;
+ end;
+ if (hoDblClickResize in FOptions) and (FColumns.FTrackIndex > NoColumn) then
+ begin
+ with FColumns do
+ AnimatedResize(FTrackIndex, Max(FColumns[FTrackIndex].MinWidth, Treeview.GetMaxColumnWidth(FTrackIndex)));
+ end
+ else
+ FColumns.HandleClick(P, Button, True, True);
+ FOwner.DoHeaderDblClick(FColumns.FClickIndex, Button, GetShiftState + [ssDouble], P.X, P.Y + Integer(FHeight));
+ end;
+ end;
+ WM_NCLBUTTONDOWN:
+ begin
+ Application.CancelHint;
+
+ // make sure no auto scrolling is active...
+ Treeview.StopTimer(ScrollTimer);
+ Treeview.DoStateChange([], [tsScrollPending, tsScrolling]);
+ // ... pending editing is cancelled (actual editing remains active)
+ Treeview.StopTimer(EditTimer);
+ Treeview.DoStateChange([], [tsEditPending]);
+
+ with TWMNCLButtonDown(Message) do
+ begin
+ // want the drag start point in screen coordinates
+ FDragStart := Point(XCursor, YCursor);
+ P := Treeview.ScreenToClient(FDragStart);
+ end;
+
+ if InHeader(P) then
+ begin
+ // This is a good opportunity to notify the application.
+ FOwner.DoHeaderMouseDown(mbLeft, GetShiftState, P.X, P.Y + Integer(FHeight));
+
+ if DetermineSplitterIndex(P) and (hoColumnResize in FOptions) then
+ begin
+ FColumns.FHoverIndex := NoColumn;
+ FTrackStart := P;
+ Include(FStates, hsTrackPending);
+ SetCapture(Treeview.Handle);
+ Result := True;
+ Message.Result := 0;
+ end
+ else
+ begin
+ HitIndex := Columns.AdjustDownColumn(P);
+ if (hoDrag in FOptions) and (HitIndex > NoColumn) and (coDraggable in FColumns[HitIndex].FOptions) then
+ begin
+ // Show potential drag operation.
+ // Disabled columns do not start a drag operation because they can't be clicked.
+ Include(FStates, hsDragPending);
+ SetCapture(Treeview.Handle);
+ Result := True;
+ Message.Result := 0;
+ end;
+ end;
+ end;
+ end;
+ WM_NCRBUTTONDOWN:
+ begin
+ with TWMNCRButtonDown(Message) do
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ if InHeader(P) then
+ FOwner.DoHeaderMouseDown(mbRight, GetShiftState, P.X, P.Y + Integer(FHeight));
+ end;
+ WM_NCRBUTTONUP:
+ if not (csDesigning in FOwner.ComponentState) then
+ with TWMNCRButtonUp(Message) do
+ begin
+ Application.CancelHint;
+
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ if InHeader(P) then
+ begin
+ FColumns.HandleClick(P, mbRight, True, False);
+ FOwner.DoHeaderMouseUp(mbRight, GetShiftState, P.X, P.Y + Integer(FHeight));
+ FColumns.FDownIndex := NoColumn;
+ FColumns.FTrackIndex := NoColumn;
+
+ // Trigger header popup if there's one.
+ if Assigned(FPopupMenu) then
+ begin
+ Treeview.StopTimer(ScrollTimer);
+ Treeview.StopTimer(HeaderTimer);
+ FColumns.FHoverIndex := NoColumn;
+ Treeview.DoStateChange([], [tsScrollPending, tsScrolling]);
+ FPopupMenu.PopupComponent := Treeview;
+ FPopupMenu.Popup(XCursor, YCursor);
+ HandleMessage := True;
+ end;
+ end;
+ end;
+ // When the tree window has an active mouse capture then we only get "client-area" messages.
+ WM_LBUTTONUP,
+ WM_NCLBUTTONUP:
+ begin
+ Application.CancelHint;
+
+ if FStates <> [] then
+ begin
+ ReleaseCapture;
+ if hsDragging in FStates then
+ begin
+ // successfull dragging moves columns
+ with TWMLButtonUp(Message) do
+ P := Treeview.ClientToScreen(Point(XPos, YPos));
+ GetWindowRect(Treeview.Handle, R);
+ with FColumns do
+ begin
+ FDragImage.EndDrag;
+ if (FDropTarget > -1) and (FDropTarget <> FDragIndex) and PtInRect(R, P) then
+ begin
+ OldPosition := FColumns[FDragIndex].Position;
+ if FColumns.FDropBefore then
+ begin
+ if FColumns[FDragIndex].Position < FColumns[FDropTarget].Position then
+ FColumns[FDragIndex].Position := Max(0, FColumns[FDropTarget].Position - 1)
+ else
+ FColumns[FDragIndex].Position := FColumns[FDropTarget].Position;
+ end
+ else
+ begin
+ if FColumns[FDragIndex].Position < FColumns[FDropTarget].Position then
+ FColumns[FDragIndex].Position := FColumns[FDropTarget].Position
+ else
+ FColumns[FDragIndex].Position := FColumns[FDropTarget].Position + 1;
+ end;
+ Treeview.DoHeaderDragged(FDragIndex, OldPosition);
+ end
+ else
+ Treeview.DoHeaderDraggedOut(FDragIndex, P);
+ FDropTarget := NoColumn;
+ end;
+ Invalidate(nil);
+ end;
+ Result := True;
+ Message.Result := 0;
+ end;
+
+ case Message.Msg of
+ WM_LBUTTONUP:
+ with TWMLButtonUp(Message) do
+ begin
+ if FColumns.FDownIndex > NoColumn then
+ FColumns.HandleClick(Point(XPos, YPos), mbLeft, False, False);
+ if FStates <> [] then
+ FOwner.DoHeaderMouseUp(mbLeft, KeysToShiftState(Keys), XPos, YPos);
+ end;
+ WM_NCLBUTTONUP:
+ with TWMNCLButtonUp(Message) do
+ begin
+ P := FOwner.ScreenToClient(Point(XCursor, YCursor));
+ FColumns.HandleClick(P, mbLeft, False, False);
+ FOwner.DoHeaderMouseUp(mbLeft, GetShiftState, P.X, P.Y + Integer(FHeight));
+ end;
+ end;
+
+ if FColumns.FTrackIndex > NoColumn then
+ begin
+ Invalidate(Columns[FColumns.FTrackIndex]);
+ FColumns.FTrackIndex := NoColumn;
+ end;
+ if FColumns.FDownIndex > NoColumn then
+ begin
+ Invalidate(Columns[FColumns.FDownIndex]);
+ FColumns.FDownIndex := NoColumn;
+ end;
+ FStates := FStates - [hsDragging, hsDragPending, hsTracking, hsTrackPending];
+ end;
+ // hovering, mouse leave detection
+ WM_NCMOUSEMOVE:
+ with TWMNCMouseMove(Message), FColumns do
+ begin
+ P := Treeview.ScreenToClient(Point(XCursor, YCursor));
+ Treeview.DoHeaderMouseMove(GetShiftState, P.X, P.Y + Integer(FHeight));
+ if InHeader(P) and ((AdjustHoverColumn(P)) or ((FDownIndex >= 0) and (FHoverIndex <> FDownIndex))) then
+ begin
+ // We need a mouse leave detection from here for the non client area. The best solution available would be the
+ // TrackMouseEvent API. Unfortunately, it leaves Win95 totally and WinNT4 for non-client stuff out and
+ // currently I cannot ignore these systems. Hence I go the only other reliable way and use a timer
+ // (although, I don't like it...).
+ Treeview.StopTimer(HeaderTimer);
+ SetTimer(Treeview.Handle, HeaderTimer, 50, nil);
+ // use Delphi's internal hint handling for header hints too
+ if hoShowHint in FOptions then
+ begin
+ // client coordinates!
+ XCursor := P.x;
+ YCursor := P.y + Integer(FHeight);
+ Application.HintMouseMessage(Treeview, Message);
+ end;
+ end
+ end;
+ WM_TIMER:
+ if TWMTimer(Message).TimerID = HeaderTimer then
+ begin
+ // determine current mouse position to check if it left the window
+ GetCursorPos(P);
+ P := Treeview.ScreenToClient(P);
+ with FColumns do
+ begin
+ if not InHeader(P) or ((FDownIndex > NoColumn) and (FHoverIndex <> FDownIndex)) then
+ begin
+ Treeview.StopTimer(HeaderTimer);
+ FHoverIndex := NoColumn;
+ FClickIndex := NoColumn;
+ FDownIndex := NoColumn;
+ Result := True;
+ Message.Result := 0;
+ Invalidate(nil);
+ end;
+ end;
+ end;
+ WM_MOUSEMOVE: // mouse capture and general message redirection
+ Result := HandleHeaderMouseMove(TWMMouseMove(Message));
+ WM_SETCURSOR:
+ if FStates = [] then
+ begin
+ // Retrieve last cursor position (GetMessagePos does not work here, I don't know why).
+ GetCursorPos(P);
+ // Is the mouse in the header rectangle?
+ P := Treeview.ScreenToClient(P);
+ if InHeader(P) then
+ begin
+ NewCursor := Screen.Cursors[crDefault];
+ if hoColumnResize in FOptions then
+ begin
+ if DetermineSplitterIndex(P) then
+ NewCursor := Screen.Cursors[crHeaderSplit];
+
+ Treeview.DoGetHeaderCursor(NewCursor);
+ Result := NewCursor <> Screen.Cursors[crDefault];
+ if Result then
+ begin
+ Windows.SetCursor(NewCursor);
+ Message.Result := 1;
+ end
+ end;
+ end;
+ end
+ else
+ begin
+ Message.Result := 1;
+ Result := True;
+ end;
+ WM_KEYDOWN,
+ WM_KILLFOCUS:
+ if (Message.Msg = WM_KILLFOCUS) or
+ (TWMKeyDown(Message).CharCode = VK_ESCAPE) then
+ begin
+ if hsDragging in FStates then
+ begin
+ ReleaseCapture;
+ FDragImage.EndDrag;
+ Exclude(FStates, hsDragging);
+ FColumns.FDropTarget := NoColumn;
+ Invalidate(nil);
+ Result := True;
+ Message.Result := 0;
+ end
+ else
+ if hsTracking in FStates then
+ begin
+ ReleaseCapture;
+ Exclude(FStates, hsTracking);
+ Result := True;
+ Message.Result := 0;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.ImageListChange(Sender: TObject);
+
+begin
+ if not (csDestroying in Treeview.ComponentState) then
+ Invalidate(nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.PrepareDrag(P, Start: TPoint);
+
+// Initializes dragging of the header, P is the current mouse postion and Start the initial mouse position.
+
+var
+ ColumnR,
+ HeaderR: TRect;
+ Image: TBitmap;
+ ImagePos: TPoint;
+
+begin
+ // Determine initial position of drag image (screen coordinates).
+ FColumns.FDropTarget := NoColumn;
+ Start := Treeview.ScreenToClient(Start);
+ Inc(Start.Y, FHeight);
+ FColumns.FDragIndex := FColumns.ColumnFromPosition(Start);
+ ColumnR := FColumns[FColumns.FDragIndex].GetRect;
+
+ HeaderR := Treeview.FHeaderRect;
+ // Set right border of the header rectangle to the maximum extent.
+ HeaderR.Right := FColumns.TotalWidth;
+
+ // Take out influence of border since we need a seamless drag image.
+ OffsetRect(ColumnR, -HeaderR.Left + Treeview.FOffsetX, -HeaderR.Top);
+
+ Image := TBitmap.Create;
+ with Image do
+ try
+ PixelFormat := pf32Bit;
+ Width := ColumnR.Right - ColumnR.Left + HeaderR.Left;
+ Height := ColumnR.Bottom - ColumnR.Top + HeaderR.Top;
+
+ HeaderR.Left := 0;
+ HeaderR.Top := 0;
+
+ // Erase the entire image with the color key value, for the case not everything
+ // in the image is covered by the header image.
+ Canvas.Brush.Color := clBtnFace;
+ Canvas.FillRect(Rect(0, 0, Width, Height));
+
+ FColumns.PaintHeader(Canvas.Handle, HeaderR, -ColumnR.Left + Treeview.FOffsetX, -ColumnR.Top);
+
+ ImagePos := Treeview.ClientToScreen(ColumnR.TopLeft);
+ // Column rectangles are given in local window coordinates not client coordinates.
+ Dec(ImagePos.Y, FHeight);
+
+ if hoRestrictDrag in FOptions then
+ FDragImage.MoveRestriction := dmrHorizontalOnly
+ else
+ FDragImage.MoveRestriction := dmrNone;
+ FDragImage.PrepareDrag(Image, ImagePos, P, nil);
+ FDragImage.ShowDragImage;
+ finally
+ Image.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.ReadColumns(Reader: TReader);
+
+begin
+ Include(FStates, hsLoading);
+ Columns.Clear;
+ Reader.ReadValue;
+ Reader.ReadCollection(Columns);
+ Exclude(FStates, hsLoading);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.RecalculateHeader;
+
+// Initiate a recalculation of the non-client area of the owner tree.
+
+begin
+ if Treeview.HandleAllocated then
+ begin
+ Treeview.UpdateHeaderRect;
+ SetWindowPos(Treeview.Handle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or
+ SWP_NOSENDCHANGING or SWP_NOSIZE or SWP_NOZORDER);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.UpdateMainColumn;
+
+// Called once the load process of the owner tree is done.
+
+begin
+ if FMainColumn < 0 then
+ FMainColumn := 0;
+ if FMainColumn > FColumns.Count - 1 then
+ FMainColumn := FColumns.Count - 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.WriteColumns(Writer: TWriter);
+
+begin
+ Writer.WriteCollection(Columns);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.Assign(Source: TPersistent);
+
+begin
+ if Source is TVTHeader then
+ begin
+ AutoSizeIndex := TVTHeader(Source).AutoSizeIndex;
+ Background := TVTHeader(Source).Background;
+ Columns := TVTHeader(Source).Columns;
+ Font := TVTHeader(Source).Font;
+ Height := TVTHeader(Source).Height;
+ Options := TVTHeader(Source).Options;
+ PopupMenu := TVTHeader(Source).PopupMenu;
+ Style := TVTHeader(Source).Style;
+ end
+ else
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.AutoFitColumns;
+
+var
+ I: Integer;
+
+begin
+ with FColumns do
+ for I := 0 to Count - 1 do
+ if [coResizable, coVisible] * Items[FPositionToIndex[I]].FOptions = [coResizable, coVisible] then
+ AnimatedResize(FPositionToIndex[I], Treeview.GetMaxColumnWidth(FPositionToIndex[I]))
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTHeader.InHeader(P: TPoint): Boolean;
+
+// Determines whether the given point (client coordinates!) is within the header rectangle (non-client coordinates).
+
+var
+ R, RW: TRect;
+
+begin
+ R := Treeview.FHeaderRect;
+ // current position of the owner in screen coordinates
+ GetWindowRect(Treeview.Handle, RW);
+ // convert to client coordinates
+ MapWindowPoints(0, Treeview.Handle, RW, 2);
+ // consider the header within this rectangle
+ OffsetRect(R, RW.Left, RW.Top);
+ Result := PtInRect(R, P);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.Invalidate(Column: TVirtualTreeColumn; ExpandToRight: Boolean = False);
+
+// Because the header is in the non-client area of the tree it needs some special handling in order to initiate its
+// repainting.
+// If ExpandToRight is True then not only the given column but everything to its right will be invalidated (useful for
+// resizing). This makes only sense when a column is given.
+
+var
+ R, RW: TRect;
+
+begin
+ if (hoVisible in FOptions) and Treeview.HandleAllocated then
+ begin
+ if Column = nil then
+ R := Treeview.FHeaderRect
+ else
+ begin
+ R := Column.GetRect;
+ OffsetRect(R, Treeview.FOffsetX, 0);
+ if ExpandToRight then
+ R.Right := Treeview.FHeaderRect.Right;
+ end;
+
+ // Current position of the owner in screen coordinates.
+ GetWindowRect(Treeview.Handle, RW);
+ // Consider the header within this rectangle.
+ OffsetRect(R, RW.Left, RW.Top);
+ // Expressed in client coordinates (because RedrawWindow wants them so, they will actually become negative).
+ MapWindowPoints(0, Treeview.Handle, R, 2);
+ RedrawWindow(Treeview.Handle, @R, 0, RDW_FRAME or RDW_INVALIDATE or RDW_VALIDATE or RDW_NOINTERNALPAINT or
+ RDW_NOERASE or RDW_NOCHILDREN);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.LoadFromStream(const Stream: TStream);
+
+// restore the state of the header from the given stream
+
+var
+ Dummy,
+ Version: Integer;
+ S: string;
+ OldOptions: TVTHeaderOptions;
+
+begin
+ Include(FStates, hsLoading);
+ with Stream do
+ try
+ // switch off all options which could influence loading the columns (they will be later set again)
+ OldOptions := FOptions;
+ FOptions := [];
+
+ // determine whether the stream contains data without a version number
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ if Dummy > -1 then
+ begin
+ // seek back to undo read operation if this is an old stream format
+ Seek(-SizeOf(Dummy), soFromCurrent);
+ Version := -1;
+ end
+ else // read version number if this is a "versionized" format
+ ReadBuffer(Version, SizeOf(Version));
+ Columns.LoadFromStream(Stream, Version);
+
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ AutoSizeIndex := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Background := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Height := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ FOptions := OldOptions;
+ Options := TVTHeaderOptions(Word(Dummy));
+ // PopupMenu is neither saved nor restored
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Style := TVTHeaderStyle(Dummy);
+ // TFont has no own save routine so we do it manually
+ with Font do
+ begin
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Color := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Height := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SetLength(S, Dummy);
+ ReadBuffer(PChar(S)^, Dummy);
+ Name := S;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Pitch := TFontPitch(Dummy);
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ Style := TFontStyles(Byte(Dummy));
+ end;
+
+ // read data introduced by stream version 1+
+ if Version > 0 then
+ begin
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ MainColumn := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SortColumn := Dummy;
+ ReadBuffer(Dummy, SizeOf(Dummy));
+ SortDirection := TSortDirection(Byte(Dummy));
+ end;
+ finally
+ Exclude(FStates, hsLoading);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.RestoreColumns;
+
+// Restores all columns to their width which they had before they have been auto fitted.
+
+var
+ I: Integer;
+
+begin
+ with FColumns do
+ for I := Count - 1 downto 0 do
+ if [coResizable, coVisible] * Items[FPositionToIndex[I]].FOptions = [coResizable, coVisible] then
+ Items[I].RestoreLastWidth;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTHeader.SaveToStream(const Stream: TStream);
+
+// Saves the complete state of the header into the provided stream.
+
+var
+ Dummy: Integer;
+
+begin
+ with Stream do
+ begin
+ // In previous version of VT was no header stream version defined.
+ // For feature enhancements it is necessary, however, to know which stream
+ // format we are trying to load.
+ // In order to distict from non-version streams an indicator is inserted.
+ Dummy := -1;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ // Write current stream version number, nothing more is required at the time being.
+ Dummy := VTHeaderStreamVersion;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+
+ // Save columns in case they depend on certain options (like auto size).
+ Columns.SaveToStream(Stream);
+
+ Dummy := FAutoSizeIndex;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := FBackground;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := FHeight;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Word(FOptions);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ // PopupMenu is neither saved nor restored
+ Dummy := Ord(FStyle);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ // TFont has no own save routine so we do it manually
+ with Font do
+ begin
+ Dummy := Color;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Height;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Length(Name);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ WriteBuffer(PChar(Name)^, Dummy);
+ Dummy := Ord(Pitch);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ // need only to write one: size or height, I decided to write height
+ Dummy := Byte(Style);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ end;
+
+ // data introduced by stream version 1
+ Dummy := FMainColumn;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := FSortColumn;
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ Dummy := Byte(FSortDirection);
+ WriteBuffer(Dummy, SizeOf(Dummy));
+ end;
+end;
+
+//----------------- TScrollBarOptions ----------------------------------------------------------------------------------
+
+constructor TScrollBarOptions.Create(AOwner: TBaseVirtualTree);
+
+begin
+ inherited Create;
+
+ FOwner := AOwner;
+ FAlwaysVisible := False;
+ FScrollBarStyle := sbmRegular;
+ FScrollBars := ssBoth;
+ FIncrementX := 20;
+ FIncrementY := 20;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TScrollBarOptions.SetAlwaysVisible(Value: Boolean);
+
+begin
+ if FAlwaysVisible <> Value then
+ begin
+ FAlwaysVisible := Value;
+ if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then
+ FOwner.RecreateWnd;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TScrollBarOptions.SetScrollBars(Value: TScrollStyle);
+
+begin
+ if FScrollbars <> Value then
+ begin
+ FScrollBars := Value;
+ if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then
+ FOwner.RecreateWnd;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TScrollBarOptions.SetScrollBarStyle(Value: TScrollBarStyle);
+
+begin
+ {$ifndef UseFlatScrollbars}
+ Assert(Value = sbmRegular, 'Flat scrollbars styles are disabled. Enable UseFlatScrollbars in VirtualTrees.pas for' +
+ 'flat scrollbar support.');
+ {$endif UseFlatScrollbars}
+
+ if FScrollBarStyle <> Value then
+ begin
+ FScrollBarStyle := Value;
+ {$ifdef UseFlatScrollbars}
+ if FOwner.HandleAllocated then
+ begin
+ // If set to regular style then don't use the emulation mode of the FlatSB APIs but the original APIs.
+ // This is necessary because the FlatSB APIs don't respect NC paint request with limited update region
+ // (which is necessary for the transparent drag image).
+ FOwner.RecreateWnd;
+ end;
+ {$endif UseFlatScrollbars}
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TScrollBarOptions.GetOwner: TPersistent;
+
+begin
+ Result := FOwner;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TScrollBarOptions.Assign(Source: TPersistent);
+
+begin
+ if Source is TScrollBarOptions then
+ begin
+ AlwaysVisible := TScrollBarOptions(Source).AlwaysVisible;
+ HorizontalIncrement := TScrollBarOptions(Source).HorizontalIncrement;
+ ScrollBars := TScrollBarOptions(Source).ScrollBars;
+ ScrollBarStyle := TScrollBarOptions(Source).ScrollBarStyle;
+ VerticalIncrement := TScrollBarOptions(Source).VerticalIncrement;
+ end
+ else
+ inherited;
+end;
+
+//----------------- TVTColors ------------------------------------------------------------------------------------------
+
+constructor TVTColors.Create(AOwner: TBaseVirtualTree);
+
+begin
+ FOwner := AOwner;
+ FColors[0] := clBtnShadow; // DisabledColor
+ FColors[1] := clHighlight; // DropMarkColor
+ FColors[2] := clHighLight; // DropTargetColor
+ FColors[3] := clHighLight; // FocusedSelectionColor
+ FColors[4] := clBtnFace; // GridLineColor
+ FColors[5] := clBtnShadow; // TreeLineColor
+ FColors[6] := clBtnFace; // UnfocusedSelectionColor
+ FColors[7] := clBtnFace; // BorderColor
+ FColors[8] := clWindowText; // HotColor
+ FColors[9] := clHighLight; // FocusedSelectionBorderColor
+ FColors[10] := clBtnFace; // UnfocusedSelectionBorderColor
+ FColors[11] := clHighlight; // DropTargetBorderColor
+ FColors[12] := clHighlight; // SelectionRectangleBlendColor
+ FColors[13] := clHighlight; // SelectionRectangleBorderColor
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVTColors.GetColor(const Index: Integer): TColor;
+
+begin
+ Result := FColors[Index];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTColors.SetColor(const Index: Integer; const Value: TColor);
+
+begin
+ if FColors[Index] <> Value then
+ begin
+ FColors[Index] := Value;
+ // Cause helper bitmap rebuild for grid and tree line colors.
+ if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then
+ begin
+ FOwner.Invalidate;
+ if Index = 7 then
+ RedrawWindow(FOwner.Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTColors.Assign(Source: TPersistent);
+
+begin
+ if Source is TVTColors then
+ begin
+ FColors := TVTColors(Source).FColors;
+ if FOwner.FUpdateCount = 0 then
+ FOwner.Invalidate;
+ end
+ else
+ inherited;
+end;
+
+//----------------- TClipboardFormats ----------------------------------------------------------------------------------
+
+constructor TClipboardFormats.Create(AOwner: TBaseVirtualTree);
+
+begin
+ FOwner := AOwner;
+ Sorted := True;
+ Duplicates := dupIgnore;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TClipboardFormats.Add(const S: string): Integer;
+
+// Restrict additions to the clipbard formats to only those which are registered with the owner tree or one of its
+// ancestors.
+
+var
+ Format: Word;
+ RegisteredClass: TVirtualTreeClass;
+
+begin
+ RegisteredClass := InternalClipboardFormats.FindFormat(S, Format);
+ if Assigned(RegisteredClass) and FOwner.ClassType.InheritsFrom(RegisteredClass) then
+ Result := inherited Add(S)
+ else
+ Result := -1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TClipboardFormats.Insert(Index: Integer; const S: string);
+
+// Restrict additions to the clipbard formats to only those which are registered with the owner tree or one of its
+// ancestors.
+
+var
+ Format: Word;
+ RegisteredClass: TVirtualTreeClass;
+
+begin
+ RegisteredClass := InternalClipboardFormats.FindFormat(S, Format);
+ if Assigned(RegisteredClass) and FOwner.ClassType.InheritsFrom(RegisteredClass) then
+ inherited Insert(Index, S);
+end;
+
+//----------------- TBaseVirtualTree -----------------------------------------------------------------------------------
+
+constructor TBaseVirtualTree.Create(AOwner: TComponent);
+
+begin
+ if not Initialized then
+ InitializeGlobalStructures;
+
+ inherited;
+
+ ControlStyle := ControlStyle - [csSetCaption] + [csCaptureMouse, csOpaque, csReplicatable, csDisplayDragImage,
+ csReflector];
+ FTotalInternalDataSize := 0;
+ FNodeDataSize := -1;
+ Width := 200;
+ Height := 100;
+ TabStop := True;
+ ParentColor := False;
+ FDefaultNodeHeight := 18;
+ FDragOperations := [doCopy, doMove];
+ FHotCursor := crDefault;
+ FScrollBarOptions := TScrollBarOptions.Create(Self);
+ FFocusedColumn := NoColumn;
+ FDragImageKind := diComplete;
+ FLastSelectionLevel := -1;
+ FAnimationType := hatSystemDefault;
+ FSelectionBlendFactor := 128;
+
+ FIndent := 18;
+
+ FPlusBM := TBitmap.Create;
+ FMinusBM := TBitmap.Create;
+
+ FBorderStyle := bsSingle;
+ FButtonStyle := bsRectangle;
+ FButtonFillMode := fmTreeColor;
+
+ FHeader := GetHeaderClass.Create(Self);
+
+ // we have an own double buffer handling
+ DoubleBuffered := False;
+
+ FCheckImageKind := ckLightCheck;
+ FCheckImages := LightCheckImages;
+
+ FImageChangeLink := TChangeLink.Create;
+ FImageChangeLink.OnChange := ImageListChange;
+ FStateChangeLink := TChangeLink.Create;
+ FStateChangeLink.OnChange := ImageListChange;
+ FCustomCheckChangeLink := TChangeLink.Create;
+ FCustomCheckChangeLink.OnChange := ImageListChange;
+
+ FAutoExpandDelay := 1000;
+ FAutoScrollDelay := 1000;
+ FAutoScrollInterval := 1;
+
+ FBackground := TPicture.Create;
+
+ FDefaultPasteMode := amAddChildLast;
+ FMargin := 4;
+ FTextMargin := 4;
+ FDragType := dtOLE;
+ FDragHeight := 350;
+ FDragWidth := 200;
+
+ FColors := TVTColors.Create(Self);
+ FEditDelay := 1000;
+
+ FDragImage := TVTDragImage.Create(Self);
+ with FDragImage do
+ begin
+ Fade := True;
+ PostBlendBias := 0;
+ PreBlendBias := 0;
+ Transparency := 200;
+ end;
+
+ SetLength(FSingletonNodeArray, 1);
+ FAnimationDuration := 200;
+ FSearchTimeout := 1000;
+ FSearchStart := ssFocusedNode;
+ FNodeAlignment := naProportional;
+ FLineStyle := lsDotted;
+ FIncrementalSearch := isNone;
+ FClipboardFormats := TClipboardFormats.Create(Self);
+ FOptions := GetOptionsClass.Create(Self);
+ FChangeLock := TCriticalSection.Create;
+
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager := TVTNodeMemoryManager.Create;
+ {$endif UseLocalMemoryManager}
+
+ AddThreadReference;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TBaseVirtualTree.Destroy;
+
+begin
+ Exclude(FOptions.FMiscOptions, toReadOnly);
+ InterruptValidation;
+ StopWheelPanning;
+ CancelEditNode;
+
+ // Just in case it didn't happen already release the edit link.
+ FEditLink := nil;
+ FClipboardFormats.Free;
+ // Clear will also free the drag manager if it is still alive.
+ Clear;
+ FDragImage.Free;
+ FColors.Free;
+ FBackground.Free;
+ FImageChangeLink.Free;
+ FStateChangeLink.Free;
+ FCustomCheckChangeLink.Free;
+ FScrollBarOptions.Free;
+ FOptions.Free;
+
+ // The window handle must be destroyed before the header is freed because it is needed in WM_NCDESTROY.
+ if HandleAllocated then
+ DestroyWindowHandle;
+ FHeader.Free;
+
+ FreeMem(FRoot);
+
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager.Free;
+ {$endif UseLocalMemoryManager}
+ FPlusBM.Free;
+ FMinusBM.Free;
+ FChangeLock.Free;
+ ReleaseThreadReference(Self);
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustCoordinatesByIndent(var PaintInfo: TVTPaintInfo; Indent: Integer);
+
+// During painting of the main column some coordinates must be adjusted due to the tree lines.
+// The offset resulting from the tree lines and indentation level is given in Indent.
+
+var
+ Offset: Integer;
+
+begin
+ with PaintInfo do
+ begin
+ Offset := Indent * Integer(FIndent);
+ if BidiMode = bdLeftToRight then
+ begin
+ Inc(ContentRect.Left, Offset);
+ Inc(ImageInfo[iiNormal].XPos, Offset);
+ Inc(ImageInfo[iiState].XPos, Offset);
+ Inc(ImageInfo[iiCheck].XPos, Offset);
+ end
+ else
+ begin
+ Dec(ContentRect.Right, Offset);
+ Dec(ImageInfo[iiNormal].XPos, Offset);
+ Dec(ImageInfo[iiState].XPos, Offset);
+ Dec(ImageInfo[iiCheck].XPos, Offset);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustImageBorder(Images: TCustomImageList; BidiMode: TBidiMode; VAlign: Integer; var R: TRect;
+ var ImageInfo: TVTImageInfo);
+
+// Depending on the width of the image list as well as the given bidi mode R must be adjusted.
+
+begin
+ if BidiMode = bdLeftToRight then
+ begin
+ ImageInfo.XPos := R.Left;
+ Inc(R.Left, Images.Width + 2);
+ end
+ else
+ begin
+ ImageInfo.XPos := R.Right - Images.Width;
+ Dec(R.Right, Images.Width + 2);
+ end;
+ ImageInfo.YPos := R.Top + VAlign - Images.Height div 2;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustTotalCount(Node: PVirtualNode; Value: Integer; relative: Boolean = False);
+
+// Sets a node's total count to the given value and recursively adjusts the parent's total count
+// (actually, the adjustment is done iteratively to avoid function call overheads).
+
+var
+ Difference: Integer;
+ Run: PVirtualNode;
+
+begin
+ if relative then
+ Difference := Value
+ else
+ Difference := Integer(Value) - Integer(Node.TotalCount);
+ if Difference <> 0 then
+ begin
+ Run := Node;
+ // root node has as parent the tree view
+ while Assigned(Run) and (Run <> Pointer(Self)) do
+ begin
+ Inc(Integer(Run.TotalCount), Difference);
+ Run := Run.Parent;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustTotalHeight(Node: PVirtualNode; Value: Integer; relative: Boolean = False);
+
+// Sets a node's total height to the given value and recursively adjusts the parent's total height.
+
+var
+ Difference: Integer;
+ Run: PVirtualNode;
+
+begin
+ if relative then
+ Difference := Value
+ else
+ Difference := Integer(Value) - Integer(Node.TotalHeight);
+ if Difference <> 0 then
+ begin
+ Run := Node;
+ repeat
+ Inc(Integer(Run.TotalHeight), Difference);
+ // If the node is not visible or the parent node is not expanded or we are already at the top
+ // then nothing more remains to do.
+ if not (vsVisible in Run.States) or (Run = FRoot) or
+ (Run.Parent = nil) or not (vsExpanded in Run.Parent.States) then
+ Break;
+
+ Run := Run.Parent;
+ until False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CalculateCacheEntryCount: Integer;
+
+// Calculates the size of the position cache.
+
+begin
+ if FVisibleCount > 1 then
+ Result := Ceil(FVisibleCount / CacheThreshold)
+ else
+ Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CalculateVerticalAlignments(ShowImages, ShowStateImages: Boolean; Node: PVirtualNode;
+ var VAlign, VButtonAlign: Integer);
+
+// Calculates the vertical alignment of the given node and its associated expand/collapse button during
+// a node paint cycle depending on the required node alignment style.
+
+begin
+ // For absolute alignment the caluclation is trivial.
+ case FNodeAlignment of
+ naFromTop:
+ VAlign := Node.Align;
+ naFromBottom:
+ VAlign := Node.NodeHeight - Node.Align;
+ else // naProportional
+ // Consider button and line alignment, but make sure neither the image nor the button (whichever is taller)
+ // go out of the entire node height (100% means bottom alignment to the node's bounds).
+ if ShowImages or ShowStateImages then
+ begin
+ if ShowImages then
+ VAlign := FImages.Height
+ else
+ VAlign := FStateImages.Height;
+ VAlign := MulDiv((Node.NodeHeight - VAlign), Node.Align, 100) + VAlign div 2;
+ end
+ else
+ if toShowButtons in FOptions.FPaintOptions then
+ VAlign := MulDiv((Node.NodeHeight - FPlusBM.Height), Node.Align, 100) + FPlusBM.Height div 2
+ else
+ VAlign := MulDiv(Node.NodeHeight, Node.Align, 100);
+ end;
+
+ VButtonAlign := VAlign - FPlusBM.Height div 2;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ChangeCheckState(Node: PVirtualNode; Value: TCheckState): Boolean;
+
+// Sets the check state of the node according to the given value and the node's check type.
+// If the check state must be propagated to the parent nodes and one of them refuses to change then
+// nothing happens and False is returned, otherwise True.
+
+var
+ Run: PVirtualNode;
+ CheckCount: Cardinal;
+
+begin
+ with Node^ do
+ begin
+ Include(States, vsChecking);
+
+ // Do actions which are associated with the given check state.
+ case CheckType of
+ // Check state change with additional consequences for check states of the children.
+ ctTriStateCheckBox:
+ begin
+ // propagate state down to the children
+ if toAutoTristateTracking in FOptions.FAutoOptions then
+ case Value of
+ csUncheckedNormal:
+ begin
+ Run := FirstChild;
+ CheckCount := 0;
+ while Assigned(Run) do
+ begin
+ if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
+ begin
+ SetCheckState(Run, csUncheckedNormal);
+ // Check if the new child state was set successfully, otherwise we have to adjust the
+ // node's new check state accordingly.
+ if Run.CheckState = csUncheckedNormal then
+ Inc(CheckCount);
+ end;
+ Run := Run.NextSibling;
+ end;
+ if Node.ChildCount > 0 then
+ begin
+ if CheckCount = 0 then
+ Value := csCheckedNormal
+ else
+ if CheckCount < Node.ChildCount then
+ Value := csMixedNormal;
+ end;
+ end;
+ csCheckedNormal:
+ begin
+ Run := FirstChild;
+ CheckCount := 0;
+ while Assigned(Run) do
+ begin
+ if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
+ begin
+ SetCheckState(Run, csCheckedNormal);
+ // Check if the new child state was set successfully, otherwise we have to adjust the
+ // node's new check state accordingly.
+ if Run.CheckState = csCheckedNormal then
+ Inc(CheckCount);
+ end;
+ Run := Run.NextSibling;
+ end;
+ if Node.ChildCount > 0 then
+ begin
+ if CheckCount = 0 then
+ Value := csUncheckedNormal
+ else
+ if CheckCount < Node.ChildCount then
+ Value := csMixedNormal;
+ end;
+ end;
+ end;
+ end;
+ // radio button check state change
+ ctRadioButton:
+ if Value = csCheckedNormal then
+ begin
+ Value := csCheckedNormal;
+ // Make sure only this node is checked.
+ Run := Parent.FirstChild;
+ while Assigned(Run) do
+ begin
+ if Run.CheckType = ctRadioButton then
+ Run.CheckState := csUncheckedNormal;
+ Run := Run.NextSibling;
+ end;
+ Invalidate;
+ end;
+ end;
+
+ // Propagate state up to the parent.
+ if not (vsInitialized in Parent.States) then
+ InitNode(Parent);
+ if (toAutoTristateTracking in FOptions.FAutoOptions) and ([vsChecking, vsDisabled] * Parent.States = []) and
+ (CheckType in [ctCheckBox, ctTriStateCheckBox]) and (Parent <> FRoot) and
+ (Parent.CheckType = ctTriStateCheckBox) then
+ Result := CheckParentCheckState(Node, Value)
+ else
+ Result := True;
+
+ if Result then
+ CheckState := Value // Set new check state
+ else
+ CheckState := UnpressedState[CheckState]; // Reset dynmic check state.
+ InvalidateNode(Node);
+ Exclude(States, vsChecking);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CollectSelectedNodesLTR(MainColumn, NodeLeft, NodeRight: Integer; Alignment: TAlignment;
+ OldRect, NewRect: TRect): Boolean;
+
+// Helper routine used when a draw selection takes place. This version handles left-to-right directionality.
+// In the process of adding or removing nodes the current selection is modified which requires to pack it after
+// the function returns. Another side effect of this method is that a temporary list of nodes will be created
+// (see also InternalCacheNode) which must be inserted into the current selection by the caller.
+
+var
+ Run,
+ NextNode: PVirtualNode;
+ TextRight,
+ TextLeft,
+ CheckOffset,
+ CurrentTop,
+ CurrentRight,
+ NextTop,
+ NextColumn,
+ NodeWidth,
+ Dummy: Integer;
+ MinY, MaxY: Integer;
+ ImageOffset,
+ StateImageOffset: Integer;
+ IsInOldRect,
+ IsInNewRect: Boolean;
+
+ // quick check variables for various parameters
+ WithCheck,
+ WithImages,
+ WithStateImages,
+ DoSwitch,
+ AutoSpan,
+ Ghosted: Boolean;
+
+begin
+ // a priory nothing changes
+ Result := False;
+
+ // Determine minimum and maximum vertical coordinates to limit iteration to.
+ MinY := Min(OldRect.Top, NewRect.Top);
+ MaxY := Max(OldRect.Bottom, NewRect.Bottom);
+
+ // Initialize short hand variables to speed up tests below.
+ DoSwitch := ssCtrl in FDrawSelShiftState;
+ WithCheck := (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages);
+ // Don't check the events here as descendant trees might have overriden the DoGetImageIndex method.
+ WithImages := Assigned(FImages);
+ if WithImages then
+ ImageOffset := FImages.Width + 2
+ else
+ ImageOffset := 0;
+ WithStateImages := Assigned(FStateImages);
+ if WithStateImages then
+ StateImageOffset := FStateImages.Width + 2
+ else
+ StateImageOffset := 0;
+ if WithCheck then
+ CheckOffset := FCheckImages.Width + 2
+ else
+ CheckOffset := 0;
+ AutoSpan := FHeader.UseColumns and (toAutoSpanColumns in FOptions.FAutoOptions);
+
+ // This is the node to start with.
+ Run := GetNodeAt(0, MinY, False, CurrentTop);
+
+ if Assigned(Run) then
+ begin
+ // The initial minimal left border is determined by the identation level of the node and is dynamically adjusted.
+ if toShowRoot in FOptions.FPaintOptions then
+ Inc(NodeLeft, Integer((GetNodeLevel(Run) + 1) * FIndent) + FMargin)
+ else
+ Inc(NodeLeft, Integer(GetNodeLevel(Run) * FIndent) + FMargin);
+
+ // ----- main loop
+ // Change selection depending on the node's rectangle being in the selection rectangle or not, but
+ // touch only those nodes which overlap either the old selection rectangle or the new one but not both.
+ repeat
+ // Collect offsets for check, normal and state images.
+ TextLeft := NodeLeft;
+ if WithCheck and (Run.CheckType <> ctNone) then
+ Inc(TextLeft, CheckOffset);
+ if WithImages and (GetImageIndex(Run, ikNormal, MainColumn, Ghosted) > -1) then
+ Inc(TextLeft, ImageOffset);
+ if WithStateImages and (GetImageIndex(Run, ikState, MainColumn, Ghosted) > -1) then
+ Inc(TextLeft, StateImageOffset);
+
+ NextTop := CurrentTop + Run.NodeHeight;
+
+ // The right column border might be extended if column spanning is enabled.
+ if AutoSpan then
+ begin
+ with FHeader.FColumns do
+ begin
+ NextColumn := MainColumn;
+ repeat
+ Dummy := GetNextVisibleColumn(NextColumn);
+ if (Dummy = InvalidColumn) or not ColumnIsEmpty(Run, Dummy) or
+ (Items[Dummy].BidiMode <> bdLeftToRight) then
+ Break;
+ NextColumn := Dummy;
+ until False;
+ if NextColumn = MainColumn then
+ CurrentRight := NodeRight
+ else
+ GetColumnBounds(NextColumn, Dummy, CurrentRight);
+ end;
+ end
+ else
+ CurrentRight := NodeRight;
+
+ // Check if we need the node's width. This is the case when the node is not left aligned or the
+ // left border of the selection rectangle is to the right of the left node border.
+ if (TextLeft < OldRect.Left) or (TextLeft < NewRect.Left) or (Alignment <> taLeftJustify) then
+ begin
+ NodeWidth := DoGetNodeWidth(Run, MainColumn);
+ if NodeWidth >= (CurrentRight - TextLeft) then
+ TextRight := CurrentRight
+ else
+ case Alignment of
+ taLeftJustify:
+ TextRight := TextLeft + NodeWidth;
+ taCenter:
+ begin
+ TextLeft := (TextLeft + CurrentRight - NodeWidth) div 2;
+ TextRight := TextLeft + NodeWidth;
+ end;
+ else
+ // taRightJustify
+ TextRight := CurrentRight;
+ TextLeft := TextRight - NodeWidth;
+ end;
+ end
+ else
+ TextRight := CurrentRight;
+
+ // Now determine whether we need to change the state.
+ IsInOldRect := (OldRect.Left <= TextRight) and (OldRect.Right >= TextLeft) and
+ (NextTop > OldRect.Top) and (CurrentTop < OldRect.Bottom);
+ IsInNewRect := (NewRect.Left <= TextRight) and (NewRect.Right >= TextLeft) and
+ (NextTop > NewRect.Top) and (CurrentTop < NewRect.Bottom);
+
+ if IsInOldRect xor IsInNewRect then
+ begin
+ Result := True;
+ if DoSwitch then
+ begin
+ if vsSelected in Run.States then
+ InternalRemoveFromSelection(Run)
+ else
+ InternalCacheNode(Run);
+ end
+ else
+ begin
+ if IsInNewRect then
+ InternalCacheNode(Run)
+ else
+ InternalRemoveFromSelection(Run);
+ end;
+ end;
+
+ CurrentTop := NextTop;
+ // Get next visible node and update left node position.
+ NextNode := GetNextVisibleNoInit(Run);
+ if NextNode = nil then
+ Break;
+ Inc(NodeLeft, CountLevelDifference(Run, NextNode) * Integer(FIndent));
+ Run := NextNode;
+ until CurrentTop > MaxY;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CollectSelectedNodesRTL(MainColumn, NodeLeft, NodeRight: Integer; Alignment: TAlignment;
+ OldRect, NewRect: TRect): Boolean;
+
+// Helper routine used when a draw selection takes place. This version handles right-to-left directionality.
+// See also comments in CollectSelectedNodesLTR.
+
+var
+ Run,
+ NextNode: PVirtualNode;
+ TextRight,
+ TextLeft,
+ CheckOffset,
+ CurrentTop,
+ CurrentLeft,
+ NextTop,
+ NextColumn,
+ NodeWidth,
+ Dummy: Integer;
+ MinY, MaxY: Integer;
+ ImageOffset,
+ StateImageOffset: Integer;
+ IsInOldRect,
+ IsInNewRect: Boolean;
+
+ // quick check variables for various parameters
+ WithCheck,
+ WithImages,
+ WithStateImages,
+ DoSwitch,
+ AutoSpan,
+ Ghosted: Boolean;
+
+begin
+ // A priori nothing changes.
+ Result := False;
+ // Switch the alignment to the opposite value in RTL context.
+ ChangeBiDiModeAlignment(Alignment);
+
+ // Determine minimum and maximum vertical coordinates to limit iteration to.
+ MinY := Min(OldRect.Top, NewRect.Top);
+ MaxY := Max(OldRect.Bottom, NewRect.Bottom);
+
+ // Initialize short hand variables to speed up tests below.
+ DoSwitch := ssCtrl in FDrawSelShiftState;
+ WithCheck := (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages);
+ // Don't check the events here as descendant trees might have overriden the DoGetImageIndex method.
+ WithImages := Assigned(FImages);
+ if WithImages then
+ ImageOffset := FImages.Width + 2
+ else
+ ImageOffset := 0;
+ WithStateImages := Assigned(FStateImages);
+ if WithStateImages then
+ StateImageOffset := FStateImages.Width + 2
+ else
+ StateImageOffset := 0;
+ if WithCheck then
+ CheckOffset := FCheckImages.Width + 2
+ else
+ CheckOffset := 0;
+ AutoSpan := FHeader.UseColumns and (toAutoSpanColumns in FOptions.FAutoOptions);
+
+ // This is the node to start with.
+ Run := GetNodeAt(0, MinY, False, CurrentTop);
+
+ if Assigned(Run) then
+ begin
+ // The initial minimal left border is determined by the identation level of the node and is dynamically adjusted.
+ if toShowRoot in FOptions.FPaintOptions then
+ Dec(NodeRight, Integer((GetNodeLevel(Run) + 1) * FIndent) + FMargin)
+ else
+ Dec(NodeRight, Integer(GetNodeLevel(Run) * FIndent) + FMargin);
+
+ // ----- main loop
+ // Change selection depending on the node's rectangle being in the selection rectangle or not, but
+ // touch only those nodes which overlap either the old selection rectangle or the new one but not both.
+ repeat
+ // Collect offsets for check, normal and state images.
+ TextRight := NodeRight;
+ if WithCheck and (Run.CheckType <> ctNone) then
+ Dec(TextRight, CheckOffset);
+ if WithImages and (GetImageIndex(Run, ikNormal, MainColumn, Ghosted) > -1) then
+ Dec(TextRight, ImageOffset);
+ if WithStateImages and (GetImageIndex(Run, ikState, MainColumn, Ghosted) > -1) then
+ Dec(TextRight, StateImageOffset);
+
+ NextTop := CurrentTop + Run.NodeHeight;
+
+ // The left column border might be extended if column spanning is enabled.
+ if AutoSpan then
+ begin
+ NextColumn := MainColumn;
+ repeat
+ Dummy := FHeader.FColumns.GetPreviousVisibleColumn(NextColumn);
+ if (Dummy = InvalidColumn) or not ColumnIsEmpty(Run, Dummy) or
+ (FHeader.FColumns[Dummy].BiDiMode = bdLeftToRight) then
+ Break;
+ NextColumn := Dummy;
+ until False;
+ if NextColumn = MainColumn then
+ CurrentLeft := NodeLeft
+ else
+ FHeader.FColumns.GetColumnBounds(NextColumn, CurrentLeft, Dummy);
+ end
+ else
+ CurrentLeft := NodeLeft;
+
+ // Check if we need the node's width. This is the case when the node is not left aligned (in RTL context this
+ // means actually right aligned) or the right border of the selection rectangle is to the left
+ // of the right node border.
+ if (TextRight > OldRect.Right) or (TextRight > NewRect.Right) or (Alignment <> taRightJustify) then
+ begin
+ NodeWidth := DoGetNodeWidth(Run, MainColumn);
+ if NodeWidth >= (TextRight - CurrentLeft) then
+ TextLeft := CurrentLeft
+ else
+ case Alignment of
+ taLeftJustify:
+ begin
+ TextLeft := CurrentLeft;
+ TextRight := TextLeft + NodeWidth;
+ end;
+ taCenter:
+ begin
+ TextLeft := (TextRight + CurrentLeft - NodeWidth) div 2;
+ TextRight := TextLeft + NodeWidth;
+ end;
+ else
+ // taRightJustify
+ TextLeft := TextRight - NodeWidth;
+ end;
+ end
+ else
+ TextLeft := CurrentLeft;
+
+ // Now determine whether we need to change the state.
+ IsInOldRect := (OldRect.Right >= TextLeft) and (OldRect.Left <= TextRight) and
+ (NextTop > OldRect.Top) and (CurrentTop < OldRect.Bottom);
+ IsInNewRect := (NewRect.Right >= TextLeft) and (NewRect.Left <= TextRight) and
+ (NextTop > NewRect.Top) and (CurrentTop < NewRect.Bottom);
+
+ if IsInOldRect xor IsInNewRect then
+ begin
+ Result := True;
+ if DoSwitch then
+ begin
+ if vsSelected in Run.States then
+ InternalRemoveFromSelection(Run)
+ else
+ InternalCacheNode(Run);
+ end
+ else
+ begin
+ if IsInNewRect then
+ InternalCacheNode(Run)
+ else
+ InternalRemoveFromSelection(Run);
+ end;
+ end;
+
+ CurrentTop := NextTop;
+ // Get next visible node and update left node position.
+ NextNode := GetNextVisibleNoInit(Run);
+ if NextNode = nil then
+ Break;
+ Dec(NodeRight, CountLevelDifference(Run, NextNode) * Integer(FIndent));
+ Run := NextNode;
+ until CurrentTop > MaxY;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ClearNodeBackground(const PaintInfo: TVTPaintInfo; UseBackground, Floating: Boolean;
+ R: TRect);
+
+// Erases a nodes background depending on what the application decides to do.
+// UseBackground determines whether or not to use the background picture, while Floating indicates
+// that R is given in coordinates of the small node bitmap or the superordinated target bitmap used in PaintTree.
+
+var
+ BackColor: TColor;
+ EraseAction: TItemEraseAction;
+ Offset: TPoint;
+
+begin
+ with PaintInfo do
+ begin
+ EraseAction := eaDefault;
+ BackColor := Color;
+ DoBeforeItemErase(Canvas, Node, R, Backcolor, EraseAction);
+ if Floating then
+ begin
+ Offset := Point(FOffsetX, R.Top);
+ OffsetRect(R, 0, -Offset.Y);
+ end
+ else
+ Offset := Point(0, 0);
+
+ with Canvas do
+ begin
+ case EraseAction of
+ eaColor:
+ begin
+ // user has given a new background color
+ Brush.Color := BackColor;
+ FillRect(R);
+ DoAfterItemErase(Canvas, Node, R);
+ end;
+ else // eaDefault
+ if UseBackground then
+ TileBackground(FBackground.Bitmap, Canvas, Offset, R)
+ else
+ begin
+ if (poDrawSelection in PaintOptions) and (toFullRowSelect in FOptions.FSelectionOptions) and
+ (vsSelected in Node.States) then
+ begin
+ if toShowHorzGridLines in FOptions.PaintOptions then
+ Dec(R.Bottom);
+ if Focused or (toPopupMode in FOptions.FPaintOptions)then
+ begin
+ Brush.Color := FColors.FocusedSelectionColor;
+ Pen.Color := FColors.FocusedSelectionBorderColor;
+ end
+ else
+ begin
+ Brush.Color := FColors.UnfocusedSelectionColor;
+ Pen.Color := FColors.UnfocusedSelectionBorderColor;
+ end;
+ with R do
+ RoundRect(Left, Top, Right, Bottom, FSelectionCurveRadius, FSelectionCurveRadius);
+ end
+ else
+ begin
+ Brush.Color := Color;
+ FillRect(R);
+ end;
+ end;
+ DoAfterItemErase(Canvas, Node, R);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CompareNodePositions(Node1, Node2: PVirtualNode): Integer;
+
+// Tries hard and smart to quickly determine whether Node1's structural position is before Node2's position
+// Returns 0 if Node1 = Node2, < 0 if Node1 is located before Node2 else > 0.
+
+var
+ Run1,
+ Run2: PVirtualNode;
+ Level1,
+ Level2: Cardinal;
+
+begin
+ Assert(Assigned(Node1) and Assigned(Node2), 'Nodes must never be nil.');
+
+ if Node1 = Node2 then
+ Result := 0
+ else
+ begin
+ if HasAsParent(Node1, Node2) then
+ Result := 1
+ else
+ if HasAsParent(Node2, Node1) then
+ Result := -1
+ else
+ begin
+ // the given nodes are neither equal nor are they parents of each other, so go up to FRoot
+ // for each node and compare the child indices of the top level parents
+ // Note: neither Node1 nor Node2 can be FRoot at this point as this (a bit strange) circumstance would
+ // be caught by the previous code.
+
+ // start lookup at the same level
+ Level1 := GetNodeLevel(Node1);
+ Level2 := GetNodeLevel(Node2);
+ Run1 := Node1;
+ while Level1 > Level2 do
+ begin
+ Run1 := Run1.Parent;
+ Dec(Level1);
+ end;
+ Run2 := Node2;
+ while Level2 > Level1 do
+ begin
+ Run2 := Run2.Parent;
+ Dec(Level2);
+ end;
+
+ // now go up until we find a common parent node (loop will safely stop at FRoot if the nodes
+ // don't share a common parent)
+ while Run1.Parent <> Run2.Parent do
+ begin
+ Run1 := Run1.Parent;
+ Run2 := Run2.Parent;
+ end;
+ Result := Integer(Run1.Index) - Integer(Run2.Index);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DrawLineImage(const PaintInfo: TVTPaintInfo; X, Y, H, VAlign: Integer; Style: TVTLineType;
+ Reverse: Boolean);
+
+// Draws (depending on Style) one of the 5 line types of the tree.
+// If Reverse is True then a right-to-left column is being drawn, hence horizontal lines must be mirrored.
+// X and Y describe the left upper corner of the line image rectangle, while H denotes its height (and width).
+
+var
+ HalfWidth,
+ TargetX: Integer;
+
+begin
+ HalfWidth := Integer(FIndent) div 2;
+ if Reverse then
+ TargetX := 0
+ else
+ TargetX := FIndent;
+
+ with PaintInfo.Canvas do
+ begin
+ case Style of
+ ltBottomRight:
+ begin
+ DrawDottedVLine(PaintInfo, Y + VAlign, Y + H, X + HalfWidth);
+ DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign);
+ end;
+ ltTopDown:
+ DrawDottedVLine(PaintInfo, Y, Y + H, X + HalfWidth);
+ ltTopDownRight:
+ begin
+ DrawDottedVLine(PaintInfo, Y, Y + H, X + HalfWidth);
+ DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign);
+ end;
+ ltRight:
+ DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign);
+ ltTopRight:
+ begin
+ DrawDottedVLine(PaintInfo, Y, Y + VAlign, X + HalfWidth);
+ DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign);
+ end;
+ ltLeft: // left can also mean right for RTL context
+ if Reverse then
+ DrawDottedVLine(PaintInfo, Y, Y + H, X + Integer(FIndent))
+ else
+ DrawDottedVLine(PaintInfo, Y, Y + H, X);
+ ltLeftBottom:
+ if Reverse then
+ begin
+ DrawDottedVLine(PaintInfo, Y, Y + H, X + Integer(FIndent));
+ DrawDottedHLine(PaintInfo, X, X + Integer(FIndent), Y + H);
+ end
+ else
+ begin
+ DrawDottedVLine(PaintInfo, Y, Y + H, X);
+ DrawDottedHLine(PaintInfo, X, X + Integer(FIndent), Y + H);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.FindInPositionCache(Node: PVirtualNode; var CurrentPos: Cardinal): PVirtualNode;
+
+// Looks through the position cache and returns the node whose top position is the largest one which is smaller or equal
+// to the position of the given node.
+
+var
+ L, H, I: Integer;
+
+begin
+ L := 0;
+ H := High(FPositionCache);
+ while L <= H do
+ begin
+ I := (L + H) shr 1;
+ if CompareNodePositions(FPositionCache[I].Node, Node) <= 0 then
+ L := I + 1
+ else
+ H := I - 1;
+ end;
+ Result := FPositionCache[L - 1].Node;
+ CurrentPos := FPositionCache[L - 1].AbsoluteTop;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.FindInPositionCache(Position: Cardinal; var CurrentPos: Cardinal): PVirtualNode;
+
+// Looks through the position cache and returns the node whose top position is the largest one which is smaller or equal
+// to the given vertical position.
+// The returned node does not necessarily occupy the given position but is the nearest one to start
+// iterating from to approach the real node for a given position. CurrentPos receives the actual position of the found
+// node which is needed for further iteration.
+
+var
+ L, H, I: Integer;
+
+begin
+ L := 0;
+ H := High(FPositionCache);
+ while L <= H do
+ begin
+ I := (L + H) shr 1;
+ if FPositionCache[I].AbsoluteTop <= Position then
+ L := I + 1
+ else
+ H := I - 1;
+ end;
+ Result := FPositionCache[L - 1].Node;
+ CurrentPos := FPositionCache[L - 1].AbsoluteTop;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetCheckState(Node: PVirtualNode): TCheckState;
+
+begin
+ Result := Node.CheckState;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetCheckType(Node: PVirtualNode): TCheckType;
+
+begin
+ Result := Node.CheckType;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetChildCount(Node: PVirtualNode): Cardinal;
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.ChildCount
+ else
+ Result := Node.ChildCount;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetChildrenInitialized(Node: PVirtualNode): Boolean;
+
+begin
+ Result := not (vsHasChildren in Node.States) or (Node.ChildCount > 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetDisabled(Node: PVirtualNode): Boolean;
+
+begin
+ Result := Assigned(Node) and (vsDisabled in Node.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetDragManager: IVTDragManager;
+
+// Returns the internal drag manager interface. If this does not yet exist then it is created here.
+
+begin
+ if FDragManager = nil then
+ begin
+ FDragManager := DoCreateDragManager;
+ if FDragManager = nil then
+ FDragManager := TVTDragManager.Create(Self);
+ end;
+
+ Result := FDragManager;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetExpanded(Node: PVirtualNode): Boolean;
+
+begin
+ if Assigned(Node) then
+ Result := vsExpanded in Node.States
+ else
+ Result := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFullyVisible(Node: PVirtualNode): Boolean;
+
+// Determines whether the given node has the visibility flag set as well as all its parents are expanded.
+
+begin
+ Assert(Assigned(Node), 'Invalid parameter.');
+ Result := vsVisible in Node.States;
+ if Result and (Node <> FRoot) then
+ Result := VisiblePath[Node];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetHasChildren(Node: PVirtualNode): Boolean;
+
+begin
+ if Assigned(Node) then
+ Result := vsHasChildren in Node.States
+ else
+ Result := vsHasChildren in FRoot.States;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetMultiline(Node: PVirtualNode): Boolean;
+
+begin
+ Result := Assigned(Node) and (Node <> FRoot) and (vsMultiline in Node.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeHeight(Node: PVirtualNode): Cardinal;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ Result := Node.NodeHeight
+ else
+ Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeParent(Node: PVirtualNode): PVirtualNode;
+
+begin
+ if Assigned(Node) and (Node.Parent <> FRoot) then
+ Result := Node.Parent
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetOffsetXY: TPoint;
+
+begin
+ Result := Point(FOffsetX, FOffsetY);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetRootNodeCount: Cardinal;
+
+begin
+ Result := FRoot.ChildCount;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetSelected(Node: PVirtualNode): Boolean;
+
+begin
+ Result := Assigned(Node) and (vsSelected in Node.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetTopNode: PVirtualNode;
+
+var
+ Dummy: Integer;
+
+begin
+ Result := GetNodeAt(0, 0, True, Dummy);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetTotalCount: Cardinal;
+
+begin
+ Inc(FUpdateCount);
+ try
+ ValidateNode(FRoot, True);
+ finally
+ Dec(FUpdateCount);
+ end;
+ // The root node itself doesn't count as node.
+ Result := FRoot.TotalCount - 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetVerticalAlignment(Node: PVirtualNode): Byte;
+
+begin
+ Result := Node.Align;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetVisible(Node: PVirtualNode): Boolean;
+
+// Determines if the given node marked as being visible.
+
+begin
+ if Node = nil then
+ Node := FRoot;
+
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ Result := vsVisible in Node.States;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetVisiblePath(Node: PVirtualNode): Boolean;
+
+// Determines if all parents of the given node are expanded and have the visibility flag set.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameters.');
+
+ // FRoot is always expanded
+ repeat
+ Node := Node.Parent;
+ until (Node = FRoot) or not (vsExpanded in Node.States) or not (vsVisible in Node.States);
+
+ Result := Node = FRoot;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleClickSelection(LastFocused, NewNode: PVirtualNode; Shift: TShiftState);
+
+// Handles multi-selection with mouse click.
+
+begin
+ // Ctrl key down
+ if ssCtrl in Shift then
+ begin
+ if ssShift in Shift then
+ begin
+ SelectNodes(FRangeAnchor, NewNode, True);
+ Invalidate;
+ end
+ else
+ begin
+ if not (toSiblingSelectConstraint in FOptions.SelectionOptions) then
+ FRangeAnchor := NewNode;
+ DoStateChange([tsClearFocusedSelection])
+ end;
+ end
+ else
+ // Shift key down
+ if ssShift in Shift then
+ begin
+ if FRangeAnchor = nil then
+ FRangeAnchor := FRoot.FirstChild;
+
+ // select node range
+ if Assigned(FRangeAnchor) then
+ begin
+ SelectNodes(FRangeAnchor, NewNode, False);
+ Invalidate;
+ end;
+ end
+ else
+ begin
+ // any other case
+ if not (vsSelected in NewNode.States) then
+ begin
+ AddToSelection(NewNode);
+ InvalidateNode(NewNode);
+ end;
+ // assign new reference item
+ FRangeAnchor := NewNode;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.HandleDrawSelection(X, Y: Integer): Boolean;
+
+// Handles multi-selection with a focus rectangle.
+// Result is True if something changed in selection.
+
+var
+ OldRect,
+ NewRect: TRect;
+ MainColumn: TColumnIndex;
+ MaxValue: Integer;
+
+ // limits of a node and its text
+ NodeLeft,
+ NodeRight: Integer;
+
+ // alignment and directionality
+ CurrentBidiMode: TBidiMode;
+ CurrentAlignment: TAlignment;
+
+begin
+ Result := False;
+
+ // Selection changes are only done if the user drew a selection rectangle large
+ // enough to exceed the threshold.
+ if (FRoot.TotalCount > 1) and (tsDrawSelecting in FStates) then
+ begin
+ // Effective handling of node selection is done by using two rectangles stored in FSelectRec.
+ OldRect := OrderRect(FLastSelRect);
+ NewRect := OrderRect(FNewSelRect);
+ ClearTempCache;
+
+ MainColumn := FHeader.MainColumn;
+
+ // Alignment and bidi mode determine where the node text is located within a node.
+ if MainColumn = NoColumn then
+ begin
+ CurrentBidiMode := BidiMode;
+ CurrentAlignment := Alignment;
+ end
+ else
+ begin
+ CurrentBidiMode := FHeader.FColumns[MainColumn].BidiMode;
+ CurrentAlignment := FHeader.FColumns[MainColumn].Alignment;
+ end;
+
+ // Determine initial left border of first node (take column reordering into account).
+ if FHeader.UseColumns then
+ begin
+ // The mouse coordinates don't include any horizontal scrolling hence take this also
+ // out from the returned column position.
+ NodeLeft := FHeader.FColumns[MainColumn].Left - FOffsetX;
+ NodeRight := NodeLeft + FHeader.FColumns[MainColumn].Width;
+ end
+ else
+ begin
+ NodeLeft := 0;
+ NodeRight := ClientWidth;
+ end;
+ if CurrentBidiMode = bdLeftToRight then
+ Result := CollectSelectedNodesLTR(MainColumn, NodeLeft, NodeRight, CurrentAlignment, OldRect, NewRect)
+ else
+ Result := CollectSelectedNodesRTL(MainColumn, NodeLeft, NodeRight, CurrentAlignment, OldRect, NewRect);
+ end;
+
+ if Result then
+ begin
+ // Do some housekeeping if there was a change.
+ MaxValue := PackArray(FSelection, FSelectionCount);
+ if MaxValue > -1 then
+ begin
+ FSelectionCount := MaxValue;
+ SetLength(FSelection, FSelectionCount);
+ end;
+ if FTempNodeCount > 0 then
+ begin
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+ end;
+
+ Change(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.HasVisibleNextSibling(Node: PVirtualNode): Boolean;
+
+// Helper method to determine if the given node has a visible sibling. This is needed to
+// draw correct tree lines.
+
+begin
+ // Check if there is a sibling at all.
+ Result := Assigned(Node.NextSibling);
+
+ if Result then
+ begin
+ repeat
+ Node := Node.NextSibling;
+ Result := vsVisible in Node.States;
+ until Result or (Node.NextSibling = nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ImageListChange(Sender: TObject);
+
+begin
+ if not (csDestroying in ComponentState) then
+ Invalidate;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InitializeFirstColumnValues(var PaintInfo: TVTPaintInfo);
+
+// Determines initial index, position and cell size of the first visible column.
+
+begin
+ PaintInfo.Column := FHeader.FColumns.GetFirstVisibleColumn;
+ with FHeader.FColumns, PaintInfo do
+ begin
+ if Column > NoColumn then
+ begin
+ CellRect.Right := CellRect.Left + Items[Column].Width;
+ Position := Items[Column].Position;
+ end
+ else
+ Position := 0;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InitializeLineImageAndSelectLevel(Node: PVirtualNode; var LineImage: TLineImage): Integer;
+
+// This method is used during paint cycles and initializes an array of line type IDs. These IDs are used to paint
+// the tree lines in front of the given node.
+// Additionally an initial count of selected parents is determined and returned which is used for specific painting.
+
+var
+ X: Integer;
+ Run: PVirtualNode;
+
+begin
+ Result := 0;
+ if toShowRoot in FOptions.FPaintOptions then
+ X := 1
+ else
+ X := 0;
+ Run := Node;
+ // Determine indentation level of top node.
+ while Run.Parent <> FRoot do
+ begin
+ Inc(X);
+ Run := Run.Parent;
+ // Count selected nodes (FRoot is never selected).
+ if vsSelected in Run.States then
+ Inc(Result);
+ end;
+
+ // Set initial size of line index array, this will automatically initialized all entries to ltNone.
+ SetLength(LineImage, X);
+
+ // Only use lines if requested.
+ if toShowTreeLines in FOptions.FPaintOptions then
+ begin
+ // Start over parent traversal if necessary.
+ Run := Node;
+ if Run.Parent <> FRoot then
+ begin
+ // The very last image (the one immediately before the item label) is different.
+ if HasVisibleNextSibling(Run) then
+ LineImage[X - 1] := ltTopDownRight
+ else
+ LineImage[X - 1] := ltTopRight;
+ Run := Run.Parent;
+
+ // Now go up all parents.
+ repeat
+ if Run.Parent = FRoot then
+ Break;
+ Dec(X);
+ if HasVisibleNextSibling(Run) then
+ LineImage[X - 1] := ltTopDown
+ else
+ LineImage[X - 1] := ltNone;
+ Run := Run.Parent;
+ until False;
+ end;
+
+ // Prepare root level. Run points at this stage to a top level node.
+ if (toShowRoot in FOptions.FPaintOptions) and (toShowTreeLines in FOptions.FPaintOptions) then
+ begin
+ // Is the top node a root node?
+ if Run = Node then
+ begin
+ // First child gets the bottom-right bitmap if it isn't also the only child.
+ if IsFirstVisibleChild(FRoot, Run) then
+ // Is it the only child?
+ if IsLastVisibleChild(FRoot, Run) then
+ LineImage[0] := ltRight
+ else
+ LineImage[0] := ltBottomRight
+ else
+ // real last child
+ if IsLastVisibleChild(FRoot, Run) then
+ LineImage[0] := ltTopRight
+ else
+ LineImage[0] := ltTopDownRight;
+ end
+ else
+ begin
+ // No, top node is not a top level node. So we need different painting.
+ if HasVisibleNextSibling(Run) then
+ LineImage[0] := ltTopDown
+ else
+ LineImage[0] := ltNone;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InitRootNode(OldSize: Cardinal = 0);
+
+// Reinitializes the root node.
+
+var
+ NewSize: Cardinal;
+
+begin
+ NewSize := TreeNodeSize + FTotalInternalDataSize;
+ if FRoot = nil then
+ FRoot := AllocMem(NewSize)
+ else
+ begin
+ ReallocMem(FRoot, NewSize);
+ ZeroMemory(PChar(FRoot) + OldSize, NewSize - OldSize);
+ end;
+
+ with FRoot^ do
+ begin
+ // Indication that this node is the root node.
+ PrevSibling := FRoot;
+ NextSibling := FRoot;
+ Parent := Pointer(Self);
+ States := [vsInitialized, vsExpanded, vsHasChildren, vsVisible];
+ TotalHeight := FDefaultNodeHeight;
+ TotalCount := 1;
+ TotalHeight := FDefaultNodeHeight;
+ NodeHeight := FDefaultNodeHeight;
+ Align := 50;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InterruptValidation;
+
+// Waits until the worker thread has stopped validating the caches of this tree.
+
+begin
+ if tsValidating in FStates then
+ begin
+ DoStateChange([tsStopValidation], [tsUseCache]);
+ // Make a hard break until the worker thread has stopped validation.
+ while (tsValidating in FStates) and (WorkerThread.FCurrentTree = Self) and not Application.Terminated do
+ Sleep(100);
+ DoStateChange([tsValidationNeeded]);
+ end
+ else // Remove any pending validation.
+ WorkerThread.RemoveTree(Self);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IsFirstVisibleChild(Parent, Node: PVirtualNode): Boolean;
+
+// Helper method to check if Node is the same as the first visible child of Parent.
+
+var
+ Run: PVirtualNode;
+
+begin
+ // Find first visible child.
+ Run := Parent.FirstChild;
+ while Assigned(Run) and not (vsVisible in Run.States) do
+ Run := Run.NextSibling;
+
+ Result := Assigned(Run) and (Run = Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IsLastVisibleChild(Parent, Node: PVirtualNode): Boolean;
+
+// Helper method to check if Node is the same as the last visible child of Parent.
+
+var
+ Run: PVirtualNode;
+
+begin
+ // Find last visible child.
+ Run := Parent.LastChild;
+ while Assigned(Run) and not (vsVisible in Run.States) do
+ Run := Run.PrevSibling;
+
+ Result := Assigned(Run) and (Run = Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.LimitPaintingToArea(Canvas: TCanvas; ClipRect: TRect; VisibleRegion: HRGN = 0);
+
+// Limits further painting onto the given canvas to the given rectangle.
+// VisibleRegion is an optional region which can be used to limit drawing further.
+
+var
+ ClipRegion: HRGN;
+
+begin
+ // Regions expect their coordinates in device coordinates, hence we have to transform the region rectangle.
+ LPtoDP(Canvas.Handle, ClipRect, 2);
+ ClipRegion := CreateRectRgnIndirect(ClipRect);
+ if VisibleRegion <> 0 then
+ CombineRgn(ClipRegion, ClipRegion, VisibleRegion, RGN_AND);
+ SelectClipRgn(Canvas.Handle, ClipRegion);
+ DeleteObject(ClipRegion);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.MakeNewNode: PVirtualNode;
+
+var
+ Size: Cardinal;
+
+begin
+ Size := TreeNodeSize;
+ if not (csDesigning in ComponentState) then
+ begin
+ // Make sure FNodeDataSize is valid.
+ if FNodeDataSize = -1 then
+ ValidateNodeDataSize(FNodeDataSize);
+
+ // Take record alignment into account.
+ Inc(Size, FNodeDataSize);
+ end;
+
+ {$ifdef UseLocalMemoryManager}
+ Result := FNodeMemoryManager.AllocNode(Size + FTotalInternalDataSize);
+ {$else}
+ Result := AllocMem(Size + FTotalInternalDataSize);
+ {$endif UseLocalMemoryManager}
+
+ // Fill in some default values.
+ with Result^ do
+ begin
+ TotalCount := 1;
+ TotalHeight := FDefaultNodeHeight;
+ NodeHeight := FDefaultNodeHeight;
+ States := [vsVisible];
+ Align := 50;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.OriginalWMNCPaint(DC: HDC);
+
+// Unfortunately, the painting for the non-client area in TControl is not always correct and does also not consider
+// existing clipping regions, so it has been modified here to take this into account.
+
+const
+ InnerStyles: array[TBevelCut] of Integer = (0, BDR_SUNKENINNER, BDR_RAISEDINNER, 0);
+ OuterStyles: array[TBevelCut] of Integer = (0, BDR_SUNKENOUTER, BDR_RAISEDOUTER, 0);
+ EdgeStyles: array[TBevelKind] of Integer = (0, 0, BF_SOFT, BF_FLAT);
+ Ctl3DStyles: array[Boolean] of Integer = (BF_MONO, 0);
+
+var
+ RC, RW: TRect;
+ EdgeSize: Integer;
+ Styles: Integer;
+
+begin
+ if (BevelKind <> bkNone) or (BorderWidth > 0) then
+ begin
+ RC := Rect(0, 0, Width, Height);
+ Styles := GetWindowLong(Handle, GWL_STYLE);
+ if (Styles and WS_BORDER) <> 0 then
+ InflateRect(RC, -1, -1);
+ if (Styles and WS_THICKFRAME) <> 0 then
+ InflateRect(RC, -3, -3);
+ Styles := GetWindowLong(Handle, GWL_EXSTYLE);
+ if (Styles and WS_EX_CLIENTEDGE) <> 0 then
+ InflateRect(RC, -2, -2);
+
+ RW := RC;
+
+ if BevelKind <> bkNone then
+ begin
+ DrawEdge(DC, RC, InnerStyles[BevelInner] or OuterStyles[BevelOuter], Byte(BevelEdges) or EdgeStyles[BevelKind] or
+ Ctl3DStyles[Ctl3D]);
+
+ EdgeSize := 0;
+ if BevelInner <> bvNone then
+ Inc(EdgeSize, BevelWidth);
+ if BevelOuter <> bvNone then
+ Inc(EdgeSize, BevelWidth);
+ with RC do
+ begin
+ if beLeft in BevelEdges then
+ Inc(Left, EdgeSize);
+ if beTop in BevelEdges then
+ Inc(Top, EdgeSize);
+ if beRight in BevelEdges then
+ Dec(Right, EdgeSize);
+ if beBottom in BevelEdges then
+ Dec(Bottom, EdgeSize);
+ end;
+ end;
+
+ // Repaint only the part in the original clipping region and not yet drawn parts.
+ IntersectClipRect(DC, RC.Left, RC.Top, RC.Right, RC.Bottom);
+
+ // Determine inner rectangle to exclude (RC corresponds then to the client area).
+ InflateRect(RC, -BorderWidth, -BorderWidth);
+
+ // Remove the inner rectangle.
+ ExcludeClipRect(DC, RC.Left, RC.Top, RC.Right, RC.Bottom);
+
+ // Erase parts not drawn.
+ Brush.Color := FColors.BorderColor;
+ Windows.FillRect(DC, RW, Brush.Handle);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.PackArray(TheArray: TNodeArray; Count: Integer): Integer; assembler;
+
+// Removes all entries from the selection array which are no longer in use. The selection array must be sorted for this
+// algo to work. Values which must be removed are marked with bit 0 (LSB) set. This little trick works because memory
+// is always allocated DWORD aligned. Since the selection array must be sorted while determining the entries to be
+// removed it is much more efficient to increment the entry in question instead of setting it to nil (which would break
+// the ordered appearance of the list).
+//
+// On enter EAX contains self reference, EDX the address to TheArray and ECX Count
+// The returned value is the number of remaining entries in the array, so the caller can reallocate (shorten)
+// the selection array if needed or -1 if nothing needs to be changed.
+
+asm
+ PUSH EBX
+ PUSH EDI
+ PUSH ESI
+ MOV ESI, EDX
+ MOV EDX, -1
+ JCXZ @@Finish // Empty list?
+ INC EDX // init remaining entries counter
+ MOV EDI, ESI // source and destination point to the list memory
+ MOV EBX, 1 // use a register instead of immediate operant to check against
+@@PreScan:
+ TEST [ESI], EBX // do the fastest scan possible to find the first entry
+ // which must be removed
+ JNZ @@DoMainLoop
+ INC EDX
+ ADD ESI, 4
+ DEC ECX
+ JNZ @@PreScan
+ JMP @@Finish
+
+@@DoMainLoop:
+ MOV EDI, ESI
+@@MainLoop:
+ TEST [ESI], EBX // odd entry?
+ JNE @@Skip // yes, so skip this one
+ MOVSD // else move the entry to new location
+ INC EDX // count the moved entries
+ DEC ECX
+ JNZ @@MainLoop // do it until all entries are processed
+ JMP @@Finish
+
+@@Skip:
+ ADD ESI, 4 // point to the next entry
+ DEC ECX
+ JNZ @@MainLoop // do it until all entries are processed
+@@Finish:
+ MOV EAX, EDX // prepare return value
+ POP ESI
+ POP EDI
+ POP EBX
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PrepareBitmaps(NeedButtons, NeedLines: Boolean);
+
+// initializes the contents of the internal bitmaps
+
+const
+ LineBitsDotted: array [0..8] of Word = ($55, $AA, $55, $AA, $55, $AA, $55, $AA, $55);
+ LineBitsSolid: array [0..7] of Word = (0, 0, 0, 0, 0, 0, 0, 0);
+
+var
+ PatternBitmap: HBITMAP;
+ Bits: Pointer;
+ {$ifdef ThemeSupport}
+ Details: TThemedElementDetails;
+ {$endif ThemeSupport}
+
+begin
+ if NeedButtons then
+ begin
+ with FMinusBM, Canvas do
+ begin
+ // box is always of odd size
+ Width := 9;
+ Height := Width;
+ Transparent := True;
+ TransparentColor := clFuchsia;
+ Brush.Color := clFuchsia;
+ FillRect(Rect(0, 0, Width, Height));
+ if FButtonStyle = bsTriangle then
+ begin
+ Brush.Color := clBlack;
+ Pen.Color := clBlack;
+ Polygon([Point(0, 2), Point(8, 2), Point(4, 6)]);
+ end
+ else
+ begin
+ // Button style is rectangular. Now ButtonFillMode determines how to fill the interior.
+ if FButtonFillMode in [fmTreeColor, fmWindowColor, fmTransparent] then
+ begin
+ case FButtonFillMode of
+ fmTreeColor:
+ Brush.Color := Self.Color;
+ fmWindowColor:
+ Brush.Color := clWindow;
+ end;
+ Pen.Color := FColors.TreeLineColor;
+ Rectangle(0, 0, Width, Height);
+ Pen.Color := Self.Font.Color;
+ MoveTo(2, Width div 2);
+ LineTo(Width - 2 , Width div 2);
+ end
+ else
+ FMinusBM.Handle := LoadBitmap(HInstance, 'VT_XPBUTTONMINUS');
+ end;
+ end;
+
+ with FPlusBM, Canvas do
+ begin
+ Width := 9;
+ Height := Width;
+ Transparent := True;
+ TransparentColor := clFuchsia;
+ Brush.Color := clFuchsia;
+ FillRect(Rect(0, 0, Width, Height));
+ if FButtonStyle = bsTriangle then
+ begin
+ Brush.Color := clBlack;
+ Pen.Color := clBlack;
+ Polygon([Point(2, 0), Point(6, 4), Point(2, 8)]);
+ end
+ else
+ begin
+ // Button style is rectangular. Now ButtonFillMode determines how to fill the interior.
+ if FButtonFillMode in [fmTreeColor, fmWindowColor, fmTransparent] then
+ begin
+ case FButtonFillMode of
+ fmTreeColor:
+ Brush.Color := Self.Color;
+ fmWindowColor:
+ Brush.Color := clWindow;
+ end;
+
+ Pen.Color := FColors.TreeLineColor;
+ Rectangle(0, 0, Width, Height);
+ Pen.Color := Self.Font.Color;
+ MoveTo(2, Width div 2);
+ LineTo(Width - 2 , Width div 2);
+ MoveTo(Width div 2, 2);
+ LineTo(Width div 2, Width - 2);
+ end
+ else
+ FPlusBM.Handle := LoadBitmap(HInstance, 'VT_XPBUTTONPLUS');
+ end;
+ end;
+
+ {$ifdef ThemeSupport}
+ // Overwrite glyph images if theme is active.
+ if tsUseThemes in FStates then
+ begin
+ Details := ThemeServices.GetElementDetails(ttGlyphClosed);
+ ThemeServices.DrawElement(FPlusBM.Canvas.Handle, Details, Rect(0, 0, 9, 9));
+ Details := ThemeServices.GetElementDetails(ttGlyphOpened);
+ ThemeServices.DrawElement(FMinusBM.Canvas.Handle, Details, Rect(0, 0, 9, 9));
+ end;
+ {$endif ThemeSupport}
+ end;
+
+ if NeedLines then
+ begin
+ if FDottedBrush <> 0 then
+ DeleteObject(FDottedBrush);
+
+ case FLineStyle of
+ lsDotted:
+ Bits := @LineBitsDotted;
+ lsSolid:
+ Bits := @LineBitsSolid;
+ else // lsCustomStyle
+ Bits := @LineBitsDotted;
+ DoGetLineStyle(Bits);
+ end;
+ PatternBitmap := CreateBitmap(8, 8, 1, 1, Bits);
+ FDottedBrush := CreatePatternBrush(PatternBitmap);
+ DeleteObject(PatternBitmap);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PrepareCell(var PaintInfo: TVTPaintInfo);
+
+// This method is called immediately before a cell's content is drawn und is responsible to paint selection colors etc.
+
+var
+ TextColorBackup,
+ BackColorBackup: COLORREF;
+ InnerRect: TRect;
+
+begin
+ with PaintInfo, Canvas do
+ begin
+ InnerRect := ContentRect;
+
+ // Fill cell background if its color differs from tree background.
+ with FHeader.FColumns do
+ if poColumnColor in PaintOptions then
+ begin
+ Brush.Color := Items[Column].Color;
+ FillRect(CellRect);
+ end;
+
+ // Let the application customize the cell background.
+ DoBeforeCellPaint(Canvas, Node, Column, CellRect);
+
+ if (Column = FFocusedColumn) or (toFullRowSelect in FOptions.FSelectionOptions) then
+ begin
+ // The selection rectangle depends on alignment.
+ if not (toGridExtensions in FOptions.FMiscOptions) then
+ begin
+ case Alignment of
+ taLeftJustify:
+ with InnerRect do
+ if Left + NodeWidth < Right then
+ Right := Left + NodeWidth;
+ taCenter:
+ with InnerRect do
+ if (Right - Left) > NodeWidth then
+ begin
+ Left := (Left + Right - NodeWidth) div 2;
+ Right := Left + NodeWidth;
+ end;
+ taRightJustify:
+ with InnerRect do
+ if (Right - Left) > NodeWidth then
+ Left := Right - NodeWidth;
+ end;
+ end;
+
+ // Fill the selection rectangle.
+ if poDrawSelection in PaintOptions then
+ begin
+ if Node = FDropTargetNode then
+ begin
+ if (FLastDropMode = dmOnNode) or (vsSelected in Node.States) then
+ begin
+ Brush.Color := FColors.DropTargetColor;
+ Pen.Color := FColors.DropTargetBorderColor;
+
+ if (toGridExtensions in FOptions.FMiscOptions) or
+ (toFullRowSelect in FOptions.FSelectionOptions) then
+ InnerRect := CellRect;
+ if not IsRectEmpty(InnerRect) then
+ with InnerRect do
+ RoundRect(Left, Top, Right, Bottom, FSelectionCurveRadius, FSelectionCurveRadius);
+ end
+ else
+ begin
+ Brush.Style := bsClear;
+ end;
+ end
+ else
+ if vsSelected in Node.States then
+ begin
+ if Focused or (toPopupMode in FOptions.FPaintOptions) then
+ begin
+ Brush.Color := FColors.FocusedSelectionColor;
+ Pen.Color := FColors.FocusedSelectionBorderColor;
+ end
+ else
+ begin
+ Brush.Color := FColors.UnfocusedSelectionColor;
+ Pen.Color := FColors.UnfocusedSelectionBorderColor;
+ end;
+
+ if (toGridExtensions in FOptions.FMiscOptions) or (toFullRowSelect in FOptions.FSelectionOptions) then
+ InnerRect := CellRect;
+ if not IsRectEmpty(InnerRect) then
+ with InnerRect do
+ RoundRect(Left, Top, Right, Bottom, FSelectionCurveRadius, FSelectionCurveRadius);
+ end;
+ end;
+
+ // draw focus rect
+ if (poDrawFocusRect in PaintOptions) and (Column = FFocusedColumn) and
+ (Focused or (toPopupMode in FOptions.FPaintOptions)) and (FFocusedNode = Node) then
+ begin
+ TextColorBackup := GetTextColor(Handle);
+ SetTextColor(Handle, $FFFFFF);
+ BackColorBackup := GetBkColor(Handle);
+ SetBkColor(Handle, 0);
+
+ if toGridExtensions in FOptions.FMiscOptions then
+ Windows.DrawFocusRect(Handle, CellRect)
+ else
+ Windows.DrawFocusRect(Handle, InnerRect);
+
+ SetTextColor(Handle, TextColorBackup);
+ SetBkColor(Handle, BackColorBackup);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ TOldVTOption = (voAcceptOLEDrop, voAnimatedToggle, voAutoDropExpand, voAutoExpand, voAutoScroll,
+ voAutoSort, voAutoSpanColumns, voAutoTristateTracking, voCheckSupport, voDisableDrawSelection, voEditable,
+ voExtendedFocus, voFullRowSelect, voGridExtensions, voHideFocusRect, voHideSelection, voHotTrack, voInitOnSave,
+ voLevelSelectConstraint, voMiddleClickSelect, voMultiSelect, voRightClickSelect, voPopupMode, voShowBackground,
+ voShowButtons, voShowDropmark, voShowHorzGridLines, voShowRoot, voShowTreeLines, voShowVertGridLines,
+ voSiblingSelectConstraint, voToggleOnDblClick);
+
+const
+ OptionMap: array[TOldVTOption] of Integer = (
+ Ord(toAcceptOLEDrop), Ord(toAnimatedToggle), Ord(toAutoDropExpand), Ord(toAutoExpand), Ord(toAutoScroll),
+ Ord(toAutoSort), Ord(toAutoSpanColumns), Ord(toAutoTristateTracking), Ord(toCheckSupport), Ord(toDisableDrawSelection),
+ Ord(toEditable), Ord(toExtendedFocus), Ord(toFullRowSelect), Ord(toGridExtensions), Ord(toHideFocusRect),
+ Ord(toHideSelection), Ord(toHotTrack), Ord(toInitOnSave), Ord(toLevelSelectConstraint), Ord(toMiddleClickSelect),
+ Ord(toMultiSelect), Ord(toRightClickSelect), Ord(toPopupMode), Ord(toShowBackground),
+ Ord(toShowButtons), Ord(toShowDropmark), Ord(toShowHorzGridLines), Ord(toShowRoot), Ord(toShowTreeLines),
+ Ord(toShowVertGridLines), Ord(toSiblingSelectConstraint), Ord(toToggleOnDblClick)
+ );
+
+procedure TBaseVirtualTree.ReadOldOptions(Reader: TReader);
+
+// Migration helper routine to silently convert forms containing the old tree options member into the new
+// sub-options structure.
+
+var
+ OldOption: TOldVTOption;
+ EnumName: string;
+
+begin
+ // If we are at design time currently then let the designer know we changed something.
+ UpdateDesigner;
+
+ // It should never happen at this place that there is something different than the old set.
+ if Reader.ReadValue = vaSet then
+ begin
+ // Remove all default values set by the constructor.
+ FOptions.AnimationOptions := [];
+ FOptions.AutoOptions := [];
+ FOptions.MiscOptions := [];
+ FOptions.PaintOptions := [];
+ FOptions.SelectionOptions := [];
+
+ while True do
+ begin
+ // Sets are stored with their members as simple strings. Read them one by one and map them to the new option
+ // in the correct sub-option set.
+ EnumName := Reader.ReadStr;
+ if EnumName = '' then
+ Break;
+ OldOption := TOldVTOption(GetEnumValue(TypeInfo(TOldVTOption), EnumName));
+ case OldOption of
+ voAcceptOLEDrop, voCheckSupport, voEditable, voGridExtensions, voInitOnSave, voToggleOnDblClick:
+ FOptions.MiscOptions := FOptions.FMiscOptions + [TVTMiscOption(OptionMap[OldOption])];
+ voAnimatedToggle:
+ FOptions.AnimationOptions := FOptions.FAnimationOptions + [TVTAnimationOption(OptionMap[OldOption])];
+ voAutoDropExpand, voAutoExpand, voAutoScroll, voAutoSort, voAutoSpanColumns, voAutoTristateTracking:
+ FOptions.AutoOptions := FOptions.FAutoOptions + [TVTAutoOption(OptionMap[OldOption])];
+ voDisableDrawSelection, voExtendedFocus, voFullRowSelect, voLevelSelectConstraint,
+ voMiddleClickSelect, voMultiSelect, voRightClickSelect, voSiblingSelectConstraint:
+ FOptions.SelectionOptions := FOptions.FSelectionOptions + [TVTSelectionOption(OptionMap[OldOption])];
+ voHideFocusRect, voHideSelection, voHotTrack, voPopupMode, voShowBackground, voShowButtons,
+ voShowDropmark, voShowHorzGridLines, voShowRoot, voShowTreeLines, voShowVertGridLines:
+ FOptions.PaintOptions := FOptions.FPaintOptions + [TVTPaintOption(OptionMap[OldOption])];
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetAlignment(const Value: TAlignment);
+
+begin
+ if FAlignment <> Value then
+ begin
+ FAlignment := Value;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetAnimationDuration(const Value: Cardinal);
+
+begin
+ FAnimationDuration := Value;
+ if FAnimationDuration = 0 then
+ Exclude(FOptions.FAnimationOptions, toAnimatedToggle)
+ else
+ Include(FOptions.FAnimationOptions, toAnimatedToggle);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetBackground(const Value: TPicture);
+
+begin
+ FBackground.Assign(Value);
+ Invalidate;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetBackgroundOffset(const Index, Value: Integer);
+
+begin
+ case Index of
+ 0:
+ if FBackgroundOffsetX <> Value then
+ begin
+ FBackgroundOffsetX := Value;
+ Invalidate;
+ end;
+ 1:
+ if FBackgroundOffsetY <> Value then
+ begin
+ FBackgroundOffsetY := Value;
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetBorderStyle(Value: TBorderStyle);
+
+begin
+ if FBorderStyle <> Value then
+ begin
+ FBorderStyle := Value;
+ RecreateWnd;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetButtonFillMode(const Value: TVTButtonFillMode);
+
+begin
+ if FButtonFillMode <> Value then
+ begin
+ FButtonFillMode := Value;
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(True, False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetButtonStyle(const Value: TVTButtonStyle);
+
+begin
+ if FButtonStyle <> Value then
+ begin
+ FButtonStyle := Value;
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(True, False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetCheckImageKind(Value: TCheckImageKind);
+
+begin
+ if FCheckImageKind <> Value then
+ begin
+ FCheckImageKind := Value;
+ case Value of
+ ckDarkCheck:
+ FCheckImages := DarkCheckImages;
+ ckLightTick:
+ FCheckImages := LightTickImages;
+ ckDarkTick:
+ FCheckImages := DarkTickImages;
+ ckLightCheck:
+ FCheckImages := LightCheckImages;
+ ckFlat:
+ FCheckImages := FlatImages;
+ ckXP:
+ FCheckImages := XPImages;
+ ckSystem:
+ FCheckImages := SystemCheckImages;
+ ckSystemFlat:
+ FCheckImages := SystemFlatCheckImages;
+ else
+ FCheckImages := FCustomCheckImages;
+ end;
+ if HandleAllocated and (FUpdateCount = 0) and not (csLoading in ComponentState) then
+ InvalidateRect(Handle, nil, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetCheckState(Node: PVirtualNode; Value: TCheckState);
+
+begin
+ if (Node.CheckState <> Value) and not (vsDisabled in Node.States) and DoChecking(Node, Value) then
+ DoCheckClick(Node, Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetCheckType(Node: PVirtualNode; Value: TCheckType);
+
+begin
+ if (Node.CheckType <> Value) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Node.CheckType := Value;
+ Node.CheckState := csUncheckedNormal;
+ // For check boxes with tri-state check box parents we have to initialize differently.
+ if (toAutoTriStateTracking in FOptions.FAutoOptions) and (Value in [ctCheckBox, ctTriStateCheckBox]) and
+ (Node.Parent <> FRoot) then
+ begin
+ if not (vsInitialized in Node.Parent.States) then
+ InitNode(Node.Parent);
+ if (Node.Parent.CheckType = ctTriStateCheckBox) and
+ (Node.Parent.CheckState in [csUncheckedNormal, csCheckedNormal]) then
+ CheckState[Node] := Node.Parent.CheckState;
+ end;
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetChildCount(Node: PVirtualNode; NewChildCount: Cardinal);
+
+// Changes a node's child structure to accomodate the new child count. This is used to add or delete
+// child nodes to/from the end of the node's child list. To insert or delete a specific node a separate
+// routine is used.
+
+var
+ Count: Integer;
+ Index: Cardinal;
+ Child: PVirtualNode;
+ C: Integer;
+ NewHeight: Integer;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ if Node = nil then
+ Node := FRoot;
+
+ if NewChildCount = 0 then
+ DeleteChildren(Node)
+ else
+ begin
+ Count := Integer(NewChildCount) - Integer(Node.ChildCount);
+
+ // If nothing changed then do nothing.
+ if Count <> 0 then
+ begin
+ InterruptValidation;
+
+ C := Count;
+ NewHeight := 0;
+
+ if Count > 0 then
+ begin
+ // New nodes to add.
+ if Assigned(Node.LastChild) then
+ Index := Node.LastChild.Index + 1
+ else
+ begin
+ Index := 0;
+ Include(Node.States, vsHasChildren);
+ end;
+
+ // New nodes are by default always visible, so we don't need to check the visibility.
+ while Count > 0 do
+ begin
+ Child := MakeNewNode;
+ Child.Index := Index;
+ Child.PrevSibling := Node.LastChild;
+ if Assigned(Node.LastChild) then
+ Node.LastChild.NextSibling := Child;
+ Child.Parent := Node;
+ Node.LastChild := Child;
+ if Node.FirstChild = nil then
+ Node.FirstChild := Child;
+ Dec(Count);
+ Inc(Index);
+ Inc(NewHeight, Child.NodeHeight);
+ end;
+
+ if vsExpanded in Node.States then
+ begin
+ AdjustTotalHeight(Node, NewHeight, True);
+ if FullyVisible[Node] then
+ Inc(Integer(FVisibleCount), C);
+ end;
+
+ AdjustTotalCount(Node, C, True);
+ Node.ChildCount := NewChildCount;
+ if (FUpdateCount = 0) and (toAutoSort in FOptions.FAutoOptions) and (FHeader.FSortColumn > InvalidColumn) then
+ Sort(Node, FHeader.FSortColumn, FHeader.FSortDirection, True);
+
+ InvalidateCache;
+ end
+ else
+ begin
+ // Nodes have to be deleted.
+ while Count < 0 do
+ begin
+ DeleteNode(Node.LastChild);
+ Inc(Count);
+ end;
+ end;
+
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ Invalidate;
+ end;
+
+ if Node = FRoot then
+ StructureChange(nil, crChildAdded)
+ else
+ StructureChange(Node, crChildAdded);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetClipboardFormats(const Value: TClipboardFormats);
+
+var
+ I: Integer;
+
+begin
+ // Add string by string instead doing an Assign or AddStrings because the list may return -1 for
+ // invalid entries which cause trouble for the standard implementation.
+ FClipboardFormats.Clear;
+ for I := 0 to Value.Count - 1 do
+ FClipboardFormats.Add(Value[I]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetColors(const Value: TVTColors);
+
+begin
+ FColors.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetCustomCheckImages(const Value: TCustomImageList);
+
+begin
+ if FCustomCheckImages <> Value then
+ begin
+ if Assigned(FCustomCheckImages) then
+ begin
+ FCustomCheckImages.UnRegisterChanges(FCustomCheckChangeLink);
+ {$ifdef COMPILER_5_UP}
+ FCustomCheckImages.RemoveFreeNotification(Self);
+ {$endif COMPILER_5_UP}
+ // Reset the internal check image list reference too, if necessary.
+ if FCheckImages = FCustomCheckImages then
+ FCheckImages := nil;
+ end;
+ FCustomCheckImages := Value;
+ if Assigned(FCustomCheckImages) then
+ begin
+ FCustomCheckImages.RegisterChanges(FCustomCheckChangeLink);
+ FCustomCheckImages.FreeNotification(Self);
+ end;
+ // Check if currently custom check images are active.
+ if FCheckImageKind = ckCustom then
+ FCheckImages := Value;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetDefaultNodeHeight(Value: Cardinal);
+
+begin
+ if Value = 0 then
+ Value := 18;
+ if FDefaultNodeHeight <> Value then
+ begin
+ DoStateChange([tsNeedScale]);
+ Inc(Integer(FRoot.TotalHeight), Integer(Value) - Integer(FDefaultNodeHeight));
+ Inc(SmallInt(FRoot.NodeHeight), Integer(Value) - Integer(FDefaultNodeHeight));
+ FDefaultNodeHeight := Value;
+ InvalidateCache;
+ if (FUpdateCount = 0) and HandleAllocated and not (csLoading in ComponentState) then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions, True);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetDisabled(Node: PVirtualNode; Value: Boolean);
+
+begin
+ if Assigned(Node) and (Value xor (vsDisabled in Node.States)) then
+ begin
+ if Value then
+ Include(Node.States, vsDisabled)
+ else
+ Exclude(Node.States, vsDisabled);
+
+ if FUpdateCount = 0 then
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetExpanded(Node: PVirtualNode; Value: Boolean);
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and (Value xor (vsExpanded in Node.States)) then
+ ToggleNode(Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetFocusedColumn(Value: TColumnIndex);
+
+begin
+ if (FFocusedColumn <> Value) and
+ DoFocusChanging(FFocusedNode, FFocusedNode, FFocusedColumn, Value) then
+ begin
+ CancelEditNode;
+ FFocusedColumn := Value;
+ if Assigned(FFocusedNode) then
+ begin
+ ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions,
+ not (toDisableAutoscrollOnFocus in FOptions.FAutoOptions));
+ InvalidateNode(FFocusedNode);
+ end;
+
+ DoFocusChange(FFocusedNode, FFocusedColumn);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetFocusedNode(Value: PVirtualNode);
+
+var
+ WasDifferent: Boolean;
+
+begin
+ WasDifferent := Value <> FFocusedNode;
+ DoFocusNode(Value, True);
+ // Do change event only if there was actually a change.
+ if WasDifferent and (FFocusedNode = Value) then
+ DoFocusChange(FFocusedNode, FFocusedColumn);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetFullyVisible(Node: PVirtualNode; Value: Boolean);
+
+// This method ensures that a node is visible and all its parent nodes are expanded and also visible
+// if Value is True. Otherwise the visibility flag of the node is reset but the expand state
+// of the parent nodes stays untouched.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter');
+
+ IsVisible[Node] := Value;
+ if Value then
+ begin
+ repeat
+ Node := Node.Parent;
+ if Node = FRoot then
+ Break;
+ if not (vsExpanded in Node.States) then
+ ToggleNode(Node);
+ if not (vsVisible in Node.States) then
+ IsVisible[Node] := True;
+ until False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetHasChildren(Node: PVirtualNode; Value: Boolean);
+
+begin
+ if Assigned(Node) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ if Value then
+ Include(Node.States, vsHasChildren)
+ else
+ begin
+ Exclude(Node.States, vsHasChildren);
+ DeleteChildren(Node);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetHeader(const Value: TVTHeader);
+
+begin
+ FHeader.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetImages(const Value: TCustomImageList);
+
+begin
+ if FImages <> Value then
+ begin
+ if Assigned(FImages) then
+ begin
+ FImages.UnRegisterChanges(FImageChangeLink);
+ {$ifdef COMPILER_5_UP}
+ FImages.RemoveFreeNotification(Self);
+ {$endif COMPILER_5_UP}
+ end;
+ FImages := Value;
+ if Assigned(FImages) then
+ begin
+ FImages.RegisterChanges(FImageChangeLink);
+ FImages.FreeNotification(Self);
+ end;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetIndent(Value: Cardinal);
+
+begin
+ if FIndent <> Value then
+ begin
+ FIndent := Value;
+ if not (csLoading in ComponentState) and (FUpdateCount = 0) and HandleAllocated then
+ begin
+ UpdateScrollBars(True);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetLineMode(const Value: TVTLineMode);
+
+begin
+ if FLineMode <> Value then
+ begin
+ FLineMode := Value;
+ if HandleAllocated and not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetLineStyle(const Value: TVTLineStyle);
+
+begin
+ if FLineStyle <> Value then
+ begin
+ FLineStyle := Value;
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(False, True);
+ if HandleAllocated then
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetMargin(Value: Integer);
+
+begin
+ if FMargin <> Value then
+ begin
+ FMargin := Value;
+ if HandleAllocated and not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetMultiline(Node: PVirtualNode; const Value: Boolean);
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ if Value <> (vsMultiline in Node.States) then
+ begin
+ if Value then
+ Include(Node.States, vsMultiline)
+ else
+ Exclude(Node.States, vsMultiline);
+
+ if FUpdateCount = 0 then
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetNodeAlignment(const Value: TVTNodeAlignment);
+
+begin
+ if FNodeAlignment <> Value then
+ begin
+ FNodeAlignment := Value;
+ if HandleAllocated and not (csReading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetNodeDataSize(Value: Integer);
+
+var
+ LastRootCount: Cardinal;
+
+begin
+ if Value < -1 then
+ Value := -1;
+ if FNodeDataSize <> Value then
+ begin
+ FNodeDataSize := Value;
+ if not (csLoading in ComponentState) and not (csDesigning in ComponentState) then
+ begin
+ LastRootCount := FRoot.ChildCount;
+ Clear;
+ SetRootNodeCount(LastRootCount);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetNodeHeight(Node: PVirtualNode; Value: Cardinal);
+
+var
+ Difference: Integer;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and (Node.NodeHeight <> Value) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Difference := Integer(Value) - Integer(Node.NodeHeight);
+ Node.NodeHeight := Value;
+ AdjustTotalHeight(Node, Difference, True);
+ if FullyVisible[Node] then
+ begin
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ InvalidateToBottom(Node);
+ UpdateScrollBars(True);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetNodeParent(Node: PVirtualNode; const Value: PVirtualNode);
+
+begin
+ if Assigned(Node) and Assigned(Value) and (Node.Parent <> Value) then
+ MoveTo(Node, Value, amAddChildLast, False);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetOffsetX(const Value: Integer);
+
+begin
+ DoSetOffsetXY(Point(Value, FOffsetY), DefaultScrollUpdateFlags);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetOffsetXY(const Value: TPoint);
+
+begin
+ DoSetOffsetXY(Value, DefaultScrollUpdateFlags);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetOffsetY(const Value: Integer);
+
+begin
+ DoSetOffsetXY(Point(FOffsetX, Value), DefaultScrollUpdateFlags);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetOptions(const Value: TCustomVirtualTreeOptions);
+
+begin
+ FOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetRootNodeCount(Value: Cardinal);
+
+begin
+ // Don't set the root node count until all other properties (in particular the OnInitNode event) have been set.
+ if csLoading in ComponentState then
+ begin
+ FRoot.ChildCount := Value;
+ DoStateChange([tsNeedRootCountUpdate]);
+ end
+ else
+ if FRoot.ChildCount <> Value then
+ begin
+ BeginUpdate;
+ InterruptValidation;
+ SetChildCount(FRoot, Value);
+ EndUpdate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetScrollBarOptions(Value: TScrollBarOptions);
+
+begin
+ FScrollBarOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetSearchOption(const Value: TVTIncrementalSearch);
+
+begin
+ if FIncrementalSearch <> Value then
+ begin
+ FIncrementalSearch := Value;
+ if FIncrementalSearch = isNone then
+ begin
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetSelected(Node: PVirtualNode; Value: Boolean);
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and (Value xor (vsSelected in Node.States)) then
+ begin
+ if Value then
+ begin
+ if FSelectionCount = 0 then
+ FRangeAnchor := Node
+ else
+ if not (toMultiSelect in FOptions.FSelectionOptions) then
+ ClearSelection;
+
+ AddToSelection(Node);
+
+ // Make sure there is a valid column selected (if there are columns at all).
+ if ((FFocusedColumn < 0) or not (coVisible in FHeader.Columns[FFocusedColumn].Options)) and
+ (FHeader.MainColumn > NoColumn) then
+ if coVisible in FHeader.Columns[FHeader.MainColumn].Options then
+ FFocusedColumn := FHeader.MainColumn
+ else
+ FFocusedColumn := FHeader.Columns.GetFirstVisibleColumn;
+ if FRangeAnchor = nil then
+ FRangeAnchor := Node;
+ end
+ else
+ begin
+ RemoveFromSelection(Node);
+ if FSelectionCount = 0 then
+ ResetRangeAnchor;
+ end;
+ if FullyVisible[Node] then
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetSelectionCurveRadius(const Value: Cardinal);
+
+begin
+ if FSelectionCurveRadius <> Value then
+ begin
+ FSelectionCurveRadius := Value;
+ if HandleAllocated and not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetStateImages(const Value: TCustomImageList);
+
+begin
+ if FStateImages <> Value then
+ begin
+ if Assigned(FStateImages) then
+ begin
+ FStateImages.UnRegisterChanges(FStateChangeLink);
+ {$ifdef COMPILER_5_UP}
+ FStateImages.RemoveFreeNotification(Self);
+ {$endif COMPILER_5_UP}
+ end;
+ FStateImages := Value;
+ if Assigned(FStateImages) then
+ begin
+ FStateImages.RegisterChanges(FStateChangeLink);
+ FStateImages.FreeNotification(Self);
+ end;
+ if HandleAllocated and not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetTextMargin(Value: Integer);
+
+begin
+ if FTextMargin <> Value then
+ begin
+ FTextMargin := Value;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetTopNode(Node: PVirtualNode);
+
+var
+ R: TRect;
+ Run: PVirtualNode;
+
+begin
+ if Assigned(Node) then
+ begin
+ // make sure all parents of the node are expanded
+ Run := Node.Parent;
+ while Run <> FRoot do
+ begin
+ if not (vsExpanded in Run.States) then
+ ToggleNode(Run);
+ Run := Run.Parent;
+ end;
+ R := GetDisplayRect(Node, FHeader.MainColumn, True);
+ SetOffsetY(FOffsetY - R.Top);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetUpdateState(Updating: Boolean);
+
+begin
+ // The check for visibility is necessary otherwise the tree is automatically shown when
+ // updating is allowed. As this happens internally the VCL does not get notified and
+ // still assumes the control is hidden. This results in weird "cannot focus invisble control" errors.
+ if Visible and HandleAllocated then
+ SendMessage(Handle, WM_SETREDRAW, Ord(not Updating), 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetVerticalAlignment(Node: PVirtualNode; Value: Byte);
+
+begin
+ if Value > 100 then
+ Value := 100;
+ if Node.Align <> Value then
+ begin
+ Node.Align := Value;
+ if FullyVisible[Node] and (FUpdateCount = 0) then
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetVisible(Node: PVirtualNode; Value: Boolean);
+
+// Sets the visibility style of the given node according to Value.
+
+var
+ NeedUpdate: Boolean;
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ if Value <> (vsVisible in Node.States) then
+ begin
+ InterruptValidation;
+ NeedUpdate := False;
+ if Value then
+ begin
+ Include(Node.States, vsVisible);
+ if vsExpanded in Node.Parent.States then
+ AdjustTotalHeight(Node.Parent, Node.TotalHeight, True);
+ if VisiblePath[Node] then
+ begin
+ Inc(FVisibleCount, 1 + CountVisibleChildren(Node));
+ NeedUpdate := True;
+ end;
+
+ // Update the hidden children flag of the parent.
+ // Since this node is now visible we simply have to remove the flag.
+ Exclude(Node.Parent.States, vsAllChildrenHidden);
+ end
+ else
+ begin
+ Exclude(Node.States, vsVisible);
+ if vsExpanded in Node.Parent.States then
+ AdjustTotalHeight(Node.Parent, -Integer(Node.TotalHeight), True);
+ if VisiblePath[Node] then
+ begin
+ Dec(FVisibleCount, 1 + CountVisibleChildren(Node));
+ NeedUpdate := True;
+ end;
+
+ if FUpdateCount = 0 then
+ DetermineHiddenChildrenFlag(Node.Parent)
+ else
+ Include(FStates, tsUpdateHiddenChildrenNeeded)
+ end;
+
+ InvalidateCache;
+ if NeedUpdate and (FUpdateCount = 0) then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetVisiblePath(Node: PVirtualNode; Value: Boolean);
+
+// If Value is True then all parent nodes of Node are expanded.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ if Value then
+ begin
+ repeat
+ Node := Node.Parent;
+ if Node = FRoot then
+ Break;
+ if not (vsExpanded in Node.States) then
+ ToggleNode(Node);
+ until False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.StopTimer(ID: Integer);
+
+begin
+ if HandleAllocated then
+ KillTimer(Handle, ID);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.TileBackground(Source: TBitmap; Target: TCanvas; Offset: TPoint; R: TRect);
+
+// Draws the given source graphic so that it tiles into the given rectangle which is relative to the target bitmap.
+// The graphic is aligned so that it always starts at the upper left corner of the target canvas.
+// Offset gives the position of the target window in an possible superordinated surface.
+
+var
+ SourceX,
+ SourceY,
+ TargetX,
+
+ DeltaY: Integer;
+
+begin
+ with Target do
+ begin
+ SourceY := (R.Top + Offset.Y + FBackgroundOffsetY) mod Source.Height;
+ // Always wrap the source coordinates into positive range.
+ if SourceY < 0 then
+ SourceY := Source.Height + SourceY;
+
+ // Tile image vertically until target rect is filled.
+ while R.Top < R.Bottom do
+ begin
+ SourceX := (R.Left + Offset.X + FBackgroundOffsetX) mod Source.Width;
+ // always wrap the source coordinates into positive range
+ if SourceX < 0 then
+ SourceX := Source.Width + SourceX;
+
+ TargetX := R.Left;
+ // height of strip to draw
+ DeltaY := Min(R.Bottom - R.Top, Source.Height - SourceY);
+
+ // tile the image horizontally
+ while TargetX < R.Right do
+ begin
+ BitBlt(Handle, TargetX, R.Top, Min(R.Right - TargetX, Source.Width - SourceX), DeltaY,
+ Source.Canvas.Handle, SourceX, SourceY, SRCCOPY);
+ Inc(TargetX, Source.Width - SourceX);
+ SourceX := 0;
+ end;
+ Inc(R.Top, Source.Height - SourceY);
+ SourceY := 0;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ToggleCallback(Step, StepSize: Integer; Data: Pointer): Boolean;
+
+var
+ ScrollRect: TRect;
+ Column: TColumnIndex;
+ Run: TRect;
+
+ //--------------- local function --------------------------------------------
+
+ procedure EraseLine;
+
+ var
+ LocalBrush: HBRUSH;
+
+ begin
+ with TToggleAnimationData(Data^), FHeader.FColumns do
+ begin
+ // Iterate through all columns and erase background in their local color.
+ // LocalBrush is a brush in the color of the particular column.
+ Column := ColumnFromPosition(Run.TopLeft);
+ while (Column > InvalidColumn) and (Run.Left < ClientWidth) do
+ begin
+ GetColumnBounds(Column, Run.Left, Run.Right);
+ if coParentColor in Items[Column].FOptions then
+ FillRect(DC, Run, Brush)
+ else
+ begin
+ LocalBrush := CreateSolidBrush(ColorToRGB(Items[Column].Color));
+ FillRect(DC, Run, LocalBrush);
+ DeleteObject(LocalBrush);
+ end;
+ Column := GetNextVisibleColumn(Column);
+ end;
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+begin
+ Result := True;
+ if StepSize > 0 then
+ begin
+ with TToggleAnimationData(Data^) do
+ begin
+ ScrollRect := R;
+ if Expand then
+ begin
+ ScrollDC(DC, 0, StepSize, ScrollRect, ScrollRect, 0, nil);
+
+ // In the first step the background must be cleared (only a small stripe) to avoid artefacts.
+ if Step = 0 then
+ if not FHeader.UseColumns then
+ FillRect(DC, Rect(R.Left, R.Top, R.Right, R.Top + StepSize + 1), Brush)
+ else
+ begin
+ Run := Rect(R.Left, R.Top, R.Right, R.Top + StepSize + 1);
+ EraseLine;
+ end;
+ end
+ else
+ begin
+ // Collapse branch.
+ ScrollDC(DC, 0, -StepSize, ScrollRect, ScrollRect, 0, nil);
+
+ if Step = 0 then
+ if not FHeader.UseColumns then
+ FillRect(DC, Rect(R.Left, R.Bottom - StepSize - 1, R.Right, R.Bottom), Brush)
+ else
+ begin
+ Run := Rect(R.Left, R.Bottom - StepSize - 1, R.Right, R.Bottom);
+ EraseLine;
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMColorChange(var Message: TMessage);
+
+begin
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(True, False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMCtl3DChanged(var Message: TMessage);
+
+begin
+ inherited;
+ if FBorderStyle = bsSingle then
+ RecreateWnd;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMDenySubclassing(var Message: TMessage);
+
+// If a Windows XP Theme Manager component is used in the application it will try to subclass all controls which do not
+// explicitly deny this. Virtual Treeview knows how to handle XP themes so it does not need subclassing.
+
+begin
+ Message.Result := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMDrag(var Message: TCMDrag);
+
+var
+ S: TObject;
+ ShiftState: Integer;
+ P: TPoint;
+ Formats: TFormatArray;
+
+begin
+ with Message, DragRec^ do
+ begin
+ S := Source;
+ Formats := nil;
+
+ // Let the ancestor handle dock operations.
+ if S is TDragDockObject then
+ inherited
+ else
+ begin
+ // We need an extra check for the control drag object as there might be other objects not derived from
+ // this class (e.g. TActionDragObject).
+ if not (tsUserDragObject in FStates) and (S is TBaseDragControlObject) then
+ S := (S as TBaseDragControlObject).Control;
+ case DragMessage of
+ dmDragEnter, dmDragLeave, dmDragMove:
+ begin
+ if DragMessage = dmDragEnter then
+ DoStateChange([tsVCLDragging]);
+ if DragMessage = dmDragLeave then
+ DoStateChange([], [tsVCLDragging]);
+
+ if DragMessage = dmDragMove then
+ with ScreenToClient(Pos) do
+ DoAutoScroll(X, Y);
+
+ ShiftState := 0;
+ // Alt key will be queried by the KeysToShiftState function in DragOver.
+ if GetKeyState(VK_SHIFT) < 0 then
+ ShiftState := ShiftState or MK_SHIFT;
+ if GetKeyState(VK_CONTROL) < 0 then
+ ShiftState := ShiftState or MK_CONTROL;
+
+ // Allowed drop effects are simulated for VCL dd.
+ Result := DROPEFFECT_MOVE or DROPEFFECT_COPY;
+ DragOver(S, ShiftState, TDragState(DragMessage), Pos, Result);
+ FLastVCLDragTarget := FDropTargetNode;
+ FVCLDragEffect := Result;
+ if (DragMessage = dmDragLeave) and Assigned(FDropTargetNode) then
+ begin
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := nil;
+ end;
+ end;
+ dmDragDrop:
+ begin
+ ShiftState := 0;
+ // Alt key will be queried by the KeysToShiftState function in DragOver
+ if GetKeyState(VK_SHIFT) < 0 then
+ ShiftState := ShiftState or MK_SHIFT;
+ if GetKeyState(VK_CONTROL) < 0 then
+ ShiftState := ShiftState or MK_CONTROL;
+
+ // allowed drop effects are simulated for VCL dd,
+ // replace target node with cached node from other VCL dd messages
+ if Assigned(FDropTargetNode) then
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := FLastVCLDragTarget;
+ P := Point(Pos.X, Pos.Y);
+ P := ScreenToClient(P);
+ DoDragDrop(S, nil, Formats, KeysToShiftState(ShiftState), P, FVCLDragEffect, FLastDropMode);
+ if Assigned(FDropTargetNode) then
+ begin
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := nil;
+ end;
+ end;
+ dmFindTarget:
+ begin
+ Result := Integer(ControlAtPos(ScreenToClient(Pos), False));
+ if Result = 0 then
+ Result := Integer(Self);
+
+ // This is a reliable place to check whether VCL drag has
+ // really begun.
+ if tsVCLDragPending in FStates then
+ DoStateChange([tsVCLDragging], [tsVCLDragPending, tsEditPending, tsClearPending]);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMEnabledChanged(var Message: TMessage);
+
+begin
+ inherited;
+
+ // Need to invalidate the non-client area as well, since the header must be redrawn too.
+ if csDesigning in ComponentState then
+ RedrawWindow(Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMFontChanged(var Message: TMessage);
+
+begin
+ inherited;
+
+ if not (csLoading in ComponentState) then
+ begin
+ PrepareBitmaps(True, False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMHintShow(var Message: TCMHintShow);
+
+// Determines hint message (tooltip) and out-of-hint rect.
+// Note: A special handling is needed here because we cannot pass wide strings back to the caller.
+// I had to introduce the hint data record anyway so we can use this to pass the hint string.
+// We still need to set a dummy hint string in the message to make the VCL showing the hint window.
+
+var
+ NodeRect: TRect;
+ SpanColumn,
+ Dummy,
+ ColLeft,
+ ColRight: Integer;
+ HitInfo: THitInfo;
+ ShowOwnHint: Boolean;
+ IsFocusedOrEditing: Boolean;
+ ParentForm: TCustomForm;
+
+begin
+ with Message do
+ begin
+ Result := 1;
+
+ if PtInRect(FLastHintRect, HintInfo.CursorPos) then
+ Exit;
+ // Determine node for which to show hint/tooltip.
+ with HintInfo^ do
+ GetHitTestInfoAt(CursorPos.X, CursorPos.Y, True, HitInfo);
+
+ // Make sure a hint is only shown if the tree or at least its parent form is active.
+ // Active editing is ok too as long as we don't want the hint for the current edit node.
+ if IsEditing then
+ IsFocusedOrEditing := HitInfo.HitNode <> FFocusedNode
+ else
+ begin
+ IsFocusedOrEditing := Focused;
+ ParentForm := GetParentForm(Self);
+ if Assigned(ParentForm) then
+ IsFocusedOrEditing := ParentForm.Focused or Application.Active;
+ end;
+
+ if (GetCapture = 0) and ShowHint and not (Dragging or IsMouseSelecting) and ([tsScrolling] * FStates = []) and
+ (FHeader.States = []) and IsFocusedOrEditing then
+ begin
+ with HintInfo^ do
+ begin
+ Result := 0;
+ ShowOwnHint := False;
+ // Assign a dummy string otherwise the VCL will not show the hint window.
+ HintStr := ' ';
+
+ // First check whether there is a header hint to show.
+ if FHeader.UseColumns and (hoShowHint in FHeader.FOptions) and FHeader.InHeader(CursorPos) then
+ begin
+ CursorRect := FHeaderRect;
+ // Convert the cursor rectangle into real client coordinates.
+ OffsetRect(CursorRect, 0, -Integer(FHeader.FHeight));
+ HitInfo.HitColumn := FHeader.FColumns.GetColumnAndBounds(CursorPos, CursorRect.Left, CursorRect.Right);
+ // align the vertical hint position on the bottom bound of the header, but
+ // avoid overlapping of mouse cursor and hint
+ HintPos.Y := Max(HintPos.Y, ClientToScreen(Point(0, CursorRect.Bottom)).Y);
+ // Note: the test for the left mouse button in ControlState might cause problems whenever the VCL does not
+ // realize when the button is released. This, for instance, happens when doing OLE drag'n drop and
+ // cancel this with ESC.
+ if (HitInfo.HitColumn > -1) and not (csLButtonDown in ControlState) then
+ begin
+ FHintData.DefaultHint := FHeader.FColumns[HitInfo.HitColumn].FHint;
+ if FHintData.DefaultHint <> '' then
+ ShowOwnHint := True
+ else
+ Result := 1;
+ end
+ else
+ Result := 1;
+ end
+ else
+ begin
+ // Default mode is handled as would the tree be a usual VCL control (no own hint window necessary).
+ if FHintMode = hmDefault then
+ HintStr := GetShortHint(Hint)
+ else
+ begin
+ if Assigned(HitInfo.HitNode) and (HitInfo.HitColumn > InvalidColumn) then
+ begin
+ // A draw tree should only display a hint when at least its OnGetHintSize
+ // event handler is assigned.
+ if Self is TCustomVirtualDrawTree then
+ begin
+ FHintData.HintRect := Rect(0, 0, 0, 0);
+ with Self as TCustomVirtualDrawTree do
+ DoGetHintSize(HitInfo.HitNode, HitInfo.HitColumn, FHintData.HintRect);
+ ShowOwnHint := not IsRectEmpty(FHintData.HintRect);
+ end
+ else
+ // For string trees a decision about showing the hint or not is based
+ // on the hint string (if it is empty then no hint is shown).
+ ShowOwnHint := True;
+
+ if ShowOwnHint then
+ begin
+ if HitInfo.HitColumn > NoColumn then
+ begin
+ FHeader.FColumns.GetColumnBounds(HitInfo.HitColumn, ColLeft, ColRight);
+ // The right column border might be extended if column spanning is enabled.
+ if toAutoSpanColumns in FOptions.FAutoOptions then
+ begin
+ SpanColumn := HitInfo.HitColumn;
+ repeat
+ Dummy := FHeader.FColumns.GetNextVisibleColumn(SpanColumn);
+ if (Dummy = InvalidColumn) or not ColumnIsEmpty(HitInfo.HitNode, Dummy) then
+ Break;
+ SpanColumn := Dummy;
+ until False;
+ if SpanColumn <> HitInfo.HitColumn then
+ FHeader.FColumns.GetColumnBounds(SpanColumn, Dummy, ColRight);
+ end;
+ end
+ else
+ begin
+ ColLeft := 0;
+ ColRight := ClientWidth;
+ end;
+
+ FHintData.DefaultHint := '';
+ if FHintMode <> hmTooltip then
+ begin
+ // Node specific hint text.
+ CursorRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, False);
+ // Align the vertical hint position on the bottom bound of the node, but
+ // avoid overlapping of mouse cursor and hint.
+ HintPos.Y := Max(HintPos.Y, ClientToScreen(CursorRect.BottomRight).Y) + 2;
+ end
+ else
+ begin
+ // Tool tip to show. This means the full caption of the node must be displayed.
+ if vsMultiline in HitInfo.HitNode.States then
+ begin
+ ShowOwnHint := True;
+ NodeRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, True, False);
+ end
+ else
+ begin
+ NodeRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, True, True);
+ ShowOwnHint := (HitInfo.HitColumn > InvalidColumn) and PtInRect(NodeRect, CursorPos) and
+ (CursorPos.X <= ColRight) and (CursorPos.X >= ColLeft) and
+ ((NodeRect.Right > Min(ColRight, ClientWidth)) or (NodeRect.Left < Max(ColLeft, 0)));
+ end;
+
+ if ShowOwnHint then
+ begin
+ // Node specific hint text given will be retrieved when needed.
+ FHintData.DefaultHint := '';
+ HintPos := ClientToScreen(Point(NodeRect.Left, NodeRect.Top));
+ CursorRect := NodeRect;
+ end
+ else
+ // nothing to show
+ Result := 1;
+ end;
+ end
+ else
+ Result := 1; // Avoid hint if this is a draw tree returning an empty hint rectangle.
+ end
+ else
+ begin
+ // No node so fall back to control's hint (if indicated) or show nothing.
+ if FHintMode = hmHintAndDefault then
+ begin
+ FHintData.DefaultHint := GetShortHint(Hint);
+ if Length(FHintData.DefaultHint) = 0 then
+ Result := 1
+ else
+ ShowOwnHint := True;
+ end
+ else
+ Result := 1;
+ end;
+ end;
+ end;
+
+ // Set our own hint window class and prepare structure to be passed to the hint window.
+ if ShowOwnHint and (Result = 0) then
+ begin
+ HintWindowClass := TVirtualTreeHintWindow;
+
+ FHintData.Tree := Self;
+ FHintData.Column := HitInfo.HitColumn;
+ FHintData.Node := HitInfo.HitNode;
+ FLastHintRect := CursorRect;
+ HintData := @FHintData;
+ end
+ else
+ FLastHintRect := Rect(0, 0, 0, 0);
+ end;
+
+ // Remind that a hint is about to show.
+ if Result = 0 then
+ DoStateChange([tsHint])
+ else
+ DoStateChange([], [tsHint]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMHintShowPause(var Message: TCMHintShowPause);
+
+// Tells the application that the tree (and only the tree) does not want a delayed tool tip.
+// Normal hints / header hints use the default delay (except the first time).
+
+var
+ P: TPoint;
+
+begin
+ // A little workaround is needed here to make the application class using the correct hint window class.
+ // Once the application gets ShowHint set to true (which is the case when we want to show hints in the tree) then
+ // an internal hint window will be created which is not our own class (because we don't set an application wide
+ // hint window class but only one for the tree). Unfortunately, this default hint window class will prevent
+ // hints for the non-client area to show up (e.g. for the header) by calling CancelHint whenever certain messages
+ // arrive. By setting the hint show pause to 0 if our hint class was not used recently we make sure
+ // that the hint timer (in Forms.pas) is not used and our class is created immediately.
+ if HintWindowDestroyed then
+ begin
+ GetCursorPos(P);
+ // Check if the mouse is in the header or tool tips are enabled, which must be shown without delay anyway.
+ if FHeader.UseColumns and (hoShowHint in FHeader.FOptions) and FHeader.InHeader(ScreenToClient(P)) or
+ (FHintMode = hmToolTip) then
+ Message.Pause^ := 0
+ end
+ else
+ if (FHintMode = hmToolTip) then
+ Message.Pause^ := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMMouseLeave(var Message: TMessage);
+
+var
+ LeaveStates: TVirtualTreeStates;
+
+begin
+ LeaveStates := [tsHint];
+ if [tsWheelPanning, tsWheelScrolling] * FStates = [] then
+ begin
+ StopTimer(ScrollTimer);
+ LeaveStates := LeaveStates + [tsScrollPending, tsScrolling];
+ end;
+ DoStateChange([], LeaveStates);
+ if Assigned(FCurrentHotNode) then
+ begin
+ DoHotChange(FCurrentHotNode, nil);
+ InvalidateNode(FCurrentHotNode);
+ FCurrentHotNode := nil;
+ end;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMMouseWheel(var Message: TCMMouseWheel);
+
+var
+ ScrollCount: Integer;
+ ScrollLines: Integer;
+
+begin
+ StopWheelPanning;
+
+ inherited;
+
+ if Message.Result = 0 then
+ begin
+ with Message do
+ begin
+ Result := 1;
+ if FRangeY > Cardinal(ClientHeight) then
+ begin
+ // Scroll vertically if there's something to scroll...
+ if ssCtrl in ShiftState then
+ ScrollCount := WheelDelta div WHEEL_DELTA * (ClientHeight div Integer(FDefaultNodeHeight))
+ else
+ begin
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, @ScrollLines, 0);
+ ScrollCount := ScrollLines * WheelDelta div WHEEL_DELTA;
+ end;
+ SetOffsetY(FOffsetY + ScrollCount * Integer(FDefaultNodeHeight));
+ end
+ else
+ begin
+ // ...else scroll horizontally.
+ if ssCtrl in ShiftState then
+ ScrollCount := WheelDelta div WHEEL_DELTA * ClientWidth
+ else
+ ScrollCount := WheelDelta div WHEEL_DELTA;
+ SetOffsetX(FOffsetX + ScrollCount * Integer(FIndent));
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CMSysColorChange(var Message: TMessage);
+
+begin
+ inherited;
+
+ ConvertImageList(LightCheckImages, 'VT_CHECK_LIGHT');
+ ConvertImageList(DarkCheckImages, 'VT_CHECK_DARK');
+ ConvertImageList(LightTickImages, 'VT_TICK_LIGHT');
+ ConvertImageList(DarkTickImages, 'VT_TICK_DARK');
+ ConvertImageList(FlatImages, 'VT_FLAT');
+ ConvertImageList(UtilityImages, 'VT_UTILITIES');
+ // XP images do not need to be converted.
+ // System check images do not need to be converted.
+ Message.Msg := WM_SYSCOLORCHANGE;
+ DefaultHandler(Message);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMCancelMode(var Message: TWMCancelMode);
+
+begin
+ // Clear any transient state.
+ StopTimer(ExpandTimer);
+ StopTimer(EditTimer);
+ StopTimer(HeaderTimer);
+ StopTimer(ScrollTimer);
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+
+ DoStateChange([], [tsClearPending, tsEditPending, tsOLEDragPending, tsVCLDragPending, tsDrawSelecting,
+ tsDrawSelPending, tsIncrementalSearching]);
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMChangeState(var Message: TMessage);
+
+var
+ EnterStates,
+ LeaveStates: TVirtualTreeStates;
+
+begin
+ EnterStates := [];
+ if csStopValidation in TChangeStates(Byte(Message.WParam)) then
+ Include(EnterStates, tsStopValidation);
+ if csUseCache in TChangeStates(Byte(Message.WParam)) then
+ Include(EnterStates, tsUseCache);
+ if csValidating in TChangeStates(Byte(Message.WParam)) then
+ Include(EnterStates, tsValidating);
+ if csValidationNeeded in TChangeStates(Byte(Message.WParam)) then
+ Include(EnterStates, tsValidationNeeded);
+
+ LeaveStates := [];
+ if csStopValidation in TChangeStates(Byte(Message.LParam)) then
+ Include(LeaveStates, tsStopValidation);
+ if csUseCache in TChangeStates(Byte(Message.LParam)) then
+ Include(LeaveStates, tsUseCache);
+ if csValidating in TChangeStates(Byte(Message.LParam)) then
+ Include(LeaveStates, tsValidating);
+ if csValidationNeeded in TChangeStates(Byte(Message.LParam)) then
+ Include(LeaveStates, tsValidationNeeded);
+
+ DoStateChange(EnterStates, LeaveStates);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMChar(var Message: TWMChar);
+
+begin
+ if tsIncrementalSearchPending in FStates then
+ begin
+ HandleIncrementalSearch(Message.CharCode);
+ DoStateChange([], [tsIncrementalSearchPending]);
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMContextMenu(var Message: TWMContextMenu);
+
+// This method is called when a popup menu is about to be displayed.
+// We have to cancel some pending states here to avoid interferences.
+
+begin
+ DoStateChange([], [tsClearPending, tsEditPending, tsOLEDragPending, tsVCLDragPending]);
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMCopy(var Message: TWMCopy);
+
+begin
+ CopyToClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMCut(var Message: TWMCut);
+
+begin
+ CutToClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMEnable(var Message: TWMEnable);
+
+begin
+ inherited;
+ RedrawWindow(Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMEraseBkgnd(var Message: TWMEraseBkgnd);
+
+begin
+ Message.Result := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMGetDlgCode(var Message: TWMGetDlgCode);
+
+begin
+ Message.Result := DLGC_WANTCHARS or DLGC_WANTARROWS;
+ if FWantTabs then
+ Message.Result := Message.Result or DLGC_WANTTAB;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMHScroll(var Message: TWMHScroll);
+
+ //--------------- local functions -------------------------------------------
+
+ function GetRealScrollPosition: Integer;
+
+ var
+ SI: TScrollInfo;
+ Code: Integer;
+
+ begin
+ SI.cbSize := SizeOf(TScrollInfo);
+ SI.fMask := SIF_TRACKPOS;
+ Code := SB_HORZ;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_GetScrollInfo(Handle, Code, SI);
+ {$else}
+ GetScrollInfo(Handle, Code, SI);
+ {$endif UseFlatScrollbars}
+ Result := SI.nTrackPos;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+begin
+ case Message.ScrollCode of
+ SB_BOTTOM:
+ SetOffsetX(-Integer(FRangeX));
+ SB_ENDSCROLL:
+ begin
+ DoStateChange([], [tsThumbTracking]);
+ // avoiding to adjust the vertical scroll position while tracking makes it much smoother
+ // but we need to adjust the final position here then
+ UpdateHorizontalScrollBar(False);
+ end;
+ SB_LINELEFT:
+ SetOffsetX(FOffsetX + FScrollBarOptions.FIncrementX);
+ SB_LINERIGHT:
+ SetOffsetX(FOffsetX - FScrollBarOptions.FIncrementX);
+ SB_PAGELEFT:
+ SetOffsetX(FOffsetX + ClientWidth);
+ SB_PAGERIGHT:
+ SetOffsetX(FOffsetX - ClientWidth);
+ SB_THUMBPOSITION,
+ SB_THUMBTRACK:
+ begin
+ DoStateChange([tsThumbTracking]);
+ SetOffsetX(-GetRealScrollPosition);
+ end;
+ SB_TOP:
+ SetOffsetX(0);
+ end;
+
+ Message.Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMKeyDown(var Message: TWMKeyDown);
+
+// Keyboard event handling for node focus, selection, node specific popup menus and help invokation.
+// For a detailed description of every action done here read the help.
+
+var
+ Shift: TShiftState;
+ Node, Temp,
+ LastFocused: PVirtualNode;
+ Offset: Integer;
+ ClearPending,
+ NeedInvalidate,
+ DoRangeSelect,
+ HandleMultiSelect: Boolean;
+ Context: Integer;
+ ParentControl: TWinControl;
+ R: TRect;
+ NewCheckState: TCheckState;
+ NewColumn: TColumnIndex;
+ ActAsGrid: Boolean;
+
+ // for tabulator handling
+ GetStartColumn: function: TColumnIndex of object;
+ GetNextColumn: function(Column: TColumnIndex): TColumnIndex of object;
+ GetNextNode: TGetNextNodeProc;
+
+ KeyState: TKeyboardState;
+ Buffer: array[0..1] of Char;
+
+begin
+ // Make form key preview work and let application modify the key if it wants this.
+ inherited;
+
+ with Message do
+ begin
+ Shift := KeyDataToShiftState(KeyData);
+ // Ask the application if the default key handling is desired.
+ if DoKeyAction(CharCode, Shift) then
+ begin
+ if (tsKeyCheckPending in FStates) and (CharCode <> VK_SPACE) then
+ begin
+ DoStateChange([], [tskeyCheckPending]);
+ FCheckNode.CheckState := UnpressedState[FCheckNode.CheckState];
+ RepaintNode(FCheckNode);
+ FCheckNode := nil;
+ end;
+
+ if CharCode in [VK_HOME, VK_END, VK_PRIOR, VK_NEXT, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_BACK, VK_TAB] then
+ begin
+ HandleMultiSelect := (ssShift in Shift) and (toMultiSelect in FOptions.FSelectionOptions) and not IsEditing;
+
+ // Flag to avoid range selection in case of single node advance.
+ DoRangeSelect := (CharCode in [VK_HOME, VK_END, VK_PRIOR, VK_NEXT]) and HandleMultiSelect and not IsEditing;
+
+ NeedInvalidate := DoRangeSelect or (FSelectionCount > 1);
+ ActAsGrid := toGridExtensions in FOptions.FMiscOptions;
+ ClearPending := (Shift = []) or (ActAsGrid and not (ssShift in Shift)) or
+ not (toMultiSelect in FOptions.FSelectionOptions) or (CharCode in [VK_TAB, VK_BACK]);
+
+ // Keep old focused node for range selection. Use a default node if none was focused until now.
+ LastFocused := FFocusedNode;
+ if (LastFocused = nil) and (Shift <> []) then
+ LastFocused := GetFirstVisible;
+
+ // Set an initial range anchor if there is not yet one.
+ if FRangeAnchor = nil then
+ FRangeAnchor := GetFirstSelected;
+ if FRangeAnchor = nil then
+ FRangeAnchor := GetFirst;
+
+ // Determine new focused node.
+ case CharCode of
+ VK_HOME, VK_END:
+ begin
+ if CharCode = VK_END then
+ begin
+ GetStartColumn := FHeader.FColumns.GetLastVisibleColumn;
+ GetNextColumn := FHeader.FColumns.GetPreviousVisibleColumn;
+ GetNextNode := GetPreviousVisible;
+ Node := GetLastVisible;
+ end
+ else
+ begin
+ GetStartColumn := FHeader.FColumns.GetFirstVisibleColumn;
+ GetNextColumn := FHeader.FColumns.GetNextVisibleColumn;
+ GetNextNode := GetNextVisible;
+ Node := GetFirstVisible;
+ end;
+
+ // Advance to next/previous visible column.
+ if FHeader.UseColumns then
+ NewColumn := GetStartColumn
+ else
+ NewColumn := NoColumn;
+ // Find a column for the new/current node which can be focused.
+ while (NewColumn > NoColumn) and not DoFocusChanging(FFocusedNode, Node, FFocusedColumn, NewColumn) do
+ NewColumn := GetNextColumn(NewColumn);
+ if NewColumn > InvalidColumn then
+ begin
+ if (Shift = [ssCtrl]) and not ActAsGrid then
+ begin
+ ScrollIntoView(Node, toCenterScrollIntoView in FOptions.SelectionOptions,
+ not (toDisableAutoscrollOnFocus in FOptions.FAutoOptions));
+ if CharCode = VK_HOME then
+ SetOffsetX(0)
+ else
+ SetOffsetX(-MaxInt);
+ end
+ else
+ begin
+ if not ActAsGrid or (ssCtrl in Shift) then
+ FocusedNode := Node;
+ if ActAsGrid and not (toFullRowSelect in FOptions.FSelectionOptions) then
+ FocusedColumn := NewColumn;
+ end;
+ end;
+ end;
+ VK_PRIOR:
+ if ssCtrl in Shift then
+ SetOffsetY(FOffsetY + ClientHeight)
+ else
+ begin
+ Offset := 0;
+ // If there's no focused node then just take the very first visible one.
+ if FFocusedNode = nil then
+ Node := GetFirstVisible
+ else
+ begin
+ // Go up as many nodes as comprise together a size of ClientHeight.
+ Node := FFocusedNode;
+ while Offset < ClientHeight do
+ begin
+ Temp := GetPreviousVisible(Node);
+ if Temp = nil then
+ Break;
+ Node := Temp;
+ Inc(Offset, Node.NodeHeight);
+ end;
+ end;
+ FocusedNode := Node;
+ end;
+ VK_NEXT:
+ if ssCtrl in Shift then
+ SetOffsetY(FOffsetY - ClientHeight)
+ else
+ begin
+ Offset := 0;
+ // If there's no focused node then just take the very last one.
+ if FFocusedNode = nil then
+ Node := GetLastVisible
+ else
+ begin
+ // Go up as many nodes as comprise together a size of ClientHeight.
+ Node := FFocusedNode;
+ while Offset < ClientHeight do
+ begin
+ Temp := GetNextVisible(Node);
+ if Temp = nil then
+ Break;
+ Node := Temp;
+ Inc(Offset, Node.NodeHeight);
+ end;
+ end;
+ FocusedNode := Node;
+ end;
+ VK_UP:
+ begin
+ // scrolling without selection change
+ if ssCtrl in Shift then
+ SetOffsetY(FOffsetY + Integer(FDefaultNodeHeight))
+ else
+ begin
+ if FFocusedNode = nil then
+ Node := GetLastVisible
+ else
+ Node := GetPreviousVisible(FFocusedNode);
+
+ if Assigned(Node) then
+ begin
+ EndEditNode;
+ if HandleMultiSelect and (CompareNodePositions(LastFocused, FRangeAnchor) > 0) and
+ Assigned(FFocusedNode) then
+ RemoveFromSelection(FFocusedNode);
+ if FFocusedColumn = NoColumn then
+ FFocusedColumn := FHeader.MainColumn;
+ FocusedNode := Node;
+ end
+ else
+ if Assigned(FFocusedNode) then
+ InvalidateNode(FFocusedNode);
+ end;
+ end;
+ VK_DOWN:
+ begin
+ // scrolling without selection change
+ if ssCtrl in Shift then
+ SetOffsetY(FOffsetY - Integer(FDefaultNodeHeight))
+ else
+ begin
+ if FFocusedNode = nil then
+ Node := GetFirstVisible
+ else
+ Node := GetNextVisible(FFocusedNode);
+
+ if Assigned(Node) then
+ begin
+ EndEditNode;
+ if HandleMultiSelect and (CompareNodePositions(LastFocused, FRangeAnchor) < 0) and
+ Assigned(FFocusedNode) then
+ RemoveFromSelection(FFocusedNode);
+ if FFocusedColumn = NoColumn then
+ FFocusedColumn := FHeader.MainColumn;
+ FocusedNode := Node;
+ end
+ else
+ if Assigned(FFocusedNode) then
+ InvalidateNode(FFocusedNode);
+ end;
+ end;
+ VK_LEFT:
+ begin
+ // special handling
+ if ssCtrl in Shift then
+ SetOffsetX(FOffsetX + Integer(FIndent))
+ else
+ begin
+ // other special cases
+ Context := NoColumn;
+ if (toExtendedFocus in FOptions.FSelectionOptions) and (toGridExtensions in FOptions.FMiscOptions) then
+ begin
+ Context := FHeader.Columns.GetPreviousVisibleColumn(FFocusedColumn);
+ if Context > -1 then
+ FocusedColumn := Context
+ end
+ else
+ if Assigned(FFocusedNode) and (vsExpanded in FFocusedNode.States) and
+ (Shift = []) and (vsHasChildren in FFocusedNode.States) then
+ ToggleNode(FFocusedNode)
+ else
+ begin
+ if FFocusedNode = nil then
+ FocusedNode := GetFirstVisible
+ else
+ begin
+ if FFocusedNode.Parent <> FRoot then
+ Node := FFocusedNode.Parent
+ else
+ Node := nil;
+ if Assigned(Node) then
+ begin
+ if HandleMultiSelect then
+ begin
+ // and a third special case
+ if FFocusedNode.Index > 0 then
+ DoRangeSelect := True
+ else
+ if CompareNodePositions(Node, FRangeAnchor) > 0 then
+ RemoveFromSelection(FFocusedNode);
+ end;
+ FocusedNode := Node;
+ end;
+ end;
+ end;
+ end;
+ end;
+ VK_RIGHT:
+ begin
+ // special handling
+ if ssCtrl in Shift then
+ SetOffsetX(FOffsetX - Integer(FIndent))
+ else
+ begin
+ // other special cases
+ Context := NoColumn;
+ if (toExtendedFocus in FOptions.FSelectionOptions) and (toGridExtensions in FOptions.FMiscOptions) then
+ begin
+ Context := FHeader.Columns.GetNextVisibleColumn(FFocusedColumn);
+ if Context > -1 then
+ FocusedColumn := Context;
+ end
+ else
+ if Assigned(FFocusedNode) and not (vsExpanded in FFocusedNode.States) and
+ (Shift = []) and (vsHasChildren in FFocusedNode.States) then
+ ToggleNode(FFocusedNode)
+ else
+ begin
+ if FFocusedNode = nil then
+ FocusedNode := GetFirstVisible
+ else
+ begin
+ Node := GetFirstVisibleChild(FFocusedNode);
+ if Assigned(Node) then
+ begin
+ if HandleMultiSelect and (CompareNodePositions(Node, FRangeAnchor) < 0) then
+ RemoveFromSelection(FFocusedNode);
+ FocusedNode := Node;
+ end;
+ end;
+ end;
+ end;
+ end;
+ VK_BACK:
+ if tsIncrementalSearching in FStates then
+ DoStateChange([tsIncrementalSearchPending])
+ else
+ if Assigned(FFocusedNode) and (FFocusedNode.Parent <> FRoot) then
+ FocusedNode := FocusedNode.Parent;
+ VK_TAB:
+ if (toExtendedFocus in FOptions.FSelectionOptions) and FHeader.UseColumns then
+ begin
+ // In order to avoid duplicating source code just to change the direction
+ // we use function variables.
+ if ssShift in Shift then
+ begin
+ GetStartColumn := FHeader.FColumns.GetLastVisibleColumn;
+ GetNextColumn := FHeader.FColumns.GetPreviousVisibleColumn;
+ GetNextNode := GetPreviousVisible;
+ end
+ else
+ begin
+ GetStartColumn := FHeader.FColumns.GetFirstVisibleColumn;
+ GetNextColumn := FHeader.FColumns.GetNextVisibleColumn;
+ GetNextNode := GetNextVisible;
+ end;
+
+ // Advance to next/previous visible column/node.
+ Node := FFocusedNode;
+ NewColumn := GetNextColumn(FFocusedColumn);
+ repeat
+ // Find a column for the current node which can be focused.
+ while (NewColumn > NoColumn) and not DoFocusChanging(FFocusedNode, Node, FFocusedColumn, NewColumn) do
+ NewColumn := GetNextColumn(NewColumn);
+
+ if NewColumn > NoColumn then
+ begin
+ FocusedNode := Node;
+ FocusedColumn := NewColumn;
+ Break;
+ end;
+
+ // No next column was accepted for the current node. So advance to next node and try again.
+ Node := GetNextNode(Node);
+ NewColumn := GetStartColumn;
+ until Node = nil;
+ end;
+ end;
+
+ // Clear old selection if required but take care about change events.
+ if ClearPending then
+ if (LastFocused = FFocusedNode) and (FSelectionCount <= 1) then
+ InternalClearSelection
+ else
+ ClearSelection;
+
+ // Determine new selection anchor.
+ if Shift = [] then
+ begin
+ FRangeAnchor := FFocusedNode;
+ FLastSelectionLevel := GetNodeLevel(FFocusedNode);
+ end;
+ // Finally change the selection for a specific range of nodes.
+ if DoRangeSelect then
+ ToggleSelection(LastFocused, FFocusedNode);
+
+ // Make sure the new focused node is also selected.
+ // Avoid change event if this node was already the only selected node.
+ if Assigned(FFocusedNode) then
+ if LastFocused = FFocusedNode then
+ InternalAddToSelection(FFocusedNode, False)
+ else
+ AddToSelection(FFocusedNode);
+
+ // If a repaint is needed then paint the entire tree because of the ClearSelection call,
+ if NeedInvalidate then
+ Invalidate;
+ end
+ else
+ begin
+ // Second chance for keys not directly concerned with selection changes.
+
+ // For +, -, /, * keys on the main keyboard (not numpad) there is no virtual key code defined.
+ // We have to do special processing to get them working too.
+ GetKeyboardState(KeyState);
+ // Avoid conversion to control characters. We have captured the control key state already in Shift.
+ KeyState[VK_CONTROL] := 0;
+ if ToASCII(Message.CharCode, (Message.KeyData shr 16) and 7, KeyState, Buffer, 0) > 0 then
+ begin
+ case Buffer[0] of
+ '*':
+ CharCode := VK_MULTIPLY;
+ '+':
+ CharCode := VK_ADD;
+ '/':
+ CharCode := VK_DIVIDE;
+ '-':
+ CharCode := VK_SUBTRACT;
+ end;
+ end;
+
+ case CharCode of
+ VK_F2:
+ if (Shift = []) and Assigned(FFocusedNode) and CanEdit(FFocusedNode, FFocusedColumn) then
+ begin
+ FEditColumn := FFocusedColumn;
+ DoEdit;
+ end;
+ VK_ADD:
+ if not (tsIncrementalSearching in FStates) then
+ begin
+ if ssCtrl in Shift then
+ if {$ifdef ReverseFullExpandHotKey} not {$endif ReverseFullExpandHotKey} (ssShift in Shift) then
+ FullExpand
+ else
+ FHeader.AutoFitColumns
+ else
+ if Assigned(FFocusedNode) and not (vsExpanded in FFocusedNode.States) then
+ ToggleNode(FFocusedNode);
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_SUBTRACT:
+ if not (tsIncrementalSearching in FStates) then
+ begin
+ if ssCtrl in Shift then
+ if {$ifdef ReverseFullExpandHotKey} not {$endif ReverseFullExpandHotKey} (ssShift in Shift) then
+ FullCollapse
+ else
+ FHeader.RestoreColumns
+ else
+ if Assigned(FFocusedNode) and (vsExpanded in FFocusedNode.States) then
+ ToggleNode(FFocusedNode);
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_MULTIPLY:
+ if not (tsIncrementalSearching in FStates) then
+ begin
+ if Assigned(FFocusedNode) then
+ FullExpand(FFocusedNode);
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_DIVIDE:
+ if not (tsIncrementalSearching in FStates) then
+ begin
+ if Assigned(FFocusedNode) then
+ FullCollapse(FFocusedNode);
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_ESCAPE: // cancel actions currently in progress
+ begin
+ if IsMouseSelecting then
+ begin
+ DoStateChange([], [tsDrawSelecting, tsDrawSelPending]);
+ Invalidate;
+ end
+ else
+ if IsEditing then
+ CancelEditNode;
+ end;
+ VK_SPACE:
+ if (toCheckSupport in FOptions.MiscOptions) and Assigned(FFocusedNode) and
+ (FFocusedNode.CheckType <> ctNone) then
+ begin
+ if (FStates * [tsKeyCheckPending, tsMouseCheckPending] = []) and Assigned(FFocusedNode) and
+ not (vsDisabled in FFocusedNode.States) then
+ begin
+ with FFocusedNode^ do
+ NewCheckState := DetermineNextCheckState(CheckType, CheckState);
+ if DoChecking(FFocusedNode, NewCheckState) then
+ begin
+ DoStateChange([tsKeyCheckPending]);
+ FCheckNode := FFocusedNode;
+ FPendingCheckState := NewCheckState;
+ FCheckNode.CheckState := PressedState[FCheckNode.CheckState];
+ RepaintNode(FCheckNode);
+ end;
+ end;
+ end
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ VK_F1:
+ if Assigned(FOnGetHelpContext) then
+ begin
+ Context := 0;
+ if Assigned(FFocusedNode) then
+ begin
+ Node := FFocusedNode;
+ // Traverse the tree structure up to the root.
+ repeat
+ FOnGetHelpContext(Self, Node, 0, Context);
+ Node := Node.Parent;
+ until (Node = FRoot) or (Context <> 0);
+ end;
+
+ // If no help context could be found try the tree's one or its parent's contexts.
+ ParentControl := Self;
+ while Assigned(ParentControl) and (Context = 0) do
+ begin
+ Context := ParentControl.HelpContext;
+ ParentControl := ParentControl.Parent;
+ end;
+ if Context <> 0 then
+ Application.HelpContext(Context);
+ end;
+ VK_APPS:
+ if Assigned(FFocusedNode) then
+ begin
+ R := GetDisplayRect(FFocusedNode, FFocusedColumn, True);
+ Offset := DoGetNodeWidth(FFocusedNode, FFocusedColumn);
+ if FFocusedColumn >= 0 then
+ begin
+ if Offset > FHeader.Columns[FFocusedColumn].Width then
+ Offset := FHeader.Columns[FFocusedColumn].Width;
+ end
+ else
+ begin
+ if Offset > ClientWidth then
+ Offset := ClientWidth;
+ end;
+ DoPopupMenu(FFocusedNode, FFocusedColumn, Point(R.Left + Offset div 2, (R.Top + R.Bottom) div 2));
+ end;
+ Ord('a'), Ord('A'):
+ if ssCtrl in Shift then
+ SelectAll(True)
+ else
+ DoStateChange([tsIncrementalSearchPending]);
+ else
+ begin
+ // Use the key for incremental search.
+ // Since we are dealing with Unicode all the time there should be a more sophisticated way
+ // of checking for valid characters for incremental search.
+ // This is available but would require to include a significant amount of Unicode character
+ // properties, so we stick with the simple space check.
+ if (Shift * [ssCtrl, ssAlt] = []) and (CharCode >= 32) then
+ DoStateChange([tsIncrementalSearchPending]);
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMKeyUp(var Message: TWMKeyUp);
+
+begin
+ inherited;
+
+ case Message.CharCode of
+ VK_SPACE:
+ if tsKeyCheckPending in FStates then
+ begin
+ DoStateChange([], [tskeyCheckPending]);
+ if FCheckNode = FFocusedNode then
+ DoCheckClick(FCheckNode, FPendingCheckState);
+ InvalidateNode(FCheckNode);
+ FCheckNode := nil;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMKillFocus(var Msg: TWMKillFocus);
+
+var
+ Form: TCustomForm;
+ Control: TWinControl;
+ Pos: TSmallPoint;
+ Unknown: IUnknown;
+
+begin
+ inherited;
+
+ // Stop wheel panning if active.
+ StopWheelPanning;
+
+ // Don't let any timer continue if the tree is no longer the active control (except change timers).
+ StopTimer(ExpandTimer);
+ StopTimer(EditTimer);
+ StopTimer(HeaderTimer);
+ StopTimer(ScrollTimer);
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+
+ DoStateChange([], [tsScrollPending, tsScrolling, tsEditPending, tsLeftButtonDown, tsRightButtonDown,
+ tsMiddleButtonDown, tsOLEDragPending, tsVCLDragPending, tsIncrementalSearching]);
+
+ if (FSelectionCount > 0) or not (toGhostedIfUnfocused in FOptions.FPaintOptions) then
+ Invalidate
+ else
+ if Assigned(FFocusedNode) then
+ InvalidateNode(FFocusedNode);
+
+ // Workaround for wrapped non-VCL controls (like TWebBrowser), which do not use VCL mechanisms and
+ // leave the ActiveControl property in the wrong state, which causes trouble when the control is refocused.
+ Form := GetParentForm(Self);
+ if Assigned(Form) and (Form.ActiveControl = Self) then
+ begin
+ Cardinal(Pos) := GetMessagePos;
+ Control := FindVCLWindow(SmallPointToPoint(Pos));
+ // Every control derived from TOleControl has potentially the focus problem. In order to avoid including
+ // the OleCtrls unit (which will, among others, include Variants), which would allow to test for the TOleControl
+ // class, the IOleClientSite interface is used for the test, which is supported by TOleControl and a good indicator.
+ if Assigned(Control) and Control.GetInterface(IOleClientSite, Unknown) then
+ Form.ActiveControl := nil;
+
+ // For other classes the active control should not be modified. Otherwise you need two clicks to select it.
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMLButtonDblClk(var Message: TWMLButtonDblClk);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ inherited;
+
+ // get information about the hit
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDblClick(Message, HitInfo);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMLButtonDown(var Message: TWMLButtonDown);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([tsLeftButtonDown]);
+ inherited;
+
+ // get information about the hit
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDown(Message, HitInfo);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMLButtonUp(var Message: TWMLButtonUp);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([], [tsLeftButtonDown]);
+
+ // get information about the hit
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseUp(Message, HitInfo);
+
+ inherited;
+
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMMButtonDblClk(var Message: TWMMButtonDblClk);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ inherited;
+
+ // get information about the hit
+ if toMiddleClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDblClick(Message, HitInfo);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMMButtonDown(var Message: TWMMButtonDown);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([tsMiddleButtonDown]);
+
+ if FHeader.FStates = [] then
+ begin
+ inherited;
+
+ // Start wheel panning or scrolling if not already active, allowed and scrolling is useful at all.
+ if (toWheelPanning in FOptions.FMiscOptions) and ([tsWheelScrolling, tsWheelPanning] * FStates = []) and
+ ((Integer(FRangeX) > ClientWidth) or (Integer(FRangeY) > ClientHeight)) then
+ begin
+ FLastClickPos := SmallPointToPoint(Message.Pos);
+ StartWheelPanning(FLastClickPos);
+ end
+ else
+ begin
+ StopWheelPanning;
+
+ // Get information about the hit.
+ if toMiddleClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDown(Message, HitInfo);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMMButtonUp(var Message: TWMMButtonUp);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([], [tsMiddleButtonDown]);
+
+ // If wheel panning/scrolling is active and the mouse has not yet been moved then the user starts wheel auto scrolling.
+ // Indicate this by removing the panning flag. Otherwise (the mouse has moved meanwhile) stop panning.
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ if tsWheelScrolling in FStates then
+ DoStateChange([], [tsWheelPanning])
+ else
+ StopWheelPanning;
+ end
+ else
+ if FHeader.FStates = [] then
+ begin
+ inherited;
+
+ // get information about the hit
+ if toMiddleClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseUp(Message, HitInfo);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMNCCalcSize(var Message: TWMNCCalcSize);
+
+begin
+ inherited;
+
+ with FHeader do
+ if hoVisible in FHeader.FOptions then
+ with Message.CalcSize_Params^ do
+ Inc(rgrc[0].Top, FHeight);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMNCDestroy(var Message: TWMNCDestroy);
+
+// Used to release a reference of the drag manager. This is the only reliable way we get notified about
+// window destruction, because of the automatic release of a window if its parent window is freed.
+
+begin
+ StopTimer(ChangeTimer);
+ StopTimer(StructureChangeTimer);
+
+ if not (csDesigning in ComponentState) and (toAcceptOLEDrop in FOptions.FMiscOptions) then
+ RevokeDragDrop(Handle);
+
+ // Clean up other stuff.
+ DeleteObject(FDottedBrush);
+ FDottedBrush := 0;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMNCHitTest(var Message: TWMNCHitTest);
+
+begin
+ inherited;
+ if not (csDesigning in ComponentState) and (hoVisible in FHeader.FOptions) and
+ FHeader.InHeader(ScreenToClient(SmallPointToPoint(Message.Pos))) then
+ Message.Result := HTBORDER;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMNCPaint(var Message: TRealWMNCPaint);
+
+var
+ DC: HDC;
+ R: TRect;
+ Flags: DWORD;
+
+begin
+ DefaultHandler(Message);
+
+ // If the tree is themed then the border which is drawn by the default handler will be overpainted here.
+ // This will, when resizing columns, cause a bit flicker, but since I found nowhwere documentation about
+ // how to do it right I have to live with that for the time being.
+ Flags := DCX_CACHE or DCX_CLIPSIBLINGS or DCX_WINDOW or DCX_VALIDATE;
+
+ if True or (Message.Rgn = 1) or not IsWinNT then
+ DC := GetDCEx(Handle, 0, Flags)
+ else
+ DC := GetDCEx(Handle, Message.Rgn, Flags or DCX_INTERSECTRGN);
+
+ if DC <> 0 then
+ begin
+ if hoVisible in FHeader.FOptions then
+ begin
+ R := FHeaderRect;
+ FHeader.FColumns.PaintHeader(DC, R, FOffsetX);
+ end;
+ OriginalWMNCPaint(DC);
+ ReleaseDC(Handle, DC);
+ end;
+ {$ifdef ThemeSupport}
+ if tsUseThemes in FStates then
+ ThemeServices.PaintBorder(Self, False);
+ {$endif ThemeSupport}
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMPaint(var Message: TWMPaint);
+
+begin
+ if tsVCLDragging in FStates then
+ ImageList_DragShowNolock(False);
+ GetUpdateRect(Handle, FUpdateRect, True);
+ inherited;
+ if tsVCLDragging in FStates then
+ ImageList_DragShowNolock(True);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMPaste(var Message: TWMPaste);
+
+begin
+ PasteFromClipboard;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMPrint(var Message: TWMPrint);
+
+// This message is sent to request that the tree draws itself to a given device context. This includes not only
+// the client area but also the non-client area (header!).
+
+begin
+ // Draw only if the window is visible or visibility is not required.
+ if ((Message.Flags and PRF_CHECKVISIBLE) = 0) or IsWindowVisible(Handle) then
+ Header.Columns.PaintHeader(Message.DC, FHeaderRect, FOffsetX);
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMPrintClient(var Message: TWMPrintClient);
+
+var
+ Window: TRect;
+ Target: TPoint;
+ Canvas: TCanvas;
+
+begin
+ // Draw only if the window is visible or visibility is not required.
+ if ((Message.Flags and PRF_CHECKVISIBLE) = 0) or IsWindowVisible(Handle) then
+ begin
+ // Determine area of the entire tree to be displayed in the control.
+ Window := ClientRect;
+ Target := Window.TopLeft;
+
+ // The Window rectangle is given in client coordinates. We have to convert it into
+ // a sliding window of the tree image.
+ OffsetRect(Window, -FOffsetX, -FOffsetY);
+
+ Canvas := TCanvas.Create;
+ try
+ Canvas.Handle := Message.DC;
+ PaintTree(Canvas, Window, Target, [poBackground, poDrawFocusRect, poDrawDropMark, poDrawSelection, poGridLines]);
+ finally
+ Canvas.Handle := 0;
+ Canvas.Free;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMRButtonDblClk(var Message: TWMRButtonDblClk);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ inherited;
+
+ // get information about the hit
+ if toMiddleClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDblClick(Message, HitInfo);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMRButtonDown(var Message: TWMRButtonDown);
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([tsRightButtonDown]);
+
+ if FHeader.FStates = [] then
+ begin
+ inherited;
+
+ // get information about the hit
+ if toRightClickSelect in FOptions.FSelectionOptions then
+ begin
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+ HandleMouseDown(Message, HitInfo);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMRButtonUp(var Message: TWMRButtonUp);
+
+// handle right click selection and node specific popup menu
+
+var
+ HitInfo: THitInfo;
+
+begin
+ DoStateChange([], [tsRightButtonDown]);
+
+ if FHeader.FStates = [] then
+ begin
+ Application.CancelHint;
+
+ if IsMouseSelecting and Assigned(PopupMenu) then
+ begin
+ // Reset selection state already here, before the inherited handler opens the default menu.
+ DoStateChange([], [tsDrawSelecting, tsDrawSelPending]);
+ Invalidate;
+ end;
+
+ inherited;
+
+ // get information about the hit
+ GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo);
+
+ if toRightClickSelect in FOptions.FSelectionOptions then
+ HandleMouseUp(Message, HitInfo);
+
+ if not Assigned(PopupMenu) then
+ DoPopupMenu(HitInfo.HitNode, HitInfo.HitColumn, Point(Message.XPos, Message.YPos));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMReleaseEditLink(var Message: TMessage);
+
+begin
+ // Finally free edit link memory after editing has been finished.
+ if not IsEditing then
+ FEditLink := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMSetCursor(var Message: TWMSetCursor);
+
+// Sets the hot node mouse cursor for the tree. Cursor changes for the header are handled in Header.HandleMessage.
+
+var
+ NewCursor: TCursor;
+
+begin
+ with Message do
+ begin
+ if (CursorWnd = Handle) and not (csDesigning in ComponentState) then
+ begin
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ Beep;
+ end
+ else
+ if not FHeader.HandleMessage(TMessage(Message)) then
+ begin
+ // Apply own cursors only if there is no global cursor set.
+ if Screen.Cursor = crDefault then
+ begin
+ if (toHotTrack in FOptions.PaintOptions) and Assigned(FCurrentHotNode) then
+ NewCursor := FHotCursor
+ else
+ NewCursor := Cursor;
+
+ DoGetCursor(NewCursor);
+ Windows.SetCursor(Screen.Cursors[NewCursor]);
+ Message.Result := 1;
+ end
+ else
+ inherited;
+ end;
+ end
+ else
+ inherited;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMSetFocus(var Msg: TWMSetFocus);
+
+begin
+ inherited;
+ if (FSelectionCount > 0) or not (toGhostedIfUnfocused in FOptions.FPaintOptions) then
+ Invalidate;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMSize(var Message: TWMSize);
+
+begin
+ inherited;
+
+ // Need to update scroll bars here. This will cause a recursion because of the change of the client area
+ // when changing a scrollbar. Usually this is no problem since with the second level recursion no change of the
+ // window size happens (the same values for the scrollbars are set, which shouldn't cause a window size change).
+ // Appearently, this applies not to all systems, however.
+ if HandleAllocated and ([tsSizing, tsWindowCreating] * FStates = []) and (ClientHeight > 0) then
+ try
+ DoStateChange([tsSizing]);
+ // This call will invalidate the entire non-client area which needs recalculation on resize.
+ FHeader.RecalculateHeader;
+ UpdateScrollBars(True);
+
+ if (tsEditing in FStates) and not FHeader.UseColumns then
+ UpdateEditBounds;
+ finally
+ DoStateChange([], [tsSizing]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMTimer(var Message: TWMTimer);
+
+// centralized timer handling happens here
+
+begin
+ with Message do
+ begin
+ case TimerID of
+ ExpandTimer:
+ DoDragExpand;
+ EditTimer:
+ DoEdit;
+ ScrollTimer:
+ begin
+ if tsScrollPending in FStates then
+ begin
+ Application.CancelHint;
+ // Scroll delay has elapsed, set to normal scroll interval now.
+ SetTimer(Handle, ScrollTimer, FAutoScrollInterval, nil);
+ DoStateChange([tsScrolling], [tsScrollPending]);
+ end;
+ DoTimerScroll;
+ end;
+ ChangeTimer:
+ DoChange(FLastChangedNode);
+ StructureChangeTimer:
+ DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason);
+ SearchTimer:
+ begin
+ // When this event triggers then the user did not pressed any key for the specified timeout period.
+ // Hence incremental searching is stopped.
+ DoStateChange([], [tsIncrementalSearching]);
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WMVScroll(var Message: TWMVScroll);
+
+ //--------------- local functions -------------------------------------------
+
+ function GetRealScrollPosition: Integer;
+
+ var
+ SI: TScrollInfo;
+ Code: Integer;
+
+ begin
+ SI.cbSize := SizeOf(TScrollInfo);
+ SI.fMask := SIF_TRACKPOS;
+ Code := SB_VERT;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_GetScrollInfo(Handle, Code, SI);
+ {$else}
+ GetScrollInfo(Handle, Code, SI);
+ {$endif UseFlatScrollbars}
+ Result := SI.nTrackPos;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+begin
+ case Message.ScrollCode of
+ SB_BOTTOM:
+ SetOffsetY(-Integer(FRoot.TotalHeight));
+ SB_ENDSCROLL:
+ begin
+ DoStateChange([], [tsThumbTracking]);
+ // Avoiding to adjust the horizontal scroll position while tracking makes scrolling much smoother
+ // but we need to adjust the final position here then.
+ UpdateScrollBars(True);
+ // Really weird invalidation needed here (and I do it only because it happens so rarely), because
+ // when showing the horizontal scrollbar while scrolling down using the down arrow button,
+ // the button will be repainted on mouse up (at the wrong place in the far right lower corner)...
+ RedrawWindow(Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN);
+ end;
+ SB_LINEUP:
+ SetOffsetY(FOffsetY + FScrollBarOptions.FIncrementY);
+ SB_LINEDOWN:
+ SetOffsetY(FOffsetY - FScrollBarOptions.FIncrementY);
+ SB_PAGEUP:
+ SetOffsetY(FOffsetY + ClientHeight);
+ SB_PAGEDOWN:
+ SetOffsetY(FOffsetY - ClientHeight);
+
+ SB_THUMBPOSITION,
+ SB_THUMBTRACK:
+ begin
+ DoStateChange([tsThumbTracking]);
+ SetOffsetY(-GetRealScrollPosition);
+ end;
+ SB_TOP:
+ SetOffsetY(0);
+ end;
+ Message.Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AddToSelection(Node: PVirtualNode);
+
+var
+ Changed: Boolean;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil!');
+ FSingletonNodeArray[0] := Node;
+ Changed := InternalAddToSelection(FSingletonNodeArray, 1, False);
+ if Changed then
+ Change(Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AddToSelection(const NewItems: TNodeArray; NewLength: Integer; ForceInsert: Boolean = False);
+
+// Adds the given items all at once into the current selection array. NewLength is the amount of
+// nodes to add (necessary to allow NewItems to be larger than the actual used entries).
+// ForceInsert is True if nodes must be inserted without consideration of level select constraint or
+// already set selected flags (e.g. when loading from stream).
+// Note: In the case ForceInsert is True the caller is responsible for making sure the new nodes aren't already in the
+// selection array!
+
+var
+ Changed: Boolean;
+
+begin
+ Changed := InternalAddToSelection(NewItems, NewLength, ForceInsert);
+ if Changed then
+ begin
+ if NewLength = 1 then
+ Change(NewItems[0])
+ else
+ Change(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex);
+
+// Used in descentants to modify the clip rectangle of the current column while painting a certain node.
+
+begin
+ // Since cells are always drawn from left to right the next column index is independent of the
+ // bidi mode, but not the column borders which might change depending on the cell's content.
+ NextNonEmpty := FHeader.FColumns.GetNextVisibleColumn(PaintInfo.Column);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdjustPanningCursor(X, Y: Integer);
+
+// Triggered by a mouse move when wheel panning/scrolling is active.
+// Loads the proper cursor which indicates into which direction scrolling is done.
+
+var
+ Name: string;
+ NewCursor: HCURSOR;
+ ScrollHorizontal,
+ ScrollVertical: Boolean;
+
+begin
+ ScrollHorizontal := Integer(FRangeX) > ClientWidth;
+ ScrollVertical := Integer(FRangeY) > ClientHeight;
+
+ if (Abs(X - FLastClickPos.X) < 8) and (Abs(Y - FLastClickPos.Y) < 8) then
+ begin
+ // Mouse is in the neutral zone.
+ if ScrollHorizontal then
+ begin
+ if ScrollVertical then
+ Name := 'VT_MOVEALL'
+ else
+ Name := 'VT_MOVEEW'
+ end
+ else
+ Name := 'VT_MOVENS';
+ end
+ else
+ begin
+ // One of 8 directions applies: north, north-east, east, south-east, south, south-west, west and north-west.
+ // Check also if scrolling in the particular direction is possible.
+ if ScrollVertical and ScrollHorizontal then
+ begin
+ // All directions allowed.
+ if X - FlastClickPos.X < -8 then
+ begin
+ // Left hand side.
+ if Y - FLastClickPos.Y < -8 then
+ Name := 'VT_MOVENW'
+ else
+ if Y - FLastClickPos.Y > 8 then
+ Name := 'VT_MOVESW'
+ else
+ Name := 'VT_MOVEW';
+ end
+ else
+ if X - FLastClickPos.X > 8 then
+ begin
+ // Right hand side.
+ if Y - FLastClickPos.Y < -8 then
+ Name := 'VT_MOVENE'
+ else
+ if Y - FLastClickPos.Y > 8 then
+ Name := 'VT_MOVESE'
+ else
+ Name := 'VT_MOVEE';
+ end
+ else
+ begin
+ // Up or down.
+ if Y < FLastClickPos.Y then
+ Name := 'VT_MOVEN'
+ else
+ Name := 'VT_MOVES';
+ end;
+ end
+ else
+ if ScrollHorizontal then
+ begin
+ // Only horizontal movement allowed.
+ if X < FlastClickPos.X then
+ Name := 'VT_MOVEW'
+ else
+ Name := 'VT_MOVEE';
+ end
+ else
+ begin
+ // Only vertical movement allowed.
+ if Y < FlastClickPos.Y then
+ Name := 'VT_MOVEN'
+ else
+ Name := 'VT_MOVES';
+ end;
+ end;
+
+ // Now load the cursor and apply it.
+ NewCursor := LoadCursor(HInstance, PChar(Name));
+ if FPanningCursor <> NewCursor then
+ begin
+ DeleteObject(FPanningCursor);
+ FPanningCursor := NewCursor;
+ Windows.SetCursor(FPanningCursor);
+ end
+ else
+ DeleteObject(NewCursor);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AdviseChangeEvent(StructureChange: Boolean; Node: PVirtualNode; Reason: TChangeReason);
+
+// Used to register a delayed change event. If StructureChange is False then we have a selection change event (without
+// a specific reason) otherwise it is a structure change.
+
+begin
+ if StructureChange then
+ begin
+ if tsStructureChangePending in FStates then
+ StopTimer(StructureChangeTimer)
+ else
+ DoStateChange([tsStructureChangePending]);
+
+ FLastStructureChangeNode := Node;
+ if FLastStructureChangeReason = crIgnore then
+ FLastStructureChangeReason := Reason
+ else
+ if Reason <> crIgnore then
+ FLastStructureChangeReason := crAccumulated;
+ end
+ else
+ begin
+ if tsChangePending in FStates then
+ StopTimer(ChangeTimer)
+ else
+ DoStateChange([tsChangePending]);
+
+ FLastChangedNode := Node;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.AllocateInternalDataArea(Size: Cardinal): Cardinal;
+
+// Simple registration method to be called by each descendant to claim their internal data area.
+// Result is the offset from the begin of the node to the internal data area of the calling tree class.
+
+begin
+ Assert((FRoot = nil) or (FRoot.ChildCount = 0), 'Internal data allocation must be done before any node is created.');
+
+ Result := TreeNodeSize + FTotalInternalDataSize;
+ Inc(FTotalInternalDataSize, (Size + 3) and not 3);
+ InitRootNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Animate(Steps, Duration: Cardinal; Callback: TVTAnimationCallback; Data: Pointer);
+
+// This method does the calculation part of an animation as used for node toggling and hint animations.
+// Steps is the maximum amount of animation steps to do and Duration determines the milliseconds the animation
+// has to run. Callback is a task specific method which is called in the loop for every step and Data is simply
+// something to pass on to the callback.
+// The callback is called with the current step, the current step size and the Data parameter. Since the step amount
+// as well as the step size are possibly adjusted during the animation, it is impossible to determine if the current
+// step is the last step, even if the original step amount is known. To solve this problem the callback will be
+// called after the loop has finished with a step size of 0 indicating so to execute any post processing.
+
+var
+ StepSize,
+ RemainingTime,
+ RemainingSteps,
+ NextTimeStep,
+ CurrentStep,
+ StartTime,
+ CurrentTime: Cardinal;
+
+begin
+ if not (tsInAnimation in FStates) and (Duration > 0) then
+ begin
+ DoStateChange([tsInAnimation]);
+ try
+ RemainingTime := Duration;
+ RemainingSteps := Steps;
+
+ // Determine the initial step size which is either 1 if the needed steps are less than the number of
+ // steps possible given by the duration or > 1 otherwise.
+ StepSize := Round(Max(1, RemainingSteps / Duration));
+ RemainingSteps := RemainingSteps div StepSize;
+ CurrentStep := 0;
+
+ while (RemainingSteps > 0) and (RemainingTime > 0) and not Application.Terminated do
+ begin
+ StartTime := timeGetTime;
+ NextTimeStep := StartTime + RemainingTime div RemainingSteps;
+ if not Callback(CurrentStep, StepSize, Data) then
+ Break;
+
+ // Keep duration for this step for rest calculation.
+ CurrentTime := timeGetTime;
+ // Wait until the calculated time has been reached.
+ while CurrentTime < NextTimeStep do
+ CurrentTime := timeGetTime;
+
+ // Subtract the time this step really needed.
+ if RemainingTime >= CurrentTime - StartTime then
+ begin
+ Dec(RemainingTime, CurrentTime - StartTime);
+ Dec(RemainingSteps);
+ end
+ else
+ begin
+ RemainingTime := 0;
+ RemainingSteps := 0;
+ end;
+ // If the remaining time per step is less than one time step then we have to decrease the
+ // step count and increase the step size.
+ if (RemainingSteps > 0) and ((RemainingTime div RemainingSteps) < 1) then
+ begin
+ repeat
+ Inc(StepSize);
+ RemainingSteps := RemainingTime div StepSize;
+ until (RemainingSteps <= 0) or ((RemainingTime div RemainingSteps) >= 1);
+ end;
+ CurrentStep := Cardinal(Steps) - RemainingSteps;
+ end;
+
+ if not Application.Terminated then
+ Callback(0, 0, Data);
+ finally
+ DoStateChange([], [tsInAnimation]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CalculateSelectionRect(X, Y: Integer): Boolean;
+
+// Recalculates old and new selection rectangle given that X, Y are new mouse coordinates.
+// Returns True if there was a change since the last call.
+
+var
+ MaxValue: Integer;
+
+begin
+ if tsDrawSelecting in FStates then
+ FLastSelRect := FNewSelRect;
+ FNewSelRect.BottomRight := Point(X - FOffsetX, Y - FOffsetY);
+ if FNewSelRect.Right < 0 then
+ FNewSelRect.Right := 0;
+ if FNewSelRect.Bottom < 0 then
+ FNewSelRect.Bottom := 0;
+ MaxValue := ClientWidth;
+ if FRangeX > Cardinal(MaxValue) then
+ MaxValue := FRangeX;
+ if FNewSelRect.Right > MaxValue then
+ FNewSelRect.Right := MaxValue;
+ MaxValue := ClientHeight;
+ if FRangeY > Cardinal(MaxValue) then
+ MaxValue := FRangeY;
+ if FNewSelRect.Bottom > MaxValue then
+ FNewSelRect.Bottom := MaxValue;
+
+ Result := not CompareMem(@FLastSelRect, @FNewSelRect, SizeOf(FNewSelRect));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CanAutoScroll: Boolean;
+
+// Determines if auto scrolling is currently allowed.
+
+begin
+ // Don't scroll the client area if the header is currently doing tracking or dragging.
+ // Do auto scroll only if there is a draw selection in progress or the tree is the current drop target or
+ // wheel panning/scrolling is active.
+ Result := (toAutoScroll in FOptions.FAutoOptions) and (FHeader.FStates = []) and
+ (([tsDrawSelPending, tsDrawSelecting] * FStates <> []) or (Assigned(FDragManager) and DragManager.IsDropTarget) or
+ (tsVCLDragging in FStates) or
+ ([tsWheelPanning, tsWheelScrolling] * FStates <> []));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CanEdit(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// Returns True if the given node can be edited.
+
+begin
+ Result := (toEditable in FOptions.FMiscOptions) and Enabled and not (toReadOnly in FOptions.FMiscOptions);
+ DoCanEdit(Node, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CanShowDragImage: Boolean;
+
+// Determines whether a drag image should be shown.
+
+begin
+ Result := FDragImageKind <> diNoImage;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Change(Node: PVirtualNode);
+
+begin
+ AdviseChangeEvent(False, Node, crIgnore);
+
+ if FUpdateCount = 0 then
+ begin
+ if (FChangeDelay > 0) and not (tsSynchMode in FStates) then
+ SetTimer(Handle, ChangeTimer, FChangeDelay, nil)
+ else
+ DoChange(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ChangeScale(M, D: Integer);
+
+var
+ DoScale: Boolean;
+
+begin
+ inherited;
+
+ if (M <> D) and (toAutoChangeScale in FOptions.FAutoOptions) then
+ begin
+ if (csLoading in ComponentState) then
+ DoScale := tsNeedScale in FStates
+ else
+ DoScale := True;
+ if DoScale then
+ begin
+ FDefaultNodeHeight := MulDiv(FDefaultNodeHeight, M, D);
+ FHeader.ChangeScale(M, D);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CheckParentCheckState(Node: PVirtualNode; NewCheckState: TCheckState): Boolean;
+
+// Checks all siblings of node to determine which check state Node's parent must get.
+
+var
+ CheckCount,
+ BoxCount: Cardinal;
+ PartialCheck: Boolean;
+ Run: PVirtualNode;
+
+begin
+ CheckCount := 0;
+ BoxCount := 0;
+ PartialCheck := False;
+ Run := Node.Parent.FirstChild;
+ while Assigned(Run) do
+ begin
+ if Run = Node then
+ begin
+ // The given node cannot be checked because it does not yet have its new check state (as this depends
+ // on the outcome of this method). Instead NewCheckState is used as this contains the new state the node
+ // will get if this method returns True.
+ if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
+ begin
+ Inc(BoxCount);
+ if NewCheckState in [csCheckedNormal, csCheckedPressed] then
+ Inc(CheckCount);
+ PartialCheck := PartialCheck or (NewCheckState = csMixedNormal);
+ end;
+ end
+ else
+ if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then
+ begin
+ Inc(BoxCount);
+ if Run.CheckState in [csCheckedNormal, csCheckedPressed] then
+ Inc(CheckCount);
+ PartialCheck := PartialCheck or (Run.CheckState = csMixedNormal);
+ end;
+ Run := Run.NextSibling;
+ end;
+
+ if (CheckCount = 0) and not PartialCheck then
+ NewCheckState := csUncheckedNormal
+ else
+ if CheckCount < BoxCount then
+ NewCheckState := csMixedNormal
+ else
+ NewCheckState := csCheckedNormal;
+
+ Node := Node.Parent;
+ Result := DoChecking(Node, NewCheckState);
+ if Result then
+ begin
+ DoCheckClick(Node, NewCheckState);
+ // Recursively adjust parent of parent.
+ with Node^ do
+ begin
+ if not (vsInitialized in Parent.States) then
+ InitNode(Parent);
+ if ([vsChecking, vsDisabled] * Parent.States = []) and (Parent <> FRoot) and
+ (Parent.CheckType = ctTriStateCheckBox) then
+ Result := CheckParentCheckState(Node, NewCheckState);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ClearTempCache;
+
+// make sure the temporary node cache is in a reliable state
+
+begin
+ FTempNodeCache := nil;
+ FTempNodeCount := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// Returns True if the given column is to be considered as being empty. This will usually be determined by
+// descentants as the base tree implementation has not enough information to decide.
+
+begin
+ Result := False;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CountLevelDifference(Node1, Node2: PVirtualNode): Integer;
+
+// This method counts how many indentation levels the given nodes are apart. If both nodes have the same parent then the
+// difference is 0 otherwise the result is basically GetNodeLevel(Node2) - GetNodeLevel(Node1), but with sign.
+// If the result is negative then Node2 is less intended than Node1.
+
+var
+ Level1, Level2: Integer;
+
+begin
+ Assert(Assigned(Node1) and Assigned(Node2), 'Both nodes must be Assigned.');
+
+ Level1 := 0;
+ while Node1.Parent <> FRoot do
+ begin
+ Inc(Level1);
+ Node1 := Node1.Parent;
+ end;
+
+ Level2 := 0;
+ while Node2.Parent <> FRoot do
+ begin
+ Inc(Level2);
+ Node2 := Node2.Parent;
+ end;
+
+ Result := Level2 - Level1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CountVisibleChildren(Node: PVirtualNode): Cardinal;
+
+// Returns the number of visible child nodes of the given node.
+
+begin
+ Result := 0;
+ // its direct children
+ if vsExpanded in Node.States then
+ begin
+ // and their children
+ Node := Node.FirstChild;
+ while Assigned(Node) do
+ begin
+ if vsVisible in Node.States then
+ Inc(Result, CountVisibleChildren(Node) + 1);
+ Node := Node.NextSibling;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CreateParams(var Params: TCreateParams);
+
+const
+ ScrollBar: array[TScrollStyle] of Cardinal = (0, WS_HSCROLL, WS_VSCROLL, WS_HSCROLL or WS_VSCROLL);
+
+begin
+ inherited CreateParams(Params);
+
+ with Params do
+ begin
+ Style := Style or WS_CLIPCHILDREN or WS_CLIPSIBLINGS or ScrollBar[ScrollBarOptions.FScrollBars];
+ if toFullRepaintOnResize in FOptions.MiscOptions then
+ WindowClass.style := WindowClass.style or CS_HREDRAW or CS_VREDRAW
+ else
+ WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
+ if FBorderStyle = bsSingle then
+ begin
+ if Ctl3D then
+ begin
+ ExStyle := ExStyle or WS_EX_CLIENTEDGE;
+ Style := Style and not WS_BORDER;
+ end
+ else
+ Style := Style or WS_BORDER;
+ end
+ else
+ Style := Style and not WS_BORDER;
+
+ // Left scrollbars can be used with Win2K and up, regardless of the system locale.
+ if BidiMode <> bdLeftToRight then
+ ExStyle := ExStyle or WS_EX_LEFTSCROLLBAR;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CreateWnd;
+
+// Initializes data which depends on a valid window handle.
+
+begin
+ DoStateChange([tsWindowCreating]);
+ inherited;
+ DoStateChange([], [tsWindowCreating]);
+
+ {$ifdef ThemeSupport}
+ if ThemeServices.ThemesEnabled and (toThemeAware in TreeOptions.PaintOptions) then
+ DoStateChange([tsUseThemes])
+ else
+ {$endif ThemeSupport}
+ DoStateChange([], [tsUseThemes]);
+
+ // Because of the special recursion and update stopper when creating the window (or resizing it)
+ // we have to manually trigger the auto size calculation here.
+ if hoAutoResize in FHeader.FOptions then
+ FHeader.FColumns.AdjustAutoSize(InvalidColumn);
+
+ // Initialize flat scroll bar library if required.
+ {$ifdef UseFlatScrollbars}
+ if FScrollBarOptions.FScrollBarStyle <> sbmRegular then
+ begin
+ InitializeFlatSB(Handle);
+ FlatSB_SetScrollProp(Handle, WSB_PROP_HSTYLE, ScrollBarProp[FScrollBarOptions.ScrollBarStyle], False);
+ FlatSB_SetScrollProp(Handle, WSB_PROP_VSTYLE, ScrollBarProp[FScrollBarOptions.ScrollBarStyle], False);
+ end;
+ {$endif UseFlatScrollbars}
+
+ PrepareBitmaps(True, True);
+
+ // Register tree as OLE drop target.
+ if not (csDesigning in ComponentState) and (toAcceptOLEDrop in FOptions.FMiscOptions) then
+ RegisterDragDrop(Handle, DragManager as IDropTarget);
+
+ UpdateScrollBars(True);
+ UpdateHeaderRect;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DefineProperties(Filer: TFiler);
+
+// There were heavy changes in some properties during development of VT. This method helps to make migration easier
+// by reading old properties manually and put them into the new properties as appropriate.
+// Note: these old properties are never written again and silently disappear.
+// June 2002: Meanwhile another task is done here too: working around the problem that TCollection is not streamed
+// correctly when using Visual Form Inheritance (VFI).
+
+var
+ StoreIt: Boolean;
+
+begin
+ inherited;
+
+ // The header can prevent writing columns altogether.
+ if FHeader.CanWriteColumns then
+ begin
+ // Check if we inherit from an ancestor form (Visual Form Inheritance).
+ StoreIt := Filer.Ancestor = nil;
+ // If there is an ancestor then save columns only if they are different to the base set.
+ if not StoreIt then
+ StoreIt := not FHeader.Columns.Equals(TBaseVirtualTree(Filer.Ancestor).FHeader.Columns);
+ end
+ else
+ StoreIt := False;
+
+ Filer.DefineProperty('Columns', FHeader.ReadColumns, FHeader.WriteColumns, StoreIt);
+ Filer.DefineProperty('Options', ReadOldOptions, nil, False);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DetermineHiddenChildrenFlag(Node: PVirtualNode);
+
+// Update the hidden children flag of the given node.
+
+var
+ Run: PVirtualNode;
+
+begin
+ // Iterate through all siblings and stop when one visible is found.
+ Run := Node.FirstChild;
+ while Assigned(Run) and not (vsVisible in Run.States) do
+ Run := Run.NextSibling;
+ if Assigned(Run) then
+ Exclude(Node.States, vsAllChildrenHidden)
+ else
+ Include(Node.States, vsAllChildrenHidden);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DetermineHiddenChildrenFlagAllNodes;
+
+var
+ Run: PVirtualNode;
+
+begin
+ Run := GetFirstNoInit;
+ while Assigned(Run) do
+ begin
+ DetermineHiddenChildrenFlag(Run);
+ Run := GetNextNoInit(Run);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DetermineHitPositionLTR(var HitInfo: THitInfo; Offset, Right: Integer;
+ Alignment: TAlignment);
+
+// This method determines the hit position within a node with left-to-right orientation.
+
+var
+ MainColumnHit,
+ Ghosted: Boolean;
+ Run: PVirtualNode;
+ Indent,
+ TextWidth,
+ ImageOffset: Integer;
+
+begin
+ MainColumnHit := HitInfo.HitColumn = FHeader.MainColumn;
+ Indent := 0;
+
+ // If columns are not used or the main column is hit then the tree indentation must be considered too.
+ if MainColumnHit then
+ begin
+ Run := HitInfo.HitNode;
+ while (Run.Parent <> FRoot) do
+ begin
+ Inc(Indent, FIndent);
+ Run := Run.Parent;
+ end;
+ if toShowRoot in FOptions.FPaintOptions then
+ Inc(Indent, FIndent);
+ end;
+
+ if Offset < Indent then
+ begin
+ // Position is to the left of calculated indentation which can only happen for the main column.
+ // Check whether it corresponds to a button/checkbox.
+ if (toShowButtons in FOptions.FPaintOptions) and (vsHasChildren in HitInfo.HitNode.States) then
+ begin
+ // Position of button is interpreted very generously to avoid forcing the user
+ // to click exactly into the 9x9 pixels area. The entire node height and one full
+ // indentation level is accepted as button hit.
+ if Offset >= Indent - Integer(FIndent) then
+ Include(HitInfo.HitPositions, hiOnItemButton);
+ end;
+ // no button hit so position is on indent
+ if HitInfo.HitPositions = [] then
+ Include(HitInfo.HitPositions, hiOnItemIndent);
+ end
+ else
+ begin
+ // The next hit positions can be:
+ // - on the check box
+ // - on the state image
+ // - on the normal image
+ // - to the left of the text area
+ // - on the label or
+ // - to the right of the text area
+ // (in this order).
+
+ // In report mode no hit other than in the main column is possible.
+ if MainColumnHit or not (toReportMode in FOptions.FMiscOptions) then
+ begin
+ ImageOffset := Indent + FMargin;
+
+ // Check support is only available for the main column.
+ if MainColumnHit and (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages) and
+ (HitInfo.HitNode.CheckType <> ctNone) then
+ Inc(ImageOffset, FCheckImages.Width + 2);
+
+ if MainColumnHit and (Offset < ImageOffset) then
+ HitInfo.HitPositions := [hiOnItem, hiOnItemCheckBox]
+ else
+ begin
+ if Assigned(FStateImages) and (GetImageIndex(HitInfo.HitNode, ikState, HitInfo.HitColumn, Ghosted) > -1) then
+ Inc(ImageOffset, FStateImages.Width + 2);
+ if Offset < ImageOffset then
+ Include(HitInfo.HitPositions, hiOnStateIcon)
+ else
+ begin
+ if Assigned(FImages) and (GetImageIndex(HitInfo.HitNode, ikNormal, HitInfo.HitColumn, Ghosted) > -1) then
+ Inc(ImageOffset, FImages.Width + 2);
+ if Offset < ImageOffset then
+ Include(HitInfo.HitPositions, hiOnNormalIcon)
+ else
+ begin
+ // ImageOffset contains now the left border of the node label area. This is used to calculate the
+ // correct alignment in the column.
+ TextWidth := DoGetNodeWidth(HitInfo.HitNode, HitInfo.HitColumn);
+
+ // Check if the text can be aligned at all. This is only possible if there is enough room
+ // in the remaining text rectangle.
+ if TextWidth > Right - ImageOffset then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ begin
+ case Alignment of
+ taCenter:
+ begin
+ Indent := (ImageOffset + Right - TextWidth) div 2;
+ if Offset < Indent then
+ Include(HitInfo.HitPositions, hiOnItemLeft)
+ else
+ if Offset < Indent + TextWidth then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ Include(HitInfo.HitPositions, hiOnItemRight)
+ end;
+ taRightJustify:
+ begin
+ Indent := Right - TextWidth;
+ if Offset < Indent then
+ Include(HitInfo.HitPositions, hiOnItemLeft)
+ else
+ Include(HitInfo.HitPositions, hiOnItemLabel);
+ end;
+ else // taLeftJustify
+ if Offset < ImageOffset + TextWidth then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ Include(HitInfo.HitPositions, hiOnItemRight);
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DetermineHitPositionRTL(var HitInfo: THitInfo; Offset, Right: Integer; Alignment: TAlignment);
+
+// This method determines the hit position within a node with right-to-left orientation.
+
+var
+ MainColumnHit,
+ Ghosted: Boolean;
+ Run: PVirtualNode;
+ Indent,
+ TextWidth,
+ ImageOffset: Integer;
+
+begin
+ MainColumnHit := HitInfo.HitColumn = FHeader.MainColumn;
+
+ // If columns are not used or the main column is hit then the tree indentation must be considered too.
+ if MainColumnHit then
+ begin
+ Run := HitInfo.HitNode;
+ while (Run.Parent <> FRoot) do
+ begin
+ Dec(Right, FIndent);
+ Run := Run.Parent;
+ end;
+ if toShowRoot in FOptions.FPaintOptions then
+ Dec(Right, FIndent);
+ end;
+
+ if Offset >= Right then
+ begin
+ // Position is to the right of calculated indentation which can only happen for the main column.
+ // Check whether it corresponds to a button/checkbox.
+ if (toShowButtons in FOptions.FPaintOptions) and (vsHasChildren in HitInfo.HitNode.States) then
+ begin
+ // Position of button is interpreted very generously to avoid forcing the user
+ // to click exactly into the 9x9 pixels area. The entire node height and one full
+ // indentation level is accepted as button hit.
+ if Offset <= Right + Integer(FIndent) then
+ Include(HitInfo.HitPositions, hiOnItemButton);
+ end;
+ // no button hit so position is on indent
+ if HitInfo.HitPositions = [] then
+ Include(HitInfo.HitPositions, hiOnItemIndent);
+ end
+ else
+ begin
+ // The next hit positions can be:
+ // - on the check box
+ // - on the state image
+ // - on the normal image
+ // - to the left of the text area
+ // - on the label or
+ // - to the right of the text area
+ // (in this order).
+
+ // In report mode no hit other than in the main column is possible.
+ if MainColumnHit or not (toReportMode in FOptions.FMiscOptions) then
+ begin
+ ImageOffset := Right - FMargin;
+
+ // Check support is only available for the main column.
+ if MainColumnHit and (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages) and
+ (HitInfo.HitNode.CheckType <> ctNone) then
+ Dec(ImageOffset, FCheckImages.Width + 2);
+
+ if MainColumnHit and (Offset > ImageOffset) then
+ HitInfo.HitPositions := [hiOnItem, hiOnItemCheckBox]
+ else
+ begin
+ if Assigned(FStateImages) and (GetImageIndex(HitInfo.HitNode, ikState, HitInfo.HitColumn, Ghosted) > -1) then
+ Dec(ImageOffset, FStateImages.Width + 2);
+ if Offset > ImageOffset then
+ Include(HitInfo.HitPositions, hiOnStateIcon)
+ else
+ begin
+ if Assigned(FImages) and (GetImageIndex(HitInfo.HitNode, ikNormal, HitInfo.HitColumn, Ghosted) > -1) then
+ Dec(ImageOffset, FImages.Width + 2);
+ if Offset > ImageOffset then
+ Include(HitInfo.HitPositions, hiOnNormalIcon)
+ else
+ begin
+ // ImageOffset contains now the right border of the node label area. This is used to calculate the
+ // correct alignment in the column.
+ TextWidth := DoGetNodeWidth(HitInfo.HitNode, HitInfo.HitColumn);
+
+ // Check if the text can be aligned at all. This is only possible if there is enough room
+ // in the remaining text rectangle.
+ if TextWidth > ImageOffset then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ begin
+ // Consider bidi mode here. In RTL context does left alignment actually mean right alignment
+ // and vice versa.
+ ChangeBiDiModeAlignment(Alignment);
+
+ case Alignment of
+ taCenter:
+ begin
+ Indent := (ImageOffset - TextWidth) div 2;
+ if Offset < Indent then
+ Include(HitInfo.HitPositions, hiOnItemLeft)
+ else
+ if Offset < Indent + TextWidth then
+ Include(HitInfo.HitPositions, hiOnItemLabel)
+ else
+ Include(HitInfo.HitPositions, hiOnItemRight)
+ end;
+ taRightJustify:
+ begin
+ Indent := ImageOffset - TextWidth;
+ if Offset < Indent then
+ Include(HitInfo.HitPositions, hiOnItemLeft)
+ else
+ Include(HitInfo.HitPositions, hiOnItemLabel);
+ end;
+ else // taLeftJustify
+ if Offset > TextWidth then
+ Include(HitInfo.HitPositions, hiOnItemRight)
+ else
+ Include(HitInfo.HitPositions, hiOnItemLabel);
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DetermineNextCheckState(CheckType: TCheckType; CheckState: TCheckState): TCheckState;
+
+// Determines the next check state in case the user click the check image or pressed the space key.
+
+begin
+ case CheckType of
+ ctTriStateCheckBox,
+ ctCheckBox:
+ if CheckState = csCheckedNormal then
+ Result := csUncheckedNormal
+ else
+ Result := csCheckedNormal;
+ ctRadioButton:
+ Result := csCheckedNormal;
+ ctButton:
+ Result := csUncheckedNormal;
+ else
+ Result := csMixedNormal;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DetermineScrollDirections(X, Y: Integer): TScrollDirections;
+
+// Determines which direction the client area must be scrolled depending on the given position.
+
+begin
+ Result:= [];
+
+ if CanAutoScroll then
+ begin
+ // Calculation for wheel panning/scrolling is a bit different to normal auto scroll.
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ if (X - FLastClickPos.X) < -8 then
+ Include(Result, sdLeft);
+ if (X - FLastClickPos.X) > 8 then
+ Include(Result, sdRight);
+
+ if (Y - FLastClickPos.Y) < -8 then
+ Include(Result, sdUp);
+ if (Y - FLastClickPos.Y) > 8 then
+ Include(Result, sdDown);
+ end
+ else
+ begin
+ if (X < Integer(FDefaultNodeHeight)) and (FOffsetX <> 0) then
+ Include(Result, sdLeft);
+ if (ClientWidth - FOffsetX < Integer(FRangeX)) and (X > ClientWidth - Integer(FDefaultNodeHeight)) then
+ Include(Result, sdRight);
+
+ if (Y < Integer(FDefaultNodeHeight)) and (FOffsetY <> 0) then
+ Include(Result, sdUp);
+ if (ClientHeight - FOffsetY < Integer(FRangeY)) and (Y > ClientHeight - Integer(FDefaultNodeHeight)) then
+ Include(Result, sdDown);
+
+ // Since scrolling during dragging is not handled via the timer we do a check here whether the auto
+ // scroll timeout already has elapsed or not.
+ if (Result <> []) and
+ ((Assigned(FDragManager) and DragManager.IsDropTarget) or
+ (FindDragTarget(Point(X, Y), False) = Self)) then
+ begin
+ if FDragScrollStart = 0 then
+ FDragScrollStart := timeGetTime;
+ // Reset any scroll direction to avoid scroll in the case the user is dragging and the auto scroll time has not
+ // yet elapsed.
+ if ((timeGetTime - FDragScrollStart) < FAutoScrollDelay) then
+ Result := [];
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAdvancedHeaderDraw(var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements);
+
+begin
+ if Assigned(FOnAdvancedHeaderDraw) then
+ FOnAdvancedHeaderDraw(FHeader, PaintInfo, Elements);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAfterCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect);
+
+begin
+ if Assigned(FOnAfterCellPaint) then
+ FOnAfterCellPaint(Self, Canvas, Node, Column, CellRect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAfterItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
+
+begin
+ if Assigned(FOnAfterItemErase) then
+ FOnAfterItemErase(Self, Canvas, Node, ItemRect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAfterItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
+
+begin
+ if Assigned(FOnAfterItemPaint) then
+ FOnAfterItemPaint(Self, Canvas, Node, ItemRect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAfterPaint(Canvas: TCanvas);
+
+begin
+ if Assigned(FOnAfterPaint) then
+ FOnAfterPaint(Self, Canvas);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoAutoScroll(X, Y: Integer);
+
+begin
+ FScrollDirections := DetermineScrollDirections(X, Y);
+
+ if FStates * [tsWheelPanning, tsWheelScrolling] = [] then
+ begin
+ if FScrollDirections = [] then
+ begin
+ if ((FStates * [tsScrollPending, tsScrolling]) <> []) then
+ begin
+ StopTimer(ScrollTimer);
+ DoStateChange([], [tsScrollPending, tsScrolling]);
+ end;
+ end
+ else
+ begin
+ // start auto scroll if not yet done
+ if (FStates * [tsScrollPending, tsScrolling]) = [] then
+ begin
+ DoStateChange([tsScrollPending]);
+ SetTimer(Handle, ScrollTimer, FAutoScrollDelay, nil);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoBeforeDrag(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+begin
+ Result := False;
+ if Assigned(FOnDragAllowed) then
+ FOnDragAllowed(Self, Node, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoBeforeCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect);
+
+begin
+ if Assigned(FOnBeforeCellPaint) then
+ FOnBeforeCellPaint(Self, Canvas, Node, Column, CellRect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoBeforeItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect; var Color: TColor;
+ var EraseAction: TItemEraseAction);
+
+begin
+ if Assigned(FOnBeforeItemErase) then
+ FOnBeforeItemErase(Self, Canvas, Node, ItemRect, Color, EraseAction);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoBeforeItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect): Boolean;
+
+begin
+ // By default custom draw will not be used, so the tree handles drawing the node.
+ Result := False;
+ if Assigned(FOnBeforeItemPaint) then
+ FOnBeforeItemPaint(Self, Canvas, Node, ItemRect, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoBeforePaint(Canvas: TCanvas);
+
+begin
+ if Assigned(FOnBeforePaint) then
+ FOnBeforePaint(Self, Canvas);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCancelEdit: Boolean;
+
+// Called when the current edit action or a pending edit must be cancelled.
+
+begin
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ Result := (tsEditing in FStates) and FEditLink.CancelEdit;
+ if Result then
+ begin
+ DoStateChange([], [tsEditing]);
+ if Assigned(FOnEditCancelled) then
+ FOnEditCancelled(Self, FEditColumn);
+ if not (csDestroying in ComponentState) then
+ // Asynchroniously release edit link.
+ PostMessage(Handle, WM_RELEASEEDITLINK, 0, 0);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoCanEdit(Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean);
+
+begin
+ if Assigned(FOnEditing) then
+ FOnEditing(Self, Node, Column, Allowed);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoChange(Node: PVirtualNode);
+
+begin
+ StopTimer(ChangeTimer);
+ if Assigned(FOnChange) then
+ FOnChange(Self, Node);
+
+ // This is a good place to reset the cached node. This is the same as the node passed in here.
+ // This is necessary to allow descentants to override this method and get the node then.
+ DoStateChange([], [tsChangePending]);
+ FLastChangedNode := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoCheckClick(Node: PVirtualNode; NewCheckState: TCheckState);
+
+begin
+ if ChangeCheckState(Node, NewCheckState) then
+ DoChecked(Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoChecked(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnChecked) then
+ FOnChecked(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoChecking(Node: PVirtualNode; var NewCheckState: TCheckState): Boolean;
+
+// Determines if a node is allowed to change its check state to NewCheckState.
+
+begin
+ if toReadOnly in FOptions.FMiscOptions then
+ Result := False
+ else
+ begin
+ Result := True;
+ if Assigned(FOnChecking) then
+ FOnChecking(Self, Node, NewCheckState, Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoCollapsed(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnCollapsed) then
+ FOnCollapsed(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCollapsing(Node: PVirtualNode): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnCollapsing) then
+ FOnCollapsing(Self, Node, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoColumnClick(Column: TColumnIndex; Shift: TShiftState);
+
+begin
+ if Assigned(FOnColumnClick) then
+ FOnColumnClick(Self, Column, Shift);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoColumnDblClick(Column: TColumnIndex; Shift: TShiftState);
+
+begin
+ if Assigned(FOnColumnDblClick) then
+ FOnColumnDblClick(Self, Column, Shift);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoColumnResize(Column: TColumnIndex);
+
+var
+ R: TRect;
+
+begin
+ if not (csLoading in ComponentState) and HandleAllocated then
+ begin
+ UpdateHorizontalScrollBar(True);
+ // Invalidate client area from the current column all to the right.
+ R := ClientRect;
+ if not (toAutoSpanColumns in FOptions.FAutoOptions) then
+ R.Left := FHeader.Columns[Column].Left;
+ InvalidateRect(Handle, @R, False);
+ FHeader.Invalidate(FHeader.Columns[Column], True);
+ if hsTracking in FHeader.States then
+ UpdateWindow(Handle);
+
+ UpdateDesigner; // design time only
+
+ if Assigned(FOnColumnResize) then
+ FOnColumnResize(FHeader, Column);
+
+ // If the tree is currently in edit state then notify edit link.
+ if tsEditing in FStates then
+ UpdateEditBounds;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCompare(Node1, Node2: PVirtualNode; Column: TColumnIndex): Integer;
+
+begin
+ Result := 0;
+ if Assigned(FOnCompareNodes) then
+ FOnCompareNodes(Self, Node1, Node2, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCreateDataObject: IDataObject;
+
+begin
+ Result := nil;
+ if Assigned(FOnCreateDataObject) then
+ FOnCreateDataObject(Self, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCreateDragManager: IVTDragManager;
+
+begin
+ Result := nil;
+ if Assigned(FOnCreateDragManager) then
+ FOnCreateDragManager(Self, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink;
+
+begin
+ Result := nil;
+ if Assigned(FOnCreateEditor) then
+ begin
+ FOnCreateEditor(Self, Node, Column, Result);
+ if Result = nil then
+ ShowError(SEditLinkIsNil, hcTFEditLinkIsNil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoDragging(P: TPoint);
+
+// Initiates finally the drag'n drop operation and returns after DD is finished.
+
+ //--------------- local function --------------------------------------------
+
+ function GetDragOperations: Integer;
+
+ begin
+ if FDragOperations = [] then
+ Result := DROPEFFECT_COPY or DROPEFFECT_MOVE or DROPEFFECT_LINK
+ else
+ begin
+ Result := 0;
+ if doCopy in FDragOperations then
+ Result := Result or DROPEFFECT_COPY;
+ if doLink in FDragOperations then
+ Result := Result or DROPEFFECT_LINK;
+ if doMove in FDragOperations then
+ Result := Result or DROPEFFECT_MOVE;
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ I,
+ DragEffect,
+ AllowedEffects: Integer;
+ DragObject: TDragObject;
+
+ DataObject: IDataObject;
+
+begin
+ DataObject := nil;
+ // Dragging is dragging, nothing else.
+ DoCancelEdit;
+
+ if Assigned(FCurrentHotNode) then
+ begin
+ InvalidateNode(FCurrentHotNode);
+ FCurrentHotNode := nil;
+ end;
+ // Select the focused node if not already done.
+ if Assigned(FFocusedNode) and not (vsSelected in FFocusedNode.States) then
+ begin
+ InternalAddToSelection(FFocusedNode, False);
+ InvalidateNode(FFocusedNode);
+ end;
+
+ UpdateWindow(Handle);
+
+ // Keep a list of all currently selected nodes as this list might change,
+ // but we have probably to delete currently selected nodes.
+ FDragSelection := GetSortedSelection(True);
+ try
+ DoStateChange([tsOLEDragging], [tsOLEDragPending, tsClearPending]);
+
+ // An application might create a drag object like used during VCL dd. This is not required for OLE dd but
+ // required as parameter.
+ DragObject := nil;
+ DoStartDrag(DragObject);
+ DragObject.Free;
+
+ DataObject := DragManager.DataObject;
+ PrepareDragImage(P, DataObject);
+
+ FLastDropMode := dmOnNode;
+ // Don't forget to initialize the result. It might never be touched.
+ DragEffect := DROPEFFECT_NONE;
+ AllowedEffects := GetDragOperations;
+ try
+ ActiveX.DoDragDrop(DataObject, DragManager as IDropSource, AllowedEffects, DragEffect);
+ DragManager.ForceDragLeave;
+ finally
+ GetCursorPos(P);
+ P := ScreenToClient(P);
+ DoEndDrag(Self, P.X, P.Y);
+
+ FDragImage.EndDrag;
+
+ // Finish the operation.
+ if (DragEffect = DROPEFFECT_MOVE) and (toAutoDeleteMovedNodes in TreeOptions.AutoOptions) then
+ begin
+ // The operation was a move so delete the previously selected nodes.
+ BeginUpdate;
+ try
+ // The list of selected nodes was retrieved in resolved state. That means there can never be a node
+ // in the list whose parent (or its parent etc.) is also selected.
+ for I := 0 to High(FDragSelection) do
+ DeleteNode(FDragSelection[I]);
+ finally
+ EndUpdate;
+ end;
+ end;
+
+ DoStateChange([], [tsOLEDragging]);
+ end;
+ finally
+ FDragSelection := nil;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoDragExpand;
+
+var
+ SourceTree: TBaseVirtualTree;
+
+begin
+ StopTimer(ExpandTimer);
+ if Assigned(FDropTargetNode) and (vsHasChildren in FDropTargetNode.States) and
+ not (vsExpanded in FDropTargetNode.States) then
+ begin
+ if Assigned(FDragManager) then
+ SourceTree := DragManager.DragSource
+ else
+ SourceTree := nil;
+
+ if not DragManager.DropTargetHelperSupported and Assigned(SourceTree) then
+ SourceTree.FDragImage.HideDragImage;
+ ToggleNode(FDropTargetNode);
+ UpdateWindow(Handle);
+ if not DragManager.DropTargetHelperSupported and Assigned(SourceTree) then
+ SourceTree.FDragImage.ShowDragImage;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoDragOver(Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode;
+ var Effect: Integer): Boolean;
+
+begin
+ Result := False;
+ if Assigned(FOnDragOver) then
+ FOnDragOver(Self, Source, Shift, State, Pt, Mode, Effect, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoDragDrop(Source: TObject; DataObject: IDataObject; Formats: TFormatArray;
+ Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode);
+
+begin
+ if Assigned(FOnDragDrop) then
+ FOnDragDrop(Self, Source, DataObject, Formats, Shift, Pt, Effect, Mode);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoEdit;
+
+begin
+ Application.CancelHint;
+ StopTimer(ScrollTimer);
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ if Assigned(FFocusedNode) and not (vsDisabled in FFocusedNode.States) and
+ not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ FEditLink := DoCreateEditor(FFocusedNode, FEditColumn);
+ if Assigned(FEditLink) then
+ begin
+ DoStateChange([tsEditing], [tsDrawSelecting, tsDrawSelPending, tsClearFocusedSelection, tsOLEDragPending,
+ tsOLEDragging, tsClearPending, tsDrawSelPending, tsScrollPending, tsScrolling, tsMouseCheckPending]);
+ ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions, True);
+ if FEditLink.PrepareEdit(Self, FFocusedNode, FEditColumn) then
+ begin
+ UpdateEditBounds;
+ // Node needs repaint because the selection rectangle and static text must disappear.
+ InvalidateNode(FFocusedNode);
+ if not FEditLink.BeginEdit then
+ DoStateChange([], [tsEditing]);
+ end
+ else
+ DoStateChange([], [tsEditing]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoEndDrag(Target: TObject; X, Y: Integer);
+
+// Does some housekeeping for VCL drag'n drop;
+
+begin
+ inherited;
+
+ DragFinished;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoEndEdit: Boolean;
+
+begin
+ Result := (tsEditing in FStates) and FEditLink.EndEdit;
+ if Result then
+ begin
+ DoStateChange([], [tsEditing]);
+ // Asynchronously release edit link.
+ PostMessage(Handle, WM_RELEASEEDITLINK, 0, 0);
+ if Assigned(FOnEdited) then
+ FOnEdited(Self, FFocusedNode, FEditColumn);
+ end;
+ DoStateChange([], [tsEditPending]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoExpanded(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnExpanded) then
+ FOnExpanded(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoExpanding(Node: PVirtualNode): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnExpanding) then
+ FOnExpanding(Self, Node, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoFocusChange(Node: PVirtualNode; Column: TColumnIndex);
+
+begin
+ if Assigned(FOnFocusChanged) then
+ FOnFocusChanged(Self, Node, Column);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoFocusChanging(OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnFocusChanging) then
+ FOnFocusChanging(Self, OldNode, NewNode, OldColumn, NewColumn, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoFocusNode(Node: PVirtualNode; Ask: Boolean);
+
+begin
+ if not (tsEditing in FStates) or EndEditNode then
+ begin
+ if Node = FRoot then
+ Node := nil;
+ if (FFocusedNode <> Node) and (not Ask or DoFocusChanging(FFocusedNode, Node, FFocusedColumn, FFocusedColumn)) then
+ begin
+ if Assigned(FFocusedNode) then
+ begin
+ // Do automatic collapsing of last focused node if enabled. This is however only done if
+ // old and new focused node have a common parent node.
+ if (toAutoExpand in FOptions.FAutoOptions) and Assigned(Node) and (Node.Parent = FFocusedNode.Parent) and
+ (vsExpanded in FFocusedNode.States) then
+ ToggleNode(FFocusedNode)
+ else
+ InvalidateNode(FFocusedNode);
+ end;
+ FFocusedNode := Node;
+ end;
+
+ // Have to scroll the node into view, even it is the same node as before.
+ if Assigned(FFocusedNode) then
+ begin
+ // Make sure a valid column is set if columns are used and no column has currently the focus.
+ if FHeader.UseColumns and (FFocusedColumn < 0) then
+ FFocusedColumn := 0;
+ // Do automatic expansion of the newly focused node if enabled.
+ if (toAutoExpand in FOptions.FAutoOptions) and not (vsExpanded in FFocusedNode.States) then
+ ToggleNode(FFocusedNode);
+ InvalidateNode(FFocusedNode);
+ if FUpdateCount = 0 then
+ ScrollIntoView(FFocusedNode, (toCenterScrollIntoView in FOptions.SelectionOptions) and
+ (MouseButtonDown * FStates = []), not (toDisableAutoscrollOnFocus in FOptions.FAutoOptions));
+ end;
+
+ // Reset range anchor if necessary.
+ if FSelectionCount = 0 then
+ ResetRangeAnchor;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoFreeNode(Node: PVirtualNode);
+
+begin
+ if Node = FCurrentHotNode then
+ FCurrentHotNode := nil;
+ if Assigned(FOnFreeNode) and ([vsInitialized, vsInitialUserData] * Node.States <> []) then
+ FOnFreeNode(Self, Node);
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager.FreeNode(Node);
+ {$else}
+ FreeMem(Node);
+ {$endif UseLocalMemoryManager}
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+// These constants are defined in the platform SDK for W2K/XP, but not yet in Delphi.
+const
+ SPI_GETTOOLTIPANIMATION = $1016;
+ SPI_GETTOOLTIPFADE = $1018;
+
+function TBaseVirtualTree.DoGetAnimationType: THintAnimationType;
+
+// Determines (depending on the properties settings and the system) which hint
+// animation type is to be used.
+
+var
+ Animation: BOOL;
+
+begin
+ Result := FAnimationType;
+ if Result = hatSystemDefault then
+ begin
+ if not IsWinNT then
+ Result := hatSlide
+ else
+ begin
+ SystemParametersInfo(SPI_GETTOOLTIPANIMATION, 0, @Animation, 0);
+ if not Animation then
+ Result := hatNone
+ else
+ begin
+ SystemParametersInfo(SPI_GETTOOLTIPFADE, 0, @Animation, 0);
+ if Animation then
+ Result := hatFade
+ else
+ Result := hatSlide;
+ end;
+ end;
+ end;
+
+ // Check availability of MMX if fading is requested.
+ if not MMXAvailable and (Result = hatFade) then
+ Result := hatSlide;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetCursor(var Cursor: TCursor);
+
+begin
+ if Assigned(FOnGetCursor) then
+ FOnGetCursor(Self, Cursor);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetHeaderCursor(var Cursor: HCURSOR);
+
+begin
+ if Assigned(FOnGetHeaderCursor) then
+ FOnGetHeaderCursor(FHeader, Cursor);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean; var Index: Integer);
+
+begin
+ if Assigned(FOnGetImage) then
+ FOnGetImage(Self, Node, Kind, Column, Ghosted, Index);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetLineStyle(var Bits: Pointer);
+
+begin
+ if Assigned(FOnGetLineStyle) then
+ FOnGetLineStyle(Self, Bits);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Result := Hint;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Result := Hint;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;
+
+begin
+ Result := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoGetPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint): TPopupMenu;
+
+// Queries the application whether there is a node specific popup menu.
+
+var
+ Run: PVirtualNode;
+ AskParent: Boolean;
+
+begin
+ Result := nil;
+ if Assigned(FOnGetPopupMenu) then
+ begin
+ Run := Node;
+
+ if Assigned(Run) then
+ begin
+ AskParent := True;
+ repeat
+ FOnGetPopupMenu(Self, Run, Column, Position, AskParent, Result);
+ Run := Run.Parent;
+ until (Run = FRoot) or Assigned(Result) or not AskParent;
+ end
+ else
+ FOnGetPopupMenu(Self, nil, -1, Position, AskParent, Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoGetUserClipboardFormats(var Formats: TFormatEtcArray);
+
+begin
+ if Assigned(FOnGetUserClipboardFormats) then
+ FOnGetUserClipboardFormats(Self, Formats);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderClick(Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderClick) then
+ FOnHeaderClick(FHeader, Column, Button, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDblClick(Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderDblClick) then
+ FOnHeaderDblClick(FHeader, Column, Button, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDragged(Column: TColumnIndex; OldPosition: TColumnPosition);
+
+begin
+ if Assigned(FOnHeaderDragged) then
+ FOnHeaderDragged(FHeader, Column, OldPosition);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDraggedOut(Column: TColumnIndex; DropPosition: TPoint);
+
+begin
+ if Assigned(FOnHeaderDraggedOut) then
+ FOnHeaderDraggedOut(FHeader, Column, DropPosition);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoHeaderDragging(Column: TColumnIndex): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnHeaderDragging) then
+ FOnHeaderDragging(FHeader, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDraw(Canvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover, Pressed: Boolean;
+ DropMark: TVTDropMarkMode);
+
+begin
+ if Assigned(FOnHeaderDraw) then
+ FOnHeaderDraw(FHeader, Canvas, Column, R, Hover, Pressed, DropMark);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderDrawQueryElements(var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements);
+
+begin
+ if Assigned(FOnHeaderDrawQueryElements) then
+ FOnHeaderDrawQueryElements(FHeader, PaintInfo, Elements);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderMouseDown) then
+ FOnHeaderMouseDown(FHeader, Button, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderMouseMove(Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderMouseMove) then
+ FOnHeaderMouseMove(FHeader, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHeaderMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+
+begin
+ if Assigned(FOnHeaderMouseUp) then
+ FOnHeaderMouseUp(FHeader, Button, Shift, X, Y);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoHotChange(Old, New: PVirtualNode);
+
+begin
+ if Assigned(FOnHotChange) then
+ FOnHotChange(Self, Old, New);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoIncrementalSearch(Node: PVirtualNode; const Text: WideString): Integer;
+
+begin
+ Result := 0;
+ if Assigned(FOnIncrementalSearch) then
+ FOnIncrementalSearch(Self, Node, Text, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoInitChildren(Node: PVirtualNode; var ChildCount: Cardinal);
+
+begin
+ if Assigned(FOnInitChildren) then
+ FOnInitChildren(Self, Node, ChildCount);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoInitNode(Parent, Node: PVirtualNode; var InitStates: TVirtualNodeInitStates);
+
+begin
+ if Assigned(FOnInitNode) then
+ FOnInitNode(Self, Parent, Node, InitStates);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoKeyAction(var CharCode: Word; var Shift: TShiftState): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnKeyAction) then
+ FOnKeyAction(Self, CharCode, Shift, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoLoadUserData(Node: PVirtualNode; Stream: TStream);
+
+begin
+ if Assigned(FOnLoadNode) then
+ if Node = FRoot then
+ FOnLoadNode(Self, nil, Stream)
+ else
+ FOnLoadNode(Self, Node, Stream);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoNodeCopied(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnNodeCopied) then
+ FOnNodeCopied(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoNodeCopying(Node, NewParent: PVirtualNode): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnNodeCopying) then
+ FOnNodeCopying(Self, Node, NewParent, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoNodeMoved(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnNodeMoved) then
+ FOnNodeMoved(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoNodeMoving(Node, NewParent: PVirtualNode): Boolean;
+
+begin
+ Result := True;
+ if Assigned(FOnNodeMoving) then
+ FOnNodeMoving(Self, Node, NewParent, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoPaintBackground(Canvas: TCanvas; R: TRect): Boolean;
+
+begin
+ Result := False;
+ if Assigned(FOnPaintBackground) then
+ FOnPaintBackground(Self, Canvas, R, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoPaintDropMark(Canvas: TCanvas; Node: PVirtualNode; R: TRect);
+
+// draws the drop mark into the given rectangle
+// Note: Changed properties of the given canvas should be reset to their previous values.
+
+var
+ SaveBrushColor: TColor;
+ SavePenStyle: TPenStyle;
+
+begin
+ if FLastDropMode in [dmAbove, dmBelow] then
+ with Canvas do
+ begin
+ SavePenStyle := Pen.Style;
+ Pen.Style := psClear;
+ SaveBrushColor := Brush.Color;
+ Brush.Color := FColors.DropMarkColor;
+
+ if FLastDropMode = dmAbove then
+ begin
+ Polygon([Point(R.Left + 2, R.Top),
+ Point(R.Right - 2, R.Top),
+ Point(R.Right - 2, R.Top + 6),
+ Point(R.Right - 6, R.Top + 2),
+ Point(R.Left + 6 , R.Top + 2),
+ Point(R.Left + 2, R.Top + 6)
+ ]);
+ end
+ else
+ Polygon([Point(R.Left + 2, R.Bottom - 1),
+ Point(R.Right - 2, R.Bottom - 1),
+ Point(R.Right - 2, R.Bottom - 8),
+ Point(R.Right - 7, R.Bottom - 3),
+ Point(R.Left + 7 , R.Bottom - 3),
+ Point(R.Left + 2, R.Bottom - 8)
+ ]);
+ Brush.Color := SaveBrushColor;
+ Pen.Style := SavePenStyle;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoPaintNode(var PaintInfo: TVTPaintInfo);
+
+begin
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint);
+
+// Support for node dependent popup menus.
+
+var
+ Menu: TPopupMenu;
+
+begin
+ Menu := DoGetPopupMenu(Node, Column, Position);
+
+ if Assigned(Menu) then
+ begin
+ StopTimer(EditTimer);
+ Menu.PopupComponent := Self;
+ with ClientToScreen(Position) do
+ Menu.Popup(X, Y);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoRenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean): HRESULT;
+
+begin
+ Result := E_FAIL;
+ if Assigned(FOnRenderOLEData) then
+ FOnRenderOLEData(Self, FormatEtcIn, Medium, ForClipboard, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoReset(Node: PVirtualNode);
+
+begin
+ if Assigned(FOnResetNode) then
+ FOnResetNode(Self, Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoSaveUserData(Node: PVirtualNode; Stream: TStream);
+
+begin
+ if Assigned(FOnSaveNode) then
+ if Node = FRoot then
+ FOnSaveNode(Self, nil, Stream)
+ else
+ FOnSaveNode(Self, Node, Stream);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoScroll(DeltaX, DeltaY: Integer);
+
+begin
+ if Assigned(FOnScroll) then
+ FOnScroll(Self, DeltaX, DeltaY);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoSetOffsetXY(Value: TPoint; Options: TScrollUpdateOptions; ClipRect: PRect = nil): Boolean;
+
+// Actual offset setter used to scroll the client area, update scroll bars and invalidating the header (all optional).
+// Returns True if the offset really changed otherwise False is returned.
+
+var
+ DeltaX: Integer;
+ DeltaY: Integer;
+ DWPStructure: HDWP;
+ I: Integer;
+ P: TPoint;
+
+begin
+ // Range check, order is important here.
+ if Value.X < (ClientWidth - Integer(FRangeX)) then
+ Value.X := ClientWidth - Integer(FRangeX);
+ if Value.X > 0 then
+ Value.X := 0;
+ DeltaX := Value.X - FOffsetX;
+ if Value.Y < (ClientHeight - Integer(FRangeY)) then
+ Value.Y := ClientHeight - Integer(FRangeY);
+ if Value.Y > 0 then
+ Value.Y := 0;
+ DeltaY := Value.Y - FOffsetY;
+
+ Result := (DeltaX <> 0) or (DeltaY <> 0);
+ if Result then
+ begin
+ FOffsetX := Value.X;
+ FOffsetY := Value.Y;
+ Result := True;
+
+ if FUpdateCount = 0 then
+ begin
+ // The drag image from VCL controls need special consideration.
+ if tsVCLDragging in FStates then
+ ImageList_DragShowNolock(False);
+
+ if suoScrollClientArea in Options then
+ begin
+ // Have to invalidate the entire window if there's a background.
+ if (toShowBackground in FOptions.FPaintOptions) and (FBackground.Graphic is TBitmap) then
+ begin
+ // Since we don't use ScrollWindow here we have to move all client windows ourselves.
+ DWPStructure := BeginDeferWindowPos(ControlCount);
+ for I := 0 to ControlCount - 1 do
+ if Controls[I] is TWinControl then
+ begin
+ with Controls[I] as TWinControl do
+ DWPStructure := DeferWindowPos(DWPStructure, Handle, 0, Left + DeltaX, Top + DeltaY, 0, 0,
+ SWP_NOZORDER or SWP_NOACTIVATE or SWP_NOSIZE);
+ if DWPStructure = 0 then
+ Break;
+ end;
+ if DWPStructure <> 0 then
+ EndDeferWindowPos(DWPStructure);
+ InvalidateRect(Handle, nil, False);
+ end
+ else
+ ScrollWindow(Handle, DeltaX, DeltaY, ClipRect, ClipRect);
+ end;
+
+ if suoUpdateNCArea in Options then
+ begin
+ if DeltaX <> 0 then
+ begin
+ if (suoRepaintHeader in Options) and (hoVisible in FHeader.FOptions) then
+ FHeader.Invalidate(nil);
+ if not (tsSizing in FStates) and (FScrollBarOptions.ScrollBars in [ssHorizontal, ssBoth]) then
+ UpdateHorizontalScrollBar(suoRepaintScrollbars in Options);
+ end;
+
+ if (DeltaY <> 0) and ([tsThumbTracking, tsSizing] * FStates = []) then
+ begin
+ UpdateVerticalScrollBar(suoRepaintScrollbars in Options);
+ if not (FHeader.UseColumns or IsMouseSelecting) and
+ (FScrollBarOptions.ScrollBars in [ssHorizontal, ssBoth]) then
+ UpdateHorizontalScrollBar(suoRepaintScrollbars in Options);
+ end;
+ end;
+
+ if tsVCLDragging in FStates then
+ ImageList_DragShowNolock(True);
+ end;
+
+ // Finally update "hot" node if hot tracking is activated
+ GetCursorPos(P);
+ P := ScreenToClient(P);
+ if PtInRect(ClientRect, P) then
+ HandleHotTrack(P.X, P.Y);
+
+ DoScroll(DeltaX, DeltaY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoStartDrag(var DragObject: TDragObject);
+
+begin
+ inherited;
+
+ // Check if the application created an own drag object. This is needed to pass the correct source in
+ // OnDragOver and OnDragDrop.
+ if Assigned(DragObject) then
+ DoStateChange([tsUserDragObject]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoStateChange(Enter: TVirtualTreeStates; Leave: TVirtualTreeStates = []);
+
+var
+ ActualEnter,
+ ActualLeave: TVirtualTreeStates;
+
+begin
+ if Assigned(FOnStateChange) then
+ begin
+ ActualEnter := Enter - FStates;
+ ActualLeave := FStates * Leave;
+ if (ActualEnter + ActualLeave) <> [] then
+ FOnStateChange(Self, Enter, Leave);
+ end;
+ FStates := FStates + Enter - Leave;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoStructureChange(Node: PVirtualNode; Reason: TChangeReason);
+
+begin
+ StopTimer(StructureChangeTimer);
+ if Assigned(FOnStructureChange) then
+ FOnStructureChange(Self, Node, Reason);
+
+ // This is a good place to reset the cached node and reason. These are the same as the values passed in here.
+ // This is necessary to allow descentants to override this method and get them.
+ DoStateChange([], [tsStructureChangePending]);
+ FLastStructureChangeNode := nil;
+ FLastStructureChangeReason := crIgnore;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoTimerScroll;
+
+var
+ P,
+ ClientP: TPoint;
+ InRect,
+ Panning: Boolean;
+ R,
+ ClipRect: TRect;
+ DeltaX,
+ DeltaY: Integer;
+
+begin
+ GetCursorPos(P);
+ R := ClientRect;
+ ClipRect := R;
+ MapWindowPoints(Handle, 0, R, 2);
+ InRect := PtInRect(R, P);
+ ClientP := ScreenToClient(P);
+ Panning := [tsWheelPanning, tsWheelScrolling] * FStates <> [];
+
+ if IsMouseSelecting or InRect or ([tsWheelPanning, tsWheelScrolling] * FStates <> []) then
+ begin
+ DeltaX := 0;
+ DeltaY := 0;
+ if sdUp in FScrollDirections then
+ begin
+ if Panning then
+ DeltaY := FLastClickPos.Y - ClientP.Y - 8
+ else
+ if InRect then
+ DeltaY := Min(FScrollBarOptions.FIncrementY, ClientHeight)
+ else
+ DeltaY := Min(FScrollBarOptions.FIncrementY, ClientHeight) * Abs(R.Top - P.Y);
+ if FOffsetY = 0 then
+ Exclude(FScrollDirections, sdUp);
+ end;
+
+ if sdDown in FScrollDirections then
+ begin
+ if Panning then
+ DeltaY := FLastClickPos.Y - ClientP.Y + 8
+ else
+ if InRect then
+ DeltaY := -Min(FScrollBarOptions.FIncrementY, ClientHeight)
+ else
+ DeltaY := -Min(FScrollBarOptions.FIncrementY, ClientHeight) * Abs(P.Y - R.Bottom);
+ if (ClientHeight - FOffsetY) = Integer(FRangeY) then
+ Exclude(FScrollDirections, sdDown);
+ end;
+
+ if sdLeft in FScrollDirections then
+ begin
+ if Panning then
+ DeltaX := FLastClickPos.X - ClientP.X - 8
+ else
+ if InRect then
+ DeltaX := FScrollBarOptions.FIncrementX
+ else
+ DeltaX := FScrollBarOptions.FIncrementX * Abs(R.Left - P.X);
+ if FOffsetX = 0 then
+ Exclude(FScrollDirections, sdleft);
+ end;
+
+ if sdRight in FScrollDirections then
+ begin
+ if Panning then
+ DeltaX := FLastClickPos.X - ClientP.X + 8
+ else
+ if InRect then
+ DeltaX := -FScrollBarOptions.FIncrementX
+ else
+ DeltaX := -FScrollBarOptions.FIncrementX * Abs(P.X - R.Right);
+
+ if (ClientWidth - FOffsetX) = Integer(FRangeX) then
+ Exclude(FScrollDirections, sdRight);
+ end;
+
+ if IsMouseSelecting then
+ begin
+ // In order to avoid scrolling the area which needs a repaint due to the changed selection rectangle
+ // we limit the scroll area explicitely.
+ OffsetRect(ClipRect, DeltaX, DeltaY);
+ DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), DefaultScrollUpdateFlags, @ClipRect);
+ // When selecting with the mouse then either update only the parts of the window which have been uncovered
+ // by the scroll operation if no change in the selection happend or invalidate and redraw the entire
+ // client area otherwise (to avoid the time consuming task of determining the display rectangles of every
+ // changed node).
+ if CalculateSelectionRect(ClientP.X, ClientP.Y) and HandleDrawSelection(ClientP.X, ClientP.Y) then
+ InvalidateRect(Handle, nil, False)
+ else
+ begin
+ // The selection did not change so invalidate only the part of the window which really needs an update.
+ // 1) Invalidate the parts uncovered by the scroll operation. Add another offset range, we have to
+ // scroll only one stripe but have to update two.
+ OffsetRect(ClipRect, DeltaX, DeltaY);
+ SubtractRect(ClipRect, ClientRect, ClipRect);
+ InvalidateRect(Handle, @ClipRect, False);
+
+ // 2) Invalidate the selection rectangles.
+ UnionRect(ClipRect, OrderRect(FNewSelRect), OrderRect(FLastSelRect));
+ OffsetRect(ClipRect, FOffsetX, FOffsetY);
+ InvalidateRect(Handle, @ClipRect, False);
+ end;
+ end
+ else
+ begin
+ // Scroll only if there is no drag'n drop in progress. Drag'n drop scrolling is handled in DragOver.
+ if ((FDragManager = nil) or not DragManager.IsDropTarget) and ((DeltaX <> 0) or (DeltaY <> 0)) then
+ DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), DefaultScrollUpdateFlags, nil);
+ end;
+ UpdateWindow(Handle);
+
+ if (FScrollDirections = []) and ([tsWheelPanning, tsWheelScrolling] * FStates = []) then
+ begin
+ StopTimer(ScrollTimer);
+ DoStateChange([], [tsScrollPending, tsScrolling]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DoUpdating(State: TVTUpdateState);
+
+begin
+ if Assigned(FOnUpdating) then
+ FOnUpdating(Self, State);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DoValidateCache: Boolean;
+
+// This method fills the caches used in various situations to speed up search for nodes.
+// The strategy is simple: Take the current number of visible nodes and distribute evenly a number of marks
+// (which are stored in FPositionCache) so that iterating through the tree doesn't cost too much time.
+// If there are less than 'CacheThreshold' nodes in the tree then the cache remains empty.
+// Result is True if the cache was filled without interruption, otherwise False.
+// Note: You can adjust the maximum number of nodes between two cache entries by changing CacheThreshold.
+
+var
+ EntryCount,
+ CurrentTop,
+ Index: Cardinal;
+ CurrentNode,
+ Temp: PVirtualNode;
+
+begin
+ EntryCount := 0;
+ if not (tsStopValidation in FStates) then
+ begin
+ if FStartIndex = 0 then
+ FPositionCache := nil;
+
+ if FVisibleCount > CacheThreshold then
+ begin
+ EntryCount := CalculateCacheEntryCount;
+ SetLength(FPositionCache, EntryCount);
+ if FStartIndex > EntryCount then
+ FStartIndex := EntryCount;
+
+ // Optimize validation by starting with FStartIndex if set.
+ if (FStartIndex > 0) and Assigned(FPositionCache[FStartIndex - 1].Node) then
+ begin
+ // Index is the current entry in FPositionCache.
+ Index := FStartIndex - 1;
+ // Running term for absolute top value.
+ CurrentTop := FPositionCache[Index].AbsoluteTop;
+ // Running node pointer.
+ CurrentNode := FPositionCache[Index].Node;
+ end
+ else
+ begin
+ // Index is the current entry in FPositionCache.
+ Index := 0;
+ // Running term for absolute top value.
+ CurrentTop := 0;
+ // Running node pointer.
+ CurrentNode := GetFirstVisibleNoInit;
+ end;
+
+ // EntryCount serves as counter for processed nodes here. This value can always start at 0 as
+ // the validation either starts also at index 0 or an index which is always a multiple of CacheThreshold
+ // and EntryCount is only used with modulo CacheThreshold.
+ EntryCount := 0;
+ if Assigned(CurrentNode) then
+ begin
+ while not (tsStopValidation in FStates) do
+ begin
+ if (EntryCount mod CacheThreshold) = 0 then
+ begin
+ // New cache entry to set up.
+ with FPositionCache[Index] do
+ begin
+ Node := CurrentNode;
+ AbsoluteTop := CurrentTop;
+ end;
+ Inc(Index);
+ end;
+
+ Inc(CurrentTop, CurrentNode.NodeHeight);
+ // Advance to next visible node.
+ Temp := GetNextVisibleNoInit(CurrentNode);
+ // If there is no further node or the cache is full then stop the loop.
+ if (Temp = nil) or (Integer(Index) = Length(FPositionCache)) then
+ Break;
+
+ CurrentNode := Temp;
+ Inc(EntryCount);
+ end;
+ end;
+ // Finalize the position cache so no nil entry remains there.
+ if not (tsStopValidation in FStates) and (Integer(Index) <= High(FPositionCache)) then
+ begin
+ SetLength(FPositionCache, Index + 1);
+ with FPositionCache[Index] do
+ begin
+ Node := CurrentNode;
+ AbsoluteTop := CurrentTop;
+ end;
+ end;
+ end;
+ end;
+
+ Result := EntryCount > 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DragCanceled;
+
+// Does some housekeeping for VCL drag'n drop;
+
+begin
+ inherited;
+
+ DragFinished;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DragDrop(const DataObject: IDataObject; KeyState: Integer; Pt: TPoint;
+ var Effect: Integer): HResult;
+
+var
+ Shift: TShiftState;
+ EnumFormat: IEnumFormatEtc;
+ Fetched: Integer;
+ OLEFormat: TFormatEtc;
+ Formats: TFormatArray;
+
+begin
+ StopTimer(ExpandTimer);
+ StopTimer(ScrollTimer);
+ DoStateChange([], [tsScrollPending, tsScrolling]);
+ Formats := nil;
+
+ // Ask explicitly again whether the action is allowed. Otherwise we may accept a drop which is intentionally not
+ // allowed but cannot be prevented by the application because when the tree was scrolling while dropping
+ // no DragOver event is created by the OLE subsystem.
+ Result := DragOver(DragManager.DragSource, KeyState, dsDragMove, Pt, Effect);
+ try
+ if (Result <> NOERROR) or ((Effect and not DROPEFFECT_SCROLL) = DROPEFFECT_NONE) then
+ Result := E_FAIL
+ else
+ begin
+ try
+ Shift := KeysToShiftState(KeyState);
+ Pt := ScreenToClient(Pt);
+ // Determine which formats we can get and pass them along with the data object to the drop handler.
+ Result := DataObject.EnumFormatEtc(DATADIR_GET, EnumFormat);
+ if Failed(Result) then
+ Abort;
+ Result := EnumFormat.Reset;
+ if Failed(Result) then
+ Abort;
+ // create a list of available formats
+ while EnumFormat.Next(1, OLEFormat, @Fetched) = S_OK do
+ begin
+ SetLength(Formats, Length(Formats) + 1);
+ Formats[High(Formats)] := OLEFormat.cfFormat;
+ end;
+ DoDragDrop(DragManager.DragSource, DataObject, Formats, Shift, Pt, Effect, FLastDropMode);
+ except
+ Result := E_UNEXPECTED;
+ raise;
+ end;
+ end;
+ finally
+ if Assigned(FDropTargetNode) then
+ begin
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := nil;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DragEnter(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult;
+
+// callback routine for the drop target interface
+
+var
+ Shift: TShiftState;
+ Accept: Boolean;
+ R: TRect;
+ HitInfo: THitInfo;
+
+begin
+ try
+ // Determine acceptance of drag operation and reset scroll start time.
+ FDragScrollStart := 0;
+
+ Shift := KeysToShiftState(KeyState);
+ Pt := ScreenToClient(Pt);
+ Effect := SuggestDropEffect(DragManager.DragSource, Shift, Pt, Effect);
+ Accept := DoDragOver(DragManager.DragSource, Shift, dsDragEnter, Pt, FLastDropMode, Effect);
+ if not Accept then
+ Effect := DROPEFFECT_NONE
+ else
+ begin
+ // Set initial drop target node and drop mode.
+ GetHitTestInfoAt(Pt.X, Pt.Y, True, HitInfo);
+ if Assigned(HitInfo.HitNode) then
+ begin
+ FDropTargetNode := HitInfo.HitNode;
+ R := GetDisplayRect(HitInfo.HitNode, FHeader.MainColumn, False);
+ if hiOnItemLabel in HitInfo.HitPositions then
+ FLastDropMode := dmOnNode
+ else
+ if ((R.Top + R.Bottom) div 2) > Pt.Y then
+ FLastDropMode := dmAbove
+ else
+ FLastDropMode := dmBelow;
+ end
+ else
+ FLastDropMode := dmNowhere;
+ end;
+
+ // If the drag source is a virtual tree then we know how to control the drag image
+ // and can show it even if the source is not the target tree.
+ // This is only necessary if we cannot use the drag image helper interfaces.
+ if not DragManager.DropTargetHelperSupported and Assigned(DragManager.DragSource) then
+ DragManager.DragSource.FDragImage.ShowDragImage;
+ Result := NOERROR;
+ except
+ Result := E_UNEXPECTED;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DragFinished;
+
+// Called by DragCancelled or EndDrag to make up for the still missing mouse button up messages.
+// These are important for such important things like popup menus.
+
+var
+ P: TPoint;
+
+begin
+ GetCursorPos(P);
+ P := ScreenToClient(P);
+ if tsRightButtonDown in FStates then
+ Perform(WM_RBUTTONUP, 0, Longint(PointToSmallPoint(P)))
+ else
+ if tsMiddleButtonDown in FStates then
+ Perform(WM_MBUTTONUP, 0, Longint(PointToSmallPoint(P)))
+ else
+ Perform(WM_LBUTTONUP, 0, Longint(PointToSmallPoint(P)));
+ DoStateChange([], [tsVCLDragPending, tsVCLDragging, tsUserDragObject]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DragLeave;
+
+var
+ Effect: Integer;
+
+begin
+ StopTimer(ExpandTimer);
+
+ if not DragManager.DropTargetHelperSupported and Assigned(DragManager.DragSource) then
+ DragManager.DragSource.FDragImage.HideDragImage;
+
+ if Assigned(FDropTargetNode) then
+ begin
+ InvalidateNode(FDropTargetNode);
+ FDropTargetNode := nil;
+ end;
+ UpdateWindow(Handle);
+
+ Effect := 0;
+ DoDragOver(nil, [], dsDragLeave, Point(0, 0), FLastDropMode, Effect);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.DragOver(Source: TObject; KeyState: Integer; DragState: TDragState; Pt: TPoint;
+ var Effect: Integer): HResult;
+
+// callback routine for the drop target interface
+
+var
+ Shift: TShiftState;
+ Accept,
+ DragImageWillMove,
+ WindowScrolled: Boolean;
+ OldR, R: TRect;
+ NewDropMode: TDropMode;
+ HitInfo: THitInfo;
+ ImageHit: Boolean;
+ LabelHit: Boolean;
+ DragPos: TPoint;
+ Tree: TBaseVirtualTree;
+ LastNode: PVirtualNode;
+
+ DeltaX,
+ DeltaY: Integer;
+ ScrollOptions: TScrollUpdateOptions;
+
+begin
+ if not DragManager.DropTargetHelperSupported and (Source is TBaseVirtualTree) then
+ begin
+ Tree := Source as TBaseVirtualTree;
+ ScrollOptions := [suoUpdateNCArea];
+ end
+ else
+ begin
+ Tree := nil;
+ ScrollOptions := DefaultScrollUpdateFlags;
+ end;
+
+ try
+ DragPos := Pt;
+ Pt := ScreenToClient(Pt);
+
+ // Check if we have to scroll the client area.
+ FScrollDirections := DetermineScrollDirections(Pt.X, Pt.Y);
+ DeltaX := 0;
+ DeltaY := 0;
+ if FScrollDirections <> [] then
+ begin
+ // Determine amount to scroll.
+ if sdUp in FScrollDirections then
+ begin
+ DeltaY := Min(FScrollBarOptions.FIncrementY, ClientHeight);
+ if FOffsetY = 0 then
+ Exclude(FScrollDirections, sdUp);
+ end;
+ if sdDown in FScrollDirections then
+ begin
+ DeltaY := -Min(FScrollBarOptions.FIncrementY, ClientHeight);
+ if (ClientHeight - FOffsetY) = Integer(FRangeY) then
+ Exclude(FScrollDirections, sdDown);
+ end;
+ if sdLeft in FScrollDirections then
+ begin
+ DeltaX := FScrollBarOptions.FIncrementX;
+ if FOffsetX = 0 then
+ Exclude(FScrollDirections, sdleft);
+ end;
+ if sdRight in FScrollDirections then
+ begin
+ DeltaX := -FScrollBarOptions.FIncrementX;
+ if (ClientWidth - FOffsetX) = Integer(FRangeX) then
+ Exclude(FScrollDirections, sdRight);
+ end;
+ WindowScrolled := DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), ScrollOptions, nil);
+ end
+ else
+ WindowScrolled := False;
+
+ // Determine acceptance of drag operation as well as drag target.
+ Shift := KeysToShiftState(KeyState);
+ GetHitTestInfoAt(Pt.X, Pt.Y, True, HitInfo);
+ ImageHit := HitInfo.HitPositions * [hiOnNormalIcon, hiOnStateIcon] <> [];
+ LabelHit := hiOnItemLabel in HitInfo.HitPositions;
+ // In report mode only direct hits of the node captions/images in the main column are accepted as hits.
+ if (toReportMode in FOptions.MiscOptions) and not ((LabelHit or ImageHit) and
+ (HitInfo.HitColumn = FHeader.MainColumn)) then
+ HitInfo.HitNode := nil;
+
+ if Assigned(HitInfo.HitNode) then
+ begin
+ R := GetDisplayRect(HitInfo.HitNode, NoColumn, False);
+ if LabelHit or ImageHit or not (toShowDropmark in FOptions.FPaintOptions) then
+ NewDropMode := dmOnNode
+ else
+ if ((R.Top + R.Bottom) div 2) > Pt.Y then
+ NewDropMode := dmAbove
+ else
+ NewDropMode := dmBelow;
+ end
+ else
+ begin
+ NewDropMode := dmNowhere;
+ R := Rect(0, 0, 0, 0);
+ end;
+
+ if Assigned(Tree) then
+ DragImageWillMove := Tree.FDragImage.WillMove(DragPos)
+ else
+ DragImageWillMove := False;
+
+ if (HitInfo.HitNode <> FDropTargetNode) or (FLastDropMode <> NewDropMode) then
+ begin
+ // Something in the tree will change. This requires to update the screen and/or the drag image.
+ FLastDropMode := NewDropMode;
+ if HitInfo.HitNode <> FDropTargetNode then
+ begin
+ StopTimer(ExpandTimer);
+ // The last target node is needed for the rectangle determination but must already be set for
+ // the recapture call, hence it must be stored somewhere.
+ LastNode := FDropTargetNode;
+ FDropTargetNode := HitInfo.HitNode;
+ // In order to show a selection rectangle a column must be focused.
+ if FFocusedColumn = NoColumn then
+ FFocusedColumn := FHeader.MainColumn;
+
+ if Assigned(LastNode) and Assigned(FDropTargetNode) then
+ begin
+ // Optimize the case that the selection moved between two nodes.
+ OldR := GetDisplayRect(LastNode, NoColumn, False);
+ UnionRect(R, R, OldR);
+ if Assigned(Tree) then
+ begin
+ if WindowScrolled then
+ UpdateWindowAndDragImage(Tree, ClientRect, True, not DragImageWillMove)
+ else
+ UpdateWindowAndDragImage(Tree, R, False, not DragImageWillMove);
+ end
+ else
+ InvalidateRect(Handle, @R, False);
+ end
+ else
+ begin
+ if Assigned(LastNode) then
+ begin
+ // Repaint last target node.
+ OldR := GetDisplayRect(LastNode, NoColumn, False);
+ if Assigned(Tree) then
+ begin
+ if WindowScrolled then
+ UpdateWindowAndDragImage(Tree, ClientRect, WindowScrolled, not DragImageWillMove)
+ else
+ UpdateWindowAndDragImage(Tree, OldR, False, not DragImageWillMove);
+ end
+ else
+ InvalidateRect(Handle, @OldR, False);
+ end
+ else
+ begin
+ if Assigned(Tree) then
+ begin
+ if WindowScrolled then
+ UpdateWindowAndDragImage(Tree, ClientRect, WindowScrolled, not DragImageWillMove)
+ else
+ UpdateWindowAndDragImage(Tree, R, False, not DragImageWillMove);
+ end
+ else
+ InvalidateRect(Handle, @R, False);
+ end;
+ end;
+
+ // Start auto expand timer if necessary.
+ if (toAutoDropExpand in FOptions.FAutoOptions) and Assigned(FDropTargetNode) and
+ (vsHasChildren in FDropTargetNode.States) then
+ SetTimer(Handle, ExpandTimer, FAutoExpandDelay, nil);
+ end
+ else
+ begin
+ // Only the drop mark position changed so invalidate the current drop target node.
+ if Assigned(Tree) then
+ begin
+ if WindowScrolled then
+ UpdateWindowAndDragImage(Tree, ClientRect, WindowScrolled, not DragImageWillMove)
+ else
+ UpdateWindowAndDragImage(Tree, R, False, not DragImageWillMove);
+ end
+ else
+ InvalidateRect(Handle, @R, False);
+ end;
+ end
+ else
+ begin
+ // No change in the current drop target or drop mode. This might still mean horizontal or vertical scrolling.
+ if Assigned(Tree) and ((DeltaX <> 0) or (DeltaY <> 0)) then
+ UpdateWindowAndDragImage(Tree, ClientRect, WindowScrolled, not DragImageWillMove);
+ end;
+
+ Update;
+
+ if Assigned(Tree) and DragImageWillMove then
+ Tree.FDragImage.DragTo(DragPos, False);
+
+ Effect := SuggestDropEffect(Source, Shift, Pt, Effect);
+ Accept := DoDragOver(Source, Shift, DragState, Pt, FLastDropMode, Effect);
+ if not Accept then
+ Effect := DROPEFFECT_NONE;
+ if WindowScrolled then
+ Effect := Effect or Integer(DROPEFFECT_SCROLL);
+ Result := NOERROR;
+ except
+ Result := E_UNEXPECTED;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DrawDottedHLine(const PaintInfo: TVTPaintInfo; Left, Right, Top: Integer);
+
+// Draws a horizontal line with alternating pixels (this style is not supported for pens under Win9x).
+
+var
+ R: TRect;
+
+begin
+ with PaintInfo, Canvas do
+ begin
+ Brush.Color := Color;
+ R := Rect(Min(Left, Right), Top, Max(Left, Right) + 1, Top + 1);
+ Windows.FillRect(Handle, R, FDottedBrush);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DrawDottedVLine(const PaintInfo: TVTPaintInfo; Top, Bottom, Left: Integer);
+
+// Draws a horizontal line with alternating pixels (this style is not supported for pens under Win9x).
+
+var
+ R: TRect;
+
+begin
+ with PaintInfo, Canvas do
+ begin
+ Brush.Color := Color;
+ R := Rect(Left, Min(Top, Bottom), Left + 1, Max(Top, Bottom) + 1);
+ Windows.FillRect(Handle, R, FDottedBrush);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.FindNodeInSelection(P: PVirtualNode; var Index: Integer; LowBound,
+ HighBound: Integer): Boolean;
+
+// Search routine to find a specific node in the selection array.
+// LowBound and HighBound determine the range in which to search the node.
+// Either value can be -1 to denote the maximum range otherwise LowBound must be less or equal HighBound.
+
+var
+ L, H,
+ I, C: Integer;
+
+begin
+ Result := False;
+ L := 0;
+ if LowBound >= 0 then
+ L := LowBound;
+ H := FSelectionCount - 1;
+ if HighBound >= 0 then
+ H := HighBound;
+ while L <= H do
+ begin
+ I := (L + H) shr 1;
+ C := Integer(FSelection[I]) - Integer(P);
+ if C < 0 then
+ L := I + 1
+ else
+ begin
+ H := I - 1;
+ if C = 0 then
+ begin
+ Result := True;
+ L := I;
+ end;
+ end;
+ end;
+ Index := L;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FinishChunkHeader(Stream: TStream; StartPos, EndPos: Integer);
+
+// used while streaming out a node to finally write out the size of the chunk
+
+var
+ Size: Integer;
+
+begin
+ // seek back to the second entry in the chunk header
+ Stream.Position := StartPos + SizeOf(Integer);
+ // determine size of chunk without the chunk header
+ Size := EndPos - StartPos - SizeOf(TChunkHeader);
+ // write the size...
+ Stream.Write(Size, SizeOf(Size));
+ // ... and seek to the last endposition
+ Stream.Position := EndPos;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FontChanged(AFont: TObject);
+
+// Little helper function for font changes (as they are not tracked in TBitmap/TCanvas.OnChange).
+
+begin
+ FFontChanged := True;
+ FOldFontChange(AFont);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetCheckImage(Node: PVirtualNode): Integer;
+
+// Determines the index into the check image list for the given node depending on the check type
+// and enabled state.
+
+const
+ // Four dimensional array consisting of image indices for the check type, the check state, the enabled state and the
+ // hot state.
+ CheckStateToCheckImage: array[ctCheckBox..ctButton, csUncheckedNormal..csMixedPressed, Boolean, Boolean] of Integer = (
+ // ctCheckBox, ctTriStateCheckBox
+ (
+ // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckCheckUncheckedDisabled, ckCheckUncheckedDisabled), (ckCheckUncheckedNormal, ckCheckUncheckedHot)),
+ // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckCheckUncheckedDisabled, ckCheckUncheckedDisabled), (ckCheckUncheckedPressed, ckCheckUncheckedPressed)),
+ // csCheckedNormal
+ ((ckCheckCheckedDisabled, ckCheckCheckedDisabled), (ckCheckCheckedNormal, ckCheckCheckedHot)),
+ // csCheckedPressed
+ ((ckCheckCheckedDisabled, ckCheckCheckedDisabled), (ckCheckCheckedPressed, ckCheckCheckedPressed)),
+ // csMixedNormal
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)),
+ // csMixedPressed
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed))
+ ),
+ // ctRadioButton
+ (
+ // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckRadioUncheckedDisabled, ckRadioUncheckedDisabled), (ckRadioUncheckedNormal, ckRadioUncheckedHot)),
+ // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckRadioUncheckedDisabled, ckRadioUncheckedDisabled), (ckRadioUncheckedPressed, ckRadioUncheckedPressed)),
+ // csCheckedNormal
+ ((ckRadioCheckedDisabled, ckRadioCheckedDisabled), (ckRadioCheckedNormal, ckRadioCheckedHot)),
+ // csCheckedPressed
+ ((ckRadioCheckedDisabled, ckRadioCheckedDisabled), (ckRadioCheckedPressed, ckRadioCheckedPressed)),
+ // csMixedNormal (should never appear with ctRadioButton)
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)),
+ // csMixedPressed (should never appear with ctRadioButton)
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed))
+ ),
+ // ctButton
+ (
+ // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckButtonDisabled, ckButtonDisabled), (ckButtonNormal, ckButtonHot)),
+ // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot])
+ ((ckButtonDisabled, ckButtonDisabled), (ckButtonPressed, ckButtonPressed)),
+ // csCheckedNormal
+ ((ckButtonDisabled, ckButtonDisabled), (ckButtonNormal, ckButtonHot)),
+ // csCheckedPressed
+ ((ckButtonDisabled, ckButtonDisabled), (ckButtonPressed, ckButtonPressed)),
+ // csMixedNormal (should never appear with ctButton)
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)),
+ // csMixedPressed (should never appear with ctButton)
+ ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed))
+ )
+ );
+
+var
+ AType: TCheckType;
+
+begin
+ if Node.CheckType = ctNone then
+ Result := -1
+ else
+ begin
+ AType := Node.CheckType;
+ if AType = ctTriStateCheckBox then
+ AType := ctCheckBox;
+ Result := CheckStateToCheckImage[AType, Node.CheckState, not (vsDisabled in Node.States) and Enabled,
+ Node = FCurrentHotNode];
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetColumnClass: TVirtualTreeColumnClass;
+
+begin
+ Result := TVirtualTreeColumn;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetHeaderClass: TVTHeaderClass;
+
+begin
+ Result := TVTHeader;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
+ var Ghosted: Boolean): Integer;
+
+begin
+ Result := -1;
+ Ghosted := False;
+ DoGetImageIndex(Node, Kind, Column, Ghosted, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetMaxRightExtend: Cardinal;
+
+// Determines the maximum with of the currently visible part of the tree, depending on the length
+// of the node texts. This method is used for determining the horizontal scroll range if no columns are used.
+
+var
+ Node,
+ NextNode: PVirtualNode;
+ TopPosition: Integer;
+ NodeLeft,
+ CurrentWidth: Integer;
+ WithCheck: Boolean;
+ CheckOffset: Integer;
+
+begin
+ Node := GetNodeAt(0, 0, True, TopPosition);
+ Result := 0;
+ if toShowRoot in FOptions.FPaintOptions then
+ NodeLeft := (GetNodeLevel(Node) + 1) * FIndent
+ else
+ NodeLeft := GetNodeLevel(Node) * FIndent;
+
+ if Assigned(FStateImages) then
+ Inc(NodeLeft, FStateImages.Width + 2);
+ if Assigned(FImages) then
+ Inc(NodeLeft, FImages.Width + 2);
+ WithCheck := (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages);
+ if WithCheck then
+ CheckOffset := FCheckImages.Width + 2
+ else
+ CheckOffset := 0;
+
+ while Assigned(Node) do
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ if WithCheck and (Node.CheckType <> ctNone) then
+ Inc(NodeLeft, CheckOffset);
+ CurrentWidth := DoGetNodeWidth(Node, NoColumn);
+ if Integer(Result) < (NodeLeft + CurrentWidth) then
+ Result := NodeLeft + CurrentWidth;
+ Inc(TopPosition, Node.NodeHeight);
+ if TopPosition > Height then
+ Break;
+
+ if WithCheck and (Node.CheckType <> ctNone) then
+ Dec(NodeLeft, CheckOffset);
+
+ // Get next visible node and update left node position.
+ NextNode := GetNextVisible(Node);
+ if NextNode = nil then
+ Break;
+ Inc(NodeLeft, CountLevelDifference(Node, NextNode) * Integer(FIndent));
+ Node := NextNode;
+ end;
+
+ Inc(Result, 2 * FMargin);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.GetNativeClipboardFormats(var Formats: TFormatEtcArray);
+
+// Returns the supported clipboard formats of the tree.
+
+begin
+ InternalClipboardFormats.EnumerateFormats(TVirtualTreeClass(ClassType), Formats, FClipboardFormats);
+ // Ask application/descentants for self defined formats.
+ DoGetUserClipboardFormats(Formats);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TCustomVirtualTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect;
+ var Text: WideString);
+
+// Generic base method for editors, hint windows etc. to get some info about a node.
+
+begin
+ R := Rect(0, 0, 0, 0);
+ Text := '';
+ AFont.Assign(Font);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetTreeFromDataObject(const DataObject: IDataObject): TBaseVirtualTree;
+
+// Returns the owner/sender of the given data object by means of a special clipboard format
+// or nil if the sender is in another process or no virtual tree at all.
+
+var
+ Medium: TStgMedium;
+ Data: PVTReference;
+
+begin
+ Result := nil;
+ if Assigned(DataObject) then
+ begin
+ StandardOLEFormat.cfFormat := CF_VTREFERENCE;
+ if DataObject.GetData(StandardOLEFormat, Medium) = S_OK then
+ begin
+ Data := GlobalLock(Medium.hGlobal);
+ if Assigned(Data) then
+ begin
+ if Data.Process = GetCurrentProcessID then
+ Result := Data.Tree;
+ GlobalUnlock(Medium.hGlobal);
+ end;
+ ReleaseStgMedium(Medium);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleHotTrack(X, Y: Integer);
+
+// Updates the current "hot" node.
+
+var
+ HitInfo: THitInfo;
+ DoInvalidate: Boolean;
+
+begin
+ // Get information about the hit.
+ GetHitTestInfoAt(X, Y, True, HitInfo);
+ // Only make the new node being "hot" if its label is hit or full row selection is enabled.
+ if ([hiOnItemLabel, hiOnItemCheckbox] * HitInfo.HitPositions = []) and
+ not (toFullRowSelect in FOptions.FSelectionOptions) then
+ HitInfo.HitNode := nil;
+ if HitInfo.HitNode <> FCurrentHotNode then
+ begin
+ DoInvalidate := (toHotTrack in FOptions.PaintOptions) or (toCheckSupport in FOptions.MiscOptions);
+ DoHotChange(FCurrentHotNode, HitInfo.HitNode);
+ if Assigned(FCurrentHotNode) and DoInvalidate then
+ InvalidateNode(FCurrentHotNode);
+ FCurrentHotNode := HitInfo.HitNode;
+ if Assigned(FCurrentHotNode) and DoInvalidate then
+ InvalidateNode(FCurrentHotNode);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleIncrementalSearch(CharCode: Word);
+
+var
+ Run, Stop: PVirtualNode;
+ GetNextNode: TGetNextNodeProc;
+ NewSearchText: WideString;
+ SingleLetter,
+ PreviousSearch: Boolean; // True if VK_BACK was sent.
+ SearchDirection: TVTSearchDirection;
+
+ //--------------- local functions -------------------------------------------
+
+ procedure SetupNavigation;
+
+ // If the search buffer is empty then we start searching with the next node after the last one, otherwise
+ // we continue with the last one. Node navigation function is set up too here, to avoid frequent checks.
+
+ var
+ FindNextNode: Boolean;
+
+ begin
+ FindNextNode := (Length(FSearchBuffer) = 0) or (Run = nil) or SingleLetter or PreviousSearch;
+ case FIncrementalSearch of
+ isVisibleOnly:
+ if SearchDirection = sdForward then
+ begin
+ GetNextNode := GetNextVisible;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetFirstVisible
+ else
+ begin
+ Run := GetNextVisible(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetFirstVisible;
+ end;
+ end;
+ end
+ else
+ begin
+ GetNextNode := GetPreviousVisible;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetLastVisible
+ else
+ begin
+ Run := GetPreviousVisible(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetLastVisible;
+ end;
+ end;
+ end;
+ isInitializedOnly:
+ if SearchDirection = sdForward then
+ begin
+ GetNextNode := GetNextNoInit;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetFirstNoInit
+ else
+ begin
+ Run := GetNextNoInit(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetFirstNoInit;
+ end;
+ end;
+ end
+ else
+ begin
+ GetNextNode := GetPreviousNoInit;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetLastNoInit
+ else
+ begin
+ Run := GetPreviousNoInit(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetLastNoInit;
+ end;
+ end;
+ end;
+ else
+ // isAll
+ if SearchDirection = sdForward then
+ begin
+ GetNextNode := GetNext;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetFirst
+ else
+ begin
+ Run := GetNext(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetFirst;
+ end;
+ end;
+ end
+ else
+ begin
+ GetNextNode := GetPrevious;
+ if FindNextNode then
+ begin
+ if Run = nil then
+ Run := GetLast
+ else
+ begin
+ Run := GetPrevious(Run);
+ // Do wrap around.
+ if Run = nil then
+ Run := GetLast;
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function CodePageFromLocale(Language: LCID): Integer;
+
+ // Determines the code page for a given locale.
+ // Unfortunately there is no easier way than this, currently.
+
+ var
+ Buf: array[0..6] of Char;
+
+ begin
+ GetLocaleInfo(Language, LOCALE_IDEFAULTANSICODEPAGE, Buf, 6);
+ Result := StrToIntDef(Buf, GetACP);
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function KeyUnicode(C: Char): WideChar;
+
+ // Converts the given character into its corresponding Unicode character
+ // depending on the active keyboard layout.
+
+ begin
+ MultiByteToWideChar(CodePageFromLocale(GetKeyboardLayout(0) and $FFFF),
+ MB_USEGLYPHCHARS, @C, 1, @Result, 1);
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ FoundMatch: Boolean;
+ NewChar: WideChar;
+
+begin
+ StopTimer(SearchTimer);
+
+ if FIncrementalSearch <> isNone then
+ begin
+ if CharCode <> 0 then
+ begin
+ DoStateChange([tsIncrementalSearching]);
+
+ // Convert the given virtual key code into a Unicode character based on the current locale.
+ NewChar := KeyUnicode(Char(CharCode));
+ PreviousSearch := NewChar = WideChar(VK_BACK);
+ // We cannot do a search with an empty search buffer.
+ if not PreviousSearch or (Length(FSearchBuffer) > 1) then
+ begin
+ // Determine which method to use to advance nodes and the start node to search from.
+ case FSearchStart of
+ ssAlwaysStartOver:
+ Run := nil;
+ ssFocusedNode:
+ Run := FFocusedNode;
+ else // ssLastHit
+ Run := FLastSearchNode;
+ end;
+
+ // Make sure the start node corresponds to the search criterion.
+ if Assigned(Run) then
+ begin
+ case FIncrementalSearch of
+ isInitializedOnly:
+ if not (vsInitialized in Run.States) then
+ Run := nil;
+ isVisibleOnly:
+ if not FullyVisible[Run] then
+ Run := nil;
+ end;
+ end;
+ Stop := Run;
+
+ // VK_BACK temporarily changes search direction to opposite mode.
+ if PreviousSearch then
+ begin
+ if SearchDirection = sdBackward then
+ SearchDirection := sdForward
+ else
+ SearchDirection := sdBackward
+ end
+ else
+ SearchDirection := FSearchDirection;
+ // The "single letter mode" is used to advance quickly from node to node when pressing the same key several times.
+ SingleLetter := (Length(FSearchBuffer) = 1) and not PreviousSearch and (FSearchBuffer[1] = NewChar);
+ SetupNavigation;
+ FoundMatch := False;
+
+ if Assigned(Run) then
+ begin
+ if SingleLetter then
+ NewSearchText := FSearchBuffer
+ else
+ if PreviousSearch then
+ begin
+ SetLength(FSearchBuffer, Length(FSearchBuffer) - 1);
+ NewSearchText := FSearchBuffer;
+ end
+ else
+ NewSearchText := FSearchBuffer + NewChar;
+
+ repeat
+ if DoIncrementalSearch(Run, NewSearchText) = 0 then
+ begin
+ FoundMatch := True;
+ Break;
+ end;
+
+ // Advance to next node if we have not found a match.
+ Run := GetNextNode(Run);
+ // Do wrap around start or end of tree.
+ if (Run <> Stop) and (Run = nil) then
+ SetupNavigation;
+ until Run = Stop;
+ end;
+
+ if FoundMatch then
+ begin
+ ClearSelection;
+ FSearchBuffer := NewSearchText;
+ FLastSearchNode := Run;
+ FocusedNode := Run;
+ Selected[Run] := True;
+ FLastSearchNode := Run;
+ end
+ else
+ // Play an acoustic signal if nothing could be found but don't beep if only the currently
+ // focused node matches.
+ if Assigned(Run) and (DoIncrementalSearch(Run, NewSearchText) <> 0) then
+ Beep;
+ end;
+ end;
+
+ // Restart search timeout interval.
+ SetTimer(Handle, SearchTimer, FSearchTimeout, nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleMouseDblClick(var Message: TWMMouse; const HitInfo: THitInfo);
+
+var
+ NewCheckState: TCheckState;
+
+begin
+ if tsEditPending in FStates then
+ begin
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ end;
+
+ if not (tsEditing in FStates) or DoEndEdit then
+ begin
+ if HitInfo.HitColumn = FHeader.FColumns.FClickIndex then
+ DoColumnDblClick(HitInfo.HitColumn, KeysToShiftState(Message.Keys));
+
+ if hiOnItemCheckBox in HitInfo.HitPositions then
+ begin
+ if (FStates * [tsMouseCheckPending, tsKeyCheckPending] = []) and not (vsDisabled in HitInfo.HitNode.States) then
+ begin
+ with HitInfo.HitNode^ do
+ NewCheckState := DetermineNextCheckState(CheckType, CheckState);
+ if DoChecking(HitInfo.HitNode, NewCheckState) then
+ begin
+ DoStateChange([tsMouseCheckPending]);
+ FCheckNode := HitInfo.HitNode;
+ FPendingCheckState := NewCheckState;
+ FCheckNode.CheckState := PressedState[FCheckNode.CheckState];
+ InvalidateNode(HitInfo.HitNode);
+ end;
+ end;
+ end
+ else
+ begin
+ if hiOnItemButton in HitInfo.HitPositions then
+ ToggleNode(HitInfo.HitNode)
+ else
+ begin
+ if toToggleOnDblClick in FOptions.FMiscOptions then
+ begin
+ if ((([hiOnItemButton, hiOnItemLabel, hiOnNormalIcon, hiOnStateIcon] * HitInfo.HitPositions) <> []) or
+ ((toFullRowSelect in FOptions.FSelectionOptions) and Assigned(HitInfo.HitNode))) then
+ ToggleNode(HitInfo.HitNode);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleMouseDown(var Message: TWMMouse; const HitInfo: THitInfo);
+
+// centralized mouse button down handling
+
+var
+ LastFocused: PVirtualNode;
+ Column: TColumnIndex;
+ ShiftState: TShiftState;
+
+ // helper variables to shorten boolean equations/expressions
+ AutoDrag, // automatic (or allowed) drag start
+ IsHit, // the node's caption or images are hit
+ IsCellHit, // for grid extension or full row select (but not check box, button)
+ IsAnyHit, // either IsHit or IsCellHit
+ MultiSelect, // multiselection is enabled
+ ShiftEmpty, // ShiftState = []
+ NodeSelected: Boolean; // the new node (if any) is selected
+ NewColumn: Boolean; // column changed
+ NeedChange: Boolean; // change event is required for selection change
+ CanClear: Boolean;
+ NewCheckState: TCheckState;
+
+begin
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ StopWheelPanning;
+ Exit;
+ end;
+
+ if tsEditPending in FStates then
+ begin
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ end;
+
+ if not (tsEditing in FStates) or DoEndEdit then
+ begin
+ // Keep clicked column in case the application needs it.
+ FHeader.FColumns.FClickIndex := HitInfo.HitColumn;
+
+ // Change column only if we have hit the node label.
+ if (hiOnItemLabel in HitInfo.HitPositions) or
+ (toFullRowSelect in FOptions.FSelectionOptions) or
+ (toGridExtensions in FOptions.FMiscOptions) then
+ begin
+ NewColumn := FFocusedColumn <> HitInfo.HitColumn;
+ if toExtendedFocus in FOptions.FSelectionOptions then
+ Column := HitInfo.HitColumn
+ else
+ Column := FHeader.MainColumn;
+ end
+ else
+ begin
+ NewColumn := False;
+ Column := FFocusedColumn;
+ end;
+
+ // Translate keys and filter out shift and control key.
+ ShiftState := KeysToShiftState(Message.Keys) * [ssShift, ssCtrl];
+
+ // Various combinations determine what states the tree enters now.
+ // We initialize shorthand variables to avoid the following expressions getting too large
+ // and to avoid repeative expensive checks.
+ IsHit := (hiOnItemLabel in HitInfo.HitPositions) or (hiOnNormalIcon in HitInfo.HitPositions);
+ IsCellHit := not IsHit and Assigned(HitInfo.HitNode) and
+ ([hiOnItemButton, hiOnItemCheckBox] * HitInfo.HitPositions = []) and
+ ((toFullRowSelect in FOptions.FSelectionOptions) or (toGridExtensions in FOptions.FMiscOptions));
+ IsAnyHit := IsHit or IsCellHit;
+ MultiSelect := toMultiSelect in FOptions.FSelectionOptions;
+ ShiftEmpty := ShiftState = [];
+ NodeSelected := IsAnyHit and (vsSelected in HitInfo.HitNode.States);
+
+ // Dragging might be started in the inherited handler manually (which is discouraged for stability reasons)
+ // the test for manual mode is done below (after the focused node is set).
+ AutoDrag := ((DragMode = dmAutomatic) or Dragging) and not IsCellHit;
+
+ // Query the application to learn if dragging may start now (if set to dmManual).
+ if Assigned(HitInfo.HitNode) and not AutoDrag and (DragMode = dmManual) then
+ AutoDrag := DoBeforeDrag(HitInfo.HitNode, Column) and not IsCellHit;
+
+ // handle button clicks
+ if (hiOnItemButton in HitInfo.HitPositions) and (vsHasChildren in HitInfo.HitNode.States) then
+ begin
+ ToggleNode(HitInfo.HitNode);
+ Exit;
+ end;
+
+ // check event
+ if hiOnItemCheckBox in HitInfo.HitPositions then
+ begin
+ if (FStates * [tsMouseCheckPending, tsKeyCheckPending] = []) and not (vsDisabled in HitInfo.HitNode.States) then
+ begin
+ with HitInfo.HitNode^ do
+ NewCheckState := DetermineNextCheckState(CheckType, CheckState);
+ if DoChecking(HitInfo.HitNode, NewCheckState) then
+ begin
+ DoStateChange([tsMouseCheckPending]);
+ FCheckNode := HitInfo.HitNode;
+ FPendingCheckState := NewCheckState;
+ FCheckNode.CheckState := PressedState[FCheckNode.CheckState];
+ InvalidateNode(HitInfo.HitNode);
+ end;
+ end;
+ Exit;
+ end;
+
+ // Keep this node's level in case we need it for constraint selection.
+ if (FRoot.ChildCount > 0) and ShiftEmpty or (FSelectionCount = 0) then
+ if Assigned(HitInfo.HitNode) then
+ FLastSelectionLevel := GetNodeLevel(HitInfo.HitNode)
+ else
+ FLastSelectionLevel := GetNodeLevel(GetLastVisibleNoInit);
+
+ // pending clearance
+ if MultiSelect and ShiftEmpty and not (hiOnItemCheckbox in HitInfo.HitPositions) and
+ (IsHit and ShiftEmpty and AutoDrag and NodeSelected) then
+ DoStateChange([tsClearPending]);
+
+ // immediate clearance
+ // Determine for the right mouse button if there is a popup menu. In this case and if drag'n drop is pending
+ // the current selection has to stay as it is.
+ with HitInfo, Message do
+ CanClear := not AutoDrag and
+ (not (tsRightButtonDown in FStates) or not HasPopupMenu(HitNode, HitColumn, Point(XPos, YPos)));
+ if (not IsAnyHit and MultiSelect and ShiftEmpty) or
+ (IsAnyHit and (not NodeSelected or (NodeSelected and CanClear)) and (ShiftEmpty or not MultiSelect)) then
+ begin
+ Assert(not (tsClearPending in FStates), 'Pending and direct clearance are mutual exclusive!');
+ if NodeSelected then
+ begin
+ // If the currently hit node is (also) selected then we have to reselect it again but without
+ // a change event if it is the only selected node.
+ NeedChange := FSelectionCount > 1;
+ InternalClearSelection;
+ InternalAddToSelection(HitInfo.HitNode, True);
+ if NeedChange then
+ begin
+ Invalidate;
+ Change(nil);
+ end;
+ end
+ else
+ ClearSelection;
+ end;
+
+ // pending node edit
+ if Focused and
+ ((hiOnItemLabel in HitInfo.HitPositions) or ((toGridExtensions in FOptions.FMiscOptions) and
+ (hiOnItem in HitInfo.HitPositions))) and NodeSelected and not NewColumn and ShiftEmpty then
+ DoStateChange([tsEditPending]);
+
+ // focus change
+ if not Focused and CanFocus then
+ SetFocus;
+
+ // User starts a selection with a selection rectangle.
+ if not (toDisableDrawSelection in FOptions.FSelectionOptions) and not IsHit and MultiSelect then
+ begin
+ SetCapture(Handle);
+ DoStateChange([tsDrawSelPending]);
+ FDrawSelShiftState := ShiftState;
+ FNewSelRect := Rect(Message.XPos - FOffsetX, Message.YPos - FOffsetY, Message.XPos - FOffsetX,
+ Message.YPos - FOffsetY);
+ FLastSelRect := FNewSelRect;
+ if not IsCellHit then
+ Exit;
+ end;
+
+ // Keep current mouse position.
+ FLastClickPos := Point(Message.XPos, Message.YPos);
+
+ // Handle selection and node focus change.
+ if (IsHit or IsCellHit) and
+ DoFocusChanging(FFocusedNode, HitInfo.HitNode, FFocusedColumn, Column) then
+ begin
+ if NewColumn then
+ begin
+ InvalidateColumn(FFocusedColumn);
+ InvalidateColumn(Column);
+ FFocusedColumn := Column;
+ end;
+ if DragKind = dkDock then
+ begin
+ StopTimer(ScrollTimer);
+ DoStateChange([], [tsScrollPending, tsScrolling]);
+ end;
+ // Get the currently focused node to make multiple multi-selection blocks possible.
+ LastFocused := FFocusedNode;
+ DoFocusNode(HitInfo.HitNode, False);
+
+ if MultiSelect and not Dragging and not ShiftEmpty then
+ HandleClickSelection(LastFocused, HitInfo.HitNode, ShiftState)
+ else
+ begin
+ if ShiftEmpty then
+ FRangeAnchor := HitInfo.HitNode;
+
+ // If the hit node is not yet selected then do it now.
+ if not NodeSelected then
+ AddToSelection(HitInfo.HitNode);
+ end;
+
+ DoFocusChange(FFocusedNode, FFocusedColumn);
+
+ // Drag'n drop initiation
+ // If we lost focus in the interim the button states would be cleared in WM_KILLFOCUS.
+ if AutoDrag and (FStates * [tsLeftButtonDown, tsRightButtonDown, tsMiddleButtonDown] <> []) then
+ BeginDrag(False);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.HandleMouseUp(var Message: TWMMouse; const HitInfo: THitInfo);
+
+// Counterpart to the mouse down handler.
+
+var
+ ReselectFocusedNode: Boolean;
+
+begin
+ ReleaseCapture;
+
+ if not (tsVCLDragPending in FStates) then
+ begin
+ // reset pending or persistent states
+ if IsMouseSelecting then
+ begin
+ DoStateChange([], [tsDrawSelecting, tsDrawSelPending]);
+ Invalidate;
+ end;
+
+ if tsClearPending in FStates then
+ begin
+ ReselectFocusedNode := Assigned(FFocusedNode) and (vsSelected in FFocusedNode.States);
+ ClearSelection;
+ if ReselectFocusedNode then
+ AddToSelection(FFocusedNode);
+ end;
+
+ if (tsClearFocusedSelection in FStates) and Assigned(HitInfo.HitNode) then
+ begin
+ if vsSelected in HitInfo.HitNode.States then
+ RemoveFromSelection(HitInfo.HitNode)
+ else
+ AddToSelection(HitInfo.HitNode);
+ InvalidateNode(HitInfo.HitNode);
+ end;
+
+ DoStateChange([], [tsOLEDragPending, tsOLEDragging, tsClearPending, tsDrawSelPending, tsScrollPending,
+ tsScrolling, tsClearFocusedSelection]);
+ StopTimer(ScrollTimer);
+
+ if tsMouseCheckPending in FStates then
+ begin
+ DoStateChange([], [tsMouseCheckPending]);
+ // Is the mouse still over the same node?
+ if (HitInfo.HitNode = FCheckNode) and (hiOnItem in HitInfo.HitPositions) then
+ begin
+ ChangeCheckState(FCheckNode, FPendingCheckState);
+ DoCheckClick(FCheckNode, FPendingCheckState);
+ end
+ else
+ FCheckNode.CheckState := UnpressedState[FCheckNode.CheckState];
+ InvalidateNode(FCheckNode);
+ FCheckNode := nil;
+ end;
+
+ if (FHeader.FColumns.FClickIndex > NoColumn) and (FHeader.FColumns.FClickIndex = HitInfo.HitColumn) then
+ DoColumnClick(HitInfo.HitColumn, KeysToShiftState(Message.Keys));
+
+ // handle a pending edit event
+ if tsEditPending in FStates then
+ begin
+ // Is the mouse still over the same node?
+ if (HitInfo.HitNode = FFocusedNode) and (hiOnItem in HitInfo.HitPositions) and
+ CanEdit(FFocusedNode, HitInfo.HitColumn) then
+ begin
+ FEditColumn := FFocusedColumn;
+ SetTimer(Handle, EditTimer, FEditDelay, nil);
+ end
+ else
+ DoStateChange([], [tsEditPending]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.HasPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Pos: TPoint): Boolean;
+
+// Determines whether the tree got a popup menu, either in its PopupMenu property, via the OnGetPopupMenu event or
+// through inheritannce. The latter case must be checked by the descendant which must override this method.
+
+begin
+ Result := Assigned(PopupMenu) or Assigned(DoGetPopupMenu(Node, Column, Pos));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InitChildren(Node: PVirtualNode);
+
+// Initiates the initialization of the child number of the given node.
+
+var
+ Count: Cardinal;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and (vsHasChildren in Node.States) then
+ begin
+ Count := Node.ChildCount;
+ DoInitChildren(Node, Count);
+ if Count = 0 then
+ begin
+ // Remove any child node which is already there.
+ DeleteChildren(Node);
+ Exclude(Node.States, vsHasChildren);
+ end
+ else
+ SetChildCount(Node, Count);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InitNode(Node: PVirtualNode);
+
+// Initiates the initialization of the given node to allow the application to load needed data for it.
+
+var
+ InitStates: TVirtualNodeInitStates;
+
+begin
+ with Node^ do
+ begin
+ InitStates := [];
+ if Parent = FRoot then
+ DoInitNode(nil, Node, InitStates)
+ else
+ DoInitNode(Parent, Node, InitStates);
+ Include(States, vsInitialized);
+ if ivsDisabled in InitStates then
+ Include(States, vsDisabled);
+ if ivsHasChildren in InitStates then
+ Include(States, vsHasChildren);
+ if ivsSelected in InitStates then
+ begin
+ FSingletonNodeArray[0] := Node;
+ InternalAddToSelection(FSingletonNodeArray, 1, False);
+ end;
+ if ivsMultiline in InitStates then
+ Include(States, vsMultiline);
+
+ // Expanded may already be set (when called from ReinitNode) or be set in DoInitNode, allow both.
+ if (vsExpanded in Node.States) xor (ivsExpanded in InitStates) then
+ begin
+ // Expand node if not yet done (this will automatically initialize child nodes).
+ if ivsExpanded in InitStates then
+ ToggleNode(Node)
+ else
+ // If the node already was expanded then explicitly trigger child initialization.
+ if vsHasChildren in Node.States then
+ InitChildren(Node);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalAddFromStream(Stream: TStream; Version: Integer; Node: PVirtualNode);
+
+// Loads nodes from the given stream and adds them as children to Node.
+// Because the new nodes might be selected this method also fixes the selection array.
+
+var
+ Stop: PVirtualNode;
+ LastVisibleCount: Cardinal;
+ Index: Integer;
+
+begin
+ if Node = nil then
+ Node := FRoot;
+
+ // Read in the new nodes, keep number of visible nodes for a correction.
+ LastVisibleCount := FVisibleCount;
+ ReadNode(Stream, Version, Node);
+
+ // I need to fix the visible count here because of the hierarchical load procedure.
+ if (Node = FRoot) or ([vsExpanded, vsVisible] * Node.Parent.States = [vsExpanded, vsVisible]) then
+ FVisibleCount := LastVisibleCount + CountVisibleChildren(Node)
+ else
+ FVisibleCount := LastVisibleCount;
+
+ // Fix selection array.
+ ClearTempCache;
+ if Node = FRoot then
+ Stop := nil
+ else
+ Stop := Node.NextSibling;
+
+ if toMultiSelect in FOptions.FSelectionOptions then
+ begin
+ // Add all nodes which were selected before to the current selection (unless they are already there).
+ while Node <> Stop do
+ begin
+ if (vsSelected in Node.States) and not FindNodeInSelection(Node, Index, 0, High(FSelection)) then
+ InternalCacheNode(Node);
+ Node := GetNextNoInit(Node);
+ end;
+ if FTempNodeCount > 0 then
+ AddToSelection(FTempNodeCache, FTempNodeCount, True);
+ ClearTempCache;
+ end
+ else // No further selected nodes allowed so delete the corresponding flag in all new nodes.
+ while Node <> Stop do
+ begin
+ Exclude(Node.States, vsSelected);
+ Node := GetNextNoInit(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InternalAddToSelection(Node: PVirtualNode; ForceInsert: Boolean): Boolean;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil!');
+ FSingletonNodeArray[0] := Node;
+ Result := InternalAddToSelection(FSingletonNodeArray, 1, ForceInsert);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InternalAddToSelection(const NewItems: TNodeArray; NewLength: Integer;
+ ForceInsert: Boolean): Boolean;
+
+// Internal version of method AddToSelection which does not trigger OnChange events
+
+var
+ I, J: Integer;
+ CurrentEnd: Integer;
+ Constrained,
+ SiblingConstrained: Boolean;
+
+begin
+ // The idea behind this code is to use a kind of reverse merge sort. QuickSort is quite fast
+ // and would do the job here too but has a serious problem with already sorted lists like FSelection.
+
+ // 1) Remove already selected items, mark all other as being selected.
+ if ForceInsert then
+ begin
+ for I := 0 to NewLength - 1 do
+ Include(NewItems[I].States, vsSelected);
+ end
+ else
+ begin
+ Constrained := toLevelSelectConstraint in FOptions.FSelectionOptions;
+ if Constrained and (FLastSelectionLevel = -1) then
+ FLastSelectionLevel := GetNodeLevel(NewItems[0]);
+ SiblingConstrained := toSiblingSelectConstraint in FOptions.FSelectionOptions;
+ if SiblingConstrained and (FRangeAnchor = nil) then
+ FRangeAnchor := NewItems[0];
+
+ for I := 0 to NewLength - 1 do
+ if ([vsSelected, vsDisabled] * NewItems[I].States <> []) or
+ (Constrained and (Cardinal(FLastSelectionLevel) <> GetNodeLevel(NewItems[I]))) or
+ (SiblingConstrained and (FRangeAnchor.Parent <> NewItems[I].Parent)) then
+ Inc(Cardinal(NewItems[I]))
+ else
+ Include(NewItems[I].States, vsSelected);
+ end;
+
+ I := PackArray(NewItems, NewLength);
+ if I > -1 then
+ NewLength := I;
+
+ Result := NewLength > 0;
+ if Result then
+ begin
+ // 2) Sort the new item list so we can easily traverse it.
+ if NewLength > 1 then
+ QuickSort(NewItems, 0, NewLength - 1);
+ // 3) Make room in FSelection for the new items.
+ if FSelectionCount + NewLength >= Length(FSelection) then
+ SetLength(FSelection, FSelectionCount + NewLength);
+
+ // 4) Merge in new items
+ J := NewLength - 1;
+ CurrentEnd := FSelectionCount - 1;
+
+ while J >= 0 do
+ begin
+ // First insert all new entries which are greater than the greatest entry in the old list.
+ // If the current end marker is < 0 then there's nothing more to move in the selection
+ // array and only the remaining new items must be inserted.
+ if CurrentEnd >= 0 then
+ begin
+ while (J >= 0) and (Cardinal(NewItems[J]) > Cardinal(FSelection[CurrentEnd])) do
+ begin
+ FSelection[CurrentEnd + J + 1] := NewItems[J];
+ Dec(J);
+ end;
+ // early out if nothing more needs to be copied
+ if J < 0 then
+ Break;
+ end
+ else
+ begin
+ // insert remaining new entries at position 0
+ Move(NewItems[0], FSelection[0], (J + 1) * SizeOf(Pointer));
+ // nothing more to do so exit main loop
+ Break;
+ end;
+
+ // find the last entry in the remaining selection list which is smaller then the largest
+ // entry in the remaining new items list
+ FindNodeInSelection(NewItems[J], I, 0, CurrentEnd);
+ Dec(I);
+ // move all entries which are greater than the greatest entry in the new items list up
+ // so the remaining gap travels down to where new items must be inserted
+ Move(FSelection[I + 1], FSelection[I + J + 2], (CurrentEnd - I) * SizeOf(Pointer));
+ CurrentEnd := I;
+ end;
+
+ Inc(FSelectionCount, NewLength);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalCacheNode(Node: PVirtualNode);
+
+// Adds the given node to the temporary node cache (used when collecting possibly large amounts of nodes).
+
+var
+ Len: Cardinal;
+
+begin
+ Len := Length(FTempNodeCache);
+ if FTempNodeCount = Len then
+ begin
+ if Len < 100 then
+ Len := 100
+ else
+ Len := Len + Len div 10;
+ SetLength(FTempNodeCache, Len);
+ end;
+ FTempNodeCache[FTempNodeCount] := Node;
+ Inc(FTempNodeCount);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalClearSelection;
+
+var
+ Count: Integer;
+
+begin
+ // It is possible that there are invalid node references in the selection array
+ // if the tree update is locked and changes in the structure were made.
+ // Handle this potentially dangerous situation by packing the selection array explicitely.
+ if FUpdateCount > 0 then
+ begin
+ Count := PackArray(FSelection, FSelectionCount);
+ if Count > -1 then
+ begin
+ FSelectionCount := Count;
+ SetLength(FSelection, FSelectionCount);
+ end;
+ end;
+
+ while FSelectionCount > 0 do
+ begin
+ Dec(FSelectionCount);
+ Exclude(FSelection[FSelectionCount].States, vsSelected);
+ end;
+ ResetRangeAnchor;
+ FSelection := nil;
+ DoStateChange([], [tsClearPending]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalConnectNode(Node, Destination: PVirtualNode; Target: TBaseVirtualTree;
+ Mode: TVTNodeAttachMode);
+
+// Connects Node with Destination depending on Mode.
+// No error checking takes place. Node as well as Destination must be valid. Node must never be a root node and
+// Destination must not be a root node if Mode is amInsertBefore or amInsertAfter.
+
+var
+ Run: PVirtualNode;
+
+begin
+ // Keep in mind that the destination node might belong to another tree.
+ with Target do
+ begin
+ case Mode of
+ amInsertBefore:
+ begin
+ Node.PrevSibling := Destination.PrevSibling;
+ Destination.PrevSibling := Node;
+ Node.NextSibling := Destination;
+ Node.Parent := Destination.Parent;
+ Node.Index := Destination.Index;
+ if Node.PrevSibling = nil then
+ Node.Parent.FirstChild := Node
+ else
+ Node.PrevSibling.NextSibling := Node;
+
+ // reindex all following nodes
+ Run := Destination;
+ while Assigned(Run) do
+ begin
+ Inc(Run.Index);
+ Run := Run.NextSibling;
+ end;
+
+ Inc(Destination.Parent.ChildCount);
+ Include(Destination.Parent.States, vsHasChildren);
+ AdjustTotalCount(Destination.Parent, Node.TotalCount, True);
+
+ // Add the new node's height only if its parent is expanded.
+ if vsExpanded in Destination.Parent.States then
+ AdjustTotalHeight(Destination.Parent, Node.TotalHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node) + 1);
+ end;
+ amInsertAfter:
+ begin
+ Node.NextSibling := Destination.NextSibling;
+ Destination.NextSibling := Node;
+ Node.PrevSibling := Destination;
+ Node.Parent := Destination.Parent;
+ if Node.NextSibling = nil then
+ Node.Parent.LastChild := Node
+ else
+ Node.NextSibling.PrevSibling := Node;
+ Node.Index := Destination.Index;
+
+ // reindex all following nodes
+ Run := Node;
+ while Assigned(Run) do
+ begin
+ Inc(Run.Index);
+ Run := Run.NextSibling;
+ end;
+
+ Inc(Destination.Parent.ChildCount);
+ Include(Destination.Parent.States, vsHasChildren);
+ AdjustTotalCount(Destination.Parent, Node.TotalCount, True);
+ // Add the new node's height only if its parent is expanded.
+ if vsExpanded in Destination.Parent.States then
+ AdjustTotalHeight(Destination.Parent, Node.TotalHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node) + 1);
+ end;
+ amAddChildFirst:
+ begin
+ if Assigned(Destination.FirstChild) then
+ begin
+ // If there's a first child then there must also be a last child.
+ Destination.FirstChild.PrevSibling := Node;
+ Node.NextSibling := Destination.FirstChild;
+ Destination.FirstChild := Node;
+ end
+ else
+ begin
+ // First child node at this location.
+ Destination.FirstChild := Node;
+ Destination.LastChild := Node;
+ Node.NextSibling := nil;
+ end;
+ Node.PrevSibling := nil;
+ Node.Parent := Destination;
+ Node.Index := 0;
+ // reindex all following nodes
+ Run := Node.NextSibling;
+ while Assigned(Run) do
+ begin
+ Inc(Run.Index);
+ Run := Run.NextSibling;
+ end;
+
+ Inc(Destination.ChildCount);
+ Include(Destination.States, vsHasChildren);
+ AdjustTotalCount(Destination, Node.TotalCount, True);
+ // add the new node's height only if its parent is expanded (visibility is handled elsewhere)
+ if vsExpanded in Destination.States then
+ AdjustTotalHeight(Destination, Node.TotalHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node) + 1);
+ end;
+ amAddChildLast:
+ begin
+ if Assigned(Destination.LastChild) then
+ begin
+ // If there's a last child then there must also be a first child.
+ Destination.LastChild.NextSibling := Node;
+ Node.PrevSibling := Destination.LastChild;
+ Destination.LastChild := Node;
+ end
+ else
+ begin
+ // first child node at this location
+ Destination.FirstChild := Node;
+ Destination.LastChild := Node;
+ Node.PrevSibling := nil;
+ end;
+ Node.NextSibling := nil;
+ Node.Parent := Destination;
+ if Assigned(Node.PrevSibling) then
+ Node.Index := Node.PrevSibling.Index + 1
+ else
+ Node.Index := 0;
+ Inc(Destination.ChildCount);
+ Include(Destination.States, vsHasChildren);
+ AdjustTotalCount(Destination, Node.TotalCount, True);
+ // Add the new node's height only if its parent is expanded (visibility is handled elsewhere).
+ if vsExpanded in Destination.States then
+ AdjustTotalHeight(Destination, Node.TotalHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node) + 1);
+ end;
+ else
+ // amNoWhere: do nothing
+ end;
+
+ // Update the hidden children flag of the parent.
+ if (Mode <> amNoWhere) and (Node.Parent <> FRoot) then
+ begin
+ // If we have added a visible node then simply remove the all-children-hidden flag.
+ if vsVisible in Node.States then
+ Exclude(Node.Parent.States, vsAllChildrenHidden)
+ else
+ // If we have added an invisible node and this is the only child node then
+ // make sure the all-children-hidden flag is in a determined state.
+ // If there were child nodes before then no action is needed.
+ if Node.Parent.ChildCount = 1 then
+ Include(Node.Parent.States, vsAllChildrenHidden);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InternalData(Node: PVirtualNode): Pointer;
+
+begin
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalDisconnectNode(Node: PVirtualNode; KeepFocus: Boolean; Reindex: Boolean = True);
+
+// Disconnects the given node from its parent and siblings. The node's pointer are not reset so they can still be used
+// after return from this method (probably a very short time only!).
+// If KeepFocus is True then the focused node is not reset. This is useful if the given node is reconnected to the tree
+// immediately after return of this method and should stay being the focused node if it was it before.
+// Note: Node must not be nil or the root node.
+
+var
+ Parent,
+ Run: PVirtualNode;
+ Index: Integer;
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Node must neither be nil nor the root node.');
+
+ if (Node = FFocusedNode) and not KeepFocus then
+ begin
+ DoFocusNode(nil, False);
+ DoFocusChange(FFocusedNode, FFocusedColumn);
+ end;
+
+ if Node = FRangeAnchor then
+ ResetRangeAnchor;
+
+ // Update the hidden children flag of the parent.
+ if (Node.Parent <> FRoot) and not (vsClearing in Node.Parent.States) then
+ DetermineHiddenChildrenFlag(Node.Parent);
+
+ if not (vsDeleting in Node.States) then
+ begin
+ // Some states are only temporary so take them out.
+ Node.States := Node.States - [vsChecking];
+ Parent := Node.Parent;
+ Dec(Parent.ChildCount);
+ if Parent.ChildCount = 0 then
+ Exclude(Parent.States, vsHasChildren);
+ AdjustTotalCount(Parent, -Integer(Node.TotalCount), True);
+ if vsExpanded in Parent.States then
+ AdjustTotalHeight(Parent, -Integer(Node.TotalHeight), True);
+ if FullyVisible[Node] then
+ Dec(FVisibleCount, CountVisibleChildren(Node) + 1);
+ if Assigned(Node.PrevSibling) then
+ Node.PrevSibling.NextSibling := Node.NextSibling
+ else
+ Parent.FirstChild := Node.NextSibling;
+
+ if Assigned(Node.NextSibling) then
+ begin
+ Node.NextSibling.PrevSibling := Node.PrevSibling;
+ // Reindex all following nodes.
+ if Reindex then
+ begin
+ Run := Node.NextSibling;
+ Index := Node.Index;
+ while Assigned(Run) do
+ begin
+ Run.Index := Index;
+ Inc(Index);
+ Run := Run.NextSibling;
+ end;
+ end;
+ end
+ else
+ Parent.LastChild := Node.PrevSibling;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InternalRemoveFromSelection(Node: PVirtualNode);
+
+// Special version to mark a node to be no longer in the current selection. PackArray must
+// be used to remove finally those entries.
+
+var
+ Index: Integer;
+
+begin
+ // Because pointers are always DWORD aligned we can simply increment all those
+ // which we want to have removed (see also PackArray) and still have the
+ // order in the list preserved.
+ if FindNodeInSelection(Node, Index, -1, -1) then
+ begin
+ Exclude(Node.States, vsSelected);
+ Inc(Cardinal(FSelection[Index]));
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvalidateCache;
+
+// Marks the cache as invalid.
+
+begin
+ DoStateChange([tsValidationNeeded], [tsUseCache]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MarkCutCopyNodes;
+
+// Sets the vsCutOrCopy style in every currently selected but not disabled node to indicate it is
+// now part of a clipboard operation.
+
+var
+ Nodes: TNodeArray;
+ I: Integer;
+
+begin
+ Nodes := nil;
+ if FSelectionCount > 0 then
+ begin
+ // need the current selection sorted to exclude selected nodes which are children, grandchildren etc. of
+ // already selected nodes
+ Nodes := GetSortedSelection(False);
+ for I := 0 to High(Nodes) do
+ with Nodes[I]^ do
+ if not (vsDisabled in States) then
+ Include(States, vsCutOrCopy);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Loaded;
+
+var
+ LastRootCount: Cardinal;
+ IsReadOnly: Boolean;
+
+begin
+ inherited;
+
+ // If a root node count has been set during load of the tree then update its child structure now
+ // as this hasn't been done yet in this case.
+ if (tsNeedRootCountUpdate in FStates) and (FRoot.ChildCount > 0) then
+ begin
+ DoStateChange([], [tsNeedRootCountUpdate]);
+ IsReadOnly := toReadOnly in FOptions.FMiscOptions;
+ Exclude(FOptions.FMiscOptions, toReadOnly);
+ LastRootCount := FRoot.ChildCount;
+ FRoot.ChildCount := 0;
+ BeginUpdate;
+ SetChildCount(FRoot, LastRootCount);
+ EndUpdate;
+ if IsReadOnly then
+ Include(FOptions.FMiscOptions, toReadOnly);
+ end;
+
+ // Prevent the object inspector at design time from marking the header as being modified
+ // when auto resize is enabled.
+ Updating;
+ try
+ FHeader.UpdateMainColumn;
+ FHeader.FColumns.FixPositions;
+ FHeader.RecalculateHeader;
+ if hoAutoResize in FHeader.FOptions then
+ FHeader.FColumns.AdjustAutoSize(InvalidColumn, True);
+ finally
+ Updated;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MainColumnChanged;
+
+begin
+ DoCancelEdit;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MouseMove(Shift: TShiftState; X, Y: Integer);
+
+var
+ R: TRect;
+
+begin
+ // Remove current selection in case the user clicked somewhere in the window (but not a node)
+ // and moved the mouse.
+ if tsDrawSelPending in FStates then
+ begin
+ if CalculateSelectionRect(X, Y) then
+ begin
+ InvalidateRect(Handle, @FNewSelRect, False);
+ UpdateWindow(Handle);
+ if (Abs(FNewSelRect.Right - FNewSelRect.Left) > Mouse.DragThreshold) or
+ (Abs(FNewSelRect.Bottom - FNewSelRect.Top) > Mouse.DragThreshold) then
+ begin
+ if tsClearPending in FStates then
+ begin
+ DoStateChange([], [tsClearPending]);
+ ClearSelection;
+ end;
+ DoStateChange([tsDrawSelecting], [tsDrawSelPending]);
+ // reset to main column for multiselection
+ FocusedColumn := FHeader.MainColumn;
+
+ // The current rectangle may already include some node captions. Handle this.
+ if HandleDrawSelection(X, Y) then
+ InvalidateRect(Handle, nil, False);
+ end;
+ end;
+ end
+ else
+ begin
+ // If both wheel panning and auto scrolling are pending then the user moved the mouse while holding down the
+ // middle mouse button. This means panning is being used, hence remove the autoscroll flag.
+ if [tsWheelPanning, tsWheelScrolling] * FStates = [tsWheelPanning, tsWheelScrolling] then
+ begin
+ if ((Abs(FLastClickPos.X - X) >= Mouse.DragThreshold) or (Abs(FLastClickPos.Y - Y) >= Mouse.DragThreshold)) then
+ DoStateChange([], [tsWheelScrolling]);
+ end;
+
+ // Really start dragging if the mouse has been moved more than the threshold.
+ if (tsOLEDragPending in FStates) and ((Abs(FLastClickPos.X - X) >= FDragThreshold) or
+ (Abs(FLastClickPos.Y - Y) >= FDragThreshold)) then
+ DoDragging(FLastClickPos)
+ else
+ begin
+ if CanAutoScroll then
+ DoAutoScroll(X, Y);
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ AdjustPanningCursor(X, Y);
+ if not IsMouseSelecting then
+ begin
+ HandleHotTrack(X, Y);
+ inherited MouseMove(Shift, X, Y);
+ end
+ else
+ begin
+ // Handle draw selection if required, but don't do the work twice if the
+ // auto scrolling code already cares about the selection.
+ if not (tsScrolling in FStates) and CalculateSelectionRect(X, Y) then
+ begin
+ // If something in the selection changed then invalidate the entire
+ // tree instead trying to figure out the display rects of all changed nodes.
+ if HandleDrawSelection(X, Y) then
+ InvalidateRect(Handle, nil, False)
+ else
+ begin
+ UnionRect(R, OrderRect(FNewSelRect), OrderRect(FLastSelRect));
+ OffsetRect(R, FOffsetX, FOffsetY);
+ InvalidateRect(Handle, @R, False);
+ end;
+ UpdateWindow(Handle);
+ end;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Notification(AComponent: TComponent; Operation: TOperation);
+
+begin
+ if (AComponent <> Self) and (Operation = opRemove) then
+ begin
+ // Check for components linked to the tree.
+ if AComponent = FImages then
+ begin
+ Images := nil;
+ if not (csDestroying in ComponentState) then
+ Invalidate;
+ end
+ else
+ if AComponent = FStateImages then
+ begin
+ StateImages := nil;
+ if not (csDestroying in ComponentState) then
+ Invalidate;
+ end
+ else
+ if AComponent = FCustomCheckImages then
+ begin
+ CustomCheckImages := nil;
+ FCheckImageKind := ckLightCheck;
+ if not (csDestroying in ComponentState) then
+ Invalidate;
+ end
+ else
+ if AComponent = PopupMenu then
+ PopupMenu := nil
+ else
+ // Check for components linked to the header.
+ if AComponent = FHeader.FImages then
+ FHeader.Images := nil
+ else
+ if AComponent = FHeader.PopupMenu then
+ FHeader.PopupMenu := nil;
+ end;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Paint;
+
+// Window paint routine. Used when the tree window needs to be updated.
+
+var
+ Window: TRect;
+ Target: TPoint;
+
+begin
+ // The update rect has already been filled in WMPaint, as it is the window's update rect, which gets
+ // reset when BeginPaint is called (in the ancestor).
+ // The difference to the DC's clipbox is that it is also valid with internal paint operations used
+ // e.g. by the Explorer while dragging, but show window content while dragging is disabled.
+ if not IsRectEmpty(FUpdateRect) then
+ begin
+ Window := FUpdateRect;
+ Target := Window.TopLeft;
+
+ // The clipping rectangle is given in client coordinates of the window. We have to convert it into
+ // a sliding window of the tree image.
+ OffsetRect(Window, -FOffsetX, -FOffsetY);
+ PaintTree(Canvas, Window, Target, [poBackground, poColumnColor, poDrawFocusRect, poDrawDropMark, poDrawSelection,
+ poGridLines]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintCheckImage(const PaintInfo: TVTPaintInfo);
+
+var
+ ForegroundColor: COLORREF;
+ {$ifdef ThemeSupport}
+ R: TRect;
+ Details: TThemedElementDetails;
+ {$endif ThemeSupport}
+
+begin
+ with PaintInfo, ImageInfo[iiCheck] do
+ begin
+ {$ifdef ThemeSupport}
+ if (tsUseThemes in FStates) and (FCheckImageKind <> ckCustom) then
+ begin
+ R := Rect(XPos - 1, YPos, XPos + 16, YPos + 16);
+ Details.Element := teButton;
+ case Index of
+ 0..8: // radio buttons
+ begin
+ Details.Part := BP_RADIOBUTTON;
+ Details.State := Index;
+ end;
+ 9..20: // check boxes
+ begin
+ Details.Part := BP_CHECKBOX;
+ Details.State := Index - 8;
+ end;
+ 21..24: // buttons
+ begin
+ Details.Part := BP_PUSHBUTTON;
+ Details.State := Index - 20;
+ end;
+ else
+ Details.Part := 0;
+ Details.State := 0;
+ end;
+ ThemeServices.DrawElement(Canvas.Handle, Details, R);
+ if Index in [21..24] then
+ UtilityImages.Draw(Canvas, XPos - 1, YPos, 4);
+ end
+ else
+ {$endif ThemeSupport}
+ with FCheckImages do
+ begin
+ if (vsSelected in Node.States) and not Ghosted then
+ begin
+ if Focused or (toPopupMode in FOptions.FPaintOptions) then
+ ForegroundColor := ColorToRGB(FColors.FocusedSelectionColor)
+ else
+ ForegroundColor := ColorToRGB(FColors.UnfocusedSelectionColor);
+ end
+ else
+ ForegroundColor := GetRGBColor(BlendColor);
+
+ ImageList_DrawEx(Handle, Index, Canvas.Handle, XPos, YPos, 0, 0, GetRGBColor(BkColor), ForegroundColor,
+ ILD_TRANSPARENT);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintImage(const PaintInfo: TVTPaintInfo; ImageInfoIndex: TVTImageInfoIndex;
+ Images: TCustomImageList; DoOverlay: Boolean);
+
+const
+ Style: array[TImageType] of Cardinal = (0, ILD_MASK);
+
+var
+ OverlayImage: Integer;
+ OverlayGhosted: Boolean;
+ ExtraStyle: Cardinal;
+ ForegroundColor: COLORREF;
+ CutNode: Boolean;
+ PaintFocused: Boolean;
+
+begin
+ with PaintInfo, ImageInfo[ImageInfoIndex], Images do
+ begin
+ CutNode := (vsCutOrCopy in Node.States) and (tsCutPending in FStates);
+ PaintFocused := Focused or (toGhostedIfUnfocused in FOptions.FPaintOptions);
+
+ if (vsSelected in Node.States) and not (Ghosted or CutNode) then
+ begin
+ if PaintFocused or (toPopupMode in FOptions.FPaintOptions) then
+ ForegroundColor := ColorToRGB(FColors.FocusedSelectionColor)
+ else
+ ForegroundColor := ColorToRGB(FColors.UnfocusedSelectionColor);
+ end
+ else
+ ForegroundColor := GetRGBColor(Color);
+
+ // Since the overlay image must be specified together with the image to draw
+ // it is meaningfull to retrieve it in advance.
+ if DoOverlay then
+ OverlayImage := GetImageIndex(PaintInfo.Node, ikOverlay, PaintInfo.Column, OverlayGhosted)
+ else
+ OverlayImage := -1;
+ if (vsDisabled in Node.States) or not Enabled then
+ begin
+ // The internal handling for disabled images in TImageList destroys the forground color on Windows API level.
+ // Hence the canvas does not recognize the change and we have to restore the color manually.
+ ForegroundColor := ColorToRGB(Canvas.Font.Color);
+
+ // If the tree or the current node is disabled then let the VCL draw the image as it already
+ // contains code to convert the image to the system colors.
+ if OverlayImage > -1 then
+ Images.DrawOverlay(Canvas, XPos, YPos, Index, OverlayImage, False)
+ else
+ Images.Draw(Canvas, XPos, YPos, Index, False);
+
+ SetTextColor(Canvas.Handle, ForegroundColor);
+ end
+ else
+ begin
+ if OverlayImage > -1 then
+ ExtraStyle := ILD_TRANSPARENT or ILD_OVERLAYMASK and IndexToOverlayMask(OverlayImage + 1)
+ else
+ ExtraStyle := ILD_TRANSPARENT;
+
+ // Blend image if enabled and the tree has the focus (or ghosted images must be drawn also if unfocused) ...
+ if (toUseBlendedImages in FOptions.FPaintOptions) and PaintFocused
+ // ... and the image is ghosted...
+ and (Ghosted or
+ // ... or it is not the check image and the node is selected (but selection is not for the entire row)...
+ ((vsSelected in Node.States) and
+ not (toFullRowSelect in FOptions.FSelectionOptions) and
+ not (toGridExtensions in FOptions.FMiscOptions)) or
+ // ... or the node must be shown in cut mode.
+ CutNode) then
+ ExtraStyle := ExtraStyle or ILD_BLEND50;
+
+ ImageList_DrawEx(Handle, Index, Canvas.Handle, XPos, YPos, 0, 0, GetRGBColor(BkColor), ForegroundColor,
+ Style[ImageType] or ExtraStyle);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintNodeButton(Canvas: TCanvas; Node: PVirtualNode; const R: TRect; ButtonX,
+ ButtonY: Integer; BidiMode: TBiDiMode);
+
+var
+ Bitmap: TBitmap;
+ XPos: Integer;
+
+begin
+ if vsExpanded in Node.States then
+ Bitmap := FMinusBM
+ else
+ Bitmap := FPlusBM;
+
+ // Draw the node's plus/minus button according to the directionality.
+ if BidiMode = bdLeftToRight then
+ XPos := R.Left + ButtonX
+ else
+ XPos := R.Right - ButtonX - Bitmap.Width;
+
+ // Need to draw this masked.
+ Canvas.Draw(XPos, R.Top + ButtonY, Bitmap);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintTreeLines(const PaintInfo: TVTPaintInfo; VAlignment, IndentSize: Integer;
+ LineImage: TLineImage);
+
+var
+ I: Integer;
+ XPos,
+ Offset: Integer;
+ NewStyles: TLineImage;
+
+begin
+ NewStyles := nil;
+
+ with PaintInfo do
+ begin
+ if BidiMode = bdLeftToRight then
+ begin
+ XPos := CellRect.Left;
+ Offset := FIndent;
+ end
+ else
+ begin
+ Offset := -Integer(FIndent);
+ XPos := CellRect.Right + Offset;
+ end;
+
+ case FLineMode of
+ lmBands:
+ if poGridLines in PaintInfo.PaintOptions then
+ begin
+ // Convert the line images in correct bands.
+ SetLength(NewStyles, Length(LineImage));
+ for I := IndentSize - 1 downto 0 do
+ begin
+ if vsExpanded in Node.States then
+ NewStyles[I] := ltLeft
+ else
+ case LineImage[I] of
+ ltRight,
+ ltBottomRight,
+ ltTopDownRight,
+ ltTopRight:
+ NewStyles[I] := ltLeftBottom;
+ ltNone:
+ // Have to take over the image to the right of this one. A no line entry can never appear as
+ // last entry so I don't need an end check here.
+ if LineImage[I + 1] in [ltNone, ltTopRight] then
+ NewStyles[I] := NewStyles[I + 1]
+ else
+ NewStyles[I] := ltLeft;
+ ltTopDown:
+ // Have to check the image to the right of this one. A top down line can never appear as
+ // last entry so I don't need an end check here.
+ if LineImage[I + 1] in [ltNone, ltTopRight] then
+ NewStyles[I] := NewStyles[I + 1]
+ else
+ NewStyles[I] := ltLeft;
+ end;
+ end;
+
+ PaintInfo.Canvas.Font.Color := FColors.GridLineColor;
+ for I := 0 to IndentSize - 1 do
+ begin
+ DrawLineImage(PaintInfo, XPos, CellRect.Top, Node.NodeHeight - 1, VAlignment, NewStyles[I],
+ BidiMode <> bdLeftToRight);
+ Inc(XPos, Offset);
+ end;
+ end;
+ else // lmNormal
+ PaintInfo.Canvas.Font.Color := FColors.TreeLineColor;
+ for I := 0 to IndentSize - 1 do
+ begin
+ DrawLineImage(PaintInfo, XPos, CellRect.Top, Node.NodeHeight, VAlignment, LineImage[I],
+ BidiMode <> bdLeftToRight);
+ Inc(XPos, Offset);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintSelectionRectangle(Target: TCanvas; WindowOrgX: Integer; const SelectionRect: TRect;
+ TargetRect: TRect);
+
+// Helper routine to draw a selection rectangle in the mode determined by DrawSelectionMode.
+
+var
+ BlendRect: TRect;
+ TextColorBackup,
+ BackColorBackup: COLORREF; // used to restore forground and background colors when drawing a selection rectangle
+
+begin
+ if ((FDrawSelectionMode = smDottedRectangle) and not (tsUseThemes in FStates)) or
+ not MMXAvailable then
+ begin
+ // Classical selection rectangle using dotted borderlines.
+ TextColorBackup := GetTextColor(Target.Handle);
+ SetTextColor(Target.Handle, $FFFFFF);
+ BackColorBackup := GetBkColor(Target.Handle);
+ SetBkColor(Target.Handle, 0);
+ Target.DrawFocusRect(SelectionRect);
+ SetTextColor(Target.Handle, TextColorBackup);
+ SetBkColor(Target.Handle, BackColorBackup);
+ end
+ else
+ begin
+ // Modern alpha blended style.
+ OffsetRect(TargetRect, WindowOrgX, 0);
+ if IntersectRect(BlendRect, OrderRect(SelectionRect), TargetRect) then
+ begin
+ OffsetRect(BlendRect, -WindowOrgX, 0);
+ AlphaBlend(0, Target.Handle, BlendRect, Point(0, 0), bmConstantAlphaAndColor, FSelectionBlendFactor,
+ ColorToRGB(FColors.SelectionRectangleBlendColor));
+
+ Target.Brush.Color := FColors.SelectionRectangleBorderColor;
+ Target.FrameRect(SelectionRect);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PanningWindowProc(var Message: TMessage);
+
+var
+ PS: TPaintStruct;
+ Canvas: TCanvas;
+
+begin
+ if Message.Msg = WM_PAINT then
+ begin
+ BeginPaint(FPanningWindow, PS);
+ Canvas := TCanvas.Create;
+ Canvas.Handle := PS.hdc;
+ try
+ Canvas.Draw(0, 0, FPanningImage);
+ finally
+ Canvas.Handle := 0;
+ Canvas.Free;
+ EndPaint(FPanningWindow, PS);
+ end;
+ Message.Result := 0;
+ end
+ else
+ with Message do
+ Result := DefWindowProc(FPanningWindow, Msg, wParam, lParam);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType,
+ ChunkSize: Integer): Boolean;
+
+// Called while loading a tree structure, Node is already valid (allocated) at this point.
+// The function handles the base and user chunks, any other chunk is marked as being unknown (result becomes False)
+// and skipped. Descentants may handle them by overriding this method.
+// Returns True if the chunk could be handled, otherwise False.
+
+var
+ ChunkBody: TBaseChunkBody;
+ Run: PVirtualNode;
+ LastPosition: Integer;
+
+begin
+ case ChunkType of
+ BaseChunk:
+ begin
+ // Load base chunk's body (chunk header has already been consumed).
+ if Version > 1 then
+ Stream.Read(ChunkBody, SizeOf(ChunkBody))
+ else
+ begin
+ with ChunkBody do
+ begin
+ // In version prior to 2 there was a smaller chunk body. Hence we have to read it entry by entry now.
+ Stream.Read(ChildCount, SizeOf(ChildCount));
+ Stream.Read(NodeHeight, SizeOf(NodeHeight));
+ // TVirtualNodeStates was a byte sized type in version 1
+ States := [];
+ Stream.Read(States, SizeOf(Byte));
+ // vsVisible is now in the place where vsSelected was before, but every node was visible in the old version
+ // so we need to fix this too.
+ if vsVisible in States then
+ Include(States, vsSelected)
+ else
+ Include(States, vsVisible);
+ Stream.Read(Align, SizeOf(Align));
+ Stream.Read(CheckState, SizeOf(CheckState));
+ Stream.Read(CheckType, SizeOf(CheckType));
+ end;
+ end;
+
+ with Node^ do
+ begin
+ // Set states first, in case the node is invisble.
+ States := ChunkBody.States;
+
+ NodeHeight := ChunkBody.NodeHeight;
+ AdjustTotalHeight(Node, NodeHeight);
+
+ Align := ChunkBody.Align;
+ CheckState := ChunkBody.CheckState;
+ CheckType := ChunkBody.CheckType;
+
+ // Create and read child nodes.
+ while ChunkBody.ChildCount > 0 do
+ begin
+ Run := MakeNewNode;
+ InternalConnectNode(Run, Node, Self, amAddChildLast);
+ ReadNode(Stream, Version, Run);
+ Dec(ChunkBody.ChildCount);
+ end;
+ end;
+ Result := True;
+ end;
+ UserChunk:
+ if ChunkSize > 0 then
+ begin
+ // need to know whether the data was read
+ LastPosition := Stream.Position;
+ DoLoadUserData(Node, Stream);
+ // compare stream position to learn whether the data was read
+ Result := Stream.Position > LastPosition;
+ // Improve stability by advancing the stream to the chunk's real end if
+ // the application did not read what has been written.
+ if not Result or (Stream.Position <> (LastPosition + ChunkSize)) then
+ Stream.Position := LastPosition + ChunkSize;
+ end
+ else
+ Result := True;
+ else
+ // unknown chunk, skip it
+ Stream.Position := Stream.Position + ChunkSize;
+ Result := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ReadNode(Stream: TStream; Version: Integer; Node: PVirtualNode);
+
+// Reads the anchor chunk of each node and initiates reading the sub chunks for this node
+
+var
+ Header: TChunkHeader;
+ EndPosition: Integer;
+
+begin
+ with Stream do
+ begin
+ // Read anchor chunk of the node.
+ Stream.Read(Header, SizeOf(Header));
+ if Header.ChunkType = NodeChunk then
+ begin
+ EndPosition := Stream.Position + Header.ChunkSize;
+ // Read all subchunks until the indicated chunk end position is reached in the stream.
+ while Position < EndPosition do
+ begin
+ // Read new chunk header.
+ Stream.Read(Header, SizeOf(Header));
+ ReadChunk(Stream, Version, Node, Header.ChunkType, Header.ChunkSize);
+ end;
+ // If the last chunk does not end at the given end position then there is something wrong.
+ if Position <> EndPosition then
+ ShowError(SCorruptStream2, hcTFCorruptStream2);
+ end
+ else
+ ShowError(SCorruptStream1, hcTFCorruptStream1);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.RedirectFontChangeEvent(Canvas: TCanvas);
+
+begin
+ if @Canvas.Font.OnChange <> @FOldFontChange then
+ begin
+ FOldFontChange := Canvas.Font.OnChange;
+ Canvas.Font.OnChange := FontChanged;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.RemoveFromSelection(Node: PVirtualNode);
+
+var
+ Index: Integer;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil!');
+ if vsSelected in Node.States then
+ begin
+ Exclude(Node.States, vsSelected);
+ if FindNodeInSelection(Node, Index, -1, -1) and (Index < FSelectionCount - 1) then
+ Move(FSelection[Index + 1], FSelection[Index], (FSelectionCount - Index - 1) * 4);
+ if FSelectionCount > 0 then
+ Dec(FSelectionCount);
+ SetLength(FSelection, FSelectionCount);
+
+ if FSelectionCount = 0 then
+ ResetRangeAnchor;
+
+ Change(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean): HResult;
+
+// Returns a memory expression of all currently selected nodes in the Medium structure.
+// Note: The memory requirement of this method might be very high. This depends however on the requested storage format.
+// For HGlobal (a global memory block) we need to render first all nodes to local memory and copy this then to
+// the global memory in Medium. This is necessary because we have first to determine how much
+// memory is needed before we can allocate it. Hence for a short moment we need twice the space as used by the
+// nodes alone (plus the amount the nodes need in the tree anyway)!
+// With IStream this does not happen. We directly stream out the nodes and pass the constructed stream along.
+
+ //--------------- local function --------------------------------------------
+
+ procedure WriteNodes(Stream: TStream);
+
+ var
+ Selection: TNodeArray;
+ I: Integer;
+
+ begin
+ if ForClipboard then
+ Selection := GetSortedCutCopySet(True)
+ else
+ Selection := GetSortedSelection(True);
+ for I := 0 to High(Selection) do
+ WriteNode(Stream, Selection[I]);
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ Data: PCardinal;
+ ResPointer: Pointer;
+ ResSize: Integer;
+ OLEStream: IStream;
+ VCLStream: TStream;
+
+begin
+ FillChar(Medium, SizeOf(Medium), 0);
+
+ // We can render the native clipboard format in two different storage media.
+ if (FormatEtcIn.cfFormat = CF_VIRTUALTREE) and (FormatEtcIn.tymed and (TYMED_HGLOBAL or TYMED_ISTREAM) <> 0) then
+ begin
+ VCLStream := nil;
+ try
+ Medium.unkForRelease := nil;
+ // Return data in one of the supported storage formats, prefer IStream.
+ if FormatEtcIn.tymed and TYMED_ISTREAM <> 0 then
+ begin
+ // Create an IStream on a memory handle (here it is 0 which indicates to implicitely allocated a handle).
+ // Do not use TStreamAdapter as it is not compatible with OLE (when flushing the clipboard OLE wants the HGlobal
+ // back which is not supported by TStreamAdapater).
+ CreateStreamOnHGlobal(0, True, OLEStream);
+ VCLStream := TOLEStream.Create(OLEStream);
+ WriteNodes(VCLStream);
+ // Rewind stream.
+ VCLStream.Position := 0;
+ Medium.tymed := TYMED_ISTREAM;
+ IUnknown(Medium.stm) := OLEStream;
+ Result := S_OK;
+ end
+ else
+ begin
+ VCLStream := TMemoryStream.Create;
+ WriteNodes(VCLStream);
+ ResPointer := TMemoryStream(VCLStream).Memory;
+ ResSize := VCLStream.Position;
+
+ // Allocate memory to hold the string.
+ if ResSize > 0 then
+ begin
+ Medium.hGlobal := GlobalAlloc(GHND or GMEM_SHARE, ResSize + SizeOf(Cardinal));
+ Data := GlobalLock(Medium.hGlobal);
+ // Store the size of the data too, for easy retrival.
+ Data^ := ResSize;
+ Inc(Data);
+ Move(ResPointer^, Data^, ResSize);
+ GlobalUnlock(Medium.hGlobal);
+ Medium.tymed := TYMED_HGLOBAL;
+
+ Result := S_OK;
+ end
+ else
+ Result := E_FAIL;
+ end;
+ finally
+ // We can free the VCL stream here since it was either a pure memory stream or only a wrapper around
+ // the OLEStream which exists independently.
+ VCLStream.Free;
+ end;
+ end
+ else // Ask application descentants to render self defined formats.
+ Result := DoRenderOLEData(FormatEtcIn, Medium, ForClipboard);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ResetRangeAnchor;
+
+// Called when there is no selected node anymore and the selection range anchor needs a new value.
+
+begin
+ FRangeAnchor := FFocusedNode;
+ FLastSelectionLevel := -1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.RestoreFontChangeEvent(Canvas: TCanvas);
+
+begin
+ Canvas.Font.OnChange := FOldFontChange;
+ FOldFontChange := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SelectNodes(StartNode, EndNode: PVirtualNode; AddOnly: Boolean);
+
+// Selects a range of nodes and unselects all other eventually selected nodes which are not in this range if
+// AddOnly is False.
+// EndNode must be visible while StartNode does not necessarily as in the case where the last focused node is the start
+// node but it is a child of a node which has been collapsed previously. In this case the first visible parent node
+// is used as start node. StartNode can be nil in which case the very first node in the tree is used.
+
+var
+ NodeFrom,
+ NodeTo,
+ LastAnchor: PVirtualNode;
+ Index: Integer;
+
+begin
+ Assert(Assigned(EndNode), 'EndNode must not be nil!');
+ ClearTempCache;
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ else
+ if not FullyVisible[StartNode] then
+ begin
+ StartNode := GetPreviousVisible(StartNode);
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ end;
+
+ if CompareNodePositions(StartNode, EndNode) < 0 then
+ begin
+ NodeFrom := StartNode;
+ NodeTo := EndNode;
+ end
+ else
+ begin
+ NodeFrom := EndNode;
+ NodeTo := StartNode;
+ end;
+
+ // The range anchor will be reset by the following call.
+ LastAnchor := FRangeAnchor;
+ if not AddOnly then
+ InternalClearSelection;
+
+ while NodeFrom <> NodeTo do
+ begin
+ InternalCacheNode(NodeFrom);
+ NodeFrom := GetNextVisible(NodeFrom);
+ end;
+ // select last node too
+ InternalCacheNode(NodeFrom);
+ // now add them all in "one" step
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+ if Assigned(LastAnchor) and FindNodeInSelection(LastAnchor, Index, -1, -1) then
+ FRangeAnchor := LastAnchor;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SetBiDiMode(Value: TBiDiMode);
+
+begin
+ inherited;
+
+ RecreateWnd;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SkipNode(Stream: TStream);
+
+// Skips the data for the next node in the given stream (including the child nodes).
+
+var
+ Header: TChunkHeader;
+
+begin
+ with Stream do
+ begin
+ // read achor chunk of the node
+ Stream.Read(Header, SizeOf(Header));
+ if Header.ChunkType = NodeChunk then
+ Stream.Position := Stream.Position + Header.ChunkSize
+ else
+ ShowError(SCorruptStream1, hcTFCorruptStream1);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+var
+ PanningWindowClass: TWndClass = (
+ style: 0;
+ lpfnWndProc: @DefWindowProc;
+ cbClsExtra: 0;
+ cbWndExtra: 0;
+ hInstance: 0;
+ hIcon: 0;
+ hCursor: 0;
+ hbrBackground: 0;
+ lpszMenuName: nil;
+ lpszClassName: 'VTPanningWindow'
+ );
+
+procedure TBaseVirtualTree.StartWheelPanning(Position: TPoint);
+
+// Called when wheel panning should start. A little helper window is created to indicate the reference position,
+// which determines in which direction and how far wheel panning/scrolling will happen.
+
+ //--------------- local function --------------------------------------------
+
+ function CreateClipRegion: HRGN;
+
+ // In order to avoid doing all the transparent drawing ourselves we use a
+ // window region for the wheel window.
+ // Since we only work on a very small image (32x32 pixels) this is acceptable.
+
+ var
+ Start, X, Y: Integer;
+ Temp: HRGN;
+
+ begin
+ Assert(not FPanningImage.Empty, 'Invalid wheel panning image.');
+
+ // Create an initial region on which we operate.
+ Result := CreateRectRgn(0, 0, 0, 0);
+ with FPanningImage, Canvas do
+ begin
+ for Y := 0 to Height - 1 do
+ begin
+ Start := -1;
+ for X := 0 to Width - 1 do
+ begin
+ // Start a new span if we found a non-transparent pixel and no span is currently started.
+ if (Start = -1) and (Pixels[X, Y] <> clFuchsia) then
+ Start := X
+ else
+ if (Start > -1) and (Pixels[X, Y] = clFuchsia) then
+ begin
+ // A non-transparent span is finished. Add it to the result region.
+ Temp := CreateRectRgn(Start, Y, X, Y + 1);
+ CombineRgn(Result, Result, Temp, RGN_OR);
+ DeleteObject(Temp);
+ Start := -1;
+ end;
+ end;
+ // If there is an open span then add this also to the result region.
+ if Start > -1 then
+ begin
+ Temp := CreateRectRgn(Start, Y, Width, Y + 1);
+ CombineRgn(Result, Result, Temp, RGN_OR);
+ DeleteObject(Temp);
+ end;
+ end;
+ end;
+ // The resulting region is used as window region so we must not delete it.
+ // Windows will own it after the assignment below.
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ TempClass: TWndClass;
+ ClassRegistered: Boolean;
+ ImageName: string;
+
+begin
+ // Set both panning and scrolling flag. One will be removed shortly depending on whether the middle mouse button is
+ // released before the mouse is moved or vice versa. The first case is referred to as wheel scrolling while the
+ // latter is called wheel panning.
+ StopTimer(ScrollTimer);
+ DoStateChange([tsWheelPanning, tsWheelScrolling]);
+
+ // Register the helper window class.
+ PanningWindowClass.hInstance := HInstance;
+ ClassRegistered := GetClassInfo(HInstance, PanningWindowClass.lpszClassName, TempClass);
+ if not ClassRegistered or (TempClass.lpfnWndProc <> @DefWindowProc) then
+ begin
+ if ClassRegistered then
+ Windows.UnregisterClass(PanningWindowClass.lpszClassName, HInstance);
+ Windows.RegisterClass(PanningWindowClass);
+ end;
+ // Create the helper window and show at the given position without activating it.
+ with ClientToScreen(Position) do
+ FPanningWindow := CreateWindowEx(WS_EX_TOOLWINDOW, PanningWindowClass.lpszClassName, nil, WS_POPUP, X - 16, Y - 16,
+ 32, 32, Handle, 0, HInstance, nil);
+
+ FPanningImage := TBitmap.Create;
+ if Integer(FRangeX) > ClientWidth then
+ begin
+ if Integer(FRangeY) > ClientHeight then
+ ImageName := 'VT_MOVEALL'
+ else
+ ImageName := 'VT_MOVEEW'
+ end
+ else
+ ImageName := 'VT_MOVENS';
+ FPanningImage.LoadFromResourceName(HInstance, ImageName);
+ SetWindowRgn(FPanningWindow, CreateClipRegion, False);
+
+ {$ifdef COMPILER_6_UP}
+ SetWindowLong(FPanningWindow, GWL_WNDPROC, Integer(Classes.MakeObjectInstance(PanningWindowProc)));
+ {$else}
+ SetWindowLong(FPanningWindow, GWL_WNDPROC, Integer(MakeObjectInstance(PanningWindowProc)));
+ {$endif}
+ ShowWindow(FPanningWindow, SW_SHOWNOACTIVATE);
+
+ // Setup the panscroll timer and capture all mouse input.
+ SetFocus;
+ SetCapture(Handle);
+ SetTimer(Handle, ScrollTimer, 20, nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.StopWheelPanning;
+
+// Stops panning if currently active and destroys the helper window.
+
+var
+ Instance: Pointer;
+
+begin
+ if [tsWheelPanning, tsWheelScrolling] * FStates <> [] then
+ begin
+ // Release the mouse capture and stop the panscroll timer.
+ StopTimer(ScrollTimer);
+ ReleaseCapture;
+ DoStateChange([], [tsWheelPanning, tsWheelScrolling]);
+
+ // Destroy the helper window.
+ Instance := Pointer(GetWindowLong(FPanningWindow, GWL_WNDPROC));
+ DestroyWindow(FPanningWindow);
+ if Instance <> @DefWindowProc then
+ {$ifdef COMPILER_6_UP}
+ Classes.FreeObjectInstance(Instance);
+ {$else}
+ FreeObjectInstance(Instance);
+ {$endif}
+ FPanningWindow := 0;
+ FPanningImage.Free;
+ FPanningImage := nil;
+ DeleteObject(FPanningCursor);
+ FPanningCursor := 0;
+ Windows.SetCursor(Screen.Cursors[Cursor]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.StructureChange(Node: PVirtualNode; Reason: TChangeReason);
+
+begin
+ AdviseChangeEvent(True, Node, Reason);
+
+ if FUpdateCount = 0 then
+ begin
+ if (FChangeDelay > 0) and not (tsSynchMode in FStates) then
+ SetTimer(Handle, StructureChangeTimer, FChangeDelay, nil)
+ else
+ DoStructureChange(Node, Reason);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.SuggestDropEffect(Source: TObject; Shift: TShiftState; Pt: TPoint;
+ AllowedEffects: Integer): Integer;
+
+// determines the drop action to take if the drag'n drop operation ends on this tree
+// Note: Source can be any Delphi object not just a virtual tree
+
+begin
+ Result := AllowedEffects;
+
+ // prefer MOVE if source and target are the same control, otherwise whatever is allowed as initial value
+ if Assigned(Source) and (Source = Self) then
+ if (AllowedEffects and DROPEFFECT_MOVE) <> 0 then
+ Result := DROPEFFECT_MOVE
+ else // no change
+ else
+ // drag between different applicatons
+ if (AllowedEffects and DROPEFFECT_COPY) <> 0 then
+ Result := DROPEFFECT_COPY;
+
+ // consider modifier keys and what is allowed at the moment, if none of the following conditions apply then
+ // the initial value just set is used
+ if ssCtrl in Shift then
+ begin
+ // copy or link
+ if ssShift in Shift then
+ begin
+ // link
+ if (AllowedEffects and DROPEFFECT_LINK) <> 0 then
+ Result := DROPEFFECT_LINK;
+ end
+ else
+ begin
+ // copy
+ if (AllowedEffects and DROPEFFECT_COPY) <> 0 then
+ Result := DROPEFFECT_COPY;
+ end;
+ end
+ else
+ begin
+ // move, link or default
+ if ssShift in Shift then
+ begin
+ // move
+ if (AllowedEffects and DROPEFFECT_MOVE) <> 0 then
+ Result := DROPEFFECT_MOVE;
+ end
+ else
+ begin
+ // link or default
+ if ssAlt in Shift then
+ begin
+ // link
+ if (AllowedEffects and DROPEFFECT_LINK) <> 0 then
+ Result := DROPEFFECT_LINK;
+ end;
+ // else default
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ToggleSelection(StartNode, EndNode: PVirtualNode);
+
+// Switchs the selection state of a range of nodes.
+// Note: This method is specifically designed to help selecting ranges with the keyboard and considers therefore
+// the range anchor.
+
+var
+ NodeFrom,
+ NodeTo: PVirtualNode;
+ NewSize: Integer;
+ Position: Integer;
+
+begin
+ Assert(Assigned(EndNode), 'EndNode must not be nil!');
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ else
+ if not FullyVisible[StartNode] then
+ StartNode := GetPreviousVisible(StartNode);
+
+ Position := CompareNodePositions(StartNode, EndNode);
+ // nothing to do if start and end node are the same
+ if Position <> 0 then
+ begin
+ if Position < 0 then
+ begin
+ NodeFrom := StartNode;
+ NodeTo := EndNode;
+ end
+ else
+ begin
+ NodeFrom := EndNode;
+ NodeTo := StartNode;
+ end;
+
+ ClearTempCache;
+
+ // 1) toggle the start node if it is before the range anchor
+ if CompareNodePositions(NodeFrom, FRangeAnchor) < 0 then
+ if not (vsSelected in NodeFrom.States) then
+ InternalCacheNode(NodeFrom)
+ else
+ InternalRemoveFromSelection(NodeFrom);
+
+ // 2) toggle all nodes within the range
+ NodeFrom := GetNextVisible(NodeFrom);
+ while NodeFrom <> NodeTo do
+ begin
+ if not (vsSelected in NodeFrom.States) then
+ InternalCacheNode(NodeFrom)
+ else
+ InternalRemoveFromSelection(NodeFrom);
+ NodeFrom := GetNextVisible(NodeFrom);
+ end;
+
+ // 3) toggle end node if it is after the range anchor
+ if CompareNodePositions(NodeFrom, FRangeAnchor) > 0 then
+ if not (vsSelected in NodeFrom.States) then
+ InternalCacheNode(NodeFrom)
+ else
+ InternalRemoveFromSelection(NodeFrom);
+
+ // Do some housekeeping if there was a change.
+ NewSize := PackArray(FSelection, FSelectionCount);
+ if NewSize > -1 then
+ begin
+ FSelectionCount := NewSize;
+ SetLength(FSelection, FSelectionCount);
+ end;
+ // If the range went over the anchor then we need to reselect it.
+ if not (vsSelected in FRangeAnchor.States) then
+ InternalCacheNode(FRangeAnchor);
+ if FTempNodeCount > 0 then
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UnselectNodes(StartNode, EndNode: PVirtualNode);
+
+// Deselects a range of nodes.
+// EndNode must be visible while StartNode must not as in the case where the last focused node is the start node
+// but it is a child of a node which has been collapsed previously. In this case the first visible parent node
+// is used as start node. StartNode can be nil in which case the very first node in the tree is used.
+
+var
+ NodeFrom,
+ NodeTo: PVirtualNode;
+ NewSize: Integer;
+
+begin
+ Assert(Assigned(EndNode), 'EndNode must not be nil!');
+
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ else
+ if not FullyVisible[StartNode] then
+ begin
+ StartNode := GetPreviousVisible(StartNode);
+ if StartNode = nil then
+ StartNode := FRoot.FirstChild
+ end;
+
+ if CompareNodePositions(StartNode, EndNode) < 0 then
+ begin
+ NodeFrom := StartNode;
+ NodeTo := EndNode;
+ end
+ else
+ begin
+ NodeFrom := EndNode;
+ NodeTo := StartNode;
+ end;
+
+ while NodeFrom <> NodeTo do
+ begin
+ InternalRemoveFromSelection(NodeFrom);
+ NodeFrom := GetNextVisible(NodeFrom);
+ end;
+ // Deselect last node too.
+ InternalRemoveFromSelection(NodeFrom);
+
+ // Do some housekeeping.
+ NewSize := PackArray(FSelection, FSelectionCount);
+ if NewSize > -1 then
+ begin
+ FSelectionCount := NewSize;
+ SetLength(FSelection, FSelectionCount);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateDesigner;
+
+var
+ ParentForm: TCustomForm;
+
+begin
+ if (csDesigning in ComponentState) and not (csUpdating in ComponentState) then
+ begin
+ ParentForm := GetParentForm(Self);
+ if Assigned(ParentForm) and Assigned(ParentForm.Designer) then
+ ParentForm.Designer.Modified;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateHeaderRect;
+
+// Calculates the rectangle the header occupies in non-client area.
+// These coordinates are in window rectangle.
+
+var
+ OffsetX,
+ OffsetY: Integer;
+ EdgeSize: Integer;
+ Styles: Integer;
+
+begin
+ FHeaderRect := Rect(0, 0, Width, Height);
+
+ // Consider borders...
+ Styles := GetWindowLong(Handle, GWL_STYLE);
+ if (Styles and WS_BORDER) <> 0 then
+ InflateRect(FHeaderRect, -1, -1);
+ if (Styles and WS_THICKFRAME) <> 0 then
+ InflateRect(FHeaderRect, -3, -3);
+
+ Styles := GetWindowLong(Handle, GWL_EXSTYLE);
+ if (Styles and WS_EX_CLIENTEDGE) <> 0 then
+ InflateRect(FHeaderRect, -2, -2);
+
+ // ... and bevels.
+ OffsetX := BorderWidth;
+ OffsetY := BorderWidth;
+ if BevelKind <> bkNone then
+ begin
+ EdgeSize := 0;
+ if BevelInner <> bvNone then
+ Inc(EdgeSize, BevelWidth);
+ if BevelOuter <> bvNone then
+ Inc(EdgeSize, BevelWidth);
+ if beLeft in BevelEdges then
+ Inc(OffsetX, EdgeSize);
+ if beTop in BevelEdges then
+ Inc(OffsetY, EdgeSize);
+ end;
+
+ InflateRect(FHeaderRect, -OffsetX, -OffsetY);
+
+ if hoVisible in FHeader.FOptions then
+ begin
+ if FHeaderRect.Left <= FHeaderRect.Right then
+ FHeaderRect.Bottom := FHeaderRect.Top + Integer(FHeader.FHeight)
+ else
+ FHeaderRect := Rect(0, 0, 0, 0);
+ end
+ else
+ FHeaderRect.Bottom := FHeaderRect.Top;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateEditBounds;
+
+// Used to update the bounds of the current node editor if editing is currently active.
+
+var
+ R: TRect;
+ Dummy: Integer;
+ BidiMode: TBidiMode;
+
+begin
+ if tsEditing in FStates then
+ begin
+ if vsMultiline in FFocusedNode.States then
+ R := GetDisplayRect(FFocusedNode, FEditColumn, True, False)
+ else
+ R := GetDisplayRect(FFocusedNode, FEditColumn, True, True);
+ if (toGridExtensions in FOptions.MiscOptions) then
+ begin
+ // Consider visible tree lines, check boxes or images here. Do not forget about bidi.
+ if FEditColumn = NoColumn then
+ BidiMode := Self.BidiMode
+ else
+ BidiMode := FHeader.Columns[FEditColumn].FBiDiMode;
+ if BiDiMode = bdLeftToRight then
+ FHeader.Columns.GetColumnBounds(FEditColumn, Dummy, R.Right)
+ else
+ FHeader.Columns.GetColumnBounds(FEditColumn, R.Left, Dummy);
+ end;
+ if toShowHorzGridLines in TreeOptions.PaintOptions then
+ Dec(R.Bottom);
+ FEditLink.SetBounds(R);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+const
+ ScrollMasks: array[Boolean] of Cardinal = (0, SIF_DISABLENOSCROLL);
+
+const // Region identifiers for GetRandomRgn
+ CLIPRGN = 1;
+ METARGN = 2;
+ APIRGN = 3;
+ SYSRGN = 4;
+
+function GetRandomRgn(DC: HDC; Rgn: HRGN; iNum: Integer): Integer; stdcall; external 'GDI32.DLL';
+
+procedure TBaseVirtualTree.UpdateWindowAndDragImage(const Tree: TBaseVirtualTree; TreeRect: TRect; UpdateNCArea,
+ ReshowDragImage: Boolean);
+
+// Method to repaint part of the window area which is not covered by the drag image and to initiate a recapture
+// of the drag image.
+// Note: This method must only be called during a drag operation and the tree passed in is the one managing the current
+// drag image (so it is the actual drag source).
+
+var
+ DragRegion, // the region representing the drag image
+ UpdateRegion, // the unclipped region within the tree to be updated
+ NCRegion: HRGN; // the region representing the non-client area of the tree
+ DragRect,
+ NCRect: TRect;
+ RedrawFlags: Cardinal;
+
+ VisibleTreeRegion: HRGN;
+
+ DC: HDC;
+
+begin
+ if IntersectRect(TreeRect, TreeRect, ClientRect) then
+ begin
+ // Retrieve the visible region of the window. This is important to avoid overpainting parts of other windows
+ // which overlap this one.
+ VisibleTreeRegion := CreateRectRgn(0, 0, 1, 1);
+ DC := GetDCEx(Handle, 0, DCX_CACHE or DCX_WINDOW or DCX_CLIPSIBLINGS or DCX_CLIPCHILDREN);
+ GetRandomRgn(DC, VisibleTreeRegion, SYSRGN);
+ ReleaseDC(Handle, DC);
+
+ // In Win9x the returned visible region is given in client coordinates. We need it in screen coordinates, though.
+ if not IsWinNT then
+ with ClientToScreen(Point(0, 0)) do
+ OffsetRgn(VisibleTreeRegion, X, Y);
+
+ // The drag image will figure out itself what part of the rectangle can be recaptured.
+ // Recapturing is not done by taking a snapshot of the screen, but by letting the tree draw itself
+ // into the back bitmap of the drag image. So the order here is unimportant.
+ Tree.FDragImage.RecaptureBackground(Self, TreeRect, VisibleTreeRegion, UpdateNCArea, ReshowDragImage);
+
+ // Calculate the screen area not covered by the drag image and which needs an update.
+ DragRect := Tree.FDragImage.GetDragImageRect;
+ MapWindowPoints(0, Handle, DragRect, 2);
+ DragRegion := CreateRectRgnIndirect(DragRect);
+
+ // Start with non-client area if requested.
+ if UpdateNCArea then
+ begin
+ // Compute the part of the non-client area which must be updated.
+
+ // Determine the outer rectangle of the entire tree window.
+ GetWindowRect(Handle, NCRect);
+ // Express the tree window rectangle in client coordinates (because RedrawWindow wants them so).
+ MapWindowPoints(0, Handle, NCRect, 2);
+ NCRegion := CreateRectRgnIndirect(NCRect);
+ // Determine client rect in screen coordinates and create another region for it.
+ UpdateRegion := CreateRectRgnIndirect(ClientRect);
+ // Create a region which only contains the NC part by subtracting out the client area.
+ CombineRgn(NCRegion, NCRegion, UpdateRegion, RGN_DIFF);
+ // Subtract also out what is hidden by the drag image.
+ CombineRgn(NCRegion, NCRegion, DragRegion, RGN_DIFF);
+ RedrawWindow(Handle, nil, NCRegion, RDW_FRAME or RDW_NOERASE or RDW_NOCHILDREN or RDW_INVALIDATE or RDW_VALIDATE or
+ RDW_UPDATENOW);
+ DeleteObject(NCRegion);
+ DeleteObject(UpdateRegion);
+ end;
+
+ UpdateRegion := CreateRectRgnIndirect(TreeRect);
+ RedrawFlags := RDW_INVALIDATE or RDW_VALIDATE or RDW_UPDATENOW or RDW_NOERASE or RDW_NOCHILDREN;
+ // Remove the part of the update region which is covered by the drag image.
+ CombineRgn(UpdateRegion, UpdateRegion, DragRegion, RGN_DIFF);
+ RedrawWindow(Handle, nil, UpdateRegion, RedrawFlags);
+ DeleteObject(UpdateRegion);
+ DeleteObject(DragRegion);
+ DeleteObject(VisibleTreeRegion);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ValidateCache;
+
+// Starts cache validation if not already done by adding this instance to the worker thread's waiter list
+// (if not already there) and signalling the thread it can start validating.
+
+begin
+ // Wait for thread to stop validation if it is currently validating this tree's cache.
+ InterruptValidation;
+
+ FStartIndex := 0;
+ if tsValidationNeeded in FStates then
+ begin
+ // Tell the thread this tree needs actually something to do.
+ WorkerThread.AddTree(Self);
+ SetEvent(WorkEvent);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ValidateNodeDataSize(var Size: Integer);
+
+begin
+ Size := 0;
+ if Assigned(FOnGetNodeDataSize) then
+ FOnGetNodeDataSize(Self, Size);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WndProc(var Message: TMessage);
+
+var
+ Handled: Boolean;
+
+begin
+ Handled := False;
+
+ // Try the header whether it needs to take this message.
+ if Assigned(FHeader) and (FHeader.FStates <> []) then
+ Handled := FHeader.HandleMessage(Message);
+ if not Handled then
+ begin
+ // For auto drag mode, let tree handle itself, instead of TControl.
+ if not (csDesigning in ComponentState) and
+ ((Message.Msg = WM_LBUTTONDOWN) or (Message.Msg = WM_LBUTTONDBLCLK)) then
+ begin
+ if (DragMode = dmAutomatic) and (DragKind = dkDrag) then
+ begin
+ if IsControlMouseMsg(TWMMouse(Message)) then
+ Handled := True;
+ if not Handled then
+ begin
+ ControlState := ControlState + [csLButtonDown];
+ Dispatch(Message); // overrides TControl's BeginDrag
+ Handled := True;
+ end;
+ end;
+ end;
+
+ if not Handled and Assigned(FHeader) then
+ Handled := FHeader.HandleMessage(Message);
+
+ if not Handled then
+ begin
+ if (Message.Msg in [WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN, WM_NCMBUTTONDOWN]) and not Focused and CanFocus then
+ SetFocus;
+ inherited;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WriteChunks(Stream: TStream; Node: PVirtualNode);
+
+// writes the core chunks for Node into the stream
+// Node: Descentants can optionally override this method to add other node specific chunks.
+// Keep in mind that this method is also called for the root node. Using this fact in descentants you can
+// create a kind of "global" chunks not directly bound to a specific node.
+
+var
+ Header: TChunkHeader;
+ LastPosition,
+ ChunkSize: Integer;
+ Chunk: TBaseChunk;
+ Run: PVirtualNode;
+
+begin
+ with Stream do
+ begin
+ // 1. The base chunk...
+ LastPosition := Position;
+ Chunk.Header.ChunkType := BaseChunk;
+ with Node^, Chunk do
+ begin
+ Body.ChildCount := ChildCount;
+ Body.NodeHeight := NodeHeight;
+ // some states are only temporary so take them out as they make no sense at the new location
+ Body.States := States - [vsChecking, vsCutOrCopy, vsDeleting, vsInitialUserData];
+ Body.Align := Align;
+ Body.CheckState := CheckState;
+ Body.CheckType := CheckType;
+ Body.Reserved := 0;
+ end;
+ // write the base chunk
+ Write(Chunk, SizeOf(Chunk));
+
+ // 2. ... directly followed by the child node chunks (actually they are child chunks of
+ // the base chunk)
+ if vsInitialized in Node.States then
+ begin
+ Run := Node.FirstChild;
+ while Assigned(Run) do
+ begin
+ WriteNode(Stream, Run);
+ Run := Run.NextSibling;
+ end;
+ end;
+
+ FinishChunkHeader(Stream, LastPosition, Position);
+
+ // 3. write user data
+ LastPosition := Position;
+ Header.ChunkType := UserChunk;
+ Write(Header, SizeOf(Header));
+ DoSaveUserData(Node, Stream);
+ // check if the application actually wrote data
+ ChunkSize := Position - LastPosition - SizeOf(TChunkHeader);
+ // seek back to start of chunk if nothing has been written
+ if ChunkSize = 0 then
+ begin
+ Position := LastPosition;
+ Size := Size - SizeOf(Header);
+ end
+ else
+ FinishChunkHeader(Stream, LastPosition, Position);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.WriteNode(Stream: TStream; Node: PVirtualNode);
+
+// Writes the "cover" chunk for Node to Stream and initiates writing child nodes and chunks.
+
+var
+ LastPosition: Integer;
+ Header: TChunkHeader;
+
+begin
+ // Initialize the node first if necessary and wanted.
+ if toInitOnSave in FOptions.FMiscOptions then
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+ end;
+
+ with Stream do
+ begin
+ LastPosition := Position;
+ // Emit the anchor chunk.
+ Header.ChunkType := NodeChunk;
+ Write(Header, SizeOf(Header));
+ // Write other chunks to stream taking their size into this chunk's size.
+ WriteChunks(Stream, Node);
+
+ // Update chunk size.
+ FinishChunkHeader(Stream, LastPosition, Position);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.AbsoluteIndex(Node: PVirtualNode): Cardinal;
+
+begin
+ Result := 0;
+ while Assigned(Node) and (Node <> FRoot) do
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if Assigned(Node.PrevSibling) then
+ begin
+ // if there's a previous sibling then add its total count to the result
+ Node := Node.PrevSibling;
+ Inc(Result, Node.TotalCount);
+ end
+ else
+ begin
+ Node := Node.Parent;
+ if Node <> FRoot then
+ Inc(Result);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode;
+
+// Adds a new node to the given parent node. This is simply done by increasing the child count of the
+// parent node. If Parent is nil then the new node is added as (last) top level node.
+// UserData can be used to set the first 4 bytes of the user data area to an initial value which can be used
+// in OnInitNode and will also cause to trigger the OnFreeNode event (if <> nil) even if the node is not yet
+// "officially" initialized.
+// AddChild is a compatibility method and will implicitly validate the parent node. This is however
+// against the virtual paradigm and hence I dissuade from its usage.
+
+var
+ NodeData: ^Pointer;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ CancelEditNode;
+
+ if Parent = nil then
+ Parent := FRoot;
+ if not (vsInitialized in Parent.States) then
+ InitNode(Parent);
+
+ // Locally stop updates of the tree in order to avoid usage of the new node before it is correctly set up.
+ // If the update count was 0 on enter then there will be a correct update at the end of this method.
+ Inc(FUpdateCount);
+ try
+ SetChildCount(Parent, Parent.ChildCount + 1);
+ // Update the hidden children flag of the parent. Nodes are added as being visible by default.
+ Exclude(Parent.States, vsAllChildrenHidden);
+ finally
+ Dec(FUpdateCount);
+ end;
+ Result := Parent.LastChild;
+
+ // Check if there is initial user data and there is also enough user data space allocated.
+ if Assigned(UserData) then
+ if FNodeDataSize >= 4 then
+ begin
+ NodeData := Pointer(PChar(@Result.Data) + FTotalInternalDataSize);
+ NodeData^ := UserData;
+ Include(Result.States, vsInitialUserData);
+ end
+ else
+ ShowError(SCannotSetUserData, hcTFCannotSetUserData);
+
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ if tsStructureChangePending in FStates then
+ begin
+ if Parent = FRoot then
+ StructureChange(nil, crChildAdded)
+ else
+ StructureChange(Parent, crChildAdded);
+ end;
+
+ if (toAutoSort in FOptions.FAutoOptions) and (FHeader.FSortColumn > InvalidColumn) then
+ Sort(Parent, FHeader.FSortColumn, FHeader.FSortDirection, True);
+
+ InvalidateToBottom(Parent);
+ UpdateScrollbars(True);
+ end;
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AddFromStream(Stream: TStream; TargetNode: PVirtualNode);
+
+// loads nodes from the given stream and adds them to TargetNode
+// the current content is not cleared before the load process starts (see also LoadFromStream)
+
+var
+ ThisID: TMagicID;
+ Version,
+ Count: Cardinal;
+ Node: PVirtualNode;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ // check first whether this is a stream we can read
+ Stream.ReadBuffer(ThisID, SizeOf(TMagicID));
+ if (ThisID[0] = MagicID[0]) and
+ (ThisID[1] = MagicID[1]) and
+ (ThisID[2] = MagicID[2]) and
+ (ThisID[5] = MagicID[5]) then
+ begin
+ Version := Word(ThisID[3]);
+ if Version <= VTTreeStreamVersion then
+ begin
+ BeginUpdate;
+ try
+ if Version < 2 then
+ Count := MaxInt
+ else
+ Stream.ReadBuffer(Count, SizeOf(Count));
+
+ while (Stream.Position < Stream.Size) and (Count > 0) do
+ begin
+ Dec(Count);
+ Node := MakeNewNode;
+ InternalConnectNode(Node, TargetNode, Self, amAddChildLast);
+ InternalAddFromStream(Stream, Version, Node);
+ end;
+ if TargetNode = FRoot then
+ DoNodeCopied(nil)
+ else
+ DoNodeCopied(TargetNode);
+ finally
+ EndUpdate;
+ end;
+ end
+ else
+ ShowError(SWrongStreamVersion, hcTFWrongStreamVersion);
+ end
+ else
+ ShowError(SWrongStreamVersion, hcTFWrongStreamVersion);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.AfterConstruction;
+
+begin
+ inherited;
+
+ if FRoot = nil then
+ InitRootNode;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Assign(Source: TPersistent);
+
+begin
+ if (Source is TBaseVirtualTree) and not (toReadOnly in FOptions.FMiscOptions) then
+ with Source as TBaseVirtualTree do
+ begin
+ Self.Align := Align;
+ Self.Anchors := Anchors;
+ Self.AutoScrollDelay := AutoScrollDelay;
+ Self.AutoScrollInterval := AutoScrollInterval;
+ Self.AutoSize := AutoSize;
+ Self.Background := Background;
+ Self.BevelEdges := BevelEdges;
+ Self.BevelInner := BevelInner;
+ Self.BevelKind := BevelKind;
+ Self.BevelOuter := BevelOuter;
+ Self.BevelWidth := BevelWidth;
+ Self.BiDiMode := BiDiMode;
+ Self.BorderStyle := BorderStyle;
+ Self.BorderWidth := BorderWidth;
+ Self.ChangeDelay := ChangeDelay;
+ Self.CheckImageKind := CheckImageKind;
+ Self.Color := Color;
+ Self.Colors.Assign(Colors);
+ Self.Constraints.Assign(Constraints);
+ Self.Ctl3D := Ctl3D;
+ Self.DefaultNodeHeight := DefaultNodeHeight;
+ Self.DefaultPasteMode := DefaultPasteMode;
+ Self.DragCursor := DragCursor;
+ Self.DragImageKind := DragImageKind;
+ Self.DragKind := DragKind;
+ Self.DragMode := DragMode;
+ Self.Enabled := Enabled;
+ Self.Font := Font;
+ Self.Header := Header;
+ Self.HintAnimation := HintAnimation;
+ Self.HintMode := HintMode;
+ Self.HotCursor := HotCursor;
+ Self.Images := Images;
+ Self.ImeMode := ImeMode;
+ Self.ImeName := ImeName;
+ Self.Indent := Indent;
+ Self.Margin := Margin;
+ Self.NodeAlignment := NodeAlignment;
+ Self.NodeDataSize := NodeDataSize;
+ Self.TreeOptions := TreeOptions;
+ Self.ParentBiDiMode := ParentBiDiMode;
+ Self.ParentColor := ParentColor;
+ Self.ParentCtl3D := ParentCtl3D;
+ Self.ParentFont := ParentFont;
+ Self.ParentShowHint := ParentShowHint;
+ Self.PopupMenu := PopupMenu;
+ Self.RootNodeCount := RootNodeCount;
+ Self.ScrollBarOptions := ScrollBarOptions;
+ Self.ShowHint := ShowHint;
+ Self.StateImages := StateImages;
+ Self.TabOrder := TabOrder;
+ Self.TabStop := TabStop;
+ Self.Visible := Visible;
+ Self.SelectionCurveRadius := SelectionCurveRadius;
+ Self.SelectionBlendFactor := SelectionBlendFactor;
+ end
+ else
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.BeginDrag(Immediate: Boolean; Threshold: Integer);
+
+// Reintroduced method to allow to start OLE drag'n drop as well as VCL drag'n drop.
+
+begin
+ if FDragType = dtVCL then
+ begin
+ DoStateChange([tsVCLDragPending]);
+ inherited;
+ end
+ else
+ if (FStates * [tsOLEDragPending, tsOLEDragging]) = [] then
+ begin
+ // Drag start position has already been recorded in WMMouseDown.
+ if Threshold < 0 then
+ FDragThreshold := Mouse.DragThreshold
+ else
+ FDragThreshold := Threshold;
+ if Immediate then
+ DoDragging(FLastClickPos)
+ else
+ DoStateChange([tsOLEDragPending]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.BeginSynch;
+
+// Starts the synchronous update mode (if not already active).
+
+begin
+ if not (csDestroying in ComponentState) then
+ begin
+ if FSynchUpdateCount = 0 then
+ begin
+ DoUpdating(usBeginSynch);
+
+ // Stop all timers...
+ StopTimer(ChangeTimer);
+ StopTimer(StructureChangeTimer);
+ StopTimer(ExpandTimer);
+ StopTimer(EditTimer);
+ StopTimer(HeaderTimer);
+ StopTimer(ScrollTimer);
+ StopTimer(SearchTimer);
+ FSearchBuffer := '';
+ FLastSearchNode := nil;
+ DoStateChange([], [tsEditPending, tsScrollPending, tsScrolling, tsIncrementalSearching]);
+
+ // ...and trigger pending update states.
+ if tsStructureChangePending in FStates then
+ DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason);
+ if tsChangePending in FStates then
+ DoChange(FLastChangedNode);
+ end
+ else
+ DoUpdating(usSynch);
+ end;
+ Inc(FSynchUpdateCount);
+ DoStateChange([tsSynchMode]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.BeginUpdate;
+
+begin
+ if not (csDestroying in ComponentState) then
+ begin
+ if FUpdateCount = 0 then
+ begin
+ DoUpdating(usBegin);
+ SetUpdateState(True);
+ end
+ else
+ DoUpdating(usUpdate);
+ end;
+ Inc(FUpdateCount);
+ DoStateChange([tsUpdating]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CancelCutOrCopy;
+
+// Resets nodes which are marked as being cut.
+
+var
+ Run: PVirtualNode;
+
+begin
+ if ([tsCutPending, tsCopyPending] * FStates) <> [] then
+ begin
+ Run := FRoot.FirstChild;
+ while Assigned(Run) do
+ begin
+ if vsCutOrCopy in Run.States then
+ Exclude(Run.States, vsCutOrCopy);
+ Run := GetNextNoInit(Run);
+ end;
+ end;
+ DoStateChange([], [tsCutPending, tsCopyPending]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CancelEditNode: Boolean;
+
+// Called by the application or the current edit link to cancel the edit action.
+
+begin
+ if HandleAllocated and ([tsEditing, tsEditPending] * FStates <> []) then
+ Result := DoCancelEdit
+ else
+ Result := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CanFocus: Boolean;
+
+var
+ Form: TCustomForm;
+
+begin
+ {$ifdef COMPILER_5_UP}
+ Result := inherited CanFocus;
+ {$else}
+ Result := True;
+ {$endif}
+
+ if Result then
+ begin
+ Form := GetParentForm(Self);
+ Result := (Form = nil) or (Form.Enabled and Form.Visible);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Clear;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) or (csDestroying in ComponentState) then
+ begin
+ BeginUpdate;
+ try
+ InterruptValidation;
+ if IsEditing then
+ CancelEditNode;
+
+ if ClipboardStates * FStates <> [] then
+ begin
+ OleSetClipBoard(nil);
+ DoStateChange([], ClipboardStates);
+ end;
+ ClearSelection;
+ FFocusedNode := nil;
+ FLastSelected := nil;
+ FCurrentHotNode := nil;
+ DeleteChildren(FRoot, True);
+ FVisibleCount := 0;
+ FOffsetX := 0;
+ FOffsetY := 0;
+
+ {$ifdef UseLocalMemoryManager}
+ FNodeMemoryManager.Clear;
+ {$endif UseLocalMemoryManager}
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ClearSelection;
+
+var
+ Node: PVirtualNode;
+ Dummy: Integer;
+ R: TRect;
+ Counter: Integer;
+
+begin
+ if (FSelectionCount > 0) and not (csDestroying in ComponentState) then
+ begin
+ if (FUpdateCount = 0) and HandleAllocated and (FVisibleCount > 0) then
+ begin
+ // Iterate through nodes currently visible in the client area and invalidate them.
+ Node := GetNodeAt(0, 0, True, Dummy);
+ if Assigned(Node) then
+ R := GetDisplayRect(Node, NoColumn, False);
+ Counter := FSelectionCount;
+
+ while Assigned(Node) do
+ begin
+ R.Bottom := R.Top + Node.NodeHeight;
+ if vsSelected in Node.States then
+ begin
+ InvalidateRect(Handle, @R, False);
+ Dec(Counter);
+ // Only try as many nodes as are selected.
+ if Counter = 0 then
+ Break;
+ end;
+ R.Top := R.Bottom;
+ if R.Top > ClientHeight then
+ Break;
+ Node := GetNextVisibleNoInit(Node);
+ end;
+ end;
+
+ InternalClearSelection;
+ Change(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CopyTo(Source: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean): PVirtualNode;
+
+// A simplified CopyTo method to allow to copy nodes to the root of another tree.
+
+begin
+ Result := CopyTo(Source, Tree.FRoot, Mode, ChildrenOnly);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.CopyTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean): PVirtualNode;
+
+// Copies Source and all its child nodes to Target.
+// Mode is used to specify further where to add the new node actually (as sibling of Target or as child of Target).
+// Result is the newly created node to which source has been copied if ChildrenOnly is False or just contains Target
+// in the other case.
+// ChildrenOnly determines whether to copy also the source node or only its child nodes.
+
+var
+ TargetTree: TBaseVirtualTree;
+ Stream: TMemoryStream;
+
+begin
+ Assert(TreeFromNode(Source) = Self, 'The source tree must contain the source node.');
+
+ Result := nil;
+ if (Mode <> amNoWhere) and Assigned(Source) and (Source <> FRoot) then
+ begin
+ // Assume that an empty destination means the root in this (the source) tree.
+ if Target = nil then
+ begin
+ TargetTree := Self;
+ Target := FRoot;
+ Mode := amAddChildFirst;
+ end
+ else
+ TargetTree := TreeFromNode(Target);
+
+ if not (toReadOnly in TargetTree.FOptions.FMiscOptions) then
+ begin
+ if Target = TargetTree.FRoot then
+ begin
+ case Mode of
+ amInsertBefore:
+ Mode := amAddChildFirst;
+ amInsertAfter:
+ Mode := amAddChildLast;
+ end;
+ end;
+
+ Stream := TMemoryStream.Create;
+ try
+ // Write all nodes into a temprary stream depending on the ChildrenOnly flag.
+ if not ChildrenOnly then
+ WriteNode(Stream, Source)
+ else
+ begin
+ Source := Source.FirstChild;
+ while Assigned(Source) do
+ begin
+ WriteNode(Stream, Source);
+ Source := Source.NextSibling;
+ end;
+ end;
+ // Now load the serialized nodes into the target node (tree).
+ TargetTree.BeginUpdate;
+ try
+ Stream.Position := 0;
+ while Stream.Position < Stream.Size do
+ begin
+ Result := TargetTree.MakeNewNode;
+ InternalConnectNode(Result, Target, TargetTree, Mode);
+ TargetTree.InternalAddFromStream(Stream, VTTreeStreamVersion, Result);
+ if not DoNodeCopying(Result, Target) then
+ begin
+ TargetTree.DeleteNode(Result);
+ Result := nil;
+ end
+ else
+ DoNodeCopied(Result);
+ end;
+ if ChildrenOnly then
+ Result := Target;
+ finally
+ TargetTree.EndUpdate;
+ end;
+ finally
+ Stream.Free;
+ end;
+
+ with TargetTree do
+ begin
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ Invalidate;
+ end;
+ StructureChange(Source, crNodeCopied);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CopyToClipBoard;
+
+var
+ DataObject: IDataObject;
+
+begin
+ if FSelectionCount > 0 then
+ begin
+ DataObject := TVTDataObject.Create(Self, True) as IDataObject;
+ if OleSetClipBoard(DataObject) = S_OK then
+ begin
+ MarkCutCopyNodes;
+ DoStateChange([tsCopyPending]);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.CutToClipBoard;
+
+var
+ DataObject: IDataObject;
+
+begin
+ if (FSelectionCount > 0) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ DataObject := TVTDataObject.Create(Self, True) as IDataObject;
+ if OleSetClipBoard(DataObject) = S_OK then
+ begin
+ MarkCutCopyNodes;
+ DoStateChange([tsCutPending]);
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DeleteChildren(Node: PVirtualNode; ResetHasChildren: Boolean = False);
+
+// Removes all children and their children from memory without changing the vsHasChildren style by default.
+
+var
+ Run,
+ Mark: PVirtualNode;
+ LastTop,
+ LastLeft: Integer;
+ ParentVisible: Boolean;
+
+begin
+ if (Node.ChildCount > 0) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Assert(not (tsIterating in FStates), 'Deleting nodes during tree iteration leads to invalid pointers.');
+
+ // The code below uses some flags for speed improvements which may cause invalid pointers if updates of
+ // the tree happen. Hence switch updates off until we have finished the operation.
+ Inc(FUpdateCount);
+ try
+ InterruptValidation;
+ LastLeft := FOffsetX;
+ LastTop := FOffsetY;
+
+ // Make a local copy of the visibility state of this node to speed up
+ // adjusting the visible nodes count.
+ ParentVisible := Node = FRoot;
+ if not ParentVisible then
+ ParentVisible := FullyVisible[Node] and (vsExpanded in Node.States);
+
+ // Show that we are clearing the child list, to avoid registering structure change events.
+ Include(Node.States, vsClearing);
+ Run := Node.LastChild;
+ while Assigned(Run) do
+ begin
+ if ParentVisible and (vsVisible in Run.States) then
+ Dec(FVisibleCount);
+
+ Include(Run.States, vsDeleting);
+ Mark := Run;
+ Run := Run.PrevSibling;
+ // Important, to avoid exchange of invalid pointers while disconnecting the node.
+ if Assigned(Run) then
+ Run.NextSibling := nil;
+ DeleteNode(Mark);
+ end;
+ Exclude(Node.States, vsClearing);
+ if ResetHasChildren then
+ Exclude(Node.States, vsHasChildren);
+ if Node <> FRoot then
+ Exclude(Node.States, vsExpanded);
+ Node.ChildCount := 0;
+ if (Node = FRoot) or (vsDeleting in Node.States) then
+ begin
+ Node.TotalHeight := Node.NodeHeight;
+ Node.TotalCount := 1;
+ end
+ else
+ begin
+ AdjustTotalHeight(Node, Node.NodeHeight);
+ AdjustTotalCount(Node, 1);
+ end;
+ Node.FirstChild := nil;
+ Node.LastChild := nil;
+ finally
+ Dec(FUpdateCount);
+ end;
+
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ UpdateScrollbars(True);
+ // Invalidate entire tree if it scrolled e.g. to make the last node also the
+ // bottom node in the treeview.
+ if (LastLeft <> FOffsetX) or (LastTop <> FOffsetY) then
+ Invalidate
+ else
+ InvalidateToBottom(Node);
+ end;
+ StructureChange(Node, crChildDeleted);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DeleteNode(Node: PVirtualNode; Reindex: Boolean = True);
+
+var
+ LastTop,
+ LastLeft: Integer;
+ LastParent: PVirtualNode;
+ WasInSynchMode: Boolean;
+ ParentClearing: Boolean;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Assert(not (tsIterating in FStates), 'Deleting nodes during tree iteration leads to invalid pointers.');
+
+ // Determine parent node for structure change notification.
+ ParentClearing := vsClearing in Node.Parent.States;
+ LastParent := Node.Parent;
+
+ if not ParentClearing then
+ begin
+ if LastParent = FRoot then
+ StructureChange(nil, crChildDeleted)
+ else
+ StructureChange(LastParent, crChildDeleted);
+ end;
+
+ LastLeft := FOffsetX;
+ LastTop := FOffsetY;
+
+ if vsSelected in Node.States then
+ begin
+ if FUpdateCount = 0 then
+ begin
+ // Go temporarily into sync mode to avoid a delayed change event for the node
+ // when unselecting.
+ WasInSynchMode := tsSynchMode in FStates;
+ Include(FStates, tsSynchMode);
+ RemoveFromSelection(Node);
+ if not WasInSynchMode then
+ Exclude(FStates, tsSynchMode);
+ InvalidateToBottom(LastParent);
+ end
+ else
+ InternalRemoveFromSelection(Node);
+ end
+ else
+ InvalidateToBottom(LastParent);
+
+ if tsHint in FStates then
+ begin
+ Application.CancelHint;
+ DoStateChange([], [tsHint]);
+ end;
+
+ DeleteChildren(Node);
+ InternalDisconnectNode(Node, False, Reindex);
+ DoFreeNode(Node);
+
+ if not ParentClearing then
+ begin
+ DetermineHiddenChildrenFlag(LastParent);
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ UpdateScrollbars(True);
+ // Invalidate entire tree if it scrolled e.g. to make the last node also the
+ // bottom node in the treeview.
+ if (LastLeft <> FOffsetX) or (LastTop <> FOffsetY) then
+ Invalidate;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.DeleteSelectedNodes;
+
+// Deletes all currently selected nodes (including their child nodes).
+
+var
+ Nodes: TNodeArray;
+ I: Integer;
+ LevelChange: Boolean;
+
+begin
+ Nodes := nil;
+ if (FSelectionCount > 0) and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ BeginUpdate;
+ try
+ Nodes := GetSortedSelection(True);
+ for I := High(Nodes) downto 1 do
+ begin
+ LevelChange := Nodes[I].Parent <> Nodes[I - 1].Parent;
+ DeleteNode(Nodes[I], LevelChange);
+ end;
+ DeleteNode(Nodes[0]);
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.Dragging: Boolean;
+
+begin
+ // Check for both OLE drag'n drop as well as VCL drag'n drop.
+ Result := ([tsOLEDragPending, tsOLEDragging] * FStates <> []) or inherited Dragging;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.EditNode(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// Application triggered edit event for the given node.
+// Returns True if the tree started editing otherwise False.
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+ Assert((Column > InvalidColumn) and (Column < FHeader.Columns.Count),
+ 'Column must be a valid column index (-1 if no header is shown).');
+
+ Result := tsEditing in FStates;
+ // If the tree is already editing then we don't disrupt this.
+ if not Result and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ FocusedNode := Node;
+ if Assigned(FFocusedNode) and (Node = FFocusedNode) and CanEdit(FFocusedNode, Column) then
+ begin
+ FEditColumn := Column;
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ DoEdit;
+ Result := tsEditing in FStates;
+ end
+ else
+ Result := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.EndEditNode: Boolean;
+
+// Called by the application or the current edit link to finish the edit action.
+
+begin
+ if [tsEditing, tsEditPending] * FStates <> [] then
+ Result := DoEndEdit
+ else
+ Result := True;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.EndSynch;
+
+begin
+ if FSynchUpdateCount > 0 then
+ Dec(FSynchUpdateCount);
+
+ if not (csDestroying in ComponentState) then
+ begin
+ if FSynchUpdateCount = 0 then
+ begin
+ DoStateChange([], [tsSynchMode]);
+ DoUpdating(usEndSynch);
+ end
+ else
+ DoUpdating(usSynch);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.EndUpdate;
+
+var
+ NewSize: Integer;
+
+begin
+ if FUpdateCount > 0 then
+ Dec(FUpdateCount);
+
+ if not (csDestroying in ComponentState) then
+ begin
+ if (FUpdateCount = 0) and (tsUpdating in FStates) then
+ begin
+ if tsUpdateHiddenChildrenNeeded in FStates then
+ begin
+ DetermineHiddenChildrenFlagAllNodes;
+ Exclude(FStates, tsUpdateHiddenChildrenNeeded);
+ end;
+
+ DoStateChange([], [tsUpdating]);
+
+ NewSize := PackArray(FSelection, FSelectionCount);
+ if NewSize > -1 then
+ begin
+ FSelectionCount := NewSize;
+ SetLength(FSelection, FSelectionCount);
+ end;
+ ValidateCache;
+ if HandleAllocated then
+ UpdateScrollBars(True);
+
+ if tsStructureChangePending in FStates then
+ DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason);
+ if tsChangePending in FStates then
+ DoChange(FLastChangedNode);
+
+ if toAutoSort in FOptions.FAutoOptions then
+ SortTree(FHeader.FSortColumn, FHeader.FSortDirection, True);
+
+ SetUpdateState(False);
+ if HandleAllocated then
+ Invalidate;
+ end;
+
+ if FUpdateCount = 0 then
+ DoUpdating(usEnd)
+ else
+ DoUpdating(usUpdate);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ExecuteAction(Action: TBasicAction): Boolean;
+
+// Some support for standard actions.
+
+begin
+ Result := inherited ExecuteAction(Action);
+
+ if not Result and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Result := Action is TEditCut;
+ if Result then
+ CutToClipboard
+ else
+ begin
+ Result := Action is TEditCopy;
+ if Result then
+ CopyToClipboard
+ else
+ begin
+ Result := Action is TEditPaste;
+ if Result then
+ PasteFromClipboard
+ {$ifdef COMPILER_5_UP}
+ else
+ begin
+ Result := Action is TEditDelete;
+ if Result then
+ DeleteSelectedNodes
+ else
+ begin
+ Result := Action is TEditSelectAll;
+ if Result then
+ SelectAll(False);
+ end;
+ end;
+ {$endif COMPILER_5_UP}
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FinishCutOrCopy;
+
+// Deletes nodes which are marked as being cutted.
+
+var
+ Run: PVirtualNode;
+
+begin
+ if tsCutPending in FStates then
+ begin
+ Run := FRoot.FirstChild;
+ while Assigned(Run) do
+ begin
+ if vsCutOrCopy in Run.States then
+ DeleteNode(Run);
+ Run := GetNextNoInit(Run);
+ end;
+ DoStateChange([], [tsCutPending]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FlushClipboard;
+
+// Used to render the data which is currently on the clipboard (finishes delayed rendering).
+
+begin
+ if ClipboardStates * FStates <> [] then
+ begin
+ DoStateChange([tsClipboardFlushing]);
+ OleFlushClipboard;
+ CancelCutOrCopy;
+ DoStateChange([], [tsClipboardFlushing]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FullCollapse(Node: PVirtualNode = nil);
+
+// This routine collapses all expanded nodes in the subtree given by Node or the whole tree if Node is FRoot or nil.
+// Only nodes which are expanded will be collapsed. This excludes uninitialized nodes but nodes marked as visible
+// will still be collapsed if they are expanded.
+
+var
+ Stop: PVirtualNode;
+
+begin
+ if FRoot.TotalCount > 1 then
+ begin
+ if Node = FRoot then
+ Node := nil;
+
+ DoStateChange([tsCollapsing]);
+ BeginUpdate;
+ try
+ Stop := Node;
+ Node := GetLastVisibleNoInit(Node);
+
+ if Assigned(Node) then
+ begin
+ repeat
+ if [vsHasChildren, vsExpanded] * Node.States = [vsHasChildren, vsExpanded] then
+ ToggleNode(Node);
+ Node := GetPreviousNoInit(Node);
+ until Node = Stop;
+
+ // Collapse the start node too.
+ if Assigned(Node) and ([vsHasChildren, vsExpanded] * Node.States = [vsHasChildren, vsExpanded]) then
+ ToggleNode(Node);
+ end;
+ finally
+ EndUpdate;
+ DoStateChange([], [tsCollapsing]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.FullExpand(Node: PVirtualNode = nil);
+
+// This routine expands all collapsed nodes in the subtree given by Node or the whole tree if Node is FRoot or nil.
+// All nodes on the way down are initialized so this procedure might take a long time.
+// Since all nodes are validated, the tree cannot make use of optimatizations. Hence it is counter productive and you
+// should consider avoiding its use.
+
+var
+ Stop: PVirtualNode;
+
+begin
+ if FRoot.TotalCount > 1 then
+ begin
+ DoStateChange([tsExpanding]);
+ BeginUpdate;
+ try
+ if Node = nil then
+ begin
+ Node := FRoot.FirstChild;
+ Stop := nil;
+ end
+ else
+ begin
+ Stop := Node.NextSibling;
+ if Stop = nil then
+ begin
+ Stop := Node;
+ repeat
+ Stop := Stop.Parent;
+ until (Stop = FRoot) or Assigned(Stop.NextSibling);
+ if Stop = FRoot then
+ Stop := nil
+ else
+ Stop := Stop.NextSibling;
+ end;
+ end;
+
+ // Initialize the start node. Others will be initialized in GetNext.
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ repeat
+ if not (vsExpanded in Node.States) then
+ ToggleNode(Node);
+ Node := GetNext(Node);
+ until Node = Stop;
+ finally
+ EndUpdate;
+ DoStateChange([], [tsExpanding]);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetControlsAlignment: TAlignment;
+
+begin
+ Result := FAlignment;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetDisplayRect(Node: PVirtualNode; Column: TColumnIndex; TextOnly: Boolean;
+ Unclipped: Boolean = False): TRect;
+
+// Determines the client coordinates the given node covers, depending on scrolling, expand state etc.
+// If the given node cannot be found (because one of its parents is collapsed or it is invisible) then an empty
+// rectangle is returned.
+// If TextOnly is True then only the text bounds are returned, that is, the resulting rectangle's left and right border
+// are updated according to bidi mode, alignment and text width of the node.
+// If Unclipped is True (which only makes sense if also TextOnly is True) then the calculated text rectangle is
+// not clipped if the text does not entirely fit into the text space. This is special handling needed for hints.
+// If Column is -1 then the entire client width is used before determining the node's width otherwise the bounds of the
+// particular column are used.
+// Note: Column must be a valid column and is used independent of whether the header is visible or not.
+
+var
+ Temp: PVirtualNode;
+ Offset: Cardinal;
+ Indent,
+ TextWidth: Integer;
+ MainColumnHit,
+ Ghosted: Boolean;
+ CurrentBidiMode: TBidiMode;
+ CurrentAlignment: TAlignment;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+ Assert(Node <> FRoot, 'Node must not be the hidden root node.');
+
+ MainColumnHit := (Column + 1) in [0, FHeader.MainColumn + 1];
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ Result := Rect(0, 0, 0, 0);
+
+ // Check whether the node is visible (determine indentation level btw.).
+ Temp := Node;
+ Indent := 0;
+ while Temp <> FRoot do
+ begin
+ if not (vsVisible in Temp.States) or not (vsExpanded in Temp.Parent.States) then
+ Exit;
+ Temp := Temp.Parent;
+ if MainColumnHit and (Temp <> FRoot) then
+ Inc(Indent, FIndent);
+ end;
+
+ // Here we know the node is visible.
+ Offset := 0;
+ if tsUseCache in FStates then
+ begin
+ // If we can use the position cache then do a binary search to find a cached node which is as close as possible
+ // to the current node. Iterate then through all following and visible nodes and sum up their heights.
+ Temp := FindInPositionCache(Node, Offset);
+ while Assigned(Temp) and (Temp <> Node) do
+ begin
+ Inc(Offset, Temp.NodeHeight);
+ Temp := GetNextVisibleNoInit(Temp);
+ end;
+ end
+ else
+ begin
+ // If the cache is not available then go straight through all nodes up to the root and sum up their heights.
+ Temp := Node;
+ repeat
+ Temp := GetPreviousVisibleNoInit(Temp);
+ if Temp = nil then
+ Break;
+ Inc(Offset, Temp.NodeHeight);
+ until False;
+ end;
+
+ Result := Rect(0, Offset, Max(FRangeX, ClientWidth), Offset + Node.NodeHeight);
+
+ // Limit left and right bounds to the given column (if any) and move bounds according to current scroll state.
+ if Column > NoColumn then
+ begin
+ FHeader.FColumns.GetColumnBounds(Column, Result.Left, Result.Right);
+ // The right column border is not part of this cell.
+ Dec(Result.Right);
+ OffsetRect(Result, 0, FOffsetY);
+ end
+ else
+ OffsetRect(Result, FOffsetX, FOffsetY);
+
+ // Limit left and right bounds further if only the text area is required.
+ if TextOnly then
+ begin
+ // Start with the offset of the text in the column and consider the indentation level too.
+ Offset := FMargin + Indent;
+ // If the text of a node is involved then we have to consider directionality and alignment too.
+ if Column = NoColumn then
+ begin
+ CurrentBidiMode := BidiMode;
+ CurrentAlignment := Alignment;
+ end
+ else
+ begin
+ CurrentBidiMode := FHeader.FColumns[Column].BidiMode;
+ CurrentAlignment := FHeader.FColumns[Column].Alignment;
+ end;
+
+ TextWidth := DoGetNodeWidth(Node, Column);
+
+ if MainColumnHit then
+ begin
+ if toShowRoot in FOptions.FPaintOptions then
+ Inc(Offset, FIndent);
+ if (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages) and (Node.CheckType <> ctNone) then
+ Inc(Offset, FCheckImages.Width + 2);
+ end;
+ // Consider associated images.
+ if Assigned(FStateImages) and (GetImageIndex(Node, ikState, Column, Ghosted) > -1) then
+ Inc(Offset, FStateImages.Width + 2);
+ if Assigned(FImages) and (GetImageIndex(Node, ikNormal, Column, Ghosted) > -1) then
+ Inc(Offset, FImages.Width + 2);
+
+ // Offset contains now the distance from the left or right border of the rectangle (depending on bidi mode).
+ // Now consider the alignment too and calculate the final result.
+ if CurrentBidiMode = bdLeftToRight then
+ begin
+ Inc(Result.Left, Offset);
+ // Left-to-right reading does not need any special adjustment of the alignment.
+ end
+ else
+ begin
+ Dec(Result.Right, Offset);
+
+ // Consider bidi mode here. In RTL context does left alignment actually mean right alignment and vice versa.
+ ChangeBiDiModeAlignment(CurrentAlignment);
+ end;
+
+ if Unclipped then
+ begin
+ // The caller requested the text coordinates unclipped. This means they must be calculated so as would
+ // there be enough space, regardless of column bounds etc.
+ // The layout still depends on the available space too, because this determines the position
+ // of the unclipped text rectangle.
+ if Result.Right - Result.Left < TextWidth then
+ if CurrentBidiMode = bdLeftToRight then
+ CurrentAlignment := taLeftJustify
+ else
+ CurrentAlignment := taRightJustify;
+
+ case CurrentAlignment of
+ taCenter:
+ begin
+ Result.Left := (Result.Left + Result.Right - TextWidth) div 2;
+ Result.Right := Result.Left + TextWidth;
+ end;
+ taRightJustify:
+ Result.Left := Result.Right - TextWidth;
+ else // taLeftJustify
+ Result.Right := Result.Left + TextWidth;
+ end;
+ end
+ else
+ // Modify rectangle only if the text fits entirely into the given room.
+ if Result.Right - Result.Left > TextWidth then
+ case CurrentAlignment of
+ taCenter:
+ begin
+ Result.Left := (Result.Left + Result.Right - TextWidth) div 2;
+ Result.Right := Result.Left + TextWidth;
+ end;
+ taRightJustify:
+ Result.Left := Result.Right - TextWidth;
+ else // taLeftJustify
+ Result.Right := Result.Left + TextWidth;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirst: PVirtualNode;
+
+// Returns the first node in the tree.
+
+begin
+ Result := FRoot.FirstChild;
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstChild(Node: PVirtualNode): PVirtualNode;
+
+// Returns the first child of the given node. The result node is initialized before exit.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.FirstChild
+ else
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if vsHasChildren in Node.States then
+ begin
+ if Node.ChildCount = 0 then
+ InitChildren(Node);
+ Result := Node.FirstChild;
+ end
+ else
+ Result := nil;
+ end;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstCutCopy: PVirtualNode;
+
+// Returns the first node in the tree which is currently marked for a clipboard operation.
+// See also GetNextCutCopy for comments on initialization.
+
+begin
+ Result := GetNextCutCopy(nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstInitialized: PVirtualNode;
+
+// Returns the first node which is already initialized.
+
+begin
+ Result := FRoot.FirstChild;
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ Result := GetNextInitialized(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstNoInit: PVirtualNode;
+
+begin
+ Result := FRoot.FirstChild;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstSelected: PVirtualNode;
+
+// Returns the first node in the current selection.
+
+begin
+ Result := GetNextSelected(nil);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstVisible: PVirtualNode;
+
+// Returns the first visible node in the tree. If necessary nodes are initialized on demand.
+
+begin
+ if vsHasChildren in FRoot.States then
+ begin
+ Result := FRoot;
+
+ if Result.ChildCount = 0 then
+ InitChildren(Result);
+
+ // Child nodes are the first choice if possible.
+ if Assigned(Result.FirstChild) then
+ begin
+ Result := GetFirstChild(Result);
+
+ // If there are no children or the first child is not visible then search the sibling nodes or traverse parents.
+ if not (vsVisible in Result.States) then
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ // The visible state can be removed during initialization so init the node first.
+ if not (vsInitialized in Result.States) then
+ InitNode(Result);
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end
+ else
+ Result := nil;
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstVisibleChild(Node: PVirtualNode): PVirtualNode;
+
+// Returns the first visible child node of Node. If necessary nodes are initialized on demand.
+
+begin
+ Result := GetFirstChild(Node);
+ if Assigned(Result) and not (vsVisible in Result.States) then
+ Result := GetNextVisibleSibling(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstVisibleChildNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the first visible child node of Node.
+
+begin
+ if Node = nil then
+ Node := FRoot;
+ Result := Node.FirstChild;
+ if Assigned(Result) and not (vsVisible in Result.States) then
+ Result := GetNextVisibleSiblingNoInit(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetFirstVisibleNoInit: PVirtualNode;
+
+// Returns the first visible node in the tree. No initialization is performed.
+
+begin
+ if vsHasChildren in FRoot.States then
+ begin
+ Result := FRoot;
+
+ // Child nodes are the first choice if possible.
+ if Assigned(Result.FirstChild) then
+ begin
+ Result := Result.FirstChild;
+
+ // If there are no children or the first child is not visible then search the sibling nodes or traverse parents.
+ if not (vsVisible in Result.States) then
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end
+ else
+ Result := nil;
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.GetHitTestInfoAt(X, Y: Integer; Relative: Boolean; var HitInfo: THitInfo);
+
+// Determines the node that occupies the specified point or nil if there's none. The parameter Relative determines
+// whether to consider X and Y as being client coordinates (if True) or as being absolute tree coordinates.
+// HitInfo is filled with flags describing the hit further.
+
+var
+ ColLeft,
+ ColRight: Integer;
+ NodeTop: Integer;
+ InitialColumn,
+ NextColumn: TColumnIndex;
+ CurrentBidiMode: TBidiMode;
+ CurrentAlignment: TAlignment;
+
+begin
+ HitInfo.HitNode := nil;
+ HitInfo.HitPositions := [];
+ HitInfo.HitColumn := NoColumn;
+
+ // Determine if point lies in the tree's client area.
+ if X < 0 then
+ Include(HitInfo.HitPositions, hiToLeft)
+ else
+ if X > Max(FRangeX, ClientWidth) then
+ Include(HitInfo.HitPositions, hiToRight);
+
+ if Y < 0 then
+ Include(HitInfo.HitPositions, hiAbove)
+ else
+ if Y > Max(FRangeY, ClientHeight) then
+ Include(HitInfo.HitPositions, hiBelow);
+
+ // Convert position into absolute coordinate if necessary.
+ if Relative then
+ begin
+ Inc(X, -FOffsetX);
+ Inc(Y, -FOffsetY);
+ end;
+
+ // If the point is in the tree area then check the nodes.
+ if HitInfo.HitPositions = [] then
+ begin
+ HitInfo.HitNode := GetNodeAt(X, Y, False, NodeTop);
+ if HitInfo.HitNode = nil then
+ Include(HitInfo.HitPositions, hiNowhere)
+ else
+ begin
+ // At this point we need some info about the node, so it must be initialized.
+ if not (vsInitialized in HitInfo.HitNode.States) then
+ InitNode(HitInfo.HitNode);
+
+ if FHeader.UseColumns then
+ begin
+ HitInfo.HitColumn := FHeader.Columns.GetColumnAndBounds(Point(X, Y), ColLeft, ColRight, False);
+ // If auto column spanning is enabled then look for the last non empty column.
+ if toAutoSpanColumns in FOptions.FAutoOptions then
+ begin
+ InitialColumn := HitInfo.HitColumn;
+ // Search to the left of the hit column for empty columns.
+ while (HitInfo.HitColumn > NoColumn) and ColumnIsEmpty(HitInfo.HitNode, HitInfo.HitColumn) do
+ begin
+ NextColumn := FHeader.FColumns.GetPreviousVisibleColumn(HitInfo.HitColumn);
+ if NextColumn = InvalidColumn then
+ Break;
+ HitInfo.HitColumn := NextColumn;
+ Dec(ColLeft, FHeader.FColumns[NextColumn].Width);
+ end;
+ // Search to the right of the hit column for empty columns.
+ repeat
+ InitialColumn := FHeader.FColumns.GetNextVisibleColumn(InitialColumn);
+ if (InitialColumn = InvalidColumn) or not ColumnIsEmpty(HitInfo.HitNode, InitialColumn) then
+ Break;
+ Inc(ColRight, FHeader.FColumns[InitialColumn].Width);
+ until False;
+ end;
+ // Make the X position and the right border relative to the start of the column.
+ Dec(X, ColLeft);
+ Dec(ColRight, ColLeft);
+ end
+ else
+ begin
+ HitInfo.HitColumn := NoColumn;
+ ColRight := Max(FRangeX, ClientWidth);
+ end;
+ ColLeft := 0;
+
+ if HitInfo.HitColumn = InvalidColumn then
+ Include(HitInfo.HitPositions, hiNowhere)
+ else
+ begin
+ // From now on X is in "column" coordinates (relative to the left column border).
+ HitInfo.HitPositions := [hiOnItem];
+ if HitInfo.HitColumn = NoColumn then
+ begin
+ CurrentBidiMode := BidiMode;
+ CurrentAlignment := Alignment;
+ end
+ else
+ begin
+ CurrentBidiMode := FHeader.FColumns[HitInfo.HitColumn].BidiMode;
+ CurrentAlignment := FHeader.FColumns[HitInfo.HitColumn].Alignment;
+ end;
+
+ if CurrentBidiMode = bdLeftToRight then
+ DetermineHitPositionLTR(HitInfo, X, ColRight, CurrentAlignment)
+ else
+ DetermineHitPositionRTL(HitInfo, X, ColRight, CurrentAlignment);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLast(Node: PVirtualNode = nil): PVirtualNode;
+
+// Returns the very last node in the tree branch given by Node and initializes the nodes all the way down including the
+// result. By using Node = nil the very last node in the tree is returned.
+
+var
+ Next: PVirtualNode;
+
+begin
+ Result := GetLastChild(Node);
+ while Assigned(Result) do
+ begin
+ // Test if there is a next last child. If not keep the node from the last run.
+ // Otherwise use the next last child.
+ Next := GetLastChild(Result);
+ if Next = nil then
+ Break;
+ Result := Next;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastInitialized(Node: PVirtualNode): PVirtualNode;
+
+// Returns the very last initialized child node in the tree branch given by Node.
+
+begin
+ Result := GetLastNoInit(Node);
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ Result := GetPreviousInitialized(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastNoInit(Node: PVirtualNode = nil): PVirtualNode;
+
+// Returns the very last node in the tree branch given by Node without initialization.
+
+var
+ Next: PVirtualNode;
+
+begin
+ Result := GetLastChildNoInit(Node);
+ while Assigned(Result) do
+ begin
+ // Test if there is a next last child. If not keep the node from the last run.
+ // Otherwise use the next last child.
+ Next := GetLastChildNoInit(Result);
+ if Next = nil then
+ Break;
+ Result := Next;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastChild(Node: PVirtualNode): PVirtualNode;
+
+// Determines the last child of the given node and initializes it if there is one.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.LastChild
+ else
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if vsHasChildren in Node.States then
+ begin
+ if Node.ChildCount = 0 then
+ InitChildren(Node);
+ Result := Node.LastChild;
+ end
+ else
+ Result := nil;
+ end;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastChildNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Determines the last child of the given node but does not initialize it.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.LastChild
+ else
+ begin
+ if vsHasChildren in Node.States then
+ Result := Node.LastChild
+ else
+ Result := nil;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastVisible(Node: PVirtualNode = nil): PVirtualNode;
+
+// Returns the very last visible node in the tree and initializes nodes all the way down including the result node.
+
+var
+ Next: PVirtualNode;
+
+begin
+ Result := GetLastVisibleChild(Node);
+ while Assigned(Result) do
+ begin
+ // Test if there is a next last visible child. If not keep the node from the last run.
+ // Otherwise use the next last visible child.
+ Next := GetLastVisibleChild(Result);
+ if Next = nil then
+ Break;
+ Result := Next;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastVisibleChild(Node: PVirtualNode): PVirtualNode;
+
+// Determines the last visible child of the given node and initializes it if necessary.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := GetLastChild(FRoot)
+ else
+ if FullyVisible[Node] and (vsExpanded in Node.States) then
+ Result := GetLastChild(Node)
+ else
+ Result := nil;
+
+ if Assigned(Result) and not (vsVisible in Result.States) then
+ Result := GetPreviousVisibleSibling(Result);
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastVisibleChildNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Determines the last visible child of the given node without initialization.
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := GetLastChildNoInit(FRoot)
+ else
+ if FullyVisible[Node] and (vsExpanded in Node.States) then
+ Result := GetLastChildNoInit(Node)
+ else
+ Result := nil;
+
+ if Assigned(Result) and not (vsVisible in Result.States) then
+ Result := GetPreviousVisibleSiblingNoInit(Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetLastVisibleNoInit(Node: PVirtualNode = nil): PVirtualNode;
+
+// Returns the very last visible node in the tree without initialization.
+
+var
+ Next: PVirtualNode;
+
+begin
+ Result := GetLastVisibleChildNoInit(Node);
+ while Assigned(Result) do
+ begin
+ // Test if there is a next last visible child. If not keep the node from the last run.
+ // Otherwise use the next last visible child.
+ Next := GetLastVisibleChildNoInit(Result);
+ if Next = nil then
+ Break;
+ Result := Next;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetMaxColumnWidth(Column: TColumnIndex): Integer;
+
+// This method determines the width of the largest node in the given column.
+// Note: Every visible node in the tree will be initialized contradicting so the virtual paradigm.
+
+var
+ Run,
+ NextNode: PVirtualNode;
+ NodeLeft,
+ TextLeft,
+ CurrentWidth: Integer;
+ WithCheck,
+ WithImages,
+ WithStateImages,
+ Ghosted: Boolean;
+ CheckOffset,
+ ImageOffset,
+ StateImageOffset: Integer;
+
+begin
+ Result := 0;
+
+ // Don't check the event here as descendant trees might have overriden the DoGetImageIndex method.
+ WithImages := Assigned(FImages);
+ if WithImages then
+ ImageOffset := FImages.Width + 2
+ else
+ ImageOffset := 0;
+ WithStateImages := Assigned(FStateImages);
+ if WithStateImages then
+ StateImageOffset := FStateImages.Width + 2
+ else
+ StateImageOffset := 0;
+ if Assigned(FCheckImages) then
+ CheckOffset := FCheckImages.Width + 2
+ else
+ CheckOffset := 0;
+
+ Run := GetFirstVisible;
+ if Column = FHeader.MainColumn then
+ begin
+ if toShowRoot in FOptions.FPaintOptions then
+ NodeLeft := Integer((GetNodeLevel(Run) + 1) * FIndent)
+ else
+ NodeLeft := Integer(GetNodeLevel(Run) * FIndent);
+
+ WithCheck := (toCheckSupport in FOptions.FMiscOptions) and Assigned(FCheckImages);
+ end
+ else
+ begin
+ NodeLeft := 0;
+ WithCheck := False;
+ end;
+
+ // Leave a margin at both sides of the nodes.
+ Inc(NodeLeft, 2 * FMargin);
+
+ while Assigned(Run) do
+ begin
+ TextLeft := NodeLeft;
+ if WithCheck and (Run.CheckType <> ctNone) then
+ Inc(TextLeft, CheckOffset);
+ if WithImages and (GetImageIndex(Run, ikNormal, Column, Ghosted) > -1) then
+ Inc(TextLeft, ImageOffset);
+ if WithStateImages and (GetImageIndex(Run, ikState, Column, Ghosted) > -1) then
+ Inc(TextLeft, StateImageOffset);
+
+ CurrentWidth := DoGetNodeWidth(Run, Column);
+
+ if Result < (TextLeft + CurrentWidth) then
+ Result := TextLeft + CurrentWidth;
+
+ // Get next visible node and update left node position if needed.
+ NextNode := GetNextVisible(Run);
+ if NextNode = nil then
+ Break;
+ if Column = Header.MainColumn then
+ Inc(NodeLeft, CountLevelDifference(Run, NextNode) * Integer(FIndent));
+ Run := NextNode;
+ end;
+ if toShowVertGridLines in FOptions.FPaintOptions then
+ Inc(Result)
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNext(Node: PVirtualNode): PVirtualNode;
+
+// Returns next node in tree (advances to next sibling of the node's parent or its parent, if necessary).
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // Has this node got children?
+ if vsHasChildren in Result.States then
+ begin
+ // Yes, there are child nodes. Initialize them if necessary.
+ if Result.ChildCount = 0 then
+ InitChildren(Result);
+ end;
+
+ // if there is no child node try siblings
+ if Assigned(Result.FirstChild) then
+ Result := Result.FirstChild
+ else
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextCutCopy(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next node in the tree which is currently marked for a clipboard operation. Since only visible nodes can
+// be marked (or they are hidden after they have been marked) it is not necessary to initialize nodes to check for
+// child nodes. The result, however, is initialized if necessary.
+
+begin
+ if ClipboardStates * FStates <> [] then
+ begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.FirstChild
+ else
+ Result := GetNextNoInit(Node);
+ while Assigned(Result) and not (vsCutOrCopy in Result.States) do
+ Result := GetNextNoInit(Result);
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextInitialized(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next node in tree which is initialized.
+
+begin
+ Result := Node;
+ repeat
+ Result := GetNextNoInit(Result);
+ until (Result = nil) or (vsInitialized in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextNoInit(Node: PVirtualNode): PVirtualNode;
+
+// optimized variant of GetNext, no initialization of nodes is performed (if a node is not initialized
+// then it is considered as not being there)
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // if there is no child node try siblings
+ if Assigned(Result.FirstChild) then
+ Result := Result.FirstChild
+ else
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextSelected(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next node in the tree which is currently selected. Since children of unitialized nodes cannot be
+// in the current selection (because they simply do not exist yet) it is not necessary to initialize nodes here.
+// The result however is initialized if necessary.
+
+begin
+ if FSelectionCount > 0 then
+ begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := FRoot.FirstChild
+ else
+ Result := GetNextNoInit(Node);
+ while Assigned(Result) and not (vsSelected in Result.States) do
+ Result := GetNextNoInit(Result);
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextSibling(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next sibling of Node and initializes it if necessary.
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ Result := Node.NextSibling;
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextVisible(Node: PVirtualNode): PVirtualNode;
+
+// Returns next node in tree, with regard to Node, which is visible.
+// Nodes which need an initialization (including the result) are initialized.
+
+var
+ ForceSearch: Boolean;
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // If the given node is not visible then look for a parent node which is visible, otherwise we will
+ // likely go unnecessarily through a whole bunch of invisible nodes.
+ if not FullyVisible[Result] then
+ Result := GetVisibleParent(Result);
+
+ // Has this node got children?
+ if [vsHasChildren, vsExpanded] * Result.States = [vsHasChildren, vsExpanded] then
+ begin
+ // Yes, there are child nodes. Initialize them if necessary.
+ if Result.ChildCount = 0 then
+ InitChildren(Result);
+ end;
+
+ // Child nodes are the first choice if possible.
+ if (vsExpanded in Result.States) and Assigned(Result.FirstChild) then
+ begin
+ Result := GetFirstChild(Result);
+ ForceSearch := False;
+ end
+ else
+ ForceSearch := True;
+
+ // If there are no children or the first child is not visible then search the sibling nodes or traverse parents.
+ if Assigned(Result) and (ForceSearch or not (vsVisible in Result.States)) then
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ if not (vsInitialized in Result.States) then
+ InitNode(Result);
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextVisibleNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next node in tree, with regard to Node, which is visible.
+// No initialization is done.
+
+var
+ ForceSearch: Boolean;
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // If the given node is not visible then look for a parent node which is visible, otherwise we will
+ // likely go unnecessarily through a whole bunch of invisible nodes.
+ if not FullyVisible[Result] then
+ Result := GetVisibleParent(Result);
+
+ // Child nodes are the first choice if possible.
+ if (vsExpanded in Result.States) and Assigned(Result.FirstChild) then
+ begin
+ Result := Result.FirstChild;
+ ForceSearch := False;
+ end
+ else
+ ForceSearch := True;
+
+ // If there are no children or the first child is not visible then search the sibling nodes or traverse parents.
+ if ForceSearch or not (vsVisible in Result.States) then
+ begin
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextVisibleSibling(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next visible sibling after Node. Initialization is done implicitly.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ Result := Node;
+ repeat
+ Result := GetNextSibling(Result);
+ until (Result = nil) or (vsVisible in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNextVisibleSiblingNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the next visible sibling after Node.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ Result := Node;
+ repeat
+ Result := Result.NextSibling;
+ until (Result = nil) or (vsVisible in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeAt(X, Y: Integer): PVirtualNode;
+
+// Overloaded variant of GetNodeAt to easy life of application developers which do not need to have the exact
+// top position returned and always use client coordinates.
+
+var
+ Dummy: Integer;
+
+begin
+ Result := GetNodeAt(X, Y, True, Dummy);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeAt(X, Y: Integer; Relative: Boolean; var NodeTop: Integer): PVirtualNode;
+
+// This method returns the node that occupies the specified point, or nil if there's none.
+// If Releative is True then X and Y are given in client coordinates otherwise they are considered as being
+// absolute values into the virtual tree image (regardless of the current offsets in the tree window).
+// NodeTop gets the absolute or relative top position of the node returned or is untouched if no node
+// could be found.
+
+var
+ AbsolutePos,
+ CurrentPos: Cardinal;
+
+begin
+ if Y < 0 then
+ Y := 0;
+
+ AbsolutePos := Y;
+ if Relative then
+ Inc(AbsolutePos, -FOffsetY);
+
+ // CurrentPos tracks a running term of the current position to test for.
+ // It corresponds always to the top position of the currently considered node.
+ CurrentPos := 0;
+
+ // If the cache is available then use it.
+ if tsUseCache in FStates then
+ Result := FindInPositionCache(AbsolutePos, CurrentPos)
+ else
+ Result := GetFirstVisibleNoInit;
+
+ // Determine node, of which position and height corresponds to the scroll position most closely.
+ while Assigned(Result) and (Result <> FRoot) do
+ begin
+ if (vsVisible in Result.States) and (AbsolutePos < (CurrentPos + Result.TotalHeight)) then
+ begin
+ // Found a node which covers the given position. Now go down one level
+ // and search its children (if any, otherwise stop looking).
+ if (AbsolutePos >= CurrentPos + Result.NodeHeight) and Assigned(Result.FirstChild) and
+ (vsExpanded in Result.States) then
+ begin
+ Inc(CurrentPos, Result.NodeHeight);
+ Result := Result.FirstChild;
+ Continue;
+ end
+ else
+ Break;
+ end
+ else
+ begin
+ // Advance current position to after the current node, if the node is visible.
+ if vsVisible in Result.States then
+ Inc(CurrentPos, Result.TotalHeight);
+ // Find following node not being a child of the currently considered node (e.g. a sibling or parent).
+ repeat
+ // Is there a next sibling?
+ if Assigned(Result.NextSibling) then
+ begin
+ Result := Result.NextSibling;
+ if vsVisible in Result.States then
+ Break;
+ end
+ else
+ begin
+ // No sibling anymore, so use the parent's next sibling.
+ if Result.Parent <> FRoot then
+ Result := Result.Parent
+ else
+ begin
+ // There are no further nodes to examine, hence there is no further visible node.
+ Result := nil;
+ Break;
+ end;
+ end;
+ until False;
+ end;
+ end;
+
+ if Result = FRoot then
+ Result := nil;
+
+ // Since the given vertical position is likely not the same as the top position
+ // of the found node this top position is returned.
+ if Assigned(Result) then
+ begin
+ NodeTop := CurrentPos;
+ if Relative then
+ Inc(NodeTop, FOffsetY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeData(Node: PVirtualNode): Pointer;
+
+// Returns the address of the user defined data area in the node.
+
+begin
+ Assert(FNodeDataSize > 0, 'NodeDataSize not initialized.');
+
+ if (FNodeDataSize <= 0) or (Node = nil) or (Node = FRoot) then
+ Result := nil
+ else
+ Result := PChar(@Node.Data) + FTotalInternalDataSize;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetNodeLevel(Node: PVirtualNode): Cardinal;
+
+// returns the level of the given node
+
+var
+ Run: PVirtualNode;
+
+begin
+ Result := 0;
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ Run := Node.Parent;
+ while Run <> FRoot do
+ begin
+ Run := Run.Parent;
+ Inc(Result);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPrevious(Node: PVirtualNode): PVirtualNode;
+
+// Resturns previous node in tree with regard to Node. The result node is initialized if necessary.
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(vsInitialized in Result.States, 'Node must already be initialized.');
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // Is there a previous sibling?
+ if Assigned(Node.PrevSibling) then
+ begin
+ // Go down and find the last child node.
+ Result := GetLast(Node.PrevSibling);
+ if Result = nil then
+ Result := Node.PrevSibling;
+ end
+ else
+ // no previous sibling so the parent of the node is the previous visible node
+ if Node.Parent <> FRoot then
+ Result := Node.Parent
+ else
+ Result := nil;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousInitialized(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous node in tree which is initialized.
+
+begin
+ Result := Node;
+ repeat
+ Result := GetPreviousNoInit(Result);
+ until (Result = nil) or (vsInitialized in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous node in the tree with regard to Node. No initialization in done, hence this
+// method might be faster than GetPrevious. Not yet initialized nodes are ignored during search.
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // Is there a previous sibling?
+ if Assigned(Node.PrevSibling) then
+ begin
+ // Go down and find the last child node.
+ Result := GetLastNoInit(Node.PrevSibling);
+ if Result = nil then
+ Result := Node.PrevSibling;
+ end
+ else
+ // No previous sibling so the parent of the node is the previous node.
+ if Node.Parent <> FRoot then
+ Result := Node.Parent
+ else
+ Result := nil
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousSibling(Node: PVirtualNode): PVirtualNode;
+
+// get next sibling of Node, initialize it if necessary
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ Result := Node.PrevSibling;
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousVisible(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous node in tree, with regard to Node, which is visible.
+// Nodes which need an initialization (including the result) are initialized.
+
+var
+ Marker: PVirtualNode;
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(vsInitialized in Result.States, 'Node must already be initialized.');
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // If the given node is not visible then look for a parent node which is visible and use its last visible
+ // child or the parent node (if there is no visible child) as result.
+ if not FullyVisible[Result] then
+ begin
+ Result := GetVisibleParent(Result);
+ if Result = FRoot then
+ Result := nil;
+ Marker := GetLastVisible(Result);
+ if Assigned(Marker) then
+ Result := Marker;
+ end
+ else
+ begin
+ repeat
+ // Is there a previous sibling node?
+ if Assigned(Result.PrevSibling) then
+ begin
+ Result := Result.PrevSibling;
+ // Initialize the new node and check its visibility.
+ if not (vsInitialized in Result.States) then
+ InitNode(Result);
+ if vsVisible in Result.States then
+ begin
+ // If there are visible child nodes then use the last one.
+ Marker := GetLastVisible(Result);
+ if Assigned(Marker) then
+ Result := Marker;
+ Break;
+ end;
+ end
+ else
+ begin
+ // No previous sibling there so the parent node is the nearest previous node.
+ Result := Result.Parent;
+ if Result = FRoot then
+ Result := nil;
+ Break;
+ end;
+ until False;
+
+ if Assigned(Result) and not (vsInitialized in Result.States) then
+ InitNode(Result);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousVisibleNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous node in tree, with regard to Node, which is visible.
+
+var
+ Marker: PVirtualNode;
+
+begin
+ Result := Node;
+ if Assigned(Result) then
+ begin
+ Assert(Result <> FRoot, 'Node must not be the hidden root node.');
+
+ // If the given node is not visible then look for a parent node which is visible and use its last visible
+ // child or the parent node (if there is no visible child) as result.
+ if not FullyVisible[Result] then
+ begin
+ Result := GetVisibleParent(Result);
+ if Result = FRoot then
+ Result := nil;
+ Marker := GetLastVisibleNoInit(Result);
+ if Assigned(Marker) then
+ Result := Marker;
+ end
+ else
+ begin
+ repeat
+ // Is there a previous sibling node?
+ if Assigned(Result.PrevSibling) then
+ begin
+ Result := Result.PrevSibling;
+ if vsVisible in Result.States then
+ begin
+ // If there are visible child nodes then use the last one.
+ Marker := GetLastVisibleNoInit(Result);
+ if Assigned(Marker) then
+ Result := Marker;
+ Break;
+ end;
+ end
+ else
+ begin
+ // No previous sibling there so the parent node is the nearest previous node.
+ Result := Result.Parent;
+ if Result = FRoot then
+ Result := nil;
+ Break;
+ end;
+ until False;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousVisibleSibling(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous visible sibling before Node. Initialization is done implicitly.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ Result := Node;
+ repeat
+ Result := GetPreviousSibling(Result);
+ until (Result = nil) or (vsVisible in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetPreviousVisibleSiblingNoInit(Node: PVirtualNode): PVirtualNode;
+
+// Returns the previous visible sibling before Node.
+
+begin
+ Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.');
+
+ Result := Node;
+ repeat
+ Result := Result.PrevSibling;
+ until (Result = nil) or (vsVisible in Result.States);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetSortedCutCopySet(Resolve: Boolean): TNodeArray;
+
+// Same as GetSortedSelection but with nodes marked as being part in the current cut/copy set (e.g. for clipboard).
+
+var
+ Run: PVirtualNode;
+ Counter: Cardinal;
+
+ //--------------- local function --------------------------------------------
+
+ procedure IncludeThisNode(Node: PVirtualNode);
+
+ // adds the given node to the result
+
+ var
+ Len: Cardinal;
+
+ begin
+ Len := Length(Result);
+ if Counter = Len then
+ begin
+ if Len < 100 then
+ Len := 100
+ else
+ Len := Len + Len div 10;
+ SetLength(Result, Len);
+ end;
+ Result[Counter] := Node;
+ Inc(Counter);
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+begin
+ Run := FRoot.FirstChild;
+ Counter := 0;
+ if Resolve then
+ begin
+ // Resolving is actually easy: just find the first cutted node in logical order
+ // and then never go deeper in level than this node as long as there's a sibling node.
+ // Restart the search for a cutted node (at any level) if there are no further siblings.
+ while Assigned(Run) do
+ begin
+ if vsCutOrCopy in Run.States then
+ begin
+ IncludeThisNode(Run);
+ if Assigned(Run.NextSibling) then
+ Run := Run.NextSibling
+ else
+ begin
+ // If there are no further siblings then go up one or more levels until a node is
+ // found or all nodes have been processed. Although we consider here only initialized
+ // nodes we don't need to make any special checks as only initialized nodes can also be selected.
+ repeat
+ Run := Run.Parent;
+ until (Run = FRoot) or Assigned(Run.NextSibling);
+ if Run = FRoot then
+ Break
+ else
+ Run := Run.NextSibling;
+ end;
+ end
+ else
+ Run := GetNextNoInit(Run);
+ end;
+ end
+ else
+ while Assigned(Run) do
+ begin
+ if vsCutOrCopy in Run.States then
+ IncludeThisNode(Run);
+ Run := GetNextNoInit(Run);
+ end;
+
+ // set the resulting array to its real length
+ SetLength(Result, Counter);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetSortedSelection(Resolve: Boolean): TNodeArray;
+
+// Returns a list of selected nodes sorted in logical order, that is, as they appear in the tree.
+// If Resolve is True then nodes which are children of other selected nodes are not put into the new array.
+// This feature is in particuar important when doing drag'n drop as in this case all selected node plus their children
+// need to be considered. A selected node which is child (grand child etc.) of another selected node is then
+// automatically included and doesn't need to be explicitely mentioned in the returned selection array.
+//
+// Note: The caller is responsible for freeing the array. Allocation is done here. Usually, though, freeing the array
+// doesn't need additional attention as it is automatically freed by Delphi when it gets out of scope.
+
+var
+ Run: PVirtualNode;
+ Counter: Cardinal;
+
+begin
+ SetLength(Result, FSelectionCount);
+ if FSelectionCount > 0 then
+ begin
+ Run := FRoot.FirstChild;
+ Counter := 0;
+ if Resolve then
+ begin
+ // Resolving is actually easy: just find the first selected node in logical order
+ // and then never go deeper in level than this node as long as there's a sibling node.
+ // Restart the search for a selected node (at any level) if there are no further siblings.
+ while Assigned(Run) do
+ begin
+ if vsSelected in Run.States then
+ begin
+ Result[Counter] := Run;
+ Inc(Counter);
+ if Assigned(Run.NextSibling) then
+ Run := Run.NextSibling
+ else
+ begin
+ // If there are no further siblings then go up one or more levels until a node is
+ // found or all nodes have been processed. Although we consider here only initialized
+ // nodes we don't need to make any special checks as only initialized nodes can also be selected.
+ repeat
+ Run := Run.Parent;
+ until (Run = FRoot) or Assigned(Run.NextSibling);
+ if Run = FRoot then
+ Break
+ else
+ Run := Run.NextSibling;
+ end;
+ end
+ else
+ Run := GetNextNoInit(Run);
+ end;
+ end
+ else
+ while Assigned(Run) do
+ begin
+ if vsSelected in Run.States then
+ begin
+ Result[Counter] := Run;
+ Inc(Counter);
+ end;
+ Run := GetNextNoInit(Run);
+ end;
+
+ // Since we may have skipped some nodes the result array is likely to be smaller than the
+ // selection array, hence shorten the result to true length.
+ if Integer(Counter) < Length(Result) then
+ SetLength(Result, Counter);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetTreeRect: TRect;
+
+// Returns the true size of the tree in pixels. This size is at least ClientHeight x ClientWidth and depends on
+// the expand state, header size etc.
+// Note: if no columns are used then the width of the tree is determined by the largest node which is currently in the
+// client area. This might however not be the largest node in the entire tree.
+
+begin
+ Result := Rect(0, 0, Max(FRangeX, ClientWidth), Max(FRangeY, ClientHeight));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.GetVisibleParent(Node: PVirtualNode): PVirtualNode;
+
+// Returns the first (nearest) parent node of Node which is visible.
+// This method is one of the seldom cases where the hidden root node could be returned.
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+
+ Result := Node;
+ while Result <> FRoot do
+ begin
+ // FRoot is always expanded hence the loop will safely stop there if no other node is expanded
+ repeat
+ Result := Result.Parent;
+ until vsExpanded in Result.States;
+
+ if (Result = FRoot) or FullyVisible[Result] then
+ Break;
+
+ // if there is still a collapsed parent node then advance to it and repeat the entire loop
+ while (Result <> FRoot) and (vsExpanded in Result.Parent.States) do
+ Result := Result.Parent;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.HasAsParent(Node, PotentialParent: PVirtualNode): Boolean;
+
+// Determines whether Node has got PotentialParent as one of its parents.
+
+var
+ Run: PVirtualNode;
+
+begin
+ Result := Assigned(Node) and Assigned(PotentialParent) and (Node <> PotentialParent);
+ if Result then
+ begin
+ Run := Node;
+ while (Run <> FRoot) and (Run <> PotentialParent) do
+ Run := Run.Parent;
+ Result := Run = PotentialParent;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InsertNode(Node: PVirtualNode; Mode: TVTNodeAttachMode; UserData: Pointer = nil): PVirtualNode;
+
+// Adds a new node relative to Node. The final position is determined by Mode.
+// UserData can be used to set the first 4 bytes of the user data area to an initial value which can be used
+// in OnInitNode and will also cause to trigger the OnFreeNode event (if <> nil) even if the node is not yet
+// "officially" initialized.
+// InsertNode is a compatibility method and will implicitly validate the given node if the new node
+// is to be added as child node. This is however against the virtual paradigm and hence I dissuade from its usage.
+
+var
+ NodeData: ^Pointer;
+
+begin
+ if Mode <> amNoWhere then
+ begin
+ CancelEditNode;
+
+ if Node = nil then
+ Node := FRoot;
+ // we need a new node...
+ Result := MakeNewNode;
+ // avoid erronous attach modes
+ if Node = FRoot then
+ begin
+ case Mode of
+ amInsertBefore:
+ Mode := amAddChildFirst;
+ amInsertAfter:
+ Mode := amAddChildLast;
+ end;
+ end;
+
+ // Validate given node in case the new node becomes its child.
+ if (Mode in [amAddChildFirst, amAddChildLast]) and not (vsInitialized in Node.States) then
+ InitNode(Node);
+ InternalConnectNode(Result, Node, Self, Mode);
+
+ // Check if there is initial user data and there is also enough user data space allocated.
+ if Assigned(UserData) then
+ if FNodeDataSize >= 4 then
+ begin
+ NodeData := Pointer(PChar(@Result.Data) + FTotalInternalDataSize);
+ NodeData^ := UserData;
+ Include(Result.States, vsInitialUserData);
+ end
+ else
+ ShowError(SCannotSetUserData, hcTFCannotSetUserData);
+
+ if FUpdateCount = 0 then
+ begin
+ // If auto sort is enabled then sort the node or its parent (depending on the insert mode).
+ if (toAutoSort in FOptions.FAutoOptions) and (FHeader.FSortColumn > InvalidColumn) then
+ case Mode of
+ amInsertBefore,
+ amInsertAfter:
+ // Here no initialization is necessary because *if* a node has already got children then it
+ // must also be initialized.
+ // Note: Node can never be FRoot at this point.
+ Sort(Node.Parent, FHeader.FSortColumn, FHeader.FSortDirection, True);
+ amAddChildFirst,
+ amAddChildLast:
+ Sort(Node, FHeader.FSortColumn, FHeader.FSortDirection, True);
+ end;
+
+ UpdateScrollbars(True);
+ if Mode = amInsertBefore then
+ InvalidateToBottom(Result)
+ else
+ InvalidateToBottom(Node);
+ end;
+ StructureChange(Result, crNodeAdded);
+ end
+ else
+ Result := nil;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvalidateChildren(Node: PVirtualNode; Recursive: Boolean);
+
+// Invalidates Node and its immediate children.
+// If Recursive is True then all grandchildren are invalidated as well.
+// The node itself is initialized if necessary and its child nodes are created (and initialized too if
+// Recursive is True).
+
+var
+ Run: PVirtualNode;
+
+begin
+ if Assigned(Node) then
+ begin
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ InvalidateNode(Node);
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+ Run := Node.FirstChild;
+ end
+ else
+ Run := FRoot.FirstChild;
+
+ while Assigned(Run) do
+ begin
+ InvalidateNode(Run);
+ if Recursive then
+ InvalidateChildren(Run, True);
+ Run := Run.NextSibling;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvalidateColumn(Column: TColumnIndex);
+
+// Invalidates the client area part of a column.
+
+var
+ R: TRect;
+
+begin
+ if (FUpdateCount = 0) and FHeader.Columns.IsValidColumn(Column) then
+ begin
+ R := ClientRect;
+ FHeader.Columns.GetColumnBounds(Column, R.Left, R.Right);
+ InvalidateRect(Handle, @R, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.InvalidateNode(Node: PVirtualNode): TRect;
+
+// Initiates repaint of the given node and returns the just invalidated rectangle.
+
+begin
+ if (FUpdateCount = 0) and HandleAllocated then
+ begin
+ Result := GetDisplayRect(Node, NoColumn, False);
+ InvalidateRect(Handle, @Result, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvalidateToBottom(Node: PVirtualNode);
+
+// Initiates repaint of client area starting at given node. If this node is not visible or not yet initialized
+// then nothing happens.
+
+var
+ R: TRect;
+
+begin
+ if FUpdateCount = 0 then
+ begin
+ if (Node = nil) or (Node = FRoot) then
+ Invalidate
+ else
+ if [vsInitialized, vsVisible] * Node.States = [vsInitialized, vsVisible] then
+ begin
+ R := GetDisplayRect(Node, -1, False);
+ if R.Top < ClientHeight then
+ begin
+ R.Bottom := ClientHeight;
+ InvalidateRect(Handle, @R, False);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.InvertSelection(VisibleOnly: Boolean);
+
+// Inverts the current selection (so nodes which are selected become unselected and vice versa).
+// If VisibleOnly is True then only visible nodes are considered.
+
+var
+ Run: PVirtualNode;
+ NewSize: Integer;
+ NextFunction: function(Node: PVirtualNode): PVirtualNode of object;
+ TriggerChange: Boolean;
+
+begin
+ if toMultiSelect in FOptions.FSelectionOptions then
+ begin
+ Run := FRoot.FirstChild;
+ ClearTempCache;
+ if VisibleOnly then
+ NextFunction := GetNextVisibleNoInit
+ else
+ NextFunction := GetNextNoInit;
+ while Assigned(Run) do
+ begin
+ if vsSelected in Run.States then
+ InternalRemoveFromSelection(Run)
+ else
+ InternalCacheNode(Run);
+ Run := NextFunction(Run);
+ end;
+
+ // do some housekeeping
+ // Need to trigger the OnChange event from here if nodes were only deleted but not added.
+ TriggerChange := False;
+ NewSize := PackArray(FSelection, FSelectionCount);
+ if NewSize > -1 then
+ begin
+ FSelectionCount := NewSize;
+ SetLength(FSelection, FSelectionCount);
+ TriggerChange := True;
+ end;
+ if FTempNodeCount > 0 then
+ begin
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+ TriggerChange := False;
+ end;
+ Invalidate;
+ if TriggerChange then
+ Change(nil);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IsEditing: Boolean;
+
+begin
+ Result := tsEditing in FStates;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IsMouseSelecting: Boolean;
+
+begin
+ Result := (tsDrawSelPending in FStates) or (tsDrawSelecting in FStates);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.IterateSubtree(Node: PVirtualNode; Callback: TVTGetNodeProc; Data: Pointer;
+ Filter: TVirtualNodeStates = []; DoInit: Boolean = False; ChildNodesOnly: Boolean = False): PVirtualNode;
+
+// Iterates through the all children and grandchildren etc. of Node (or the entire tree if Node = nil)
+// and calls for each node the provided callback method (which must not be empty).
+// Filter determines which nodes to consider (an empty set denotes all nodes).
+// If DoInit is True then nodes which aren't initialized yet will be initialized.
+// Note: During execution of the callback the application can set Abort to True. In this case the iteration is stopped
+// and the last accessed node (the one on which the callback set Abort to True) is returned to the caller.
+// Otherwise (no abort) nil is returned.
+
+var
+ Stop: PVirtualNode;
+ Abort: Boolean;
+ GetNextNode: TGetNextNodeProc;
+ WasIterating: Boolean;
+
+begin
+ Assert(Node <> FRoot, 'Node must not be the hidden root node.');
+
+ WasIterating := tsIterating in FStates;
+ DoStateChange([tsIterating]);
+ try
+ // prepare function to be used when advancing
+ if DoInit then
+ GetNextNode := GetNext
+ else
+ GetNextNode := GetNextNoInit;
+
+ Abort := False;
+ if Node = nil then
+ Stop := nil
+ else
+ begin
+ if not (vsInitialized in Node.States) and DoInit then
+ InitNode(Node);
+
+ // The stopper does not need to be initialized since it is not taken into the enumeration.
+ Stop := Node.NextSibling;
+ if Stop = nil then
+ begin
+ Stop := Node;
+ repeat
+ Stop := Stop.Parent;
+ until (Stop = FRoot) or Assigned(Stop.NextSibling);
+ if Stop = FRoot then
+ Stop := nil
+ else
+ Stop := Stop.NextSibling;
+ end;
+ end;
+
+ // Use first node if we start with the root.
+ if Node = nil then
+ Node := GetFirstNoInit;
+
+ if Assigned(Node) then
+ begin
+ if not (vsInitialized in Node.States) and DoInit then
+ InitNode(Node);
+
+ // Skip given node if only the child nodes are requested.
+ if ChildNodesOnly then
+ begin
+ if Node.ChildCount = 0 then
+ Node := nil
+ else
+ Node := GetNextNode(Node);
+ end;
+
+ if Filter = [] then
+ begin
+ // unfiltered loop
+ while Assigned(Node) and (Node <> Stop) do
+ begin
+ Callback(Self, Node, Data, Abort);
+ if Abort then
+ Break;
+ Node := GetNextNode(Node);
+ end;
+ end
+ else
+ begin
+ // filtered loop
+ while Assigned(Node) and (Node <> Stop) do
+ begin
+ if Node.States * Filter = Filter then
+ Callback(Self, Node, Data, Abort);
+ if Abort then
+ Break;
+ Node := GetNextNode(Node)
+ end;
+ end;
+ end;
+
+ if Abort then
+ Result := Node
+ else
+ Result := nil;
+ finally
+ if not WasIterating then
+ DoStateChange([], [tsIterating]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.LoadFromFile(const FileName: TFileName);
+
+var
+ FileStream: TFileStream;
+
+begin
+ FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+ try
+ LoadFromStream(FileStream);
+ finally
+ FileStream.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.LoadFromStream(Stream: TStream);
+
+// Clears the current content of the tree and loads a new structure from the given stream.
+
+var
+ ThisID: TMagicID;
+ Version,
+ Count: Cardinal;
+ Node: PVirtualNode;
+
+begin
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ Clear;
+ // Check first whether this is a stream we can read.
+ if Stream.Read(ThisID, SizeOf(TMagicID)) < SizeOf(TMagicID) then
+ ShowError(SStreamTooSmall, hcTFStreamTooSmall);
+
+ if (ThisID[0] = MagicID[0]) and (ThisID[1] = MagicID[1]) and (ThisID[2] = MagicID[2]) and
+ (ThisID[5] = MagicID[5]) then
+ begin
+ Version := Word(ThisID[3]);
+ if Version <= VTTreeStreamVersion then
+ begin
+ BeginUpdate;
+ try
+ if Version < 2 then
+ Count := MaxInt
+ else
+ Stream.ReadBuffer(Count, SizeOf(Count));
+
+ while (Stream.Position < Stream.Size) and (Count > 0) do
+ begin
+ Dec(Count);
+ Node := MakeNewNode;
+ InternalConnectNode(Node, FRoot, Self, amAddChildLast);
+ InternalAddFromStream(Stream, Version, Node);
+ end;
+ DoNodeCopied(nil);
+ finally
+ EndUpdate;
+ end;
+ end
+ else
+ ShowError(SWrongStreamVersion, hcTFWrongStreamVersion);
+ end
+ else
+ ShowError(SWrongStreamFormat, hcTFWrongStreamFormat);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MoveTo(Node: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode;
+ ChildrenOnly: Boolean);
+
+// A simplified method to allow to move nodes to the root of another tree.
+
+begin
+ MoveTo(Node, Tree.FRoot, Mode, ChildrenOnly);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.MoveTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; ChildrenOnly: Boolean);
+
+// Moves the given node (and all its children) to Target. Source must belong to the tree instance which calls this
+// MoveTo method. Mode determines how to connect Source to Target.
+// This method might involve a change of the tree if Target belongs to a different tree than Source.
+
+var
+ TargetTree: TBaseVirtualTree;
+ Allowed: Boolean;
+ NewNode: PVirtualNode;
+ Stream: TMemoryStream;
+
+begin
+ Assert(TreeFromNode(Source) = Self, 'The source tree must contain the source node.');
+
+ // When moving nodes then source and target must not be the same node unless only the source's children are
+ // moved and they are inserted before or after the node itself.
+ Allowed := (Source <> Target) or ((Mode in [amInsertBefore, amInsertAfter]) and ChildrenOnly);
+
+ if Allowed and (Mode <> amNoWhere) and Assigned(Source) and (Source <> FRoot) and
+ not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ // Assume that an empty destination means the root in this (the source) tree.
+ if Target = nil then
+ begin
+ TargetTree := Self;
+ Target := FRoot;
+ Mode := amAddChildFirst;
+ end
+ else
+ TargetTree := TreeFromNode(Target);
+
+ if Target = TargetTree.FRoot then
+ begin
+ case Mode of
+ amInsertBefore:
+ Mode := amAddChildFirst;
+ amInsertAfter:
+ Mode := amAddChildLast;
+ end;
+ end;
+
+ if TargetTree = Self then
+ begin
+ // Simple case: move node(s) within the same tree.
+ if Target = FRoot then
+ Allowed := DoNodeMoving(Source, nil)
+ else
+ Allowed := DoNodeMoving(Source, Target);
+ if Allowed then
+ begin
+ // Check first that Source is not added as new child to a target node which
+ // is already a child of Source.
+ // Consider the case Source and Target are the same node, but only child nodes are moved.
+ if (Source <> Target) and HasAsParent(Target, Source) then
+ ShowError(SWrongMoveError, hcTFWrongMoveError);
+
+ if not ChildrenOnly then
+ begin
+ // Disconnect from old location.
+ InternalDisconnectNode(Source, True);
+ // Connect to new location.
+ InternalConnectNode(Source, Target, Self, Mode);
+ DoNodeMoved(Source);
+ end
+ else
+ begin
+ // Only child nodes should be moved.
+ Source := Source.LastChild;
+ while Assigned(Source) do
+ begin
+ NewNode := Source.PrevSibling;
+ // Disconnect from old location.
+ InternalDisconnectNode(Source, True, False);
+ // Connect to new location.
+ InternalConnectNode(Source, Target, Self, Mode);
+ DoNodeMoved(Source);
+ Source := NewNode;
+ end;
+ end;
+ end;
+ end
+ else
+ begin
+ // Difficult case: move node(s) to another tree.
+ // In opposition to node copying we ask only once if moving is allowed because
+ // we cannot take back a move once done.
+ if Target = TargetTree.FRoot then
+ Allowed := DoNodeMoving(Source, nil)
+ else
+ Allowed := DoNodeMoving(Source, Target);
+
+ if Allowed then
+ begin
+ Stream := TMemoryStream.Create;
+ try
+ // Write all nodes into a temporary stream depending on the ChildrenOnly flag.
+ if not ChildrenOnly then
+ WriteNode(Stream, Source)
+ else
+ begin
+ Source := Source.FirstChild;
+ while Assigned(Source) do
+ begin
+ WriteNode(Stream, Source);
+ Source := Source.NextSibling;
+ end;
+ end;
+ // Now load the serialized nodes into the target node (tree).
+ TargetTree.BeginUpdate;
+ try
+ Stream.Position := 0;
+ while Stream.Position < Stream.Size do
+ begin
+ NewNode := TargetTree.MakeNewNode;
+ InternalConnectNode(NewNode, Target, TargetTree, Mode);
+ TargetTree.InternalAddFromStream(Stream, VTTreeStreamVersion, NewNode);
+ DoNodeMoved(NewNode);
+ end;
+ finally
+ TargetTree.EndUpdate;
+ end;
+ finally
+ Stream.Free;
+ end;
+ // finally delete original nodes
+ BeginUpdate;
+ try
+ if ChildrenOnly then
+ DeleteChildren(Source)
+ else
+ DeleteNode(Source);
+ finally
+ EndUpdate;
+ end;
+ end;
+ end;
+
+ InvalidateCache;
+ if (FUpdateCount = 0) and Allowed then
+ begin
+ ValidateCache;
+ UpdateScrollBars(True);
+ Invalidate;
+ if TargetTree <> Self then
+ TargetTree.Invalidate;
+ end;
+ StructureChange(Source, crNodeMoved);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PaintTree(TargetCanvas: TCanvas; Window: TRect; Target: TPoint;
+ PaintOptions: TVTInternalPaintOptions);
+
+// This is the core paint routine of the tree. It is responsible for maintaining the paint cycles per node as well
+// as coordinating drawing of the various parts of the tree image.
+// TargetCanvas is the canvas to which to draw the tree image. This is usually the tree window itself but could well
+// be a bitmap or printer canvas.
+// Window determines which part of the entire tree image to draw. The full size of the virtual image is determined
+// by GetTreeRect.
+// Target is the position in TargetCanvas where to draw the tree part specified by Window.
+// PaintOptions determines what of the tree to draw. For different tasks usually different parts need to be drawn, with
+// a full image in the window, selected only nodes for a drag image etc.
+
+const
+ ImageKind: array[Boolean] of TVTImageKind = (ikNormal, ikSelected);
+
+var
+ DrawSelectionRect,
+ UseBackground,
+ ShowImages,
+ ShowStateImages,
+ ShowCheckImages,
+ UseColumns,
+ IsMainColumn: Boolean;
+
+ VAlign,
+ IndentSize,
+ ButtonX,
+ ButtonY: Integer;
+ Temp: PVirtualNode;
+ LineImage: TLineImage;
+ PaintInfo: TVTPaintInfo; // all necessary information about a node to pass to the paint routines
+
+ R, // the area of an entire node in its local coordinate
+ TargetRect, // the area of a node (part) in the target canvas
+ SelectionRect: TRect; // ordered rectangle used for drawing the selection focus rect
+ NextColumn: TColumnIndex;
+ BaseOffset: Integer; // top position of the top node to draw given in absolute tree coordinates
+ NodeBitmap: TBitmap; // small buffer to draw flicker free
+ MaximumRight, // maximum horizontal target position
+ MaximumBottom: Integer; // maximum vertical target position
+ SelectLevel: Integer; // > 0 if current node is selected or child/grandchild etc. of a selected node
+ FirstColumn: TColumnIndex; // index of first column which is at least partially visible in the given window
+
+begin
+ DoStateChange([tsPainting]);
+
+ DoBeforePaint(TargetCanvas);
+
+ // Create small bitmaps and initialize default values.
+ // The bitmaps are used to paint one node at a time and to draw the result to the target (e.g. screen) in one step,
+ // to prevent flickering.
+ NodeBitmap := TBitmap.Create;
+ // For alpha blending we need the 32 bit pixel format.
+ if MMXAvailable and ((FDrawSelectionMode = smBlendedRectangle) or (tsUseThemes in FStates)) then
+ NodeBitmap.PixelFormat := pf32Bit;
+
+ // Prepare paint info structure and lock the back bitmap canvas to avoid that it gets freed on the way.
+ FillChar(PaintInfo, SizeOf(PaintInfo), 0);
+ PaintInfo.Canvas := NodeBitmap.Canvas;
+ NodeBitmap.Canvas.Lock;
+ try
+ // Prepare the current selection rectangle once. The corner points are absolute tree coordinates.
+ SelectionRect := OrderRect(FNewSelRect);
+ DrawSelectionRect := IsMouseSelecting and not IsRectEmpty(SelectionRect);
+
+ // R represents an entire node (all columns), but is a bit unprecise when it comes to
+ // trees without any column defined, because FRangeX only represents the maximum width of all
+ // nodes in the client area (not all defined nodes). There might be, however, wider nodes somewhere. Without full
+ // validation I cannot better determine the width, though. By using at least the control's width it is ensured
+ // that the tree is fully displayed on screen.
+ R := Rect(0, 0, Max(FRangeX, ClientWidth), 0);
+ NodeBitmap.Width := Window.Right - Window.Left;
+
+ // Make sure the buffer bitmap and target bitmap use the same transformation mode.
+ SetMapMode(NodeBitmap.Canvas.Handle, GetMapMode(TargetCanvas.Handle));
+
+ // For quick checks some intermediate variables are used.
+ UseBackground := (toShowBackground in FOptions.FPaintOptions) and (FBackground.Graphic is TBitmap) and
+ (poBackground in PaintOptions);
+ ShowImages := Assigned(FImages);
+ ShowStateImages := Assigned(FStateImages);
+ ShowCheckImages := Assigned(FCheckImages) and (toCheckSupport in FOptions.FMiscOptions);
+ UseColumns := FHeader.UseColumns;
+
+ // Adjust paint options to tree settings.
+ if not Focused and (toHideSelection in FOptions.FPaintOptions) then
+ Exclude(PaintOptions, poDrawSelection);
+ if toHideFocusRect in FOptions.FPaintOptions then
+ Exclude(PaintOptions, poDrawFocusRect);
+
+ // Determine node to start drawing with.
+ BaseOffset := 0;
+ PaintInfo.Node := GetNodeAt(0, Window.Top, False, BaseOffset);
+
+ // Transform selection rectangle into node bitmap coordinates.
+ if DrawSelectionRect then
+ OffsetRect(SelectionRect, 0, -BaseOffset);
+
+ // The target rectangle holds the coordinates of the exact area to blit in target canvas coordinates.
+ // It is usually smaller than an entire node and wanders while the paint loop advances.
+ MaximumRight := Target.X + (Window.Right - Window.Left);
+ MaximumBottom := Target.Y + (Window.Bottom - Window.Top);
+
+ TargetRect := Rect(Target.X, Target.Y - (Window.Top - BaseOffset), MaximumRight, 0);
+ TargetRect.Bottom := TargetRect.Top;
+
+ // This marker gets the index of the first column which is visible in the given window.
+ // This is needed for column based background colors.
+ FirstColumn := InvalidColumn;
+
+ if Assigned(PaintInfo.Node) then
+ begin
+ SelectLevel := InitializeLineImageAndSelectLevel(PaintInfo.Node, LineImage);
+ IndentSize := Length(LineImage);
+
+ // Precalculate horizontal position of buttons relative to the column start.
+ ButtonX := (Length(LineImage) * Integer(FIndent)) + Round((Integer(FIndent) - FPlusBM.Width) / 2) - FIndent;
+
+ // ----- main node paint loop
+ while Assigned(PaintInfo.Node) do
+ begin
+ // Initialize node if not already done.
+ if not (vsInitialized in PaintInfo.Node.States) then
+ InitNode(PaintInfo.Node);
+ if vsSelected in PaintInfo.Node.States then
+ Inc(SelectLevel);
+
+ // Adjust the brush origin for dotted lines depending on the current source position.
+ // It is applied some lines later, as the canvas might get reallocated, when changing the node bitmap.
+ PaintInfo.BrushOrigin := Point(Window.Left and 1, BaseOffset and 1);
+ Inc(BaseOffset, PaintInfo.Node.NodeHeight);
+
+ TargetRect.Bottom := TargetRect.Top + PaintInfo.Node.NodeHeight;
+
+ // If poSelectedOnly is active then do the following stuff only for selected nodes or nodes
+ // which are children of selected nodes.
+ if (SelectLevel > 0) or not (poSelectedOnly in PaintOptions) then
+ begin
+ // Adjust height of temporary node bitmap.
+ with NodeBitmap do
+ begin
+ if Height <> PaintInfo.Node.NodeHeight then
+ begin
+ // Avoid that the VCL copies the bitmap while changing its height.
+ Height := 0;
+ Height := PaintInfo.Node.NodeHeight;
+ SetWindowOrgEx(Canvas.Handle, Window.Left, 0, nil);
+ R.Bottom := PaintInfo.Node.NodeHeight;
+ end;
+ // Set the origin of the canvas' brush. This depends on the node heights.
+ with PaintInfo do
+ SetBrushOrgEx(Canvas.Handle, BrushOrigin.X, BrushOrigin.Y, nil);
+ end;
+ CalculateVerticalAlignments(ShowImages, ShowStateImages, PaintInfo.Node, VAlign, ButtonY);
+
+ // Let application decide whether the node should normally be drawn or by the application itself.
+ if not DoBeforeItemPaint(PaintInfo.Canvas, PaintInfo.Node, R) then
+ begin
+ // Init paint options for the background painting.
+ PaintInfo.PaintOptions := PaintOptions;
+
+ // The node background can contain a single color, a bitmap or can be drawn by the application.
+ ClearNodeBackground(PaintInfo, UseBackground, True, Rect(Window.Left, TargetRect.Top, Window.Right,
+ TargetRect.Bottom));
+
+ // Prepare column, position and node clipping rectangle.
+ PaintInfo.CellRect := R;
+ if UseColumns then
+ InitializeFirstColumnValues(PaintInfo);
+
+ // Now go through all visible columns (there's still one run if columns aren't used).
+ with FHeader.FColumns do
+ begin
+ while ((PaintInfo.Column > InvalidColumn) or not UseColumns)
+ and (PaintInfo.CellRect.Left < Window.Right) do
+ begin
+ if UseColumns then
+ begin
+ PaintInfo.Column := FPositionToIndex[PaintInfo.Position];
+ if FirstColumn = InvalidColumn then
+ FirstColumn := PaintInfo.Column;
+ PaintInfo.BidiMode := Items[PaintInfo.Column].FBiDiMode;
+ PaintInfo.Alignment := Items[PaintInfo.Column].FAlignment;
+ end
+ else
+ begin
+ PaintInfo.Column := NoColumn;
+ PaintInfo.BidiMode := BidiMode;
+ PaintInfo.Alignment := FAlignment;
+ end;
+
+ PaintInfo.PaintOptions := PaintOptions;
+ with PaintInfo do
+ begin
+ if (tsEditing in FStates) and (Node = FFocusedNode) and
+ ((Column = FEditColumn) or not UseColumns) then
+ Exclude(PaintOptions, poDrawSelection);
+ if not UseColumns or
+ ((vsSelected in Node.States) and (toFullRowSelect in FOptions.FSelectionOptions) and
+ (poDrawSelection in PaintOptions)) or
+ (coParentColor in Items[PaintInfo.Column].Options) then
+ Exclude(PaintOptions, poColumnColor);
+ end;
+ IsMainColumn := PaintInfo.Column = FHeader.MainColumn;
+
+ // Consider bidi mode here. In RTL context means left alignment actually right alignment and vice versa.
+ if PaintInfo.BidiMode <> bdLeftToRight then
+ ChangeBiDiModeAlignment(PaintInfo.Alignment);
+
+ // Paint the current cell if it is marked as being visible or columns aren't used and
+ // if this cell belongs to the main column if only the main column should be drawn.
+ if (not UseColumns or (coVisible in Items[PaintInfo.Column].FOptions)) and
+ (not (poMainOnly in PaintOptions) or IsMainColumn) then
+ begin
+ AdjustPaintCellRect(PaintInfo, NextColumn);
+
+ // Paint the cell only if it is in the current window.
+ if PaintInfo.CellRect.Right > Window.Left then
+ begin
+ with PaintInfo do
+ begin
+ // Fill in remaining values in the paint info structure.
+ NodeWidth := DoGetNodeWidth(Node, Column, Canvas);
+ // Not the entire cell is covered by text. Hence we need a running rectangle to follow up.
+ ContentRect := CellRect;
+ // Set up the distance from column border (margin).
+ if BidiMode <> bdLeftToRight then
+ Dec(ContentRect.Right, FMargin)
+ else
+ Inc(ContentRect.Left, FMargin);
+
+ if ShowCheckImages and IsMainColumn then
+ begin
+ ImageInfo[iiCheck].Index := GetCheckImage(Node);
+ if ImageInfo[iiCheck].Index > -1 then
+ begin
+ AdjustImageBorder(FCheckImages, BidiMode, VAlign, ContentRect, ImageInfo[iiCheck]);
+ ImageInfo[iiCheck].Ghosted := False;
+ end;
+ end
+ else
+ ImageInfo[iiCheck].Index := -1;
+ if ShowStateImages then
+ begin
+ ImageInfo[iiState].Index := GetImageIndex(Node, ikState, Column, ImageInfo[iiState].Ghosted);
+ if ImageInfo[iiState].Index > -1 then
+ AdjustImageBorder(FStateImages, BidiMode, VAlign, ContentRect, ImageInfo[iiState]);
+ end
+ else
+ ImageInfo[iiState].Index := -1;
+ if ShowImages then
+ begin
+ ImageInfo[iiNormal].Index := GetImageIndex(Node, ImageKind[vsSelected in Node.States], Column,
+ ImageInfo[iiNormal].Ghosted);
+ if ImageInfo[iiNormal].Index > -1 then
+ AdjustImageBorder(FImages, BidiMode, VAlign, ContentRect, ImageInfo[iiNormal]);
+ end
+ else
+ ImageInfo[iiNormal].Index := -1;
+
+ // Take the space for the tree lines into account.
+ if IsMainColumn then
+ AdjustCoordinatesByIndent(PaintInfo, IndentSize);
+
+ if UseColumns then
+ LimitPaintingToArea(Canvas, CellRect);
+
+ // Paint the horizontal grid line.
+ if (poGridLines in PaintOptions) and (toShowHorzGridLines in FOptions.FPaintOptions) then
+ begin
+ Canvas.Font.Color := FColors.GridLineColor;
+ if IsMainColumn and (FLineMode = lmBands) then
+ begin
+ if BidiMode = bdLeftToRight then
+ begin
+ DrawDottedHLine(PaintInfo, CellRect.Left + IndentSize * Integer(FIndent), CellRect.Right - 1,
+ CellRect.Bottom - 1);
+ end
+ else
+ begin
+ DrawDottedHLine(PaintInfo, CellRect.Left, CellRect.Right - IndentSize * Integer(FIndent) - 1,
+ CellRect.Bottom - 1);
+ end;
+ end
+ else
+ DrawDottedHLine(PaintInfo, CellRect.Left, CellRect.Right, CellRect.Bottom - 1);
+ Dec(CellRect.Bottom);
+ Dec(ContentRect.Bottom);
+ end;
+
+ if UseColumns then
+ begin
+ // Paint vertical grid line.
+ // Don't draw if this is the last column and the header is in autosize mode.
+ if (poGridLines in PaintOptions) and (toShowVertGridLines in FOptions.FPaintOptions) and
+ (not (hoAutoResize in FHeader.FOptions) or (Position < TColumnPosition(Count - 1))) then
+ begin
+ if (BidiMode = bdLeftToRight) or not ColumnIsEmpty(Node, Column) then
+ begin
+ Canvas.Font.Color := FColors.GridLineColor;
+ DrawDottedVLine(PaintInfo, CellRect.Top, CellRect.Bottom, CellRect.Right - 1);
+ end;
+ Dec(CellRect.Right);
+ Dec(ContentRect.Right);
+ end;
+ end;
+
+ // Prepare background and focus rect for the current cell.
+ PrepareCell(PaintInfo);
+
+ // Some parts are only drawn for the main column.
+ if IsMainColumn then
+ begin
+ if toShowTreeLines in FOptions.FPaintOptions then
+ PaintTreeLines(PaintInfo, VAlign, IndentSize, LineImage);
+ // Show node button if allowed, if there child nodes and at least one of the child
+ // nodes is visible or auto button hiding is disabled.
+ if (toShowButtons in FOptions.FPaintOptions) and (vsHasChildren in Node.States) and
+ not ((vsAllChildrenHidden in Node.States) and
+ (toAutoHideButtons in TreeOptions.FAutoOptions)) then
+ PaintNodeButton(Canvas, Node, CellRect, ButtonX, ButtonY, BidiMode);
+
+ if ImageInfo[iiCheck].Index > -1 then
+ PaintCheckImage(PaintInfo);
+ end;
+
+ if ImageInfo[iiState].Index > -1 then
+ PaintImage(PaintInfo, iiState, FStateImages, False);
+ if ImageInfo[iiNormal].Index > -1 then
+ PaintImage(PaintInfo, iiNormal, FImages, True);
+
+ // Now let descendants or applications draw whatever they want,
+ // but don't draw the node if it is currently being edited.
+ if not ((tsEditing in FStates) and (Node = FFocusedNode) and
+ ((Column = FEditColumn) or not UseColumns)) then
+ DoPaintNode(PaintInfo);
+
+ DoAfterCellPaint(Canvas, Node, Column, CellRect);
+ end;
+ end;
+
+ // leave after first run if columns aren't used
+ if not UseColumns then
+ Break;
+ end
+ else
+ NextColumn := GetNextVisibleColumn(PaintInfo.Column);
+
+ SelectClipRgn(PaintInfo.Canvas.Handle, 0);
+ // Stop column loop if there are no further columns in the given window.
+ if (PaintInfo.CellRect.Left >= Window.Right) or (NextColumn = InvalidColumn) then
+ Break;
+
+ // Move on to next column which might not be the one immediately following the current one
+ // because of auto span feature.
+ PaintInfo.Position := Items[NextColumn].Position;
+
+ // Move clip rectangle and continue.
+ if coVisible in Items[NextColumn].FOptions then
+ with PaintInfo do
+ begin
+ Items[NextColumn].GetAbsoluteBounds(CellRect.Left, CellRect.Right);
+ CellRect.Bottom := Node.NodeHeight;
+ ContentRect.Bottom := Node.NodeHeight;
+ end;
+ end;
+ end;
+
+ // This node is finished, notify descentants/application.
+ with PaintInfo do
+ begin
+ DoAfterItemPaint(Canvas, Node, R);
+
+ // Final touch for this node: mark it if it is the current drop target node.
+ if (Node = FDropTargetNode) and (toShowDropmark in FOptions.FPaintOptions) and
+ (poDrawDropMark in PaintOptions) then
+ DoPaintDropMark(Canvas, Node, R);
+ end;
+ end;
+
+ with PaintInfo.Canvas do
+ begin
+ if DrawSelectionRect then
+ begin
+ PaintSelectionRectangle(PaintInfo.Canvas, Window.Left, SelectionRect, Rect(0, 0, NodeBitmap.Width,
+ NodeBitmap.Height));
+ end;
+
+ // Put the constructed node image onto the target canvas.
+ with TargetRect, NodeBitmap do
+ BitBlt(TargetCanvas.Handle, Left, Top, Width, Height, Canvas.Handle, Window.Left, 0, SRCCOPY);
+ end;
+ end;
+
+ Inc(TargetRect.Top, PaintInfo.Node.NodeHeight);
+ if TargetRect.Top >= MaximumBottom then
+ Break;
+
+ // Keep selection rectangle coordinates in sync.
+ if DrawSelectionRect then
+ OffsetRect(SelectionRect, 0, -PaintInfo.Node.NodeHeight);
+
+ // Advance to next visible node.
+ Temp := GetNextVisible(PaintInfo.Node);
+ if Assigned(Temp) then
+ begin
+ // Adjust line bitmap (and so also indentation level).
+ if Temp.Parent = PaintInfo.Node then
+ begin
+ // New node is a child node. Need to adjust previous bitmap level.
+ if IndentSize > 0 then
+ if HasVisibleNextSibling(PaintInfo.Node) then
+ LineImage[IndentSize - 1] := ltTopDown
+ else
+ LineImage[IndentSize - 1] := ltNone;
+ // Enhance line type array if necessary.
+ Inc(IndentSize);
+ if Length(LineImage) <= IndentSize then
+ SetLength(LineImage, IndentSize + 8);
+ Inc(ButtonX, FIndent);
+ end
+ else
+ begin
+ // New node is at the same or higher tree level.
+ // Take back select level increase if the node was selected
+ if vsSelected in PaintInfo.Node.States then
+ Dec(SelectLevel);
+ if PaintInfo.Node.Parent <> Temp.Parent then
+ begin
+ // We went up one or more levels. Determine how many levels it was actually.
+ while PaintInfo.Node.Parent <> Temp.Parent do
+ begin
+ Dec(IndentSize);
+ Dec(ButtonX, FIndent);
+ PaintInfo.Node := PaintInfo.Node.Parent;
+ // Take back one selection level increase for every step up.
+ if vsSelected in PaintInfo.Node.States then
+ Dec(SelectLevel);
+ end;
+ end;
+ end;
+
+ // Set new image in front of the new node.
+ if IndentSize > 0 then
+ if HasVisibleNextSibling(Temp) then
+ LineImage[IndentSize - 1] := ltTopDownRight
+ else
+ LineImage[IndentSize - 1] := ltTopRight;
+ end;
+
+ PaintInfo.Node := Temp;
+ end;
+ end;
+
+ // Erase rest of window not covered by a node.
+ if TargetRect.Top < MaximumBottom then
+ begin
+ // Keep the horizontal target position to determine the selection rectangle offset later (if necessary).
+ BaseOffset := Target.X;
+ Target := TargetRect.TopLeft;
+ R := Rect(TargetRect.Left, 0, MaximumRight, MaximumBottom - Target.Y);
+ TargetRect := Rect(0, 0, MaximumRight - Target.X, MaximumBottom - Target.Y);
+ // Avoid unnecessary copying of bitmap content. This will destroy the DC handle too.
+ NodeBitmap.Height := 0;
+ NodeBitmap.PixelFormat := pf32Bit;
+ NodeBitmap.Width := TargetRect.Right - TargetRect.Left + 1;
+ NodeBitmap.Height := TargetRect.Bottom - TargetRect.Top + 1;
+
+ // Call back application/descentants whether they want to erase this area.
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, Target.X, 0, nil);
+ if not DoPaintBackground(NodeBitmap.Canvas, TargetRect) then
+ begin
+ if UseBackground then
+ begin
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, 0, 0, nil);
+ TileBackground(FBackground.Bitmap, NodeBitmap.Canvas, Target, TargetRect);
+ end
+ else
+ begin
+ // Consider here also colors of the columns.
+ if UseColumns then
+ begin
+ with FHeader.FColumns do
+ begin
+ // If there is no content in the tree then the first column has not yet been determined.
+ if FirstColumn = InvalidColumn then
+ begin
+ FirstColumn := GetFirstVisibleColumn;
+ repeat
+ if FirstColumn <> InvalidColumn then
+ begin
+ R.Left := Items[FirstColumn].Left;
+ R.Right := R.Left + Items[FirstColumn].FWidth;
+ if R.Right > TargetRect.Left then
+ Break;
+ FirstColumn := GetNextVisibleColumn(FirstColumn);
+ end;
+ until FirstColumn = InvalidColumn;
+ end
+ else
+ begin
+ R.Left := Items[FirstColumn].Left;
+ R.Right := R.Left + Items[FirstColumn].FWidth;
+ end;
+
+ while (FirstColumn <> InvalidColumn) and (R.Left < TargetRect.Right + Target.X) do
+ begin
+ if not (coParentColor in Items[FirstColumn].FOptions) then
+ NodeBitmap.Canvas.Brush.Color := Items[FirstColumn].FColor
+ else
+ NodeBitmap.Canvas.Brush.Color := Color;
+
+ NodeBitmap.Canvas.FillRect(R);
+ FirstColumn := GetNextVisibleColumn(FirstColumn);
+ if FirstColumn <> InvalidColumn then
+ begin
+ R.Left := Items[FirstColumn].Left;
+ R.Right := R.Left + Items[FirstColumn].FWidth;
+ end;
+ end;
+ // Erase also the part of the tree not covert by a column.
+ if R.Right < TargetRect.Right + Target.X then
+ begin
+ R.Left := R.Right;
+ R.Right := TargetRect.Right + Target.X;
+ NodeBitmap.Canvas.Brush.Color := Color;
+ NodeBitmap.Canvas.FillRect(R);
+ end;
+ end;
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, 0, 0, nil);
+ end
+ else
+ begin
+ // No columns nor bitmap background. Simply erase it with the tree color.
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, 0, 0, nil);
+ NodeBitmap.Canvas.Brush.Color := Color;
+ NodeBitmap.Canvas.FillRect(TargetRect);
+ end;
+ end;
+ end;
+ SetWindowOrgEx(NodeBitmap.Canvas.Handle, 0, 0, nil);
+
+ if DrawSelectionRect then
+ begin
+ R := OrderRect(FNewSelRect);
+ // Remap the selection rectangle to the current window of the tree.
+ // Since Target has been used for other tasks BaseOffset got the left extent of the target position here.
+ OffsetRect(R, -Target.X + BaseOffset - Window.Left, -Target.Y);
+ SetBrushOrgEx(NodeBitmap.Canvas.Handle, 0, Target.X and 1, nil);
+ PaintSelectionRectangle(NodeBitmap.Canvas, 0, R, TargetRect);
+ end;
+ with Target, NodeBitmap do
+ BitBlt(TargetCanvas.Handle, X, Y, Width, Height, Canvas.Handle, 0, 0, SRCCOPY);
+ end;
+ finally
+ NodeBitmap.Canvas.Unlock;
+ NodeBitmap.Free;
+ end;
+ DoAfterPaint(TargetCanvas);
+ DoStateChange([], [tsPainting]);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.PasteFromClipboard: Boolean;
+
+// Reads what is currently on the clipboard into the tree (if the format is supported).
+// Note: If the application wants to have text or special formats to be inserted then it must implement
+// its own code (OLE). Here only the native tree format is accepted.
+
+var
+ Data: IDataObject;
+ Source: TBaseVirtualTree;
+
+begin
+ Result := False;
+ if not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ if OleGetClipboard(Data) <> S_OK then
+ ShowError(SClipboardFailed, hcTFClipboardFailed)
+ else
+ try
+ // Try to get the source tree of the operation to optimize the operation.
+ Source := GetTreeFromDataObject(Data);
+ Result := ProcessOLEData(Source, Data, FFocusedNode, FDefaultPasteMode, Assigned(Source) and
+ (tsCutPending in Source.FStates));
+ if Assigned(Source) and (Source <> Self) then
+ Source.FinishCutOrCopy;
+ finally
+ Data := nil;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.PrepareDragImage(Hotspot: TPoint; const DataObject: IDataObject);
+
+// Initiates an image drag operation. Hotspot is the position of the mouse in client coordinates.
+
+var
+ PaintOptions: TVTInternalPaintOptions;
+ TreeRect,
+ PaintRect: TRect;
+ LocalSpot,
+ ImagePos,
+ PaintTarget: TPoint;
+ Image: TBitmap;
+
+begin
+ if CanShowDragImage then
+ begin
+ // Determine the drag rectangle which is a square around the hot spot. Operate in virtual tree space.
+ LocalSpot := HotSpot;
+ Dec(LocalSpot.X, FOffsetX);
+ Dec(LocalSpot.Y, FOffsetY);
+ TreeRect := Rect(LocalSpot.X - FDragWidth div 2, LocalSpot.Y - FDragHeight div 2, LocalSpot.X + FDragWidth div 2,
+ LocalSpot.Y + FDragHeight div 2);
+
+ // Check that we have a valid rectangle.
+ with TreeRect do
+ begin
+ PaintRect := TreeRect;
+ if Left < 0 then
+ begin
+ PaintTarget.X := -Left;
+ PaintRect.Left := 0;
+ end
+ else
+ PaintTarget.X := 0;
+ if Top < 0 then
+ begin
+ PaintTarget.Y := -Top;
+ PaintRect.Top := 0;
+ end
+ else
+ PaintTarget.Y := 0;
+ end;
+
+ Image := TBitmap.Create;
+ with Image do
+ try
+ PixelFormat := pf32Bit;
+ Width := TreeRect.Right - TreeRect.Left;
+ Height := TreeRect.Bottom - TreeRect.Top;
+ // Erase the entire image with the color key value, for the case not everything
+ // in the image is covered by the tree image.
+ Canvas.Brush.Color := Color;
+ Canvas.FillRect(Rect(0, 0, Width, Height));
+
+ PaintOptions := [poDrawSelection, poSelectedOnly];
+ if FDragImageKind = diMainColumnOnly then
+ Include(PaintOptions, poMainOnly);
+ PaintTree(Image.Canvas, PaintRect, PaintTarget, PaintOptions);
+
+ // Once we have got the drag image we can convert all necessary coordinates into screen space.
+ OffsetRect(TreeRect, FOffsetX, FOffsetY);
+ ImagePos := ClientToScreen(TreeRect.TopLeft);
+ HotSpot := ClientToScreen(HotSpot);
+
+ FDragImage.ColorKey := Color;
+ FDragImage.PrepareDrag(Image, ImagePos, HotSpot, DataObject);
+ finally
+ Image.Free;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Print(Printer: TPrinter; PrintHeader: Boolean);
+
+var
+ SaveTreeFont: TFont; // Remembers the tree's current font.
+ SaveHeaderFont: TFont; // Remembers the header's current font.
+ ImgRect, // Describes the dimensions of Image.
+ TreeRect, // The total VTree dimensions.
+ DestRect, // Dimensions of PrinterImage.
+ SrcRect: TRect; // Clip dimensions from Image -> PrinterImage
+ P: TPoint; // Used by PaintTree.
+ Options: TVTInternalPaintOptions; // Used by PaintTree.
+ Image, // Complete Tree is drawn to this image.
+ PrinterImage: TBitmap; // This is the image that gets printed.
+ SaveColor: TColor; // Remembers the VTree Color.
+ pTxtHeight, // Height of font in the TPrinter.Canvas
+ vTxtHeight, // Height of font in the VTree Canvas
+ vPageWidth,
+ vPageHeight, // Printer height in VTree resolution
+ xPageNum, yPageNum, // # of pages (except the occasional last one)
+ xPage, yPage: Integer; // Loop counter
+ Scale: Extended; // Scale factor between Printer Canvas and VTree Canvas
+ LogFont: TLogFont;
+
+begin
+ if Assigned(Printer) then
+ begin
+ BeginUpdate;
+
+ // Grid lines are the only parts which are desirable when printing.
+ Options := [poGridLines];
+
+ // Remember the tree font.
+ SaveTreeFont := TFont.Create;
+ SaveTreeFont.Assign(Font);
+ // Create a new font for printing which does not use clear type output (but is antialiased, if possible)
+ // and which has the highest possible quality.
+ GetObject(Font.Handle, SizeOf(TLogFont), @LogFont);
+ LogFont.lfQuality := ANTIALIASED_QUALITY;
+ Font.Handle := CreateFontIndirect(LogFont);
+
+ // Create an image that will hold the complete VTree
+ Image := TBitmap.Create;
+ Image.PixelFormat := pf32Bit;
+ PrinterImage := nil;
+ try
+ TreeRect := GetTreeRect;
+
+ Image.Width := TreeRect.Right - TreeRect.Left;
+ P := Point(0, 0);
+ if (hoVisible in FHeader.Options) and PrintHeader then
+ begin
+ Inc(TreeRect.Bottom, FHeader.Height);
+ Inc(P.Y, FHeader.Height);
+ end;
+ Image.Height := TreeRect.Bottom - TreeRect.Top;
+
+ ImgRect.Left := 0;
+ ImgRect.Top := 0;
+ ImgRect.Right := Image.Width;
+
+ // Force the background to white color during the rendering.
+ SaveColor := Color;
+ Color := clWhite;
+ // Print header if it is visible.
+ if (hoVisible in FHeader.Options) and PrintHeader then
+ begin
+ SaveHeaderFont := TFont.Create;
+ try
+ SaveHeaderFont.Assign(FHeader.Font);
+ // Create a new font for printing which does not use clear type output (but is antialiased, if possible)
+ // and which has the highest possible quality.
+ GetObject(FHeader.Font.Handle, SizeOf(TLogFont), @LogFont);
+ LogFont.lfQuality := ANTIALIASED_QUALITY;
+ FHeader.Font.Handle := CreateFontIndirect(LogFont);
+ ImgRect.Bottom := FHeader.Height;
+ FHeader.FColumns.PaintHeader(Image.Canvas.Handle, ImgRect, 0);
+ FHeader.Font := SaveHeaderFont;
+ finally
+ SaveHeaderFont.Free;
+ end;
+ end;
+ // The image's height is already adjusted for the header if it is visible.
+ ImgRect.Bottom := Image.Height;
+
+ PaintTree(Image.Canvas, ImgRect, P, Options);
+ Color := SaveColor;
+
+ // Activate the printer
+ Printer.BeginDoc;
+ Printer.Canvas.Font := Font;
+
+ // Now we can calculate the scaling :
+ pTxtHeight := Printer.Canvas.TextHeight('Tj');
+ vTxtHeight := Canvas.TextHeight('Tj');
+
+ Scale := pTxtHeight / vTxtHeight;
+
+ // Create an Image that has the same dimensions as the printer canvas but
+ // scaled to the VTree resolution:
+ PrinterImage := TBitmap.Create;
+
+ vPageHeight := Round(Printer.PageHeight / Scale);
+ vPageWidth := Round(Printer.PageWidth / Scale);
+
+ // We do a minumum of one page.
+ xPageNum := Trunc(Image.Width / vPageWidth);
+ yPageNum := Trunc(Image.Height / vPageHeight);
+
+ PrinterImage.Width := vPageWidth;
+ PrinterImage.Height := vPageHeight;
+
+ // Split vertically:
+ for yPage := 0 to yPageNum do
+ begin
+ DestRect.Left := 0;
+ DestRect.Top := 0;
+ DestRect.Right := PrinterImage.Width;
+ DestRect.Bottom := PrinterImage.Height;
+
+ // Split horizontally:
+ for xPage := 0 to xPageNum do
+ begin
+ SrcRect.Left := vPageWidth * xPage;
+ SrcRect.Top := vPageHeight * yPage;
+ SrcRect.Right := vPageWidth * xPage + PrinterImage.Width;
+ SrcRect.Bottom := SrcRect.Top + vPageHeight;
+
+ // Clear the image
+ PrinterImage.Canvas.Brush.Color := clWhite;
+ PrinterImage.Canvas.FillRect(Rect(0, 0, PrinterImage.Width, PrinterImage.Height));
+ PrinterImage.Canvas.CopyRect(DestRect, Image.Canvas, SrcRect);
+ PrtStretchDrawDIB(Printer.Canvas, Rect(0, 0, Printer.PageWidth, Printer.PageHeight - 1), PrinterImage);
+ if xPage <> xPageNum then
+ Printer.NewPage;
+ end;
+ if yPage <> yPageNum then
+ Printer.NewPage;
+ end;
+
+ // Restore tree font.
+ Font := SaveTreeFont;
+ SaveTreeFont.Free;
+ Printer.EndDoc;
+ finally
+ PrinterImage.Free;
+ Image.Free;
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ProcessDrop(DataObject: IDataObject; TargetNode: PVirtualNode; var Effect: Integer;
+ Mode: TVTNodeAttachMode): Boolean;
+
+// Recreates the (sub) tree structure serialized into memory and provided by DataObject. The new nodes are attached to
+// the passed node or FRoot if TargetNode is nil.
+// Returns True on success, i.e. the CF_VIRTUALTREE format is supported by the data object and the structure could be
+// recreated, otherwise False.
+
+var
+ Source: TBaseVirtualTree;
+
+begin
+ Result := False;
+ if Mode = amNoWhere then
+ Effect := DROPEFFECT_NONE
+ else
+ begin
+ BeginUpdate;
+ // try to get the source tree of the operation
+ Source := GetTreeFromDataObject(DataObject);
+ if Assigned(Source) then
+ Source.BeginUpdate;
+ try
+ try
+ // Before adding the new nodes try to optimize the operation if source and target tree reside in
+ // the same application and operation is a move.
+ if ((Effect and DROPEFFECT_MOVE) <> 0) and Assigned(Source) then
+ begin
+ // If both copy and move are specified then prefer a copy because this is not destructing.
+ Result := ProcessOLEData(Source, DataObject, TargetNode, Mode, (Effect and DROPEFFECT_COPY) = 0);
+ // Since we made an optimized move or a copy there's no reason to act further after DoDragging returns.
+ Effect := DROPEFFECT_NONE;
+ end
+ else
+ // Act only if move or copy operation is requested.
+ if (Effect and (DROPEFFECT_MOVE or DROPEFFECT_COPY)) <> 0 then
+ Result := ProcessOLEData(Source, DataObject, TargetNode, Mode, False)
+ else
+ Result := False;
+ except
+ Effect := DROPEFFECT_NONE;
+ end;
+ finally
+ if Assigned(Source) then
+ Source.EndUpdate;
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ // needed to handle OLE global memory objects
+ TOLEMemoryStream = class(TCustomMemoryStream)
+ public
+ function Write(const Buffer; Count: Integer): Longint; override;
+ end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TOLEMemoryStream.Write(const Buffer; Count: Integer): Integer;
+
+begin
+ {$ifdef COMPILER_5_UP}
+ raise EStreamError.CreateRes(PResStringRec(@SCantWriteResourceStreamError));
+ {$else}
+ raise EStreamError.Create(SCantWriteResourceStreamError);
+ {$endif COMPILER_5_UP}
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ProcessOLEData(Source: TBaseVirtualTree; DataObject: IDataObject; TargetNode: PVirtualNode;
+ Mode: TVTNodeAttachMode; Optimized: Boolean): Boolean;
+
+// Recreates the (sub) tree structure serialized into memory and provided by DataObject. The new nodes are attached to
+// the passed node or FRoot if TargetNode is nil according to Mode. Optimized can be set to True if the entire operation
+// happens within the same process (i.e. sender and receiver of the OLE operation are located in the same process).
+// Optimize = True makes only sense if the operation to carry out is a move hence it is also the indication of the
+// operation to be done here. Source is the source of the OLE data and only of use (and usually assigned) when
+// an OLE operation takes place in the same application.
+// Returns True on success, i.e. the CF_VIRTUALTREE format is supported by the data object and the structure could be
+// recreated, otherwise False.
+
+var
+ Medium: TStgMedium;
+ Stream: TStream;
+ Data: Pointer;
+ Node: PVirtualNode;
+ Nodes: TNodeArray;
+ I: Integer;
+ Res: HRESULT;
+ ChangeReason: TChangeReason;
+
+begin
+ Nodes := nil;
+ // Check the data format available by the data object.
+ with StandardOLEFormat do
+ begin
+ // Read best format.
+ cfFormat := CF_VIRTUALTREE;
+ end;
+ Result := DataObject.QueryGetData(StandardOLEFormat) = S_OK;
+ if Result and not (toReadOnly in FOptions.FMiscOptions) then
+ begin
+ BeginUpdate;
+ Result := False;
+ try
+ if TargetNode = nil then
+ TargetNode := FRoot;
+ if TargetNode = FRoot then
+ begin
+ case Mode of
+ amInsertBefore:
+ Mode := amAddChildFirst;
+ amInsertAfter:
+ Mode := amAddChildLast;
+ end;
+ end;
+
+ // Optimized means source is known and in the same process so we can access its pointers, which avoids duplicating
+ // the data while doing a serialization. Can only be used with cut'n paste and drag'n drop with move effect.
+ if Optimized then
+ begin
+ if tsOLEDragging in Source.FStates then
+ Nodes := Source.FDragSelection
+ else
+ Nodes := Source.GetSortedCutCopySet(True);
+
+ if Mode in [amInsertBefore,amAddChildLast] then
+ begin
+ for I := 0 to High(Nodes) do
+ if not HasAsParent(TargetNode, Nodes[I]) then
+ Source.MoveTo(Nodes[I], TargetNode, Mode, False);
+ end
+ else
+ begin
+ for I := High(Nodes) downto 0 do
+ if not HasAsParent(TargetNode, Nodes[I]) then
+ Source.MoveTo(Nodes[I], TargetNode, Mode, False);
+ end;
+ Result := True;
+ end
+ else
+ begin
+ if Source = Self then
+ ChangeReason := crNodeCopied
+ else
+ ChangeReason := crNodeAdded;
+ Res := DataObject.GetData(StandardOLEFormat, Medium);
+ if Res = S_OK then
+ begin
+ case Medium.tymed of
+ TYMED_ISTREAM, // IStream interface
+ TYMED_HGLOBAL: // global memory block
+ begin
+ Stream := nil;
+ if Medium.tymed = TYMED_ISTREAM then
+ Stream := TOLEStream.Create(IUnknown(Medium.stm) as IStream)
+ else
+ begin
+ Data := GlobalLock(Medium.hGlobal);
+ if Assigned(Data) then
+ begin
+ // Get the total size of data to retrieve.
+ I := PCardinal(Data)^;
+ Inc(PCardinal(Data));
+ Stream := TOLEMemoryStream.Create;
+ TOLEMemoryStream(Stream).SetPointer(Data, I);
+ end;
+ end;
+
+ if Assigned(Stream) then
+ try
+ while Stream.Position < Stream.Size do
+ begin
+ Node := MakeNewNode;
+ InternalConnectNode(Node, TargetNode, Self, Mode);
+ InternalAddFromStream(Stream, VTTreeStreamVersion, Node);
+ // This seems a bit strange because of the callback for granting to add the node
+ // which actually comes after the node has been added. The reason is that the node must
+ // contain valid data otherwise I don't see how the application can make a funded decision.
+ if not DoNodeCopying(Node, TargetNode) then
+ DeleteNode(Node)
+ else
+ DoNodeCopied(Node);
+ StructureChange(Node, ChangeReason);
+ end;
+ Result := True;
+ finally
+ Stream.Free;
+ if Medium.tymed = TYMED_HGLOBAL then
+ GlobalUnlock(Medium.hGlobal);
+ end;
+ end;
+ end;
+ ReleaseStgMedium(Medium);
+ end;
+ end;
+ finally
+ EndUpdate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ReinitChildren(Node: PVirtualNode; Recursive: Boolean);
+
+// Forces all child nodes of Node to be reinitialized.
+// If Recursive is True then also the grandchildren are reinitialized.
+
+var
+ Run: PVirtualNode;
+
+begin
+ if Assigned(Node) then
+ begin
+ InitChildren(Node);
+ Run := Node.FirstChild;
+ end
+ else
+ begin
+ InitChildren(FRoot);
+ Run := FRoot.FirstChild;
+ end;
+
+ while Assigned(Run) do
+ begin
+ ReinitNode(Run, recursive);
+ Run := Run.NextSibling;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ReinitNode(Node: PVirtualNode; Recursive: Boolean);
+
+// Forces the given node and all its children (if recursive is True) to be initialized again without
+// modifying any data in the nodes nor deleting children (unless the application requests a different amount).
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ // remove dynamic styles
+ Node.States := Node.States - [vsChecking, vsCutOrCopy, vsDeleting];
+ InitNode(Node);
+ end;
+
+ if Recursive then
+ ReinitChildren(Node, True);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.RepaintNode(Node: PVirtualNode);
+
+// Causes an immediate repaint of the given node.
+
+var
+ R: Trect;
+
+begin
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ R := GetDisplayRect(Node, -1, False);
+ RedrawWindow(Handle, @R, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE or RDW_VALIDATE or RDW_NOCHILDREN);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ResetNode(Node: PVirtualNode);
+
+// Deletes all children of the given node and marks it as being uninitialized.
+
+begin
+ DoCancelEdit;
+ if (Node = nil) or (Node = FRoot) then
+ Clear
+ else
+ begin
+ DoReset(Node);
+ DeleteChildren(Node);
+ // Remove initialized and other dynamic styles, keep persistent styles.
+ Node.States := Node.States - [vsInitialized, vsChecking, vsCutOrCopy, vsDeleting, vsHasChildren, vsExpanded];
+ InvalidateNode(Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SaveToFile(const FileName: TFileName);
+
+// Saves the entire content of the tree into a file (see further notes in SaveToStream).
+
+var
+ FileStream: TFileStream;
+
+begin
+ FileStream := TFileStream.Create(FileName, fmCreate);
+ try
+ SaveToStream(FileStream);
+ finally
+ FileStream.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SaveToStream(Stream: TStream; Node: PVirtualNode = nil);
+
+// Saves Node and all its children to Stream. If Node is nil then all top level nodes will be stored.
+// Note: You should be careful about assuming what is actually saved. The problem here is that we are dealing with
+// virtual data. The tree can so not know what it has to save. The only fact we reliably know is the tree's
+// structure. To be flexible for future enhancements as well as unknown content (unknown to the tree class which
+// is saving/loading the stream) a chunk based approach is used here. Every tree class handles only those
+// chunks which are not handled by an anchestor class and are known by the class.
+//
+// The base tree class saves only the structure of the tree along with application provided data. Descentants may
+// optionally add their own chunks to store additional information. See: WriteChunks.
+
+var
+ Count: Cardinal;
+
+begin
+ Stream.Write(MagicID, SizeOf(MagicID));
+ if Node = nil then
+ begin
+ // Keep number of top level nodes for easy restauration.
+ Count := FRoot.ChildCount;
+ Stream.WriteBuffer(Count, SizeOf(Count));
+
+ // Save entire tree here.
+ Node := FRoot.FirstChild;
+ while Assigned(Node) do
+ begin
+ WriteNode(Stream, Node);
+ Node := Node.NextSibling;
+ end;
+ end
+ else
+ begin
+ Count := 1;
+ Stream.WriteBuffer(Count, SizeOf(Count));
+ WriteNode(Stream, Node);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.ScrollIntoView(Node: PVirtualNode; Center: Boolean; Horizontally: Boolean = False): Boolean;
+
+// Scrolls the tree so that the given node is in the client area and returns True if the tree really has been
+// scrolled (e.g. to avoid further updates) else returns False. If extened focus is enabled then the tree will also
+// be horizontally scrolled if needed.
+// Note: All collapsed parents of the node are expanded.
+
+var
+ MidPoint: Integer;
+ R: TRect;
+ Run: PVirtualNode;
+ UseColumns,
+ HScrollBarVisible: Boolean;
+
+begin
+ Result := False;
+ if Assigned(Node) and (Node <> FRoot) then
+ begin
+ // Make sure all parents of the node are expanded.
+ Run := Node.Parent;
+ while Run <> FRoot do
+ begin
+ if not (vsExpanded in Run.States) then
+ ToggleNode(Run);
+ Run := Run.Parent;
+ end;
+ UseColumns := FHeader.UseColumns;
+ if UseColumns then
+ R := GetDisplayRect(Node, FFocusedColumn, not (toGridExtensions in FOptions.FMiscOptions))
+ else
+ R := GetDisplayRect(Node, NoColumn, not (toGridExtensions in FOptions.FMiscOptions));
+
+ // The returned rectangle can never be empty after the expand code above.
+ // 1) scroll vertically
+ if R.Top < 0 then
+ begin
+ if Center then
+ SetOffsetY(FOffsetY - R.Top + ClientHeight div 2)
+ else
+ SetOffsetY(FOffsetY - R.Top);
+ Result := True;
+ end
+ else
+ if (R.Bottom > ClientHeight) or Center then
+ begin
+ HScrollBarVisible := (ScrollBarOptions.ScrollBars in [ssBoth, ssHorizontal]) and
+ (ScrollBarOptions.AlwaysVisible or (Integer(FRangeX) > ClientWidth));
+ if Center then
+ SetOffsetY(FOffsetY - R.Bottom + ClientHeight div 2)
+ else
+ SetOffsetY(FOffsetY - R.Bottom + ClientHeight);
+ // When scrolling up and the horizontal scroll appears because of the operation
+ // then we have to move up the node the horizontal scrollbar's height too
+ // in order to avoid that the scroll bar hides the node which we wanted to have in view.
+ if not UseColumns and not HScrollBarVisible and (Integer(FRangeX) > ClientWidth) then
+ SetOffsetY(FOffsetY - GetSystemMetrics(SM_CYHSCROLL));
+ Result := True;
+ end;
+
+ if Horizontally then
+ begin
+ // 2) scroll horizontally
+ if (R.Right > ClientWidth) or (R.Left < 0) then
+ begin
+ MidPoint := -FOffsetX + (R.Left + R.Right) div 2;
+ SetOffsetX((ClientWidth div 2) - MidPoint);
+ Result := True;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SelectAll(VisibleOnly: Boolean);
+
+// Select all nodes in the tree.
+// If VisibleOnly is True then only visible nodes are selected.
+
+var
+ Run: PVirtualNode;
+ NextFunction: function(Node: PVirtualNode): PVirtualNode of object;
+
+begin
+ if toMultiSelect in FOptions.FSelectionOptions then
+ begin
+ ClearTempCache;
+ if VisibleOnly then
+ begin
+ Run := GetFirstVisible;
+ NextFunction := GetNextVisible;
+ end
+ else
+ begin
+ Run := GetFirst;
+ NextFunction := GetNext;
+ end;
+
+ while Assigned(Run) do
+ begin
+ if not(vsSelected in Run.States) then
+ InternalCacheNode(Run);
+ Run := NextFunction(Run);
+ end;
+ if FTempNodeCount > 0 then
+ AddToSelection(FTempNodeCache, FTempNodeCount);
+ ClearTempCache;
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.Sort(Node: PVirtualNode; Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True);
+
+// Sorts the given node. The application is queried about how to sort via the OnCompareNodes event.
+// Column is simply passed to the the compare function so the application can also sort in a particular column.
+// In order to free the application from taking care about the sort direction the parameter Direction is used.
+// This way the application can always sort in increasing order, while this method reorders nodes according to this flag.
+
+ //--------------- local functions -------------------------------------------
+
+ function MergeAscending(A, B: PVirtualNode): PVirtualNode;
+
+ // Merges A and B (which both must be sorted via Compare) into one list.
+
+ var
+ Dummy: TVirtualNode;
+
+ begin
+ // This avoids checking for Result = nil in the loops.
+ Result := @Dummy;
+ while Assigned(A) and Assigned(B) do
+ begin
+ if DoCompare(A, B, Column) <= 0 then
+ begin
+ Result.NextSibling := A;
+ Result := A;
+ A := A.NextSibling;
+ end
+ else
+ begin
+ Result.NextSibling := B;
+ Result := B;
+ B := B.NextSibling;
+ end;
+ end;
+
+ // Just append the list which is not nil (or set end of result list to nil if both lists are nil).
+ if Assigned(A) then
+ Result.NextSibling := A
+ else
+ Result.NextSibling := B;
+ // return start of the new merged list
+ Result := Dummy.NextSibling;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function MergeDescending(A, B: PVirtualNode): PVirtualNode;
+
+ // Merges A and B (which both must be sorted via Compare) into one list.
+
+ var
+ Dummy: TVirtualNode;
+
+ begin
+ // this avoids checking for Result = nil in the loops
+ Result := @Dummy;
+ while Assigned(A) and Assigned(B) do
+ begin
+ if DoCompare(A, B, Column) >= 0 then
+ begin
+ Result.NextSibling := A;
+ Result := A;
+ A := A.NextSibling;
+ end
+ else
+ begin
+ Result.NextSibling := B;
+ Result := B;
+ B := B.NextSibling;
+ end;
+ end;
+
+ // Just append the list which is not nil (or set end of result list to nil if both lists are nil).
+ if Assigned(A) then
+ Result.NextSibling := A
+ else
+ Result.NextSibling := B;
+ // Return start of the newly merged list.
+ Result := Dummy.NextSibling;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function MergeSortAscending(var Node: PVirtualNode; N: Cardinal): PVirtualNode;
+
+ // Sorts the list of nodes given by Node (which must not be nil).
+
+ var
+ A, B: PVirtualNode;
+
+ begin
+ if N > 1 then
+ begin
+ A := MergeSortAscending(Node, N div 2);
+ B := MergeSortAscending(Node, (N + 1) div 2);
+ Result := MergeAscending(A, B);
+ end
+ else
+ begin
+ Result := Node;
+ Node := Node.NextSibling;
+ Result.NextSibling := nil;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function MergeSortDescending(var Node: PVirtualNode; N: Cardinal): PVirtualNode;
+
+ // Sorts the list of nodes given by Node (which must not be nil).
+
+ var
+ A, B: PVirtualNode;
+
+ begin
+ if N > 1 then
+ begin
+ A := MergeSortDescending(Node, N div 2);
+ B := MergeSortDescending(Node, (N + 1) div 2);
+ Result := MergeDescending(A, B);
+ end
+ else
+ begin
+ Result := Node;
+ Node := Node.NextSibling;
+ Result.NextSibling := nil;
+ end;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ Run: PVirtualNode;
+ Index: Cardinal;
+
+begin
+ InterruptValidation;
+ if tsEditPending in FStates then
+ begin
+ StopTimer(EditTimer);
+ DoStateChange([], [tsEditPending]);
+ end;
+
+ if not (tsEditing in FStates) or DoEndEdit then
+ begin
+ if Node = nil then
+ Node := FRoot;
+ if vsHasChildren in Node.States then
+ begin
+ if (Node.ChildCount = 0) and DoInit then
+ InitChildren(Node);
+ // Make sure the children are valid, so they can be sorted at all.
+ if DoInit and (Node.ChildCount > 1) then
+ ValidateChildren(Node, False);
+ // Child count might have changed.
+ if Node.ChildCount > 1 then
+ begin
+ // Sort the linked list, check direction flag only once.
+ if Direction = sdAscending then
+ Node.FirstChild := MergeSortAscending(Node.FirstChild, Node.ChildCount)
+ else
+ Node.FirstChild := MergeSortDescending(Node.FirstChild, Node.ChildCount);
+ // Consolidate the child list finally.
+ Run := Node.FirstChild;
+ Run.PrevSibling := nil;
+ Index := 0;
+ repeat
+ Run.Index := Index;
+ Inc(Index);
+ if Run.NextSibling = nil then
+ Break;
+ Run.NextSibling.PrevSibling := Run;
+ Run := Run.NextSibling;
+ until False;
+ Node.LastChild := Run;
+
+ InvalidateCache;
+ end;
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ Invalidate;
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.SortTree(Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True);
+
+ //--------------- local function --------------------------------------------
+
+ procedure DoSort(Node: PVirtualNode);
+
+ // Recursively sorts Node and its child nodes.
+
+ var
+ Run: PVirtualNode;
+
+ begin
+ Sort(Node, Column, Direction, DoInit);
+
+ Run := Node.FirstChild;
+ while Assigned(Run) do
+ begin
+ if DoInit and not (vsInitialized in Run.States) then
+ InitNode(Run);
+ if vsInitialized in Run.States then
+ DoSort(Run);
+ Run := Run.NextSibling;
+ end;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+begin
+ // Instead of wrapping the sort using BeginUpdate/EndUpdate simply the update counter
+ // is modified. Otherwise the EndUpdate call will recurse here.
+ Inc(FUpdateCount);
+ try
+ if Column > InvalidColumn then
+ DoSort(FRoot);
+ InvalidateCache;
+ finally
+ if FUpdateCount > 0 then
+ Dec(FUpdateCount);
+ if FUpdateCount = 0 then
+ begin
+ ValidateCache;
+ Invalidate;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ToggleNode(Node: PVirtualNode);
+
+// Changes a node's expand state to the opposite state.
+
+var
+ LastTopNode,
+ Child: PVirtualNode;
+ NewHeight: Integer;
+ NeedUpdate: Boolean;
+ ToggleData: TToggleAnimationData;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+ NeedUpdate := False;
+
+ // We don't need to switch the expand state if the node is being deleted otherwise some
+ // updates (e.g. visible node count) are done twice with disasterous results).
+ if not (vsDeleting in Node.States) then
+ begin
+ // LastTopNode is needed to know when the entire tree scrolled during toggling.
+ // It is of course only needed when we also update the display here.
+ if FUpdateCount = 0 then
+ LastTopNode := GetTopNode
+ else
+ LastTopNode := nil;
+
+ if vsExpanded in Node.States then
+ begin
+ if DoCollapsing(Node) then
+ begin
+ NeedUpdate := True;
+
+ if (FUpdateCount = 0) and (toAnimatedToggle in FOptions.FAnimationOptions) and not (tsCollapsing in FStates) then
+ begin
+ Application.CancelHint;
+ UpdateWindow(Handle);
+
+ // animated collapsing
+ with ToggleData do
+ begin
+ Expand := False;
+ R := GetDisplayRect(Node, NoColumn, False);
+ R.Bottom := ClientHeight;
+ Inc(R.Top, Node.NodeHeight);
+ Window := Handle;
+ DC := GetDC(Handle);
+ Self.Brush.Color := Color;
+ Brush := Self.Brush.Handle;
+ try
+ Animate(Min(R.Bottom - R.Top + 1, Node.TotalHeight - Node.NodeHeight), FAnimationDuration, ToggleCallback,
+ @ToggleData);
+ finally
+ ReleaseDC(Window, DC);
+ end;
+ end;
+ end;
+
+ // collapse the node
+ AdjustTotalHeight(Node, Node.NodeHeight);
+ if FullyVisible[Node] then
+ Dec(FVisibleCount, CountVisibleChildren(Node));
+ Exclude(Node.States, vsExpanded);
+ DoCollapsed(Node);
+
+ // Remove child nodes now, if enabled.
+ if (toAutoFreeOnCollapse in FOptions.FAutoOptions) and (Node.ChildCount > 0) then
+ begin
+ DeleteChildren(Node);
+ Include(Node.States, vsHasChildren);
+ end;
+ end;
+ end
+ else
+ if DoExpanding(Node) then
+ begin
+ NeedUpdate := True;
+ // expand the node, need to adjust the height
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+
+ // Avoid setting the vsExpanded style if there are no child nodes.
+ if Node.ChildCount > 0 then
+ begin
+ // Iterate through the child nodes without initializing them. We have to determine the entire height.
+ NewHeight := 0;
+ Child := Node.FirstChild;
+ repeat
+ if vsVisible in Child.States then
+ Inc(NewHeight, Child.TotalHeight);
+ Child := Child.NextSibling;
+ until Child = nil;
+
+ if FUpdateCount = 0 then
+ begin
+ ToggleData.R := GetDisplayRect(Node, NoColumn, False);
+
+ // Do animated expanding if enabled and it is not the last visible node to be expanded.
+ if (ToggleData.R.Top < ClientHeight) and ([tsPainting, tsExpanding] * FStates = []) and
+ (toAnimatedToggle in FOptions.FAnimationOptions) and (GetNextVisibleNoInit(Node) <> nil) then
+ begin
+ Application.CancelHint;
+ UpdateWindow(Handle);
+ // animated expanding
+ with ToggleData do
+ begin
+ Inc(R.Top, Node.NodeHeight);
+ R.Bottom := ClientHeight;
+ if R.Bottom > R.Top then
+ begin
+ Expand := True;
+ Window := Handle;
+ DC := GetDC(Handle);
+
+ Self.Brush.Color := Color;
+ Brush := Self.Brush.Handle;
+ try
+ Animate(Min(R.Bottom - R.Top + 1, NewHeight), FAnimationDuration, ToggleCallback, @ToggleData);
+ finally
+ ReleaseDC(Window, DC);
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ Include(Node.States, vsExpanded);
+ AdjustTotalHeight(Node, NewHeight, True);
+ if FullyVisible[Node] then
+ Inc(FVisibleCount, CountVisibleChildren(Node));
+
+ DoExpanded(Node);
+ end;
+ end;
+
+ if NeedUpdate then
+ begin
+ InvalidateCache;
+ if FUpdateCount = 0 then
+ if Node.ChildCount > 0 then
+ begin
+ ValidateCache;
+ UpdateScrollbars(True);
+ // Scroll as much child nodes into view as possible if the node has been expanded.
+ if (toAutoScrollOnExpand in FOptions.FAutoOptions) and (vsExpanded in Node.States) then
+ begin
+ if Integer(Node.TotalHeight) <= ClientHeight then
+ ScrollIntoView(GetLastChild(Node), toCenterScrollIntoView in FOptions.SelectionOptions)
+ else
+ TopNode := Node;
+ end;
+
+ // Check for automatically scrolled tree.
+ if LastTopNode <> GetTopNode then
+ Invalidate
+ else
+ InvalidateToBottom(Node);
+ end
+ else
+ InvalidateNode(Node);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.UpdateAction(Action: TBasicAction): Boolean;
+
+// Support for standard actions.
+
+begin
+ if not Focused then
+ Result := inherited UpdateAction(Action)
+ else
+ begin
+ Result := (Action is TEditCut) or (Action is TEditCopy)
+ {$ifdef COMPILER_5_UP} or (Action is TEditDelete) {$endif COMPILER_5_UP};
+
+ if Result then
+ TAction(Action).Enabled := (FSelectionCount > 0) and
+ ({$ifdef COMPILER_5_UP} (Action is TEditDelete) or {$endif COMPILER_5_UP} (FClipboardFormats.Count > 0))
+ else
+ begin
+ Result := Action is TEditPaste;
+ if Result then
+ TAction(Action).Enabled := True
+ else
+ begin
+ {$ifdef COMPILER_5_UP}
+ Result := Action is TEditSelectAll;
+ if Result then
+ TAction(Action).Enabled := (toMultiSelect in FOptions.FSelectionOptions) and (FVisibleCount > 0)
+ else
+ {$endif COMPILER_5_UP}
+ Result := inherited UpdateAction(Action);
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateHorizontalScrollBar(DoRepaint: Boolean);
+
+var
+ ScrollInfo: TScrollInfo;
+
+begin
+ if FHeader.UseColumns then
+ FRangeX := FHeader.FColumns.TotalWidth
+ else
+ FRangeX := GetMaxRightExtend;
+
+ if FScrollBarOptions.ScrollBars in [ssHorizontal, ssBoth] then
+ begin
+ FillChar(ScrollInfo, SizeOf(ScrollInfo), 0);
+ ScrollInfo.cbSize := SizeOf(ScrollInfo);
+ ScrollInfo.fMask := SIF_ALL;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_GetScrollInfo(Handle, SB_HORZ, ScrollInfo);
+ {$else}
+ GetScrollInfo(Handle, SB_HORZ, ScrollInfo);
+ {$endif UseFlatScrollbars}
+
+ if (Integer(FRangeX) > ClientWidth) or FScrollBarOptions.AlwaysVisible then
+ begin
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_HORZ, True);
+ {$else}
+ ShowScrollBar(Handle, SB_HORZ, True);
+ {$endif UseFlatScrollbars}
+
+ ScrollInfo.nMin := 0;
+ ScrollInfo.nMax := FRangeX;
+ ScrollInfo.nPos := -FOffsetX;
+ ScrollInfo.nPage := Max(0, ClientWidth + 1);
+
+ ScrollInfo.fMask := SIF_ALL or ScrollMasks[FScrollBarOptions.AlwaysVisible];
+ {$ifdef UseFlatScrollbars}
+ FlatSB_SetScrollInfo(Handle, SB_HORZ, ScrollInfo, DoRepaint);
+ {$else}
+ SetScrollInfo(Handle, SB_HORZ, ScrollInfo, DoRepaint);
+ {$endif UseFlatScrollbars}
+ end
+ else
+ begin
+ ScrollInfo.nMin := 0;
+ ScrollInfo.nMax := 0;
+ ScrollInfo.nPos := 0;
+ ScrollInfo.nPage := 0;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_HORZ, False);
+ FlatSB_SetScrollInfo(Handle, SB_HORZ, ScrollInfo, False);
+ {$else}
+ ShowScrollBar(Handle, SB_HORZ, False);
+ SetScrollInfo(Handle, SB_HORZ, ScrollInfo, False);
+ {$endif UseFlatScrollbars}
+ end;
+
+ // Since the position is automatically changed if it doesn't meet the range
+ // we better read the current position back to stay synchronized.
+ {$ifdef UseFlatScrollbars}
+ SetOffsetX(-FlatSB_GetScrollPos(Handle, SB_HORZ));
+ {$else}
+ SetOffsetX(-GetScrollPos(Handle, SB_HORZ));
+ {$endif UseFlatScrollbars}
+ end
+ else
+ begin
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_HORZ, False);
+ {$else}
+ ShowScrollBar(Handle, SB_HORZ, False);
+ {$endif UseFlatScrollbars}
+
+ // Reset the current horizontal offset to account for window resize etc.
+ SetOffsetX(FOffsetX);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateScrollBars(DoRepaint: Boolean);
+
+// adjusts scrollbars to reflect current size and paint offset of the tree
+
+begin
+ if HandleAllocated then
+ begin
+ UpdateHorizontalScrollBar(DoRepaint);
+ UpdateVerticalScrollBar(DoRepaint);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.UpdateVerticalScrollBar(DoRepaint: Boolean);
+
+var
+ ScrollInfo: TScrollInfo;
+
+begin
+ // total node height includes the height of the invisble root node
+ if FRoot.TotalHeight < FDefaultNodeHeight then
+ FRoot.TotalHeight := FDefaultNodeHeight;
+ FRangeY := FRoot.TotalHeight - FRoot.NodeHeight;
+
+ if FScrollBarOptions.ScrollBars in [ssVertical, ssBoth] then
+ begin
+ ScrollInfo.cbSize := SizeOf(ScrollInfo);
+ ScrollInfo.fMask := SIF_ALL;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_GetScrollInfo(Handle, SB_VERT, ScrollInfo);
+ {$else}
+ GetScrollInfo(Handle, SB_VERT, ScrollInfo);
+ {$endif UseFlatScrollbars}
+
+ if (Integer(FRangeY) > ClientHeight) or FScrollBarOptions.AlwaysVisible then
+ begin
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_VERT, True);
+ {$else}
+ ShowScrollBar(Handle, SB_VERT, True);
+ {$endif UseFlatScrollbars}
+
+ ScrollInfo.nMin := 0;
+ ScrollInfo.nMax := FRangeY;
+ ScrollInfo.nPos := -FOffsetY;
+ ScrollInfo.nPage := Max(0, ClientHeight + 1);
+
+ ScrollInfo.fMask := SIF_ALL or ScrollMasks[FScrollBarOptions.AlwaysVisible];
+ {$ifdef UseFlatScrollbars}
+ FlatSB_SetScrollInfo(Handle, SB_VERT, ScrollInfo, DoRepaint);
+ {$else}
+ SetScrollInfo(Handle, SB_VERT, ScrollInfo, DoRepaint);
+ {$endif UseFlatScrollbars}
+ end
+ else
+ begin
+ ScrollInfo.nMin := 0;
+ ScrollInfo.nMax := 0;
+ ScrollInfo.nPos := 0;
+ ScrollInfo.nPage := 0;
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_VERT, False);
+ FlatSB_SetScrollInfo(Handle, SB_VERT, ScrollInfo, False);
+ {$else}
+ ShowScrollBar(Handle, SB_VERT, False);
+ SetScrollInfo(Handle, SB_VERT, ScrollInfo, False);
+ {$endif UseFlatScrollbars}
+ end;
+
+ // Since the position is automatically changed if it doesn't meet the range
+ // we better read the current position back to stay synchronized.
+ {$ifdef UseFlatScrollbars}
+ SetOffsetY(-FlatSB_GetScrollPos(Handle, SB_VERT));
+ {$else}
+ SetOffsetY(-GetScrollPos(Handle, SB_VERT));
+ {$endif UseFlatScrollBars}
+ end
+ else
+ begin
+ {$ifdef UseFlatScrollbars}
+ FlatSB_ShowScrollBar(Handle, SB_VERT, False);
+ {$else}
+ ShowScrollBar(Handle, SB_VERT, False);
+ {$endif UseFlatScrollbars}
+
+ // Reset the current vertical offset to account for window resize etc.
+ SetOffsetY(FOffsetY);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TBaseVirtualTree.UseRightToLeftReading: Boolean;
+
+// The tree can handle right-to-left reading also on non-middle-east systems, so we cannot use the same function as
+// it is implemented in TControl.
+
+begin
+ Result := BiDiMode <> bdLeftToRight;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ValidateChildren(Node: PVirtualNode; Recursive: Boolean);
+
+// Ensures that the children of the given node (and all their children, if Recursive is True) are initialized.
+// Node must already be initialized
+
+var
+ Child: PVirtualNode;
+
+begin
+ if Node = nil then
+ Node := FRoot;
+
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+ Child := Node.FirstChild;
+ while Assigned(Child) do
+ begin
+ ValidateNode(Child, Recursive);
+ Child := Child.NextSibling;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TBaseVirtualTree.ValidateNode(Node: PVirtualNode; Recursive: Boolean);
+
+// Ensures that the given node (and all its children, if Recursive is True) are initialized.
+
+var
+ Child: PVirtualNode;
+
+begin
+ if Node = nil then
+ Node := FRoot
+ else
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+
+ if Recursive then
+ begin
+ if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then
+ InitChildren(Node);
+ Child := Node.FirstChild;
+ while Assigned(Child) do
+ begin
+ ValidateNode(Child, recursive);
+ Child := Child.NextSibling;
+ end;
+ end;
+end;
+
+//----------------- TCustomStringTreeOptions ---------------------------------------------------------------------------
+
+constructor TCustomStringTreeOptions.Create(AOwner: TBaseVirtualTree);
+
+begin
+ inherited;
+
+ FStringOptions := DefaultStringOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomStringTreeOptions.SetStringOptions(const Value: TVTStringOptions);
+
+var
+ ChangedOptions: TVTStringOptions;
+
+begin
+ if FStringOptions <> Value then
+ begin
+ // Exclusive ORing to get all entries wich are in either set but not in both.
+ ChangedOptions := FStringOptions + Value - (FStringOptions * Value);
+ FStringOptions := Value;
+ with FOwner do
+ if (toShowStaticText in ChangedOptions) and not (csLoading in ComponentState) and HandleAllocated then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomStringTreeOptions.AssignTo(Dest: TPersistent);
+
+begin
+ if Dest is TCustomStringTreeOptions then
+ begin
+ with Dest as TCustomStringTreeOptions do
+ StringOptions := Self.StringOptions;
+ end;
+
+ // Let ancestors assign their options to the destination class.
+ inherited;
+end;
+
+//----------------- TVTEdit --------------------------------------------------------------------------------------------
+
+// Implementation of a generic node caption editor.
+
+constructor TVTEdit.Create(Link: TStringEditLink);
+
+begin
+ inherited Create(nil);
+ ShowHint := False;
+ ParentShowHint := False;
+ FLink := Link;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.CMAutoAdjust(var Message: TMessage);
+
+begin
+ AutoAdjustSize;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.CMExit(var Message: TMessage);
+
+begin
+ if not FLink.FStopping then
+ with FLink, FTree do
+ begin
+ if (toAutoAcceptEditChange in TreeOptions.StringOptions) then
+ FLink.FTree.DoEndEdit
+ else
+ FLink.FTree.DoCancelEdit;
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.CNCommand(var Message: TWMCommand);
+
+begin
+ if Assigned(FLink) and Assigned(FLink.FTree) and (Message.NotifyCode = EN_UPDATE) and
+ not (toGridExtensions in FLink.FTree.FOptions.MiscOptions) and
+ not (vsMultiline in FLink.FNode.States) then
+ // Instead directly calling AutoAdjustSize it is necessary on Win9x/Me to decouple this notification message
+ // and eventual resizing. Hence we use a message to accomplish that.
+ if IsWinNT then
+ AutoAdjustSize
+ else
+ PostMessage(Handle, CM_AUTOADJUST, 0, 0);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.WMChar(var Message: TWMChar);
+
+begin
+ if not (Message.CharCode in [VK_ESCAPE, VK_TAB]) then
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.WMDestroy(var Message: TWMDestroy);
+
+begin
+ // If editing stopped by other means than accept or cancel then we have to do default processing for
+ // pending changes.
+ if not FLink.FStopping then
+ with FLink, FTree do
+ begin
+ if (toAutoAcceptEditChange in TreeOptions.StringOptions) and Modified then
+ DoNewText(FNode, FColumn, FEdit.Caption);
+ end;
+
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.WMGetDlgCode(var Message: TWMGetDlgCode);
+
+begin
+ inherited;
+
+ Message.Result := Message.Result or DLGC_WANTALLKEYS;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.WMKeyDown(var Message: TWMKeyDown);
+
+// Handles some control keys.
+
+var
+ Shift: TShiftState;
+ EndEdit: Boolean;
+
+begin
+ case Message.CharCode of
+ // Pretend these keycodes were send to the tree.
+ VK_ESCAPE:
+ begin
+ FLink.FTree.DoCancelEdit;
+ // Set focus back to tree.
+ FLink.FTree.SetFocus;
+ end;
+ VK_RETURN:
+ begin
+ EndEdit := not (vsMultiline in FLink.FNode.States);
+ if not EndEdit then
+ begin
+ // If a multiline node is being edited the finish editing only if Ctrl+Enter was pressed,
+ // otherwise allow to insert line breaks into the text.
+ Shift := KeyDataToShiftState(Message.KeyData);
+ EndEdit := ssCtrl in Shift;
+ end;
+ if EndEdit then
+ begin
+ FLink.FTree.InvalidateNode(FLink.FNode);
+ FLink.FTree.DoEndEdit;
+ // Set focus back to tree.
+ FLink.FTree.SetFocus;
+ end;
+ end;
+ VK_UP:
+ begin
+ if not (vsMultiline in FLink.FNode.States) then
+ Message.CharCode := VK_LEFT;
+ inherited;
+ end;
+ VK_DOWN:
+ begin
+ if not (vsMultiline in FLink.FNode.States) then
+ Message.CharCode := VK_RIGHT;
+ inherited;
+ end;
+ else
+ inherited;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.AutoAdjustSize;
+
+// Changes the size of the edit to accomodate as much as possible of its text within its container window.
+// NewChar describes the next character which will be added to the edit's text.
+
+var
+ DC: HDC;
+ Size: TSize;
+ LastFont: THandle;
+
+begin
+ if not (vsMultiline in FLink.FNode.States) then
+ begin
+ // avoid flicker
+ SendMessage(Handle, WM_SETREDRAW, 0, 0);
+
+ DC := GetDC(Handle);
+ LastFont := SelectObject(DC, Font.Handle);
+ try
+ // Read needed space for the current text.
+ {$ifdef TntSupport}
+ GetTextExtentPoint32W(DC, PWideChar(Text), Length(Text), Size);
+ {$else}
+ GetTextExtentPoint32(DC, PChar(Text), Length(Text), Size);
+ {$endif TntSupport}
+ Inc(Size.cx, 2 * FLink.FTree.FTextMargin);
+
+ // Repaint associated node if the edit becomes smaller.
+ if Size.cx < Width then
+ FLink.FTree.InvalidateNode(FLink.FNode);
+
+ if FLink.FAlignment = taRightJustify then
+ FLink.SetBounds(Rect(Left + Width - Size.cx, Top, Left + Width, Top + Height))
+ else
+ FLink.SetBounds(Rect(Left, Top, Left + Size.cx, Top + Height));
+ finally
+ SelectObject(DC, LastFont);
+ ReleaseDC(Handle, DC);
+ SendMessage(Handle, WM_SETREDRAW, 1, 0);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVTEdit.CreateParams(var Params: TCreateParams);
+
+begin
+ inherited;
+
+ // Only with multiline style we can use the text formatting rectangle.
+ // This does not harm formatting as single line control, if we don't use word wrapping.
+ with Params do
+ begin
+ Style := Style or ES_MULTILINE;
+ if vsMultiline in FLink.FNode.States then
+ Style := Style and not (ES_AUTOHSCROLL or WS_HSCROLL) or WS_VSCROLL or ES_AUTOVSCROLL;
+ if tsUseThemes in FLink.FTree.FStates then
+ begin
+ Style := Style and not WS_BORDER;
+ ExStyle := ExStyle or WS_EX_CLIENTEDGE;
+ end
+ else
+ begin
+ Style := Style or WS_BORDER;
+ ExStyle := ExStyle and not WS_EX_CLIENTEDGE;
+ end;
+ end;
+end;
+
+//----------------- TStringEditLink ------------------------------------------------------------------------------------
+
+constructor TStringEditLink.Create;
+
+begin
+ inherited;
+ FEdit := TVTEdit.Create(Self);
+ with FEdit do
+ begin
+ Visible := False;
+ BorderStyle := bsSingle;
+ AutoSize := False;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+destructor TStringEditLink.Destroy;
+
+begin
+ FEdit.Free;
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.BeginEdit: Boolean;
+
+// Notifies the edit link that editing can start now. Descentants may cancel node edit
+// by returning False.
+
+begin
+ Result := not FStopping;
+ if Result then
+ begin
+ FEdit.Show;
+ FEdit.SelectAll;
+ FEdit.SetFocus;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TStringEditLink.SetEdit(const Value: TVTEdit);
+
+begin
+ if Assigned(FEdit) then
+ FEdit.Free;
+ FEdit := Value;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.CancelEdit: Boolean;
+
+begin
+ Result := not FStopping;
+ if Result then
+ begin
+ FStopping := True;
+ FEdit.Hide;
+ FTree.CancelEditNode;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.EndEdit: Boolean;
+
+begin
+ Result := not FStopping;
+ if Result then
+ try
+ FStopping := True;
+ if FEdit.Modified then
+ FTree.DoNewText(FNode, FColumn, FEdit.Text);
+ FEdit.Hide;
+ except
+ FStopping := False;
+ raise;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.GetBounds: TRect;
+
+begin
+ Result := FEdit.BoundsRect;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TStringEditLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// Retrieves the true text bounds from the owner tree.
+
+var
+ Text: WideString;
+
+begin
+ Result := Tree is TCustomVirtualStringTree;
+ if Result then
+ begin
+ FTree := Tree as TCustomVirtualStringTree;
+ FNode := Node;
+ FColumn := Column;
+ // Initial size, font and text of the node.
+ FTree.GetTextInfo(Node, Column, FEdit.Font, FTextBounds, Text);
+ FEdit.Font.Color := clBlack;
+ FEdit.Parent := Tree;
+ FEdit.RecreateWnd;
+ FEdit.HandleNeeded;
+ {$ifdef TntSupport}
+ FEdit.Text := Text;
+ {$else}
+ FEdit.Caption := Text;
+ {$endif}
+
+ if Column <= NoColumn then
+ begin
+ FEdit.BidiMode := FTree.BidiMode;
+ FAlignment := FTree.Alignment;
+ end
+ else
+ begin
+ FEdit.BidiMode := FTree.Header.Columns[Column].BidiMode;
+ FAlignment := FTree.Header.Columns[Column].Alignment;
+ end;
+
+ if FEdit.BidiMode <> bdLeftToRight then
+ ChangeBidiModeAlignment(FAlignment);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TStringEditLink.ProcessMessage(var Message: TMessage);
+
+begin
+ FEdit.WindowProc(Message);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TStringEditLink.SetBounds(R: TRect);
+
+// Sets the outer bounds of the edit control and the actual edit area in the control.
+
+var
+ Offset: Integer;
+
+begin
+ if not FStopping then
+ begin
+ with R do
+ begin
+ // Set the edit's bounds but make sure there's a minimum width and the right border does not
+ // extend beyond the parent's left/right border.
+ if Left < 0 then
+ Left := 0;
+ if Right - Left < 30 then
+ begin
+ if FAlignment = taRightJustify then
+ Left := Right - 30
+ else
+ Right := Left + 30;
+ end;
+ if Right > FTree.ClientWidth then
+ Right := FTree.ClientWidth;
+ FEdit.BoundsRect := R;
+
+ // The selected text shall exclude the text margins and be centered vertically.
+ // We have to take out the two pixel border of the edit control as well as a one pixel "edit border" the
+ // control leaves around the (selected) text.
+ R := FEdit.ClientRect;
+ Offset := 2;
+ if tsUseThemes in FTree.FStates then
+ Inc(Offset);
+ if vsMultiline in FNode.States then
+ InflateRect(R, -FTree.FTextMargin + Offset, -FTree.FTextMargin + Offset)
+ else
+ begin
+ InflateRect(R, -FTree.FTextMargin + Offset, Offset);
+ OffsetRect(R, 0, FTextBounds.Top - FEdit.Top);
+ end;
+
+ SendMessage(FEdit.Handle, EM_SETRECTNP, 0, Integer(@R));
+ end;
+ end;
+end;
+
+//----------------- TCustomVirtualString -------------------------------------------------------------------------------
+
+constructor TCustomVirtualStringTree.Create(AOwner: TComponent);
+
+begin
+ inherited;
+
+ FDefaultText := 'Node';
+ FInternalDataOffset := AllocateInternalDataArea(SizeOf(Cardinal));
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.GetRenderStartValues(Source: TVSTTextSourceType; var Node: PVirtualNode;
+ var NextNodeProc: TGetNextNodeProc);
+
+begin
+ case Source of
+ tstInitialized:
+ begin
+ Node := GetFirstInitialized;
+ NextNodeProc := GetNextInitialized;
+ end;
+ tstSelected:
+ begin
+ Node := GetFirstSelected;
+ NextNodeProc := GetNextSelected;
+ end;
+ tstCutCopySet:
+ begin
+ Node := GetFirstCutCopy;
+ NextNodeProc := GetNextCutCopy;
+ end;
+ tstVisible:
+ begin
+ Node := GetFirstVisible;
+ NextNodeProc := GetNextVisible;
+ end;
+ else // tstAll
+ Node := GetFirst;
+ NextNodeProc := GetNext;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.GetOptions: TCustomStringTreeOptions;
+
+begin
+ Result := FOptions as TCustomStringTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.GetText(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Assert(Assigned(Node), 'Node must not be nil.');
+
+ if not (vsInitialized in Node.States) then
+ InitNode(Node);
+ Result := FDefaultText;
+
+ DoGetText(Node, Column, ttNormal, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.InitializeTextProperties(const Canvas: TCanvas; Node: PVirtualNode;
+ Column: TColumnIndex);
+
+// Initializes default values for customization in PaintNormalText.
+
+begin
+ Canvas.Font := Font;
+
+ if (toHotTrack in FOptions.FPaintOptions) and (Node = FCurrentHotNode) then
+ begin
+ Canvas.Font.Style := Canvas.Font.Style + [fsUnderline];
+ Canvas.Font.Color := FColors.HotColor;
+ end;
+
+ if (Column = FFocusedColumn) or (toFullRowSelect in FOptions.FSelectionOptions) then
+ begin
+ if Node = FDropTargetNode then
+ begin
+ if (FLastDropMode = dmOnNode) or (vsSelected in Node.States)then
+ Canvas.Font.Color := clHighlightText
+ else
+ Canvas.Font.Color := Font.Color;
+ end
+ else
+ if vsSelected in Node.States then
+ begin
+ if Focused or (toPopupMode in FOptions.FPaintOptions) then
+ Canvas.Font.Color := clHighlightText
+ else
+ Canvas.Font.Color := Font.Color;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.PaintNormalText(var PaintInfo: TVTPaintInfo; TextOutFlags: Integer;
+ Text: WideString);
+
+// This method is responsible for painting the given test to target canvas (under consideration of the given rectangles).
+// The text drawn here is considered as the normal text in a node.
+// Note: NodeWidth is the actual width of the text to be drawn. This does not necessarily correspond to the width of
+// the node rectangle. The clipping rectangle comprises the entire node (including tree lines, buttons etc.).
+
+var
+ TripleWidth: Integer;
+ R: TRect;
+ DrawFormat: Cardinal;
+ Size: TSize;
+
+begin
+ with PaintInfo do
+ begin
+ InitializeTextProperties(Canvas, Node, Column);
+
+ R := ContentRect;
+ Canvas.TextFlags := 0;
+
+ // Multiline nodes don't need special font handling or text manipulation.
+ // Note: multiline support requires the Unicode version of DrawText, which is able to do word breaking.
+ // The emulation in this unit does not support this so we have to use the OS version. However
+ // DrawTextW is only available on NT/2000/XP and up. Hence there is only partial multiline support
+ // for 9x/Me.
+ if vsMultiline in Node.States then
+ begin
+ InflateRect(R, -FTextMargin, -FTextMargin);
+ DoPaintText(Node, Canvas, Column, ttNormal);
+ // Disabled node color overrides all other variants.
+ if (vsDisabled in Node.States) or not Enabled then
+ Canvas.Font.Color := FColors.DisabledColor;
+
+ // The edit control flag will ensure that no partial line is displayed, that is, only lines
+ // which are (vertically) fully visible are drawn.
+ DrawFormat := DT_NOPREFIX or DT_WORDBREAK or DT_END_ELLIPSIS or DT_EDITCONTROL or AlignmentToDrawFlag[Alignment];
+ if BidiMode <> bdLeftToRight then
+ DrawFormat := DrawFormat or DT_RTLREADING;
+ end
+ else
+ begin
+ InflateRect(R, -FTextMargin, 0);
+ FFontChanged := False;
+ TripleWidth := FEllipsisWidth;
+ DoPaintText(Node, Canvas, Column, ttNormal);
+ if FFontChanged then
+ begin
+ // If the font has been changed then the ellipsis width must be recalculated.
+ TripleWidth := 0;
+ // Recalculate also the width of the normal text.
+ GetTextExtentPoint32W(Canvas.Handle, PWideChar(Text), Length(Text), Size);
+ NodeWidth := Size.cx + 2 * FTextMargin;
+ end;
+
+ // Disabled node color overrides all other variants.
+ if (vsDisabled in Node.States) or not Enabled then
+ Canvas.Font.Color := FColors.DisabledColor;
+
+ DrawFormat := DT_NOPREFIX or DT_VCENTER or DT_SINGLELINE;
+ if BidiMode <> bdLeftToRight then
+ DrawFormat := DrawFormat or DT_RTLREADING;
+ // Check if the text must be shortend.
+ if (Column > -1) and ((NodeWidth - 2 * FTextMargin) > R.Right - R.Left) then
+ begin
+ Text := DoShortenString(Canvas, Node, Column, Text, R.Right - R.Left, BidiMode <> bdLeftToRight, TripleWidth);
+ if Alignment = taRightJustify then
+ DrawFormat := DrawFormat or DT_RIGHT
+ else
+ DrawFormat := DrawFormat or DT_LEFT;
+ end
+ else
+ DrawFormat := DrawFormat or AlignmentToDrawFlag[Alignment];
+ end;
+
+ if Canvas.TextFlags and ETO_OPAQUE = 0 then
+ SetBkMode(Canvas.Handle, TRANSPARENT)
+ else
+ SetBkMode(Canvas.Handle, OPAQUE);
+ if IsWinNT then
+ Windows.DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat)
+ else
+ DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.PaintStaticText(const PaintInfo: TVTPaintInfo; TextOutFlags: Integer;
+ const Text: WideString);
+
+// This method retrives and draws the static text bound to a particular node.
+
+var
+ R: TRect;
+ DrawFormat: Cardinal;
+
+begin
+ with PaintInfo do
+ begin
+ Canvas.Font := Font;
+ if toFullRowSelect in FOptions.FSelectionOptions then
+ begin
+ if Node = FDropTargetNode then
+ begin
+ if (FLastDropMode = dmOnNode) or (vsSelected in Node.States)then
+ Canvas.Font.Color := clHighlightText
+ else
+ Canvas.Font.Color := Font.Color;
+ end
+ else
+ if vsSelected in Node.States then
+ begin
+ if Focused or (toPopupMode in FOptions.FPaintOptions) then
+ Canvas.Font.Color := clHighlightText
+ else
+ Canvas.Font.Color := Font.Color;
+ end;
+ end;
+
+ DrawFormat := DT_VCENTER or DT_SINGLELINE;
+ Canvas.TextFlags := 0;
+ DoPaintText(Node, Canvas, Column, ttStatic);
+
+ // Disabled node color overrides all other variants.
+ if (vsDisabled in Node.States) or not Enabled then
+ Canvas.Font.Color := FColors.DisabledColor;
+
+ R := ContentRect;
+ if Alignment = taRightJustify then
+ Dec(R.Right, NodeWidth + FTextMargin)
+ else
+ Inc(R.Left, NodeWidth + FTextMargin);
+
+ if Canvas.TextFlags and ETO_OPAQUE = 0 then
+ SetBkMode(Canvas.Handle, TRANSPARENT)
+ else
+ SetBkMode(Canvas.Handle, OPAQUE);
+ if IsWinNT then
+ Windows.DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat)
+ else
+ DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat, False);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.ReadText(Reader: TReader);
+
+begin
+ case Reader.NextValue of
+ vaLString, vaString:
+ SetDefaultText(Reader.ReadString);
+ else
+ SetDefaultText(Reader.ReadWideString);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.SetDefaultText(const Value: WideString);
+
+begin
+ if FDefaultText <> Value then
+ begin
+ FDefaultText := Value;
+ if not (csLoading in ComponentState) then
+ Invalidate;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.SetOptions(const Value: TCustomStringTreeOptions);
+
+begin
+ FOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.SetText(Node: PVirtualNode; Column: TColumnIndex; const Value: WideString);
+
+begin
+ DoNewText(Node, Column, Value);
+ InvalidateNode(Node);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.WriteText(Writer: TWriter);
+
+begin
+ Writer.WriteWideString(FDefaultText);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.WMSetFont(var Msg: TWMSetFont);
+
+// Whenever a new font is applied to the tree some default values are determined to avoid frequent
+// determination of the same value.
+
+var
+ MemDC: HDC;
+ Run: PVirtualNode;
+ TM: TTextMetric;
+ Size: TSize;
+
+begin
+ inherited;
+
+ MemDC := CreateCompatibleDC(0);
+ try
+ SelectObject(MemDC, Msg.Font);
+ GetTextMetrics(MemDC, TM);
+ FTextHeight := TM.tmHeight;
+
+ GetTextExtentPoint32W(MemDC, '...', 3, Size);
+ FEllipsisWidth := Size.cx;
+ finally
+ DeleteDC(MemDC);
+ end;
+
+ // Have to reset all node widths.
+ Run := FRoot.FirstChild;
+ while Assigned(Run) do
+ begin
+ PInteger(InternalData(Run))^ := 0;
+ Run := GetNextNoInit(Run);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex);
+
+// In the case a node spans several columns (if enabled) we need to determine how many columns.
+// Note: the autospan feature can only be used with left-to-right layout.
+
+begin
+ if (toAutoSpanColumns in FOptions.FAutoOptions) and FHeader.UseColumns and (PaintInfo.BidiMode = bdLeftToRight) then
+ with FHeader.FColumns, PaintInfo do
+ begin
+ // Start with the directly following column.
+ NextNonEmpty := GetNextVisibleColumn(Column);
+
+ // Auto spanning columns can only be used for left-to-right directionality because the tree is drawn
+ // from left to right. For RTL directionality it would be necessary to draw it from right to left.
+ // While this could be managed, it becomes impossible when directionality is mixed.
+ repeat
+ if (NextNonEmpty = InvalidColumn) or not ColumnIsEmpty(Node, NextNonEmpty) or
+ (Items[NextNonEmpty].BidiMode <> bdLeftToRight) then
+ Break;
+ Inc(CellRect.Right, Items[NextNonEmpty].Width);
+ NextNonEmpty := GetNextVisibleColumn(NextNonEmpty);
+ until False;
+ end
+ else
+ inherited;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.CalculateTextWidth(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ Text: WideString): Integer;
+
+// determines the width of the given text
+
+var
+ Size: TSize;
+
+begin
+ Result := 2 * FTextMargin;
+ if Length(Text) > 0 then
+ begin
+ Canvas.Font := Font;
+ DoPaintText(Node, Canvas, Column, ttNormal);
+
+ GetTextExtentPoint32W(Canvas.Handle, PWideChar(Text), Length(Text), Size);
+ Inc(Result, Size.cx);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean;
+
+// For hit tests it is necessary to consider cases where columns are empty and automatic column spanning is enabled.
+// This method simply checks the given column's text and if this is empty then the column is considered as being empty.
+
+begin
+ Result := Length(Text[Node, Column]) = 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DefineProperties(Filer: TFiler);
+
+begin
+ inherited;
+
+ // Delphi still cannot handle wide strings properly while streaming
+ Filer.DefineProperty('WideDefaultText', ReadText, WriteText, FDefaultText <> 'Node');
+ Filer.DefineProperty('StringOptions', ReadOldStringOptions, nil, False);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink;
+
+begin
+ Result := inherited DoCreateEditor(Node, Column);
+ // Enable generic label editing support if the application does not have own editors.
+ if Result = nil then
+ Result := TStringEditLink.Create;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Result := inherited DoGetNodeHint(Node, Column);
+ if Assigned(FOnGetHint) then
+ FOnGetHint(Self, Node, Column, ttNormal, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex): WideString;
+
+begin
+ Result := Hint;
+ Result := Text[Node, Column];
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;
+
+// Returns the text width of the given node in pixels.
+// This width is stored in the node's data member to increase access speed.
+
+var
+ Data: PInteger;
+
+begin
+ if (Column > NoColumn) and (vsMultiline in Node.States) then
+ Result := FHeader.Columns[Column].Width
+ else
+ begin
+ if Canvas = nil then
+ Canvas := Self.Canvas;
+
+ if Column = FHeader.MainColumn then
+ begin
+ // primary column or no columns
+ Data := InternalData(Node);
+ Result := Data^;
+ if Result = 0 then
+ begin
+ Data^ := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]);
+ Result := Data^;
+ end;
+ end
+ else
+ // any other column
+ Result := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DoGetText(Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var Text: WideString);
+
+begin
+ if Assigned(FOnGetText) then
+ FOnGetText(Self, Node, Column, TextType, Text);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoIncrementalSearch(Node: PVirtualNode; const Text: WideString): Integer;
+
+// Since the string tree has access to node text it can do incremental search on its own. Use the event to
+// override the default behavior.
+
+begin
+ Result := 0;
+ if Assigned(FOnIncrementalSearch) then
+ FOnIncrementalSearch(Self, Node, Text, Result)
+ else
+ // Default behavior is to match the search string with the start of the node text.
+ if Pos(Text, GetText(Node, FocusedColumn)) <> 1 then
+ Result := 1;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DoNewText(Node: PVirtualNode; Column: TColumnIndex; Text: WideString);
+
+begin
+ if Assigned(FOnNewText) then
+ FOnNewText(Self, Node, Column, Text);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DoPaintNode(var PaintInfo: TVTPaintInfo);
+
+// Main output routine to print the text of the given node using the space provided in PaintInfo.ContentRect.
+
+var
+ S: WideString;
+ TextOutFlags: Integer;
+
+begin
+ // Set a new OnChange event for the canvas' font so we know if the application changes it in the callbacks.
+ // This long winded procedure is necessary because font changes (as well as brush and pen changes) are
+ // unfortunately not announced via the Canvas.OnChange event.
+ RedirectFontChangeEvent(PaintInfo.Canvas);
+
+ // Determine main text direction as well as other text properties.
+ TextOutFlags := ETO_CLIPPED or RTLFlag[PaintInfo.BidiMode <> bdLeftToRight];
+ S := Text[PaintInfo.Node, PaintInfo.Column];
+
+ // Paint the normal text first...
+ if Length(S) > 0 then
+ PaintNormalText(PaintInfo, TextOutFlags, S);
+
+ // ... and afterwards the static text if not centered and the node is not multiline enabled.
+ if (Alignment <> taCenter) and not (vsMultiline in PaintInfo.Node.States) and (toShowStaticText in TreeOptions.FStringOptions) then
+ begin
+ S := '';
+ with PaintInfo do
+ DoGetText(Node, Column, ttStatic, S);
+ if Length(S) > 0 then
+ PaintStaticText(PaintInfo, TextOutFlags, S);
+ end;
+ RestoreFontChangeEvent(PaintInfo.Canvas);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.DoPaintText(Node: PVirtualNode; const Canvas: TCanvas; Column: TColumnIndex;
+ TextType: TVSTTextType);
+
+begin
+ if Assigned(FOnPaintText) then
+ FOnPaintText(Self, Canvas, Node, Column, TextType);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.DoShortenString(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
+ const S: WideString; Width: Integer; RightToLeft: Boolean; EllipsisWidth: Integer = 0): WideString;
+
+var
+ Done: Boolean;
+
+begin
+ Done := False;
+ if Assigned(FOnShortenString) then
+ FOnShortenString(Self, Canvas, Node, Column, S, Width, RightToLeft, Result, Done);
+ if not Done then
+ Result := ShortenString(Canvas.Handle, S, Width, RightToLeft, EllipsisWidth);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TCustomStringTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect;
+ var Text: WideString);
+
+// Returns the font, the text and its bounding rectangle to the caller. R is returned as the closest
+// bounding rectangle around Text.
+
+var
+ NewHeight: Integer;
+ TM: TTextMetric;
+
+begin
+ // Get default font and initialize the other parameters.
+ inherited GetTextInfo(Node, Column, AFont, R, Text);
+
+ Canvas.Font := AFont;
+
+ FFontChanged := False;
+ RedirectFontChangeEvent(Canvas);
+ DoPaintText(Node, Canvas, Column, ttNormal);
+ if FFontChanged then
+ begin
+ AFont.Assign(Canvas.Font);
+ GetTextMetrics(Canvas.Handle, TM);
+ NewHeight := TM.tmHeight;
+ end
+ else // Otherwise the correct font is already there and we only need to set the correct height.
+ NewHeight := FTextHeight;
+ RestoreFontChangeEvent(Canvas);
+
+ // Alignment to the actual text.
+ Text := Self.Text[Node, Column];
+ R := GetDisplayRect(Node, Column, True, not (vsMultiline in Node.States));
+ if toShowHorzGridLines in TreeOptions.PaintOptions then
+ Dec(R.Bottom);
+ InflateRect(R, 0, -(R.Bottom - R.Top - NewHeight) div 2);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
+
+begin
+ if (Node = FRoot) or (Node = nil) then
+ Result := nil
+ else
+ Result := PChar(Node) + FInternalDataOffset;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.MainColumnChanged;
+
+var
+ Run: PVirtualNode;
+
+begin
+ inherited;
+
+ // Have to reset all node widths.
+ Run := FRoot.FirstChild;
+ while Assigned(Run) do
+ begin
+ PInteger(InternalData(Run))^ := 0;
+ Run := GetNextNoInit(Run);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType,
+ ChunkSize: Integer): Boolean;
+
+// read in the caption chunk if there is one
+
+var
+ NewText: WideString;
+
+begin
+ case ChunkType of
+ CaptionChunk:
+ begin
+ NewText := '';
+ if ChunkSize > 0 then
+ begin
+ SetLength(NewText, ChunkSize div 2);
+ Stream.Read(PWideChar(NewText)^, ChunkSize);
+ end;
+ // Do a new text event regardless of the caption content to allow removing the default string.
+ DoNewText(Node, FHeader.MainColumn, NewText);
+ Result := True;
+ end;
+ else
+ Result := inherited ReadChunk(Stream, Version, Node, ChunkType, ChunkSize);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+type
+ TOldVTStringOption = (soSaveCaptions, soShowStaticText);
+
+procedure TCustomVirtualStringTree.ReadOldStringOptions(Reader: TReader);
+
+// Migration helper routine to silently convert forms containing the old tree options member into the new
+// sub-options structure.
+
+var
+ OldOption: TOldVTStringOption;
+ EnumName: string;
+
+begin
+ // If we are at design time currently then let the designer know we changed something.
+ UpdateDesigner;
+
+ // It should never happen at this place that there is something different than the old set.
+ if Reader.ReadValue = vaSet then
+ with TreeOptions do
+ begin
+ // Remove all default values set by the constructor.
+ StringOptions := [];
+
+ while True do
+ begin
+ // Sets are stored with their members as simple strings. Read them one by one and map them to the new option
+ // in the correct sub-option set.
+ EnumName := Reader.ReadStr;
+ if EnumName = '' then
+ Break;
+ OldOption := TOldVTStringOption(GetEnumValue(TypeInfo(TOldVTStringOption), EnumName));
+ case OldOption of
+ soSaveCaptions:
+ StringOptions := FStringOptions + [toSaveCaptions];
+ soShowStaticText:
+ StringOptions := FStringOptions + [toShowStaticText];
+ end;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium;
+ ForClipboard: Boolean): HResult;
+
+// Returns string expressions of all currently selected nodes in the Medium structure.
+
+begin
+ Result := inherited RenderOLEData(FormatEtcIn, Medium, ForClipboard);
+ if Failed(Result) then
+ try
+ if ForClipboard then
+ Medium.hGlobal := ContentToClipboard(FormatEtcIn.cfFormat, tstCutCopySet)
+ else
+ Medium.hGlobal := ContentToClipboard(FormatEtcIn.cfFormat, tstSelected);
+
+ // Fill rest of the Medium structure if rendering went fine.
+ if Medium.hGlobal <> 0 then
+ begin
+ Medium.tymed := TYMED_HGLOBAL;
+ Medium.unkForRelease := nil;
+
+ Result := S_OK;
+ end;
+ except
+ Result := E_FAIL;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.WriteChunks(Stream: TStream; Node: PVirtualNode);
+
+// Adds another sibling chunk for Node storing the label if the node is initialized.
+// Note: If the application stores a node's caption in the node's data member (which will be quite common) and needs to
+// store more node specific data then it should use the OnSaveNode event rather than the caption autosave function
+// (take out soSaveCaption from StringOptions). Otherwise the caption is unnecessarily stored twice.
+
+var
+ Header: TChunkHeader;
+ S: WideString;
+ Len: Integer;
+
+begin
+ inherited;
+ if (toSaveCaptions in TreeOptions.FStringOptions) and (Node <> FRoot) and
+ (vsInitialized in Node.States) then
+ with Stream do
+ begin
+ // Read the node's caption (primary column only).
+ S := Text[Node, FHeader.MainColumn];
+ Len := 2 * Length(S);
+ if Len > 0 then
+ begin
+ // Write a new sub chunk.
+ Header.ChunkType := CaptionChunk;
+ Header.ChunkSize := Len;
+ Write(Header, SizeOf(Header));
+ Write(PWideChar(S)^, Len);
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToClipboard(Format: Word; Source: TVSTTextSourceType): HGLOBAL;
+
+// This method constructs a shareable memory object filled with string data in the required format. Supported are:
+// CF_TEXT - plain ANSI text (Unicode text is converted using the user's current locale)
+// CF_UNICODETEXT - plain Unicode text
+// CF_CSV - comma separated plain ANSI text
+// CF_VRTF + CF_RTFNOOBS - rich text (plain ANSI)
+// CF_HTML - HTML text encoded using UTF-8
+//
+// Result is the handle to a globally allocated memory block which can directly be used for clipboard and drag'n drop
+// transfers. The caller is responsible for freeing the memory. If for some reason the content could not be rendered
+// the Result is 0.
+
+ //--------------- local function --------------------------------------------
+
+ procedure MakeFragment(var HTML: string);
+
+ // Helper routine to build a properly-formatted HTML fragment.
+
+ const
+ Version = 'Version:1.0'#13#10;
+ StartHTML = 'StartHTML:';
+ EndHTML = 'EndHTML:';
+ StartFragment = 'StartFragment:';
+ EndFragment = 'EndFragment:';
+ DocType = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">';
+ HTMLIntro = '<html><head><META http-equiv=Content-Type content="text/html; charset=utf-8">' +
+ '</head><body><!--StartFragment-->';
+ HTMLExtro = '<!--EndFragment--></body></html>';
+ NumberLengthAndCR = 10;
+
+ // Let the compiler determine the description length.
+ DescriptionLength = Length(Version) + Length(StartHTML) + Length(EndHTML) + Length(StartFragment) +
+ Length(EndFragment) + 4 * NumberLengthAndCR;
+
+ var
+ Description: string;
+ StartHTMLIndex,
+ EndHTMLIndex,
+ StartFragmentIndex,
+ EndFragmentIndex: Integer;
+
+ begin
+ // The HTML clipboard format is defined by using byte positions in the entire block where HTML text and
+ // fragments start and end. These positions are written in a description. Unfortunately the positions depend on the
+ // length of the description but the description may change with varying positions.
+ // To solve this dilemma the offsets are converted into fixed length strings which makes it possible to know
+ // the description length in advance.
+ StartHTMLIndex := DescriptionLength; // position 0 after the description
+ StartFragmentIndex := StartHTMLIndex + Length(DocType) + Length(HTMLIntro);
+ EndFragmentIndex := StartFragmentIndex + Length(HTML);
+ EndHTMLIndex := EndFragmentIndex + Length(HTMLExtro);
+
+ Description := Version +
+ SysUtils.Format('%s%.8d', [StartHTML, StartHTMLIndex]) + #13#10 +
+ SysUtils.Format('%s%.8d', [EndHTML, EndHTMLIndex]) + #13#10 +
+ SysUtils.Format('%s%.8d', [StartFragment, StartFragmentIndex]) + #13#10 +
+ SysUtils.Format('%s%.8d', [EndFragment, EndFragmentIndex]) + #13#10;
+ HTML := Description + DocType + HTMLIntro + HTML + HTMLExtro;
+ end;
+
+ //--------------- end local function ----------------------------------------
+
+var
+ Data: Pointer;
+ DataSize: Cardinal;
+ S: string;
+ WS: WideString;
+ P: Pointer;
+
+begin
+ Result := 0;
+ case Format of
+ CF_TEXT:
+ begin
+ S := ContentToText(Source, #9) + #0;
+ Data := PChar(S);
+ DataSize := Length(S);
+ end;
+ CF_UNICODETEXT:
+ begin
+ WS := ContentToUnicode(Source, #9) + #0;
+ Data := PWideChar(WS);
+ DataSize := 2 * Length(WS);
+ end;
+ else
+ if Format = CF_CSV then
+ S := ContentToText(Source, ListSeparator) + #0
+ else
+ if (Format = CF_VRTF) or (Format = CF_VRTFNOOBJS) then
+ S := ContentToRTF(Source) + #0
+ else
+ if Format = CF_HTML then
+ begin
+ S := ContentToHTML(Source);
+ // Build a valid HTML clipboard fragment.
+ MakeFragment(S);
+ S := S + #0;
+ end;
+ Data := PChar(S);
+ DataSize := Length(S);
+ end;
+
+ if DataSize > 0 then
+ begin
+ Result := GlobalAlloc(GHND or GMEM_SHARE, DataSize);
+ P := GlobalLock(Result);
+ Move(Data^, P^, DataSize);
+ GlobalUnlock(Result);
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToHTML(Source: TVSTTextSourceType; Caption: WideString = ''): string;
+
+// Renders the current tree content (depending on Source) as HTML text encoded in UTF-8.
+// If Caption is not empty then it is used to create and fill the header for the table built here.
+// Based on ideas and code from Frank van den Bergh and Andreas Hörstemeier.
+
+type
+ UCS2 = Word;
+ UCS4 = Cardinal;
+
+const
+ MaximumUCS4: UCS4 = $7FFFFFFF;
+ ReplacementCharacter: UCS4 = $0000FFFD;
+
+var
+ Buffer: TBufferedString;
+
+ //--------------- local functions -------------------------------------------
+
+ function ConvertSurrogate(S1, S2: UCS2): UCS4;
+
+ // Converts a pair of high and low surrogate into the corresponding UCS4 character.
+
+ const
+ SurrogateOffset = ($D800 shl 10) + $DC00 - $10000;
+
+ begin
+ Result := Word(S1) shl 10 + Word(S2) - SurrogateOffset;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ function UTF16ToUTF8(const S: WideString): string;
+
+ // Converts the given Unicode text (which may contain surrogates) into
+ // the UTF-8 encoding used for the HTML clipboard format.
+
+ const
+ FirstByteMark: array[0..6] of Byte = ($00, $00, $C0, $E0, $F0, $F8, $FC);
+
+ var
+ Ch: UCS4;
+ I, J, T: Integer;
+ BytesToWrite: Cardinal;
+
+ begin
+ if Length(S) = 0 then
+ Result := ''
+ else
+ begin
+ // Make room for the result. Assume worst case, there are only short texts to convert.
+ SetLength(Result, 6 * Length(S));
+ T := 1;
+ I := 1;
+ while I <= Length(S) do
+ begin
+ Ch := UCS4(S[I]);
+
+ // Is the character a surrogate?
+ if (Ch and $FFFFF800) = $D800 then
+ begin
+ Inc(I);
+ // Check the following char whether it forms a valid surrogate pair with the first character.
+ if (I <= Length(S)) and ((UCS4(S[I]) and $FFFFFC00) = $DC00) then
+ Ch := ConvertSurrogate(UCS2(Ch), UCS2(S[I]))
+ else // Skip invalid surrogate value.
+ Continue;
+ end;
+
+ if Ch < $80 then
+ BytesToWrite := 1
+ else
+ if Ch < $800 then
+ BytesToWrite := 2
+ else
+ if Ch < $10000 then
+ BytesToWrite := 3
+ else
+ if Ch < $200000 then
+ BytesToWrite := 4
+ else
+ if Ch < $4000000 then
+ BytesToWrite := 5
+ else
+ if Ch <= MaximumUCS4 then
+ BytesToWrite := 6
+ else
+ begin
+ BytesToWrite := 2;
+ Ch := ReplacementCharacter;
+ end;
+
+ for J := BytesToWrite downto 2 do
+ begin
+ Result[T + J - 1] := Char((Ch or $80) and $BF);
+ Ch := Ch shr 6;
+ end;
+ Result[T] := Char(Ch or FirstByteMark[BytesToWrite]);
+ Inc(T, BytesToWrite);
+
+ Inc(I);
+ end;
+ SetLength(Result, T - 1); // set to actual length
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure WriteColorAsHex(Color: TColor);
+
+ var
+ WinColor: COLORREF;
+ I: Integer;
+ Component,
+ Value: Byte;
+
+ begin
+ Buffer.Add('#');
+ WinColor := ColorToRGB(Color);
+ I := 1;
+ while I <= 6 do
+ begin
+ Component := WinColor and $FF;
+
+ Value := 48 + (Component shr 4);
+ if Value > $39 then
+ Inc(Value, 7);
+ Buffer.Add(Char(Value));
+ Inc(I);
+
+ Value := 48 + (Component and $F);
+ if Value > $39 then
+ Inc(Value, 7);
+ Buffer.Add(Char(Value));
+ Inc(I);
+
+ WinColor := WinColor shr 8;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure WriteStyle(Name: string; Font: TFont);
+
+ // Creates a CSS style entry with the given name for the given font.
+ // If Name is empty then the entry is created as inline style.
+
+ begin
+ if Length(Name) = 0 then
+ Buffer.Add(' style="{font:')
+ else
+ begin
+ Buffer.Add('.');
+ Buffer.Add(Name);
+ Buffer.Add('{font:');
+ end;
+ if fsUnderline in Font.Style then
+ Buffer.Add(' underline');
+ if fsItalic in Font.Style then
+ Buffer.Add(' italic');
+ if fsBold in Font.Style then
+ Buffer.Add(' bold');
+ Buffer.Add(Format(' %dpt "%s";', [Font.Size, Font.Name]));
+ Buffer.Add('color:');
+ WriteColorAsHex(Font.Color);
+ Buffer.Add(';}');
+ if Length(Name) = 0 then
+ Buffer.Add('"');
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ I, J : Integer;
+ Level, MaxLevel: Cardinal;
+ AddHeader: string;
+ Save, Run: PVirtualNode;
+ GetNextNode: TGetNextNodeProc;
+ Text: WideString;
+
+ RenderColumns: Boolean;
+ Columns: TColumnsArray;
+ ColumnColors: array of string;
+ Index: Integer;
+ IndentWidth,
+ LineStyleText: string;
+ Alignment: TAlignment;
+ BidiMode: TBidiMode;
+
+ CellPadding: string;
+
+begin
+ Buffer := TBufferedString.Create;
+ try
+ // For customization by the application or descentants we use again the redirected font change event.
+ RedirectFontChangeEvent(Canvas);
+
+ CellPadding := Format('padding-left:%dpx;padding-right:%0:dpx;', [FMargin]);
+
+ IndentWidth := IntToStr(FIndent);
+ AddHeader := ' ';
+ // Add title if adviced so by giving a caption.
+ if Length(Caption) > 0 then
+ AddHeader := AddHeader + 'caption="' + UTF16ToUTF8(Caption) + '"';
+ if Borderstyle <> bsNone then
+ AddHeader := AddHeader + Format('border="%d" frame=box', [BorderWidth + 1]);
+
+ // Create HTML table based on the tree structure. To simplify formatting we use styles defined in a small CSS area.
+ Buffer.Add('<style type="text/css">');
+ Buffer.AddnewLine;
+ WriteStyle('default', Font);
+ Buffer.AddNewLine;
+ WriteStyle('header', FHeader.Font);
+ Buffer.AddNewLine;
+
+ // Determine grid/table lines and create CSS for it.
+ // Vertical and/or horizontal border to show.
+ if FLineStyle = lsSolid then
+ LineStyleText := 'solid;'
+ else
+ LineStyleText := 'dotted;';
+ if toShowHorzGridLines in FOptions.FPaintOptions then
+ begin
+ Buffer.Add('.noborder{border-style:');
+ Buffer.Add(LineStyleText);
+ Buffer.Add(' border-bottom:1;border-left:0;border-right:0; border-top:0;');
+ Buffer.Add(CellPadding);
+ Buffer.Add('}');
+ end
+ else
+ begin
+ Buffer.Add('.noborder{border-style:none;');
+ Buffer.Add(CellPadding);
+ Buffer.Add('}');
+ end;
+ Buffer.AddNewLine;
+
+ Buffer.Add('.normalborder {border-top:none; border-left:none; ');
+ if toShowVertGridLines in FOptions.FPaintOptions then
+ Buffer.Add('border-right:1 ' + LineStyleText)
+ else
+ Buffer.Add('border-right:none;');
+ if toShowHorzGridLines in FOptions.FPaintOptions then
+ Buffer.Add('border-bottom:1 ' + LineStyleText)
+ else
+ Buffer.Add('border-bottom:none;');
+ Buffer.Add(CellPadding);
+ Buffer.Add('}');
+ Buffer.Add('</style>');
+ Buffer.AddNewLine;
+
+ // General table properties.
+ Buffer.Add('<table class="default" bgcolor=');
+ WriteColorAsHex(Color);
+ Buffer.Add(AddHeader);
+ Buffer.Add(' cellspacing="0" cellpadding=');
+ Buffer.Add(IntToStr(FMargin) + '>');
+ Buffer.AddNewLine;
+
+ Columns := nil;
+ ColumnColors := nil;
+ RenderColumns := FHeader.UseColumns;
+ if RenderColumns then
+ begin
+ Columns := FHeader.FColumns.GetVisibleColumns;
+ SetLength(ColumnColors, Length(Columns));
+ end;
+
+ GetRenderStartValues(Source, Run, GetNextNode);
+ Save := Run;
+
+ MaxLevel := 0;
+ // The table consists of visible columns and rows as used in the tree, but the main tree column is splitted
+ // into several HTML columns to accomodate the indentation.
+ while Assigned(Run) do
+ begin
+ Level := GetNodeLevel(Run);
+ If Level > MaxLevel then
+ MaxLevel := Level;
+ Run := GetNextNode(Run);
+ end;
+
+ if RenderColumns then
+ begin
+ Buffer.Add('<tr class="header" style="');
+ Buffer.Add(CellPadding);
+ Buffer.Add('">');
+ Buffer.AddNewLine;
+ // Make the first row in the HTML table an image of the tree header.
+ for I := 0 to High(Columns) do
+ begin
+ Buffer.Add('<th height="');
+ Buffer.Add(IntToStr(FHeader.FHeight));
+ Buffer.Add('px"');
+ Alignment := Columns[I].Alignment;
+ // Consider directionality.
+ if Columns[I].FBiDiMode <> bdLeftToRight then
+ begin
+ ChangeBidiModeAlignment(Alignment);
+ Buffer.Add(' dir="rtl"');
+ end;
+
+ // Consider aligment.
+ case Alignment of
+ taRightJustify:
+ Buffer.Add(' align=right');
+ taCenter:
+ Buffer.Add(' align=center');
+ else
+ Buffer.Add(' align=left');
+ end;
+
+ Index := Columns[I].Index;
+ // Merge cells of the header emulation in the main column.
+ if (MaxLevel > 0) and (Index = Header.MainColumn) then
+ begin
+ Buffer.Add(' colspan="');
+ Buffer.Add(IntToStr(MaxLevel + 1));
+ Buffer.Add('"');
+ end;
+
+ // The color of the header is usually clBtnFace.
+ Buffer.Add(' bgcolor=');
+ WriteColorAsHex(clBtnFace);
+
+ // Set column width in pixels.
+ Buffer.Add(' width="');
+ Buffer.Add(IntToStr(Columns[I].Width));
+ Buffer.Add('px">');
+
+ if Length(Columns[I].Text) > 0 then
+ Buffer.Add(UTF16ToUTF8(Columns[I].Text));
+ Buffer.Add('</th>');
+ end;
+ Buffer.Add('</tr>');
+ Buffer.AddNewLine;
+ end;
+
+ // Now go through the tree.
+ Run := Save;
+ while Assigned(Run) do
+ begin
+ Level := GetNodeLevel(Run);
+ Buffer.Add(' <tr class="default">');
+ Buffer.AddNewLine;
+
+ I := 0;
+ while (I < Length(Columns)) or not RenderColumns do
+ begin
+ if RenderColumns then
+ Index := Columns[I].Index
+ else
+ Index := NoColumn;
+
+ if not RenderColumns or (coVisible in Columns[I].FOptions) then
+ begin
+ // Call back the application to know about font customization.
+ Canvas.Font := Font;
+ FFontChanged := False;
+ DoPaintText(Run, Canvas, Index, ttNormal);
+
+ if Index = Header.MainColumn then
+ begin
+ // Create a cell for each indentation level.
+ if RenderColumns and not (coParentColor in Columns[I].FOptions) then
+ begin
+ for J := 1 to Level do
+ begin
+ Buffer.Add('<td class="noborder" width="');
+ Buffer.Add(IndentWidth);
+ Buffer.Add('" height="');
+ Buffer.Add(IntToStr(Run.NodeHeight));
+ Buffer.Add('px"');
+ if not (coParentColor in Columns[I].FOptions) then
+ begin
+ Buffer.Add(' bgcolor=');
+ WriteColorAsHex(Columns[I].Color);
+ end;
+ Buffer.Add('> </td>');
+ end;
+ end
+ else
+ begin
+ for J := 1 to Level do
+ if J = 1 then
+ begin
+ Buffer.Add(' <td height="');
+ Buffer.Add(IntToStr(Run.NodeHeight));
+ Buffer.Add('px"> </td>');
+ end
+ else
+ Buffer.Add(' <td> </td>');
+ end;
+ end;
+
+ if FFontChanged then
+ begin
+ Buffer.Add(' <td class="normalborder" ');
+ WriteStyle('', Canvas.Font);
+ Buffer.Add(' height="');
+ Buffer.Add(IntToStr(Run.NodeHeight));
+ Buffer.Add('px"');
+ end
+ else
+ begin
+ Buffer.Add(' <td class="normalborder" height="');
+ Buffer.Add(IntToStr(Run.NodeHeight));
+ Buffer.Add('px"');
+ end;
+
+ if RenderColumns then
+ begin
+ Alignment := Columns[I].Alignment;
+ BidiMode := Columns[I].BidiMode;
+ end
+ else
+ begin
+ Alignment := Self.Alignment;
+ BidiMode := Self.BidiMode;
+ end;
+ // Consider directionality.
+ if BiDiMode <> bdLeftToRight then
+ begin
+ ChangeBidiModeAlignment(Alignment);
+ Buffer.Add(' dir="rtl"');
+ end;
+
+ // Consider aligment.
+ case Alignment of
+ taRightJustify:
+ Buffer.Add(' align=right');
+ taCenter:
+ Buffer.Add(' align=center');
+ else
+ Buffer.Add(' align=left');
+ end;
+ // Merge cells in the main column.
+ if (MaxLevel > 0) and (Index = FHeader.MainColumn) and (Level < MaxLevel) then
+ begin
+ Buffer.Add(' colspan="');
+ Buffer.Add(IntToStr(MaxLevel - Level + 1));
+ Buffer.Add('"');
+ end;
+ if RenderColumns and not (coParentColor in Columns[I].FOptions) then
+ begin
+ Buffer.Add(' bgcolor=');
+ WriteColorAsHex(Columns[I].Color);
+ end;
+ Buffer.Add('>');
+ Text := Self.Text[Run, Index];
+ if Length(Text) > 0 then
+ begin
+ Text := UTF16ToUTF8(Text);
+ Buffer.Add(Text);
+ end;
+ Buffer.Add('</td>');
+ end;
+
+ if not RenderColumns then
+ Break;
+ Inc(I);
+ end;
+ Run := GetNextNode(Run);
+ Buffer.Add(' </tr>');
+ Buffer.AddNewLine;
+ end;
+ Buffer.Add('</table>');
+
+ RestoreFontChangeEvent(Canvas);
+
+ Result := Buffer.AsString;
+ finally
+ Buffer.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToRTF(Source: TVSTTextSourceType): string;
+
+// Renders the current tree content (depending on Source) as RTF (rich text).
+// Based on ideas and code from Frank van den Bergh and Andreas Hörstemeier.
+
+var
+ Fonts: TStringList;
+ Colors: TList;
+ CurrentFontIndex,
+ CurrentFontColor,
+ CurrentFontSize: Integer;
+ Buffer: TBufferedString;
+
+ //--------------- local functions -------------------------------------------
+
+ procedure SelectFont(Font: string);
+
+ var
+ I: Integer;
+
+ begin
+ I := Fonts.IndexOf(Font);
+ if I > -1 then
+ begin
+ // Font has already been used
+ if I <> CurrentFontIndex then
+ begin
+ Buffer.Add('\f');
+ Buffer.Add(IntToStr(I));
+ CurrentFontIndex := I;
+ end;
+ end
+ else
+ begin
+ I := Fonts.Add(Font);
+ Buffer.Add('\f');
+ Buffer.Add(IntToStr(I));
+ CurrentFontIndex := I;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure SelectColor(Color: TColor);
+
+ var
+ I: Integer;
+
+ begin
+ I := Colors.IndexOf(Pointer(Color));
+ if I > -1 then
+ begin
+ // Color has already been used
+ if I <> CurrentFontColor then
+ begin
+ Buffer.Add('\cf');
+ Buffer.Add(IntToStr(I + 1));
+ CurrentFontColor := I;
+ end;
+ end
+ else
+ begin
+ I := Colors.Add(Pointer(Color));
+ Buffer.Add('\cf');
+ Buffer.Add(IntToStr(I + 1));
+ CurrentFontColor := I;
+ end;
+ end;
+
+ //---------------------------------------------------------------------------
+
+ procedure TextPlusFont(Text: WideString; Font: TFont);
+
+ var
+ UseUnderline,
+ UseItalic,
+ UseBold: Boolean;
+ I: Integer;
+
+ begin
+ if Length(Text) > 0 then
+ begin
+ UseUnderline := fsUnderline in Font.Style;
+ if UseUnderline then
+ Buffer.Add('\ul');
+ UseItalic := fsItalic in Font.Style;
+ if UseItalic then
+ Buffer.Add('\i');
+ UseBold := fsBold in Font.Style;
+ if UseBold then
+ Buffer.Add('\b');
+ SelectFont(Font.Name);
+ SelectColor(Font.Color);
+ if Font.Size <> CurrentFontSize then
+ begin
+ // Font size must be given in half points.
+ Buffer.Add('\fs');
+ Buffer.Add(IntToStr(2 * Font.Size));
+ CurrentFontSize := Font.Size;
+ end;
+ // Use escape sequences to note Unicode text.
+ Buffer.Add(' ');
+ // Note: Unicode values > 32767 must be expressed as negative numbers. This is implicitly done
+ // by interpreting the wide chars (word values) as small integers.
+ for I := 1 to Length(Text) do
+ Buffer.Add(Format('\u%d\''3f', [SmallInt(Text[I])]));
+ if UseUnderline then
+ Buffer.Add('\ul0');
+ if UseItalic then
+ Buffer.Add('\i0');
+ if UseBold then
+ Buffer.Add('\b0');
+ end;
+ end;
+
+ //--------------- end local functions ---------------------------------------
+
+var
+ Level, LastLevel: Integer;
+ I, J: Integer;
+ Save, Run: PVirtualNode;
+ GetNextNode: TGetNextNodeProc;
+ S, Tabs : string;
+ Text: WideString;
+ Twips: Integer;
+
+ RenderColumns: Boolean;
+ Columns: TColumnsArray;
+ Index: Integer;
+ Alignment: TAlignment;
+ BidiMode: TBidiMode;
+
+begin
+ Buffer := TBufferedString.Create;
+ try
+ // For customization by the application or descentants we use again the redirected font change event.
+ RedirectFontChangeEvent(Canvas);
+
+ Fonts := TStringList.Create;
+ Colors := TList.Create;
+ CurrentFontIndex := -1;
+ CurrentFontColor := -1;
+ CurrentFontSize := -1;
+
+ Columns := nil;
+ Tabs := '';
+ LastLevel := 0;
+
+ RenderColumns := FHeader.UseColumns;
+ if RenderColumns then
+ Columns := FHeader.FColumns.GetVisibleColumns;
+
+ GetRenderStartValues(Source, Run, GetNextNode);
+ Save := Run;
+
+ // First make a table structure. The \rtf and other header stuff is included
+ // when the font and color tables are created.
+ Buffer.Add('\uc1\trowd\trgaph70');
+ J := 0;
+ if RenderColumns then
+ begin
+ for I := 0 to High(Columns) do
+ begin
+ Inc(J, Columns[I].Width);
+ // This value must be expressed in twips (1 inch = 1440 twips).
+ Twips := Round(1440 * J / Screen.PixelsPerInch);
+ Buffer.Add('\cellx');
+ Buffer.Add(IntToStr(Twips));
+ end;
+ end
+ else
+ begin
+ Twips := Round(1440 * ClientWidth / Screen.PixelsPerInch);
+ Buffer.Add('\cellx');
+ Buffer.Add(IntToStr(Twips));
+ end;
+
+ // Fill table header.
+ if RenderColumns then
+ begin
+ Buffer.Add('\pard\intbl');
+ for I := 0 to High(Columns) do
+ begin
+ Alignment := Columns[I].Alignment;
+ BidiMode := Columns[I].BidiMode;
+
+ // Alignment is not supported with older RTF formats, however it will be ignored.
+ if BidiMode <> bdLeftToRight then
+ ChangeBidiModeAlignment(Alignment);
+ case Alignment of
+ taRightJustify:
+ Buffer.Add('\qr');
+ taCenter:
+ Buffer.Add('\qc');
+ end;
+
+ TextPlusFont(Columns[I].Text, Header.Font);
+ Buffer.Add('\cell');
+ end;
+ Buffer.Add('\row');
+ end;
+
+ // Now write the contents.
+ Run := Save;
+ while Assigned(Run) do
+ begin
+ I := 0;
+ while not RenderColumns or (I < Length(Columns)) do
+ begin
+ if RenderColumns then
+ begin
+ Index := Columns[I].Index;
+ Alignment := Columns[I].Alignment;
+ BidiMode := Columns[I].BidiMode;
+ end
+ else
+ begin
+ Index := NoColumn;
+ Alignment := FAlignment;
+ BidiMode := Self.BidiMode;
+ end;
+
+ if not RenderColumns or (coVisible in Columns[I].Options) then
+ begin
+ Text := Self.Text[Run, Index];
+ Buffer.Add('\pard\intbl');
+
+ // Alignment is not supported with older RTF formats, however it will be ignored.
+ if BidiMode <> bdLeftToRight then
+ ChangeBidiModeAlignment(Alignment);
+ case Alignment of
+ taRightJustify:
+ Buffer.Add('\qr');
+ taCenter:
+ Buffer.Add('\qc');
+ end;
+
+ // Call back the application to know about font customization.
+ Canvas.Font := Font;
+ FFontChanged := False;
+ DoPaintText(Run, Canvas, Index, ttNormal);
+
+ if Index = Header.MainColumn then
+ begin
+ Level := GetNodeLevel(Run);
+ if Level <> LastLevel then
+ begin
+ LastLevel := Level;
+ Tabs := '';
+ for J := 0 to Level - 1 do
+ Tabs := Tabs + '\tab';
+ end;
+ if Level > 0 then
+ begin
+ Buffer.Add(Tabs);
+ Buffer.Add(' ');
+ TextPlusFont(Text, Canvas.Font);
+ Buffer.Add('\cell');
+ end
+ else
+ begin
+ TextPlusFont(Text, Canvas.Font);
+ Buffer.Add('\cell');
+ end;
+ end
+ else
+ begin
+ TextPlusFont(Text, Canvas.Font);
+ Buffer.Add('\cell');
+ end;
+ end;
+
+ if not RenderColumns then
+ Break;
+ Inc(I);
+ end;
+ Buffer.Add('\row');
+ Run := GetNextNode(Run);
+ end;
+
+ Buffer.Add('\pard\par');
+
+ // Build lists with fonts and colors. They have to be at the start of the document.
+ S := '{\rtf1\ansi\ansicpg1252\deff0\deflang1043{\fonttbl';
+ for I := 0 to Fonts.Count - 1 do
+ S := S + Format('{\f%d %s;}', [I, Fonts[I]]);
+ S := S + '}';
+
+ S := S + '{\colortbl;';
+ for I := 0 to Colors.Count - 1 do
+ begin
+ J := ColorToRGB(TColor(Colors[I]));
+ S := S + Format('\red%d\green%d\blue%d;', [J and $FF, (J shr 8) and $FF, (J shr 16) and $FF]);
+ end;
+ S := S + '}';
+
+ Result := S + Buffer.AsString + '}';
+ Fonts.Free;
+ Colors.Free;
+
+ RestoreFontChangeEvent(Canvas);
+ finally
+ Buffer.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToText(Source: TVSTTextSourceType; Separator: Char): string;
+
+// Renders the current tree content (depending on Source) as plain ANSI text.
+// Note: Unicode strings are implicitely converted to ANSI strings based on the currently active user locale.
+
+var
+ RenderColumns: Boolean;
+ Tabs: string;
+ GetNextNode: TGetNextNodeProc;
+ Run, Save: PVirtualNode;
+ Level, MaxLevel: Cardinal;
+ Columns: TColumnsArray;
+ LastColumn: TVirtualTreeColumn;
+ Index,
+ I: Integer;
+ Text: string;
+ Buffer: TBufferedString;
+
+begin
+ Columns := nil;
+ Buffer := TBufferedString.Create;
+ try
+ RenderColumns := FHeader.UseColumns;
+ if RenderColumns then
+ Columns := FHeader.FColumns.GetVisibleColumns;
+
+ GetRenderStartValues(Source, Run, GetNextNode);
+ Save := Run;
+
+ // The text consists of visible groups representing the columns, which are separated by one or more separator
+ // characters. There are always MaxLevel separator chars in a line (main column only). Either before the caption
+ // to ident it or after the caption to make the following column aligned.
+ MaxLevel := 0;
+ while Assigned(Run) do
+ begin
+ Level := GetNodeLevel(Run);
+ If Level > MaxLevel then
+ MaxLevel := Level;
+ Run := GetNextNode(Run);
+ end;
+
+ SetLength(Tabs, MaxLevel);
+ FillChar(PChar(Tabs)^, MaxLevel, Separator);
+
+ // First line is always the header if used.
+ if RenderColumns then
+ begin
+ LastColumn := Columns[High(Columns)];
+ for I := 0 to High(Columns) do
+ begin
+ Buffer.Add(Columns[I].Text);
+ if Columns[I] <> LastColumn then
+ begin
+ if Columns[I].Index = Header.MainColumn then
+ begin
+ Buffer.Add(Tabs);
+ Buffer.Add(Separator);
+ end
+ else
+ Buffer.Add(Separator);
+ end;
+ end;
+ Buffer.AddNewLine;
+ end
+ else
+ LastColumn := nil;
+
+ Run := Save;
+ if RenderColumns then
+ begin
+ while Assigned(Run) do
+ begin
+ for I := 0 to High(Columns) do
+ begin
+ if coVisible in Columns[I].Options then
+ begin
+ Index := Columns[I].Index;
+ // This line implicitly converts the Unicode text to ANSI.
+ Text := Self.Text[Run, Index];
+ if Index = Header.MainColumn then
+ begin
+ Level := GetNodeLevel(Run);
+ Buffer.Add(Copy(Tabs, 1, Level));
+ Buffer.Add(Text);
+ Buffer.Add(Copy(Tabs, 1, MaxLevel - Level));
+ end
+ else
+ Buffer.Add(Text);
+
+ if Columns[I] <> LastColumn then
+ Buffer.Add(Separator);
+ end;
+ end;
+ Run := GetNextNode(Run);
+ Buffer.AddNewLine;
+ end;
+ end
+ else
+ begin
+ while Assigned(Run) do
+ begin
+ // This line implicitly converts the Unicode text to ANSI.
+ Text := Self.Text[Run, NoColumn];
+ Level := GetNodeLevel(Run);
+ Buffer.Add(Copy(Tabs, 1, Level));
+ Buffer.Add(Text);
+ Buffer.AddNewLine;
+
+ Run := GetNextNode(Run);
+ end;
+ end;
+
+ Result := Buffer.AsString;
+ finally
+ Buffer.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.ContentToUnicode(Source: TVSTTextSourceType; Separator: WideChar): WideString;
+
+// Renders the current tree content (depending on Source) as Unicode text.
+
+const
+ WideCRLF: WideString = #13#10;
+
+var
+ RenderColumns: Boolean;
+ Tabs: WideString;
+ GetNextNode: TGetNextNodeProc;
+ Run, Save: PVirtualNode;
+
+ Columns: TColumnsArray;
+ LastColumn: TVirtualTreeColumn;
+ Level, MaxLevel: Cardinal;
+ Index,
+ I: Integer;
+ Text: WideString;
+ Buffer: TWideBufferedString;
+
+begin
+ Columns := nil;
+
+ Buffer := TWideBufferedString.Create;
+ try
+ RenderColumns := FHeader.UseColumns;
+ if RenderColumns then
+ Columns := FHeader.FColumns.GetVisibleColumns;
+
+ GetRenderStartValues(Source, Run, GetNextNode);
+ Save := Run;
+
+ // The text consists of visible groups representing the columns, which are separated by one or more separator
+ // characters. There are always MaxLevel separator chars in a line (main column only). Either before the caption
+ // to ident it or after the caption to make the following column aligned.
+ MaxLevel := 0;
+ while Assigned(Run) do
+ begin
+ Level := GetNodeLevel(Run);
+ If Level > MaxLevel then
+ MaxLevel := Level;
+ Run := GetNextNode(Run);
+ end;
+
+ SetLength(Tabs, MaxLevel);
+ for I := 1 to MaxLevel do
+ Tabs[I] := Separator;
+
+ // First line is always the header if used.
+ if RenderColumns then
+ begin
+ LastColumn := Columns[High(Columns)];
+ for I := 0 to High(Columns) do
+ begin
+ Buffer.Add(Columns[I].Text);
+ if Columns[I] <> LastColumn then
+ begin
+ if Columns[I].Index = Header.MainColumn then
+ begin
+ Buffer.Add(Tabs);
+ Buffer.Add(Separator);
+ end
+ else
+ Buffer.Add(Separator);
+ end;
+ end;
+ Buffer.AddNewLine;
+ end
+ else
+ LastColumn := nil;
+
+ Run := Save;
+ if RenderColumns then
+ begin
+ while Assigned(Run) do
+ begin
+ for I := 0 to High(Columns) do
+ begin
+ if coVisible in Columns[I].Options then
+ begin
+ Index := Columns[I].Index;
+ Text := Self.Text[Run, Index];
+ if Index = Header.MainColumn then
+ begin
+ Level := GetNodeLevel(Run);
+ Buffer.Add(Copy(Tabs, 1, Level));
+ Buffer.Add(Text);
+ Buffer.Add(Copy(Tabs, 1, MaxLevel - Level));
+ end
+ else
+ Buffer.Add(Text);
+
+ if Columns[I] <> LastColumn then
+ Buffer.Add(Separator);
+ end;
+ end;
+ Run := GetNextNode(Run);
+ Buffer.AddNewLine;
+ end;
+ end
+ else
+ begin
+ while Assigned(Run) do
+ begin
+ Text := Self.Text[Run, NoColumn];
+ Level := GetNodeLevel(Run);
+ Buffer.Add(Copy(Tabs, 1, Level));
+ Buffer.Add(Text);
+ Buffer.AddNewLine;
+
+ Run := GetNextNode(Run);
+ end;
+ end;
+ Result := Buffer.AsString;
+ finally
+ Buffer.Free;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.InvalidateNode(Node: PVirtualNode): TRect;
+
+var
+ Data: PInteger;
+
+begin
+ Result := inherited InvalidateNode(Node);
+ // Reset node width so changed text attributes are applied correctly.
+ Data := InternalData(Node);
+ if Assigned(Data) then
+ Data^ := 0;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualStringTree.Path(Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ Delimiter: WideChar): WideString;
+
+// Constructs a string containing the node and all its parents. The last character in the returned path is always the
+// given delimiter.
+
+var
+ S: WideString;
+
+begin
+ if (Node = nil) or (Node = FRoot) then
+ Result := Delimiter
+ else
+ begin
+ Result := '';
+ while Node <> FRoot do
+ begin
+ DoGetText(Node, Column, TextType, S);
+ Result := S + Delimiter + Result;
+ Node := Node.Parent;
+ end;
+ end;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualStringTree.ReinitNode(Node: PVirtualNode; Recursive: Boolean);
+
+begin
+ inherited;
+ // Reset node width so changed text attributes are applied correctly.
+ if Assigned(Node) and (Node <> FRoot) then
+ PInteger(InternalData(Node))^ := 0;
+end;
+
+//----------------- TVirtualStringTree ---------------------------------------------------------------------------------
+
+function TVirtualStringTree.GetOptions: TStringTreeOptions;
+
+begin
+ Result := FOptions as TStringTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualStringTree.SetOptions(const Value: TStringTreeOptions);
+
+begin
+ FOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualStringTree.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TStringTreeOptions;
+end;
+
+//----------------- TCustomVirtualDrawTree -----------------------------------------------------------------------------
+
+procedure TCustomVirtualDrawTree.DoDrawHint(Canvas: TCanvas; Node: PVirtualNode; R: TRect; Column: TColumnIndex);
+
+begin
+ if Assigned(FOnDrawHint) then
+ FOnDrawHint(Self, Canvas, Node, R, Column);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualDrawTree.DoGetHintSize(Node: PVirtualNode; Column: TColumnIndex; var R: TRect);
+
+begin
+ if Assigned(FOnGetHintSize) then
+ FOnGetHintSize(Self, Node, Column, R);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TCustomVirtualDrawTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): Integer;
+
+begin
+ Result := 2 * FTextMargin;
+ if Canvas = nil then
+ Canvas := Self.Canvas;
+
+ if Assigned(FOnGetNodeWidth) then
+ FOnGetNodeWidth(Self, Canvas, Node, Column, Result);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TCustomVirtualDrawTree.DoPaintNode(var PaintInfo: TVTPaintInfo);
+
+begin
+ if Assigned(FOnDrawNode) then
+ FOnDrawNode(Self, PaintInfo);
+end;
+
+//----------------- TVirtualDrawTree -----------------------------------------------------------------------------------
+
+function TVirtualDrawTree.GetOptions: TVirtualTreeOptions;
+
+begin
+ Result := FOptions as TVirtualTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+procedure TVirtualDrawTree.SetOptions(const Value: TVirtualTreeOptions);
+
+begin
+ FOptions.Assign(Value);
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+function TVirtualDrawTree.GetOptionsClass: TTreeOptionsClass;
+
+begin
+ Result := TVirtualTreeOptions;
+end;
+
+//----------------------------------------------------------------------------------------------------------------------
+
+initialization
+ // This watcher is used whenever a global structure could be modified by more than one thread.
+ Watcher := TCriticalSection.Create;
+finalization
+ if Initialized then
+ FinalizeGlobalStructures;
+
+ InternalClipboardFormats.Free;
+ Watcher.Free;
+end.
Added: trunk/WPGM/ImportDefinitions/ImportDefinitions.cfg
===================================================================
--- trunk/WPGM/ImportDefinitions/ImportDefinitions.cfg 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/ImportDefinitions.cfg 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,38 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J-
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q-
+-$R-
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$YD
+-$Z1
+-cg
+-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+-H+
+-W+
+-M
+-$M16384,1048576
+-K$00400000
+-LE"c:\program files\borland\delphi7\Projects\Bpl"
+-LN"c:\program files\borland\delphi7\Projects\Bpl"
+-w-UNSAFE_TYPE
+-w-UNSAFE_CODE
+-w-UNSAFE_CAST
Added: trunk/WPGM/ImportDefinitions/ImportDefinitions.dof
===================================================================
--- trunk/WPGM/ImportDefinitions/ImportDefinitions.dof 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/ImportDefinitions.dof 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,132 @@
+[FileVersion]
+Version=7.0
+[Compiler]
+A=8
+B=0
+C=1
+D=1
+E=0
+F=0
+G=1
+H=1
+I=1
+J=0
+K=0
+L=1
+M=0
+N=1
+O=1
+P=1
+Q=0
+R=0
+S=0
+T=0
+U=0
+V=1
+W=0
+X=1
+Y=1
+Z=1
+ShowHints=1
+ShowWarnings=1
+UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+NamespacePrefix=
+SymbolDeprecated=1
+SymbolLibrary=1
+SymbolPlatform=1
+UnitLibrary=1
+UnitPlatform=1
+UnitDeprecated=1
+HResultCompat=1
+HidingMember=1
+HiddenVirtual=1
+Garbage=1
+BoundsError=1
+ZeroNilCompat=1
+StringConstTruncated=1
+ForLoopVarVarPar=1
+TypedConstVarPar=1
+AsgToTypedConst=1
+CaseLabelRange=1
+ForVariable=1
+ConstructingAbstract=1
+ComparisonFalse=1
+ComparisonTrue=1
+ComparingSignedUnsigned=1
+CombiningSignedUnsigned=1
+UnsupportedConstruct=1
+FileOpen=1
+FileOpenUnitSrc=1
+BadGlobalSymbol=1
+DuplicateConstructorDestructor=1
+InvalidDirective=1
+PackageNoLink=1
+PackageThreadVar=1
+ImplicitImport=1
+HPPEMITIgnored=1
+NoRetVal=1
+UseBeforeDef=1
+ForLoopVarUndef=1
+UnitNameMismatch=1
+NoCFGFileFound=1
+MessageDirective=1
+ImplicitVariants=1
+UnicodeToLocale=1
+LocaleToUnicode=1
+ImagebaseMultiple=1
+SuspiciousTypecast=1
+PrivatePropAccessor=1
+UnsafeType=0
+UnsafeCode=0
+UnsafeCast=0
+[Linker]
+MapFile=0
+OutputObjs=0
+ConsoleApp=1
+DebugInfo=0
+RemoteSymbols=0
+MinStackSize=16384
+MaxStackSize=1048576
+ImageBase=4194304
+ExeDescription=
+[Directories]
+OutputDir=
+UnitOutputDir=
+PackageDLLOutputDir=
+PackageDCPOutputDir=
+SearchPath=
+Packages=
+Conditionals=
+DebugSourceDirs=
+UsePackages=0
+[Parameters]
+RunParams=
+HostApplication=
+Launcher=
+UseLauncher=0
+DebugCWD=
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1031
+CodePage=1252
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
Added: trunk/WPGM/ImportDefinitions/ImportDefinitions.dpr
===================================================================
--- trunk/WPGM/ImportDefinitions/ImportDefinitions.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/ImportDefinitions.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,14 @@
+program ImportDefinitions;
+
+uses
+ Forms,
+ Main in 'Main.pas' {MainForm},
+ WpConfiguration in 'WpConfiguration.pas';
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TMainForm, MainForm);
+ Application.Run;
+end.
Added: trunk/WPGM/ImportDefinitions/ImportDefinitions.exe
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/ImportDefinitions/ImportDefinitions.exe
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/ImportDefinitions/ImportDefinitions.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/ImportDefinitions/ImportDefinitions.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/ImportDefinitions/ImportDefinitions.~dpr
===================================================================
--- trunk/WPGM/ImportDefinitions/ImportDefinitions.~dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/ImportDefinitions.~dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,13 @@
+program ImportDefinitions;
+
+uses
+ Forms,
+ Main in 'Main.pas' {MainForm};
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TMainForm, MainForm);
+ Application.Run;
+end.
Added: trunk/WPGM/ImportDefinitions/Main.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/ImportDefinitions/Main.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/ImportDefinitions/Main.dfm
===================================================================
--- trunk/WPGM/ImportDefinitions/Main.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/Main.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,5167 @@
+object MainForm: TMainForm
+ Left = 487
+ Top = 332
+ BorderIcons = [biSystemMenu, biMinimize]
+ BorderStyle = bsSingle
+ Caption = 'Import Definitions'
+ ClientHeight = 287
+ ClientWidth = 433
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ PixelsPerInch = 96
+ TextHeight = 13
+ object BottomBevel: TBevel
+ Left = 0
+ Top = 232
+ Width = 433
+ Height = 9
+ Shape = bsBottomLine
+ end
+ object TopImage: TImage
+ Left = 0
+ Top = 0
+ Width = 586
+ Height = 87
+ AutoSize = True
+ Picture.Data = {
+ 07544269746D617056560200424D565602000000000036000000280000004A02
+ 000057000000010018000000000020560200120B0000120B0000000000000000
+ 0000284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00274A00274A00274A00274A
+ 00274A00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00274B00274B00274B00284C00294D01254B00264D00284C00264802274B
+ 00284A03294D01284B01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294D01284C00284C00284B01274A
+ 0026480126480225470124460024460024460024460023440123440122420122
+ 4201244300234200234200244300244300244300254401264502264502264502
+ 264502244300244300234200244300244300243F00243F00233E00243F00243F
+ 00243F00233E00233D01253E00253E00253E00243D00253E00253E00253E0026
+ 4000253E00263F01264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01
+ 284C00274B00274B00284C00284C00284C00284C00284A03264A00264801274B
+ 00274902294C02294B04284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294D01284C00284C00284C00274B
+ 00274A00274A0026490024460024460024460024450223440122430022420122
+ 4201244300244300244300244300244300244300244300254401244300254401
+ 284402274301274301254401234200244201263F01263F01253E00253E00243D
+ 00253E00243D00243D00253E00253E00253E00243D00243D00253E00263F0126
+ 3F01264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 274B00274B00284C00284C00284C00284C002B5000284B01284C002C5003284C
+ 00274B002B4E04284B01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C0025470025470024460024460024460023450023440123
+ 4401244300244300244300234200244300244201244201244201234200244300
+ 284402284402284402284402244300244201264000264000264000264000253F
+ 00253F00243D00253E00243D00253E00253E00243D00243D00243D00253E0026
+ 3F01264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000294C02294C02294C02294C02294C02294C02294C02294C02284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01
+ 284C00284C00284C00284C00294D012A4E02284C002B4F02274A002C50042C51
+ 01274B002A4E02274B00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01284B
+ 01294C02294C02294B0427490226480125470025470125470124460023440123
+ 4401264502254401264502244300244300244201244201244201244201244300
+ 274301284402284402284402244300244300253F00253F00264000264000263F
+ 01263F01243D00243D00243D00243D00253E00243D00243D00243D00253E0025
+ 3E00264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00284C00284C00284C00284C00274A00274A00
+ 274A00274A00274A00274A00274A00274A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00294D01294D012A4E022B4F022648012E5009284B012749022B4F
+ 02284B012A4E01274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01284C
+ 00284C00294C02284B01284C00274A0026490026480125470025470125470124
+ 4600284402284402284402264502264502254401244300244201244201234200
+ 2443002743012743012844022544012443002640002640002640002640002640
+ 00264000264000264000243D00243D00253E00253E00243D00243D00243D0024
+ 3D00264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274A00274A00274A00274A00274A00274A00274A00274A00274A00274A00
+ 274A00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A
+ 00274A00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00294D012A4E022B4F022B4F02274E00375C14284F012648012D50
+ 06274B002C5003274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00274A0026480125470024460024
+ 4600284402284402284402284402274301244300244300244300244300244300
+ 2443002443002544012544012844022743012743012743012642002642002642
+ 00264200254100254100243D00253E00253E00253E00253E00243D00243D0024
+ 3D00253E00263F01264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801274A00274A00
+ 274A00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A
+ 00274A00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01
+ 294D01284C00284C002A4E012C50032C5003325A08426C15325909254B002E52
+ 062A4E012B4F02284B01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294D01284C00284C00284C00274A
+ 00274A00274A00274902284C00284C00284B01274A0025470024460024460024
+ 4502284500284402284402284402274301244300244300244300244300244300
+ 2344012243002344012342002743012743012844022844022642002642002641
+ 01264101264101254000253E00253E00253E00253E00253E00253E00243D0024
+ 3D00243D00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801264802244600244600254701274902274A00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274B00274A00274A00254903254A00
+ 264D00264C00254D00264D012248061F4B06264D02274D012750002C50032C50
+ 042E51012C53002B50002C5101284C00284C00284C00284B01294C02284C0026
+ 4900274A00274A00274A00264900274A00284C00284C00284C002A4E01284B01
+ 284C00284C00284C00274E002A51012E5800295600507B483B59282C52002959
+ 01274E03284E02274A00294D01284C00284C00294D01294D01284C00274A0027
+ 4A00284C00284C00284C00284C00284C00294D01284C00284C00294C02284B01
+ 294D01284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00264801274A00284C00284C00284C00284C00284C00284C00274E00274E00
+ 274E00274E00274E00274E00274E00274E00274A002C4F052446002B50002648
+ 02264802264801264801284C00284C00294D01284C00274D01264D00274E0027
+ 4E00274A00284A04294B05294B05264802274A00284C002B50002A5101305A05
+ 234A002B52072A4E02284A032C5004274D01284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00264900274A0027490226480126480126480126480126
+ 4801284A04284A04284A04284A04284A04284A04284A04284A04284A03284A03
+ 284A03284A03284A03284A03284A03284A03284A04284A04284A04284A04284A
+ 04284A04284A04284A04284A03284A03284A03284A03284A03284A03284A0328
+ 4A03284A04284A04284A04284A04284A04284A04284A04284A04264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600244201244201
+ 2443002342002443002544012443002443002642002642002642002642002642
+ 00264200244300244300254000243F00233E00243F00243F00243F00243D0024
+ 3D00233E00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801264802244600244600254700274A00274A00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00274A00274A00274B00264C00
+ 2C4E012A50002C52002851002C50032B4E042E52002E51012C53002C56003155
+ 012E50032B4D002C4F002C5003294D01284C00284C00294D012A4E02294C0228
+ 4B01274B00284C00284C00284C00284C00284C00284C00284C00274B00264C00
+ 284A03264900274B002A4E012A52002C56003063096E9568477632335C012E5C
+ 03294F03285002244B00284C00284C00284C00284C00284C00274B00274A0026
+ 4900284C00284C00284C00284C00284C00284C00284C00284C00284B01284B01
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274A00274A00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294D002A4E01274A002D51052648
+ 022B4F022C50042B4E04284C00284C00284C00284C00284C00264C00274E0027
+ 4E00274A00294C02284A03284A04264801284C002B50002A51012B5500284F01
+ 335A0A2244002D4C07274D012A5103294D00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00264900274A00274A0026480126480226480126480126
+ 4801264802264802264802264802264802264802264802264802264802264802
+ 2648022648022648022648022648022648022648022648022648022648022648
+ 0226480226480226480226480226480226480226480226480226480226480226
+ 4802264802264802264802264802264802264802264802264802264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600264502254401
+ 2544012443002443002443002443002443002642002642002642002642002443
+ 00244300244300244300254000254000243F00243F00233E00243F00253E0024
+ 3D00243F00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264802264802254700254700264801274A00274B00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00294D01284C00284C00284C00294D012B4C01
+ 275400335403315501375A03315503315600375B01375B01345A02355B033054
+ 003354032C51012750002C50042A4E01294D01284B01284C002A4E02294C0228
+ 4B012A4E022A4E02294D01294D01294D01294D01294D01294D01284C00284B01
+ 264A04284906294B042A51012F55032E570235620180AA75527C453360032955
+ 02294E042D5104254C00284C00284C00284C00284C00274B00274B00274A0027
+ 4A00284C00284C00284C00284C00284C00284C00284C00284C00274A00274A00
+ 274A00274B00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C002A4E022A4E022345
+ 002C50032C5004274B00264C00274D01294D01284C00294D01294D01294D0128
+ 4C00284C00284C00274903294C02284C00294D012A52002C56002D59002A5300
+ 3059082B51052C50032C5004274E002E4E01284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00274A00274A0026490024460024460024460025470026
+ 4801264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600274400284500
+ 2844022844022544012443002442012442012443002443002443002443002443
+ 00244300244300244300264000264000264000253E00243D00243D00243F0024
+ 3F00243F00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801244600254700264801274A00274A00274A00284C00294D01284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00294D012751042C5206
+ 305400365C023A5A013C5D023F5E033F5D04415D033A64003763043B5B02365D
+ 07305C002E59022E55002B4F02294D00284C00274A00284C00294D01284C0028
+ 4C00294C02294C02284B01284B01284B01284C00294D01284C00284B01274E00
+ 2A4C062B4D07294E042C50032F5901345B062B590078A677527B482D5C002A55
+ 002A4C052C5305244F00294D01294D01284C00284C00274B00274B00274A0027
+ 4A00284A03284A03284A03294B04284A03284A03264801264801264900264900
+ 274A00274B00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00294D01294D01294D00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284B01274A002A4E02294D00284C
+ 002C5003294C02284C00284C00294D01284C00274B00284C00294D01294C0229
+ 4C02274B00284C00284B01294C02284C002A4F002C56002F5902315C01335907
+ 2F52084677332F53062E55002C5200244E01284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00274B00274B0026490024460024460024460026480126
+ 4801264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600274400284500
+ 2743012844022844022743012844022844022443002443002443002443002443
+ 00244300244300244300264000264000264000264000253E00243D00233E0024
+ 3F00243F00263F01264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801244600264801274A00284B01284C00284C00284C00294D01284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274B00274B00284C00284C002A4E022B4F032E55072C5600
+ 385B003060003B65003965003863023A63014167073F69043864013C63013463
+ 003362002F5E02335C012B51002A4E01284C00274A00274A00284C00284C0028
+ 4C00264C00264C00284C00284C00274B00274A00274A00274A00264B01294D01
+ 264C00294C022B4F032A51012F5600315B0334610085A778547B473361012D59
+ 002D5105295103294D00274B00284C00284C00284C00284C00284C00284C0028
+ 4C00294C02294C02284B01284B01284B01284B01274A00274A00284C00284C00
+ 284C00284C00284C00294D01284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00294D01294D00294D002A4F002B4F022B4F02
+ 2B4F022B4F022B4F022B4F022B4F022B4F02274E00274E00284E022C5200345A
+ 083056042B50002F54042D50002D50002A4F002A4E012A4E01274D01264C0027
+ 4D01264C00284C00294D01284B01274B002B51002D5601315B03336200315B06
+ 4776315284362F57052B55022E5500264A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00274B0026490025470124460024460026480126
+ 4802244600244600244600244600244600244600244600244600264801264801
+ 2648012648012648012648012648012648012446002446002446002446002446
+ 0024460024460024460026480126480126480126480126480126480126480126
+ 4801244600244600244600244600244600244600244600244600244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460024460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600284402284402
+ 2844022844022844022844022844022844022443002443002443002443002443
+ 00244300264200264200264000264000264000264000264000253E00243F0024
+ 3F00243F00263F01264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801274A00284B01284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00294D01284C00274B00274A00284C00284C002A4E022B4F02385B01385B01
+ 336101376304396A023A6C00396C0B3D6C0A3A6D0B3B6B0B396D093A6D0C3A64
+ 00346003316101315D002C53002A4E01294D01284C00284B01294D01294D0028
+ 4C00295000284F002950002B50002B50002B5000295000295000295002285000
+ 2A4E01274E00284F002C52002E5800315C0130640683A977507D453461003461
+ 002B52062B5400284F01284C00284C00284C00284C00284C00284C00284C0028
+ 4C002B4F022B4F022A4E01294D00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00274A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00294D01294D002A4F002B51002B5100315501315501
+ 3155013155013155013155013155013155012A53002C5500284F012D5301365D
+ 072E55002D57002A52002E58012D57002C56002C55002B53012C51012B4F022C
+ 5003295000274C02294D01284C00284C002C52002D5601315C01315B03315A09
+ A6C99047782E2A5B053058002C5903264C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294D01284C00274A0026480124460024460026480125
+ 4701264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460024460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600254401284402
+ 2844022844022844022844022844022844022443002443002443002443002443
+ 00264200264200264200264000264000264000264000264000264000243F0023
+ 3E00243F00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801274A00274A00284C00284C00294D01284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00264900284B01284C002B4F032C5003375A033E5D00
+ 3766003B6A033A6D0B3975173775173A76183776163977193976143675173C6C
+ 0C3D6C0A3965023460012E54022D52022B4F02294D002A4E022B4F032D51052C
+ 50042B55022C55002C55002C56002D57002E58012E58012F59022F59012C5500
+ 2C56002C55002C55002E5900315C0134610033620084A879547A48346003325D
+ 022A56032D5000274F01284C00284C00284C00284C00294D01294D012A4E022A
+ 4E012C56002C55002E55002E55002D53012C52002A52002A52002B4F032B4F02
+ 2A4E012A4E01284C00284C00274A00274A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00294D01294D002B51002E54022F5503375B01375B01
+ 375B01375B01375B01375B01375B01375B01315C01315C01305800345C04355E
+ 03315B04426D162E5A01346202326000315E01305B002E58002F560031550131
+ 55032A52002A52002B5000294D012A4E012F5601305A02315C01316200406D17
+ C8F2C9365B172D5C00325E012A54002A4F05284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294C02294C02294C02284A0327490326480126480124
+ 4600264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460023440123440123440123440123440123440123440123
+ 4401244600244600244600244600244600244600244600244600264502264502
+ 2844022743012743012743012743012743012443002443002443002443002443
+ 0024430024430024430026400026400026400026400026400026400025400024
+ 3F00243F00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801274A00274B00284C00294D01294D00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00264900284B01284C002C50032C5003355C003D6500
+ 4168063B6C0A4273094279163B7828397A243C852939852747862844831D4279
+ 163C74093D6A033864003056042E54022C51012A4E012A4F002C50032E51072E
+ 51072D59002E5A01315B03305B00315C01345E06345E06355F07346100345F04
+ 345E06315B03315C01335F003764033B6A0432620989AA87578647336101305B
+ 002E5507275400295000284C00284C00284C00284C00294D012B4F032B4F022B
+ 4F022E58002E58002F56002F56012E55002E55002C55002C55002C50032C5003
+ 2B4F022A4E01294D00284C00274A00274A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00294D002A4F002B51002F5503305604375B01375B01
+ 375B01375B01375B01375B01375B01375B013461003862033965003D69043965
+ 02416D14628F393A6D0B3A6301396502366302346001315D00305A022E58012C
+ 56002C55002D56012D52022C52002C52002E5500315C01335F003B6409548638
+ C8F3C8365A14365E063460012252002B5206284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294C02294C02294C02284A0327490326480126480124
+ 4600264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460021440121440121440121440121440121440121440121
+ 4401244600244600244600244600244600244600244600244600264500254400
+ 2844022844022844022743012642002442012443002443002443002443002443
+ 0024430024430024430026400026400026400026400026400026400025400025
+ 4000233E00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254701244600264801274A00274A00274902264801264900264801264801
+ 2648012648012648012648012648012648012446002547002446002547012446
+ 0025470124460024460026480125470025470026480126480126480126480126
+ 4802284C00284C00284C00284C00284C00294D01284C00274B002E4E00264D00
+ 325302264C002E5500285100254401285002284E06264C00264D01254C002449
+ 01284C00295000284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274D01284C00284C00284C00294D01284F012951002C550029541B296501
+ 32620A4279163A7618588B598AAA91A7C8B3C8D9CBC7D9CCC5E0BFA3BBA977A5
+ 764877333774062A72072D6401235A002151022951032D5605305500365B0038
+ 64013B630B385B01406A053A63023864013B6C04396A023269023B6B01346902
+ 3D6B013B6B013B6A04316902346901316B0C39761684A8795786473973062659
+ 022E5D002A52002A4C06214C012A5302294B04244600264801314C0331560035
+ 5C003362003B64023A5D03425C02426A053A63012C6601316801415D03315503
+ 3054002C4E012D4E042B5207244900285506284C00284C00284C00284C00284C
+ 00284C00284C00284C002847022C5004274A00254A022A5004214D002753002A
+ 5200305C03284E0232520B2A4C00335F042D5900315C01315B08336200346001
+ 375B013F5D043F5E033F5E033460033A63013B6C00396C0B2B65003E6C0C4279
+ 16416D1484A9773B6C00316902326804296501316200345F04336101325B0033
+ 62003161012D59002E5A002E55002D5801305C0131620039650C326A01568D54
+ B5CBB83C64003269023162002E58002B55002B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00274B00274A00274A0027
+ 4A00244600244600244600244600244600264802264801264801264802254701
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460024460024460024460024460024460024460024460024
+ 4600244600254701264802244600244600264801264801264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440224430024430024430024430024430024430024430024
+ 4300244300254401244300254401254401244300254401244300284402274301
+ 2642002743012743012844022443002342002443002443002342002443002443
+ 00244201244201244201254000254000243F00233E00233E00233E00243F0023
+ 3D01253F00253F00264000264000253F00264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600244600264801274A00274A00274A00274A00274A00274A00274A00
+ 274A00274A00274A00274A00274A00274A002648022648022648022648022446
+ 00244600244600244600264801264801264801274902274A00274A00274A0027
+ 4A00284C00284C00284C00284C00284C00284C00284C00284C00294902284C00
+ 2E52002C56002A51032B54002E55072B5301284E02264C002951032D5104244B
+ 00254701284C00254B00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274D01284C00284C00284C00284C00274E002A52002C55003B6500367206
+ 3E640A527C45A6C990EDF6F9F0FEFDECFEFDF3FFFFEBF7F9EDFDF2EAFFFDEBFF
+ F2C8D9CC629153365B153864013A6603306000315C01375B013863023F680642
+ 68043774063972093575043B6A033A74084079173C6E0A377517367305347208
+ 376C0B3B6C0A3B6D0F3777143877173C751A37771797BB97588D54326B09346A
+ 00326104265600264802214E00264D00274A00254B002A5103305505385B0137
+ 5C00436808426A0440730B417A1840730B3C6D0B3B6A0D436907386401346001
+ 345F083757062D50002B4C01284E02254700284C00284C00284C00284C00284C
+ 00284C00284C00284C002C5101294F03224400264A042C5004284F012F59012B
+ 59002E5A00234A003155083253092B51003D6303416A013B6403385B01375A00
+ 3863023B65003362003A6902386C012B650033630A30630737720938811B2872
+ 08396B1776B07A377307316B0C3669013A6B00387507386C013469023B6A033A
+ 6B01365D12365D083361012B65003261043361013965004268043773078A9D84
+ 98AD97336101316902315C012E55002A51012B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00274B00274A0027
+ 4A00244600244600244600244600244600264802264801264801244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460024460024460024460024460024460024460024460024
+ 4600254700254700264801264801264801264801264801264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402244300244300244300244300244300244300244300244300274301284402
+ 2743012844022844022844022743012743012645022544012443002443002443
+ 00244300244300234200264000264000264000253E00253E00243D00243D0024
+ 3D00264000264000253F00264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254701264802264801274A00274B00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284A04284A04284A03284A032648
+ 0125470024460024460024460024460025470125470126480127490226480125
+ 4700284C00284C00284C00284C00284C00284C00284C00284C00294A002A5204
+ 284F013055002952002C55002D5503224A032D5507234D00274D01295201264D
+ 01264801284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00284C00284C00284C00284C00274E002A52002D56013765023D6B01
+ 578648B9D8BBF1FFF4F2FFFDD7EAD9B8D7BA93BC979AC9A38BC699CCE6D6D0F0
+ D1EBFDFED1F0CF709468426E153B64034369054169043C6D013F6B003B6A0340
+ 7409407916427817497B1D49841B4278143A77152E731837811B397927397A25
+ 44781A436E133877173A79233D782736831B47772FB5CDBB6B9467346A093B6C
+ 043261002E5A012E5009274D01254A00274A002950002B5400295901305B003B
+ 630438640044750943750937761645821A43851C4178154379183573073B6B01
+ 2D5900345A00395C022A4C002B52072A4C05284C00284C00284C00284C00284C
+ 00284C00284C00284C002A4E01264900274902284E062C52062850022D57002D
+ 5900284F00436E17254A02345E07396403426A053965023E5D02375A03406B04
+ 3C6C022765013971083774062C71083A7717336C0A3D7925458319366B144587
+ 35558D5299B9A86A95685A8D535F905267915459854850863947772F406D172A
+ 52042D64013463012F5B0830580A335F063F6A033B6B013864013B6C0AAFCDB0
+ 6A96673269023B6C00365D08325A082D56052B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00274B00274B0027
+ 4A00264801264801264801264801254700264801264802264802244600244600
+ 2446002446002547012547002648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801274A00274A00274A00274A00264900264801254701264802264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402284402284402284402284402284402284402284402284402274301284402
+ 2844022844022844022844022844022844022743012844022844022743012443
+ 00244300244300244300264000264000264000264000264000253E00253E0024
+ 3D00264000264000253F00253F00264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600264802264801274A00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294C02294C02294C02284B01274A
+ 00274902254701244502264801264801264801264801274902284A03284A0328
+ 4A04284C00284C00284C00294D01284C00284C00284C00294D002D4E04355308
+ 2C55002C55002F5B022D5C06214A00375A17396A162E5507204C00284F01274F
+ 012A4E012B50002C4D02284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00294D00284C00284C00284C00274E002A52002C5500335D08346202
+ 899C81EEFEF3AECDAC6F956B5586484F8538478A47458A4746893494BD8A5986
+ 47899E85C0E6C8CFE5CD4F7A1F4078194074093B6A0335730741831A42841B43
+ 831946852946842A588449659154517B46527B486D936987B586A5BBA8A9C7B4
+ B2CDB9C7D9CCB4CCBA9EB497889D846A9568547C45ABC7B46D94673E6E153B6C
+ 0A2F59022651002B5006295005254C012950042950002A52002B5A003965023B
+ 6B013674083773073975173A842A46893444883537792747862838811A427817
+ 316902336003385A032D5100274B002B4B0A284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00294D002B4F002B52042851002855002E5A002C
+ 5902375C1281B96E345A08345E074169033C64003B6402416806426808315C01
+ 3068013774063977193B741743773146762E56854678A26BA6C991C3E1BEF5FF
+ EED9F7E4F3F9FEEEFFF2D6E8DBB6DAC4A8C7B8B2CDB9CBE5D7ECFEF1E4FDE9B6
+ CCB97AA369457731315C01305C033463062A5B0532620A41750A456D15D9F7E4
+ 527C45397307386C00335C002A54012D51042B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0027
+ 4B00264801264801264801264801254700254700244600244600244600244600
+ 244600254701254700264801264801264801284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274B00274B00284C00284C00284B01264900264801264802264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402284402274301284402284402284402284402274301284402284402284402
+ 2844022844022844022844022844022844022844022844022844022844022743
+ 01284402264200264200274101264000253F0026400026400026400026400026
+ 4000264000263F01243D00243F00254001264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254701264802264801284B01294D01284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284B01274A00274B
+ 00274A0026480125470126480126480126480126480226480226480227490326
+ 4802284C00284C00284C00284C00284C00284C002A4E012B4F022B52062D5601
+ 365D07315D0039640D2E53032B510578A26B406E152F5C06295000265100284F
+ 012A4B00264D00294A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00294D00294D01284C00284C00274E002A52002C5500365C14276812
+ B0CDAC98C8A4518734397A254486274785273C8F2D39842851963B9CD7AA5196
+ 3B517E46558648AAD5AA65A45445862A48831A4587284587283885293B792748
+ 8737398A3558995495BE8BC2E6C8E2EFDFFAFFFEFEFEFEFFFAFFEDFEF3D4E8DC
+ C8D8CDB4CCBAB5CEBAB8D7BAD3EFD2E4FDE9B0E5BAE2FDF9A0B4973A77172C66
+ 013163052E5902285100254A02244D022B51002C55002B58013B64023B6B013B
+ 6B012C73053978286A9568A4B9AAB6D8BABAD9BA87B489578B55397A254A831A
+ 44811F3B6B01315D00355B01295000224700284C00284C00284C00284C00284C
+ 00284C00284C00284C00284E022A4E012E5101284F012C5600355F0739640932
+ 6307385829A5C890426E153D65003A6A043B6B013F68063965021E63022F7108
+ 3776183B7417457731507C478AAA91C8D8CDF2FEFEEDF8F6CAF1D198B8A585A8
+ 767AA16DB5CEBA45772F427719396C0A3C6D0B346A092F59013263074F7A1F51
+ 8636879D84B0CCAFB2D2AF7CA36B3E6A0B2866023C6C023D6C09457731E5FBE8
+ 4376323A6B01335F022B59002F57002A52042B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00264801264801264801264801264801264801244600244600244600244600
+ 244600254701254700264801264801264801294C02294C02294C02294C02294C
+ 02294C02294C02294C02294C02294C02294C02294C02294C02294C02294C0229
+ 4C02284C00284C00294D01294D01284C00274A00264900264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402284402274301284402284402284402284402274301284402274301274301
+ 2844022743012743012743012844022844022743012743012743012844022844
+ 02284402264200264200274101264000253F0026400026400026400026400026
+ 4000264000263F01243D00243F00243F00263F01264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600254701264801284B01294D01284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00274A00274A00274A00274B
+ 00274B00274B00284B01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00294D002B4F022C50032C5902295502
+ 386401346001365F04244E01527B48A6C990335D062E55002A5401305402264E
+ 00264801284C00274D01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00274E00294D01284C00284C00284F012A52002E5500265A002E6502
+ AFE3BB4377312D73184786283A85293688353A893244894652974699D5A55596
+ 4A558B564B8A4565A3578BC797559746398936468A37458736517E465A8B5774
+ A775C5DACBEDFCF4F1FFFBF3FFF9E3FFF1CBE5D798BB996A95683B7927366A17
+ 386A16416C15377517396B17387618468626609153C8E6D3C5E0BE54963D3268
+ 042E5D012D58012A51032648012B4C01274D0129510033610134610030610039
+ 6502477632AECDAEF8FFF8F8FBFFFFF6FFFBFDFEF7FFFDE5FBE977B17A457632
+ 3B79273775172C6502336000325A082A4E02284C00284C00284C00284C00284C
+ 00284C00284C00284C00294902254A002C51012B5202325B00386409315B0333
+ 5C0186B48964905339630B427916396D013B6B0B3469023269022C76183D7827
+ 4776316E9666B1CBADDCF8E5F1FFF8E9FEFBAECCAF6B9566467832547B473D78
+ 2844792FAEE2BA43781A407409326B02316801326B02305B00345F04365D0732
+ 5A08365B152C5504396C1561905195BF8A95BE8B62A1573A76186C9667D1F0CF
+ 386917316801346301385E06315C013053092B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294D01284C00284C00284C00284C00284C00284C0028
+ 4C00284A04284A03274902264801264801264801244600244600244600244600
+ 244600244600254701254700264801264801284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274A00274A00274902264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402284402284402284402284402284402284402284402284402244300244300
+ 2443002443002443002443002443002642002743012844022844022844022443
+ 00244300234200244300264000264000264000264000264000253E00253E0024
+ 3D00264000263F01243F00243F00243F00243F00253E00264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600244600264801274A00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00274902264801264801274A
+ 00284C002B4F022C50042E56042D55032B52022C51012C51012C51012C52002C
+ 5200284C00284C00284C00294D01284C002A4E012C50032D5104315D00335F02
+ 3460033766002F5B00345C1593BF8A6C95682F59022A55002F56012C5500254C
+ 002749022B4F03294F03284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274F01284F012A4E02294D01284C002A4E012D53012E55002C6601326902
+ ADCCAF477631437916428627397A2547782E3B7925498A45458B44A4E7C24CA2
+ 544689464BA454399145489954448A44498947527C476F956BB1D3AEDCF8E5F3
+ FFFEFFF6FFFEFFFDE2ECE6B6DAC46A966746883730802537821A387717356C09
+ 326307326B09346B08356B0A3774193C8628477632B5CFB895BB973877172B64
+ 023660012B5900254B00264A00284C00234901265100315D00305A0230620A4D
+ 791EB4CEB7E0F0DFCDEFD0B8DAC2CAE4D6EFFFF4F9FFFEFFFEFEDAF8E584A977
+ 47772F3A7B25306B09285B012E54022C4E01284C00284C00284C00284C00284C
+ 00284C00284C00284C00274800264B012A53002D59003965023362002F5B0241
+ 6C15D9F6DC527C47426C1544831D377209346A09346B163B7A24437731578C53
+ A7C8ADEBFCF1F8FFFFF1FFF3C5E0BF6C956846821D4379182E7207397A253886
+ 28497532A9D6AB386A162B6401336800356A032D5900295900355F07325E052A
+ 5504275B01316200326A012C6502245B00386A16588E5388AA92B6CEB6B9D6BD
+ 436D163D6A033A6301345F04265500284C002B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294D01294D01284C00284C00284C00284C00284C0028
+ 4C00294B05294B05284A03264801264801264801244600244600244600244600
+ 244600244600244600244600244600244600284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274A00274A00264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402244300244300244300244300244300244300244300244300254401244300
+ 2443002342002443002443002443002342002443002443002342002443002442
+ 01244201244201234100264000264000264000253E00253E00243D00243D0024
+ 3D00254000254000253E00253E00243D00243D00233E00243F00264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600244600264801274A00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274B00274902264802264801274A
+ 002A4E022F5307305309315C012F5A002E58002D57002F56012E55002E55002E
+ 55002A4E02294D01294D01284C00284C002A4E012D51052D51053461003A6B01
+ 2C65023D6B0139650C5B8645D6F6DD3B582B31640A305D002B5900295300244B
+ 00274B00284F01274902284C00284C00284C00284C00284C00284C00284C0028
+ 4C00285100274E002A4E02294D01284C002A4E012E54022F5601336101315D00
+ 879D846C966739761642791647862843862B47862A509747498A45AFE3BB65B1
+ 6A489A51379F403C9E44489954529A6586D5A2CCF1C9F3FDECFBFFF9FEFAFFFF
+ F5FDB2E3BD78B88472B1798DC7975786473B7927427719326A013B6B01376502
+ 3361013362003762013D63093A6D0B377618457731BAD9C486AA86396C0A3B6A
+ 03305C012A52002B4D06274902294F032951002C5B003462092C5902426E1567
+ A257F5FFF36A95682276283B90453C914765A675C9DACDFEFDFFF7FFFEC1E7CB
+ 6D95653B78282E71081C63032E5A002D4F02284C00284C00284C00284C00284C
+ 00284C00284C00284C00264D002C4F052F56012C5A013864013C6400416F1665
+ A357A4C8AA43782F4F7A1F44831B3983192D74173C852946883779AC86D8F7DA
+ F6FEFEF4F6FEECF3F09CB4964A78302D80243C6D0B3877173573073A77153975
+ 17467830B2D3B0436C17346B083169022F5B00225902275901255900265A0031
+ 5B033460012B5900285A02326307306309356A09397209388218CAE4D69EB497
+ 406E153B6B01366302345E062654022C52062B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C002A4E02294D01294D01284C00284C00284C00284C0028
+ 4C00284A04294B05284A04264801264801264801244600244600264802254701
+ 244600244600244600244600244600244600284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274A00274902264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440224430024430024430024430024430024430024430024
+ 4300244201244201244201244201244201244201244201244201244201244201
+ 2442012442012442012341002442012442012442012442012442012442012341
+ 00234100234100224000254000254000243F00233E00233E00233E00243F0023
+ 3D01243F00254000243D00243D00243D00243D00233E00233E00264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00274A00284C00
+ 284C00284C00294D01294D01284C00274A00254603274902264801244901284F
+ 002F5503385B013B640239630C2C740431670333630A2063022E6601345A002A
+ 5400274D01284F01264D00204B02264D022B5100305400355B03427309366502
+ 3671082F7308376B17D8E9DB879E822C7108386400335C002D5202294B042A4C
+ 06274C04254C01234D00214E00274E022C4D03294805294803314C032C510927
+ 4C062D4E042C4F002852002F55032B4900294F032C51012B59002D58012C5107
+ 49772EB3D2B387B489527B4847772F45772F4888363B8935489954B2E4BA76A6
+ 7653975678B07BA7C8B3E7ECF5FFF5FDFFFFFFF5FFFEF1FFFBD5F6DB8BC69965
+ A45446984646974883BE929FCFB746831B407819376B17316902305C012E5800
+ 2C58002A5700355B093362063B6C0A38751A4D8526B7CDBB9DB397356C093A6B
+ 03335C012D53012956002E4E002945032C52062D56012F5B003D6B01396409AF
+ CEAD8BC7973B792537832B38852A4889443A9246469A528FE1ACFBFFFFF4F6FE
+ AAC8B54689442E75183D6B012C5200265108295000264D00254B00264C00294D
+ 01294C02274902254A022B4705285100305C012F4D01335C012A72072D6911C7
+ D9CC76B07954863853853743862B3984283A9246478C53B3D2B1FDEFFBFFFBFC
+ ECFCF5B3E5BB48A3542E7F284379183169043361013A6B033A6B01376B0D3973
+ 07366A17E0F0DF3965003462023361012E58002A52002950022A4E012B4F022C
+ 51012D59002A520432520B3059082E66013B6C04396B17598548F2FFFE5B8647
+ 437918326902275B01305C013054002F4903284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00274A00264900274A00274A00244600244600
+ 244600244600244600244600244600244600264801264802284A03294C022A4E
+ 02284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00274B00274A00264801264801264802274A00264801
+ 2648012446002648012648012547012446002544012443002544012743012743
+ 0128440228440227430126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 264000264000264000264000264000264000243F00243F00243F00243F00243F
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00254001
+ 263F01264000264000264000253F002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00284C00284C00
+ 284C00284C00284C00284C00274A00264900224700264C04234800224C002A52
+ 00375C00376403416903437A17367206356C1781B771396A18316904385C0233
+ 5C012B5000285100274E00254C00254C002A5401385B003E5D023D6B014E791E
+ 3B771946862686B489E2F0DE517C432B6402296402335C012A5401294D012F4B
+ 05274903274D01215102214D002C52062A4C00324D033352072C4F002E510128
+ 55003054072D59002C55002B5500284B01284D032850022952002D5801336200
+ 21510343782E79A269C9F3CAD1EFD29AB9A496BB9992BB96A3BAABE1ECE4D5EA
+ DBE7FBE8EBFDF6FBFFFFF0FEF8F2FFFAECFDF2B8D7BA78A77656854648873746
+ 923A46913B44883589B487B2CDB9437A17356C092F62063461002E58002B5500
+ 2B52002D55032A5700305C01346A093F73074F7B1EB8D9B789AA873269023B6C
+ 00315D002F5503275000294D012948032C5101325500305C0131690238630CB4
+ CDB977A5763B792739821B3777143D78273B84283B8936559B66E3F8EFFCFDFF
+ E5FBE866A4683985273169043362002B5502284F00284F01264C00274D01274D
+ 01274C02264B01254A002B4803264C002E5A013A640C446B152A7207678F55F4
+ FEED598647518636468837479A453B9045588C56CEF0D2F5FFF3FEFAFFF5FAF9
+ A6C6AD578B553A86283176152A6601346001315D04386401326A00346902396A
+ 0249772EE8FCE93A6B013361013361012F59012A5101284F01284C002A4E012B
+ 50002E55002B51002C5107356005336900326804356B1865A367E5F6F2527B48
+ 407409346901325B002D58012F5601324D03284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00274A00274A00274A00274A00244600244600
+ 244600244600244600244600244600244600264801264802284A03294C02294D
+ 01284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00274B00274A00264801264801264802274A00254700
+ 2547012446002648012648012547012446002443002443002844022743012844
+ 0228440228440227430126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 264000264000264000264000264000264000243F00243F00243F00243F00243F
+ 00243F00243F00233E00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00243F00
+ 263F012640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00294D01284C00
+ 284C00284C00284C00274A00274A00264801244502274700264704264B013254
+ 00335D06426A05437A174485293B79256E9567F3FFED77A5763A6B153A6B0336
+ 5F032C56002A52002A4E02284D032C4F00305400345E073C650A437A1744831B
+ 468836538B56D1F2D0A7C7B44678322E7207346902315D022E5402284D052A4C
+ 06284B01264D02234D00234D002850022847022D51003155012B540034630131
+ 62002F5B00356104315D002D5900254B002B4B0A2B4C022951002953002D5900
+ 34600334600132640658854687B58ADAF8E5FAFEF3F3FFF3ECF8F8FFF9FFFDF8
+ FFF5FFF9F0FFF7ECF3F0ADD4AE74B179588C5646792F4775333A86282F7F242E
+ 8027448627387B2682B687B6DAC43774062E6601345E072E5800265401295002
+ 294D002C52002E5402305D003469023C6D0B3A7618CAE3D587AC843B6C0A3469
+ 023059002D5900294F03284F002847022C4F002F5902315C013068013C6C0CB8
+ D7BC568D56396A183273063B6C0A3A7715387618398329478B4498B9A4F9FFF9
+ FDFEFC9AC9A3398A353076192F6A02315503295000295002274D01264C00264C
+ 00264C00274C02254A002C4B062F5C00315C013F6806446F14356B1895BE8BE0
+ F0DE5086395098453D91493790466AA578D3F6DBFAFFFAFFFFFFECFFF0B0CCAF
+ 568D54397A242C761834690B3462002E5A012E50032E5A012C65022C65023573
+ 09527B48ECFDF23C6B043361013361012E5A01295000274E00284C00284C0029
+ 4D002750002B4C01274E00325A022C6503316703467733AAD5AAC7DACB487634
+ 357307326804315C012B55002A5000304D04284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274A00274A00264900264801264801
+ 264801264801264801264801264801264801264801264801274902284B01284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00274A00274A00264801264801264801274902254700
+ 2446002446002648012547002446002446002443002743012844022743012844
+ 0228440227430125440126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000253E00253E00
+ 253E00253E00253E00253E00253E00253E00233E00233E00233E00233E00233E
+ 00233E00233E00233E00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00243F00233E00
+ 253E002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C002A4E01294D00
+ 284C00284C00284B01274A00264801264801214602274C002A4B00294E00375A
+ 0333630A426D164D7A1D3D912B568546B2CDB9FFFEFFCEF2CE45772F417A1732
+ 69022D59002A54002852002A4F002E52002E5A013B64093A6D0C4D78213C8626
+ 458D519BBBA2F6FEFD9BBC9947883338831B346A092F6103295600274E00294F
+ 03254B03294D01274D01285205244B00274E002952012953003462023D6A032C
+ 6601396502306900316902335B03284F032E5003204C05285002284A042A4F05
+ 365D07255A00286503326B08366A1645772F6E956786B5879BC8A1E0EBE8B2CD
+ B97AB68668A369517949468836478628397517306B09346C072D64012D720938
+ 811A3B79253A782489AA87B5CBB82F6A02346001315B062D5702265300284F00
+ 294D002750002C5500315D0432690242730B397517E3FFF089AA883C6A0A3169
+ 022956002D56052951002D4D00254A06294E002D59002E5D002A66023B6C0AB9
+ D7BA6C96673976143875073F6A033665002C650237821A398A33539B66DBF7E4
+ FEFFFBDEF1DE448A443986252B66003956002B5202295002274E00264C00274D
+ 01274E00274D01264B012A4B01315C01315C013C6C02416D14527C47C8F2C9A7
+ BBA84DA4543992434BA45558AA75DAF8E5FDFEFCF1F4F2FEFAFF98D5A9589857
+ 3D7925437918306803335C01345E06294902284D092B5500356201326A013573
+ 07639254EDFEF13864003362003361012D5900285100274D01264C00284C0029
+ 4D002B4D00284F012251022A66022B6401326307578745E6FDE79BB9A6387A21
+ 3573073169022D5801284F002A4E012A5103284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00274A00274A00264801264801
+ 264801264801264801264801264801264801264801264801264801284B01274B
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00274A00274A00264801264801264801264801244600
+ 2446002446002547002547002446002446002844022844022844022743012844
+ 0228440224430024430026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000253E00253E00
+ 253E00253E00253E00253E00253E00253E00243F00243F00243F00243F00243F
+ 00233E00233E00233E00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00243F00233E00
+ 253E00263F012640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C002A4E01294D00
+ 294D01284C00274A00274A002648012648012348002949022D4D00315600355F
+ 083B64093877174786283A933694BB8DFDFFFFF6F6FCF1FFF886B48939852739
+ 751733630A2659012952012C52003054002D5B02396C043F7307508528469748
+ 549B63E4F7F4FBFFFFD0EFD2509747498F2B3878153564082E59002A52002E50
+ 03284C00274C02264E002D5100204B022F5B00335B03335C0132630732630750
+ 8327407A15356B0A3D6B003361012956002A4D03264B012B4F02304C10264A04
+ 2B4F032751003362002965013469023973073B7925479946438D51BAE6C765A6
+ 753789363A902C398428367108336C09306801326902346001336101316B0035
+ 6D083A771737792789AA87B6CCB92E65023B6402315A05315B03285200264D01
+ 2649002A4E012C5700315C01306A0B4475074F7B1EF0FEFC88AA853A6C0E3268
+ 042A55042D5406285100284F00294A072750002F5901325B002A6602396C0AAE
+ CDAE85A97B397A25427408386203305C032D65002C7207397517399046B9D8BB
+ FFFAF9FFFFFB77A5763B8936346804405C032B5202284F00274E00254D00264E
+ 00284F01274E00274D012750002B55003069004079163B79277AA16AE4FEF077
+ AD823B9E4248A96657A766D6F5DAFFFCF8FFFBFFF4FEFEB4CDB94499453B8935
+ 2F76162E65023460012E5A012A52002B4C022B4D062E5500316003356A0C4074
+ 09629153EEFEFD326A0B3461003362002D5900275000264C00274B00284C0028
+ 4F01254A062E5604245A013469012864003A6B1977A16CF3FFF977A5773A7717
+ 3973073462022951032650022C4B00264C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00264801264801
+ 264801264801264801264801264801264801264801264802254700274A00274B
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00274A00274902264801264801264801264801244600
+ 2446002446002446002446002446002446002844022844022844022743012844
+ 0225440124430024430026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000233E00233E00
+ 233E00233E00233E00233E00233E00233E00243F00243F00243F00243F00243F
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00233E00
+ 243D00253E002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00294D00294D01
+ 284C00274A00274A00274A00274A00274A00274902284C002B50003859043665
+ 003B6B0B377616478527558C55D8F7DCF0FFF9E2F7EFF7FFF8D5F5DC458B4539
+ 7A24346A092E5D002956002F5601385B013361013E6B0E43771944902B4B8848
+ 9DD0B5F1FFFEF4F9F7F3FEF486B58746883744831D3D6C0A305C032E55002D50
+ 00264C00284C00254C012A4C002950002D59002A6601326A0B386A16457731A7
+ CA926E946A3B77293E6D0A3169022E5800284F00254A00254C01234A002B5100
+ 2B50062B5105254F02265901346B08336801336C0A368836457632E7FCE668A3
+ 693081243A801B2A72082E6601325F02305D002E55003057023A5A013561043A
+ 6301356C094F7A1F83AA76B4D9C53467053A6B03345A082E5A01295103274D01
+ 284B012C4D022F5300335C00386D0C437817387826EDFFFD89AA8F346B083268
+ 04345909325A08264E002850022449032850003158022B59003168013C6D0B99
+ BA98A8D6AB4776323B6C0A396500326100326805306B02427817378A3586B489
+ FAFFFDFFFDFFB2D3B02B87342C76164268082D54042A5101295000274E00284F
+ 01295000284F00284E02295600325A023A6B03387618557B47B4CEB7E1FFF252
+ 9A6636A74F55B06BB4E5C5FFFFFAFFFAFFFEF9F8D9F6DC468D5439842838821C
+ 326A012D59002D59002C54022B4E002C51072C4B062D56013260003168014474
+ 0A6E9666F3FFFF4B7A1D3663023461002E5A01285100264C00284C00284C0028
+ 4F012B4F03325400275B01266400326902518538B2D2AFF5FEFB538B56397818
+ 3873033361012950042A4E01285002254D00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00264801264801
+ 264801264801264801264801264801264801264801264802264801274A00274B
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00274A00264801254700254700254701264801244600
+ 2446002446002446002446002446002345002844022844022844022844022844
+ 02244300244300244201243D00243D00243D00243D00243D00243D00243D0024
+ 3D00243D00243D00243D00243D00243D00243D00243D00243D00233E00233E00
+ 233E00233E00233E00233E00233E00233E00233E00233E00233E00233E00243F
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00233E00
+ 243D00253E00263F012640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00294D01284C00
+ 274B00274A00274A00274A00274A00274A00244A022D4E032E55003864014169
+ 033C6D0B3A782646883696BC98EDFEF3B4D9C5AFE4BDF8FDEEF9FEFF6DAC8037
+ 79273A72093365072D58012F5601375B0139660043730946831B39922B6B9566
+ EEFFFCE5F6F2E2F0DEFEFFFAC5E6CB458D514486273A76183363032D57002B53
+ 01294D00254A002B4E042E4E013054002E580336690143791648792F89A986E3
+ FCE8B9D6BC6491524278173A69023162002A5401285200244B002E5200234C01
+ 254B032D54042A5004285002205002355F07396D093E792949772FF3FEEA6A95
+ 68346B142D72093962003163002D5C002F54042D51002F50002D5700305C0138
+ 6400316A0842781787B688D6E9DA3B6C043269022E5505295901295103264E00
+ 294D01274F01325602375F073D6C0A427A15377927EBFFFA9EB6983C6B093B6A
+ 03325A08305604295201284F01264C042953002D5900245A0034690232690C88
+ 9F83E6FDE7578648426D163B6A0D33630A2B66002B6401437A173A933665A268
+ F5FFFFFFFEFFE3FDE5498B443080253765022E55052C5402295000274D01274E
+ 00295000285100285002295600345D083E6D0A3975176E9568E4FDF9BCE8D14A
+ A35454B6748BC896EEFFF3FCFEFEFDFFFFDCF8E567A3663A913942841A2B6500
+ 275A02335E072D5000254B002A4B00254D00324D032E5500386401326A014074
+ 086C9568E9FFFA5986473A66033461002E5A01295201274E00284C00284C0027
+ 4E002F50052D5900275A002C65023878156F9367E6FCE9C6E6D54A7732397106
+ 3469022B59002E4E07284F03284C001F4D00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00264801264801
+ 264801264801264801264801264801264801264801264802264802274902274A
+ 00274B00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00294D01274A00274A00264801244600244600254701264801244600
+ 2446002446002446002446002446002344012743012844022844022844022743
+ 01244300244201244201243F00243F00243F00243F00243F00243F00243F0024
+ 3F00243F00243F00243F00243F00243F00243F00243F00243F00233E00233E00
+ 233E00233E00233E00233E00233E00233E00233E00233E00233E00233E00233E
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00233E00
+ 243D00243D00253E002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00284C00274B00
+ 264900274A00274A00274A00274B00284C00264B012C4C002F56013A64004273
+ 0936751738852944923AE6F7F3F3FFF884CBA37BB886FAFEF2F9FCFFB9E7D147
+ 8A45377717366B0A305C01385A03405C023D690642730B44841A3D902EA4C8AA
+ F2FFFFB2CDB9D3E6CDFDF8F9E9FEFB68BA8548902C4379183263072E5A012A52
+ 00274D012949022B4D07304E033A5E042C65023E7A1646821D629152B6DAC4EE
+ FEFDE2FDF977A6755084263E730B316902325D022E55002A4B012C47052C4E08
+ 284C00295100204D002B59001F4D00346307316902346A09467830F4FFEB6E94
+ 6A376A1A346902396502275804215200264D00264906264B032C50032D590029
+ 650037740638761897BF88E6FEF23E7409316A01305A07315D00245108254E03
+ 274A002C4D022E55003361013A6D0C437A173A7826F0FFFBA4C7AC4278173A6D
+ 0B2B52042851002E5505275100264C04275502315B03265B003B6B01346B086C
+ 9667F3FFF977A2694F8427396C153463072B64022F6A023D6B0B378428488C55
+ E2EDE3FEFDFFF3FEF467A16A3B89353D6C0A2D54042D5503295000284E02284F
+ 01284F00285200274F01245A003A640C427916478F2F87B688F1FFFD98B9A453
+ C47468BA79D8F8E5FCFEFFFFFAFFF2FFFD8BC896458B4538811A326902325E01
+ 2B59002C51072B4C01294D01294F03284E02304E032E5A003764033D6C09417A
+ 186B9467F3F8FF6291523965023461002E5A01295201274E00284C00284C0027
+ 4E002E4E002D59002F6A022E751544852984A977F6FFF2A5BAAB397A252A7305
+ 2C66012D59002D4D06254A06244900225102284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00264801264801
+ 264801264801264801264801264801264801264801264802274903274902274A
+ 00274A00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00264900274902264801244600244600244600264801254701
+ 2446002446002446002446002145002144012844022844022844022844022743
+ 01244300244201224000233E00233E00233E00233E00233E00233E00233E0023
+ 3E00233E00233E00233E00233E00233E00233E00233E00233E00243F00243F00
+ 243F00243F00243F00243F00243F00243F00233E00233E00233E00243F00243F
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00233E00
+ 253E00243D00243D00253F002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000234401284A04244600264801274903214600264B01274B002E4E07284B01
+ 284B01285000285000274902264801284906304C102956003B64023B64094E7B
+ 1E2E7515477631A1BBA9FDF5FFC9F2D749B87446B774E8FCE9FFF8FBEDFFF26C
+ 95683A87263976162062033E5D0240690730720840791742831D578B55E8FBEC
+ FDFEFA65BC7A6CC996FBFEFFF4FFEBD2E5CC3A91474686263964032B65002855
+ 002D49033253091E4C002E55002F5B002E720738811B50964984B587F3FEF4FF
+ FEFDFFF9FFB9E7D1488C5339821B3B6B012D5B09225B00245200284F00274E00
+ 284C00274E002750002B51002855002E59022D65002E6502397616F0FFF96E94
+ 6A3169043169022E5A012956002A53002A4E01274A00274A00265100315B0332
+ 69023773073B7828C6D7CCFFFFFB386A16326B08345E072C55042A5300274D01
+ 2A4B08274A002B58012E58003B6B0B4F7921477632FFFEF9C7DACB3775173469
+ 022959002A5C04334D11244C04284C00284C002B52072D59003A640042781747
+ 8A45FFFBFFCFF1D32E88353876183673052A6503326804416806508426488E52
+ A6D7B7EEF9F7FEFEFE98C8A44689462E7518326A01245A00275000294B042A4C
+ 05274D01224C00245902346001326C143B7927458B44E1F1E0F5FEF453C37554
+ B572C9E3D5F3FCF9FFF7FFFBFFFFB7E6C5489A523789362E7108345F042E5A01
+ 2A53002950002850022851002950002750002A4E02295600265E0D3A640C4279
+ 16629152FCFDF4568D54396D013360033058002654072A50042A4B012B51002B
+ 50002A5406375B0134670533821A527C45E9EAF4FBFEFC78A36A387717326902
+ 305C012C55002A4B01264A04284E02295000274B00294D01294D00284C00284B
+ 01284B01294C022A4E02244901294C022C4E012A4E01284C00284C002A4E022C
+ 5003274D012A4F002B4F02294D01274E00264D00294D002D5100274B00284C00
+ 2A4E012A4E01284C00284C00274D01274E00284F00234901264D01264D022851
+ 002A5200264C00274D01284906284A03284A042849062A4C06274A00274A0027
+ 4D01284C00284C00284C00284B01274A00264900264B01274C02294E00294D01
+ 2A4E022B4F02284C00274A00274A00294D01284C00274A002A4D03274B00274A
+ 002B4F03274A00284C00284B01294D012A4D032C5003294D01294D01284A0325
+ 4701284C00294D01284C00284B01284C00284C00294D01284C002950002A5200
+ 274E00284F00274D01244901264D00274902254A002A4E02264A042648012648
+ 01284906294D01264D00274E00274E00274E00274E00274E00274E00274E0027
+ 4E00264C00284C00284B01264C00264C00284B01284C00264C00284C00274D01
+ 284B01284A03284801284A04294B05284D05284C00274A00264900274B00284B
+ 01284A03284A04264801284C002C50042B4F02284C00274B00294D002C500327
+ 4B002B4D07284A04284A04284A03264801264801264801264802284605274601
+ 2746032443002645022547002648022043002742022742022641012842022640
+ 00264000264000253F00253E04253E04253E04253E04253E04253E04253E0425
+ 3E04243F00243F00254000254000254000243F00233E00233E00253E00263F01
+ 264000254000254000243F00243F00233E00263F01274002263F01253E00253E
+ 00253E00253E00253E00233E00253E00264000264000264000264000253E0023
+ 3E00254000254000254000254000254000254000254000254000253E00243F00
+ 233E00243E02243E02243F00254001263F012640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284A042B4D072648022A4904284A03234800274902264801244600264801
+ 264B01264D00264C00254A00254603224201324D033162003A6302426D164484
+ 1A38902C498A45E2EFDFFAFFFF9CD6A637B46545B567A6D8B6FCFFFAF5FFF8B0
+ CCAE46863A3B7927296713426A044268042D751549862B45842699BBA3FEFEF2
+ D7EADB57B06B53C375D9F7E4FCFEF8F2FFF465B16A45893443821C356A032E58
+ 002D4A01264C0028560430540032690238831B478E2D539756C7E6C9F4FDFFFE
+ FEFEFDFEFCEDFFEF69A575449338427408345F042F5902315600274E02254C00
+ 274C02284D05274D052A4E022A5302325A082F6A02316801447A17F9FFFA889D
+ 843B6C00326902315E012F510A284F042A4C052649062D4D002F5600315C012D
+ 6500377307448736C6DBCCFDFFF93B7828387408326000286602295000254A00
+ 284A03284B013562013161013B6A0D4E7B1E408727FEFFFDB9D6BC376B173473
+ 052B6401275905284C06254D0030540239630B1F4E023D6C0A3A6B0342841B49
+ 8A45DBE2E5EDFEF377A7733B79253978183A72073260003F6A0144831B479947
+ 97C7A3FDFEFCFFFCFFC5E0BE4A8C442F8023447A173263072E5A002C4E012B4C
+ 012C50042D50002953003A6B032E741746883777A675FDFFF7E5FBE94FC47568
+ B988E6FFF0F9FFFEFFFBFFEEFFF279B78946923A2E77152B64012F54042A5103
+ 274D01274D01274E00294D00264C00254A002A50002B58012C69113B6C0A4683
+ 1B579756FFFEF6558C553D6A033361012E5B00285500284E02224B002B4C0132
+ 4D032D5900345E00437B1639852787AB87F7FBFCE5FBE8529747397517346804
+ 305C012E58012E4F042B4D07284F042952012F55032C51012A4E01294D00294E
+ 002B4F022B4F022A4E02254A00284C00294D00294D00274E00284C002A4E012C
+ 5003274D012A4E022A4E01294D00284B01284C00284C002A4B01294C02284C00
+ 284C00284B01284B01284C002A4E022C50032C5504275100285002254C012850
+ 022D5406274F012750002B4D06294B042A4D032C50042D5104284C00274A0028
+ 4B013054082D51052A4E01294D002A4E012C50032C50032A4E012B4F02294D00
+ 284C002B4F022B4F02294D01294D012C50042E5505274B00284F01264C002A4F
+ 002B5305294A00274E00274E00274E00264D00264D00274C02264C00264D0027
+ 4E002C51012A50002A4E01294E00294D012A4E012D4F022F5005264B012A4F05
+ 284C002B4F032B4E04294D012C4F05294C02284F002951002C5004294D01284C
+ 002D4E032850002B4F02284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284B01284C00284C00284B01284C00284C00274902284B01
+ 2A51032B4F02274D01274A00274902264802274A002648012648022648012649
+ 00264801264802264802274B00284B012A4E01294D00284C002A4E012A4E0126
+ 4900264801264801264802264802244600254700264801264801284704274603
+ 2746012442012645002547012547002144012640002742022540002640002640
+ 00264000264000264000243D00243D00243D00243D00243D00243D00243D0024
+ 3D00253E00243D00264000264000253E00243D00233E00243F00253E00253E00
+ 253E00253E00263F01253E00253E00253E00243F00243F00243F00233E00233E
+ 00233E00233E00233E00243F00243D00253E00253F00253F00253E00243D0024
+ 3F00254000254000254000254000254000254000254000254000253F00253E00
+ 233E00233E00243F00233E00253E002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244901254A02254603264802264801234800264B012446002246002C5206
+ 325A082E55072B52042C5107294E042648013A5303355B01386B034279163675
+ 173B852B76B079F8FFFAF3FDEC65BA7C37A65046A8666AAC82F0FEF2FFF9FAE1
+ FCE864A468449846397A25377616437A17377927398837468836DAF9E4FFFDFF
+ 8BC69948A8623BB26793CEAFFFFFFFFFFCFFA8D7B6478A473380252B6401385B
+ 013A54002851002A5401315503426C15438827478A4577AC84F2FEF8FFFFFEFF
+ FDFFD5EADBF1FFFDB4D9C55796582D7614356A0C3B53003B5400274E00244B00
+ 274A00214C03264A04254C012C5101305505306803357307407917FCFEF299AD
+ 963168012A6503325F022C51072C53082A4C062E4F04294F03315501305B002D
+ 6500458319478A45C7D8CBF4FFF43A78243773072E64002062032751042C4D02
+ 2E4E002C51013A6B033169023C6E0A508327388726FEFCF4C5E0BF2D74173469
+ 022C6601265B002A4E012A54013965023664012965003C6D0B3D730844831B38
+ 8934A5BBA9F6FFFAC7D8CD547A482C82242D7106326A013B6A0D37811B3C902A
+ 78B17EFBFFF9FBFFFFF5FEEA55965836933840862925600B2952012C4B002D50
+ 002E54023155012C56033C6D0B308025539448B3D2B1FFFEFEB5E8C347B672A8
+ E6C2FAFEFFFEFDFFF6FFFFC7E6CB468E52378428356B083361012A53022B5000
+ 295000274F01264D00264E00264D01294C02295306335C00397616406E154683
+ 1B66A369FAFDF4689668326804316902336000285800275103274D012D4C0731
+ 5208305C03336A0345811C46913BC6DEBEFFFFFFB7D5BC2076283876182C6502
+ 2559002E5500254C00264802274D01285100345A082E54022A4E01284F002A51
+ 012C53052A5101264C00284F012B50002C52002A52002A51012A51012C52002C
+ 5402274D012B4E042C4F05284B01294B042D51052D5104274B00294F03284E02
+ 274D01264C00264C00284E02294E042A4C052E5309284E02274E00254A022B4D
+ 063053092A4D03294F032B4F03284C002A4F002B52042C53052B5000294E0028
+ 4E023053092C4F052A4B01274A00294C02284D03284B01274A0030520B2C4F05
+ 2D4E042E4F052E4F052B4C01284B01294C02345E062950002951002B50002B55
+ 002E54022851002A5200284E022B50002B50002A4F00295100294D00274D0127
+ 4D01315B062D57022B5502295201295100284E02274E00274D012749022B4E04
+ 274B00294C02294C022648012B4D07284A032A53002C5500295000284C00284C
+ 002B51002E55002A5101284A04284A04284A04284A04284A04284A04284A0428
+ 4A042A4C00264D00264C00294D00294D00264C00264D002A4C00284C002A5200
+ 2D55032A53022A4F00254B00264801274B00264801254700274A00274A002648
+ 01254701254700264900264900274A00284C00284C00284C00294D00284C0027
+ 4B00274A00274A00264801264801264801274902244900254A00274603284704
+ 2746032645022746012648012547002446002741012641012641012640002640
+ 00264000264000253F0025400025400025400025400025400025400025400025
+ 4000253E00243D00264000264000243D00243D00253E00253E00253E00243D00
+ 243D00253F00264000253E00243D00253E00253E00243D00243D00243D00253E
+ 00264000264000264000243F00253E00253E00264000264000253E00253E0024
+ 3F00254000254000254000254000254000254000254000254000264000264000
+ 253E00253E00253E00253E00253F002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000234A00295000274D012A4F002951002950002C55002C52002950002E5801
+ 3159072E58002D57002D56012B54002A52003C54003C650A4379163979274688
+ 3759854AD2E6C9FCFFFBD1E5CE55996237A85145A86256A975CAF1D7FEFEFEFB
+ FFFF8FC697479B534776313977194588335486383B904685B787F4FEFEF4F9FA
+ 509B6347AA6445B67355BA87F9FAFEFFFBFFE4FDE96AAD803991453979273057
+ 022D51002C56003B6409426C15397A25509545558B56D1F0D3FDFFFFFEFEFEF8
+ FBFF65BF94E6FFF1EBF1F078AC873B7927367305355B01385708315C012C5300
+ 2A4F002A52002953002C55002B58012B5A003269023D7925477631EBFFF29AAB
+ 963063072B64013364082956002956003054002D50002651002B5400345E0633
+ 6B1851953C498A45C6DACEF0FEFD45883737821A3A76182063002E5A012B5400
+ 2A53003159013A6A042C6502336C0A518636558C53F8FEF9C9DACD3679242E76
+ 16326B092F65022B5500346001386401305C003E792838781539792752954A3C
+ 91467BBF96F3FFF9FFFAFF9ABB993B88372C7616326B0839691A3D912B368934
+ 4F9B65F5FFF3FEFAFFFBFFF97BAC86389246529747245E0D265100355B033A5A
+ 01315501315A09346A17436E133A8F2D569759EDF2F0F5F8FF8ADCB268BA85EC
+ FEFDFFFAFFF5F6FAECFFFB78AD853887362A7207336C09385A032950022A5200
+ 2B5500295300284F00284F002750002852002D54002E5A013A7717436D164278
+ 17579853FFFEF688AA852C7305326B092C65032B55002950002B5204254D002B
+ 5204416D1438831946923A77B17AEBFFF2F8FFFC96BB9B3081243776161F6201
+ 2B5500295600264C00254A022B5204315C01315D002D56012A52002A52002C56
+ 002C56002C52002B4F022C55002C56002F56002E58012D58012E58012D57002E
+ 58002950002850002950002A4E01284D002A52002B5204254A002F56012C5200
+ 2C51012B50002C52003054003155013155012E5A002B52022A5300274E002D57
+ 00335D062D57002E5A012B4F02274E002750002D56012B54002953002A54012A
+ 52003054072B5204284F012950002C52002F53012C5200295000325B06305702
+ 2F56012F56012E54022B51002B50002A4F0039630B284F00274D012850002F55
+ 032E57022B50002C55002C56002E54023057022F56012F56012C52002C530028
+ 4F00315C01315D002D59002B56002A5200284F00284F00284F01284F002C5500
+ 2B50002C51012C51012A4E022D51042C50032E5A012C5600295100284C00284C
+ 002A52002E55002C55002C52002C52002C52002C52002C52002C52002C52002C
+ 52002B4D00274E002A4E012C51012C51012A4E01274E002B4D002850002D5601
+ 2F5B02335C012C54022C5101284F002B4F03274A00284C002A4E01294D01274A
+ 00264801264900274B00284B01284C00284C00284C00284C002C50032B4F022A
+ 4E02274E00294D00284C00284C00284C00284C00284C00294D00274603284702
+ 284704284702284A04294C02274A00274A002845002744002746012744002845
+ 0027440029450327430128440228440228440228440228440228440228440228
+ 4402243D00243D00253F00264000243F00243F00254000254000254000254000
+ 254000264000274101264000253F00243D002640002640002640002640002640
+ 0026400026400028400025400025400025400026410126410125400025400025
+ 4000264200264200264200264200264200264200264200264200264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002E5902336101335F00396403335F00305B00366401386401315B03315D00
+ 346001346100336000315B033462003B6A0436640B61903A56963C458B4467A8
+ 7794AC94F8FFFFFAFFFDA4C9A954A975539B6657A97455B989A0CFB5FFFEFAFF
+ FFFFC9F1D856A877488A4239893667A25768A468529A65D1EFD2FAFFFDB5CEBA
+ 3C92444AA35454B77346B773E1EEE6FFF9FFFFFFFEA5E5C249A7665096493A62
+ 0A345D083462023964035186364F964669B26986B587F5FFFFF5F6FAFAFFFFC8
+ E3D939C98E9ED9CAFAFFFFC8DACD488A432D74172C650229690F40730B336200
+ 315D02325F023462003764033B6304396502336A07478A45598A56ECFFFBA6C9
+ B54688374493384589343972093672063C6C023A6B013664013A650A4D791E53
+ 863654973B4A8846C5DACBF2FEFE559C635195485786473979273168013B6C00
+ 3965023864003F7609326902396B175985487AB588FCFAFFC9E4D4488B464689
+ 34438936377616325A083B6C0A436D164D8834459139448A43659156A9D5AC53
+ 9C6456B987E5FBE8FEFAFFE1F7F265A36746893437761846883649A253519C64
+ 6AA676E2F6F1FFFAFFFFFFFFA6D6B9489954529747245E0D2B5500436D16426E
+ 13436C174E782065A35554863839913787BC95FEFAFFF1FFFD84DBAF9EDDB6F9
+ F9FFFEFAFFF7FAFFDDF8E4488E513984282C66013E6A0B405F04346003346100
+ 396502386302346202336003346001386302345E0631630B4485294D7A1D4682
+ 1D6C9667FDFEFAA5CAAA468837397A253B76143965083A640C38640B3162003B
+ 65004F8637519646519D63B7E5D2F8FDFEF7FFFE67A5753B9046468529396C0A
+ 336101345E072D510B284C063055053A640C2E5A012E5A012F5B002F59012E57
+ 022F5601305402315501315C01315C01325D02315C01305D00315D00305B0031
+ 5C01335F06335F0639630C39630C355F083964093964092F5B02345F04315B03
+ 315B03305B00305B00325D02345E06365D07346003335F00346100315D003765
+ 023A650A315C013361012A5200274E00284F002E59022E5902315B04345E062E
+ 5902305A02345F04356005345F04315B03315B03345E06365E06305C032D5900
+ 2E5800315C01346003315B03315B03345F04396409295100284F002C5600365D
+ 07345E062F5601305A022E5A00315B03335D06325A08315C012E55002A520028
+ 4F002C56002E58002E58002F5901315B03315D00315C01305B00315D00346001
+ 305B00315B03315C01315B03345F04315D00315C012F5B022E5500284F00284F
+ 002F5503305A02335D00315C01315C01315C01315C01315C01315C01315C0131
+ 5C012C5101294D002D50002D54042D54042D5000294D002C51012C54022D5900
+ 335B03315B033056002C56002F56012D58012B4F032D51052E52062C4F05294C
+ 02274A00274A00274A002C50042A4E02274B00274A00284C002C50032D51042C
+ 50042B52022A51012A51012B50002A4F002A4E01294D002A4E01254701274603
+ 2746012A49042A4E022C4F052A4E022A4E022A47022948052746032B47052A46
+ 042C48062A46042B47052C49002C49002C49002C49002C49002C49002C49002C
+ 4900243F002540012641012743012844022945032A46042945032945032A4604
+ 2945032844022743012641012540002540002746032746032847042746032645
+ 0227430126410125400027430128440228440228440228440228440228440227
+ 4301284402284402284402284402284402284402284402284402264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000315C013765023965023E6A05396403315D003965023A6400346100335F00
+ 3561043664013765023665003B6A034376074F7A1F57864756985755A76666A4
+ 74C6E5D6F7FAFEEBF7FB6DAD7F6AA676549A6558A76454B57268AD82F5FFF3FF
+ FDFEF2FFF778BE9649995648974665B26867A57579AC86F4FFF9FEFFFA87AB87
+ 3988373C8A3649984944B4669BD0B5FEFDFFFCFAFFD7F6DB559C64428B43245F
+ 0B2A5D053A62033D6A0352863965A05669BB86B7D9C1FFFEFFFFFBFFE4FEF178
+ BF943AC9926BBA89D7F8E3F3F9F87196682D761438811A368629407408386302
+ 3260003B64023562013965003A6B03356703326B09478B4465A367ECFFFCA2B9
+ AA488737498A453B79273875073973074275063E6B043765023B640947763262
+ 8F39509545588C57C9E6D6F6FEFE7AAC845597565586484677333A6B033D6C0A
+ 3A690D3765023D720A2F6A023C7929538C5598BC98F7FAFFC9E6D6458C534689
+ 465587393978283A640C316408508633639254589759578B56A7BBA8E2FFF076
+ B88443B667B2E4BAFAFFFEFBFFFFBAD7BD4B8A453B852748A3545AA976549A65
+ 67A575B9E6D3FEFEFEFEF6FDD6F7DC49A96367A3553A7A283B6B0B4E791E4D7B
+ 1B416D144A783065A35547975449A455BBE7D0FCFBFFE4FEF06BC895D9F8E3FD
+ FCFFFEF7FEECFDF29FCDBA3C91462D80242B64022D57002F56013B6B01396A00
+ 3A6B013B6B013B6B013B6A033C6B053D6C0A3864093B6B0B5085285385374286
+ 276F946CFFFEFAB5CEBA44894647893839792731640A335F00386401315D0032
+ 6902598B5568A36988B388F3FFFFF9FAFEC3E6CB488E523C89355585373A7618
+ 326B08375F072F4F082B4E043257013161012C55002F5901345E07345E07325A
+ 0831580A325A08325A08305C01315C01315C01315C01305D00315D00315C0131
+ 5C013361012D5900326000376502315D00315D00335F002E5A01366302346100
+ 346001346001346100366401386401386401386302366500346001315B033864
+ 013965022E58003561042F5601284F002B5202345A08335907345E0639650836
+ 5E06305C01346001386401396502346001336003376403396500336101305C01
+ 305D00346100376403346001346001376403335D052A51012C52002F5503335D
+ 05395E08325C05365E06305C01325B06345A08325A08345A082E54022B51002B
+ 4F022E5500305702305A02325A08345D08345D08325B06325A08336200366502
+ 305D00315D00305B002F5901346003305C00335D05335D062E54022A4F002E52
+ 05335808345E06315D00315C01315C01315C01315C01315C01315C01315C0131
+ 5C012D5202284F012E51012E55052E55052E5101284F012D52022E58002F5902
+ 2F59023055002F55033054002E5801315C052D51042F54042F53062E52062C50
+ 04284C00284C002649003054082B4F03274A00274A00284C00294D002B4F022C
+ 50042B52042B52022A51012B50002A4F002A4F002C4E012C4E01264802254701
+ 2648022B4B042E4F042C50042A4E022A4E022C47052B47052843032B47052A46
+ 042F4C072B47052C46062C47052C47052C47052C47052C47052C47052C47052C
+ 4705243F002540002642002844022A46042A46042B47052A4702294805294805
+ 2847042945032844022642002540002540002746032847022948032847042746
+ 0327430126410125400027430128440227430128450028450027430128440227
+ 4301284402284402284402284402284402284402284402284402264000264000
+ 264000253F00253F002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002E5402345B062E55003156002F56012C53002E55003054002C56002C5500
+ 2F56002E55002E56002E58003461003B6B05436D16426C17498B444DA35577A7
+ 77F1FCFAFFFEFDB6D7BC469846478A45468C4545903A4AA35454A868C2E6C8FF
+ FEFFF7FFFFB3DAC14899544AA35348A453549966B6CDB7FEFAFFF6FEED459853
+ 3B89363679243885294B985465BB7BFDFEF5FFFAFFF6FFFAAAD5AA57A7663991
+ 45366A16386401407506387826469B476CAC82DBF9E6FFF6FCFEFDFFB3E2BB46
+ B7733BB16852A763B3D4B1F8FEF9A3BAAB2274292C771542730B366500335B03
+ 315C013361012E58012D590039650232610032690251853879A877F2FFF797BB
+ A3367826397A252D74173169003A64053664013A630131600334620938761851
+ 8636478A45588D54D3E8D9F9FEFF73B378498A4549772F387618316003315C01
+ 315A092E5500336200275A00376B184787277AAC84FEFAFFCAE4D6478A473B79
+ 2539691730680142690730680153832A478A4757975666A468D4E8DBEFFFFD8D
+ C69942B56578BE96E5FFF1FFFBFDF7FFF87BAB87478B44469846489855389246
+ 529C6289C799F4FFFDFEF6FFF1FFF357A97552963F377717346A09417A174F7B
+ 1E51842843913A57A66749A45568B97AECFFFBFEF4FFA9E5C362C097F6FFFCFE
+ F9FFFFFEFAF1FEF667BB8557A7662D8024336A03264F00254C002B58012D5801
+ 2D58012D58012E5A012D59002D59002E59023054003362003C75184C791C4588
+ 276B9467FFFBFA98B9A42D86363B79253B79253161013462023A630129660041
+ 750A458C536AA578C7DFBFFEFDFFFAFFFE87B688388934377B282A68142C5B05
+ 2659002B5A002A51032B4E043159073462023054003055002F56002F56002D55
+ 032D54062C55042A53022D58012D56012E55002D57002E58002E58002D57002C
+ 5500315B032950002F5902345F042F56002E55002F59012C56002F59012D5900
+ 2D59002D59002D59002F59012E5800305A022B54002E5A002D59002851002D59
+ 002E5A00254D002D5801315A052A4D032B4F022E58012C56002F5503335A052C
+ 54023054002D57002D59002F59012F56013054022F56012D5801315C012F5901
+ 2F5901315B032E58012D56012D56012E58012F59022A52002C55002A51013155
+ 01325B063155012E58012F55033155013054002F56012F56012E52002B4D0029
+ 4D002F56012E55002E55002F56012F55032F56002D53012B51002F5902315B03
+ 2C54022C55002A5200284F012D56012A51012D55032E55002B52042A4E022C50
+ 042E54082F56012C54022C56002C56002C56002C56002C56002C56002C56002C
+ 56002C5101284F012E51012D54042D54042E5101284F012C51012E55002D5700
+ 2E55002A53002F56012B53012A51032B5204284F012B50002C51012C50032D51
+ 042A4E01284C00274A00305408294D01264900274902284C00274B00284C0029
+ 4D012B4F032B4F032A4E02284C00294D01294D01284C00284C00264801244600
+ 2648022B4C012D4E04294D01274902274A002C48022845002946012744002B49
+ 022B49022B490228440028440228440228440228440228440228440228440228
+ 4402254000264101264200274301274301284402284402274301254401254401
+ 2844022844022844022844022641012641012743012743012844022844022844
+ 0227430126410125400026410126420026420026420026420026420026420026
+ 4101264200264200264200264200264200264200264200264200264000264000
+ 264000253E00253E002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254A02264906234401264802284C00274E00284D03264801294C022E5107
+ 2E4E0D294A07264802264B012A53002B55002B65004E791E43862A3B923A8BC6
+ 99FFFFFBFDFEF486B58729942037720A377616308025478E2D489A528EC898FC
+ F6F7FFFDFFEDFFF245AB7444B46748A45344A965F6FFF4FEFAFFB2CCBA2E8224
+ 3B7A244F7A1F4587282D873439A552C5DACBFFFDFFFFFFF1B6D7BC458E504997
+ 573B79273A6B0346841A45902E3B904579B789ECFFFCFFFBFFFFFAF968A67613
+ A547478D513D92486B9566FEFFFBE5F6F2487732316C0A436A04315D002E5500
+ 325A08315B062950002A5302385D073765023D6A0343773184A977FBFFF49DB3
+ 962F68132B6713316902245206274B00264D0129510028520027570033630A3B
+ 7925548539517B44C9E6D6F7FEF963A368397927376B182063022F59012A5000
+ 264F04274E00335C012C650235740639821B78A26DFDFAF6C5E0BF3080232D75
+ 152A6913255B023A65004F842738782653963A52974798D6A8EAFFFDF2FFFDA9
+ D5AE47B66649AC748FCFACFFFDFFFDFAFFDBF8E1539C6446913B3A91393A9336
+ 4498466DAC84F4FEF8FFFBFDF5FFF96BAD8352973C478727397517426E154F79
+ 2145883746994449A45544B5658AD4A4EAFFFBFCFBFF88D4A48AD4A4FDFFFEFF
+ FEF9FDFFF3C8E5D63F925E4CA2542D74172B55002C5600265108275000295000
+ 274F01264D01274D01284F01285100284F00295300336200306309436C174486
+ 2768A366FEFDFF88AB91217527307415387618305C03335C0139650234690251
+ 842A498D5278B785F4FFEBFFFEFFF4FEED498A452E81252D6813265A00245A01
+ 2B5600285500294D01284C002955022B55002B5500295000274E00274D012C51
+ 012B5100284C002648012A54012A51012A4F002A52002D56012C55002A520029
+ 50022C5004224700294F03345A082C5003274A002B4F03295002264900284C00
+ 2A4E02264C00264B01284B01284C002A4E01264C002B5105285100244B002B52
+ 042C5107274E00315B06325A08254A00274D012A5200264D00284F012B520226
+ 4C002A50042A4E022A4B00284C00284C00284F01284C002A4B00264C00254B00
+ 254B002A4D03284C00274B00284C002C5003275000264E00295002294D00264C
+ 002C5101284E022950002C50032D50002A4F002A4F00264B01284C00294D0127
+ 4E00295002284F00284F01284F01274E00274D01284F01284B013054082F5208
+ 2C50032C50032A4D03284C002C50042A4E022A4E01295100284C00274B002A4E
+ 022C50042951002449002A4E022A4E022A4E022A4E022A4E022A4E022A4E022A
+ 4E022D5000264E002B50002E55052E55052B5000264E002D50003155012C5200
+ 284F00295000284F00295000284F01264B01264D00284C00284C00284B012A4E
+ 012A4F00274B00264802305408284C00264801264802274B00274B00274A0027
+ 4A00274B00274A00274A00264801274902274A00274A00284C00274902244600
+ 2648012A4B012B4C012848012446002446002944022641012240002641012844
+ 02284702274301264200253E00253E00253E00253E00253E00253E00253E0025
+ 3E00264101264200264200274301264200254000264101254000243F00254000
+ 2540002541002642002844022743012642002240002341002642002642002743
+ 01264200234100224000223F00243F00254000264101264101254000243F0022
+ 3F00254000254000254000254000254000254000254000254000264000264000
+ 263F01253E00253E00263F01264000264000253E00253E00253E00253E00253E
+ 00253E00253E00253E0026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274B00264802264704224201244600254700264801264801274E00254A00
+ 254C00234A00254B032C51092C500330540831610138811A458728478D50F3F4
+ F2FEFDFFF4FFEB3F925B3882183772093B6A03417509478628498A4567A577E3
+ FFF1F7FFFEFFFAFB85D5A040BF6A44AA6288CCA3FFFAF9F1FFFE67A366397927
+ 3D6C0A386917427A1546842A51964668BB87FDFFF9FBFFFFFCFAF96DAC84439A
+ 444E791E2E8125468837439139498A45B6D9C5FEFAFFFDFEFAAEE4B945974544
+ 923B37893648893444923AAFE2BCFCFFFB889D843B79272C7207335C012B5A00
+ 335C0139630B2A51012E55003263013361012A720744841A84A977F5FFF6A7BA
+ AB2D76142A7207436905265106254D062B5207284E022850002E5A0132610040
+ 7409508528478B44E7FDFBFBFFFA6E956838811B357307206302315B03244A02
+ 244D022651082451021F62012C650338771767A367FFFDFCB6D7BC3C85292D75
+ 15316A012E6502326307437A1746923A37904786B686EEFFF2FCFAFAFAFFFEDD
+ E1E645B56741B66746A866D4F8DAFFFEFEFCEEFAD6E9DA499B533B9E423B9F40
+ 35A75344AA63E5FFF1FFF8FFFBFEF587CBA24A9D3A4693385585373989363A90
+ 2A3CA04155A76657AA76B4CDB9DCF7E7FFFFF9F6FEED67BA86A6E6C3ECFDF2F1
+ FFFEFFFFFB97C8A256B26B398936326B092659012A4F002F4C032752012E5200
+ 24480234520B2547002E59002E5402285100304E03415D032261053776164485
+ 2965A268F1FFFBA5BBA83976163A7A28488836265E0B325C07325E033B792547
+ 933B559756CFEED1FFFAFFFBFFFE98C8A438862839821C2B6500325A08295002
+ 274F012B5202264B01254C00264B01294C02274D012950022B5202264C002B52
+ 042B5204244B00285002284E02264E002B4F032C5107305408284E02274A0026
+ 4C00274F01264C002A5200325A082A5300274E00264B01264C04284F01274D01
+ 264D01274D01264D01274D01264C00274D01284C00294D00254A00294E062B52
+ 02264C00284F00325B062E56042951032A50042D5208264B03244900284F0326
+ 4B01284E02284E02274D01274D01264C00264C00264C00264C00274C04274A00
+ 234A00274D01264D02214B00274D01285100264A04284F012850022852002851
+ 00295000274E02254A04274D01274D01274D01274D01274D01274D01274D0127
+ 4D012750002851002950022A5103284E02274C02294C02294C022A5200284F00
+ 295002274E00274D01284F01264C00264C00274C02264D00274E00274D01264B
+ 01274D01294D01274A00274D01264C00254C00254C00274D01284E02264C0025
+ 4C00264C00274D01284F002E55072D54042B52022850002950022E55052D5404
+ 2A5302285002295002274E00274E00284F01284E02284C00274A00284B012A50
+ 042D53072B4F03274B002F56002A4E01284C00284C00264801264801284A0324
+ 4600274B00274A00274A00254700244600254701264802254700284402274603
+ 284704284704284402264200264101264101254401254000243F00253E02263F
+ 01264102274203264004264000264000274002253E00253E00263F0126400025
+ 3F00233E00233E00233E00243F00253E00253E00233E00243F00233E00253E00
+ 264000284202284202274101264000254001274002263F012540012945032A46
+ 04254001253E00274101233E00254001264101254000243F00243F0025400126
+ 4101233E00233E00233E00233E00233E00233E00233E00233E00274200264000
+ 2640002540002540002642002844022744002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274A00264802284A03294908284A03284A04294D01284C00234C01214901
+ 2B4E04274F01284F00274E002F4F023159073A640038811A45863777A576F5FA
+ F9FFFFFFD0E3CE478A4739821C346902336101316A01437918458736589857B1
+ E2BCFEFAFFFAFFFDBEF2CD52C27554B674D0F1CFFDFFFFE8EAF552964938751A
+ 366802326000386D0C44831D46933855A766DDF7E7FDF9F8FFFEFF9BD0B53C90
+ 4846883644862748883649933B549A65DBFAE5FFF9FEF6FFF57BB8863A914738
+ 78263C85294487263B792587B587F9FEFCC7D8CA4678323672063462092D5801
+ 2F5C0039630B2851002E55002B58013B640230741546852982AA7AF2FEFEB5CE
+ BA377B242C72072E5C032D5B08215100284B01274E002E51012D5900385E0440
+ 79163A85293A9147E7FEF9FBFFF977A2693883194273093361012B56002D5503
+ 2D51052446002D5503316902356B0A427916519C64FFFFFBC7DACB45772F3975
+ 1737740628730737751B488F2E47923C64B97BD7F6D9FDFEFFFFFFFFF4F9F7F0
+ FFF846B4663CB26946A96375B27AEDFEF3FFFEFEEDFDF6AFE4BC46995436A750
+ 36A75047A963CAF1D8FFFFFEFDFEFAB6D8C753A766399E423CA04047A3525198
+ 4857A7669CDAB6EDFDF2FBFFF9F8FFF9F5FFF8E4FEF059BA88BBE7D0FFFFFAFC
+ FEFEF3FFF986BD963B90452C76182B64012A5401285200254A022A4E01224600
+ 324E12294E062C50042343022951002B52072E4F053E5C032E72073B79254287
+ 2668A26BF8FFF6C5D9CD387B2639761646821D2965012C6503366A1643883748
+ 923A96C9A3EEFDF5F9F9FFEDFFF276A5773784282C72072B64022A5200254B00
+ 2A5101295002264C00274D01274C02274C02284F012950002A5101274E002B52
+ 042A5103244B002A5302274E022750002A51032C52062C5206294F03274D0127
+ 4E00274D01274E002C54023159072C5500295002294E04274C04274E00254D00
+ 264D00264E00274E00264D00274D01264D002B5204294E042950022A51032950
+ 00264D00295002325A08285100234901264C00284F04254B03274C02284F0326
+ 5000284E02284E02274D01264C00274E00284F01284F01284F01294F03294D01
+ 264E00294F03284F01254C00274E00275000274C04264C00254C01274F012950
+ 02274E00264C00274D05274D01274D01274D01274D01274D01274D01274D0127
+ 4D01274E00264D00254C00244B00244B00244900244900294C02285200284E02
+ 284E02274D01295100295002295002284F032850022750002851002851002750
+ 00275000285100295000285100274E00274D01284F01275000285100284F0127
+ 4D01294E04284F002C53032D55032E5505294F03284F012950002B52042B5204
+ 285002274F01274E00274E00264D00254C002B4F02284C00274B00284C002A4E
+ 022D4F022A4E01284C002D51042A4E012A4E012A4E01274A00264802284A0426
+ 4801294C02284B01274A00264801254700264801264801264801274603284704
+ 254603274603274603284402284402274202284500264101253E00243D00263F
+ 01263F01253E00243E02253E00263F01263F01253E00253E00263F01253E0025
+ 3E00243F00233E00243D00253E00263F01264000264000264000243F00243F00
+ 254000264101274202264101264101254000253E00253E00243F002641012742
+ 02243F00253E00264000253E00243D00264000264000243D00243D00253E0024
+ 3D00233E00233E00233E00233E00233E00233E00233E00233E00243F00254000
+ 254000243F00254000243F002641012844022640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264802264900294B04264900254800294D01254C00274E00264D00264D01
+ 2952012A4E012753002A54002B5500305D00326B0844831B478A45B0CDACF3FF
+ FEFFFDFC95BA98378B333A7717346100316101396502397306488737488E5185
+ BC95FFFEFFF9FFFEF6FEF36ABB8467BA86FFFDF5ECFFFCA9C9B13989362F7216
+ 316B002B67023A6B00427309478E2E499952B1DBC4FFFFF9FCFEFED5F5DC488E
+ 512E843647923C4689444497486AAC82FCFDF9FFFEFFE4FAE83C915D3C91473A
+ 77173776164377193C7A286C9568D6E9DAEDFEF3558C55407917387618235A00
+ 2E5A01305701254D00305B002C5902416C153B792748862C76A168F5FFFEB7D6
+ B93979272E72073362003268042659012C59022D59003355012D59003B640952
+ 83274B9F39498D52FBFFFAFBFEF577A8762C7E253A7618315C012D59002C5500
+ 3048002D490337590239650032690237792768A468FFFFFBE6FCE9488A434687
+ 2B46821D46841A4785273A923855A864B7E6C6EBFEFBFAFCFDFFFCFEFBFEFFF5
+ FFF953C47446B46638A7514B985499B9A6ECFFFCF5FFFEFBFEFC97BE8A55B168
+ 38A85048B7739BDBB8EBFFFAFEFEFEF1F3F346B77356B2694CA25438A85068BA
+ 86D8F6DDFDFFF7FDFFFFFBFEFCFEFFFDF8FBFFF5FFFE9FCFB7D6F9E5FDFEFCFF
+ FDFFDCF8E568A6762B87362B6810325B002D58012B5A002851002B4F032E5206
+ 2C5107204500345E062D58013055052C510734520B3D5D042C76163776164688
+ 367CB785F6FFFAC7D8CB38811A2A7305316C0A2C65033C811A38852952944565
+ B169DAF9E4FAFFF6FDFFFCB4D9C54A89442F7F262965003362002B5400295002
+ 2952002E5505295000274E00274E00264C00274E00284F002B5202274E00264D
+ 00295002274D012A5101264F00275000285002294F03264E00284F00264F0025
+ 4D00284F01274D012A52002C55002A5200264C00284E02274C02284F002C5206
+ 2B5204285200295000285002295002284F012A51052C5206284F00264D002950
+ 00284F01295000325A08284F00264C002A4E01284D03274C022A5000284F0029
+ 5000254C00254C00264D01264E00264E00285002274F01285002295002274D01
+ 275000294F03295002264E00264C00264E00294F03274D01264E002750002951
+ 002B52042B5204284E0227500027500027500027500027500027500027500027
+ 50002B52042950022850022850022850022850022950022B5204275000285002
+ 285002284F00284F01254C01254C01254D00295000295002284E02284F01274E
+ 00284F012950022B5204274D01264D00264F00274F01274D01264C00274E0027
+ 5000295000284F01294F032A52042A5204284F00274D01295100284F01295002
+ 275000284F002950002950002950002851002C4E01274B00274A00274A00264A
+ 00294B00284C00284C00274D01264C002A4E022B4F02274B00264A00284B0127
+ 4902284B01274A00264900274902264801254700254701254701264802264802
+ 254701254701274603294503274301264101284402264101263F01253E002640
+ 00253F00243D00243D01243D01263F01264000264000253F00254000243F0024
+ 3E02243D00243D00243D00253E00263F01264000264000264000253E00253E00
+ 253E00264000284202264000263F01263F01253E00233E00233E002540002540
+ 00243F00233E00253E00253E00253E00264000264000253E00253E00243D0024
+ 3D00264000264000264000264000264000264000264000264000254001254001
+ 243F00233E002540012540002540002540002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264D00274D01264801254603264802274902264C00254A02224C002D5406
+ 2F5404274E002D59003C6B04326804296500397209478628459854E0F0DFF2FE
+ FEF3FFF066A3692F7F24326307346100335B0333620034680438872646913B57
+ A863FFFAF9FDFFFFFFFFF99DCFB79AD5A8FDFEFAEAFFFB9BB9A62D8024297309
+ 2A65033168013369053772093A85294598546AB986FFFFFAFEFDFFFBFFF777B3
+ 77279A4B48A45366BA7A53B16AA4C8AAFFFFFEFEFFFDA9D8B82E88353791453B
+ 792731690439720944883368A369A6C7B2EDFFFE97C9A1457731458735275F0C
+ 2659012756002750003C650A38620A4F8427458728387A216C946AF4FEFEB5D9
+ C32076282E7318396B1737750433610133610139650C346A092C691339792751
+ 963B56A867548B52FFFFFBFFF7F497BE8A3B923A2F80232C6713316408285002
+ 2D5100375C00385B002D650038761838883565A577FFFFFFF5FFF3479B533989
+ 363689343B902E3A933653A767AAD7B6F3FFF9F8FBFFF8F4FFFFFEFFFEFEFEF6
+ F4F363BD994399533B933948A4533D935D9DCFB7EDFEF1FFFEFFEEFEF395C8A3
+ 44A96549B77787D2A6E5FFF9FEFAFFFEFAFF6CC99646B77353B57398D6A8D7F7
+ E6FFFEFFFEFAFFFEFBFDE5FEFAFCFEFFFFFAFFF2FEFFF4FCFCFCFFFDFEF6F6F2
+ FFFDBDEFCF3F935D2277272C6810315C01336101326804265901285100244A02
+ 1F5000326902255A003C6D0B3864092A540032530939650C47902E46772D4989
+ 378CC79BF9FFFACAE4D62F7F242E7616346A092A73054CA03A3B904575B27AAE
+ E3BBFDFEFAFAFFFFEDFEF377AC853B89352D7106326A053763002C5500295000
+ 2C55002D55032D5503295002274E00264E002950002950002C5303284F01284F
+ 01284F00264D002D5404254C00295000285100264C00234A00284F01274F0126
+ 4E002A51032A53002A5300295002295000274E00274D01264D00274F01305505
+ 2C56032B5100295300295000264E00274E00244901295100295000274D012950
+ 002A52002C56002F59022A540029530028510027500027500028500227500028
+ 5100274E00274E00284F01284F00295000295000284F01295002274F01264B01
+ 274F01284F01284E02285000274D01284F00295000295002274F012A52002E58
+ 002D55032A5200264D0029500029500029500029500029500029500029500029
+ 5000264D01264C00274E00295000284F00275000285100264E00295002284F00
+ 295002284F00284E02274E00264C00274D01295000284F01274D01274E00254E
+ 00264E002850022A5302274D01274D01274E00274E00274D01274D01274D0127
+ 4E00284E02274D01254C00285200275000264E00264D00284F00274E00284F01
+ 2950002A51012A52002A52002A5101295201284C00284C00284C00284C00254A
+ 00254A00254B00284C00264801264802294D002A4E01274A00264801284C0027
+ 4A00274B00274B00274A00274A00264801244600234500234401264801254700
+ 2547002446002645002645022443002341002540002540002641012641012642
+ 00254100254000233E0025400127420226410125400025400027420225400024
+ 3F00243F00243F00243D00253E00253E00253E00253E00243D00253E00253E00
+ 253E00253E00263F01253E00243D00243D00254000243F00233E00243F002540
+ 00254000243F00233E00243D00264000264000264000253F00253E00253F0026
+ 4000254000254000254000254000254000254000254000254000254000243F00
+ 2540002540002540002540002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002C5500284F00254A002648012A4E022A51012C56002C5500244B00275700
+ 2E58002B4F022D59003B6A03326C073773073A8628458B456AA676FEF6F6F0FE
+ FCDFF2DF4C8C5139821C396409346001305C0332610032620247852750974748
+ A256D5EADBFFFEFFFAFFFED8F9E4D6F6DDF8FFFAE2F6F169AE813C8A362A6711
+ 2965012E5800315B03326B09397A24569857549A65E6FEE6FAFBFFFFFEFFA7D6
+ B635A75354A76356B57256B987D5F6DBFFF9FAFCFEFE6BAD833C91473A883437
+ 6B17426A04387206397A255A965978AD86ECFEF1E0F8E6537A46488C532B6810
+ 235E0D2F5B00295100386400365D075084264587364F873676A577F7FFFDB5D9
+ C3477631318225397927436D16316507386917487830448835388A373789363C
+ A04148B67447AE75F2FDFAFFFEFA98D6A63892462D87342076283869172D6814
+ 335D053462021D61022E75183A88343D92487ABE95F6FBFEEBFEF557A766529B
+ 63499A5537A65047A865B8D9C4F3FFF3FAFFFBF6FFFCC4D9CAFFFEFFFFFBFAF9
+ FFFA91D0A94799583990383B91393A9246478D51A8D5AAF4FFFDF9FEFFDEF1DE
+ 84BC9346B77464C097E5FFF0FDFEFAFDFFFF88D5A288D3A5B7E6C6EFFDF2FFFB
+ FCFBF6FFF7F5FBFCFFF5F3FFFFF7FFFDFFF7F79CDAC8FEFEFEF6FEFEFCF8FDEC
+ FFFBB7E6C53C915D2D86372E7715315C01375A043168013066022D57002D5900
+ 2659012A63012C660146781A335B14365C14386A16346307449338478A455184
+ 3A8EC79AF9FFFDDBE2E53789363D79253878263C8938449A5440945D97C6A5E7
+ FEFAFFFAFDF6FEFEB8E8D0568D563A88343877173469013A62032952002A5200
+ 2D55032D55032E5505295000264D01274F012C55002C5402325B062C54022A52
+ 002D56012C5402325B062A51032D54042D56052A4E01264D01284F002952012A
+ 5103325A08325A082F58032C56002C54022A5101284F00274E00284F012D5900
+ 3158022A53022B56002C56002652002A5200274D012D57002C55002950002B56
+ 002E59022E5A002D59002F59012C5500284F00274E00274E002950002A51012C
+ 55002C55002C55002C55002C55002C55002C55002A52002A5200254C00244B00
+ 2B52022A52002A51012E58012A51012C56002C5600284F00264D012950002C56
+ 002D56012D56012A510129500029500029500029500029500029500029500029
+ 5000274F01284F01274E00284F012951002953002B55002855002950022A5101
+ 2C55002B52022A51012950022950002A51012C5402295000284F002A5101284F
+ 00284F002950002D5404284F002B53012C55002A53002950002950002A52002A
+ 5300295000274D01264D01275000295201274F012A53002D5700274E00284F01
+ 2A51012A51012A52002953002A52002A51012A4F002B50002B52042B52042950
+ 022950002A4F002B50002648012648012A4E012C5004294C02284B012A4F0028
+ 4C00284C00284C00284C00284C00284B01264801254700244600294A00274A00
+ 274A00274A002648012547012446002446002642002743012844022844022844
+ 022642002540002640002A46042B470529450325400025400028440229450327
+ 4301274301274202274202264101254000254000243F00243F00264000254000
+ 2540002641012641012641012540002640002844022641012540002540002641
+ 0128440226410125400025400026420028440228440226410126410126410127
+ 4301264200264200264200264200264200264200264200264200264200264200
+ 2743012743012642002642002843012742002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000335D062D5700264C00295200345A08335D063964093A660932620A386308
+ 3E6A053F69044269073068013E6C0C478E2D53963B559756A7C9ABFFFCFEF7FF
+ FEA6D7B7498B4440791750791D4274083261003964033B6C0A618E3764B36A56
+ B16CA9D8B8FFFCFEF4FFFFFAFEF8FCFFFAF2FDFBC5DACB44AC755597563C7A26
+ 37771439630B436D16628F3965A35573B17B55B673C4E5CAFCFEFEFDFAFCD9F9
+ E856B88A53C37646B77359A875EEFFF2FFFDFFF1FFF8519C6446A7643A8A3728
+ 66124E7A1D47902E2D812367A3556AA578C8E4D7F4FFF3859E82489A52378937
+ 3B7828427408346301335F003A660952833955965865A35598C7A6F2FFFCC8D9
+ CE4598544498464B8947519548468944588546549857569857458C543C914658
+ A76456B9875FBF97E5FFF9F7FFFFA8E5C146B67647AC7546AC75498B44468946
+ 37792738771739821B30802546995555BA87C1E1BEFFFAFFE6FDF93BBA833BBC
+ 8361BE9786C9A4B0E5BAFDFEF5FDFEFAF7FFF8B8E8D09CBCA3FDFEFAFEFEFEF5
+ FFFDABD8B751964547933B4AA256449A523984285C8748A5C8B4E5F7F0FDFFF9
+ E9FDEA87D4A165BD99E5FFF1FDFFF9F5FFFFA8E4C6E3FDE6FBFFFAFAFAFFF7F9
+ FFFAFFFEDFEDE7BEF0CEFFFBFFFFFCFFD9F8E33BCB909FDCC8EAFFFCFFFAFFFE
+ FDFFB4E7C5589A6748985545852B416B063A6302306400305B00264C042D5404
+ 548638568638558B56527B4877A16AC7DFBF558747346A0945933C5596586392
+ 5498C8A4F9FAFEDBE2E555A76648995457A667469A52549A6578AD82D7EADBFB
+ FFFFFEFEFEEAFFFC89CAA353996445933C518527336200366500315B04345E07
+ 335D06345E07325B062A5300284F012A5302345F042D5700355F07345E062E58
+ 00305B00315B03345E062F5A00325B06325A082D56012C56002C56002E580132
+ 5A08315808355F07345F04345E06345E06315B032A5200274E002B5500345E06
+ 356005305A02345E06326209375E083662092C5600345D08345F042F5901315E
+ 01305C012C58002D5900326000325C042B5500294F032D5404305C03315B0336
+ 6207315C01325D02315C01315C01315C01315C012F59012E5800285100274E02
+ 325B062C55002D57003560052D5900315C01345E062E58012A51012950002C54
+ 02315907355F07315B03315C01315C01315C01315C01315C01315C01315C0131
+ 5C012E56042B5204274E02254D002952012D5801305C03345F04315C01335C07
+ 335B093159072D5700285000295002295002345B062F56012F5601335A052F55
+ 032C52002C5402325B062D5700315907325B0A305A072D56012C56002E570230
+ 5A072B5202294F03284F002C55042E5A012F59022D56012E58012B56002D5700
+ 2E58012E5A012D59002D59002E58002E58003055002F56013159073159072F56
+ 013054002F56012D5601284C00284C002C50032E51072C52002C52002E55002C
+ 52002D51052D51052C50042C50032C50032A4E02284C00274B002C4E012C4E01
+ 2B4F022B4F032A4E02294C02284B01264B032C48022B48032A47022A46042844
+ 02254000263F01263F012B48032A47022945032540002540002844022B48032A
+ 47022B48032B48032A47022945032743012743012642002641012B47052B4705
+ 284704284704274603284704284402284402284402274301254000243F002641
+ 012A460428440225400026420028440229450329450328440227430127430128
+ 4402264200264200264200264200264200264200264200264200274301284402
+ 2744002845002844022844022642002642002540002540002540002540002540
+ 0025400025400025400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00003A650A2B5400254B002D55033964093964093765023C6A072E5A07315E01
+ 3A62033B64033A63012B5A002C671353963B56975953A864C7F1D8FFFEFEFEFF
+ F878B686398A353A761842831D4279162C66013D6A03426E1361903A68A36955
+ A8647ABF94E3FFF2F6F9FEFDFFFEFEFDFFFFFFF998CAA23BB2675597563A8529
+ 4379163B630B3964095184284F873658985766BA7A85CCA1FAFFFFFCFBFFEEFE
+ F387CBA239C88F3DBA8284CBA3F9FFF9FFFDFCC3E8C842925D4CA3534685292C
+ 77154C7B1E50943D48923A66A46868A678A5C9B3FFFFF3BBD6BC509B63469A52
+ 3C7A2846841A386C01396500507A1B50873865A35567A367B0CDACF7FFFFC8D9
+ CB559C644CA156469A52509B635797566C966776A57787B58698BC98A6C8AAB4
+ E6C6D0F1CEC9F2D7F6FEFDFEFAFFB9E7D162C0975AB9873EBA864AA256369146
+ 2274273A86283784293988376AA874A0DAC8E0EFE1FFF8FEE5FFF13ACA8F6CC8
+ 979FDAC6DDF8E8F9FFFAFFFEFFFAFDF4B7F9D665BE9755B888EEFEF3FFFEFFF1
+ F9FFC8E4D7478C532B87344498573D7827437A1738751A65A3679FCFB7D9F9E8
+ F2FEF2DAF7E7B6DAC2E3F8F0FFFEFAFEFFFBFBFEFCF7FFFDFEFEFEFDFEFADBF7
+ E489DBB086CCA4DAF9E4FFFAFFFEFEFEBAFAD73DC7916AC996F7FFF6FFFBFFFF
+ FEFFB1E3BB559C64469954468934396C0A406A053461002E5A012B52042B5605
+ 5F8E3843782F568D54B6D8BAD5F6DB889E824689443D78274AA35366A5675397
+ 5697BB97FFFEFFF5FAF857B57547A96355BA8645AC7379BF97C0E6C8FEFFFDFE
+ FDFFF9FFFABBE7D057A978469A52488836508426315D023965023964093A650A
+ 3A650A345E06345E062C5600284F002D5704315C012D5700325E05305C012E58
+ 00315D00315C01315B032E58002E5902305A022D59002C56002B55002D580133
+ 5F042E5801345E06345E06325D02345E06345F042C55002950022D590039650C
+ 386308345D023262093A640C3262093A650A315C01345E07345F04315D003461
+ 00335F02315D042F5B02346100335D052B56002A5101325B06346007335D0537
+ 65022D5900305C01315C01315C01315C01315C012F5B002E5A01284F00275000
+ 345D082E5902315D003964092E5A00315B0339630B3560052C55002850002E55
+ 07325A08345F04346202345E06345E06345E06345E06345E06345E06345E0634
+ 5E062B5204274D01244B00244C002953002E5902305B00315C01345E06345E07
+ 3159072F59022B5202274E00284E02295000305C032D59002E5A01335F042D58
+ 012953002A5400305C032E5A01315B03335E03315C012D59002D59002F590132
+ 5D022E55072A5200284F002E5604315A05325A082E58012E5800315C01315C01
+ 315C01305C01305C01305C01315C01315C013155032D57002E5A012F59022E54
+ 023054023156003059002B4D06294C022C50032D50062C51012D51042E54022C
+ 51012C50042C50042D51042D51042B4F022A4E02284C00274A002E51012E5003
+ 2B4F022B4F022A4E02294D01294C02294C022B49022B49022A47022A46042641
+ 01243F0026400026400028470428470229450326410126410127430129460128
+ 44022B47052B47052B47052945032844022844022844022743012B48032B4705
+ 2847042746032746032746032844022743012845002844022641012540002641
+ 012A470229450325400026420028440228440227430128440226420026420028
+ 4402284402284402284402284402284402284402284402284402264200284402
+ 2844022844022844022642002540002540002642002642002642002642002642
+ 0026420026420026420026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00003964092951002245022C5500345E06315C01305900335B03225B002E5800
+ 325D023765023A630139630B39792765A35556985757A975EFFCF4FFFEFFFAFE
+ F3559B663A86283574062E66012965002558003E63033E5C0344783257864748
+ 8C5157A975C8F3D8FEFAFFF5FFFEFBFFFFFFFFFB65A577279A4B2B8736226103
+ 3169042D59002D59003B6B0B376B1858985757A66756A975EAF6FCFFFAFFFAFF
+ FEA5E5C13CC8923AC990BBE7D0FDFEF5FDFEFAA5BBA9458C532F802329761522
+ 60023956062E75182D7515478A45488E5288A987FAF6F5F5FFF93F935D478A47
+ 255C0D356C09376600315B04436D16457731498A45568D5498B8A5F5FFFFC5D9
+ CC3F935D379047478D50479853488E5268A676A8C7B8DAF8E5FBFFFAF9FFFAFB
+ FFFFFEFFFDF4FDFFFDF7FCFFFAFFF8FFF9DCF6E8C0F2D09AD0B346A9653F935D
+ 39914544923B48923A65A355B0D4B0E7FEFA9ADBB4F2FBFFF9FFFAB7E6C6DEEC
+ E6FEFAFFF6FFFCF9F9FFFCFBFDE5EDE657B7883DCA913AC990DAF8E5F2F3EFF7
+ F9FFCAF2D93A91472D8833478A4539691A3965023971062B7515468F516C946A
+ A8C7AAF4F5F3F9FEFFF7FAFFFFFFFFFFF9FFF1F9FFFDF5FFFEEEF9A7D5B855BA
+ 8646B77378BE95E7FEF9F3F9FEFEF9FA87DCB03CBB843BBA83FFFEF4E3F7F2FA
+ FFFDA7D5AB3E905F2A88342D7515315C013B6402346003305C012D5801426D16
+ 39792752863879AD85E5FBE9A8C8A93858293779273A77173B8936498A455985
+ 4896BB9BFCFEFFF7F9F944AA6337A6543BB16849AB75A7E4C2EDFEF3FFFEFAFC
+ FAF9E6FCE983BD943E915D3C91473B79273A640C305701305D002E5800315B03
+ 2E59002C55002F59012A52002A51033259092F59022953002E59022E59022B56
+ 002F5A002F59012C56002B55002A54012D57002D59002A5101284F032953002E
+ 5A012C5600305B002F59022A54002E5803315C012C56002A5101295201346100
+ 305C002A54012D5900295A002D5900305C012E5800315C012F59022E58013461
+ 00315D00305C00315C01305C01315B03285200284F002C55002D59002F59012D
+ 59002A54002D58012D58012D59002E5A012D59002E5A012E5902295000275000
+ 325A082D59002E5A01345E062B56002C5500325C042E58002A51012950002B52
+ 042C55002F59012E5A012C55002C55002C55002C55002C55002C55002C55002C
+ 5500285002264E00284F002C5500315B03346003356104315C01284F01295000
+ 2A5400295201274F01264D012A51012E56042D59002B56002E5801325D022C56
+ 002950022851002D59002C54022C56002D59002D59002C55002A52002B54002E
+ 5A012E55052950002950002C5402325A082F59012C55002A52002E57022C5500
+ 2C55002A54002A54002B55002C55002C55002C55002C54022953002A52002A52
+ 002E55002E55002F5601274D01244802264C00284D032850002A52002B550028
+ 4D03294D002A4E012B4F022B4F03284C00274A002648012446002C4E012A4E01
+ 294D00284C00284C00294A00294A002648012744002A47022645022645022443
+ 0025410026420028450026440328470428440226420026420028440228440226
+ 4101274101264101264101264200264200264200264200264200294402284402
+ 2743012642002743012642002642002742002844022743012540002340012341
+ 0029460128440225400025400026420028440228440227430126420026420026
+ 4200284402284402284402284402284402284402284402284402264000254000
+ 264200274301264101264101254000233E002642002642002642002642002642
+ 0026420026420026420026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00003D6906255100255000284F003A640C244E002852002C5004295002264D01
+ 2A5204265200395C022E58002A691363A35748984585BD92FEFDFFFFFAFCD8F5
+ DB4499552D81234268043158082D52022E51012B50002C56003263073B741751
+ 922C47A4538BC699F6FFF2FFFBFFFCFAFFC7F1D84BA3573C86283E6C0C305B00
+ 2B5502294D00274A00295300436D1565A3573B902E5496479CDAB6FFFFFAFBFA
+ FEFCF6F754B5733EC067D9E2E5FDF9F8F4FFF366A36B398A353A74073864012F
+ 59012F56012B590035630A427817458728498B43D5F6DBFFFDFF84A977457731
+ 296501326902355F072E55003B640340740945862A47872799BA98FEFBF7DBE2
+ E53C923A2C85364892383A902C6C9667D9E2E6FEFFFAF3FFEDE7FBE8BFF2CDBE
+ F1CFEAFFFCF6FFF5FEFFFDFFFBFFFEF6FFF7FAFFFAFBFFFDFEFAE5FBE8D0E6CA
+ A5BBA8A5BBA9D1E5CEF5FFF3C9F2D79CDAB69ADAB7F7FFFEFEF6FDFFFFFFFEFD
+ FFFEFEFEFFFFFAF4FEEE8BC89646A86635A8514AA35456B474BFF1CFFDFFF7FF
+ FEFEE3FDE6498B442B8736468837396C0B315C0132620A39630B38730A407916
+ 46883648A35466BA796CCA94E5FFF1FEFEFEF7FFFF89D4A13DC0693DC1673DBF
+ 6A44B565A6D8B6FEF6FDFFFFFFEDFEF353C37552C27447B777FFFEF4FDFFF9F2
+ FFFD8AD4A43990462E76162D64013A5708284A031D4C002D5900396403377406
+ 2F7518517B46D8E9DCF3FFF3507B482D75153B6A03366B034076054486274B89
+ 479AC8A4F1FFF8FFFEFE36A75041B66746AD7493D0ACEDFEF3FFFAF9FFFEFEF1
+ FFFE88D5A249A766399F403886282C64003D6309234A00275306285100285100
+ 284F00274E00274D01284E022B52042E55052E55052A5101274E00274E00284F
+ 012B52042A5103284E0229500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 50002950022B5204295100264B012B5301325A082E5801284F00275000295201
+ 284F00274E002950003159072E56042950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E00284F01274E002950022B52042A5103274D01244A00284C00284C00
+ 284C00284C00284C00284C00284C00284C002A4E022A4E022A4E022A4E022A4E
+ 022A4E022A4E022A4E022A4E012A4E012A4E012A4E012A4E012A4E012A4E012A
+ 4E01274D01274D01274D01274D01274D01274D01274D01274D01295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000284C00284C00284C00284C00274A0026480126480226
+ 4802274A00274A00274A00264801264802244600244600244600274A00264801
+ 2648012645002544012443002342002442012640002640002640002640002640
+ 00253E00243D00243D0126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000274202264101
+ 254000233E00233E00233E00243F002540002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00003E6B0A2B55002E59022D5601396409285100285200274E002D4C01244903
+ 285002295000355B033965023B7A2463B26849A455A9D8B8FBFDFDFFF7FEC3E5
+ C749A4552E8125406908355C062C4F002F4F022B4D002C55003460033A6E0A52
+ 912946984678B686F6FFF4FDF9FEF8FDFCB7E6C6489A513585283268042A5C00
+ 2C56002A4F00284C00285002336108508527488F2E5196468BC699FBFFF9FEFD
+ FFFFF9F968BC863EC067F6F9FFFFFFFEECFCF1598D57308025346B0033610129
+ 56003355012F5A00336200447A17448529458837B8D7BAFAFBFFB9D6BC43782F
+ 3D76142C6201315D0431550138630239730646872B48902C95BA98FDFEFAEBF8
+ FA4397453A933644923A488944C0E7C7F6FFFFC7DFBC83A87A549759549A6563
+ B26956BB87AAD6B9F9FEFCFFFBFDFBFDFEF5FFFEFFFDFCFFFEF4FEFDFFFAFFFF
+ F8FDFEF4FFFEEDFEF5B7D9C17BBE995FBF97A9D5B6F8FFFCFFFEFFF3FFF2E5FE
+ FAE7FEFAB3D8C478A36A68A3592D873438923847994647AA62A5D6B6FFFDF5FC
+ FDFFEDFEF5448B422D86364887373B6C0A2757002753002A56002B6600356C09
+ 3775173A88344CA25456B473C7F1D8FEFAFFF8FEFD88D5A23FBE683BC0693CC1
+ 6547B567BFF2CDFEFAFFFFFDFFDBF7E346B7744FC47548B674F4FEEDFFFFFFF4
+ FEFE98C8A43A91472B7517336A03325B002B4F03234D002E5A00366500377209
+ 468626639156F3FFF3E3F8EF4877323B821B3E6A053368003B74173885294889
+ 449AC9A3F1FFFBFFFDFF51C3763CB2696FC994D9F6E6FFFEFAFCFFFAF4F5FFFE
+ FAFF98D6A853A8644798533A86283A730A2D5900426D16244900275000285100
+ 295000274E00264D00274E002950022B52022D55032A5101274E00274E002950
+ 022B5204295002284F0129500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295002295002285000274C022950002E55052C5500284F00284F002A5101
+ 295002274E00284F012F56062D54042950022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00284F00264D00284F002B52022D54062E55072D5406284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C002A4E012A4E012A4E012A4E012A4E012A4E012A4E012A
+ 4E01274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000294D01284C00284C00284C00284C0026490026480126
+ 4802274A00274A00274A00274902264801244600244600244600274A00264801
+ 2648012747002645022743012443002442012640002640002640002640002640
+ 00263F01253E00243D0026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000274202264101
+ 264101243F00243F00243F00243F002540002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000335F062B5500315C012E5801345E06274E00284F00274E002C5300265003
+ 285204265100375B014268043C792965A35753A864D7F5DCFFFEFFFFFBFD98C7
+ A64998472E75153965002D58012C52002C4F002C4E012C51012B5801346A094F
+ 8427499847549B63E7FBE8FFFAFFFEFDFFB8D9C4488D542D8024326902265A00
+ 2A51012A4C00264D002950002956003D6C0941882846913D68A676EDFDF2FFFE
+ FFFFFFF99CD5A853C474FEFDFFFDFEFAD8F7DC468946317F27326B093561022B
+ 55002E4E01285500315D023F710B45851B47893895BA98FAFFFEE3FFF1578647
+ 4587282A66013460012B590039650842750646852747902E98BC98FDFEFAFAFF
+ FE4699553CA04153943E8AAA91EEFDFFC8D9CC6C966746994447A25335A95043
+ B56840C06797D7A9FBFFFAF3F6FBD8F7DC9ADAB7BFF1CFDAF9E4FAFFFEF5FFF9
+ E3FDE6C8E6D397C7A366A77647AC7558B987B6E5C5F0FFFBFAFEFFE5FFF2A7E4
+ C267BB85599656398A354F84272F7616388628469338469A5298C7A6FFFFF8FD
+ FFFFFBFFFA5698573B89364589343E6C0C335C002A5B072D5801315C01366207
+ 326B0839811D3A933648A354B6D8C7FFFAFFFBFFFF9ADAB647B66639B16A3DBF
+ 6866BA7AE6FAE7FFFBFFFDFFFFB9E6C543B66742B56645B974E3FCE8FFF9FAFB
+ F9FF9AC6A7448A442E7514326A00385B012B4F022151002D59003262093A7715
+ 4589347AAB85F6FFFCE1EDE756864438821C427506397307367819398625458B
+ 459AC8A4F2FEF8FDFFFF49AB777ABF94E4FFEFF1FFF9FAFFFFFEFDFFFFFBFDFF
+ F6FCE7FCE6A7D3AE479A553A92383671092E5C033B64081E4C00275000275000
+ 295000284F01274E00284F012950022950002D55032A5101274E00274E002950
+ 022A5103295002274E0029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E00295002295000274D01284F002D54042C5500284F00274E00295002
+ 295002274E002950022D54042B5202274E002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F01274E00264D00274E002950002D54042E55052E5604284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C002A4E012A4E012A4E012A4E012A4E012A4E012A4E012A
+ 4E01274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000284C00284C00284C00284C00284C00274A0026490026
+ 4801274A00274A00274A00274A00264801244600244600244600274A00264801
+ 2648012848012645022844022642002442012640002640002640002640002640
+ 00264000263F01253E0026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000274101264000
+ 264000253E00253E00243D00253E002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002850022950002D57002951002E5604284B01295002274D012C4F002C5004
+ 2954032B5500346001386E0A38772753954667A367EDFFF2FEFDFFFBFEFC6CA6
+ 76398A352A72083561022E55072B50002A4E01294D012A51012E5A0132690244
+ 831B46913D468E52B6E7C7FDFEFAFFFFFFE5F1DF57965830812434690B2E5A01
+ 295300254A022749022D51002D59003C6C0C47862844923A559855D4F9D9FCFE
+ FEFEFDFFBFF2D069C895FAFCFDF5FFF9C2E7C7478B4438821C3C6D0B31610122
+ 5300254A002652002F59013C6C0C44831B44873668A678F8FFF9F1FFFE74A775
+ 4487362A7207316900335B0338630C40791747862842923997BA98FFFFF7F7FF
+ FD4899543D9D424D9646B2CDB9ECFEF16E95683689343D9E402A973144B56544
+ B4663EBF6A7ABE95FFFEFFFEFEFEBFF2CD54B57344B67658B16C529B63569966
+ 578B55457731467733448A444BA45446A965A9D8B8F0FFF5F0FFF998D6A856B2
+ 693D91433B92363D912B426D16326B0936761638821C3A914787BC94F9FEFCFE
+ FAFFF3FFF95698572F80232B7515315B032854012A52002B50002F55032B5900
+ 2D59003473053D902D48985598C7A6FFFEFDFFFEFFB7E5C845B5673CBF6847B8
+ 7587CBA2EEFFF6FDF9FFF7FEFB85CBA247A86547A96345A961C8F2D9FFFAF7FF
+ FBFDA6C8A9438B453A801B3269022F56003151042650022B580134630738811D
+ 46863A95BF8AF7FFFEF7FFFE86B4892F7F243A7A2836761638821C398A355196
+ 4598C8A4F5FFF9FFFAFF86CBA6E5FBE8FEF9FAFDFFFEEDFEF5F8FDFBFBFFFFF7
+ FAFFFFFFFAE5FFF26AAD8048984537821A437607315B03365E06284F00295000
+ 295000284F00284F01284F01284F01284F012D55032A5101274E00274E002950
+ 02295002284F01264E0029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F01295002284F00274D01284F002B52022A5200295002284F01295002
+ 295002274E002950022A5101295000264D002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000285002274F01264E00254C00254C00264E00274F01274F01284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284F00284F00284F00284F00284F00284F00284F00284F00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000284C00284C00284C00284C00284C00284C00284C0027
+ 4A00274A00274A00274A00274A00274902254701244600244600274A00264801
+ 2648012547002645022743012845002844022640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000274101264000
+ 264000253E00253E00243D00253E002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000234A00274E002C5101274D01295002284C002D5104274F01274A00274C02
+ 2853022C56003763044278174587284698467BAD85F7FEF9FFFFFFEDFEF1538E
+ 542F7F24336C0A305C002E55072951002A5103284C002D4F0232560233600043
+ 7A17478F2B4799468BC797F9FFFAFFFAFFF8FFFF67A268358627346B08335B03
+ 295600244B00264801305100315C01396D09447A1751953C489857B7E5C8FAFF
+ FFFFFFFEE6F9E899D7A9FFFEFFF7FEF9ABD7B8498B432B7614376403375B0123
+ 51002D4E032D55032B58013E6B0445821A478B38568A54EEFDF5F9FEFFB2D2AF
+ 4A77323A761832680433610032620A4379164287374794389AC8A4FBF9F8F5FF
+ FF4698463B9F40519646E1EFE49AC8A4478A45398A353E9F414CA35348A35457
+ A9753EC26578BE95F5FCFFFEFDFFC0F3CE51C4753DC06936A750399F403A8628
+ 2D73183A771543831947902E48923A479947A6C7ACF5FFFEEEFFF268A7753990
+ 4646913B47862A316904405C032A67003A6B003973073A923872B07CF7FFF8FE
+ FAFFF8FFFE65A2682C88352C69132F5C002E5A01305505264B01254D00285200
+ 29560031690438811B46923A79AC86FFFFF9FFFFFFD7F7E655B16A3DC16757B5
+ 74B6E4C7F3FFF6FCFFFBEEFEF36DAD834BA35048A5544DA355AEE1BBFDFEFAFF
+ FEFFB9D6BD468A433684193268052D57002A5204254C002C55003263073B8319
+ 46883684B589FAFFFFF9FFFEC2E6C84989473984282E7616317F273B912B4797
+ 549BD6A9F1FFFBFEFCFCF7FFF8F7FFFFFFFFFFFEF9FAF6FFF19CDAB6B8E6D3EC
+ FFFBFEF8F9F9FFFACAF2D967A3674688374279163E6503275600284F00284F00
+ 284F00284F00284F00284F00284F01274E00295100295000284F00284F002950
+ 0228500227500027500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000264D00284E02284F01264C00284F00295000295000295002284F01284F00
+ 284F01274E00284F01284F00284F00284F012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000285100275000274F01254C00244B00234A00234A00244B00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274B00274B00274B00274B00274B
+ 00274B00274B00274B00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284F00284F00284F00284F00284F00284F00284F00284F00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274A00274A00274B00274A00274902264801264802254701274A00264801
+ 2648012648012645022743012845002844022640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000253F00
+ 264000253E00253E00253E00263F012640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264D012A50042C5305284D03275000274E002950002851002B4F02284C00
+ 2A52042F59013D6402437918478F2B439945A5C9ABFFFFFAFEFEFED7F6DB488B
+ 4638811A326B08315C012951032A5004294F03284C002F4D01305400325D0242
+ 6C1443882748974674AF7CF5FEFBFEF8FDF8FEFD87B6883989363672062F6200
+ 2D5900284F00254B002C4D022F5404345E07427A1546913B54954986D5A2F8FD
+ FBFBF9FFFFFEFABAE8D1FEFDFFF3FFF998C7A63C88362E75183A640030540026
+ 51082950002953002B5A00386401447A17468D2D468F51D8F7DCF7FAFFE5FCE6
+ 57854A3676163773073169003369054279164A8737479139B3D3B0F9FFF9F1FF
+ FE4A9A55399F4048923AD9F7E475A876459139459647448E5465A57798C9A3A7
+ E5C1B7F7D9D7E9DCFFF6FFF5F4FEBDEFCD69BA7B44B56535A9503C902A377717
+ 346A093269022F71072E812539913748A354A7C9ABEFFEFFEBF8F669A4774792
+ 3E378625407409426A05375A0332610042690743730938923868A468F4FFF7FF
+ F9FFFAFFFE75B17B3C88362968123460012B59002C5109244900284E06295103
+ 375A003864013A740837913866A567F3FFF3FFFAFFEDFEF364BB773EC06964B9
+ 7BDCF7E7FCF9FFFFFEFAD7F6DB44A9654998474AA2564AA35486CCA3FFFFFAFC
+ FEFEC8E5D6478A473A811A3469022D57002C52061F4E002B5204305C033A7717
+ 45912C589857F0FFF7F8FBFFE6FCEA72B07A3789363181242D7F26399339489A
+ 5298D5A9F1FFF6FFF8FFFFFFFFFEFDFFFBFFF9EFFFF499C8A267BA7C69B887B9
+ F9D6FEFFFAF8FFF8F3FFFFA8D7B64B8A4537821A3773073361012B52022A5101
+ 295002295000295000295000284F01274E00284F00295000284F002950002850
+ 02274F0127500028510029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000264C00284E02294F03274D01274E00284F01295000274E00275000285100
+ 285100284F01284F00284F00284F00274E002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000264D00284E02294F03284E02274D01264C00254B00254B00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000294D00294D00284C00284C00284C00284C00284C0028
+ 4C00274A00274A00274B00274A00274A00264801264801254700274A00264801
+ 2648012648012746032645022845002544012741012640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000263F01264000
+ 274101264000263F01263F012640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000294F032A50042A5004274C02285100295000284F002851002C51012B5000
+ 265604315D003B6B0142841B51963B469846CAE5D5FEFAFFFDFFFFA8D7B73B90
+ 463A751A3269022D5702295100264D00284C00254800294D01305400335C013A
+ 6D0B51842846984654A965F0FEF3FDF5FFFFFDFFA8D6A83889343A77172D6401
+ 2E59002A5204284C002B4E002C5600375A034074083D902D51954868BA85F9FE
+ FCFAFAFFFDFFFFE4F5F1FAFAFFEDFDF283BE92378A3530731736650031550120
+ 5200264B01214E002E550031620042740839902E488C51C5E0BFFAFAFFF3FEFB
+ 77A5763984283772093C6D05316900437B16458735449338AFE2BCFFFEFFF2FF
+ FD4699553CA04048913BE5FEF4498B4446923A569759A6C8A9E5FCE6F6FFF4F4
+ FFFDFCFFFAFFFCFFFFFAFFFFFFFFEDFFFE9ADAB654B888249C4B3B7927397517
+ 3D69063E6A053368012D7515378936469846B7D9C1FDFEFFFBFFFF6D95653784
+ 2937821A316902385B002E51012D58013665023472083D912B478D51F4FFF3FF
+ FAFFF6FAFF74B07A3989362E7515376502315B042D5307274D01224C00274C02
+ 375C00315C012C72073D902D579658D8F7DAFFFFFFF2FEF88BC79748B6766CCA
+ 94F2FEFEFEFBFDFEFFF8A6D6B943995346923A48A13951964657A975F5FDF6FC
+ FFFAE3F8F0578C5335821A377307315D00305407224D002B5305385B04387205
+ 3E912B468944C5E0BFF7FAFFF6FDFFC4E2BF4899543688353B8C374797444AA3
+ 549BD6AAF0FEFAFEFAFFFAFFFEFBF9F8E5FBE884CAA654B16C4BA25254A86744
+ B873E7FBE8FDFFFFFFF7FEF0FEF868A7753D922A2C72073962062E55052B5202
+ 284F01274E00284F00295000284F00274E00284F01295000284F00284F002851
+ 00274F0127500027500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284E02284D03284D03284E02284F01274E00274E00274E00285002285100
+ 274F01285002275000295000295000284F012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274C02294E042A4F05294E04284E02274D01264D00264D00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 002950002950002950002A4E01294D00294D00284C00284C00284C00284C0028
+ 4C00274A00274A00274B00274A00274A00264801264801264801264900254701
+ 2547002648022847042746032847022847042842022741012640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000253E00253E00
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274C02274C02274C02284D03285100274F01274E02254C002E4E01294A00
+ 295201345E073C6C0C47821A51953C469846E1EEE6FDF9FFFFFFFF9AC7A63893
+ 362F76163162002E59021F4D00254C00284B012645002A4B002C520030540042
+ 69075283273D912B489954EBFFF3FFF5FDFEFAFFC8F2C93C933944831B2A6601
+ 2C5402295004294E002E5200315600345A0040730B35821A46994456A975FCFF
+ FBF9FBFCFEFBFDF6FEFDFFFEFEF0FFF878B7853B89352D75153965023054001E
+ 4D01274C04284C002B5900375A044074093B8428488E51A5C9ABFCFBFFF3FFF9
+ 9CC8A34688363574063469023B6B0141821C46883646913DC4E6C8FCFFFDF3FA
+ FD479A55399F4044923AB6DAC4478B4448923A9AC9A3F5FEFFFFFAFAFDFEFCFD
+ F5FFFFFDFFFEFEFEF9FFFAFAF9FFFFFFFFF6FFFCC9F1D869A4773888352C6913
+ 305D003864013B6C0439751744862753963BC3E7C9FBFFFFFAFFFE77A7773C8F
+ 2C2F7209296500315C012A50042B5700385B003B6C003C8F2D458D51F3FFF3FF
+ FFFFFDFFFF76B27C3889343877173B6A032C56002849062B4D07225200214C01
+ 2F5700375A0434690238902C498A45C2E5CAFCF9FFF1FFF991E1AC49B77585D5
+ A0F5FFFDFFFBFDF3FDED88BD95279A4A46913B3A902A5297473F915DDEF1DEFF
+ FFF9F2FDFA598B5536831B3872063461002D5406214C012B52023C5301326902
+ 37821A53953C869F85FEFFFDFFFFFFF6FFF257B06B469A524698464798494BA4
+ 5498D6A8F3FFF9FFFBFDFEFFFBCAE4D66DAD834898553B92362896303B9F4038
+ A75178BE96F1FFF9FEF6FDFFF9FFA7D5AB3B9F4038811A3864003259092D5404
+ 295002284F01284F00295000284F00284F01274E00284F01284F002851002851
+ 00274F0127500027500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000264C00284D03294E04284F01295002274E00274E00284F01285002285002
+ 285002295103274F01285100285002284F032950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E02284F03295004274E03244B00234A00244B00254C01284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274D01274D01274D01274D01274D01274D01274D01274D01295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000294D002A4E01294D00284C00284C00284C00294D0128
+ 4C00274A00274A00274B00274A00274A00264801264801264801264801264802
+ 2449012648022647042746032847042847042842022842022741012640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000253E02243D00
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000295000295000295000295000295000295000295000295000235100295300
+ 2E55003E5C034175094686264889344AA354FBFFFAFFFFFFF2FFFD86B4893989
+ 36346B083562012956002A4E01294D01274B00284B01284C00294D002E550036
+ 5E0644841A48923A589759BBE7D0F9FFFDFCFEFEEEFDF5568D563A8628336C0A
+ 2B59002F4F00254A04264900285100315D0032690246841852964953A766DCF8
+ E5FBFFFFFEFEFEFDFEFCFFFEFFFDFEF467BB7B3B92383A73062766002C550027
+ 50002F56002C53002952013965023D740755912C4F97458AD4A4F5FFFEFAFEFF
+ D5E9DC547A4838862832690240740851842A488F2E489746C5E0BEFFFDFFFEFF
+ FD54A66547994746994482BA6D55854A889E82F5FFF2E5FAEBB8DAC284CAA255
+ C3756CC897A5E5C2FFFFFFFFFEFFFFFEFAE5FFF0FDFEFAF8EEFA5786482B7515
+ 2B6401265A003965083A771747902E489746CBE4D6F9FEFFF6FFFA77A5763784
+ 282C72073462002A5B072253003C53012E5900396B0D388529478D51F5FFF3FE
+ FAFFFFFFF86CAC82398837417A172D64012F56012F4C032A5302284C00264D01
+ 3055052D5900426A054D7A1D5096498AD5A2FFFAFFF8FFF8BFF2CD3AB26BD8F7
+ DCEAF7F9FEFAFFFFFBFA57A7663B883745862A46862636862948A453A5C9ABFF
+ FDFFF7FFF888A9873B7927377209326A012D57022B5600245A01245A00305C01
+ 437A1747862A49A455B1E3B9F7FEF9FEF9FFBFF1CF559C644EA25437A75345A8
+ 64B5CFB8FAFEFFF5FFF987DCB054A5664CA353468F2D437A1737792744831B51
+ 912D4BA552A5E5C2FBFFF7FEFAFFF7FAF867A2683B89363D6A033361012D5900
+ 2E55002E5101274902294D00285204234D002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C002950002950002950002950002950
+ 0029500029500029500028510028510028510028510028510028510028510028
+ 5100284C00284C00284C00284C00274A00264801264802264802274A00274A00
+ 2649002446002446002446002648012648012844022844022844022743012443
+ 0022420121410023400126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000295000295000295000295000295000295000295000295000215100234D00
+ 305001415D0342730947902E45933C65B169FEFFFBFFFDFEF1FFF979AD853984
+ 28397209335F00295000284C00284C00274B00284B01284C002A4E012F560136
+ 5E0640791647902E489A52B7E6C6FBFFFFFFFFFFF3FFF269A5753B8527316D09
+ 2E58002E5101254C01244B002A51032D5C003D6A0347831E52973C559C64C7F1
+ D8F9FEFDFFFFFFFDFEFAFFFAFFFFFEF464B87D3A92383671092966003155012A
+ 4F051D4B03295103315503315C0132690241852653984798D5A9F4FAF9FFFDFF
+ EDFFF264A46836852A3782184379183D792548912D439745C3E1BEFEFDFFF9FF
+ F655AA7844994549923C46913B5A8C56D5F7D9BBD6BC6C9667458C533E945E55
+ B16A56B4739ADAB6FFFEFFFEFEFEFEFFFBB8E5C4E9FCE9FFFEFF97BE8A3A7826
+ 326A012B64013A6301387618428627449944C5D9CDFBFFFFF7FFF878A6773885
+ 292B70093360032950001F53003C5400305C033469023885293C9244E7FAE9FE
+ F5FFFDFFF96AAF843C88364379153469022B59002F4D022C5101284F01254C01
+ 2C56002E550038640043781A458A476BC895FEFDFFF5FFFED9F6DD54B985E5FB
+ E9F5FFFEFEFBFDEDF2F04499453687264278173976163B912B47923E76A574F5
+ FFFFF2FFFDAECDAC497631387814276501315B03274E002753002252002F5B02
+ 3B640247862A43913976B986EEFFF2FFFBFCEEFEF396C9A44AA4513DBF6A48AB
+ 63B8D8C5FBFFFFFAFEF985CCA14999543688352F75182B6702326307346A093B
+ 821B3D8F466DAD83ECFDF4FBF6FFFAFFFEA7D8B843933638751A3460032D5801
+ 305402285000274B00284F03285205214D002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C002950002950002950002950002950
+ 00295000295000295000284F00284F00284F00284F00284F00284F00284F0028
+ 4F00294D01284C00284C00284C00284C00264900264801264802274A00274A00
+ 274A002547002446002446002648012648012645022844022844022743012443
+ 0024420123410022400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274E00274E00274E00274E00274E00274E00274E00274E00205100274E00
+ 2E520038640041730D498F2B4F94496BBB86FFFFF7FCFEFFEFFEFA69A6743785
+ 27377504315B03275201284C00284C00274B00284B01284C00294D002F560136
+ 5E0642740846913D479B53A5D6B6FCFEFFFFF9FFF5FEF485B6883885292D7515
+ 315C01315600274C021F4B002A52002E5A003A6B0343781751953E469A52BBE6
+ D1F5FFF9FFFEFDFFFDFEFFFDFFFDFFF968BB84378A353B6C0A3562013354032C
+ 50001C4D012750052A5302305B003E6D0B4A8E2F5795598AD4A4FFFEFDFFF9FF
+ F6FEFD87BC943B842844841A39751744852943923B469846C8E0C0FEFEFEFFFE
+ F966B97B4397453A923838912A68A775D5F6DB62915245772F46923A44994546
+ A96555B1689CDBB4F8FEF9FDFFFFFDFEF47ABE95A6D7B7F0FEFAD1EFD2467832
+ 2965013A6B013862034479184388274DA257C9E6D7FEFEFEF0FFF87AA6773784
+ 2938730A3965002A52002A54003D54003161013468043B8428469846E0F0DEFF
+ FFFFFCFFFB6AAC833B893546821D3269022F5B00304E03284F00295100274C02
+ 2952002B54003965003E6B0A46883667BB7BFFFAFFF1FFFDECFDF29BC9A5EFFD
+ F2F9FEFFFFFAFFB8D8C73A913938811A3876183A6D0B458329378527478A45C4
+ E6C8F7FFFED3EFD2517A4739821B316A013461002A5701284E02264D00325A08
+ 315D00427719378527589759C4E6C8F9FFFEFBFFFFDCF7E769BB8639BE6753C3
+ 75B7E6C6F5FFFEFFFEFF89CBA2478C533B8428306C08235801285B002C650234
+ 7206488F2F4C9545B8E5C4F9FFFEFFFFFFE5FBE8568C572F8023316801325E01
+ 285500305100284C00254C012751042150012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294C02294C02294C02294C02294C
+ 02294C02294C02294C02284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274E00274E00274E00274E00274E
+ 00274E00274E00274E00284F00284F00284F00284F00284F00284F00284F0028
+ 4F00284C00284C00284C00284C00284C00274A00264900264801274A00274A00
+ 274A002648012547012446002648012648012645022743012844022844022642
+ 0024420123410022400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274E00274E00274E00274E00274E00274E00274E00274E002C52002A4E01
+ 2E550041640D3F78164587285097478DC896FCFDF9FEFDFFEDFDF2519C662F7F
+ 24357307335C01285302294D01284C00284C00294C02284C00284C002F560136
+ 5E0643740A498E2D45974599C8A7FBFFFEFFF9FFF8FFFA9AC9A33A8E2F397614
+ 3162002959002950021F4D002A4E0131560039650243791648923A489954AFE4
+ BCF1FFFBFCFDFFFFFEFFFAFEFFFDFFF96CB9863B89363D6B0B3460032E55002E
+ 53002854012956002D5601366100377406448F2D48A25694E2ACFEFDFFFEF8FD
+ FBFFFFB7E6C6468A37468529397616398A3548923A479947C7E0BEFFFFFFFFFE
+ FE67B88744984646923A468837ABD8B786AA7630610B46781A3C8F2C3A923848
+ 974658B16B91E0AFF6FFFFFFF9FFFCFDF345AD7667B887B3E3B9EDFEFA558845
+ 2965013D6B003A6301407916458728469846CBE5D5F8FFFAF7FEFB78B7853C89
+ 383673053A6B012D59002D57023953003063073776163B922A459854DAF8E5FE
+ FEFEFCFFFB6DAC84398A354079162F6904335C01304D042850022D51002A4E01
+ 2850022F5503306000386C0E3D842755B168FEFEFEF2FEFEFEFFF8D4E8DBF3FE
+ FBFEFDFFFEFDFF78BF973A92382F7616396C0A436907447A1747821944883575
+ B27AF4FFFDEBFFF26E9567397A252E7205326804325B002E4D08295000315503
+ 345F0431690439831951964687B489F0FDF5FEF7FEF7FFFEB3E2BB43B66752C2
+ 75B8E7C7FCFDFFFFFDFF88D5A2458A473D7925316A012E59022E580131620036
+ 6B0A43821A48923A6CAE84ECFDF2FEFAFFFBFEFC86B587398A353675072D6500
+ 285500285100284C00274E002B5202274E022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274E00274E00274E00274E00274E
+ 00274E00274E00274E0028500228500228500228500228500228500228500228
+ 5002284C00284C00284C00284C00284C00284C00284C00274A00274A00274A00
+ 274A002648012547012547012648012648012645002544002744002844022743
+ 0124430023410023410026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274E00274E00274E00274E00274E00274E00274E00274E002E4F04254C01
+ 2F56013964094379154486274F95489AD6A6FAFFFDFDFFFFECFDF2578D52327F
+ 243A72072B59002A5204284C00284C00284C00294C02284C00284C002E550034
+ 5E063B6A0345862A3A914782BD91F9FEFCFCFDFFFBFFF9B8D8C5479139377618
+ 336200325B002C51011E4C002A5004325302386401407917468F2D4BA4549BD3
+ A8F8FFF9FFFEFFFAFFFFFAFAFFFDFEF566BB893B92383A76182C6503385B0031
+ 5503315D002D5900315C013A6C0E37821A4B9E3B53A86492E2ADFFFAFFFDF9FE
+ FFFFFFD8F4DD46894644831D39831939832954973C459744CFE5CCFFFEFFFEFE
+ FE6DBA873A914746933845772FECFDF2508528386C013B6B0B38730B3A832749
+ 9F3B48A45388DCB2FCFFFDFFFEFFFEFCF448B77343B66661B269E3F7F26D9663
+ 32620A3169023D64024173074886283B9046CAE5D5FBFDFDF8FFFC85BD924591
+ 3938811A3B6C0A2E5A07265B00385C022A69133C84243B933948A157F7FDECFF
+ FFFFFDFEFA6CAC823C8A374278172B64012E5A012F4C03294D002E51012A5103
+ 2650022D5400346301356B073A852949A455F5FBF6F9FEFFFFFEFFFDFEF4F0FF
+ FEFFFDFFF1FFF857A877478F2F3366043463013F68063A6B01417A18488F2E47
+ 8A47C3D9CDF2FFF9B2D3AE4776312C73052F6A022E5D013054082E55002A4E01
+ 345F08325B0039821B44913D569956B5E6C6FAFAFFFFFDFFE5FDE56DBA874AB7
+ 72B4F8D5FBFFFFFEFAFF8DC7974588373A76183169002D59002F56012D590031
+ 6200437509498D2E458D51BBEAD0FCFEFFFEFEFEC5E0BF478A45397616296501
+ 2B59002A5400264C00284E022951032750002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274E00274E00274E00274E00274E
+ 00274E00274E00274E0028500228500228500228500228500228500228500228
+ 5002284C00284C00284C00284C00284C00284C00284C00284C00274A00274A00
+ 274A002648012648022547002648012648012547012746012544002744002743
+ 0126420024420124420126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274D01274D01274D01274D01274D01274D01274D01274D01294D012C4C00
+ 2F5503366401437918488F2E579756B1E3B9FAFFFFFFFCFEF6FFF3478D513883
+ 193167032E5A012A5004284C00274B00284C00294C02284C00284C002B540031
+ 5B033B6B0145882749974479B886FAFEF9FEFAFFFCFEFFC6E5D64498463B7925
+ 356806335C012C5101214E002A4F002A5200365F03437A17468F2B48A3549BC9
+ A5F5FFF9FFFEFFFCFEFEFFFEFFFFFFFA6BC895389147447A172A6300305D002C
+ 5902366500336101346B083B79273B922A47984963B26999D9B5FEFEFEFEFAFF
+ FFFEFEE5FFF264A5564079173A811A37852753953C459947D0F1CFFFFAFFFFFF
+ FF67B9853C914746923A437731F4FEF83460013B6B012E5D014074093A771746
+ 8F2B46984598DAB7FCFFFDFFF9FFF3FFF34BB77546A963479853C7D8CD7BA26B
+ 346A092965003B6B0143740A44902B3C9147C8E5D6F9FFF9F7FFFE92CFAB4999
+ 523D902D3676162968122D69113665092E75153B923C3CA04046AA62F7FFF5FF
+ F9FCFDFFF967AF803A88344279162C66012E5A01324E022151022B5100274F01
+ 274F012B5600315C013167033686294AA354D5EBD9FCFBFFFEF8F9FEFEFEF2FF
+ FDFDF6FDDBF8E848985139821B326902305D003C640C3F680639730745821A39
+ 79276C9667E6F9E8EBFFF36790573869173068012D6302325A082E59022A4B00
+ 2F500034630137720946821E55994678B686F0FFFBFFFFFEF5FEFBB6E5C558AA
+ 76B7F8D8FAFFFEFFFEFE89D3A34688363A76183768062D59002E54022E590031
+ 5B03346A0944831D41994578B785F2FEFEFFFAFFE6FCE9458C533B811C2D6C06
+ 285A022E55002A4F002B4D00284F002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274D01274D01274D01274D01274D
+ 01274D01274D01274D0129500029500029500029500029500029500029500029
+ 5000294D00294D00284C00284C00284C00284C00284C00284C00274A00274A00
+ 274A002648012648012648012648012648012648022648022446002645002844
+ 0227430124430024420126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254C00254C00254C00254C00254C00254C00254C00254C00294D01274D01
+ 325400336101407916478F2F569759B5E6C6FBFFFFFEFDFFF4FEF1468E523883
+ 1B316A012E5A01265108284C00274B00294D01294C02284C00264C002A530030
+ 5B003C6B0444852947994776B079F8FFF9FEFAFFFEFDFFE0ECE64698462E8027
+ 306803305C01285500244E012A4D032C4E01375C0042740848902C43984485BD
+ 94F5FFF3FFFFFEF9FFFDFFFAFDFFFDFC87D6A34BA4554587352F7717346A0934
+ 6A092F73063976163988373B8A3346995465A57797CAA4E4EBE8FDFEFAFFFEFE
+ FFFDFFE5FFF276A16842791638771736862944923A489A52E5FBE9FFF9FEFEFD
+ FF68BA86479B4345903A4F8427ECFFFC427309396A02375F073673053D792544
+ 87364CA254B8E6C9FEFAFFFDF7FCF3FEF466BA7A4AA3543B9D43A5BBA878A469
+ 3772092867013673053B74193B902E469A52E2EDE3FEFDFFF4FEFEA9D8B854A6
+ 654AA3533A91393080252E8224397927398A354898454AA35457BA8AF0FFF1FF
+ FBFFFFFFFA7AB6863B903B36831B2B6600315B032A5000245200285200254F02
+ 274E02325500325B002E66003882183B9E42BCE6D4FDFFF9FAFFFDFFFEFFF4FF
+ FDFFFEFFB6E5C5439846387717326804336200365E064369073E750843740643
+ 7918397A2595BF88EEFEF3B2CCBA5485473A7408346902336200335C01255100
+ 294C02345E07326902387507479139569857B5E6C6F8FDFBFFFDFFE6FCEA7ABE
+ 95C8F3D8F9FEFFFFFFFE8AD5A24586373878153063092B560028510029500029
+ 55022D650037761846923A579755D9F6DCFFFEFFF7FFF868A77545821A357406
+ 325F022B5900295000254C002550002851002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002A4E012A4E012A4E012A4E012A4E
+ 012A4E012A4E012A4E01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00254C00254C00254C00254C00254C
+ 00254C00254C00254C00284F01284F01284F01284F01284F01284F01284F0128
+ 4F012A4E01294D00294D00284C00284C00284C00284C00284C00274A00274B00
+ 274A002648012648012648012648012648012648012648012446002645002645
+ 0228440226420023420026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264D01264D01264D01264D01264D01264D01264D01264D01344D032B4D00
+ 2D5801335C013A7717468F2D5A9659B9E7D1FDFFFFFBF9FFF4FFF4478D513881
+ 1B3268042B5900265106284C00264A00294D01294C02284C00264C002A530031
+ 5C013B6A0338831944994577B17BF5FEFBFEFAFFFEFDFFF0FEF24898452E8027
+ 3469013362002B5500274E002B4C012E4E01385B013F750A498D2E47994778B7
+ 85F4FFF3FEFDFFFCFEFFFCFAFFFFFEF98ADCB143A86454963D46852744831B3A
+ 852946852937943944984656B47491E1ACDCF8E5EEFFFCFCFBFDF3FFF0FFFEFF
+ FBF9FFA6C8AA477631396C0A4479183B8329468837469A52F3FEF4FFFBFFFEFE
+ FE68BC8648A3543B893644841AE5FFF9538438336A03416D142D730842862749
+ 894749A455BFF2CDFDF7FCFFFAFFF3FFF96AC9974AA3543B92368AA99465A357
+ 2D7308316902437A1743821A3A913B47AA64F4FFF5FFFEFFF1F9FFA0DAC854B6
+ 7445B5674AA2563A92463D9E4053953C48A3544AA45155B06B6BC895F5FFF2FF
+ F9FFFFFEFA78B68646984544831B326A01335C012C5300215001284F00284F03
+ 284D052B5204305C032B64013A811A3B9F40A9E5C3FDFEFAF7FFFDFEFAFFFDFF
+ FFFFFAFA88D4A43A91373877172D6401346003295300375B0143740A3B6A033A
+ 6D0B2E741745772FC6D8CBFAFEF86A95683B75162A72072A65032965002C5600
+ 2E54082E550534600137730738862846984668A678F7FFF3FCFEFEF3FFF2B7E6
+ C6BCE8D1FCFFFDFEFFFD9AD5A8468C453976163063092D54002950022C520029
+ 56001E630241771646821D489954B6D7BCFFFFFFF6FEF398C8A4458728357307
+ 2E65022F59012A4E01284F01294E00284E022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002A4E012A4E012A4E012A4E012A4E
+ 012A4E012A4E012A4E01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00264D01264D01264D01264D01264D
+ 01264D01264D01264D01274D01274D01274D01274D01274D01274D01274D0127
+ 4D01294D002A4E01294D00284C00284C00284C00294D01284C00264900274B00
+ 274A002648012648012648012648012648012648012648012446002446002645
+ 0028440227430124430026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00274B00274B00274B00274A00274E002C4E01
+ 2E550033630A4074083C8F2D478D50D6E9DAFFFDF5FEFDFFEFFEFA478D503882
+ 1C326902345E07254B00264C00254B00274D01274F01275000284F012A4E012E
+ 55053A6C0050791E54954946A866F9FAFEF9FFF9FFFEFAFDFFF9489A512F7F24
+ 336C0A3462002C5500264B01255100274D011B620142730948902C53953C67BB
+ 85FCFAFFFFF9FFFDFEFAFFFEFFFEFAF9CAF3D844B67637A8503E9F4152974646
+ 99554699548DC896C7F1D8F5FFF8FFFAFFFEFBFDFFFDFFFDFFFFE5FFF9B9E5C8
+ 77B07D4391393A72072C710834720844831B3B8935579756F5FFFEF9FAFEFFFE
+ F67ABE9548974638923945772FCBF2CC659154396C0B35740637751749883848
+ 9E38549A65D2E5CAFEF6FDF8FBFFE9FEFB7DBF964AA354458A4797BD8B558747
+ 376B183B79273A852938923837A8503EC069F3FFF9FCFEFFFDFCFEE6FCEA85CB
+ A289CAA3A5E4C4C8E5D5E9ECF4FFF9FFFFFBFDFFFFFFFDFDF7E2F1DCFBFFFFFE
+ F5FFF1F8FF85BD924CA25428931F2A66013864092A51032659002C5300285100
+ 295100305003365D013B65063B79273A9147ABD7B8F4FFFDF4FFFCFAFFFEFDF5
+ FFEAFFFC63B269478A473B6B013462002D58012B52042D54043760053B6A043B
+ 6B01377209407408568539D5F6DBDCF9E2558747326B09397307235E0D265A00
+ 2E59002C51012F5208375B1538771753922C469954AFE4B9F8FFF9F4FEFEF2FE
+ FEDBE2E5FFFFF8F5FFFFA8D7B6498B4438811B2A65032D5900225200274E0030
+ 54083054003D6B0B417B1653953C75B17BECFFFCF3F4F2D1E5CE3A902C3B8319
+ 346902305B043155012B4E042749032852002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00264D01264D01264D01254C00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000274E00274E00274E00274E00274E00274E00274E00274E00295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00284C00284C
+ 00294D01284C00274B00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C002648012648012648022648022648
+ 0225470124460024460028440228440228440227430124430022420121410023
+ 4001264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00284B01274A00274A00274A00244D022C4F00
+ 2B51002C5A07396C0A39922B469A52E5FFF2FCFEF8FFFBFDF1FFF65797563985
+ 272C6503315B082B5000274D01254B00264C00274F01275000284F012A4E012D
+ 54043B6A03437A174591394AA354FFFFFFF7FEF9FFFFFFFFFDFF4497483B852B
+ 346B083460012B5600274D012951032850002E65024169034485294D9E3D7ABD
+ 96FDF9FEFFFDFEFCFFFAF3F6FBFBFFFEC8F0D748AC7854C27467BB7B86BF92A7
+ E4C2E5FFF2EDFDF2F9FEFCFFFFFFFEFDFFF7FAFFF3FEFBEDFCF48DC89668A676
+ 5386363777173269022B6401316D094378174598494AA353F4FFFDF8F9FFFCFE
+ F887CBA24599473B933939792765A268A7D5AA396917377307478E2D3A902C4A
+ A35346A963CEF1CFFFFEFFFEFEFEF4FFFA69C9933BB1683CA0414698463C8935
+ 398A353C923A43974549A55457B06A55B673FDF6FDFEF5FFFDFCFEFBFDFEF1FF
+ F6EFFFF8FDFFFFFBF7FDF9FFFEF5FFF9F8FFFFECF5F9FAFFFFFBFFFFFBF9F8FF
+ FEF4FFFAFFC7E6D767A3663784284378172D56013B630B2052002B5600285002
+ 275103305001375A033765023876183C91479AD6A6FBFEFCFCFEF2FFFFFBFFF9
+ FFC5F2D84899543A85293B6A033461002B56002B52042E5505335D053765023B
+ 6B0137740641750A3B6B0B609153D7E9DCCAE4D6517A472C65023169042C6601
+ 355D052D55032C5A012B64013876184589343EA04086BC91EDFEF3F7FFFDF3FC
+ F9F2F4F4FEFDFFFCFEFFBAE8D246974837821A2B6500315B082A54002951002F
+ 4C03375B0132620228730747862866A369E6FDF9FBFFFFF2F6F146913B37821A
+ 3269022D59002A52003253092C4D022B50002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00274D01254C00254C00264D01274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000284F01284F01284F01284F01284F01284F01284F01284F01295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00284C00284C
+ 00284C00274B00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C002648012749022648012547002648
+ 0226480224460025470126450228440228440227430124430024420123410022
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00294D01284C00274A00274A00274A00254C012E5200
+ 2751002B5C06426D163D8F2C499956F1FFFBFFFFFFFFF9FFF0FEF8478D513687
+ 28316902365E06285002274D01254B00264C00285002285100284F012950022E
+ 55052C660143821A4899444BA455FFFCFDFBFFFFFEFDFFFFFDFF4799473A8327
+ 306C08356104285100214C01284F03284F00265A004069084685274BA03868BC
+ 86FFF9FEFFFBFAFDFEF5FFF6FFFDF8FFFBFFFFB9D9BAB9E5C6F0FDEDF8FEF9F2
+ FEFEFFFBFDFFFBFFFFFAFFFFFEFFF7FFFFE5FCF8A7D9B76AA77567A257518537
+ 387B263472063269022B64013069003877173A923848A453F3FFF8F7FFFEFDFF
+ F68FCEAE4698453A913543821A467830BBD6BC9AC9A3448A443C912F3A9E3F47
+ A8653EC069BEF0CEFEFFFAFDFEFAF3FFF28EC89843B66738A8503B9E423CA041
+ 3C914748995466A3698EC997B7E4C9D6F9E5FCFEFFFEFAFFF7FAFFFBFFFEFFFA
+ FBFCFEF8FEF5FFFEF5FFCAE4D6A5D6B685CBA386CCA486CDA2BAE8D2EDFEF3F3
+ FEEAFEF6FDF3FFFFE4FEF198C089386B14436D161F4D013064062E59022C5200
+ 2853022E5200375B013965003A731644943B6CC996F3FEF4FFFFF3FDF6F3F6FB
+ FEB1E2BC4B9F3939821B3B6A043361012B55002B52042E5505315B033663023B
+ 6A033D6B013361013B6C0A466F146B9369C8E5D5C6E0C245772F3973062D6401
+ 365D0139620D3362002D64012E7207478E2E4AA35457A766B5E6C6F7FFFDFFFE
+ FFE8F7F9F7FFFDFCFEFEC7F2D75398483882183460012F5C062855002652002D
+ 49033255002E59022E700A3B821B578648C9E7D4F5FFFFFFF8FB5898563A8529
+ 346908325D022953002E5101284F03274C042950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00274E00264C00254C00264D01274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000274E00274E00274E00274E00274E00274E00274E00274E00295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00294D01284C
+ 00284C00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00264900274A002648012648012648
+ 0126480224460024460026450227430128440228440226420024420123410022
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00284C00274B00274B00274A00254A022F4E00
+ 284F002A5B053B6D0937821A478C53EDFFF2FFFAFFFFFAFFF1FFF9478A453984
+ 28316904325C05295002274D01264C00274D01285002275000274E002950022D
+ 54042B6402447A1645933B4CA254FFFBFFFFFEFEFDFFFFFFFDFF46984539821C
+ 356C092D5C00265100224F00274C022A4F00255B02416806438925499E3C57B0
+ 6AFCFEFFFFFFF9FEFFF8FEFEFEF6F6FCF1FFFDE6FDF8F9FEFFFFFEFEF5F4FDF7
+ FAFFFEF5FFFFFBFEFFFFFFF2FEF2B5E5C879B78755975646984648902C42841B
+ 4578173B6B01365F0334630133630A3675173A902C499954F4FEF8F7FFFEFDFF
+ F384CAA246913B358A3546821D397517558747DAFAE2B6DAC464B26B549B6357
+ A97846B773C1F1CDFFFEF9FFFFF9F3FDF085BD9446B77359B57453A86475B17B
+ 8CC997C4E6C8E0FEF1F3FFF9EFFBFBF7FFFEFBF9F9FDFFFFF2FFFDE7FEFAC7F1
+ D8D8F7DAD9F7E4EAFFFBE1F6F393D1AD66BA7A3DBF6A46B774A8E7C0F3FFF9FC
+ F5FAF8FFFA9AB9A49AC9A2C5F2D8B0E3BD47782E355C06255B022D59002B5204
+ 2852052A4F0031550139640337761843933654B573F7FEF9FFFEFEFCF7F6F6FD
+ FF87BD924B9F394074093461002E5A002852002850022B52022E5801335F0037
+ 6502316B00396C0B3B630440730B316408558747C6E5CAD8F7DC4F8637376C15
+ 36630233610133610133630A346A09397307388F2D46AA6290CFAFF6FEFDFEFE
+ FEEEF7FAF2FFFFFFF6FCC6F4D75196463A831D3160033058002252002050012B
+ 4C022D570031580238720638831B468A37A6C8A9F4FEFEFFFFFE65A268457731
+ 3A6D0C3864002B51002B5202265002274D012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F01284F01
+ 284F01274E00274E00274E00274D01264D01274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000295002295002295002295002295002295002295002295002295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00284C00284C
+ 00274A00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274B002649002649002648012648
+ 0126480126480125470026450025440027440028440227430124430023410023
+ 4100264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00274A00274A00274A00274A00274A002449002C4A03
+ 254A00285200426A0439821B458E50F5FFF9F6FAFFF9F9FFDDEEE04B89373780
+ 19335C012E5200335501264C00254C00254C00284F01284F00274E002950022D
+ 54043268042C7207478F2B48A354FEFAFFF9FAFEFAFFFFF8FFF848923A387815
+ 336703315C01245102244A00294F032E4D022D5B08406B0448831B469D3B55A7
+ 66F7FAFFFFFFFAFDFEF4F2FEF8D4E8DBEFFFFDF2FFFFFEF6FDFEEDFBFEFAFFF4
+ FCFCECFFFCE5FFF1B5E6C684B58758985750963C488F2E468527377307347208
+ 3D6B013260002D5900305C003263073A7717469338559658F8FAFAF4FFFDFBFE
+ F586CCA446913B39832938771744831B396917899E85F1FFFDECFDF4C5E6CBA7
+ C8B379BE99D6E9DAF7F4FDFDFFFFF5FEF4A8D7B798DBB6BFF2CDE2FFF0F4FEFE
+ F1FFFEF2FBFFFDF9FEFFF9FFFEFAFFFFFAFDF7FFFEFAFFFEEFFCFABBE5C669AE
+ 8346B77365BC8485CBA2F8FEEBEEFEF3E5FFF09DD5AA87B587D1F2D0FFF5F7FB
+ F7FCAFE3BB538C55488D54548C5789A986C7DFBF4678302D59002E5A012A5204
+ 2651082751003155013A630139730748852A68BA85F4FAF9FFFEFEFCFEFEF3FF
+ FD6AA5793984283A6301315C012D58012953002850022B52022C55002F5A0034
+ 60012C59033C6C023A6B013B6C02437309346200366A1792BD8AEEFDFF89A986
+ 3F6E122A66023469022C640030640A5083274A9E3848A45385CDA3F0FEF8FFFF
+ FFE5F5EEF7FFFEFFF9FFBBE7D049894738821839650231550123510022510234
+ 4D032E4E012951002C670029720B44852988A986F1FBFBF9FEFF75A575487732
+ 33680B3B64033159012953002B51052A53022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000275000284F00
+ 284F01284F01274E00274E00274E00274E00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00274B00274A
+ 00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A0027
+ 4A00274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00274B00274A00274A002547
+ 0025470026480125470025470127460125440027440027430126420024420124
+ 4201264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002648012648012648012547002547002648012648012648012045002C4A00
+ 284A032B510542690737811B458B45EDF2F0F7FAFEFAFFFED1E6CD4385262D73
+ 083361012F5503295300274E00264D01254C00284F01274E00264E00284F012B
+ 520233610131690445862A4BA038FEFEFEFBFFFFF0FDFBE3FCE843862A3B7516
+ 3765022D58012951001E4A03264B052C4E01215200415D044D791E4B9F394BA4
+ 55FDFAF6FEFFFBF7FEF9F2FEEA87B688A8D4ABF3FFEBFBFFF9FEFFFAF9FFFAE2
+ F0DE8FE1AD78B07B478C53478A454591394588273E7409357307357406346901
+ 386401355B032E5A00315B0329650037761646783266A369F4F3FCFBFEFFFDFE
+ FA8DC896498E2D367714326A0B48831A447A173B582A8DAA93E1EFE4F2FFFDF1
+ FFF3E3FFF1FFFCFFFEFAFFF4FBFEFBFFFFE1F6EEE2FEF1FEFFFAFFF9FFFFFBFF
+ F9FBFCFAFFFFF6FEFEF4FFFDF4F5F3F6FBFCF7FAFFFFF7FEFFFDFDCAE5D545AB
+ 7426994F37A6504A9956529C62A6D8B8ECF5F8FAFBFFEFF4F2F5FAF9F7FFFEDD
+ E2E555A766489746378218296910265419547B47A3C98F325D022D59002A5300
+ 2452062850022F5601336101326B084486276AAC82F7FFFFFDFEFCF5FEF4C5E7
+ C9478D5036831B3A650A2E58012A5400275000284F002950002A52002C560031
+ 5C01365B153362003A72073368013A6B0140740834690139650C649152B3D3B0
+ C4E8CA6D9467365B15326B08437918377714468837579755BBE5D4EDFFFDECF1
+ F2E1EDE7F3F4F2FDFFFFC3E6CB458A4737821A386B033A59042050012152002B
+ 4F022A5101325B062B64013774063A77176C9568F0FEF8F6FEFE82BC6E448529
+ 346B083A6301315C012B52022A51032151002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000275000285100
+ 295000284F01284F01274E00274E00274E00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000285100285100285100285100285100285100285100285100295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00274B00274A002649
+ 00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A0027
+ 4A00274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00274A00274A00274A
+ 0026480124460024460026480226480224460026450028440227430124430024
+ 4201264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264802264802264802254701244600244600244600244600234302264801
+ 294C0230550539650834831C478735C8D9CCF3FFFEF1FCECAAC99238821C2971
+ 07306309385708214B00284E02254C00254C00274E00274E00264E00284F012B
+ 52042F560032680446821D39902EFCFEFFF9FDF7D1F0CF9ABB9938831B386B0A
+ 3261002F5A00215001224905254C01294E002850023F5C06417A1851922C4499
+ 45FEFFFAF7FEF9E5FFF188D4A447A76744AA6379B787CDF2CABEF1CC8DC89665
+ B16949994648984545933B38831B367305366804316902386401346100325B00
+ 335C003155012C54022F5B00356102377209649152A9D6ABFFFBFFFFFEFDFFFE
+ FA85BD924587283D6B0B3575042D640135740646831B4E791E78A26DC4E5CAEB
+ FEF5F3FFF3FFFFFFFFF6FCF8FBFFFEFDFFF9FFFAF2FFFDFEF5FFF7FFFEF0FEF8
+ EEFFF6D9F9E1AAD4AB86B686A6D6BAE6FEF2F6FFFCF5FFF2F1FFF3AFE2BC4CA2
+ 543992353789364488353A902C5596586A956ACAD8CDEEF7FAE6FDF9C6F4D76A
+ A6763B842844852936831B36720633630A365B17294B04315A093156002C5004
+ 2351052751032D590033610134690245831976A676FBFFFAE8FCE9A7D5AB77A2
+ 693B78162B710639630C2D5503284F00275000295000284F002950002B53012D
+ 5700304F042B59003460013B6A04316003325E004273093B6B013B6A03376A1A
+ 70946AB6D6BDC9F3CA84A977467530487830588C5695BB97E5FFF2D8F8E5D4E9
+ DAFEFFF4FFFEFAF1FFFEC2E6C8478937397517376600365A002650022051002F
+ 4F002C4C0033530C2D5900316902326B08578648F4FDE8E6FCE9519548427A15
+ 3C6D013A6301355C002D56012B51002150012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285100285100
+ 285100284F00284F01274E00274E00274E00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00274A00274A00274A
+ 00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A0027
+ 4A00274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00274B00274A00284B
+ 0127490225470024460026480126480124460026450026450228440226420023
+ 4200264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600244600254701244600244600244600244600254701204604284402
+ 244600264E00385B0138771745772FC8D9CCE1EDE799AE9545772F2C72072B65
+ 002B5801344D032D5104284E02254C00254C00274E00294D00264D00274E002D
+ 51043F5C0634620039720938912AFFFFF7C7D8CB869F8545772F39821B326902
+ 315D042D5900264C04214A072D4E042F4D01245A00406B0442740846831B498A
+ 45FDFFF9D8E9DC8AAA9163A455279A4B37A851498B446A9667588C5747913938
+ 902C52912939821B306A0B346B083C6C0C3361012C5A01315C01355B01315404
+ 2C55042B54032B5202355B033461003B6C04A9D6ABE8FAE9FBF6FFF3F5FDFDFF
+ F986B587407917326B0934680431690232690234730539821C478F2B5A8D5386
+ B48AB6DAC4FCF8F7FFFEFFFEFDFFFDFFF9FDFEF4ECFEFDEAECF4C2E6C898C8A4
+ 67A5774BA45548A35455A76661B36866BA7987B68877A57675B27A5596582E75
+ 15417C144278173C761746831B46831B489238478A4776B884D6F6DD79A16A3B
+ 7927437A17346A093168013D6A03346A00305C03345E062E50032F5601295201
+ 2350072851062B590033610131690040791695BB97E0F0DE84A97748913B5184
+ 284583192D7209385B012B5202295002285002295000284F002B4F022A51012C
+ 55002E5C03375B15304D0E315C013169023A63013E640C316200335F063B6A03
+ 326804356C0958854685AB87B6CCB9EDFEF3E5FFF1E2EFDFB2CEB7A7C7B4F6FE
+ EDFDFFF3FFFFFAEAFFFCB6DAC247763139730734600131550121510022520028
+ 4C002F560131510A2956003269022C6502366A17C8E1BF6A95682E72072A6503
+ 386B033D6A03375C002E54082E5505265A002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285100285100
+ 275000275000284F01274E00274E00274E00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000284F00284F00284F00284F00284F00284F00284F00284F00295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00274A00264900274A00274A
+ 00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A0027
+ 4A00274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284B01284C00274B00274A00274A
+ 0027490226480124460026480126480124460024460026450028440227430124
+ 4300264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274603284704274603264502284402284402284402284402264101244201
+ 274805284D032E560439630B4D7920628F395084264479183B6B0B335F042D58
+ 012B5301294E00294D01274D01274D01274E00274E00274E00274E00284F0029
+ 50002D59003360033B6B0B4379165F903C52912950842A4379183B6B01376502
+ 315B032A5200274E002A4E022A4E02294C022F59012B58013A6D0C4277195185
+ 2767A35553922A51922C478E2D468F2D4A902C498D2E488F2E42862745872847
+ 862A40720C3D6C09336101305C012F59022C55002B5202284F01285002295004
+ 2950052A51032950002C5500335C00396502608F3951853854863850932A478E
+ 2D46791834690B316300385B013962003766003C6D0136720646821D48902C53
+ 963B46984548A45366B26A64BB7B68B87B56B47348A4554CA3534AA354469846
+ 46923A47913744913D48913B46933844923A51932A4686263F7B173973073068
+ 012E65023169043A6C0037730743781744831D48821D46821D44841A40740837
+ 7307336101325F02315C01305B002E58002F59022C55002A52002B52042A5103
+ 2950002B50002E5500315C0138640143730952974753963B53922A50842A427A
+ 15386C01345F042D590029500029500029500029500029500029500029500029
+ 50002C50042C50032E54022F5600335C01315D0035620136640131640A346306
+ 3663023766003B6A033D6A033A6B013A6B0138811A468F2D52974763A35767A2
+ 6853A86446995448984555922A46821D3369082D64012A5B002B550028500226
+ 4D00284E022851002B56002E5A00305C033662093967073A6B03365E06345E06
+ 315B03305B00315C012F59012D59002E5A012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00284F00284F00284F00284F00284F00284F00284F00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284B01284C00284C00284C00274B
+ 00264900264801264801274A00274A00274A00274A00274A00274A00274A0027
+ 4A00264801264801264801274A00274A00264900274A00274A00274A00274A00
+ 274A00274A00284B012B4C022B4C022B4C02274A00274A00274A00274A00274A
+ 00274A00274A00274A0026480126480226480127470025440128440228440224
+ 4201264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254401264502284402284402284402284402284402284402244300244300
+ 244600284A042C4F052D5404335E07426E1537650C3362062E5A012B55002C54
+ 022D53012E52002D5000274D01274D01274E00274E00274E00274E00284F0029
+ 50002B54002B5801336200326B094378173F7B174079163A76183B6B01366401
+ 2F59012C5200294D002A4E022A4E02294C022A4E012D57003766003D6C0A3B6A
+ 0344831B346A093B7419437B16437918427817497A1E447918447A174273093E
+ 75083D6C09366503315D002E58002B54002C54022C5303295002284F01284F03
+ 2950042A51032950002C5500315C01366401426E15447A1745821A45841C3883
+ 193772093269023863022E5500385B04305B00346001306B0336720645821A4E
+ 8528478E2D48903D53963B52974654964747933B45903A468F2D47862A43821C
+ 417B163A7717437817407916427817417A1838751A377307356A092C6503275B
+ 01305C00305A022F5B022C6502316904306C083B6C0A3D6C0A336B0C2B640126
+ 5A00305D00315C01315B032F59022C56002A5300295100295000294F032B5204
+ 2C53032D51002E5402325C0436640141750944841A4E7A21437915427309396C
+ 0A3361012D59002A560029500029500029500029500029500029500029500029
+ 50002C50042C50032E53032F5601305A02315C01336101336101345E06346003
+ 3360003B64023965003A6B033B6A033D6B013973074379185083275287375896
+ 3C53963B48902C488F2F42831D4079163C6D013460032D590028550026500229
+ 51002750002851002B55002D59002D5900315D04325F02336200315C01315C01
+ 305B002F5A002E5A002D59002E5A012E5A012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00274B002649
+ 00274A0027490226480124490124490124490124490124490124490124490124
+ 4901264802264802264802264802264801264801264801264801274A00274A00
+ 274A00274A00274A00284B01294C02294C02274A00274A00274A00274A00274A
+ 00274A00274A00274A00274A0026480226480128480126450228440228440228
+ 4303264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284402274301284402284402284402274301264200264200223E02224000
+ 234500284A032C4F052E52052850002B53012854012A5400285200275000284F
+ 01274E002A4E01284C00274D01274D01274E00274E00274E00274E00284F0029
+ 50002C55002F5404335C00325D023B6B0B3C6D014074094274083B6A03366302
+ 3058002C52002A4E012A4E022A4E02284C002B5100395C02396200406B043660
+ 01336C09315C013864093D6A033C6B043F6A03426A053F6A03406A0541690442
+ 6A05336101315D002D57002B54002951002B52022B5204295002284F01294F03
+ 294F03295002284F002C5500315C013461003864013973074274084074093774
+ 063068013562013460012E52002E55002F59022F5901305D003B6402396C0A42
+ 781746821E42841A46831B45841E44831B4079164379184373093B6D093B6B01
+ 3568003564023564023965003766003A63012A5B072E5B052D59002958022B59
+ 003054002F56002E5801305C01345D02336200326307326202326100325C042E
+ 58012F59022C56002C5500295100295100284F00295002284E02295000295103
+ 2850022950002B5400315C013D64023F6A0341750A43730944740A3B6B013664
+ 012D59002A4F07294E0629500029500029500029500029500029500029500029
+ 50002C50032B4F022C51012C54022D57002D5900305C01305C01305C01305D00
+ 3361013461003461003362003965023A63013A6B0141750A43740C4D7A1D5083
+ 274E832547831E42831D4379153E74093B6B01335F00325C042E54022E550031
+ 55032750002851002952012B55022B56002D58012D59002F59012D59002E5A01
+ 2E59022D58012D58012D58012E59022D58012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000285100285100285100285100285100285100285100285100295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274B00274B00274A00274A002649
+ 0026480126480126480226480126480126480126480126480126480126480126
+ 4801264801264801264801264801264801264801264801264801264900274A00
+ 274A00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A
+ 00274A00274A00274A00274A0026480126480126480226450227430128450028
+ 4402264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274301264200264101264101264101264000264000264000253F03243F00
+ 244201274603284A032C4F05284E02284F01274E02284F01295000285002274D
+ 01254B00254A00274A00274D01274D01274E00274E00274E00274E00284F0029
+ 5000335501305402385B01365B003965023B6B013B6B013D6A03376502335F00
+ 2F56002C51012A4E012A4E022A4E02284C003152012E54022F5404396502315B
+ 03355F082D5900365E06315D003361013A63023B64023965003B640239650238
+ 64012D59002E5A012A5400285200285100285100274F01274F01295000295002
+ 284E02284E02284F012B53012E5800315D003665003B6A033D6A033A6B033B6A
+ 03396502335C012B55002B4E042A52042A50042C56002E5900385A033A640042
+ 6A043B6A033C6C023F6806416703406A053D6A03326400336101335F00305C03
+ 315C01315D00305C03315C01365E00385B012E55002C55002C56002C56002E52
+ 052D54002C52002E51012E54022E56003155013155012E55002D54002E550029
+ 5201295000284F00295000274E00274E00274D01274D01264B01284F01284F01
+ 284F012A4F002C5200335B033C62023E6B0443720B4369053F6A033A6400335C
+ 00305400265200264D0129500029500029500029500029500029500029500029
+ 50002A4E01294D002A4E012A51012A52002C55002F59022E5A01335C01335C01
+ 335C00305D002D5C00315C01305C01315C013965023A63013F6904406A054074
+ 0944750B4172084273094268043D6B013663023462022E58003055002F560031
+ 5503285100275000274F012851002953002A53002A53002B53012A52002A5200
+ 2A52002B53012C55002E55002E55002E55002A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00274A00274A00274A002648
+ 0126480125470026480226480126480126480126480126480126480126480126
+ 4801274700274700274700274700264801264801264801264801264802264802
+ 264802264802264802274903284A04284A042648012648012648012648012648
+ 01264801264801264801274A0026480126480126480227460328440228450027
+ 4301264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000274200274301
+ 274301234001234001224300224400224700284702294A00284C00284C002A4C
+ 00284C00284F012D5104274D01274D01274E00274E00274E00274E00284F0029
+ 50002C4F002C4F002B5100355B03375B01386401396502386302346001315C01
+ 2F56012C51012A4E022A4E02284C00284C002B50002C52002F4F02345B00355C
+ 003157002F56012D51002756002956002C59032D57002D58012B59002E58002B
+ 59002E58012C5500295300285100285100285100285100275000295000295002
+ 284F01274D01274D012950002B56002E5A01315C01326100336200375B013A5B
+ 00325E052E5505284B01274F01294F032B51052D50002F5601305400375A033E
+ 5D02336200305C01335C01325C042E58012F5B002B58012B5502275300275201
+ 2851002950002A54012A52002D5000305100274E00294D002A4E02294D01294D
+ 00294C022A4C002C4B002E4E00284F012C4E012D4D002C4E012A4F002A4E012A
+ 4F002A5004294F03284E02274D01264C00284E02284E022A5004274E00274E00
+ 284F012A4E012B50002F5600375C003A6302376600366401336003385A032C56
+ 002850022951002B550029500029500029500029500029500029500029500029
+ 5000284C00284C002A4E012B4F022C51012C52002F56012D54002C5A012C5A01
+ 2E58002D59002D58012F59022D58012E58012B59002C5A01335C00345D013362
+ 00366205356A033B6B01396403386400375B01375B013056003156002E55002C
+ 5101295002295000284F002950022950002950002951002A5101275000285100
+ 2750002950002A52002B53012B54002D56012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295002295002295002295002295002295002295002295002295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00284B01274A002547002648
+ 0126480126480226480227430127430127430127430127430127430127430127
+ 4301284402264502254401254401264502274603274603284704264801254700
+ 2648012749022648012648012648012547002648012648012648012648012648
+ 01264801264801264801274A0026480126480126480227460328440228450027
+ 4301264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000243D00264000
+ 284301254100223F002140012242012242012642002744002848012648022648
+ 01274A00264C00284F01274D01274D01274E00274E00274E00274E00284F0029
+ 50002A5204274B00284F00315600315501375C00375902385C02315C012E5800
+ 2E54022C50032B4F032A4E02284C00284F012E50032B5200295200325C043A5A
+ 013057023350012D5601214D002350012751032D56052855062957052954032B
+ 56052C55002A52002A51012A5101284F00295000284F00284F00295000284F00
+ 284F01274D01274D01284F012A52002B55002C55002D5900375B012F55032E56
+ 002D5409314D08284A04264C00264E00284B012A4B012D4F022B50002C550031
+ 5503315B042D58012E59002C5B002D58012B55002B54032A5603214D00214E00
+ 234D00214D00284F01274F01284D03284D03284F012D5000284C00284B01274E
+ 00264C00294D002A4F002C5004304E05314F062D51042F50052E4F042C50042D
+ 5105294E04294F03274D01284E02284E022A51032950022A5103285100274F01
+ 254C00294F032950002D5400395B04375B01385A03385B013155032D50002A4F
+ 002953002A510128540129500029500029500029500029500029500029500029
+ 5000284C00284C00294D00294D002A4F002A4F002E52002D51002E5500305500
+ 2F56003355013155012B54002E55002E55002951032A54062757052C5C042F59
+ 01335C00305C01325B00385B01375A03385B002F55032D55032A540029530028
+ 4F01295000295000295000284F002950002950002950002B5100284F00284F00
+ 284F01284F01284F012950022B50002C51012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002749022749022648012547002648
+ 0126480226480225470128440228440228440228440228440228440228440228
+ 4402284402284402284402274301274301284402284402284402284801284801
+ 2848012848012547002547002547002648012648012648012648012648012648
+ 01264801264801264801274A0026480126480126480226450227430128450028
+ 4402264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000253F00264000264000264000264000264000264000264000243E02274002
+ 284202254001243F002543022644032443002742022645022746032546032445
+ 02234701264B03234A00274D01274D01274E00274E00274E00274E00284F0029
+ 5000275103284F032B4C012C54062C5101315A09365C02355B012E58012D5601
+ 2D52022C50032A4E02294D01284C00274E00234802224C00274E022655002B56
+ 002952012950002C50032951032852042A50042A52042A54072A51032B52062A
+ 51032B52022A51012B52042B5204295000295000284F00274E002A5101284F00
+ 284F01264B01274C022950022950002A51012856032F5901385A033354033055
+ 00305001274E02284E02264C00244E01274B00254A04244A02294D002750002C
+ 51012C50032A4D032C55002B56002C55002A5200294E04254B03275103295002
+ 265002274E02274E032D4E032A5004294F032C50032C4D032B5204295002284F
+ 012A52042A5204275103285100285100275000285100284F01285002284F0328
+ 4F03294F03294F03295002295002295002284F01284F002A5101274F01295002
+ 284F012C4E012C50032B52022E55002E5800335C002D59002A55042F50052950
+ 042A5103284F032B500029500029500029500029500029500029500029500029
+ 5000294D002A4E01294D00294D00294D002A4E012C50032C50032C55002E5500
+ 2C55003155033054022C53032C52002D5100255203295002284F03274F012B51
+ 002B52003152012A51032B50002F56013155012C51012B50002C530527520122
+ 4E012C51012B50002B50002A4F002950002C50032B4F022B5000285002285002
+ 295103285002284F03295004284F03284F032A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F01284F01284F01284F01284F01284F01284F01284F01295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002648012547002446002648012648
+ 0124460024460024460028440228440228440228440228440228440228440228
+ 4402274301284500284500284500284500284500284500274400284402284402
+ 2645022746032847042847042746032647042648012648012648012648012648
+ 01264801264801264801274A0026480226480128480126450228440228440228
+ 4303264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274002274002274002263F01263F01264000264000264000254000274202
+ 253E00233E00243F00264101243F00243F00263C012742022844022B4803284A
+ 03274A00294D01234A00274D01274D01274E00274E00274E00274E00284F0029
+ 5000234D001F4E00264D012D57042848012C50042E4F053151042C55002C5402
+ 2B52022C50042A4D03284C00284C00274E00265108254D002952012B4F022854
+ 01315503285100274E00294D002C51012E51012E52002B50002C52002D4D002E
+ 4E00284F01295002285002295103285100284F00295002274E002A5101285000
+ 295002264B01274C02294F032950022950002955022852002C52002952003155
+ 012C56002652002351002950022B5100284B01244A02264C04254B0324520020
+ 51002F51042E52002C53002C51012C53002A4F002A4E02284F042951002B4F02
+ 2C4E01274E00284F01294D012E4E012C5200274E00294D002750002851002951
+ 00264C00274E00214C01284F04275100264E00264C00254C00255100284F0327
+ 5201284F032850022851002750002851002750002851002953002950002A5103
+ 284E022B4F032B4F022C5101335403315501245A01245200215100274C042C4B
+ 082A4C06294D012A4B0029500029500029500029500029500029500029500029
+ 50002B50002B5000294D002A4E012A4E012C50032B4F032C50042B55002E5500
+ 3054002B53012B52042C50042C50042C50042F51042950002C51012E52002E4E
+ 002C4E01314C03304D042E4E012C50042C50032950002850022C54062752091F
+ 4D002C52002B4F022C50032A4F002A4E012A4E022A4D032A4E022B52042A5103
+ 2B52042B52042851002851002750002750002A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002446002446002446002547002547
+ 0024460025470124460024420124420124420124420124420124420124420124
+ 4201244201254401264502284402274301284402284402284402284402284402
+ 2743012844022847042847042746032746032648022648022648022648022648
+ 0226480226480226480226480126480226480127470025440128440228440224
+ 4201264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002442012442012743012645002847
+ 02264801274A00274A00274A00284C00284C00284C002A4E01294D01284C0029
+ 4D01295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00284F00
+ 284F00284F00284F00284F00284F00284F002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A52002A5200
+ 2A52002A52002A52002A52002A52002A52002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 295000295000295000295000295000295000284F00284F00284F00284F00284F
+ 00284F00284F00284F0029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00284C00
+ 294D01284C00274A00274A00274A00274A002449012648022749032746032544
+ 0126450226450224430026410126410126410126410126410126410126410126
+ 4101264101264101264101264101264101264101264101264101274301274301
+ 2743012743012743012743012743012743012446002446002446002446002446
+ 0024460024460024460023480023480024490126480125470024460024460024
+ 4600284402284402274301264200264200264200264101254000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002442012642002844022844022746
+ 01264801274902274A00274A00284B01284C00294D012A4E012A4E02284C0028
+ 4C00295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A52002A5200
+ 2A52002A52002A52002A52002A52002A52002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00294D01
+ 284C00274B00264900274A00274A00274A002648012547012746032844022743
+ 0128440226450224430026420026420026420026420026420026420026420026
+ 4200264200264200264200264200264200264200264200264200284402284402
+ 2844022844022844022844022844022844022246002246002246002246002246
+ 0022460022460022460026480226480225470125470124460024460024460024
+ 4600284402274301274301264200264200264101254000254000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002443002642002844022743012645
+ 00254701264801264801264801274A00284B01284C00284C00284C00284C0028
+ 4C00295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285100285100
+ 2851002851002851002851002851002851002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002851002851002851002851002851
+ 0028510028510028510029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00294D01
+ 284C00274B00274A00274A002749022648012847022746012844022743012844
+ 0228440225440123410026420026420026420026420026420026420026420026
+ 4200264200264200264200264200264200264200264200264200284402284402
+ 2844022844022844022844022844022844022844022844022844022844022844
+ 0228440228440228440225440125440126450226450226450226450226450226
+ 4502274301264200264200264200264200274101264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002342002443002743012544012645
+ 02264500274601284702244600254700274A00284C00284C00284C00284C0029
+ 4D01295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00284F00
+ 284F00284F00284F00284F00284F00284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00284C00
+ 274B00274A00274A002648012547002446002544002844022844022743012743
+ 0124430023410024420126420026420026420026420026420026420026420026
+ 4200264200264200264200264200264200264200264200264200264200264200
+ 2642002642002642002642002642002642002844022844022844022844022844
+ 0228440228440228440228440228440227430127430127430127430127430128
+ 4402274301264200264200274200274101264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002443002443002443002443002544
+ 01274301284402264500244600244600254700274A00284C00284C00284C0028
+ 4C00295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295002295002
+ 2950022950022950022950022950022950022950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285002285002
+ 2850022850022850022850022850022850022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950022950022950022950022950
+ 0229500229500229500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00284C00
+ 274B00274A002648012446002446002446002443002442012442012442012443
+ 0024420123410023400126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264200264200
+ 2642002642002642002642002642002642002443002443002443002443002443
+ 0024430024430024430027430128440228440228440228440225440124430024
+ 4300264200264200264200264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002341002242012242012443002743
+ 01284402284402274301244600244600244600264900284B01294C02284C0029
+ 4D01295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00274E00274E00274E00274E002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285002285002
+ 2850022850022850022850022850022850022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 295000295000295000295000295000295000274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00284C00
+ 274A002648012446002446002446002345002341002442012442012341002240
+ 00224000223F00233F0326400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264200264200
+ 2642002642002642002642002642002642002443002443002443002443002443
+ 0024430024430024430028440226450225440124430024430024430024420124
+ 4201274301264200264000253F00264000264000264000243F00264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002341002442012242012443002443
+ 00264200264200244201244600254701264802274902284B01284B01294C0229
+ 4D01295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F01284F01
+ 284F01284F01284F01284F01284F01284F012950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285002285002
+ 2850022850022850022850022850022850022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 295000295000295000295000295000295000284F01284F01284F01284F01284F
+ 01284F01284F01284F0129500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00274B00
+ 2649002446002446002446002345002244002240002341002340012240002341
+ 00234001233F03233F0326400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264200264200
+ 2642002642002642002642002642002642002240002240002240002240002240
+ 0022400022400022400024430024430024430024430023410023410022400022
+ 4000264200264200264000264000264000264000254000254000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 264000264000264000264000264000264000264000264000264000264000263F
+ 01263F01263F01263F0126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002540012341002341002443002342
+ 00244300244201244201234500244600254701264801264801284B01294C0229
+ 4C02295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00274E00274E00274E00274E002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285002285002
+ 2850022850022850022850022850022850022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 295000295000295000295000295000295000274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00274B00
+ 264900244600244600244600234500234500223F002340012340012340012340
+ 01223F00243E02253E0426400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264200264200
+ 264200264200264200264200264200264200223F00223F00223F00223F00223F
+ 00223F00223F00223F00264200264200244201244201234100223F0023400122
+ 3F00264200264200264000264000264000254000243F00254000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 264000264000264000264000264000264000264000264000264000253F00253E
+ 00243D00243D00243D00243D00243D00243D00243D00243D00243D00243D0024
+ 3D00243D00243D00243D00243D00243D00243D00243D00243D00243D00243D00
+ 0000}
+ end
+ object TopBevel: TBevel
+ Left = -9
+ Top = -1
+ Width = 443
+ Height = 89
+ end
+ object InfoLabel1: TLabel
+ Left = 48
+ Top = 96
+ Width = 369
+ Height = 33
+ AutoSize = False
+ Caption =
+ 'This tool will import your Wolfpack definition files and create ' +
+ 'a new categories.db for the WP GM Tool.'
+ WordWrap = True
+ end
+ object WolfpackIcon: TImage
+ Left = 8
+ Top = 96
+ Width = 32
+ Height = 32
+ AutoSize = True
+ Picture.Data = {
+ 055449636F6E0000010006001010020000000000B00000006600000010100000
+ 0000000068050000160100001010000000000000680300007E06000020200200
+ 0000000030010000E60900002020000000000000A8080000160B000020200000
+ 00000000A80C0000BE1300002800000010000000200000000100010000000000
+ 8000000000000000000000000000000000000000FFFFFF0000000000FFFFB9BC
+ FFF70E15E7FD0E0FFFFE07F5FF8300009FA300FBCB39FFADFF67FFFFF7EFFBF6
+ FBEF0000FF9FF500FE3F2B07F8FFF607F17F1614EDFF0D07DEFF000003FFB9BC
+ 00030E1500010E0F000007F500000000000000FB0001FFAD0007FFFF000FFBF6
+ 000F0000001FF500003F2B07007FF607007F16140C7F0D071E7F000028000000
+ 1000000020000000010008000000000040010000000000000000000000000000
+ 0000000000000000000008000008080000081000080810000810100008101800
+ 0018210010182100102121000818290018293100212931003131310021293900
+ 183139002131390029313900213142002939420029394A0029424A0031424A00
+ 2942520031425200314A5200314A5A00394A5A0039525A003152630039526300
+ 42526300425A6300425A6B00425A7300426373004A6373004A637B004A6B7B00
+ 526B7B004A6B8400527384005A7384005A738C005A7B8C00637B8C005A7B9400
+ 6384940063849C006B8C9C006B8CA5006B94A5007394AD007B9CAD007B9CB500
+ 7BA5B5007BA5BD0084A5BD009CADBD0084ADC6008CADC6008CB5C6008CB5CE00
+ 94B5CE009CBDCE00A5C6DE00ADCEDE00BDD6E700ADD6EF00B5DEEF00D6E7EF00
+ DEF7FF00FFFFFF00000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000016000308002900000000000000000000120B03181F00101F27292929
+ 2F290000121F1F3332080005050000000000370023272329120815230C101F0C
+ 0C12033A29231F161818161F29343B333B44000D1F2F361818231615292F292F
+ 394117100C18372F1C2F1F0B343D181C293241001C001523181F1818321D2937
+ 3F0000001C080B1F2E1C00101203232F0000000008000016232F1D1218072200
+ 000000000000050910122923283F000000000000000012120B181F3441000000
+ 0000000018290000233D41432E000000000000000512150F4300371D34000000
+ 0000000000121D3D000036072900000000000000102D41000000002F1F000000
+ 0000000003FFB9BC00030E1500010E0F000007F500000000000000FB0001FFAD
+ 0007FFFF000FFBF6001F0000003FF500007F2B07007FF607047F16140C7F0D07
+ 1E7F000028000000100000002000000001001800000000004003000000000000
+ 00000000000000000000000030434D020307090E10121B210003065E77860000
+ 000000000000000000000000000000000000000000000000000000002A39431E
+ 2A32090F14394D58445A6800020628373F44576151697A5F7B8B597587597788
+ 6484975B78880000000000002D3D46455C694358676F93A66A8CA1141C23050A
+ 0E0810140B121701060A00000006090B0103050002007BA0B50000004F697A50
+ 6D7D4D67755975862C3D47141F262F414B4C6775222F3827343D435A67222F37
+ 202D362C3D48000C149FAEB95A7687476070455B6A31434F374C583548543141
+ 4C445A685672827195A984AAC16D90A389AEC4A9D2EA000000343332435B6763
+ 8194789AB13A4E5A3345504D667530424C2E404A567484638395597687638294
+ 85A6BAA1C4DA2A42512D363C222F373749527EA4BB6584963C535E648396445D
+ 6A1E2B337496AB8EB5CC3346523A515C5C788A688DA6A2C5DA0000003C515E00
+ 00002F404B4A6371374B56475F6F354854384C596B8EA03F56655876857FA2B7
+ 90B5CB0000000000000000003C505E111A211D2A31465F6E5F7F903C505D0000
+ 00233038283D430D0F124D6878618399000000000000000000000000161E2400
+ 0000070C0E30404D4963706A8B9E3F55632B3A463B4E5A071A25405F74D2E7EF
+ 0000000000000000000000000205040000000E161B16202624323A2F3F4A5472
+ 814864784E6F8399BACDDEF6FF00000000000000000000000000000003050606
+ 090B2A3B452C3C471D2D36364E5C415C6D7797A9A1C3D8000000000000000000
+ 0000000000000000000000003244505876870000000000004962708BB0C2A1C4
+ DAB7DAEF5D7D920000000000000000000000000000000000000000000E161A2E
+ 3E492D404B1A303FBDD6E10000007FA4BB3351637E9DAF000000000000000000
+ 0000000000000000000000000000002234403F57648FB6CD0000000000007B9D
+ B00E1F2A58738400000000000000000000000000000000000000000026313A64
+ 7988ACCCDE000000000000000000000000658698465F6E000000000000000000
+ 00000000000000000000000003FFB9BC00030E1500010E0F000007F500000000
+ 000000FB0001FFAD0007FFFF000FFBF6000F0000001FF500007F2B07007FF607
+ 047F16140C7F0D071E7F00002800000020000000400000000100010000000000
+ 0001000000000000000000000000000000000000FFFFFF0000000000FFEFFFFF
+ FFF7FFFFFFF9FFFFFFFFFF9FFF7FFFF7FCFFFFFFFEFFFFFFFFFFF7DFFFFFC10E
+ 7FFF790F73FFE80FC3FF9F86E1EF8F91F9EF8F8FFFEF983FFFFE72FFFFFFF5FF
+ FF9FF5FFFFCF3DFFFFFFF9FFFFFB61FFFFFF87FFFFFE0FFFFFFC3FFFDFB0BFFF
+ DF80BFFFFF82BFFFF7037FFFFEF7FFFFF9F3FFFFF7FDFFFF6FFEFFFF000FFFFF
+ 0007FFFF0001FFFF0000001F0000000700000007000000030000000100000000
+ 000000000000000000000000000000010000000F0000003F000000FF000001FF
+ 000001FF000001FF000001FF000001FF000007FF00000FFF00003FFF00003FFF
+ 00003FFF00003FFF00007FFF00F07FFF01F07FFF07FC7FFF0FFE7FFF28000000
+ 2000000040000000010008000000000080040000000000000000000000000000
+ 0000000000000000000008000008080000081000080810000810100008101800
+ 0818180010181800101821001021210018212100102129001821290018292900
+ 1821310018293100212931002131310021293900083139001831390021313900
+ 293139002131420029314200213942002939420029394A0029424A0031424A00
+ 31425200314A5200394A5200394A5A0039525A0042525A003952630042526300
+ 395A6300425A6300395A6B00425A6B004A5A6B0042636B004A636B005A636B00
+ 426373004A6373004A637B004A6B7B00526B7B0052737B004A6B8400526B8400
+ 527384005A73840052738C005A738C005A7B8C00637B8C005A7B9400637B9400
+ 6384940063849C006B849C00638C9C006B8C9C00738C9C006B8CA5006B94A500
+ 7394A5007B94A5006B94AD007394AD00739CAD007B9CAD00849CAD007B9CB500
+ 7BA5B50084A5B50084A5BD0084ADBD008CADBD0084ADC6008CADC600A5B5C600
+ 8CB5CE0094B5CE0094BDCE009CBDCE0094BDD6009CBDD600A5BDD600A5C6D600
+ A5C6DE00A5CEDE00ADCEDE00B5CEDE00ADCEE700ADD6E700B5D6E700B5D6EF00
+ BDD6EF00C6DEEF00BDDEF700C6DEF700DEEFF700CEEFFF00D6EFFF00DEEFFF00
+ D6F7FF00DEF7FF00E7FFFF00F7FFFF00FFFFFF00000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000018120900080A080F0A0F2F0000000000000000000000000000000000
+ 000000001F1F0A00000F09090508050000000000000000000000000000000000
+ 000000000A1E120003111226120A08001D3F0000000000000000000000000000
+ 00000000121F1F1209121233373718000505091E2C373C372637372C333F3F00
+ 000000000A232326182326333F372311090A050000030505050912181D12051F
+ 0000000012262F1F26373F46371F0A050512180F091818050000000000000000
+ 2C000000233333262F37373F3718050A18232F2F1F09000518120F0A0A0A0A09
+ 1137000026372F2C2F251F26120A1E261211261F1F181F373F372F2626333F37
+ 18001F0037363737262F1F1F1F1E121E1E1F2F261F333E5050453F333F3F5054
+ 120000003E251D372F231F26262F1F1F1F1F182F3F372F37373F453750505858
+ 0300002E3F2F18373F3E261F122F26262C181E2C372F373F37474E4747586C50
+ 120A000018263F47453F331F122337231E1F18181F3F3F37332F37333745544F
+ 47353C562309264747473C2F261F263E261F181F37454745262526232F3F4536
+ 475E00002F0F00183C3F45372326373E2625121837505B4E1F25332F374F544E
+ 000000001F1805031F262F372F26334533231218334745262F3F4F47584E0000
+ 00000000261D11030A25121F1F1218252312183F543718123F3F365800000000
+ 000000002F1811050A1F26262F261F0A000018371400001F581F440000000000
+ 000000001F0F120F0818251F3C3F471E0300000A3424001F47123F0000000000
+ 000000001205050500121E1F2F263F471F1F0A183F3F052618265E0000000000
+ 0000000011000000000918121F252F3737252F261F0A18262657000000000000
+ 000000000A00000000051809121E1F18333F2C333F2F3D475B00000000000000
+ 00000000050000000A0A0908181F181F2F3736333746636F0000000000000000
+ 00000000000000000A261F180F1E1F2F2625253D4E6500000000000000000000
+ 00000000080305050A1818180F23262F37334765625000000000000000000000
+ 00000000180A452F0000090A093F372F455B6C682F4500000000000000000000
+ 000000000A1E4E18000000001857585E645B5E502F5800000000000000000000
+ 00000000051818000F1F18153C0000005E463745375D00000000000000000000
+ 00000000000812263F2636265000000054462F263F0000000000000000000000
+ 0000000000001F26121D375800000000582F1E18370000000000000000000000
+ 0000000000001F18124465000000000065471F18370000000000000000000000
+ 0000000000000F1F5E0000000000000000005425370000000000000000000000
+ 000000004D18376B0000000000000000000000452F0000000000000000000000
+ 00000000001FFFFF001FFFFF0003FFFF0000001F0000000F0000000700000003
+ 0000000100000001000000000000000000000000000000030000000F0000003F
+ 000000FF000001FF000001FF000001FF000003FF000007FF00000FFF00003FFF
+ 00003FFF00003FFF00003FFF00703FFF00707FFF00F07FFF01F07FFF07FC7FFF
+ 0FFE7FFF2800000020000000400000000100180000000000800C000000000000
+ 0000000000000000000000002A3A4223303A131C2302050610191C1D282F1019
+ 1C1C27301A252A1C28314E667800000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000374956374B561A252D0202020202021D2932131C
+ 23141F2509111410191D0B151B49637000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000018232830414D27343D060A0F070F12202E372230
+ 3942576425333D18222A10191C0202062E414D00000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000022303737495534475126343E131C2224323A2835
+ 3F506C7B5C7A8E5571812D3C46050A0E0C14180C151C111C2300000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000001923293A505B3D515D4459692F3F4B3C505D4259
+ 66506C7B6585975D7A8D3C505D202D35131C2019242A091013020507050A0F09
+ 0F140912180F181D0B1318131E25233038283A432F414B26353F0E181D3A4C56
+ 00000000000000000000000025333C435A674963703548534258665774856383
+ 966F92A55B788A3346521B272E0F151A0F1A1D25333C293B431F2D35141D232C
+ 3C452939420E161B050A0E02020202020205070A040508020202020202020202
+ 4F626F0000000000000000003C505F506B79526E7F4359664C64725976865976
+ 856B8B9F5672832D3D470B11151620282838433C505D4F6B7B49627134465213
+ 1C230202020B111429394328373F1F2D321622261823281B242A182229151F25
+ 202D35597788000000000000465F6B5A77894C657447606D4B65743F55623345
+ 5141576526353E1C292F31424E42586526353D232F39475F6B3446523548552F
+ 3F4B3B4F5D5672836383955C788A4B6574415563415765516E7C658397557082
+ 2D3E48020202384B56000000587284536F805A77885570824158654E66773C4F
+ 5C384B573A4E5A30434E24343C32454F30424B354852496271475F6D34475252
+ 6E7C617E9084AABF80A5BB6D8DA2678599526D7E60809261819583A4BB88ADC2
+ 24343C020202020202000000617F903E56622F414C5772834C65753B505B384E
+ 5A435867465F6C4C6474374855384B583346503345502C3C464C65756A8A9F59
+ 76864C64755F7C8E59768567869A6E8FA157718285A7B985A5BB95B8CA95B9CD
+ 070F150202020202025F656969899D4C66752E3D465770826A899E617F904257
+ 63374C5723313A496271445C6A445A6747606C2C3D4631444E47606E5570804F
+ 69795D7A8B6C8D9F5672827296A97B9EB2799CAF7698AD99BBCFC9E8F982A8BC
+ 24313B18252C0204090202022C3C46435966638496769AAE6F8FA3618092536E
+ 7E37485327333D3D515F5672833C515D30424C3547552E3F482D3E493A4F5962
+ 819367869A5C7A8B536D7E4F69785C788A526C7B5C7A8D6F8FA38CADC27EA0B6
+ 7094A94E6C80627C8BA0B4C03D525F111B20445B697496AB7194A97294A9607F
+ 8F4B6371425A69384D58455B6A617F92445C6A3549562E3E473A4F5B5A76866C
+ 8CA0789DAF6C8CA04257643F5662455C6B3C515C4D66766A899A6D8EA2516E82
+ 7497ABAACADE0000000000004C63721F2D34020202283841617E8F6585986D8C
+ A25A77863D525D465D6C597586617F92465F6D3E556127353F2E3D485A778883
+ A5BB96B9D07C9FB4374B563F5561526E7C4E6A785772847FA2B688ACC3799EB4
+ 0000000000000000000000003B4F5A2D3D470E1519080F13344650445B6B4C62
+ 70537080486170415763506B7A6C8DA0516D7B3C515D233039273741516B7C72
+ 96AB6A8BA0455D6D4B62716280937CA1B6789CAF90B3C87B9DB1000000000000
+ 000000000000000000000000455C6B2E414B222E35070E111B262D3E55622535
+ 3D394D59394D592332392C3D473E53623A505C24323D2938426B899C83ACC156
+ 70802A3C46203038698999678899536E8097B9CD000000000000000000000000
+ 0000000000000000000000004D6575283841222F370C12161923283C4F5B455F
+ 6B485F6E4F6A79465D6D394C581A252D0406090202022E3B445C778808353902
+ 020202020232465297BBCF3A4F5C708C9E000000000000000000000000000000
+ 000000000000000000000000384B581D2A3224323C1C2930111B1F2A3B473F55
+ 63394E5A607E8F6685987195A932434E080E1202020202020216202657707B43
+ 525D0202023749557994A522313B698B9F000000000000000000000000000000
+ 00000000000000000000000026353F0F151B0E151A0E151A06080C2230383344
+ 4F3848564C6472455B6A6180927193A73A4E593446531B252E2C3B4864819064
+ 81930E151B415765243541435C6EA1C0D0000000000000000000000000000000
+ 000000000000000000000000222F38020202020202020202020202131D232C3A
+ 4524303A384D573D55624E67785977865774853F5562486170465D6B32445019
+ 252C263842435D6D415C6F8AB3CB000000000000000000000000000000000000
+ 0000000000000000000000001822280202020202020202020207070A11162939
+ 42151E2425343C30434C3444502E3D48516C7A61809249616F506A7A62829546
+ 60715D7E907198AE000000000000000000000000000000000000000000000000
+ 0000000000000000000000000B111402020202020204060819232A192429141E
+ 23121B1E2C3945384C562F3F4B3A4E5A4B64725C798B556F80516B7E5B7B8F6D
+ 90A4ACCDE2000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000020608020202020202020202182328455C6B394D
+ 592839431F2D3533444F394D584C6575475F6E3F57643D58665F7F937F9EB2B1
+ D1E4000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000111A1E0A0F120910130F181C19262D2D3E492C3C
+ 462E3F491D2A313B515F445B674D6777577486516C7F7294A7B4D4E6B1CDDE8C
+ ACBD000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000002839411620276D8DA34F6978020608020206141D
+ 23182227131D2365889C5776894F6A7A6B8DA299BCD1CDEBFEC0DEEF4662746F
+ 8EA1000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000018232A30424C799EB32A3B450202020202020202
+ 020202022E3F4B8BB3CA93B6CCA4C6D8AFD1E198BBD0A5C8DB83A7BD4966789A
+ B9CD000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000E13182737422A3B450202061F2A313548552837
+ 411F313B637C8B000000000000000000A2C0D36E90A75371836F8FA4557284A1
+ BED0000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000002020211191E25333D435A67608090435867526F
+ 81425F6E82A2B400000000000000000089ADC16E93A9486270425C6B65849700
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000020202020205394E58455C6C24333A2E414E5977
+ 8994B7CC00000000000000000000000093B6CB48657730434F2637425F7A8D00
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000002020205080A374C5626374220313D718E9E0000
+ 00000000000000000000000000000000BBD7E97B9CAF384F5C2535415F7A8C00
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000202050205091B27323449560000000000000000
+ 000000000000000000000000000000000000000000008CAEC13D596A59728300
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000859FAE2A3B445A72810000000000000000000000
+ 000000000000000000000000000000000000000000000000006F8EA247627200
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000001FFFFF000FFFFF0007FFFF0001FFFF0000000F
+ 0000000700000003000000010000000100000000000000000000000000000003
+ 0000000F0000003F000000FF000001FF000001FF000001FF000003FF00000FFF
+ 00001FFF00003FFF00003FFF00003FFF00003FFF00703FFF00707FFF00F07FFF
+ 03F07FFF0FFC7FFF1FFE7FFF}
+ end
+ object CancelButton: TButton
+ Left = 344
+ Top = 248
+ Width = 75
+ Height = 25
+ Caption = '&Cancel'
+ TabOrder = 0
+ OnClick = CancelButtonClick
+ end
+ object NextButton: TButton
+ Left = 264
+ Top = 248
+ Width = 75
+ Height = 25
+ Caption = '&Next'
+ TabOrder = 1
+ OnClick = NextButtonClick
+ end
+ object GroupBox1: TGroupBox
+ Left = 48
+ Top = 136
+ Width = 369
+ Height = 89
+ Caption = 'Wolfpack Installation Folder'
+ TabOrder = 2
+ object InfoLabel2: TLabel
+ Left = 8
+ Top = 56
+ Width = 284
+ Height = 13
+ Caption = 'Please select the wolfpack.xml of your Wolfpack installation.'
+ end
+ object WolfpackPath: TEdit
+ Left = 8
+ Top = 24
+ Width = 265
+ Height = 21
+ TabOrder = 0
+ end
+ object BrowseButton: TButton
+ Left = 280
+ Top = 24
+ Width = 75
+ Height = 21
+ Caption = 'Browse'
+ TabOrder = 1
+ OnClick = BrowseButtonClick
+ end
+ end
+ object XPManifest: TXPManifest
+ Left = 384
+ Top = 104
+ end
+ object OpenFolderDialog: TOpenFolderDialog
+ Title = 'Please select your Wolfpack installation folder.'
+ Options = [flReturnOnlyFSDirs, flShowStatusText]
+ OnSelectionChange = OpenFolderDialogSelectionChange
+ Left = 8
+ Top = 152
+ end
+end
Added: trunk/WPGM/ImportDefinitions/Main.pas
===================================================================
--- trunk/WPGM/ImportDefinitions/Main.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/Main.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,109 @@
+unit Main;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, ExtCtrls, StdCtrls, XPMan, OpenFolderDialog;
+
+type
+ TMainForm = class(TForm)
+ BottomBevel: TBevel;
+ CancelButton: TButton;
+ NextButton: TButton;
+ TopImage: TImage;
+ TopBevel: TBevel;
+ InfoLabel1: TLabel;
+ WolfpackIcon: TImage;
+ XPManifest: TXPManifest;
+ GroupBox1: TGroupBox;
+ WolfpackPath: TEdit;
+ BrowseButton: TButton;
+ InfoLabel2: TLabel;
+ OpenFolderDialog: TOpenFolderDialog;
+ procedure CancelButtonClick(Sender: TObject);
+ procedure BrowseButtonClick(Sender: TObject);
+ procedure OpenFolderDialogSelectionChange(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure NextButtonClick(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ MainForm: TMainForm;
+
+implementation
+
+{$R *.dfm}
+
+uses Registry, WpConfiguration;
+
+{
+ Close the wizard.
+}
+procedure TMainForm.CancelButtonClick(Sender: TObject);
+begin
+ Close;
+end;
+
+{
+ Let the user select a directory.
+}
+procedure TMainForm.BrowseButtonClick(Sender: TObject);
+begin
+ if OpenFolderDialog.Execute then
+ WolfpackPath.Text := OpenFolderDialog.Folder;
+end;
+
+{
+ Show the user if the directory he selected is valid or not.
+}
+procedure TMainForm.OpenFolderDialogSelectionChange(Sender: TObject);
+begin
+ if FileExists(IncludeTrailingPathDelimiter(OpenFolderDialog.Folder) + 'wolfpack.xml') then
+ OpenFolderDialog.StatusText := 'This is a valid Wolfpack installation directory.'
+ else
+ OpenFolderDialog.StatusText := 'This is not a valid Wolfpack installation directory.';
+end;
+
+(*
+ Query the Wolfpack installation directory from the uninstallation database
+ @ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{44306150-2736-4554-ACD5-957D5F12604B}}_is1
+*)
+procedure TMainForm.FormCreate(Sender: TObject);
+var
+ Registry: TRegistry;
+begin
+ Registry := TRegistry.Create;
+ Registry.RootKey := HKEY_LOCAL_MACHINE;
+
+ // Open the Uninstall Key.
+ if not Registry.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{44306150-2736-4554-ACD5-957D5F12604B}}_is1') then begin
+ Registry.Free;
+ exit;
+ end;
+
+ // Read Installation Directory
+ WolfpackPath.Text := Registry.ReadString('Inno Setup: App Path');
+
+ Registry.Free;
+end;
+
+procedure TMainForm.NextButtonClick(Sender: TObject);
+var
+ WpConfiguration: TWpConfiguration;
+begin
+ // Try to load the configuration file
+ try
+ WpConfiguration := TWpConfiguration.Create(IncludeTrailingPathDelimiter(WolfpackPath.Text) + 'wolfpack.xml');
+ ShowMessage(WpConfiguration.ImportDefinitions.GetText);
+ WpConfiguration.Free;
+ except
+ Application.MessageBox('An error occured while loading the wolfpack.xml file from your Wolfpack installation directory', 'Error', MB_OK+MB_ICONERROR);
+ end;
+end;
+
+end.
Added: trunk/WPGM/ImportDefinitions/Main.~dfm
===================================================================
--- trunk/WPGM/ImportDefinitions/Main.~dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/Main.~dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,5167 @@
+object MainForm: TMainForm
+ Left = 487
+ Top = 332
+ BorderIcons = [biSystemMenu, biMinimize]
+ BorderStyle = bsSingle
+ Caption = 'Import Definitions'
+ ClientHeight = 287
+ ClientWidth = 433
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ PixelsPerInch = 96
+ TextHeight = 13
+ object BottomBevel: TBevel
+ Left = 0
+ Top = 232
+ Width = 433
+ Height = 9
+ Shape = bsBottomLine
+ end
+ object TopImage: TImage
+ Left = 0
+ Top = 0
+ Width = 586
+ Height = 87
+ AutoSize = True
+ Picture.Data = {
+ 07544269746D617056560200424D565602000000000036000000280000004A02
+ 000057000000010018000000000020560200120B0000120B0000000000000000
+ 0000284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00274A00274A00274A00274A
+ 00274A00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00274B00274B00274B00284C00294D01254B00264D00284C00264802274B
+ 00284A03294D01284B01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294D01284C00284C00284B01274A
+ 0026480126480225470124460024460024460024460023440123440122420122
+ 4201244300234200234200244300244300244300254401264502264502264502
+ 264502244300244300234200244300244300243F00243F00233E00243F00243F
+ 00243F00233E00233D01253E00253E00253E00243D00253E00253E00253E0026
+ 4000253E00263F01264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01
+ 284C00274B00274B00284C00284C00284C00284C00284A03264A00264801274B
+ 00274902294C02294B04284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294D01284C00284C00284C00274B
+ 00274A00274A0026490024460024460024460024450223440122430022420122
+ 4201244300244300244300244300244300244300244300254401244300254401
+ 284402274301274301254401234200244201263F01263F01253E00253E00243D
+ 00253E00243D00243D00253E00253E00253E00243D00243D00253E00263F0126
+ 3F01264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 274B00274B00284C00284C00284C00284C002B5000284B01284C002C5003284C
+ 00274B002B4E04284B01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C0025470025470024460024460024460023450023440123
+ 4401244300244300244300234200244300244201244201244201234200244300
+ 284402284402284402284402244300244201264000264000264000264000253F
+ 00253F00243D00253E00243D00253E00253E00243D00243D00243D00253E0026
+ 3F01264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000294C02294C02294C02294C02294C02294C02294C02294C02284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01
+ 284C00284C00284C00284C00294D012A4E02284C002B4F02274A002C50042C51
+ 01274B002A4E02274B00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01284B
+ 01294C02294C02294B0427490226480125470025470125470124460023440123
+ 4401264502254401264502244300244300244201244201244201244201244300
+ 274301284402284402284402244300244300253F00253F00264000264000263F
+ 01263F01243D00243D00243D00243D00253E00243D00243D00243D00253E0025
+ 3E00264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00284C00284C00284C00284C00274A00274A00
+ 274A00274A00274A00274A00274A00274A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00294D01294D012A4E022B4F022648012E5009284B012749022B4F
+ 02284B012A4E01274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01284C
+ 00284C00294C02284B01284C00274A0026490026480125470025470125470124
+ 4600284402284402284402264502264502254401244300244201244201234200
+ 2443002743012743012844022544012443002640002640002640002640002640
+ 00264000264000264000243D00243D00253E00253E00243D00243D00243D0024
+ 3D00264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274A00274A00274A00274A00274A00274A00274A00274A00274A00274A00
+ 274A00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A
+ 00274A00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00294D012A4E022B4F022B4F02274E00375C14284F012648012D50
+ 06274B002C5003274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00274A0026480125470024460024
+ 4600284402284402284402284402274301244300244300244300244300244300
+ 2443002443002544012544012844022743012743012743012642002642002642
+ 00264200254100254100243D00253E00253E00253E00253E00243D00243D0024
+ 3D00253E00263F01264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801274A00274A00
+ 274A00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A
+ 00274A00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00294D01
+ 294D01284C00284C002A4E012C50032C5003325A08426C15325909254B002E52
+ 062A4E012B4F02284B01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294D01284C00284C00284C00274A
+ 00274A00274A00274902284C00284C00284B01274A0025470024460024460024
+ 4502284500284402284402284402274301244300244300244300244300244300
+ 2344012243002344012342002743012743012844022844022642002642002641
+ 01264101264101254000253E00253E00253E00253E00253E00253E00243D0024
+ 3D00243D00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801264802244600244600254701274902274A00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274B00274A00274A00254903254A00
+ 264D00264C00254D00264D012248061F4B06264D02274D012750002C50032C50
+ 042E51012C53002B50002C5101284C00284C00284C00284B01294C02284C0026
+ 4900274A00274A00274A00264900274A00284C00284C00284C002A4E01284B01
+ 284C00284C00284C00274E002A51012E5800295600507B483B59282C52002959
+ 01274E03284E02274A00294D01284C00284C00294D01294D01284C00274A0027
+ 4A00284C00284C00284C00284C00284C00294D01284C00284C00294C02284B01
+ 294D01284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00264801274A00284C00284C00284C00284C00284C00284C00274E00274E00
+ 274E00274E00274E00274E00274E00274E00274A002C4F052446002B50002648
+ 02264802264801264801284C00284C00294D01284C00274D01264D00274E0027
+ 4E00274A00284A04294B05294B05264802274A00284C002B50002A5101305A05
+ 234A002B52072A4E02284A032C5004274D01284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00264900274A0027490226480126480126480126480126
+ 4801284A04284A04284A04284A04284A04284A04284A04284A04284A03284A03
+ 284A03284A03284A03284A03284A03284A03284A04284A04284A04284A04284A
+ 04284A04284A04284A04284A03284A03284A03284A03284A03284A03284A0328
+ 4A03284A04284A04284A04284A04284A04284A04284A04284A04264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600244201244201
+ 2443002342002443002544012443002443002642002642002642002642002642
+ 00264200244300244300254000243F00233E00243F00243F00243F00243D0024
+ 3D00233E00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801264802244600244600254700274A00274A00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00274A00274A00274B00264C00
+ 2C4E012A50002C52002851002C50032B4E042E52002E51012C53002C56003155
+ 012E50032B4D002C4F002C5003294D01284C00284C00294D012A4E02294C0228
+ 4B01274B00284C00284C00284C00284C00284C00284C00284C00274B00264C00
+ 284A03264900274B002A4E012A52002C56003063096E9568477632335C012E5C
+ 03294F03285002244B00284C00284C00284C00284C00284C00274B00274A0026
+ 4900284C00284C00284C00284C00284C00284C00284C00284C00284B01284B01
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274A00274A00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294D002A4E01274A002D51052648
+ 022B4F022C50042B4E04284C00284C00284C00284C00284C00264C00274E0027
+ 4E00274A00294C02284A03284A04264801284C002B50002A51012B5500284F01
+ 335A0A2244002D4C07274D012A5103294D00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00264900274A00274A0026480126480226480126480126
+ 4801264802264802264802264802264802264802264802264802264802264802
+ 2648022648022648022648022648022648022648022648022648022648022648
+ 0226480226480226480226480226480226480226480226480226480226480226
+ 4802264802264802264802264802264802264802264802264802264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600264502254401
+ 2544012443002443002443002443002443002642002642002642002642002443
+ 00244300244300244300254000254000243F00243F00233E00243F00253E0024
+ 3D00243F00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264802264802254700254700264801274A00274B00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00294D01284C00284C00284C00294D012B4C01
+ 275400335403315501375A03315503315600375B01375B01345A02355B033054
+ 003354032C51012750002C50042A4E01294D01284B01284C002A4E02294C0228
+ 4B012A4E022A4E02294D01294D01294D01294D01294D01294D01284C00284B01
+ 264A04284906294B042A51012F55032E570235620180AA75527C453360032955
+ 02294E042D5104254C00284C00284C00284C00284C00274B00274B00274A0027
+ 4A00284C00284C00284C00284C00284C00284C00284C00284C00274A00274A00
+ 274A00274B00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C002A4E022A4E022345
+ 002C50032C5004274B00264C00274D01294D01284C00294D01294D01294D0128
+ 4C00284C00284C00274903294C02284C00294D012A52002C56002D59002A5300
+ 3059082B51052C50032C5004274E002E4E01284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00274A00274A0026490024460024460024460025470026
+ 4801264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600274400284500
+ 2844022844022544012443002442012442012443002443002443002443002443
+ 00244300244300244300264000264000264000253E00243D00243D00243F0024
+ 3F00243F00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801244600254700264801274A00274A00274A00284C00294D01284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00294D012751042C5206
+ 305400365C023A5A013C5D023F5E033F5D04415D033A64003763043B5B02365D
+ 07305C002E59022E55002B4F02294D00284C00274A00284C00294D01284C0028
+ 4C00294C02294C02284B01284B01284B01284C00294D01284C00284B01274E00
+ 2A4C062B4D07294E042C50032F5901345B062B590078A677527B482D5C002A55
+ 002A4C052C5305244F00294D01294D01284C00284C00274B00274B00274A0027
+ 4A00284A03284A03284A03294B04284A03284A03264801264801264900264900
+ 274A00274B00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00294D01294D01294D00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284B01274A002A4E02294D00284C
+ 002C5003294C02284C00284C00294D01284C00274B00284C00294D01294C0229
+ 4C02274B00284C00284B01294C02284C002A4F002C56002F5902315C01335907
+ 2F52084677332F53062E55002C5200244E01284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00274B00274B0026490024460024460024460026480126
+ 4801264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600274400284500
+ 2743012844022844022743012844022844022443002443002443002443002443
+ 00244300244300244300264000264000264000264000253E00243D00233E0024
+ 3F00243F00263F01264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801244600264801274A00284B01284C00284C00284C00294D01284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274B00274B00284C00284C002A4E022B4F032E55072C5600
+ 385B003060003B65003965003863023A63014167073F69043864013C63013463
+ 003362002F5E02335C012B51002A4E01284C00274A00274A00284C00284C0028
+ 4C00264C00264C00284C00284C00274B00274A00274A00274A00264B01294D01
+ 264C00294C022B4F032A51012F5600315B0334610085A778547B473361012D59
+ 002D5105295103294D00274B00284C00284C00284C00284C00284C00284C0028
+ 4C00294C02294C02284B01284B01284B01284B01274A00274A00284C00284C00
+ 284C00284C00284C00294D01284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00294D01294D00294D002A4F002B4F022B4F02
+ 2B4F022B4F022B4F022B4F022B4F022B4F02274E00274E00284E022C5200345A
+ 083056042B50002F54042D50002D50002A4F002A4E012A4E01274D01264C0027
+ 4D01264C00284C00294D01284B01274B002B51002D5601315B03336200315B06
+ 4776315284362F57052B55022E5500264A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00274B0026490025470124460024460026480126
+ 4802244600244600244600244600244600244600244600244600264801264801
+ 2648012648012648012648012648012648012446002446002446002446002446
+ 0024460024460024460026480126480126480126480126480126480126480126
+ 4801244600244600244600244600244600244600244600244600244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460024460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600284402284402
+ 2844022844022844022844022844022844022443002443002443002443002443
+ 00244300264200264200264000264000264000264000264000253E00243F0024
+ 3F00243F00263F01264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801274A00284B01284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00294D01284C00274B00274A00284C00284C002A4E022B4F02385B01385B01
+ 336101376304396A023A6C00396C0B3D6C0A3A6D0B3B6B0B396D093A6D0C3A64
+ 00346003316101315D002C53002A4E01294D01284C00284B01294D01294D0028
+ 4C00295000284F002950002B50002B50002B5000295000295000295002285000
+ 2A4E01274E00284F002C52002E5800315C0130640683A977507D453461003461
+ 002B52062B5400284F01284C00284C00284C00284C00284C00284C00284C0028
+ 4C002B4F022B4F022A4E01294D00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00274A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00294D01294D002A4F002B51002B5100315501315501
+ 3155013155013155013155013155013155012A53002C5500284F012D5301365D
+ 072E55002D57002A52002E58012D57002C56002C55002B53012C51012B4F022C
+ 5003295000274C02294D01284C00284C002C52002D5601315C01315B03315A09
+ A6C99047782E2A5B053058002C5903264C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294D01284C00274A0026480124460024460026480125
+ 4701264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460024460024460024460024460024460024460024460024
+ 4600244600244600244600244600244600244600244600244600254401284402
+ 2844022844022844022844022844022844022443002443002443002443002443
+ 00264200264200264200264000264000264000264000264000264000243F0023
+ 3E00243F00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801274A00274A00284C00284C00294D01284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00264900284B01284C002B4F032C5003375A033E5D00
+ 3766003B6A033A6D0B3975173775173A76183776163977193976143675173C6C
+ 0C3D6C0A3965023460012E54022D52022B4F02294D002A4E022B4F032D51052C
+ 50042B55022C55002C55002C56002D57002E58012E58012F59022F59012C5500
+ 2C56002C55002C55002E5900315C0134610033620084A879547A48346003325D
+ 022A56032D5000274F01284C00284C00284C00284C00294D01294D012A4E022A
+ 4E012C56002C55002E55002E55002D53012C52002A52002A52002B4F032B4F02
+ 2A4E012A4E01284C00284C00274A00274A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00294D01294D002B51002E54022F5503375B01375B01
+ 375B01375B01375B01375B01375B01375B01315C01315C01305800345C04355E
+ 03315B04426D162E5A01346202326000315E01305B002E58002F560031550131
+ 55032A52002A52002B5000294D012A4E012F5601305A02315C01316200406D17
+ C8F2C9365B172D5C00325E012A54002A4F05284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294C02294C02294C02284A0327490326480126480124
+ 4600264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460023440123440123440123440123440123440123440123
+ 4401244600244600244600244600244600244600244600244600264502264502
+ 2844022743012743012743012743012743012443002443002443002443002443
+ 0024430024430024430026400026400026400026400026400026400025400024
+ 3F00243F00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801264801264801264801264801264801264801264801
+ 2648012648012648012648012648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801274A00274B00284C00294D01294D00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00264900284B01284C002C50032C5003355C003D6500
+ 4168063B6C0A4273094279163B7828397A243C852939852747862844831D4279
+ 163C74093D6A033864003056042E54022C51012A4E012A4F002C50032E51072E
+ 51072D59002E5A01315B03305B00315C01345E06345E06355F07346100345F04
+ 345E06315B03315C01335F003764033B6A0432620989AA87578647336101305B
+ 002E5507275400295000284C00284C00284C00284C00294D012B4F032B4F022B
+ 4F022E58002E58002F56002F56012E55002E55002C55002C55002C50032C5003
+ 2B4F022A4E01294D00284C00274A00274A00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00294D002A4F002B51002F5503305604375B01375B01
+ 375B01375B01375B01375B01375B01375B013461003862033965003D69043965
+ 02416D14628F393A6D0B3A6301396502366302346001315D00305A022E58012C
+ 56002C55002D56012D52022C52002C52002E5500315C01335F003B6409548638
+ C8F3C8365A14365E063460012252002B5206284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294C02294C02294C02284A0327490326480126480124
+ 4600264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002648012648012648012648012648
+ 0126480126480126480124460024460024460024460024460024460024460024
+ 4600264801264801264801264801264801264801264801264801244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460021440121440121440121440121440121440121440121
+ 4401244600244600244600244600244600244600244600244600264500254400
+ 2844022844022844022743012642002442012443002443002443002443002443
+ 0024430024430024430026400026400026400026400026400026400025400025
+ 4000233E00253E00264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254701244600264801274A00274A00274902264801264900264801264801
+ 2648012648012648012648012648012648012446002547002446002547012446
+ 0025470124460024460026480125470025470026480126480126480126480126
+ 4802284C00284C00284C00284C00284C00294D01284C00274B002E4E00264D00
+ 325302264C002E5500285100254401285002284E06264C00264D01254C002449
+ 01284C00295000284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274D01284C00284C00284C00294D01284F012951002C550029541B296501
+ 32620A4279163A7618588B598AAA91A7C8B3C8D9CBC7D9CCC5E0BFA3BBA977A5
+ 764877333774062A72072D6401235A002151022951032D5605305500365B0038
+ 64013B630B385B01406A053A63023864013B6C04396A023269023B6B01346902
+ 3D6B013B6B013B6A04316902346901316B0C39761684A8795786473973062659
+ 022E5D002A52002A4C06214C012A5302294B04244600264801314C0331560035
+ 5C003362003B64023A5D03425C02426A053A63012C6601316801415D03315503
+ 3054002C4E012D4E042B5207244900285506284C00284C00284C00284C00284C
+ 00284C00284C00284C002847022C5004274A00254A022A5004214D002753002A
+ 5200305C03284E0232520B2A4C00335F042D5900315C01315B08336200346001
+ 375B013F5D043F5E033F5E033460033A63013B6C00396C0B2B65003E6C0C4279
+ 16416D1484A9773B6C00316902326804296501316200345F04336101325B0033
+ 62003161012D59002E5A002E55002D5801305C0131620039650C326A01568D54
+ B5CBB83C64003269023162002E58002B55002B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00274B00274A00274A0027
+ 4A00244600244600244600244600244600264802264801264801264802254701
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460024460024460024460024460024460024460024460024
+ 4600244600254701264802244600244600264801264801264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440224430024430024430024430024430024430024430024
+ 4300244300254401244300254401254401244300254401244300284402274301
+ 2642002743012743012844022443002342002443002443002342002443002443
+ 00244201244201244201254000254000243F00233E00233E00233E00243F0023
+ 3D01253F00253F00264000264000253F00264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600244600264801274A00274A00274A00274A00274A00274A00274A00
+ 274A00274A00274A00274A00274A00274A002648022648022648022648022446
+ 00244600244600244600264801264801264801274902274A00274A00274A0027
+ 4A00284C00284C00284C00284C00284C00284C00284C00284C00294902284C00
+ 2E52002C56002A51032B54002E55072B5301284E02264C002951032D5104244B
+ 00254701284C00254B00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274D01284C00284C00284C00284C00274E002A52002C55003B6500367206
+ 3E640A527C45A6C990EDF6F9F0FEFDECFEFDF3FFFFEBF7F9EDFDF2EAFFFDEBFF
+ F2C8D9CC629153365B153864013A6603306000315C01375B013863023F680642
+ 68043774063972093575043B6A033A74084079173C6E0A377517367305347208
+ 376C0B3B6C0A3B6D0F3777143877173C751A37771797BB97588D54326B09346A
+ 00326104265600264802214E00264D00274A00254B002A5103305505385B0137
+ 5C00436808426A0440730B417A1840730B3C6D0B3B6A0D436907386401346001
+ 345F083757062D50002B4C01284E02254700284C00284C00284C00284C00284C
+ 00284C00284C00284C002C5101294F03224400264A042C5004284F012F59012B
+ 59002E5A00234A003155083253092B51003D6303416A013B6403385B01375A00
+ 3863023B65003362003A6902386C012B650033630A30630737720938811B2872
+ 08396B1776B07A377307316B0C3669013A6B00387507386C013469023B6A033A
+ 6B01365D12365D083361012B65003261043361013965004268043773078A9D84
+ 98AD97336101316902315C012E55002A51012B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00274B00274A0027
+ 4A00244600244600244600244600244600264802264801264801244600244600
+ 2446002446002446002446002446002446002446002446002446002446002446
+ 0024460024460024460024460024460024460024460024460024460024460024
+ 4600254700254700264801264801264801264801264801264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402244300244300244300244300244300244300244300244300274301284402
+ 2743012844022844022844022743012743012645022544012443002443002443
+ 00244300244300234200264000264000264000253E00253E00243D00243D0024
+ 3D00264000264000253F00264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254701264802264801274A00274B00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284A04284A04284A03284A032648
+ 0125470024460024460024460024460025470125470126480127490226480125
+ 4700284C00284C00284C00284C00284C00284C00284C00284C00294A002A5204
+ 284F013055002952002C55002D5503224A032D5507234D00274D01295201264D
+ 01264801284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00284C00284C00284C00284C00274E002A52002D56013765023D6B01
+ 578648B9D8BBF1FFF4F2FFFDD7EAD9B8D7BA93BC979AC9A38BC699CCE6D6D0F0
+ D1EBFDFED1F0CF709468426E153B64034369054169043C6D013F6B003B6A0340
+ 7409407916427817497B1D49841B4278143A77152E731837811B397927397A25
+ 44781A436E133877173A79233D782736831B47772FB5CDBB6B9467346A093B6C
+ 043261002E5A012E5009274D01254A00274A002950002B5400295901305B003B
+ 630438640044750943750937761645821A43851C4178154379183573073B6B01
+ 2D5900345A00395C022A4C002B52072A4C05284C00284C00284C00284C00284C
+ 00284C00284C00284C002A4E01264900274902284E062C52062850022D57002D
+ 5900284F00436E17254A02345E07396403426A053965023E5D02375A03406B04
+ 3C6C022765013971083774062C71083A7717336C0A3D7925458319366B144587
+ 35558D5299B9A86A95685A8D535F905267915459854850863947772F406D172A
+ 52042D64013463012F5B0830580A335F063F6A033B6B013864013B6C0AAFCDB0
+ 6A96673269023B6C00365D08325A082D56052B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00274B00274B0027
+ 4A00264801264801264801264801254700264801264802264802244600244600
+ 2446002446002547012547002648012648012648012648012648012648012648
+ 0126480126480126480126480126480126480126480126480126480126480126
+ 4801274A00274A00274A00274A00264900264801254701264802264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402284402284402284402284402284402284402284402284402274301284402
+ 2844022844022844022844022844022844022743012844022844022743012443
+ 00244300244300244300264000264000264000264000264000253E00253E0024
+ 3D00264000264000253F00253F00264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600264802264801274A00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294C02294C02294C02284B01274A
+ 00274902254701244502264801264801264801264801274902284A03284A0328
+ 4A04284C00284C00284C00294D01284C00284C00284C00294D002D4E04355308
+ 2C55002C55002F5B022D5C06214A00375A17396A162E5507204C00284F01274F
+ 012A4E012B50002C4D02284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00294D00284C00284C00284C00274E002A52002C5500335D08346202
+ 899C81EEFEF3AECDAC6F956B5586484F8538478A47458A4746893494BD8A5986
+ 47899E85C0E6C8CFE5CD4F7A1F4078194074093B6A0335730741831A42841B43
+ 831946852946842A588449659154517B46527B486D936987B586A5BBA8A9C7B4
+ B2CDB9C7D9CCB4CCBA9EB497889D846A9568547C45ABC7B46D94673E6E153B6C
+ 0A2F59022651002B5006295005254C012950042950002A52002B5A003965023B
+ 6B013674083773073975173A842A46893444883537792747862838811A427817
+ 316902336003385A032D5100274B002B4B0A284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00294D002B4F002B52042851002855002E5A002C
+ 5902375C1281B96E345A08345E074169033C64003B6402416806426808315C01
+ 3068013774063977193B741743773146762E56854678A26BA6C991C3E1BEF5FF
+ EED9F7E4F3F9FEEEFFF2D6E8DBB6DAC4A8C7B8B2CDB9CBE5D7ECFEF1E4FDE9B6
+ CCB97AA369457731315C01305C033463062A5B0532620A41750A456D15D9F7E4
+ 527C45397307386C00335C002A54012D51042B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0027
+ 4B00264801264801264801264801254700254700244600244600244600244600
+ 244600254701254700264801264801264801284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274B00274B00284C00284C00284B01264900264801264802264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402284402274301284402284402284402284402274301284402284402284402
+ 2844022844022844022844022844022844022844022844022844022844022743
+ 01284402264200264200274101264000253F0026400026400026400026400026
+ 4000264000263F01243D00243F00254001264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254701264802264801284B01294D01284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284B01274A00274B
+ 00274A0026480125470126480126480126480126480226480226480227490326
+ 4802284C00284C00284C00284C00284C00284C002A4E012B4F022B52062D5601
+ 365D07315D0039640D2E53032B510578A26B406E152F5C06295000265100284F
+ 012A4B00264D00294A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00294D00294D01284C00284C00274E002A52002C5500365C14276812
+ B0CDAC98C8A4518734397A254486274785273C8F2D39842851963B9CD7AA5196
+ 3B517E46558648AAD5AA65A45445862A48831A4587284587283885293B792748
+ 8737398A3558995495BE8BC2E6C8E2EFDFFAFFFEFEFEFEFFFAFFEDFEF3D4E8DC
+ C8D8CDB4CCBAB5CEBAB8D7BAD3EFD2E4FDE9B0E5BAE2FDF9A0B4973A77172C66
+ 013163052E5902285100254A02244D022B51002C55002B58013B64023B6B013B
+ 6B012C73053978286A9568A4B9AAB6D8BABAD9BA87B489578B55397A254A831A
+ 44811F3B6B01315D00355B01295000224700284C00284C00284C00284C00284C
+ 00284C00284C00284C00284E022A4E012E5101284F012C5600355F0739640932
+ 6307385829A5C890426E153D65003A6A043B6B013F68063965021E63022F7108
+ 3776183B7417457731507C478AAA91C8D8CDF2FEFEEDF8F6CAF1D198B8A585A8
+ 767AA16DB5CEBA45772F427719396C0A3C6D0B346A092F59013263074F7A1F51
+ 8636879D84B0CCAFB2D2AF7CA36B3E6A0B2866023C6C023D6C09457731E5FBE8
+ 4376323A6B01335F022B59002F57002A52042B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00264801264801264801264801264801264801244600244600244600244600
+ 244600254701254700264801264801264801294C02294C02294C02294C02294C
+ 02294C02294C02294C02294C02294C02294C02294C02294C02294C02294C0229
+ 4C02284C00284C00294D01294D01284C00274A00264900264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402284402274301284402284402284402284402274301284402274301274301
+ 2844022743012743012743012844022844022743012743012743012844022844
+ 02284402264200264200274101264000253F0026400026400026400026400026
+ 4000264000263F01243D00243F00243F00263F01264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600254701264801284B01294D01284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00274A00274A00274A00274B
+ 00274B00274B00284B01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00294D002B4F022C50032C5902295502
+ 386401346001365F04244E01527B48A6C990335D062E55002A5401305402264E
+ 00264801284C00274D01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00274E00294D01284C00284C00284F012A52002E5500265A002E6502
+ AFE3BB4377312D73184786283A85293688353A893244894652974699D5A55596
+ 4A558B564B8A4565A3578BC797559746398936468A37458736517E465A8B5774
+ A775C5DACBEDFCF4F1FFFBF3FFF9E3FFF1CBE5D798BB996A95683B7927366A17
+ 386A16416C15377517396B17387618468626609153C8E6D3C5E0BE54963D3268
+ 042E5D012D58012A51032648012B4C01274D0129510033610134610030610039
+ 6502477632AECDAEF8FFF8F8FBFFFFF6FFFBFDFEF7FFFDE5FBE977B17A457632
+ 3B79273775172C6502336000325A082A4E02284C00284C00284C00284C00284C
+ 00284C00284C00284C00294902254A002C51012B5202325B00386409315B0333
+ 5C0186B48964905339630B427916396D013B6B0B3469023269022C76183D7827
+ 4776316E9666B1CBADDCF8E5F1FFF8E9FEFBAECCAF6B9566467832547B473D78
+ 2844792FAEE2BA43781A407409326B02316801326B02305B00345F04365D0732
+ 5A08365B152C5504396C1561905195BF8A95BE8B62A1573A76186C9667D1F0CF
+ 386917316801346301385E06315C013053092B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294D01284C00284C00284C00284C00284C00284C0028
+ 4C00284A04284A03274902264801264801264801244600244600244600244600
+ 244600244600254701254700264801264801284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274A00274A00274902264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402284402284402284402284402284402284402284402284402244300244300
+ 2443002443002443002443002443002642002743012844022844022844022443
+ 00244300234200244300264000264000264000264000264000253E00253E0024
+ 3D00264000263F01243F00243F00243F00243F00253E00264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600244600264801274A00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00274902264801264801274A
+ 00284C002B4F022C50042E56042D55032B52022C51012C51012C51012C52002C
+ 5200284C00284C00284C00294D01284C002A4E012C50032D5104315D00335F02
+ 3460033766002F5B00345C1593BF8A6C95682F59022A55002F56012C5500254C
+ 002749022B4F03294F03284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274F01284F012A4E02294D01284C002A4E012D53012E55002C6601326902
+ ADCCAF477631437916428627397A2547782E3B7925498A45458B44A4E7C24CA2
+ 544689464BA454399145489954448A44498947527C476F956BB1D3AEDCF8E5F3
+ FFFEFFF6FFFEFFFDE2ECE6B6DAC46A966746883730802537821A387717356C09
+ 326307326B09346B08356B0A3774193C8628477632B5CFB895BB973877172B64
+ 023660012B5900254B00264A00284C00234901265100315D00305A0230620A4D
+ 791EB4CEB7E0F0DFCDEFD0B8DAC2CAE4D6EFFFF4F9FFFEFFFEFEDAF8E584A977
+ 47772F3A7B25306B09285B012E54022C4E01284C00284C00284C00284C00284C
+ 00284C00284C00284C00274800264B012A53002D59003965023362002F5B0241
+ 6C15D9F6DC527C47426C1544831D377209346A09346B163B7A24437731578C53
+ A7C8ADEBFCF1F8FFFFF1FFF3C5E0BF6C956846821D4379182E7207397A253886
+ 28497532A9D6AB386A162B6401336800356A032D5900295900355F07325E052A
+ 5504275B01316200326A012C6502245B00386A16588E5388AA92B6CEB6B9D6BD
+ 436D163D6A033A6301345F04265500284C002B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00294D01294D01284C00284C00284C00284C00284C0028
+ 4C00294B05294B05284A03264801264801264801244600244600244600244600
+ 244600244600244600244600244600244600284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274A00274A00264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440228440228440228440228440228440228440228440228
+ 4402244300244300244300244300244300244300244300244300254401244300
+ 2443002342002443002443002443002342002443002443002342002443002442
+ 01244201244201234100264000264000264000253E00253E00243D00243D0024
+ 3D00254000254000253E00253E00243D00243D00233E00243F00264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600244600264801274A00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274B00274902264802264801274A
+ 002A4E022F5307305309315C012F5A002E58002D57002F56012E55002E55002E
+ 55002A4E02294D01294D01284C00284C002A4E012D51052D51053461003A6B01
+ 2C65023D6B0139650C5B8645D6F6DD3B582B31640A305D002B5900295300244B
+ 00274B00284F01274902284C00284C00284C00284C00284C00284C00284C0028
+ 4C00285100274E002A4E02294D01284C002A4E012E54022F5601336101315D00
+ 879D846C966739761642791647862843862B47862A509747498A45AFE3BB65B1
+ 6A489A51379F403C9E44489954529A6586D5A2CCF1C9F3FDECFBFFF9FEFAFFFF
+ F5FDB2E3BD78B88472B1798DC7975786473B7927427719326A013B6B01376502
+ 3361013362003762013D63093A6D0B377618457731BAD9C486AA86396C0A3B6A
+ 03305C012A52002B4D06274902294F032951002C5B003462092C5902426E1567
+ A257F5FFF36A95682276283B90453C914765A675C9DACDFEFDFFF7FFFEC1E7CB
+ 6D95653B78282E71081C63032E5A002D4F02284C00284C00284C00284C00284C
+ 00284C00284C00284C00264D002C4F052F56012C5A013864013C6400416F1665
+ A357A4C8AA43782F4F7A1F44831B3983192D74173C852946883779AC86D8F7DA
+ F6FEFEF4F6FEECF3F09CB4964A78302D80243C6D0B3877173573073A77153975
+ 17467830B2D3B0436C17346B083169022F5B00225902275901255900265A0031
+ 5B033460012B5900285A02326307306309356A09397209388218CAE4D69EB497
+ 406E153B6B01366302345E062654022C52062B50002A4E01294D00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C002A4E02294D01294D01284C00284C00284C00284C0028
+ 4C00284A04294B05284A04264801264801264801244600244600264802254701
+ 244600244600244600244600244600244600284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274A00274902264801264801264801
+ 2648012648012446002446002446002446002844022844022844022844022844
+ 0228440228440228440224430024430024430024430024430024430024430024
+ 4300244201244201244201244201244201244201244201244201244201244201
+ 2442012442012442012341002442012442012442012442012442012442012341
+ 00234100234100224000254000254000243F00233E00233E00233E00243F0023
+ 3D01243F00254000243D00243D00243D00243D00233E00233E00264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00274A00284C00
+ 284C00284C00294D01294D01284C00274A00254603274902264801244901284F
+ 002F5503385B013B640239630C2C740431670333630A2063022E6601345A002A
+ 5400274D01284F01264D00204B02264D022B5100305400355B03427309366502
+ 3671082F7308376B17D8E9DB879E822C7108386400335C002D5202294B042A4C
+ 06274C04254C01234D00214E00274E022C4D03294805294803314C032C510927
+ 4C062D4E042C4F002852002F55032B4900294F032C51012B59002D58012C5107
+ 49772EB3D2B387B489527B4847772F45772F4888363B8935489954B2E4BA76A6
+ 7653975678B07BA7C8B3E7ECF5FFF5FDFFFFFFF5FFFEF1FFFBD5F6DB8BC69965
+ A45446984646974883BE929FCFB746831B407819376B17316902305C012E5800
+ 2C58002A5700355B093362063B6C0A38751A4D8526B7CDBB9DB397356C093A6B
+ 03335C012D53012956002E4E002945032C52062D56012F5B003D6B01396409AF
+ CEAD8BC7973B792537832B38852A4889443A9246469A528FE1ACFBFFFFF4F6FE
+ AAC8B54689442E75183D6B012C5200265108295000264D00254B00264C00294D
+ 01294C02274902254A022B4705285100305C012F4D01335C012A72072D6911C7
+ D9CC76B07954863853853743862B3984283A9246478C53B3D2B1FDEFFBFFFBFC
+ ECFCF5B3E5BB48A3542E7F284379183169043361013A6B033A6B01376B0D3973
+ 07366A17E0F0DF3965003462023361012E58002A52002950022A4E012B4F022C
+ 51012D59002A520432520B3059082E66013B6C04396B17598548F2FFFE5B8647
+ 437918326902275B01305C013054002F4903284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00274A00264900274A00274A00244600244600
+ 244600244600244600244600244600244600264801264802284A03294C022A4E
+ 02284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00274B00274A00264801264801264802274A00264801
+ 2648012446002648012648012547012446002544012443002544012743012743
+ 0128440228440227430126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 264000264000264000264000264000264000243F00243F00243F00243F00243F
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00254001
+ 263F01264000264000264000253F002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00284C00284C00
+ 284C00284C00284C00284C00274A00264900224700264C04234800224C002A52
+ 00375C00376403416903437A17367206356C1781B771396A18316904385C0233
+ 5C012B5000285100274E00254C00254C002A5401385B003E5D023D6B014E791E
+ 3B771946862686B489E2F0DE517C432B6402296402335C012A5401294D012F4B
+ 05274903274D01215102214D002C52062A4C00324D033352072C4F002E510128
+ 55003054072D59002C55002B5500284B01284D032850022952002D5801336200
+ 21510343782E79A269C9F3CAD1EFD29AB9A496BB9992BB96A3BAABE1ECE4D5EA
+ DBE7FBE8EBFDF6FBFFFFF0FEF8F2FFFAECFDF2B8D7BA78A77656854648873746
+ 923A46913B44883589B487B2CDB9437A17356C092F62063461002E58002B5500
+ 2B52002D55032A5700305C01346A093F73074F7B1EB8D9B789AA873269023B6C
+ 00315D002F5503275000294D012948032C5101325500305C0131690238630CB4
+ CDB977A5763B792739821B3777143D78273B84283B8936559B66E3F8EFFCFDFF
+ E5FBE866A4683985273169043362002B5502284F00284F01264C00274D01274D
+ 01274C02264B01254A002B4803264C002E5A013A640C446B152A7207678F55F4
+ FEED598647518636468837479A453B9045588C56CEF0D2F5FFF3FEFAFFF5FAF9
+ A6C6AD578B553A86283176152A6601346001315D04386401326A00346902396A
+ 0249772EE8FCE93A6B013361013361012F59012A5101284F01284C002A4E012B
+ 50002E55002B51002C5107356005336900326804356B1865A367E5F6F2527B48
+ 407409346901325B002D58012F5601324D03284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00274A00274A00274A00274A00244600244600
+ 244600244600244600244600244600244600264801264802284A03294C02294D
+ 01284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00274B00274A00264801264801264802274A00254700
+ 2547012446002648012648012547012446002443002443002844022743012844
+ 0228440228440227430126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 264000264000264000264000264000264000243F00243F00243F00243F00243F
+ 00243F00243F00233E00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00243F00
+ 263F012640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00294D01284C00
+ 284C00284C00284C00274A00274A00264801244502274700264704264B013254
+ 00335D06426A05437A174485293B79256E9567F3FFED77A5763A6B153A6B0336
+ 5F032C56002A52002A4E02284D032C4F00305400345E073C650A437A1744831B
+ 468836538B56D1F2D0A7C7B44678322E7207346902315D022E5402284D052A4C
+ 06284B01264D02234D00234D002850022847022D51003155012B540034630131
+ 62002F5B00356104315D002D5900254B002B4B0A2B4C022951002953002D5900
+ 34600334600132640658854687B58ADAF8E5FAFEF3F3FFF3ECF8F8FFF9FFFDF8
+ FFF5FFF9F0FFF7ECF3F0ADD4AE74B179588C5646792F4775333A86282F7F242E
+ 8027448627387B2682B687B6DAC43774062E6601345E072E5800265401295002
+ 294D002C52002E5402305D003469023C6D0B3A7618CAE3D587AC843B6C0A3469
+ 023059002D5900294F03284F002847022C4F002F5902315C013068013C6C0CB8
+ D7BC568D56396A183273063B6C0A3A7715387618398329478B4498B9A4F9FFF9
+ FDFEFC9AC9A3398A353076192F6A02315503295000295002274D01264C00264C
+ 00264C00274C02254A002C4B062F5C00315C013F6806446F14356B1895BE8BE0
+ F0DE5086395098453D91493790466AA578D3F6DBFAFFFAFFFFFFECFFF0B0CCAF
+ 568D54397A242C761834690B3462002E5A012E50032E5A012C65022C65023573
+ 09527B48ECFDF23C6B043361013361012E5A01295000274E00284C00284C0029
+ 4D002750002B4C01274E00325A022C6503316703467733AAD5AAC7DACB487634
+ 357307326804315C012B55002A5000304D04284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00274A00274A00264900264801264801
+ 264801264801264801264801264801264801264801264801274902284B01284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00274A00274A00264801264801264801274902254700
+ 2446002446002648012547002446002446002443002743012844022743012844
+ 0228440227430125440126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000253E00253E00
+ 253E00253E00253E00253E00253E00253E00233E00233E00233E00233E00233E
+ 00233E00233E00233E00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00243F00233E00
+ 253E002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C002A4E01294D00
+ 284C00284C00284B01274A00264801264801214602274C002A4B00294E00375A
+ 0333630A426D164D7A1D3D912B568546B2CDB9FFFEFFCEF2CE45772F417A1732
+ 69022D59002A54002852002A4F002E52002E5A013B64093A6D0C4D78213C8626
+ 458D519BBBA2F6FEFD9BBC9947883338831B346A092F6103295600274E00294F
+ 03254B03294D01274D01285205244B00274E002952012953003462023D6A032C
+ 6601396502306900316902335B03284F032E5003204C05285002284A042A4F05
+ 365D07255A00286503326B08366A1645772F6E956786B5879BC8A1E0EBE8B2CD
+ B97AB68668A369517949468836478628397517306B09346C072D64012D720938
+ 811A3B79253A782489AA87B5CBB82F6A02346001315B062D5702265300284F00
+ 294D002750002C5500315D0432690242730B397517E3FFF089AA883C6A0A3169
+ 022956002D56052951002D4D00254A06294E002D59002E5D002A66023B6C0AB9
+ D7BA6C96673976143875073F6A033665002C650237821A398A33539B66DBF7E4
+ FEFFFBDEF1DE448A443986252B66003956002B5202295002274E00264C00274D
+ 01274E00274D01264B012A4B01315C01315C013C6C02416D14527C47C8F2C9A7
+ BBA84DA4543992434BA45558AA75DAF8E5FDFEFCF1F4F2FEFAFF98D5A9589857
+ 3D7925437918306803335C01345E06294902284D092B5500356201326A013573
+ 07639254EDFEF13864003362003361012D5900285100274D01264C00284C0029
+ 4D002B4D00284F012251022A66022B6401326307578745E6FDE79BB9A6387A21
+ 3573073169022D5801284F002A4E012A5103284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00274A00274A00264801264801
+ 264801264801264801264801264801264801264801264801264801284B01274B
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00274A00274A00264801264801264801264801244600
+ 2446002446002547002547002446002446002844022844022844022743012844
+ 0228440224430024430026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000253E00253E00
+ 253E00253E00253E00253E00253E00253E00243F00243F00243F00243F00243F
+ 00233E00233E00233E00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00243F00233E00
+ 253E00263F012640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C002A4E01294D00
+ 294D01284C00274A00274A002648012648012348002949022D4D00315600355F
+ 083B64093877174786283A933694BB8DFDFFFFF6F6FCF1FFF886B48939852739
+ 751733630A2659012952012C52003054002D5B02396C043F7307508528469748
+ 549B63E4F7F4FBFFFFD0EFD2509747498F2B3878153564082E59002A52002E50
+ 03284C00274C02264E002D5100204B022F5B00335B03335C0132630732630750
+ 8327407A15356B0A3D6B003361012956002A4D03264B012B4F02304C10264A04
+ 2B4F032751003362002965013469023973073B7925479946438D51BAE6C765A6
+ 753789363A902C398428367108336C09306801326902346001336101316B0035
+ 6D083A771737792789AA87B6CCB92E65023B6402315A05315B03285200264D01
+ 2649002A4E012C5700315C01306A0B4475074F7B1EF0FEFC88AA853A6C0E3268
+ 042A55042D5406285100284F00294A072750002F5901325B002A6602396C0AAE
+ CDAE85A97B397A25427408386203305C032D65002C7207397517399046B9D8BB
+ FFFAF9FFFFFB77A5763B8936346804405C032B5202284F00274E00254D00264E
+ 00284F01274E00274D012750002B55003069004079163B79277AA16AE4FEF077
+ AD823B9E4248A96657A766D6F5DAFFFCF8FFFBFFF4FEFEB4CDB94499453B8935
+ 2F76162E65023460012E5A012A52002B4C022B4D062E5500316003356A0C4074
+ 09629153EEFEFD326A0B3461003362002D5900275000264C00274B00284C0028
+ 4F01254A062E5604245A013469012864003A6B1977A16CF3FFF977A5773A7717
+ 3973073462022951032650022C4B00264C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00264801264801
+ 264801264801264801264801264801264801264801264802254700274A00274B
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00274A00274902264801264801264801264801244600
+ 2446002446002446002446002446002446002844022844022844022743012844
+ 0225440124430024430026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000233E00233E00
+ 233E00233E00233E00233E00233E00233E00243F00243F00243F00243F00243F
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00233E00
+ 243D00253E002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00294D00294D01
+ 284C00274A00274A00274A00274A00274A00274902284C002B50003859043665
+ 003B6B0B377616478527558C55D8F7DCF0FFF9E2F7EFF7FFF8D5F5DC458B4539
+ 7A24346A092E5D002956002F5601385B013361013E6B0E43771944902B4B8848
+ 9DD0B5F1FFFEF4F9F7F3FEF486B58746883744831D3D6C0A305C032E55002D50
+ 00264C00284C00254C012A4C002950002D59002A6601326A0B386A16457731A7
+ CA926E946A3B77293E6D0A3169022E5800284F00254A00254C01234A002B5100
+ 2B50062B5105254F02265901346B08336801336C0A368836457632E7FCE668A3
+ 693081243A801B2A72082E6601325F02305D002E55003057023A5A013561043A
+ 6301356C094F7A1F83AA76B4D9C53467053A6B03345A082E5A01295103274D01
+ 284B012C4D022F5300335C00386D0C437817387826EDFFFD89AA8F346B083268
+ 04345909325A08264E002850022449032850003158022B59003168013C6D0B99
+ BA98A8D6AB4776323B6C0A396500326100326805306B02427817378A3586B489
+ FAFFFDFFFDFFB2D3B02B87342C76164268082D54042A5101295000274E00284F
+ 01295000284F00284E02295600325A023A6B03387618557B47B4CEB7E1FFF252
+ 9A6636A74F55B06BB4E5C5FFFFFAFFFAFFFEF9F8D9F6DC468D5439842838821C
+ 326A012D59002D59002C54022B4E002C51072C4B062D56013260003168014474
+ 0A6E9666F3FFFF4B7A1D3663023461002E5A01285100264C00284C00284C0028
+ 4F012B4F03325400275B01266400326902518538B2D2AFF5FEFB538B56397818
+ 3873033361012950042A4E01285002254D00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00264801264801
+ 264801264801264801264801264801264801264801264802264801274A00274B
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00274A00274A00264801254700254700254701264801244600
+ 2446002446002446002446002446002345002844022844022844022844022844
+ 02244300244300244201243D00243D00243D00243D00243D00243D00243D0024
+ 3D00243D00243D00243D00243D00243D00243D00243D00243D00233E00233E00
+ 233E00233E00233E00233E00233E00233E00233E00233E00233E00233E00243F
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00233E00
+ 243D00253E00263F012640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00294D01284C00
+ 274B00274A00274A00274A00274A00274A00244A022D4E032E55003864014169
+ 033C6D0B3A782646883696BC98EDFEF3B4D9C5AFE4BDF8FDEEF9FEFF6DAC8037
+ 79273A72093365072D58012F5601375B0139660043730946831B39922B6B9566
+ EEFFFCE5F6F2E2F0DEFEFFFAC5E6CB458D514486273A76183363032D57002B53
+ 01294D00254A002B4E042E4E013054002E580336690143791648792F89A986E3
+ FCE8B9D6BC6491524278173A69023162002A5401285200244B002E5200234C01
+ 254B032D54042A5004285002205002355F07396D093E792949772FF3FEEA6A95
+ 68346B142D72093962003163002D5C002F54042D51002F50002D5700305C0138
+ 6400316A0842781787B688D6E9DA3B6C043269022E5505295901295103264E00
+ 294D01274F01325602375F073D6C0A427A15377927EBFFFA9EB6983C6B093B6A
+ 03325A08305604295201284F01264C042953002D5900245A0034690232690C88
+ 9F83E6FDE7578648426D163B6A0D33630A2B66002B6401437A173A933665A268
+ F5FFFFFFFEFFE3FDE5498B443080253765022E55052C5402295000274D01274E
+ 00295000285100285002295600345D083E6D0A3975176E9568E4FDF9BCE8D14A
+ A35454B6748BC896EEFFF3FCFEFEFDFFFFDCF8E567A3663A913942841A2B6500
+ 275A02335E072D5000254B002A4B00254D00324D032E5500386401326A014074
+ 086C9568E9FFFA5986473A66033461002E5A01295201274E00284C00284C0027
+ 4E002F50052D5900275A002C65023878156F9367E6FCE9C6E6D54A7732397106
+ 3469022B59002E4E07284F03284C001F4D00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00264801264801
+ 264801264801264801264801264801264801264801264802264802274902274A
+ 00274B00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00294D01274A00274A00264801244600244600254701264801244600
+ 2446002446002446002446002446002344012743012844022844022844022743
+ 01244300244201244201243F00243F00243F00243F00243F00243F00243F0024
+ 3F00243F00243F00243F00243F00243F00243F00243F00243F00233E00233E00
+ 233E00233E00233E00233E00233E00233E00233E00233E00233E00233E00233E
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00233E00
+ 243D00243D00253E002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264801264801264801274A00274A00274A00284C00284C00284C00274B00
+ 264900274A00274A00274A00274B00284C00264B012C4C002F56013A64004273
+ 0936751738852944923AE6F7F3F3FFF884CBA37BB886FAFEF2F9FCFFB9E7D147
+ 8A45377717366B0A305C01385A03405C023D690642730B44841A3D902EA4C8AA
+ F2FFFFB2CDB9D3E6CDFDF8F9E9FEFB68BA8548902C4379183263072E5A012A52
+ 00274D012949022B4D07304E033A5E042C65023E7A1646821D629152B6DAC4EE
+ FEFDE2FDF977A6755084263E730B316902325D022E55002A4B012C47052C4E08
+ 284C00295100204D002B59001F4D00346307316902346A09467830F4FFEB6E94
+ 6A376A1A346902396502275804215200264D00264906264B032C50032D590029
+ 650037740638761897BF88E6FEF23E7409316A01305A07315D00245108254E03
+ 274A002C4D022E55003361013A6D0C437A173A7826F0FFFBA4C7AC4278173A6D
+ 0B2B52042851002E5505275100264C04275502315B03265B003B6B01346B086C
+ 9667F3FFF977A2694F8427396C153463072B64022F6A023D6B0B378428488C55
+ E2EDE3FEFDFFF3FEF467A16A3B89353D6C0A2D54042D5503295000284E02284F
+ 01284F00285200274F01245A003A640C427916478F2F87B688F1FFFD98B9A453
+ C47468BA79D8F8E5FCFEFFFFFAFFF2FFFD8BC896458B4538811A326902325E01
+ 2B59002C51072B4C01294D01294F03284E02304E032E5A003764033D6C09417A
+ 186B9467F3F8FF6291523965023461002E5A01295201274E00284C00284C0027
+ 4E002E4E002D59002F6A022E751544852984A977F6FFF2A5BAAB397A252A7305
+ 2C66012D59002D4D06254A06244900225102284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00264801264801
+ 264801264801264801264801264801264801264801264802274903274902274A
+ 00274A00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00264900274902264801244600244600244600264801254701
+ 2446002446002446002446002145002144012844022844022844022844022743
+ 01244300244201224000233E00233E00233E00233E00233E00233E00233E0023
+ 3E00233E00233E00233E00233E00233E00233E00233E00233E00243F00243F00
+ 243F00243F00243F00243F00243F00243F00233E00233E00233E00243F00243F
+ 00243F00243F00243F00253E00253E00253E00253E00253E00253E00253E0025
+ 3E00253E00253E00253E00253E00253E00253E00253E00253E00233E00233E00
+ 253E00243D00243D00253F002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000234401284A04244600264801274903214600264B01274B002E4E07284B01
+ 284B01285000285000274902264801284906304C102956003B64023B64094E7B
+ 1E2E7515477631A1BBA9FDF5FFC9F2D749B87446B774E8FCE9FFF8FBEDFFF26C
+ 95683A87263976162062033E5D0240690730720840791742831D578B55E8FBEC
+ FDFEFA65BC7A6CC996FBFEFFF4FFEBD2E5CC3A91474686263964032B65002855
+ 002D49033253091E4C002E55002F5B002E720738811B50964984B587F3FEF4FF
+ FEFDFFF9FFB9E7D1488C5339821B3B6B012D5B09225B00245200284F00274E00
+ 284C00274E002750002B51002855002E59022D65002E6502397616F0FFF96E94
+ 6A3169043169022E5A012956002A53002A4E01274A00274A00265100315B0332
+ 69023773073B7828C6D7CCFFFFFB386A16326B08345E072C55042A5300274D01
+ 2A4B08274A002B58012E58003B6B0B4F7921477632FFFEF9C7DACB3775173469
+ 022959002A5C04334D11244C04284C00284C002B52072D59003A640042781747
+ 8A45FFFBFFCFF1D32E88353876183673052A6503326804416806508426488E52
+ A6D7B7EEF9F7FEFEFE98C8A44689462E7518326A01245A00275000294B042A4C
+ 05274D01224C00245902346001326C143B7927458B44E1F1E0F5FEF453C37554
+ B572C9E3D5F3FCF9FFF7FFFBFFFFB7E6C5489A523789362E7108345F042E5A01
+ 2A53002950002850022851002950002750002A4E02295600265E0D3A640C4279
+ 16629152FCFDF4568D54396D013360033058002654072A50042A4B012B51002B
+ 50002A5406375B0134670533821A527C45E9EAF4FBFEFC78A36A387717326902
+ 305C012C55002A4B01264A04284E02295000274B00294D01294D00284C00284B
+ 01284B01294C022A4E02244901294C022C4E012A4E01284C00284C002A4E022C
+ 5003274D012A4F002B4F02294D01274E00264D00294D002D5100274B00284C00
+ 2A4E012A4E01284C00284C00274D01274E00284F00234901264D01264D022851
+ 002A5200264C00274D01284906284A03284A042849062A4C06274A00274A0027
+ 4D01284C00284C00284C00284B01274A00264900264B01274C02294E00294D01
+ 2A4E022B4F02284C00274A00274A00294D01284C00274A002A4D03274B00274A
+ 002B4F03274A00284C00284B01294D012A4D032C5003294D01294D01284A0325
+ 4701284C00294D01284C00284B01284C00284C00294D01284C002950002A5200
+ 274E00284F00274D01244901264D00274902254A002A4E02264A042648012648
+ 01284906294D01264D00274E00274E00274E00274E00274E00274E00274E0027
+ 4E00264C00284C00284B01264C00264C00284B01284C00264C00284C00274D01
+ 284B01284A03284801284A04294B05284D05284C00274A00264900274B00284B
+ 01284A03284A04264801284C002C50042B4F02284C00274B00294D002C500327
+ 4B002B4D07284A04284A04284A03264801264801264801264802284605274601
+ 2746032443002645022547002648022043002742022742022641012842022640
+ 00264000264000253F00253E04253E04253E04253E04253E04253E04253E0425
+ 3E04243F00243F00254000254000254000243F00233E00233E00253E00263F01
+ 264000254000254000243F00243F00233E00263F01274002263F01253E00253E
+ 00253E00253E00253E00233E00253E00264000264000264000264000253E0023
+ 3E00254000254000254000254000254000254000254000254000253E00243F00
+ 233E00243E02243E02243F00254001263F012640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284A042B4D072648022A4904284A03234800274902264801244600264801
+ 264B01264D00264C00254A00254603224201324D033162003A6302426D164484
+ 1A38902C498A45E2EFDFFAFFFF9CD6A637B46545B567A6D8B6FCFFFAF5FFF8B0
+ CCAE46863A3B7927296713426A044268042D751549862B45842699BBA3FEFEF2
+ D7EADB57B06B53C375D9F7E4FCFEF8F2FFF465B16A45893443821C356A032E58
+ 002D4A01264C0028560430540032690238831B478E2D539756C7E6C9F4FDFFFE
+ FEFEFDFEFCEDFFEF69A575449338427408345F042F5902315600274E02254C00
+ 274C02284D05274D052A4E022A5302325A082F6A02316801447A17F9FFFA889D
+ 843B6C00326902315E012F510A284F042A4C052649062D4D002F5600315C012D
+ 6500377307448736C6DBCCFDFFF93B7828387408326000286602295000254A00
+ 284A03284B013562013161013B6A0D4E7B1E408727FEFFFDB9D6BC376B173473
+ 052B6401275905284C06254D0030540239630B1F4E023D6C0A3A6B0342841B49
+ 8A45DBE2E5EDFEF377A7733B79253978183A72073260003F6A0144831B479947
+ 97C7A3FDFEFCFFFCFFC5E0BE4A8C442F8023447A173263072E5A002C4E012B4C
+ 012C50042D50002953003A6B032E741746883777A675FDFFF7E5FBE94FC47568
+ B988E6FFF0F9FFFEFFFBFFEEFFF279B78946923A2E77152B64012F54042A5103
+ 274D01274D01274E00294D00264C00254A002A50002B58012C69113B6C0A4683
+ 1B579756FFFEF6558C553D6A033361012E5B00285500284E02224B002B4C0132
+ 4D032D5900345E00437B1639852787AB87F7FBFCE5FBE8529747397517346804
+ 305C012E58012E4F042B4D07284F042952012F55032C51012A4E01294D00294E
+ 002B4F022B4F022A4E02254A00284C00294D00294D00274E00284C002A4E012C
+ 5003274D012A4E022A4E01294D00284B01284C00284C002A4B01294C02284C00
+ 284C00284B01284B01284C002A4E022C50032C5504275100285002254C012850
+ 022D5406274F012750002B4D06294B042A4D032C50042D5104284C00274A0028
+ 4B013054082D51052A4E01294D002A4E012C50032C50032A4E012B4F02294D00
+ 284C002B4F022B4F02294D01294D012C50042E5505274B00284F01264C002A4F
+ 002B5305294A00274E00274E00274E00264D00264D00274C02264C00264D0027
+ 4E002C51012A50002A4E01294E00294D012A4E012D4F022F5005264B012A4F05
+ 284C002B4F032B4E04294D012C4F05294C02284F002951002C5004294D01284C
+ 002D4E032850002B4F02284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284B01284C00284C00284B01284C00284C00274902284B01
+ 2A51032B4F02274D01274A00274902264802274A002648012648022648012649
+ 00264801264802264802274B00284B012A4E01294D00284C002A4E012A4E0126
+ 4900264801264801264802264802244600254700264801264801284704274603
+ 2746012442012645002547012547002144012640002742022540002640002640
+ 00264000264000264000243D00243D00243D00243D00243D00243D00243D0024
+ 3D00253E00243D00264000264000253E00243D00233E00243F00253E00253E00
+ 253E00253E00263F01253E00253E00253E00243F00243F00243F00233E00233E
+ 00233E00233E00233E00243F00243D00253E00253F00253F00253E00243D0024
+ 3F00254000254000254000254000254000254000254000254000253F00253E00
+ 233E00233E00243F00233E00253E002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244901254A02254603264802264801234800264B012446002246002C5206
+ 325A082E55072B52042C5107294E042648013A5303355B01386B034279163675
+ 173B852B76B079F8FFFAF3FDEC65BA7C37A65046A8666AAC82F0FEF2FFF9FAE1
+ FCE864A468449846397A25377616437A17377927398837468836DAF9E4FFFDFF
+ 8BC69948A8623BB26793CEAFFFFFFFFFFCFFA8D7B6478A473380252B6401385B
+ 013A54002851002A5401315503426C15438827478A4577AC84F2FEF8FFFFFEFF
+ FDFFD5EADBF1FFFDB4D9C55796582D7614356A0C3B53003B5400274E00244B00
+ 274A00214C03264A04254C012C5101305505306803357307407917FCFEF299AD
+ 963168012A6503325F022C51072C53082A4C062E4F04294F03315501305B002D
+ 6500458319478A45C7D8CBF4FFF43A78243773072E64002062032751042C4D02
+ 2E4E002C51013A6B033169023C6E0A508327388726FEFCF4C5E0BF2D74173469
+ 022C6601265B002A4E012A54013965023664012965003C6D0B3D730844831B38
+ 8934A5BBA9F6FFFAC7D8CD547A482C82242D7106326A013B6A0D37811B3C902A
+ 78B17EFBFFF9FBFFFFF5FEEA55965836933840862925600B2952012C4B002D50
+ 002E54023155012C56033C6D0B308025539448B3D2B1FFFEFEB5E8C347B672A8
+ E6C2FAFEFFFEFDFFF6FFFFC7E6CB468E52378428356B083361012A53022B5000
+ 295000274F01264D00264E00264D01294C02295306335C00397616406E154683
+ 1B66A369FAFDF4689668326804316902336000285800275103274D012D4C0731
+ 5208305C03336A0345811C46913BC6DEBEFFFFFFB7D5BC2076283876182C6502
+ 2559002E5500254C00264802274D01285100345A082E54022A4E01284F002A51
+ 012C53052A5101264C00284F012B50002C52002A52002A51012A51012C52002C
+ 5402274D012B4E042C4F05284B01294B042D51052D5104274B00294F03284E02
+ 274D01264C00264C00284E02294E042A4C052E5309284E02274E00254A022B4D
+ 063053092A4D03294F032B4F03284C002A4F002B52042C53052B5000294E0028
+ 4E023053092C4F052A4B01274A00294C02284D03284B01274A0030520B2C4F05
+ 2D4E042E4F052E4F052B4C01284B01294C02345E062950002951002B50002B55
+ 002E54022851002A5200284E022B50002B50002A4F00295100294D00274D0127
+ 4D01315B062D57022B5502295201295100284E02274E00274D012749022B4E04
+ 274B00294C02294C022648012B4D07284A032A53002C5500295000284C00284C
+ 002B51002E55002A5101284A04284A04284A04284A04284A04284A04284A0428
+ 4A042A4C00264D00264C00294D00294D00264C00264D002A4C00284C002A5200
+ 2D55032A53022A4F00254B00264801274B00264801254700274A00274A002648
+ 01254701254700264900264900274A00284C00284C00284C00294D00284C0027
+ 4B00274A00274A00264801264801264801274902244900254A00274603284704
+ 2746032645022746012648012547002446002741012641012641012640002640
+ 00264000264000253F0025400025400025400025400025400025400025400025
+ 4000253E00243D00264000264000243D00243D00253E00253E00253E00243D00
+ 243D00253F00264000253E00243D00253E00253E00243D00243D00243D00253E
+ 00264000264000264000243F00253E00253E00264000264000253E00253E0024
+ 3F00254000254000254000254000254000254000254000254000264000264000
+ 253E00253E00253E00253E00253F002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000234A00295000274D012A4F002951002950002C55002C52002950002E5801
+ 3159072E58002D57002D56012B54002A52003C54003C650A4379163979274688
+ 3759854AD2E6C9FCFFFBD1E5CE55996237A85145A86256A975CAF1D7FEFEFEFB
+ FFFF8FC697479B534776313977194588335486383B904685B787F4FEFEF4F9FA
+ 509B6347AA6445B67355BA87F9FAFEFFFBFFE4FDE96AAD803991453979273057
+ 022D51002C56003B6409426C15397A25509545558B56D1F0D3FDFFFFFEFEFEF8
+ FBFF65BF94E6FFF1EBF1F078AC873B7927367305355B01385708315C012C5300
+ 2A4F002A52002953002C55002B58012B5A003269023D7925477631EBFFF29AAB
+ 963063072B64013364082956002956003054002D50002651002B5400345E0633
+ 6B1851953C498A45C6DACEF0FEFD45883737821A3A76182063002E5A012B5400
+ 2A53003159013A6A042C6502336C0A518636558C53F8FEF9C9DACD3679242E76
+ 16326B092F65022B5500346001386401305C003E792838781539792752954A3C
+ 91467BBF96F3FFF9FFFAFF9ABB993B88372C7616326B0839691A3D912B368934
+ 4F9B65F5FFF3FEFAFFFBFFF97BAC86389246529747245E0D265100355B033A5A
+ 01315501315A09346A17436E133A8F2D569759EDF2F0F5F8FF8ADCB268BA85EC
+ FEFDFFFAFFF5F6FAECFFFB78AD853887362A7207336C09385A032950022A5200
+ 2B5500295300284F00284F002750002852002D54002E5A013A7717436D164278
+ 17579853FFFEF688AA852C7305326B092C65032B55002950002B5204254D002B
+ 5204416D1438831946923A77B17AEBFFF2F8FFFC96BB9B3081243776161F6201
+ 2B5500295600264C00254A022B5204315C01315D002D56012A52002A52002C56
+ 002C56002C52002B4F022C55002C56002F56002E58012D58012E58012D57002E
+ 58002950002850002950002A4E01284D002A52002B5204254A002F56012C5200
+ 2C51012B50002C52003054003155013155012E5A002B52022A5300274E002D57
+ 00335D062D57002E5A012B4F02274E002750002D56012B54002953002A54012A
+ 52003054072B5204284F012950002C52002F53012C5200295000325B06305702
+ 2F56012F56012E54022B51002B50002A4F0039630B284F00274D012850002F55
+ 032E57022B50002C55002C56002E54023057022F56012F56012C52002C530028
+ 4F00315C01315D002D59002B56002A5200284F00284F00284F01284F002C5500
+ 2B50002C51012C51012A4E022D51042C50032E5A012C5600295100284C00284C
+ 002A52002E55002C55002C52002C52002C52002C52002C52002C52002C52002C
+ 52002B4D00274E002A4E012C51012C51012A4E01274E002B4D002850002D5601
+ 2F5B02335C012C54022C5101284F002B4F03274A00284C002A4E01294D01274A
+ 00264801264900274B00284B01284C00284C00284C00284C002C50032B4F022A
+ 4E02274E00294D00284C00284C00284C00284C00284C00294D00274603284702
+ 284704284702284A04294C02274A00274A002845002744002746012744002845
+ 0027440029450327430128440228440228440228440228440228440228440228
+ 4402243D00243D00253F00264000243F00243F00254000254000254000254000
+ 254000264000274101264000253F00243D002640002640002640002640002640
+ 0026400026400028400025400025400025400026410126410125400025400025
+ 4000264200264200264200264200264200264200264200264200264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002E5902336101335F00396403335F00305B00366401386401315B03315D00
+ 346001346100336000315B033462003B6A0436640B61903A56963C458B4467A8
+ 7794AC94F8FFFFFAFFFDA4C9A954A975539B6657A97455B989A0CFB5FFFEFAFF
+ FFFFC9F1D856A877488A4239893667A25768A468529A65D1EFD2FAFFFDB5CEBA
+ 3C92444AA35454B77346B773E1EEE6FFF9FFFFFFFEA5E5C249A7665096493A62
+ 0A345D083462023964035186364F964669B26986B587F5FFFFF5F6FAFAFFFFC8
+ E3D939C98E9ED9CAFAFFFFC8DACD488A432D74172C650229690F40730B336200
+ 315D02325F023462003764033B6304396502336A07478A45598A56ECFFFBA6C9
+ B54688374493384589343972093672063C6C023A6B013664013A650A4D791E53
+ 863654973B4A8846C5DACBF2FEFE559C635195485786473979273168013B6C00
+ 3965023864003F7609326902396B175985487AB588FCFAFFC9E4D4488B464689
+ 34438936377616325A083B6C0A436D164D8834459139448A43659156A9D5AC53
+ 9C6456B987E5FBE8FEFAFFE1F7F265A36746893437761846883649A253519C64
+ 6AA676E2F6F1FFFAFFFFFFFFA6D6B9489954529747245E0D2B5500436D16426E
+ 13436C174E782065A35554863839913787BC95FEFAFFF1FFFD84DBAF9EDDB6F9
+ F9FFFEFAFFF7FAFFDDF8E4488E513984282C66013E6A0B405F04346003346100
+ 396502386302346202336003346001386302345E0631630B4485294D7A1D4682
+ 1D6C9667FDFEFAA5CAAA468837397A253B76143965083A640C38640B3162003B
+ 65004F8637519646519D63B7E5D2F8FDFEF7FFFE67A5753B9046468529396C0A
+ 336101345E072D510B284C063055053A640C2E5A012E5A012F5B002F59012E57
+ 022F5601305402315501315C01315C01325D02315C01305D00315D00305B0031
+ 5C01335F06335F0639630C39630C355F083964093964092F5B02345F04315B03
+ 315B03305B00305B00325D02345E06365D07346003335F00346100315D003765
+ 023A650A315C013361012A5200274E00284F002E59022E5902315B04345E062E
+ 5902305A02345F04356005345F04315B03315B03345E06365E06305C032D5900
+ 2E5800315C01346003315B03315B03345F04396409295100284F002C5600365D
+ 07345E062F5601305A022E5A00315B03335D06325A08315C012E55002A520028
+ 4F002C56002E58002E58002F5901315B03315D00315C01305B00315D00346001
+ 305B00315B03315C01315B03345F04315D00315C012F5B022E5500284F00284F
+ 002F5503305A02335D00315C01315C01315C01315C01315C01315C01315C0131
+ 5C012C5101294D002D50002D54042D54042D5000294D002C51012C54022D5900
+ 335B03315B033056002C56002F56012D58012B4F032D51052E52062C4F05294C
+ 02274A00274A00274A002C50042A4E02274B00274A00284C002C50032D51042C
+ 50042B52022A51012A51012B50002A4F002A4E01294D002A4E01254701274603
+ 2746012A49042A4E022C4F052A4E022A4E022A47022948052746032B47052A46
+ 042C48062A46042B47052C49002C49002C49002C49002C49002C49002C49002C
+ 4900243F002540012641012743012844022945032A46042945032945032A4604
+ 2945032844022743012641012540002540002746032746032847042746032645
+ 0227430126410125400027430128440228440228440228440228440228440227
+ 4301284402284402284402284402284402284402284402284402264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000315C013765023965023E6A05396403315D003965023A6400346100335F00
+ 3561043664013765023665003B6A034376074F7A1F57864756985755A76666A4
+ 74C6E5D6F7FAFEEBF7FB6DAD7F6AA676549A6558A76454B57268AD82F5FFF3FF
+ FDFEF2FFF778BE9649995648974665B26867A57579AC86F4FFF9FEFFFA87AB87
+ 3988373C8A3649984944B4669BD0B5FEFDFFFCFAFFD7F6DB559C64428B43245F
+ 0B2A5D053A62033D6A0352863965A05669BB86B7D9C1FFFEFFFFFBFFE4FEF178
+ BF943AC9926BBA89D7F8E3F3F9F87196682D761438811A368629407408386302
+ 3260003B64023562013965003A6B03356703326B09478B4465A367ECFFFCA2B9
+ AA488737498A453B79273875073973074275063E6B043765023B640947763262
+ 8F39509545588C57C9E6D6F6FEFE7AAC845597565586484677333A6B033D6C0A
+ 3A690D3765023D720A2F6A023C7929538C5598BC98F7FAFFC9E6D6458C534689
+ 465587393978283A640C316408508633639254589759578B56A7BBA8E2FFF076
+ B88443B667B2E4BAFAFFFEFBFFFFBAD7BD4B8A453B852748A3545AA976549A65
+ 67A575B9E6D3FEFEFEFEF6FDD6F7DC49A96367A3553A7A283B6B0B4E791E4D7B
+ 1B416D144A783065A35547975449A455BBE7D0FCFBFFE4FEF06BC895D9F8E3FD
+ FCFFFEF7FEECFDF29FCDBA3C91462D80242B64022D57002F56013B6B01396A00
+ 3A6B013B6B013B6B013B6A033C6B053D6C0A3864093B6B0B5085285385374286
+ 276F946CFFFEFAB5CEBA44894647893839792731640A335F00386401315D0032
+ 6902598B5568A36988B388F3FFFFF9FAFEC3E6CB488E523C89355585373A7618
+ 326B08375F072F4F082B4E043257013161012C55002F5901345E07345E07325A
+ 0831580A325A08325A08305C01315C01315C01315C01305D00315D00315C0131
+ 5C013361012D5900326000376502315D00315D00335F002E5A01366302346100
+ 346001346001346100366401386401386401386302366500346001315B033864
+ 013965022E58003561042F5601284F002B5202345A08335907345E0639650836
+ 5E06305C01346001386401396502346001336003376403396500336101305C01
+ 305D00346100376403346001346001376403335D052A51012C52002F5503335D
+ 05395E08325C05365E06305C01325B06345A08325A08345A082E54022B51002B
+ 4F022E5500305702305A02325A08345D08345D08325B06325A08336200366502
+ 305D00315D00305B002F5901346003305C00335D05335D062E54022A4F002E52
+ 05335808345E06315D00315C01315C01315C01315C01315C01315C01315C0131
+ 5C012D5202284F012E51012E55052E55052E5101284F012D52022E58002F5902
+ 2F59023055002F55033054002E5801315C052D51042F54042F53062E52062C50
+ 04284C00284C002649003054082B4F03274A00274A00284C00294D002B4F022C
+ 50042B52042B52022A51012B50002A4F002A4F002C4E012C4E01264802254701
+ 2648022B4B042E4F042C50042A4E022A4E022C47052B47052843032B47052A46
+ 042F4C072B47052C46062C47052C47052C47052C47052C47052C47052C47052C
+ 4705243F002540002642002844022A46042A46042B47052A4702294805294805
+ 2847042945032844022642002540002540002746032847022948032847042746
+ 0327430126410125400027430128440227430128450028450027430128440227
+ 4301284402284402284402284402284402284402284402284402264000264000
+ 264000253F00253F002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002E5402345B062E55003156002F56012C53002E55003054002C56002C5500
+ 2F56002E55002E56002E58003461003B6B05436D16426C17498B444DA35577A7
+ 77F1FCFAFFFEFDB6D7BC469846478A45468C4545903A4AA35454A868C2E6C8FF
+ FEFFF7FFFFB3DAC14899544AA35348A453549966B6CDB7FEFAFFF6FEED459853
+ 3B89363679243885294B985465BB7BFDFEF5FFFAFFF6FFFAAAD5AA57A7663991
+ 45366A16386401407506387826469B476CAC82DBF9E6FFF6FCFEFDFFB3E2BB46
+ B7733BB16852A763B3D4B1F8FEF9A3BAAB2274292C771542730B366500335B03
+ 315C013361012E58012D590039650232610032690251853879A877F2FFF797BB
+ A3367826397A252D74173169003A64053664013A630131600334620938761851
+ 8636478A45588D54D3E8D9F9FEFF73B378498A4549772F387618316003315C01
+ 315A092E5500336200275A00376B184787277AAC84FEFAFFCAE4D6478A473B79
+ 2539691730680142690730680153832A478A4757975666A468D4E8DBEFFFFD8D
+ C69942B56578BE96E5FFF1FFFBFDF7FFF87BAB87478B44469846489855389246
+ 529C6289C799F4FFFDFEF6FFF1FFF357A97552963F377717346A09417A174F7B
+ 1E51842843913A57A66749A45568B97AECFFFBFEF4FFA9E5C362C097F6FFFCFE
+ F9FFFFFEFAF1FEF667BB8557A7662D8024336A03264F00254C002B58012D5801
+ 2D58012D58012E5A012D59002D59002E59023054003362003C75184C791C4588
+ 276B9467FFFBFA98B9A42D86363B79253B79253161013462023A630129660041
+ 750A458C536AA578C7DFBFFEFDFFFAFFFE87B688388934377B282A68142C5B05
+ 2659002B5A002A51032B4E043159073462023054003055002F56002F56002D55
+ 032D54062C55042A53022D58012D56012E55002D57002E58002E58002D57002C
+ 5500315B032950002F5902345F042F56002E55002F59012C56002F59012D5900
+ 2D59002D59002D59002F59012E5800305A022B54002E5A002D59002851002D59
+ 002E5A00254D002D5801315A052A4D032B4F022E58012C56002F5503335A052C
+ 54023054002D57002D59002F59012F56013054022F56012D5801315C012F5901
+ 2F5901315B032E58012D56012D56012E58012F59022A52002C55002A51013155
+ 01325B063155012E58012F55033155013054002F56012F56012E52002B4D0029
+ 4D002F56012E55002E55002F56012F55032F56002D53012B51002F5902315B03
+ 2C54022C55002A5200284F012D56012A51012D55032E55002B52042A4E022C50
+ 042E54082F56012C54022C56002C56002C56002C56002C56002C56002C56002C
+ 56002C5101284F012E51012D54042D54042E5101284F012C51012E55002D5700
+ 2E55002A53002F56012B53012A51032B5204284F012B50002C51012C50032D51
+ 042A4E01284C00274A00305408294D01264900274902284C00274B00284C0029
+ 4D012B4F032B4F032A4E02284C00294D01294D01284C00284C00264801244600
+ 2648022B4C012D4E04294D01274902274A002C48022845002946012744002B49
+ 022B49022B490228440028440228440228440228440228440228440228440228
+ 4402254000264101264200274301274301284402284402274301254401254401
+ 2844022844022844022844022641012641012743012743012844022844022844
+ 0227430126410125400026410126420026420026420026420026420026420026
+ 4101264200264200264200264200264200264200264200264200264000264000
+ 264000253E00253E002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254A02264906234401264802284C00274E00284D03264801294C022E5107
+ 2E4E0D294A07264802264B012A53002B55002B65004E791E43862A3B923A8BC6
+ 99FFFFFBFDFEF486B58729942037720A377616308025478E2D489A528EC898FC
+ F6F7FFFDFFEDFFF245AB7444B46748A45344A965F6FFF4FEFAFFB2CCBA2E8224
+ 3B7A244F7A1F4587282D873439A552C5DACBFFFDFFFFFFF1B6D7BC458E504997
+ 573B79273A6B0346841A45902E3B904579B789ECFFFCFFFBFFFFFAF968A67613
+ A547478D513D92486B9566FEFFFBE5F6F2487732316C0A436A04315D002E5500
+ 325A08315B062950002A5302385D073765023D6A0343773184A977FBFFF49DB3
+ 962F68132B6713316902245206274B00264D0129510028520027570033630A3B
+ 7925548539517B44C9E6D6F7FEF963A368397927376B182063022F59012A5000
+ 264F04274E00335C012C650235740639821B78A26DFDFAF6C5E0BF3080232D75
+ 152A6913255B023A65004F842738782653963A52974798D6A8EAFFFDF2FFFDA9
+ D5AE47B66649AC748FCFACFFFDFFFDFAFFDBF8E1539C6446913B3A91393A9336
+ 4498466DAC84F4FEF8FFFBFDF5FFF96BAD8352973C478727397517426E154F79
+ 2145883746994449A45544B5658AD4A4EAFFFBFCFBFF88D4A48AD4A4FDFFFEFF
+ FEF9FDFFF3C8E5D63F925E4CA2542D74172B55002C5600265108275000295000
+ 274F01264D01274D01284F01285100284F00295300336200306309436C174486
+ 2768A366FEFDFF88AB91217527307415387618305C03335C0139650234690251
+ 842A498D5278B785F4FFEBFFFEFFF4FEED498A452E81252D6813265A00245A01
+ 2B5600285500294D01284C002955022B55002B5500295000274E00274D012C51
+ 012B5100284C002648012A54012A51012A4F002A52002D56012C55002A520029
+ 50022C5004224700294F03345A082C5003274A002B4F03295002264900284C00
+ 2A4E02264C00264B01284B01284C002A4E01264C002B5105285100244B002B52
+ 042C5107274E00315B06325A08254A00274D012A5200264D00284F012B520226
+ 4C002A50042A4E022A4B00284C00284C00284F01284C002A4B00264C00254B00
+ 254B002A4D03284C00274B00284C002C5003275000264E00295002294D00264C
+ 002C5101284E022950002C50032D50002A4F002A4F00264B01284C00294D0127
+ 4E00295002284F00284F01284F01274E00274D01284F01284B013054082F5208
+ 2C50032C50032A4D03284C002C50042A4E022A4E01295100284C00274B002A4E
+ 022C50042951002449002A4E022A4E022A4E022A4E022A4E022A4E022A4E022A
+ 4E022D5000264E002B50002E55052E55052B5000264E002D50003155012C5200
+ 284F00295000284F00295000284F01264B01264D00284C00284C00284B012A4E
+ 012A4F00274B00264802305408284C00264801264802274B00274B00274A0027
+ 4A00274B00274A00274A00264801274902274A00274A00284C00274902244600
+ 2648012A4B012B4C012848012446002446002944022641012240002641012844
+ 02284702274301264200253E00253E00253E00253E00253E00253E00253E0025
+ 3E00264101264200264200274301264200254000264101254000243F00254000
+ 2540002541002642002844022743012642002240002341002642002642002743
+ 01264200234100224000223F00243F00254000264101264101254000243F0022
+ 3F00254000254000254000254000254000254000254000254000264000264000
+ 263F01253E00253E00263F01264000264000253E00253E00253E00253E00253E
+ 00253E00253E00253E0026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274B00264802264704224201244600254700264801264801274E00254A00
+ 254C00234A00254B032C51092C500330540831610138811A458728478D50F3F4
+ F2FEFDFFF4FFEB3F925B3882183772093B6A03417509478628498A4567A577E3
+ FFF1F7FFFEFFFAFB85D5A040BF6A44AA6288CCA3FFFAF9F1FFFE67A366397927
+ 3D6C0A386917427A1546842A51964668BB87FDFFF9FBFFFFFCFAF96DAC84439A
+ 444E791E2E8125468837439139498A45B6D9C5FEFAFFFDFEFAAEE4B945974544
+ 923B37893648893444923AAFE2BCFCFFFB889D843B79272C7207335C012B5A00
+ 335C0139630B2A51012E55003263013361012A720744841A84A977F5FFF6A7BA
+ AB2D76142A7207436905265106254D062B5207284E022850002E5A0132610040
+ 7409508528478B44E7FDFBFBFFFA6E956838811B357307206302315B03244A02
+ 244D022651082451021F62012C650338771767A367FFFDFCB6D7BC3C85292D75
+ 15316A012E6502326307437A1746923A37904786B686EEFFF2FCFAFAFAFFFEDD
+ E1E645B56741B66746A866D4F8DAFFFEFEFCEEFAD6E9DA499B533B9E423B9F40
+ 35A75344AA63E5FFF1FFF8FFFBFEF587CBA24A9D3A4693385585373989363A90
+ 2A3CA04155A76657AA76B4CDB9DCF7E7FFFFF9F6FEED67BA86A6E6C3ECFDF2F1
+ FFFEFFFFFB97C8A256B26B398936326B092659012A4F002F4C032752012E5200
+ 24480234520B2547002E59002E5402285100304E03415D032261053776164485
+ 2965A268F1FFFBA5BBA83976163A7A28488836265E0B325C07325E033B792547
+ 933B559756CFEED1FFFAFFFBFFFE98C8A438862839821C2B6500325A08295002
+ 274F012B5202264B01254C00264B01294C02274D012950022B5202264C002B52
+ 042B5204244B00285002284E02264E002B4F032C5107305408284E02274A0026
+ 4C00274F01264C002A5200325A082A5300274E00264B01264C04284F01274D01
+ 264D01274D01264D01274D01264C00274D01284C00294D00254A00294E062B52
+ 02264C00284F00325B062E56042951032A50042D5208264B03244900284F0326
+ 4B01284E02284E02274D01274D01264C00264C00264C00264C00274C04274A00
+ 234A00274D01264D02214B00274D01285100264A04284F012850022852002851
+ 00295000274E02254A04274D01274D01274D01274D01274D01274D01274D0127
+ 4D012750002851002950022A5103284E02274C02294C02294C022A5200284F00
+ 295002274E00274D01284F01264C00264C00274C02264D00274E00274D01264B
+ 01274D01294D01274A00274D01264C00254C00254C00274D01284E02264C0025
+ 4C00264C00274D01284F002E55072D54042B52022850002950022E55052D5404
+ 2A5302285002295002274E00274E00284F01284E02284C00274A00284B012A50
+ 042D53072B4F03274B002F56002A4E01284C00284C00264801264801284A0324
+ 4600274B00274A00274A00254700244600254701264802254700284402274603
+ 284704284704284402264200264101264101254401254000243F00253E02263F
+ 01264102274203264004264000264000274002253E00253E00263F0126400025
+ 3F00233E00233E00233E00243F00253E00253E00233E00243F00233E00253E00
+ 264000284202284202274101264000254001274002263F012540012945032A46
+ 04254001253E00274101233E00254001264101254000243F00243F0025400126
+ 4101233E00233E00233E00233E00233E00233E00233E00233E00274200264000
+ 2640002540002540002642002844022744002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274A00264802284A03294908284A03284A04294D01284C00234C01214901
+ 2B4E04274F01284F00274E002F4F023159073A640038811A45863777A576F5FA
+ F9FFFFFFD0E3CE478A4739821C346902336101316A01437918458736589857B1
+ E2BCFEFAFFFAFFFDBEF2CD52C27554B674D0F1CFFDFFFFE8EAF552964938751A
+ 366802326000386D0C44831D46933855A766DDF7E7FDF9F8FFFEFF9BD0B53C90
+ 4846883644862748883649933B549A65DBFAE5FFF9FEF6FFF57BB8863A914738
+ 78263C85294487263B792587B587F9FEFCC7D8CA4678323672063462092D5801
+ 2F5C0039630B2851002E55002B58013B640230741546852982AA7AF2FEFEB5CE
+ BA377B242C72072E5C032D5B08215100284B01274E002E51012D5900385E0440
+ 79163A85293A9147E7FEF9FBFFF977A2693883194273093361012B56002D5503
+ 2D51052446002D5503316902356B0A427916519C64FFFFFBC7DACB45772F3975
+ 1737740628730737751B488F2E47923C64B97BD7F6D9FDFEFFFFFFFFF4F9F7F0
+ FFF846B4663CB26946A96375B27AEDFEF3FFFEFEEDFDF6AFE4BC46995436A750
+ 36A75047A963CAF1D8FFFFFEFDFEFAB6D8C753A766399E423CA04047A3525198
+ 4857A7669CDAB6EDFDF2FBFFF9F8FFF9F5FFF8E4FEF059BA88BBE7D0FFFFFAFC
+ FEFEF3FFF986BD963B90452C76182B64012A5401285200254A022A4E01224600
+ 324E12294E062C50042343022951002B52072E4F053E5C032E72073B79254287
+ 2668A26BF8FFF6C5D9CD387B2639761646821D2965012C6503366A1643883748
+ 923A96C9A3EEFDF5F9F9FFEDFFF276A5773784282C72072B64022A5200254B00
+ 2A5101295002264C00274D01274C02274C02284F012950002A5101274E002B52
+ 042A5103244B002A5302274E022750002A51032C52062C5206294F03274D0127
+ 4E00274D01274E002C54023159072C5500295002294E04274C04274E00254D00
+ 264D00264E00274E00264D00274D01264D002B5204294E042950022A51032950
+ 00264D00295002325A08285100234901264C00284F04254B03274C02284F0326
+ 5000284E02284E02274D01264C00274E00284F01284F01284F01294F03294D01
+ 264E00294F03284F01254C00274E00275000274C04264C00254C01274F012950
+ 02274E00264C00274D05274D01274D01274D01274D01274D01274D01274D0127
+ 4D01274E00264D00254C00244B00244B00244900244900294C02285200284E02
+ 284E02274D01295100295002295002284F032850022750002851002851002750
+ 00275000285100295000285100274E00274D01284F01275000285100284F0127
+ 4D01294E04284F002C53032D55032E5505294F03284F012950002B52042B5204
+ 285002274F01274E00274E00264D00254C002B4F02284C00274B00284C002A4E
+ 022D4F022A4E01284C002D51042A4E012A4E012A4E01274A00264802284A0426
+ 4801294C02284B01274A00264801254700264801264801264801274603284704
+ 254603274603274603284402284402274202284500264101253E00243D00263F
+ 01263F01253E00243E02253E00263F01263F01253E00253E00263F01253E0025
+ 3E00243F00233E00243D00253E00263F01264000264000264000243F00243F00
+ 254000264101274202264101264101254000253E00253E00243F002641012742
+ 02243F00253E00264000253E00243D00264000264000243D00243D00253E0024
+ 3D00233E00233E00233E00233E00233E00233E00233E00233E00243F00254000
+ 254000243F00254000243F002641012844022640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264802264900294B04264900254800294D01254C00274E00264D00264D01
+ 2952012A4E012753002A54002B5500305D00326B0844831B478A45B0CDACF3FF
+ FEFFFDFC95BA98378B333A7717346100316101396502397306488737488E5185
+ BC95FFFEFFF9FFFEF6FEF36ABB8467BA86FFFDF5ECFFFCA9C9B13989362F7216
+ 316B002B67023A6B00427309478E2E499952B1DBC4FFFFF9FCFEFED5F5DC488E
+ 512E843647923C4689444497486AAC82FCFDF9FFFEFFE4FAE83C915D3C91473A
+ 77173776164377193C7A286C9568D6E9DAEDFEF3558C55407917387618235A00
+ 2E5A01305701254D00305B002C5902416C153B792748862C76A168F5FFFEB7D6
+ B93979272E72073362003268042659012C59022D59003355012D59003B640952
+ 83274B9F39498D52FBFFFAFBFEF577A8762C7E253A7618315C012D59002C5500
+ 3048002D490337590239650032690237792768A468FFFFFBE6FCE9488A434687
+ 2B46821D46841A4785273A923855A864B7E6C6EBFEFBFAFCFDFFFCFEFBFEFFF5
+ FFF953C47446B46638A7514B985499B9A6ECFFFCF5FFFEFBFEFC97BE8A55B168
+ 38A85048B7739BDBB8EBFFFAFEFEFEF1F3F346B77356B2694CA25438A85068BA
+ 86D8F6DDFDFFF7FDFFFFFBFEFCFEFFFDF8FBFFF5FFFE9FCFB7D6F9E5FDFEFCFF
+ FDFFDCF8E568A6762B87362B6810325B002D58012B5A002851002B4F032E5206
+ 2C5107204500345E062D58013055052C510734520B3D5D042C76163776164688
+ 367CB785F6FFFAC7D8CB38811A2A7305316C0A2C65033C811A38852952944565
+ B169DAF9E4FAFFF6FDFFFCB4D9C54A89442F7F262965003362002B5400295002
+ 2952002E5505295000274E00274E00264C00274E00284F002B5202274E00264D
+ 00295002274D012A5101264F00275000285002294F03264E00284F00264F0025
+ 4D00284F01274D012A52002C55002A5200264C00284E02274C02284F002C5206
+ 2B5204285200295000285002295002284F012A51052C5206284F00264D002950
+ 00284F01295000325A08284F00264C002A4E01284D03274C022A5000284F0029
+ 5000254C00254C00264D01264E00264E00285002274F01285002295002274D01
+ 275000294F03295002264E00264C00264E00294F03274D01264E002750002951
+ 002B52042B5204284E0227500027500027500027500027500027500027500027
+ 50002B52042950022850022850022850022850022950022B5204275000285002
+ 285002284F00284F01254C01254C01254D00295000295002284E02284F01274E
+ 00284F012950022B5204274D01264D00264F00274F01274D01264C00274E0027
+ 5000295000284F01294F032A52042A5204284F00274D01295100284F01295002
+ 275000284F002950002950002950002851002C4E01274B00274A00274A00264A
+ 00294B00284C00284C00274D01264C002A4E022B4F02274B00264A00284B0127
+ 4902284B01274A00264900274902264801254700254701254701264802264802
+ 254701254701274603294503274301264101284402264101263F01253E002640
+ 00253F00243D00243D01243D01263F01264000264000253F00254000243F0024
+ 3E02243D00243D00243D00253E00263F01264000264000264000253E00253E00
+ 253E00264000284202264000263F01263F01253E00233E00233E002540002540
+ 00243F00233E00253E00253E00253E00264000264000253E00253E00243D0024
+ 3D00264000264000264000264000264000264000264000264000254001254001
+ 243F00233E002540012540002540002540002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264D00274D01264801254603264802274902264C00254A02224C002D5406
+ 2F5404274E002D59003C6B04326804296500397209478628459854E0F0DFF2FE
+ FEF3FFF066A3692F7F24326307346100335B0333620034680438872646913B57
+ A863FFFAF9FDFFFFFFFFF99DCFB79AD5A8FDFEFAEAFFFB9BB9A62D8024297309
+ 2A65033168013369053772093A85294598546AB986FFFFFAFEFDFFFBFFF777B3
+ 77279A4B48A45366BA7A53B16AA4C8AAFFFFFEFEFFFDA9D8B82E88353791453B
+ 792731690439720944883368A369A6C7B2EDFFFE97C9A1457731458735275F0C
+ 2659012756002750003C650A38620A4F8427458728387A216C946AF4FEFEB5D9
+ C32076282E7318396B1737750433610133610139650C346A092C691339792751
+ 963B56A867548B52FFFFFBFFF7F497BE8A3B923A2F80232C6713316408285002
+ 2D5100375C00385B002D650038761838883565A577FFFFFFF5FFF3479B533989
+ 363689343B902E3A933653A767AAD7B6F3FFF9F8FBFFF8F4FFFFFEFFFEFEFEF6
+ F4F363BD994399533B933948A4533D935D9DCFB7EDFEF1FFFEFFEEFEF395C8A3
+ 44A96549B77787D2A6E5FFF9FEFAFFFEFAFF6CC99646B77353B57398D6A8D7F7
+ E6FFFEFFFEFAFFFEFBFDE5FEFAFCFEFFFFFAFFF2FEFFF4FCFCFCFFFDFEF6F6F2
+ FFFDBDEFCF3F935D2277272C6810315C01336101326804265901285100244A02
+ 1F5000326902255A003C6D0B3864092A540032530939650C47902E46772D4989
+ 378CC79BF9FFFACAE4D62F7F242E7616346A092A73054CA03A3B904575B27AAE
+ E3BBFDFEFAFAFFFFEDFEF377AC853B89352D7106326A053763002C5500295000
+ 2C55002D55032D5503295002274E00264E002950002950002C5303284F01284F
+ 01284F00264D002D5404254C00295000285100264C00234A00284F01274F0126
+ 4E002A51032A53002A5300295002295000274E00274D01264D00274F01305505
+ 2C56032B5100295300295000264E00274E00244901295100295000274D012950
+ 002A52002C56002F59022A540029530028510027500027500028500227500028
+ 5100274E00274E00284F01284F00295000295000284F01295002274F01264B01
+ 274F01284F01284E02285000274D01284F00295000295002274F012A52002E58
+ 002D55032A5200264D0029500029500029500029500029500029500029500029
+ 5000264D01264C00274E00295000284F00275000285100264E00295002284F00
+ 295002284F00284E02274E00264C00274D01295000284F01274D01274E00254E
+ 00264E002850022A5302274D01274D01274E00274E00274D01274D01274D0127
+ 4E00284E02274D01254C00285200275000264E00264D00284F00274E00284F01
+ 2950002A51012A52002A52002A5101295201284C00284C00284C00284C00254A
+ 00254A00254B00284C00264801264802294D002A4E01274A00264801284C0027
+ 4A00274B00274B00274A00274A00264801244600234500234401264801254700
+ 2547002446002645002645022443002341002540002540002641012641012642
+ 00254100254000233E0025400127420226410125400025400027420225400024
+ 3F00243F00243F00243D00253E00253E00253E00253E00243D00253E00253E00
+ 253E00253E00263F01253E00243D00243D00254000243F00233E00243F002540
+ 00254000243F00233E00243D00264000264000264000253F00253E00253F0026
+ 4000254000254000254000254000254000254000254000254000254000243F00
+ 2540002540002540002540002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002C5500284F00254A002648012A4E022A51012C56002C5500244B00275700
+ 2E58002B4F022D59003B6A03326C073773073A8628458B456AA676FEF6F6F0FE
+ FCDFF2DF4C8C5139821C396409346001305C0332610032620247852750974748
+ A256D5EADBFFFEFFFAFFFED8F9E4D6F6DDF8FFFAE2F6F169AE813C8A362A6711
+ 2965012E5800315B03326B09397A24569857549A65E6FEE6FAFBFFFFFEFFA7D6
+ B635A75354A76356B57256B987D5F6DBFFF9FAFCFEFE6BAD833C91473A883437
+ 6B17426A04387206397A255A965978AD86ECFEF1E0F8E6537A46488C532B6810
+ 235E0D2F5B00295100386400365D075084264587364F873676A577F7FFFDB5D9
+ C3477631318225397927436D16316507386917487830448835388A373789363C
+ A04148B67447AE75F2FDFAFFFEFA98D6A63892462D87342076283869172D6814
+ 335D053462021D61022E75183A88343D92487ABE95F6FBFEEBFEF557A766529B
+ 63499A5537A65047A865B8D9C4F3FFF3FAFFFBF6FFFCC4D9CAFFFEFFFFFBFAF9
+ FFFA91D0A94799583990383B91393A9246478D51A8D5AAF4FFFDF9FEFFDEF1DE
+ 84BC9346B77464C097E5FFF0FDFEFAFDFFFF88D5A288D3A5B7E6C6EFFDF2FFFB
+ FCFBF6FFF7F5FBFCFFF5F3FFFFF7FFFDFFF7F79CDAC8FEFEFEF6FEFEFCF8FDEC
+ FFFBB7E6C53C915D2D86372E7715315C01375A043168013066022D57002D5900
+ 2659012A63012C660146781A335B14365C14386A16346307449338478A455184
+ 3A8EC79AF9FFFDDBE2E53789363D79253878263C8938449A5440945D97C6A5E7
+ FEFAFFFAFDF6FEFEB8E8D0568D563A88343877173469013A62032952002A5200
+ 2D55032D55032E5505295000264D01274F012C55002C5402325B062C54022A52
+ 002D56012C5402325B062A51032D54042D56052A4E01264D01284F002952012A
+ 5103325A08325A082F58032C56002C54022A5101284F00274E00284F012D5900
+ 3158022A53022B56002C56002652002A5200274D012D57002C55002950002B56
+ 002E59022E5A002D59002F59012C5500284F00274E00274E002950002A51012C
+ 55002C55002C55002C55002C55002C55002C55002A52002A5200254C00244B00
+ 2B52022A52002A51012E58012A51012C56002C5600284F00264D012950002C56
+ 002D56012D56012A510129500029500029500029500029500029500029500029
+ 5000274F01284F01274E00284F012951002953002B55002855002950022A5101
+ 2C55002B52022A51012950022950002A51012C5402295000284F002A5101284F
+ 00284F002950002D5404284F002B53012C55002A53002950002950002A52002A
+ 5300295000274D01264D01275000295201274F012A53002D5700274E00284F01
+ 2A51012A51012A52002953002A52002A51012A4F002B50002B52042B52042950
+ 022950002A4F002B50002648012648012A4E012C5004294C02284B012A4F0028
+ 4C00284C00284C00284C00284C00284B01264801254700244600294A00274A00
+ 274A00274A002648012547012446002446002642002743012844022844022844
+ 022642002540002640002A46042B470529450325400025400028440229450327
+ 4301274301274202274202264101254000254000243F00243F00264000254000
+ 2540002641012641012641012540002640002844022641012540002540002641
+ 0128440226410125400025400026420028440228440226410126410126410127
+ 4301264200264200264200264200264200264200264200264200264200264200
+ 2743012743012642002642002843012742002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000335D062D5700264C00295200345A08335D063964093A660932620A386308
+ 3E6A053F69044269073068013E6C0C478E2D53963B559756A7C9ABFFFCFEF7FF
+ FEA6D7B7498B4440791750791D4274083261003964033B6C0A618E3764B36A56
+ B16CA9D8B8FFFCFEF4FFFFFAFEF8FCFFFAF2FDFBC5DACB44AC755597563C7A26
+ 37771439630B436D16628F3965A35573B17B55B673C4E5CAFCFEFEFDFAFCD9F9
+ E856B88A53C37646B77359A875EEFFF2FFFDFFF1FFF8519C6446A7643A8A3728
+ 66124E7A1D47902E2D812367A3556AA578C8E4D7F4FFF3859E82489A52378937
+ 3B7828427408346301335F003A660952833955965865A35598C7A6F2FFFCC8D9
+ CE4598544498464B8947519548468944588546549857569857458C543C914658
+ A76456B9875FBF97E5FFF9F7FFFFA8E5C146B67647AC7546AC75498B44468946
+ 37792738771739821B30802546995555BA87C1E1BEFFFAFFE6FDF93BBA833BBC
+ 8361BE9786C9A4B0E5BAFDFEF5FDFEFAF7FFF8B8E8D09CBCA3FDFEFAFEFEFEF5
+ FFFDABD8B751964547933B4AA256449A523984285C8748A5C8B4E5F7F0FDFFF9
+ E9FDEA87D4A165BD99E5FFF1FDFFF9F5FFFFA8E4C6E3FDE6FBFFFAFAFAFFF7F9
+ FFFAFFFEDFEDE7BEF0CEFFFBFFFFFCFFD9F8E33BCB909FDCC8EAFFFCFFFAFFFE
+ FDFFB4E7C5589A6748985545852B416B063A6302306400305B00264C042D5404
+ 548638568638558B56527B4877A16AC7DFBF558747346A0945933C5596586392
+ 5498C8A4F9FAFEDBE2E555A76648995457A667469A52549A6578AD82D7EADBFB
+ FFFFFEFEFEEAFFFC89CAA353996445933C518527336200366500315B04345E07
+ 335D06345E07325B062A5300284F012A5302345F042D5700355F07345E062E58
+ 00305B00315B03345E062F5A00325B06325A082D56012C56002C56002E580132
+ 5A08315808355F07345F04345E06345E06315B032A5200274E002B5500345E06
+ 356005305A02345E06326209375E083662092C5600345D08345F042F5901315E
+ 01305C012C58002D5900326000325C042B5500294F032D5404305C03315B0336
+ 6207315C01325D02315C01315C01315C01315C012F59012E5800285100274E02
+ 325B062C55002D57003560052D5900315C01345E062E58012A51012950002C54
+ 02315907355F07315B03315C01315C01315C01315C01315C01315C01315C0131
+ 5C012E56042B5204274E02254D002952012D5801305C03345F04315C01335C07
+ 335B093159072D5700285000295002295002345B062F56012F5601335A052F55
+ 032C52002C5402325B062D5700315907325B0A305A072D56012C56002E570230
+ 5A072B5202294F03284F002C55042E5A012F59022D56012E58012B56002D5700
+ 2E58012E5A012D59002D59002E58002E58003055002F56013159073159072F56
+ 013054002F56012D5601284C00284C002C50032E51072C52002C52002E55002C
+ 52002D51052D51052C50042C50032C50032A4E02284C00274B002C4E012C4E01
+ 2B4F022B4F032A4E02294C02284B01264B032C48022B48032A47022A46042844
+ 02254000263F01263F012B48032A47022945032540002540002844022B48032A
+ 47022B48032B48032A47022945032743012743012642002641012B47052B4705
+ 284704284704274603284704284402284402284402274301254000243F002641
+ 012A460428440225400026420028440229450329450328440227430127430128
+ 4402264200264200264200264200264200264200264200264200274301284402
+ 2744002845002844022844022642002642002540002540002540002540002540
+ 0025400025400025400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00003A650A2B5400254B002D55033964093964093765023C6A072E5A07315E01
+ 3A62033B64033A63012B5A002C671353963B56975953A864C7F1D8FFFEFEFEFF
+ F878B686398A353A761842831D4279162C66013D6A03426E1361903A68A36955
+ A8647ABF94E3FFF2F6F9FEFDFFFEFEFDFFFFFFF998CAA23BB2675597563A8529
+ 4379163B630B3964095184284F873658985766BA7A85CCA1FAFFFFFCFBFFEEFE
+ F387CBA239C88F3DBA8284CBA3F9FFF9FFFDFCC3E8C842925D4CA3534685292C
+ 77154C7B1E50943D48923A66A46868A678A5C9B3FFFFF3BBD6BC509B63469A52
+ 3C7A2846841A386C01396500507A1B50873865A35567A367B0CDACF7FFFFC8D9
+ CB559C644CA156469A52509B635797566C966776A57787B58698BC98A6C8AAB4
+ E6C6D0F1CEC9F2D7F6FEFDFEFAFFB9E7D162C0975AB9873EBA864AA256369146
+ 2274273A86283784293988376AA874A0DAC8E0EFE1FFF8FEE5FFF13ACA8F6CC8
+ 979FDAC6DDF8E8F9FFFAFFFEFFFAFDF4B7F9D665BE9755B888EEFEF3FFFEFFF1
+ F9FFC8E4D7478C532B87344498573D7827437A1738751A65A3679FCFB7D9F9E8
+ F2FEF2DAF7E7B6DAC2E3F8F0FFFEFAFEFFFBFBFEFCF7FFFDFEFEFEFDFEFADBF7
+ E489DBB086CCA4DAF9E4FFFAFFFEFEFEBAFAD73DC7916AC996F7FFF6FFFBFFFF
+ FEFFB1E3BB559C64469954468934396C0A406A053461002E5A012B52042B5605
+ 5F8E3843782F568D54B6D8BAD5F6DB889E824689443D78274AA35366A5675397
+ 5697BB97FFFEFFF5FAF857B57547A96355BA8645AC7379BF97C0E6C8FEFFFDFE
+ FDFFF9FFFABBE7D057A978469A52488836508426315D023965023964093A650A
+ 3A650A345E06345E062C5600284F002D5704315C012D5700325E05305C012E58
+ 00315D00315C01315B032E58002E5902305A022D59002C56002B55002D580133
+ 5F042E5801345E06345E06325D02345E06345F042C55002950022D590039650C
+ 386308345D023262093A640C3262093A650A315C01345E07345F04315D003461
+ 00335F02315D042F5B02346100335D052B56002A5101325B06346007335D0537
+ 65022D5900305C01315C01315C01315C01315C012F5B002E5A01284F00275000
+ 345D082E5902315D003964092E5A00315B0339630B3560052C55002850002E55
+ 07325A08345F04346202345E06345E06345E06345E06345E06345E06345E0634
+ 5E062B5204274D01244B00244C002953002E5902305B00315C01345E06345E07
+ 3159072F59022B5202274E00284E02295000305C032D59002E5A01335F042D58
+ 012953002A5400305C032E5A01315B03335E03315C012D59002D59002F590132
+ 5D022E55072A5200284F002E5604315A05325A082E58012E5800315C01315C01
+ 315C01305C01305C01305C01315C01315C013155032D57002E5A012F59022E54
+ 023054023156003059002B4D06294C022C50032D50062C51012D51042E54022C
+ 51012C50042C50042D51042D51042B4F022A4E02284C00274A002E51012E5003
+ 2B4F022B4F022A4E02294D01294C02294C022B49022B49022A47022A46042641
+ 01243F0026400026400028470428470229450326410126410127430129460128
+ 44022B47052B47052B47052945032844022844022844022743012B48032B4705
+ 2847042746032746032746032844022743012845002844022641012540002641
+ 012A470229450325400026420028440228440227430128440226420026420028
+ 4402284402284402284402284402284402284402284402284402264200284402
+ 2844022844022844022642002540002540002642002642002642002642002642
+ 0026420026420026420026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00003964092951002245022C5500345E06315C01305900335B03225B002E5800
+ 325D023765023A630139630B39792765A35556985757A975EFFCF4FFFEFFFAFE
+ F3559B663A86283574062E66012965002558003E63033E5C0344783257864748
+ 8C5157A975C8F3D8FEFAFFF5FFFEFBFFFFFFFFFB65A577279A4B2B8736226103
+ 3169042D59002D59003B6B0B376B1858985757A66756A975EAF6FCFFFAFFFAFF
+ FEA5E5C13CC8923AC990BBE7D0FDFEF5FDFEFAA5BBA9458C532F802329761522
+ 60023956062E75182D7515478A45488E5288A987FAF6F5F5FFF93F935D478A47
+ 255C0D356C09376600315B04436D16457731498A45568D5498B8A5F5FFFFC5D9
+ CC3F935D379047478D50479853488E5268A676A8C7B8DAF8E5FBFFFAF9FFFAFB
+ FFFFFEFFFDF4FDFFFDF7FCFFFAFFF8FFF9DCF6E8C0F2D09AD0B346A9653F935D
+ 39914544923B48923A65A355B0D4B0E7FEFA9ADBB4F2FBFFF9FFFAB7E6C6DEEC
+ E6FEFAFFF6FFFCF9F9FFFCFBFDE5EDE657B7883DCA913AC990DAF8E5F2F3EFF7
+ F9FFCAF2D93A91472D8833478A4539691A3965023971062B7515468F516C946A
+ A8C7AAF4F5F3F9FEFFF7FAFFFFFFFFFFF9FFF1F9FFFDF5FFFEEEF9A7D5B855BA
+ 8646B77378BE95E7FEF9F3F9FEFEF9FA87DCB03CBB843BBA83FFFEF4E3F7F2FA
+ FFFDA7D5AB3E905F2A88342D7515315C013B6402346003305C012D5801426D16
+ 39792752863879AD85E5FBE9A8C8A93858293779273A77173B8936498A455985
+ 4896BB9BFCFEFFF7F9F944AA6337A6543BB16849AB75A7E4C2EDFEF3FFFEFAFC
+ FAF9E6FCE983BD943E915D3C91473B79273A640C305701305D002E5800315B03
+ 2E59002C55002F59012A52002A51033259092F59022953002E59022E59022B56
+ 002F5A002F59012C56002B55002A54012D57002D59002A5101284F032953002E
+ 5A012C5600305B002F59022A54002E5803315C012C56002A5101295201346100
+ 305C002A54012D5900295A002D5900305C012E5800315C012F59022E58013461
+ 00315D00305C00315C01305C01315B03285200284F002C55002D59002F59012D
+ 59002A54002D58012D58012D59002E5A012D59002E5A012E5902295000275000
+ 325A082D59002E5A01345E062B56002C5500325C042E58002A51012950002B52
+ 042C55002F59012E5A012C55002C55002C55002C55002C55002C55002C55002C
+ 5500285002264E00284F002C5500315B03346003356104315C01284F01295000
+ 2A5400295201274F01264D012A51012E56042D59002B56002E5801325D022C56
+ 002950022851002D59002C54022C56002D59002D59002C55002A52002B54002E
+ 5A012E55052950002950002C5402325A082F59012C55002A52002E57022C5500
+ 2C55002A54002A54002B55002C55002C55002C55002C54022953002A52002A52
+ 002E55002E55002F5601274D01244802264C00284D032850002A52002B550028
+ 4D03294D002A4E012B4F022B4F03284C00274A002648012446002C4E012A4E01
+ 294D00284C00284C00294A00294A002648012744002A47022645022645022443
+ 0025410026420028450026440328470428440226420026420028440228440226
+ 4101274101264101264101264200264200264200264200264200294402284402
+ 2743012642002743012642002642002742002844022743012540002340012341
+ 0029460128440225400025400026420028440228440227430126420026420026
+ 4200284402284402284402284402284402284402284402284402264000254000
+ 264200274301264101264101254000233E002642002642002642002642002642
+ 0026420026420026420026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00003D6906255100255000284F003A640C244E002852002C5004295002264D01
+ 2A5204265200395C022E58002A691363A35748984585BD92FEFDFFFFFAFCD8F5
+ DB4499552D81234268043158082D52022E51012B50002C56003263073B741751
+ 922C47A4538BC699F6FFF2FFFBFFFCFAFFC7F1D84BA3573C86283E6C0C305B00
+ 2B5502294D00274A00295300436D1565A3573B902E5496479CDAB6FFFFFAFBFA
+ FEFCF6F754B5733EC067D9E2E5FDF9F8F4FFF366A36B398A353A74073864012F
+ 59012F56012B590035630A427817458728498B43D5F6DBFFFDFF84A977457731
+ 296501326902355F072E55003B640340740945862A47872799BA98FEFBF7DBE2
+ E53C923A2C85364892383A902C6C9667D9E2E6FEFFFAF3FFEDE7FBE8BFF2CDBE
+ F1CFEAFFFCF6FFF5FEFFFDFFFBFFFEF6FFF7FAFFFAFBFFFDFEFAE5FBE8D0E6CA
+ A5BBA8A5BBA9D1E5CEF5FFF3C9F2D79CDAB69ADAB7F7FFFEFEF6FDFFFFFFFEFD
+ FFFEFEFEFFFFFAF4FEEE8BC89646A86635A8514AA35456B474BFF1CFFDFFF7FF
+ FEFEE3FDE6498B442B8736468837396C0B315C0132620A39630B38730A407916
+ 46883648A35466BA796CCA94E5FFF1FEFEFEF7FFFF89D4A13DC0693DC1673DBF
+ 6A44B565A6D8B6FEF6FDFFFFFFEDFEF353C37552C27447B777FFFEF4FDFFF9F2
+ FFFD8AD4A43990462E76162D64013A5708284A031D4C002D5900396403377406
+ 2F7518517B46D8E9DCF3FFF3507B482D75153B6A03366B034076054486274B89
+ 479AC8A4F1FFF8FFFEFE36A75041B66746AD7493D0ACEDFEF3FFFAF9FFFEFEF1
+ FFFE88D5A249A766399F403886282C64003D6309234A00275306285100285100
+ 284F00274E00274D01284E022B52042E55052E55052A5101274E00274E00284F
+ 012B52042A5103284E0229500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 50002950022B5204295100264B012B5301325A082E5801284F00275000295201
+ 284F00274E002950003159072E56042950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E00284F01274E002950022B52042A5103274D01244A00284C00284C00
+ 284C00284C00284C00284C00284C00284C002A4E022A4E022A4E022A4E022A4E
+ 022A4E022A4E022A4E022A4E012A4E012A4E012A4E012A4E012A4E012A4E012A
+ 4E01274D01274D01274D01274D01274D01274D01274D01274D01295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000284C00284C00284C00284C00274A0026480126480226
+ 4802274A00274A00274A00264801264802244600244600244600274A00264801
+ 2648012645002544012443002342002442012640002640002640002640002640
+ 00253E00243D00243D0126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000274202264101
+ 254000233E00233E00233E00243F002540002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00003E6B0A2B55002E59022D5601396409285100285200274E002D4C01244903
+ 285002295000355B033965023B7A2463B26849A455A9D8B8FBFDFDFFF7FEC3E5
+ C749A4552E8125406908355C062C4F002F4F022B4D002C55003460033A6E0A52
+ 912946984678B686F6FFF4FDF9FEF8FDFCB7E6C6489A513585283268042A5C00
+ 2C56002A4F00284C00285002336108508527488F2E5196468BC699FBFFF9FEFD
+ FFFFF9F968BC863EC067F6F9FFFFFFFEECFCF1598D57308025346B0033610129
+ 56003355012F5A00336200447A17448529458837B8D7BAFAFBFFB9D6BC43782F
+ 3D76142C6201315D0431550138630239730646872B48902C95BA98FDFEFAEBF8
+ FA4397453A933644923A488944C0E7C7F6FFFFC7DFBC83A87A549759549A6563
+ B26956BB87AAD6B9F9FEFCFFFBFDFBFDFEF5FFFEFFFDFCFFFEF4FEFDFFFAFFFF
+ F8FDFEF4FFFEEDFEF5B7D9C17BBE995FBF97A9D5B6F8FFFCFFFEFFF3FFF2E5FE
+ FAE7FEFAB3D8C478A36A68A3592D873438923847994647AA62A5D6B6FFFDF5FC
+ FDFFEDFEF5448B422D86364887373B6C0A2757002753002A56002B6600356C09
+ 3775173A88344CA25456B473C7F1D8FEFAFFF8FEFD88D5A23FBE683BC0693CC1
+ 6547B567BFF2CDFEFAFFFFFDFFDBF7E346B7744FC47548B674F4FEEDFFFFFFF4
+ FEFE98C8A43A91472B7517336A03325B002B4F03234D002E5A00366500377209
+ 468626639156F3FFF3E3F8EF4877323B821B3E6A053368003B74173885294889
+ 449AC9A3F1FFFBFFFDFF51C3763CB2696FC994D9F6E6FFFEFAFCFFFAF4F5FFFE
+ FAFF98D6A853A8644798533A86283A730A2D5900426D16244900275000285100
+ 295000274E00264D00274E002950022B52022D55032A5101274E00274E002950
+ 022B5204295002284F0129500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295002295002285000274C022950002E55052C5500284F00284F002A5101
+ 295002274E00284F012F56062D54042950022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00284F00264D00284F002B52022D54062E55072D5406284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C002A4E012A4E012A4E012A4E012A4E012A4E012A4E012A
+ 4E01274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000294D01284C00284C00284C00284C0026490026480126
+ 4802274A00274A00274A00274902264801244600244600244600274A00264801
+ 2648012747002645022743012443002442012640002640002640002640002640
+ 00263F01253E00243D0026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000274202264101
+ 264101243F00243F00243F00243F002540002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000335F062B5500315C012E5801345E06274E00284F00274E002C5300265003
+ 285204265100375B014268043C792965A35753A864D7F5DCFFFEFFFFFBFD98C7
+ A64998472E75153965002D58012C52002C4F002C4E012C51012B5801346A094F
+ 8427499847549B63E7FBE8FFFAFFFEFDFFB8D9C4488D542D8024326902265A00
+ 2A51012A4C00264D002950002956003D6C0941882846913D68A676EDFDF2FFFE
+ FFFFFFF99CD5A853C474FEFDFFFDFEFAD8F7DC468946317F27326B093561022B
+ 55002E4E01285500315D023F710B45851B47893895BA98FAFFFEE3FFF1578647
+ 4587282A66013460012B590039650842750646852747902E98BC98FDFEFAFAFF
+ FE4699553CA04153943E8AAA91EEFDFFC8D9CC6C966746994447A25335A95043
+ B56840C06797D7A9FBFFFAF3F6FBD8F7DC9ADAB7BFF1CFDAF9E4FAFFFEF5FFF9
+ E3FDE6C8E6D397C7A366A77647AC7558B987B6E5C5F0FFFBFAFEFFE5FFF2A7E4
+ C267BB85599656398A354F84272F7616388628469338469A5298C7A6FFFFF8FD
+ FFFFFBFFFA5698573B89364589343E6C0C335C002A5B072D5801315C01366207
+ 326B0839811D3A933648A354B6D8C7FFFAFFFBFFFF9ADAB647B66639B16A3DBF
+ 6866BA7AE6FAE7FFFBFFFDFFFFB9E6C543B66742B56645B974E3FCE8FFF9FAFB
+ F9FF9AC6A7448A442E7514326A00385B012B4F022151002D59003262093A7715
+ 4589347AAB85F6FFFCE1EDE756864438821C427506397307367819398625458B
+ 459AC8A4F2FEF8FDFFFF49AB777ABF94E4FFEFF1FFF9FAFFFFFEFDFFFFFBFDFF
+ F6FCE7FCE6A7D3AE479A553A92383671092E5C033B64081E4C00275000275000
+ 295000284F01274E00284F012950022950002D55032A5101274E00274E002950
+ 022A5103295002274E0029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E00295002295000274D01284F002D54042C5500284F00274E00295002
+ 295002274E002950022D54042B5202274E002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F01274E00264D00274E002950002D54042E55052E5604284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C002A4E012A4E012A4E012A4E012A4E012A4E012A4E012A
+ 4E01274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000284C00284C00284C00284C00284C00274A0026490026
+ 4801274A00274A00274A00274A00264801244600244600244600274A00264801
+ 2648012848012645022844022642002442012640002640002640002640002640
+ 00264000263F01253E0026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000274101264000
+ 264000253E00253E00243D00253E002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002850022950002D57002951002E5604284B01295002274D012C4F002C5004
+ 2954032B5500346001386E0A38772753954667A367EDFFF2FEFDFFFBFEFC6CA6
+ 76398A352A72083561022E55072B50002A4E01294D012A51012E5A0132690244
+ 831B46913D468E52B6E7C7FDFEFAFFFFFFE5F1DF57965830812434690B2E5A01
+ 295300254A022749022D51002D59003C6C0C47862844923A559855D4F9D9FCFE
+ FEFEFDFFBFF2D069C895FAFCFDF5FFF9C2E7C7478B4438821C3C6D0B31610122
+ 5300254A002652002F59013C6C0C44831B44873668A678F8FFF9F1FFFE74A775
+ 4487362A7207316900335B0338630C40791747862842923997BA98FFFFF7F7FF
+ FD4899543D9D424D9646B2CDB9ECFEF16E95683689343D9E402A973144B56544
+ B4663EBF6A7ABE95FFFEFFFEFEFEBFF2CD54B57344B67658B16C529B63569966
+ 578B55457731467733448A444BA45446A965A9D8B8F0FFF5F0FFF998D6A856B2
+ 693D91433B92363D912B426D16326B0936761638821C3A914787BC94F9FEFCFE
+ FAFFF3FFF95698572F80232B7515315B032854012A52002B50002F55032B5900
+ 2D59003473053D902D48985598C7A6FFFEFDFFFEFFB7E5C845B5673CBF6847B8
+ 7587CBA2EEFFF6FDF9FFF7FEFB85CBA247A86547A96345A961C8F2D9FFFAF7FF
+ FBFDA6C8A9438B453A801B3269022F56003151042650022B580134630738811D
+ 46863A95BF8AF7FFFEF7FFFE86B4892F7F243A7A2836761638821C398A355196
+ 4598C8A4F5FFF9FFFAFF86CBA6E5FBE8FEF9FAFDFFFEEDFEF5F8FDFBFBFFFFF7
+ FAFFFFFFFAE5FFF26AAD8048984537821A437607315B03365E06284F00295000
+ 295000284F00284F01284F01284F01284F012D55032A5101274E00274E002950
+ 02295002284F01264E0029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F01295002284F00274D01284F002B52022A5200295002284F01295002
+ 295002274E002950022A5101295000264D002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000285002274F01264E00254C00254C00264E00274F01274F01284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284F00284F00284F00284F00284F00284F00284F00284F00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000284C00284C00284C00284C00284C00284C00284C0027
+ 4A00274A00274A00274A00274A00274902254701244600244600274A00264801
+ 2648012547002645022743012845002844022640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000274101264000
+ 264000253E00253E00243D00253E002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000234A00274E002C5101274D01295002284C002D5104274F01274A00274C02
+ 2853022C56003763044278174587284698467BAD85F7FEF9FFFFFFEDFEF1538E
+ 542F7F24336C0A305C002E55072951002A5103284C002D4F0232560233600043
+ 7A17478F2B4799468BC797F9FFFAFFFAFFF8FFFF67A268358627346B08335B03
+ 295600244B00264801305100315C01396D09447A1751953C489857B7E5C8FAFF
+ FFFFFFFEE6F9E899D7A9FFFEFFF7FEF9ABD7B8498B432B7614376403375B0123
+ 51002D4E032D55032B58013E6B0445821A478B38568A54EEFDF5F9FEFFB2D2AF
+ 4A77323A761832680433610032620A4379164287374794389AC8A4FBF9F8F5FF
+ FF4698463B9F40519646E1EFE49AC8A4478A45398A353E9F414CA35348A35457
+ A9753EC26578BE95F5FCFFFEFDFFC0F3CE51C4753DC06936A750399F403A8628
+ 2D73183A771543831947902E48923A479947A6C7ACF5FFFEEEFFF268A7753990
+ 4646913B47862A316904405C032A67003A6B003973073A923872B07CF7FFF8FE
+ FAFFF8FFFE65A2682C88352C69132F5C002E5A01305505264B01254D00285200
+ 29560031690438811B46923A79AC86FFFFF9FFFFFFD7F7E655B16A3DC16757B5
+ 74B6E4C7F3FFF6FCFFFBEEFEF36DAD834BA35048A5544DA355AEE1BBFDFEFAFF
+ FEFFB9D6BD468A433684193268052D57002A5204254C002C55003263073B8319
+ 46883684B589FAFFFFF9FFFEC2E6C84989473984282E7616317F273B912B4797
+ 549BD6A9F1FFFBFEFCFCF7FFF8F7FFFFFFFFFFFEF9FAF6FFF19CDAB6B8E6D3EC
+ FFFBFEF8F9F9FFFACAF2D967A3674688374279163E6503275600284F00284F00
+ 284F00284F00284F00284F00284F01274E00295100295000284F00284F002950
+ 0228500227500027500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000264D00284E02284F01264C00284F00295000295000295002284F01284F00
+ 284F01274E00284F01284F00284F00284F012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000285100275000274F01254C00244B00234A00234A00244B00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274B00274B00274B00274B00274B
+ 00274B00274B00274B00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284F00284F00284F00284F00284F00284F00284F00284F00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274A00274A00274B00274A00274902264801264802254701274A00264801
+ 2648012648012645022743012845002844022640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000253F00
+ 264000253E00253E00253E00263F012640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264D012A50042C5305284D03275000274E002950002851002B4F02284C00
+ 2A52042F59013D6402437918478F2B439945A5C9ABFFFFFAFEFEFED7F6DB488B
+ 4638811A326B08315C012951032A5004294F03284C002F4D01305400325D0242
+ 6C1443882748974674AF7CF5FEFBFEF8FDF8FEFD87B6883989363672062F6200
+ 2D5900284F00254B002C4D022F5404345E07427A1546913B54954986D5A2F8FD
+ FBFBF9FFFFFEFABAE8D1FEFDFFF3FFF998C7A63C88362E75183A640030540026
+ 51082950002953002B5A00386401447A17468D2D468F51D8F7DCF7FAFFE5FCE6
+ 57854A3676163773073169003369054279164A8737479139B3D3B0F9FFF9F1FF
+ FE4A9A55399F4048923AD9F7E475A876459139459647448E5465A57798C9A3A7
+ E5C1B7F7D9D7E9DCFFF6FFF5F4FEBDEFCD69BA7B44B56535A9503C902A377717
+ 346A093269022F71072E812539913748A354A7C9ABEFFEFFEBF8F669A4774792
+ 3E378625407409426A05375A0332610042690743730938923868A468F4FFF7FF
+ F9FFFAFFFE75B17B3C88362968123460012B59002C5109244900284E06295103
+ 375A003864013A740837913866A567F3FFF3FFFAFFEDFEF364BB773EC06964B9
+ 7BDCF7E7FCF9FFFFFEFAD7F6DB44A9654998474AA2564AA35486CCA3FFFFFAFC
+ FEFEC8E5D6478A473A811A3469022D57002C52061F4E002B5204305C033A7717
+ 45912C589857F0FFF7F8FBFFE6FCEA72B07A3789363181242D7F26399339489A
+ 5298D5A9F1FFF6FFF8FFFFFFFFFEFDFFFBFFF9EFFFF499C8A267BA7C69B887B9
+ F9D6FEFFFAF8FFF8F3FFFFA8D7B64B8A4537821A3773073361012B52022A5101
+ 295002295000295000295000284F01274E00284F00295000284F002950002850
+ 02274F0127500028510029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000264C00284E02294F03274D01274E00284F01295000274E00275000285100
+ 285100284F01284F00284F00284F00274E002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000264D00284E02294F03284E02274D01264C00254B00254B00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000294D00294D00284C00284C00284C00284C00284C0028
+ 4C00274A00274A00274B00274A00274A00264801264801254700274A00264801
+ 2648012648012746032645022845002544012741012640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000263F01264000
+ 274101264000263F01263F012640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000294F032A50042A5004274C02285100295000284F002851002C51012B5000
+ 265604315D003B6B0142841B51963B469846CAE5D5FEFAFFFDFFFFA8D7B73B90
+ 463A751A3269022D5702295100264D00284C00254800294D01305400335C013A
+ 6D0B51842846984654A965F0FEF3FDF5FFFFFDFFA8D6A83889343A77172D6401
+ 2E59002A5204284C002B4E002C5600375A034074083D902D51954868BA85F9FE
+ FCFAFAFFFDFFFFE4F5F1FAFAFFEDFDF283BE92378A3530731736650031550120
+ 5200264B01214E002E550031620042740839902E488C51C5E0BFFAFAFFF3FEFB
+ 77A5763984283772093C6D05316900437B16458735449338AFE2BCFFFEFFF2FF
+ FD4699553CA04048913BE5FEF4498B4446923A569759A6C8A9E5FCE6F6FFF4F4
+ FFFDFCFFFAFFFCFFFFFAFFFFFFFFEDFFFE9ADAB654B888249C4B3B7927397517
+ 3D69063E6A053368012D7515378936469846B7D9C1FDFEFFFBFFFF6D95653784
+ 2937821A316902385B002E51012D58013665023472083D912B478D51F4FFF3FF
+ FAFFF6FAFF74B07A3989362E7515376502315B042D5307274D01224C00274C02
+ 375C00315C012C72073D902D579658D8F7DAFFFFFFF2FEF88BC79748B6766CCA
+ 94F2FEFEFEFBFDFEFFF8A6D6B943995346923A48A13951964657A975F5FDF6FC
+ FFFAE3F8F0578C5335821A377307315D00305407224D002B5305385B04387205
+ 3E912B468944C5E0BFF7FAFFF6FDFFC4E2BF4899543688353B8C374797444AA3
+ 549BD6AAF0FEFAFEFAFFFAFFFEFBF9F8E5FBE884CAA654B16C4BA25254A86744
+ B873E7FBE8FDFFFFFFF7FEF0FEF868A7753D922A2C72073962062E55052B5202
+ 284F01274E00284F00295000284F00274E00284F01295000284F00284F002851
+ 00274F0127500027500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284E02284D03284D03284E02284F01274E00274E00274E00285002285100
+ 274F01285002275000295000295000284F012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274C02294E042A4F05294E04284E02274D01264D00264D00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 002950002950002950002A4E01294D00294D00284C00284C00284C00284C0028
+ 4C00274A00274A00274B00274A00274A00264801264801264801264900254701
+ 2547002648022847042746032847022847042842022741012640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000253E00253E00
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274C02274C02274C02284D03285100274F01274E02254C002E4E01294A00
+ 295201345E073C6C0C47821A51953C469846E1EEE6FDF9FFFFFFFF9AC7A63893
+ 362F76163162002E59021F4D00254C00284B012645002A4B002C520030540042
+ 69075283273D912B489954EBFFF3FFF5FDFEFAFFC8F2C93C933944831B2A6601
+ 2C5402295004294E002E5200315600345A0040730B35821A46994456A975FCFF
+ FBF9FBFCFEFBFDF6FEFDFFFEFEF0FFF878B7853B89352D75153965023054001E
+ 4D01274C04284C002B5900375A044074093B8428488E51A5C9ABFCFBFFF3FFF9
+ 9CC8A34688363574063469023B6B0141821C46883646913DC4E6C8FCFFFDF3FA
+ FD479A55399F4044923AB6DAC4478B4448923A9AC9A3F5FEFFFFFAFAFDFEFCFD
+ F5FFFFFDFFFEFEFEF9FFFAFAF9FFFFFFFFF6FFFCC9F1D869A4773888352C6913
+ 305D003864013B6C0439751744862753963BC3E7C9FBFFFFFAFFFE77A7773C8F
+ 2C2F7209296500315C012A50042B5700385B003B6C003C8F2D458D51F3FFF3FF
+ FFFFFDFFFF76B27C3889343877173B6A032C56002849062B4D07225200214C01
+ 2F5700375A0434690238902C498A45C2E5CAFCF9FFF1FFF991E1AC49B77585D5
+ A0F5FFFDFFFBFDF3FDED88BD95279A4A46913B3A902A5297473F915DDEF1DEFF
+ FFF9F2FDFA598B5536831B3872063461002D5406214C012B52023C5301326902
+ 37821A53953C869F85FEFFFDFFFFFFF6FFF257B06B469A524698464798494BA4
+ 5498D6A8F3FFF9FFFBFDFEFFFBCAE4D66DAD834898553B92362896303B9F4038
+ A75178BE96F1FFF9FEF6FDFFF9FFA7D5AB3B9F4038811A3864003259092D5404
+ 295002284F01284F00295000284F00284F01274E00284F01284F002851002851
+ 00274F0127500027500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A4E012A4E01
+ 2A4E012A4E012A4E012A4E012A4E012A4E012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000264C00284D03294E04284F01295002274E00274E00284F01285002285002
+ 285002295103274F01285100285002284F032950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E02284F03295004274E03244B00234A00244B00254C01284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00274D01274D01274D01274D01274D01274D01274D01274D01295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000294D002A4E01294D00284C00284C00284C00294D0128
+ 4C00274A00274A00274B00274A00274A00264801264801264801264801264802
+ 2449012648022647042746032847042847042842022842022741012640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000253E02243D00
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000295000295000295000295000295000295000295000295000235100295300
+ 2E55003E5C034175094686264889344AA354FBFFFAFFFFFFF2FFFD86B4893989
+ 36346B083562012956002A4E01294D01274B00284B01284C00294D002E550036
+ 5E0644841A48923A589759BBE7D0F9FFFDFCFEFEEEFDF5568D563A8628336C0A
+ 2B59002F4F00254A04264900285100315D0032690246841852964953A766DCF8
+ E5FBFFFFFEFEFEFDFEFCFFFEFFFDFEF467BB7B3B92383A73062766002C550027
+ 50002F56002C53002952013965023D740755912C4F97458AD4A4F5FFFEFAFEFF
+ D5E9DC547A4838862832690240740851842A488F2E489746C5E0BEFFFDFFFEFF
+ FD54A66547994746994482BA6D55854A889E82F5FFF2E5FAEBB8DAC284CAA255
+ C3756CC897A5E5C2FFFFFFFFFEFFFFFEFAE5FFF0FDFEFAF8EEFA5786482B7515
+ 2B6401265A003965083A771747902E489746CBE4D6F9FEFFF6FFFA77A5763784
+ 282C72073462002A5B072253003C53012E5900396B0D388529478D51F5FFF3FE
+ FAFFFFFFF86CAC82398837417A172D64012F56012F4C032A5302284C00264D01
+ 3055052D5900426A054D7A1D5096498AD5A2FFFAFFF8FFF8BFF2CD3AB26BD8F7
+ DCEAF7F9FEFAFFFFFBFA57A7663B883745862A46862636862948A453A5C9ABFF
+ FDFFF7FFF888A9873B7927377209326A012D57022B5600245A01245A00305C01
+ 437A1747862A49A455B1E3B9F7FEF9FEF9FFBFF1CF559C644EA25437A75345A8
+ 64B5CFB8FAFEFFF5FFF987DCB054A5664CA353468F2D437A1737792744831B51
+ 912D4BA552A5E5C2FBFFF7FEFAFFF7FAF867A2683B89363D6A033361012D5900
+ 2E55002E5101274902294D00285204234D002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C002950002950002950002950002950
+ 0029500029500029500028510028510028510028510028510028510028510028
+ 5100284C00284C00284C00284C00274A00264801264802264802274A00274A00
+ 2649002446002446002446002648012648012844022844022844022743012443
+ 0022420121410023400126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000295000295000295000295000295000295000295000295000215100234D00
+ 305001415D0342730947902E45933C65B169FEFFFBFFFDFEF1FFF979AD853984
+ 28397209335F00295000284C00284C00274B00284B01284C002A4E012F560136
+ 5E0640791647902E489A52B7E6C6FBFFFFFFFFFFF3FFF269A5753B8527316D09
+ 2E58002E5101254C01244B002A51032D5C003D6A0347831E52973C559C64C7F1
+ D8F9FEFDFFFFFFFDFEFAFFFAFFFFFEF464B87D3A92383671092966003155012A
+ 4F051D4B03295103315503315C0132690241852653984798D5A9F4FAF9FFFDFF
+ EDFFF264A46836852A3782184379183D792548912D439745C3E1BEFEFDFFF9FF
+ F655AA7844994549923C46913B5A8C56D5F7D9BBD6BC6C9667458C533E945E55
+ B16A56B4739ADAB6FFFEFFFEFEFEFEFFFBB8E5C4E9FCE9FFFEFF97BE8A3A7826
+ 326A012B64013A6301387618428627449944C5D9CDFBFFFFF7FFF878A6773885
+ 292B70093360032950001F53003C5400305C033469023885293C9244E7FAE9FE
+ F5FFFDFFF96AAF843C88364379153469022B59002F4D022C5101284F01254C01
+ 2C56002E550038640043781A458A476BC895FEFDFFF5FFFED9F6DD54B985E5FB
+ E9F5FFFEFEFBFDEDF2F04499453687264278173976163B912B47923E76A574F5
+ FFFFF2FFFDAECDAC497631387814276501315B03274E002753002252002F5B02
+ 3B640247862A43913976B986EEFFF2FFFBFCEEFEF396C9A44AA4513DBF6A48AB
+ 63B8D8C5FBFFFFFAFEF985CCA14999543688352F75182B6702326307346A093B
+ 821B3D8F466DAD83ECFDF4FBF6FFFAFFFEA7D8B843933638751A3460032D5801
+ 305402285000274B00284F03285205214D002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C002950002950002950002950002950
+ 00295000295000295000284F00284F00284F00284F00284F00284F00284F0028
+ 4F00294D01284C00284C00284C00284C00264900264801264802274A00274A00
+ 274A002547002446002446002648012648012645022844022844022743012443
+ 0024420123410022400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274E00274E00274E00274E00274E00274E00274E00274E00205100274E00
+ 2E520038640041730D498F2B4F94496BBB86FFFFF7FCFEFFEFFEFA69A6743785
+ 27377504315B03275201284C00284C00274B00284B01284C00294D002F560136
+ 5E0642740846913D479B53A5D6B6FCFEFFFFF9FFF5FEF485B6883885292D7515
+ 315C01315600274C021F4B002A52002E5A003A6B0343781751953E469A52BBE6
+ D1F5FFF9FFFEFDFFFDFEFFFDFFFDFFF968BB84378A353B6C0A3562013354032C
+ 50001C4D012750052A5302305B003E6D0B4A8E2F5795598AD4A4FFFEFDFFF9FF
+ F6FEFD87BC943B842844841A39751744852943923B469846C8E0C0FEFEFEFFFE
+ F966B97B4397453A923838912A68A775D5F6DB62915245772F46923A44994546
+ A96555B1689CDBB4F8FEF9FDFFFFFDFEF47ABE95A6D7B7F0FEFAD1EFD2467832
+ 2965013A6B013862034479184388274DA257C9E6D7FEFEFEF0FFF87AA6773784
+ 2938730A3965002A52002A54003D54003161013468043B8428469846E0F0DEFF
+ FFFFFCFFFB6AAC833B893546821D3269022F5B00304E03284F00295100274C02
+ 2952002B54003965003E6B0A46883667BB7BFFFAFFF1FFFDECFDF29BC9A5EFFD
+ F2F9FEFFFFFAFFB8D8C73A913938811A3876183A6D0B458329378527478A45C4
+ E6C8F7FFFED3EFD2517A4739821B316A013461002A5701284E02264D00325A08
+ 315D00427719378527589759C4E6C8F9FFFEFBFFFFDCF7E769BB8639BE6753C3
+ 75B7E6C6F5FFFEFFFEFF89CBA2478C533B8428306C08235801285B002C650234
+ 7206488F2F4C9545B8E5C4F9FFFEFFFFFFE5FBE8568C572F8023316801325E01
+ 285500305100284C00254C012751042150012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00294C02294C02294C02294C02294C
+ 02294C02294C02294C02284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274E00274E00274E00274E00274E
+ 00274E00274E00274E00284F00284F00284F00284F00284F00284F00284F0028
+ 4F00284C00284C00284C00284C00284C00274A00264900264801274A00274A00
+ 274A002648012547012446002648012648012645022743012844022844022642
+ 0024420123410022400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274E00274E00274E00274E00274E00274E00274E00274E002C52002A4E01
+ 2E550041640D3F78164587285097478DC896FCFDF9FEFDFFEDFDF2519C662F7F
+ 24357307335C01285302294D01284C00284C00294C02284C00284C002F560136
+ 5E0643740A498E2D45974599C8A7FBFFFEFFF9FFF8FFFA9AC9A33A8E2F397614
+ 3162002959002950021F4D002A4E0131560039650243791648923A489954AFE4
+ BCF1FFFBFCFDFFFFFEFFFAFEFFFDFFF96CB9863B89363D6B0B3460032E55002E
+ 53002854012956002D5601366100377406448F2D48A25694E2ACFEFDFFFEF8FD
+ FBFFFFB7E6C6468A37468529397616398A3548923A479947C7E0BEFFFFFFFFFE
+ FE67B88744984646923A468837ABD8B786AA7630610B46781A3C8F2C3A923848
+ 974658B16B91E0AFF6FFFFFFF9FFFCFDF345AD7667B887B3E3B9EDFEFA558845
+ 2965013D6B003A6301407916458728469846CBE5D5F8FFFAF7FEFB78B7853C89
+ 383673053A6B012D59002D57023953003063073776163B922A459854DAF8E5FE
+ FEFEFCFFFB6DAC84398A354079162F6904335C01304D042850022D51002A4E01
+ 2850022F5503306000386C0E3D842755B168FEFEFEF2FEFEFEFFF8D4E8DBF3FE
+ FBFEFDFFFEFDFF78BF973A92382F7616396C0A436907447A1747821944883575
+ B27AF4FFFDEBFFF26E9567397A252E7205326804325B002E4D08295000315503
+ 345F0431690439831951964687B489F0FDF5FEF7FEF7FFFEB3E2BB43B66752C2
+ 75B8E7C7FCFDFFFFFDFF88D5A2458A473D7925316A012E59022E580131620036
+ 6B0A43821A48923A6CAE84ECFDF2FEFAFFFBFEFC86B587398A353675072D6500
+ 285500285100284C00274E002B5202274E022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274E00274E00274E00274E00274E
+ 00274E00274E00274E0028500228500228500228500228500228500228500228
+ 5002284C00284C00284C00284C00284C00284C00284C00274A00274A00274A00
+ 274A002648012547012547012648012648012645002544002744002844022743
+ 0124430023410023410026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274E00274E00274E00274E00274E00274E00274E00274E002E4F04254C01
+ 2F56013964094379154486274F95489AD6A6FAFFFDFDFFFFECFDF2578D52327F
+ 243A72072B59002A5204284C00284C00284C00294C02284C00284C002E550034
+ 5E063B6A0345862A3A914782BD91F9FEFCFCFDFFFBFFF9B8D8C5479139377618
+ 336200325B002C51011E4C002A5004325302386401407917468F2D4BA4549BD3
+ A8F8FFF9FFFEFFFAFFFFFAFAFFFDFEF566BB893B92383A76182C6503385B0031
+ 5503315D002D5900315C013A6C0E37821A4B9E3B53A86492E2ADFFFAFFFDF9FE
+ FFFFFFD8F4DD46894644831D39831939832954973C459744CFE5CCFFFEFFFEFE
+ FE6DBA873A914746933845772FECFDF2508528386C013B6B0B38730B3A832749
+ 9F3B48A45388DCB2FCFFFDFFFEFFFEFCF448B77343B66661B269E3F7F26D9663
+ 32620A3169023D64024173074886283B9046CAE5D5FBFDFDF8FFFC85BD924591
+ 3938811A3B6C0A2E5A07265B00385C022A69133C84243B933948A157F7FDECFF
+ FFFFFDFEFA6CAC823C8A374278172B64012E5A012F4C03294D002E51012A5103
+ 2650022D5400346301356B073A852949A455F5FBF6F9FEFFFFFEFFFDFEF4F0FF
+ FEFFFDFFF1FFF857A877478F2F3366043463013F68063A6B01417A18488F2E47
+ 8A47C3D9CDF2FFF9B2D3AE4776312C73052F6A022E5D013054082E55002A4E01
+ 345F08325B0039821B44913D569956B5E6C6FAFAFFFFFDFFE5FDE56DBA874AB7
+ 72B4F8D5FBFFFFFEFAFF8DC7974588373A76183169002D59002F56012D590031
+ 6200437509498D2E458D51BBEAD0FCFEFFFEFEFEC5E0BF478A45397616296501
+ 2B59002A5400264C00284E022951032750002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274E00274E00274E00274E00274E
+ 00274E00274E00274E0028500228500228500228500228500228500228500228
+ 5002284C00284C00284C00284C00284C00284C00284C00284C00274A00274A00
+ 274A002648012648022547002648012648012547012746012544002744002743
+ 0126420024420124420126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274D01274D01274D01274D01274D01274D01274D01274D01294D012C4C00
+ 2F5503366401437918488F2E579756B1E3B9FAFFFFFFFCFEF6FFF3478D513883
+ 193167032E5A012A5004284C00274B00284C00294C02284C00284C002B540031
+ 5B033B6B0145882749974479B886FAFEF9FEFAFFFCFEFFC6E5D64498463B7925
+ 356806335C012C5101214E002A4F002A5200365F03437A17468F2B48A3549BC9
+ A5F5FFF9FFFEFFFCFEFEFFFEFFFFFFFA6BC895389147447A172A6300305D002C
+ 5902366500336101346B083B79273B922A47984963B26999D9B5FEFEFEFEFAFF
+ FFFEFEE5FFF264A5564079173A811A37852753953C459947D0F1CFFFFAFFFFFF
+ FF67B9853C914746923A437731F4FEF83460013B6B012E5D014074093A771746
+ 8F2B46984598DAB7FCFFFDFFF9FFF3FFF34BB77546A963479853C7D8CD7BA26B
+ 346A092965003B6B0143740A44902B3C9147C8E5D6F9FFF9F7FFFE92CFAB4999
+ 523D902D3676162968122D69113665092E75153B923C3CA04046AA62F7FFF5FF
+ F9FCFDFFF967AF803A88344279162C66012E5A01324E022151022B5100274F01
+ 274F012B5600315C013167033686294AA354D5EBD9FCFBFFFEF8F9FEFEFEF2FF
+ FDFDF6FDDBF8E848985139821B326902305D003C640C3F680639730745821A39
+ 79276C9667E6F9E8EBFFF36790573869173068012D6302325A082E59022A4B00
+ 2F500034630137720946821E55994678B686F0FFFBFFFFFEF5FEFBB6E5C558AA
+ 76B7F8D8FAFFFEFFFEFE89D3A34688363A76183768062D59002E54022E590031
+ 5B03346A0944831D41994578B785F2FEFEFFFAFFE6FCE9458C533B811C2D6C06
+ 285A022E55002A4F002B4D00284F002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C
+ 00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274D01274D01274D01274D01274D
+ 01274D01274D01274D0129500029500029500029500029500029500029500029
+ 5000294D00294D00284C00284C00284C00284C00284C00284C00274A00274A00
+ 274A002648012648012648012648012648012648022648022446002645002844
+ 0227430124430024420126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254C00254C00254C00254C00254C00254C00254C00254C00294D01274D01
+ 325400336101407916478F2F569759B5E6C6FBFFFFFEFDFFF4FEF1468E523883
+ 1B316A012E5A01265108284C00274B00294D01294C02284C00264C002A530030
+ 5B003C6B0444852947994776B079F8FFF9FEFAFFFEFDFFE0ECE64698462E8027
+ 306803305C01285500244E012A4D032C4E01375C0042740848902C43984485BD
+ 94F5FFF3FFFFFEF9FFFDFFFAFDFFFDFC87D6A34BA4554587352F7717346A0934
+ 6A092F73063976163988373B8A3346995465A57797CAA4E4EBE8FDFEFAFFFEFE
+ FFFDFFE5FFF276A16842791638771736862944923A489A52E5FBE9FFF9FEFEFD
+ FF68BA86479B4345903A4F8427ECFFFC427309396A02375F073673053D792544
+ 87364CA254B8E6C9FEFAFFFDF7FCF3FEF466BA7A4AA3543B9D43A5BBA878A469
+ 3772092867013673053B74193B902E469A52E2EDE3FEFDFFF4FEFEA9D8B854A6
+ 654AA3533A91393080252E8224397927398A354898454AA35457BA8AF0FFF1FF
+ FBFFFFFFFA7AB6863B903B36831B2B6600315B032A5000245200285200254F02
+ 274E02325500325B002E66003882183B9E42BCE6D4FDFFF9FAFFFDFFFEFFF4FF
+ FDFFFEFFB6E5C5439846387717326804336200365E064369073E750843740643
+ 7918397A2595BF88EEFEF3B2CCBA5485473A7408346902336200335C01255100
+ 294C02345E07326902387507479139569857B5E6C6F8FDFBFFFDFFE6FCEA7ABE
+ 95C8F3D8F9FEFFFFFFFE8AD5A24586373878153063092B560028510029500029
+ 55022D650037761846923A579755D9F6DCFFFEFFF7FFF868A77545821A357406
+ 325F022B5900295000254C002550002851002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002A4E012A4E012A4E012A4E012A4E
+ 012A4E012A4E012A4E01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00254C00254C00254C00254C00254C
+ 00254C00254C00254C00284F01284F01284F01284F01284F01284F01284F0128
+ 4F012A4E01294D00294D00284C00284C00284C00284C00284C00274A00274B00
+ 274A002648012648012648012648012648012648012648012446002645002645
+ 0228440226420023420026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264D01264D01264D01264D01264D01264D01264D01264D01344D032B4D00
+ 2D5801335C013A7717468F2D5A9659B9E7D1FDFFFFFBF9FFF4FFF4478D513881
+ 1B3268042B5900265106284C00264A00294D01294C02284C00264C002A530031
+ 5C013B6A0338831944994577B17BF5FEFBFEFAFFFEFDFFF0FEF24898452E8027
+ 3469013362002B5500274E002B4C012E4E01385B013F750A498D2E47994778B7
+ 85F4FFF3FEFDFFFCFEFFFCFAFFFFFEF98ADCB143A86454963D46852744831B3A
+ 852946852937943944984656B47491E1ACDCF8E5EEFFFCFCFBFDF3FFF0FFFEFF
+ FBF9FFA6C8AA477631396C0A4479183B8329468837469A52F3FEF4FFFBFFFEFE
+ FE68BC8648A3543B893644841AE5FFF9538438336A03416D142D730842862749
+ 894749A455BFF2CDFDF7FCFFFAFFF3FFF96AC9974AA3543B92368AA99465A357
+ 2D7308316902437A1743821A3A913B47AA64F4FFF5FFFEFFF1F9FFA0DAC854B6
+ 7445B5674AA2563A92463D9E4053953C48A3544AA45155B06B6BC895F5FFF2FF
+ F9FFFFFEFA78B68646984544831B326A01335C012C5300215001284F00284F03
+ 284D052B5204305C032B64013A811A3B9F40A9E5C3FDFEFAF7FFFDFEFAFFFDFF
+ FFFFFAFA88D4A43A91373877172D6401346003295300375B0143740A3B6A033A
+ 6D0B2E741745772FC6D8CBFAFEF86A95683B75162A72072A65032965002C5600
+ 2E54082E550534600137730738862846984668A678F7FFF3FCFEFEF3FFF2B7E6
+ C6BCE8D1FCFFFDFEFFFD9AD5A8468C453976163063092D54002950022C520029
+ 56001E630241771646821D489954B6D7BCFFFFFFF6FEF398C8A4458728357307
+ 2E65022F59012A4E01284F01294E00284E022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002A4E012A4E012A4E012A4E012A4E
+ 012A4E012A4E012A4E01284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00264D01264D01264D01264D01264D
+ 01264D01264D01264D01274D01274D01274D01274D01274D01274D01274D0127
+ 4D01294D002A4E01294D00284C00284C00284C00294D01284C00264900274B00
+ 274A002648012648012648012648012648012648012648012446002446002645
+ 0028440227430124430026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00274B00274B00274B00274A00274E002C4E01
+ 2E550033630A4074083C8F2D478D50D6E9DAFFFDF5FEFDFFEFFEFA478D503882
+ 1C326902345E07254B00264C00254B00274D01274F01275000284F012A4E012E
+ 55053A6C0050791E54954946A866F9FAFEF9FFF9FFFEFAFDFFF9489A512F7F24
+ 336C0A3462002C5500264B01255100274D011B620142730948902C53953C67BB
+ 85FCFAFFFFF9FFFDFEFAFFFEFFFEFAF9CAF3D844B67637A8503E9F4152974646
+ 99554699548DC896C7F1D8F5FFF8FFFAFFFEFBFDFFFDFFFDFFFFE5FFF9B9E5C8
+ 77B07D4391393A72072C710834720844831B3B8935579756F5FFFEF9FAFEFFFE
+ F67ABE9548974638923945772FCBF2CC659154396C0B35740637751749883848
+ 9E38549A65D2E5CAFEF6FDF8FBFFE9FEFB7DBF964AA354458A4797BD8B558747
+ 376B183B79273A852938923837A8503EC069F3FFF9FCFEFFFDFCFEE6FCEA85CB
+ A289CAA3A5E4C4C8E5D5E9ECF4FFF9FFFFFBFDFFFFFFFDFDF7E2F1DCFBFFFFFE
+ F5FFF1F8FF85BD924CA25428931F2A66013864092A51032659002C5300285100
+ 295100305003365D013B65063B79273A9147ABD7B8F4FFFDF4FFFCFAFFFEFDF5
+ FFEAFFFC63B269478A473B6B013462002D58012B52042D54043760053B6A043B
+ 6B01377209407408568539D5F6DBDCF9E2558747326B09397307235E0D265A00
+ 2E59002C51012F5208375B1538771753922C469954AFE4B9F8FFF9F4FEFEF2FE
+ FEDBE2E5FFFFF8F5FFFFA8D7B6498B4438811B2A65032D5900225200274E0030
+ 54083054003D6B0B417B1653953C75B17BECFFFCF3F4F2D1E5CE3A902C3B8319
+ 346902305B043155012B4E042749032852002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00264D01264D01264D01254C00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000274E00274E00274E00274E00274E00274E00274E00274E00295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00284C00284C
+ 00294D01284C00274B00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C002648012648012648022648022648
+ 0225470124460024460028440228440228440227430124430022420121410023
+ 4001264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00284B01274A00274A00274A00244D022C4F00
+ 2B51002C5A07396C0A39922B469A52E5FFF2FCFEF8FFFBFDF1FFF65797563985
+ 272C6503315B082B5000274D01254B00264C00274F01275000284F012A4E012D
+ 54043B6A03437A174591394AA354FFFFFFF7FEF9FFFFFFFFFDFF4497483B852B
+ 346B083460012B5600274D012951032850002E65024169034485294D9E3D7ABD
+ 96FDF9FEFFFDFEFCFFFAF3F6FBFBFFFEC8F0D748AC7854C27467BB7B86BF92A7
+ E4C2E5FFF2EDFDF2F9FEFCFFFFFFFEFDFFF7FAFFF3FEFBEDFCF48DC89668A676
+ 5386363777173269022B6401316D094378174598494AA353F4FFFDF8F9FFFCFE
+ F887CBA24599473B933939792765A268A7D5AA396917377307478E2D3A902C4A
+ A35346A963CEF1CFFFFEFFFEFEFEF4FFFA69C9933BB1683CA0414698463C8935
+ 398A353C923A43974549A55457B06A55B673FDF6FDFEF5FFFDFCFEFBFDFEF1FF
+ F6EFFFF8FDFFFFFBF7FDF9FFFEF5FFF9F8FFFFECF5F9FAFFFFFBFFFFFBF9F8FF
+ FEF4FFFAFFC7E6D767A3663784284378172D56013B630B2052002B5600285002
+ 275103305001375A033765023876183C91479AD6A6FBFEFCFCFEF2FFFFFBFFF9
+ FFC5F2D84899543A85293B6A033461002B56002B52042E5505335D053765023B
+ 6B0137740641750A3B6B0B609153D7E9DCCAE4D6517A472C65023169042C6601
+ 355D052D55032C5A012B64013876184589343EA04086BC91EDFEF3F7FFFDF3FC
+ F9F2F4F4FEFDFFFCFEFFBAE8D246974837821A2B6500315B082A54002951002F
+ 4C03375B0132620228730747862866A369E6FDF9FBFFFFF2F6F146913B37821A
+ 3269022D59002A52003253092C4D022B50002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00274D01254C00254C00264D01274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000284F01284F01284F01284F01284F01284F01284F01284F01295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00284C00284C
+ 00284C00274B00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C002648012749022648012547002648
+ 0226480224460025470126450228440228440227430124430024420123410022
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00294D01284C00274A00274A00274A00254C012E5200
+ 2751002B5C06426D163D8F2C499956F1FFFBFFFFFFFFF9FFF0FEF8478D513687
+ 28316902365E06285002274D01254B00264C00285002285100284F012950022E
+ 55052C660143821A4899444BA455FFFCFDFBFFFFFEFDFFFFFDFF4799473A8327
+ 306C08356104285100214C01284F03284F00265A004069084685274BA03868BC
+ 86FFF9FEFFFBFAFDFEF5FFF6FFFDF8FFFBFFFFB9D9BAB9E5C6F0FDEDF8FEF9F2
+ FEFEFFFBFDFFFBFFFFFAFFFFFEFFF7FFFFE5FCF8A7D9B76AA77567A257518537
+ 387B263472063269022B64013069003877173A923848A453F3FFF8F7FFFEFDFF
+ F68FCEAE4698453A913543821A467830BBD6BC9AC9A3448A443C912F3A9E3F47
+ A8653EC069BEF0CEFEFFFAFDFEFAF3FFF28EC89843B66738A8503B9E423CA041
+ 3C914748995466A3698EC997B7E4C9D6F9E5FCFEFFFEFAFFF7FAFFFBFFFEFFFA
+ FBFCFEF8FEF5FFFEF5FFCAE4D6A5D6B685CBA386CCA486CDA2BAE8D2EDFEF3F3
+ FEEAFEF6FDF3FFFFE4FEF198C089386B14436D161F4D013064062E59022C5200
+ 2853022E5200375B013965003A731644943B6CC996F3FEF4FFFFF3FDF6F3F6FB
+ FEB1E2BC4B9F3939821B3B6A043361012B55002B52042E5505315B033663023B
+ 6A033D6B013361013B6C0A466F146B9369C8E5D5C6E0C245772F3973062D6401
+ 365D0139620D3362002D64012E7207478E2E4AA35457A766B5E6C6F7FFFDFFFE
+ FFE8F7F9F7FFFDFCFEFEC7F2D75398483882183460012F5C062855002652002D
+ 49033255002E59022E700A3B821B578648C9E7D4F5FFFFFFF8FB5898563A8529
+ 346908325D022953002E5101284F03274C042950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00274E00264C00254C00264D01274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000274E00274E00274E00274E00274E00274E00274E00274E00295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00294D01284C
+ 00284C00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00264900274A002648012648012648
+ 0126480224460024460026450227430128440228440226420024420123410022
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00284C00284C00274B00274B00274A00254A022F4E00
+ 284F002A5B053B6D0937821A478C53EDFFF2FFFAFFFFFAFFF1FFF9478A453984
+ 28316904325C05295002274D01264C00274D01285002275000274E002950022D
+ 54042B6402447A1645933B4CA254FFFBFFFFFEFEFDFFFFFFFDFF46984539821C
+ 356C092D5C00265100224F00274C022A4F00255B02416806438925499E3C57B0
+ 6AFCFEFFFFFFF9FEFFF8FEFEFEF6F6FCF1FFFDE6FDF8F9FEFFFFFEFEF5F4FDF7
+ FAFFFEF5FFFFFBFEFFFFFFF2FEF2B5E5C879B78755975646984648902C42841B
+ 4578173B6B01365F0334630133630A3675173A902C499954F4FEF8F7FFFEFDFF
+ F384CAA246913B358A3546821D397517558747DAFAE2B6DAC464B26B549B6357
+ A97846B773C1F1CDFFFEF9FFFFF9F3FDF085BD9446B77359B57453A86475B17B
+ 8CC997C4E6C8E0FEF1F3FFF9EFFBFBF7FFFEFBF9F9FDFFFFF2FFFDE7FEFAC7F1
+ D8D8F7DAD9F7E4EAFFFBE1F6F393D1AD66BA7A3DBF6A46B774A8E7C0F3FFF9FC
+ F5FAF8FFFA9AB9A49AC9A2C5F2D8B0E3BD47782E355C06255B022D59002B5204
+ 2852052A4F0031550139640337761843933654B573F7FEF9FFFEFEFCF7F6F6FD
+ FF87BD924B9F394074093461002E5A002852002850022B52022E5801335F0037
+ 6502316B00396C0B3B630440730B316408558747C6E5CAD8F7DC4F8637376C15
+ 36630233610133610133630A346A09397307388F2D46AA6290CFAFF6FEFDFEFE
+ FEEEF7FAF2FFFFFFF6FCC6F4D75196463A831D3160033058002252002050012B
+ 4C022D570031580238720638831B468A37A6C8A9F4FEFEFFFFFE65A268457731
+ 3A6D0C3864002B51002B5202265002274D012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F01284F01
+ 284F01274E00274E00274E00274D01264D01274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000295002295002295002295002295002295002295002295002295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00284C00284C
+ 00274A00274A00274A00284C00284C00284C00284C00284C00284C00284C0028
+ 4C00284C00284C00284C00284C00284C00284C00284C00284C00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274B002649002649002648012648
+ 0126480126480125470026450025440027440028440227430124430023410023
+ 4100264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284C00284C00284C00274A00274A00274A00274A00274A002449002C4A03
+ 254A00285200426A0439821B458E50F5FFF9F6FAFFF9F9FFDDEEE04B89373780
+ 19335C012E5200335501264C00254C00254C00284F01284F00274E002950022D
+ 54043268042C7207478F2B48A354FEFAFFF9FAFEFAFFFFF8FFF848923A387815
+ 336703315C01245102244A00294F032E4D022D5B08406B0448831B469D3B55A7
+ 66F7FAFFFFFFFAFDFEF4F2FEF8D4E8DBEFFFFDF2FFFFFEF6FDFEEDFBFEFAFFF4
+ FCFCECFFFCE5FFF1B5E6C684B58758985750963C488F2E468527377307347208
+ 3D6B013260002D5900305C003263073A7717469338559658F8FAFAF4FFFDFBFE
+ F586CCA446913B39832938771744831B396917899E85F1FFFDECFDF4C5E6CBA7
+ C8B379BE99D6E9DAF7F4FDFDFFFFF5FEF4A8D7B798DBB6BFF2CDE2FFF0F4FEFE
+ F1FFFEF2FBFFFDF9FEFFF9FFFEFAFFFFFAFDF7FFFEFAFFFEEFFCFABBE5C669AE
+ 8346B77365BC8485CBA2F8FEEBEEFEF3E5FFF09DD5AA87B587D1F2D0FFF5F7FB
+ F7FCAFE3BB538C55488D54548C5789A986C7DFBF4678302D59002E5A012A5204
+ 2651082751003155013A630139730748852A68BA85F4FAF9FFFEFEFCFEFEF3FF
+ FD6AA5793984283A6301315C012D58012953002850022B52022C55002F5A0034
+ 60012C59033C6C023A6B013B6C02437309346200366A1792BD8AEEFDFF89A986
+ 3F6E122A66023469022C640030640A5083274A9E3848A45385CDA3F0FEF8FFFF
+ FFE5F5EEF7FFFEFFF9FFBBE7D049894738821839650231550123510022510234
+ 4D032E4E012951002C670029720B44852988A986F1FBFBF9FEFF75A575487732
+ 33680B3B64033159012953002B51052A53022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000275000284F00
+ 284F01284F01274E00274E00274E00274E00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00284C00274B00274A
+ 00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A0027
+ 4A00274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00274B00274A00274A002547
+ 0025470026480125470025470127460125440027440027430126420024420124
+ 4201264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 00002648012648012648012547002547002648012648012648012045002C4A00
+ 284A032B510542690737811B458B45EDF2F0F7FAFEFAFFFED1E6CD4385262D73
+ 083361012F5503295300274E00264D01254C00284F01274E00264E00284F012B
+ 520233610131690445862A4BA038FEFEFEFBFFFFF0FDFBE3FCE843862A3B7516
+ 3765022D58012951001E4A03264B052C4E01215200415D044D791E4B9F394BA4
+ 55FDFAF6FEFFFBF7FEF9F2FEEA87B688A8D4ABF3FFEBFBFFF9FEFFFAF9FFFAE2
+ F0DE8FE1AD78B07B478C53478A454591394588273E7409357307357406346901
+ 386401355B032E5A00315B0329650037761646783266A369F4F3FCFBFEFFFDFE
+ FA8DC896498E2D367714326A0B48831A447A173B582A8DAA93E1EFE4F2FFFDF1
+ FFF3E3FFF1FFFCFFFEFAFFF4FBFEFBFFFFE1F6EEE2FEF1FEFFFAFFF9FFFFFBFF
+ F9FBFCFAFFFFF6FEFEF4FFFDF4F5F3F6FBFCF7FAFFFFF7FEFFFDFDCAE5D545AB
+ 7426994F37A6504A9956529C62A6D8B8ECF5F8FAFBFFEFF4F2F5FAF9F7FFFEDD
+ E2E555A766489746378218296910265419547B47A3C98F325D022D59002A5300
+ 2452062850022F5601336101326B084486276AAC82F7FFFFFDFEFCF5FEF4C5E7
+ C9478D5036831B3A650A2E58012A5400275000284F002950002A52002C560031
+ 5C01365B153362003A72073368013A6B0140740834690139650C649152B3D3B0
+ C4E8CA6D9467365B15326B08437918377714468837579755BBE5D4EDFFFDECF1
+ F2E1EDE7F3F4F2FDFFFFC3E6CB458A4737821A386B033A59042050012152002B
+ 4F022A5101325B062B64013774063A77176C9568F0FEF8F6FEFE82BC6E448529
+ 346B083A6301315C012B52022A51032151002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000275000285100
+ 295000284F01284F01274E00274E00274E00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000285100285100285100285100285100285100285100285100295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00274B00274A002649
+ 00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A0027
+ 4A00274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00274A00274A00274A
+ 0026480124460024460026480226480224460026450028440227430124430024
+ 4201264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264802264802264802254701244600244600244600244600234302264801
+ 294C0230550539650834831C478735C8D9CCF3FFFEF1FCECAAC99238821C2971
+ 07306309385708214B00284E02254C00254C00274E00274E00264E00284F012B
+ 52042F560032680446821D39902EFCFEFFF9FDF7D1F0CF9ABB9938831B386B0A
+ 3261002F5A00215001224905254C01294E002850023F5C06417A1851922C4499
+ 45FEFFFAF7FEF9E5FFF188D4A447A76744AA6379B787CDF2CABEF1CC8DC89665
+ B16949994648984545933B38831B367305366804316902386401346100325B00
+ 335C003155012C54022F5B00356102377209649152A9D6ABFFFBFFFFFEFDFFFE
+ FA85BD924587283D6B0B3575042D640135740646831B4E791E78A26DC4E5CAEB
+ FEF5F3FFF3FFFFFFFFF6FCF8FBFFFEFDFFF9FFFAF2FFFDFEF5FFF7FFFEF0FEF8
+ EEFFF6D9F9E1AAD4AB86B686A6D6BAE6FEF2F6FFFCF5FFF2F1FFF3AFE2BC4CA2
+ 543992353789364488353A902C5596586A956ACAD8CDEEF7FAE6FDF9C6F4D76A
+ A6763B842844852936831B36720633630A365B17294B04315A093156002C5004
+ 2351052751032D590033610134690245831976A676FBFFFAE8FCE9A7D5AB77A2
+ 693B78162B710639630C2D5503284F00275000295000284F002950002B53012D
+ 5700304F042B59003460013B6A04316003325E004273093B6B013B6A03376A1A
+ 70946AB6D6BDC9F3CA84A977467530487830588C5695BB97E5FFF2D8F8E5D4E9
+ DAFEFFF4FFFEFAF1FFFEC2E6C8478937397517376600365A002650022051002F
+ 4F002C4C0033530C2D5900316902326B08578648F4FDE8E6FCE9519548427A15
+ 3C6D013A6301355C002D56012B51002150012950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285100285100
+ 285100284F00284F01274E00274E00274E00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00284C00274A00274A00274A
+ 00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A0027
+ 4A00274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00274B00274A00284B
+ 0127490225470024460026480126480124460026450026450228440226420023
+ 4200264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000244600244600254701244600244600244600244600254701204604284402
+ 244600264E00385B0138771745772FC8D9CCE1EDE799AE9545772F2C72072B65
+ 002B5801344D032D5104284E02254C00254C00274E00294D00264D00274E002D
+ 51043F5C0634620039720938912AFFFFF7C7D8CB869F8545772F39821B326902
+ 315D042D5900264C04214A072D4E042F4D01245A00406B0442740846831B498A
+ 45FDFFF9D8E9DC8AAA9163A455279A4B37A851498B446A9667588C5747913938
+ 902C52912939821B306A0B346B083C6C0C3361012C5A01315C01355B01315404
+ 2C55042B54032B5202355B033461003B6C04A9D6ABE8FAE9FBF6FFF3F5FDFDFF
+ F986B587407917326B0934680431690232690234730539821C478F2B5A8D5386
+ B48AB6DAC4FCF8F7FFFEFFFEFDFFFDFFF9FDFEF4ECFEFDEAECF4C2E6C898C8A4
+ 67A5774BA45548A35455A76661B36866BA7987B68877A57675B27A5596582E75
+ 15417C144278173C761746831B46831B489238478A4776B884D6F6DD79A16A3B
+ 7927437A17346A093168013D6A03346A00305C03345E062E50032F5601295201
+ 2350072851062B590033610131690040791695BB97E0F0DE84A97748913B5184
+ 284583192D7209385B012B5202295002285002295000284F002B4F022A51012C
+ 55002E5C03375B15304D0E315C013169023A63013E640C316200335F063B6A03
+ 326804356C0958854685AB87B6CCB9EDFEF3E5FFF1E2EFDFB2CEB7A7C7B4F6FE
+ EDFDFFF3FFFFFAEAFFFCB6DAC247763139730734600131550121510022520028
+ 4C002F560131510A2956003269022C6502366A17C8E1BF6A95682E72072A6503
+ 386B033D6A03375C002E54082E5505265A002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285100285100
+ 275000275000284F01274E00274E00274E00274E00274E00264D01254C00274D
+ 01274E0029500028510029500029500029500029500029500029500029500029
+ 5000284F00284F00284F00284F00284F00284F00284F00284F00295000284F00
+ 274E00274E00274E00274E00274D01274D01284C00274A00264900274A00274A
+ 00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A0027
+ 4A00274A00274A00274A00274A00274A00274A00274A00274A00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284B01284C00274B00274A00274A
+ 0027490226480124460026480126480124460024460026450028440227430124
+ 4300264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274603284704274603264502284402284402284402284402264101244201
+ 274805284D032E560439630B4D7920628F395084264479183B6B0B335F042D58
+ 012B5301294E00294D01274D01274D01274E00274E00274E00274E00284F0029
+ 50002D59003360033B6B0B4379165F903C52912950842A4379183B6B01376502
+ 315B032A5200274E002A4E022A4E02294C022F59012B58013A6D0C4277195185
+ 2767A35553922A51922C478E2D468F2D4A902C498D2E488F2E42862745872847
+ 862A40720C3D6C09336101305C012F59022C55002B5202284F01285002295004
+ 2950052A51032950002C5500335C00396502608F3951853854863850932A478E
+ 2D46791834690B316300385B013962003766003C6D0136720646821D48902C53
+ 963B46984548A45366B26A64BB7B68B87B56B47348A4554CA3534AA354469846
+ 46923A47913744913D48913B46933844923A51932A4686263F7B173973073068
+ 012E65023169043A6C0037730743781744831D48821D46821D44841A40740837
+ 7307336101325F02315C01305B002E58002F59022C55002A52002B52042A5103
+ 2950002B50002E5500315C0138640143730952974753963B53922A50842A427A
+ 15386C01345F042D590029500029500029500029500029500029500029500029
+ 50002C50042C50032E54022F5600335C01315D0035620136640131640A346306
+ 3663023766003B6A033D6A033A6B013A6B0138811A468F2D52974763A35767A2
+ 6853A86446995448984555922A46821D3369082D64012A5B002B550028500226
+ 4D00284E022851002B56002E5A00305C033662093967073A6B03365E06345E06
+ 315B03305B00315C012F59012D59002E5A012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F00284F00284F00284F00284F00284F00284F00284F00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284B01284C00284C00284C00274B
+ 00264900264801264801274A00274A00274A00274A00274A00274A00274A0027
+ 4A00264801264801264801274A00274A00264900274A00274A00274A00274A00
+ 274A00274A00284B012B4C022B4C022B4C02274A00274A00274A00274A00274A
+ 00274A00274A00274A0026480126480226480127470025440128440228440224
+ 4201264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000254401264502284402284402284402284402284402284402244300244300
+ 244600284A042C4F052D5404335E07426E1537650C3362062E5A012B55002C54
+ 022D53012E52002D5000274D01274D01274E00274E00274E00274E00284F0029
+ 50002B54002B5801336200326B094378173F7B174079163A76183B6B01366401
+ 2F59012C5200294D002A4E022A4E02294C022A4E012D57003766003D6C0A3B6A
+ 0344831B346A093B7419437B16437918427817497A1E447918447A174273093E
+ 75083D6C09366503315D002E58002B54002C54022C5303295002284F01284F03
+ 2950042A51032950002C5500315C01366401426E15447A1745821A45841C3883
+ 193772093269023863022E5500385B04305B00346001306B0336720645821A4E
+ 8528478E2D48903D53963B52974654964747933B45903A468F2D47862A43821C
+ 417B163A7717437817407916427817417A1838751A377307356A092C6503275B
+ 01305C00305A022F5B022C6502316904306C083B6C0A3D6C0A336B0C2B640126
+ 5A00305D00315C01315B032F59022C56002A5300295100295000294F032B5204
+ 2C53032D51002E5402325C0436640141750944841A4E7A21437915427309396C
+ 0A3361012D59002A560029500029500029500029500029500029500029500029
+ 50002C50042C50032E53032F5601305A02315C01336101336101345E06346003
+ 3360003B64023965003A6B033B6A033D6B013973074379185083275287375896
+ 3C53963B48902C488F2F42831D4079163C6D013460032D590028550026500229
+ 51002750002851002B55002D59002D5900315D04325F02336200315C01315C01
+ 305B002F5A002E5A002D59002E5A012E5A012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00284C00284C00284C00274B002649
+ 00274A0027490226480124490124490124490124490124490124490124490124
+ 4901264802264802264802264802264801264801264801264801274A00274A00
+ 274A00274A00274A00284B01294C02294C02274A00274A00274A00274A00274A
+ 00274A00274A00274A00274A0026480226480128480126450228440228440228
+ 4303264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000284402274301284402284402284402274301264200264200223E02224000
+ 234500284A032C4F052E52052850002B53012854012A5400285200275000284F
+ 01274E002A4E01284C00274D01274D01274E00274E00274E00274E00284F0029
+ 50002C55002F5404335C00325D023B6B0B3C6D014074094274083B6A03366302
+ 3058002C52002A4E012A4E022A4E02284C002B5100395C02396200406B043660
+ 01336C09315C013864093D6A033C6B043F6A03426A053F6A03406A0541690442
+ 6A05336101315D002D57002B54002951002B52022B5204295002284F01294F03
+ 294F03295002284F002C5500315C013461003864013973074274084074093774
+ 063068013562013460012E52002E55002F59022F5901305D003B6402396C0A42
+ 781746821E42841A46831B45841E44831B4079164379184373093B6D093B6B01
+ 3568003564023564023965003766003A63012A5B072E5B052D59002958022B59
+ 003054002F56002E5801305C01345D02336200326307326202326100325C042E
+ 58012F59022C56002C5500295100295100284F00295002284E02295000295103
+ 2850022950002B5400315C013D64023F6A0341750A43730944740A3B6B013664
+ 012D59002A4F07294E0629500029500029500029500029500029500029500029
+ 50002C50032B4F022C51012C54022D57002D5900305C01305C01305C01305D00
+ 3361013461003461003362003965023A63013A6B0141750A43740C4D7A1D5083
+ 274E832547831E42831D4379153E74093B6B01335F00325C042E54022E550031
+ 55032750002851002952012B55022B56002D58012D59002F59012D59002E5A01
+ 2E59022D58012D58012D58012E59022D58012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000285100285100285100285100285100285100285100285100295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274B00274B00274A00274A002649
+ 0026480126480126480226480126480126480126480126480126480126480126
+ 4801264801264801264801264801264801264801264801264801264900274A00
+ 274A00274A00274A00274A00274A00274A00274A00274A00274A00274A00274A
+ 00274A00274A00274A00274A0026480126480126480226450227430128450028
+ 4402264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274301264200264101264101264101264000264000264000253F03243F00
+ 244201274603284A032C4F05284E02284F01274E02284F01295000285002274D
+ 01254B00254A00274A00274D01274D01274E00274E00274E00274E00284F0029
+ 5000335501305402385B01365B003965023B6B013B6B013D6A03376502335F00
+ 2F56002C51012A4E012A4E022A4E02284C003152012E54022F5404396502315B
+ 03355F082D5900365E06315D003361013A63023B64023965003B640239650238
+ 64012D59002E5A012A5400285200285100285100274F01274F01295000295002
+ 284E02284E02284F012B53012E5800315D003665003B6A033D6A033A6B033B6A
+ 03396502335C012B55002B4E042A52042A50042C56002E5900385A033A640042
+ 6A043B6A033C6C023F6806416703406A053D6A03326400336101335F00305C03
+ 315C01315D00305C03315C01365E00385B012E55002C55002C56002C56002E52
+ 052D54002C52002E51012E54022E56003155013155012E55002D54002E550029
+ 5201295000284F00295000274E00274E00274D01274D01264B01284F01284F01
+ 284F012A4F002C5200335B033C62023E6B0443720B4369053F6A033A6400335C
+ 00305400265200264D0129500029500029500029500029500029500029500029
+ 50002A4E01294D002A4E012A51012A52002C55002F59022E5A01335C01335C01
+ 335C00305D002D5C00315C01305C01315C013965023A63013F6904406A054074
+ 0944750B4172084273094268043D6B013663023462022E58003055002F560031
+ 5503285100275000274F012851002953002A53002A53002B53012A52002A5200
+ 2A52002B53012C55002E55002E55002E55002A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00274A00274A00274A002648
+ 0126480125470026480226480126480126480126480126480126480126480126
+ 4801274700274700274700274700264801264801264801264801264802264802
+ 264802264802264802274903284A04284A042648012648012648012648012648
+ 01264801264801264801274A0026480126480126480227460328440228450027
+ 4301264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000274200274301
+ 274301234001234001224300224400224700284702294A00284C00284C002A4C
+ 00284C00284F012D5104274D01274D01274E00274E00274E00274E00284F0029
+ 50002C4F002C4F002B5100355B03375B01386401396502386302346001315C01
+ 2F56012C51012A4E022A4E02284C00284C002B50002C52002F4F02345B00355C
+ 003157002F56012D51002756002956002C59032D57002D58012B59002E58002B
+ 59002E58012C5500295300285100285100285100285100275000295000295002
+ 284F01274D01274D012950002B56002E5A01315C01326100336200375B013A5B
+ 00325E052E5505284B01274F01294F032B51052D50002F5601305400375A033E
+ 5D02336200305C01335C01325C042E58012F5B002B58012B5502275300275201
+ 2851002950002A54012A52002D5000305100274E00294D002A4E02294D01294D
+ 00294C022A4C002C4B002E4E00284F012C4E012D4D002C4E012A4F002A4E012A
+ 4F002A5004294F03284E02274D01264C00284E02284E022A5004274E00274E00
+ 284F012A4E012B50002F5600375C003A6302376600366401336003385A032C56
+ 002850022951002B550029500029500029500029500029500029500029500029
+ 5000284C00284C002A4E012B4F022C51012C52002F56012D54002C5A012C5A01
+ 2E58002D59002D58012F59022D58012E58012B59002C5A01335C00345D013362
+ 00366205356A033B6B01396403386400375B01375B013056003156002E55002C
+ 5101295002295000284F002950022950002950002951002A5101275000285100
+ 2750002950002A52002B53012B54002D56012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295002295002295002295002295002295002295002295002295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C00274A00284B01274A002547002648
+ 0126480126480226480227430127430127430127430127430127430127430127
+ 4301284402264502254401254401264502274603274603284704264801254700
+ 2648012749022648012648012648012547002648012648012648012648012648
+ 01264801264801264801274A0026480126480126480227460328440228450027
+ 4301264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000243D00264000
+ 284301254100223F002140012242012242012642002744002848012648022648
+ 01274A00264C00284F01274D01274D01274E00274E00274E00274E00284F0029
+ 50002A5204274B00284F00315600315501375C00375902385C02315C012E5800
+ 2E54022C50032B4F032A4E02284C00284F012E50032B5200295200325C043A5A
+ 013057023350012D5601214D002350012751032D56052855062957052954032B
+ 56052C55002A52002A51012A5101284F00295000284F00284F00295000284F00
+ 284F01274D01274D01284F012A52002B55002C55002D5900375B012F55032E56
+ 002D5409314D08284A04264C00264E00284B012A4B012D4F022B50002C550031
+ 5503315B042D58012E59002C5B002D58012B55002B54032A5603214D00214E00
+ 234D00214D00284F01274F01284D03284D03284F012D5000284C00284B01274E
+ 00264C00294D002A4F002C5004304E05314F062D51042F50052E4F042C50042D
+ 5105294E04294F03274D01284E02284E022A51032950022A5103285100274F01
+ 254C00294F032950002D5400395B04375B01385A03385B013155032D50002A4F
+ 002953002A510128540129500029500029500029500029500029500029500029
+ 5000284C00284C00294D00294D002A4F002A4F002E52002D51002E5500305500
+ 2F56003355013155012B54002E55002E55002951032A54062757052C5C042F59
+ 01335C00305C01325B00385B01375A03385B002F55032D55032A540029530028
+ 4F01295000295000295000284F002950002950002950002B5100284F00284F00
+ 284F01284F01284F012950022B50002C51012A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002749022749022648012547002648
+ 0126480226480225470128440228440228440228440228440228440228440228
+ 4402284402284402284402274301274301284402284402284402284801284801
+ 2848012848012547002547002547002648012648012648012648012648012648
+ 01264801264801264801274A0026480126480126480226450227430128450028
+ 4402264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000253F00264000264000264000264000264000264000264000243E02274002
+ 284202254001243F002543022644032443002742022645022746032546032445
+ 02234701264B03234A00274D01274D01274E00274E00274E00274E00284F0029
+ 5000275103284F032B4C012C54062C5101315A09365C02355B012E58012D5601
+ 2D52022C50032A4E02294D01284C00274E00234802224C00274E022655002B56
+ 002952012950002C50032951032852042A50042A52042A54072A51032B52062A
+ 51032B52022A51012B52042B5204295000295000284F00274E002A5101284F00
+ 284F01264B01274C022950022950002A51012856032F5901385A033354033055
+ 00305001274E02284E02264C00244E01274B00254A04244A02294D002750002C
+ 51012C50032A4D032C55002B56002C55002A5200294E04254B03275103295002
+ 265002274E02274E032D4E032A5004294F032C50032C4D032B5204295002284F
+ 012A52042A5204275103285100285100275000285100284F01285002284F0328
+ 4F03294F03294F03295002295002295002284F01284F002A5101274F01295002
+ 284F012C4E012C50032B52022E55002E5800335C002D59002A55042F50052950
+ 042A5103284F032B500029500029500029500029500029500029500029500029
+ 5000294D002A4E01294D00294D00294D002A4E012C50032C50032C55002E5500
+ 2C55003155033054022C53032C52002D5100255203295002284F03274F012B51
+ 002B52003152012A51032B50002F56013155012C51012B50002C530527520122
+ 4E012C51012B50002B50002A4F002950002C50032B4F022B5000285002285002
+ 295103285002284F03295004284F03284F032A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000284F01284F01284F01284F01284F01284F01284F01284F01295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002648012547002446002648012648
+ 0124460024460024460028440228440228440228440228440228440228440228
+ 4402274301284500284500284500284500284500284500274400284402284402
+ 2645022746032847042847042746032647042648012648012648012648012648
+ 01264801264801264801274A0026480226480128480126450228440228440228
+ 4303264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000274002274002274002263F01263F01264000264000264000254000274202
+ 253E00233E00243F00264101243F00243F00263C012742022844022B4803284A
+ 03274A00294D01234A00274D01274D01274E00274E00274E00274E00284F0029
+ 5000234D001F4E00264D012D57042848012C50042E4F053151042C55002C5402
+ 2B52022C50042A4D03284C00284C00274E00265108254D002952012B4F022854
+ 01315503285100274E00294D002C51012E51012E52002B50002C52002D4D002E
+ 4E00284F01295002285002295103285100284F00295002274E002A5101285000
+ 295002264B01274C02294F032950022950002955022852002C52002952003155
+ 012C56002652002351002950022B5100284B01244A02264C04254B0324520020
+ 51002F51042E52002C53002C51012C53002A4F002A4E02284F042951002B4F02
+ 2C4E01274E00284F01294D012E4E012C5200274E00294D002750002851002951
+ 00264C00274E00214C01284F04275100264E00264C00254C00255100284F0327
+ 5201284F032850022851002750002851002750002851002953002950002A5103
+ 284E022B4F032B4F022C5101335403315501245A01245200215100274C042C4B
+ 082A4C06294D012A4B0029500029500029500029500029500029500029500029
+ 50002B50002B5000294D002A4E012A4E012C50032B4F032C50042B55002E5500
+ 3054002B53012B52042C50042C50042C50042F51042950002C51012E52002E4E
+ 002C4E01314C03304D042E4E012C50042C50032950002850022C54062752091F
+ 4D002C52002B4F022C50032A4F002A4E012A4E022A4D032A4E022B52042A5103
+ 2B52042B52042851002851002750002750002A52002A5200295000284F002850
+ 0228500228500228500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000274E00274E00274E00274E00274E00274E00274E00274E00295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00295000
+ 285100295000295002274E00284F01274E00274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000284F00295000285100295000295002274E00284F01274E00284C00284C00
+ 284C00284C00284C00284C00284C00284C002446002446002446002547002547
+ 0024460025470124460024420124420124420124420124420124420124420124
+ 4201244201254401264502284402274301284402284402284402284402284402
+ 2743012844022847042847042746032746032648022648022648022648022648
+ 0226480226480226480226480126480226480127470025440128440228440224
+ 4201264101264200264200264200264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002442012442012743012645002847
+ 02264801274A00274A00274A00284C00284C00284C002A4E01294D01284C0029
+ 4D01295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00284F00
+ 284F00284F00284F00284F00284F00284F002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A52002A5200
+ 2A52002A52002A52002A52002A52002A52002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 295000295000295000295000295000295000284F00284F00284F00284F00284F
+ 00284F00284F00284F0029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00284C00
+ 294D01284C00274A00274A00274A00274A002449012648022749032746032544
+ 0126450226450224430026410126410126410126410126410126410126410126
+ 4101264101264101264101264101264101264101264101264101274301274301
+ 2743012743012743012743012743012743012446002446002446002446002446
+ 0024460024460024460023480023480024490126480125470024460024460024
+ 4600284402284402274301264200264200264200264101254000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002442012642002844022844022746
+ 01264801274902274A00274A00284B01284C00294D012A4E012A4E02284C0028
+ 4C00295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 50002950002950002950002950002950002950002950002950002A52002A5200
+ 2A52002A52002A52002A52002A52002A52002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00294D01
+ 284C00274B00264900274A00274A00274A002648012547012746032844022743
+ 0128440226450224430026420026420026420026420026420026420026420026
+ 4200264200264200264200264200264200264200264200264200284402284402
+ 2844022844022844022844022844022844022246002246002246002246002246
+ 0022460022460022460026480226480225470125470124460024460024460024
+ 4600284402274301274301264200264200264101254000254000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002443002642002844022743012645
+ 00254701264801264801264801274A00284B01284C00284C00284C00284C0028
+ 4C00295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285100285100
+ 2851002851002851002851002851002851002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002851002851002851002851002851
+ 0028510028510028510029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00294D01
+ 284C00274B00274A00274A002749022648012847022746012844022743012844
+ 0228440225440123410026420026420026420026420026420026420026420026
+ 4200264200264200264200264200264200264200264200264200284402284402
+ 2844022844022844022844022844022844022844022844022844022844022844
+ 0228440228440228440225440125440126450226450226450226450226450226
+ 4502274301264200264200264200264200274101264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002342002443002743012544012645
+ 02264500274601284702244600254700274A00284C00284C00284C00284C0029
+ 4D01295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F00284F00
+ 284F00284F00284F00284F00284F00284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00284C00
+ 274B00274A00274A002648012547002446002544002844022844022743012743
+ 0124430023410024420126420026420026420026420026420026420026420026
+ 4200264200264200264200264200264200264200264200264200264200264200
+ 2642002642002642002642002642002642002844022844022844022844022844
+ 0228440228440228440228440228440227430127430127430127430127430128
+ 4402274301264200264200274200274101264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002443002443002443002443002544
+ 01274301284402264500244600244600254700274A00284C00284C00284C0028
+ 4C00295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295002295002
+ 2950022950022950022950022950022950022950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285002285002
+ 2850022850022850022850022850022850022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950022950022950022950022950
+ 0229500229500229500229500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00284C00
+ 274B00274A002648012446002446002446002443002442012442012442012443
+ 0024420123410023400126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264200264200
+ 2642002642002642002642002642002642002443002443002443002443002443
+ 0024430024430024430027430128440228440228440228440225440124430024
+ 4300264200264200264200264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002341002242012242012443002743
+ 01284402284402274301244600244600244600264900284B01294C02284C0029
+ 4D01295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00274E00274E00274E00274E002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285002285002
+ 2850022850022850022850022850022850022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 295000295000295000295000295000295000274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00284C00
+ 274A002648012446002446002446002345002341002442012442012341002240
+ 00224000223F00233F0326400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264200264200
+ 2642002642002642002642002642002642002443002443002443002443002443
+ 0024430024430024430028440226450225440124430024430024430024420124
+ 4201274301264200264000253F00264000264000264000243F00264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002341002442012242012443002443
+ 00264200264200244201244600254701264802274902284B01284B01294C0229
+ 4D01295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000284F01284F01
+ 284F01284F01284F01284F01284F01284F012950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285002285002
+ 2850022850022850022850022850022850022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 295000295000295000295000295000295000284F01284F01284F01284F01284F
+ 01284F01284F01284F0129500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00274B00
+ 2649002446002446002446002345002244002240002341002340012240002341
+ 00234001233F03233F0326400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264200264200
+ 2642002642002642002642002642002642002240002240002240002240002240
+ 0022400022400022400024430024430024430024430023410023410022400022
+ 4000264200264200264000264000264000264000254000254000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 264000264000264000264000264000264000264000264000264000264000263F
+ 01263F01263F01263F0126400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 0000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002540012341002341002443002342
+ 00244300244201244201234500244600254701264801264801284B01294C0229
+ 4C02295000295000295000295000295000295000295000295000274E00284F01
+ 274E00295002295000285100295000284F002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000274E00274E00
+ 274E00274E00274E00274E00274E00274E002950002950002950002950002950
+ 00295000295000295000274E00284F01274E0029500229500028510029500028
+ 4F00295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000285002285002
+ 2850022850022850022850022850022850022950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 295000295000295000295000295000295000274E00274E00274E00274E00274E
+ 00274E00274E00274E0029500029500029500029500029500029500029500029
+ 5000295000295000295000295000295000295000295000295000295000295000
+ 2950002950002950002950002950002950002950002950002950002950002950
+ 0029500029500029500029500029500029500029500029500029500029500029
+ 5000295000284F00274E00274E00274E00274E00274D01274D01284C00274B00
+ 264900244600244600244600234500234500223F002340012340012340012340
+ 01223F00243E02253E0426400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264200264200
+ 264200264200264200264200264200264200223F00223F00223F00223F00223F
+ 00223F00223F00223F00264200264200244201244201234100223F0023400122
+ 3F00264200264200264000264000264000254000243F00254000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 2640002640002640002640002640002640002640002640002640002640002640
+ 0026400026400026400026400026400026400026400026400026400026400026
+ 4000264000264000264000264000264000264000264000264000264000264000
+ 264000264000264000264000264000264000264000264000264000253F00253E
+ 00243D00243D00243D00243D00243D00243D00243D00243D00243D00243D0024
+ 3D00243D00243D00243D00243D00243D00243D00243D00243D00243D00243D00
+ 0000}
+ end
+ object TopBevel: TBevel
+ Left = -9
+ Top = -1
+ Width = 443
+ Height = 89
+ end
+ object InfoLabel1: TLabel
+ Left = 48
+ Top = 96
+ Width = 369
+ Height = 33
+ AutoSize = False
+ Caption =
+ 'This tool will import your Wolfpack definition files and create ' +
+ 'a new categories.db for the WP GM Tool.'
+ WordWrap = True
+ end
+ object WolfpackIcon: TImage
+ Left = 8
+ Top = 96
+ Width = 32
+ Height = 32
+ AutoSize = True
+ Picture.Data = {
+ 055449636F6E0000010006001010020000000000B00000006600000010100000
+ 0000000068050000160100001010000000000000680300007E06000020200200
+ 0000000030010000E60900002020000000000000A8080000160B000020200000
+ 00000000A80C0000BE1300002800000010000000200000000100010000000000
+ 8000000000000000000000000000000000000000FFFFFF0000000000FFFFB9BC
+ FFF70E15E7FD0E0FFFFE07F5FF8300009FA300FBCB39FFADFF67FFFFF7EFFBF6
+ FBEF0000FF9FF500FE3F2B07F8FFF607F17F1614EDFF0D07DEFF000003FFB9BC
+ 00030E1500010E0F000007F500000000000000FB0001FFAD0007FFFF000FFBF6
+ 000F0000001FF500003F2B07007FF607007F16140C7F0D071E7F000028000000
+ 1000000020000000010008000000000040010000000000000000000000000000
+ 0000000000000000000008000008080000081000080810000810100008101800
+ 0018210010182100102121000818290018293100212931003131310021293900
+ 183139002131390029313900213142002939420029394A0029424A0031424A00
+ 2942520031425200314A5200314A5A00394A5A0039525A003152630039526300
+ 42526300425A6300425A6B00425A7300426373004A6373004A637B004A6B7B00
+ 526B7B004A6B8400527384005A7384005A738C005A7B8C00637B8C005A7B9400
+ 6384940063849C006B8C9C006B8CA5006B94A5007394AD007B9CAD007B9CB500
+ 7BA5B5007BA5BD0084A5BD009CADBD0084ADC6008CADC6008CB5C6008CB5CE00
+ 94B5CE009CBDCE00A5C6DE00ADCEDE00BDD6E700ADD6EF00B5DEEF00D6E7EF00
+ DEF7FF00FFFFFF00000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000016000308002900000000000000000000120B03181F00101F27292929
+ 2F290000121F1F3332080005050000000000370023272329120815230C101F0C
+ 0C12033A29231F161818161F29343B333B44000D1F2F361818231615292F292F
+ 394117100C18372F1C2F1F0B343D181C293241001C001523181F1818321D2937
+ 3F0000001C080B1F2E1C00101203232F0000000008000016232F1D1218072200
+ 000000000000050910122923283F000000000000000012120B181F3441000000
+ 0000000018290000233D41432E000000000000000512150F4300371D34000000
+ 0000000000121D3D000036072900000000000000102D41000000002F1F000000
+ 0000000003FFB9BC00030E1500010E0F000007F500000000000000FB0001FFAD
+ 0007FFFF000FFBF6001F0000003FF500007F2B07007FF607047F16140C7F0D07
+ 1E7F000028000000100000002000000001001800000000004003000000000000
+ 00000000000000000000000030434D020307090E10121B210003065E77860000
+ 000000000000000000000000000000000000000000000000000000002A39431E
+ 2A32090F14394D58445A6800020628373F44576151697A5F7B8B597587597788
+ 6484975B78880000000000002D3D46455C694358676F93A66A8CA1141C23050A
+ 0E0810140B121701060A00000006090B0103050002007BA0B50000004F697A50
+ 6D7D4D67755975862C3D47141F262F414B4C6775222F3827343D435A67222F37
+ 202D362C3D48000C149FAEB95A7687476070455B6A31434F374C583548543141
+ 4C445A685672827195A984AAC16D90A389AEC4A9D2EA000000343332435B6763
+ 8194789AB13A4E5A3345504D667530424C2E404A567484638395597687638294
+ 85A6BAA1C4DA2A42512D363C222F373749527EA4BB6584963C535E648396445D
+ 6A1E2B337496AB8EB5CC3346523A515C5C788A688DA6A2C5DA0000003C515E00
+ 00002F404B4A6371374B56475F6F354854384C596B8EA03F56655876857FA2B7
+ 90B5CB0000000000000000003C505E111A211D2A31465F6E5F7F903C505D0000
+ 00233038283D430D0F124D6878618399000000000000000000000000161E2400
+ 0000070C0E30404D4963706A8B9E3F55632B3A463B4E5A071A25405F74D2E7EF
+ 0000000000000000000000000205040000000E161B16202624323A2F3F4A5472
+ 814864784E6F8399BACDDEF6FF00000000000000000000000000000003050606
+ 090B2A3B452C3C471D2D36364E5C415C6D7797A9A1C3D8000000000000000000
+ 0000000000000000000000003244505876870000000000004962708BB0C2A1C4
+ DAB7DAEF5D7D920000000000000000000000000000000000000000000E161A2E
+ 3E492D404B1A303FBDD6E10000007FA4BB3351637E9DAF000000000000000000
+ 0000000000000000000000000000002234403F57648FB6CD0000000000007B9D
+ B00E1F2A58738400000000000000000000000000000000000000000026313A64
+ 7988ACCCDE000000000000000000000000658698465F6E000000000000000000
+ 00000000000000000000000003FFB9BC00030E1500010E0F000007F500000000
+ 000000FB0001FFAD0007FFFF000FFBF6000F0000001FF500007F2B07007FF607
+ 047F16140C7F0D071E7F00002800000020000000400000000100010000000000
+ 0001000000000000000000000000000000000000FFFFFF0000000000FFEFFFFF
+ FFF7FFFFFFF9FFFFFFFFFF9FFF7FFFF7FCFFFFFFFEFFFFFFFFFFF7DFFFFFC10E
+ 7FFF790F73FFE80FC3FF9F86E1EF8F91F9EF8F8FFFEF983FFFFE72FFFFFFF5FF
+ FF9FF5FFFFCF3DFFFFFFF9FFFFFB61FFFFFF87FFFFFE0FFFFFFC3FFFDFB0BFFF
+ DF80BFFFFF82BFFFF7037FFFFEF7FFFFF9F3FFFFF7FDFFFF6FFEFFFF000FFFFF
+ 0007FFFF0001FFFF0000001F0000000700000007000000030000000100000000
+ 000000000000000000000000000000010000000F0000003F000000FF000001FF
+ 000001FF000001FF000001FF000001FF000007FF00000FFF00003FFF00003FFF
+ 00003FFF00003FFF00007FFF00F07FFF01F07FFF07FC7FFF0FFE7FFF28000000
+ 2000000040000000010008000000000080040000000000000000000000000000
+ 0000000000000000000008000008080000081000080810000810100008101800
+ 0818180010181800101821001021210018212100102129001821290018292900
+ 1821310018293100212931002131310021293900083139001831390021313900
+ 293139002131420029314200213942002939420029394A0029424A0031424A00
+ 31425200314A5200394A5200394A5A0039525A0042525A003952630042526300
+ 395A6300425A6300395A6B00425A6B004A5A6B0042636B004A636B005A636B00
+ 426373004A6373004A637B004A6B7B00526B7B0052737B004A6B8400526B8400
+ 527384005A73840052738C005A738C005A7B8C00637B8C005A7B9400637B9400
+ 6384940063849C006B849C00638C9C006B8C9C00738C9C006B8CA5006B94A500
+ 7394A5007B94A5006B94AD007394AD00739CAD007B9CAD00849CAD007B9CB500
+ 7BA5B50084A5B50084A5BD0084ADBD008CADBD0084ADC6008CADC600A5B5C600
+ 8CB5CE0094B5CE0094BDCE009CBDCE0094BDD6009CBDD600A5BDD600A5C6D600
+ A5C6DE00A5CEDE00ADCEDE00B5CEDE00ADCEE700ADD6E700B5D6E700B5D6EF00
+ BDD6EF00C6DEEF00BDDEF700C6DEF700DEEFF700CEEFFF00D6EFFF00DEEFFF00
+ D6F7FF00DEF7FF00E7FFFF00F7FFFF00FFFFFF00000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000018120900080A080F0A0F2F0000000000000000000000000000000000
+ 000000001F1F0A00000F09090508050000000000000000000000000000000000
+ 000000000A1E120003111226120A08001D3F0000000000000000000000000000
+ 00000000121F1F1209121233373718000505091E2C373C372637372C333F3F00
+ 000000000A232326182326333F372311090A050000030505050912181D12051F
+ 0000000012262F1F26373F46371F0A050512180F091818050000000000000000
+ 2C000000233333262F37373F3718050A18232F2F1F09000518120F0A0A0A0A09
+ 1137000026372F2C2F251F26120A1E261211261F1F181F373F372F2626333F37
+ 18001F0037363737262F1F1F1F1E121E1E1F2F261F333E5050453F333F3F5054
+ 120000003E251D372F231F26262F1F1F1F1F182F3F372F37373F453750505858
+ 0300002E3F2F18373F3E261F122F26262C181E2C372F373F37474E4747586C50
+ 120A000018263F47453F331F122337231E1F18181F3F3F37332F37333745544F
+ 47353C562309264747473C2F261F263E261F181F37454745262526232F3F4536
+ 475E00002F0F00183C3F45372326373E2625121837505B4E1F25332F374F544E
+ 000000001F1805031F262F372F26334533231218334745262F3F4F47584E0000
+ 00000000261D11030A25121F1F1218252312183F543718123F3F365800000000
+ 000000002F1811050A1F26262F261F0A000018371400001F581F440000000000
+ 000000001F0F120F0818251F3C3F471E0300000A3424001F47123F0000000000
+ 000000001205050500121E1F2F263F471F1F0A183F3F052618265E0000000000
+ 0000000011000000000918121F252F3737252F261F0A18262657000000000000
+ 000000000A00000000051809121E1F18333F2C333F2F3D475B00000000000000
+ 00000000050000000A0A0908181F181F2F3736333746636F0000000000000000
+ 00000000000000000A261F180F1E1F2F2625253D4E6500000000000000000000
+ 00000000080305050A1818180F23262F37334765625000000000000000000000
+ 00000000180A452F0000090A093F372F455B6C682F4500000000000000000000
+ 000000000A1E4E18000000001857585E645B5E502F5800000000000000000000
+ 00000000051818000F1F18153C0000005E463745375D00000000000000000000
+ 00000000000812263F2636265000000054462F263F0000000000000000000000
+ 0000000000001F26121D375800000000582F1E18370000000000000000000000
+ 0000000000001F18124465000000000065471F18370000000000000000000000
+ 0000000000000F1F5E0000000000000000005425370000000000000000000000
+ 000000004D18376B0000000000000000000000452F0000000000000000000000
+ 00000000001FFFFF001FFFFF0003FFFF0000001F0000000F0000000700000003
+ 0000000100000001000000000000000000000000000000030000000F0000003F
+ 000000FF000001FF000001FF000001FF000003FF000007FF00000FFF00003FFF
+ 00003FFF00003FFF00003FFF00703FFF00707FFF00F07FFF01F07FFF07FC7FFF
+ 0FFE7FFF2800000020000000400000000100180000000000800C000000000000
+ 0000000000000000000000002A3A4223303A131C2302050610191C1D282F1019
+ 1C1C27301A252A1C28314E667800000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000374956374B561A252D0202020202021D2932131C
+ 23141F2509111410191D0B151B49637000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000018232830414D27343D060A0F070F12202E372230
+ 3942576425333D18222A10191C0202062E414D00000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000022303737495534475126343E131C2224323A2835
+ 3F506C7B5C7A8E5571812D3C46050A0E0C14180C151C111C2300000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000001923293A505B3D515D4459692F3F4B3C505D4259
+ 66506C7B6585975D7A8D3C505D202D35131C2019242A091013020507050A0F09
+ 0F140912180F181D0B1318131E25233038283A432F414B26353F0E181D3A4C56
+ 00000000000000000000000025333C435A674963703548534258665774856383
+ 966F92A55B788A3346521B272E0F151A0F1A1D25333C293B431F2D35141D232C
+ 3C452939420E161B050A0E02020202020205070A040508020202020202020202
+ 4F626F0000000000000000003C505F506B79526E7F4359664C64725976865976
+ 856B8B9F5672832D3D470B11151620282838433C505D4F6B7B49627134465213
+ 1C230202020B111429394328373F1F2D321622261823281B242A182229151F25
+ 202D35597788000000000000465F6B5A77894C657447606D4B65743F55623345
+ 5141576526353E1C292F31424E42586526353D232F39475F6B3446523548552F
+ 3F4B3B4F5D5672836383955C788A4B6574415563415765516E7C658397557082
+ 2D3E48020202384B56000000587284536F805A77885570824158654E66773C4F
+ 5C384B573A4E5A30434E24343C32454F30424B354852496271475F6D34475252
+ 6E7C617E9084AABF80A5BB6D8DA2678599526D7E60809261819583A4BB88ADC2
+ 24343C020202020202000000617F903E56622F414C5772834C65753B505B384E
+ 5A435867465F6C4C6474374855384B583346503345502C3C464C65756A8A9F59
+ 76864C64755F7C8E59768567869A6E8FA157718285A7B985A5BB95B8CA95B9CD
+ 070F150202020202025F656969899D4C66752E3D465770826A899E617F904257
+ 63374C5723313A496271445C6A445A6747606C2C3D4631444E47606E5570804F
+ 69795D7A8B6C8D9F5672827296A97B9EB2799CAF7698AD99BBCFC9E8F982A8BC
+ 24313B18252C0204090202022C3C46435966638496769AAE6F8FA3618092536E
+ 7E37485327333D3D515F5672833C515D30424C3547552E3F482D3E493A4F5962
+ 819367869A5C7A8B536D7E4F69785C788A526C7B5C7A8D6F8FA38CADC27EA0B6
+ 7094A94E6C80627C8BA0B4C03D525F111B20445B697496AB7194A97294A9607F
+ 8F4B6371425A69384D58455B6A617F92445C6A3549562E3E473A4F5B5A76866C
+ 8CA0789DAF6C8CA04257643F5662455C6B3C515C4D66766A899A6D8EA2516E82
+ 7497ABAACADE0000000000004C63721F2D34020202283841617E8F6585986D8C
+ A25A77863D525D465D6C597586617F92465F6D3E556127353F2E3D485A778883
+ A5BB96B9D07C9FB4374B563F5561526E7C4E6A785772847FA2B688ACC3799EB4
+ 0000000000000000000000003B4F5A2D3D470E1519080F13344650445B6B4C62
+ 70537080486170415763506B7A6C8DA0516D7B3C515D233039273741516B7C72
+ 96AB6A8BA0455D6D4B62716280937CA1B6789CAF90B3C87B9DB1000000000000
+ 000000000000000000000000455C6B2E414B222E35070E111B262D3E55622535
+ 3D394D59394D592332392C3D473E53623A505C24323D2938426B899C83ACC156
+ 70802A3C46203038698999678899536E8097B9CD000000000000000000000000
+ 0000000000000000000000004D6575283841222F370C12161923283C4F5B455F
+ 6B485F6E4F6A79465D6D394C581A252D0406090202022E3B445C778808353902
+ 020202020232465297BBCF3A4F5C708C9E000000000000000000000000000000
+ 000000000000000000000000384B581D2A3224323C1C2930111B1F2A3B473F55
+ 63394E5A607E8F6685987195A932434E080E1202020202020216202657707B43
+ 525D0202023749557994A522313B698B9F000000000000000000000000000000
+ 00000000000000000000000026353F0F151B0E151A0E151A06080C2230383344
+ 4F3848564C6472455B6A6180927193A73A4E593446531B252E2C3B4864819064
+ 81930E151B415765243541435C6EA1C0D0000000000000000000000000000000
+ 000000000000000000000000222F38020202020202020202020202131D232C3A
+ 4524303A384D573D55624E67785977865774853F5562486170465D6B32445019
+ 252C263842435D6D415C6F8AB3CB000000000000000000000000000000000000
+ 0000000000000000000000001822280202020202020202020207070A11162939
+ 42151E2425343C30434C3444502E3D48516C7A61809249616F506A7A62829546
+ 60715D7E907198AE000000000000000000000000000000000000000000000000
+ 0000000000000000000000000B111402020202020204060819232A192429141E
+ 23121B1E2C3945384C562F3F4B3A4E5A4B64725C798B556F80516B7E5B7B8F6D
+ 90A4ACCDE2000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000020608020202020202020202182328455C6B394D
+ 592839431F2D3533444F394D584C6575475F6E3F57643D58665F7F937F9EB2B1
+ D1E4000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000111A1E0A0F120910130F181C19262D2D3E492C3C
+ 462E3F491D2A313B515F445B674D6777577486516C7F7294A7B4D4E6B1CDDE8C
+ ACBD000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000002839411620276D8DA34F6978020608020206141D
+ 23182227131D2365889C5776894F6A7A6B8DA299BCD1CDEBFEC0DEEF4662746F
+ 8EA1000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000018232A30424C799EB32A3B450202020202020202
+ 020202022E3F4B8BB3CA93B6CCA4C6D8AFD1E198BBD0A5C8DB83A7BD4966789A
+ B9CD000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000E13182737422A3B450202061F2A313548552837
+ 411F313B637C8B000000000000000000A2C0D36E90A75371836F8FA4557284A1
+ BED0000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000002020211191E25333D435A67608090435867526F
+ 81425F6E82A2B400000000000000000089ADC16E93A9486270425C6B65849700
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000020202020205394E58455C6C24333A2E414E5977
+ 8994B7CC00000000000000000000000093B6CB48657730434F2637425F7A8D00
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000002020205080A374C5626374220313D718E9E0000
+ 00000000000000000000000000000000BBD7E97B9CAF384F5C2535415F7A8C00
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000202050205091B27323449560000000000000000
+ 000000000000000000000000000000000000000000008CAEC13D596A59728300
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000859FAE2A3B445A72810000000000000000000000
+ 000000000000000000000000000000000000000000000000006F8EA247627200
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000001FFFFF000FFFFF0007FFFF0001FFFF0000000F
+ 0000000700000003000000010000000100000000000000000000000000000003
+ 0000000F0000003F000000FF000001FF000001FF000001FF000003FF00000FFF
+ 00001FFF00003FFF00003FFF00003FFF00003FFF00703FFF00707FFF00F07FFF
+ 03F07FFF0FFC7FFF1FFE7FFF}
+ end
+ object CancelButton: TButton
+ Left = 344
+ Top = 248
+ Width = 75
+ Height = 25
+ Caption = '&Cancel'
+ TabOrder = 0
+ OnClick = CancelButtonClick
+ end
+ object NextButton: TButton
+ Left = 264
+ Top = 248
+ Width = 75
+ Height = 25
+ Caption = '&Next'
+ TabOrder = 1
+ OnClick = NextButtonClick
+ end
+ object GroupBox1: TGroupBox
+ Left = 48
+ Top = 136
+ Width = 369
+ Height = 89
+ Caption = 'Wolfpack Installation Folder'
+ TabOrder = 2
+ object InfoLabel2: TLabel
+ Left = 8
+ Top = 56
+ Width = 284
+ Height = 13
+ Caption = 'Please select the wolfpack.xml of your Wolfpack installation.'
+ end
+ object WolfpackPath: TEdit
+ Left = 8
+ Top = 24
+ Width = 265
+ Height = 21
+ TabOrder = 0
+ end
+ object BrowseButton: TButton
+ Left = 280
+ Top = 24
+ Width = 75
+ Height = 21
+ Caption = 'Browse'
+ TabOrder = 1
+ OnClick = BrowseButtonClick
+ end
+ end
+ object XPManifest: TXPManifest
+ Left = 384
+ Top = 104
+ end
+ object OpenFolderDialog: TOpenFolderDialog
+ Title = 'Please select your Wolfpack installation folder.'
+ Options = [flReturnOnlyFSDirs, flShowStatusText]
+ OnSelectionChange = OpenFolderDialogSelectionChange
+ Left = 8
+ Top = 152
+ end
+end
Added: trunk/WPGM/ImportDefinitions/Main.~pas
===================================================================
--- trunk/WPGM/ImportDefinitions/Main.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/Main.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,108 @@
+unit Main;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, ExtCtrls, StdCtrls, XPMan, OpenFolderDialog;
+
+type
+ TMainForm = class(TForm)
+ BottomBevel: TBevel;
+ CancelButton: TButton;
+ NextButton: TButton;
+ TopImage: TImage;
+ TopBevel: TBevel;
+ InfoLabel1: TLabel;
+ WolfpackIcon: TImage;
+ XPManifest: TXPManifest;
+ GroupBox1: TGroupBox;
+ WolfpackPath: TEdit;
+ BrowseButton: TButton;
+ InfoLabel2: TLabel;
+ OpenFolderDialog: TOpenFolderDialog;
+ procedure CancelButtonClick(Sender: TObject);
+ procedure BrowseButtonClick(Sender: TObject);
+ procedure OpenFolderDialogSelectionChange(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure NextButtonClick(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ MainForm: TMainForm;
+
+implementation
+
+{$R *.dfm}
+
+uses Registry, WpConfiguration;
+
+{
+ Close the wizard.
+}
+procedure TMainForm.CancelButtonClick(Sender: TObject);
+begin
+ Close;
+end;
+
+{
+ Let the user select a directory.
+}
+procedure TMainForm.BrowseButtonClick(Sender: TObject);
+begin
+ if OpenFolderDialog.Execute then
+ WolfpackPath.Text := OpenFolderDialog.Folder;
+end;
+
+{
+ Show the user if the directory he selected is valid or not.
+}
+procedure TMainForm.OpenFolderDialogSelectionChange(Sender: TObject);
+begin
+ if FileExists(IncludeTrailingPathDelimiter(OpenFolderDialog.Folder) + 'wolfpack.xml') then
+ OpenFolderDialog.StatusText := 'This is a valid Wolfpack installation directory.'
+ else
+ OpenFolderDialog.StatusText := 'This is not a valid Wolfpack installation directory.';
+end;
+
+(*
+ Query the Wolfpack installation directory from the uninstallation database
+ @ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{44306150-2736-4554-ACD5-957D5F12604B}}_is1
+*)
+procedure TMainForm.FormCreate(Sender: TObject);
+var
+ Registry: TRegistry;
+begin
+ Registry := TRegistry.Create;
+ Registry.RootKey := HKEY_LOCAL_MACHINE;
+
+ // Open the Uninstall Key.
+ if not Registry.OpenKeyReadOnly('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{44306150-2736-4554-ACD5-957D5F12604B}}_is1') then begin
+ Registry.Free;
+ exit;
+ end;
+
+ // Read Installation Directory
+ WolfpackPath.Text := Registry.ReadString('Inno Setup: App Path');
+
+ Registry.Free;
+end;
+
+procedure TMainForm.NextButtonClick(Sender: TObject);
+var
+ WpConfiguration: TWpConfiguration;
+begin
+ // Try to load the configuration file
+ try
+ WpConfiguration := TWpConfiguration.Create(IncludeTrailingPathDelimiter(WolfpackPath.Text) + 'wolfpack.xml');
+ WpConfiguration.Free;
+ except
+ Application.MessageBox('An error occured while loading the wolfpack.xml file from your Wolfpack installation directory', 'Error', MB_OK+MB_ICONERROR);
+ end;
+end;
+
+end.
Added: trunk/WPGM/ImportDefinitions/Strlib.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/ImportDefinitions/Strlib.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/ImportDefinitions/Strlib.pas
===================================================================
--- trunk/WPGM/ImportDefinitions/Strlib.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/Strlib.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,645 @@
+{:
+PURPOSE AND IMPLEMENTATION:
+ This unit defines some useful string handling routines.
+
+HISTORY:
+ ??/??/96 - Created by Colin Patrick Sarsfield (colin.sarsfield at usa.net)
+ 11/08/96 - Left and Right functions added by CPS
+ 05/21/97 - IntlStrToFloat added by CPS
+
+COPYRIGHT:
+ Released into the public domain.
+}
+unit Strlib;
+
+interface
+
+uses
+ Classes;
+
+type
+ CharSet = set of Char;
+
+function Split(Source, Deli: string; StringList: TStringList): TStringList;
+function BoolToStr(const b: Boolean): string;
+function CompareStrNumMix(const str1, str2: String): Integer;
+function DequoteString(s: String): String;
+procedure DivideStrInt(const Str: string; var BegStr: string; var Int: Integer);
+function DropTrailingZeros(const S: String): String;
+procedure FileSplit(const Path: String; var Dir, Name, Ext: String);
+function FormatAsIdentifier(const AString: String): String;
+function FracToStr(const n, d: Integer): string;
+function IntlStrToFloat(const AString: string): Single;
+function IntToAlpha(const i: Longint): string;
+function Left(const AString: string; i: Integer): string;
+function LookupOrdStr(const s: String; const a: array of String): Integer;
+function LTrim(const AString: string): string;
+procedure MergeValues(A, B: TStringList);
+function NextStrColumn(S: String; var Pos: Integer): String;
+function PosAfter(SubStr, S: String; StartingAt: Integer): Integer;
+function QtyList(A: TStringList): String;
+function RepeatStr(const Str: String; const qty: Integer): String;
+function Replace(const PTarget, BeforeStr, AfterStr: string): string;
+function Right(const AString: string; i: Integer): string;
+function RScan(const AString: string; chr: Char): Integer;
+function RTrim(const AString: string): string;
+function Scan(const AString: string; chr: Char): Integer;
+{$IFNDEF WIN32}
+procedure SetLength(var S: string; NewLength: Integer);
+{$ENDIF}
+procedure StreamToString(AStream: TStream; var AString: string);
+function StringOfChar(const AChar: Char; Length: Integer): string;
+procedure StringToStream(const AString: string; AStream: TStream);
+function Trim(const AString: string): string;
+function TrimChars(const AString: String; TrimChars: CharSet): string;
+
+implementation
+
+uses
+ SysUtils;
+
+{:Return a string representation for the boolean value b. (e.g. True = 'True') }
+function BoolToStr(const b: Boolean): string;
+begin
+ if b then
+ Result := 'True'
+ else
+ Result := 'False';
+end;
+
+{:compare two strings. Unlike a normal string comparison, digits 0..9 are seen
+as a number with any other adjoining numbers and these numbers are compared as
+whole numbers. An example of a list properly sorted using this comparision
+function:
+
+AH-1
+AH-2b
+AH-12-15c
+AH-31
+
+This function is case-insensitive.}
+function CompareStrNumMix(const str1, str2: String): Integer;
+var
+ w1, w2: String;
+ p1, p2: Integer;
+ isdigit1, isdigit2: Boolean;
+const
+ Digits = ['0'..'9'];
+
+ procedure GetDigits(const source: String; var work: String; var pos: Integer);
+ begin
+ while (pos <= Length(source)) and (source[pos] in Digits) do begin
+ work := work + source[pos];
+ Inc(pos)
+ end;
+ end;
+
+ procedure GetString(const source: String; var work: String; var pos: Integer);
+ begin
+ while (pos <= Length(source)) and not (source[pos] in Digits) do begin
+ work := work + source[pos];
+ Inc(pos)
+ end;
+ end;
+begin
+ { if str1 < str2 then negative
+ if str1 > str2 then positive
+ if str1 = str2 then zero }
+ p1 := 1;
+ p2 := 1;
+ repeat
+ { terminate with longer string being greater if end of either string is
+ reached }
+ if p1 > Length(str1) then begin Result := -1; Exit end;
+ if p2 > Length(str2) then begin Result := 1; Exit end;
+ w1 := '';
+ w2 := '';
+
+ isdigit1 := str1[p1] in Digits;
+ isdigit2 := str2[p2] in Digits;
+ { if different types of strings then exit }
+ if isdigit1 <> isdigit2 then begin Result := Ord(isdigit1) - Ord(isdigit2); Exit end;
+ if isdigit1 then begin
+ { number portion }
+ GetDigits(str1, w1, p1);
+ GetDigits(str2, w2, p2);
+ try
+ Result := StrToInt(w1) - StrToInt(w2);
+ except
+ // if StrToInt fails, just compare the text normally
+ Result := CompareText(w1, w2);
+ end;
+ end
+ else begin
+ // string portion
+ GetString(str1, w1, p1);
+ GetString(str2, w2, p2);
+ Result := CompareText(w1, w2);
+ end;
+ until Result <> 0;
+end;
+
+{:Revert a quoted-style string to normal. Leave other styles of strings
+untouched. For example,
+
+"1"" pipe thread"
+
+becomes
+
+1" pipe thread
+}
+function DequoteString(s: String): String;
+var
+ Len: Integer;
+begin
+ Len := Length(s);
+ if ((Copy(s, 1, 1) = '"') and (Copy(s, Len, 1) = '"')) then begin
+ s := Copy(s, 2, Len - 2);
+ s := Replace(s, '""', '"');
+ end;
+ Result := s;
+end;
+
+{:Assuming Str begins with non-numeric characters and ends with numeric
+characters (i.e., 0..9), return the non-numeric portion in BegStr and convert
+the numeric portion to an integer returning it in Int.}
+procedure DivideStrInt(const Str: string; var BegStr: string; var Int: Integer);
+var
+ TStr: string;
+ i: Integer;
+begin
+ for i := Length(Str) downto 1 do
+ if (Str[i] < '0') or (Str[i] > '9') then
+ Break;
+ BegStr := Copy(Str, 1, i);
+ if i = Length(Str) then
+ Int := 0
+ else begin
+ TStr := Copy(Str, i + 1, Length(Str) - i);
+ try { capture range check errors, etc. }
+ Int := StrToInt(TStr);
+ except
+ Int := 0;
+ end;
+ end;
+end;
+
+{:Eliminates .00 from end of whole numbers. (i.e., 10.00 = 10, 10.50 = 10.5,
+10.05 = 10.05) Looks through string for decimal. If found, goes to the end
+and looks back one character for a decimal or zero. Continues that action
+eliminating zeros and decimals until whole number is found to left of decimal.}
+function DropTrailingZeros(const S: String): String;
+var
+ I: Integer;
+ L: Integer;
+begin
+ Result := S;
+ I := POS('.',Result);
+ if I <> 0 then begin
+ L := Length(Result);
+ while Result[L] = '0' do
+ dec(L);
+ if Result[L] = '.' then
+ dec(L);
+ SetLength(Result,L)
+ end;
+end;
+
+{:Split a file path "Path" into three parts: its directory "Dir", its name
+"Name", and its extension "Ext".}
+procedure FileSplit(const Path: String; var Dir, Name, Ext: String);
+var
+ NamePos, ExtPos: Integer;
+begin
+ NamePos := RScan(Path, '\');
+ if NamePos = 0 then NamePos := RScan(Path, ':');
+ if NamePos = 0 then NamePos := 1 else Inc(NamePos);
+ ExtPos := RScan(Path, '.');
+ if ExtPos < NamePos then ExtPos := Length(Name);
+ Dir := Copy(Path, 1, NamePos - 1);
+ Name := Copy(Path, NamePos, ExtPos - NamePos);
+ Ext := Copy(Path, ExtPos, Length(Path) - ExtPos + 1);
+end;
+
+{:Take a string and format it as an identifier (e.g.,
+"Cond. fluid" = "CondFluid"
+"24 times" = "Times"
+"Cond. fluid_Water" = "CondFluid_Water"
+}
+function FormatAsIdentifier(const AString: String): String;
+var
+ i, Len: Integer;
+ Cap: Boolean;
+begin
+ Len := Length(AString);
+ Result := '';
+ i := 1;
+ // skip over junk at beginning
+ while (i <= Len) and not (AString[i] in ['a'..'z', 'A'..'Z', '_']) do
+ Inc(i);
+ Cap := True;
+ while i <= Len do begin
+ if AString[i] = '_' then begin
+ Result := Result + '_';
+ Cap := True
+ end
+ else if AString[i] in ['a'..'z', 'A'..'Z', '0'..'9'] then begin
+ if Cap then begin
+ Result := Result + UpperCase(AString[i]);
+ Cap := False;
+ end
+ else
+ Result := Result + AString[i];
+ end
+ else
+ Cap := True;
+ Inc(i)
+ end;
+end;
+
+{:Convert a fraction to its string representation where "n" is the numerator
+and "d" is the denomiator. Simplify the fraction if possible. Fractions will
+be displayed as an integer (optionally) followed by a fraction less than one
+(optionally). Note that this function only works for positive integers or zero. }
+function FracToStr(const n, d: Integer): string;
+var
+ i, w, nn, dd: Integer;
+begin
+ // fail if n or d are negative
+ if (n < 0) or (d < 0) then
+ raise Exception.Create('FracToStr does not support negative integers');
+ // calculate the whole number portion of the fraction
+ w := n div d;
+ // calculate the remaining numerator after the whole number is subtracted out
+ nn := n mod d;
+ // store a copy of the denominator for simplification
+ dd := d;
+ // check all possible divisors to simply
+ for i := d - 1 downto 2 do
+ // if the nominator and the denominator are both divisable by the same
+ // number than divide by that number to simplify.
+ if ((dd mod i) = 0) and ((nn mod i) = 0) then begin
+ dd := dd div i;
+ nn := nn div i;
+ end;
+ // if the whole number > 0 then represent it in the result
+ if w > 0 then
+ Result := Format('%d ', [w])
+ else // otherwise blank out the result
+ Result := '';
+ // if the numerator is also zero than display zero
+ if nn = 0 then begin
+ if w = 0 then Result := '0';
+ end
+ else // otherwise add the string representation of the fraction to the result
+ Result := Result + Format('%d/%d', [nn, dd]);
+end;
+
+{:This function will convert a String to a Single whether the decimal seperator
+used is the localized (international) decimal seperator or the period (i.e., '.'). }
+function IntlStrToFloat(const AString: string): Single;
+var
+ RCode: Integer;
+begin
+ try
+ // StrToFloat recognizes the international decimal seperator (e.g., '.' in
+ // USA, ',' in parts of Latin America)
+ Result := StrToFloat(AString);
+ except
+ // Val always recognizes '.' as the decimal seperator
+ Val(AString, Result, RCode);
+ if RCode <> 0 then
+ raise EConvertError.Create('Unable to convert string to number: ''' + AString + '');
+ end;
+end;
+
+{:Convert an integer to a base 26 number based on the alphabet much like
+column headings in most spreadsheet programs (e.g., A, B, C .., Z, AA, AB, etc.).}
+function IntToAlpha(const i: Longint): string;
+begin
+ if i <= 26 then
+ Result := Chr(Ord('A') + i - 1)
+ else
+ Result := IntToAlpha(i div 26) + Chr(Ord('A') + (i mod 26));
+end;
+
+{:This function returns a string "i" characters long starting at the left
+(beginning) of "AString". Note that if "AString" is less that "i" characters
+long this function will return the whole string. }
+function Left(const AString: string; i: Integer): string;
+begin
+ Result := Copy(AString, 1, i);
+end;
+
+{:This function returns an integer indicating the position of s in a. Note that
+this is often used to look up an ordinal based on its string representation;
+hence its name.}
+function LookupOrdStr(const s: String; const a: array of String): Integer;
+var
+ i: Integer;
+begin
+ for i := Low(a) to High(a) do
+ if a[i] = s then begin
+ Result := i;
+ Exit;
+ end;
+ raise Exception.CreateFmt('Unable to lookup ordinal string value: "%s"', [s]);
+end;
+
+{:This function returns the remainder of "AString" after any leading spaces are
+removed.}
+function LTrim(const AString: string): string;
+var
+ i, b, l: Integer;
+begin
+ b := 1;
+ l := Length(AString);
+ for i := 1 to l do
+ if AString[i] = ' ' then
+ b := i + 1
+ else
+ Break;
+ if b > l then
+ Result := ''
+ else
+ Result := Copy(AString, b, l - b + 1)
+end;
+
+{:This procedure takes two TStringList's populated with lines like "coil=true"
+(reference the "Values" property in the help) and merges them. The result is
+placed in A. Note that for any strings that both A & B have B have the part to
+the left of the equals sign in common the merged list will use the line from B.}
+procedure MergeValues(A, B: TStringList);
+var
+ i, p: Integer;
+begin
+ for i := 0 to Pred(B.Count) do begin
+ p := Pos('=', B[i]);
+ if (p <> 0) then
+ A.Values[Copy(B[i], 1, p - 1)] := Copy(B[i], p + 1, Length(B[i]) - p);
+ end;
+end;
+
+{:This function extracts the next "column" out of "S" which should a line from
+either a space or tab delimited text file. Note that Pos should be 1 on the
+first call to this function for a given string and the Pos returned by this
+function should be used in subsequent calls.}
+function NextStrColumn(S: String; var Pos: Integer): String;
+var
+ Start, Len: Integer;
+
+ function IsSpace(C: Char): Boolean;
+ begin
+ Result := C in [' ', #9];
+ end;
+begin
+ Len := Length(S);
+ while IsSpace(S[Pos]) and (Pos <= Len) do Inc(Pos);
+ if Pos > Len then begin Result := ''; Exit end;
+ Start := Pos;
+ while not IsSpace(S[Pos]) and (Pos <= Len) do Inc(Pos);
+ Result := Copy(S, Start, Pos - Start);
+end;
+
+{:This function is just like the "Pos" function that is provided with Delphi
+except it accepts an additional argument, "StartingAt". This argument tells
+this function where to start its search whereas the "Pos" function always starts
+at position 1.}
+function PosAfter(SubStr, S: String; StartingAt: Integer): Integer;
+begin
+ if StartingAt < 1 then StartingAt := 1;
+ Delete(S, 1, StartingAt - 1);
+ Result := Pos(SubStr, S);
+ if Result <> 0 then
+ Result := Result + StartingAt - 1;
+end;
+
+{:this function takes a TStringList and formats it as a "quantity list" of the
+string list's values. For example:
+The StringList 'A','B','A','B','B','C'
+becomes '(2)A/(3)B/(1)C'
+If the string list contains only one item it is considered a special case and
+that item is returned without any change in formatting.
+Note: the string list is sorted by list function}
+function QtyList(A: TStringList): String;
+var
+ i, qty: Integer;
+ str: String;
+begin
+ if A.Count = 1 then begin
+ Result := A[0];
+ Exit;
+ end;
+ A.Sort;
+ i := 0;
+ Result := '';
+ while i < A.Count do begin
+ str := A[i];
+ qty := 1;
+ while (i < Pred(A.Count)) and (A[i + 1] = str) do begin
+ Inc(qty);
+ Inc(i);
+ end;
+ if Result <> '' then Result := Result + '/';
+ Result := Result + Format('(%d)%s', [qty, str]);
+ Inc(i)
+ end;
+end;
+
+{:This function creates a string that is the concatenation of "qty" instances of
+the string "Str".}
+function RepeatStr(const Str: String; const qty: Integer): String;
+var
+ i: Integer;
+begin
+ if qty > 0 then begin
+ Result := Str;
+ for i := 2 to qty do
+ Result := Result + Str;
+ end
+ else
+ Result := '';
+end;
+
+{:This function returns a modified version of "PTarget" where all instances of
+"BeforeStr" have been replaced by "AfterStr".}
+function Replace(const PTarget, BeforeStr, AfterStr: string): string;
+var
+ i, j: Integer;
+begin
+ Result := PTarget;
+ { start at beginning of string }
+ i := 1;
+ while True do begin
+ j := i;
+ i := Pos(BeforeStr, Copy(Result, i, Length(Result) - i + 1));
+ if i = 0 then
+ Break;
+ Inc(i, j - 1);
+ Delete(Result, i, Length(BeforeStr));
+ Insert(AfterStr, Result, i);
+ { adjust i to correct position }
+ i := i + Length(AfterStr);
+ end;
+ Result := Result;
+end;
+
+{:This function returns a string "i" characters long starting at the right
+(end) of "AString". Note that if "AString" is less that "i" characters
+long this function will return the whole string. }
+function Right(const AString: string; i: Integer): string;
+begin
+ if i > Length(AString) then
+ Result := AString
+ else
+ Result := Copy(AString, Length(AString) - i + 1, i);
+end;
+
+{:This function returns the index of the last instance of "chr" in "AString".
+It returns 0 if none was found.}
+function RScan(const AString: string; chr: Char): Integer;
+var
+ i: Integer;
+begin
+ Result := 0;
+ for i := Length(AString) downto 1 do
+ if AString[i] = chr then begin
+ Result := i;
+ Exit;
+ end;
+end;
+
+{:This function returns the remainder of "AString" after any trailing spaces are
+removed.}
+function RTrim(const AString: string): string;
+var
+ i, e: Integer;
+begin
+ e := Length(AString);
+ for i := Length(AString) downto 1 do
+ if AString[i] = ' ' then
+ e := i - 1
+ else
+ Break;
+ if 1 > e then
+ Result := ''
+ else
+ Result := Copy(AString, 1, e)
+end;
+
+{:This function returns the index of the first instance of "chr" in "AString".
+It returns 0 if none was found.}
+function Scan(const AString: string; chr: Char): Integer;
+var
+ i: Integer;
+begin
+ Result := 0;
+ for i := 1 to Length(AString) do
+ if AString[i] = chr then begin
+ Result := i;
+ Exit;
+ end;
+end;
+
+{$IFNDEF WIN32}
+
+{:This function is to enable portability between 16-bit and 32-bit programs.
+Since 32-bit Delphi defines a SetLength function, this defines one for 16-bit
+programs.}
+procedure SetLength(var S: string; NewLength: Integer);
+begin
+ S[0] := Char(NewLength);
+end;
+{$ENDIF}
+
+{:This procedure duplicates the contents of "AStream" and places it in "AString".}
+procedure StreamToString(AStream: TStream; var AString: string);
+var
+ L: Integer;
+begin
+ AStream.Read(L, Sizeof(Integer));
+ SetLength(AString, L);
+ AStream.Read(AString[1], L);
+end;
+
+{:This function returns a string "Length" characters long where each character
+is "AChar".}
+function StringOfChar(const AChar: Char; Length: Integer): string;
+begin
+ SetLength(Result, Length);
+ FillChar(Result[1], Length, AChar);
+end;
+
+{:This procedure writes the contents of "AString" to "AStream".}
+procedure StringToStream(const AString: string; AStream: TStream);
+var
+ L: Integer;
+begin
+ L := Length(AString);
+ AStream.Write(L, Sizeof(Integer));
+ AStream.Write(AString[1], L);
+end;
+
+{:This function returns the remainder of "AString" after any leading or trailing
+spaces are removed.}
+function Trim(const AString: string): string;
+var
+ i, b, e: Integer;
+begin
+ b := 1;
+ e := Length(AString);
+ for i := 1 to e do
+ if AString[i] = ' ' then
+ b := i + 1
+ else
+ Break;
+ for i := Length(AString) downto b do
+ if AString[i] = ' ' then
+ e := i - 1
+ else
+ Break;
+ if b > e then
+ Result := ''
+ else
+ Result := Copy(AString, b, e - b + 1)
+end;
+
+function TrimChars(const AString: string; TrimChars: CharSet): string;
+var
+ i, b, e: Integer;
+begin
+ b := 1;
+ e := Length(AString);
+ for i := 1 to e do
+ if AString[i] in TrimChars then
+ b := i + 1
+ else
+ Break;
+ for i := Length(AString) downto b do
+ if AString[i] in TrimChars then
+ e := i - 1
+ else
+ Break;
+ if b > e then
+ Result := ''
+ else
+ Result := Copy(AString, b, e - b + 1)
+end;
+
+function Split(Source, Deli: string; StringList: TStringList): TStringList;
+var
+ EndOfCurrentString: byte;
+begin
+ repeat
+ EndOfCurrentString := Pos(Deli, Source);
+ if EndOfCurrentString = 0 then
+ StringList.add(Source)
+ else
+ StringList.add(Copy(Source, 1, EndOfCurrentString - 1));
+ Source := Copy(Source, EndOfCurrentString + length(Deli), length(Source) - EndOfCurrentString);
+ until EndOfCurrentString = 0;
+ result := StringList;
+end;
+
+end.
+
Added: trunk/WPGM/ImportDefinitions/WpConfiguration.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/ImportDefinitions/WpConfiguration.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/ImportDefinitions/WpConfiguration.pas
===================================================================
--- trunk/WPGM/ImportDefinitions/WpConfiguration.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/WpConfiguration.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,111 @@
+unit WpConfiguration;
+
+interface
+
+uses Classes;
+
+type TWpConfiguration = class
+ protected
+ procedure processOption(Group: String; Name: String; Value: String);
+
+ public
+ ImportDefinitions: TStringList;
+
+ constructor Create(Filename: String);
+ destructor Destroy; override;
+end;
+
+implementation
+
+uses SysUtils, XmlReader, StrLib;
+
+{
+ Helper Function
+}
+function LoadFile( FileName: String ): String;
+var
+ Input: TStream;
+ StringStream: TStringStream;
+begin
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+ StringStream := TStringStream.Create( '' );
+ StringStream.CopyFrom( Input, Input.Size );
+ Result := StringStream.DataString;
+ StringStream.Free;
+ Input.Free;
+end;
+
+{
+ Constructor for the Wp Configuration class.
+}
+constructor TWpConfiguration.Create(Filename: String);
+var
+ XmlReader: TXMLStringReader;
+ Document, Outmost, Group, Option: TXMLNode;
+ i, j: Integer;
+ Content, GroupName, OptionName, OptionValue: String;
+begin
+ ImportDefinitions := TStringList.Create;
+
+ Content := LoadFile(Filename);
+
+ XmlReader := TXMLStringReader.Create(Content);
+ Document := XmlReader.ParseDocument;
+
+ // Get outmost node
+ Outmost := Document.FindNode('preferences');
+
+ for i := 0 to Outmost.NodeCount - 1 do begin
+ Group := Outmost.Nodes[i];
+
+ // We found a group
+ if (Group.Name = 'group') and (Group.NodeType = xntElement) then begin
+ GroupName := '';
+ Group.LookupBasicData('name', GroupName);
+
+ if GroupName = '' then
+ continue; // Skip this group without a name.
+
+ // Parse options
+ for j := 0 to Group.NodeCount - 1 do begin
+ Option := Group.Nodes[j];
+
+ if (Option.Name = 'option') and (Option.NodeType = xntElement) then begin
+ OptionName := '';
+ Option.LookupBasicData('name', OptionName);
+
+ if OptionName = '' then
+ continue; // Skip option without a name.
+
+ Option.LookupBasicData('value', OptionValue);
+ processOption(GroupName, OptionName, OptionValue);
+ end;
+ end;
+ end;
+ end;
+
+ Document.Free;
+ XmlReader.Free;
+end;
+
+{
+ Destructor for the configuration class.
+}
+destructor TWpConfiguration.Destroy;
+begin
+ ImportDefinitions.Free;
+ inherited;
+end;
+
+{
+ Process a wp configuration node.
+}
+procedure TWpConfiguration.processOption(Group: String; Name: String; Value: String);
+begin
+ if (Group = 'General') and (Name = 'Definitions') then begin
+ ImportDefinitions.Clear;
+ StrLib.Split(Value, ';', ImportDefinitions);
+ end;
+end;
+
+end.
Added: trunk/WPGM/ImportDefinitions/WpConfiguration.~pas
===================================================================
--- trunk/WPGM/ImportDefinitions/WpConfiguration.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/WpConfiguration.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,110 @@
+unit WpConfiguration;
+
+interface
+
+uses Classes;
+
+type TWpConfiguration = class
+ protected
+ procedure processOption(Group: String; Name: String; Value: String);
+
+ public
+ ImportDefinitions: TStringList;
+
+ constructor Create(Filename: String);
+ destructor Destroy; override;
+end;
+
+implementation
+
+uses SysUtils, XmlReader, StrLib;
+
+{
+ Helper Function
+}
+function LoadFile( FileName: String ): String;
+var
+ Input: TStream;
+ StringStream: TStringStream;
+begin
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+ StringStream := TStringStream.Create( '' );
+ StringStream.CopyFrom( Input, Input.Size );
+ Result := StringStream.DataString;
+ StringStream.Free;
+ Input.Free;
+end;
+
+{
+ Constructor for the Wp Configuration class.
+}
+constructor TWpConfiguration.Create(Filename: String);
+var
+ XmlReader: TXMLStringReader;
+ Document, Outmost, Group, Option: TXMLNode;
+ i, j: Integer;
+ Content, GroupName, OptionName, OptionValue: String;
+begin
+ ImportDefinitions := TStringList.Create;
+
+ Content := LoadFile(Filename);
+
+ XmlReader := TXMLStringReader.Create(Content);
+ Document := XmlReader.ParseDocument;
+
+ // Get outmost node
+ Outmost := Document.FindNode('preferences');
+
+ for i := 0 to Outmost.NodeCount - 1 do begin
+ Group := Outmost.Nodes[i];
+
+ // We found a group
+ if (Group.Name = 'group') and (Group.NodeType = xntElement) then begin
+ GroupName := '';
+ Group.LookupBasicData('name', GroupName);
+
+ if GroupName = '' then
+ continue; // Skip this group without a name.
+
+ // Parse options
+ for j := 0 to Group.NodeCount - 1 do begin
+ Option := Group.Nodes[j];
+
+ if (Option.Name = 'option') and (Option.NodeType = xntElement) then begin
+ OptionName := '';
+ Option.LookupBasicData('name', OptionName);
+
+ if OptionName = '' then
+ continue; // Skip option without a name.
+
+ Option.LookupBasicData('value', OptionValue);
+ processOption(GroupName, OptionName, OptionValue);
+ end;
+ end;
+ end;
+ end;
+
+ Document.Free;
+ XmlReader.Free;
+end;
+
+{
+ Destructor for the configuration class.
+}
+destructor TWpConfiguration.Destroy;
+begin
+ ImportDefinitions.Free;
+ inherited;
+end;
+
+{
+ Process a wp configuration node.
+}
+procedure TWpConfiguration.processOption(Group: String; Name: String; Value: String);
+begin
+ if (Group = 'General') and (Name = 'Definitions') then begin
+ StrLib.Split(Value, ';', ImportDefinitions);
+ end;
+end;
+
+end.
Added: trunk/WPGM/ImportDefinitions/XmlReader.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/ImportDefinitions/XmlReader.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/ImportDefinitions/XmlReader.pas
===================================================================
--- trunk/WPGM/ImportDefinitions/XmlReader.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/XmlReader.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,772 @@
+{:
+PURPOSE AND IMPLEMENTATION:
+ This unit defines classes for parsing a well-formed standalone XML document in
+ to a tree of nodes describing the data therein. These classes only support a
+ subset of the XML 1.0 recommendation and have not been analyzed for
+ conformance with the recommendation. This module also only supports 8-bit
+ character sets and makes no special allowances for UTF-8. Nor has any support
+ for the "<!DOCTYPE" node been implemented. Parsing of the XML declaration
+ lazily uses the attribute parsing code which is not correct (but works). This
+ module also freely trims element whitespace which is not always correct.
+
+ Q: Why use this module instead of Microsoft's XML parser or the OpenXML
+ project?
+
+ A: I wrote this module to be free of dependencies on outside libraries and to
+ be small and fast. Neither of the above libraries met that criteria. I
+ didn't like the idea of requiring my users to install Microsoft's XML
+ library (and the potential compatibility problems that arise). Nor did I
+ like the idea of adding 135 kb (OpenXML) to my executable just to load files
+ in XML format. Instead this unit only uses about 7 kb.
+
+ This was written for Delphi 5. It may work for other versions, but does
+ require method overloading which was introduced in Delphi 4.
+
+HISTORY:
+ 09/12/00 - Created by Colin Patrick Sarsfield
+
+DISCLAIMER:
+ Use at your own risk.
+
+COPYRIGHT:
+ Released into the public domain by Colin Sarsfield 9/13/00
+}
+unit XMLReader;
+
+interface
+
+uses
+ Classes;
+
+type
+ CharSet = set of Char;
+
+ TXMLNode = class;
+
+ TXMLNodeType = (xntDocument, xntElement, xntAttribute, xntProcessingInstruction,
+ xntXMLDeclaration);
+
+ TXMLReader = class
+ private
+ CurChar: Char;
+ function ParseAttribute(Node: TXMLNode): Boolean;
+ function ParseAttValue(var AttValue: String): Boolean;
+ function ParseCDSect(Node: TXMLNode): Boolean;
+ function ParseCharData(Node: TXMLNode): Boolean;
+ function ParseComment: Boolean;
+ procedure ParseContent(Node: TXMLNode);
+ procedure ParseDocTypeDecl(Node: TXMLNode);
+ function ParseElement(Node: TXMLNode): Boolean;
+ function ParseEq: Boolean;
+ function ParseETag(Node: TXMLNode): Boolean;
+ function ParseMisc(Node: TXMLNode): Boolean;
+ function ParseName(var Name: String): Boolean;
+ function ParseProcessingInstruction(Node: TXMLNode): Boolean;
+ function ParseProlog(Node: TXMLNode): Boolean;
+ function ParseReference: Char;
+ function ParseWhitespace: Boolean;
+ procedure ParseXMLDecl(Node: TXMLNode);
+ procedure ReportError(Err: String);
+ protected
+ function DoesStreamMatchString(Str: String): Boolean;
+ function EndOfData: Boolean; virtual; abstract;
+ procedure FreeState(State: TObject); virtual; abstract;
+ procedure ReadChar; virtual; abstract;
+ procedure ReadCharAndCheckForEnd;
+ procedure RestoreState(State: TObject); virtual; abstract;
+ function SaveState: TObject; virtual; abstract;
+ public
+ function ParseDocument: TXMLNode;
+ end;
+
+ TXMLStringReader = class(TXMLReader)
+ private
+ FData: String;
+ FPosition: Integer;
+ protected
+ function EndOfData: Boolean; override;
+ procedure FreeState(State: TObject); override;
+ procedure ReadChar; override;
+ procedure RestoreState(State: TObject); override;
+ function SaveState: TObject; override;
+ public
+ constructor Create(AData: String);
+ end;
+
+ TXMLNode = class
+ private
+ FData: String;
+ FName: String;
+ FNodes: TList;
+ FNodeType: TXMLNodeType;
+ function GetNodeCount: Integer;
+ function GetNodes(Index: Integer): TXMLNode;
+ function GetTotalNodeCount: Integer;
+ function GetAsInteger: Integer;
+ function GetAsSingle: Single;
+ function GetAsDateTime: TDateTime;
+ public
+ constructor Create; virtual;
+ destructor Destroy; override;
+
+ function AddNode(Node: TXMLNode): Integer;
+ function Description: String;
+ function FindNode(const Name: String; const Index: Integer): TXMLNode; overload;
+ function FindNode(const Name: String): TXMLNode; overload;
+ function FindNodeExc(const Name: String): TXMLNode;
+ function HasNode(const Name: String): Boolean;
+ procedure LookupBasicData(const Name: String; var LData: String); overload;
+ procedure LookupBasicData(const Name: String; var LData: TDateTime); overload;
+ procedure LookupBasicData(const Name: String; var LData: Integer); overload;
+ procedure LookupBasicData(const Name: String; var LData: Smallint); overload;
+ procedure LookupBasicData(const Name: String; var LData: Boolean); overload;
+ procedure LookupBasicData(const Name: String; var LData: Single); overload;
+ procedure LookupBasicData(const Name: String; LData: TStrings); overload;
+ procedure RemoveNode(Index: Integer); overload;
+ procedure RemoveNode(Node: TXMLNode); overload;
+
+ property AsDateTime: TDateTime read GetAsDateTime;
+ property AsInteger: Integer read GetAsInteger;
+ property AsSingle: Single read GetAsSingle;
+ property Data: String read FData write FData;
+ property Name: String read FName write FName;
+ property NodeCount: Integer read GetNodeCount;
+ property Nodes[Index: Integer]: TXMLNode read GetNodes;
+ property NodeType: TXMLNodeType read FNodeType write FNodeType;
+ property TotalNodeCount: Integer read GetTotalNodeCount;
+ end;
+
+const
+ TXMLNodeTypeStrings: array[TXMLNodeType] of String = ('Document', 'Element',
+ 'Attribute', 'ProcessingInstruction', 'XMLDeclaration');
+
+implementation
+
+uses
+ SysUtils, Strlib;
+
+const
+ LetterSet: CharSet = ['A'..'Z', 'a'..'z'];
+ WhitespaceSet: CharSet = [' ', #9, #10, #13];
+ CombiningCharSet: CharSet = [];
+ DigitSet: CharSet = ['0'..'9'];
+ ExtenderSet: CharSet = [#$b7];
+ FirstNameCharSet: CharSet = ['_', ':', 'A'..'Z', 'a'..'z'];
+var
+ NameCharSet: CharSet;
+
+type
+ TXMLStringReaderState = class
+ public
+ Position: Integer;
+ CurChar: Char;
+ end;
+
+{ TXMLNode }
+
+constructor TXMLNode.Create;
+begin
+ FNodes := TList.Create;
+end;
+
+destructor TXMLNode.Destroy;
+var
+ i: Integer;
+begin
+ inherited;
+ for i := 0 to Pred(NodeCount) do
+ Nodes[i].Free;
+ FNodes.Free;
+end;
+
+function TXMLNode.AddNode(Node: TXMLNode): Integer;
+begin
+ Result := FNodes.Add(Node)
+end;
+
+function TXMLNode.Description: String;
+begin
+ Result := Name + ': ' + TXMLNodeTypeStrings[NodeType];
+ if Data <> '' then
+ Result := Result + ' = ' + Data
+end;
+
+function TXMLNode.FindNode(const Name: String): TXMLNode;
+begin
+ Result := FindNode(Name, 0)
+end;
+
+function TXMLNode.FindNode(const Name: String;
+ const Index: Integer): TXMLNode;
+var
+ i, ThisIndex: Integer;
+begin
+ ThisIndex := 0;
+ for i := 0 to Pred(NodeCount) do
+ if Nodes[i].Name = Name then begin
+ if ThisIndex = Index then begin
+ Result := Nodes[i];
+ Exit;
+ end;
+ Inc(ThisIndex);
+ end;
+ Result := nil;
+end;
+
+function TXMLNode.FindNodeExc(const Name: String): TXMLNode;
+begin
+ Result := FindNode(Name, 0);
+ if Result = nil then
+ raise Exception.Create('Node "' + Name + '" not found');
+end;
+
+function TXMLNode.GetAsDateTime: TDateTime;
+begin
+ Result := StrToDateTime(Data)
+end;
+
+function TXMLNode.GetAsInteger: Integer;
+begin
+ try
+ Result := StrToInt(Data);
+ except
+ raise Exception.Create('Node "' + Name + '" does not contain a valid integer');
+ end;
+end;
+
+function TXMLNode.GetAsSingle: Single;
+begin
+ try
+ Result := StrToFloat(Data);
+ except
+ raise Exception.Create('Node "' + Name + '" does not contain a valid floating point value');
+ end;
+end;
+
+function TXMLNode.GetNodeCount: Integer;
+begin
+ Result := FNodes.Count
+end;
+
+function TXMLNode.GetNodes(Index: Integer): TXMLNode;
+begin
+ Result := TXMLNode(FNodes[Index])
+end;
+
+function TXMLNode.GetTotalNodeCount: Integer;
+var
+ i: Integer;
+begin
+ Result := 1;
+ for i := 0 to Pred(NodeCount) do
+ Result := Result + Nodes[i].TotalNodeCount;
+end;
+
+function TXMLNode.HasNode(const Name: String): Boolean;
+begin
+ Result := FindNode(Name, 0) <> nil
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: String);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.Data
+ else
+ LData := ''
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: TDateTime);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsDateTime
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String;
+ var LData: Smallint);
+var
+ L: Integer;
+begin
+ LookupBasicData(Name, L);
+ LData := L
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Integer);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsInteger
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Boolean);
+begin
+ LData := HasNode(Name)
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Single);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsSingle
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; LData: TStrings);
+var
+ i: Integer;
+ Node, SubNode: TXMLNode;
+begin
+ LData.Clear;
+ Node := FindNode(Name);
+ if Node = nil then Exit;
+ for i := 0 to Pred(Node.NodeCount) do begin
+ SubNode := Node.Nodes[i];
+ if (SubNode.Name = 'S') and (SubNode.NodeType = xntElement) then
+ LData.Add(SubNode.Data);
+ end;
+end;
+
+procedure TXMLNode.RemoveNode(Index: Integer);
+begin
+ RemoveNode(Nodes[Index])
+end;
+
+procedure TXMLNode.RemoveNode(Node: TXMLNode);
+begin
+ FNodes.Remove(Node);
+end;
+
+{ TXMLStringReader }
+
+constructor TXMLStringReader.Create(AData: String);
+begin
+ FPosition := 1;
+ FData := AData;
+end;
+
+function TXMLStringReader.EndOfData: Boolean;
+begin
+ Result := FPosition > Length(FData)
+end;
+
+procedure TXMLStringReader.FreeState(State: TObject);
+begin
+ State.Free;
+end;
+
+procedure TXMLStringReader.ReadChar;
+begin
+ if FPosition > Length(FData) then
+ CurChar := #0
+ else begin
+ CurChar := FData[FPosition];
+ Inc(FPosition)
+ end
+end;
+
+procedure TXMLStringReader.RestoreState(State: TObject);
+var
+ XSRState: TXMLStringReaderState;
+begin
+ XSRState := (State as TXMLStringReaderState);
+ FPosition := XSRState.Position;
+ CurChar := XSRState.CurChar;
+end;
+
+function TXMLStringReader.SaveState: TObject;
+var
+ XSRState: TXMLStringReaderState;
+begin
+ XSRState := TXMLStringReaderState.Create;
+ XSRState.Position := FPosition;
+ XSRState.CurChar := CurChar;
+ Result := XSRState;
+end;
+
+{ TXMLReader }
+
+function TXMLReader.DoesStreamMatchString(Str: String): Boolean;
+var
+ i: Integer;
+ State: TObject;
+begin
+ if Str = '' then begin Result := False; Exit end;
+ State := SaveState;
+ i := 1;
+ repeat
+ Result := Str[i] = CurChar;
+ Inc(i);
+ ReadChar;
+ until (not Result) or EndOfData or (i > Length(Str));
+
+ if not Result then
+ RestoreState(State);
+ FreeState(State);
+end;
+
+
+function TXMLReader.ParseAttribute(Node: TXMLNode): Boolean;
+var
+ Name, AttValue: String;
+ ThisNode: TXMLNode;
+begin
+ Result := False;
+ if not ParseName(Name) then Exit;
+ if not ParseEq then
+ ReportError('Equals sign missing in attribute');
+ if not ParseAttValue(AttValue) then
+ ReportError('Attribute "' + Name + '" missing value');
+ ThisNode := TXMLNode.Create;
+ ThisNode.NodeType := xntAttribute;
+ ThisNode.Name := Name;
+ ThisNode.Data := AttValue;
+ Node.AddNode(ThisNode);
+ Result := True;
+end;
+
+function TXMLReader.ParseAttValue(var AttValue: String): Boolean;
+var
+ QuoteChar: Char;
+begin
+ QuoteChar := CurChar;
+ Result := False;
+ if not (CurChar in ['"', '''']) then Exit;
+ ReadCharAndCheckForEnd;
+
+ while CurChar <> QuoteChar do begin
+ if CurChar = '<' then
+ ReportError('Invalid character "' + CurChar + '" in attribute value')
+ else if CurChar = '&' then
+ CurChar := ParseReference;
+ AttValue := AttValue + CurChar;
+ ReadCharAndCheckForEnd;
+ end;
+ ReadCharAndCheckForEnd;
+ Result := True;
+end;
+
+function TXMLReader.ParseCDSect(Node: TXMLNode): Boolean;
+var
+ CData: String;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<![CDATA[') then Exit;
+ repeat
+ CData := CData + CurChar;
+ ReadCharAndCheckForEnd;
+ until Right(CData, 3) = ']]>';
+ Node.Data := Node.Data + Left(CData, Length(CData) - 3);
+ Result := True;
+end;
+
+function TXMLReader.ParseCharData(Node: TXMLNode): Boolean;
+var
+ CharData: String;
+begin
+ while not (CurChar in ['<', '&', #0]) do begin
+ CharData := CharData + CurChar;
+ ReadChar;
+ end;
+ if Pos(']]>', CharData) <> 0 then
+ ReportError('Character data cannot contain "]]>"');
+ Node.Data := Node.Data + CharData;
+ Result := CharData <> '';
+end;
+
+function TXMLReader.ParseComment: Boolean;
+var
+ Comment: String;
+ Terminated: Boolean;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<!--') then Exit;
+ repeat
+ Comment := Comment + CurChar;
+ Terminated := Right(Comment, 3) = '-->';
+ if EndOfData then Break;
+ ReadChar;
+ until Terminated;
+ if Right(Comment, 4) = '--->' then
+ ReportError('Comments cannot end in "--->"');
+ Result := True;
+end;
+
+procedure TXMLReader.ParseContent(Node: TXMLNode);
+var
+ FoundContent: Boolean;
+begin
+ repeat
+ FoundContent := True;
+ if ParseCDSect(Node) then
+ else if ParseProcessingInstruction(Node) then
+ else if ParseComment then
+ else if ParseElement(Node) then
+ else if ParseCharData(Node) then
+ else if CurChar = '&' then
+ Node.Data := Node.Data + ParseReference
+ else
+ FoundContent := False;
+ until not FoundContent;
+end;
+
+procedure TXMLReader.ParseDocTypeDecl(Node: TXMLNode);
+begin
+ if not DoesStreamMatchString('<!DOCTYPE') then Exit;
+// ReportError('DocTypeDecl parsing not yet implemented');
+end;
+
+function TXMLReader.ParseDocument: TXMLNode;
+begin
+ ReadCharAndCheckForEnd;
+ Result := TXMLNode.Create;
+ Result.Name := '';
+ Result.NodeType := xntDocument;
+ if not ParseProlog(Result) then
+ ReportError('Missing prolog');
+ if not ParseElement(Result) then
+ ReportError('Missing element');
+ while ParseMisc(Result) do
+ ;
+end;
+
+function TXMLReader.ParseElement(Node: TXMLNode): Boolean;
+var
+ Name: String;
+ ThisNode: TXMLNode;
+ State: TObject;
+begin
+ Result := False;
+ if CurChar <> '<' then Exit;
+ State := SaveState;
+ ReadCharAndCheckForEnd;
+ if not ParseName(Name) then begin
+ RestoreState(State);
+ FreeState(State);
+ Exit;
+ end;
+
+ FreeState(State);
+
+ ThisNode := TXMLNode.Create;
+ Node.AddNode(ThisNode);
+ try
+ ThisNode.Name := Name;
+ ThisNode.NodeType := xntElement;
+ repeat
+ ParseWhitespace;
+ until not ParseAttribute(ThisNode);
+
+ if CurChar = '/' then begin
+ // EmptyElemTag
+ ReadCharAndCheckForEnd;
+ if CurChar <> '>' then
+ ReportError('Tag not terminated properly');
+ ReadCharAndCheckForEnd;
+ end else if CurChar = '>' then begin
+ // STag
+ ReadCharAndCheckForEnd;
+ ParseContent(ThisNode);
+ ThisNode.Data := TrimChars(ThisNode.Data, [' ', #9, #13, #10]);
+ if not ParseETag(ThisNode) then
+ ReportError('No ending tag for ' + Name);
+ end else
+ ReportError('Tag not terminated properly');
+ except
+ Node.RemoveNode(ThisNode);
+ ThisNode.Free;
+ raise;
+ end;
+ Result := True;
+end;
+
+function TXMLReader.ParseEq: Boolean;
+begin
+ ParseWhitespace;
+ Result := CurChar = '=';
+ ReadCharAndCheckForEnd;
+ ParseWhitespace;
+end;
+
+function TXMLReader.ParseETag(Node: TXMLNode): Boolean;
+var
+ Name: String;
+begin
+ Result := False;
+ if not DoesStreamMatchString('</') then Exit;
+ if not ParseName(Name) then Exit;
+ if Name <> Node.Name then
+ ReportError('End tag name "' + Name + '" does not match start tag name "' + Node.Name + '"');
+ ParseWhitespace;
+ if CurChar <> '>' then
+ ReportError('End tag missing ">"');
+ ReadChar;
+ Result := True;
+end;
+
+function TXMLReader.ParseMisc(Node: TXMLNode): Boolean;
+begin
+ Result := ParseWhitespace;
+ if Result then Exit;
+ Result := ParseComment;
+ if Result then Exit;
+ Result := ParseProcessingInstruction(Node);
+end;
+
+function TXMLReader.ParseName(var Name: String): Boolean;
+begin
+ Result := False;
+ if not (CurChar in FirstNameCharSet) then Exit;
+ Result := True;
+ Name := '';
+ repeat
+ Name := Name + CurChar;
+ ReadCharAndCheckForEnd;
+ until not (CurChar in NameCharSet);
+end;
+
+function TXMLReader.ParseProcessingInstruction(Node: TXMLNode): Boolean;
+var
+ Name, Chars: String;
+ ThisNode: TXMLNode;
+ Terminated: Boolean;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<?') then Exit;
+ if not ParseName(Name) then
+ ReportError('Processing instruction does not contain valid name');
+ if Name = 'xml' then
+ ReportError('Processing instruction cannot have the reserved name "xml"');
+ ThisNode := TXMLNode.Create;
+ try
+ ThisNode.Name := Name;
+ ThisNode.NodeType := xntProcessingInstruction;
+ ParseWhitespace;
+ repeat
+ Chars := Chars + CurChar;
+ Terminated := Right(Chars, 2) = '?>';
+ if EndOfData then break;
+ ReadChar;
+ until Terminated;
+ if not Terminated then
+ ReportError('Unterminated processing instruction');
+ ThisNode.Data := Left(Chars, Length(Chars) - 2);
+ except
+ ThisNode.Free;
+ raise;
+ end;
+ Node.AddNode(ThisNode);
+ Result := True;
+end;
+
+function TXMLReader.ParseProlog(Node: TXMLNode): Boolean;
+begin
+ ParseXMLDecl(Node);
+ while ParseMisc(Node) do
+ ;
+ ParseDocTypeDecl(Node);
+ while ParseMisc(Node) do
+ ;
+ Result := True;
+end;
+
+function TXMLReader.ParseReference: Char;
+var
+ RefStr: String;
+begin
+ Result := #0; // silence compiler warning
+ if CurChar <> '&' then
+ ReportError('All references must begin with "&"');
+ ReadCharAndCheckForEnd;
+ while CurChar <> ';' do begin
+ RefStr := RefStr + CurChar;
+ ReadCharAndCheckForEnd;
+ end;
+ if Left(RefStr, 2) = '#x' then
+ try
+ Result := Chr(StrToInt('$' + Right(RefStr, Length(RefStr) - 2)));
+ except
+ ReportError('Invalid integer in reference &' + RefStr + ';');
+ end
+ else if Left(RefStr, 1) = '#' then
+ try
+ Result := Chr(StrToInt(Right(RefStr, Length(RefStr) - 1)));
+ except
+ ReportError('Invalid integer in reference &' + RefStr + ';');
+ end
+ else if RefStr = 'amp' then
+ Result := '&'
+ else if RefStr = 'lt' then
+ Result := '<'
+ else if RefStr = 'gt' then
+ Result := '>'
+ else if RefStr = 'quot' then
+ Result := '"'
+ else if RefStr = 'apos' then
+ Result := ''''
+ else
+ ReportError('Unrecognized reference');
+
+ ReadCharAndCheckForEnd;
+end;
+
+function TXMLReader.ParseWhitespace: Boolean;
+begin
+ Result := False;
+ while (CurChar in [' ', #13, #10, #9]) do begin
+ Result := True;
+ ReadChar;
+ if EndOfData then Exit;
+ end;
+end;
+
+procedure TXMLReader.ParseXMLDecl(Node: TXMLNode);
+var
+ ThisNode: TXMLNode;
+begin
+ if not DoesStreamMatchString('<?xml') then Exit;
+ ThisNode := TXMLNode.Create;
+ ThisNode.NodeType := xntXMLDeclaration;
+ try
+ repeat
+ ParseWhitespace;
+ until not ParseAttribute(ThisNode);
+ ParseWhitespace;
+ if not DoesStreamMatchString('?>') then
+ ReportError('XML declaration not terminated with "?>"');
+ except
+ ThisNode.Free;
+ raise;
+ end;
+ Node.AddNode(ThisNode);
+end;
+
+procedure TXMLReader.ReadCharAndCheckForEnd;
+begin
+ if EndOfData then
+ ReportError('Unexpected end of data');
+ ReadChar;
+end;
+
+procedure TXMLReader.ReportError(Err: String);
+begin
+ raise Exception.Create(Err);
+end;
+
+initialization
+ NameCharSet := LetterSet + CombiningCharSet + DigitSet + ExtenderSet
+ + ['.', '-', '_', ':'];
+end.
Added: trunk/WPGM/ImportDefinitions/XmlReader.~pas
===================================================================
--- trunk/WPGM/ImportDefinitions/XmlReader.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/ImportDefinitions/XmlReader.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,772 @@
+{:
+PURPOSE AND IMPLEMENTATION:
+ This unit defines classes for parsing a well-formed standalone XML document in
+ to a tree of nodes describing the data therein. These classes only support a
+ subset of the XML 1.0 recommendation and have not been analyzed for
+ conformance with the recommendation. This module also only supports 8-bit
+ character sets and makes no special allowances for UTF-8. Nor has any support
+ for the "<!DOCTYPE" node been implemented. Parsing of the XML declaration
+ lazily uses the attribute parsing code which is not correct (but works). This
+ module also freely trims element whitespace which is not always correct.
+
+ Q: Why use this module instead of Microsoft's XML parser or the OpenXML
+ project?
+
+ A: I wrote this module to be free of dependencies on outside libraries and to
+ be small and fast. Neither of the above libraries met that criteria. I
+ didn't like the idea of requiring my users to install Microsoft's XML
+ library (and the potential compatibility problems that arise). Nor did I
+ like the idea of adding 135 kb (OpenXML) to my executable just to load files
+ in XML format. Instead this unit only uses about 7 kb.
+
+ This was written for Delphi 5. It may work for other versions, but does
+ require method overloading which was introduced in Delphi 4.
+
+HISTORY:
+ 09/12/00 - Created by Colin Patrick Sarsfield
+
+DISCLAIMER:
+ Use at your own risk.
+
+COPYRIGHT:
+ Released into the public domain by Colin Sarsfield 9/13/00
+}
+unit XMLReader;
+
+interface
+
+uses
+ Classes;
+
+type
+ CharSet = set of Char;
+
+ TXMLNode = class;
+
+ TXMLNodeType = (xntDocument, xntElement, xntAttribute, xntProcessingInstruction,
+ xntXMLDeclaration);
+
+ TXMLReader = class
+ private
+ CurChar: Char;
+ function ParseAttribute(Node: TXMLNode): Boolean;
+ function ParseAttValue(var AttValue: String): Boolean;
+ function ParseCDSect(Node: TXMLNode): Boolean;
+ function ParseCharData(Node: TXMLNode): Boolean;
+ function ParseComment: Boolean;
+ procedure ParseContent(Node: TXMLNode);
+ procedure ParseDocTypeDecl(Node: TXMLNode);
+ function ParseElement(Node: TXMLNode): Boolean;
+ function ParseEq: Boolean;
+ function ParseETag(Node: TXMLNode): Boolean;
+ function ParseMisc(Node: TXMLNode): Boolean;
+ function ParseName(var Name: String): Boolean;
+ function ParseProcessingInstruction(Node: TXMLNode): Boolean;
+ function ParseProlog(Node: TXMLNode): Boolean;
+ function ParseReference: Char;
+ function ParseWhitespace: Boolean;
+ procedure ParseXMLDecl(Node: TXMLNode);
+ procedure ReportError(Err: String);
+ protected
+ function DoesStreamMatchString(Str: String): Boolean;
+ function EndOfData: Boolean; virtual; abstract;
+ procedure FreeState(State: TObject); virtual; abstract;
+ procedure ReadChar; virtual; abstract;
+ procedure ReadCharAndCheckForEnd;
+ procedure RestoreState(State: TObject); virtual; abstract;
+ function SaveState: TObject; virtual; abstract;
+ public
+ function ParseDocument: TXMLNode;
+ end;
+
+ TXMLStringReader = class(TXMLReader)
+ private
+ FData: String;
+ FPosition: Integer;
+ protected
+ function EndOfData: Boolean; override;
+ procedure FreeState(State: TObject); override;
+ procedure ReadChar; override;
+ procedure RestoreState(State: TObject); override;
+ function SaveState: TObject; override;
+ public
+ constructor Create(AData: String);
+ end;
+
+ TXMLNode = class
+ private
+ FData: String;
+ FName: String;
+ FNodes: TList;
+ FNodeType: TXMLNodeType;
+ function GetNodeCount: Integer;
+ function GetNodes(Index: Integer): TXMLNode;
+ function GetTotalNodeCount: Integer;
+ function GetAsInteger: Integer;
+ function GetAsSingle: Single;
+ function GetAsDateTime: TDateTime;
+ public
+ constructor Create; virtual;
+ destructor Destroy; override;
+
+ function AddNode(Node: TXMLNode): Integer;
+ function Description: String;
+ function FindNode(const Name: String; const Index: Integer): TXMLNode; overload;
+ function FindNode(const Name: String): TXMLNode; overload;
+ function FindNodeExc(const Name: String): TXMLNode;
+ function HasNode(const Name: String): Boolean;
+ procedure LookupBasicData(const Name: String; var LData: String); overload;
+ procedure LookupBasicData(const Name: String; var LData: TDateTime); overload;
+ procedure LookupBasicData(const Name: String; var LData: Integer); overload;
+ procedure LookupBasicData(const Name: String; var LData: Smallint); overload;
+ procedure LookupBasicData(const Name: String; var LData: Boolean); overload;
+ procedure LookupBasicData(const Name: String; var LData: Single); overload;
+ procedure LookupBasicData(const Name: String; LData: TStrings); overload;
+ procedure RemoveNode(Index: Integer); overload;
+ procedure RemoveNode(Node: TXMLNode); overload;
+
+ property AsDateTime: TDateTime read GetAsDateTime;
+ property AsInteger: Integer read GetAsInteger;
+ property AsSingle: Single read GetAsSingle;
+ property Data: String read FData write FData;
+ property Name: String read FName write FName;
+ property NodeCount: Integer read GetNodeCount;
+ property Nodes[Index: Integer]: TXMLNode read GetNodes;
+ property NodeType: TXMLNodeType read FNodeType write FNodeType;
+ property TotalNodeCount: Integer read GetTotalNodeCount;
+ end;
+
+const
+ TXMLNodeTypeStrings: array[TXMLNodeType] of String = ('Document', 'Element',
+ 'Attribute', 'ProcessingInstruction', 'XMLDeclaration');
+
+implementation
+
+uses
+ SysUtils, Strlib;
+
+const
+ LetterSet: CharSet = ['A'..'Z', 'a'..'z'];
+ WhitespaceSet: CharSet = [' ', #9, #10, #13];
+ CombiningCharSet: CharSet = [];
+ DigitSet: CharSet = ['0'..'9'];
+ ExtenderSet: CharSet = [#$b7];
+ FirstNameCharSet: CharSet = ['_', ':', 'A'..'Z', 'a'..'z'];
+var
+ NameCharSet: CharSet;
+
+type
+ TXMLStringReaderState = class
+ public
+ Position: Integer;
+ CurChar: Char;
+ end;
+
+{ TXMLNode }
+
+constructor TXMLNode.Create;
+begin
+ FNodes := TList.Create;
+end;
+
+destructor TXMLNode.Destroy;
+var
+ i: Integer;
+begin
+ inherited;
+ for i := 0 to Pred(NodeCount) do
+ Nodes[i].Free;
+ FNodes.Free;
+end;
+
+function TXMLNode.AddNode(Node: TXMLNode): Integer;
+begin
+ Result := FNodes.Add(Node)
+end;
+
+function TXMLNode.Description: String;
+begin
+ Result := Name + ': ' + TXMLNodeTypeStrings[NodeType];
+ if Data <> '' then
+ Result := Result + ' = ' + Data
+end;
+
+function TXMLNode.FindNode(const Name: String): TXMLNode;
+begin
+ Result := FindNode(Name, 0)
+end;
+
+function TXMLNode.FindNode(const Name: String;
+ const Index: Integer): TXMLNode;
+var
+ i, ThisIndex: Integer;
+begin
+ ThisIndex := 0;
+ for i := 0 to Pred(NodeCount) do
+ if Nodes[i].Name = Name then begin
+ if ThisIndex = Index then begin
+ Result := Nodes[i];
+ Exit;
+ end;
+ Inc(ThisIndex);
+ end;
+ Result := nil;
+end;
+
+function TXMLNode.FindNodeExc(const Name: String): TXMLNode;
+begin
+ Result := FindNode(Name, 0);
+ if Result = nil then
+ raise Exception.Create('Node "' + Name + '" not found');
+end;
+
+function TXMLNode.GetAsDateTime: TDateTime;
+begin
+ Result := StrToDateTime(Data)
+end;
+
+function TXMLNode.GetAsInteger: Integer;
+begin
+ try
+ Result := StrToInt(Data);
+ except
+ raise Exception.Create('Node "' + Name + '" does not contain a valid integer');
+ end;
+end;
+
+function TXMLNode.GetAsSingle: Single;
+begin
+ try
+ Result := StrToFloat(Data);
+ except
+ raise Exception.Create('Node "' + Name + '" does not contain a valid floating point value');
+ end;
+end;
+
+function TXMLNode.GetNodeCount: Integer;
+begin
+ Result := FNodes.Count
+end;
+
+function TXMLNode.GetNodes(Index: Integer): TXMLNode;
+begin
+ Result := TXMLNode(FNodes[Index])
+end;
+
+function TXMLNode.GetTotalNodeCount: Integer;
+var
+ i: Integer;
+begin
+ Result := 1;
+ for i := 0 to Pred(NodeCount) do
+ Result := Result + Nodes[i].TotalNodeCount;
+end;
+
+function TXMLNode.HasNode(const Name: String): Boolean;
+begin
+ Result := FindNode(Name, 0) <> nil
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: String);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.Data
+ else
+ LData := ''
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: TDateTime);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsDateTime
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String;
+ var LData: Smallint);
+var
+ L: Integer;
+begin
+ LookupBasicData(Name, L);
+ LData := L
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Integer);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsInteger
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Boolean);
+begin
+ LData := HasNode(Name)
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Single);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsSingle
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; LData: TStrings);
+var
+ i: Integer;
+ Node, SubNode: TXMLNode;
+begin
+ LData.Clear;
+ Node := FindNode(Name);
+ if Node = nil then Exit;
+ for i := 0 to Pred(Node.NodeCount) do begin
+ SubNode := Node.Nodes[i];
+ if (SubNode.Name = 'S') and (SubNode.NodeType = xntElement) then
+ LData.Add(SubNode.Data);
+ end;
+end;
+
+procedure TXMLNode.RemoveNode(Index: Integer);
+begin
+ RemoveNode(Nodes[Index])
+end;
+
+procedure TXMLNode.RemoveNode(Node: TXMLNode);
+begin
+ FNodes.Remove(Node);
+end;
+
+{ TXMLStringReader }
+
+constructor TXMLStringReader.Create(AData: String);
+begin
+ FPosition := 1;
+ FData := AData;
+end;
+
+function TXMLStringReader.EndOfData: Boolean;
+begin
+ Result := FPosition > Length(FData)
+end;
+
+procedure TXMLStringReader.FreeState(State: TObject);
+begin
+ State.Free;
+end;
+
+procedure TXMLStringReader.ReadChar;
+begin
+ if FPosition > Length(FData) then
+ CurChar := #0
+ else begin
+ CurChar := FData[FPosition];
+ Inc(FPosition)
+ end
+end;
+
+procedure TXMLStringReader.RestoreState(State: TObject);
+var
+ XSRState: TXMLStringReaderState;
+begin
+ XSRState := (State as TXMLStringReaderState);
+ FPosition := XSRState.Position;
+ CurChar := XSRState.CurChar;
+end;
+
+function TXMLStringReader.SaveState: TObject;
+var
+ XSRState: TXMLStringReaderState;
+begin
+ XSRState := TXMLStringReaderState.Create;
+ XSRState.Position := FPosition;
+ XSRState.CurChar := CurChar;
+ Result := XSRState;
+end;
+
+{ TXMLReader }
+
+function TXMLReader.DoesStreamMatchString(Str: String): Boolean;
+var
+ i: Integer;
+ State: TObject;
+begin
+ if Str = '' then begin Result := False; Exit end;
+ State := SaveState;
+ i := 1;
+ repeat
+ Result := Str[i] = CurChar;
+ Inc(i);
+ ReadChar;
+ until (not Result) or EndOfData or (i > Length(Str));
+
+ if not Result then
+ RestoreState(State);
+ FreeState(State);
+end;
+
+
+function TXMLReader.ParseAttribute(Node: TXMLNode): Boolean;
+var
+ Name, AttValue: String;
+ ThisNode: TXMLNode;
+begin
+ Result := False;
+ if not ParseName(Name) then Exit;
+ if not ParseEq then
+ ReportError('Equals sign missing in attribute');
+ if not ParseAttValue(AttValue) then
+ ReportError('Attribute "' + Name + '" missing value');
+ ThisNode := TXMLNode.Create;
+ ThisNode.NodeType := xntAttribute;
+ ThisNode.Name := Name;
+ ThisNode.Data := AttValue;
+ Node.AddNode(ThisNode);
+ Result := True;
+end;
+
+function TXMLReader.ParseAttValue(var AttValue: String): Boolean;
+var
+ QuoteChar: Char;
+begin
+ QuoteChar := CurChar;
+ Result := False;
+ if not (CurChar in ['"', '''']) then Exit;
+ ReadCharAndCheckForEnd;
+
+ while CurChar <> QuoteChar do begin
+ if CurChar = '<' then
+ ReportError('Invalid character "' + CurChar + '" in attribute value')
+ else if CurChar = '&' then
+ CurChar := ParseReference;
+ AttValue := AttValue + CurChar;
+ ReadCharAndCheckForEnd;
+ end;
+ ReadCharAndCheckForEnd;
+ Result := True;
+end;
+
+function TXMLReader.ParseCDSect(Node: TXMLNode): Boolean;
+var
+ CData: String;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<![CDATA[') then Exit;
+ repeat
+ CData := CData + CurChar;
+ ReadCharAndCheckForEnd;
+ until Right(CData, 3) = ']]>';
+ Node.Data := Node.Data + Left(CData, Length(CData) - 3);
+ Result := True;
+end;
+
+function TXMLReader.ParseCharData(Node: TXMLNode): Boolean;
+var
+ CharData: String;
+begin
+ while not (CurChar in ['<', '&', #0]) do begin
+ CharData := CharData + CurChar;
+ ReadChar;
+ end;
+ if Pos(']]>', CharData) <> 0 then
+ ReportError('Character data cannot contain "]]>"');
+ Node.Data := Node.Data + CharData;
+ Result := CharData <> '';
+end;
+
+function TXMLReader.ParseComment: Boolean;
+var
+ Comment: String;
+ Terminated: Boolean;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<!--') then Exit;
+ repeat
+ Comment := Comment + CurChar;
+ Terminated := Right(Comment, 3) = '-->';
+ if EndOfData then Break;
+ ReadChar;
+ until Terminated;
+ if Right(Comment, 4) = '--->' then
+ ReportError('Comments cannot end in "--->"');
+ Result := True;
+end;
+
+procedure TXMLReader.ParseContent(Node: TXMLNode);
+var
+ FoundContent: Boolean;
+begin
+ repeat
+ FoundContent := True;
+ if ParseCDSect(Node) then
+ else if ParseProcessingInstruction(Node) then
+ else if ParseComment then
+ else if ParseElement(Node) then
+ else if ParseCharData(Node) then
+ else if CurChar = '&' then
+ Node.Data := Node.Data + ParseReference
+ else
+ FoundContent := False;
+ until not FoundContent;
+end;
+
+procedure TXMLReader.ParseDocTypeDecl(Node: TXMLNode);
+begin
+ if not DoesStreamMatchString('<!DOCTYPE') then Exit;
+ ReportError('DocTypeDecl parsing not yet implemented');
+end;
+
+function TXMLReader.ParseDocument: TXMLNode;
+begin
+ ReadCharAndCheckForEnd;
+ Result := TXMLNode.Create;
+ Result.Name := '';
+ Result.NodeType := xntDocument;
+ if not ParseProlog(Result) then
+ ReportError('Missing prolog');
+ if not ParseElement(Result) then
+ ReportError('Missing element');
+ while ParseMisc(Result) do
+ ;
+end;
+
+function TXMLReader.ParseElement(Node: TXMLNode): Boolean;
+var
+ Name: String;
+ ThisNode: TXMLNode;
+ State: TObject;
+begin
+ Result := False;
+ if CurChar <> '<' then Exit;
+ State := SaveState;
+ ReadCharAndCheckForEnd;
+ if not ParseName(Name) then begin
+ RestoreState(State);
+ FreeState(State);
+ Exit;
+ end;
+
+ FreeState(State);
+
+ ThisNode := TXMLNode.Create;
+ Node.AddNode(ThisNode);
+ try
+ ThisNode.Name := Name;
+ ThisNode.NodeType := xntElement;
+ repeat
+ ParseWhitespace;
+ until not ParseAttribute(ThisNode);
+
+ if CurChar = '/' then begin
+ // EmptyElemTag
+ ReadCharAndCheckForEnd;
+ if CurChar <> '>' then
+ ReportError('Tag not terminated properly');
+ ReadCharAndCheckForEnd;
+ end else if CurChar = '>' then begin
+ // STag
+ ReadCharAndCheckForEnd;
+ ParseContent(ThisNode);
+ ThisNode.Data := TrimChars(ThisNode.Data, [' ', #9, #13, #10]);
+ if not ParseETag(ThisNode) then
+ ReportError('No ending tag for ' + Name);
+ end else
+ ReportError('Tag not terminated properly');
+ except
+ Node.RemoveNode(ThisNode);
+ ThisNode.Free;
+ raise;
+ end;
+ Result := True;
+end;
+
+function TXMLReader.ParseEq: Boolean;
+begin
+ ParseWhitespace;
+ Result := CurChar = '=';
+ ReadCharAndCheckForEnd;
+ ParseWhitespace;
+end;
+
+function TXMLReader.ParseETag(Node: TXMLNode): Boolean;
+var
+ Name: String;
+begin
+ Result := False;
+ if not DoesStreamMatchString('</') then Exit;
+ if not ParseName(Name) then Exit;
+ if Name <> Node.Name then
+ ReportError('End tag name "' + Name + '" does not match start tag name "' + Node.Name + '"');
+ ParseWhitespace;
+ if CurChar <> '>' then
+ ReportError('End tag missing ">"');
+ ReadChar;
+ Result := True;
+end;
+
+function TXMLReader.ParseMisc(Node: TXMLNode): Boolean;
+begin
+ Result := ParseWhitespace;
+ if Result then Exit;
+ Result := ParseComment;
+ if Result then Exit;
+ Result := ParseProcessingInstruction(Node);
+end;
+
+function TXMLReader.ParseName(var Name: String): Boolean;
+begin
+ Result := False;
+ if not (CurChar in FirstNameCharSet) then Exit;
+ Result := True;
+ Name := '';
+ repeat
+ Name := Name + CurChar;
+ ReadCharAndCheckForEnd;
+ until not (CurChar in NameCharSet);
+end;
+
+function TXMLReader.ParseProcessingInstruction(Node: TXMLNode): Boolean;
+var
+ Name, Chars: String;
+ ThisNode: TXMLNode;
+ Terminated: Boolean;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<?') then Exit;
+ if not ParseName(Name) then
+ ReportError('Processing instruction does not contain valid name');
+ if Name = 'xml' then
+ ReportError('Processing instruction cannot have the reserved name "xml"');
+ ThisNode := TXMLNode.Create;
+ try
+ ThisNode.Name := Name;
+ ThisNode.NodeType := xntProcessingInstruction;
+ ParseWhitespace;
+ repeat
+ Chars := Chars + CurChar;
+ Terminated := Right(Chars, 2) = '?>';
+ if EndOfData then break;
+ ReadChar;
+ until Terminated;
+ if not Terminated then
+ ReportError('Unterminated processing instruction');
+ ThisNode.Data := Left(Chars, Length(Chars) - 2);
+ except
+ ThisNode.Free;
+ raise;
+ end;
+ Node.AddNode(ThisNode);
+ Result := True;
+end;
+
+function TXMLReader.ParseProlog(Node: TXMLNode): Boolean;
+begin
+ ParseXMLDecl(Node);
+ while ParseMisc(Node) do
+ ;
+ ParseDocTypeDecl(Node);
+ while ParseMisc(Node) do
+ ;
+ Result := True;
+end;
+
+function TXMLReader.ParseReference: Char;
+var
+ RefStr: String;
+begin
+ Result := #0; // silence compiler warning
+ if CurChar <> '&' then
+ ReportError('All references must begin with "&"');
+ ReadCharAndCheckForEnd;
+ while CurChar <> ';' do begin
+ RefStr := RefStr + CurChar;
+ ReadCharAndCheckForEnd;
+ end;
+ if Left(RefStr, 2) = '#x' then
+ try
+ Result := Chr(StrToInt('$' + Right(RefStr, Length(RefStr) - 2)));
+ except
+ ReportError('Invalid integer in reference &' + RefStr + ';');
+ end
+ else if Left(RefStr, 1) = '#' then
+ try
+ Result := Chr(StrToInt(Right(RefStr, Length(RefStr) - 1)));
+ except
+ ReportError('Invalid integer in reference &' + RefStr + ';');
+ end
+ else if RefStr = 'amp' then
+ Result := '&'
+ else if RefStr = 'lt' then
+ Result := '<'
+ else if RefStr = 'gt' then
+ Result := '>'
+ else if RefStr = 'quot' then
+ Result := '"'
+ else if RefStr = 'apos' then
+ Result := ''''
+ else
+ ReportError('Unrecognized reference');
+
+ ReadCharAndCheckForEnd;
+end;
+
+function TXMLReader.ParseWhitespace: Boolean;
+begin
+ Result := False;
+ while (CurChar in [' ', #13, #10, #9]) do begin
+ Result := True;
+ ReadChar;
+ if EndOfData then Exit;
+ end;
+end;
+
+procedure TXMLReader.ParseXMLDecl(Node: TXMLNode);
+var
+ ThisNode: TXMLNode;
+begin
+ if not DoesStreamMatchString('<?xml') then Exit;
+ ThisNode := TXMLNode.Create;
+ ThisNode.NodeType := xntXMLDeclaration;
+ try
+ repeat
+ ParseWhitespace;
+ until not ParseAttribute(ThisNode);
+ ParseWhitespace;
+ if not DoesStreamMatchString('?>') then
+ ReportError('XML declaration not terminated with "?>"');
+ except
+ ThisNode.Free;
+ raise;
+ end;
+ Node.AddNode(ThisNode);
+end;
+
+procedure TXMLReader.ReadCharAndCheckForEnd;
+begin
+ if EndOfData then
+ ReportError('Unexpected end of data');
+ ReadChar;
+end;
+
+procedure TXMLReader.ReportError(Err: String);
+begin
+ raise Exception.Create(Err);
+end;
+
+initialization
+ NameCharSet := LetterSet + CombiningCharSet + DigitSet + ExtenderSet
+ + ['.', '-', '_', ':'];
+end.
Added: trunk/WPGM/Main.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Main.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Main.ddp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Main.ddp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Main.dfm
===================================================================
--- trunk/WPGM/Main.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Main.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1417 @@
+object frmMain: TfrmMain
+ Left = 365
+ Top = 496
+ Width = 612
+ Height = 199
+ Caption = 'Wolfpack - GM Tool'
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poDesktopCenter
+ ShowHint = True
+ OnClose = FormClose
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Pages: TPageControl
+ Left = 0
+ Top = 0
+ Width = 604
+ Height = 165
+ ActivePage = tsTags
+ Align = alClient
+ RaggedRight = True
+ TabOrder = 0
+ object tsCommands: TTabSheet
+ Caption = 'Commands'
+ ImageIndex = 3
+ object GroupBox1: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 185
+ Height = 121
+ Caption = 'Toggle Flags'
+ TabOrder = 0
+ object btnCmdAllmove: TButton
+ Left = 8
+ Top = 24
+ Width = 75
+ Height = 25
+ Hint = 'Toggle moving immovable objects.'
+ Caption = 'Allmove'
+ TabOrder = 0
+ OnClick = btnCmdAllmoveClick
+ end
+ object btnCmdAllshow: TButton
+ Left = 8
+ Top = 56
+ Width = 75
+ Height = 25
+ Hint = 'Toggle showing logged out characters.'
+ Caption = 'Allshow'
+ TabOrder = 1
+ OnClick = btnCmdAllshowClick
+ end
+ object btnCmdInvisible: TButton
+ Left = 8
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Toggle the invisible status.'
+ Caption = 'Invisible'
+ TabOrder = 2
+ OnClick = btnCmdInvisibleClick
+ end
+ object btnCmdStaff: TButton
+ Left = 96
+ Top = 56
+ Width = 75
+ Height = 25
+ Hint = 'Toggle the GM mode flag.'
+ Caption = 'Staff Flag'
+ TabOrder = 3
+ OnClick = btnCmdStaffClick
+ end
+ object btnCmdInvul: TButton
+ Left = 96
+ Top = 24
+ Width = 75
+ Height = 25
+ Hint = 'Toggle invulnerability.'
+ Caption = 'Invulnerable'
+ TabOrder = 4
+ OnClick = btnCmdInvulClick
+ end
+ object btnCmdPageNotify: TButton
+ Left = 96
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Be notified about incoming pages.'
+ Caption = 'Page Notify'
+ Enabled = False
+ TabOrder = 5
+ OnClick = btnCmdStaffClick
+ end
+ end
+ object GroupBox2: TGroupBox
+ Left = 200
+ Top = 8
+ Width = 233
+ Height = 121
+ Caption = 'System Commands'
+ TabOrder = 1
+ object btnCmdShutdown: TButton
+ Left = 8
+ Top = 24
+ Width = 105
+ Height = 25
+ Hint = 'Close the server.'
+ Caption = 'Shutdown'
+ TabOrder = 0
+ OnClick = btnCmdShutdownClick
+ end
+ object btnCmdReloadPython: TButton
+ Left = 8
+ Top = 56
+ Width = 105
+ Height = 25
+ Hint = 'Reload the python scripts.'
+ Caption = 'Reload Python'
+ TabOrder = 1
+ OnClick = btnCmdReloadPythonClick
+ end
+ object btnCmdReloadScripts: TButton
+ Left = 8
+ Top = 88
+ Width = 105
+ Height = 25
+ Hint = 'Reload the definitions and python scripts.'
+ Caption = 'Reload Definitions'
+ TabOrder = 2
+ OnClick = btnCmdReloadScriptsClick
+ end
+ object btnCmdReloadAccounts: TButton
+ Left = 120
+ Top = 56
+ Width = 105
+ Height = 25
+ Hint = 'Reload the accounts.'
+ Caption = 'Reload Accounts'
+ TabOrder = 3
+ OnClick = btnCmdReloadAccountsClick
+ end
+ object btnCmdReloadAll: TButton
+ Left = 120
+ Top = 88
+ Width = 105
+ Height = 25
+ Hint = 'Reload everything.'
+ Caption = 'Reload All'
+ TabOrder = 4
+ OnClick = btnCmdReloadAllClick
+ end
+ object btnCmdServertime: TButton
+ Left = 120
+ Top = 24
+ Width = 105
+ Height = 25
+ Hint = 'Show the current servertime.'
+ Caption = 'Show Servertime'
+ TabOrder = 5
+ OnClick = btnCmdServertimeClick
+ end
+ end
+ object Button1: TButton
+ Left = 440
+ Top = 16
+ Width = 97
+ Height = 25
+ Caption = 'Pattern Tilecolor'
+ TabOrder = 2
+ OnClick = Button1Click
+ end
+ end
+ object tsItems: TTabSheet
+ Caption = 'Items'
+ ImageIndex = -1
+ DesignSize = (
+ 596
+ 137)
+ object Label7: TLabel
+ Left = 162
+ Top = 118
+ Width = 39
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Z Level:'
+ end
+ object pnlItems: TPanel
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object spItems: TSplitter
+ Left = 201
+ Top = 0
+ Height = 112
+ end
+ object vtCategories: TVirtualStringTree
+ Left = 0
+ Top = 0
+ Width = 201
+ Height = 112
+ Align = alLeft
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.MainColumn = -1
+ Header.Options = [hoColumnResize, hoDrag]
+ IncrementalSearchStart = ssAlwaysStartOver
+ ScrollBarOptions.AlwaysVisible = True
+ TabOrder = 0
+ TreeOptions.PaintOptions = [toShowButtons, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages]
+ OnChange = vtCategoriesChange
+ OnExpanding = vtCategoriesExpanding
+ OnGetText = vtCategoriesGetText
+ Columns = <>
+ end
+ object vtItems: TVirtualStringTree
+ Left = 204
+ Top = 0
+ Width = 305
+ Height = 112
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ Header.SortColumn = 0
+ ScrollBarOptions.AlwaysVisible = True
+ ScrollBarOptions.ScrollBars = ssVertical
+ TabOrder = 1
+ TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoFreeOnCollapse]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toDisableDrawSelection, toFullRowSelect, toMultiSelect]
+ OnChange = vtItemsChange
+ OnCompareNodes = vtItemsCompareNodes
+ OnDblClick = btnAddItemClick
+ OnGetText = vtItemsGetText
+ OnHeaderClick = vtItemsHeaderClick
+ Columns = <
+ item
+ Position = 0
+ Width = 197
+ WideText = 'Name'
+ end
+ item
+ Position = 1
+ WideText = 'ID'
+ end>
+ end
+ object imgItemPreview: TImage32
+ Left = 509
+ Top = 0
+ Width = 85
+ Height = 112
+ Align = alRight
+ BitmapAlign = baCenter
+ Scale = 1.000000000000000000
+ ScaleMode = smNormal
+ TabOrder = 2
+ end
+ end
+ object btnAddItem: TButton
+ Left = 0
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnAddItemClick
+ end
+ object btnRemoveItem: TButton
+ Left = 80
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Remove'
+ TabOrder = 2
+ OnClick = btnRemoveItemClick
+ end
+ object btnTileItem: TButton
+ Left = 249
+ Top = 114
+ Width = 75
+ Height = 21
+ Hint = 'Fill a rectangle with items at the given z level.'
+ Anchors = [akLeft, akBottom]
+ Caption = 'Tile'
+ Enabled = False
+ TabOrder = 4
+ OnClick = btnTileItemClick
+ end
+ object eZLevel: TEdit
+ Left = 208
+ Top = 114
+ Width = 35
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 3
+ Text = '0'
+ end
+ object btnCmdItemNuke: TButton
+ Left = 329
+ Top = 114
+ Width = 75
+ Height = 21
+ Hint = 'Nuke a rectangle of items.'
+ Anchors = [akLeft, akBottom]
+ Caption = 'Nuke'
+ TabOrder = 5
+ OnClick = btnCmdNukeClick
+ end
+ object cbStatic: TCheckBox
+ Left = 413
+ Top = 116
+ Width = 49
+ Height = 17
+ Anchors = [akLeft, akBottom]
+ Caption = 'Static'
+ TabOrder = 6
+ end
+ end
+ object tsItemManip: TTabSheet
+ Caption = 'Item Manipulation'
+ ImageIndex = 4
+ object GroupBox3: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 145
+ Height = 121
+ Caption = 'Change Color'
+ TabOrder = 0
+ object eItemHue: TEdit
+ Left = 8
+ Top = 24
+ Width = 97
+ Height = 21
+ TabOrder = 0
+ Text = '0'
+ OnChange = eItemHueChange
+ end
+ object btnChangeItemHue: TButton
+ Left = 109
+ Top = 23
+ Width = 28
+ Height = 23
+ Caption = '...'
+ TabOrder = 1
+ OnClick = btnChangeItemHueClick
+ end
+ object btnCmdDye: TButton
+ Left = 8
+ Top = 88
+ Width = 57
+ Height = 25
+ Caption = 'Set'
+ TabOrder = 2
+ OnClick = btnCmdDyeClick
+ end
+ object pbHuePreview: TPaintBox32
+ Left = 8
+ Top = 56
+ Width = 128
+ Height = 25
+ TabOrder = 3
+ OnPaintBuffer = pbHuePreviewPaintBuffer
+ end
+ object btnCmdItemTileColor: TButton
+ Left = 72
+ Top = 88
+ Width = 67
+ Height = 25
+ Hint = 'Tiles this color over an area of items.'
+ Caption = 'Tile'
+ TabOrder = 4
+ OnClick = btnCmdItemTileColorClick
+ end
+ end
+ object GroupBox4: TGroupBox
+ Left = 160
+ Top = 8
+ Width = 185
+ Height = 121
+ Caption = 'Commands'
+ TabOrder = 1
+ object btnCmdDupe: TButton
+ Left = 8
+ Top = 24
+ Width = 75
+ Height = 25
+ Hint = 'Create an exact duplicate of the item.'
+ Caption = 'Dupe'
+ TabOrder = 0
+ OnClick = btnCmdDupeClick
+ end
+ object btnCmdInfo: TButton
+ Left = 8
+ Top = 56
+ Width = 75
+ Height = 25
+ Hint = 'Show an info dialog for the item.'
+ Caption = 'Info'
+ TabOrder = 1
+ OnClick = btnCmdInfoClick
+ end
+ object btnCmdRemove: TButton
+ Left = 8
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Remove the item.'
+ Caption = 'Remove'
+ TabOrder = 2
+ OnClick = btnCmdRemoveClick
+ end
+ object btnCmdLock: TButton
+ Left = 96
+ Top = 24
+ Width = 75
+ Height = 25
+ Hint = 'Attach a lock to the item.'
+ Caption = 'Lock'
+ TabOrder = 3
+ OnClick = btnCmdLockClick
+ end
+ object btnCmdNuke: TButton
+ Left = 96
+ Top = 56
+ Width = 75
+ Height = 25
+ Hint = 'Wipe an area from its items.'
+ Caption = 'Nuke'
+ TabOrder = 4
+ OnClick = btnCmdNukeClick
+ end
+ object btnCmdMoveUp: TBitBtn
+ Left = 96
+ Top = 88
+ Width = 33
+ Height = 25
+ Hint = 'Move the item up by 1 point of z.'
+ TabOrder = 5
+ OnClick = btnCmdMoveUpClick
+ Glyph.Data = {
+ 32010000424D3201000000000000360000002800000009000000090000000100
+ 180000000000FC000000120B0000120B00000000000000000000FFFFFFFFFFFF
+ FFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF00
+ 0000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF0000000000
+ 00000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF000000000000000000
+ FFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000
+ 000000000000FFFFFF000000000000000000000000000000000000000000FFFF
+ FF00FFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFF00FFFF
+ FFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF
+ FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF00}
+ end
+ object btnCmdMoveDown: TBitBtn
+ Left = 136
+ Top = 88
+ Width = 33
+ Height = 25
+ Hint = 'Move the item down by 1 point of z.'
+ TabOrder = 6
+ OnClick = btnCmdMoveDownClick
+ Glyph.Data = {
+ 32010000424D3201000000000000360000002800000009000000090000000100
+ 180000000000FC000000120B0000120B00000000000000000000FFFFFFFFFFFF
+ FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF00
+ 0000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF0000000000000000
+ 00000000000000FFFFFFFFFFFF00FFFFFF000000000000000000000000000000
+ 000000000000FFFFFF0000000000000000000000000000000000000000000000
+ 000000000000FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFF
+ FF00FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00FFFF
+ FFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF
+ FFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00}
+ end
+ end
+ object GroupBox5: TGroupBox
+ Left = 352
+ Top = 8
+ Width = 177
+ Height = 121
+ Caption = 'Properties'
+ TabOrder = 2
+ object Label1: TLabel
+ Left = 10
+ Top = 60
+ Width = 30
+ Height = 13
+ Caption = 'Value:'
+ end
+ object cbItemProperty: TComboBox
+ Left = 8
+ Top = 24
+ Width = 153
+ Height = 21
+ ItemHeight = 13
+ TabOrder = 0
+ OnChange = cbItemPropertyChange
+ Items.Strings = (
+ 'amount'
+ 'baseid'
+ 'color'
+ 'decay'
+ 'health'
+ 'id'
+ 'movable'
+ 'maxhealth'
+ 'name'
+ 'newbie'
+ 'owner'
+ 'ownervisible'
+ 'pos'
+ 'secured'
+ 'serial'
+ 'spawnregion'
+ 'totalweight'
+ 'type'
+ 'visible')
+ end
+ object eItemPropValue: TEdit
+ Left = 56
+ Top = 56
+ Width = 105
+ Height = 21
+ TabOrder = 1
+ end
+ object btnCmdItemSet: TButton
+ Left = 8
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Set the value of the selected property'
+ Caption = 'Set'
+ Enabled = False
+ TabOrder = 2
+ OnClick = btnCmdItemSetClick
+ end
+ object btnCmdItemShow: TButton
+ Left = 88
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Show the value of the selected property.'
+ Caption = 'Show'
+ Enabled = False
+ TabOrder = 3
+ OnClick = btnCmdItemShowClick
+ end
+ end
+ end
+ object tsNpcs: TTabSheet
+ Caption = 'NPCs'
+ ImageIndex = 6
+ DesignSize = (
+ 596
+ 137)
+ object Label8: TLabel
+ Left = 242
+ Top = 118
+ Width = 36
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Radius:'
+ end
+ object Label9: TLabel
+ Left = 330
+ Top = 118
+ Width = 46
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Min. Time'
+ end
+ object Label10: TLabel
+ Left = 426
+ Top = 118
+ Width = 49
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Max. Time'
+ end
+ object pnNpcs: TPanel
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object Splitter1: TSplitter
+ Left = 201
+ Top = 0
+ Height = 112
+ end
+ object Splitter2: TSplitter
+ Left = 496
+ Top = 0
+ Height = 112
+ Align = alRight
+ end
+ object vtNpcCategories: TVirtualStringTree
+ Left = 0
+ Top = 0
+ Width = 201
+ Height = 112
+ Align = alLeft
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.MainColumn = -1
+ Header.Options = [hoColumnResize, hoDrag]
+ IncrementalSearchStart = ssAlwaysStartOver
+ ScrollBarOptions.AlwaysVisible = True
+ TabOrder = 0
+ TreeOptions.PaintOptions = [toShowButtons, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages]
+ OnChange = vtNpcCategoriesChange
+ OnExpanding = vtNpcCategoriesExpanding
+ OnGetText = vtCategoriesGetText
+ Columns = <>
+ end
+ object vtNpcs: TVirtualStringTree
+ Left = 204
+ Top = 0
+ Width = 292
+ Height = 112
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ Header.SortColumn = 0
+ ScrollBarOptions.AlwaysVisible = True
+ ScrollBarOptions.ScrollBars = ssVertical
+ TabOrder = 1
+ TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoFreeOnCollapse]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toDisableDrawSelection, toFullRowSelect]
+ OnChange = vtNpcsChange
+ OnCompareNodes = vtNpcsCompareNodes
+ OnDblClick = btnAddNpcClick
+ OnGetText = vtNpcsGetText
+ OnHeaderClick = vtNpcsHeaderClick
+ Columns = <
+ item
+ Position = 0
+ Width = 197
+ WideText = 'Name'
+ end
+ item
+ Position = 1
+ WideText = 'ID'
+ end>
+ end
+ object pbNpcPreview: TPaintBox32
+ Left = 499
+ Top = 0
+ Width = 95
+ Height = 112
+ Align = alRight
+ TabOrder = 2
+ OnPaintBuffer = pbNpcPreviewPaintBuffer
+ end
+ end
+ object btnAddNpc: TButton
+ Left = 0
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnAddNpcClick
+ end
+ object btnRemoveNpc: TButton
+ Left = 79
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Remove'
+ TabOrder = 2
+ OnClick = btnRemoveNpcClick
+ end
+ object eSpawnRadius: TEdit
+ Left = 288
+ Top = 114
+ Width = 35
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 3
+ Text = '0'
+ OnExit = eSpawnRadiusExit
+ end
+ object eSpawnMin: TEdit
+ Left = 384
+ Top = 114
+ Width = 35
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 4
+ Text = '0'
+ OnExit = eSpawnMinExit
+ end
+ object eSpawnMax: TEdit
+ Left = 480
+ Top = 114
+ Width = 35
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 5
+ Text = '0'
+ OnExit = eSpawnMaxExit
+ end
+ object btnNpcSpawn: TButton
+ Left = 159
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Spawn'
+ Enabled = False
+ TabOrder = 6
+ OnClick = btnNpcSpawnClick
+ end
+ end
+ object TabSheet1: TTabSheet
+ Caption = 'Multis'
+ ImageIndex = 7
+ DesignSize = (
+ 596
+ 137)
+ object Panel1: TPanel
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object vtMultis: TVirtualStringTree
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ Header.SortColumn = 0
+ ScrollBarOptions.AlwaysVisible = True
+ ScrollBarOptions.ScrollBars = ssVertical
+ TabOrder = 0
+ TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoFreeOnCollapse]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toDisableDrawSelection, toFullRowSelect]
+ OnChange = vtMultisChange
+ OnCompareNodes = vtMultisCompareNodes
+ OnDblClick = btnAddMultiClick
+ OnGetText = vtMultisGetText
+ OnHeaderClick = vtMultisHeaderClick
+ Columns = <
+ item
+ Position = 0
+ Width = 197
+ WideText = 'Name'
+ end
+ item
+ Position = 1
+ WideText = 'ID'
+ end>
+ end
+ end
+ object btnAddMulti: TButton
+ Left = 0
+ Top = 115
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnAddMultiClick
+ end
+ object btnRemoveMulti: TButton
+ Left = 79
+ Top = 115
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Remove'
+ TabOrder = 2
+ end
+ object btnPreviewMulti: TButton
+ Left = 158
+ Top = 115
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Preview'
+ Enabled = False
+ TabOrder = 3
+ OnClick = btnPreviewMultiClick
+ end
+ end
+ object tsTags: TTabSheet
+ Caption = 'Object Manipulation'
+ ImageIndex = 5
+ object GroupBox6: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 233
+ Height = 121
+ Caption = 'Manage Tags'
+ TabOrder = 0
+ object Label2: TLabel
+ Left = 10
+ Top = 60
+ Width = 30
+ Height = 13
+ Caption = 'Value:'
+ end
+ object Label3: TLabel
+ Left = 10
+ Top = 28
+ Width = 31
+ Height = 13
+ Caption = 'Name:'
+ end
+ object eTagValue: TEdit
+ Left = 56
+ Top = 56
+ Width = 97
+ Height = 21
+ Hint = 'The new tag value if you use set.'
+ TabOrder = 0
+ end
+ object btnTagSet: TButton
+ Left = 8
+ Top = 88
+ Width = 49
+ Height = 25
+ Caption = 'Set'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnTagSetClick
+ end
+ object eTagName: TEdit
+ Left = 56
+ Top = 24
+ Width = 169
+ Height = 21
+ Hint = 'The name of the tag you want to set.'
+ TabOrder = 2
+ OnChange = eTagNameChange
+ end
+ object btnTagShow: TButton
+ Left = 64
+ Top = 88
+ Width = 49
+ Height = 25
+ Caption = 'Show'
+ Enabled = False
+ TabOrder = 3
+ OnClick = btnTagShowClick
+ end
+ object btnTagDelete: TButton
+ Left = 120
+ Top = 88
+ Width = 49
+ Height = 25
+ Caption = 'Delete'
+ Enabled = False
+ TabOrder = 4
+ OnClick = btnTagDeleteClick
+ end
+ object cbTagType: TComboBox
+ Left = 160
+ Top = 56
+ Width = 65
+ Height = 21
+ Hint = 'The type of the tag value.'
+ Style = csDropDownList
+ ItemHeight = 13
+ ItemIndex = 0
+ TabOrder = 5
+ Text = 'String'
+ Items.Strings = (
+ 'String'
+ 'Integer'
+ 'Float')
+ end
+ object btnTagInfo: TButton
+ Left = 176
+ Top = 88
+ Width = 49
+ Height = 25
+ Caption = 'Info'
+ TabOrder = 6
+ OnClick = btnTagInfoClick
+ end
+ end
+ object GroupBox7: TGroupBox
+ Left = 248
+ Top = 8
+ Width = 137
+ Height = 121
+ Caption = 'Move Relatively'
+ TabOrder = 1
+ object Label4: TLabel
+ Left = 16
+ Top = 18
+ Width = 29
+ Height = 13
+ Caption = 'X Axis'
+ end
+ object Label5: TLabel
+ Left = 16
+ Top = 42
+ Width = 29
+ Height = 13
+ Caption = 'Y Axis'
+ end
+ object Label6: TLabel
+ Left = 16
+ Top = 66
+ Width = 29
+ Height = 13
+ Caption = 'Z Axis'
+ end
+ object eMoveX: TEdit
+ Left = 80
+ Top = 16
+ Width = 41
+ Height = 21
+ TabOrder = 0
+ Text = '0'
+ end
+ object eMoveY: TEdit
+ Left = 80
+ Top = 40
+ Width = 41
+ Height = 21
+ TabOrder = 1
+ Text = '0'
+ end
+ object eMoveZ: TEdit
+ Left = 80
+ Top = 64
+ Width = 41
+ Height = 21
+ TabOrder = 2
+ Text = '0'
+ end
+ object btnCmdMove: TButton
+ Left = 8
+ Top = 88
+ Width = 65
+ Height = 25
+ Caption = 'Move'
+ TabOrder = 3
+ OnClick = btnCmdMoveClick
+ end
+ end
+ object GroupBox8: TGroupBox
+ Left = 392
+ Top = 8
+ Width = 137
+ Height = 121
+ Caption = 'Manage Scripts'
+ TabOrder = 2
+ object btnCmdAddEvent: TButton
+ Left = 8
+ Top = 56
+ Width = 57
+ Height = 25
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnCmdAddEventClick
+ end
+ object btnCmdRemoveEvent: TButton
+ Left = 72
+ Top = 56
+ Width = 57
+ Height = 25
+ Caption = 'Remove'
+ Enabled = False
+ TabOrder = 2
+ OnClick = btnCmdRemoveEventClick
+ end
+ object btnCmdShowEventlist: TButton
+ Left = 8
+ Top = 88
+ Width = 121
+ Height = 25
+ Caption = 'Show Eventlist'
+ TabOrder = 3
+ OnClick = btnCmdShowEventlistClick
+ end
+ object cbEventName: TComboBox
+ Left = 8
+ Top = 24
+ Width = 121
+ Height = 21
+ ItemHeight = 13
+ TabOrder = 0
+ OnChange = eEventNameChange
+ end
+ end
+ end
+ object TravelMap: TTabSheet
+ Caption = 'Travel'
+ ImageIndex = 2
+ DesignSize = (
+ 596
+ 137)
+ object pnlTravel: TPanel
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object spTravel: TSplitter
+ Left = 201
+ Top = 0
+ Height = 112
+ end
+ object spMap: TSplitter
+ Left = 441
+ Top = 0
+ Height = 112
+ Align = alRight
+ end
+ object vtLocCategories: TVirtualStringTree
+ Left = 0
+ Top = 0
+ Width = 201
+ Height = 112
+ Align = alLeft
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.MainColumn = -1
+ Header.Options = [hoColumnResize, hoDrag]
+ IncrementalSearchStart = ssAlwaysStartOver
+ ScrollBarOptions.AlwaysVisible = True
+ TabOrder = 0
+ TreeOptions.PaintOptions = [toShowButtons, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages]
+ OnChange = vtLocCategoriesChange
+ OnExpanding = vtLocCategoriesExpanding
+ OnGetText = vtCategoriesGetText
+ Columns = <>
+ end
+ object vtLocItems: TVirtualStringTree
+ Left = 204
+ Top = 0
+ Width = 237
+ Height = 112
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ Header.SortColumn = 0
+ ScrollBarOptions.AlwaysVisible = True
+ ScrollBarOptions.ScrollBars = ssVertical
+ TabOrder = 1
+ TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoFreeOnCollapse]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toDisableDrawSelection, toFullRowSelect]
+ OnChange = vtLocItemsChange
+ OnCompareNodes = vtLocItemsCompareNodes
+ OnDblClick = Go1Click
+ OnGetText = vtLocItemsGetText
+ OnHeaderClick = vtLocItemsHeaderClick
+ Columns = <
+ item
+ Position = 0
+ Width = 197
+ WideText = 'Name'
+ end>
+ end
+ object pbMap: TPaintBox32
+ Left = 444
+ Top = 0
+ Width = 150
+ Height = 112
+ Align = alRight
+ PopupMenu = pmTravel
+ TabOrder = 2
+ OnMouseDown = pbMapMouseDown
+ OnPaintBuffer = pbMapPaintBuffer
+ end
+ end
+ object btnTravel: TButton
+ Left = 0
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Travel'
+ TabOrder = 1
+ OnClick = Go1Click
+ end
+ object btnSend: TButton
+ Left = 80
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Send'
+ TabOrder = 2
+ OnClick = btnSendClick
+ end
+ object Button2: TButton
+ Left = 160
+ Top = 114
+ Width = 89
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Teleport Self'
+ TabOrder = 3
+ OnClick = Button2Click
+ end
+ object btnCmdSendOther: TButton
+ Left = 254
+ Top = 114
+ Width = 89
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Teleport Other'
+ TabOrder = 4
+ OnClick = btnCmdSendOtherClick
+ end
+ object btnCmdWhere: TButton
+ Left = 348
+ Top = 114
+ Width = 75
+ Height = 21
+ Hint = 'Show your current position.'
+ Anchors = [akLeft, akBottom]
+ Caption = 'Where'
+ TabOrder = 5
+ OnClick = btnCmdWhereClick
+ end
+ object btnMapOverview: TButton
+ Left = 428
+ Top = 114
+ Width = 75
+ Height = 21
+ Hint = 'Show your current position.'
+ Anchors = [akLeft, akBottom]
+ Caption = 'Overview'
+ TabOrder = 6
+ OnClick = btnMapOverviewClick
+ end
+ end
+ object tsSettings: TTabSheet
+ Caption = 'Settings'
+ ImageIndex = 1
+ object gbSettingsGeneral: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 241
+ Height = 97
+ Caption = 'General Settings'
+ TabOrder = 0
+ object lblCommandPrefix: TLabel
+ Left = 45
+ Top = 64
+ Width = 76
+ Height = 13
+ Caption = 'Command Prefix'
+ end
+ object cbAlwaysOnTop: TCheckBox
+ Left = 16
+ Top = 24
+ Width = 97
+ Height = 17
+ Caption = 'Always on top'
+ TabOrder = 0
+ OnClick = cbAlwaysOnTopClick
+ end
+ object eCommandPrefix: TEdit
+ Left = 15
+ Top = 60
+ Width = 25
+ Height = 21
+ TabOrder = 1
+ end
+ object btnSave: TButton
+ Left = 152
+ Top = 56
+ Width = 75
+ Height = 25
+ Caption = '&Save'
+ TabOrder = 2
+ OnClick = btnSaveClick
+ end
+ end
+ object btnRegions: TButton
+ Left = 264
+ Top = 16
+ Width = 75
+ Height = 25
+ Caption = 'Regions'
+ TabOrder = 1
+ OnClick = btnRegionsClick
+ end
+ end
+ object TabSheet2: TTabSheet
+ Caption = 'Build'
+ ImageIndex = 8
+ DesignSize = (
+ 596
+ 137)
+ object GroupBox9: TGroupBox
+ Left = 0
+ Top = 0
+ Width = 89
+ Height = 137
+ Anchors = [akLeft, akTop, akBottom]
+ Caption = 'Settings'
+ TabOrder = 0
+ object Label11: TLabel
+ Left = 8
+ Top = 18
+ Width = 10
+ Height = 16
+ Caption = 'Z'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -13
+ Font.Name = 'MS Sans Serif'
+ Font.Style = [fsBold]
+ ParentFont = False
+ end
+ object cbBuildZ: TComboBox
+ Left = 23
+ Top = 16
+ Width = 58
+ Height = 21
+ ItemHeight = 13
+ TabOrder = 0
+ Text = '0'
+ Items.Strings = (
+ '0'
+ '5'
+ '7'
+ '10'
+ '15'
+ '17'
+ '20'
+ '25'
+ '27'
+ '30'
+ '35'
+ '37'
+ '40')
+ end
+ end
+ object gbBuild: TGroupBox
+ Left = 96
+ Top = 0
+ Width = 489
+ Height = 137
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Caption = 'Build'
+ TabOrder = 1
+ DesignSize = (
+ 489
+ 137)
+ object sbBuild: TScrollBox
+ Left = 8
+ Top = 16
+ Width = 473
+ Height = 113
+ HorzScrollBar.Smooth = True
+ HorzScrollBar.Tracking = True
+ VertScrollBar.Smooth = True
+ VertScrollBar.Tracking = True
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ BevelKind = bkSoft
+ TabOrder = 0
+ OnClick = sbBuildClick
+ OnMouseWheelDown = sbBuildMouseWheelDown
+ OnMouseWheelUp = sbBuildMouseWheelUp
+ OnResize = sbBuildResize
+ end
+ end
+ end
+ object tsCustom: TTabSheet
+ Caption = 'Custom'
+ ImageIndex = 9
+ OnResize = tsCustomResize
+ end
+ end
+ object XPManifest1: TXPManifest
+ Left = 572
+ Top = 28
+ end
+ object pmTravel: TPopupMenu
+ Left = 572
+ Top = 25
+ object Go1: TMenuItem
+ Caption = '&Go'
+ OnClick = Go1Click
+ end
+ object Send1: TMenuItem
+ Caption = '&Send'
+ OnClick = btnSendClick
+ end
+ object Center1: TMenuItem
+ Caption = '&Center'
+ OnClick = Center1Click
+ end
+ object N1: TMenuItem
+ Caption = '-'
+ end
+ object Felucca1: TMenuItem
+ Caption = 'Felucca'
+ Checked = True
+ GroupIndex = 1
+ RadioItem = True
+ OnClick = Felucca1Click
+ end
+ object Trammel1: TMenuItem
+ Caption = 'Trammel'
+ GroupIndex = 1
+ RadioItem = True
+ OnClick = Trammel1Click
+ end
+ object Ilshenar1: TMenuItem
+ Caption = 'Ilshenar'
+ GroupIndex = 1
+ RadioItem = True
+ OnClick = Ilshenar1Click
+ end
+ object Malas1: TMenuItem
+ Caption = 'Malas'
+ GroupIndex = 1
+ RadioItem = True
+ OnClick = Malas1Click
+ end
+ object SamuraiEmpire1: TMenuItem
+ Caption = 'Samurai Empire'
+ GroupIndex = 1
+ OnClick = SamuraiEmpire1Click
+ end
+ end
+ object animtimer: TTimer
+ Enabled = False
+ Interval = 100
+ OnTimer = animtimerTimer
+ Left = 572
+ Top = 24
+ end
+ object ontopTimer: TTimer
+ Interval = 100
+ OnTimer = ontopTimerTimer
+ Left = 572
+ Top = 24
+ end
+ object btnCustomPopup: TPopupMenu
+ Left = 572
+ Top = 56
+ object AddButton1: TMenuItem
+ Caption = '&Add Button'
+ OnClick = AddButton1Click
+ end
+ object Change1: TMenuItem
+ Caption = '&Change'
+ OnClick = Change1Click
+ end
+ object Remove1: TMenuItem
+ Caption = '&Remove'
+ OnClick = Remove1Click
+ end
+ end
+end
Added: trunk/WPGM/Main.pas
===================================================================
--- trunk/WPGM/Main.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Main.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,2398 @@
+unit Main;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ VirtualTrees, ComCtrls, ImgList, ExtCtrls, SQLite, SQLiteTable, UOTiledata,
+ GR32, GR32_Image, UOArt, UOAnim, StdCtrls, uConfig, XPMan, UOMap, UOStatics, UORadarCol,
+ Menus, UOHues, Buttons, SyncObjs;
+
+type TNode = record
+ Id: Cardinal;
+ Name: WideString;
+end;
+
+type TLocationNode = record
+ Id: Cardinal;
+ Name: WideString;
+ LocId: String;
+ PosX: Cardinal;
+ PosY: Cardinal;
+ PosZ: ShortInt;
+ PosMap: Byte;
+end;
+
+type TItemNode = record
+ Id: Cardinal;
+ Name: WideString;
+ ArtId: Word;
+ Color: Word;
+ AddId: String;
+end;
+
+type TMultiNode = record
+ Id: Cardinal;
+ Name: WideString;
+ AddId: String;
+ MultiId: Word;
+end;
+
+type TNpcEquipment = record
+ Layer: Byte;
+ Anim: Word;
+ Color: Word;
+end;
+
+type TNpcNode = record
+ Id: Cardinal;
+ Name: WideString;
+ BodyId: Word;
+ Skin: Word;
+ AddId: String;
+ Equipment: Array of TNpcEquipment;
+end;
+
+type PMultiNode = ^TMultiNode;
+type PItemNode = ^TItemNode;
+type PNPCNode = ^TNPCNode;
+type PLocationNode = ^TLocationNode;
+type PNode = ^TNode;
+
+type
+ TfrmMain = class(TForm)
+ Pages: TPageControl;
+ tsItems: TTabSheet;
+ tsSettings: TTabSheet;
+ pnlItems: TPanel;
+ spItems: TSplitter;
+ vtCategories: TVirtualStringTree;
+ vtItems: TVirtualStringTree;
+ XPManifest1: TXPManifest;
+ gbSettingsGeneral: TGroupBox;
+ cbAlwaysOnTop: TCheckBox;
+ btnAddItem: TButton;
+ btnRemoveItem: TButton;
+ lblCommandPrefix: TLabel;
+ eCommandPrefix: TEdit;
+ TravelMap: TTabSheet;
+ imgItemPreview: TImage32;
+ pnlTravel: TPanel;
+ vtLocCategories: TVirtualStringTree;
+ vtLocItems: TVirtualStringTree;
+ pbMap: TPaintBox32;
+ spTravel: TSplitter;
+ spMap: TSplitter;
+ pmTravel: TPopupMenu;
+ Go1: TMenuItem;
+ btnTravel: TButton;
+ btnSend: TButton;
+ tsCommands: TTabSheet;
+ GroupBox1: TGroupBox;
+ btnCmdAllmove: TButton;
+ btnCmdAllshow: TButton;
+ btnCmdInvisible: TButton;
+ btnCmdStaff: TButton;
+ btnCmdInvul: TButton;
+ btnCmdPageNotify: TButton;
+ GroupBox2: TGroupBox;
+ btnCmdShutdown: TButton;
+ btnCmdReloadPython: TButton;
+ btnCmdReloadScripts: TButton;
+ btnCmdReloadAccounts: TButton;
+ btnCmdReloadAll: TButton;
+ btnSave: TButton;
+ tsItemManip: TTabSheet;
+ tsTags: TTabSheet;
+ GroupBox3: TGroupBox;
+ eItemHue: TEdit;
+ btnChangeItemHue: TButton;
+ btnCmdDye: TButton;
+ pbHuePreview: TPaintBox32;
+ GroupBox4: TGroupBox;
+ btnCmdDupe: TButton;
+ btnCmdInfo: TButton;
+ btnCmdRemove: TButton;
+ btnCmdLock: TButton;
+ btnCmdNuke: TButton;
+ GroupBox5: TGroupBox;
+ cbItemProperty: TComboBox;
+ eItemPropValue: TEdit;
+ btnCmdItemSet: TButton;
+ btnCmdItemShow: TButton;
+ Label1: TLabel;
+ btnCmdItemTileColor: TButton;
+ GroupBox6: TGroupBox;
+ Label2: TLabel;
+ eTagValue: TEdit;
+ btnTagSet: TButton;
+ eTagName: TEdit;
+ Label3: TLabel;
+ btnTagShow: TButton;
+ btnTagDelete: TButton;
+ cbTagType: TComboBox;
+ btnTagInfo: TButton;
+ GroupBox7: TGroupBox;
+ Button2: TButton;
+ btnCmdSendOther: TButton;
+ Send1: TMenuItem;
+ eMoveX: TEdit;
+ eMoveY: TEdit;
+ eMoveZ: TEdit;
+ btnCmdMove: TButton;
+ Label4: TLabel;
+ Label5: TLabel;
+ Label6: TLabel;
+ btnCmdMoveUp: TBitBtn;
+ btnCmdMoveDown: TBitBtn;
+ btnTileItem: TButton;
+ eZLevel: TEdit;
+ Label7: TLabel;
+ btnCmdItemNuke: TButton;
+ GroupBox8: TGroupBox;
+ btnCmdAddEvent: TButton;
+ btnCmdRemoveEvent: TButton;
+ btnCmdShowEventlist: TButton;
+ btnCmdWhere: TButton;
+ btnCmdServertime: TButton;
+ cbEventName: TComboBox;
+ tsNpcs: TTabSheet;
+ pnNpcs: TPanel;
+ Splitter1: TSplitter;
+ vtNpcCategories: TVirtualStringTree;
+ vtNpcs: TVirtualStringTree;
+ btnAddNpc: TButton;
+ btnRemoveNpc: TButton;
+ Splitter2: TSplitter;
+ pbNpcPreview: TPaintBox32;
+ animtimer: TTimer;
+ TabSheet1: TTabSheet;
+ Panel1: TPanel;
+ vtMultis: TVirtualStringTree;
+ btnAddMulti: TButton;
+ btnRemoveMulti: TButton;
+ btnPreviewMulti: TButton;
+ N1: TMenuItem;
+ Felucca1: TMenuItem;
+ Trammel1: TMenuItem;
+ Ilshenar1: TMenuItem;
+ Malas1: TMenuItem;
+ Center1: TMenuItem;
+ SamuraiEmpire1: TMenuItem;
+ cbStatic: TCheckBox;
+ btnMapOverview: TButton;
+ ontopTimer: TTimer;
+ Label8: TLabel;
+ eSpawnRadius: TEdit;
+ Label9: TLabel;
+ eSpawnMin: TEdit;
+ Label10: TLabel;
+ eSpawnMax: TEdit;
+ btnNpcSpawn: TButton;
+ btnRegions: TButton;
+ Button1: TButton;
+ TabSheet2: TTabSheet;
+ GroupBox9: TGroupBox;
+ cbBuildZ: TComboBox;
+ Label11: TLabel;
+ gbBuild: TGroupBox;
+ sbBuild: TScrollBox;
+ tsCustom: TTabSheet;
+ btnCustomPopup: TPopupMenu;
+ Remove1: TMenuItem;
+ Change1: TMenuItem;
+ AddButton1: TMenuItem;
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure vtCategoriesGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure vtCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+ procedure vtItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure vtCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+ procedure vtItemsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure vtItemsHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure btnAddItemClick(Sender: TObject);
+ procedure vtItemsChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure btnRemoveItemClick(Sender: TObject);
+ procedure cbAlwaysOnTopClick(Sender: TObject);
+ procedure btnSaveClick(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure pbMapPaintBuffer(Sender: TObject);
+ procedure pbMapMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure vtLocCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+ procedure vtLocCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+ procedure vtLocItemsGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure vtLocItemsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure vtLocItemsHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+ procedure vtLocItemsChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+ procedure Go1Click(Sender: TObject);
+ procedure btnSendClick(Sender: TObject);
+ procedure btnCmdAllmoveClick(Sender: TObject);
+ procedure btnCmdAllshowClick(Sender: TObject);
+ procedure btnCmdInvisibleClick(Sender: TObject);
+ procedure btnCmdStaffClick(Sender: TObject);
+ procedure btnCmdInvulClick(Sender: TObject);
+ procedure btnCmdShutdownClick(Sender: TObject);
+ procedure btnCmdReloadAllClick(Sender: TObject);
+ procedure btnCmdReloadConfigClick(Sender: TObject);
+ procedure btnCmdReloadAccountsClick(Sender: TObject);
+ procedure btnCmdReloadPythonClick(Sender: TObject);
+ procedure btnCmdReloadScriptsClick(Sender: TObject);
+ procedure btnCmdDyeClick(Sender: TObject);
+ procedure pbHuePreviewPaintBuffer(Sender: TObject);
+ procedure eItemHueChange(Sender: TObject);
+ procedure btnChangeItemHueClick(Sender: TObject);
+ procedure btnCmdDupeClick(Sender: TObject);
+ procedure btnCmdInfoClick(Sender: TObject);
+ procedure btnCmdRemoveClick(Sender: TObject);
+ procedure btnCmdLockClick(Sender: TObject);
+ procedure btnCmdNukeClick(Sender: TObject);
+ procedure btnCmdItemSetClick(Sender: TObject);
+ procedure btnCmdItemShowClick(Sender: TObject);
+ procedure cbItemPropertyChange(Sender: TObject);
+ procedure btnCmdItemTileColorClick(Sender: TObject);
+ procedure btnTagInfoClick(Sender: TObject);
+ procedure eTagNameChange(Sender: TObject);
+ procedure btnTagSetClick(Sender: TObject);
+ procedure btnTagShowClick(Sender: TObject);
+ procedure btnTagDeleteClick(Sender: TObject);
+ procedure btnCmdSendOtherClick(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure btnCmdMoveClick(Sender: TObject);
+ procedure btnCmdMoveUpClick(Sender: TObject);
+ procedure btnCmdMoveDownClick(Sender: TObject);
+ procedure btnTileItemClick(Sender: TObject);
+ procedure btnCmdShowEventlistClick(Sender: TObject);
+ procedure eEventNameChange(Sender: TObject);
+ procedure btnCmdAddEventClick(Sender: TObject);
+ procedure btnCmdRemoveEventClick(Sender: TObject);
+ procedure btnCmdWhereClick(Sender: TObject);
+ procedure btnCmdServertimeClick(Sender: TObject);
+ procedure vtNpcCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+ procedure vtNpcCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+ procedure vtNpcsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure vtNpcsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure btnRemoveNpcClick(Sender: TObject);
+ procedure btnAddNpcClick(Sender: TObject);
+ procedure vtNpcsChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure vtNpcsHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure pbNpcPreviewPaintBuffer(Sender: TObject);
+ procedure animtimerTimer(Sender: TObject);
+ procedure vtMultisGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure vtMultisCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure vtMultisHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure vtMultisChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure btnPreviewMultiClick(Sender: TObject);
+ procedure btnAddMultiClick(Sender: TObject);
+ procedure Felucca1Click(Sender: TObject);
+ procedure Trammel1Click(Sender: TObject);
+ procedure Ilshenar1Click(Sender: TObject);
+ procedure Malas1Click(Sender: TObject);
+ procedure Center1Click(Sender: TObject);
+ procedure SamuraiEmpire1Click(Sender: TObject);
+ procedure btnStaticItemClick(Sender: TObject);
+ procedure btnMapOverviewClick(Sender: TObject);
+ procedure ontopTimerTimer(Sender: TObject);
+ procedure btnNpcSpawnClick(Sender: TObject);
+ procedure eSpawnRadiusExit(Sender: TObject);
+ procedure eSpawnMinExit(Sender: TObject);
+ procedure eSpawnMaxExit(Sender: TObject);
+ procedure btnRegionsClick(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure sbBuildResize(Sender: TObject);
+ procedure clickBuildButton(Sender: TObject);
+ procedure sbBuildClick(Sender: TObject);
+ procedure sbBuildMouseWheelDown(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+ procedure sbBuildMouseWheelUp(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+ procedure customButtonClick(Sender: TObject);
+ procedure customButtonMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure Remove1Click(Sender: TObject);
+ procedure Change1Click(Sender: TObject);
+ procedure AddButton1Click(Sender: TObject);
+ procedure tsCustomResize(Sender: TObject);
+ private
+ { Private-Deklarationen }
+ UpdateMutex: TCriticalSection;
+ public
+ { Public-Deklarationen }
+ procedure pixelCombine(F: TColor32; var B: TColor32; M: TColor32);
+ procedure loadMultis;
+ procedure addBuildButton(Id: String; ItemId: Word; Text: String);
+ procedure rebuildBuildMenu;
+ procedure reorderCustomButtons;
+ procedure loadCustomButtons;
+ procedure saveCustomButtons;
+ procedure changeCustomButton(Button: TButton; NewButton: Boolean = False);
+ end;
+
+var
+ frmMain: TfrmMain;
+ SQLiteDb: TSQLiteDatabase;
+ ItemCategory: Cardinal;
+ Tiledata: TTiledataReader;
+ Art: TArtReader;
+ Anim: TAnimReader;
+ Maps: Array[0..4] of TMapReader;
+ Statics: Array[0..4] of TStaticReader;
+ Hues: THuesReader;
+ RadarCol: TRadarcolReader;
+ Config: TConfig;
+ MapCenterX, MapCenterY: Cardinal;
+ MapCenterZ: ShortInt;
+ MapCenterMap: Byte;
+ MapId: Cardinal;
+ npcPreview: Array of TAnimation;
+ npcPreviewFrame: Integer;
+ BuildCurrentX: Integer;
+ BuildCurrentY: Integer;
+
+implementation
+
+uses UOUtilities, uChooseHue, Math, uCenter, Overview, Spawnregions,
+ uPatternColor;
+
+{$R *.DFM}
+
+procedure TfrmMain.FormCreate(Sender: TObject);
+var
+ RootQuery: TSQLiteTable;
+ CountQuery: TSQLiteTable;
+ Node: PNode;
+ TreeNode: PVirtualNode;
+ UOPath: String;
+ i: Integer;
+ value: String;
+begin
+ inherited;
+
+ UpdateMutex := TCriticalSection.Create;
+
+ npcPreview := nil;
+ npcPreviewFrame := 0;
+ Tiledata := TTiledataReader.Create;
+ Art := TArtReader.Create;
+ Anim := TAnimReader.Create;
+ Config := TConfig.Create;
+ Hues := THuesReader.Create;
+ Art.hues := Hues; // Tell the art reader about the hues
+ Anim.hues := Hues; // Tell the anim reader about the hues
+
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 0;
+
+ // Should be updated to support multiple maps
+ for i := 0 to 4 do begin
+ Maps[i] := TMapReader.Create;
+ Statics[i] := TStaticReader.Create;
+ end;
+ RadarCol := TRadarColReader.Create;
+
+ Config.Load(ExtractFilePath( Application.ExeName ) + 'config.ini');
+
+ vtCategories.NodeDataSize := sizeof( TNode );
+ vtNpcCategories.NodeDataSize := sizeof(TNode);
+ vtLocCategories.NodeDataSize := sizeof(TNode);
+
+ vtItems.NodeDataSize := sizeof( TItemNode );
+ vtLocItems.NodeDataSize := sizeof(TLocationNode);
+ vtNpcs.NodeDataSize := sizeof( TNpcNode );
+ vtMultis.NodeDataSize := sizeof( TMultiNode );
+
+ eSpawnRadius.Text := Config.getString('SpawnRadius', '5');
+ eSpawnMin.Text := Config.getString('SpawnMin', '5');
+ eSpawnMax.Text := Config.getString('SpawnMax', '10');
+ eCommandPrefix.Text := Config.getString('Command Prefix', '''');
+ cbAlwaysOnTop.Checked := Config.getBool('Always On Top', False);
+ cbAlwaysOnTopClick(nil); // Refresh the Status
+ UOPath := getUoPath;
+
+ // Query initial count of Items
+ try
+ SQLiteDb := TSQLiteDatabase.Create( 'categories.db' );
+ SQLiteDb.ExecSQL( 'PRAGMA default_cache_size = 10000;' );
+ SQLiteDb.ExecSQL( 'PRAGMA default_synchronous = OFF;' );
+ SQLiteDb.ExecSQL( 'PRAGMA full_column_names = OFF;' );
+ SQLiteDb.ExecSQL( 'PRAGMA show_datatypes = OFF;' );
+
+ RootQuery := TSQLiteTable.Create( SQLiteDb, 'SELECT id,name FROM categories WHERE type = 0 AND parent = 0 ORDER BY name ASC;' );
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtCategories.AddChild( nil );
+ Node := vtCategories.GetNodeData( TreeNode );
+ Node.Id := StrToInt( RootQuery.Fields[0] );
+ Node.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM categories WHERE type = 0 AND parent = %u', [ Node.Id ] ) );
+
+ if StrToInt(CountQuery.Fields[0]) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+ CountQuery.Free;
+ RootQuery.Next;
+ end;
+ RootQuery.Free;
+
+ RootQuery := TSQLiteTable.Create( SQLiteDb, 'SELECT id,name FROM locationcategories WHERE type = 0 AND parent = 0 ORDER BY name ASC;' );
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtLocCategories.AddChild( nil );
+ Node := vtLocCategories.GetNodeData( TreeNode );
+ Node.Id := StrToInt( RootQuery.Fields[0] );
+ Node.Name := UTF8Decode(RootQuery.Fields[1]);
+
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM locationcategories WHERE type = 0 AND parent = %u', [ Node.Id ] ) );
+
+ if StrToInt(CountQuery.Fields[0]) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+ CountQuery.Free;
+ RootQuery.Next;
+ end;
+ RootQuery.Free;
+
+ RootQuery := TSQLiteTable.Create( SQLiteDb, 'SELECT id,name FROM npccategories WHERE type = 0 AND parent = 0 ORDER BY name ASC;' );
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtNpcCategories.AddChild( nil );
+ Node := vtNpcCategories.GetNodeData( TreeNode );
+ Node.Id := StrToInt( RootQuery.Fields[0] );
+ Node.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM npccategories WHERE type = 0 AND parent = %u', [ Node.Id ] ) );
+
+ if StrToInt(CountQuery.Fields[0]) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+ CountQuery.Free;
+ RootQuery.Next;
+ end;
+ RootQuery.Free;
+
+ loadMultis;
+
+ { Load UO Files }
+ Tiledata.Open(Config.getString('Tiledata.mul Path',
+ UOPath + 'tiledata.mul'));
+ Art.Open(Config.getString('Artidx.mul Path', UOPath + 'artidx.mul'),
+ Config.getString('Art.mul Path', UOPath + 'art.mul'));
+ Anim.Open(Config.getString('Anim.idx Path', UOPath + 'anim.idx'),
+ Config.getString('Anim.mul Path', UOPath + 'anim.mul'),
+ Config.getString('Anim2.idx Path', UOPath + 'anim2.idx'),
+ Config.getString('Anim2.mul Path', UOPath + 'anim2.mul'),
+ Config.getString('Anim3.idx Path', UOPath + 'anim3.idx'),
+ Config.getString('Anim3.mul Path', UOPath + 'anim3.mul'),
+ Config.getString('Bodyconv.def Path', UOPath + 'bodyconv.def'),
+ Config.getString('Body.def Path', UOPath + 'body.def'));
+ RadarCol.Load(Config.getString('Radarcol.mul Path',
+ UOPath + 'radarcol.mul'));
+ Hues.Load(Config.getString('Hues.mul Path',
+ UOPath + 'hues.mul'));
+
+ Maps[0].Open(Config.getString('Map0.mul Path', UOPath + 'map0.mul'));
+ Statics[0].Open(
+ Config.getString('Staidx0.mul Path', UOPath + 'staidx0.mul'),
+ Config.getString('Statics0.mul Path', UOPath + 'statics0.mul'));
+ Maps[1] := Maps[0];
+ Statics[1] := Statics[0];
+ Maps[2].Open(Config.getString('Map2.mul Path', UOPath + 'map2.mul'));
+ Statics[2].Open(
+ Config.getString('Staidx2.mul Path', UOPath + 'staidx2.mul'),
+ Config.getString('Statics2.mul Path', UOPath + 'statics2.mul'));
+ Maps[3].Open(Config.getString('Map3.mul Path', UOPath + 'map3.mul'));
+ Statics[3].Open(
+ Config.getString('Staidx3.mul Path', UOPath + 'staidx3.mul'),
+ Config.getString('Statics3.mul Path', UOPath + 'statics3.mul'));
+ Maps[4].Open(Config.getString('Map4.mul Path', UOPath + 'map4.mul'));
+ Statics[4].Open(
+ Config.getString('Staidx4.mul Path', UOPath + 'staidx4.mul'),
+ Config.getString('Statics4.mul Path', UOPath + 'statics4.mul'));
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox(PChar(E.Message), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+
+ // Load Position
+ Left := Config.getInt('Window Position X', Left);
+ Top := Config.getInt('Window Position Y', Top);
+ Width := Config.getInt('Window Width', Width);
+ Height := Config.getInt('Window Height', Height);
+ Pages.ActivePageIndex := Config.getInt('Current Page', 0);
+
+ if Left > Screen.Width then
+ Left := Screen.Width - Width;
+
+ if Top > Screen.Height then
+ Top := Screen.Height - Height;
+
+ for i := 0 to Config.getInt('EventCount', 0) - 1 do
+ begin
+ Value := Config.getString(Format('Event%u', [i]), '');
+
+ if Value <> '' then
+ cbEventName.Items.Add(Value);
+ end;
+
+ rebuildBuildMenu;
+ loadCustomButtons;
+end;
+
+{
+ Handler for WM_DESTROY
+}
+procedure TfrmMain.FormDestroy(Sender: TObject);
+begin
+ SQLiteDb.Free;
+ Tiledata.Free;
+
+ Art.Close;
+ Art.Free;
+
+ Anim.Close;
+ Anim.Free;
+
+ Maps[0].Close;
+ Maps[0].Free;
+
+ Statics[0].Close;
+ Statics[0].Free;
+
+ RadarCol.Free;
+ Hues.Free;
+
+ Config.Save;
+ Config.Free;
+
+ UpdateMutex.Free;
+
+ inherited;
+end;
+
+procedure TfrmMain.vtCategoriesGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+begin
+ if TextType = ttNormal then
+ CellText := PNode( Sender.GetNodeData( Node ) ).Name;
+end;
+
+{
+ An Item Category has been selected.
+}
+procedure TfrmMain.vtCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyData: PNode;
+ ItemData: PItemNode;
+ Query: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+ vtItems.Clear;
+ btnAddItem.Enabled := False;
+ btnTileItem.Enabled := False;
+
+ if Node = nil then
+ Exit;
+
+ MyData := Sender.GetNodeData(Node);
+ try
+ Query := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name,artid,addid,color FROM items WHERE parent = %u ORDER BY name;', [ MyData.Id ] ) );
+ while not Query.EOF do
+ begin
+ TreeNode := vtItems.AddChild( nil );
+ ItemData := vtItems.GetNodeData( TreeNode );
+
+ ItemData.Id := StrToInt( Query.Fields[0] );
+ ItemData.Name := UTF8Decode(Query.Fields[1]);
+ ItemData.ArtId := StrToInt( Query.Fields[2] );
+ ItemData.AddId := Query.Fields[3];
+ ItemData.Color := StrToIntDef( Query.Fields[4], 0);
+
+ Query.Next;
+ end;
+ Query.Free;
+ vtItems.SortTree(vtItems.Header.SortColumn, vtItems.Header.SortDirection);
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( 'Error retrieving ChildCount: ' + E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtItemsGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+var
+ MyData: PItemNode;
+begin
+ MyData := Sender.GetNodeData( Node );
+
+ case Column of
+ 0:
+ begin
+ if Length( MyData.Name ) = 0 then
+ CellText := Tiledata.getItemName( MyData.ArtId )
+ else
+ CellText := MyData.Name;
+ end;
+
+ 1: CellText := MyData.AddId;
+ end;
+end;
+
+procedure TfrmMain.vtCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+var
+ MyData: PNode;
+ RootQuery, CountQuery: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+ // Children Already Added
+ if ( Sender.ChildCount[ Node ] > 0 ) or not ( vsHasChildren in Node.States ) then
+ exit;
+
+ // Add the Children
+ MyData := Sender.GetNodeData( Node );
+
+ try
+ RootQuery := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name FROM categories WHERE type = 0 AND parent = %u ORDER BY name ASC;', [ MyData.Id ] ) );
+
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtCategories.AddChild( Node );
+ MyData := vtCategories.GetNodeData( TreeNode );
+ MyData.Id := StrToInt( RootQuery.Fields[0] );
+ MyData.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM categories WHERE type = 0 AND parent = %u', [ MyData.Id ] ) );
+
+ if StrToInt( CountQuery.Fields[0] ) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+
+ CountQuery.Free;
+
+ RootQuery.Next;
+ end;
+
+ RootQuery.Free;
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtItemsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ MyData1, MyData2: PItemNode;
+begin
+ MyData1 := Sender.GetNodeData( Node1 );
+ MyData2 := Sender.GetNodeData( Node2 );
+
+ case Column of
+ 0: Result := CompareStr( MyData1.Name, MyData2.Name );
+ 1: Result := CompareStr( MyData1.AddId, MyData2.AddId );
+ end;
+end;
+
+procedure TfrmMain.vtItemsHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+begin
+ // When changing we keep our sort direction
+ if Sender.SortColumn = Column then
+ begin
+ if Sender.SortDirection = sdAscending then
+ Sender.SortDirection := sdDescending
+ else
+ Sender.SortDirection := sdAscending;
+ exit;
+ end;
+
+ Sender.SortColumn := Column;
+ Sender.SortDirection := sdAscending;
+end;
+
+procedure TfrmMain.btnAddItemClick(Sender: TObject);
+var
+ NodeData: PItemNode;
+ Node: PVirtualNode;
+begin
+ Node := vtItems.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtItems.GetNodeData(Node);
+ if cbStatic.Checked then
+ SendCommand('static ' + NodeData.AddId, true)
+ else
+ SendCommand('add ' + NodeData.AddId, true);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.vtItemsChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyItemData: PItemNode;
+ btmap: TBitmap32;
+begin
+ // Display a Preview Item
+ if Node <> nil then
+ begin
+ MyItemData := Sender.GetNodeData(Node);
+ btmap := Art.GetTile(MyItemData.ArtId, MyItemData.Color);
+ imgItemPreview.Bitmap.SetSizeFrom(btmap);
+ imgItemPreview.Bitmap.Clear(Color32(clBtnFace));
+ btmap.DrawTo(imgItemPreview.Bitmap, 0, 0);
+ end else begin
+ imgItemPreview.Bitmap.SetSize(0, 0);
+ end;
+
+ btnAddItem.Enabled := False;
+ btnTileItem.Enabled := False;
+
+ // See if there is some selected node
+ Node := vtItems.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ btnAddItem.Enabled := True;
+ btnTileItem.Enabled := True;
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.btnRemoveItemClick(Sender: TObject);
+begin
+ SendCommand('remove', true);
+end;
+
+procedure TfrmMain.cbAlwaysOnTopClick(Sender: TObject);
+var
+ lastpage: Integer;
+begin
+ lastpage := Pages.ActivePageIndex;
+
+ if not cbAlwaysOnTop.Checked then
+ frmMain.FormStyle := fsNormal
+ else
+ frmMain.FormStyle := fsStayOnTop;
+
+ Pages.ActivePageIndex := lastpage;
+end;
+
+procedure TfrmMain.btnSaveClick(Sender: TObject);
+begin
+ Config.setBool('Always On Top', cbAlwaysOnTop.Checked);
+ Config.setString('Command Prefix', eCommandPrefix.Text);
+ Config.Save;
+end;
+
+procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
+var
+ i: Integer;
+begin
+ // Save Position
+ Config.setInt('Window Position X', Left);
+ Config.setInt('Window Position Y', Top);
+ Config.setInt('Window Width', Width);
+ Config.setInt('Window Height', Height);
+ Config.setInt('Current Page', Pages.ActivePageIndex);
+
+ // Save the history of event names
+ Config.setInt('EventCount', cbEventName.Items.Count);
+ for i := 0 to cbEventName.Items.Count - 1 do
+ begin
+ Config.setString(Format('Event%u', [i]), cbEventName.Items[i]);
+ end;
+
+ inherited;
+end;
+
+procedure TfrmMain.rebuildBuildMenu;
+var
+ i: Integer;
+begin
+ if sbBuild.ControlCount > 0 then begin
+ UpdateMutex.Enter;
+ BuildCurrentX := 8;
+ BuildCurrentY := 8 - sbBuild.VertScrollBar.Position;
+
+ for i := 0 to sbBuild.ControlCount - 1 do begin
+ // Reposition
+ sbBuild.Controls[i].Left := BuildCurrentX;
+ sbBuild.Controls[i].Top := BuildCurrentY;
+
+ Inc(BuildCurrentX, sbBuild.Controls[i].Width + 8);
+
+ // If the next button wouldn't fit anymore, go to the next row
+ if BuildCurrentX + sbBuild.Controls[i].Width + 8 > sbBuild.ClientWidth then begin
+ BuildCurrentX := 8;
+ Inc(BuildCurrentY, sbBuild.Controls[i].Height + 8);
+ end;
+ end;
+ UpdateMutex.Leave;
+ exit;
+ end;
+
+ BuildCurrentX := 8;
+ BuildCurrentY := 8;
+
+ // Add Build Table
+ addBuildButton('woodenboardse', $4ab, 'Floor');
+ addBuildButton('woodenboardsn', $4b5, 'Floor');
+
+ addBuildButton('woodenplankse', $4c7, 'Floor');
+ addBuildButton('woodenplanksn', $4d5, 'Floor');
+
+ addBuildButton('woodenlogse1', $507, 'Floor');
+ addBuildButton('woodenlogse2', $505, 'Floor');
+
+ addBuildButton('woodenlogsn1', $4c2, 'Floor');
+ addBuildButton('woodenlogsn2', $4c4, 'Floor');
+
+ addBuildButton('redfloor', $4f3, 'Floor');
+ addBuildButton('bluefloor', $4f2, 'Floor');
+
+ // Walls
+ addBuildButton('wall1', $1c, 'Wall');
+ addBuildButton('wall1small', $25, 'Wall');
+ addBuildButton('wall1tiny', $2f, 'Wall');
+
+ addBuildButton('wall2', $58, 'Wall');
+ addBuildButton('wall2small', $5f, 'Wall');
+ addBuildButton('wall2smaller', $63, 'Wall');
+ addBuildButton('wall2tiny', $69, 'Wall');
+
+ addBuildButton('wall3small', $2ce, 'Wall');
+
+ addBuildButton('wall4', $c8, 'Wall');
+ addBuildButton('wall4small', $de, 'Wall');
+
+ addBuildButton('wall5', $1d0, 'Wall');
+ addBuildButton('wall5small', $1e9, 'Wall');
+
+ addBuildButton('woodenwall1', $c, 'Wall');
+ addBuildButton('woodenwall1small', $12, 'Wall');
+ addBuildButton('woodenwall1tiny', $16, 'Wall');
+ addBuildButton('woodenwall2', $a8, 'Wall');
+ addBuildButton('woodenwall2small', $b7, 'Wall');
+ addBuildButton('woodenwall2tiny', $bf, 'Wall');
+
+ addBuildButton('plasterwall1', $12e, 'Wall');
+ addBuildButton('plasterwall1wrecked', $389, 'Wall');
+ addBuildButton('brickwall', $34, 'Wall');
+ addBuildButton('brickwallsmall', $3e, 'Wall');
+ addBuildButton('brickwalltiny', $42, 'Wall');
+
+ // Roofs
+ addBuildButton('slateroofe', $5a1, 'Roof');
+ addBuildButton('slateroofn', $595, 'Roof');
+ addBuildButton('stonetileroofe', $193d, 'Roof');
+ addBuildButton('stonetileroofn', $193e, 'Roof');
+ addBuildButton('thatchroofe', $5a8, 'Roof');
+ addBuildButton('thatchroofn', $5a5, 'Roof');
+ addBuildButton('tileroofe', $5bf, 'Roof');
+ addBuildButton('tileroofn', $5b3, 'Roof');
+ addBuildButton('woodenshinglese', $5ce, 'Roof');
+ addBuildButton('woodenshinglesn', $5c2, 'Roof');
+ addBuildButton('palmroofe', $593, 'Roof');
+ addBuildButton('palmroofn', $590, 'Roof');
+ addBuildButton('logroofe', $5fc, 'Roof');
+ addBuildButton('logroofn', $5f0, 'Roof');
+ addBuildButton('hayroofe', $26ea, 'Roof');
+ addBuildButton('hayroofn', $26da, 'Roof');
+ addBuildButton('woodenslatee', $28d8, 'Roof');
+ addBuildButton('woodenslaten', $28c8, 'Roof');
+ addBuildButton('barkroofe', $2708, 'Roof');
+ addBuildButton('barkroofn', $26f8, 'Roof');
+
+ // Carpets
+ addBuildButton('bluecarpet1a', $abe, 'Carpet');
+ addBuildButton('bluecarpet1b', $abd, 'Carpet');
+ addBuildButton('bluecarpet1c', $abf, 'Carpet');
+ addBuildButton('bluecarpet1d', $ac0, 'Carpet');
+ addBuildButton('bluecarpet2', $ad1, 'Carpet');
+ addBuildButton('bluecarpet3a', $aec, 'Carpet');
+ addBuildButton('bluecarpet3b', $aed, 'Carpet');
+ addBuildButton('browncarpet', $ada, 'Carpet');
+
+ addBuildButton('redcarpet1a', $ac8, 'Carpet');
+ addBuildButton('redcarpet1b', $ac6, 'Carpet');
+ addBuildButton('redcarpet1c', $ac7, 'Carpet');
+ addBuildButton('redcarpet2', $aeb, 'Carpet');
+ addBuildButton('grayrug', $1df7, 'Carpet');
+ addBuildButton('greenrug1', $ab3, 'Carpet');
+ addBuildButton('greenrug2', $1dea, 'Carpet');
+ addBuildButton('greenrug3', $1de9, 'Carpet');
+
+ addBuildButton('bearskinn', $1e37, 'Carpet');
+ addBuildButton('bearskine', $1e41, 'Carpet');
+ addBuildButton('polarskinn', $1e4a, 'Carpet');
+ addBuildButton('polarskine', $1e54, 'Carpet');
+
+ addBuildButton('stonefountain', $1741, 'Fountains');
+ addBuildButton('sandstonefountain', $19d3, 'Fountains');
+end;
+
+procedure TfrmMain.pbMapPaintBuffer(Sender: TObject);
+var
+ x, y: Integer;
+ mapx, mapy: Integer;
+ MapLeft, MapTop: Integer;
+ MapCell: TMapCell;
+ StaticBlock: TStaticBlock;
+ i: Integer;
+ RelX, RelY: Byte;
+ HighestZ: Shortint;
+ Map: TMapReader;
+ Static: TStaticReader;
+ Width, Height: Word;
+ Position: String;
+ TextY: Integer;
+ Color: TColor;
+begin
+ MapLeft := - (pbMap.Width div 2);
+ MapTop := - (pbMap.Height div 2);
+
+ if MapCenterMap > 4 then
+ exit;
+
+ Width := Maps[MapCenterMap].getWidth * 8;
+ Height := Maps[MapCenterMap].getHeight * 8;
+
+ Map := Maps[MapCenterMap];
+ Static := Statics[MapCenterMap];
+
+ pbMap.Buffer.Clear(clBlack32);
+ for x := 0 to pbMap.Width do
+ begin
+ for y := 0 to pbMap.Height do
+ begin
+ mapx := Integer(MapCenterX) + x + MapLeft;
+ mapy := Integer(MapCenterY) + y + MapTop;
+
+ if (mapx >= Width) or (mapy >= Height) then begin
+ pbMap.Buffer.PixelS[x, y] := clBlack32;
+ continue;
+ end;
+
+ if (mapx >= 0) and (mapy >= 0) then begin
+ Map.ReadCell(mapx, mapy, MapCell);
+ pbMap.Buffer.PixelS[x, y] := RadarCol.GetLandColor(MapCell.Id);
+
+ RelX := mapx mod 8;
+ RelY := mapy mod 8;
+ HighestZ := MapCell.Height;
+ Static.ReadBlock(mapx div 8, mapy div 8, StaticBlock);
+ for i := 0 to Length(StaticBlock) - 1 do begin
+ if (StaticBlock[i].X = RelX) and (StaticBlock[i].Y = RelY)
+ and (StaticBlock[i].Z >= HighestZ) then begin
+ if StaticBlock[i].Hue = 0 then
+ pbMap.Buffer.PixelS[x, y] :=
+ RadarCol.GetItemColor(StaticBlock[i].Id)
+ else begin
+ // A little more complicated
+ //pbMap.Buffer.PixelS[x, y] := Color32(Color15to24(StaticBlock[i].Hue));
+ Color := RadarCol.GetItemColor(StaticBlock[i].Id);
+ Color := Hues.translateColor(StaticBlock[i].Hue, Color);
+ pbMap.Buffer.PixelS[x, y] := Color;
+ end;
+
+ HighestZ := StaticBlock[i].Z;
+ end;
+ end;
+
+ if (Cardinal(mapx) = MapCenterX) and
+ (Cardinal(mapy) = MapCenterY) then begin
+ MapCenterZ := HighestZ;
+ pbMap.Buffer.PixelS[x, y] := clWhite32;
+ continue;
+ end;
+ end else begin
+ pbMap.Buffer.PixelS[x, y] := clGray32;
+ end;
+ end;
+ end;
+
+ // Show the current location
+ Position := Format('%u,%u,%d,%u', [MapCenterX, MapCenterY,
+ MapCenterZ, MapCenterMap]);
+ TextY := pbMap.Height - 2 - pbMap.Buffer.TextHeight(Position);
+ pbMap.Buffer.Font.Color := clWhite;
+ pbMap.Buffer.Textout(2, TextY, Position);
+end;
+
+procedure TfrmMain.pbMapMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+var
+ RelX, RelY: Integer;
+ Width, Height: Cardinal;
+begin
+ if MapCenterMap > 4 then
+ exit;
+
+ if Button <> mbLeft then
+ exit;
+
+ Width := Maps[MapCenterMap].getWidth * 8;
+ Height := Maps[MapCenterMap].getHeight * 8;
+
+ RelX := X - pbMap.Width div 2;
+ RelY := y - pbMap.Height div 2;
+
+ if Integer(MapCenterX) + RelX >= 0 then begin
+ MapCenterX := Integer(MapCenterX) + RelX;
+ end else begin
+ MapCenterX := 0;
+ end;
+
+ if Integer(MapCenterY) + RelY >= 0 then begin
+ MapCenterY := Integer(MapCenterY) + RelY;
+ end else begin
+ MapCenterY := 0;
+ end;
+
+ if MapCenterX >= Width then
+ MapCenterX := Width - 1;
+
+ if MapCenterY >= Height then
+ MapCenterY := Height - 1;
+
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.vtLocCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+var
+ MyData: PNode;
+ RootQuery, CountQuery: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+ // Children Already Added
+ if ( Sender.ChildCount[ Node ] > 0 ) or not ( vsHasChildren in Node.States ) then
+ exit;
+
+ // Add the Children
+ MyData := Sender.GetNodeData( Node );
+
+ try
+ RootQuery := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name FROM locationcategories WHERE type = 0 AND parent = %u ORDER BY name ASC;', [ MyData.Id ] ) );
+
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtLocCategories.AddChild( Node );
+ MyData := vtLocCategories.GetNodeData( TreeNode );
+ MyData.Id := StrToInt( RootQuery.Fields[0] );
+ MyData.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM locationcategories WHERE type = 0 AND parent = %u', [ MyData.Id ] ) );
+
+ if StrToInt( CountQuery.Fields[0] ) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+
+ CountQuery.Free;
+
+ RootQuery.Next;
+ end;
+
+ RootQuery.Free;
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+
+procedure TfrmMain.vtLocCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyData: PNode;
+ LocationData: PLocationNode;
+ Query: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+
+
+ vtLocItems.Clear;
+ if Node = nil then
+ Exit;
+ MyData := Sender.GetNodeData(Node);
+ try
+ Query := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name,posx,posy,posz,posmap,location FROM locations WHERE parent = %u ORDER BY name;', [ MyData.Id ] ) );
+ while not Query.EOF do
+ begin
+ TreeNode := vtLocItems.AddChild( nil );
+ LocationData := vtLocItems.GetNodeData(TreeNode);
+
+ LocationData.Id := StrToInt( Query.Fields[0] );
+ LocationData.Name := UTF8Decode(Query.Fields[1]);
+ LocationData.PosX := StrToInt(Query.Fields[2]);
+ LocationData.PosY := StrToInt(Query.Fields[3]);
+ LocationData.PosZ := StrToInt(Query.Fields[4]);
+ LocationData.PosMap := StrToInt(Query.Fields[5]);
+ LocationData.LocId := Query.Fields[6];
+ Query.Next;
+ end;
+ Query.Free;
+ vtLocItems.SortTree(vtLocItems.Header.SortColumn, vtLocItems.Header.SortDirection);
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( 'Error retrieving ChildCount: ' + E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtLocItemsGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+var
+ MyData: PLocationNode;
+begin
+ myData := Sender.GetNodeData( Node );
+
+ case Column of
+ 0:
+ begin
+ CellText := MyData.Name;
+ end;
+ end;
+
+end;
+
+procedure TfrmMain.vtLocItemsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ MyData1, MyData2: PLocationNode;
+begin
+ MyData1 := Sender.GetNodeData( Node1 );
+ MyData2 := Sender.GetNodeData( Node2 );
+ Result := CompareStr( MyData1.Name, MyData2.Name );
+end;
+
+procedure TfrmMain.vtLocItemsHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+begin
+ // When changing we keep our sort direction
+ if Sender.SortDirection = sdAscending then
+ Sender.SortDirection := sdDescending
+ else
+ Sender.SortDirection := sdAscending;
+end;
+
+procedure TfrmMain.vtLocItemsChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ LocationData: PLocationNode;
+begin
+ // Display a Preview Item
+ if Node <> nil then begin
+ LocationData := Sender.GetNodeData(Node);
+ MapCenterX := LocationData.PosX;
+ MapCenterY := LocationData.PosY;
+ MapCenterZ := LocationData.PosZ;
+ MapCenterMap := LocationData.PosMap;
+ pbMap.Invalidate;
+ end;
+end;
+
+procedure TfrmMain.Go1Click(Sender: TObject);
+begin
+ SendCommand(Format('go %u,%u,%d,%u',
+ [MapCenterX, MapCenterY, MapCenterZ, MapCenterMap]));
+end;
+
+procedure TfrmMain.btnSendClick(Sender: TObject);
+begin
+ SendCommand(Format('send %u,%u,%d,%u',
+ [MapCenterX, MapCenterY, MapCenterZ, MapCenterMap]));
+end;
+
+procedure TfrmMain.btnCmdAllmoveClick(Sender: TObject);
+begin
+ SendCommand('allmove');
+end;
+
+procedure TfrmMain.btnCmdAllshowClick(Sender: TObject);
+begin
+ SendCommand('allshow');
+end;
+
+procedure TfrmMain.btnCmdInvisibleClick(Sender: TObject);
+begin
+ SendCommand('invis');
+end;
+
+procedure TfrmMain.btnCmdStaffClick(Sender: TObject);
+begin
+ SendCommand('staff');
+end;
+
+procedure TfrmMain.btnCmdInvulClick(Sender: TObject);
+begin
+ SendCommand('invul');
+end;
+
+procedure TfrmMain.btnCmdShutdownClick(Sender: TObject);
+begin
+ if Application.MessageBox('Do you really want to close the Wolfpack server?',
+ 'Shutdown', MB_YESNO+MB_ICONQUESTION) = IDYES then
+ SendCommand('shutdown');
+end;
+
+procedure TfrmMain.btnCmdReloadAllClick(Sender: TObject);
+begin
+ SendCommand('reload all');
+end;
+
+procedure TfrmMain.btnCmdReloadConfigClick(Sender: TObject);
+begin
+ SendCommand('reload configuration');
+end;
+
+procedure TfrmMain.btnCmdReloadAccountsClick(Sender: TObject);
+begin
+ SendCommand('reload accounts');
+end;
+
+procedure TfrmMain.btnCmdReloadPythonClick(Sender: TObject);
+begin
+ SendCommand('reload python');
+end;
+
+procedure TfrmMain.btnCmdReloadScriptsClick(Sender: TObject);
+begin
+ SendCommand('reload scripts');
+end;
+
+procedure TfrmMain.btnCmdDyeClick(Sender: TObject);
+begin
+ SendCommand(Format('dye %u', [StrToIntDef(eItemHue.Text, 0)]), True);
+end;
+
+procedure TfrmMain.pbHuePreviewPaintBuffer(Sender: TObject);
+var
+ i: Integer;
+ Width: Integer;
+ Hue: Word;
+begin
+ Hue := StrToIntDef(eItemHue.Text, 0);
+
+ if Hue = 0 then begin
+ pbHuePreview.Buffer.Clear(clGray32);
+ exit;
+ end;
+
+ Width := Ceil(pbHuePreview.Width / 32.0);
+ for i := 0 to 31 do
+ begin
+ pbHuePreview.Buffer.FillRect(i * Width, 0, (i + 1) * Width,
+ pbHuePreview.Height, Hues.getColor(Hue, i));
+ end;
+end;
+
+procedure TfrmMain.eItemHueChange(Sender: TObject);
+begin
+ pbHuePreview.Invalidate;
+end;
+
+procedure TfrmMain.btnChangeItemHueClick(Sender: TObject);
+begin
+ frmChooseHue.ShowModal;
+
+ if frmChooseHue.ModalResult = mrOk then
+ begin
+ eItemHue.Text := '0x' + IntToHex(frmChooseHue.ColorId, 0);
+ pbHuePreview.Invalidate;
+ end;
+end;
+
+procedure TfrmMain.btnCmdDupeClick(Sender: TObject);
+begin
+ SendCommand('dupe', True);
+end;
+
+procedure TfrmMain.btnCmdInfoClick(Sender: TObject);
+begin
+ SendCommand('info', True);
+end;
+
+procedure TfrmMain.btnCmdRemoveClick(Sender: TObject);
+begin
+ SendCommand('remove', True);
+end;
+
+procedure TfrmMain.btnCmdLockClick(Sender: TObject);
+begin
+ SendCommand('lock', True);
+end;
+
+procedure TfrmMain.btnCmdNukeClick(Sender: TObject);
+begin
+ SendCommand('nuke', True);
+end;
+
+procedure TfrmMain.btnCmdItemSetClick(Sender: TObject);
+begin
+ SendCommand(Format('set %s %s', [cbItemProperty.Text, eItemPropValue.Text]), True);
+end;
+
+procedure TfrmMain.btnCmdItemShowClick(Sender: TObject);
+begin
+ SendCommand(Format('show %s', [cbItemProperty.Text]), True);
+end;
+
+procedure TfrmMain.cbItemPropertyChange(Sender: TObject);
+begin
+ btnCmdItemSet.Enabled := Length(cbItemProperty.Text) <> 0;
+ btnCmdItemShow.Enabled := Length(cbItemProperty.Text) <> 0;
+end;
+
+procedure TfrmMain.btnCmdItemTileColorClick(Sender: TObject);
+begin
+ SendCommand('tilecolor ' + eItemHue.Text, true);
+end;
+
+procedure TfrmMain.btnTagInfoClick(Sender: TObject);
+begin
+ SendCommand('taginfo', True);
+end;
+
+procedure TfrmMain.eTagNameChange(Sender: TObject);
+begin
+ btnTagSet.Enabled := Length(eTagName.Text) > 0;
+ btnTagShow.Enabled := btnTagSet.Enabled;
+ btnTagDelete.Enabled := btnTagSet.Enabled;
+end;
+
+procedure TfrmMain.btnTagSetClick(Sender: TObject);
+var
+ TagType: String;
+begin
+ TagType := 'string';
+ if cbTagType.ItemIndex = 1 then
+ TagType := 'int'
+ else if cbTagType.ItemIndex = 2 then
+ TagType := 'float';
+
+ if AnsiStrPos(PAnsiChar(eTagName.Text), ' ') <> nil then begin
+ Application.MessageBox('Tag names may not contain spaces.', 'Error',
+ MB_ICONERROR+MB_OK);
+ exit;
+ end;
+
+ SendCommand(format('settag %s %s %s',
+ [eTagName.Text, TagType, eTagValue.Text]), True);
+end;
+
+procedure TfrmMain.btnTagShowClick(Sender: TObject);
+begin
+ if AnsiStrPos(PAnsiChar(eTagName.Text), ' ') <> nil then begin
+ Application.MessageBox('Tag names may not contain spaces.', 'Error',
+ MB_ICONERROR+MB_OK);
+ exit;
+ end;
+
+ SendCommand(format('gettag %s', [eTagName.Text]), True);
+end;
+
+procedure TfrmMain.btnTagDeleteClick(Sender: TObject);
+begin
+ if AnsiStrPos(PAnsiChar(eTagName.Text), ' ') <> nil then begin
+ Application.MessageBox('Tag names may not contain spaces.', 'Error',
+ MB_ICONERROR+MB_OK);
+ exit;
+ end;
+
+ SendCommand(format('deltag %s', [eTagName.Text]), True);
+end;
+
+procedure TfrmMain.btnCmdSendOtherClick(Sender: TObject);
+begin
+ SendCommand('send', True);
+end;
+
+procedure TfrmMain.Button2Click(Sender: TObject);
+begin
+ SendCommand('tele', True);
+end;
+
+procedure TfrmMain.btnCmdMoveClick(Sender: TObject);
+begin
+ SendCommand(format('move %d,%d,%d',
+ [StrToIntDef(eMoveX.Text, 0), StrToIntDef(eMoveY.Text, 0),
+ StrToIntDef(eMoveZ.Text, 0)]), True);
+end;
+
+procedure TfrmMain.btnCmdMoveUpClick(Sender: TObject);
+begin
+ SendCommand('move 0,0,1', True);
+end;
+
+procedure TfrmMain.btnCmdMoveDownClick(Sender: TObject);
+begin
+ SendCommand('move 0,0,-1', True);
+end;
+
+procedure TfrmMain.btnTileItemClick(Sender: TObject);
+var
+ NodeData: PItemNode;
+ Node: PVirtualNode;
+ Ids: String;
+begin
+ Node := vtItems.RootNode.FirstChild;
+ Ids := '';
+
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtItems.GetNodeData(Node);
+ if Length(Ids) > 0 then
+ Ids := Ids + ',' + NodeData.AddId
+ else
+ Ids := NodeData.AddId;
+ end;
+ Node := Node.NextSibling;
+ end;
+
+ SendCommand(format('tile %d %s',
+ [StrToIntDef(eZLevel.Text, 0), Ids]), True);
+end;
+
+procedure TfrmMain.btnCmdShowEventlistClick(Sender: TObject);
+begin
+ SendCommand('show scriptlist', True);
+end;
+
+procedure TfrmMain.eEventNameChange(Sender: TObject);
+begin
+ btnCmdAddEvent.Enabled := Length(cbEventName.Text) > 0;
+ btnCmdRemoveEvent.Enabled := Length(cbEventName.Text) > 0;
+end;
+
+procedure TfrmMain.btnCmdAddEventClick(Sender: TObject);
+var
+ i: Integer;
+begin
+ SendCommand(format('addscript %s', [cbEventName.Text]), True);
+
+ // Add the text to the history if it's not already in there
+ for i := 0 to cbEventName.Items.Count - 1 do
+ begin
+ if cbEventName.Items[i] = cbEventName.Text then
+ exit;
+ end;
+
+ cbEventName.Items.Add(cbEventName.Text);
+end;
+
+procedure TfrmMain.btnCmdRemoveEventClick(Sender: TObject);
+var
+ i: Integer;
+begin
+ SendCommand(format('removescript %s', [cbEventName.Text]), True);
+
+ // Add the text to the history if it's not already in there
+ for i := 0 to cbEventName.Items.Count - 1 do
+ begin
+ if cbEventName.Items[i] = cbEventName.Text then
+ exit;
+ end;
+
+ cbEventName.Items.Add(cbEventName.Text);
+end;
+
+procedure TfrmMain.btnCmdWhereClick(Sender: TObject);
+begin
+ SendCommand('where');
+end;
+
+procedure TfrmMain.btnCmdServertimeClick(Sender: TObject);
+begin
+ SendCommand('servertime');
+end;
+
+procedure TfrmMain.vtNpcCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+var
+ MyData: PNode;
+ RootQuery, CountQuery: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+ // Children Already Added
+ if ( Sender.ChildCount[ Node ] > 0 ) or not ( vsHasChildren in Node.States ) then
+ exit;
+
+ // Add the Children
+ MyData := Sender.GetNodeData( Node );
+
+ try
+ RootQuery := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name FROM npccategories WHERE type = 0 AND parent = %u ORDER BY name ASC;', [ MyData.Id ] ) );
+
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtNpcCategories.AddChild( Node );
+ MyData := vtNpcCategories.GetNodeData( TreeNode );
+ MyData.Id := StrToInt( RootQuery.Fields[0] );
+ MyData.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM npccategories WHERE type = 0 AND parent = %u', [ MyData.Id ] ) );
+
+ if StrToInt( CountQuery.Fields[0] ) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+
+ CountQuery.Free;
+
+ RootQuery.Next;
+ end;
+
+ RootQuery.Free;
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtNpcCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyData: PNode;
+ ItemData: PNpcNode;
+ Query, SubQuery: TSQLiteTable;
+ TreeNode: PVirtualNode;
+ i: Integer;
+begin
+ vtNpcs.Clear;
+ btnAddNpc.Enabled := False;
+ btnNpcSpawn.Enabled := False;
+
+ if Node = nil then
+ Exit;
+
+ MyData := Sender.GetNodeData(Node);
+ try
+ Query := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name,bodyid,addid,skin FROM npcs WHERE parent = %u ORDER BY name;', [ MyData.Id ] ) );
+ while not Query.EOF do
+ begin
+ TreeNode := vtNpcs.AddChild( nil );
+ ItemData := vtNpcs.GetNodeData( TreeNode );
+
+ ItemData.Id := StrToInt( Query.Fields[0] );
+ ItemData.Name := UTF8Decode(Query.Fields[1]);
+ ItemData.BodyId := StrToInt( Query.Fields[2] );
+ ItemData.AddId := Query.Fields[3];
+ ItemData.Skin := StrToIntDef( Query.Fields[4], 0);
+
+ SubQuery := TSQLiteTable.Create(SQLiteDb, Format('SELECT layer,artid,color FROM npcequipment WHERE id = %u ORDER BY layer DESC', [ ItemData.Id ] ) );
+
+ while not SubQuery.Eof do
+ begin
+ i := Length(ItemData.Equipment);
+ SetLength(ItemData.Equipment, i + 1);
+ ItemData.Equipment[i].Layer := StrToInt( SubQuery.Fields[0] );
+ ItemData.Equipment[i].Anim := StrToInt( SubQuery.Fields[1] );
+ ItemData.Equipment[i].Color := StrToInt( SubQuery.Fields[2] );
+ SubQuery.Next;
+ end;
+
+ SubQuery.Free;
+
+ Query.Next;
+ end;
+ Query.Free;
+ vtNpcs.SortTree(vtNpcs.Header.SortColumn, vtNpcs.Header.SortDirection);
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( 'Error retrieving ChildCount: ' + E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtNpcsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ MyData1, MyData2: PNpcNode;
+begin
+ MyData1 := Sender.GetNodeData( Node1 );
+ MyData2 := Sender.GetNodeData( Node2 );
+
+ case Column of
+ 0: Result := CompareStr( MyData1.Name, MyData2.Name );
+ 1: Result := CompareStr( MyData1.AddId, MyData2.AddId );
+ end;
+
+end;
+
+procedure TfrmMain.vtNpcsGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+var
+ MyData: PNpcNode;
+begin
+ MyData := Sender.GetNodeData( Node );
+
+ case Column of
+ 0: CellText := MyData.Name;
+ 1: CellText := MyData.AddId;
+ end;
+end;
+
+procedure TfrmMain.btnRemoveNpcClick(Sender: TObject);
+begin
+ SendCommand('remove', true);
+end;
+
+procedure TfrmMain.btnAddNpcClick(Sender: TObject);
+var
+ NodeData: PNpcNode;
+ Node: PVirtualNode;
+begin
+ Node := vtNpcs.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtNpcs.GetNodeData(Node);
+ SendCommand('add ' + NodeData.AddId, true);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.vtNpcsChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyItemData: PNpcNode;
+ frames: TAnimation;
+ i, j: Integer;
+
+ const LayerOrder: Array[0..21] of Byte = ( 20, 5, 4, 3, 24, 23, 13, 19, 17, 22, 12, 14, 8, 7, 1, 2, 10, 16, 11, 18, 6, 21 );
+begin
+ animtimer.Enabled := false;
+
+ for i := 0 to Length(npcPreview) - 1 do
+ npcPreview[i].Free;
+
+ SetLength(npcPreview, 0);
+
+ // Display a Preview Item
+ if Node <> nil then
+ begin
+ MyItemData := Sender.GetNodeData(Node);
+
+ frames := Anim.GetFrames(MyItemData.BodyId, 1, MyItemData.Skin);
+
+ if frames <> nil then begin
+ SetLength(npcPreview, 1);
+ npcPreview[0] := frames;
+
+ // Add Equipment
+ for j := 0 to Length(LayerOrder) - 1 do begin
+ for i := 0 to Length(MyItemData.Equipment) - 1 do begin
+ if MyItemData.Equipment[i].Layer = LayerOrder[j] then begin
+ frames := Anim.GetFrames(MyItemData.Equipment[i].Anim, 1, MyItemData.Equipment[i].Color);
+ if frames <> nil then begin
+ SetLength(npcPreview, Length(npcPreview) + 1);
+ npcPreview[Length(npcPreview) - 1] := frames;
+ end;
+ end;
+ end;
+ end;
+
+ npcPreviewFrame := 0;
+ pbNpcPreview.Invalidate;
+ animtimer.Interval := npcPreview[0].frameDelay;
+ animtimer.Enabled := true;
+ end;
+
+ end else begin
+ pbNpcPreview.Invalidate;
+ end;
+
+ btnAddNpc.Enabled := False;
+ btnNpcSpawn.Enabled := False;
+
+ // See if there is some selected node
+ Node := vtNpcs.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ btnAddNpc.Enabled := True;
+ btnNpcSpawn.Enabled := True;
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.vtNpcsHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+begin
+ // When changing we keep our sort direction
+ if Sender.SortColumn = Column then
+ begin
+ if Sender.SortDirection = sdAscending then
+ Sender.SortDirection := sdDescending
+ else
+ Sender.SortDirection := sdAscending;
+ exit;
+ end;
+
+ Sender.SortColumn := Column;
+ Sender.SortDirection := sdAscending;
+end;
+
+procedure TFrmMain.pixelCombine(F: TColor32; var B: TColor32; M: TColor32);
+begin
+
+end;
+
+procedure TfrmMain.pbNpcPreviewPaintBuffer(Sender: TObject);
+var
+ pb: TPaintBox32;
+ totalHeight, totalWidth, i, xpos, ypos: Integer;
+ frame: PAnimFrame;
+begin
+ if not (Sender is TPaintBox32) then
+ exit;
+
+ pb := Sender as TPaintBox32;
+ pb.Buffer.Clear(clGray32);
+
+ // Draw Centered
+ if (npcPreview <> nil) and (length(npcPreview) > 0) then begin
+ // Measure Total Height and Width
+ totalHeight := 0;
+ totalWidth := 0;
+
+ for i := 0 to Length(npcPreview) - 1 do begin
+ totalHeight := Max(npcPreview[i].getTotalHeight, totalHeight);
+ totalWidth := Max(npcPreview[i].getTotalWidth, totalWidth);
+ end;
+
+ xpos := (pb.ClientWidth div 2);
+ ypos := (pb.ClientHeight div 2) + (totalHeight div 2);
+
+ for i := 0 to Length(npcPreview) - 1 do begin
+ frame := npcPreview[i].getFrame(npcPreviewFrame);
+
+ if frame <> nil then begin
+ pb.Buffer.Draw(xpos - frame.CenterX, ypos - frame.image.height - frame.CenterY, frame.Image);
+ end;
+ end;
+ end;
+end;
+
+procedure TfrmMain.animtimerTimer(Sender: TObject);
+begin
+ if (npcPreview <> nil) and (npcPreview[0].frameCount > 0) then begin
+ npcPreviewFrame := (npcPreviewFrame + 1) mod npcPreview[0].frameCount;
+ pbNpcPreview.Invalidate;
+ end;
+end;
+
+procedure TfrmMain.loadMultis;
+var
+ Query: TSQLiteTable;
+ Node: PVirtualNode;
+ Data: PMultiNode;
+begin
+ try
+ Query := TSQLiteTable.Create(SQLiteDb, 'SELECT id,name,addid,multiid FROM multis;');
+
+ while not Query.EOF do begin
+ Node := vtMultis.AddChild(nil);
+ Data := vtMultis.GetNodeData(Node);
+
+ Data.Id := StrToInt(Query.Fields[0]);
+ Data.Name := UTF8Decode(Query.Fields[1]);
+ Data.AddId := Query.Fields[2];
+ Data.MultiId := StrToInt(Query.Fields[0]);
+
+ Query.Next;
+ end;
+
+ Query.Free;
+ vtMultis.SortTree(vtMultis.Header.SortColumn, vtMultis.Header.SortDirection);
+ except
+ on E: Exception do
+ Application.MessageBox(PChar(E.Message), 'Error', MB_OK+MB_ICONERROR );
+ end;
+end;
+
+procedure TfrmMain.vtMultisGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+var
+ MyData: PMultiNode;
+begin
+ MyData := Sender.GetNodeData( Node );
+
+ case Column of
+ 0: CellText := MyData.Name;
+ 1: CellText := MyData.AddId;
+ end;
+end;
+
+procedure TfrmMain.vtMultisCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ MyData1, MyData2: PMultiNode;
+begin
+ MyData1 := Sender.GetNodeData( Node1 );
+ MyData2 := Sender.GetNodeData( Node2 );
+
+ case Column of
+ 0: Result := CompareStr( MyData1.Name, MyData2.Name );
+ 1: Result := CompareStr( MyData1.AddId, MyData2.AddId );
+ end;
+end;
+
+procedure TfrmMain.vtMultisHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+begin
+ // When changing we keep our sort direction
+ if Sender.SortColumn = Column then
+ begin
+ if Sender.SortDirection = sdAscending then
+ Sender.SortDirection := sdDescending
+ else
+ Sender.SortDirection := sdAscending;
+ exit;
+ end;
+
+ Sender.SortColumn := Column;
+ Sender.SortDirection := sdAscending;
+end;
+
+procedure TfrmMain.vtMultisChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+begin
+ if Sender.SelectedCount < 1 then begin
+ btnAddMulti.Enabled := False;
+ btnPreviewMulti.Enabled := False;
+ end else begin
+ btnAddMulti.Enabled := True;
+ btnPreviewMulti.Enabled := True;
+ end;
+end;
+
+procedure TfrmMain.btnPreviewMultiClick(Sender: TObject);
+begin
+ Application.MessageBox('Not yet implemented', 'Error', MB_OK+MB_ICONERROR);
+end;
+
+procedure TfrmMain.btnAddMultiClick(Sender: TObject);
+var
+ NodeData: PMultiNode;
+ Node: PVirtualNode;
+begin
+ Node := vtMultis.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtMultis.GetNodeData(Node);
+ SendCommand('add ' + NodeData.AddId, true);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.Felucca1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 0;
+ Felucca1.Checked := True;
+ Trammel1.Checked := False;
+ Ilshenar1.Checked := False;
+ Malas1.Checked := False;
+ SamuraiEmpire1.Checked := False;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.Trammel1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 1;
+ Felucca1.Checked := False;
+ Trammel1.Checked := True;
+ Ilshenar1.Checked := False;
+ Malas1.Checked := False;
+ SamuraiEmpire1.Checked := False;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.Ilshenar1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 2;
+ Felucca1.Checked := False;
+ Trammel1.Checked := False;
+ Ilshenar1.Checked := True;
+ Malas1.Checked := False;
+ SamuraiEmpire1.Checked := False;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.Malas1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 3;
+ Felucca1.Checked := False;
+ Trammel1.Checked := False;
+ Ilshenar1.Checked := False;
+ Malas1.Checked := True;
+ SamuraiEmpire1.Checked := False;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.Center1Click(Sender: TObject);
+begin
+ frmCenter.Show;
+ frmCenter.X.Text := IntToStr(MapCenterX);
+ frmCenter.Y.Text := IntToStr(MapCenterY);
+ frmCenter.Map.ItemIndex := MapCenterMap;
+end;
+
+procedure TfrmMain.SamuraiEmpire1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 4;
+ Felucca1.Checked := False;
+ Trammel1.Checked := False;
+ Ilshenar1.Checked := False;
+ Malas1.Checked := False;
+ SamuraiEmpire1.Checked := True;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.btnStaticItemClick(Sender: TObject);
+var
+ NodeData: PItemNode;
+ Node: PVirtualNode;
+begin
+ Node := vtItems.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtItems.GetNodeData(Node);
+ SendCommand('static ' + NodeData.AddId, true);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+
+end;
+
+procedure TfrmMain.btnMapOverviewClick(Sender: TObject);
+begin
+ if not frmOverview.Generating then begin
+ frmOverview.showMap(MapCenterMap);
+ frmOverview.Show;
+ end;
+end;
+
+function IsInParent(Control: TWinControl): Boolean;
+begin
+ if Control is TCustomForm then
+ Result := True
+ else if Control.Parent <> nil then
+ Result := IsInParent(Control.Parent)
+ else
+ Result := False;
+end;
+
+procedure TfrmMain.ontopTimerTimer(Sender: TObject);
+begin
+ // If one of the forms is active, skip this code
+ if frmMain.Active or frmCenter.Active or frmOverview.Active then
+ exit;
+
+ if IsInParent(Screen.ActiveControl) then
+ exit;
+
+ if cbAlwaysOnTop.Checked then begin
+ if frmMain.Visible then begin
+ SetWindowPos(frmMain.Handle, HWND_TOPMOST, 0, 0, 0, 0, 3 or SWP_NOACTIVATE);
+ end;
+
+ if frmCenter.Visible then begin
+ SetWindowPos(frmCenter.Handle, HWND_TOPMOST, 0, 0, 0, 0, 3 or SWP_NOACTIVATE);
+ end;
+
+ if frmOverview.Visible then begin
+ SetWindowPos(frmOverview.Handle, HWND_TOPMOST, 0, 0, 0, 0, 3 or SWP_NOACTIVATE);
+ end;
+ end;
+end;
+
+procedure TfrmMain.btnNpcSpawnClick(Sender: TObject);
+var
+ NodeData: PNpcNode;
+ Node: PVirtualNode;
+begin
+ Node := vtNpcs.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtNpcs.GetNodeData(Node);
+ SendCommand(Format('spawn %s %s %s %s', [NodeData.AddId, eSpawnRadius.Text, eSpawnMin.Text, eSpawnMax.Text]), True);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.eSpawnRadiusExit(Sender: TObject);
+begin
+ Config.setString('SpawnRadius', eSpawnRadius.Text);
+ Config.Save;
+end;
+
+procedure TfrmMain.eSpawnMinExit(Sender: TObject);
+begin
+ Config.setString('SpawnMin', eSpawnMin.Text);
+ Config.Save;
+end;
+
+procedure TfrmMain.eSpawnMaxExit(Sender: TObject);
+begin
+ Config.setString('SpawnMax', eSpawnMax.Text);
+ Config.Save;
+end;
+
+procedure TfrmMain.btnRegionsClick(Sender: TObject);
+begin
+ frmRegions.Show;
+end;
+
+procedure TfrmMain.Button1Click(Sender: TObject);
+begin
+ frmPatternColor.Show;
+end;
+
+procedure TFrmMain.addBuildButton(Id: String; ItemId: Word; Text: String);
+var
+ BitBtn: TBitBtn;
+begin
+ BitBtn := TBitBtn.Create(sbBuild);
+ BitBtn.SetBounds(BuildCurrentX, BuildCurrentY, 70, 120);
+// BitBtn.Caption := Text;
+ BitBtn.Glyph.Assign(Art.GetTile(ItemId));
+ BitBtn.Layout := blGlyphTop;
+ BitBtn.Hint := id;
+ BitBtn.OnClick := clickBuildButton;
+ sbBuild.InsertControl(BitBtn);
+
+ Inc(BuildCurrentX, 70 + 8);
+
+ // If the next button wouldn't fit anymore, go to the next row
+ if BuildCurrentX + 70 + 8 > sbBuild.ClientWidth then begin
+ BuildCurrentX := 8;
+ Inc(BuildCurrentY, 120 + 8);
+ end;
+end;
+
+procedure TfrmMain.sbBuildResize(Sender: TObject);
+begin
+ rebuildBuildMenu;
+end;
+
+procedure TfrmMain.clickBuildButton(Sender: TObject);
+var
+ BitBtn: TBitBtn;
+begin
+ if not (Sender is TBitBtn) then
+ exit;
+
+ BitBtn := Sender as TBitBtn;
+ SendCommand(Format('build %s %d', [BitBtn.Hint, StrToIntDef(cbBuildZ.Text, 0)]), True);
+end;
+
+procedure TfrmMain.sbBuildClick(Sender: TObject);
+begin
+ sbBuild.SetFocus;
+end;
+
+procedure TfrmMain.sbBuildMouseWheelDown(Sender: TObject;
+ Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
+begin
+ SendMessage(sbBuild.Handle, WM_VSCROLL, SB_LINEDOWN, 0);
+ Handled := True;
+end;
+
+procedure TfrmMain.sbBuildMouseWheelUp(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+begin
+ SendMessage(sbBuild.Handle, WM_VSCROLL, SB_LINEUP, 0);
+ Handled := True;
+end;
+
+procedure TfrmMain.reorderCustomButtons;
+var
+ currentx, currenty, i: Integer;
+begin
+ currentx := 8;
+ currenty := 8;
+
+ for i := 0 to tsCustom.ControlCount - 1 do begin
+ tsCustom.Controls[i].Left := currentx;
+ tsCustom.Controls[i].Top := currenty;
+ Inc(currenty, tsCustom.Controls[i].Height + 8);
+
+ if CurrentY + tsCustom.Controls[i].Height > tsCustom.ClientHeight then begin
+ CurrentY := 8;
+ inc(CurrentX, tsCustom.Controls[i].Width + 8);
+ end;
+ end;
+end;
+
+procedure TfrmMain.loadCustomButtons;
+var
+ count, i: Integer;
+ command: String;
+ button: TButton;
+begin
+ count := Config.getInt('CustomButtonCount', 0);
+
+ // Load the custom buttons
+ for i := 0 to count - 1 do begin
+ command := Config.getString(Format('CustomButton%u', [i]), '');
+
+ button := TButton.Create(tsCustom);
+ button.SetBounds(0, 0, 129, 25);
+ button.Caption := command;
+ button.OnClick := customButtonClick;
+ button.OnMouseDown := customButtonMouseDown;
+ button.PopupMenu := btnCustomPopup;
+ button.Parent := tsCustom;
+ end;
+
+ // If no button at all was loaded, create an empty one to make
+ // adding buttons possible. (RightClick -> Add Button)
+ if Count = 0 then begin
+ button := TButton.Create(tsCustom);
+ button.SetBounds(0, 0, 129, 25);
+ button.Caption := '';
+ button.OnClick := customButtonClick;
+ button.OnMouseDown := customButtonMouseDown;
+ button.PopupMenu := btnCustomPopup;
+ button.Parent := tsCustom;
+ end;
+
+ reorderCustomButtons;
+end;
+
+procedure TfrmMain.saveCustomButtons;
+var
+ count, i: Integer;
+ button: TButton;
+begin
+ count := 0;
+
+ // Account for all custom buttons
+ for i := 0 to tsCustom.ControlCount - 1 do begin
+ button := tsCustom.Controls[i] as TButton;
+ if button <> nil then begin
+ Config.setString(Format('CustomButton%u', [i]), Button.Caption);
+ Inc(Count);
+ end;
+ end;
+
+ Config.setInt('CustomButtonCount', count);
+end;
+
+procedure TfrmMain.customButtonClick(Sender: TObject);
+var
+ button: TButton;
+begin
+ button := sender as TButton;
+
+ if button <> nil then begin
+ // If it's empty, show the change gump instead
+ if button.caption = '' then begin
+ changeCustomButton(button);
+ end else begin
+ SendCommand(button.caption, True);
+ end;
+ end;
+end;
+
+procedure TfrmMain.customButtonMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+var
+ i, index: Integer;
+begin
+ if Button = mbRight then begin
+ index := -1;
+
+ // Find the index of this button in the custom ctrl
+ for i := 0 to tsCustom.ControlCount - 1 do begin
+ if tsCustom.Controls[i] = Sender then begin
+ index := i;
+ break;
+ end;
+ end;
+
+ btnCustomPopup.Tag := index;
+ end;
+
+ inherited;
+end;
+
+procedure TfrmMain.Remove1Click(Sender: TObject);
+var
+ index: Integer;
+begin
+ index := btnCustomPopup.Tag;
+
+ if (index <> -1) and (index < tsCustom.ControlCount) then begin
+ tsCustom.Controls[index].Free;
+ btnCustomPopup.Tag := -1;
+ reorderCustomButtons;
+ saveCustomButtons;
+ end;
+end;
+
+procedure TFrmMain.changeCustomButton(Button: TButton; NewButton: Boolean = False);
+var
+ value: String;
+begin
+ value := Button.Caption;
+ // Query the new caption from the user
+ if InputQuery('Change Custom Button', 'Please input the command to associate with this button:', value) then
+ begin
+ Button.Caption := value;
+ saveCustomButtons;
+ end;
+end;
+
+procedure TfrmMain.Change1Click(Sender: TObject);
+var
+ button: TButton;
+ index: Integer;
+begin
+ index := btnCustomPopup.Tag;
+
+ if (index <> -1) and (index < tsCustom.ControlCount) then begin
+ button := tsCustom.Controls[index] as TButton;
+ if button <> nil then
+ changeCustomButton(button, False);
+ end;
+end;
+
+procedure TfrmMain.AddButton1Click(Sender: TObject);
+var
+ button: TButton;
+begin
+ button := TButton.Create(tsCustom);
+ button.SetBounds(0, 0, 129, 25);
+ button.Caption := '';
+ button.OnClick := customButtonClick;
+ button.OnMouseDown := customButtonMouseDown;
+ button.PopupMenu := btnCustomPopup;
+ button.Parent := tsCustom;
+
+ reorderCustomButtons;
+ saveCustomButtons;
+end;
+
+procedure TfrmMain.tsCustomResize(Sender: TObject);
+begin
+ reorderCustomButtons;
+end;
+
+end.
+
Added: trunk/WPGM/Main.~ddp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Main.~ddp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Main.~dfm
===================================================================
--- trunk/WPGM/Main.~dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Main.~dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,1417 @@
+object frmMain: TfrmMain
+ Left = 365
+ Top = 496
+ Width = 612
+ Height = 199
+ Caption = 'Wolfpack - GM Tool'
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poDesktopCenter
+ ShowHint = True
+ OnClose = FormClose
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Pages: TPageControl
+ Left = 0
+ Top = 0
+ Width = 604
+ Height = 165
+ ActivePage = tsTags
+ Align = alClient
+ RaggedRight = True
+ TabOrder = 0
+ object tsCommands: TTabSheet
+ Caption = 'Commands'
+ ImageIndex = 3
+ object GroupBox1: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 185
+ Height = 121
+ Caption = 'Toggle Flags'
+ TabOrder = 0
+ object btnCmdAllmove: TButton
+ Left = 8
+ Top = 24
+ Width = 75
+ Height = 25
+ Hint = 'Toggle moving immovable objects.'
+ Caption = 'Allmove'
+ TabOrder = 0
+ OnClick = btnCmdAllmoveClick
+ end
+ object btnCmdAllshow: TButton
+ Left = 8
+ Top = 56
+ Width = 75
+ Height = 25
+ Hint = 'Toggle showing logged out characters.'
+ Caption = 'Allshow'
+ TabOrder = 1
+ OnClick = btnCmdAllshowClick
+ end
+ object btnCmdInvisible: TButton
+ Left = 8
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Toggle the invisible status.'
+ Caption = 'Invisible'
+ TabOrder = 2
+ OnClick = btnCmdInvisibleClick
+ end
+ object btnCmdStaff: TButton
+ Left = 96
+ Top = 56
+ Width = 75
+ Height = 25
+ Hint = 'Toggle the GM mode flag.'
+ Caption = 'Staff Flag'
+ TabOrder = 3
+ OnClick = btnCmdStaffClick
+ end
+ object btnCmdInvul: TButton
+ Left = 96
+ Top = 24
+ Width = 75
+ Height = 25
+ Hint = 'Toggle invulnerability.'
+ Caption = 'Invulnerable'
+ TabOrder = 4
+ OnClick = btnCmdInvulClick
+ end
+ object btnCmdPageNotify: TButton
+ Left = 96
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Be notified about incoming pages.'
+ Caption = 'Page Notify'
+ Enabled = False
+ TabOrder = 5
+ OnClick = btnCmdStaffClick
+ end
+ end
+ object GroupBox2: TGroupBox
+ Left = 200
+ Top = 8
+ Width = 233
+ Height = 121
+ Caption = 'System Commands'
+ TabOrder = 1
+ object btnCmdShutdown: TButton
+ Left = 8
+ Top = 24
+ Width = 105
+ Height = 25
+ Hint = 'Close the server.'
+ Caption = 'Shutdown'
+ TabOrder = 0
+ OnClick = btnCmdShutdownClick
+ end
+ object btnCmdReloadPython: TButton
+ Left = 8
+ Top = 56
+ Width = 105
+ Height = 25
+ Hint = 'Reload the python scripts.'
+ Caption = 'Reload Python'
+ TabOrder = 1
+ OnClick = btnCmdReloadPythonClick
+ end
+ object btnCmdReloadScripts: TButton
+ Left = 8
+ Top = 88
+ Width = 105
+ Height = 25
+ Hint = 'Reload the definitions and python scripts.'
+ Caption = 'Reload Definitions'
+ TabOrder = 2
+ OnClick = btnCmdReloadScriptsClick
+ end
+ object btnCmdReloadAccounts: TButton
+ Left = 120
+ Top = 56
+ Width = 105
+ Height = 25
+ Hint = 'Reload the accounts.'
+ Caption = 'Reload Accounts'
+ TabOrder = 3
+ OnClick = btnCmdReloadAccountsClick
+ end
+ object btnCmdReloadAll: TButton
+ Left = 120
+ Top = 88
+ Width = 105
+ Height = 25
+ Hint = 'Reload everything.'
+ Caption = 'Reload All'
+ TabOrder = 4
+ OnClick = btnCmdReloadAllClick
+ end
+ object btnCmdServertime: TButton
+ Left = 120
+ Top = 24
+ Width = 105
+ Height = 25
+ Hint = 'Show the current servertime.'
+ Caption = 'Show Servertime'
+ TabOrder = 5
+ OnClick = btnCmdServertimeClick
+ end
+ end
+ object Button1: TButton
+ Left = 440
+ Top = 16
+ Width = 97
+ Height = 25
+ Caption = 'Pattern Tilecolor'
+ TabOrder = 2
+ OnClick = Button1Click
+ end
+ end
+ object tsItems: TTabSheet
+ Caption = 'Items'
+ ImageIndex = -1
+ DesignSize = (
+ 596
+ 137)
+ object Label7: TLabel
+ Left = 162
+ Top = 118
+ Width = 39
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Z Level:'
+ end
+ object pnlItems: TPanel
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object spItems: TSplitter
+ Left = 201
+ Top = 0
+ Height = 112
+ end
+ object vtCategories: TVirtualStringTree
+ Left = 0
+ Top = 0
+ Width = 201
+ Height = 112
+ Align = alLeft
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.MainColumn = -1
+ Header.Options = [hoColumnResize, hoDrag]
+ IncrementalSearchStart = ssAlwaysStartOver
+ ScrollBarOptions.AlwaysVisible = True
+ TabOrder = 0
+ TreeOptions.PaintOptions = [toShowButtons, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages]
+ OnChange = vtCategoriesChange
+ OnExpanding = vtCategoriesExpanding
+ OnGetText = vtCategoriesGetText
+ Columns = <>
+ end
+ object vtItems: TVirtualStringTree
+ Left = 204
+ Top = 0
+ Width = 305
+ Height = 112
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ Header.SortColumn = 0
+ ScrollBarOptions.AlwaysVisible = True
+ ScrollBarOptions.ScrollBars = ssVertical
+ TabOrder = 1
+ TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoFreeOnCollapse]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toDisableDrawSelection, toFullRowSelect, toMultiSelect]
+ OnChange = vtItemsChange
+ OnCompareNodes = vtItemsCompareNodes
+ OnDblClick = btnAddItemClick
+ OnGetText = vtItemsGetText
+ OnHeaderClick = vtItemsHeaderClick
+ Columns = <
+ item
+ Position = 0
+ Width = 197
+ WideText = 'Name'
+ end
+ item
+ Position = 1
+ WideText = 'ID'
+ end>
+ end
+ object imgItemPreview: TImage32
+ Left = 509
+ Top = 0
+ Width = 85
+ Height = 112
+ Align = alRight
+ BitmapAlign = baCenter
+ Scale = 1.000000000000000000
+ ScaleMode = smNormal
+ TabOrder = 2
+ end
+ end
+ object btnAddItem: TButton
+ Left = 0
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnAddItemClick
+ end
+ object btnRemoveItem: TButton
+ Left = 80
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Remove'
+ TabOrder = 2
+ OnClick = btnRemoveItemClick
+ end
+ object btnTileItem: TButton
+ Left = 249
+ Top = 114
+ Width = 75
+ Height = 21
+ Hint = 'Fill a rectangle with items at the given z level.'
+ Anchors = [akLeft, akBottom]
+ Caption = 'Tile'
+ Enabled = False
+ TabOrder = 4
+ OnClick = btnTileItemClick
+ end
+ object eZLevel: TEdit
+ Left = 208
+ Top = 114
+ Width = 35
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 3
+ Text = '0'
+ end
+ object btnCmdItemNuke: TButton
+ Left = 329
+ Top = 114
+ Width = 75
+ Height = 21
+ Hint = 'Nuke a rectangle of items.'
+ Anchors = [akLeft, akBottom]
+ Caption = 'Nuke'
+ TabOrder = 5
+ OnClick = btnCmdNukeClick
+ end
+ object cbStatic: TCheckBox
+ Left = 413
+ Top = 116
+ Width = 49
+ Height = 17
+ Anchors = [akLeft, akBottom]
+ Caption = 'Static'
+ TabOrder = 6
+ end
+ end
+ object tsItemManip: TTabSheet
+ Caption = 'Item Manipulation'
+ ImageIndex = 4
+ object GroupBox3: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 145
+ Height = 121
+ Caption = 'Change Color'
+ TabOrder = 0
+ object eItemHue: TEdit
+ Left = 8
+ Top = 24
+ Width = 97
+ Height = 21
+ TabOrder = 0
+ Text = '0'
+ OnChange = eItemHueChange
+ end
+ object btnChangeItemHue: TButton
+ Left = 109
+ Top = 23
+ Width = 28
+ Height = 23
+ Caption = '...'
+ TabOrder = 1
+ OnClick = btnChangeItemHueClick
+ end
+ object btnCmdDye: TButton
+ Left = 8
+ Top = 88
+ Width = 57
+ Height = 25
+ Caption = 'Set'
+ TabOrder = 2
+ OnClick = btnCmdDyeClick
+ end
+ object pbHuePreview: TPaintBox32
+ Left = 8
+ Top = 56
+ Width = 128
+ Height = 25
+ TabOrder = 3
+ OnPaintBuffer = pbHuePreviewPaintBuffer
+ end
+ object btnCmdItemTileColor: TButton
+ Left = 72
+ Top = 88
+ Width = 67
+ Height = 25
+ Hint = 'Tiles this color over an area of items.'
+ Caption = 'Tile'
+ TabOrder = 4
+ OnClick = btnCmdItemTileColorClick
+ end
+ end
+ object GroupBox4: TGroupBox
+ Left = 160
+ Top = 8
+ Width = 185
+ Height = 121
+ Caption = 'Commands'
+ TabOrder = 1
+ object btnCmdDupe: TButton
+ Left = 8
+ Top = 24
+ Width = 75
+ Height = 25
+ Hint = 'Create an exact duplicate of the item.'
+ Caption = 'Dupe'
+ TabOrder = 0
+ OnClick = btnCmdDupeClick
+ end
+ object btnCmdInfo: TButton
+ Left = 8
+ Top = 56
+ Width = 75
+ Height = 25
+ Hint = 'Show an info dialog for the item.'
+ Caption = 'Info'
+ TabOrder = 1
+ OnClick = btnCmdInfoClick
+ end
+ object btnCmdRemove: TButton
+ Left = 8
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Remove the item.'
+ Caption = 'Remove'
+ TabOrder = 2
+ OnClick = btnCmdRemoveClick
+ end
+ object btnCmdLock: TButton
+ Left = 96
+ Top = 24
+ Width = 75
+ Height = 25
+ Hint = 'Attach a lock to the item.'
+ Caption = 'Lock'
+ TabOrder = 3
+ OnClick = btnCmdLockClick
+ end
+ object btnCmdNuke: TButton
+ Left = 96
+ Top = 56
+ Width = 75
+ Height = 25
+ Hint = 'Wipe an area from its items.'
+ Caption = 'Nuke'
+ TabOrder = 4
+ OnClick = btnCmdNukeClick
+ end
+ object btnCmdMoveUp: TBitBtn
+ Left = 96
+ Top = 88
+ Width = 33
+ Height = 25
+ Hint = 'Move the item up by 1 point of z.'
+ TabOrder = 5
+ OnClick = btnCmdMoveUpClick
+ Glyph.Data = {
+ 32010000424D3201000000000000360000002800000009000000090000000100
+ 180000000000FC000000120B0000120B00000000000000000000FFFFFFFFFFFF
+ FFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF00
+ 0000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF0000000000
+ 00000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF000000000000000000
+ FFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000
+ 000000000000FFFFFF000000000000000000000000000000000000000000FFFF
+ FF00FFFFFFFFFFFF000000000000000000000000000000FFFFFFFFFFFF00FFFF
+ FFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF
+ FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF00}
+ end
+ object btnCmdMoveDown: TBitBtn
+ Left = 136
+ Top = 88
+ Width = 33
+ Height = 25
+ Hint = 'Move the item down by 1 point of z.'
+ TabOrder = 6
+ OnClick = btnCmdMoveDownClick
+ Glyph.Data = {
+ 32010000424D3201000000000000360000002800000009000000090000000100
+ 180000000000FC000000120B0000120B00000000000000000000FFFFFFFFFFFF
+ FFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFF00
+ 0000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF0000000000000000
+ 00000000000000FFFFFFFFFFFF00FFFFFF000000000000000000000000000000
+ 000000000000FFFFFF0000000000000000000000000000000000000000000000
+ 000000000000FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFF
+ FF00FFFFFFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00FFFF
+ FFFFFFFFFFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00FFFFFFFFFFFF
+ FFFFFF000000000000000000FFFFFFFFFFFFFFFFFF00}
+ end
+ end
+ object GroupBox5: TGroupBox
+ Left = 352
+ Top = 8
+ Width = 177
+ Height = 121
+ Caption = 'Properties'
+ TabOrder = 2
+ object Label1: TLabel
+ Left = 10
+ Top = 60
+ Width = 30
+ Height = 13
+ Caption = 'Value:'
+ end
+ object cbItemProperty: TComboBox
+ Left = 8
+ Top = 24
+ Width = 153
+ Height = 21
+ ItemHeight = 13
+ TabOrder = 0
+ OnChange = cbItemPropertyChange
+ Items.Strings = (
+ 'amount'
+ 'baseid'
+ 'color'
+ 'decay'
+ 'health'
+ 'id'
+ 'movable'
+ 'maxhealth'
+ 'name'
+ 'newbie'
+ 'owner'
+ 'ownervisible'
+ 'pos'
+ 'secured'
+ 'serial'
+ 'spawnregion'
+ 'totalweight'
+ 'type'
+ 'visible')
+ end
+ object eItemPropValue: TEdit
+ Left = 56
+ Top = 56
+ Width = 105
+ Height = 21
+ TabOrder = 1
+ end
+ object btnCmdItemSet: TButton
+ Left = 8
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Set the value of the selected property'
+ Caption = 'Set'
+ Enabled = False
+ TabOrder = 2
+ OnClick = btnCmdItemSetClick
+ end
+ object btnCmdItemShow: TButton
+ Left = 88
+ Top = 88
+ Width = 75
+ Height = 25
+ Hint = 'Show the value of the selected property.'
+ Caption = 'Show'
+ Enabled = False
+ TabOrder = 3
+ OnClick = btnCmdItemShowClick
+ end
+ end
+ end
+ object tsNpcs: TTabSheet
+ Caption = 'NPCs'
+ ImageIndex = 6
+ DesignSize = (
+ 596
+ 137)
+ object Label8: TLabel
+ Left = 242
+ Top = 118
+ Width = 36
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Radius:'
+ end
+ object Label9: TLabel
+ Left = 330
+ Top = 118
+ Width = 46
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Min. Time'
+ end
+ object Label10: TLabel
+ Left = 426
+ Top = 118
+ Width = 49
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Max. Time'
+ end
+ object pnNpcs: TPanel
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object Splitter1: TSplitter
+ Left = 201
+ Top = 0
+ Height = 112
+ end
+ object Splitter2: TSplitter
+ Left = 496
+ Top = 0
+ Height = 112
+ Align = alRight
+ end
+ object vtNpcCategories: TVirtualStringTree
+ Left = 0
+ Top = 0
+ Width = 201
+ Height = 112
+ Align = alLeft
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.MainColumn = -1
+ Header.Options = [hoColumnResize, hoDrag]
+ IncrementalSearchStart = ssAlwaysStartOver
+ ScrollBarOptions.AlwaysVisible = True
+ TabOrder = 0
+ TreeOptions.PaintOptions = [toShowButtons, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages]
+ OnChange = vtNpcCategoriesChange
+ OnExpanding = vtNpcCategoriesExpanding
+ OnGetText = vtCategoriesGetText
+ Columns = <>
+ end
+ object vtNpcs: TVirtualStringTree
+ Left = 204
+ Top = 0
+ Width = 292
+ Height = 112
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ Header.SortColumn = 0
+ ScrollBarOptions.AlwaysVisible = True
+ ScrollBarOptions.ScrollBars = ssVertical
+ TabOrder = 1
+ TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoFreeOnCollapse]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toDisableDrawSelection, toFullRowSelect]
+ OnChange = vtNpcsChange
+ OnCompareNodes = vtNpcsCompareNodes
+ OnDblClick = btnAddNpcClick
+ OnGetText = vtNpcsGetText
+ OnHeaderClick = vtNpcsHeaderClick
+ Columns = <
+ item
+ Position = 0
+ Width = 197
+ WideText = 'Name'
+ end
+ item
+ Position = 1
+ WideText = 'ID'
+ end>
+ end
+ object pbNpcPreview: TPaintBox32
+ Left = 499
+ Top = 0
+ Width = 95
+ Height = 112
+ Align = alRight
+ TabOrder = 2
+ OnPaintBuffer = pbNpcPreviewPaintBuffer
+ end
+ end
+ object btnAddNpc: TButton
+ Left = 0
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnAddNpcClick
+ end
+ object btnRemoveNpc: TButton
+ Left = 79
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Remove'
+ TabOrder = 2
+ OnClick = btnRemoveNpcClick
+ end
+ object eSpawnRadius: TEdit
+ Left = 288
+ Top = 114
+ Width = 35
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 3
+ Text = '0'
+ OnExit = eSpawnRadiusExit
+ end
+ object eSpawnMin: TEdit
+ Left = 384
+ Top = 114
+ Width = 35
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 4
+ Text = '0'
+ OnExit = eSpawnMinExit
+ end
+ object eSpawnMax: TEdit
+ Left = 480
+ Top = 114
+ Width = 35
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 5
+ Text = '0'
+ OnExit = eSpawnMaxExit
+ end
+ object btnNpcSpawn: TButton
+ Left = 159
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Spawn'
+ Enabled = False
+ TabOrder = 6
+ OnClick = btnNpcSpawnClick
+ end
+ end
+ object TabSheet1: TTabSheet
+ Caption = 'Multis'
+ ImageIndex = 7
+ DesignSize = (
+ 596
+ 137)
+ object Panel1: TPanel
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object vtMultis: TVirtualStringTree
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ Header.SortColumn = 0
+ ScrollBarOptions.AlwaysVisible = True
+ ScrollBarOptions.ScrollBars = ssVertical
+ TabOrder = 0
+ TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoFreeOnCollapse]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toDisableDrawSelection, toFullRowSelect]
+ OnChange = vtMultisChange
+ OnCompareNodes = vtMultisCompareNodes
+ OnDblClick = btnAddMultiClick
+ OnGetText = vtMultisGetText
+ OnHeaderClick = vtMultisHeaderClick
+ Columns = <
+ item
+ Position = 0
+ Width = 197
+ WideText = 'Name'
+ end
+ item
+ Position = 1
+ WideText = 'ID'
+ end>
+ end
+ end
+ object btnAddMulti: TButton
+ Left = 0
+ Top = 115
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnAddMultiClick
+ end
+ object btnRemoveMulti: TButton
+ Left = 79
+ Top = 115
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Remove'
+ TabOrder = 2
+ end
+ object btnPreviewMulti: TButton
+ Left = 158
+ Top = 115
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Preview'
+ Enabled = False
+ TabOrder = 3
+ OnClick = btnPreviewMultiClick
+ end
+ end
+ object tsTags: TTabSheet
+ Caption = 'Object Manipulation'
+ ImageIndex = 5
+ object GroupBox6: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 233
+ Height = 121
+ Caption = 'Manage Tags'
+ TabOrder = 0
+ object Label2: TLabel
+ Left = 10
+ Top = 60
+ Width = 30
+ Height = 13
+ Caption = 'Value:'
+ end
+ object Label3: TLabel
+ Left = 10
+ Top = 28
+ Width = 31
+ Height = 13
+ Caption = 'Name:'
+ end
+ object eTagValue: TEdit
+ Left = 56
+ Top = 56
+ Width = 97
+ Height = 21
+ Hint = 'The new tag value if you use set.'
+ TabOrder = 0
+ end
+ object btnTagSet: TButton
+ Left = 8
+ Top = 88
+ Width = 49
+ Height = 25
+ Caption = 'Set'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnTagSetClick
+ end
+ object eTagName: TEdit
+ Left = 56
+ Top = 24
+ Width = 169
+ Height = 21
+ Hint = 'The name of the tag you want to set.'
+ TabOrder = 2
+ OnChange = eTagNameChange
+ end
+ object btnTagShow: TButton
+ Left = 64
+ Top = 88
+ Width = 49
+ Height = 25
+ Caption = 'Show'
+ Enabled = False
+ TabOrder = 3
+ OnClick = btnTagShowClick
+ end
+ object btnTagDelete: TButton
+ Left = 120
+ Top = 88
+ Width = 49
+ Height = 25
+ Caption = 'Delete'
+ Enabled = False
+ TabOrder = 4
+ OnClick = btnTagDeleteClick
+ end
+ object cbTagType: TComboBox
+ Left = 160
+ Top = 56
+ Width = 65
+ Height = 21
+ Hint = 'The type of the tag value.'
+ Style = csDropDownList
+ ItemHeight = 13
+ ItemIndex = 0
+ TabOrder = 5
+ Text = 'String'
+ Items.Strings = (
+ 'String'
+ 'Integer'
+ 'Float')
+ end
+ object btnTagInfo: TButton
+ Left = 176
+ Top = 88
+ Width = 49
+ Height = 25
+ Caption = 'Info'
+ TabOrder = 6
+ OnClick = btnTagInfoClick
+ end
+ end
+ object GroupBox7: TGroupBox
+ Left = 248
+ Top = 8
+ Width = 137
+ Height = 121
+ Caption = 'Move Relatively'
+ TabOrder = 1
+ object Label4: TLabel
+ Left = 16
+ Top = 18
+ Width = 29
+ Height = 13
+ Caption = 'X Axis'
+ end
+ object Label5: TLabel
+ Left = 16
+ Top = 42
+ Width = 29
+ Height = 13
+ Caption = 'Y Axis'
+ end
+ object Label6: TLabel
+ Left = 16
+ Top = 66
+ Width = 29
+ Height = 13
+ Caption = 'Z Axis'
+ end
+ object eMoveX: TEdit
+ Left = 80
+ Top = 16
+ Width = 41
+ Height = 21
+ TabOrder = 0
+ Text = '0'
+ end
+ object eMoveY: TEdit
+ Left = 80
+ Top = 40
+ Width = 41
+ Height = 21
+ TabOrder = 1
+ Text = '0'
+ end
+ object eMoveZ: TEdit
+ Left = 80
+ Top = 64
+ Width = 41
+ Height = 21
+ TabOrder = 2
+ Text = '0'
+ end
+ object btnCmdMove: TButton
+ Left = 8
+ Top = 88
+ Width = 65
+ Height = 25
+ Caption = 'Move'
+ TabOrder = 3
+ OnClick = btnCmdMoveClick
+ end
+ end
+ object GroupBox8: TGroupBox
+ Left = 392
+ Top = 8
+ Width = 137
+ Height = 121
+ Caption = 'Manage Scripts'
+ TabOrder = 2
+ object btnCmdAddEvent: TButton
+ Left = 8
+ Top = 56
+ Width = 57
+ Height = 25
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 1
+ OnClick = btnCmdAddEventClick
+ end
+ object btnCmdRemoveEvent: TButton
+ Left = 72
+ Top = 56
+ Width = 57
+ Height = 25
+ Caption = 'Remove'
+ Enabled = False
+ TabOrder = 2
+ OnClick = btnCmdRemoveEventClick
+ end
+ object btnCmdShowEventlist: TButton
+ Left = 8
+ Top = 88
+ Width = 121
+ Height = 25
+ Caption = 'Show Eventlist'
+ TabOrder = 3
+ OnClick = btnCmdShowEventlistClick
+ end
+ object cbEventName: TComboBox
+ Left = 8
+ Top = 24
+ Width = 121
+ Height = 21
+ ItemHeight = 13
+ TabOrder = 0
+ OnChange = eEventNameChange
+ end
+ end
+ end
+ object TravelMap: TTabSheet
+ Caption = 'Travel'
+ ImageIndex = 2
+ DesignSize = (
+ 596
+ 137)
+ object pnlTravel: TPanel
+ Left = 0
+ Top = 0
+ Width = 594
+ Height = 112
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ TabOrder = 0
+ object spTravel: TSplitter
+ Left = 201
+ Top = 0
+ Height = 112
+ end
+ object spMap: TSplitter
+ Left = 441
+ Top = 0
+ Height = 112
+ Align = alRight
+ end
+ object vtLocCategories: TVirtualStringTree
+ Left = 0
+ Top = 0
+ Width = 201
+ Height = 112
+ Align = alLeft
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.MainColumn = -1
+ Header.Options = [hoColumnResize, hoDrag]
+ IncrementalSearchStart = ssAlwaysStartOver
+ ScrollBarOptions.AlwaysVisible = True
+ TabOrder = 0
+ TreeOptions.PaintOptions = [toShowButtons, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages]
+ OnChange = vtLocCategoriesChange
+ OnExpanding = vtLocCategoriesExpanding
+ OnGetText = vtCategoriesGetText
+ Columns = <>
+ end
+ object vtLocItems: TVirtualStringTree
+ Left = 204
+ Top = 0
+ Width = 237
+ Height = 112
+ Align = alClient
+ Header.AutoSizeIndex = 0
+ Header.Font.Charset = DEFAULT_CHARSET
+ Header.Font.Color = clWindowText
+ Header.Font.Height = -11
+ Header.Font.Name = 'MS Sans Serif'
+ Header.Font.Style = []
+ Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible]
+ Header.SortColumn = 0
+ ScrollBarOptions.AlwaysVisible = True
+ ScrollBarOptions.ScrollBars = ssVertical
+ TabOrder = 1
+ TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoFreeOnCollapse]
+ TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages]
+ TreeOptions.SelectionOptions = [toDisableDrawSelection, toFullRowSelect]
+ OnChange = vtLocItemsChange
+ OnCompareNodes = vtLocItemsCompareNodes
+ OnDblClick = Go1Click
+ OnGetText = vtLocItemsGetText
+ OnHeaderClick = vtLocItemsHeaderClick
+ Columns = <
+ item
+ Position = 0
+ Width = 197
+ WideText = 'Name'
+ end>
+ end
+ object pbMap: TPaintBox32
+ Left = 444
+ Top = 0
+ Width = 150
+ Height = 112
+ Align = alRight
+ PopupMenu = pmTravel
+ TabOrder = 2
+ OnMouseDown = pbMapMouseDown
+ OnPaintBuffer = pbMapPaintBuffer
+ end
+ end
+ object btnTravel: TButton
+ Left = 0
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Travel'
+ TabOrder = 1
+ OnClick = Go1Click
+ end
+ object btnSend: TButton
+ Left = 80
+ Top = 114
+ Width = 75
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Send'
+ TabOrder = 2
+ OnClick = btnSendClick
+ end
+ object Button2: TButton
+ Left = 160
+ Top = 114
+ Width = 89
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Teleport Self'
+ TabOrder = 3
+ OnClick = Button2Click
+ end
+ object btnCmdSendOther: TButton
+ Left = 254
+ Top = 114
+ Width = 89
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ Caption = 'Teleport Other'
+ TabOrder = 4
+ OnClick = btnCmdSendOtherClick
+ end
+ object btnCmdWhere: TButton
+ Left = 348
+ Top = 114
+ Width = 75
+ Height = 21
+ Hint = 'Show your current position.'
+ Anchors = [akLeft, akBottom]
+ Caption = 'Where'
+ TabOrder = 5
+ OnClick = btnCmdWhereClick
+ end
+ object btnMapOverview: TButton
+ Left = 428
+ Top = 114
+ Width = 75
+ Height = 21
+ Hint = 'Show your current position.'
+ Anchors = [akLeft, akBottom]
+ Caption = 'Overview'
+ TabOrder = 6
+ OnClick = btnMapOverviewClick
+ end
+ end
+ object tsSettings: TTabSheet
+ Caption = 'Settings'
+ ImageIndex = 1
+ object gbSettingsGeneral: TGroupBox
+ Left = 8
+ Top = 8
+ Width = 241
+ Height = 97
+ Caption = 'General Settings'
+ TabOrder = 0
+ object lblCommandPrefix: TLabel
+ Left = 45
+ Top = 64
+ Width = 76
+ Height = 13
+ Caption = 'Command Prefix'
+ end
+ object cbAlwaysOnTop: TCheckBox
+ Left = 16
+ Top = 24
+ Width = 97
+ Height = 17
+ Caption = 'Always on top'
+ TabOrder = 0
+ OnClick = cbAlwaysOnTopClick
+ end
+ object eCommandPrefix: TEdit
+ Left = 15
+ Top = 60
+ Width = 25
+ Height = 21
+ TabOrder = 1
+ end
+ object btnSave: TButton
+ Left = 152
+ Top = 56
+ Width = 75
+ Height = 25
+ Caption = '&Save'
+ TabOrder = 2
+ OnClick = btnSaveClick
+ end
+ end
+ object btnRegions: TButton
+ Left = 264
+ Top = 16
+ Width = 75
+ Height = 25
+ Caption = 'Regions'
+ TabOrder = 1
+ OnClick = btnRegionsClick
+ end
+ end
+ object TabSheet2: TTabSheet
+ Caption = 'Build'
+ ImageIndex = 8
+ DesignSize = (
+ 596
+ 137)
+ object GroupBox9: TGroupBox
+ Left = 0
+ Top = 0
+ Width = 89
+ Height = 137
+ Anchors = [akLeft, akTop, akBottom]
+ Caption = 'Settings'
+ TabOrder = 0
+ object Label11: TLabel
+ Left = 8
+ Top = 18
+ Width = 10
+ Height = 16
+ Caption = 'Z'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -13
+ Font.Name = 'MS Sans Serif'
+ Font.Style = [fsBold]
+ ParentFont = False
+ end
+ object cbBuildZ: TComboBox
+ Left = 23
+ Top = 16
+ Width = 58
+ Height = 21
+ ItemHeight = 13
+ TabOrder = 0
+ Text = '0'
+ Items.Strings = (
+ '0'
+ '5'
+ '7'
+ '10'
+ '15'
+ '17'
+ '20'
+ '25'
+ '27'
+ '30'
+ '35'
+ '37'
+ '40')
+ end
+ end
+ object gbBuild: TGroupBox
+ Left = 96
+ Top = 0
+ Width = 489
+ Height = 137
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Caption = 'Build'
+ TabOrder = 1
+ DesignSize = (
+ 489
+ 137)
+ object sbBuild: TScrollBox
+ Left = 8
+ Top = 16
+ Width = 473
+ Height = 113
+ HorzScrollBar.Smooth = True
+ HorzScrollBar.Tracking = True
+ VertScrollBar.Smooth = True
+ VertScrollBar.Tracking = True
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ BevelOuter = bvNone
+ BevelKind = bkSoft
+ TabOrder = 0
+ OnClick = sbBuildClick
+ OnMouseWheelDown = sbBuildMouseWheelDown
+ OnMouseWheelUp = sbBuildMouseWheelUp
+ OnResize = sbBuildResize
+ end
+ end
+ end
+ object tsCustom: TTabSheet
+ Caption = 'Custom'
+ ImageIndex = 9
+ OnResize = tsCustomResize
+ end
+ end
+ object XPManifest1: TXPManifest
+ Left = 572
+ Top = 28
+ end
+ object pmTravel: TPopupMenu
+ Left = 572
+ Top = 25
+ object Go1: TMenuItem
+ Caption = '&Go'
+ OnClick = Go1Click
+ end
+ object Send1: TMenuItem
+ Caption = '&Send'
+ OnClick = btnSendClick
+ end
+ object Center1: TMenuItem
+ Caption = '&Center'
+ OnClick = Center1Click
+ end
+ object N1: TMenuItem
+ Caption = '-'
+ end
+ object Felucca1: TMenuItem
+ Caption = 'Felucca'
+ Checked = True
+ GroupIndex = 1
+ RadioItem = True
+ OnClick = Felucca1Click
+ end
+ object Trammel1: TMenuItem
+ Caption = 'Trammel'
+ GroupIndex = 1
+ RadioItem = True
+ OnClick = Trammel1Click
+ end
+ object Ilshenar1: TMenuItem
+ Caption = 'Ilshenar'
+ GroupIndex = 1
+ RadioItem = True
+ OnClick = Ilshenar1Click
+ end
+ object Malas1: TMenuItem
+ Caption = 'Malas'
+ GroupIndex = 1
+ RadioItem = True
+ OnClick = Malas1Click
+ end
+ object SamuraiEmpire1: TMenuItem
+ Caption = 'Samurai Empire'
+ GroupIndex = 1
+ OnClick = SamuraiEmpire1Click
+ end
+ end
+ object animtimer: TTimer
+ Enabled = False
+ Interval = 100
+ OnTimer = animtimerTimer
+ Left = 572
+ Top = 24
+ end
+ object ontopTimer: TTimer
+ Interval = 100
+ OnTimer = ontopTimerTimer
+ Left = 572
+ Top = 24
+ end
+ object btnCustomPopup: TPopupMenu
+ Left = 572
+ Top = 56
+ object AddButton1: TMenuItem
+ Caption = '&Add Button'
+ OnClick = AddButton1Click
+ end
+ object Change1: TMenuItem
+ Caption = '&Change'
+ OnClick = Change1Click
+ end
+ object Remove1: TMenuItem
+ Caption = '&Remove'
+ OnClick = Remove1Click
+ end
+ end
+end
Added: trunk/WPGM/Main.~pas
===================================================================
--- trunk/WPGM/Main.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Main.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,2398 @@
+unit Main;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ VirtualTrees, ComCtrls, ImgList, ExtCtrls, SQLite, SQLiteTable, UOTiledata,
+ GR32, GR32_Image, UOArt, UOAnim, StdCtrls, uConfig, XPMan, UOMap, UOStatics, UORadarCol,
+ Menus, UOHues, Buttons, SyncObjs;
+
+type TNode = record
+ Id: Cardinal;
+ Name: WideString;
+end;
+
+type TLocationNode = record
+ Id: Cardinal;
+ Name: WideString;
+ LocId: String;
+ PosX: Cardinal;
+ PosY: Cardinal;
+ PosZ: ShortInt;
+ PosMap: Byte;
+end;
+
+type TItemNode = record
+ Id: Cardinal;
+ Name: WideString;
+ ArtId: Word;
+ Color: Word;
+ AddId: String;
+end;
+
+type TMultiNode = record
+ Id: Cardinal;
+ Name: WideString;
+ AddId: String;
+ MultiId: Word;
+end;
+
+type TNpcEquipment = record
+ Layer: Byte;
+ Anim: Word;
+ Color: Word;
+end;
+
+type TNpcNode = record
+ Id: Cardinal;
+ Name: WideString;
+ BodyId: Word;
+ Skin: Word;
+ AddId: String;
+ Equipment: Array of TNpcEquipment;
+end;
+
+type PMultiNode = ^TMultiNode;
+type PItemNode = ^TItemNode;
+type PNPCNode = ^TNPCNode;
+type PLocationNode = ^TLocationNode;
+type PNode = ^TNode;
+
+type
+ TfrmMain = class(TForm)
+ Pages: TPageControl;
+ tsItems: TTabSheet;
+ tsSettings: TTabSheet;
+ pnlItems: TPanel;
+ spItems: TSplitter;
+ vtCategories: TVirtualStringTree;
+ vtItems: TVirtualStringTree;
+ XPManifest1: TXPManifest;
+ gbSettingsGeneral: TGroupBox;
+ cbAlwaysOnTop: TCheckBox;
+ btnAddItem: TButton;
+ btnRemoveItem: TButton;
+ lblCommandPrefix: TLabel;
+ eCommandPrefix: TEdit;
+ TravelMap: TTabSheet;
+ imgItemPreview: TImage32;
+ pnlTravel: TPanel;
+ vtLocCategories: TVirtualStringTree;
+ vtLocItems: TVirtualStringTree;
+ pbMap: TPaintBox32;
+ spTravel: TSplitter;
+ spMap: TSplitter;
+ pmTravel: TPopupMenu;
+ Go1: TMenuItem;
+ btnTravel: TButton;
+ btnSend: TButton;
+ tsCommands: TTabSheet;
+ GroupBox1: TGroupBox;
+ btnCmdAllmove: TButton;
+ btnCmdAllshow: TButton;
+ btnCmdInvisible: TButton;
+ btnCmdStaff: TButton;
+ btnCmdInvul: TButton;
+ btnCmdPageNotify: TButton;
+ GroupBox2: TGroupBox;
+ btnCmdShutdown: TButton;
+ btnCmdReloadPython: TButton;
+ btnCmdReloadScripts: TButton;
+ btnCmdReloadAccounts: TButton;
+ btnCmdReloadAll: TButton;
+ btnSave: TButton;
+ tsItemManip: TTabSheet;
+ tsTags: TTabSheet;
+ GroupBox3: TGroupBox;
+ eItemHue: TEdit;
+ btnChangeItemHue: TButton;
+ btnCmdDye: TButton;
+ pbHuePreview: TPaintBox32;
+ GroupBox4: TGroupBox;
+ btnCmdDupe: TButton;
+ btnCmdInfo: TButton;
+ btnCmdRemove: TButton;
+ btnCmdLock: TButton;
+ btnCmdNuke: TButton;
+ GroupBox5: TGroupBox;
+ cbItemProperty: TComboBox;
+ eItemPropValue: TEdit;
+ btnCmdItemSet: TButton;
+ btnCmdItemShow: TButton;
+ Label1: TLabel;
+ btnCmdItemTileColor: TButton;
+ GroupBox6: TGroupBox;
+ Label2: TLabel;
+ eTagValue: TEdit;
+ btnTagSet: TButton;
+ eTagName: TEdit;
+ Label3: TLabel;
+ btnTagShow: TButton;
+ btnTagDelete: TButton;
+ cbTagType: TComboBox;
+ btnTagInfo: TButton;
+ GroupBox7: TGroupBox;
+ Button2: TButton;
+ btnCmdSendOther: TButton;
+ Send1: TMenuItem;
+ eMoveX: TEdit;
+ eMoveY: TEdit;
+ eMoveZ: TEdit;
+ btnCmdMove: TButton;
+ Label4: TLabel;
+ Label5: TLabel;
+ Label6: TLabel;
+ btnCmdMoveUp: TBitBtn;
+ btnCmdMoveDown: TBitBtn;
+ btnTileItem: TButton;
+ eZLevel: TEdit;
+ Label7: TLabel;
+ btnCmdItemNuke: TButton;
+ GroupBox8: TGroupBox;
+ btnCmdAddEvent: TButton;
+ btnCmdRemoveEvent: TButton;
+ btnCmdShowEventlist: TButton;
+ btnCmdWhere: TButton;
+ btnCmdServertime: TButton;
+ cbEventName: TComboBox;
+ tsNpcs: TTabSheet;
+ pnNpcs: TPanel;
+ Splitter1: TSplitter;
+ vtNpcCategories: TVirtualStringTree;
+ vtNpcs: TVirtualStringTree;
+ btnAddNpc: TButton;
+ btnRemoveNpc: TButton;
+ Splitter2: TSplitter;
+ pbNpcPreview: TPaintBox32;
+ animtimer: TTimer;
+ TabSheet1: TTabSheet;
+ Panel1: TPanel;
+ vtMultis: TVirtualStringTree;
+ btnAddMulti: TButton;
+ btnRemoveMulti: TButton;
+ btnPreviewMulti: TButton;
+ N1: TMenuItem;
+ Felucca1: TMenuItem;
+ Trammel1: TMenuItem;
+ Ilshenar1: TMenuItem;
+ Malas1: TMenuItem;
+ Center1: TMenuItem;
+ SamuraiEmpire1: TMenuItem;
+ cbStatic: TCheckBox;
+ btnMapOverview: TButton;
+ ontopTimer: TTimer;
+ Label8: TLabel;
+ eSpawnRadius: TEdit;
+ Label9: TLabel;
+ eSpawnMin: TEdit;
+ Label10: TLabel;
+ eSpawnMax: TEdit;
+ btnNpcSpawn: TButton;
+ btnRegions: TButton;
+ Button1: TButton;
+ TabSheet2: TTabSheet;
+ GroupBox9: TGroupBox;
+ cbBuildZ: TComboBox;
+ Label11: TLabel;
+ gbBuild: TGroupBox;
+ sbBuild: TScrollBox;
+ tsCustom: TTabSheet;
+ btnCustomPopup: TPopupMenu;
+ Remove1: TMenuItem;
+ Change1: TMenuItem;
+ AddButton1: TMenuItem;
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure vtCategoriesGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure vtCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+ procedure vtItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure vtCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+ procedure vtItemsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure vtItemsHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure btnAddItemClick(Sender: TObject);
+ procedure vtItemsChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure btnRemoveItemClick(Sender: TObject);
+ procedure cbAlwaysOnTopClick(Sender: TObject);
+ procedure btnSaveClick(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure pbMapPaintBuffer(Sender: TObject);
+ procedure pbMapMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure vtLocCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+ procedure vtLocCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+ procedure vtLocItemsGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure vtLocItemsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure vtLocItemsHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+ procedure vtLocItemsChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+ procedure Go1Click(Sender: TObject);
+ procedure btnSendClick(Sender: TObject);
+ procedure btnCmdAllmoveClick(Sender: TObject);
+ procedure btnCmdAllshowClick(Sender: TObject);
+ procedure btnCmdInvisibleClick(Sender: TObject);
+ procedure btnCmdStaffClick(Sender: TObject);
+ procedure btnCmdInvulClick(Sender: TObject);
+ procedure btnCmdShutdownClick(Sender: TObject);
+ procedure btnCmdReloadAllClick(Sender: TObject);
+ procedure btnCmdReloadConfigClick(Sender: TObject);
+ procedure btnCmdReloadAccountsClick(Sender: TObject);
+ procedure btnCmdReloadPythonClick(Sender: TObject);
+ procedure btnCmdReloadScriptsClick(Sender: TObject);
+ procedure btnCmdDyeClick(Sender: TObject);
+ procedure pbHuePreviewPaintBuffer(Sender: TObject);
+ procedure eItemHueChange(Sender: TObject);
+ procedure btnChangeItemHueClick(Sender: TObject);
+ procedure btnCmdDupeClick(Sender: TObject);
+ procedure btnCmdInfoClick(Sender: TObject);
+ procedure btnCmdRemoveClick(Sender: TObject);
+ procedure btnCmdLockClick(Sender: TObject);
+ procedure btnCmdNukeClick(Sender: TObject);
+ procedure btnCmdItemSetClick(Sender: TObject);
+ procedure btnCmdItemShowClick(Sender: TObject);
+ procedure cbItemPropertyChange(Sender: TObject);
+ procedure btnCmdItemTileColorClick(Sender: TObject);
+ procedure btnTagInfoClick(Sender: TObject);
+ procedure eTagNameChange(Sender: TObject);
+ procedure btnTagSetClick(Sender: TObject);
+ procedure btnTagShowClick(Sender: TObject);
+ procedure btnTagDeleteClick(Sender: TObject);
+ procedure btnCmdSendOtherClick(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure btnCmdMoveClick(Sender: TObject);
+ procedure btnCmdMoveUpClick(Sender: TObject);
+ procedure btnCmdMoveDownClick(Sender: TObject);
+ procedure btnTileItemClick(Sender: TObject);
+ procedure btnCmdShowEventlistClick(Sender: TObject);
+ procedure eEventNameChange(Sender: TObject);
+ procedure btnCmdAddEventClick(Sender: TObject);
+ procedure btnCmdRemoveEventClick(Sender: TObject);
+ procedure btnCmdWhereClick(Sender: TObject);
+ procedure btnCmdServertimeClick(Sender: TObject);
+ procedure vtNpcCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+ procedure vtNpcCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+ procedure vtNpcsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure vtNpcsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure btnRemoveNpcClick(Sender: TObject);
+ procedure btnAddNpcClick(Sender: TObject);
+ procedure vtNpcsChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure vtNpcsHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure pbNpcPreviewPaintBuffer(Sender: TObject);
+ procedure animtimerTimer(Sender: TObject);
+ procedure vtMultisGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+ Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+ procedure vtMultisCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+ procedure vtMultisHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure vtMultisChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
+ procedure btnPreviewMultiClick(Sender: TObject);
+ procedure btnAddMultiClick(Sender: TObject);
+ procedure Felucca1Click(Sender: TObject);
+ procedure Trammel1Click(Sender: TObject);
+ procedure Ilshenar1Click(Sender: TObject);
+ procedure Malas1Click(Sender: TObject);
+ procedure Center1Click(Sender: TObject);
+ procedure SamuraiEmpire1Click(Sender: TObject);
+ procedure btnStaticItemClick(Sender: TObject);
+ procedure btnMapOverviewClick(Sender: TObject);
+ procedure ontopTimerTimer(Sender: TObject);
+ procedure btnNpcSpawnClick(Sender: TObject);
+ procedure eSpawnRadiusExit(Sender: TObject);
+ procedure eSpawnMinExit(Sender: TObject);
+ procedure eSpawnMaxExit(Sender: TObject);
+ procedure btnRegionsClick(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure sbBuildResize(Sender: TObject);
+ procedure clickBuildButton(Sender: TObject);
+ procedure sbBuildClick(Sender: TObject);
+ procedure sbBuildMouseWheelDown(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+ procedure sbBuildMouseWheelUp(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+ procedure customButtonClick(Sender: TObject);
+ procedure customButtonMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure Remove1Click(Sender: TObject);
+ procedure Change1Click(Sender: TObject);
+ procedure AddButton1Click(Sender: TObject);
+ procedure tsCustomResize(Sender: TObject);
+ private
+ { Private-Deklarationen }
+ UpdateMutex: TCriticalSection;
+ public
+ { Public-Deklarationen }
+ procedure pixelCombine(F: TColor32; var B: TColor32; M: TColor32);
+ procedure loadMultis;
+ procedure addBuildButton(Id: String; ItemId: Word; Text: String);
+ procedure rebuildBuildMenu;
+ procedure reorderCustomButtons;
+ procedure loadCustomButtons;
+ procedure saveCustomButtons;
+ procedure changeCustomButton(Button: TButton; NewButton: Boolean = False);
+ end;
+
+var
+ frmMain: TfrmMain;
+ SQLiteDb: TSQLiteDatabase;
+ ItemCategory: Cardinal;
+ Tiledata: TTiledataReader;
+ Art: TArtReader;
+ Anim: TAnimReader;
+ Maps: Array[0..4] of TMapReader;
+ Statics: Array[0..4] of TStaticReader;
+ Hues: THuesReader;
+ RadarCol: TRadarcolReader;
+ Config: TConfig;
+ MapCenterX, MapCenterY: Cardinal;
+ MapCenterZ: ShortInt;
+ MapCenterMap: Byte;
+ MapId: Cardinal;
+ npcPreview: Array of TAnimation;
+ npcPreviewFrame: Integer;
+ BuildCurrentX: Integer;
+ BuildCurrentY: Integer;
+
+implementation
+
+uses UOUtilities, uChooseHue, Math, uCenter, Overview, Spawnregions,
+ uPatternColor;
+
+{$R *.DFM}
+
+procedure TfrmMain.FormCreate(Sender: TObject);
+var
+ RootQuery: TSQLiteTable;
+ CountQuery: TSQLiteTable;
+ Node: PNode;
+ TreeNode: PVirtualNode;
+ UOPath: String;
+ i: Integer;
+ value: String;
+begin
+ inherited;
+
+ UpdateMutex := TCriticalSection.Create;
+
+ npcPreview := nil;
+ npcPreviewFrame := 0;
+ Tiledata := TTiledataReader.Create;
+ Art := TArtReader.Create;
+ Anim := TAnimReader.Create;
+ Config := TConfig.Create;
+ Hues := THuesReader.Create;
+ Art.hues := Hues; // Tell the art reader about the hues
+ Anim.hues := Hues; // Tell the anim reader about the hues
+
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 0;
+
+ // Should be updated to support multiple maps
+ for i := 0 to 4 do begin
+ Maps[i] := TMapReader.Create;
+ Statics[i] := TStaticReader.Create;
+ end;
+ RadarCol := TRadarColReader.Create;
+
+ Config.Load(ExtractFilePath( Application.ExeName ) + 'config.ini');
+
+ vtCategories.NodeDataSize := sizeof( TNode );
+ vtNpcCategories.NodeDataSize := sizeof(TNode);
+ vtLocCategories.NodeDataSize := sizeof(TNode);
+
+ vtItems.NodeDataSize := sizeof( TItemNode );
+ vtLocItems.NodeDataSize := sizeof(TLocationNode);
+ vtNpcs.NodeDataSize := sizeof( TNpcNode );
+ vtMultis.NodeDataSize := sizeof( TMultiNode );
+
+ eSpawnRadius.Text := Config.getString('SpawnRadius', '5');
+ eSpawnMin.Text := Config.getString('SpawnMin', '5');
+ eSpawnMax.Text := Config.getString('SpawnMax', '10');
+ eCommandPrefix.Text := Config.getString('Command Prefix', '''');
+ cbAlwaysOnTop.Checked := Config.getBool('Always On Top', False);
+ cbAlwaysOnTopClick(nil); // Refresh the Status
+ UOPath := getUoPath;
+
+ // Query initial count of Items
+ try
+ SQLiteDb := TSQLiteDatabase.Create( 'categories.db' );
+ SQLiteDb.ExecSQL( 'PRAGMA default_cache_size = 10000;' );
+ SQLiteDb.ExecSQL( 'PRAGMA default_synchronous = OFF;' );
+ SQLiteDb.ExecSQL( 'PRAGMA full_column_names = OFF;' );
+ SQLiteDb.ExecSQL( 'PRAGMA show_datatypes = OFF;' );
+
+ RootQuery := TSQLiteTable.Create( SQLiteDb, 'SELECT id,name FROM categories WHERE type = 0 AND parent = 0 ORDER BY name ASC;' );
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtCategories.AddChild( nil );
+ Node := vtCategories.GetNodeData( TreeNode );
+ Node.Id := StrToInt( RootQuery.Fields[0] );
+ Node.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM categories WHERE type = 0 AND parent = %u', [ Node.Id ] ) );
+
+ if StrToInt(CountQuery.Fields[0]) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+ CountQuery.Free;
+ RootQuery.Next;
+ end;
+ RootQuery.Free;
+
+ RootQuery := TSQLiteTable.Create( SQLiteDb, 'SELECT id,name FROM locationcategories WHERE type = 0 AND parent = 0 ORDER BY name ASC;' );
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtLocCategories.AddChild( nil );
+ Node := vtLocCategories.GetNodeData( TreeNode );
+ Node.Id := StrToInt( RootQuery.Fields[0] );
+ Node.Name := UTF8Decode(RootQuery.Fields[1]);
+
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM locationcategories WHERE type = 0 AND parent = %u', [ Node.Id ] ) );
+
+ if StrToInt(CountQuery.Fields[0]) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+ CountQuery.Free;
+ RootQuery.Next;
+ end;
+ RootQuery.Free;
+
+ RootQuery := TSQLiteTable.Create( SQLiteDb, 'SELECT id,name FROM npccategories WHERE type = 0 AND parent = 0 ORDER BY name ASC;' );
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtNpcCategories.AddChild( nil );
+ Node := vtNpcCategories.GetNodeData( TreeNode );
+ Node.Id := StrToInt( RootQuery.Fields[0] );
+ Node.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM npccategories WHERE type = 0 AND parent = %u', [ Node.Id ] ) );
+
+ if StrToInt(CountQuery.Fields[0]) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+ CountQuery.Free;
+ RootQuery.Next;
+ end;
+ RootQuery.Free;
+
+ loadMultis;
+
+ { Load UO Files }
+ Tiledata.Open(Config.getString('Tiledata.mul Path',
+ UOPath + 'tiledata.mul'));
+ Art.Open(Config.getString('Artidx.mul Path', UOPath + 'artidx.mul'),
+ Config.getString('Art.mul Path', UOPath + 'art.mul'));
+ Anim.Open(Config.getString('Anim.idx Path', UOPath + 'anim.idx'),
+ Config.getString('Anim.mul Path', UOPath + 'anim.mul'),
+ Config.getString('Anim2.idx Path', UOPath + 'anim2.idx'),
+ Config.getString('Anim2.mul Path', UOPath + 'anim2.mul'),
+ Config.getString('Anim3.idx Path', UOPath + 'anim3.idx'),
+ Config.getString('Anim3.mul Path', UOPath + 'anim3.mul'),
+ Config.getString('Bodyconv.def Path', UOPath + 'bodyconv.def'),
+ Config.getString('Body.def Path', UOPath + 'body.def'));
+ RadarCol.Load(Config.getString('Radarcol.mul Path',
+ UOPath + 'radarcol.mul'));
+ Hues.Load(Config.getString('Hues.mul Path',
+ UOPath + 'hues.mul'));
+
+ Maps[0].Open(Config.getString('Map0.mul Path', UOPath + 'map0.mul'));
+ Statics[0].Open(
+ Config.getString('Staidx0.mul Path', UOPath + 'staidx0.mul'),
+ Config.getString('Statics0.mul Path', UOPath + 'statics0.mul'));
+ Maps[1] := Maps[0];
+ Statics[1] := Statics[0];
+ Maps[2].Open(Config.getString('Map2.mul Path', UOPath + 'map2.mul'));
+ Statics[2].Open(
+ Config.getString('Staidx2.mul Path', UOPath + 'staidx2.mul'),
+ Config.getString('Statics2.mul Path', UOPath + 'statics2.mul'));
+ Maps[3].Open(Config.getString('Map3.mul Path', UOPath + 'map3.mul'));
+ Statics[3].Open(
+ Config.getString('Staidx3.mul Path', UOPath + 'staidx3.mul'),
+ Config.getString('Statics3.mul Path', UOPath + 'statics3.mul'));
+ Maps[4].Open(Config.getString('Map4.mul Path', UOPath + 'map4.mul'));
+ Statics[4].Open(
+ Config.getString('Staidx4.mul Path', UOPath + 'staidx4.mul'),
+ Config.getString('Statics4.mul Path', UOPath + 'statics4.mul'));
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox(PChar(E.Message), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+
+ // Load Position
+ Left := Config.getInt('Window Position X', Left);
+ Top := Config.getInt('Window Position Y', Top);
+ Width := Config.getInt('Window Width', Width);
+ Height := Config.getInt('Window Height', Height);
+ Pages.ActivePageIndex := Config.getInt('Current Page', 0);
+
+ if Left > Screen.Width then
+ Left := Screen.Width - Width;
+
+ if Top > Screen.Height then
+ Top := Screen.Height - Height;
+
+ for i := 0 to Config.getInt('EventCount', 0) - 1 do
+ begin
+ Value := Config.getString(Format('Event%u', [i]), '');
+
+ if Value <> '' then
+ cbEventName.Items.Add(Value);
+ end;
+
+ rebuildBuildMenu;
+ loadCustomButtons;
+end;
+
+{
+ Handler for WM_DESTROY
+}
+procedure TfrmMain.FormDestroy(Sender: TObject);
+begin
+ SQLiteDb.Free;
+ Tiledata.Free;
+
+ Art.Close;
+ Art.Free;
+
+ Anim.Close;
+ Anim.Free;
+
+ Maps[0].Close;
+ Maps[0].Free;
+
+ Statics[0].Close;
+ Statics[0].Free;
+
+ RadarCol.Free;
+ Hues.Free;
+
+ Config.Save;
+ Config.Free;
+
+ UpdateMutex.Free;
+
+ inherited;
+end;
+
+procedure TfrmMain.vtCategoriesGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+begin
+ if TextType = ttNormal then
+ CellText := PNode( Sender.GetNodeData( Node ) ).Name;
+end;
+
+{
+ An Item Category has been selected.
+}
+procedure TfrmMain.vtCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyData: PNode;
+ ItemData: PItemNode;
+ Query: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+ vtItems.Clear;
+ btnAddItem.Enabled := False;
+ btnTileItem.Enabled := False;
+
+ if Node = nil then
+ Exit;
+
+ MyData := Sender.GetNodeData(Node);
+ try
+ Query := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name,artid,addid,color FROM items WHERE parent = %u ORDER BY name;', [ MyData.Id ] ) );
+ while not Query.EOF do
+ begin
+ TreeNode := vtItems.AddChild( nil );
+ ItemData := vtItems.GetNodeData( TreeNode );
+
+ ItemData.Id := StrToInt( Query.Fields[0] );
+ ItemData.Name := UTF8Decode(Query.Fields[1]);
+ ItemData.ArtId := StrToInt( Query.Fields[2] );
+ ItemData.AddId := Query.Fields[3];
+ ItemData.Color := StrToIntDef( Query.Fields[4], 0);
+
+ Query.Next;
+ end;
+ Query.Free;
+ vtItems.SortTree(vtItems.Header.SortColumn, vtItems.Header.SortDirection);
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( 'Error retrieving ChildCount: ' + E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtItemsGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+var
+ MyData: PItemNode;
+begin
+ MyData := Sender.GetNodeData( Node );
+
+ case Column of
+ 0:
+ begin
+ if Length( MyData.Name ) = 0 then
+ CellText := Tiledata.getItemName( MyData.ArtId )
+ else
+ CellText := MyData.Name;
+ end;
+
+ 1: CellText := MyData.AddId;
+ end;
+end;
+
+procedure TfrmMain.vtCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+var
+ MyData: PNode;
+ RootQuery, CountQuery: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+ // Children Already Added
+ if ( Sender.ChildCount[ Node ] > 0 ) or not ( vsHasChildren in Node.States ) then
+ exit;
+
+ // Add the Children
+ MyData := Sender.GetNodeData( Node );
+
+ try
+ RootQuery := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name FROM categories WHERE type = 0 AND parent = %u ORDER BY name ASC;', [ MyData.Id ] ) );
+
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtCategories.AddChild( Node );
+ MyData := vtCategories.GetNodeData( TreeNode );
+ MyData.Id := StrToInt( RootQuery.Fields[0] );
+ MyData.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM categories WHERE type = 0 AND parent = %u', [ MyData.Id ] ) );
+
+ if StrToInt( CountQuery.Fields[0] ) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+
+ CountQuery.Free;
+
+ RootQuery.Next;
+ end;
+
+ RootQuery.Free;
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtItemsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ MyData1, MyData2: PItemNode;
+begin
+ MyData1 := Sender.GetNodeData( Node1 );
+ MyData2 := Sender.GetNodeData( Node2 );
+
+ case Column of
+ 0: Result := CompareStr( MyData1.Name, MyData2.Name );
+ 1: Result := CompareStr( MyData1.AddId, MyData2.AddId );
+ end;
+end;
+
+procedure TfrmMain.vtItemsHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+begin
+ // When changing we keep our sort direction
+ if Sender.SortColumn = Column then
+ begin
+ if Sender.SortDirection = sdAscending then
+ Sender.SortDirection := sdDescending
+ else
+ Sender.SortDirection := sdAscending;
+ exit;
+ end;
+
+ Sender.SortColumn := Column;
+ Sender.SortDirection := sdAscending;
+end;
+
+procedure TfrmMain.btnAddItemClick(Sender: TObject);
+var
+ NodeData: PItemNode;
+ Node: PVirtualNode;
+begin
+ Node := vtItems.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtItems.GetNodeData(Node);
+ if cbStatic.Checked then
+ SendCommand('static ' + NodeData.AddId, true)
+ else
+ SendCommand('add ' + NodeData.AddId, true);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.vtItemsChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyItemData: PItemNode;
+ btmap: TBitmap32;
+begin
+ // Display a Preview Item
+ if Node <> nil then
+ begin
+ MyItemData := Sender.GetNodeData(Node);
+ btmap := Art.GetTile(MyItemData.ArtId, MyItemData.Color);
+ imgItemPreview.Bitmap.SetSizeFrom(btmap);
+ imgItemPreview.Bitmap.Clear(Color32(clBtnFace));
+ btmap.DrawTo(imgItemPreview.Bitmap, 0, 0);
+ end else begin
+ imgItemPreview.Bitmap.SetSize(0, 0);
+ end;
+
+ btnAddItem.Enabled := False;
+ btnTileItem.Enabled := False;
+
+ // See if there is some selected node
+ Node := vtItems.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ btnAddItem.Enabled := True;
+ btnTileItem.Enabled := True;
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.btnRemoveItemClick(Sender: TObject);
+begin
+ SendCommand('remove', true);
+end;
+
+procedure TfrmMain.cbAlwaysOnTopClick(Sender: TObject);
+var
+ lastpage: Integer;
+begin
+ lastpage := Pages.ActivePageIndex;
+
+ if not cbAlwaysOnTop.Checked then
+ frmMain.FormStyle := fsNormal
+ else
+ frmMain.FormStyle := fsStayOnTop;
+
+ Pages.ActivePageIndex := lastpage;
+end;
+
+procedure TfrmMain.btnSaveClick(Sender: TObject);
+begin
+ Config.setBool('Always On Top', cbAlwaysOnTop.Checked);
+ Config.setString('Command Prefix', eCommandPrefix.Text);
+ Config.Save;
+end;
+
+procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
+var
+ i: Integer;
+begin
+ // Save Position
+ Config.setInt('Window Position X', Left);
+ Config.setInt('Window Position Y', Top);
+ Config.setInt('Window Width', Width);
+ Config.setInt('Window Height', Height);
+ Config.setInt('Current Page', Pages.ActivePageIndex);
+
+ // Save the history of event names
+ Config.setInt('EventCount', cbEventName.Items.Count);
+ for i := 0 to cbEventName.Items.Count - 1 do
+ begin
+ Config.setString(Format('Event%u', [i]), cbEventName.Items[i]);
+ end;
+
+ inherited;
+end;
+
+procedure TfrmMain.rebuildBuildMenu;
+var
+ i: Integer;
+begin
+ if sbBuild.ControlCount > 0 then begin
+ UpdateMutex.Enter;
+ BuildCurrentX := 8;
+ BuildCurrentY := 8 - sbBuild.VertScrollBar.Position;
+
+ for i := 0 to sbBuild.ControlCount - 1 do begin
+ // Reposition
+ sbBuild.Controls[i].Left := BuildCurrentX;
+ sbBuild.Controls[i].Top := BuildCurrentY;
+
+ Inc(BuildCurrentX, sbBuild.Controls[i].Width + 8);
+
+ // If the next button wouldn't fit anymore, go to the next row
+ if BuildCurrentX + sbBuild.Controls[i].Width + 8 > sbBuild.ClientWidth then begin
+ BuildCurrentX := 8;
+ Inc(BuildCurrentY, sbBuild.Controls[i].Height + 8);
+ end;
+ end;
+ UpdateMutex.Leave;
+ exit;
+ end;
+
+ BuildCurrentX := 8;
+ BuildCurrentY := 8;
+
+ // Add Build Table
+ addBuildButton('woodenboardse', $4ab, 'Floor');
+ addBuildButton('woodenboardsn', $4b5, 'Floor');
+
+ addBuildButton('woodenplankse', $4c7, 'Floor');
+ addBuildButton('woodenplanksn', $4d5, 'Floor');
+
+ addBuildButton('woodenlogse1', $507, 'Floor');
+ addBuildButton('woodenlogse2', $505, 'Floor');
+
+ addBuildButton('woodenlogsn1', $4c2, 'Floor');
+ addBuildButton('woodenlogsn2', $4c4, 'Floor');
+
+ addBuildButton('redfloor', $4f3, 'Floor');
+ addBuildButton('bluefloor', $4f2, 'Floor');
+
+ // Walls
+ addBuildButton('wall1', $1c, 'Wall');
+ addBuildButton('wall1small', $25, 'Wall');
+ addBuildButton('wall1tiny', $2f, 'Wall');
+
+ addBuildButton('wall2', $58, 'Wall');
+ addBuildButton('wall2small', $5f, 'Wall');
+ addBuildButton('wall2smaller', $63, 'Wall');
+ addBuildButton('wall2tiny', $69, 'Wall');
+
+ addBuildButton('wall3small', $2ce, 'Wall');
+
+ addBuildButton('wall4', $c8, 'Wall');
+ addBuildButton('wall4small', $de, 'Wall');
+
+ addBuildButton('wall5', $1d0, 'Wall');
+ addBuildButton('wall5small', $1e9, 'Wall');
+
+ addBuildButton('woodenwall1', $c, 'Wall');
+ addBuildButton('woodenwall1small', $12, 'Wall');
+ addBuildButton('woodenwall1tiny', $16, 'Wall');
+ addBuildButton('woodenwall2', $a8, 'Wall');
+ addBuildButton('woodenwall2small', $b7, 'Wall');
+ addBuildButton('woodenwall2tiny', $bf, 'Wall');
+
+ addBuildButton('plasterwall1', $12e, 'Wall');
+ addBuildButton('plasterwall1wrecked', $389, 'Wall');
+ addBuildButton('brickwall', $34, 'Wall');
+ addBuildButton('brickwallsmall', $3e, 'Wall');
+ addBuildButton('brickwalltiny', $42, 'Wall');
+
+ // Roofs
+ addBuildButton('slateroofe', $5a1, 'Roof');
+ addBuildButton('slateroofn', $595, 'Roof');
+ addBuildButton('stonetileroofe', $193d, 'Roof');
+ addBuildButton('stonetileroofn', $193e, 'Roof');
+ addBuildButton('thatchroofe', $5a8, 'Roof');
+ addBuildButton('thatchroofn', $5a5, 'Roof');
+ addBuildButton('tileroofe', $5bf, 'Roof');
+ addBuildButton('tileroofn', $5b3, 'Roof');
+ addBuildButton('woodenshinglese', $5ce, 'Roof');
+ addBuildButton('woodenshinglesn', $5c2, 'Roof');
+ addBuildButton('palmroofe', $593, 'Roof');
+ addBuildButton('palmroofn', $590, 'Roof');
+ addBuildButton('logroofe', $5fc, 'Roof');
+ addBuildButton('logroofn', $5f0, 'Roof');
+ addBuildButton('hayroofe', $26ea, 'Roof');
+ addBuildButton('hayroofn', $26da, 'Roof');
+ addBuildButton('woodenslatee', $28d8, 'Roof');
+ addBuildButton('woodenslaten', $28c8, 'Roof');
+ addBuildButton('barkroofe', $2708, 'Roof');
+ addBuildButton('barkroofn', $26f8, 'Roof');
+
+ // Carpets
+ addBuildButton('bluecarpet1a', $abe, 'Carpet');
+ addBuildButton('bluecarpet1b', $abd, 'Carpet');
+ addBuildButton('bluecarpet1c', $abf, 'Carpet');
+ addBuildButton('bluecarpet1d', $ac0, 'Carpet');
+ addBuildButton('bluecarpet2', $ad1, 'Carpet');
+ addBuildButton('bluecarpet3a', $aec, 'Carpet');
+ addBuildButton('bluecarpet3b', $aed, 'Carpet');
+ addBuildButton('browncarpet', $ada, 'Carpet');
+
+ addBuildButton('redcarpet1a', $ac8, 'Carpet');
+ addBuildButton('redcarpet1b', $ac6, 'Carpet');
+ addBuildButton('redcarpet1c', $ac7, 'Carpet');
+ addBuildButton('redcarpet2', $aeb, 'Carpet');
+ addBuildButton('grayrug', $1df7, 'Carpet');
+ addBuildButton('greenrug1', $ab3, 'Carpet');
+ addBuildButton('greenrug2', $1dea, 'Carpet');
+ addBuildButton('greenrug3', $1de9, 'Carpet');
+
+ addBuildButton('bearskinn', $1e37, 'Carpet');
+ addBuildButton('bearskine', $1e41, 'Carpet');
+ addBuildButton('polarskinn', $1e4a, 'Carpet');
+ addBuildButton('polarskine', $1e54, 'Carpet');
+
+ addBuildButton('stonefountain', $1e4a, 'Fountains');
+ addBuildButton('sandstonefountain', $1e54, 'Fountains');
+end;
+
+procedure TfrmMain.pbMapPaintBuffer(Sender: TObject);
+var
+ x, y: Integer;
+ mapx, mapy: Integer;
+ MapLeft, MapTop: Integer;
+ MapCell: TMapCell;
+ StaticBlock: TStaticBlock;
+ i: Integer;
+ RelX, RelY: Byte;
+ HighestZ: Shortint;
+ Map: TMapReader;
+ Static: TStaticReader;
+ Width, Height: Word;
+ Position: String;
+ TextY: Integer;
+ Color: TColor;
+begin
+ MapLeft := - (pbMap.Width div 2);
+ MapTop := - (pbMap.Height div 2);
+
+ if MapCenterMap > 4 then
+ exit;
+
+ Width := Maps[MapCenterMap].getWidth * 8;
+ Height := Maps[MapCenterMap].getHeight * 8;
+
+ Map := Maps[MapCenterMap];
+ Static := Statics[MapCenterMap];
+
+ pbMap.Buffer.Clear(clBlack32);
+ for x := 0 to pbMap.Width do
+ begin
+ for y := 0 to pbMap.Height do
+ begin
+ mapx := Integer(MapCenterX) + x + MapLeft;
+ mapy := Integer(MapCenterY) + y + MapTop;
+
+ if (mapx >= Width) or (mapy >= Height) then begin
+ pbMap.Buffer.PixelS[x, y] := clBlack32;
+ continue;
+ end;
+
+ if (mapx >= 0) and (mapy >= 0) then begin
+ Map.ReadCell(mapx, mapy, MapCell);
+ pbMap.Buffer.PixelS[x, y] := RadarCol.GetLandColor(MapCell.Id);
+
+ RelX := mapx mod 8;
+ RelY := mapy mod 8;
+ HighestZ := MapCell.Height;
+ Static.ReadBlock(mapx div 8, mapy div 8, StaticBlock);
+ for i := 0 to Length(StaticBlock) - 1 do begin
+ if (StaticBlock[i].X = RelX) and (StaticBlock[i].Y = RelY)
+ and (StaticBlock[i].Z >= HighestZ) then begin
+ if StaticBlock[i].Hue = 0 then
+ pbMap.Buffer.PixelS[x, y] :=
+ RadarCol.GetItemColor(StaticBlock[i].Id)
+ else begin
+ // A little more complicated
+ //pbMap.Buffer.PixelS[x, y] := Color32(Color15to24(StaticBlock[i].Hue));
+ Color := RadarCol.GetItemColor(StaticBlock[i].Id);
+ Color := Hues.translateColor(StaticBlock[i].Hue, Color);
+ pbMap.Buffer.PixelS[x, y] := Color;
+ end;
+
+ HighestZ := StaticBlock[i].Z;
+ end;
+ end;
+
+ if (Cardinal(mapx) = MapCenterX) and
+ (Cardinal(mapy) = MapCenterY) then begin
+ MapCenterZ := HighestZ;
+ pbMap.Buffer.PixelS[x, y] := clWhite32;
+ continue;
+ end;
+ end else begin
+ pbMap.Buffer.PixelS[x, y] := clGray32;
+ end;
+ end;
+ end;
+
+ // Show the current location
+ Position := Format('%u,%u,%d,%u', [MapCenterX, MapCenterY,
+ MapCenterZ, MapCenterMap]);
+ TextY := pbMap.Height - 2 - pbMap.Buffer.TextHeight(Position);
+ pbMap.Buffer.Font.Color := clWhite;
+ pbMap.Buffer.Textout(2, TextY, Position);
+end;
+
+procedure TfrmMain.pbMapMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+var
+ RelX, RelY: Integer;
+ Width, Height: Cardinal;
+begin
+ if MapCenterMap > 4 then
+ exit;
+
+ if Button <> mbLeft then
+ exit;
+
+ Width := Maps[MapCenterMap].getWidth * 8;
+ Height := Maps[MapCenterMap].getHeight * 8;
+
+ RelX := X - pbMap.Width div 2;
+ RelY := y - pbMap.Height div 2;
+
+ if Integer(MapCenterX) + RelX >= 0 then begin
+ MapCenterX := Integer(MapCenterX) + RelX;
+ end else begin
+ MapCenterX := 0;
+ end;
+
+ if Integer(MapCenterY) + RelY >= 0 then begin
+ MapCenterY := Integer(MapCenterY) + RelY;
+ end else begin
+ MapCenterY := 0;
+ end;
+
+ if MapCenterX >= Width then
+ MapCenterX := Width - 1;
+
+ if MapCenterY >= Height then
+ MapCenterY := Height - 1;
+
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.vtLocCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+var
+ MyData: PNode;
+ RootQuery, CountQuery: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+ // Children Already Added
+ if ( Sender.ChildCount[ Node ] > 0 ) or not ( vsHasChildren in Node.States ) then
+ exit;
+
+ // Add the Children
+ MyData := Sender.GetNodeData( Node );
+
+ try
+ RootQuery := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name FROM locationcategories WHERE type = 0 AND parent = %u ORDER BY name ASC;', [ MyData.Id ] ) );
+
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtLocCategories.AddChild( Node );
+ MyData := vtLocCategories.GetNodeData( TreeNode );
+ MyData.Id := StrToInt( RootQuery.Fields[0] );
+ MyData.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM locationcategories WHERE type = 0 AND parent = %u', [ MyData.Id ] ) );
+
+ if StrToInt( CountQuery.Fields[0] ) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+
+ CountQuery.Free;
+
+ RootQuery.Next;
+ end;
+
+ RootQuery.Free;
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+
+procedure TfrmMain.vtLocCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyData: PNode;
+ LocationData: PLocationNode;
+ Query: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+
+
+ vtLocItems.Clear;
+ if Node = nil then
+ Exit;
+ MyData := Sender.GetNodeData(Node);
+ try
+ Query := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name,posx,posy,posz,posmap,location FROM locations WHERE parent = %u ORDER BY name;', [ MyData.Id ] ) );
+ while not Query.EOF do
+ begin
+ TreeNode := vtLocItems.AddChild( nil );
+ LocationData := vtLocItems.GetNodeData(TreeNode);
+
+ LocationData.Id := StrToInt( Query.Fields[0] );
+ LocationData.Name := UTF8Decode(Query.Fields[1]);
+ LocationData.PosX := StrToInt(Query.Fields[2]);
+ LocationData.PosY := StrToInt(Query.Fields[3]);
+ LocationData.PosZ := StrToInt(Query.Fields[4]);
+ LocationData.PosMap := StrToInt(Query.Fields[5]);
+ LocationData.LocId := Query.Fields[6];
+ Query.Next;
+ end;
+ Query.Free;
+ vtLocItems.SortTree(vtLocItems.Header.SortColumn, vtLocItems.Header.SortDirection);
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( 'Error retrieving ChildCount: ' + E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtLocItemsGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+var
+ MyData: PLocationNode;
+begin
+ myData := Sender.GetNodeData( Node );
+
+ case Column of
+ 0:
+ begin
+ CellText := MyData.Name;
+ end;
+ end;
+
+end;
+
+procedure TfrmMain.vtLocItemsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ MyData1, MyData2: PLocationNode;
+begin
+ MyData1 := Sender.GetNodeData( Node1 );
+ MyData2 := Sender.GetNodeData( Node2 );
+ Result := CompareStr( MyData1.Name, MyData2.Name );
+end;
+
+procedure TfrmMain.vtLocItemsHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+begin
+ // When changing we keep our sort direction
+ if Sender.SortDirection = sdAscending then
+ Sender.SortDirection := sdDescending
+ else
+ Sender.SortDirection := sdAscending;
+end;
+
+procedure TfrmMain.vtLocItemsChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ LocationData: PLocationNode;
+begin
+ // Display a Preview Item
+ if Node <> nil then begin
+ LocationData := Sender.GetNodeData(Node);
+ MapCenterX := LocationData.PosX;
+ MapCenterY := LocationData.PosY;
+ MapCenterZ := LocationData.PosZ;
+ MapCenterMap := LocationData.PosMap;
+ pbMap.Invalidate;
+ end;
+end;
+
+procedure TfrmMain.Go1Click(Sender: TObject);
+begin
+ SendCommand(Format('go %u,%u,%d,%u',
+ [MapCenterX, MapCenterY, MapCenterZ, MapCenterMap]));
+end;
+
+procedure TfrmMain.btnSendClick(Sender: TObject);
+begin
+ SendCommand(Format('send %u,%u,%d,%u',
+ [MapCenterX, MapCenterY, MapCenterZ, MapCenterMap]));
+end;
+
+procedure TfrmMain.btnCmdAllmoveClick(Sender: TObject);
+begin
+ SendCommand('allmove');
+end;
+
+procedure TfrmMain.btnCmdAllshowClick(Sender: TObject);
+begin
+ SendCommand('allshow');
+end;
+
+procedure TfrmMain.btnCmdInvisibleClick(Sender: TObject);
+begin
+ SendCommand('invis');
+end;
+
+procedure TfrmMain.btnCmdStaffClick(Sender: TObject);
+begin
+ SendCommand('staff');
+end;
+
+procedure TfrmMain.btnCmdInvulClick(Sender: TObject);
+begin
+ SendCommand('invul');
+end;
+
+procedure TfrmMain.btnCmdShutdownClick(Sender: TObject);
+begin
+ if Application.MessageBox('Do you really want to close the Wolfpack server?',
+ 'Shutdown', MB_YESNO+MB_ICONQUESTION) = IDYES then
+ SendCommand('shutdown');
+end;
+
+procedure TfrmMain.btnCmdReloadAllClick(Sender: TObject);
+begin
+ SendCommand('reload all');
+end;
+
+procedure TfrmMain.btnCmdReloadConfigClick(Sender: TObject);
+begin
+ SendCommand('reload configuration');
+end;
+
+procedure TfrmMain.btnCmdReloadAccountsClick(Sender: TObject);
+begin
+ SendCommand('reload accounts');
+end;
+
+procedure TfrmMain.btnCmdReloadPythonClick(Sender: TObject);
+begin
+ SendCommand('reload python');
+end;
+
+procedure TfrmMain.btnCmdReloadScriptsClick(Sender: TObject);
+begin
+ SendCommand('reload scripts');
+end;
+
+procedure TfrmMain.btnCmdDyeClick(Sender: TObject);
+begin
+ SendCommand(Format('dye %u', [StrToIntDef(eItemHue.Text, 0)]), True);
+end;
+
+procedure TfrmMain.pbHuePreviewPaintBuffer(Sender: TObject);
+var
+ i: Integer;
+ Width: Integer;
+ Hue: Word;
+begin
+ Hue := StrToIntDef(eItemHue.Text, 0);
+
+ if Hue = 0 then begin
+ pbHuePreview.Buffer.Clear(clGray32);
+ exit;
+ end;
+
+ Width := Ceil(pbHuePreview.Width / 32.0);
+ for i := 0 to 31 do
+ begin
+ pbHuePreview.Buffer.FillRect(i * Width, 0, (i + 1) * Width,
+ pbHuePreview.Height, Hues.getColor(Hue, i));
+ end;
+end;
+
+procedure TfrmMain.eItemHueChange(Sender: TObject);
+begin
+ pbHuePreview.Invalidate;
+end;
+
+procedure TfrmMain.btnChangeItemHueClick(Sender: TObject);
+begin
+ frmChooseHue.ShowModal;
+
+ if frmChooseHue.ModalResult = mrOk then
+ begin
+ eItemHue.Text := '0x' + IntToHex(frmChooseHue.ColorId, 0);
+ pbHuePreview.Invalidate;
+ end;
+end;
+
+procedure TfrmMain.btnCmdDupeClick(Sender: TObject);
+begin
+ SendCommand('dupe', True);
+end;
+
+procedure TfrmMain.btnCmdInfoClick(Sender: TObject);
+begin
+ SendCommand('info', True);
+end;
+
+procedure TfrmMain.btnCmdRemoveClick(Sender: TObject);
+begin
+ SendCommand('remove', True);
+end;
+
+procedure TfrmMain.btnCmdLockClick(Sender: TObject);
+begin
+ SendCommand('lock', True);
+end;
+
+procedure TfrmMain.btnCmdNukeClick(Sender: TObject);
+begin
+ SendCommand('nuke', True);
+end;
+
+procedure TfrmMain.btnCmdItemSetClick(Sender: TObject);
+begin
+ SendCommand(Format('set %s %s', [cbItemProperty.Text, eItemPropValue.Text]), True);
+end;
+
+procedure TfrmMain.btnCmdItemShowClick(Sender: TObject);
+begin
+ SendCommand(Format('show %s', [cbItemProperty.Text]), True);
+end;
+
+procedure TfrmMain.cbItemPropertyChange(Sender: TObject);
+begin
+ btnCmdItemSet.Enabled := Length(cbItemProperty.Text) <> 0;
+ btnCmdItemShow.Enabled := Length(cbItemProperty.Text) <> 0;
+end;
+
+procedure TfrmMain.btnCmdItemTileColorClick(Sender: TObject);
+begin
+ SendCommand('tilecolor ' + eItemHue.Text, true);
+end;
+
+procedure TfrmMain.btnTagInfoClick(Sender: TObject);
+begin
+ SendCommand('taginfo', True);
+end;
+
+procedure TfrmMain.eTagNameChange(Sender: TObject);
+begin
+ btnTagSet.Enabled := Length(eTagName.Text) > 0;
+ btnTagShow.Enabled := btnTagSet.Enabled;
+ btnTagDelete.Enabled := btnTagSet.Enabled;
+end;
+
+procedure TfrmMain.btnTagSetClick(Sender: TObject);
+var
+ TagType: String;
+begin
+ TagType := 'string';
+ if cbTagType.ItemIndex = 1 then
+ TagType := 'int'
+ else if cbTagType.ItemIndex = 2 then
+ TagType := 'float';
+
+ if AnsiStrPos(PAnsiChar(eTagName.Text), ' ') <> nil then begin
+ Application.MessageBox('Tag names may not contain spaces.', 'Error',
+ MB_ICONERROR+MB_OK);
+ exit;
+ end;
+
+ SendCommand(format('settag %s %s %s',
+ [eTagName.Text, TagType, eTagValue.Text]), True);
+end;
+
+procedure TfrmMain.btnTagShowClick(Sender: TObject);
+begin
+ if AnsiStrPos(PAnsiChar(eTagName.Text), ' ') <> nil then begin
+ Application.MessageBox('Tag names may not contain spaces.', 'Error',
+ MB_ICONERROR+MB_OK);
+ exit;
+ end;
+
+ SendCommand(format('gettag %s', [eTagName.Text]), True);
+end;
+
+procedure TfrmMain.btnTagDeleteClick(Sender: TObject);
+begin
+ if AnsiStrPos(PAnsiChar(eTagName.Text), ' ') <> nil then begin
+ Application.MessageBox('Tag names may not contain spaces.', 'Error',
+ MB_ICONERROR+MB_OK);
+ exit;
+ end;
+
+ SendCommand(format('deltag %s', [eTagName.Text]), True);
+end;
+
+procedure TfrmMain.btnCmdSendOtherClick(Sender: TObject);
+begin
+ SendCommand('send', True);
+end;
+
+procedure TfrmMain.Button2Click(Sender: TObject);
+begin
+ SendCommand('tele', True);
+end;
+
+procedure TfrmMain.btnCmdMoveClick(Sender: TObject);
+begin
+ SendCommand(format('move %d,%d,%d',
+ [StrToIntDef(eMoveX.Text, 0), StrToIntDef(eMoveY.Text, 0),
+ StrToIntDef(eMoveZ.Text, 0)]), True);
+end;
+
+procedure TfrmMain.btnCmdMoveUpClick(Sender: TObject);
+begin
+ SendCommand('move 0,0,1', True);
+end;
+
+procedure TfrmMain.btnCmdMoveDownClick(Sender: TObject);
+begin
+ SendCommand('move 0,0,-1', True);
+end;
+
+procedure TfrmMain.btnTileItemClick(Sender: TObject);
+var
+ NodeData: PItemNode;
+ Node: PVirtualNode;
+ Ids: String;
+begin
+ Node := vtItems.RootNode.FirstChild;
+ Ids := '';
+
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtItems.GetNodeData(Node);
+ if Length(Ids) > 0 then
+ Ids := Ids + ',' + NodeData.AddId
+ else
+ Ids := NodeData.AddId;
+ end;
+ Node := Node.NextSibling;
+ end;
+
+ SendCommand(format('tile %d %s',
+ [StrToIntDef(eZLevel.Text, 0), Ids]), True);
+end;
+
+procedure TfrmMain.btnCmdShowEventlistClick(Sender: TObject);
+begin
+ SendCommand('show scriptlist', True);
+end;
+
+procedure TfrmMain.eEventNameChange(Sender: TObject);
+begin
+ btnCmdAddEvent.Enabled := Length(cbEventName.Text) > 0;
+ btnCmdRemoveEvent.Enabled := Length(cbEventName.Text) > 0;
+end;
+
+procedure TfrmMain.btnCmdAddEventClick(Sender: TObject);
+var
+ i: Integer;
+begin
+ SendCommand(format('addscript %s', [cbEventName.Text]), True);
+
+ // Add the text to the history if it's not already in there
+ for i := 0 to cbEventName.Items.Count - 1 do
+ begin
+ if cbEventName.Items[i] = cbEventName.Text then
+ exit;
+ end;
+
+ cbEventName.Items.Add(cbEventName.Text);
+end;
+
+procedure TfrmMain.btnCmdRemoveEventClick(Sender: TObject);
+var
+ i: Integer;
+begin
+ SendCommand(format('removescript %s', [cbEventName.Text]), True);
+
+ // Add the text to the history if it's not already in there
+ for i := 0 to cbEventName.Items.Count - 1 do
+ begin
+ if cbEventName.Items[i] = cbEventName.Text then
+ exit;
+ end;
+
+ cbEventName.Items.Add(cbEventName.Text);
+end;
+
+procedure TfrmMain.btnCmdWhereClick(Sender: TObject);
+begin
+ SendCommand('where');
+end;
+
+procedure TfrmMain.btnCmdServertimeClick(Sender: TObject);
+begin
+ SendCommand('servertime');
+end;
+
+procedure TfrmMain.vtNpcCategoriesExpanding(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; var Allowed: Boolean);
+var
+ MyData: PNode;
+ RootQuery, CountQuery: TSQLiteTable;
+ TreeNode: PVirtualNode;
+begin
+ // Children Already Added
+ if ( Sender.ChildCount[ Node ] > 0 ) or not ( vsHasChildren in Node.States ) then
+ exit;
+
+ // Add the Children
+ MyData := Sender.GetNodeData( Node );
+
+ try
+ RootQuery := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name FROM npccategories WHERE type = 0 AND parent = %u ORDER BY name ASC;', [ MyData.Id ] ) );
+
+ while not RootQuery.EOF do
+ begin
+ TreeNode := vtNpcCategories.AddChild( Node );
+ MyData := vtNpcCategories.GetNodeData( TreeNode );
+ MyData.Id := StrToInt( RootQuery.Fields[0] );
+ MyData.Name := UTF8Decode(RootQuery.Fields[1]);
+ TreeNode.States := [ vsInitialized ] + TreeNode.States;
+
+ // Check for Children
+ CountQuery := SQLiteDb.GetTable( Format( 'SELECT COUNT(*) FROM npccategories WHERE type = 0 AND parent = %u', [ MyData.Id ] ) );
+
+ if StrToInt( CountQuery.Fields[0] ) > 0 then
+ TreeNode.States := [ vsHasChildren ] + TreeNode.States;
+
+ CountQuery.Free;
+
+ RootQuery.Next;
+ end;
+
+ RootQuery.Free;
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtNpcCategoriesChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyData: PNode;
+ ItemData: PNpcNode;
+ Query, SubQuery: TSQLiteTable;
+ TreeNode: PVirtualNode;
+ i: Integer;
+begin
+ vtNpcs.Clear;
+ btnAddNpc.Enabled := False;
+ btnNpcSpawn.Enabled := False;
+
+ if Node = nil then
+ Exit;
+
+ MyData := Sender.GetNodeData(Node);
+ try
+ Query := TSQLiteTable.Create( SQLiteDb, Format( 'SELECT id,name,bodyid,addid,skin FROM npcs WHERE parent = %u ORDER BY name;', [ MyData.Id ] ) );
+ while not Query.EOF do
+ begin
+ TreeNode := vtNpcs.AddChild( nil );
+ ItemData := vtNpcs.GetNodeData( TreeNode );
+
+ ItemData.Id := StrToInt( Query.Fields[0] );
+ ItemData.Name := UTF8Decode(Query.Fields[1]);
+ ItemData.BodyId := StrToInt( Query.Fields[2] );
+ ItemData.AddId := Query.Fields[3];
+ ItemData.Skin := StrToIntDef( Query.Fields[4], 0);
+
+ SubQuery := TSQLiteTable.Create(SQLiteDb, Format('SELECT layer,artid,color FROM npcequipment WHERE id = %u ORDER BY layer DESC', [ ItemData.Id ] ) );
+
+ while not SubQuery.Eof do
+ begin
+ i := Length(ItemData.Equipment);
+ SetLength(ItemData.Equipment, i + 1);
+ ItemData.Equipment[i].Layer := StrToInt( SubQuery.Fields[0] );
+ ItemData.Equipment[i].Anim := StrToInt( SubQuery.Fields[1] );
+ ItemData.Equipment[i].Color := StrToInt( SubQuery.Fields[2] );
+ SubQuery.Next;
+ end;
+
+ SubQuery.Free;
+
+ Query.Next;
+ end;
+ Query.Free;
+ vtNpcs.SortTree(vtNpcs.Header.SortColumn, vtNpcs.Header.SortDirection);
+ except
+ on E: Exception do
+ begin
+ Application.MessageBox( PChar( 'Error retrieving ChildCount: ' + E.Message ), 'Error', MB_OK+MB_ICONERROR );
+ PostQuitMessage( 0 );
+ Exit;
+ end;
+ end;
+end;
+
+procedure TfrmMain.vtNpcsCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ MyData1, MyData2: PNpcNode;
+begin
+ MyData1 := Sender.GetNodeData( Node1 );
+ MyData2 := Sender.GetNodeData( Node2 );
+
+ case Column of
+ 0: Result := CompareStr( MyData1.Name, MyData2.Name );
+ 1: Result := CompareStr( MyData1.AddId, MyData2.AddId );
+ end;
+
+end;
+
+procedure TfrmMain.vtNpcsGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+var
+ MyData: PNpcNode;
+begin
+ MyData := Sender.GetNodeData( Node );
+
+ case Column of
+ 0: CellText := MyData.Name;
+ 1: CellText := MyData.AddId;
+ end;
+end;
+
+procedure TfrmMain.btnRemoveNpcClick(Sender: TObject);
+begin
+ SendCommand('remove', true);
+end;
+
+procedure TfrmMain.btnAddNpcClick(Sender: TObject);
+var
+ NodeData: PNpcNode;
+ Node: PVirtualNode;
+begin
+ Node := vtNpcs.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtNpcs.GetNodeData(Node);
+ SendCommand('add ' + NodeData.AddId, true);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.vtNpcsChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+var
+ MyItemData: PNpcNode;
+ frames: TAnimation;
+ i, j: Integer;
+
+ const LayerOrder: Array[0..21] of Byte = ( 20, 5, 4, 3, 24, 23, 13, 19, 17, 22, 12, 14, 8, 7, 1, 2, 10, 16, 11, 18, 6, 21 );
+begin
+ animtimer.Enabled := false;
+
+ for i := 0 to Length(npcPreview) - 1 do
+ npcPreview[i].Free;
+
+ SetLength(npcPreview, 0);
+
+ // Display a Preview Item
+ if Node <> nil then
+ begin
+ MyItemData := Sender.GetNodeData(Node);
+
+ frames := Anim.GetFrames(MyItemData.BodyId, 1, MyItemData.Skin);
+
+ if frames <> nil then begin
+ SetLength(npcPreview, 1);
+ npcPreview[0] := frames;
+
+ // Add Equipment
+ for j := 0 to Length(LayerOrder) - 1 do begin
+ for i := 0 to Length(MyItemData.Equipment) - 1 do begin
+ if MyItemData.Equipment[i].Layer = LayerOrder[j] then begin
+ frames := Anim.GetFrames(MyItemData.Equipment[i].Anim, 1, MyItemData.Equipment[i].Color);
+ if frames <> nil then begin
+ SetLength(npcPreview, Length(npcPreview) + 1);
+ npcPreview[Length(npcPreview) - 1] := frames;
+ end;
+ end;
+ end;
+ end;
+
+ npcPreviewFrame := 0;
+ pbNpcPreview.Invalidate;
+ animtimer.Interval := npcPreview[0].frameDelay;
+ animtimer.Enabled := true;
+ end;
+
+ end else begin
+ pbNpcPreview.Invalidate;
+ end;
+
+ btnAddNpc.Enabled := False;
+ btnNpcSpawn.Enabled := False;
+
+ // See if there is some selected node
+ Node := vtNpcs.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ btnAddNpc.Enabled := True;
+ btnNpcSpawn.Enabled := True;
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.vtNpcsHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+begin
+ // When changing we keep our sort direction
+ if Sender.SortColumn = Column then
+ begin
+ if Sender.SortDirection = sdAscending then
+ Sender.SortDirection := sdDescending
+ else
+ Sender.SortDirection := sdAscending;
+ exit;
+ end;
+
+ Sender.SortColumn := Column;
+ Sender.SortDirection := sdAscending;
+end;
+
+procedure TFrmMain.pixelCombine(F: TColor32; var B: TColor32; M: TColor32);
+begin
+
+end;
+
+procedure TfrmMain.pbNpcPreviewPaintBuffer(Sender: TObject);
+var
+ pb: TPaintBox32;
+ totalHeight, totalWidth, i, xpos, ypos: Integer;
+ frame: PAnimFrame;
+begin
+ if not (Sender is TPaintBox32) then
+ exit;
+
+ pb := Sender as TPaintBox32;
+ pb.Buffer.Clear(clGray32);
+
+ // Draw Centered
+ if (npcPreview <> nil) and (length(npcPreview) > 0) then begin
+ // Measure Total Height and Width
+ totalHeight := 0;
+ totalWidth := 0;
+
+ for i := 0 to Length(npcPreview) - 1 do begin
+ totalHeight := Max(npcPreview[i].getTotalHeight, totalHeight);
+ totalWidth := Max(npcPreview[i].getTotalWidth, totalWidth);
+ end;
+
+ xpos := (pb.ClientWidth div 2);
+ ypos := (pb.ClientHeight div 2) + (totalHeight div 2);
+
+ for i := 0 to Length(npcPreview) - 1 do begin
+ frame := npcPreview[i].getFrame(npcPreviewFrame);
+
+ if frame <> nil then begin
+ pb.Buffer.Draw(xpos - frame.CenterX, ypos - frame.image.height - frame.CenterY, frame.Image);
+ end;
+ end;
+ end;
+end;
+
+procedure TfrmMain.animtimerTimer(Sender: TObject);
+begin
+ if (npcPreview <> nil) and (npcPreview[0].frameCount > 0) then begin
+ npcPreviewFrame := (npcPreviewFrame + 1) mod npcPreview[0].frameCount;
+ pbNpcPreview.Invalidate;
+ end;
+end;
+
+procedure TfrmMain.loadMultis;
+var
+ Query: TSQLiteTable;
+ Node: PVirtualNode;
+ Data: PMultiNode;
+begin
+ try
+ Query := TSQLiteTable.Create(SQLiteDb, 'SELECT id,name,addid,multiid FROM multis;');
+
+ while not Query.EOF do begin
+ Node := vtMultis.AddChild(nil);
+ Data := vtMultis.GetNodeData(Node);
+
+ Data.Id := StrToInt(Query.Fields[0]);
+ Data.Name := UTF8Decode(Query.Fields[1]);
+ Data.AddId := Query.Fields[2];
+ Data.MultiId := StrToInt(Query.Fields[0]);
+
+ Query.Next;
+ end;
+
+ Query.Free;
+ vtMultis.SortTree(vtMultis.Header.SortColumn, vtMultis.Header.SortDirection);
+ except
+ on E: Exception do
+ Application.MessageBox(PChar(E.Message), 'Error', MB_OK+MB_ICONERROR );
+ end;
+end;
+
+procedure TfrmMain.vtMultisGetText(Sender: TBaseVirtualTree;
+ Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
+ var CellText: WideString);
+var
+ MyData: PMultiNode;
+begin
+ MyData := Sender.GetNodeData( Node );
+
+ case Column of
+ 0: CellText := MyData.Name;
+ 1: CellText := MyData.AddId;
+ end;
+end;
+
+procedure TfrmMain.vtMultisCompareNodes(Sender: TBaseVirtualTree; Node1,
+ Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
+var
+ MyData1, MyData2: PMultiNode;
+begin
+ MyData1 := Sender.GetNodeData( Node1 );
+ MyData2 := Sender.GetNodeData( Node2 );
+
+ case Column of
+ 0: Result := CompareStr( MyData1.Name, MyData2.Name );
+ 1: Result := CompareStr( MyData1.AddId, MyData2.AddId );
+ end;
+end;
+
+procedure TfrmMain.vtMultisHeaderClick(Sender: TVTHeader;
+ Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
+ Y: Integer);
+begin
+ // When changing we keep our sort direction
+ if Sender.SortColumn = Column then
+ begin
+ if Sender.SortDirection = sdAscending then
+ Sender.SortDirection := sdDescending
+ else
+ Sender.SortDirection := sdAscending;
+ exit;
+ end;
+
+ Sender.SortColumn := Column;
+ Sender.SortDirection := sdAscending;
+end;
+
+procedure TfrmMain.vtMultisChange(Sender: TBaseVirtualTree;
+ Node: PVirtualNode);
+begin
+ if Sender.SelectedCount < 1 then begin
+ btnAddMulti.Enabled := False;
+ btnPreviewMulti.Enabled := False;
+ end else begin
+ btnAddMulti.Enabled := True;
+ btnPreviewMulti.Enabled := True;
+ end;
+end;
+
+procedure TfrmMain.btnPreviewMultiClick(Sender: TObject);
+begin
+ Application.MessageBox('Not yet implemented', 'Error', MB_OK+MB_ICONERROR);
+end;
+
+procedure TfrmMain.btnAddMultiClick(Sender: TObject);
+var
+ NodeData: PMultiNode;
+ Node: PVirtualNode;
+begin
+ Node := vtMultis.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtMultis.GetNodeData(Node);
+ SendCommand('add ' + NodeData.AddId, true);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.Felucca1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 0;
+ Felucca1.Checked := True;
+ Trammel1.Checked := False;
+ Ilshenar1.Checked := False;
+ Malas1.Checked := False;
+ SamuraiEmpire1.Checked := False;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.Trammel1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 1;
+ Felucca1.Checked := False;
+ Trammel1.Checked := True;
+ Ilshenar1.Checked := False;
+ Malas1.Checked := False;
+ SamuraiEmpire1.Checked := False;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.Ilshenar1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 2;
+ Felucca1.Checked := False;
+ Trammel1.Checked := False;
+ Ilshenar1.Checked := True;
+ Malas1.Checked := False;
+ SamuraiEmpire1.Checked := False;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.Malas1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 3;
+ Felucca1.Checked := False;
+ Trammel1.Checked := False;
+ Ilshenar1.Checked := False;
+ Malas1.Checked := True;
+ SamuraiEmpire1.Checked := False;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.Center1Click(Sender: TObject);
+begin
+ frmCenter.Show;
+ frmCenter.X.Text := IntToStr(MapCenterX);
+ frmCenter.Y.Text := IntToStr(MapCenterY);
+ frmCenter.Map.ItemIndex := MapCenterMap;
+end;
+
+procedure TfrmMain.SamuraiEmpire1Click(Sender: TObject);
+begin
+ MapCenterX := 0;
+ MapCenterY := 0;
+ MapCenterZ := 0;
+ MapCenterMap := 4;
+ Felucca1.Checked := False;
+ Trammel1.Checked := False;
+ Ilshenar1.Checked := False;
+ Malas1.Checked := False;
+ SamuraiEmpire1.Checked := True;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmMain.btnStaticItemClick(Sender: TObject);
+var
+ NodeData: PItemNode;
+ Node: PVirtualNode;
+begin
+ Node := vtItems.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtItems.GetNodeData(Node);
+ SendCommand('static ' + NodeData.AddId, true);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+
+end;
+
+procedure TfrmMain.btnMapOverviewClick(Sender: TObject);
+begin
+ if not frmOverview.Generating then begin
+ frmOverview.showMap(MapCenterMap);
+ frmOverview.Show;
+ end;
+end;
+
+function IsInParent(Control: TWinControl): Boolean;
+begin
+ if Control is TCustomForm then
+ Result := True
+ else if Control.Parent <> nil then
+ Result := IsInParent(Control.Parent)
+ else
+ Result := False;
+end;
+
+procedure TfrmMain.ontopTimerTimer(Sender: TObject);
+begin
+ // If one of the forms is active, skip this code
+ if frmMain.Active or frmCenter.Active or frmOverview.Active then
+ exit;
+
+ if IsInParent(Screen.ActiveControl) then
+ exit;
+
+ if cbAlwaysOnTop.Checked then begin
+ if frmMain.Visible then begin
+ SetWindowPos(frmMain.Handle, HWND_TOPMOST, 0, 0, 0, 0, 3 or SWP_NOACTIVATE);
+ end;
+
+ if frmCenter.Visible then begin
+ SetWindowPos(frmCenter.Handle, HWND_TOPMOST, 0, 0, 0, 0, 3 or SWP_NOACTIVATE);
+ end;
+
+ if frmOverview.Visible then begin
+ SetWindowPos(frmOverview.Handle, HWND_TOPMOST, 0, 0, 0, 0, 3 or SWP_NOACTIVATE);
+ end;
+ end;
+end;
+
+procedure TfrmMain.btnNpcSpawnClick(Sender: TObject);
+var
+ NodeData: PNpcNode;
+ Node: PVirtualNode;
+begin
+ Node := vtNpcs.RootNode.FirstChild;
+ while Node <> nil do
+ begin
+ if vsSelected in Node.States then
+ begin
+ NodeData := vtNpcs.GetNodeData(Node);
+ SendCommand(Format('spawn %s %s %s %s', [NodeData.AddId, eSpawnRadius.Text, eSpawnMin.Text, eSpawnMax.Text]), True);
+ exit;
+ end;
+ Node := Node.NextSibling;
+ end;
+end;
+
+procedure TfrmMain.eSpawnRadiusExit(Sender: TObject);
+begin
+ Config.setString('SpawnRadius', eSpawnRadius.Text);
+ Config.Save;
+end;
+
+procedure TfrmMain.eSpawnMinExit(Sender: TObject);
+begin
+ Config.setString('SpawnMin', eSpawnMin.Text);
+ Config.Save;
+end;
+
+procedure TfrmMain.eSpawnMaxExit(Sender: TObject);
+begin
+ Config.setString('SpawnMax', eSpawnMax.Text);
+ Config.Save;
+end;
+
+procedure TfrmMain.btnRegionsClick(Sender: TObject);
+begin
+ frmRegions.Show;
+end;
+
+procedure TfrmMain.Button1Click(Sender: TObject);
+begin
+ frmPatternColor.Show;
+end;
+
+procedure TFrmMain.addBuildButton(Id: String; ItemId: Word; Text: String);
+var
+ BitBtn: TBitBtn;
+begin
+ BitBtn := TBitBtn.Create(sbBuild);
+ BitBtn.SetBounds(BuildCurrentX, BuildCurrentY, 70, 120);
+// BitBtn.Caption := Text;
+ BitBtn.Glyph.Assign(Art.GetTile(ItemId));
+ BitBtn.Layout := blGlyphTop;
+ BitBtn.Hint := id;
+ BitBtn.OnClick := clickBuildButton;
+ sbBuild.InsertControl(BitBtn);
+
+ Inc(BuildCurrentX, 70 + 8);
+
+ // If the next button wouldn't fit anymore, go to the next row
+ if BuildCurrentX + 70 + 8 > sbBuild.ClientWidth then begin
+ BuildCurrentX := 8;
+ Inc(BuildCurrentY, 120 + 8);
+ end;
+end;
+
+procedure TfrmMain.sbBuildResize(Sender: TObject);
+begin
+ rebuildBuildMenu;
+end;
+
+procedure TfrmMain.clickBuildButton(Sender: TObject);
+var
+ BitBtn: TBitBtn;
+begin
+ if not (Sender is TBitBtn) then
+ exit;
+
+ BitBtn := Sender as TBitBtn;
+ SendCommand(Format('build %s %d', [BitBtn.Hint, StrToIntDef(cbBuildZ.Text, 0)]), True);
+end;
+
+procedure TfrmMain.sbBuildClick(Sender: TObject);
+begin
+ sbBuild.SetFocus;
+end;
+
+procedure TfrmMain.sbBuildMouseWheelDown(Sender: TObject;
+ Shift: TShiftState; MousePos: TPoint; var Handled: Boolean);
+begin
+ SendMessage(sbBuild.Handle, WM_VSCROLL, SB_LINEDOWN, 0);
+ Handled := True;
+end;
+
+procedure TfrmMain.sbBuildMouseWheelUp(Sender: TObject; Shift: TShiftState;
+ MousePos: TPoint; var Handled: Boolean);
+begin
+ SendMessage(sbBuild.Handle, WM_VSCROLL, SB_LINEUP, 0);
+ Handled := True;
+end;
+
+procedure TfrmMain.reorderCustomButtons;
+var
+ currentx, currenty, i: Integer;
+begin
+ currentx := 8;
+ currenty := 8;
+
+ for i := 0 to tsCustom.ControlCount - 1 do begin
+ tsCustom.Controls[i].Left := currentx;
+ tsCustom.Controls[i].Top := currenty;
+ Inc(currenty, tsCustom.Controls[i].Height + 8);
+
+ if CurrentY + tsCustom.Controls[i].Height > tsCustom.ClientHeight then begin
+ CurrentY := 8;
+ inc(CurrentX, tsCustom.Controls[i].Width + 8);
+ end;
+ end;
+end;
+
+procedure TfrmMain.loadCustomButtons;
+var
+ count, i: Integer;
+ command: String;
+ button: TButton;
+begin
+ count := Config.getInt('CustomButtonCount', 0);
+
+ // Load the custom buttons
+ for i := 0 to count - 1 do begin
+ command := Config.getString(Format('CustomButton%u', [i]), '');
+
+ button := TButton.Create(tsCustom);
+ button.SetBounds(0, 0, 129, 25);
+ button.Caption := command;
+ button.OnClick := customButtonClick;
+ button.OnMouseDown := customButtonMouseDown;
+ button.PopupMenu := btnCustomPopup;
+ button.Parent := tsCustom;
+ end;
+
+ // If no button at all was loaded, create an empty one to make
+ // adding buttons possible. (RightClick -> Add Button)
+ if Count = 0 then begin
+ button := TButton.Create(tsCustom);
+ button.SetBounds(0, 0, 129, 25);
+ button.Caption := '';
+ button.OnClick := customButtonClick;
+ button.OnMouseDown := customButtonMouseDown;
+ button.PopupMenu := btnCustomPopup;
+ button.Parent := tsCustom;
+ end;
+
+ reorderCustomButtons;
+end;
+
+procedure TfrmMain.saveCustomButtons;
+var
+ count, i: Integer;
+ button: TButton;
+begin
+ count := 0;
+
+ // Account for all custom buttons
+ for i := 0 to tsCustom.ControlCount - 1 do begin
+ button := tsCustom.Controls[i] as TButton;
+ if button <> nil then begin
+ Config.setString(Format('CustomButton%u', [i]), Button.Caption);
+ Inc(Count);
+ end;
+ end;
+
+ Config.setInt('CustomButtonCount', count);
+end;
+
+procedure TfrmMain.customButtonClick(Sender: TObject);
+var
+ button: TButton;
+begin
+ button := sender as TButton;
+
+ if button <> nil then begin
+ // If it's empty, show the change gump instead
+ if button.caption = '' then begin
+ changeCustomButton(button);
+ end else begin
+ SendCommand(button.caption, True);
+ end;
+ end;
+end;
+
+procedure TfrmMain.customButtonMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+var
+ i, index: Integer;
+begin
+ if Button = mbRight then begin
+ index := -1;
+
+ // Find the index of this button in the custom ctrl
+ for i := 0 to tsCustom.ControlCount - 1 do begin
+ if tsCustom.Controls[i] = Sender then begin
+ index := i;
+ break;
+ end;
+ end;
+
+ btnCustomPopup.Tag := index;
+ end;
+
+ inherited;
+end;
+
+procedure TfrmMain.Remove1Click(Sender: TObject);
+var
+ index: Integer;
+begin
+ index := btnCustomPopup.Tag;
+
+ if (index <> -1) and (index < tsCustom.ControlCount) then begin
+ tsCustom.Controls[index].Free;
+ btnCustomPopup.Tag := -1;
+ reorderCustomButtons;
+ saveCustomButtons;
+ end;
+end;
+
+procedure TFrmMain.changeCustomButton(Button: TButton; NewButton: Boolean = False);
+var
+ value: String;
+begin
+ value := Button.Caption;
+ // Query the new caption from the user
+ if InputQuery('Change Custom Button', 'Please input the command to associate with this button:', value) then
+ begin
+ Button.Caption := value;
+ saveCustomButtons;
+ end;
+end;
+
+procedure TfrmMain.Change1Click(Sender: TObject);
+var
+ button: TButton;
+ index: Integer;
+begin
+ index := btnCustomPopup.Tag;
+
+ if (index <> -1) and (index < tsCustom.ControlCount) then begin
+ button := tsCustom.Controls[index] as TButton;
+ if button <> nil then
+ changeCustomButton(button, False);
+ end;
+end;
+
+procedure TfrmMain.AddButton1Click(Sender: TObject);
+var
+ button: TButton;
+begin
+ button := TButton.Create(tsCustom);
+ button.SetBounds(0, 0, 129, 25);
+ button.Caption := '';
+ button.OnClick := customButtonClick;
+ button.OnMouseDown := customButtonMouseDown;
+ button.PopupMenu := btnCustomPopup;
+ button.Parent := tsCustom;
+
+ reorderCustomButtons;
+ saveCustomButtons;
+end;
+
+procedure TfrmMain.tsCustomResize(Sender: TObject);
+begin
+ reorderCustomButtons;
+end;
+
+end.
+
Added: trunk/WPGM/Overview.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Overview.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Overview.ddp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Overview.ddp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Overview.dfm
===================================================================
--- trunk/WPGM/Overview.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Overview.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,34 @@
+object frmOverview: TfrmOverview
+ Left = 441
+ Top = 292
+ BorderIcons = [biSystemMenu]
+ BorderStyle = bsSingle
+ Caption = 'Map Overview'
+ ClientHeight = 367
+ ClientWidth = 528
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poScreenCenter
+ ScreenSnap = True
+ OnCreate = FormCreate
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Image: TImage32
+ Left = 0
+ Top = 0
+ Width = 528
+ Height = 367
+ Align = alClient
+ BitmapAlign = baTopLeft
+ Scale = 1.000000000000000000
+ ScaleMode = smNormal
+ TabOrder = 0
+ OnDblClick = ImageDblClick
+ OnMouseDown = ImageMouseDown
+ end
+end
Added: trunk/WPGM/Overview.pas
===================================================================
--- trunk/WPGM/Overview.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Overview.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,210 @@
+unit Overview;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, ExtCtrls, GR32, GR32_Image, UOMap, UOStatics, GR32_Layers;
+
+type
+ TfrmOverview = class(TForm)
+ Image: TImage32;
+ procedure ontopTimerTimer(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure ImageDblClick(Sender: TObject);
+ private
+ { Private declarations }
+ Map: Integer; // Map id
+ MapPreviews: Array[0..4] of TBitmap32;
+ CurrentX, CurrentY: Integer;
+ MapHeight, MapWidth: Integer;
+
+ public
+ { Public declarations }
+ Generating: Boolean;
+
+ procedure showMap(Map: Integer);
+ end;
+
+var
+ frmOverview: TfrmOverview;
+
+implementation
+
+uses Main, Progress;
+
+{$R *.dfm}
+
+procedure TfrmOverview.ontopTimerTimer(Sender: TObject);
+begin
+ if frmMain.cbAlwaysOnTop.Checked then
+ frmOverview.FormStyle := fsStayOnTop;
+end;
+
+procedure TfrmOverview.FormCreate(Sender: TObject);
+begin
+ // Clear the map previe fields
+ MapPreviews[0] := nil;
+ MapPreviews[1] := nil;
+ MapPreviews[2] := nil;
+ MapPreviews[3] := nil;
+ Map := -1;
+ Generating := False;
+end;
+
+procedure TfrmOverview.ShowMap(Map: Integer);
+var
+ Preview: TBitmap32;
+ x, y: Integer;
+ MapReader: TMapReader;
+ StaticReader: TStaticReader;
+ MapCell: TMapCell;
+ StaticCell: TStaticBlock;
+ HighestZ: Shortint;
+ CellColor: TColor;
+ i: Integer;
+ StaidxTime, StaticsTime, MapTime: TDateTime;
+ Prgr: TFrmProgress;
+begin
+ if Generating then
+ exit;
+
+ if (Map < 0) or (Map > 4) then
+ exit; // Invalid Map
+
+ Self.Map := Map; // Save Map Id
+
+ // Get a map preview...
+ if MapPreviews[Map] <> nil then begin
+ Image.Bitmap := MapPreviews[Map];
+ exit;
+ end;
+
+ // Try to read the map from file
+ Generating := True;
+ Preview := TBitmap32.Create;
+
+ try
+ // Try getting the modify time
+ // ModifyTime := FileDateToDateTime(FileAge(Format('map%u.bmp', [Map])));
+ MapTime := StrToDateTimeDef(Config.getString(Format('Map%uModify', [Map]), ''), Time);
+ StaticsTime := StrToDateTimeDef(Config.getString(Format('Statics%uModify', [Map]), ''), Time);
+ StaidxTime := StrToDateTimeDef(Config.getString(Format('Staidx%uModify', [Map]), ''), Time);
+
+ // Check if the loaded maps/statics have different times
+ if (Maps[Map].LastModified = MapTime) and (Statics[Map].LastDataModification = StaticsTime) and
+ (Statics[Map].LastIndexModification = StaidxTime) then
+ begin
+ Preview.LoadFromFile(Format('map%u.bmp', [Map]));
+ MapPreviews[Map] := Preview;
+ Image.Bitmap := Preview;
+ ClientWidth := Preview.Width;
+ ClientHeight := Preview.Height;
+ MapWidth := Preview.Width;
+ MapHeight := Preview.Height;
+ Generating := False;
+ exit;
+ end;
+ Preview.Free;
+ except
+ Preview.Free;
+ end;
+
+ // Create a map preview
+ Prgr := TfrmProgress.Create(self);
+ Prgr.FormStyle := fsStayOnTop;
+ Prgr.Show;
+
+ MapWidth := Maps[Map].getWidth;
+ MapHeight := Maps[Map].getHeight;
+
+ Prgr.pgBar.Max := MapWidth * MapHeight;
+
+ Preview := TBitmap32.Create;
+ Preview.SetSize(MapWidth, MapHeight);
+ Preview.Clear(clBlack32);
+
+ // Cache the readers
+ MapReader := Maps[Map];
+ StaticReader := Statics[Map];
+
+ // Create the preview
+ for x := 0 to MapWidth - 1 do begin
+ for y := 0 to MapHeight - 1 do begin
+ MapReader.ReadCell(x * 8, y * 8, MapCell);
+ CellColor := RadarCol.GetLandColor(MapCell.Id);
+
+ // Get Static Tiles
+ HighestZ := MapCell.Height;
+ StaticReader.ReadBlock(x, y, StaticCell);
+
+ for i := 0 to Length(StaticCell) - 1 do begin
+ if StaticCell[i].X <> 0 then
+ continue;
+
+ if StaticCell[i].Y <> 0 then
+ continue;
+
+ if StaticCell[i].Z < HighestZ then
+ continue;
+
+ if StaticCell[i].Hue = 0 then
+ CellColor := RadarCol.GetItemColor(StaticCell[i].Id)
+ else begin
+ CellColor := RadarCol.GetItemColor(StaticCell[i].Id);
+ CellColor := Hues.translateColor(StaticCell[i].Hue, CellColor);
+ end;
+
+ HighestZ := StaticCell[i].Z;
+ end;
+
+ Preview.Pixel[x, y] := CellColor;
+ end;
+ Prgr.pgBar.StepBy(MapHeight);
+ Application.ProcessMessages;
+ end;
+
+ MapPreviews[Map] := Preview;
+ Image.Bitmap := Preview;
+
+ // Write the bitmap to a file
+ Preview.SaveToFile(Format('map%u.bmp', [Map]));
+
+ // Save the modification times of the statics and map
+ Config.setString(Format('Map%uModify', [Map]), DateTimeToStr(MapReader.LastModified));
+ Config.setString(Format('Statics%uModify', [Map]), DateTimeToStr(StaticReader.LastDataModification));
+ Config.setString(Format('Staidx%uModify', [Map]), DateTimeToStr(StaticReader.LastIndexModification));
+ Config.Save;
+
+ ClientWidth := Preview.Width;
+ ClientHeight := Preview.Height;
+
+ Prgr.Free;
+
+ Generating := False;
+end;
+
+procedure TfrmOverview.ImageMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer;
+ Layer: TCustomLayer);
+begin
+ if (x < 0) or (y < 0) or (x >= MapWidth) or (y >= MapHeight) then
+ exit;
+
+ CurrentX := X * 8; // Save for DClick
+ CurrentY := Y * 8; // Save for DClick
+
+ MapCenterX := X * 8;
+ MapCenterY := Y * 8;
+ MapCenterMap := Self.Map;
+ frmMain.pbMap.Invalidate;
+end;
+
+procedure TfrmOverview.ImageDblClick(Sender: TObject);
+begin
+ frmMain.Go1Click(Self);
+end;
+
+end.
Added: trunk/WPGM/Overview.~ddp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Overview.~ddp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Overview.~dfm
===================================================================
--- trunk/WPGM/Overview.~dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Overview.~dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,34 @@
+object frmOverview: TfrmOverview
+ Left = 441
+ Top = 292
+ BorderIcons = [biSystemMenu]
+ BorderStyle = bsSingle
+ Caption = 'Map Overview'
+ ClientHeight = 367
+ ClientWidth = 528
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poScreenCenter
+ ScreenSnap = True
+ OnCreate = FormCreate
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Image: TImage32
+ Left = 0
+ Top = 0
+ Width = 528
+ Height = 367
+ Align = alClient
+ BitmapAlign = baTopLeft
+ Scale = 1.000000000000000000
+ ScaleMode = smNormal
+ TabOrder = 0
+ OnDblClick = ImageDblClick
+ OnMouseDown = ImageMouseDown
+ end
+end
Added: trunk/WPGM/Overview.~pas
===================================================================
--- trunk/WPGM/Overview.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Overview.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,210 @@
+unit Overview;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, ExtCtrls, GR32, GR32_Image, UOMap, UOStatics, GR32_Layers;
+
+type
+ TfrmOverview = class(TForm)
+ Image: TImage32;
+ procedure ontopTimerTimer(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
+ procedure ImageDblClick(Sender: TObject);
+ private
+ { Private declarations }
+ Map: Integer; // Map id
+ MapPreviews: Array[0..4] of TBitmap32;
+ CurrentX, CurrentY: Integer;
+ MapHeight, MapWidth: Integer;
+
+ public
+ { Public declarations }
+ Generating: Boolean;
+
+ procedure showMap(Map: Integer);
+ end;
+
+var
+ frmOverview: TfrmOverview;
+
+implementation
+
+uses Main, Progress;
+
+{$R *.dfm}
+
+procedure TfrmOverview.ontopTimerTimer(Sender: TObject);
+begin
+ if frmMain.cbAlwaysOnTop.Checked then
+ frmOverview.FormStyle := fsStayOnTop;
+end;
+
+procedure TfrmOverview.FormCreate(Sender: TObject);
+begin
+ // Clear the map previe fields
+ MapPreviews[0] := nil;
+ MapPreviews[1] := nil;
+ MapPreviews[2] := nil;
+ MapPreviews[3] := nil;
+ Map := -1;
+ Generating := False;
+end;
+
+procedure TfrmOverview.ShowMap(Map: Integer);
+var
+ Preview: TBitmap32;
+ x, y: Integer;
+ MapReader: TMapReader;
+ StaticReader: TStaticReader;
+ MapCell: TMapCell;
+ StaticCell: TStaticBlock;
+ HighestZ: Shortint;
+ CellColor: TColor;
+ i: Integer;
+ StaidxTime, StaticsTime, MapTime: TDateTime;
+ Prgr: TFrmProgress;
+begin
+ if Generating then
+ exit;
+
+ if (Map < 0) or (Map > 4) then
+ exit; // Invalid Map
+
+ Self.Map := Map; // Save Map Id
+
+ // Get a map preview...
+ if MapPreviews[Map] <> nil then begin
+ Image.Bitmap := MapPreviews[Map];
+ exit;
+ end;
+
+ // Try to read the map from file
+ Generating := True;
+ Preview := TBitmap32.Create;
+
+ try
+ // Try getting the modify time
+ // ModifyTime := FileDateToDateTime(FileAge(Format('map%u.bmp', [Map])));
+ MapTime := StrToDateTimeDef(Config.getString(Format('Map%uModify', [Map]), ''), Time);
+ StaticsTime := StrToDateTimeDef(Config.getString(Format('Statics%uModify', [Map]), ''), Time);
+ StaidxTime := StrToDateTimeDef(Config.getString(Format('Staidx%uModify', [Map]), ''), Time);
+
+ // Check if the loaded maps/statics have different times
+ if (Maps[Map].LastModified = MapTime) and (Statics[Map].LastDataModification = StaticsTime) and
+ (Statics[Map].LastIndexModification = StaidxTime) then
+ begin
+ Preview.LoadFromFile(Format('map%u.bmp', [Map]));
+ MapPreviews[Map] := Preview;
+ Image.Bitmap := Preview;
+ ClientWidth := Preview.Width;
+ ClientHeight := Preview.Height;
+ MapWidth := Preview.Width;
+ MapHeight := Preview.Height;
+ Generating := False;
+ exit;
+ end;
+ Preview.Free;
+ except
+ Preview.Free;
+ end;
+
+ // Create a map preview
+ Prgr := TfrmProgress.Create(self);
+ Prgr.FormStyle := fsStayOnTop;
+ Prgr.Show;
+
+ MapWidth := Maps[Map].getWidth;
+ MapHeight := Maps[Map].getHeight;
+
+ Prgr.pgBar.Max := MapWidth * MapHeight;
+
+ Preview := TBitmap32.Create;
+ Preview.SetSize(MapWidth, MapHeight);
+ Preview.Clear(clBlack32);
+
+ // Cache the readers
+ MapReader := Maps[Map];
+ StaticReader := Statics[Map];
+
+ // Create the preview
+ for x := 0 to MapWidth - 1 do begin
+ for y := 0 to MapHeight - 1 do begin
+ MapReader.ReadCell(x * 8, y * 8, MapCell);
+ CellColor := RadarCol.GetLandColor(MapCell.Id);
+
+ // Get Static Tiles
+ HighestZ := MapCell.Height;
+ StaticReader.ReadBlock(x, y, StaticCell);
+
+ for i := 0 to Length(StaticCell) - 1 do begin
+ if StaticCell[i].X <> 0 then
+ continue;
+
+ if StaticCell[i].Y <> 0 then
+ continue;
+
+ if StaticCell[i].Z < HighestZ then
+ continue;
+
+ if StaticCell[i].Hue = 0 then
+ CellColor := RadarCol.GetItemColor(StaticCell[i].Id)
+ else begin
+ CellColor := RadarCol.GetItemColor(StaticCell[i].Id);
+ CellColor := Hues.translateColor(StaticCell[i].Hue, CellColor);
+ end;
+
+ HighestZ := StaticCell[i].Z;
+ end;
+
+ Preview.Pixel[x, y] := CellColor;
+ end;
+ Prgr.pgBar.StepBy(MapHeight);
+ Application.ProcessMessages;
+ end;
+
+ MapPreviews[Map] := Preview;
+ Image.Bitmap := Preview;
+
+ // Write the bitmap to a file
+ Preview.SaveToFile(Format('map%u.bmp', [Map]));
+
+ // Save the modification times of the statics and map
+ Config.setString(Format('Map%uModify', [Map]), DateToStr(MapReader.LastModified));
+ Config.setString(Format('Statics%uModify', [Map]), DateToStr(StaticReader.LastDataModification));
+ Config.setString(Format('Staidx%uModify', [Map]), DateToStr(StaticReader.LastIndexModification));
+ Config.Save;
+
+ ClientWidth := Preview.Width;
+ ClientHeight := Preview.Height;
+
+ Prgr.Free;
+
+ Generating := False;
+end;
+
+procedure TfrmOverview.ImageMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer;
+ Layer: TCustomLayer);
+begin
+ if (x < 0) or (y < 0) or (x >= MapWidth) or (y >= MapHeight) then
+ exit;
+
+ CurrentX := X * 8; // Save for DClick
+ CurrentY := Y * 8; // Save for DClick
+
+ MapCenterX := X * 8;
+ MapCenterY := Y * 8;
+ MapCenterMap := Self.Map;
+ frmMain.pbMap.Invalidate;
+end;
+
+procedure TfrmOverview.ImageDblClick(Sender: TObject);
+begin
+ frmMain.Go1Click(Self);
+end;
+
+end.
Added: trunk/WPGM/Progress.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Progress.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Progress.dfm
===================================================================
--- trunk/WPGM/Progress.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Progress.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,300 @@
+object frmProgress: TfrmProgress
+ Left = 422
+ Top = 335
+ BorderStyle = bsToolWindow
+ Caption = 'Generating...'
+ ClientHeight = 68
+ ClientWidth = 229
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poOwnerFormCenter
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Image1: TImage
+ Left = 16
+ Top = 16
+ Width = 32
+ Height = 32
+ AutoSize = True
+ Picture.Data = {
+ 055449636F6E0000010006001010020000000000B00000006600000010100000
+ 0000000068050000160100001010000000000000680300007E06000020200200
+ 0000000030010000E60900002020000000000000A8080000160B000020200000
+ 00000000A80C0000BE1300002800000010000000200000000100010000000000
+ 8000000000000000000000000000000000000000FFFFFF0000000000FFFFB9BC
+ FFF70E15E7FD0E0FFFFE07F5FF8300009FA300FBCB39FFADFF67FFFFF7EFFBF6
+ FBEF0000FF9FF500FE3F2B07F8FFF607F17F1614EDFF0D07DEFF000003FFB9BC
+ 00030E1500010E0F000007F500000000000000FB0001FFAD0007FFFF000FFBF6
+ 000F0000001FF500003F2B07007FF607007F16140C7F0D071E7F000028000000
+ 1000000020000000010008000000000040010000000000000000000000000000
+ 0000000000000000000008000008080000081000080810000810100008101800
+ 0018210010182100102121000818290018293100212931003131310021293900
+ 183139002131390029313900213142002939420029394A0029424A0031424A00
+ 2942520031425200314A5200314A5A00394A5A0039525A003152630039526300
+ 42526300425A6300425A6B00425A7300426373004A6373004A637B004A6B7B00
+ 526B7B004A6B8400527384005A7384005A738C005A7B8C00637B8C005A7B9400
+ 6384940063849C006B8C9C006B8CA5006B94A5007394AD007B9CAD007B9CB500
+ 7BA5B5007BA5BD0084A5BD009CADBD0084ADC6008CADC6008CB5C6008CB5CE00
+ 94B5CE009CBDCE00A5C6DE00ADCEDE00BDD6E700ADD6EF00B5DEEF00D6E7EF00
+ DEF7FF00FFFFFF00000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000016000308002900000000000000000000120B03181F00101F27292929
+ 2F290000121F1F3332080005050000000000370023272329120815230C101F0C
+ 0C12033A29231F161818161F29343B333B44000D1F2F361818231615292F292F
+ 394117100C18372F1C2F1F0B343D181C293241001C001523181F1818321D2937
+ 3F0000001C080B1F2E1C00101203232F0000000008000016232F1D1218072200
+ 000000000000050910122923283F000000000000000012120B181F3441000000
+ 0000000018290000233D41432E000000000000000512150F4300371D34000000
+ 0000000000121D3D000036072900000000000000102D41000000002F1F000000
+ 0000000003FFB9BC00030E1500010E0F000007F500000000000000FB0001FFAD
+ 0007FFFF000FFBF6001F0000003FF500007F2B07007FF607047F16140C7F0D07
+ 1E7F000028000000100000002000000001001800000000004003000000000000
+ 00000000000000000000000030434D020307090E10121B210003065E77860000
+ 000000000000000000000000000000000000000000000000000000002A39431E
+ 2A32090F14394D58445A6800020628373F44576151697A5F7B8B597587597788
+ 6484975B78880000000000002D3D46455C694358676F93A66A8CA1141C23050A
+ 0E0810140B121701060A00000006090B0103050002007BA0B50000004F697A50
+ 6D7D4D67755975862C3D47141F262F414B4C6775222F3827343D435A67222F37
+ 202D362C3D48000C149FAEB95A7687476070455B6A31434F374C583548543141
+ 4C445A685672827195A984AAC16D90A389AEC4A9D2EA000000343332435B6763
+ 8194789AB13A4E5A3345504D667530424C2E404A567484638395597687638294
+ 85A6BAA1C4DA2A42512D363C222F373749527EA4BB6584963C535E648396445D
+ 6A1E2B337496AB8EB5CC3346523A515C5C788A688DA6A2C5DA0000003C515E00
+ 00002F404B4A6371374B56475F6F354854384C596B8EA03F56655876857FA2B7
+ 90B5CB0000000000000000003C505E111A211D2A31465F6E5F7F903C505D0000
+ 00233038283D430D0F124D6878618399000000000000000000000000161E2400
+ 0000070C0E30404D4963706A8B9E3F55632B3A463B4E5A071A25405F74D2E7EF
+ 0000000000000000000000000205040000000E161B16202624323A2F3F4A5472
+ 814864784E6F8399BACDDEF6FF00000000000000000000000000000003050606
+ 090B2A3B452C3C471D2D36364E5C415C6D7797A9A1C3D8000000000000000000
+ 0000000000000000000000003244505876870000000000004962708BB0C2A1C4
+ DAB7DAEF5D7D920000000000000000000000000000000000000000000E161A2E
+ 3E492D404B1A303FBDD6E10000007FA4BB3351637E9DAF000000000000000000
+ 0000000000000000000000000000002234403F57648FB6CD0000000000007B9D
+ B00E1F2A58738400000000000000000000000000000000000000000026313A64
+ 7988ACCCDE000000000000000000000000658698465F6E000000000000000000
+ 00000000000000000000000003FFB9BC00030E1500010E0F000007F500000000
+ 000000FB0001FFAD0007FFFF000FFBF6000F0000001FF500007F2B07007FF607
+ 047F16140C7F0D071E7F00002800000020000000400000000100010000000000
+ 0001000000000000000000000000000000000000FFFFFF0000000000FFEFFFFF
+ FFF7FFFFFFF9FFFFFFFFFF9FFF7FFFF7FCFFFFFFFEFFFFFFFFFFF7DFFFFFC10E
+ 7FFF790F73FFE80FC3FF9F86E1EF8F91F9EF8F8FFFEF983FFFFE72FFFFFFF5FF
+ FF9FF5FFFFCF3DFFFFFFF9FFFFFB61FFFFFF87FFFFFE0FFFFFFC3FFFDFB0BFFF
+ DF80BFFFFF82BFFFF7037FFFFEF7FFFFF9F3FFFFF7FDFFFF6FFEFFFF000FFFFF
+ 0007FFFF0001FFFF0000001F0000000700000007000000030000000100000000
+ 000000000000000000000000000000010000000F0000003F000000FF000001FF
+ 000001FF000001FF000001FF000001FF000007FF00000FFF00003FFF00003FFF
+ 00003FFF00003FFF00007FFF00F07FFF01F07FFF07FC7FFF0FFE7FFF28000000
+ 2000000040000000010008000000000080040000000000000000000000000000
+ 0000000000000000000008000008080000081000080810000810100008101800
+ 0818180010181800101821001021210018212100102129001821290018292900
+ 1821310018293100212931002131310021293900083139001831390021313900
+ 293139002131420029314200213942002939420029394A0029424A0031424A00
+ 31425200314A5200394A5200394A5A0039525A0042525A003952630042526300
+ 395A6300425A6300395A6B00425A6B004A5A6B0042636B004A636B005A636B00
+ 426373004A6373004A637B004A6B7B00526B7B0052737B004A6B8400526B8400
+ 527384005A73840052738C005A738C005A7B8C00637B8C005A7B9400637B9400
+ 6384940063849C006B849C00638C9C006B8C9C00738C9C006B8CA5006B94A500
+ 7394A5007B94A5006B94AD007394AD00739CAD007B9CAD00849CAD007B9CB500
+ 7BA5B50084A5B50084A5BD0084ADBD008CADBD0084ADC6008CADC600A5B5C600
+ 8CB5CE0094B5CE0094BDCE009CBDCE0094BDD6009CBDD600A5BDD600A5C6D600
+ A5C6DE00A5CEDE00ADCEDE00B5CEDE00ADCEE700ADD6E700B5D6E700B5D6EF00
+ BDD6EF00C6DEEF00BDDEF700C6DEF700DEEFF700CEEFFF00D6EFFF00DEEFFF00
+ D6F7FF00DEF7FF00E7FFFF00F7FFFF00FFFFFF00000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000018120900080A080F0A0F2F0000000000000000000000000000000000
+ 000000001F1F0A00000F09090508050000000000000000000000000000000000
+ 000000000A1E120003111226120A08001D3F0000000000000000000000000000
+ 00000000121F1F1209121233373718000505091E2C373C372637372C333F3F00
+ 000000000A232326182326333F372311090A050000030505050912181D12051F
+ 0000000012262F1F26373F46371F0A050512180F091818050000000000000000
+ 2C000000233333262F37373F3718050A18232F2F1F09000518120F0A0A0A0A09
+ 1137000026372F2C2F251F26120A1E261211261F1F181F373F372F2626333F37
+ 18001F0037363737262F1F1F1F1E121E1E1F2F261F333E5050453F333F3F5054
+ 120000003E251D372F231F26262F1F1F1F1F182F3F372F37373F453750505858
+ 0300002E3F2F18373F3E261F122F26262C181E2C372F373F37474E4747586C50
+ 120A000018263F47453F331F122337231E1F18181F3F3F37332F37333745544F
+ 47353C562309264747473C2F261F263E261F181F37454745262526232F3F4536
+ 475E00002F0F00183C3F45372326373E2625121837505B4E1F25332F374F544E
+ 000000001F1805031F262F372F26334533231218334745262F3F4F47584E0000
+ 00000000261D11030A25121F1F1218252312183F543718123F3F365800000000
+ 000000002F1811050A1F26262F261F0A000018371400001F581F440000000000
+ 000000001F0F120F0818251F3C3F471E0300000A3424001F47123F0000000000
+ 000000001205050500121E1F2F263F471F1F0A183F3F052618265E0000000000
+ 0000000011000000000918121F252F3737252F261F0A18262657000000000000
+ 000000000A00000000051809121E1F18333F2C333F2F3D475B00000000000000
+ 00000000050000000A0A0908181F181F2F3736333746636F0000000000000000
+ 00000000000000000A261F180F1E1F2F2625253D4E6500000000000000000000
+ 00000000080305050A1818180F23262F37334765625000000000000000000000
+ 00000000180A452F0000090A093F372F455B6C682F4500000000000000000000
+ 000000000A1E4E18000000001857585E645B5E502F5800000000000000000000
+ 00000000051818000F1F18153C0000005E463745375D00000000000000000000
+ 00000000000812263F2636265000000054462F263F0000000000000000000000
+ 0000000000001F26121D375800000000582F1E18370000000000000000000000
+ 0000000000001F18124465000000000065471F18370000000000000000000000
+ 0000000000000F1F5E0000000000000000005425370000000000000000000000
+ 000000004D18376B0000000000000000000000452F0000000000000000000000
+ 00000000001FFFFF001FFFFF0003FFFF0000001F0000000F0000000700000003
+ 0000000100000001000000000000000000000000000000030000000F0000003F
+ 000000FF000001FF000001FF000001FF000003FF000007FF00000FFF00003FFF
+ 00003FFF00003FFF00003FFF00703FFF00707FFF00F07FFF01F07FFF07FC7FFF
+ 0FFE7FFF2800000020000000400000000100180000000000800C000000000000
+ 0000000000000000000000002A3A4223303A131C2302050610191C1D282F1019
+ 1C1C27301A252A1C28314E667800000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000374956374B561A252D0202020202021D2932131C
+ 23141F2509111410191D0B151B49637000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000018232830414D27343D060A0F070F12202E372230
+ 3942576425333D18222A10191C0202062E414D00000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000022303737495534475126343E131C2224323A2835
+ 3F506C7B5C7A8E5571812D3C46050A0E0C14180C151C111C2300000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000001923293A505B3D515D4459692F3F4B3C505D4259
+ 66506C7B6585975D7A8D3C505D202D35131C2019242A091013020507050A0F09
+ 0F140912180F181D0B1318131E25233038283A432F414B26353F0E181D3A4C56
+ 00000000000000000000000025333C435A674963703548534258665774856383
+ 966F92A55B788A3346521B272E0F151A0F1A1D25333C293B431F2D35141D232C
+ 3C452939420E161B050A0E02020202020205070A040508020202020202020202
+ 4F626F0000000000000000003C505F506B79526E7F4359664C64725976865976
+ 856B8B9F5672832D3D470B11151620282838433C505D4F6B7B49627134465213
+ 1C230202020B111429394328373F1F2D321622261823281B242A182229151F25
+ 202D35597788000000000000465F6B5A77894C657447606D4B65743F55623345
+ 5141576526353E1C292F31424E42586526353D232F39475F6B3446523548552F
+ 3F4B3B4F5D5672836383955C788A4B6574415563415765516E7C658397557082
+ 2D3E48020202384B56000000587284536F805A77885570824158654E66773C4F
+ 5C384B573A4E5A30434E24343C32454F30424B354852496271475F6D34475252
+ 6E7C617E9084AABF80A5BB6D8DA2678599526D7E60809261819583A4BB88ADC2
+ 24343C020202020202000000617F903E56622F414C5772834C65753B505B384E
+ 5A435867465F6C4C6474374855384B583346503345502C3C464C65756A8A9F59
+ 76864C64755F7C8E59768567869A6E8FA157718285A7B985A5BB95B8CA95B9CD
+ 070F150202020202025F656969899D4C66752E3D465770826A899E617F904257
+ 63374C5723313A496271445C6A445A6747606C2C3D4631444E47606E5570804F
+ 69795D7A8B6C8D9F5672827296A97B9EB2799CAF7698AD99BBCFC9E8F982A8BC
+ 24313B18252C0204090202022C3C46435966638496769AAE6F8FA3618092536E
+ 7E37485327333D3D515F5672833C515D30424C3547552E3F482D3E493A4F5962
+ 819367869A5C7A8B536D7E4F69785C788A526C7B5C7A8D6F8FA38CADC27EA0B6
+ 7094A94E6C80627C8BA0B4C03D525F111B20445B697496AB7194A97294A9607F
+ 8F4B6371425A69384D58455B6A617F92445C6A3549562E3E473A4F5B5A76866C
+ 8CA0789DAF6C8CA04257643F5662455C6B3C515C4D66766A899A6D8EA2516E82
+ 7497ABAACADE0000000000004C63721F2D34020202283841617E8F6585986D8C
+ A25A77863D525D465D6C597586617F92465F6D3E556127353F2E3D485A778883
+ A5BB96B9D07C9FB4374B563F5561526E7C4E6A785772847FA2B688ACC3799EB4
+ 0000000000000000000000003B4F5A2D3D470E1519080F13344650445B6B4C62
+ 70537080486170415763506B7A6C8DA0516D7B3C515D233039273741516B7C72
+ 96AB6A8BA0455D6D4B62716280937CA1B6789CAF90B3C87B9DB1000000000000
+ 000000000000000000000000455C6B2E414B222E35070E111B262D3E55622535
+ 3D394D59394D592332392C3D473E53623A505C24323D2938426B899C83ACC156
+ 70802A3C46203038698999678899536E8097B9CD000000000000000000000000
+ 0000000000000000000000004D6575283841222F370C12161923283C4F5B455F
+ 6B485F6E4F6A79465D6D394C581A252D0406090202022E3B445C778808353902
+ 020202020232465297BBCF3A4F5C708C9E000000000000000000000000000000
+ 000000000000000000000000384B581D2A3224323C1C2930111B1F2A3B473F55
+ 63394E5A607E8F6685987195A932434E080E1202020202020216202657707B43
+ 525D0202023749557994A522313B698B9F000000000000000000000000000000
+ 00000000000000000000000026353F0F151B0E151A0E151A06080C2230383344
+ 4F3848564C6472455B6A6180927193A73A4E593446531B252E2C3B4864819064
+ 81930E151B415765243541435C6EA1C0D0000000000000000000000000000000
+ 000000000000000000000000222F38020202020202020202020202131D232C3A
+ 4524303A384D573D55624E67785977865774853F5562486170465D6B32445019
+ 252C263842435D6D415C6F8AB3CB000000000000000000000000000000000000
+ 0000000000000000000000001822280202020202020202020207070A11162939
+ 42151E2425343C30434C3444502E3D48516C7A61809249616F506A7A62829546
+ 60715D7E907198AE000000000000000000000000000000000000000000000000
+ 0000000000000000000000000B111402020202020204060819232A192429141E
+ 23121B1E2C3945384C562F3F4B3A4E5A4B64725C798B556F80516B7E5B7B8F6D
+ 90A4ACCDE2000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000020608020202020202020202182328455C6B394D
+ 592839431F2D3533444F394D584C6575475F6E3F57643D58665F7F937F9EB2B1
+ D1E4000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000111A1E0A0F120910130F181C19262D2D3E492C3C
+ 462E3F491D2A313B515F445B674D6777577486516C7F7294A7B4D4E6B1CDDE8C
+ ACBD000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000002839411620276D8DA34F6978020608020206141D
+ 23182227131D2365889C5776894F6A7A6B8DA299BCD1CDEBFEC0DEEF4662746F
+ 8EA1000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000018232A30424C799EB32A3B450202020202020202
+ 020202022E3F4B8BB3CA93B6CCA4C6D8AFD1E198BBD0A5C8DB83A7BD4966789A
+ B9CD000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000E13182737422A3B450202061F2A313548552837
+ 411F313B637C8B000000000000000000A2C0D36E90A75371836F8FA4557284A1
+ BED0000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000002020211191E25333D435A67608090435867526F
+ 81425F6E82A2B400000000000000000089ADC16E93A9486270425C6B65849700
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000020202020205394E58455C6C24333A2E414E5977
+ 8994B7CC00000000000000000000000093B6CB48657730434F2637425F7A8D00
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000002020205080A374C5626374220313D718E9E0000
+ 00000000000000000000000000000000BBD7E97B9CAF384F5C2535415F7A8C00
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000202050205091B27323449560000000000000000
+ 000000000000000000000000000000000000000000008CAEC13D596A59728300
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000859FAE2A3B445A72810000000000000000000000
+ 000000000000000000000000000000000000000000000000006F8EA247627200
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000001FFFFF000FFFFF0007FFFF0001FFFF0000000F
+ 0000000700000003000000010000000100000000000000000000000000000003
+ 0000000F0000003F000000FF000001FF000001FF000001FF000003FF00000FFF
+ 00001FFF00003FFF00003FFF00003FFF00003FFF00703FFF00707FFF00F07FFF
+ 03F07FFF0FFC7FFF1FFE7FFF}
+ end
+ object Label1: TLabel
+ Left = 56
+ Top = 16
+ Width = 126
+ Height = 13
+ Caption = 'Generating Map Preview...'
+ end
+ object pgBar: TProgressBar
+ Left = 56
+ Top = 32
+ Width = 150
+ Height = 17
+ TabOrder = 0
+ end
+end
Added: trunk/WPGM/Progress.pas
===================================================================
--- trunk/WPGM/Progress.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Progress.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,27 @@
+unit Progress;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, ExtCtrls, ComCtrls, StdCtrls;
+
+type
+ TfrmProgress = class(TForm)
+ Image1: TImage;
+ Label1: TLabel;
+ pgBar: TProgressBar;
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ frmProgress: TfrmProgress;
+
+implementation
+
+{$R *.dfm}
+
+end.
Added: trunk/WPGM/Progress.~dfm
===================================================================
--- trunk/WPGM/Progress.~dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Progress.~dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,300 @@
+object frmProgress: TfrmProgress
+ Left = 422
+ Top = 335
+ BorderStyle = bsToolWindow
+ Caption = 'Generating...'
+ ClientHeight = 68
+ ClientWidth = 233
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poOwnerFormCenter
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Image1: TImage
+ Left = 16
+ Top = 16
+ Width = 32
+ Height = 32
+ AutoSize = True
+ Picture.Data = {
+ 055449636F6E0000010006001010020000000000B00000006600000010100000
+ 0000000068050000160100001010000000000000680300007E06000020200200
+ 0000000030010000E60900002020000000000000A8080000160B000020200000
+ 00000000A80C0000BE1300002800000010000000200000000100010000000000
+ 8000000000000000000000000000000000000000FFFFFF0000000000FFFFB9BC
+ FFF70E15E7FD0E0FFFFE07F5FF8300009FA300FBCB39FFADFF67FFFFF7EFFBF6
+ FBEF0000FF9FF500FE3F2B07F8FFF607F17F1614EDFF0D07DEFF000003FFB9BC
+ 00030E1500010E0F000007F500000000000000FB0001FFAD0007FFFF000FFBF6
+ 000F0000001FF500003F2B07007FF607007F16140C7F0D071E7F000028000000
+ 1000000020000000010008000000000040010000000000000000000000000000
+ 0000000000000000000008000008080000081000080810000810100008101800
+ 0018210010182100102121000818290018293100212931003131310021293900
+ 183139002131390029313900213142002939420029394A0029424A0031424A00
+ 2942520031425200314A5200314A5A00394A5A0039525A003152630039526300
+ 42526300425A6300425A6B00425A7300426373004A6373004A637B004A6B7B00
+ 526B7B004A6B8400527384005A7384005A738C005A7B8C00637B8C005A7B9400
+ 6384940063849C006B8C9C006B8CA5006B94A5007394AD007B9CAD007B9CB500
+ 7BA5B5007BA5BD0084A5BD009CADBD0084ADC6008CADC6008CB5C6008CB5CE00
+ 94B5CE009CBDCE00A5C6DE00ADCEDE00BDD6E700ADD6EF00B5DEEF00D6E7EF00
+ DEF7FF00FFFFFF00000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000016000308002900000000000000000000120B03181F00101F27292929
+ 2F290000121F1F3332080005050000000000370023272329120815230C101F0C
+ 0C12033A29231F161818161F29343B333B44000D1F2F361818231615292F292F
+ 394117100C18372F1C2F1F0B343D181C293241001C001523181F1818321D2937
+ 3F0000001C080B1F2E1C00101203232F0000000008000016232F1D1218072200
+ 000000000000050910122923283F000000000000000012120B181F3441000000
+ 0000000018290000233D41432E000000000000000512150F4300371D34000000
+ 0000000000121D3D000036072900000000000000102D41000000002F1F000000
+ 0000000003FFB9BC00030E1500010E0F000007F500000000000000FB0001FFAD
+ 0007FFFF000FFBF6001F0000003FF500007F2B07007FF607047F16140C7F0D07
+ 1E7F000028000000100000002000000001001800000000004003000000000000
+ 00000000000000000000000030434D020307090E10121B210003065E77860000
+ 000000000000000000000000000000000000000000000000000000002A39431E
+ 2A32090F14394D58445A6800020628373F44576151697A5F7B8B597587597788
+ 6484975B78880000000000002D3D46455C694358676F93A66A8CA1141C23050A
+ 0E0810140B121701060A00000006090B0103050002007BA0B50000004F697A50
+ 6D7D4D67755975862C3D47141F262F414B4C6775222F3827343D435A67222F37
+ 202D362C3D48000C149FAEB95A7687476070455B6A31434F374C583548543141
+ 4C445A685672827195A984AAC16D90A389AEC4A9D2EA000000343332435B6763
+ 8194789AB13A4E5A3345504D667530424C2E404A567484638395597687638294
+ 85A6BAA1C4DA2A42512D363C222F373749527EA4BB6584963C535E648396445D
+ 6A1E2B337496AB8EB5CC3346523A515C5C788A688DA6A2C5DA0000003C515E00
+ 00002F404B4A6371374B56475F6F354854384C596B8EA03F56655876857FA2B7
+ 90B5CB0000000000000000003C505E111A211D2A31465F6E5F7F903C505D0000
+ 00233038283D430D0F124D6878618399000000000000000000000000161E2400
+ 0000070C0E30404D4963706A8B9E3F55632B3A463B4E5A071A25405F74D2E7EF
+ 0000000000000000000000000205040000000E161B16202624323A2F3F4A5472
+ 814864784E6F8399BACDDEF6FF00000000000000000000000000000003050606
+ 090B2A3B452C3C471D2D36364E5C415C6D7797A9A1C3D8000000000000000000
+ 0000000000000000000000003244505876870000000000004962708BB0C2A1C4
+ DAB7DAEF5D7D920000000000000000000000000000000000000000000E161A2E
+ 3E492D404B1A303FBDD6E10000007FA4BB3351637E9DAF000000000000000000
+ 0000000000000000000000000000002234403F57648FB6CD0000000000007B9D
+ B00E1F2A58738400000000000000000000000000000000000000000026313A64
+ 7988ACCCDE000000000000000000000000658698465F6E000000000000000000
+ 00000000000000000000000003FFB9BC00030E1500010E0F000007F500000000
+ 000000FB0001FFAD0007FFFF000FFBF6000F0000001FF500007F2B07007FF607
+ 047F16140C7F0D071E7F00002800000020000000400000000100010000000000
+ 0001000000000000000000000000000000000000FFFFFF0000000000FFEFFFFF
+ FFF7FFFFFFF9FFFFFFFFFF9FFF7FFFF7FCFFFFFFFEFFFFFFFFFFF7DFFFFFC10E
+ 7FFF790F73FFE80FC3FF9F86E1EF8F91F9EF8F8FFFEF983FFFFE72FFFFFFF5FF
+ FF9FF5FFFFCF3DFFFFFFF9FFFFFB61FFFFFF87FFFFFE0FFFFFFC3FFFDFB0BFFF
+ DF80BFFFFF82BFFFF7037FFFFEF7FFFFF9F3FFFFF7FDFFFF6FFEFFFF000FFFFF
+ 0007FFFF0001FFFF0000001F0000000700000007000000030000000100000000
+ 000000000000000000000000000000010000000F0000003F000000FF000001FF
+ 000001FF000001FF000001FF000001FF000007FF00000FFF00003FFF00003FFF
+ 00003FFF00003FFF00007FFF00F07FFF01F07FFF07FC7FFF0FFE7FFF28000000
+ 2000000040000000010008000000000080040000000000000000000000000000
+ 0000000000000000000008000008080000081000080810000810100008101800
+ 0818180010181800101821001021210018212100102129001821290018292900
+ 1821310018293100212931002131310021293900083139001831390021313900
+ 293139002131420029314200213942002939420029394A0029424A0031424A00
+ 31425200314A5200394A5200394A5A0039525A0042525A003952630042526300
+ 395A6300425A6300395A6B00425A6B004A5A6B0042636B004A636B005A636B00
+ 426373004A6373004A637B004A6B7B00526B7B0052737B004A6B8400526B8400
+ 527384005A73840052738C005A738C005A7B8C00637B8C005A7B9400637B9400
+ 6384940063849C006B849C00638C9C006B8C9C00738C9C006B8CA5006B94A500
+ 7394A5007B94A5006B94AD007394AD00739CAD007B9CAD00849CAD007B9CB500
+ 7BA5B50084A5B50084A5BD0084ADBD008CADBD0084ADC6008CADC600A5B5C600
+ 8CB5CE0094B5CE0094BDCE009CBDCE0094BDD6009CBDD600A5BDD600A5C6D600
+ A5C6DE00A5CEDE00ADCEDE00B5CEDE00ADCEE700ADD6E700B5D6E700B5D6EF00
+ BDD6EF00C6DEEF00BDDEF700C6DEF700DEEFF700CEEFFF00D6EFFF00DEEFFF00
+ D6F7FF00DEF7FF00E7FFFF00F7FFFF00FFFFFF00000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000018120900080A080F0A0F2F0000000000000000000000000000000000
+ 000000001F1F0A00000F09090508050000000000000000000000000000000000
+ 000000000A1E120003111226120A08001D3F0000000000000000000000000000
+ 00000000121F1F1209121233373718000505091E2C373C372637372C333F3F00
+ 000000000A232326182326333F372311090A050000030505050912181D12051F
+ 0000000012262F1F26373F46371F0A050512180F091818050000000000000000
+ 2C000000233333262F37373F3718050A18232F2F1F09000518120F0A0A0A0A09
+ 1137000026372F2C2F251F26120A1E261211261F1F181F373F372F2626333F37
+ 18001F0037363737262F1F1F1F1E121E1E1F2F261F333E5050453F333F3F5054
+ 120000003E251D372F231F26262F1F1F1F1F182F3F372F37373F453750505858
+ 0300002E3F2F18373F3E261F122F26262C181E2C372F373F37474E4747586C50
+ 120A000018263F47453F331F122337231E1F18181F3F3F37332F37333745544F
+ 47353C562309264747473C2F261F263E261F181F37454745262526232F3F4536
+ 475E00002F0F00183C3F45372326373E2625121837505B4E1F25332F374F544E
+ 000000001F1805031F262F372F26334533231218334745262F3F4F47584E0000
+ 00000000261D11030A25121F1F1218252312183F543718123F3F365800000000
+ 000000002F1811050A1F26262F261F0A000018371400001F581F440000000000
+ 000000001F0F120F0818251F3C3F471E0300000A3424001F47123F0000000000
+ 000000001205050500121E1F2F263F471F1F0A183F3F052618265E0000000000
+ 0000000011000000000918121F252F3737252F261F0A18262657000000000000
+ 000000000A00000000051809121E1F18333F2C333F2F3D475B00000000000000
+ 00000000050000000A0A0908181F181F2F3736333746636F0000000000000000
+ 00000000000000000A261F180F1E1F2F2625253D4E6500000000000000000000
+ 00000000080305050A1818180F23262F37334765625000000000000000000000
+ 00000000180A452F0000090A093F372F455B6C682F4500000000000000000000
+ 000000000A1E4E18000000001857585E645B5E502F5800000000000000000000
+ 00000000051818000F1F18153C0000005E463745375D00000000000000000000
+ 00000000000812263F2636265000000054462F263F0000000000000000000000
+ 0000000000001F26121D375800000000582F1E18370000000000000000000000
+ 0000000000001F18124465000000000065471F18370000000000000000000000
+ 0000000000000F1F5E0000000000000000005425370000000000000000000000
+ 000000004D18376B0000000000000000000000452F0000000000000000000000
+ 00000000001FFFFF001FFFFF0003FFFF0000001F0000000F0000000700000003
+ 0000000100000001000000000000000000000000000000030000000F0000003F
+ 000000FF000001FF000001FF000001FF000003FF000007FF00000FFF00003FFF
+ 00003FFF00003FFF00003FFF00703FFF00707FFF00F07FFF01F07FFF07FC7FFF
+ 0FFE7FFF2800000020000000400000000100180000000000800C000000000000
+ 0000000000000000000000002A3A4223303A131C2302050610191C1D282F1019
+ 1C1C27301A252A1C28314E667800000000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000374956374B561A252D0202020202021D2932131C
+ 23141F2509111410191D0B151B49637000000000000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000018232830414D27343D060A0F070F12202E372230
+ 3942576425333D18222A10191C0202062E414D00000000000000000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000022303737495534475126343E131C2224323A2835
+ 3F506C7B5C7A8E5571812D3C46050A0E0C14180C151C111C2300000000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000001923293A505B3D515D4459692F3F4B3C505D4259
+ 66506C7B6585975D7A8D3C505D202D35131C2019242A091013020507050A0F09
+ 0F140912180F181D0B1318131E25233038283A432F414B26353F0E181D3A4C56
+ 00000000000000000000000025333C435A674963703548534258665774856383
+ 966F92A55B788A3346521B272E0F151A0F1A1D25333C293B431F2D35141D232C
+ 3C452939420E161B050A0E02020202020205070A040508020202020202020202
+ 4F626F0000000000000000003C505F506B79526E7F4359664C64725976865976
+ 856B8B9F5672832D3D470B11151620282838433C505D4F6B7B49627134465213
+ 1C230202020B111429394328373F1F2D321622261823281B242A182229151F25
+ 202D35597788000000000000465F6B5A77894C657447606D4B65743F55623345
+ 5141576526353E1C292F31424E42586526353D232F39475F6B3446523548552F
+ 3F4B3B4F5D5672836383955C788A4B6574415563415765516E7C658397557082
+ 2D3E48020202384B56000000587284536F805A77885570824158654E66773C4F
+ 5C384B573A4E5A30434E24343C32454F30424B354852496271475F6D34475252
+ 6E7C617E9084AABF80A5BB6D8DA2678599526D7E60809261819583A4BB88ADC2
+ 24343C020202020202000000617F903E56622F414C5772834C65753B505B384E
+ 5A435867465F6C4C6474374855384B583346503345502C3C464C65756A8A9F59
+ 76864C64755F7C8E59768567869A6E8FA157718285A7B985A5BB95B8CA95B9CD
+ 070F150202020202025F656969899D4C66752E3D465770826A899E617F904257
+ 63374C5723313A496271445C6A445A6747606C2C3D4631444E47606E5570804F
+ 69795D7A8B6C8D9F5672827296A97B9EB2799CAF7698AD99BBCFC9E8F982A8BC
+ 24313B18252C0204090202022C3C46435966638496769AAE6F8FA3618092536E
+ 7E37485327333D3D515F5672833C515D30424C3547552E3F482D3E493A4F5962
+ 819367869A5C7A8B536D7E4F69785C788A526C7B5C7A8D6F8FA38CADC27EA0B6
+ 7094A94E6C80627C8BA0B4C03D525F111B20445B697496AB7194A97294A9607F
+ 8F4B6371425A69384D58455B6A617F92445C6A3549562E3E473A4F5B5A76866C
+ 8CA0789DAF6C8CA04257643F5662455C6B3C515C4D66766A899A6D8EA2516E82
+ 7497ABAACADE0000000000004C63721F2D34020202283841617E8F6585986D8C
+ A25A77863D525D465D6C597586617F92465F6D3E556127353F2E3D485A778883
+ A5BB96B9D07C9FB4374B563F5561526E7C4E6A785772847FA2B688ACC3799EB4
+ 0000000000000000000000003B4F5A2D3D470E1519080F13344650445B6B4C62
+ 70537080486170415763506B7A6C8DA0516D7B3C515D233039273741516B7C72
+ 96AB6A8BA0455D6D4B62716280937CA1B6789CAF90B3C87B9DB1000000000000
+ 000000000000000000000000455C6B2E414B222E35070E111B262D3E55622535
+ 3D394D59394D592332392C3D473E53623A505C24323D2938426B899C83ACC156
+ 70802A3C46203038698999678899536E8097B9CD000000000000000000000000
+ 0000000000000000000000004D6575283841222F370C12161923283C4F5B455F
+ 6B485F6E4F6A79465D6D394C581A252D0406090202022E3B445C778808353902
+ 020202020232465297BBCF3A4F5C708C9E000000000000000000000000000000
+ 000000000000000000000000384B581D2A3224323C1C2930111B1F2A3B473F55
+ 63394E5A607E8F6685987195A932434E080E1202020202020216202657707B43
+ 525D0202023749557994A522313B698B9F000000000000000000000000000000
+ 00000000000000000000000026353F0F151B0E151A0E151A06080C2230383344
+ 4F3848564C6472455B6A6180927193A73A4E593446531B252E2C3B4864819064
+ 81930E151B415765243541435C6EA1C0D0000000000000000000000000000000
+ 000000000000000000000000222F38020202020202020202020202131D232C3A
+ 4524303A384D573D55624E67785977865774853F5562486170465D6B32445019
+ 252C263842435D6D415C6F8AB3CB000000000000000000000000000000000000
+ 0000000000000000000000001822280202020202020202020207070A11162939
+ 42151E2425343C30434C3444502E3D48516C7A61809249616F506A7A62829546
+ 60715D7E907198AE000000000000000000000000000000000000000000000000
+ 0000000000000000000000000B111402020202020204060819232A192429141E
+ 23121B1E2C3945384C562F3F4B3A4E5A4B64725C798B556F80516B7E5B7B8F6D
+ 90A4ACCDE2000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000020608020202020202020202182328455C6B394D
+ 592839431F2D3533444F394D584C6575475F6E3F57643D58665F7F937F9EB2B1
+ D1E4000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000111A1E0A0F120910130F181C19262D2D3E492C3C
+ 462E3F491D2A313B515F445B674D6777577486516C7F7294A7B4D4E6B1CDDE8C
+ ACBD000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000002839411620276D8DA34F6978020608020206141D
+ 23182227131D2365889C5776894F6A7A6B8DA299BCD1CDEBFEC0DEEF4662746F
+ 8EA1000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000018232A30424C799EB32A3B450202020202020202
+ 020202022E3F4B8BB3CA93B6CCA4C6D8AFD1E198BBD0A5C8DB83A7BD4966789A
+ B9CD000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000E13182737422A3B450202061F2A313548552837
+ 411F313B637C8B000000000000000000A2C0D36E90A75371836F8FA4557284A1
+ BED0000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000002020211191E25333D435A67608090435867526F
+ 81425F6E82A2B400000000000000000089ADC16E93A9486270425C6B65849700
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000020202020205394E58455C6C24333A2E414E5977
+ 8994B7CC00000000000000000000000093B6CB48657730434F2637425F7A8D00
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 00000000000000000000000002020205080A374C5626374220313D718E9E0000
+ 00000000000000000000000000000000BBD7E97B9CAF384F5C2535415F7A8C00
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 0000000000000000000000000202050205091B27323449560000000000000000
+ 000000000000000000000000000000000000000000008CAEC13D596A59728300
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000859FAE2A3B445A72810000000000000000000000
+ 000000000000000000000000000000000000000000000000006F8EA247627200
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000001FFFFF000FFFFF0007FFFF0001FFFF0000000F
+ 0000000700000003000000010000000100000000000000000000000000000003
+ 0000000F0000003F000000FF000001FF000001FF000001FF000003FF00000FFF
+ 00001FFF00003FFF00003FFF00003FFF00003FFF00703FFF00707FFF00F07FFF
+ 03F07FFF0FFC7FFF1FFE7FFF}
+ end
+ object Label1: TLabel
+ Left = 56
+ Top = 16
+ Width = 126
+ Height = 13
+ Caption = 'Generating Map Preview...'
+ end
+ object ProgressBar1: TProgressBar
+ Left = 56
+ Top = 32
+ Width = 150
+ Height = 17
+ TabOrder = 0
+ end
+end
Added: trunk/WPGM/Progress.~pas
===================================================================
--- trunk/WPGM/Progress.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Progress.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,27 @@
+unit Progress;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, ExtCtrls, ComCtrls, StdCtrls;
+
+type
+ TfrmProgress = class(TForm)
+ Image1: TImage;
+ Label1: TLabel;
+ ProgressBar1: TProgressBar;
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ frmProgress: TfrmProgress;
+
+implementation
+
+{$R *.dfm}
+
+end.
Added: trunk/WPGM/SQLite.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/SQLite.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/SQLite.pas
===================================================================
--- trunk/WPGM/SQLite.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/SQLite.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,56 @@
+unit SQLite;
+
+interface
+
+type TSQLiteDB = Pointer;
+type TSQLiteResult = ^PChar;
+
+function SQLite_Open (dbname: PChar; mode: Integer; var ErrMsg: PChar): TSQLiteDB; cdecl; external 'sqlite.dll' name 'sqlite_open';
+procedure SQLite_Close (db: TSQLiteDB); cdecl; external 'sqlite.dll' name 'sqlite_close';
+function SQLite_Exec (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite.dll' name 'sqlite_exec';
+function SQLite_Version (): PChar; cdecl; external 'sqlite.dll' name 'sqlite_libversion';
+function SQLite_Encoding (): PChar; cdecl; external 'sqlite.dll' name 'sqlite_libencoding';
+function SQLite_ErrorString (ErrNo: Integer): PChar; cdecl; external 'sqlite.dll' name 'sqlite_error_string';
+function SQLite_GetTable (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite.dll' name 'sqlite_get_table';
+procedure SQLite_FreeTable (Table:TSQLiteResult ); cdecl; external 'sqlite.dll' name 'sqlite_free_table';
+procedure SQLite_FreeMem (P: PChar); cdecl; external 'sqlite.dll' name 'sqlite_freemem';
+function SQLite_Complete (P: PChar): boolean; cdecl; external 'sqlite.dll' name 'sqlite_complete';
+function SQLite_LastInsertRowID(db: TSQLiteDB): integer; cdecl; external 'sqlite.dll' name 'sqlite_last_insert_rowid';
+procedure SQLite_Cancel (db: TSQLiteDB); cdecl; external 'sqlite.dll' name 'sqlite_interrupt';
+procedure SQLite_BusyHandler (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite.dll' name'sqlite_busy_handler' ;
+procedure SQLite_BusyTimeout (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite.dll' name 'sqlite_busy_timeout';
+function SQLite_Changes (db: TSQLiteDB): integer; cdecl; external 'sqlite.dll' name 'sqlite_changes';
+
+const
+ SQLITE_OK = 0; // Successful result
+ SQLITE_ERROR = 1; // SQL error or missing database
+ SQLITE_INTERNAL = 2; // An internal logic error in SQLite
+ SQLITE_PERM = 3; // Access permission denied
+ SQLITE_ABORT = 4; // Callback routine requested an abort
+ SQLITE_BUSY = 5; // The database file is locked
+ SQLITE_LOCKED = 6; // A table in the database is locked
+ SQLITE_NOMEM = 7; // A malloc() failed
+ SQLITE_READONLY = 8; // Attempt to write a readonly database
+ SQLITE_INTERRUPT = 9; // Operation terminated by sqlite_interrupt()
+ SQLITE_IOERR = 10; // Some kind of disk I/O error occurred
+ SQLITE_CORRUPT = 11; // The database disk image is malformed
+ SQLITE_NOTFOUND = 12; // (Internal Only) Table or record not found
+ SQLITE_FULL = 13; // Insertion failed because database is full
+ SQLITE_CANTOPEN = 14; // Unable to open the database file
+ SQLITE_PROTOCOL = 15; // Database lock protocol error
+ SQLITE_EMPTY = 16; // (Internal Only) Database table is empty
+ SQLITE_SCHEMA = 17; // The database schema changed
+ SQLITE_TOOBIG = 18; // Too much data for one row of a table
+ SQLITE_CONSTRAINT = 19; // Abort due to contraint violation
+ SQLITE_MISMATCH = 20; // Data type mismatch
+ SQLITE_MISUSE = 21; // Library used incorrectly
+ SQLITE_NOLFS = 22; // Uses OS features not supported on host
+ SQLITE_AUTH = 23; // Authorization denied
+ SQLITE_FORMAT = 24; // Auxiliary database format error
+ SQLITE_ROW = 100; // sqlite_step() has another row ready
+ SQLITE_DONE = 101; // sqlite_step() has finished executing
+
+
+implementation
+
+end.
Added: trunk/WPGM/SQLiteTable.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/SQLiteTable.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/SQLiteTable.pas
===================================================================
--- trunk/WPGM/SQLiteTable.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/SQLiteTable.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,233 @@
+unit SQLiteTable;
+
+{
+ Simple classes for using SQLite's exec and get_table.
+
+ TSQLiteDatabase wraps the calls to opend and close an SQLite database.
+ It also wraps SQLite_exec for queries that do not return a result set
+
+ TSQLiteTable wraps sqlite_get_table.
+ It allows accessing fields by name as well as index and can step through a
+ result set with the Next procedure.
+
+ Created by Pablo Pissanetzky (pablo at myhtpc.net)
+}
+
+interface
+
+uses
+ SQLite , Classes;
+
+type
+
+ TSQLiteTable = class;
+
+ TSQLiteDatabase = class
+ private
+ fDB : TSQLiteDB;
+ public
+ constructor Create( const FileName : string );
+ destructor Destroy; override;
+ function GetTable( const SQL : string ) : TSQLiteTable;
+ procedure ExecSQL( const SQL : string );
+ end;
+
+ TSQLiteTable = class
+ private
+ fTable : TSQLiteResult;
+ fRecord : TSQLiteResult;
+ fRowCount : Cardinal;
+ fColCount : Cardinal;
+ fCols : TStringList;
+ fRow : Cardinal;
+ function GetFields(I: Integer): PChar;
+ function GetEOF: Boolean;
+ function GetColumns(I: Integer): string;
+ function GetFieldByName(FieldName: string): PChar;
+ function GetCount: Integer;
+ public
+ constructor Create( DB : TSQLiteDatabase; const SQL : string );
+ destructor Destroy; override;
+ property EOF : Boolean read GetEOF;
+ property Fields[ I : Integer ] : PChar read GetFields;
+ property FieldByName[ FieldName : string ] : PChar read GetFieldByName;
+ property Columns[ I : Integer ] : string read GetColumns;
+ property ColCount : Cardinal read fColCount;
+ property RowCount : Cardinal read fRowCount;
+ property Row : Cardinal read fRow;
+ procedure Next;
+
+ // The property Count is used when you execute count(*) queries.
+ // It returns 0 if the result set is empty or the value of the
+ // first field as an integer.
+ property Count : Integer read GetCount;
+ end;
+
+implementation
+
+uses
+ SysUtils;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+ Msg : PChar;
+begin
+ inherited Create;
+
+ Msg := nil;
+ try
+
+ fDB := SQLite_Open( PChar( FileName ) , 0 , Msg );
+
+ if not Assigned( fDB ) then
+ raise Exception.CreateFmt( 'Failed to open database "%s" : %s' , [ FileName , Msg ] );
+
+ finally
+ if Assigned( Msg ) then
+ SQLite_FreeMem( Msg );
+ end;
+end;
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+ if Assigned( fDB ) then
+ SQLite_Close( fDB );
+ inherited;
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+ Msg : PChar;
+begin
+ Msg := nil;
+ try
+ if SQLite_Exec( fDB , PChar( SQL ) , nil , nil , Msg ) <> SQLITE_OK then
+ raise Exception.CreateFmt( 'Error executing SQL "%s" : %s' , [ SQL , Msg ] );
+ finally
+ if Assigned( Msg ) then
+ SQLite_FreeMem( Msg );
+ end;
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+ Result := TSQLiteTable.Create( Self , SQL );
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+ Msg : PChar;
+ I : Integer;
+begin
+ fTable := nil;
+ Msg := nil;
+ try
+ if SQLite_GetTable( DB.fDB , PChar( SQL ) , fTable , fRowCount , fColCount , Msg ) <> SQLITE_OK then
+ raise Exception.CreateFmt( 'Error executing SQL "%s" : %s' , [ SQL , Msg ] );
+
+ fRecord := fTable;
+
+ fCols := TStringList.Create;
+
+ if fRowCount > 0 then
+ begin
+ for I := 0 to Pred( fColCount ) do
+ begin
+ fCols.Add( fRecord^ );
+ Inc( fRecord );
+ end;
+ end;
+
+ fRow := 0;
+
+ finally
+ if Assigned( Msg ) then
+ SQLite_FreeMem( Msg );
+ end;
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+begin
+ if Assigned( fTable ) then
+ SQLite_FreeTable( fTable );
+ if Assigned( fCols ) then
+ fCols.Free;
+ inherited;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+ Result := fCols[ I ];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCount: Integer;
+begin
+ if not EOF then
+ Result := StrToInt( Fields[ 0 ] )
+ else
+ Result := 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+ Result := fRow >= fRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): PChar;
+begin
+ Result := GetFields( fCols.IndexOf( FieldName ) );
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): PChar;
+var
+ P : TSQLiteResult;
+begin
+ Result := nil;
+
+ if not EOF then
+ begin
+ P := fRecord;
+ Inc( P , I );
+ Result := P^;
+ end;
+end;
+
+//..............................................................................
+
+procedure TSQLiteTable.Next;
+begin
+ if not EOF then
+ begin
+ Inc( fRecord , fColCount );
+ Inc( fRow );
+ end;
+end;
+
+
+end.
Added: trunk/WPGM/Spawnregions.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Spawnregions.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Spawnregions.ddp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Spawnregions.ddp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Spawnregions.dfm
===================================================================
--- trunk/WPGM/Spawnregions.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Spawnregions.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,230 @@
+object frmRegions: TfrmRegions
+ Left = 214
+ Top = 135
+ AutoScroll = False
+ Caption = 'Regions'
+ ClientHeight = 495
+ ClientWidth = 756
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ OnResize = FormResize
+ OnShow = FormShow
+ DesignSize = (
+ 756
+ 495)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Label1: TLabel
+ Left = 161
+ Top = 468
+ Width = 96
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Screen Coordinates:'
+ end
+ object Label2: TLabel
+ Left = 417
+ Top = 468
+ Width = 83
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Map Coordinates:'
+ end
+ object lblScreen: TLabel
+ Left = 264
+ Top = 468
+ Width = 3
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ end
+ object lblMap: TLabel
+ Left = 512
+ Top = 468
+ Width = 3
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ end
+ object Label3: TLabel
+ Left = 624
+ Top = 264
+ Width = 55
+ Height = 13
+ Anchors = [akTop, akRight]
+ Caption = 'Selected:'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = [fsBold]
+ ParentFont = False
+ end
+ object lblSelected: TLabel
+ Left = 624
+ Top = 280
+ Width = 3
+ Height = 13
+ Anchors = [akTop, akRight]
+ end
+ object cbMap: TComboBox
+ Left = 8
+ Top = 464
+ Width = 145
+ Height = 21
+ Style = csDropDownList
+ Anchors = [akLeft, akBottom]
+ ItemHeight = 13
+ ItemIndex = 0
+ TabOrder = 0
+ Text = 'Felucca'
+ Items.Strings = (
+ 'Felucca'
+ 'Trammel'
+ 'Ilshenar'
+ 'Malas'
+ 'Tokuno Islands')
+ end
+ object pbMap: TPaintBox32
+ Left = 3
+ Top = 8
+ Width = 597
+ Height = 433
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ TabOrder = 1
+ OnMouseDown = pbMapMouseDown
+ OnMouseMove = pbMapMouseMove
+ OnMouseUp = pbMapMouseUp
+ OnPaintBuffer = pbMapPaintBuffer
+ end
+ object sbX: TScrollBar
+ Left = 4
+ Top = 440
+ Width = 597
+ Height = 17
+ Anchors = [akLeft, akRight, akBottom]
+ LargeChange = 50
+ PageSize = 0
+ TabOrder = 2
+ OnScroll = sbXScroll
+ end
+ object sbY: TScrollBar
+ Left = 601
+ Top = 8
+ Width = 17
+ Height = 432
+ Anchors = [akTop, akRight, akBottom]
+ Kind = sbVertical
+ LargeChange = 50
+ PageSize = 0
+ TabOrder = 3
+ OnScroll = sbYScroll
+ end
+ object lbRects: TListBox
+ Left = 624
+ Top = 8
+ Width = 121
+ Height = 217
+ Anchors = [akTop, akRight]
+ ItemHeight = 13
+ TabOrder = 4
+ OnDblClick = lbRectsDblClick
+ OnKeyDown = lbRectsKeyDown
+ end
+ object btnAdd: TButton
+ Left = 624
+ Top = 232
+ Width = 57
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 5
+ OnClick = btnAddClick
+ end
+ object btnRemove: TButton
+ Left = 688
+ Top = 232
+ Width = 57
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Remove'
+ TabOrder = 6
+ OnClick = btnRemoveClick
+ end
+ object Button1: TButton
+ Left = 624
+ Top = 304
+ Width = 121
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Copy as Spawnregion'
+ TabOrder = 7
+ OnClick = Button1Click
+ end
+ object Button2: TButton
+ Left = 624
+ Top = 336
+ Width = 121
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Copy as Region'
+ TabOrder = 8
+ OnClick = Button2Click
+ end
+ object Button3: TButton
+ Left = 624
+ Top = 368
+ Width = 121
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Paste Spawnregion'
+ TabOrder = 9
+ OnClick = Button3Click
+ end
+ object Button4: TButton
+ Left = 624
+ Top = 400
+ Width = 121
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Paste Region'
+ TabOrder = 10
+ OnClick = Button4Click
+ end
+ object btnZoomOut: TButton
+ Left = 624
+ Top = 432
+ Width = 41
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = '-'
+ TabOrder = 11
+ OnClick = btnZoomOutClick
+ end
+ object btnZoomIn: TButton
+ Left = 672
+ Top = 432
+ Width = 41
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = '+'
+ TabOrder = 12
+ OnClick = btnZoomInClick
+ end
+ object btnRedraw: TButton
+ Left = 624
+ Top = 464
+ Width = 89
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = 'Redraw'
+ TabOrder = 13
+ OnClick = btnRedrawClick
+ end
+end
Added: trunk/WPGM/Spawnregions.pas
===================================================================
--- trunk/WPGM/Spawnregions.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Spawnregions.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,660 @@
+unit Spawnregions;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, GR32, GR32_Blend, GR32_Image, UOMap, UOStatics, ClipBrd;
+
+type
+ TfrmRegions = class(TForm)
+ cbMap: TComboBox;
+ pbMap: TPaintBox32;
+ sbX: TScrollBar;
+ sbY: TScrollBar;
+ Label1: TLabel;
+ Label2: TLabel;
+ lblScreen: TLabel;
+ lblMap: TLabel;
+ lbRects: TListBox;
+ btnAdd: TButton;
+ btnRemove: TButton;
+ Label3: TLabel;
+ lblSelected: TLabel;
+ Button1: TButton;
+ Button2: TButton;
+ Button3: TButton;
+ Button4: TButton;
+ btnZoomOut: TButton;
+ btnZoomIn: TButton;
+ btnRedraw: TButton;
+ procedure FormShow(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure pbMapPaintBuffer(Sender: TObject);
+ procedure sbXScroll(Sender: TObject; ScrollCode: TScrollCode;
+ var ScrollPos: Integer);
+ procedure sbYScroll(Sender: TObject; ScrollCode: TScrollCode;
+ var ScrollPos: Integer);
+ procedure FormDestroy(Sender: TObject);
+ procedure FormResize(Sender: TObject);
+ procedure pbMapMouseMove(Sender: TObject; Shift: TShiftState; X,
+ Y: Integer);
+ procedure btnRemoveClick(Sender: TObject);
+ procedure pbMapMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure pbMapMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure btnAddClick(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure Button3Click(Sender: TObject);
+ procedure Button4Click(Sender: TObject);
+ procedure lbRectsKeyDown(Sender: TObject; var Key: Word;
+ Shift: TShiftState);
+ procedure lbRectsDblClick(Sender: TObject);
+ procedure btnZoomOutClick(Sender: TObject);
+ procedure btnZoomInClick(Sender: TObject);
+ procedure btnRedrawClick(Sender: TObject);
+ private
+ { Private declarations }
+ Places: Array of TRect;
+
+ public
+ { Public declarations }
+ procedure ChangeMap(MapId: Byte);
+ procedure RedrawBuffer(Buffer: TBitmap32; StartX: Integer; StartY: Integer; Width: Integer; Height: Integer);
+
+ function MapToBuffer(Point: TPoint): TPoint;
+ function BufferToMap(Point: TPoint): TPoint;
+ procedure AddRect(X1: Integer; Y1: Integer; X2: Integer; Y2: Integer);
+ procedure UpdateSelectionLabel;
+ end;
+
+var
+ frmRegions: TfrmRegions;
+ Map: TMapReader;
+ Statics: TStaticReader;
+ Scale: Single;
+ Buffer: TBitmap32; // This is for copying map2map
+ SelStartX, SelStartY: Integer;
+ SelEndX, SelEndY: Integer;
+
+implementation
+
+{$R *.dfm}
+
+uses Main, Math, XMLReader, StrLib, UORadarCol;
+
+function TfrmRegions.MapToBuffer(Point: TPoint): TPoint;
+begin
+ Result.X := Ceil((Point.X - sbX.Position) / Scale);
+ Result.Y := Ceil((Point.Y - sbY.Position) / Scale);
+end;
+
+function TfrmRegions.BufferToMap(Point: TPoint): TPoint;
+begin
+ Result.X := Ceil(Point.X * Scale) + sbX.Position;
+ Result.Y := Ceil(Point.Y * Scale) + sbY.Position;
+end;
+
+procedure TfrmRegions.RedrawBuffer(Buffer: TBitmap32; StartX: Integer; StartY: Integer; Width: Integer; Height: Integer);
+var
+ X, Y, RealX, RealY: Integer;
+ MapBlock: TMapBlock;
+ i, j, k, l: Integer;
+ MapX, MapY: Integer; // Map Coordinates
+ MapPoint, ScreenPoint: TPoint;
+ MinBlockX, MinBlockY: Integer; // The lowest blocks we draw
+ MaxBlockX, MaxBlockY: Integer; // The highest blocks we draw
+ BlendColor: TColor32;
+ PixelCount: Integer;
+ StaticBlock: TStaticBlock;
+ DrawColor: TColor32;
+ DrawColorZ: Integer;
+begin
+ BlendColor := Color32(255, 255, 255, 127);
+
+ MapPoint := BufferToMap(Point(StartX, StartY));
+ MinBlockX := MapPoint.X div 8;
+ MinBlockY := MapPoint.Y div 8;
+
+ MapPoint := BufferToMap(Point(StartX + Width - 1, StartY + Height - 1));
+ MaxBlockX := MapPoint.X div 8;
+ MaxBlockY := MapPoint.Y div 8;
+
+ // Scale down/up ? (If Scale > 1, we draw less blocks), thus
+ // we have to divide and round up
+ {MaxBlockX := Ceil(MaxBlockX / Scale);
+ MaxBlockY := Ceil(MaxBlockY / Scale);}
+
+ for X := MinBlockX to MaxBlockX + 1 do
+ for Y := MinBlockY to MaxBlockY + 1 do begin
+ ScreenPoint := MapToBuffer(Point(X * 8, Y * 8));
+
+ // Out of screen check
+ if (ScreenPoint.X < -7) or (ScreenPoint.Y < -7) then
+ continue;
+
+ // Out of screen check
+ if (ScreenPoint.X >= Buffer.Width) or (ScreenPoint.Y >= Buffer.Height) then
+ continue;
+
+ Map.ReadBlock(X, Y, MapBlock);
+ Statics.ReadBlock(X, Y, StaticBlock);
+
+ for i := 0 to 63 do begin
+ PixelCount := Ceil(1.0 / Scale);
+
+ DrawColor := RadarCol.GetLandColor(MapBlock.Cells[i].Id);
+ DrawColorZ := MapBlock.Cells[i].Height;
+
+ // Get the topmost color here
+ for j := 0 to Length(StaticBlock) - 1 do begin
+ if (StaticBlock[j].X = i mod 8) and (StaticBlock[j].Y = i div 8) and
+ (StaticBlock[j].Z >= DrawColorZ) then begin
+ DrawColorZ := StaticBlock[j].Z;
+ DrawColor := RadarCol.GetItemColor(StaticBlock[j].Id);
+ end;
+ end;
+
+ RealX := ScreenPoint.X + (i mod 8) * PixelCount;
+ RealY := ScreenPoint.Y + (i div 8) * PixelCount;
+ if Scale <> 1.0 then begin
+ for j := 0 to PixelCount - 1 do begin
+ for k := 0 to PixelCount - 1 do begin
+ Buffer.PixelS[RealX + j, RealY + k] := DrawColor;
+ end;
+ end;
+ end else begin
+ Buffer.PixelS[RealX, RealY] := DrawColor;
+ end;
+
+ MapX := X * 8 + i mod 8;
+ MapY := Y * 8 + i div 8;
+
+ // Prüfen ob der Punkt teil eines Rectangles ist
+ for j := 0 to Length(Places) - 1 do begin
+ if (Places[j].Left <= MapX) and (Places[j].Right >= MapX)
+ and (Places[j].Top <= MapY) and (Places[j].Bottom >= MapY) then
+ begin
+ // Found a match!!
+ Buffer.PixelS[RealX, RealY] := BlendReg(BlendColor, Buffer.PixelS[RealX, RealY]);
+ EMMS();
+ //break;
+ end;
+ end;
+ end;
+ end;
+
+ // Redraw selection rectangle
+ if (SelStartX <> -1) and (SelStartY <> -1) then begin
+ MapPoint := MapToBuffer(Point(SelStartX, SelStartY));
+
+ pbMap.Buffer.Canvas.Brush.Style := bsClear;
+ pbMap.Buffer.Canvas.Pen.Color := clWhite;
+ pbMap.Buffer.Canvas.Pen.Style := psDot;
+
+ if (SelEndX <> -1) and (SelEndY <> -1) then begin
+ ScreenPoint := MapToBuffer(Point(SelEndX, SelEndY));
+ end else begin
+ ScreenPoint := pbMap.ScreenToClient(Mouse.CursorPos);
+ end;
+
+ pbMap.Buffer.Canvas.Rectangle(MapPoint.X, MapPoint.Y, ScreenPoint.X, ScreenPoint.Y);
+ end;
+end;
+
+procedure TfrmRegions.ChangeMap(MapId: Byte);
+begin
+ if MapId >= Length(Maps) then
+ exit;
+
+ Map := Main.Maps[MapId];
+ Statics := Main.Statics[MapId];
+
+ sbX.Max := Map.getWidth * 8 - 1 - pbMap.ClientWidth;
+ sbX.Min := 0;
+ sbX.Position := 0;
+
+ sbY.Max := Map.getHeight * 8 - 1 - pbMap.ClientHeight;
+ sbY.Min := 0;
+ sbY.Position := 0;
+
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.FormShow(Sender: TObject);
+begin
+ ChangeMap(0);
+end;
+
+procedure TfrmRegions.FormCreate(Sender: TObject);
+begin
+ Map := nil;
+ Statics := nil;
+ Scale := 1;
+ Buffer := TBitmap32.Create;
+
+ SelStartX := -1;
+ SelStartY := -1;
+ SelEndX := -1;
+ SelEndY := -1;
+
+ {AddRect(1776, 60, 3060, 670);
+ AddRect(1900, 670, 2515, 870);
+ AddRect(2515, 670, 2762, 870);
+ AddRect(3009, 100, 3055, 720);
+ AddRect(3055, 150, 3110, 655);
+ AddRect(3110, 320, 3210, 595);
+ AddRect(3210, 375, 3360, 550);
+ AddRect(3360, 410, 3424, 510);
+ AddRect(3424, 410, 3453, 465);}
+end;
+
+procedure TfrmRegions.pbMapPaintBuffer(Sender: TObject);
+begin
+ RedrawBuffer(pbMap.Buffer, 0, 0, pbMap.Buffer.Width, pbMap.Buffer.Height);
+end;
+
+procedure TfrmRegions.sbXScroll(Sender: TObject; ScrollCode: TScrollCode;
+ var ScrollPos: Integer);
+var
+ Diff: Integer;
+ OldPos: Integer;
+begin
+ Diff := ScrollPos - (Sender as TScrollBar).Position;
+
+ if (Buffer.Width <> pbMap.Buffer.Height) or (Buffer.Height <> pbMap.Buffer.Height) then
+ begin
+ Buffer.SetSizeFrom(pbMap.Buffer);
+ end;
+
+ if (Abs(Diff) > pbMap.Width) then
+ pbMap.Invalidate
+ else begin
+ pbMap.Buffer.DrawTo(Buffer);
+ Buffer.DrawTo(pbMap.Buffer, - Ceil(Diff / Scale), 0);
+
+ OldPos := sbX.Position;
+ sbX.Position := ScrollPos;
+
+ // If Diff is Positive, redraw right part
+ if Diff >= 0 then
+ RedrawBuffer(pbMap.Buffer, pbMap.Buffer.Width - Ceil(Diff / Scale), 0, Trunc(Diff / Scale), pbMap.Buffer.Height);
+
+ // If Diff is Negative, redraw left part
+ if Diff < 0 then
+ RedrawBuffer(pbMap.Buffer, 0, 0, - Trunc(Diff / Scale), pbMap.Buffer.Height);
+
+ sbX.Position := OldPos;
+
+ pbMap.Flush;
+ end;
+end;
+
+procedure TfrmRegions.sbYScroll(Sender: TObject; ScrollCode: TScrollCode;
+ var ScrollPos: Integer);
+var
+ Diff: Integer;
+ OldPos: Integer;
+begin
+ Diff := ScrollPos - (Sender as TScrollBar).Position;
+
+ if (Buffer.Width <> pbMap.Buffer.Height) or (Buffer.Height <> pbMap.Buffer.Height) then
+ begin
+ Buffer.SetSizeFrom(pbMap.Buffer);
+ end;
+
+ if (Abs(Diff) > pbMap.Height) then
+ pbMap.Invalidate
+ else begin
+ pbMap.Buffer.DrawTo(Buffer);
+ Buffer.DrawTo(pbMap.Buffer, 0, - Ceil(Diff / Scale));
+
+ OldPos := sbY.Position;
+ sbY.Position := ScrollPos;
+
+ // If Diff is Positive, redraw right part
+ if Diff >= 0 then
+ RedrawBuffer(pbMap.Buffer, 0, pbMap.Height - Ceil(Diff / Scale), pbMap.Buffer.Width, Ceil(Diff / Scale));
+
+ // If Diff is Negative, redraw right part
+ if Diff < 0 then
+ RedrawBuffer(pbMap.Buffer, 0, 0, pbMap.Buffer.Width, - Ceil(Diff / Scale));
+
+ sbY.Position := OldPos;
+ pbMap.Flush;
+ end;
+end;
+
+procedure TfrmRegions.FormDestroy(Sender: TObject);
+begin
+ Buffer.Free;
+end;
+
+procedure TfrmRegions.FormResize(Sender: TObject);
+var
+ OldX, OldY: Integer;
+begin
+ OldX := sbX.Position;
+ OldY := sbY.Position;
+
+ ChangeMap(MapId);
+ sbX.Position := OldX;
+ sbY.Position := OldY;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.pbMapMouseMove(Sender: TObject; Shift: TShiftState;
+ X, Y: Integer);
+var
+ P: TPoint;
+begin
+ P := BufferToMap(Point(X, Y));
+
+ lblScreen.Caption := Format('%d,%d', [X, Y]);
+ lblMap.Caption := Format('%d,%d', [P.X, P.Y]);
+
+ if ((SelStartX <> -1) or (SelStartY <> -1)) and
+ ((SelEndX = -1) and (SelEndY = -1)) then begin
+ pbMap.Invalidate;
+ end;
+end;
+
+procedure TfrmRegions.btnRemoveClick(Sender: TObject);
+var
+ i: Integer;
+begin
+ if lbRects.ItemIndex <> -1 then begin
+ if lbRects.ItemIndex < Length(Places) - 1 then begin
+ // Copy Downwards
+ for i := lbRects.ItemIndex to Length(Places) - 2 do begin
+ Places[i] := Places[i+1];
+ end;
+ SetLength(Places, Length(Places) - 1);
+ pbMap.Invalidate;
+ end;
+ lbRects.Items.Delete(lbRects.ItemIndex);
+ end;
+end;
+
+procedure TFrmRegions.AddRect(X1: Integer; Y1: Integer; X2: Integer; Y2: Integer);
+var
+ Temp: Integer;
+begin
+ if X1 > X2 then begin
+ Temp := X1;
+ X1 := X2;
+ X2 := temp;
+ end;
+
+ if Y1 > Y2 then begin
+ Temp := Y1;
+ Y1 := Y2;
+ Y2 := temp;
+ end;
+
+ SetLength(Places, Length(Places) + 1);
+ Places[Length(Places) - 1] := Rect(X1, Y1, X2, Y2);
+
+ lbRects.Items.Add(Format('%d,%d to %d,%d', [X1, Y1, X2, Y2]));
+end;
+
+procedure TfrmRegions.pbMapMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+var
+ P: TPoint;
+begin
+ SelStartX := -1;
+ SelStartY := -1;
+ SelEndX := -1;
+ SelEndY := -1;
+
+ P := BufferToMap(Point(X, Y));
+ SelStartX := P.X;
+ SelStartY := P.Y;
+
+ UpdateSelectionLabel;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.pbMapMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+var
+ P: TPoint;
+begin
+ P := BufferToMap(Point(X, Y));
+ SelEndX := P.X;
+ SelEndY := P.Y;
+ UpdateSelectionLabel;
+ pbMap.Invalidate;
+end;
+
+procedure TFrmRegions.UpdateSelectionLabel;
+begin
+ if (SelStartX = -1) or (SelStartY = -1) or (SelEndX = -1) or (SelEndY = -1) then
+ begin
+ lblSelected.Caption := '';
+ btnAdd.Enabled := False;
+ end else begin
+ lblSelected.Caption := Format('%d,%d to %d,%d', [SelStartX, SelStartY, SelEndX, SelEndY]);
+ btnAdd.Enabled := True;
+ end;
+end;
+
+procedure TfrmRegions.btnAddClick(Sender: TObject);
+begin
+ AddRect(SelStartX, SelStartY, SelEndX, SelEndY);
+ SelStartX := -1;
+ SelStartY := -1;
+ SelEndX := -1;
+ SelEndY := -1;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.Button1Click(Sender: TObject);
+var
+ i: Integer;
+ Result: String;
+ ClipBoard: TClipboard;
+begin
+ ClipBoard := TClipBoard.Create;
+
+ for i := 0 to Length(Places) - 1 do begin
+ Result := Result + Format(#9 + #9 + '<rectangle from="%d,%d" to="%d,%d" map="%u" />' + #13, [Places[i].Left, Places[i].Top, Places[i].Right, Places[i].Bottom, cbMap.ItemIndex]);
+ end;
+
+ ClipBoard.SetTextBuf(PChar(result));
+end;
+
+procedure TfrmRegions.Button2Click(Sender: TObject);
+var
+ i: Integer;
+ Result: String;
+ ClipBoard: TClipboard;
+begin
+ ClipBoard := TClipBoard.Create;
+
+ for i := 0 to Length(Places) - 1 do begin
+ Result := Result + Format(#9 + #9 + '<rectangle x1="%d" y1="%d" x2="%d" y2="%d" map="%u" />' + #13, [Places[i].Left, Places[i].Top, Places[i].Right, Places[i].Bottom, cbMap.ItemIndex]);
+ end;
+
+ ClipBoard.SetTextBuf(PChar(result));
+ ClipBoard.Free;
+end;
+
+procedure TfrmRegions.Button3Click(Sender: TObject);
+var
+ ClipBoard: TClipboard;
+ Content: String;
+ Reader: TXMLReader;
+ Document, Node: TXMLNode;
+ i: Integer;
+ sFrom, sTo: String;
+ Parts: TStringList;
+ x1, x2, y1, y2: Integer;
+begin
+ ClipBoard := TClipBoard.Create;
+ Content := '<rectangles>' + ClipBoard.AsText + '</rectangles>';
+
+ Reader := nil;
+ Document := nil;
+ Parts := TStringList.Create;
+
+ try
+ Reader := TXMLStringReader.Create(Content);
+ Document := Reader.ParseDocument.Nodes[0];
+
+ // Iterate over the rectangle nodes
+ for i := 0 to Document.NodeCount - 1 do begin
+ Node := Document.Nodes[i];
+
+ if Node.Name <> 'rectangle' then
+ continue; // Skip this node
+
+ // Look up From + To
+ Node.LookupBasicData('from', sFrom);
+ Node.LookupBasicData('to', sTo);
+
+ Parts.Clear;
+ Split(sFrom, ',', Parts);
+ if Parts.Count <> 2 then
+ continue; // From attribute is incorrect
+
+ x1 := StrToIntDef(Parts[0], 0);
+ y1 := StrToIntDef(Parts[1], 0);
+
+ Parts.Clear;
+ Split(sTo, ',', Parts);
+ if Parts.Count <> 2 then
+ continue; // To attribute is incorrect
+
+ x2 := StrToIntDef(Parts[0], 0);
+ y2 := StrToIntDef(Parts[1], 0);
+
+ AddRect(x1, y1, x2, y2);
+ end;
+ except
+ on e: Exception do begin
+ Application.MessageBox(PAnsiChar('The following error occured while parsing the XML definition: ' + #13 + e.Message), 'Error', MB_OK+MB_ICONERROR);
+ end;
+ end;
+
+ Reader.Free;
+ Document.Free;
+ Parts.Free;
+ ClipBoard.Free;
+end;
+
+procedure TfrmRegions.Button4Click(Sender: TObject);
+var
+ ClipBoard: TClipboard;
+ Content: String;
+ Reader: TXMLReader;
+ Document, Node: TXMLNode;
+ i: Integer;
+ Temp: String;
+ x1, x2, y1, y2: Integer;
+begin
+ ClipBoard := TClipBoard.Create;
+ Content := '<rectangles>' + ClipBoard.AsText + '</rectangles>';
+
+ Reader := nil;
+ Document := nil;
+
+ try
+ Reader := TXMLStringReader.Create(Content);
+ Document := Reader.ParseDocument.Nodes[0];
+
+ // Iterate over the rectangle nodes
+ for i := 0 to Document.NodeCount - 1 do begin
+ Node := Document.Nodes[i];
+
+ if Node.Name <> 'rectangle' then
+ continue; // Skip this node
+
+ Node.LookupBasicData('x1', temp);
+ x1 := StrToIntDef(temp, 0);
+
+ Node.LookupBasicData('x2', temp);
+ x2 := StrToIntDef(temp, 0);
+
+ Node.LookupBasicData('y1', temp);
+ y1 := StrToIntDef(temp, 0);
+
+ Node.LookupBasicData('y2', temp);
+ y2 := StrToIntDef(temp, 0);
+
+ AddRect(x1, y1, x2, y2);
+ end;
+ except
+ on e: Exception do begin
+ Application.MessageBox(PAnsiChar('The following error occured while parsing the XML definition: ' + #13 + e.Message), 'Error', MB_OK+MB_ICONERROR);
+ end;
+ end;
+
+ Reader.Free;
+ Document.Free;
+ ClipBoard.Free;
+end;
+
+procedure TfrmRegions.lbRectsKeyDown(Sender: TObject; var Key: Word;
+ Shift: TShiftState);
+begin
+ if Key = 46 then
+ btnRemoveClick(Sender);
+end;
+
+procedure TfrmRegions.lbRectsDblClick(Sender: TObject);
+var
+ centerx, centery: Integer;
+begin
+ if lbRects.ItemIndex = -1 then
+ exit;
+
+ // center the map view on the dbl clicked region
+ CenterX := (Places[lbRects.ItemIndex].Right - Places[lbRects.ItemIndex].Left) div 2;
+ CenterX := CenterX + Places[lbRects.ItemIndex].Left;
+
+ CenterY := (Places[lbRects.ItemIndex].Bottom - Places[lbRects.ItemIndex].Top) div 2;
+ CenterY := CenterY + Places[lbRects.ItemIndex].Top;
+
+ // Now take the viewport into account
+ CenterX := CenterX - Trunc((pbMap.ClientWidth div 2) * Scale);
+ CenterY := CenterY - Trunc((pbMap.ClientHeight div 2) * Scale);
+
+ if CenterX > sbX.Max then
+ CenterX := sbX.Max;
+
+ if CenterY > sbY.Max then
+ CenterY := sbY.Max;
+
+ if CenterX < 0 then
+ CenterX := 0;
+
+ if CenterY < 0 then
+ CenterY := 0;
+
+ sbX.Position := CenterX;
+ sbY.Position := CenterY;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.btnZoomOutClick(Sender: TObject);
+begin
+ Scale := Scale / 0.5;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.btnZoomInClick(Sender: TObject);
+begin
+ Scale := Scale * 0.5;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.btnRedrawClick(Sender: TObject);
+begin
+ pbMap.Invalidate;
+end;
+
+end.
Added: trunk/WPGM/Spawnregions.~ddp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Spawnregions.~ddp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Spawnregions.~dfm
===================================================================
--- trunk/WPGM/Spawnregions.~dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Spawnregions.~dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,230 @@
+object frmRegions: TfrmRegions
+ Left = 214
+ Top = 135
+ AutoScroll = False
+ Caption = 'Regions'
+ ClientHeight = 495
+ ClientWidth = 756
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ OnResize = FormResize
+ OnShow = FormShow
+ DesignSize = (
+ 756
+ 495)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Label1: TLabel
+ Left = 161
+ Top = 468
+ Width = 96
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Screen Coordinates:'
+ end
+ object Label2: TLabel
+ Left = 417
+ Top = 468
+ Width = 83
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = 'Map Coordinates:'
+ end
+ object lblScreen: TLabel
+ Left = 264
+ Top = 468
+ Width = 3
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ end
+ object lblMap: TLabel
+ Left = 512
+ Top = 468
+ Width = 3
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ end
+ object Label3: TLabel
+ Left = 624
+ Top = 264
+ Width = 55
+ Height = 13
+ Anchors = [akTop, akRight]
+ Caption = 'Selected:'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = [fsBold]
+ ParentFont = False
+ end
+ object lblSelected: TLabel
+ Left = 624
+ Top = 280
+ Width = 3
+ Height = 13
+ Anchors = [akTop, akRight]
+ end
+ object cbMap: TComboBox
+ Left = 8
+ Top = 464
+ Width = 145
+ Height = 21
+ Style = csDropDownList
+ Anchors = [akLeft, akBottom]
+ ItemHeight = 13
+ ItemIndex = 0
+ TabOrder = 0
+ Text = 'Felucca'
+ Items.Strings = (
+ 'Felucca'
+ 'Trammel'
+ 'Ilshenar'
+ 'Malas'
+ 'Tokuno Islands')
+ end
+ object pbMap: TPaintBox32
+ Left = 3
+ Top = 8
+ Width = 597
+ Height = 433
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ TabOrder = 1
+ OnMouseDown = pbMapMouseDown
+ OnMouseMove = pbMapMouseMove
+ OnMouseUp = pbMapMouseUp
+ OnPaintBuffer = pbMapPaintBuffer
+ end
+ object sbX: TScrollBar
+ Left = 4
+ Top = 440
+ Width = 597
+ Height = 17
+ Anchors = [akLeft, akRight, akBottom]
+ LargeChange = 50
+ PageSize = 0
+ TabOrder = 2
+ OnScroll = sbXScroll
+ end
+ object sbY: TScrollBar
+ Left = 601
+ Top = 8
+ Width = 17
+ Height = 432
+ Anchors = [akTop, akRight, akBottom]
+ Kind = sbVertical
+ LargeChange = 50
+ PageSize = 0
+ TabOrder = 3
+ OnScroll = sbYScroll
+ end
+ object lbRects: TListBox
+ Left = 624
+ Top = 8
+ Width = 121
+ Height = 217
+ Anchors = [akTop, akRight]
+ ItemHeight = 13
+ TabOrder = 4
+ OnDblClick = lbRectsDblClick
+ OnKeyDown = lbRectsKeyDown
+ end
+ object btnAdd: TButton
+ Left = 624
+ Top = 232
+ Width = 57
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Add'
+ Enabled = False
+ TabOrder = 5
+ OnClick = btnAddClick
+ end
+ object btnRemove: TButton
+ Left = 688
+ Top = 232
+ Width = 57
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Remove'
+ TabOrder = 6
+ OnClick = btnRemoveClick
+ end
+ object Button1: TButton
+ Left = 624
+ Top = 304
+ Width = 121
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Copy as Spawnregion'
+ TabOrder = 7
+ OnClick = Button1Click
+ end
+ object Button2: TButton
+ Left = 624
+ Top = 336
+ Width = 121
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Copy as Region'
+ TabOrder = 8
+ OnClick = Button2Click
+ end
+ object Button3: TButton
+ Left = 624
+ Top = 368
+ Width = 121
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Paste Spawnregion'
+ TabOrder = 9
+ OnClick = Button3Click
+ end
+ object Button4: TButton
+ Left = 624
+ Top = 400
+ Width = 121
+ Height = 25
+ Anchors = [akTop, akRight]
+ Caption = 'Paste Region'
+ TabOrder = 10
+ OnClick = Button4Click
+ end
+ object btnZoomOut: TButton
+ Left = 624
+ Top = 432
+ Width = 41
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = '-'
+ TabOrder = 11
+ OnClick = btnZoomOutClick
+ end
+ object btnZoomIn: TButton
+ Left = 672
+ Top = 432
+ Width = 41
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = '+'
+ TabOrder = 12
+ OnClick = btnZoomInClick
+ end
+ object btnRedraw: TButton
+ Left = 624
+ Top = 464
+ Width = 89
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = 'Redraw'
+ TabOrder = 13
+ OnClick = btnRedrawClick
+ end
+end
Added: trunk/WPGM/Spawnregions.~pas
===================================================================
--- trunk/WPGM/Spawnregions.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Spawnregions.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,660 @@
+unit Spawnregions;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, GR32, GR32_Blend, GR32_Image, UOMap, UOStatics, ClipBrd;
+
+type
+ TfrmRegions = class(TForm)
+ cbMap: TComboBox;
+ pbMap: TPaintBox32;
+ sbX: TScrollBar;
+ sbY: TScrollBar;
+ Label1: TLabel;
+ Label2: TLabel;
+ lblScreen: TLabel;
+ lblMap: TLabel;
+ lbRects: TListBox;
+ btnAdd: TButton;
+ btnRemove: TButton;
+ Label3: TLabel;
+ lblSelected: TLabel;
+ Button1: TButton;
+ Button2: TButton;
+ Button3: TButton;
+ Button4: TButton;
+ btnZoomOut: TButton;
+ btnZoomIn: TButton;
+ btnRedraw: TButton;
+ procedure FormShow(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure pbMapPaintBuffer(Sender: TObject);
+ procedure sbXScroll(Sender: TObject; ScrollCode: TScrollCode;
+ var ScrollPos: Integer);
+ procedure sbYScroll(Sender: TObject; ScrollCode: TScrollCode;
+ var ScrollPos: Integer);
+ procedure FormDestroy(Sender: TObject);
+ procedure FormResize(Sender: TObject);
+ procedure pbMapMouseMove(Sender: TObject; Shift: TShiftState; X,
+ Y: Integer);
+ procedure btnRemoveClick(Sender: TObject);
+ procedure pbMapMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure pbMapMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+ procedure btnAddClick(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure Button3Click(Sender: TObject);
+ procedure Button4Click(Sender: TObject);
+ procedure lbRectsKeyDown(Sender: TObject; var Key: Word;
+ Shift: TShiftState);
+ procedure lbRectsDblClick(Sender: TObject);
+ procedure btnZoomOutClick(Sender: TObject);
+ procedure btnZoomInClick(Sender: TObject);
+ procedure btnRedrawClick(Sender: TObject);
+ private
+ { Private declarations }
+ Places: Array of TRect;
+
+ public
+ { Public declarations }
+ procedure ChangeMap(MapId: Byte);
+ procedure RedrawBuffer(Buffer: TBitmap32; StartX: Integer; StartY: Integer; Width: Integer; Height: Integer);
+
+ function MapToBuffer(Point: TPoint): TPoint;
+ function BufferToMap(Point: TPoint): TPoint;
+ procedure AddRect(X1: Integer; Y1: Integer; X2: Integer; Y2: Integer);
+ procedure UpdateSelectionLabel;
+ end;
+
+var
+ frmRegions: TfrmRegions;
+ Map: TMapReader;
+ Statics: TStaticReader;
+ Scale: Single;
+ Buffer: TBitmap32; // This is for copying map2map
+ SelStartX, SelStartY: Integer;
+ SelEndX, SelEndY: Integer;
+
+implementation
+
+{$R *.dfm}
+
+uses Main, Math, XMLReader, StrLib, UORadarCol;
+
+function TfrmRegions.MapToBuffer(Point: TPoint): TPoint;
+begin
+ Result.X := Ceil((Point.X - sbX.Position) / Scale);
+ Result.Y := Ceil((Point.Y - sbY.Position) / Scale);
+end;
+
+function TfrmRegions.BufferToMap(Point: TPoint): TPoint;
+begin
+ Result.X := Ceil(Point.X * Scale) + sbX.Position;
+ Result.Y := Ceil(Point.Y * Scale) + sbY.Position;
+end;
+
+procedure TfrmRegions.RedrawBuffer(Buffer: TBitmap32; StartX: Integer; StartY: Integer; Width: Integer; Height: Integer);
+var
+ X, Y, RealX, RealY: Integer;
+ MapBlock: TMapBlock;
+ i, j, k, l: Integer;
+ MapX, MapY: Integer; // Map Coordinates
+ MapPoint, ScreenPoint: TPoint;
+ MinBlockX, MinBlockY: Integer; // The lowest blocks we draw
+ MaxBlockX, MaxBlockY: Integer; // The highest blocks we draw
+ BlendColor: TColor32;
+ PixelCount: Integer;
+ StaticBlock: TStaticBlock;
+ DrawColor: TColor32;
+ DrawColorZ: Integer;
+begin
+ BlendColor := Color32(255, 255, 255, 127);
+
+ MapPoint := BufferToMap(Point(StartX, StartY));
+ MinBlockX := MapPoint.X div 8;
+ MinBlockY := MapPoint.Y div 8;
+
+ MapPoint := BufferToMap(Point(StartX + Width - 1, StartY + Height - 1));
+ MaxBlockX := MapPoint.X div 8;
+ MaxBlockY := MapPoint.Y div 8;
+
+ // Scale down/up ? (If Scale > 1, we draw less blocks), thus
+ // we have to divide and round up
+ {MaxBlockX := Ceil(MaxBlockX / Scale);
+ MaxBlockY := Ceil(MaxBlockY / Scale);}
+
+ for X := MinBlockX to MaxBlockX + 1 do
+ for Y := MinBlockY to MaxBlockY + 1 do begin
+ ScreenPoint := MapToBuffer(Point(X * 8, Y * 8));
+
+ // Out of screen check
+ if (ScreenPoint.X < -7) or (ScreenPoint.Y < -7) then
+ continue;
+
+ // Out of screen check
+ if (ScreenPoint.X >= Buffer.Width) or (ScreenPoint.Y >= Buffer.Height) then
+ continue;
+
+ Map.ReadBlock(X, Y, MapBlock);
+ Statics.ReadBlock(X, Y, StaticBlock);
+
+ for i := 0 to 63 do begin
+ PixelCount := Ceil(1.0 / Scale);
+
+ DrawColor := RadarCol.GetLandColor(MapBlock.Cells[i].Id);
+ DrawColorZ := MapBlock.Cells[i].Height;
+
+ // Get the topmost color here
+ for j := 0 to Length(StaticBlock) - 1 do begin
+ if (StaticBlock[j].X = i mod 8) and (StaticBlock[j].Y = i div 8) and
+ (StaticBlock[j].Z >= DrawColorZ) then begin
+ DrawColorZ := StaticBlock[j].Z;
+ DrawColor := RadarCol.GetItemColor(StaticBlock[j].Id);
+ end;
+ end;
+
+ RealX := ScreenPoint.X + (i mod 8) * PixelCount;
+ RealY := ScreenPoint.Y + (i div 8) * PixelCount;
+ if Scale <> 1.0 then begin
+ for j := 0 to PixelCount - 1 do begin
+ for k := 0 to PixelCount - 1 do begin
+ Buffer.PixelS[RealX + j, RealY + k] := DrawColor;
+ end;
+ end;
+ end else begin
+ Buffer.PixelS[RealX, RealY] := DrawColor;
+ end;
+
+ MapX := X * 8 + i mod 8;
+ MapY := Y * 8 + i div 8;
+
+ // Prüfen ob der Punkt teil eines Rectangles ist
+ for j := 0 to Length(Places) - 1 do begin
+ if (Places[j].Left <= MapX) and (Places[j].Right >= MapX)
+ and (Places[j].Top <= MapY) and (Places[j].Bottom >= MapY) then
+ begin
+ // Found a match!!
+ Buffer.PixelS[RealX, RealY] := BlendReg(BlendColor, Buffer.PixelS[RealX, RealY]);
+ EMMS();
+ //break;
+ end;
+ end;
+ end;
+ end;
+
+ // Redraw selection rectangle
+ if (SelStartX <> -1) and (SelStartY <> -1) then begin
+ MapPoint := MapToBuffer(Point(SelStartX, SelStartY));
+
+ pbMap.Buffer.Canvas.Brush.Style := bsClear;
+ pbMap.Buffer.Canvas.Pen.Color := clWhite;
+ pbMap.Buffer.Canvas.Pen.Style := psDot;
+
+ if (SelEndX <> -1) and (SelEndY <> -1) then begin
+ ScreenPoint := MapToBuffer(Point(SelEndX, SelEndY));
+ end else begin
+ ScreenPoint := pbMap.ScreenToClient(Mouse.CursorPos);
+ end;
+
+ pbMap.Buffer.Canvas.Rectangle(MapPoint.X, MapPoint.Y, ScreenPoint.X, ScreenPoint.Y);
+ end;
+end;
+
+procedure TfrmRegions.ChangeMap(MapId: Byte);
+begin
+ if MapId >= Length(Maps) then
+ exit;
+
+ Map := Main.Maps[MapId];
+ Statics := Main.Statics[MapId];
+
+ sbX.Max := Map.getWidth * 8 - 1 - pbMap.ClientWidth;
+ sbX.Min := 0;
+ sbX.Position := 0;
+
+ sbY.Max := Map.getHeight * 8 - 1 - pbMap.ClientHeight;
+ sbY.Min := 0;
+ sbY.Position := 0;
+
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.FormShow(Sender: TObject);
+begin
+ ChangeMap(0);
+end;
+
+procedure TfrmRegions.FormCreate(Sender: TObject);
+begin
+ Map := nil;
+ Statics := nil;
+ Scale := 1;
+ Buffer := TBitmap32.Create;
+
+ SelStartX := -1;
+ SelStartY := -1;
+ SelEndX := -1;
+ SelEndY := -1;
+
+ {AddRect(1776, 60, 3060, 670);
+ AddRect(1900, 670, 2515, 870);
+ AddRect(2515, 670, 2762, 870);
+ AddRect(3009, 100, 3055, 720);
+ AddRect(3055, 150, 3110, 655);
+ AddRect(3110, 320, 3210, 595);
+ AddRect(3210, 375, 3360, 550);
+ AddRect(3360, 410, 3424, 510);
+ AddRect(3424, 410, 3453, 465);}
+end;
+
+procedure TfrmRegions.pbMapPaintBuffer(Sender: TObject);
+begin
+ RedrawBuffer(pbMap.Buffer, 0, 0, pbMap.Buffer.Width, pbMap.Buffer.Height);
+end;
+
+procedure TfrmRegions.sbXScroll(Sender: TObject; ScrollCode: TScrollCode;
+ var ScrollPos: Integer);
+var
+ Diff: Integer;
+ OldPos: Integer;
+begin
+ Diff := ScrollPos - (Sender as TScrollBar).Position;
+
+ if (Buffer.Width <> pbMap.Buffer.Height) or (Buffer.Height <> pbMap.Buffer.Height) then
+ begin
+ Buffer.SetSizeFrom(pbMap.Buffer);
+ end;
+
+ if (Abs(Diff) > pbMap.Width) then
+ pbMap.Invalidate
+ else begin
+ pbMap.Buffer.DrawTo(Buffer);
+ Buffer.DrawTo(pbMap.Buffer, - Ceil(Diff / Scale), 0);
+
+ OldPos := sbX.Position;
+ sbX.Position := ScrollPos;
+
+ // If Diff is Positive, redraw right part
+ if Diff >= 0 then
+ RedrawBuffer(pbMap.Buffer, pbMap.Buffer.Width - Ceil(Diff / Scale), 0, Trunc(Diff / Scale), pbMap.Buffer.Height);
+
+ // If Diff is Negative, redraw left part
+ if Diff < 0 then
+ RedrawBuffer(pbMap.Buffer, 0, 0, - Trunc(Diff / Scale), pbMap.Buffer.Height);
+
+ sbX.Position := OldPos;
+
+ pbMap.Flush;
+ end;
+end;
+
+procedure TfrmRegions.sbYScroll(Sender: TObject; ScrollCode: TScrollCode;
+ var ScrollPos: Integer);
+var
+ Diff: Integer;
+ OldPos: Integer;
+begin
+ Diff := ScrollPos - (Sender as TScrollBar).Position;
+
+ if (Buffer.Width <> pbMap.Buffer.Height) or (Buffer.Height <> pbMap.Buffer.Height) then
+ begin
+ Buffer.SetSizeFrom(pbMap.Buffer);
+ end;
+
+ if (Abs(Diff) > pbMap.Height) then
+ pbMap.Invalidate
+ else begin
+ pbMap.Buffer.DrawTo(Buffer);
+ Buffer.DrawTo(pbMap.Buffer, 0, - Ceil(Diff / Scale));
+
+ OldPos := sbY.Position;
+ sbY.Position := ScrollPos;
+
+ // If Diff is Positive, redraw right part
+ if Diff >= 0 then
+ RedrawBuffer(pbMap.Buffer, 0, pbMap.Height - Ceil(Diff / Scale), pbMap.Buffer.Width, Ceil(Diff / Scale));
+
+ // If Diff is Negative, redraw right part
+ if Diff < 0 then
+ RedrawBuffer(pbMap.Buffer, 0, 0, pbMap.Buffer.Width, - Ceil(Diff / Scale));
+
+ sbY.Position := OldPos;
+ pbMap.Flush;
+ end;
+end;
+
+procedure TfrmRegions.FormDestroy(Sender: TObject);
+begin
+ Buffer.Free;
+end;
+
+procedure TfrmRegions.FormResize(Sender: TObject);
+var
+ OldX, OldY: Integer;
+begin
+ OldX := sbX.Position;
+ OldY := sbY.Position;
+
+ ChangeMap(MapId);
+ sbX.Position := OldX;
+ sbY.Position := OldY;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.pbMapMouseMove(Sender: TObject; Shift: TShiftState;
+ X, Y: Integer);
+var
+ P: TPoint;
+begin
+ P := BufferToMap(Point(X, Y));
+
+ lblScreen.Caption := Format('%d,%d', [X, Y]);
+ lblMap.Caption := Format('%d,%d', [P.X, P.Y]);
+
+ if ((SelStartX <> -1) or (SelStartY <> -1)) and
+ ((SelEndX = -1) and (SelEndY = -1)) then begin
+ pbMap.Invalidate;
+ end;
+end;
+
+procedure TfrmRegions.btnRemoveClick(Sender: TObject);
+var
+ i: Integer;
+begin
+ if lbRects.ItemIndex <> -1 then begin
+ if lbRects.ItemIndex < Length(Places) - 1 then begin
+ // Copy Downwards
+ for i := lbRects.ItemIndex to Length(Places) - 2 do begin
+ Places[i] := Places[i+1];
+ end;
+ SetLength(Places, Length(Places) - 1);
+ pbMap.Invalidate;
+ end;
+ lbRects.Items.Delete(lbRects.ItemIndex);
+ end;
+end;
+
+procedure TFrmRegions.AddRect(X1: Integer; Y1: Integer; X2: Integer; Y2: Integer);
+var
+ Temp: Integer;
+begin
+ if X1 > X2 then begin
+ Temp := X1;
+ X1 := X2;
+ X2 := temp;
+ end;
+
+ if Y1 > Y2 then begin
+ Temp := Y1;
+ Y1 := Y2;
+ Y2 := temp;
+ end;
+
+ SetLength(Places, Length(Places) + 1);
+ Places[Length(Places) - 1] := Rect(X1, Y1, X2, Y2);
+
+ lbRects.Items.Add(Format('%d,%d to %d,%d', [X1, Y1, X2, Y2]));
+end;
+
+procedure TfrmRegions.pbMapMouseDown(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+var
+ P: TPoint;
+begin
+ SelStartX := -1;
+ SelStartY := -1;
+ SelEndX := -1;
+ SelEndY := -1;
+
+ P := BufferToMap(Point(X, Y));
+ SelStartX := P.X;
+ SelStartY := P.Y;
+
+ UpdateSelectionLabel;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.pbMapMouseUp(Sender: TObject; Button: TMouseButton;
+ Shift: TShiftState; X, Y: Integer);
+var
+ P: TPoint;
+begin
+ P := BufferToMap(Point(X, Y));
+ SelEndX := P.X;
+ SelEndY := P.Y;
+ UpdateSelectionLabel;
+ pbMap.Invalidate;
+end;
+
+procedure TFrmRegions.UpdateSelectionLabel;
+begin
+ if (SelStartX = -1) or (SelStartY = -1) or (SelEndX = -1) or (SelEndY = -1) then
+ begin
+ lblSelected.Caption := '';
+ btnAdd.Enabled := False;
+ end else begin
+ lblSelected.Caption := Format('%d,%d to %d,%d', [SelStartX, SelStartY, SelEndX, SelEndY]);
+ btnAdd.Enabled := True;
+ end;
+end;
+
+procedure TfrmRegions.btnAddClick(Sender: TObject);
+begin
+ AddRect(SelStartX, SelStartY, SelEndX, SelEndY);
+ SelStartX := -1;
+ SelStartY := -1;
+ SelEndX := -1;
+ SelEndY := -1;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.Button1Click(Sender: TObject);
+var
+ i: Integer;
+ Result: String;
+ ClipBoard: TClipboard;
+begin
+ ClipBoard := TClipBoard.Create;
+
+ for i := 0 to Length(Places) - 1 do begin
+ Result := Result + Format(#9 + #9 + '<rectangle from="%d,%d" to="%d,%d" map="%u" />' + #13, [Places[i].Left, Places[i].Top, Places[i].Right, Places[i].Bottom, cbMap.ItemIndex]);
+ end;
+
+ ClipBoard.SetTextBuf(PChar(result));
+end;
+
+procedure TfrmRegions.Button2Click(Sender: TObject);
+var
+ i: Integer;
+ Result: String;
+ ClipBoard: TClipboard;
+begin
+ ClipBoard := TClipBoard.Create;
+
+ for i := 0 to Length(Places) - 1 do begin
+ Result := Result + Format(#9 + #9 + '<rectangle x1="%d" y1="%d" x2="%d y2="%d" map="%u" />' + #13, [Places[i].Left, Places[i].Top, Places[i].Right, Places[i].Bottom, cbMap.ItemIndex]);
+ end;
+
+ ClipBoard.SetTextBuf(PChar(result));
+ ClipBoard.Free;
+end;
+
+procedure TfrmRegions.Button3Click(Sender: TObject);
+var
+ ClipBoard: TClipboard;
+ Content: String;
+ Reader: TXMLReader;
+ Document, Node: TXMLNode;
+ i: Integer;
+ sFrom, sTo: String;
+ Parts: TStringList;
+ x1, x2, y1, y2: Integer;
+begin
+ ClipBoard := TClipBoard.Create;
+ Content := '<rectangles>' + ClipBoard.AsText + '</rectangles>';
+
+ Reader := nil;
+ Document := nil;
+ Parts := TStringList.Create;
+
+ try
+ Reader := TXMLStringReader.Create(Content);
+ Document := Reader.ParseDocument.Nodes[0];
+
+ // Iterate over the rectangle nodes
+ for i := 0 to Document.NodeCount - 1 do begin
+ Node := Document.Nodes[i];
+
+ if Node.Name <> 'rectangle' then
+ continue; // Skip this node
+
+ // Look up From + To
+ Node.LookupBasicData('from', sFrom);
+ Node.LookupBasicData('to', sTo);
+
+ Parts.Clear;
+ Split(sFrom, ',', Parts);
+ if Parts.Count <> 2 then
+ continue; // From attribute is incorrect
+
+ x1 := StrToIntDef(Parts[0], 0);
+ y1 := StrToIntDef(Parts[1], 0);
+
+ Parts.Clear;
+ Split(sTo, ',', Parts);
+ if Parts.Count <> 2 then
+ continue; // To attribute is incorrect
+
+ x2 := StrToIntDef(Parts[0], 0);
+ y2 := StrToIntDef(Parts[1], 0);
+
+ AddRect(x1, y1, x2, y2);
+ end;
+ except
+ on e: Exception do begin
+ Application.MessageBox(PAnsiChar('The following error occured while parsing the XML definition: ' + #13 + e.Message), 'Error', MB_OK+MB_ICONERROR);
+ end;
+ end;
+
+ Reader.Free;
+ Document.Free;
+ Parts.Free;
+ ClipBoard.Free;
+end;
+
+procedure TfrmRegions.Button4Click(Sender: TObject);
+var
+ ClipBoard: TClipboard;
+ Content: String;
+ Reader: TXMLReader;
+ Document, Node: TXMLNode;
+ i: Integer;
+ Temp: String;
+ x1, x2, y1, y2: Integer;
+begin
+ ClipBoard := TClipBoard.Create;
+ Content := '<rectangles>' + ClipBoard.AsText + '</rectangles>';
+
+ Reader := nil;
+ Document := nil;
+
+ try
+ Reader := TXMLStringReader.Create(Content);
+ Document := Reader.ParseDocument.Nodes[0];
+
+ // Iterate over the rectangle nodes
+ for i := 0 to Document.NodeCount - 1 do begin
+ Node := Document.Nodes[i];
+
+ if Node.Name <> 'rectangle' then
+ continue; // Skip this node
+
+ Node.LookupBasicData('x1', temp);
+ x1 := StrToIntDef(temp, 0);
+
+ Node.LookupBasicData('x2', temp);
+ x2 := StrToIntDef(temp, 0);
+
+ Node.LookupBasicData('y1', temp);
+ y1 := StrToIntDef(temp, 0);
+
+ Node.LookupBasicData('y2', temp);
+ y2 := StrToIntDef(temp, 0);
+
+ AddRect(x1, y1, x2, y2);
+ end;
+ except
+ on e: Exception do begin
+ Application.MessageBox(PAnsiChar('The following error occured while parsing the XML definition: ' + #13 + e.Message), 'Error', MB_OK+MB_ICONERROR);
+ end;
+ end;
+
+ Reader.Free;
+ Document.Free;
+ ClipBoard.Free;
+end;
+
+procedure TfrmRegions.lbRectsKeyDown(Sender: TObject; var Key: Word;
+ Shift: TShiftState);
+begin
+ if Key = 46 then
+ btnRemoveClick(Sender);
+end;
+
+procedure TfrmRegions.lbRectsDblClick(Sender: TObject);
+var
+ centerx, centery: Integer;
+begin
+ if lbRects.ItemIndex = -1 then
+ exit;
+
+ // center the map view on the dbl clicked region
+ CenterX := (Places[lbRects.ItemIndex].Right - Places[lbRects.ItemIndex].Left) div 2;
+ CenterX := CenterX + Places[lbRects.ItemIndex].Left;
+
+ CenterY := (Places[lbRects.ItemIndex].Bottom - Places[lbRects.ItemIndex].Top) div 2;
+ CenterY := CenterY + Places[lbRects.ItemIndex].Top;
+
+ // Now take the viewport into account
+ CenterX := CenterX - Trunc((pbMap.ClientWidth div 2) * Scale);
+ CenterY := CenterY - Trunc((pbMap.ClientHeight div 2) * Scale);
+
+ if CenterX > sbX.Max then
+ CenterX := sbX.Max;
+
+ if CenterY > sbY.Max then
+ CenterY := sbY.Max;
+
+ if CenterX < 0 then
+ CenterX := 0;
+
+ if CenterY < 0 then
+ CenterY := 0;
+
+ sbX.Position := CenterX;
+ sbY.Position := CenterY;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.btnZoomOutClick(Sender: TObject);
+begin
+ Scale := Scale / 0.5;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.btnZoomInClick(Sender: TObject);
+begin
+ Scale := Scale * 0.5;
+ pbMap.Invalidate;
+end;
+
+procedure TfrmRegions.btnRedrawClick(Sender: TObject);
+begin
+ pbMap.Invalidate;
+end;
+
+end.
Added: trunk/WPGM/Strlib.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/Strlib.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/Strlib.pas
===================================================================
--- trunk/WPGM/Strlib.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/Strlib.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,645 @@
+{:
+PURPOSE AND IMPLEMENTATION:
+ This unit defines some useful string handling routines.
+
+HISTORY:
+ ??/??/96 - Created by Colin Patrick Sarsfield (colin.sarsfield at usa.net)
+ 11/08/96 - Left and Right functions added by CPS
+ 05/21/97 - IntlStrToFloat added by CPS
+
+COPYRIGHT:
+ Released into the public domain.
+}
+unit Strlib;
+
+interface
+
+uses
+ Classes;
+
+type
+ CharSet = set of Char;
+
+function Split(Source, Deli: string; StringList: TStringList): TStringList;
+function BoolToStr(const b: Boolean): string;
+function CompareStrNumMix(const str1, str2: String): Integer;
+function DequoteString(s: String): String;
+procedure DivideStrInt(const Str: string; var BegStr: string; var Int: Integer);
+function DropTrailingZeros(const S: String): String;
+procedure FileSplit(const Path: String; var Dir, Name, Ext: String);
+function FormatAsIdentifier(const AString: String): String;
+function FracToStr(const n, d: Integer): string;
+function IntlStrToFloat(const AString: string): Single;
+function IntToAlpha(const i: Longint): string;
+function Left(const AString: string; i: Integer): string;
+function LookupOrdStr(const s: String; const a: array of String): Integer;
+function LTrim(const AString: string): string;
+procedure MergeValues(A, B: TStringList);
+function NextStrColumn(S: String; var Pos: Integer): String;
+function PosAfter(SubStr, S: String; StartingAt: Integer): Integer;
+function QtyList(A: TStringList): String;
+function RepeatStr(const Str: String; const qty: Integer): String;
+function Replace(const PTarget, BeforeStr, AfterStr: string): string;
+function Right(const AString: string; i: Integer): string;
+function RScan(const AString: string; chr: Char): Integer;
+function RTrim(const AString: string): string;
+function Scan(const AString: string; chr: Char): Integer;
+{$IFNDEF WIN32}
+procedure SetLength(var S: string; NewLength: Integer);
+{$ENDIF}
+procedure StreamToString(AStream: TStream; var AString: string);
+function StringOfChar(const AChar: Char; Length: Integer): string;
+procedure StringToStream(const AString: string; AStream: TStream);
+function Trim(const AString: string): string;
+function TrimChars(const AString: String; TrimChars: CharSet): string;
+
+implementation
+
+uses
+ SysUtils;
+
+{:Return a string representation for the boolean value b. (e.g. True = 'True') }
+function BoolToStr(const b: Boolean): string;
+begin
+ if b then
+ Result := 'True'
+ else
+ Result := 'False';
+end;
+
+{:compare two strings. Unlike a normal string comparison, digits 0..9 are seen
+as a number with any other adjoining numbers and these numbers are compared as
+whole numbers. An example of a list properly sorted using this comparision
+function:
+
+AH-1
+AH-2b
+AH-12-15c
+AH-31
+
+This function is case-insensitive.}
+function CompareStrNumMix(const str1, str2: String): Integer;
+var
+ w1, w2: String;
+ p1, p2: Integer;
+ isdigit1, isdigit2: Boolean;
+const
+ Digits = ['0'..'9'];
+
+ procedure GetDigits(const source: String; var work: String; var pos: Integer);
+ begin
+ while (pos <= Length(source)) and (source[pos] in Digits) do begin
+ work := work + source[pos];
+ Inc(pos)
+ end;
+ end;
+
+ procedure GetString(const source: String; var work: String; var pos: Integer);
+ begin
+ while (pos <= Length(source)) and not (source[pos] in Digits) do begin
+ work := work + source[pos];
+ Inc(pos)
+ end;
+ end;
+begin
+ { if str1 < str2 then negative
+ if str1 > str2 then positive
+ if str1 = str2 then zero }
+ p1 := 1;
+ p2 := 1;
+ repeat
+ { terminate with longer string being greater if end of either string is
+ reached }
+ if p1 > Length(str1) then begin Result := -1; Exit end;
+ if p2 > Length(str2) then begin Result := 1; Exit end;
+ w1 := '';
+ w2 := '';
+
+ isdigit1 := str1[p1] in Digits;
+ isdigit2 := str2[p2] in Digits;
+ { if different types of strings then exit }
+ if isdigit1 <> isdigit2 then begin Result := Ord(isdigit1) - Ord(isdigit2); Exit end;
+ if isdigit1 then begin
+ { number portion }
+ GetDigits(str1, w1, p1);
+ GetDigits(str2, w2, p2);
+ try
+ Result := StrToInt(w1) - StrToInt(w2);
+ except
+ // if StrToInt fails, just compare the text normally
+ Result := CompareText(w1, w2);
+ end;
+ end
+ else begin
+ // string portion
+ GetString(str1, w1, p1);
+ GetString(str2, w2, p2);
+ Result := CompareText(w1, w2);
+ end;
+ until Result <> 0;
+end;
+
+{:Revert a quoted-style string to normal. Leave other styles of strings
+untouched. For example,
+
+"1"" pipe thread"
+
+becomes
+
+1" pipe thread
+}
+function DequoteString(s: String): String;
+var
+ Len: Integer;
+begin
+ Len := Length(s);
+ if ((Copy(s, 1, 1) = '"') and (Copy(s, Len, 1) = '"')) then begin
+ s := Copy(s, 2, Len - 2);
+ s := Replace(s, '""', '"');
+ end;
+ Result := s;
+end;
+
+{:Assuming Str begins with non-numeric characters and ends with numeric
+characters (i.e., 0..9), return the non-numeric portion in BegStr and convert
+the numeric portion to an integer returning it in Int.}
+procedure DivideStrInt(const Str: string; var BegStr: string; var Int: Integer);
+var
+ TStr: string;
+ i: Integer;
+begin
+ for i := Length(Str) downto 1 do
+ if (Str[i] < '0') or (Str[i] > '9') then
+ Break;
+ BegStr := Copy(Str, 1, i);
+ if i = Length(Str) then
+ Int := 0
+ else begin
+ TStr := Copy(Str, i + 1, Length(Str) - i);
+ try { capture range check errors, etc. }
+ Int := StrToInt(TStr);
+ except
+ Int := 0;
+ end;
+ end;
+end;
+
+{:Eliminates .00 from end of whole numbers. (i.e., 10.00 = 10, 10.50 = 10.5,
+10.05 = 10.05) Looks through string for decimal. If found, goes to the end
+and looks back one character for a decimal or zero. Continues that action
+eliminating zeros and decimals until whole number is found to left of decimal.}
+function DropTrailingZeros(const S: String): String;
+var
+ I: Integer;
+ L: Integer;
+begin
+ Result := S;
+ I := POS('.',Result);
+ if I <> 0 then begin
+ L := Length(Result);
+ while Result[L] = '0' do
+ dec(L);
+ if Result[L] = '.' then
+ dec(L);
+ SetLength(Result,L)
+ end;
+end;
+
+{:Split a file path "Path" into three parts: its directory "Dir", its name
+"Name", and its extension "Ext".}
+procedure FileSplit(const Path: String; var Dir, Name, Ext: String);
+var
+ NamePos, ExtPos: Integer;
+begin
+ NamePos := RScan(Path, '\');
+ if NamePos = 0 then NamePos := RScan(Path, ':');
+ if NamePos = 0 then NamePos := 1 else Inc(NamePos);
+ ExtPos := RScan(Path, '.');
+ if ExtPos < NamePos then ExtPos := Length(Name);
+ Dir := Copy(Path, 1, NamePos - 1);
+ Name := Copy(Path, NamePos, ExtPos - NamePos);
+ Ext := Copy(Path, ExtPos, Length(Path) - ExtPos + 1);
+end;
+
+{:Take a string and format it as an identifier (e.g.,
+"Cond. fluid" = "CondFluid"
+"24 times" = "Times"
+"Cond. fluid_Water" = "CondFluid_Water"
+}
+function FormatAsIdentifier(const AString: String): String;
+var
+ i, Len: Integer;
+ Cap: Boolean;
+begin
+ Len := Length(AString);
+ Result := '';
+ i := 1;
+ // skip over junk at beginning
+ while (i <= Len) and not (AString[i] in ['a'..'z', 'A'..'Z', '_']) do
+ Inc(i);
+ Cap := True;
+ while i <= Len do begin
+ if AString[i] = '_' then begin
+ Result := Result + '_';
+ Cap := True
+ end
+ else if AString[i] in ['a'..'z', 'A'..'Z', '0'..'9'] then begin
+ if Cap then begin
+ Result := Result + UpperCase(AString[i]);
+ Cap := False;
+ end
+ else
+ Result := Result + AString[i];
+ end
+ else
+ Cap := True;
+ Inc(i)
+ end;
+end;
+
+{:Convert a fraction to its string representation where "n" is the numerator
+and "d" is the denomiator. Simplify the fraction if possible. Fractions will
+be displayed as an integer (optionally) followed by a fraction less than one
+(optionally). Note that this function only works for positive integers or zero. }
+function FracToStr(const n, d: Integer): string;
+var
+ i, w, nn, dd: Integer;
+begin
+ // fail if n or d are negative
+ if (n < 0) or (d < 0) then
+ raise Exception.Create('FracToStr does not support negative integers');
+ // calculate the whole number portion of the fraction
+ w := n div d;
+ // calculate the remaining numerator after the whole number is subtracted out
+ nn := n mod d;
+ // store a copy of the denominator for simplification
+ dd := d;
+ // check all possible divisors to simply
+ for i := d - 1 downto 2 do
+ // if the nominator and the denominator are both divisable by the same
+ // number than divide by that number to simplify.
+ if ((dd mod i) = 0) and ((nn mod i) = 0) then begin
+ dd := dd div i;
+ nn := nn div i;
+ end;
+ // if the whole number > 0 then represent it in the result
+ if w > 0 then
+ Result := Format('%d ', [w])
+ else // otherwise blank out the result
+ Result := '';
+ // if the numerator is also zero than display zero
+ if nn = 0 then begin
+ if w = 0 then Result := '0';
+ end
+ else // otherwise add the string representation of the fraction to the result
+ Result := Result + Format('%d/%d', [nn, dd]);
+end;
+
+{:This function will convert a String to a Single whether the decimal seperator
+used is the localized (international) decimal seperator or the period (i.e., '.'). }
+function IntlStrToFloat(const AString: string): Single;
+var
+ RCode: Integer;
+begin
+ try
+ // StrToFloat recognizes the international decimal seperator (e.g., '.' in
+ // USA, ',' in parts of Latin America)
+ Result := StrToFloat(AString);
+ except
+ // Val always recognizes '.' as the decimal seperator
+ Val(AString, Result, RCode);
+ if RCode <> 0 then
+ raise EConvertError.Create('Unable to convert string to number: ''' + AString + '');
+ end;
+end;
+
+{:Convert an integer to a base 26 number based on the alphabet much like
+column headings in most spreadsheet programs (e.g., A, B, C .., Z, AA, AB, etc.).}
+function IntToAlpha(const i: Longint): string;
+begin
+ if i <= 26 then
+ Result := Chr(Ord('A') + i - 1)
+ else
+ Result := IntToAlpha(i div 26) + Chr(Ord('A') + (i mod 26));
+end;
+
+{:This function returns a string "i" characters long starting at the left
+(beginning) of "AString". Note that if "AString" is less that "i" characters
+long this function will return the whole string. }
+function Left(const AString: string; i: Integer): string;
+begin
+ Result := Copy(AString, 1, i);
+end;
+
+{:This function returns an integer indicating the position of s in a. Note that
+this is often used to look up an ordinal based on its string representation;
+hence its name.}
+function LookupOrdStr(const s: String; const a: array of String): Integer;
+var
+ i: Integer;
+begin
+ for i := Low(a) to High(a) do
+ if a[i] = s then begin
+ Result := i;
+ Exit;
+ end;
+ raise Exception.CreateFmt('Unable to lookup ordinal string value: "%s"', [s]);
+end;
+
+{:This function returns the remainder of "AString" after any leading spaces are
+removed.}
+function LTrim(const AString: string): string;
+var
+ i, b, l: Integer;
+begin
+ b := 1;
+ l := Length(AString);
+ for i := 1 to l do
+ if AString[i] = ' ' then
+ b := i + 1
+ else
+ Break;
+ if b > l then
+ Result := ''
+ else
+ Result := Copy(AString, b, l - b + 1)
+end;
+
+{:This procedure takes two TStringList's populated with lines like "coil=true"
+(reference the "Values" property in the help) and merges them. The result is
+placed in A. Note that for any strings that both A & B have B have the part to
+the left of the equals sign in common the merged list will use the line from B.}
+procedure MergeValues(A, B: TStringList);
+var
+ i, p: Integer;
+begin
+ for i := 0 to Pred(B.Count) do begin
+ p := Pos('=', B[i]);
+ if (p <> 0) then
+ A.Values[Copy(B[i], 1, p - 1)] := Copy(B[i], p + 1, Length(B[i]) - p);
+ end;
+end;
+
+{:This function extracts the next "column" out of "S" which should a line from
+either a space or tab delimited text file. Note that Pos should be 1 on the
+first call to this function for a given string and the Pos returned by this
+function should be used in subsequent calls.}
+function NextStrColumn(S: String; var Pos: Integer): String;
+var
+ Start, Len: Integer;
+
+ function IsSpace(C: Char): Boolean;
+ begin
+ Result := C in [' ', #9];
+ end;
+begin
+ Len := Length(S);
+ while IsSpace(S[Pos]) and (Pos <= Len) do Inc(Pos);
+ if Pos > Len then begin Result := ''; Exit end;
+ Start := Pos;
+ while not IsSpace(S[Pos]) and (Pos <= Len) do Inc(Pos);
+ Result := Copy(S, Start, Pos - Start);
+end;
+
+{:This function is just like the "Pos" function that is provided with Delphi
+except it accepts an additional argument, "StartingAt". This argument tells
+this function where to start its search whereas the "Pos" function always starts
+at position 1.}
+function PosAfter(SubStr, S: String; StartingAt: Integer): Integer;
+begin
+ if StartingAt < 1 then StartingAt := 1;
+ Delete(S, 1, StartingAt - 1);
+ Result := Pos(SubStr, S);
+ if Result <> 0 then
+ Result := Result + StartingAt - 1;
+end;
+
+{:this function takes a TStringList and formats it as a "quantity list" of the
+string list's values. For example:
+The StringList 'A','B','A','B','B','C'
+becomes '(2)A/(3)B/(1)C'
+If the string list contains only one item it is considered a special case and
+that item is returned without any change in formatting.
+Note: the string list is sorted by list function}
+function QtyList(A: TStringList): String;
+var
+ i, qty: Integer;
+ str: String;
+begin
+ if A.Count = 1 then begin
+ Result := A[0];
+ Exit;
+ end;
+ A.Sort;
+ i := 0;
+ Result := '';
+ while i < A.Count do begin
+ str := A[i];
+ qty := 1;
+ while (i < Pred(A.Count)) and (A[i + 1] = str) do begin
+ Inc(qty);
+ Inc(i);
+ end;
+ if Result <> '' then Result := Result + '/';
+ Result := Result + Format('(%d)%s', [qty, str]);
+ Inc(i)
+ end;
+end;
+
+{:This function creates a string that is the concatenation of "qty" instances of
+the string "Str".}
+function RepeatStr(const Str: String; const qty: Integer): String;
+var
+ i: Integer;
+begin
+ if qty > 0 then begin
+ Result := Str;
+ for i := 2 to qty do
+ Result := Result + Str;
+ end
+ else
+ Result := '';
+end;
+
+{:This function returns a modified version of "PTarget" where all instances of
+"BeforeStr" have been replaced by "AfterStr".}
+function Replace(const PTarget, BeforeStr, AfterStr: string): string;
+var
+ i, j: Integer;
+begin
+ Result := PTarget;
+ { start at beginning of string }
+ i := 1;
+ while True do begin
+ j := i;
+ i := Pos(BeforeStr, Copy(Result, i, Length(Result) - i + 1));
+ if i = 0 then
+ Break;
+ Inc(i, j - 1);
+ Delete(Result, i, Length(BeforeStr));
+ Insert(AfterStr, Result, i);
+ { adjust i to correct position }
+ i := i + Length(AfterStr);
+ end;
+ Result := Result;
+end;
+
+{:This function returns a string "i" characters long starting at the right
+(end) of "AString". Note that if "AString" is less that "i" characters
+long this function will return the whole string. }
+function Right(const AString: string; i: Integer): string;
+begin
+ if i > Length(AString) then
+ Result := AString
+ else
+ Result := Copy(AString, Length(AString) - i + 1, i);
+end;
+
+{:This function returns the index of the last instance of "chr" in "AString".
+It returns 0 if none was found.}
+function RScan(const AString: string; chr: Char): Integer;
+var
+ i: Integer;
+begin
+ Result := 0;
+ for i := Length(AString) downto 1 do
+ if AString[i] = chr then begin
+ Result := i;
+ Exit;
+ end;
+end;
+
+{:This function returns the remainder of "AString" after any trailing spaces are
+removed.}
+function RTrim(const AString: string): string;
+var
+ i, e: Integer;
+begin
+ e := Length(AString);
+ for i := Length(AString) downto 1 do
+ if AString[i] = ' ' then
+ e := i - 1
+ else
+ Break;
+ if 1 > e then
+ Result := ''
+ else
+ Result := Copy(AString, 1, e)
+end;
+
+{:This function returns the index of the first instance of "chr" in "AString".
+It returns 0 if none was found.}
+function Scan(const AString: string; chr: Char): Integer;
+var
+ i: Integer;
+begin
+ Result := 0;
+ for i := 1 to Length(AString) do
+ if AString[i] = chr then begin
+ Result := i;
+ Exit;
+ end;
+end;
+
+{$IFNDEF WIN32}
+
+{:This function is to enable portability between 16-bit and 32-bit programs.
+Since 32-bit Delphi defines a SetLength function, this defines one for 16-bit
+programs.}
+procedure SetLength(var S: string; NewLength: Integer);
+begin
+ S[0] := Char(NewLength);
+end;
+{$ENDIF}
+
+{:This procedure duplicates the contents of "AStream" and places it in "AString".}
+procedure StreamToString(AStream: TStream; var AString: string);
+var
+ L: Integer;
+begin
+ AStream.Read(L, Sizeof(Integer));
+ SetLength(AString, L);
+ AStream.Read(AString[1], L);
+end;
+
+{:This function returns a string "Length" characters long where each character
+is "AChar".}
+function StringOfChar(const AChar: Char; Length: Integer): string;
+begin
+ SetLength(Result, Length);
+ FillChar(Result[1], Length, AChar);
+end;
+
+{:This procedure writes the contents of "AString" to "AStream".}
+procedure StringToStream(const AString: string; AStream: TStream);
+var
+ L: Integer;
+begin
+ L := Length(AString);
+ AStream.Write(L, Sizeof(Integer));
+ AStream.Write(AString[1], L);
+end;
+
+{:This function returns the remainder of "AString" after any leading or trailing
+spaces are removed.}
+function Trim(const AString: string): string;
+var
+ i, b, e: Integer;
+begin
+ b := 1;
+ e := Length(AString);
+ for i := 1 to e do
+ if AString[i] = ' ' then
+ b := i + 1
+ else
+ Break;
+ for i := Length(AString) downto b do
+ if AString[i] = ' ' then
+ e := i - 1
+ else
+ Break;
+ if b > e then
+ Result := ''
+ else
+ Result := Copy(AString, b, e - b + 1)
+end;
+
+function TrimChars(const AString: string; TrimChars: CharSet): string;
+var
+ i, b, e: Integer;
+begin
+ b := 1;
+ e := Length(AString);
+ for i := 1 to e do
+ if AString[i] in TrimChars then
+ b := i + 1
+ else
+ Break;
+ for i := Length(AString) downto b do
+ if AString[i] in TrimChars then
+ e := i - 1
+ else
+ Break;
+ if b > e then
+ Result := ''
+ else
+ Result := Copy(AString, b, e - b + 1)
+end;
+
+function Split(Source, Deli: string; StringList: TStringList): TStringList;
+var
+ EndOfCurrentString: byte;
+begin
+ repeat
+ EndOfCurrentString := Pos(Deli, Source);
+ if EndOfCurrentString = 0 then
+ StringList.add(Source)
+ else
+ StringList.add(Copy(Source, 1, EndOfCurrentString - 1));
+ Source := Copy(Source, EndOfCurrentString + length(Deli), length(Source) - EndOfCurrentString);
+ until EndOfCurrentString = 0;
+ result := StringList;
+end;
+
+end.
+
Added: trunk/WPGM/UOCache.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UOCache.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UOCache.pas
===================================================================
--- trunk/WPGM/UOCache.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOCache.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,88 @@
+unit UOCache;
+
+interface
+
+uses Classes;
+
+(*
+ TCache
+ A utility class for caching objects.
+*)
+type TCache = class( TObject )
+ private
+ Data: TList;
+ Size: Cardinal;
+
+ public
+ constructor Create( Size: Cardinal );
+ destructor Destroy; override;
+
+ procedure Add( Key: Cardinal; Data: Pointer );
+ function Lookup( Key: Cardinal ): Pointer;
+end;
+
+implementation
+
+uses IniFiles;
+
+type TPrivateCacheObject = record
+ Key: Cardinal;
+ Data: Pointer;
+end;
+
+type PPrivateCacheObject = ^TPrivateCacheObject;
+
+constructor TCache.Create( Size: Cardinal );
+begin
+ Data := TList.Create;
+ Self.Size := Size;
+end;
+
+destructor TCache.Destroy;
+var
+ i: Integer;
+begin
+ for i := 0 to Data.Count - 1 do
+ begin
+ Dispose( PPrivateCacheObject( Data[i] ).Data );
+ Dispose( Data[i] );
+ end;
+ Data.Free;
+end;
+
+procedure TCache.Add( Key: Cardinal; Data: Pointer );
+var
+ CacheObject: PPrivateCacheObject;
+begin
+ new( CacheObject );
+ CacheObject.Key := Key;
+ CacheObject.Data := Data;
+
+ if ( Self.Data.Count >= Integer( Self.Size ) ) and ( Self.Size > 0 ) then
+ begin
+ Dispose( PPrivateCacheObject( Self.Data[0] ).Data );
+ Dispose( Self.Data[0] );
+ Self.Data.Delete( 0 );
+ end;
+
+ Self.Data.Add( CacheObject );
+end;
+
+function TCache.Lookup( Key: Cardinal ): Pointer;
+var
+ I: Integer;
+begin
+ Result := nil;
+
+ for I := 0 to ( Data.Count - 1 ) do
+ begin
+ if PPrivateCacheObject( Data[i] ).Key = Key then
+ begin
+ Result := PPrivateCacheObject( Data[i] ).Data;
+ Exit;
+ end;
+ end;
+end;
+
+end.
+
\ No newline at end of file
Added: trunk/WPGM/UOCache.~pas
===================================================================
--- trunk/WPGM/UOCache.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOCache.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,88 @@
+unit UOCache;
+
+interface
+
+uses Classes;
+
+(*
+ TCache
+ A utility class for caching objects.
+*)
+type TCache = class( TObject )
+ private
+ Data: TList;
+ Size: Cardinal;
+
+ public
+ constructor Create( Size: Cardinal );
+ destructor Destroy; override;
+
+ procedure Add( Key: Cardinal; Data: Pointer );
+ function Lookup( Key: Cardinal ): Pointer;
+end;
+
+implementation
+
+uses IniFiles;
+
+type TPrivateCacheObject = record
+ Key: Cardinal;
+ Data: Pointer;
+end;
+
+type PPrivateCacheObject = ^TPrivateCacheObject;
+
+constructor TCache.Create( Size: Cardinal );
+begin
+ Data := TList.Create;
+ Self.Size := Size;
+end;
+
+destructor TCache.Destroy;
+var
+ i: Integer;
+begin
+ for i := 0 to Data.Count - 1 do
+ begin
+ Dispose( PPrivateCacheObject( Data[i] ).Data );
+ Dispose( Data[i] );
+ end;
+ Data.Free;
+end;
+
+procedure TCache.Add( Key: Cardinal; Data: Pointer );
+var
+ CacheObject: PPrivateCacheObject;
+begin
+ new( CacheObject );
+ CacheObject.Key := Key;
+ CacheObject.Data := Data;
+
+ if ( Self.Data.Count >= Integer( Self.Size ) ) and ( Self.Size > 0 ) then
+ begin
+ Dispose( PPrivateCacheObject( Self.Data[0] ).Data );
+ Dispose( Self.Data[0] );
+ Self.Data.Delete( 0 );
+ end;
+
+ Self.Data.Add( CacheObject );
+end;
+
+function TCache.Lookup( Key: Cardinal ): Pointer;
+var
+ I: Integer;
+begin
+ Result := nil;
+
+ for I := 0 to ( Data.Count - 1 ) do
+ begin
+ if PPrivateCacheObject( Data[i] ).Key = Key then
+ begin
+ Result := PPrivateCacheObject( Data[i] ).Data;
+ Exit;
+ end;
+ end;
+end;
+
+end.
+
\ No newline at end of file
Added: trunk/WPGM/UOHues.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UOHues.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UOHues.pas
===================================================================
--- trunk/WPGM/UOHues.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOHues.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,135 @@
+unit UOHues;
+
+interface
+
+uses Classes, Graphics;
+
+type THue = packed record
+ Colors: Array[0..31] of Word;
+ TableStart: Word;
+ TableEnd: Word;
+ Name: Array[0..19] of Char;
+end;
+
+type THueBlock = packed record
+ Header: Cardinal;
+ Hues: Array[0..7] of THue;
+end;
+
+type TProcessedHue = Array[0..31] of TColor;
+type PHue = ^THue;
+
+type THuesReader = class(TObject)
+ private
+ Colors: Array[0..$BB7] of TProcessedHue;
+ Hues: Array[0..374] of THueBlock;
+ TrueBlack: THue;
+ public
+ constructor Create; overload;
+ function Load( FileName: String ): Boolean;
+ function getHue(Id: Word): PHue;
+ function translateColor(Hue: Word; Color: TColor;
+ Partial: Boolean = False): TColor;
+ function getColor(Hue: Word; Color: Byte): TColor;
+end;
+
+implementation
+
+uses Windows, SysUtils, UOUtilities;
+
+constructor THuesReader.Create;
+begin
+ ZeroMemory( @Colors, $BB8 * sizeof( TProcessedHue ) );
+ ZeroMemory(@Hues, $BB8 * sizeof( THue ) );
+ ZeroMemory(@TrueBlack, sizeof(THue));
+ TrueBlack.Name := 'True Black';
+end;
+
+function THuesReader.Load( FileName: String ): Boolean;
+var
+ Input: TFileStream;
+ i, j, k: Integer;
+begin
+ Result := False;
+
+ try
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+
+ // Read Blocks
+ for i := 0 to 374 do
+ begin
+ Input.Read(Hues[i], sizeof(THueBlock));
+ for j := 0 to 7 do
+ begin
+ for k := 0 to 31 do
+ Colors[i * 8 + j][k] := Color15to24(Hues[i].Hues[j].Colors[k]);
+ end;
+ end;
+
+ Input.Free;
+ Result := True;
+ except
+ end;
+end;
+
+function THuesReader.getHue(Id: Word): PHue;
+var
+ Block: Word;
+begin
+ Result := nil;
+
+ if Id = 0 then
+ exit;
+
+ If Id = 1 then
+ begin
+ Result := @TrueBlack;
+ exit;
+ end;
+
+ Dec(Id, 1);
+
+ Block := Id div 8;
+ if Block <= 374 then
+ Result := @(Hues[Block].Hues[Id mod 8]);
+end;
+
+function THuesReader.translateColor(Hue: Word; Color: TColor;
+ Partial: Boolean = False): TColor;
+var
+ Offset: Byte;
+begin
+ if Hue = 1 then
+ begin
+ Result := clBlack;
+ exit;
+ end;
+
+ if Hue = 0 then
+ begin
+ Result := Color;
+ exit;
+ end;
+
+ Dec(Hue); // Hue 1 is Blue
+
+ Hue := Hue mod $BB8;
+ Offset := GetRValue(Color) div 8;
+ Result := Colors[Hue][Offset];
+end;
+
+function THuesReader.getColor(Hue: Word; Color: Byte): TColor;
+begin
+ if Hue = 1 then
+ begin
+ Result := clBlack;
+ exit;
+ end;
+
+ Dec(Hue); // Hue 1 is blue
+ Hue := Hue mod $BB8;
+
+ Result := Colors[Hue][Color mod 32];
+end;
+
+end.
Added: trunk/WPGM/UOHues.~pas
===================================================================
--- trunk/WPGM/UOHues.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOHues.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,135 @@
+unit UOHues;
+
+interface
+
+uses Classes, Graphics;
+
+type THue = packed record
+ Colors: Array[0..31] of Word;
+ TableStart: Word;
+ TableEnd: Word;
+ Name: Array[0..19] of Char;
+end;
+
+type THueBlock = packed record
+ Header: Cardinal;
+ Hues: Array[0..7] of THue;
+end;
+
+type TProcessedHue = Array[0..31] of TColor;
+type PHue = ^THue;
+
+type THuesReader = class(TObject)
+ private
+ Colors: Array[0..$BB7] of TProcessedHue;
+ Hues: Array[0..374] of THueBlock;
+ TrueBlack: THue;
+ public
+ constructor Create; overload;
+ function Load( FileName: String ): Boolean;
+ function getHue(Id: Word): PHue;
+ function translateColor(Hue: Word; Color: TColor;
+ Partial: Boolean = False): TColor;
+ function getColor(Hue: Word; Color: Byte): TColor;
+end;
+
+implementation
+
+uses Windows, SysUtils, UOUtilities;
+
+constructor THuesReader.Create;
+begin
+ ZeroMemory( @Colors, $BB8 * sizeof( TProcessedHue ) );
+ ZeroMemory(@Hues, $BB8 * sizeof( THue ) );
+ ZeroMemory(@TrueBlack, sizeof(THue));
+ TrueBlack.Name := 'True Black';
+end;
+
+function THuesReader.Load( FileName: String ): Boolean;
+var
+ Input: TFileStream;
+ i, j, k: Integer;
+begin
+ Result := False;
+
+ try
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+
+ // Read Blocks
+ for i := 0 to 374 do
+ begin
+ Input.Read(Hues[i], sizeof(THueBlock));
+ for j := 0 to 7 do
+ begin
+ for k := 0 to 31 do
+ Colors[i * 8 + j][k] := Color15to24(Hues[i].Hues[j].Colors[k]);
+ end;
+ end;
+
+ Input.Free;
+ Result := True;
+ except
+ end;
+end;
+
+function THuesReader.getHue(Id: Word): PHue;
+var
+ Block: Word;
+begin
+ Result := nil;
+
+ if Id = 0 then
+ exit;
+
+ If Id = 1 then
+ begin
+ Result := @TrueBlack;
+ exit;
+ end;
+
+ Dec(Id, 1);
+
+ Block := Id div 8;
+ if Block <= 374 then
+ Result := @(Hues[Block].Hues[Id mod 8]);
+end;
+
+function THuesReader.translateColor(Hue: Word; Color: TColor;
+ Partial: Boolean = False): TColor;
+var
+ Offset: Byte;
+begin
+ if Hue = 1 then
+ begin
+ Result := clBlack;
+ exit;
+ end;
+
+ if Hue = 0 then
+ begin
+ Result := Color;
+ exit;
+ end;
+
+ Dec(Hue); // Hue 1 is Blue
+
+ Hue := Hue mod $BB8;
+ Offset := GetRValue(Color) div 8;
+ Result := Colors[Hue][Offset];
+end;
+
+function THuesReader.getColor(Hue: Word; Color: Byte): TColor;
+begin
+ if Hue = 1 then
+ begin
+ Result := clBlack;
+ exit;
+ end;
+
+ Dec(Hue); // Hue 1 is blue
+ Hue := Hue mod $BB8;
+
+ Result := Colors[Hue][Color mod 32];
+end;
+
+end.
Added: trunk/WPGM/UOLib/UOAnim.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UOLib/UOAnim.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UOLib/UOAnim.pas
===================================================================
--- trunk/WPGM/UOLib/UOAnim.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOLib/UOAnim.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,535 @@
+unit UOAnim;
+
+interface
+
+uses Classes, SysUtils, GR32, UOHues;
+
+// Animation Frame
+type TAnimFrame = record
+ Image: TBitmap32;
+ CenterX, CenterY: Integer;
+end;
+
+type PAnimFrame = ^TAnimFrame;
+
+type TAnimation = class
+private
+ Frames: TList;
+public
+ Body: Word;
+ Action: Word;
+ FrameDelay: Word;
+ Hue: Word;
+
+ function getTotalHeight: Integer;
+ function getTotalWidth: Integer;
+
+ constructor Create;
+ destructor Destroy; override;
+
+ function frameCount: Integer;
+ function getFrame(i: Integer): PAnimFrame;
+ procedure addFrame(frame: PAnimFrame);
+end;
+
+type TBodyConv = record
+ Body: Integer;
+ Anim2: Integer;
+ Anim3: Integer;
+end;
+
+type TBodyDef = record
+ Body: Integer;
+ NewBody: Integer;
+ NewHue: Integer;
+end;
+
+type TAnimReader = class
+private
+ dStream, iStream: TStream;
+ dStream2, iStream2: TStream;
+ dStream3, iStream3: TStream;
+ disabled: Boolean;
+ BodyConv: Array of TBodyConv;
+ BodyDef: Array of TBodyDef;
+
+ function GetData( Body: Word; Action: Word; var Length: Cardinal ): TStream;
+ procedure LoadBodyConv(Filename: String);
+ procedure LoadBodyDef(FileName: String);
+public
+ hues: THuesReader;
+
+ constructor Create;
+ destructor Free;
+ function GetFrames( Body, Action, Color: Word): TAnimation; overload;
+ function GetFrames( Body, Action: Word ): TAnimation; overload;
+ procedure getBodyConv(Body: Word; var Anim2: Integer; var Anim3: Integer);
+ function getBodyDef(var Body: Word; var Color: Word): Boolean;
+
+ function Open( IndexName1, DataName1, IndexName2, DataName2, IndexName3, DataName3, BodyConv, BodyDef: String ): Boolean;
+ procedure Close();
+end;
+
+implementation
+
+uses Forms, Windows, UOUtilities, Graphics, Math, StrUtils;
+
+constructor TAnimation.Create;
+begin
+ Frames := TList.Create;
+end;
+
+function TAnimation.getTotalHeight: Integer;
+var
+ i: Integer;
+ frame: PAnimFrame;
+begin
+ Result := 0;
+
+ for i := 0 to frameCount - 1 do
+ begin
+ frame := frames[i];
+ Result := Max(Result, frame.Image.Height - frame.CenterY);
+ end;
+end;
+
+function TAnimation.getTotalWidth: Integer;
+var
+ i: Integer;
+ frame: PAnimFrame;
+begin
+ Result := 0;
+
+ for i := 0 to frameCount - 1 do
+ begin
+ frame := frames[i];
+ Result := Max(Result, frame.Image.Width - frame.CenterX);
+ end;
+end;
+
+destructor TAnimation.Destroy;
+var
+ i: Integer;
+begin
+ for i := 0 to frames.Count - 1 do begin
+ PAnimFrame(Frames[i]).Image.Free;
+ dispose(Frames[i]);
+ end;
+ Frames.Free;
+ inherited Destroy;
+end;
+
+function TAnimation.frameCount: Integer;
+begin
+ Result := Frames.Count;
+end;
+
+function TAnimation.getFrame(i: Integer): PAnimFrame;
+begin
+ if I >= frames.count then
+ result := nil
+ else
+ result := frames[i];
+end;
+
+procedure TAnimation.addFrame(frame: PAnimFrame);
+begin
+ frames.Add(frame);
+end;
+
+type TIndexRecord = packed record
+ Offset: Integer;
+ Length: Integer;
+ Extra: Integer
+end;
+
+// Get a TMemoryStream of the desired data
+function TAnimReader.GetData( Body: Word; Action: Word; var Length: Cardinal ): TStream;
+var
+ IndexRecord: TIndexRecord;
+ Offset: Cardinal;
+ Anim2, Anim3: Integer;
+begin
+ // CHECK FOR VERDATA HERE
+
+ getBodyConv(Body, Anim2, Anim3);
+
+ // Read From Anim3.mul
+ if (Anim3 <> -1) and (iStream3 <> nil) and (dStream3 <> nil) then begin
+ if Anim3 < 300 then
+ Offset := Anim3 * 65 + Action
+ else if Anim3 < 400 then
+ Offset := 33000 + (Anim3 - 300) * 110 + Action
+ else
+ Offset := 35000 + (Anim3 - 400) * 175 + Action;
+
+ iStream3.Seek( Offset * 12, soFromBeginning );
+ iStream3.Read( IndexRecord, SizeOf( TIndexRecord ) );
+
+ if IndexRecord.Offset <> -1 then begin
+ Length := IndexRecord.Length;
+ dStream3.Seek( IndexRecord.Offset, soFromBeginning );
+ Result := dStream3;
+ exit;
+ end;
+ end;
+
+ // Read From Anim2.mul
+ if (Anim2 <> -1) and (iStream2 <> nil) and (dStream2 <> nil) then begin
+ if Anim2 < 200 then
+ Offset := Anim2 * 110 + Action
+ else
+ Offset := 22000 + (Anim2 - 200) * 65 + Action;
+
+ iStream2.Seek( Offset * 12, soFromBeginning );
+ iStream2.Read( IndexRecord, SizeOf( TIndexRecord ) );
+
+ if IndexRecord.Offset <> -1 then begin
+ Length := IndexRecord.Length;
+ dStream2.Seek( IndexRecord.Offset, soFromBeginning );
+ Result := dStream2;
+ exit;
+ end;
+ end;
+
+ if Body <= $C7 then begin
+ Action := Action mod 110;
+ Offset := Body * 110 + Action;
+ end else if Body <= $18F then begin
+ Action := Action mod 65;
+ Offset := (Body - $C8) * 65 + Action + 22000;
+ end else begin
+ Action := Action mod 175;
+ Offset := (Body - $190) * 175 + Action + 35000;
+ end;
+
+ iStream.Seek( Offset * 12, soFromBeginning );
+ iStream.Read( IndexRecord, SizeOf( TIndexRecord ) );
+
+ if IndexRecord.Offset = -1 then begin
+ Result := nil;
+ Length := 0;
+ exit;
+ end;
+
+ Length := IndexRecord.Length;
+
+ dStream.Seek( IndexRecord.Offset, soFromBeginning );
+ Result := dStream;
+end;
+
+function TAnimReader.Open( IndexName1, DataName1, IndexName2, DataName2, IndexName3, DataName3, BodyConv, BodyDef: String ): Boolean;
+begin
+ Result := False;
+ try
+ dStream := TFileStream.Create( DataName1, fmOpenRead+fmShareDenyNone );
+ iStream := TFileStream.Create( IndexName1, fmOpenRead+fmShareDenyNone );
+ Disabled := False;
+ except
+ Close;
+ end;
+
+ dStream2 := nil;
+ dStream3 := nil;
+ iStream2 := nil;
+ iStream3 := nil;
+
+ try
+ dStream2 := TFileStream.Create( DataName2, fmOpenRead+fmShareDenyNone );
+ iStream2 := TFileStream.Create( IndexName2, fmOpenRead+fmShareDenyNone );
+ except
+ FreeAndNil(iStream2);
+ FreeAndNil(dStream2);
+ end;
+
+ try
+ dStream3 := TFileStream.Create( DataName3, fmOpenRead+fmShareDenyNone );
+ iStream3 := TFileStream.Create( IndexName3, fmOpenRead+fmShareDenyNone );
+ except
+ FreeAndNil(iStream3);
+ FreeAndNil(dStream3);
+ end;
+
+ // Load Bodyconv.def
+ LoadBodyConv(BodyConv);
+
+ // Load Body.def
+ LoadBodyDef(BodyDef);
+end;
+
+procedure TAnimReader.Close();
+begin
+ FreeAndNil( dStream );
+ FreeAndNil( iStream );
+ disabled := True;
+end;
+
+constructor TAnimReader.Create;
+begin
+ disabled := True;
+ dStream := nil;
+ iStream := nil;
+ hues := nil;
+end;
+
+destructor TAnimReader.Free;
+begin
+end;
+
+function TAnimReader.GetFrames( Body, Action, Color: Word): TAnimation;
+var
+ Data: TStream;
+ Length: Cardinal;
+ Palette: Array[0..255] of TColor32;
+ i, j: Integer;
+ Color15: Word;
+ FrameCount: Integer;
+ FrameOffsets: Array of Integer;
+ ImageCenterX, ImageCenterY: Smallint;
+ Width, Height: Word;
+ YOffset, XOffset, XRun: Integer;
+ Chunk: Integer;
+ SeekStart: Integer;
+ PaletteIndex: Byte;
+ Frame: PAnimFrame;
+ Hue: PHue;
+begin
+ Data := GetData(Body, Action, Length);
+
+ if Data = nil then begin
+ getBodyDef(Body, Color);
+
+ Data := GetData(Body, Action, Length);
+
+ if Data = nil then begin
+ //Application.MessageBox(PAnsiChar('Unknown Body Id: ' + IntToStr(Body)), 'Error: Invalid Body Id', MB_OK+MB_ICONERROR);
+ result := nil;
+ exit;
+ end;
+ end;
+
+ result := TAnimation.Create;
+ result.body := body;
+ result.action := action;
+ result.FrameDelay := 80;
+
+ if (Hues <> nil) and (Color <> 0) then
+ Hue := Hues.getHue(Color)
+ else
+ Hue := nil;
+
+ // Read the palette
+ for i := 0 to 255 do begin
+ Data.Read(Color15, 2);
+
+ if hue <> nil then
+ Color15 := hue.Colors[((Color15 shr 10) and $1F)];
+
+ if Color15 = 0 then
+ Palette[i] := 0
+ else
+ Palette[i] := Color15to32(Color15);
+ end;
+
+ SeekStart := Data.Position;
+
+ Data.Read(FrameCount, 4);
+ SetLength(FrameOffsets, FrameCount);
+
+ for i := 0 to FrameCount - 1 do begin
+ Data.Read(FrameOffsets[i], 4);
+ end;
+
+ // Seek to the requested frame
+ for j := 0 to FrameCount - 1 do begin
+ Data.Seek(SeekStart + FrameOffsets[j], soFromBeginning);
+
+ // Read Frame Header
+ Data.Read(ImageCenterX, 2);
+ Data.Read(ImageCenterY, 2);
+ Data.Read(Width, 2);
+ Data.Read(Height, 2);
+
+ new(Frame);
+ Frame.Image := TBitmap32.Create;
+ Frame.Image.SetSize(Width, Height);
+ Frame.Image.DrawMode := dmBlend;
+ Frame.CenterX := ImageCenterX;
+ Frame.CenterY := ImageCenterY;
+
+ while true do begin
+ // Read a Chunk
+ Data.Read(Chunk, 4);
+
+ if (Chunk = $7FFF7FFF) then
+ break;
+
+ XRun := Chunk and $FFF; // Pixel Amount
+ YOffset := (Chunk shr 12) and $3FF;
+ XOffset := (Chunk shr 22) and $3FF;
+
+ if XOffset and $200 <> 0 then
+ XOffset := Integer(Cardinal(XOffset) or $FFFFFC00);
+
+ if YOffset and $200 <> 0 then
+ YOffset := Integer(Cardinal(YOffset) or $FFFFFC00);
+
+ Inc(YOffset, Height);
+
+ for i := 0 to XRun - 1 do begin
+ Data.Read(PaletteIndex, 1);
+
+ if Palette[PaletteIndex] <> 0 then
+ Frame.Image.Pixel[ImageCenterX + XOffset + i, ImageCenterY + YOffset] := Palette[PaletteIndex];
+ end;
+ end;
+
+ Result.addFrame(frame);
+ end;
+end;
+
+function TAnimReader.GetFrames( Body, Action: Word ): TAnimation;
+begin
+ Result := GetFrames(Body, Action, 0);
+end;
+
+procedure TAnimReader.LoadBodyConv(Filename: String);
+var
+ Input: TextFile;
+ Line: String;
+ Pos, Body, Anim2, Anim3: Integer;
+begin
+ try
+ AssignFile(Input, FileName);
+ Reset(Input);
+
+ // Read Line By Line
+ while not Eof(Input) do begin
+ ReadLn(Input, Line);
+
+ // Comment Lines
+ if LeftStr(Line, 1) = '#' then
+ continue;
+
+ // Get First Token
+ Pos := AnsiPos(Char($9), Line);
+ Body := StrToIntDef(LeftStr(Line, Pos - 1), -1);
+
+ if Body = -1 then
+ continue;
+
+ // Get Second Token
+ Line := RightStr(Line, Length(Line) - pos);
+ Pos := AnsiPos(Char($9), Line);
+ Anim2 := StrToIntDef(LeftStr(Line, Pos - 1), -1);
+
+ // Get Third Token
+ Line := RightStr(Line, Length(Line) - pos);
+ Pos := AnsiPos(Char($9), Line);
+ Anim3 := StrToIntDef(LeftStr(Line, Pos - 1), -1);
+
+ // Save Token
+ Pos := Length(BodyConv);
+ SetLength(BodyConv, Pos + 1);
+ BodyConv[Pos].Body := Body;
+ BodyConv[Pos].Anim2 := Anim2;
+ BodyConv[Pos].Anim3 := Anim3;
+ end;
+
+ CloseFile(Input);
+ except
+ end;
+end;
+
+procedure TAnimReader.LoadBodyDef(Filename: String);
+var
+ Input: TextFile;
+ Line: String;
+ Pos, Body, NewBody, NewHue: Integer;
+ NewBodies: String;
+begin
+ try
+ AssignFile(Input, FileName);
+ Reset(Input);
+
+ // Read Line By Line
+ while not Eof(Input) do begin
+ ReadLn(Input, Line);
+
+ // Comment Lines
+ if LeftStr(Line, 1) = '#' then
+ continue;
+
+ // Get First Token
+ Pos := AnsiPos(' ', Line);
+ Body := StrToIntDef(LeftStr(Line, Pos - 1), -1);
+
+ if Body = -1 then
+ continue;
+
+ // Get Last Token
+ Line := RightStr(Line, Length(Line) - pos);
+ Pos := LastDelimiter(' ', Line);
+ NewBodies := LeftStr(Line, Pos - 1);
+
+ // Get Third Token
+ Line := RightStr(Line, Length(Line) - pos);
+ NewHue := StrToIntDef(Line, 0);
+
+ If AnsiPos(',', NewBodies) = 0 then begin
+ NewBody := StrToIntDef(MidStr(NewBodies, 2, Length(NewBodies) - 2), Body);
+ end else begin
+ // Get the first number and use it
+ NewBodies := RightStr(NewBodies, Length(NewBodies) - 1);
+ Pos := AnsiPos(',', NewBodies);
+ NewBodies := LeftStr(NewBodies, Pos - 1);
+ NewBody := StrToIntDef(NewBodies, Body);
+ end;
+
+ Pos := Length(BodyDef);
+ SetLength(BodyDef, Pos + 1);
+ BodyDef[Pos].Body := Body;
+ BodyDef[Pos].NewBody := NewBody;
+ BodyDef[Pos].NewHue := NewHue;
+ end;
+
+ CloseFile(Input);
+ except
+ end;
+end;
+
+
+
+procedure TAnimReader.getBodyConv(Body: Word; var Anim2: Integer; var Anim3: Integer);
+var
+ i: Integer;
+begin
+ for i := 0 to Length(BodyConv) - 1 do begin
+ if BodyConv[i].Body = Body then begin
+ Anim2 := BodyConv[i].Anim2;
+ Anim3 := BodyConv[i].Anim3;
+ exit;
+ end;
+ end;
+
+ Anim2 := -1;
+ Anim3 := -1;
+end;
+
+function TAnimReader.getBodyDef(var Body: Word; var Color: Word): Boolean;
+var
+ i: Integer;
+begin
+ for i := 0 to Length(BodyDef) - 1 do begin
+ if BodyDef[i].Body = Body then begin
+ Body := BodyDef[i].NewBody;
+ Color := BodyDef[i].NewHue;
+ Result := true;
+ exit;
+ end;
+ end;
+
+ Result := false;
+end;
+
+end.
Added: trunk/WPGM/UOLib/UOAnim.~pas
===================================================================
--- trunk/WPGM/UOLib/UOAnim.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOLib/UOAnim.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,534 @@
+unit UOAnim;
+
+interface
+
+uses Classes, SysUtils, GR32, UOHues;
+
+// Animation Frame
+type TAnimFrame = record
+ Image: TBitmap32;
+ CenterX, CenterY: Integer;
+end;
+
+type PAnimFrame = ^TAnimFrame;
+
+type TAnimation = class
+private
+ Frames: TList;
+public
+ Body: Word;
+ Action: Word;
+ FrameDelay: Word;
+ Hue: Word;
+
+ function getTotalHeight: Integer;
+ function getTotalWidth: Integer;
+
+ constructor Create;
+ destructor Destroy; override;
+
+ function frameCount: Integer;
+ function getFrame(i: Integer): PAnimFrame;
+ procedure addFrame(frame: PAnimFrame);
+end;
+
+type TBodyConv = record
+ Body: Integer;
+ Anim2: Integer;
+ Anim3: Integer;
+end;
+
+type TBodyDef = record
+ Body: Integer;
+ NewBody: Integer;
+ NewHue: Integer;
+end;
+
+type TAnimReader = class
+private
+ dStream, iStream: TStream;
+ dStream2, iStream2: TStream;
+ dStream3, iStream3: TStream;
+ disabled: Boolean;
+ BodyConv: Array of TBodyConv;
+ BodyDef: Array of TBodyDef;
+
+ function GetData( Body: Word; Action: Word; var Length: Cardinal ): TStream;
+ procedure LoadBodyConv(Filename: String);
+ procedure LoadBodyDef(FileName: String);
+public
+ hues: THuesReader;
+
+ constructor Create;
+ destructor Free;
+ function GetFrames( Body, Action, Color: Word): TAnimation; overload;
+ function GetFrames( Body, Action: Word ): TAnimation; overload;
+ procedure getBodyConv(Body: Word; var Anim2: Integer; var Anim3: Integer);
+ function getBodyDef(var Body: Word; var Color: Word): Boolean;
+
+ function Open( IndexName1, DataName1, IndexName2, DataName2, IndexName3, DataName3, BodyConv, BodyDef: String ): Boolean;
+ procedure Close();
+end;
+
+implementation
+
+uses Forms, Windows, UOUtilities, Graphics, Math, StrUtils;
+
+constructor TAnimation.Create;
+begin
+ Frames := TList.Create;
+end;
+
+function TAnimation.getTotalHeight: Integer;
+var
+ i: Integer;
+ frame: PAnimFrame;
+begin
+ Result := 0;
+
+ for i := 0 to frameCount - 1 do
+ begin
+ frame := frames[i];
+ Result := Max(Result, frame.Image.Height - frame.CenterY);
+ end;
+end;
+
+function TAnimation.getTotalWidth: Integer;
+var
+ i: Integer;
+ frame: PAnimFrame;
+begin
+ Result := 0;
+
+ for i := 0 to frameCount - 1 do
+ begin
+ frame := frames[i];
+ Result := Max(Result, frame.Image.Width - frame.CenterX);
+ end;
+end;
+
+destructor TAnimation.Destroy;
+var
+ i: Integer;
+begin
+ for i := 0 to frames.Count - 1 do begin
+ dispose(Frames[i]);
+ end;
+ Frames.Free;
+ inherited Destroy;
+end;
+
+function TAnimation.frameCount: Integer;
+begin
+ Result := Frames.Count;
+end;
+
+function TAnimation.getFrame(i: Integer): PAnimFrame;
+begin
+ if I >= frames.count then
+ result := nil
+ else
+ result := frames[i];
+end;
+
+procedure TAnimation.addFrame(frame: PAnimFrame);
+begin
+ frames.Add(frame);
+end;
+
+type TIndexRecord = packed record
+ Offset: Integer;
+ Length: Integer;
+ Extra: Integer
+end;
+
+// Get a TMemoryStream of the desired data
+function TAnimReader.GetData( Body: Word; Action: Word; var Length: Cardinal ): TStream;
+var
+ IndexRecord: TIndexRecord;
+ Offset: Cardinal;
+ Anim2, Anim3: Integer;
+begin
+ // CHECK FOR VERDATA HERE
+
+ getBodyConv(Body, Anim2, Anim3);
+
+ // Read From Anim3.mul
+ if (Anim3 <> -1) and (iStream3 <> nil) and (dStream3 <> nil) then begin
+ if Anim3 < 300 then
+ Offset := Anim3 * 65 + Action
+ else if Anim3 < 400 then
+ Offset := 33000 + (Anim3 - 300) * 110 + Action
+ else
+ Offset := 35000 + (Anim3 - 400) * 175 + Action;
+
+ iStream3.Seek( Offset * 12, soFromBeginning );
+ iStream3.Read( IndexRecord, SizeOf( TIndexRecord ) );
+
+ if IndexRecord.Offset <> -1 then begin
+ Length := IndexRecord.Length;
+ dStream3.Seek( IndexRecord.Offset, soFromBeginning );
+ Result := dStream3;
+ exit;
+ end;
+ end;
+
+ // Read From Anim2.mul
+ if (Anim2 <> -1) and (iStream2 <> nil) and (dStream2 <> nil) then begin
+ if Anim2 < 200 then
+ Offset := Anim2 * 110 + Action
+ else
+ Offset := 22000 + (Anim2 - 200) * 65 + Action;
+
+ iStream2.Seek( Offset * 12, soFromBeginning );
+ iStream2.Read( IndexRecord, SizeOf( TIndexRecord ) );
+
+ if IndexRecord.Offset <> -1 then begin
+ Length := IndexRecord.Length;
+ dStream2.Seek( IndexRecord.Offset, soFromBeginning );
+ Result := dStream2;
+ exit;
+ end;
+ end;
+
+ if Body <= $C7 then begin
+ Action := Action mod 110;
+ Offset := Body * 110 + Action;
+ end else if Body <= $18F then begin
+ Action := Action mod 65;
+ Offset := (Body - $C8) * 65 + Action + 22000;
+ end else begin
+ Action := Action mod 175;
+ Offset := (Body - $190) * 175 + Action + 35000;
+ end;
+
+ iStream.Seek( Offset * 12, soFromBeginning );
+ iStream.Read( IndexRecord, SizeOf( TIndexRecord ) );
+
+ if IndexRecord.Offset = -1 then begin
+ Result := nil;
+ Length := 0;
+ exit;
+ end;
+
+ Length := IndexRecord.Length;
+
+ dStream.Seek( IndexRecord.Offset, soFromBeginning );
+ Result := dStream;
+end;
+
+function TAnimReader.Open( IndexName1, DataName1, IndexName2, DataName2, IndexName3, DataName3, BodyConv, BodyDef: String ): Boolean;
+begin
+ Result := False;
+ try
+ dStream := TFileStream.Create( DataName1, fmOpenRead+fmShareDenyNone );
+ iStream := TFileStream.Create( IndexName1, fmOpenRead+fmShareDenyNone );
+ Disabled := False;
+ except
+ Close;
+ end;
+
+ dStream2 := nil;
+ dStream3 := nil;
+ iStream2 := nil;
+ iStream3 := nil;
+
+ try
+ dStream2 := TFileStream.Create( DataName2, fmOpenRead+fmShareDenyNone );
+ iStream2 := TFileStream.Create( IndexName2, fmOpenRead+fmShareDenyNone );
+ except
+ FreeAndNil(iStream2);
+ FreeAndNil(dStream2);
+ end;
+
+ try
+ dStream3 := TFileStream.Create( DataName3, fmOpenRead+fmShareDenyNone );
+ iStream3 := TFileStream.Create( IndexName3, fmOpenRead+fmShareDenyNone );
+ except
+ FreeAndNil(iStream3);
+ FreeAndNil(dStream3);
+ end;
+
+ // Load Bodyconv.def
+ LoadBodyConv(BodyConv);
+
+ // Load Body.def
+ LoadBodyDef(BodyDef);
+end;
+
+procedure TAnimReader.Close();
+begin
+ FreeAndNil( dStream );
+ FreeAndNil( iStream );
+ disabled := True;
+end;
+
+constructor TAnimReader.Create;
+begin
+ disabled := True;
+ dStream := nil;
+ iStream := nil;
+ hues := nil;
+end;
+
+destructor TAnimReader.Free;
+begin
+end;
+
+function TAnimReader.GetFrames( Body, Action, Color: Word): TAnimation;
+var
+ Data: TStream;
+ Length: Cardinal;
+ Palette: Array[0..255] of TColor32;
+ i, j: Integer;
+ Color15: Word;
+ FrameCount: Integer;
+ FrameOffsets: Array of Integer;
+ ImageCenterX, ImageCenterY: Smallint;
+ Width, Height: Word;
+ YOffset, XOffset, XRun: Integer;
+ Chunk: Integer;
+ SeekStart: Integer;
+ PaletteIndex: Byte;
+ Frame: PAnimFrame;
+ Hue: PHue;
+begin
+ Data := GetData(Body, Action, Length);
+
+ if Data = nil then begin
+ getBodyDef(Body, Color);
+
+ Data := GetData(Body, Action, Length);
+
+ if Data = nil then begin
+ //Application.MessageBox(PAnsiChar('Unknown Body Id: ' + IntToStr(Body)), 'Error: Invalid Body Id', MB_OK+MB_ICONERROR);
+ result := nil;
+ exit;
+ end;
+ end;
+
+ result := TAnimation.Create;
+ result.body := body;
+ result.action := action;
+ result.FrameDelay := 80;
+
+ if (Hues <> nil) and (Color <> 0) then
+ Hue := Hues.getHue(Color)
+ else
+ Hue := nil;
+
+ // Read the palette
+ for i := 0 to 255 do begin
+ Data.Read(Color15, 2);
+
+ if hue <> nil then
+ Color15 := hue.Colors[((Color15 shr 10) and $1F)];
+
+ if Color15 = 0 then
+ Palette[i] := 0
+ else
+ Palette[i] := Color15to32(Color15);
+ end;
+
+ SeekStart := Data.Position;
+
+ Data.Read(FrameCount, 4);
+ SetLength(FrameOffsets, FrameCount);
+
+ for i := 0 to FrameCount - 1 do begin
+ Data.Read(FrameOffsets[i], 4);
+ end;
+
+ // Seek to the requested frame
+ for j := 0 to FrameCount - 1 do begin
+ Data.Seek(SeekStart + FrameOffsets[j], soFromBeginning);
+
+ // Read Frame Header
+ Data.Read(ImageCenterX, 2);
+ Data.Read(ImageCenterY, 2);
+ Data.Read(Width, 2);
+ Data.Read(Height, 2);
+
+ new(Frame);
+ Frame.Image := TBitmap32.Create;
+ Frame.Image.SetSize(Width, Height);
+ Frame.Image.DrawMode := dmBlend;
+ Frame.CenterX := ImageCenterX;
+ Frame.CenterY := ImageCenterY;
+
+ while true do begin
+ // Read a Chunk
+ Data.Read(Chunk, 4);
+
+ if (Chunk = $7FFF7FFF) then
+ break;
+
+ XRun := Chunk and $FFF; // Pixel Amount
+ YOffset := (Chunk shr 12) and $3FF;
+ XOffset := (Chunk shr 22) and $3FF;
+
+ if XOffset and $200 <> 0 then
+ XOffset := Integer(Cardinal(XOffset) or $FFFFFC00);
+
+ if YOffset and $200 <> 0 then
+ YOffset := Integer(Cardinal(YOffset) or $FFFFFC00);
+
+ Inc(YOffset, Height);
+
+ for i := 0 to XRun - 1 do begin
+ Data.Read(PaletteIndex, 1);
+
+ if Palette[PaletteIndex] <> 0 then
+ Frame.Image.Pixel[ImageCenterX + XOffset + i, ImageCenterY + YOffset] := Palette[PaletteIndex];
+ end;
+ end;
+
+ Result.addFrame(frame);
+ end;
+end;
+
+function TAnimReader.GetFrames( Body, Action: Word ): TAnimation;
+begin
+ Result := GetFrames(Body, Action, 0);
+end;
+
+procedure TAnimReader.LoadBodyConv(Filename: String);
+var
+ Input: TextFile;
+ Line: String;
+ Pos, Body, Anim2, Anim3: Integer;
+begin
+ try
+ AssignFile(Input, FileName);
+ Reset(Input);
+
+ // Read Line By Line
+ while not Eof(Input) do begin
+ ReadLn(Input, Line);
+
+ // Comment Lines
+ if LeftStr(Line, 1) = '#' then
+ continue;
+
+ // Get First Token
+ Pos := AnsiPos(Char($9), Line);
+ Body := StrToIntDef(LeftStr(Line, Pos - 1), -1);
+
+ if Body = -1 then
+ continue;
+
+ // Get Second Token
+ Line := RightStr(Line, Length(Line) - pos);
+ Pos := AnsiPos(Char($9), Line);
+ Anim2 := StrToIntDef(LeftStr(Line, Pos - 1), -1);
+
+ // Get Third Token
+ Line := RightStr(Line, Length(Line) - pos);
+ Pos := AnsiPos(Char($9), Line);
+ Anim3 := StrToIntDef(LeftStr(Line, Pos - 1), -1);
+
+ // Save Token
+ Pos := Length(BodyConv);
+ SetLength(BodyConv, Pos + 1);
+ BodyConv[Pos].Body := Body;
+ BodyConv[Pos].Anim2 := Anim2;
+ BodyConv[Pos].Anim3 := Anim3;
+ end;
+
+ CloseFile(Input);
+ except
+ end;
+end;
+
+procedure TAnimReader.LoadBodyDef(Filename: String);
+var
+ Input: TextFile;
+ Line: String;
+ Pos, Body, NewBody, NewHue: Integer;
+ NewBodies: String;
+begin
+ try
+ AssignFile(Input, FileName);
+ Reset(Input);
+
+ // Read Line By Line
+ while not Eof(Input) do begin
+ ReadLn(Input, Line);
+
+ // Comment Lines
+ if LeftStr(Line, 1) = '#' then
+ continue;
+
+ // Get First Token
+ Pos := AnsiPos(' ', Line);
+ Body := StrToIntDef(LeftStr(Line, Pos - 1), -1);
+
+ if Body = -1 then
+ continue;
+
+ // Get Last Token
+ Line := RightStr(Line, Length(Line) - pos);
+ Pos := LastDelimiter(' ', Line);
+ NewBodies := LeftStr(Line, Pos - 1);
+
+ // Get Third Token
+ Line := RightStr(Line, Length(Line) - pos);
+ NewHue := StrToIntDef(Line, 0);
+
+ If AnsiPos(',', NewBodies) = 0 then begin
+ NewBody := StrToIntDef(MidStr(NewBodies, 2, Length(NewBodies) - 2), Body);
+ end else begin
+ // Get the first number and use it
+ NewBodies := RightStr(NewBodies, Length(NewBodies) - 1);
+ Pos := AnsiPos(',', NewBodies);
+ NewBodies := LeftStr(NewBodies, Pos - 1);
+ NewBody := StrToIntDef(NewBodies, Body);
+ end;
+
+ Pos := Length(BodyDef);
+ SetLength(BodyDef, Pos + 1);
+ BodyDef[Pos].Body := Body;
+ BodyDef[Pos].NewBody := NewBody;
+ BodyDef[Pos].NewHue := NewHue;
+ end;
+
+ CloseFile(Input);
+ except
+ end;
+end;
+
+
+
+procedure TAnimReader.getBodyConv(Body: Word; var Anim2: Integer; var Anim3: Integer);
+var
+ i: Integer;
+begin
+ for i := 0 to Length(BodyConv) - 1 do begin
+ if BodyConv[i].Body = Body then begin
+ Anim2 := BodyConv[i].Anim2;
+ Anim3 := BodyConv[i].Anim3;
+ exit;
+ end;
+ end;
+
+ Anim2 := -1;
+ Anim3 := -1;
+end;
+
+function TAnimReader.getBodyDef(var Body: Word; var Color: Word): Boolean;
+var
+ i: Integer;
+begin
+ for i := 0 to Length(BodyDef) - 1 do begin
+ if BodyDef[i].Body = Body then begin
+ Body := BodyDef[i].NewBody;
+ Color := BodyDef[i].NewHue;
+ Result := true;
+ exit;
+ end;
+ end;
+
+ Result := false;
+end;
+
+end.
Added: trunk/WPGM/UOLib/UOArt.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UOLib/UOArt.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UOLib/UOArt.pas
===================================================================
--- trunk/WPGM/UOLib/UOArt.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOLib/UOArt.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,188 @@
+unit UOArt;
+
+interface
+
+uses Classes, SysUtils, GR32, UOHues;
+
+type TArtReader = class
+private
+ dStream, iStream: TStream;
+ disabled: Boolean;
+ function GetData( ID: Word; var Length: Integer ): TStream;
+public
+ hues: THuesReader;
+
+ constructor Create;
+ destructor Free;
+ function GetTile( ID, Color: Word ): TBitmap32; overload;
+ function GetTile( Id: Word ): TBitmap32; overload;
+
+ function Open( IndexName: String; DataName: String ): Boolean;
+ procedure Close();
+end;
+
+var
+ Art: TArtReader;
+
+implementation
+
+uses Forms, Windows, UOUtilities, Graphics;
+
+type TIndexRecord = packed record
+ Offset: Integer;
+ Length: Integer;
+ Extra: Integer
+end;
+
+// Get a TMemoryStream of the desired data
+function TArtReader.GetData( ID: Word; var Length: Integer ): TStream;
+var
+ IndexRecord: TIndexRecord;
+ Offset: Cardinal;
+begin
+ Result := nil;
+
+ // CHECK FOR VERDATA HERE
+
+ Offset := 12 * ( $4000 + Id );
+
+ iStream.Seek( Offset, soFromBeginning );
+ iStream.Read( IndexRecord, SizeOf( TIndexRecord ) );
+ Length := IndexRecord.Length;
+
+ if Length = -1 then
+ exit;
+
+ dStream.Seek( IndexRecord.Offset, soFromBeginning );
+ Result := dStream;
+end;
+
+function TArtReader.Open( IndexName: String; DataName: String ): Boolean;
+begin
+ Result := False;
+ try
+ dStream := TFileStream.Create( DataName, fmOpenRead+fmShareDenyNone );
+ iStream := TFileStream.Create( IndexName, fmOpenRead+fmShareDenyNone );
+ Disabled := False;
+ except
+ Close;
+ end;
+end;
+
+procedure TArtReader.Close();
+begin
+ FreeAndNil( dStream );
+ FreeAndNil( iStream );
+ disabled := True;
+end;
+
+constructor TArtReader.Create;
+begin
+ disabled := True;
+ dStream := nil;
+ iStream := nil;
+ hues := nil;
+end;
+
+destructor TArtReader.Free;
+begin
+end;
+
+// Create an Art-tile
+function TArtReader.GetTile( ID, Color: Word ): TBitmap32;
+var
+ Data: TStream;
+ x, y, i: Cardinal;
+ Length: Integer;
+ Width, Height: Word;
+ LookupTable: Array of Word;
+ DataSTArtReader: Cardinal;
+ XOffset, RunLength, RunColor: Word;
+ hue: PHue;
+begin
+ if (Color <> 0) and (hues <> nil) then begin
+ hue := hues.getHue(color);
+ end else begin
+ hue := nil;
+ end;
+
+ Result := TBitmap32.Create;
+
+ if disabled then
+ begin
+ Result.SetSize( 44, 44 );
+ Result.Clear( Color32( clBtnFace ) );
+ Result.Line( 1, 1, 43, 43, clRed32 );
+ Result.Line( 43, 0, 0, 43, clRed32 );
+ exit;
+ end;
+
+ Data := GetData( Id, Length );
+
+ if( Length = -1 ) then
+ exit;
+
+ Data.Seek( 4, soFromCurrent );
+ Data.Read( Width, 2 );
+ Data.Read( Height, 2 );
+
+ SetLength( LookupTable, Height );
+ for i := 0 to Height-1 do
+ Data.Read( LookupTable[i], 2 );
+
+ DataSTArtReader := Data.Position;
+ Result.SetSize( Width, Height );
+ //Result.Clear( Color32( clBtnFace ) );
+ Result.Clear(Color32(clBtnFace));
+
+ // Draw the "tile" 3d wireframe
+ for x := 0 to 21 do begin
+ Result.PixelS[((Width - 1) div 2) - x, Height - 1 - x] := clRed32;
+ Result.PixelS[((Width - 1) div 2) + x, Height - 1 - x] := clRed32;
+ Result.PixelS[((Width - 1) div 2) - x, Height - 44 + x] := clRed32;
+ Result.PixelS[((Width - 1) div 2) + x, Height - 44 + x] := clRed32;
+ end;
+
+ // Parse each line of the image
+ for y := 0 to Height-1 do
+ begin
+ Data.Seek( DataSTArtReader + ( LookupTable[y] * 2 ), soFromBeginning );
+ X := 0;
+
+ // RLE Decoding (Read Chunks)
+ repeat begin
+ Data.Read( XOffset, 2 );
+ Data.Read( RunLength, 2 );
+
+ inc( x, XOffset );
+
+ if( RunLength > 0 ) then
+ for i := 0 to RunLength-1 do
+ begin
+ Data.Read( RunColor, 2 );
+
+ // INSERT HUE PROCESSING HERE
+ if hue <> nil then begin
+ RunColor := hue.Colors[((RunColor shr 10) and $1F)];
+ end;
+
+ // 0 RRRRR GG|GGG BBBBB Encoding
+ try
+ Result.Pixel[ x+i, y ] := Color15to24( RunColor );
+ except
+ Application.MessageBox( PChar( 'Invalid Data, X=' + IntToStr(x) + ', Y=' + IntToStr(y) ), 'Invalid Data', 0 );
+ end;
+ end;
+
+ inc( X, RunLength );
+
+ end until ( ( RunLength = 0 ) and ( XOffset = 0 ) );
+ end;
+end;
+
+function TArtReader.GetTile( Id: Word ): TBitmap32;
+begin
+ Result := GetTile( Id, 0 );
+end;
+
+end.
Added: trunk/WPGM/UOLib/UOArt.~pas
===================================================================
--- trunk/WPGM/UOLib/UOArt.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOLib/UOArt.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,188 @@
+unit UOArt;
+
+interface
+
+uses Classes, SysUtils, GR32, UOHues;
+
+type TArtReader = class
+private
+ dStream, iStream: TStream;
+ disabled: Boolean;
+ function GetData( ID: Word; var Length: Integer ): TStream;
+public
+ hues: THuesReader;
+
+ constructor Create;
+ destructor Free;
+ function GetTile( ID, Color: Word ): TBitmap32; overload;
+ function GetTile( Id: Word ): TBitmap32; overload;
+
+ function Open( IndexName: String; DataName: String ): Boolean;
+ procedure Close();
+end;
+
+var
+ Art: TArtReader;
+
+implementation
+
+uses Forms, Windows, UOUtilities, Graphics;
+
+type TIndexRecord = packed record
+ Offset: Integer;
+ Length: Integer;
+ Extra: Integer
+end;
+
+// Get a TMemoryStream of the desired data
+function TArtReader.GetData( ID: Word; var Length: Integer ): TStream;
+var
+ IndexRecord: TIndexRecord;
+ Offset: Cardinal;
+begin
+ Result := nil;
+
+ // CHECK FOR VERDATA HERE
+
+ Offset := 12 * ( $4000 + Id );
+
+ iStream.Seek( Offset, soFromBeginning );
+ iStream.Read( IndexRecord, SizeOf( TIndexRecord ) );
+ Length := IndexRecord.Length;
+
+ if Length = -1 then
+ exit;
+
+ dStream.Seek( IndexRecord.Offset, soFromBeginning );
+ Result := dStream;
+end;
+
+function TArtReader.Open( IndexName: String; DataName: String ): Boolean;
+begin
+ Result := False;
+ try
+ dStream := TFileStream.Create( DataName, fmOpenRead+fmShareDenyNone );
+ iStream := TFileStream.Create( IndexName, fmOpenRead+fmShareDenyNone );
+ Disabled := False;
+ except
+ Close;
+ end;
+end;
+
+procedure TArtReader.Close();
+begin
+ FreeAndNil( dStream );
+ FreeAndNil( iStream );
+ disabled := True;
+end;
+
+constructor TArtReader.Create;
+begin
+ disabled := True;
+ dStream := nil;
+ iStream := nil;
+ hues := nil;
+end;
+
+destructor TArtReader.Free;
+begin
+end;
+
+// Create an Art-tile
+function TArtReader.GetTile( ID, Color: Word ): TBitmap32;
+var
+ Data: TStream;
+ x, y, i: Cardinal;
+ Length: Integer;
+ Width, Height: Word;
+ LookupTable: Array of Word;
+ DataSTArtReader: Cardinal;
+ XOffset, RunLength, RunColor: Word;
+ hue: PHue;
+begin
+ if (Color <> 0) and (hues <> nil) then begin
+ hue := hues.getHue(color);
+ end else begin
+ hue := nil;
+ end;
+
+ Result := TBitmap32.Create;
+
+ if disabled then
+ begin
+ Result.SetSize( 44, 44 );
+ Result.Clear( Color32( clBtnFace ) );
+ Result.Line( 1, 1, 43, 43, clRed32 );
+ Result.Line( 43, 0, 0, 43, clRed32 );
+ exit;
+ end;
+
+ Data := GetData( Id, Length );
+
+ if( Length = -1 ) then
+ exit;
+
+ Data.Seek( 4, soFromCurrent );
+ Data.Read( Width, 2 );
+ Data.Read( Height, 2 );
+
+ SetLength( LookupTable, Height );
+ for i := 0 to Height-1 do
+ Data.Read( LookupTable[i], 2 );
+
+ DataSTArtReader := Data.Position;
+ Result.SetSize( Width, Height );
+ //Result.Clear( Color32( clBtnFace ) );
+ Result.Clear(Color32(clBtnFace));
+
+ // Draw the "tile" 3d wireframe
+ for x := 0 to 21 do begin
+ Result.PixelS[((Width - 1) div 2) - x, Height - 1 - x] := clRed32;
+ Result.PixelS[((Width - 1) div 2) + x, Height - 1 - x] := clRed32;
+ Result.PixelS[((Width - 1) div 2) - x, Height - 44 + x] := clRed32;
+ Result.PixelS[((Width - 1) div 2) + x, Height - 44 + x] := clRed32;
+ end;
+
+ // Parse each line of the image
+ for y := 0 to Height-1 do
+ begin
+ Data.Seek( DataSTArtReader + ( LookupTable[y] * 2 ), soFromBeginning );
+ X := 0;
+
+ // RLE Decoding (Read Chunks)
+ repeat begin
+ Data.Read( XOffset, 2 );
+ Data.Read( RunLength, 2 );
+
+ inc( x, XOffset );
+
+ if( RunLength > 0 ) then
+ for i := 0 to RunLength-1 do
+ begin
+ Data.Read( RunColor, 2 );
+
+ // INSERT HUE PROCESSING HERE
+ if hue <> nil then begin
+ RunColor := hue.Colors[((RunColor shr 10) and $1F)];
+ end;
+
+ // 0 RRRRR GG|GGG BBBBB Encoding
+ try
+ Result.Pixel[ x+i, y ] := Color15to24( RunColor );
+ except
+ Application.MessageBox( PChar( 'Invalid Data, X=' + IntToStr(x) + ', Y=' + IntToStr(y) ), 'Invalid Data', 0 );
+ end;
+ end;
+
+ inc( X, RunLength );
+
+ end until ( ( RunLength = 0 ) and ( XOffset = 0 ) );
+ end;
+end;
+
+function TArtReader.GetTile( Id: Word ): TBitmap32;
+begin
+ Result := GetTile( Id, 0 );
+end;
+
+end.
Added: trunk/WPGM/UOLib/UOTiledata.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UOLib/UOTiledata.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UOLib/UOTiledata.pas
===================================================================
--- trunk/WPGM/UOLib/UOTiledata.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOLib/UOTiledata.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,91 @@
+unit UOTiledata;
+
+interface
+
+type TLandTiledata = packed record
+ flags: Cardinal;
+ texture: Word;
+ name: array[0..19] of Char;
+end;
+
+type TItemTiledata = packed record
+ flags: Cardinal;
+ weight: Byte;
+ layer: Byte;
+ unknown1: word;
+ unknown2: byte;
+ quantity: byte;
+ animation: word;
+ unknown3: byte;
+ hue: byte;
+ unknown4: byte;
+ unknown5: byte;
+ height: byte;
+ name: array[0..19] of Char;
+end;
+
+type PItemTiledata = ^TItemTiledata;
+
+type TTiledataReader = class( TObject )
+ private
+ StaticTiles: Array[0..$3FFF] of TItemTiledata;
+
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ function Open( FileName: String ): Boolean;
+ function getItemName( id: Word ): String;
+end;
+
+implementation
+
+uses Classes, SysUtils;
+
+constructor TTiledataReader.Create;
+begin
+end;
+
+destructor TTiledataReader.Destroy;
+begin
+end;
+
+function TTiledataReader.Open( FileName: String ): Boolean;
+var
+ Input: TFileStream;
+ i,j: Cardinal;
+begin
+ Result := False;
+ Input := Nil;
+ try
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+
+ // Skip Land Tiles (for now)
+ Input.Seek( 512 * ( 4 + ( 32 * sizeof( TLandTiledata ) ) ), soFromBeginning );
+
+ // Read all blocks
+ for i := 0 to 511 do
+ begin
+ Input.Seek( 4, soFromCurrent );
+
+ for j := 0 to 31 do
+ begin
+ Input.Read( StaticTiles[ ( i * 32 ) + j ], sizeof( TItemTiledata ) );
+ end;
+ end;
+
+ Input.Free;
+ Result := True;
+ except
+ Input.Free;
+ end;
+end;
+
+function TTiledataReader.getItemName( id: Word ): String;
+begin
+ Assert( id <= $3fff );
+
+ Result := StaticTiles[ id ].name;
+end;
+
+end.
Added: trunk/WPGM/UOLib/UOTiledata.~pas
===================================================================
--- trunk/WPGM/UOLib/UOTiledata.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOLib/UOTiledata.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,90 @@
+unit UOTiledata;
+
+interface
+
+type TLandTiledata = packed record
+ flags: Cardinal;
+ texture: Word;
+ name: array[0..19] of Char;
+end;
+
+type TItemTiledata = packed record
+ flags: Cardinal;
+ weight: Byte;
+ layer: Byte;
+ unknown1: word;
+ unknown2: byte;
+ quantity: byte;
+ animation: word;
+ unknown3: byte;
+ hue: byte;
+ unknown4: byte;
+ unknown5: byte;
+ height: byte;
+ name: array[0..19] of Char;
+end;
+
+type PItemTiledata = ^TItemTiledata;
+
+type TTiledataReader = class( TObject )
+ private
+ StaticTiles: Array[0..$3FFF] of TItemTiledata;
+
+ public
+ constructor Create;
+ destructor Destroy; override;
+
+ function Open( FileName: String ): Boolean;
+ function getItemName( id: Word ): String;
+end;
+
+implementation
+
+uses Classes, SysUtils;
+
+constructor TTiledataReader.Create;
+begin
+end;
+
+destructor TTiledataReader.Destroy;
+begin
+end;
+
+function TTiledataReader.Open( FileName: String ): Boolean;
+var
+ Input: TFileStream;
+ i,j: Cardinal;
+begin
+ Result := False;
+ Input := Nil;
+ try
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+
+ // Skip Land Tiles (for now)
+ Input.Seek( 512 * ( 4 + ( 32 * sizeof( TLandTiledata ) ) ), soFromBeginning );
+
+ // Read all blocks
+ for i := 0 to 511 do
+ begin
+ Input.Seek( 4, soFromCurrent );
+
+ for j := 0 to 31 do
+ begin
+ Input.Read( StaticTiles[ ( i * 32 ) + j ], sizeof( TItemTiledata ) );
+ end;
+ end;
+
+ Input.Free;
+ Result := True;
+ except
+ end;
+end;
+
+function TTiledataReader.getItemName( id: Word ): String;
+begin
+ Assert( id <= $3fff );
+
+ Result := StaticTiles[ id ].name;
+end;
+
+end.
Added: trunk/WPGM/UOLib/UOUtilities.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UOLib/UOUtilities.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UOLib/UOUtilities.pas
===================================================================
--- trunk/WPGM/UOLib/UOUtilities.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOLib/UOUtilities.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,105 @@
+unit UOUtilities;
+
+interface
+
+uses Graphics, GR32, Classes;
+
+function Color15to24( Color: Word ): TColor;
+function Color15to32( Color: Word ): TColor32;
+function SendCommand( Command: String; Activate: Boolean = False ): Boolean;
+function GetUoPath: String;
+procedure Split(const Delimiter: Char; Input: string; const Strings: TStrings);
+
+implementation
+
+uses Windows, Forms, Messages, Registry, SysUtils, Main, uConfig;
+
+procedure Split
+ (const Delimiter: Char;
+ Input: string;
+ const Strings: TStrings) ;
+begin
+ Assert(Assigned(Strings)) ;
+ Strings.Clear;
+ Strings.Delimiter := Delimiter;
+ Strings.DelimitedText := Input;
+end;
+
+function Color15to32( Color: Word ): TColor32;
+begin
+ Result := Color32( ((Color shr 10) and $1F) * 8,
+ ((Color shr 5) and $1F) * 8,
+ ((Color and $1F) * 8),
+ 255);
+end;
+
+function Color15to24( Color: Word ): TColor;
+begin
+ Result := TColor( ( ( (Color shr 10 ) and $1F ) * 8 shl 16 ) or
+ ( ( ( Color shr 5 ) and $1F ) * 8 shl 8 ) or
+ ( Color and $1F) * 8 );
+end;
+
+function SendCommand(Command: String; Activate: Boolean): Boolean;
+var
+ Window: HWND;
+ PStr: PChar;
+ i: Integer;
+ Prefix: String;
+begin
+ Prefix := Main.Config.getString('Command Prefix', '''');
+ Command := Prefix + Command;
+
+ Result := False;
+ Window := FindWindow('Ultima Online', nil);
+
+ if Window = 0 then
+ begin
+ Application.MessageBox(PChar('Please start the Ultima Online client before sending any commands.' + #13 + 'Ignored Command: ' + Command ), 'Ultima Online Error', MB_OK+MB_ICONWARNING);
+ exit;
+ end;
+
+ PStr := PChar(Command);
+
+ SendMessage(Window, WM_CHAR, 13, 0);
+
+ for i := 0 to Length( Command ) - 1 do
+ begin
+ PostMessage(Window, WM_CHAR, Integer( PStr[i] ), 0);
+ end;
+
+ PostMessage(Window, WM_CHAR, 13, 0);
+
+ if Activate then
+ begin
+ BringWindowToTop(Window);
+ SetFocus(Window);
+ end;
+end;
+
+function GetUoPath: String;
+var
+ Registry: TRegistry;
+begin
+ Registry := TRegistry.Create;
+ Result := '';
+
+ Registry.RootKey := HKEY_LOCAL_MACHINE;
+ if not Registry.OpenKey( 'SOFTWARE\Origin Worlds Online\Ultima Online\1.0', False ) then
+ begin
+ Registry.Free;
+ exit;
+ end;
+
+ if not Registry.ValueExists( 'ExePath' ) then
+ begin
+ Registry.Free;
+ exit;
+ end;
+
+ Result := ExtractFilePath( Registry.ReadString( 'ExePath' ) );
+
+ Registry.Free;
+end;
+
+end.
Added: trunk/WPGM/UOLib/UOUtilities.~pas
===================================================================
--- trunk/WPGM/UOLib/UOUtilities.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOLib/UOUtilities.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,93 @@
+unit UOUtilities;
+
+interface
+
+uses Graphics, GR32;
+
+function Color15to24( Color: Word ): TColor;
+function Color15to32( Color: Word ): TColor32;
+function SendCommand( Command: String; Activate: Boolean = False ): Boolean;
+function GetUoPath: String;
+
+implementation
+
+uses Windows, Forms, Messages, Registry, SysUtils, Main, uConfig;
+
+function Color15to32( Color: Word ): TColor32;
+begin
+ Result := Color32( ((Color shr 10) and $1F) * 8,
+ ((Color shr 5) and $1F) * 8,
+ ((Color and $1F) * 8),
+ 255);
+end;
+
+function Color15to24( Color: Word ): TColor;
+begin
+ Result := TColor( ( ( (Color shr 10 ) and $1F ) * 8 shl 16 ) or
+ ( ( ( Color shr 5 ) and $1F ) * 8 shl 8 ) or
+ ( Color and $1F) * 8 );
+end;
+
+function SendCommand(Command: String; Activate: Boolean): Boolean;
+var
+ Window: HWND;
+ PStr: PChar;
+ i: Integer;
+ Prefix: String;
+begin
+ Prefix := Main.Config.getString('Command Prefix', '''');
+ Command := Prefix + Command;
+
+ Result := False;
+ Window := FindWindow('Ultima Online', nil);
+
+ if Window = 0 then
+ begin
+ Application.MessageBox(PChar('Please start the Ultima Online client before sending any commands.' + #13 + 'Ignored Command: ' + Command ), 'Ultima Online Error', MB_OK+MB_ICONWARNING);
+ exit;
+ end;
+
+ PStr := PChar(Command);
+
+ SendMessage(Window, WM_CHAR, 13, 0);
+
+ for i := 0 to Length( Command ) - 1 do
+ begin
+ PostMessage(Window, WM_CHAR, Integer( PStr[i] ), 0);
+ end;
+
+ PostMessage(Window, WM_CHAR, 13, 0);
+
+ if Activate then
+ begin
+ BringWindowToTop(Window);
+ SetFocus(Window);
+ end;
+end;
+
+function GetUoPath: String;
+var
+ Registry: TRegistry;
+begin
+ Registry := TRegistry.Create;
+ Result := '';
+
+ Registry.RootKey := HKEY_LOCAL_MACHINE;
+ if not Registry.OpenKey( 'SOFTWARE\Origin Worlds Online\Ultima Online\1.0', False ) then
+ begin
+ Registry.Free;
+ exit;
+ end;
+
+ if not Registry.ValueExists( 'ExePath' ) then
+ begin
+ Registry.Free;
+ exit;
+ end;
+
+ Result := ExtractFilePath( Registry.ReadString( 'ExePath' ) );
+
+ Registry.Free;
+end;
+
+end.
Added: trunk/WPGM/UOMap.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UOMap.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UOMap.pas
===================================================================
--- trunk/WPGM/UOMap.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOMap.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,177 @@
+unit UOMap;
+
+interface
+
+uses Classes, UOCache;
+
+type TMapCell = packed record
+ Id: Word;
+ Height: Shortint;
+end;
+
+type TMapBlock = packed record
+ Header: Cardinal;
+ Cells: Array[0..63] of TMapCell;
+end;
+
+type TMapReader = class( TObject )
+ private
+ Input: TFileStream;
+ Height, Width: Word;
+ Cache: TCache;
+ Disabled: Boolean;
+ LastModifyTime: TDateTime;
+
+ public
+ function getHeight: Word;
+ function getWidth: Word;
+ constructor Create;
+ destructor Destroy; override;
+
+ function Open( FileName: String; MapWidth: Word = 0; MapHeight: Word = 0 ): Boolean;
+ procedure Close;
+
+ procedure ReadBlock( XBlock: Word; YBlock: Word; var MapBlock: TMapBlock );
+ procedure ReadCell( X: Word; Y: Word; var MapCell: TMapCell );
+ function LastModified(): TDateTime;
+ //procedure WriteBlock( X: Word, Y: Word; MapBlock: TMapBlock );
+ //procedure WriteCell( X: Word; Y: Word; MapCell: TMapCell );
+end;
+
+implementation
+
+uses Windows, Dialogs, SysUtils;
+
+function TMapReader.getWidth: Word;
+begin
+ Result := Width;
+end;
+
+function TMapReader.getHeight: Word;
+begin
+ Result := Height;
+end;
+
+constructor TMapReader.Create;
+begin
+ Input := nil;
+ Width := 0;
+ Height := 0;
+ Cache := TCache.Create( 100 ); // 100 Blocks
+ Disabled := True;
+ LastModifyTime := GetTime;
+end;
+
+destructor TMapReader.Destroy;
+begin
+ Input.Free;
+ Cache.Free;
+end;
+
+function TMapReader.Open( FileName: String; MapWidth: Word; MapHeight: Word ): Boolean;
+begin
+ Result := False;
+ Input := nil;
+
+ try
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+ Result := True;
+
+ // Measure Map Height
+ Height := MapHeight;
+ Width := MapWidth;
+
+ if Height = 0 then case Input.Size of
+ 77070336:
+ begin
+ Width := 768;
+ Height := 512;
+ Disabled := False;
+ end;
+
+ 11289600:
+ begin
+ Width := 288;
+ Height := 200;
+ Disabled := False;
+ end;
+
+ 16056320:
+ begin
+ Width := 320;
+ Height := 256;
+ Disabled := False;
+ end;
+
+ 6421156:
+ begin
+ Width := 181;
+ Height := 181;
+ Disabled := False;
+ end;
+ end;
+
+ // Try to read the modify time
+ LastModifyTime := FileDateToDateTime(FileAge(FileName));
+ except
+ Input.Free;
+ end;
+end;
+
+procedure TMapReader.Close;
+begin
+ Input.Free;
+ Input := nil;
+end;
+
+procedure TMapReader.ReadBlock(XBlock: Word; YBlock: Word; var MapBlock: TMapBlock);
+var
+ BlockId: Cardinal;
+ CacheEntry: ^TMapBlock;
+begin
+ if Disabled then begin
+ ZeroMemory(@MapBlock, sizeof(TMapBlock));
+ exit;
+ end;
+
+ BlockId := XBlock * Height + YBlock;
+
+ // See if the block is cached
+ CacheEntry := Cache.Lookup(BlockId);
+
+ if CacheEntry <> nil then begin
+ MapBlock := CacheEntry^;
+ exit;
+ end;
+
+ ZeroMemory(@MapBlock, sizeof(TMapBlock));
+ if (Input = nil) or (Height = 0) then
+ exit;
+
+ new(CacheEntry);
+ Input.Seek( BlockId * sizeof( TMapBlock ), soFromBeginning );
+ Input.Read(CacheEntry^, sizeof(TMapBlock));
+ MapBlock := CacheEntry^;
+ Cache.Add(BlockId, CacheEntry);
+end;
+
+procedure TMapReader.ReadCell( X: Word; Y: Word; var MapCell: TMapCell );
+var
+ Block: TMapBlock;
+begin
+ ZeroMemory( @MapCell, sizeof( TMapCell ) );
+
+ if( Input = nil ) or ( Height = 0 ) then
+ exit;
+
+ ReadBlock( X div 8, Y div 8, Block );
+
+ MapCell := Block.Cells[ ( ( Y mod 8 ) * 8 ) + ( X mod 8 ) ];
+end;
+
+function TMapReader.LastModified(): TDateTime;
+begin
+ Result := LastModifyTime;
+end;
+
+end.
Added: trunk/WPGM/UOMap.~pas
===================================================================
--- trunk/WPGM/UOMap.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOMap.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,177 @@
+unit UOMap;
+
+interface
+
+uses Classes, UOCache;
+
+type TMapCell = packed record
+ Id: Word;
+ Height: Shortint;
+end;
+
+type TMapBlock = packed record
+ Header: Cardinal;
+ Cells: Array[0..63] of TMapCell;
+end;
+
+type TMapReader = class( TObject )
+ private
+ Input: TFileStream;
+ Height, Width: Word;
+ Cache: TCache;
+ Disabled: Boolean;
+ LastModifyTime: TDateTime;
+
+ public
+ function getHeight: Word;
+ function getWidth: Word;
+ constructor Create;
+ destructor Destroy; override;
+
+ function Open( FileName: String; MapWidth: Word = 0; MapHeight: Word = 0 ): Boolean;
+ procedure Close;
+
+ procedure ReadBlock( XBlock: Word; YBlock: Word; var MapBlock: TMapBlock );
+ procedure ReadCell( X: Word; Y: Word; var MapCell: TMapCell );
+ function LastModified(): TDateTime;
+ //procedure WriteBlock( X: Word, Y: Word; MapBlock: TMapBlock );
+ //procedure WriteCell( X: Word; Y: Word; MapCell: TMapCell );
+end;
+
+implementation
+
+uses Windows, Dialogs, SysUtils;
+
+function TMapReader.getWidth: Word;
+begin
+ Result := Width;
+end;
+
+function TMapReader.getHeight: Word;
+begin
+ Result := Height;
+end;
+
+constructor TMapReader.Create;
+begin
+ Input := nil;
+ Width := 0;
+ Height := 0;
+ Cache := TCache.Create( 100 ); // 100 Blocks
+ Disabled := True;
+ LastModifyTime := GetTime;
+end;
+
+destructor TMapReader.Destroy;
+begin
+ Input.Free;
+ Cache.Free;
+end;
+
+function TMapReader.Open( FileName: String; MapWidth: Word; MapHeight: Word ): Boolean;
+begin
+ Result := False;
+ Input := nil;
+
+ try
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+ Result := True;
+
+ // Measure Map Height
+ Height := MapHeight;
+ Width := MapWidth;
+
+ if Height = 0 then case Input.Size of
+ 77070336:
+ begin
+ Width := 768;
+ Height := 512;
+ Disabled := False;
+ end;
+
+ 11289600:
+ begin
+ Width := 288;
+ Height := 200;
+ Disabled := False;
+ end;
+
+ 16056320:
+ begin
+ Width := 320;
+ Height := 256;
+ Disabled := False;
+ end;
+
+ 6421156:
+ begin
+ Width := 181;
+ Height := 181;
+ Disabled := False;
+ end;
+ end;
+
+ // Try to read the modify time
+ LastModifyTime := FileDateToDateTime(FileAge(FileName));
+ except
+ Input.Free;
+ end;
+end;
+
+procedure TMapReader.Close;
+begin
+ Input.Free;
+ Input := nil;
+end;
+
+procedure TMapReader.ReadBlock(XBlock: Word; YBlock: Word; var MapBlock: TMapBlock);
+var
+ BlockId: Cardinal;
+ CacheEntry: ^TMapBlock;
+begin
+ if Disabled then begin
+ ZeroMemory(@MapBlock, sizeof(TMapBlock));
+ exit;
+ end;
+
+ BlockId := XBlock * Height + YBlock;
+
+ // See if the block is cached
+ CacheEntry := Cache.Lookup(BlockId);
+
+ if CacheEntry <> nil then begin
+ MapBlock := CacheEntry^;
+ exit;
+ end;
+
+ ZeroMemory(@MapBlock, sizeof(TMapBlock));
+ if (Input = nil) or (Height = 0) then
+ exit;
+
+ new(CacheEntry);
+ Input.Seek( BlockId * sizeof( TMapBlock ), soFromBeginning );
+ Input.Read(CacheEntry^, sizeof(TMapBlock));
+ MapBlock := CacheEntry^;
+ Cache.Add(BlockId, CacheEntry);
+end;
+
+procedure TMapReader.ReadCell( X: Word; Y: Word; var MapCell: TMapCell );
+var
+ Block: TMapBlock;
+begin
+ ZeroMemory( @MapCell, sizeof( TMapCell ) );
+
+ if( Input = nil ) or ( Height = 0 ) then
+ exit;
+
+ ReadBlock( X div 8, Y div 8, Block );
+
+ MapCell := Block.Cells[ ( ( Y mod 8 ) * 8 ) + ( X mod 8 ) ];
+end;
+
+function TMapReader.LastModified(): TDateTime;
+begin
+ Result := LastModifyTime;
+end;
+
+end.
Added: trunk/WPGM/UORadarCol.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UORadarCol.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UORadarCol.pas
===================================================================
--- trunk/WPGM/UORadarCol.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UORadarCol.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,63 @@
+unit UORadarCol;
+
+interface
+
+uses Classes, Graphics;
+
+type TRadarColReader = class( TObject )
+ private
+ Colors: Array[0..$7FFF] of TColor;
+
+ public
+ constructor Create; overload;
+ function Load( FileName: String ): Boolean;
+
+ function GetLandColor( Id: Word ): TColor;
+ function GetItemColor( Id: Word ): TColor;
+end;
+
+implementation
+
+uses Windows, SysUtils, UOUtilities;
+
+constructor TRadarColReader.Create;
+begin
+ ZeroMemory( @Colors, $8000 * sizeof( TColor ) );
+end;
+
+function TRadarColReader.Load( FileName: String ): Boolean;
+var
+ Input: TFileStream;
+ i: Integer;
+begin
+ Result := False;
+
+ try
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyNone );
+
+ for i := 0 to $7FFF do
+ begin
+ Input.Read( Colors[i], 2 );
+ Colors[i] := Color15to24( Colors[i] );
+ end;
+
+ Input.Free;
+ Result := True;
+ except
+ end;
+end;
+
+function TRadarColReader.GetLandColor( Id: Word ): TColor;
+begin
+ if Id >= $7FFF then
+ Result := clBlack
+ else
+ Result := Colors[ Id ];
+end;
+
+function TRadarColReader.GetItemColor( Id: Word ): TColor;
+begin
+ Result := GetLandColor($4000 + Id);
+end;
+
+end.
Added: trunk/WPGM/UORadarCol.~pas
===================================================================
--- trunk/WPGM/UORadarCol.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UORadarCol.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,63 @@
+unit UORadarCol;
+
+interface
+
+uses Classes, Graphics;
+
+type TRadarColReader = class( TObject )
+ private
+ Colors: Array[0..$7FFF] of TColor;
+
+ public
+ constructor Create; overload;
+ function Load( FileName: String ): Boolean;
+
+ function GetLandColor( Id: Word ): TColor;
+ function GetItemColor( Id: Word ): TColor;
+end;
+
+implementation
+
+uses Windows, SysUtils, UOUtilities;
+
+constructor TRadarColReader.Create;
+begin
+ ZeroMemory( @Colors, $8000 * sizeof( TColor ) );
+end;
+
+function TRadarColReader.Load( FileName: String ): Boolean;
+var
+ Input: TFileStream;
+ i: Integer;
+begin
+ Result := False;
+
+ try
+ Input := TFileStream.Create( FileName, fmOpenRead+fmShareDenyWrite );
+
+ for i := 0 to $7FFF do
+ begin
+ Input.Read( Colors[i], 2 );
+ Colors[i] := Color15to24( Colors[i] );
+ end;
+
+ Input.Free;
+ Result := True;
+ except
+ end;
+end;
+
+function TRadarColReader.GetLandColor( Id: Word ): TColor;
+begin
+ if Id >= $7FFF then
+ Result := clBlack
+ else
+ Result := Colors[ Id ];
+end;
+
+function TRadarColReader.GetItemColor( Id: Word ): TColor;
+begin
+ Result := GetLandColor($4000 + Id);
+end;
+
+end.
Added: trunk/WPGM/UOStatics.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/UOStatics.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/UOStatics.pas
===================================================================
--- trunk/WPGM/UOStatics.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOStatics.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,331 @@
+{$A8,B-,C-,D-,E-,F-,G+,H+,I-,J+,K-,L-,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y-,Z1}
+{$MINSTACKSIZE $00004000}
+{$MAXSTACKSIZE $00100000}
+{$IMAGEBASE $00400000}
+{$APPTYPE GUI}
+{$WARN SYMBOL_DEPRECATED ON}
+{$WARN SYMBOL_LIBRARY ON}
+{$WARN SYMBOL_PLATFORM ON}
+{$WARN UNIT_LIBRARY ON}
+{$WARN UNIT_PLATFORM ON}
+{$WARN UNIT_DEPRECATED ON}
+{$WARN HRESULT_COMPAT ON}
+{$WARN HIDING_MEMBER ON}
+{$WARN HIDDEN_VIRTUAL ON}
+{$WARN GARBAGE ON}
+{$WARN BOUNDS_ERROR ON}
+{$WARN ZERO_NIL_COMPAT ON}
+{$WARN STRING_CONST_TRUNCED ON}
+{$WARN FOR_LOOP_VAR_VARPAR ON}
+{$WARN TYPED_CONST_VARPAR ON}
+{$WARN ASG_TO_TYPED_CONST ON}
+{$WARN CASE_LABEL_RANGE ON}
+{$WARN FOR_VARIABLE ON}
+{$WARN CONSTRUCTING_ABSTRACT ON}
+{$WARN COMPARISON_FALSE ON}
+{$WARN COMPARISON_TRUE ON}
+{$WARN COMPARING_SIGNED_UNSIGNED ON}
+{$WARN COMBINING_SIGNED_UNSIGNED ON}
+{$WARN UNSUPPORTED_CONSTRUCT ON}
+{$WARN FILE_OPEN ON}
+{$WARN FILE_OPEN_UNITSRC ON}
+{$WARN BAD_GLOBAL_SYMBOL ON}
+{$WARN DUPLICATE_CTOR_DTOR ON}
+{$WARN INVALID_DIRECTIVE ON}
+{$WARN PACKAGE_NO_LINK ON}
+{$WARN PACKAGED_THREADVAR ON}
+{$WARN IMPLICIT_IMPORT ON}
+{$WARN HPPEMIT_IGNORED ON}
+{$WARN NO_RETVAL ON}
+{$WARN USE_BEFORE_DEF ON}
+{$WARN FOR_LOOP_VAR_UNDEF ON}
+{$WARN UNIT_NAME_MISMATCH ON}
+{$WARN NO_CFG_FILE_FOUND ON}
+{$WARN MESSAGE_DIRECTIVE ON}
+{$WARN IMPLICIT_VARIANTS ON}
+{$WARN UNICODE_TO_LOCALE ON}
+{$WARN LOCALE_TO_UNICODE ON}
+{$WARN IMAGEBASE_MULTIPLE ON}
+{$WARN SUSPICIOUS_TYPECAST ON}
+{$WARN PRIVATE_PROPACCESSOR ON}
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CODE OFF}
+{$WARN UNSAFE_CAST OFF}
+{$A8,B-,C-,D-,E-,F-,G+,H+,I-,J+,K-,L-,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y-,Z1}
+{$MINSTACKSIZE $00004000}
+{$MAXSTACKSIZE $00100000}
+{$IMAGEBASE $00400000}
+{$APPTYPE GUI}
+{$WARN SYMBOL_DEPRECATED ON}
+{$WARN SYMBOL_LIBRARY ON}
+{$WARN SYMBOL_PLATFORM ON}
+{$WARN UNIT_LIBRARY ON}
+{$WARN UNIT_PLATFORM ON}
+{$WARN UNIT_DEPRECATED ON}
+{$WARN HRESULT_COMPAT ON}
+{$WARN HIDING_MEMBER ON}
+{$WARN HIDDEN_VIRTUAL ON}
+{$WARN GARBAGE ON}
+{$WARN BOUNDS_ERROR ON}
+{$WARN ZERO_NIL_COMPAT ON}
+{$WARN STRING_CONST_TRUNCED ON}
+{$WARN FOR_LOOP_VAR_VARPAR ON}
+{$WARN TYPED_CONST_VARPAR ON}
+{$WARN ASG_TO_TYPED_CONST ON}
+{$WARN CASE_LABEL_RANGE ON}
+{$WARN FOR_VARIABLE ON}
+{$WARN CONSTRUCTING_ABSTRACT ON}
+{$WARN COMPARISON_FALSE ON}
+{$WARN COMPARISON_TRUE ON}
+{$WARN COMPARING_SIGNED_UNSIGNED ON}
+{$WARN COMBINING_SIGNED_UNSIGNED ON}
+{$WARN UNSUPPORTED_CONSTRUCT ON}
+{$WARN FILE_OPEN ON}
+{$WARN FILE_OPEN_UNITSRC ON}
+{$WARN BAD_GLOBAL_SYMBOL ON}
+{$WARN DUPLICATE_CTOR_DTOR ON}
+{$WARN INVALID_DIRECTIVE ON}
+{$WARN PACKAGE_NO_LINK ON}
+{$WARN PACKAGED_THREADVAR ON}
+{$WARN IMPLICIT_IMPORT ON}
+{$WARN HPPEMIT_IGNORED ON}
+{$WARN NO_RETVAL ON}
+{$WARN USE_BEFORE_DEF ON}
+{$WARN FOR_LOOP_VAR_UNDEF ON}
+{$WARN UNIT_NAME_MISMATCH ON}
+{$WARN NO_CFG_FILE_FOUND ON}
+{$WARN MESSAGE_DIRECTIVE ON}
+{$WARN IMPLICIT_VARIANTS ON}
+{$WARN UNICODE_TO_LOCALE ON}
+{$WARN LOCALE_TO_UNICODE ON}
+{$WARN IMAGEBASE_MULTIPLE ON}
+{$WARN SUSPICIOUS_TYPECAST ON}
+{$WARN PRIVATE_PROPACCESSOR ON}
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CODE OFF}
+{$WARN UNSAFE_CAST OFF}
+{$A8,B-,C-,D-,E-,F-,G+,H+,I-,J+,K-,L-,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y-,Z1}
+{$MINSTACKSIZE $00004000}
+{$MAXSTACKSIZE $00100000}
+{$IMAGEBASE $00400000}
+{$APPTYPE GUI}
+{$WARN SYMBOL_DEPRECATED ON}
+{$WARN SYMBOL_LIBRARY ON}
+{$WARN SYMBOL_PLATFORM ON}
+{$WARN UNIT_LIBRARY ON}
+{$WARN UNIT_PLATFORM ON}
+{$WARN UNIT_DEPRECATED ON}
+{$WARN HRESULT_COMPAT ON}
+{$WARN HIDING_MEMBER ON}
+{$WARN HIDDEN_VIRTUAL ON}
+{$WARN GARBAGE ON}
+{$WARN BOUNDS_ERROR ON}
+{$WARN ZERO_NIL_COMPAT ON}
+{$WARN STRING_CONST_TRUNCED ON}
+{$WARN FOR_LOOP_VAR_VARPAR ON}
+{$WARN TYPED_CONST_VARPAR ON}
+{$WARN ASG_TO_TYPED_CONST ON}
+{$WARN CASE_LABEL_RANGE ON}
+{$WARN FOR_VARIABLE ON}
+{$WARN CONSTRUCTING_ABSTRACT ON}
+{$WARN COMPARISON_FALSE ON}
+{$WARN COMPARISON_TRUE ON}
+{$WARN COMPARING_SIGNED_UNSIGNED ON}
+{$WARN COMBINING_SIGNED_UNSIGNED ON}
+{$WARN UNSUPPORTED_CONSTRUCT ON}
+{$WARN FILE_OPEN ON}
+{$WARN FILE_OPEN_UNITSRC ON}
+{$WARN BAD_GLOBAL_SYMBOL ON}
+{$WARN DUPLICATE_CTOR_DTOR ON}
+{$WARN INVALID_DIRECTIVE ON}
+{$WARN PACKAGE_NO_LINK ON}
+{$WARN PACKAGED_THREADVAR ON}
+{$WARN IMPLICIT_IMPORT ON}
+{$WARN HPPEMIT_IGNORED ON}
+{$WARN NO_RETVAL ON}
+{$WARN USE_BEFORE_DEF ON}
+{$WARN FOR_LOOP_VAR_UNDEF ON}
+{$WARN UNIT_NAME_MISMATCH ON}
+{$WARN NO_CFG_FILE_FOUND ON}
+{$WARN MESSAGE_DIRECTIVE ON}
+{$WARN IMPLICIT_VARIANTS ON}
+{$WARN UNICODE_TO_LOCALE ON}
+{$WARN LOCALE_TO_UNICODE ON}
+{$WARN IMAGEBASE_MULTIPLE ON}
+{$WARN SUSPICIOUS_TYPECAST ON}
+{$WARN PRIVATE_PROPACCESSOR ON}
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CODE OFF}
+{$WARN UNSAFE_CAST OFF}
+unit UOStatics;
+
+interface
+
+uses Classes, UOCache;
+
+type TStaticItem = packed record
+ Id: Word;
+ X: Byte;
+ Y: Byte;
+ Z: Shortint;
+ Hue: Word;
+end;
+
+type TStaticBlock = array of TStaticItem;
+
+type TStaticReader = class( TObject )
+ private
+ Index, Data: TFileStream;
+ MapWidth, MapHeight: Word;
+ Cache: TCache;
+ Disabled: Boolean;
+ ModifyTimeData: TDateTime;
+ ModifyTimeIndex: TDateTime;
+
+ public
+ constructor Create;
+ destructor Destroy; override;
+ function Open( IndexName: String; DataName: String; MapHeight: Word = 0; MapWidth: Word = 0 ): Boolean;
+ procedure Close;
+ procedure ReadBlock( XBlock, YBlock: Word; var StaticBlock: TStaticBlock );
+ function LastDataModification: TDateTime;
+ function LastIndexModification: TDateTime;
+end;
+
+implementation
+
+uses SysUtils;
+
+constructor TStaticReader.Create;
+begin
+ Index := nil;
+ Data := nil;
+ MapWidth := 0;
+ MapHeight := 0;
+ Cache := TCache.Create(75);
+ Disabled := True;
+ ModifyTimeData := Time;
+ ModifyTimeIndex := Time;
+end;
+
+destructor TStaticReader.Destroy;
+begin
+ Data.Free;
+ Index.Free;
+ Cache.Free;
+end;
+
+function TStaticReader.Open( IndexName: String; DataName: String; MapHeight: Word = 0; MapWidth: Word = 0 ): Boolean;
+begin
+ Result := False;
+
+ try
+ Index := TFileStream.Create( IndexName, fmOpenRead+fmShareDenyNone );
+ Data := TFileStream.Create( DataName, fmOpenRead+fmShareDenyNone );
+
+ if MapHeight = 0 then case Index.Size of
+ 4718592:
+ begin
+ MapHeight := 512;
+ MapWidth := 768;
+ end;
+
+ 691200:
+ begin
+ MapHeight := 200;
+ MapWidth := 288;
+ end;
+
+ 983040:
+ begin
+ MapWidth := 320;
+ MapHeight := 256;
+ end;
+
+ 393132:
+ begin
+ MapWidth := 181;
+ MapHeight := 181;
+ end;
+ end;
+
+ if MapHeight = 0 then
+ raise Exception.Create( 'Couldn''t determine correct mapsize for TStaticReader' );
+
+ Self.MapHeight := MapHeight;
+ Self.MapWidth := MapWidth;
+
+ Disabled := False;
+ Result := True;
+
+ // Get modification times
+ ModifyTimeData := FileDateToDateTime(FileAge(DataName));
+ ModifyTimeIndex := FileDateToDateTime(FileAge(IndexName));
+ except
+ FreeAndNil(Data);
+ FreeAndNil(Index);
+ end;
+end;
+
+procedure TStaticReader.Close;
+begin
+ Data.Free;
+ Index.Free;
+
+ Data := nil;
+ Index := nil;
+end;
+
+procedure TStaticReader.ReadBlock( XBlock, YBlock: Word; var StaticBlock: TStaticBlock );
+var
+ Offset, Length: Cardinal;
+ I: Integer;
+ BlockId: Cardinal;
+ CacheEntry: ^TStaticBlock;
+begin
+ SetLength( StaticBlock, 0 );
+
+ if Disabled then
+ exit;
+
+ BlockId := XBlock * MapHeight + YBlock;
+
+ CacheEntry := Cache.Lookup(BlockId);
+
+ if CacheEntry <> nil then begin
+ StaticBlock := CacheEntry^;
+ exit;
+ end;
+
+ Index.Seek( BlockId * 12, soFromBeginning );
+ Index.Read( Offset, 4 );
+ Index.Read( Length, 4 );
+
+ if ( Offset = $FFFFFFFF ) or ( Length = 0 ) then
+ exit;
+
+ Data.Seek( Offset, soFromBeginning );
+
+ new(CacheEntry);
+ SetLength(CacheEntry^, Length div sizeof( TStaticItem ) );
+
+ for i := 0 to ( Length div sizeof( TStaticItem ) ) - 1 do
+ Data.Read( CacheEntry^[i], sizeof( TStaticItem ) );
+
+ Cache.Add(BlockId, CacheEntry);
+
+ StaticBlock := CacheEntry^;
+end;
+
+function TStaticReader.LastDataModification: TDateTime;
+begin
+ Result := ModifyTimeData;
+end;
+
+function TStaticReader.LastIndexModification: TDateTime;
+begin
+ Result := ModifyTimeIndex;
+end;
+
+end.
+
\ No newline at end of file
Added: trunk/WPGM/UOStatics.~pas
===================================================================
--- trunk/WPGM/UOStatics.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/UOStatics.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,331 @@
+{$A8,B-,C-,D-,E-,F-,G+,H+,I-,J+,K-,L-,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y-,Z1}
+{$MINSTACKSIZE $00004000}
+{$MAXSTACKSIZE $00100000}
+{$IMAGEBASE $00400000}
+{$APPTYPE GUI}
+{$WARN SYMBOL_DEPRECATED ON}
+{$WARN SYMBOL_LIBRARY ON}
+{$WARN SYMBOL_PLATFORM ON}
+{$WARN UNIT_LIBRARY ON}
+{$WARN UNIT_PLATFORM ON}
+{$WARN UNIT_DEPRECATED ON}
+{$WARN HRESULT_COMPAT ON}
+{$WARN HIDING_MEMBER ON}
+{$WARN HIDDEN_VIRTUAL ON}
+{$WARN GARBAGE ON}
+{$WARN BOUNDS_ERROR ON}
+{$WARN ZERO_NIL_COMPAT ON}
+{$WARN STRING_CONST_TRUNCED ON}
+{$WARN FOR_LOOP_VAR_VARPAR ON}
+{$WARN TYPED_CONST_VARPAR ON}
+{$WARN ASG_TO_TYPED_CONST ON}
+{$WARN CASE_LABEL_RANGE ON}
+{$WARN FOR_VARIABLE ON}
+{$WARN CONSTRUCTING_ABSTRACT ON}
+{$WARN COMPARISON_FALSE ON}
+{$WARN COMPARISON_TRUE ON}
+{$WARN COMPARING_SIGNED_UNSIGNED ON}
+{$WARN COMBINING_SIGNED_UNSIGNED ON}
+{$WARN UNSUPPORTED_CONSTRUCT ON}
+{$WARN FILE_OPEN ON}
+{$WARN FILE_OPEN_UNITSRC ON}
+{$WARN BAD_GLOBAL_SYMBOL ON}
+{$WARN DUPLICATE_CTOR_DTOR ON}
+{$WARN INVALID_DIRECTIVE ON}
+{$WARN PACKAGE_NO_LINK ON}
+{$WARN PACKAGED_THREADVAR ON}
+{$WARN IMPLICIT_IMPORT ON}
+{$WARN HPPEMIT_IGNORED ON}
+{$WARN NO_RETVAL ON}
+{$WARN USE_BEFORE_DEF ON}
+{$WARN FOR_LOOP_VAR_UNDEF ON}
+{$WARN UNIT_NAME_MISMATCH ON}
+{$WARN NO_CFG_FILE_FOUND ON}
+{$WARN MESSAGE_DIRECTIVE ON}
+{$WARN IMPLICIT_VARIANTS ON}
+{$WARN UNICODE_TO_LOCALE ON}
+{$WARN LOCALE_TO_UNICODE ON}
+{$WARN IMAGEBASE_MULTIPLE ON}
+{$WARN SUSPICIOUS_TYPECAST ON}
+{$WARN PRIVATE_PROPACCESSOR ON}
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CODE OFF}
+{$WARN UNSAFE_CAST OFF}
+{$A8,B-,C-,D-,E-,F-,G+,H+,I-,J+,K-,L-,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y-,Z1}
+{$MINSTACKSIZE $00004000}
+{$MAXSTACKSIZE $00100000}
+{$IMAGEBASE $00400000}
+{$APPTYPE GUI}
+{$WARN SYMBOL_DEPRECATED ON}
+{$WARN SYMBOL_LIBRARY ON}
+{$WARN SYMBOL_PLATFORM ON}
+{$WARN UNIT_LIBRARY ON}
+{$WARN UNIT_PLATFORM ON}
+{$WARN UNIT_DEPRECATED ON}
+{$WARN HRESULT_COMPAT ON}
+{$WARN HIDING_MEMBER ON}
+{$WARN HIDDEN_VIRTUAL ON}
+{$WARN GARBAGE ON}
+{$WARN BOUNDS_ERROR ON}
+{$WARN ZERO_NIL_COMPAT ON}
+{$WARN STRING_CONST_TRUNCED ON}
+{$WARN FOR_LOOP_VAR_VARPAR ON}
+{$WARN TYPED_CONST_VARPAR ON}
+{$WARN ASG_TO_TYPED_CONST ON}
+{$WARN CASE_LABEL_RANGE ON}
+{$WARN FOR_VARIABLE ON}
+{$WARN CONSTRUCTING_ABSTRACT ON}
+{$WARN COMPARISON_FALSE ON}
+{$WARN COMPARISON_TRUE ON}
+{$WARN COMPARING_SIGNED_UNSIGNED ON}
+{$WARN COMBINING_SIGNED_UNSIGNED ON}
+{$WARN UNSUPPORTED_CONSTRUCT ON}
+{$WARN FILE_OPEN ON}
+{$WARN FILE_OPEN_UNITSRC ON}
+{$WARN BAD_GLOBAL_SYMBOL ON}
+{$WARN DUPLICATE_CTOR_DTOR ON}
+{$WARN INVALID_DIRECTIVE ON}
+{$WARN PACKAGE_NO_LINK ON}
+{$WARN PACKAGED_THREADVAR ON}
+{$WARN IMPLICIT_IMPORT ON}
+{$WARN HPPEMIT_IGNORED ON}
+{$WARN NO_RETVAL ON}
+{$WARN USE_BEFORE_DEF ON}
+{$WARN FOR_LOOP_VAR_UNDEF ON}
+{$WARN UNIT_NAME_MISMATCH ON}
+{$WARN NO_CFG_FILE_FOUND ON}
+{$WARN MESSAGE_DIRECTIVE ON}
+{$WARN IMPLICIT_VARIANTS ON}
+{$WARN UNICODE_TO_LOCALE ON}
+{$WARN LOCALE_TO_UNICODE ON}
+{$WARN IMAGEBASE_MULTIPLE ON}
+{$WARN SUSPICIOUS_TYPECAST ON}
+{$WARN PRIVATE_PROPACCESSOR ON}
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CODE OFF}
+{$WARN UNSAFE_CAST OFF}
+{$A8,B-,C-,D-,E-,F-,G+,H+,I-,J+,K-,L-,M-,N+,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y-,Z1}
+{$MINSTACKSIZE $00004000}
+{$MAXSTACKSIZE $00100000}
+{$IMAGEBASE $00400000}
+{$APPTYPE GUI}
+{$WARN SYMBOL_DEPRECATED ON}
+{$WARN SYMBOL_LIBRARY ON}
+{$WARN SYMBOL_PLATFORM ON}
+{$WARN UNIT_LIBRARY ON}
+{$WARN UNIT_PLATFORM ON}
+{$WARN UNIT_DEPRECATED ON}
+{$WARN HRESULT_COMPAT ON}
+{$WARN HIDING_MEMBER ON}
+{$WARN HIDDEN_VIRTUAL ON}
+{$WARN GARBAGE ON}
+{$WARN BOUNDS_ERROR ON}
+{$WARN ZERO_NIL_COMPAT ON}
+{$WARN STRING_CONST_TRUNCED ON}
+{$WARN FOR_LOOP_VAR_VARPAR ON}
+{$WARN TYPED_CONST_VARPAR ON}
+{$WARN ASG_TO_TYPED_CONST ON}
+{$WARN CASE_LABEL_RANGE ON}
+{$WARN FOR_VARIABLE ON}
+{$WARN CONSTRUCTING_ABSTRACT ON}
+{$WARN COMPARISON_FALSE ON}
+{$WARN COMPARISON_TRUE ON}
+{$WARN COMPARING_SIGNED_UNSIGNED ON}
+{$WARN COMBINING_SIGNED_UNSIGNED ON}
+{$WARN UNSUPPORTED_CONSTRUCT ON}
+{$WARN FILE_OPEN ON}
+{$WARN FILE_OPEN_UNITSRC ON}
+{$WARN BAD_GLOBAL_SYMBOL ON}
+{$WARN DUPLICATE_CTOR_DTOR ON}
+{$WARN INVALID_DIRECTIVE ON}
+{$WARN PACKAGE_NO_LINK ON}
+{$WARN PACKAGED_THREADVAR ON}
+{$WARN IMPLICIT_IMPORT ON}
+{$WARN HPPEMIT_IGNORED ON}
+{$WARN NO_RETVAL ON}
+{$WARN USE_BEFORE_DEF ON}
+{$WARN FOR_LOOP_VAR_UNDEF ON}
+{$WARN UNIT_NAME_MISMATCH ON}
+{$WARN NO_CFG_FILE_FOUND ON}
+{$WARN MESSAGE_DIRECTIVE ON}
+{$WARN IMPLICIT_VARIANTS ON}
+{$WARN UNICODE_TO_LOCALE ON}
+{$WARN LOCALE_TO_UNICODE ON}
+{$WARN IMAGEBASE_MULTIPLE ON}
+{$WARN SUSPICIOUS_TYPECAST ON}
+{$WARN PRIVATE_PROPACCESSOR ON}
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CODE OFF}
+{$WARN UNSAFE_CAST OFF}
+unit UOStatics;
+
+interface
+
+uses Classes, UOCache;
+
+type TStaticItem = packed record
+ Id: Word;
+ X: Byte;
+ Y: Byte;
+ Z: Shortint;
+ Hue: Word;
+end;
+
+type TStaticBlock = array of TStaticItem;
+
+type TStaticReader = class( TObject )
+ private
+ Index, Data: TFileStream;
+ MapWidth, MapHeight: Word;
+ Cache: TCache;
+ Disabled: Boolean;
+ ModifyTimeData: TDateTime;
+ ModifyTimeIndex: TDateTime;
+
+ public
+ constructor Create;
+ destructor Destroy; override;
+ function Open( IndexName: String; DataName: String; MapHeight: Word = 0; MapWidth: Word = 0 ): Boolean;
+ procedure Close;
+ procedure ReadBlock( XBlock, YBlock: Word; var StaticBlock: TStaticBlock );
+ function LastDataModification: TDateTime;
+ function LastIndexModification: TDateTime;
+end;
+
+implementation
+
+uses SysUtils;
+
+constructor TStaticReader.Create;
+begin
+ Index := nil;
+ Data := nil;
+ MapWidth := 0;
+ MapHeight := 0;
+ Cache := TCache.Create(75);
+ Disabled := True;
+ ModifyTimeData := Time;
+ ModifyTimeIndex := Time;
+end;
+
+destructor TStaticReader.Destroy;
+begin
+ Data.Free;
+ Index.Free;
+ Cache.Free;
+end;
+
+function TStaticReader.Open( IndexName: String; DataName: String; MapHeight: Word = 0; MapWidth: Word = 0 ): Boolean;
+begin
+ Result := False;
+
+ try
+ Index := TFileStream.Create( IndexName, fmOpenRead+fmShareDenyNone );
+ Data := TFileStream.Create( DataName, fmOpenRead+fmShareDenyNone );
+
+ if MapHeight = 0 then case Index.Size of
+ 4718592:
+ begin
+ MapHeight := 512;
+ MapWidth := 768;
+ end;
+
+ 691200:
+ begin
+ MapHeight := 200;
+ MapWidth := 288;
+ end;
+
+ 983040:
+ begin
+ MapWidth := 320;
+ MapHeight := 256;
+ end;
+
+ 393132:
+ begin
+ MapWidth := 181;
+ MapHeight := 181;
+ end;
+ end;
+
+ if MapHeight = 0 then
+ raise Exception.Create( 'Couldn''t determine correct mapsize for TStaticReader' );
+
+ Self.MapHeight := MapHeight;
+ Self.MapWidth := MapWidth;
+
+ Disabled := False;
+ Result := True;
+
+ // Get modification times
+ ModifyTimeData := FileDateToDateTime(FileAge(DataName));
+ ModifyTimeIndex := FileDateToDateTime(FileAge(IndexName));
+ except
+ FreeAndNil(Data);
+ FreeAndNil(Index);
+ end;
+end;
+
+procedure TStaticReader.Close;
+begin
+ Data.Free;
+ Index.Free;
+
+ Data := nil;
+ Index := nil;
+end;
+
+procedure TStaticReader.ReadBlock( XBlock, YBlock: Word; var StaticBlock: TStaticBlock );
+var
+ Offset, Length: Cardinal;
+ I: Integer;
+ BlockId: Cardinal;
+ CacheEntry: ^TStaticBlock;
+begin
+ SetLength( StaticBlock, 0 );
+
+ if Disabled then
+ exit;
+
+ BlockId := XBlock * MapHeight + YBlock;
+
+ CacheEntry := Cache.Lookup(BlockId);
+
+ if CacheEntry <> nil then begin
+ StaticBlock := CacheEntry^;
+ exit;
+ end;
+
+ Index.Seek( BlockId * 12, soFromBeginning );
+ Index.Read( Offset, 4 );
+ Index.Read( Length, 4 );
+
+ if ( Offset = $FFFFFFFF ) or ( Length = 0 ) then
+ exit;
+
+ Data.Seek( Offset, soFromBeginning );
+
+ new(CacheEntry);
+ SetLength(CacheEntry^, Length div sizeof( TStaticItem ) );
+
+ for i := 0 to ( Length div sizeof( TStaticItem ) ) - 1 do
+ Data.Read( CacheEntry^[i], sizeof( TStaticItem ) );
+
+ Cache.Add(BlockId, CacheEntry);
+
+ StaticBlock := CacheEntry^;
+end;
+
+function TStaticReader.LastDataModification: TDateTime;
+begin
+ Result := ModifyTimeData;
+end;
+
+function TStaticReader.LastIndexModification: TDateTime;
+begin
+ Result := ModifyTimeIndex;
+end;
+
+end.
+
\ No newline at end of file
Added: trunk/WPGM/WPGM.cfg
===================================================================
--- trunk/WPGM/WPGM.cfg 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/WPGM.cfg 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,42 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J+
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q+
+-$R+
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$Y+
+-$Z1
+-cg
+-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+-H+
+-W+
+-M
+-$M16384,1048576
+-K$00400000
+-LE"c:\program files\borland\delphi7\Projects\Bpl"
+-LN"c:\program files\borland\delphi7\Projects\Bpl"
+-U"c:\program files\borland\delphi7\Lib\Debug;UOLib"
+-O"c:\program files\borland\delphi7\Lib\Debug;UOLib"
+-I"c:\program files\borland\delphi7\Lib\Debug;UOLib"
+-R"c:\program files\borland\delphi7\Lib\Debug;UOLib"
+-w-UNSAFE_TYPE
+-w-UNSAFE_CODE
+-w-UNSAFE_CAST
Added: trunk/WPGM/WPGM.dof
===================================================================
--- trunk/WPGM/WPGM.dof 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/WPGM.dof 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,139 @@
+[FileVersion]
+Version=7.0
+[Compiler]
+A=8
+B=0
+C=1
+D=1
+E=0
+F=0
+G=1
+H=1
+I=1
+J=1
+K=0
+L=1
+M=0
+N=1
+O=1
+P=1
+Q=1
+R=1
+S=0
+T=0
+U=0
+V=1
+W=0
+X=1
+Y=2
+Z=1
+ShowHints=1
+ShowWarnings=1
+UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+NamespacePrefix=
+SymbolDeprecated=1
+SymbolLibrary=1
+SymbolPlatform=1
+UnitLibrary=1
+UnitPlatform=1
+UnitDeprecated=1
+HResultCompat=1
+HidingMember=1
+HiddenVirtual=1
+Garbage=1
+BoundsError=1
+ZeroNilCompat=1
+StringConstTruncated=1
+ForLoopVarVarPar=1
+TypedConstVarPar=1
+AsgToTypedConst=1
+CaseLabelRange=1
+ForVariable=1
+ConstructingAbstract=1
+ComparisonFalse=1
+ComparisonTrue=1
+ComparingSignedUnsigned=1
+CombiningSignedUnsigned=1
+UnsupportedConstruct=1
+FileOpen=1
+FileOpenUnitSrc=1
+BadGlobalSymbol=1
+DuplicateConstructorDestructor=1
+InvalidDirective=1
+PackageNoLink=1
+PackageThreadVar=1
+ImplicitImport=1
+HPPEMITIgnored=1
+NoRetVal=1
+UseBeforeDef=1
+ForLoopVarUndef=1
+UnitNameMismatch=1
+NoCFGFileFound=1
+MessageDirective=1
+ImplicitVariants=1
+UnicodeToLocale=1
+LocaleToUnicode=1
+ImagebaseMultiple=1
+SuspiciousTypecast=1
+PrivatePropAccessor=1
+UnsafeType=0
+UnsafeCode=0
+UnsafeCast=0
+[Linker]
+MapFile=0
+OutputObjs=0
+ConsoleApp=1
+DebugInfo=0
+RemoteSymbols=0
+MinStackSize=16384
+MaxStackSize=1048576
+ImageBase=4194304
+ExeDescription=
+[Directories]
+OutputDir=
+UnitOutputDir=
+PackageDLLOutputDir=
+PackageDCPOutputDir=
+SearchPath=$(DELPHI)\Lib\Debug;UOLib
+Packages=Vcl50;Vclx50;VclSmp50;Qrpt50;Vcldb50;Vclbde50;ibevnt50;vcldbx50;TeeUI50;TeeDB50;Tee50;TeeQR50;VCLIB50;GR32_D5;Indy50;ThemeManager5;VirtualTreesD5
+Conditionals=
+DebugSourceDirs=
+UsePackages=0
+[Parameters]
+RunParams=
+HostApplication=
+Launcher=
+UseLauncher=0
+DebugCWD=
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=1031
+CodePage=1252
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
+[HistoryLists\hlUnitAliases]
+Count=1
+Item0=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+[HistoryLists\hlSearchPath]
+Count=2
+Item0=$(DELPHI)\Lib\Debug;UOLib
+Item1=UOLib
Added: trunk/WPGM/WPGM.dpr
===================================================================
--- trunk/WPGM/WPGM.dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/WPGM.dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,31 @@
+program WPGM;
+
+uses
+ Forms,
+ Main in 'Main.pas' {frmMain},
+ UOTiledata in 'UOLib\UOTiledata.pas',
+ UOUtilities in 'UOLib\UOUtilities.pas',
+ UOArt in 'UOLib\UOArt.pas',
+ uConfig in 'uConfig.pas',
+ UOHues in 'UOHues.pas',
+ uChooseHue in 'uChooseHue.pas' {frmChooseHue},
+ UOAnim in 'UOLib\UOAnim.pas',
+ uCenter in 'uCenter.pas' {frmCenter},
+ Overview in 'Overview.pas' {frmOverview},
+ Progress in 'Progress.pas' {frmProgress},
+ Spawnregions in 'Spawnregions.pas' {frmRegions},
+ uPatternColor in 'uPatternColor.pas' {frmPatternColor};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.Title := 'Wolfpack - GM Tool';
+ Application.CreateForm(TfrmMain, frmMain);
+ Application.CreateForm(TfrmChooseHue, frmChooseHue);
+ Application.CreateForm(TfrmCenter, frmCenter);
+ Application.CreateForm(TfrmOverview, frmOverview);
+ Application.CreateForm(TfrmRegions, frmRegions);
+ Application.CreateForm(TfrmPatternColor, frmPatternColor);
+ Application.Run;
+end.
Added: trunk/WPGM/WPGM.exe
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/WPGM.exe
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/WPGM.res
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/WPGM.res
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/WPGM.~dpr
===================================================================
--- trunk/WPGM/WPGM.~dpr 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/WPGM.~dpr 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,31 @@
+program WPGM;
+
+uses
+ Forms,
+ Main in 'Main.pas' {frmMain},
+ UOTiledata in 'UOLib\UOTiledata.pas',
+ UOUtilities in 'UOLib\UOUtilities.pas',
+ UOArt in 'UOLib\UOArt.pas',
+ uConfig in 'uConfig.pas',
+ UOHues in 'UOHues.pas',
+ uChooseHue in 'uChooseHue.pas' {frmChooseHue},
+ UOAnim in 'UOLib\UOAnim.pas',
+ uCenter in 'uCenter.pas' {frmCenter},
+ Overview in 'Overview.pas' {frmOverview},
+ Progress in 'Progress.pas' {frmProgress},
+ Spawnregions in 'Spawnregions.pas' {frmRegions},
+ uPatternColor in 'uPatternColor.pas' {frmPatternColor};
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.Title := 'Wolfpack - GM Tool';
+ Application.CreateForm(TfrmMain, frmMain);
+ Application.CreateForm(TfrmChooseHue, frmChooseHue);
+ Application.CreateForm(TfrmCenter, frmCenter);
+ Application.CreateForm(TfrmOverview, frmOverview);
+ Application.CreateForm(TfrmRegions, frmRegions);
+ Application.CreateForm(TfrmPatternColor, frmPatternColor);
+ Application.Run;
+end.
Added: trunk/WPGM/XMLReader.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/XMLReader.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/XMLReader.pas
===================================================================
--- trunk/WPGM/XMLReader.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/XMLReader.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,772 @@
+{:
+PURPOSE AND IMPLEMENTATION:
+ This unit defines classes for parsing a well-formed standalone XML document in
+ to a tree of nodes describing the data therein. These classes only support a
+ subset of the XML 1.0 recommendation and have not been analyzed for
+ conformance with the recommendation. This module also only supports 8-bit
+ character sets and makes no special allowances for UTF-8. Nor has any support
+ for the "<!DOCTYPE" node been implemented. Parsing of the XML declaration
+ lazily uses the attribute parsing code which is not correct (but works). This
+ module also freely trims element whitespace which is not always correct.
+
+ Q: Why use this module instead of Microsoft's XML parser or the OpenXML
+ project?
+
+ A: I wrote this module to be free of dependencies on outside libraries and to
+ be small and fast. Neither of the above libraries met that criteria. I
+ didn't like the idea of requiring my users to install Microsoft's XML
+ library (and the potential compatibility problems that arise). Nor did I
+ like the idea of adding 135 kb (OpenXML) to my executable just to load files
+ in XML format. Instead this unit only uses about 7 kb.
+
+ This was written for Delphi 5. It may work for other versions, but does
+ require method overloading which was introduced in Delphi 4.
+
+HISTORY:
+ 09/12/00 - Created by Colin Patrick Sarsfield
+
+DISCLAIMER:
+ Use at your own risk.
+
+COPYRIGHT:
+ Released into the public domain by Colin Sarsfield 9/13/00
+}
+unit XMLReader;
+
+interface
+
+uses
+ Classes;
+
+type
+ CharSet = set of Char;
+
+ TXMLNode = class;
+
+ TXMLNodeType = (xntDocument, xntElement, xntAttribute, xntProcessingInstruction,
+ xntXMLDeclaration);
+
+ TXMLReader = class
+ private
+ CurChar: Char;
+ function ParseAttribute(Node: TXMLNode): Boolean;
+ function ParseAttValue(var AttValue: String): Boolean;
+ function ParseCDSect(Node: TXMLNode): Boolean;
+ function ParseCharData(Node: TXMLNode): Boolean;
+ function ParseComment: Boolean;
+ procedure ParseContent(Node: TXMLNode);
+ procedure ParseDocTypeDecl(Node: TXMLNode);
+ function ParseElement(Node: TXMLNode): Boolean;
+ function ParseEq: Boolean;
+ function ParseETag(Node: TXMLNode): Boolean;
+ function ParseMisc(Node: TXMLNode): Boolean;
+ function ParseName(var Name: String): Boolean;
+ function ParseProcessingInstruction(Node: TXMLNode): Boolean;
+ function ParseProlog(Node: TXMLNode): Boolean;
+ function ParseReference: Char;
+ function ParseWhitespace: Boolean;
+ procedure ParseXMLDecl(Node: TXMLNode);
+ procedure ReportError(Err: String);
+ protected
+ function DoesStreamMatchString(Str: String): Boolean;
+ function EndOfData: Boolean; virtual; abstract;
+ procedure FreeState(State: TObject); virtual; abstract;
+ procedure ReadChar; virtual; abstract;
+ procedure ReadCharAndCheckForEnd;
+ procedure RestoreState(State: TObject); virtual; abstract;
+ function SaveState: TObject; virtual; abstract;
+ public
+ function ParseDocument: TXMLNode;
+ end;
+
+ TXMLStringReader = class(TXMLReader)
+ private
+ FData: String;
+ FPosition: Integer;
+ protected
+ function EndOfData: Boolean; override;
+ procedure FreeState(State: TObject); override;
+ procedure ReadChar; override;
+ procedure RestoreState(State: TObject); override;
+ function SaveState: TObject; override;
+ public
+ constructor Create(AData: String);
+ end;
+
+ TXMLNode = class
+ private
+ FData: String;
+ FName: String;
+ FNodes: TList;
+ FNodeType: TXMLNodeType;
+ function GetNodeCount: Integer;
+ function GetNodes(Index: Integer): TXMLNode;
+ function GetTotalNodeCount: Integer;
+ function GetAsInteger: Integer;
+ function GetAsSingle: Single;
+ function GetAsDateTime: TDateTime;
+ public
+ constructor Create; virtual;
+ destructor Destroy; override;
+
+ function AddNode(Node: TXMLNode): Integer;
+ function Description: String;
+ function FindNode(const Name: String; const Index: Integer): TXMLNode; overload;
+ function FindNode(const Name: String): TXMLNode; overload;
+ function FindNodeExc(const Name: String): TXMLNode;
+ function HasNode(const Name: String): Boolean;
+ procedure LookupBasicData(const Name: String; var LData: String); overload;
+ procedure LookupBasicData(const Name: String; var LData: TDateTime); overload;
+ procedure LookupBasicData(const Name: String; var LData: Integer); overload;
+ procedure LookupBasicData(const Name: String; var LData: Smallint); overload;
+ procedure LookupBasicData(const Name: String; var LData: Boolean); overload;
+ procedure LookupBasicData(const Name: String; var LData: Single); overload;
+ procedure LookupBasicData(const Name: String; LData: TStrings); overload;
+ procedure RemoveNode(Index: Integer); overload;
+ procedure RemoveNode(Node: TXMLNode); overload;
+
+ property AsDateTime: TDateTime read GetAsDateTime;
+ property AsInteger: Integer read GetAsInteger;
+ property AsSingle: Single read GetAsSingle;
+ property Data: String read FData write FData;
+ property Name: String read FName write FName;
+ property NodeCount: Integer read GetNodeCount;
+ property Nodes[Index: Integer]: TXMLNode read GetNodes;
+ property NodeType: TXMLNodeType read FNodeType write FNodeType;
+ property TotalNodeCount: Integer read GetTotalNodeCount;
+ end;
+
+const
+ TXMLNodeTypeStrings: array[TXMLNodeType] of String = ('Document', 'Element',
+ 'Attribute', 'ProcessingInstruction', 'XMLDeclaration');
+
+implementation
+
+uses
+ SysUtils, Strlib;
+
+const
+ LetterSet: CharSet = ['A'..'Z', 'a'..'z'];
+ WhitespaceSet: CharSet = [' ', #9, #10, #13];
+ CombiningCharSet: CharSet = [];
+ DigitSet: CharSet = ['0'..'9'];
+ ExtenderSet: CharSet = [#$b7];
+ FirstNameCharSet: CharSet = ['_', ':', 'A'..'Z', 'a'..'z'];
+var
+ NameCharSet: CharSet;
+
+type
+ TXMLStringReaderState = class
+ public
+ Position: Integer;
+ CurChar: Char;
+ end;
+
+{ TXMLNode }
+
+constructor TXMLNode.Create;
+begin
+ FNodes := TList.Create;
+end;
+
+destructor TXMLNode.Destroy;
+var
+ i: Integer;
+begin
+ inherited;
+ for i := 0 to Pred(NodeCount) do
+ Nodes[i].Free;
+ FNodes.Free;
+end;
+
+function TXMLNode.AddNode(Node: TXMLNode): Integer;
+begin
+ Result := FNodes.Add(Node)
+end;
+
+function TXMLNode.Description: String;
+begin
+ Result := Name + ': ' + TXMLNodeTypeStrings[NodeType];
+ if Data <> '' then
+ Result := Result + ' = ' + Data
+end;
+
+function TXMLNode.FindNode(const Name: String): TXMLNode;
+begin
+ Result := FindNode(Name, 0)
+end;
+
+function TXMLNode.FindNode(const Name: String;
+ const Index: Integer): TXMLNode;
+var
+ i, ThisIndex: Integer;
+begin
+ ThisIndex := 0;
+ for i := 0 to Pred(NodeCount) do
+ if Nodes[i].Name = Name then begin
+ if ThisIndex = Index then begin
+ Result := Nodes[i];
+ Exit;
+ end;
+ Inc(ThisIndex);
+ end;
+ Result := nil;
+end;
+
+function TXMLNode.FindNodeExc(const Name: String): TXMLNode;
+begin
+ Result := FindNode(Name, 0);
+ if Result = nil then
+ raise Exception.Create('Node "' + Name + '" not found');
+end;
+
+function TXMLNode.GetAsDateTime: TDateTime;
+begin
+ Result := StrToDateTime(Data)
+end;
+
+function TXMLNode.GetAsInteger: Integer;
+begin
+ try
+ Result := StrToInt(Data);
+ except
+ raise Exception.Create('Node "' + Name + '" does not contain a valid integer');
+ end;
+end;
+
+function TXMLNode.GetAsSingle: Single;
+begin
+ try
+ Result := StrToFloat(Data);
+ except
+ raise Exception.Create('Node "' + Name + '" does not contain a valid floating point value');
+ end;
+end;
+
+function TXMLNode.GetNodeCount: Integer;
+begin
+ Result := FNodes.Count
+end;
+
+function TXMLNode.GetNodes(Index: Integer): TXMLNode;
+begin
+ Result := TXMLNode(FNodes[Index])
+end;
+
+function TXMLNode.GetTotalNodeCount: Integer;
+var
+ i: Integer;
+begin
+ Result := 1;
+ for i := 0 to Pred(NodeCount) do
+ Result := Result + Nodes[i].TotalNodeCount;
+end;
+
+function TXMLNode.HasNode(const Name: String): Boolean;
+begin
+ Result := FindNode(Name, 0) <> nil
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: String);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.Data
+ else
+ LData := ''
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: TDateTime);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsDateTime
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String;
+ var LData: Smallint);
+var
+ L: Integer;
+begin
+ LookupBasicData(Name, L);
+ LData := L
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Integer);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsInteger
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Boolean);
+begin
+ LData := HasNode(Name)
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; var LData: Single);
+var
+ Node: TXMLNode;
+begin
+ Node := FindNode(Name);
+ if Node <> nil then
+ LData := Node.AsSingle
+ else
+ LData := 0
+end;
+
+procedure TXMLNode.LookupBasicData(const Name: String; LData: TStrings);
+var
+ i: Integer;
+ Node, SubNode: TXMLNode;
+begin
+ LData.Clear;
+ Node := FindNode(Name);
+ if Node = nil then Exit;
+ for i := 0 to Pred(Node.NodeCount) do begin
+ SubNode := Node.Nodes[i];
+ if (SubNode.Name = 'S') and (SubNode.NodeType = xntElement) then
+ LData.Add(SubNode.Data);
+ end;
+end;
+
+procedure TXMLNode.RemoveNode(Index: Integer);
+begin
+ RemoveNode(Nodes[Index])
+end;
+
+procedure TXMLNode.RemoveNode(Node: TXMLNode);
+begin
+ FNodes.Remove(Node);
+end;
+
+{ TXMLStringReader }
+
+constructor TXMLStringReader.Create(AData: String);
+begin
+ FPosition := 1;
+ FData := AData;
+end;
+
+function TXMLStringReader.EndOfData: Boolean;
+begin
+ Result := FPosition > Length(FData)
+end;
+
+procedure TXMLStringReader.FreeState(State: TObject);
+begin
+ State.Free;
+end;
+
+procedure TXMLStringReader.ReadChar;
+begin
+ if FPosition > Length(FData) then
+ CurChar := #0
+ else begin
+ CurChar := FData[FPosition];
+ Inc(FPosition)
+ end
+end;
+
+procedure TXMLStringReader.RestoreState(State: TObject);
+var
+ XSRState: TXMLStringReaderState;
+begin
+ XSRState := (State as TXMLStringReaderState);
+ FPosition := XSRState.Position;
+ CurChar := XSRState.CurChar;
+end;
+
+function TXMLStringReader.SaveState: TObject;
+var
+ XSRState: TXMLStringReaderState;
+begin
+ XSRState := TXMLStringReaderState.Create;
+ XSRState.Position := FPosition;
+ XSRState.CurChar := CurChar;
+ Result := XSRState;
+end;
+
+{ TXMLReader }
+
+function TXMLReader.DoesStreamMatchString(Str: String): Boolean;
+var
+ i: Integer;
+ State: TObject;
+begin
+ if Str = '' then begin Result := False; Exit end;
+ State := SaveState;
+ i := 1;
+ repeat
+ Result := Str[i] = CurChar;
+ Inc(i);
+ ReadChar;
+ until (not Result) or EndOfData or (i > Length(Str));
+
+ if not Result then
+ RestoreState(State);
+ FreeState(State);
+end;
+
+
+function TXMLReader.ParseAttribute(Node: TXMLNode): Boolean;
+var
+ Name, AttValue: String;
+ ThisNode: TXMLNode;
+begin
+ Result := False;
+ if not ParseName(Name) then Exit;
+ if not ParseEq then
+ ReportError('Equals sign missing in attribute');
+ if not ParseAttValue(AttValue) then
+ ReportError('Attribute "' + Name + '" missing value');
+ ThisNode := TXMLNode.Create;
+ ThisNode.NodeType := xntAttribute;
+ ThisNode.Name := Name;
+ ThisNode.Data := AttValue;
+ Node.AddNode(ThisNode);
+ Result := True;
+end;
+
+function TXMLReader.ParseAttValue(var AttValue: String): Boolean;
+var
+ QuoteChar: Char;
+begin
+ QuoteChar := CurChar;
+ Result := False;
+ if not (CurChar in ['"', '''']) then Exit;
+ ReadCharAndCheckForEnd;
+
+ while CurChar <> QuoteChar do begin
+ if CurChar = '<' then
+ ReportError('Invalid character "' + CurChar + '" in attribute value')
+ else if CurChar = '&' then
+ CurChar := ParseReference;
+ AttValue := AttValue + CurChar;
+ ReadCharAndCheckForEnd;
+ end;
+ ReadCharAndCheckForEnd;
+ Result := True;
+end;
+
+function TXMLReader.ParseCDSect(Node: TXMLNode): Boolean;
+var
+ CData: String;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<![CDATA[') then Exit;
+ repeat
+ CData := CData + CurChar;
+ ReadCharAndCheckForEnd;
+ until Right(CData, 3) = ']]>';
+ Node.Data := Node.Data + Left(CData, Length(CData) - 3);
+ Result := True;
+end;
+
+function TXMLReader.ParseCharData(Node: TXMLNode): Boolean;
+var
+ CharData: String;
+begin
+ while not (CurChar in ['<', '&', #0]) do begin
+ CharData := CharData + CurChar;
+ ReadChar;
+ end;
+ if Pos(']]>', CharData) <> 0 then
+ ReportError('Character data cannot contain "]]>"');
+ Node.Data := Node.Data + CharData;
+ Result := CharData <> '';
+end;
+
+function TXMLReader.ParseComment: Boolean;
+var
+ Comment: String;
+ Terminated: Boolean;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<!--') then Exit;
+ repeat
+ Comment := Comment + CurChar;
+ Terminated := Right(Comment, 3) = '-->';
+ if EndOfData then Break;
+ ReadChar;
+ until Terminated;
+ if Right(Comment, 4) = '--->' then
+ ReportError('Comments cannot end in "--->"');
+ Result := True;
+end;
+
+procedure TXMLReader.ParseContent(Node: TXMLNode);
+var
+ FoundContent: Boolean;
+begin
+ repeat
+ FoundContent := True;
+ if ParseCDSect(Node) then
+ else if ParseProcessingInstruction(Node) then
+ else if ParseComment then
+ else if ParseElement(Node) then
+ else if ParseCharData(Node) then
+ else if CurChar = '&' then
+ Node.Data := Node.Data + ParseReference
+ else
+ FoundContent := False;
+ until not FoundContent;
+end;
+
+procedure TXMLReader.ParseDocTypeDecl(Node: TXMLNode);
+begin
+ if not DoesStreamMatchString('<!DOCTYPE') then Exit;
+ ReportError('DocTypeDecl parsing not yet implemented');
+end;
+
+function TXMLReader.ParseDocument: TXMLNode;
+begin
+ ReadCharAndCheckForEnd;
+ Result := TXMLNode.Create;
+ Result.Name := '';
+ Result.NodeType := xntDocument;
+ if not ParseProlog(Result) then
+ ReportError('Missing prolog');
+ if not ParseElement(Result) then
+ ReportError('Missing element');
+ while ParseMisc(Result) do
+ ;
+end;
+
+function TXMLReader.ParseElement(Node: TXMLNode): Boolean;
+var
+ Name: String;
+ ThisNode: TXMLNode;
+ State: TObject;
+begin
+ Result := False;
+ if CurChar <> '<' then Exit;
+ State := SaveState;
+ ReadCharAndCheckForEnd;
+ if not ParseName(Name) then begin
+ RestoreState(State);
+ FreeState(State);
+ Exit;
+ end;
+
+ FreeState(State);
+
+ ThisNode := TXMLNode.Create;
+ Node.AddNode(ThisNode);
+ try
+ ThisNode.Name := Name;
+ ThisNode.NodeType := xntElement;
+ repeat
+ ParseWhitespace;
+ until not ParseAttribute(ThisNode);
+
+ if CurChar = '/' then begin
+ // EmptyElemTag
+ ReadCharAndCheckForEnd;
+ if CurChar <> '>' then
+ ReportError('Tag not terminated properly');
+ ReadCharAndCheckForEnd;
+ end else if CurChar = '>' then begin
+ // STag
+ ReadCharAndCheckForEnd;
+ ParseContent(ThisNode);
+ ThisNode.Data := TrimChars(ThisNode.Data, [' ', #9, #13, #10]);
+ if not ParseETag(ThisNode) then
+ ReportError('No ending tag for ' + Name);
+ end else
+ ReportError('Tag not terminated properly');
+ except
+ Node.RemoveNode(ThisNode);
+ ThisNode.Free;
+ raise;
+ end;
+ Result := True;
+end;
+
+function TXMLReader.ParseEq: Boolean;
+begin
+ ParseWhitespace;
+ Result := CurChar = '=';
+ ReadCharAndCheckForEnd;
+ ParseWhitespace;
+end;
+
+function TXMLReader.ParseETag(Node: TXMLNode): Boolean;
+var
+ Name: String;
+begin
+ Result := False;
+ if not DoesStreamMatchString('</') then Exit;
+ if not ParseName(Name) then Exit;
+ if Name <> Node.Name then
+ ReportError('End tag name "' + Name + '" does not match start tag name "' + Node.Name + '"');
+ ParseWhitespace;
+ if CurChar <> '>' then
+ ReportError('End tag missing ">"');
+ ReadChar;
+ Result := True;
+end;
+
+function TXMLReader.ParseMisc(Node: TXMLNode): Boolean;
+begin
+ Result := ParseWhitespace;
+ if Result then Exit;
+ Result := ParseComment;
+ if Result then Exit;
+ Result := ParseProcessingInstruction(Node);
+end;
+
+function TXMLReader.ParseName(var Name: String): Boolean;
+begin
+ Result := False;
+ if not (CurChar in FirstNameCharSet) then Exit;
+ Result := True;
+ Name := '';
+ repeat
+ Name := Name + CurChar;
+ ReadCharAndCheckForEnd;
+ until not (CurChar in NameCharSet);
+end;
+
+function TXMLReader.ParseProcessingInstruction(Node: TXMLNode): Boolean;
+var
+ Name, Chars: String;
+ ThisNode: TXMLNode;
+ Terminated: Boolean;
+begin
+ Result := False;
+ if not DoesStreamMatchString('<?') then Exit;
+ if not ParseName(Name) then
+ ReportError('Processing instruction does not contain valid name');
+ if Name = 'xml' then
+ ReportError('Processing instruction cannot have the reserved name "xml"');
+ ThisNode := TXMLNode.Create;
+ try
+ ThisNode.Name := Name;
+ ThisNode.NodeType := xntProcessingInstruction;
+ ParseWhitespace;
+ repeat
+ Chars := Chars + CurChar;
+ Terminated := Right(Chars, 2) = '?>';
+ if EndOfData then break;
+ ReadChar;
+ until Terminated;
+ if not Terminated then
+ ReportError('Unterminated processing instruction');
+ ThisNode.Data := Left(Chars, Length(Chars) - 2);
+ except
+ ThisNode.Free;
+ raise;
+ end;
+ Node.AddNode(ThisNode);
+ Result := True;
+end;
+
+function TXMLReader.ParseProlog(Node: TXMLNode): Boolean;
+begin
+ ParseXMLDecl(Node);
+ while ParseMisc(Node) do
+ ;
+ ParseDocTypeDecl(Node);
+ while ParseMisc(Node) do
+ ;
+ Result := True;
+end;
+
+function TXMLReader.ParseReference: Char;
+var
+ RefStr: String;
+begin
+ Result := #0; // silence compiler warning
+ if CurChar <> '&' then
+ ReportError('All references must begin with "&"');
+ ReadCharAndCheckForEnd;
+ while CurChar <> ';' do begin
+ RefStr := RefStr + CurChar;
+ ReadCharAndCheckForEnd;
+ end;
+ if Left(RefStr, 2) = '#x' then
+ try
+ Result := Chr(StrToInt('$' + Right(RefStr, Length(RefStr) - 2)));
+ except
+ ReportError('Invalid integer in reference &' + RefStr + ';');
+ end
+ else if Left(RefStr, 1) = '#' then
+ try
+ Result := Chr(StrToInt(Right(RefStr, Length(RefStr) - 1)));
+ except
+ ReportError('Invalid integer in reference &' + RefStr + ';');
+ end
+ else if RefStr = 'amp' then
+ Result := '&'
+ else if RefStr = 'lt' then
+ Result := '<'
+ else if RefStr = 'gt' then
+ Result := '>'
+ else if RefStr = 'quot' then
+ Result := '"'
+ else if RefStr = 'apos' then
+ Result := ''''
+ else
+ ReportError('Unrecognized reference');
+
+ ReadCharAndCheckForEnd;
+end;
+
+function TXMLReader.ParseWhitespace: Boolean;
+begin
+ Result := False;
+ while (CurChar in [' ', #13, #10, #9]) do begin
+ Result := True;
+ ReadChar;
+ if EndOfData then Exit;
+ end;
+end;
+
+procedure TXMLReader.ParseXMLDecl(Node: TXMLNode);
+var
+ ThisNode: TXMLNode;
+begin
+ if not DoesStreamMatchString('<?xml') then Exit;
+ ThisNode := TXMLNode.Create;
+ ThisNode.NodeType := xntXMLDeclaration;
+ try
+ repeat
+ ParseWhitespace;
+ until not ParseAttribute(ThisNode);
+ ParseWhitespace;
+ if not DoesStreamMatchString('?>') then
+ ReportError('XML declaration not terminated with "?>"');
+ except
+ ThisNode.Free;
+ raise;
+ end;
+ Node.AddNode(ThisNode);
+end;
+
+procedure TXMLReader.ReadCharAndCheckForEnd;
+begin
+ if EndOfData then
+ ReportError('Unexpected end of data');
+ ReadChar;
+end;
+
+procedure TXMLReader.ReportError(Err: String);
+begin
+ raise Exception.Create(Err);
+end;
+
+initialization
+ NameCharSet := LetterSet + CombiningCharSet + DigitSet + ExtenderSet
+ + ['.', '-', '_', ':'];
+end.
Added: trunk/WPGM/arrow-down.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/arrow-down.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/arrow-up.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/arrow-up.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/categories.db
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/categories.db
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/categories.zip
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/categories.zip
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/config.ini
===================================================================
--- trunk/WPGM/config.ini 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/config.ini 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,78 @@
+[General]
+Command Prefix=.
+Tiledata.mul Path=C:\Games\Ultima Online\tiledata.mul
+Art.mul Path=C:\Games\Ultima Online\Ancient Realms\art.mul
+Artidx.mul Path=C:\Games\Ultima Online\Ancient Realms\artidx.mul
+Anim2.idx Path=C:\Games\Ultima Online\anim2.idx
+Anim2.mul Path=C:\Games\Ultima Online\anim2.mul
+Anim3.idx Path=C:\Games\Ultima Online\anim3.idx
+Anim3.mul Path=C:\Games\Ultima Online\anim3.mul
+Bodyconv.def Path=C:\Games\Ultima Online\bodyconv.def
+Body.def Path=C:\Games\Ultima Online\body.def
+Anim.mul Path=C:\Games\Ultima Online\anim.mul
+Anim.idx Path=C:\Games\Ultima Online\anim.idx
+Radarcol.mul Path=C:\Games\Ultima Online\Ancient Realms\radarcol.mul
+Hues.mul Path=C:\Games\Ultima Online\Ancient Realms\hues.mul
+Map0.mul Path=C:\Games\Ultima Online\Ancient Realms\map0.mul
+Statics0.mul Path=C:\Games\Ultima Online\Ancient Realms\statics0.mul
+Staidx0.mul Path=C:\Games\Ultima Online\Ancient Realms\staidx0.mul
+Map2.mul Path=C:\Games\Ultima Online\map2.mul
+Statics2.mul Path=C:\Games\Ultima Online\statics2.mul
+Staidx2.mul Path=C:\Games\Ultima Online\staidx2.mul
+Map3.mul Path=C:\Games\Ultima Online\map3.mul
+Statics3.mul Path=C:\Games\Ultima Online\statics3.mul
+Staidx3.mul Path=C:\Games\Ultima Online\staidx3.mul
+Map4.mul Path=C:\Games\Ultima Online\map4.mul
+Window Position X=253
+Window Position Y=388
+Window Width=773
+Window Height=248
+Current Page=8
+Always On Top=1
+Map0Modify=17.02.2005 03:55:50
+Statics0Modify=17.02.2005 03:55:52
+Staidx0Modify=17.02.2005 03:55:52
+Map2Modify=25.09.2004 16:02:36
+Statics2Modify=25.09.2004 16:02:52
+Staidx2Modify=25.09.2004 16:02:48
+Map3Modify=06.01.2003 11:18:34
+Statics3Modify=09.01.2003 15:15:28
+Staidx3Modify=09.01.2003 15:15:28
+Map4Modify=31.08.2004 01:06:14
+Statics4Modify=30.12.1899 20:54:43
+Staidx4Modify=30.12.1899 20:54:43
+Statics4.mul Path=C:\Games\Ultima Online\statics4.mul
+Staidx4.mul Path=C:\Games\Ultima Online\staidx4.mul
+Map1Modify=20.02.2005 16:54:50
+Statics1Modify=20.02.2005 16:54:50
+Staidx1Modify=20.02.2005 16:54:50
+SpawnRadius=10
+SpawnMin=15
+SpawnMax=25
+EventCount=20
+CustomButtonCount=2
+CustomButton0=smove -5
+CustomButton1=
+CustomButton2=
+CustomButton3=
+Event0=qwdqwdqwd
+Event1=f123f143f
+Event2=44g4g4vv
+Event3=321f13f
+Event4=qwdqwdqwd
+Event5=f123f143f
+Event6=44g4g4vv
+Event7=321f13f
+Event8=qwdqwdqwd
+Event9=f123f143f
+Event10=44g4g4vv
+Event11=321f13f
+Event12=qwdqwdqwd
+Event13=f123f143f
+Event14=44g4g4vv
+Event15=321f13f
+Event16=qwdqwdqwd
+Event17=f123f143f
+Event18=44g4g4vv
+Event19=321f13f
+
Added: trunk/WPGM/globe.gif
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/globe.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/import.pl
===================================================================
--- trunk/WPGM/import.pl 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/import.pl 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,163 @@
+
+use XML::DOM;
+use Data::Dumper;
+use strict;
+
+my %items; # Item Definition Storage
+
+sub deep_copy
+{
+ my $this = shift;
+
+ if( not ref $this )
+ {
+ $this;
+ }
+ elsif( ref $this eq "ARRAY" )
+ {
+ [ map deep_copy( $_ ), @$this ];
+ }
+ elsif( ref $this eq "HASH" )
+ {
+ +{ map { $_ => deep_copy( $this->{ $_ } ) } keys %$this };
+ }
+ else
+ {
+ die "what type is $_?"
+ }
+}
+
+sub parseFile
+{
+ my $basepath = shift;
+ my $filename = shift;
+
+ print "Loading $filename...\n";
+
+ my $parser = new XML::DOM::Parser;
+ my $doc = $parser->parsefile( $basepath . $filename );
+
+ my $definitions = ( $doc->getElementsByTagName( 'definitions', 0 ) )[0];
+
+ for( my $node = $definitions->getFirstChild(); defined( $node ); $node = $node->getNextSibling() )
+ {
+ my $name = $node->getNodeName();
+
+ # Include another file
+ if( $name eq 'include' )
+ {
+ my $file = $node->getAttribute( 'file' );
+ parseFile( $basepath, $file );
+ }
+ elsif( $name eq 'item' )
+ {
+ my $id = $node->getAttribute( 'id' );
+
+ $items{ $id } = $node->cloneNode( 1 );
+ }
+ }
+
+ $doc->dispose();
+}
+
+parseFile( 'D:/Wolfpack/', 'definitions.xml' );
+
+my %categories;
+my $lastid = 1;
+
+sub resolveSubNode
+{
+ my $item = shift;
+ my $nodename = shift;
+
+ my @subnodes = $item->getElementsByTagName( $nodename, 0 );
+
+ if( $#subnodes >= 0 )
+ {
+ # Return the last one
+ return $subnodes[-1];
+ }
+
+ # Search and resolve inherit tags
+ my @inherit = $item->getElementsByTagName( 'inherit', 0 );
+
+ foreach my $node ( @inherit )
+ {
+ if( !defined( $node->getAttribute( $nodename ) ) )
+ {
+ next;
+ }
+
+ my $inheritfrom = $items{ $node->getAttribute( 'id' ) };
+ my $subnode = resolveSubNode( $inheritfrom, $nodename );
+
+ if( defined( $subnode ) )
+ {
+ return $subnode;
+ }
+ }
+
+ return undef;
+}
+
+foreach my $key( keys %items )
+{
+ my $node = $items{ $key };
+
+ my $category = ( $node->getElementsByTagName( 'category', 0 ) )[0];
+
+ if( !defined( $category ) )
+ {
+ next;
+ }
+
+ $category = $category->getFirstChild()->toString() . "\n";
+
+ if( !exists $categories{ $category } )
+ {
+ $categories{ $category } = $lastid;
+ $lastid++;
+ }
+
+ # Next: Display Id
+ my $dispidnode = resolveSubNode( $node, 'id' );
+
+ if( !defined( $dispidnode ) )
+ {
+ print "Missing Display Tag for Item " . $key . "\n";
+ next;
+ }
+
+ my $dispid = $dispidnode->getFirstChild()->toString();
+
+ my $color = 0;
+
+ my $colornode = resolveSubNode( $node, 'color' );
+
+ if( defined( $colornode ) )
+ {
+ $color = $colornode->getFirstChild()->toString();
+ }
+
+ my $name = 'NULL';
+
+ my $namenode = resolveSubNode( $node, 'name' );
+
+ if( defined( $namenode ) )
+ {
+ $name = "'" . $namenode->getFirstChild()->toString() . "'";
+ }
+
+ if( lc( substr( $dispid, 0, 2 ) ) eq '0x' )
+ {
+ $dispid = hex( substr( $dispid, 2, length( $dispid ) - 2 ) );
+ }
+
+ if( lc( substr( $color, 0, 2 ) ) eq '0x' )
+ {
+ $color = hex( substr( $color, 2, length( $color ) - 2 ) );
+ }
+
+ my $sql = sprintf( "INSERT INTO items VALUES(NULL,%s,%u,%u,%u,'%s');", $name, $categories{ $category }, int( $dispid ), int( $color ), $key );
+ print $sql."\n";
+}
Added: trunk/WPGM/import.py
===================================================================
--- trunk/WPGM/import.py 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/import.py 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,276 @@
+
+## Try 2
+## Python Import Script
+##
+
+basepath = 'C:/Wolfpack/'
+files = ['ancientrealms/index.xml', 'definitions.xml']
+
+print "DELETE FROM categories;"
+print "DELETE FROM items;"
+print "DELETE FROM locationcategories;"
+print "DELETE FROM locations;"
+
+import sys
+import xml.dom.minidom
+from xml.parsers.expat import ExpatError
+
+categories = {}
+items = {}
+lastcategory = 0
+
+locations = {}
+locationcategories = {}
+lastlocationcategory = 0
+
+def escapestring( string ):
+ return string.replace( "'", "''" )
+
+def hex2dec( string ):
+ if string.lower().startswith( '0x' ):
+ return int( string[2:], 16 )
+ else:
+ return int( string )
+
+def processLocation(location, node):
+ global lastlocationcategory
+
+ category = node.getAttribute('category')
+
+ if not category:
+ return location
+
+ location['categoryname'] = escapestring(category)
+
+ # Remove everything until and including the last '\'
+ category = category[:category.rfind('\\')]
+
+ if not locationcategories.has_key(category):
+ lastlocationcategory += 1
+ locationcategories[category] = lastlocationcategory
+
+ location['category'] = locationcategories[category]
+
+ position = node.firstChild.nodeValue
+ position = position.split(',')
+
+ if len(position) >= 1:
+ location['posx'] = int(position[0])
+ if len(position) >= 2:
+ location['posy'] = int(position[1])
+ if len(position) >= 3:
+ location['posz'] = int(position[2])
+ if len(position) >= 4:
+ location['posmap'] = int(position[3])
+
+ return location
+
+def processItem( item, node ):
+ global lastcategory
+
+ # Parse Node and modify item appropiately
+ for element in node.childNodes:
+ if element.nodeType != element.ELEMENT_NODE:
+ continue
+
+ if element.nodeName == 'id':
+ if not element.firstChild or element.firstChild.nodeType != element.TEXT_NODE:
+ continue
+
+ item[ 'dispid' ] = hex2dec( element.firstChild.nodeValue )
+
+ elif element.nodeName == 'name':
+ if not element.firstChild or element.firstChild.nodeType != element.TEXT_NODE:
+ continue
+
+ item[ 'name' ] = escapestring( element.firstChild.nodeValue )
+
+ elif element.nodeName == 'color':
+ if element.firstChild and element.firstChild.nodeType == element.TEXT_NODE:
+ item[ 'color' ] = hex2dec( element.firstChild.nodeValue )
+
+ elif element.nodeName == 'category':
+ if element.firstChild and element.firstChild.nodeType == element.TEXT_NODE:
+ category = element.firstChild.nodeValue
+ item[ 'categoryname' ] = escapestring( category )
+
+ # Remove everything until and including the last '\'
+ category = category[:category.rfind('\\')]
+
+ if not categories.has_key( category ):
+ lastcategory += 1
+ categories[ category ] = lastcategory
+
+ item[ 'category' ] = categories[ category ]
+
+ # Inherit another node's properties
+ elif element.nodeName == 'inherit':
+ id = element.getAttribute( 'id' )
+
+ if id and items.has_key( id ):
+ try:
+ item = processItem( item, items[ id ] )
+ except:
+ raise Exception, 'Error processing item id: ' + id
+
+ return item
+
+def parseFile( basepath, filename ):
+ global items
+
+ #print "Parsing " + filename
+
+ try:
+ dom = xml.dom.minidom.parse( basepath + filename )
+ except:
+ print "An Error occured while parsing " + filename + "."
+ raise
+
+ # Safety Thing
+ assert dom.documentElement.tagName == "definitions"
+
+ for element in dom.documentElement.childNodes:
+ if element.nodeType != element.ELEMENT_NODE:
+ continue
+
+ # Include Processing
+ if element.nodeName == 'include':
+ parseFile( basepath, element.getAttribute( 'file' ) )
+
+ # Item Processing
+ elif element.nodeName == 'item':
+ id = element.getAttribute( 'id' )
+
+ if not id:
+ continue
+
+ # Start Processing the Item before we insert it into our map
+ items[ id ] = element.cloneNode( 1 )
+
+ elif element.nodeName == 'location':
+ id = element.getAttribute('id')
+ if not id:
+ continue
+ locations[id] = element.cloneNode(1)
+
+ dom.unlink() # Forced Cleanup
+
+for file in files:
+ parseFile(basepath, file)
+
+processed = {}
+
+for ( key, element ) in locations.items():
+ location = {
+ 'id': key,
+ 'name': None,
+ 'posx': 0,
+ 'posy': 0,
+ 'posz': 0,
+ 'posmap': 0,
+ 'category': 0,
+ 'categoryname': None
+ }
+
+ location = processLocation(location, element)
+
+ if not location['categoryname']:
+ continue
+
+ location['name'] = "'" + location[ 'categoryname' ][location['categoryname'].rfind('\\')+1:] + "'"
+
+ #print "INSERT INTO items VALUES(NULL,%s,%u,%u,%u,'%s');" % ( item[ 'name' ], item[ 'category' ], item[ 'dispid' ], item[ 'color' ], item[ 'id' ] )
+ print "INSERT INTO locations VALUES(NULL,%s,%u,%u,%u,%d,%u,'%s');" % (location['name'], location['category'], location['posx'], location['posy'], location['posz'], location['posmap'], location['id'])
+
+# Split and Process Category Tags (2-pass)
+for ( category, id ) in locationcategories.items():
+ if category.find( '\\' ) < 0:
+ continue
+
+ parent_name = category[ : category.rfind('\\') ]
+
+ # Create the Parent Categories if they don't exist
+ while len( parent_name ) > 0:
+ if not locationcategories.has_key( parent_name ):
+ lastlocationcategory += 1
+ locationcategories[ parent_name ] = lastlocationcategory
+
+ if parent_name.rfind('\\') < 0:
+ break
+
+ parent_name = parent_name[:parent_name.rfind('\\')]
+
+for ( category, id ) in locationcategories.items():
+ if category.rfind('\\') == -1:
+ parent_name = None
+ else:
+ parent_name = category[:category.rfind('\\')]
+
+ if not parent_name:
+ parent_id = 0
+ else:
+ parent_id = locationcategories[ parent_name ]
+
+ # Last Part only
+ if category.find( '\\' ) >= 0:
+ category = category[category.rfind('\\')+1:]
+
+ print "INSERT INTO locationcategories VALUES(%u,'%s',%u,0);" % ( id, category, parent_id )
+
+for ( key, element ) in items.items():
+ # Initialize Item Structure
+ item = {
+ 'id': key,
+ 'name': None,
+ 'color': 0,
+ 'dispid': 0,
+ 'category': 0,
+ 'categoryname': None
+ }
+
+ item = processItem( item, element )
+
+ if not item[ 'categoryname' ]:
+ continue
+
+ if item[ 'name' ]:
+ item[ 'name' ] = "'%s'" % item[ 'name' ]
+ else:
+ item[ 'name' ] = "'" + item[ 'categoryname' ][item[ 'categoryname' ].rfind('\\')+1:] + "'"
+
+ print "INSERT INTO items VALUES(NULL,%s,%u,%u,%u,'%s');" % ( item[ 'name' ], item[ 'category' ], item[ 'dispid' ], item[ 'color' ], item[ 'id' ] )
+
+# Split and Process Category Tags (2-pass)
+for ( category, id ) in categories.items():
+ if category.find( '\\' ) < 0:
+ continue
+
+ parent_name = category[ : category.rfind('\\') ]
+
+ # Create the Parent Categories if they don't exist
+ while len( parent_name ) > 0:
+ if not categories.has_key( parent_name ):
+ lastcategory += 1
+ categories[ parent_name ] = lastcategory
+
+ if parent_name.rfind('\\') < 0:
+ break
+
+ parent_name = parent_name[:parent_name.rfind('\\')]
+
+for ( category, id ) in categories.items():
+ if category.rfind('\\') == -1:
+ parent_name = None
+ else:
+ parent_name = category[:category.rfind('\\')]
+
+ if not parent_name:
+ parent_id = 0
+ else:
+ parent_id = categories[ parent_name ]
+
+ # Last Part only
+ if category.find( '\\' ) >= 0:
+ category = category[category.rfind('\\')+1:]
+
+ print "INSERT INTO categories VALUES(%u,'%s',%u,0);" % ( id, category, parent_id )
Added: trunk/WPGM/log.txt
===================================================================
--- trunk/WPGM/log.txt 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/log.txt 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,8504 @@
+INSERT INTO items VALUES(NULL,'Fancy Shirt (N/S)',1,7933,0,'1efd');
+INSERT INTO items VALUES(NULL,'Fancy Shirt (W/E)',1,7934,0,'1efe');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 15',2,7804,0,'1e7c');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 14',2,7803,0,'1e7b');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 13',2,7802,0,'1e7a');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 18',2,7807,0,'1e7f');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 17',2,7806,0,'1e7e');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 16',2,7805,0,'1e7d');
+INSERT INTO items VALUES(NULL,'bone harvester',3,9915,0,'26bb');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 12',2,7801,0,'1e79');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 11',2,7800,0,'1e78');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 6',2,7795,0,'1e73');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 5',2,7794,0,'1e72');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 4',2,7793,0,'1e71');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 3',2,7792,0,'1e70');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 10',2,7799,0,'1e77');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 9',2,7798,0,'1e76');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 8',2,7797,0,'1e75');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 7',2,7796,0,'1e74');
+INSERT INTO items VALUES(NULL,'Vines 3 (3/4)',4,3458,0,'d82');
+INSERT INTO items VALUES(NULL,'scepter',5,9916,0,'26bc');
+INSERT INTO items VALUES(NULL,'Vines 3 (2/4)',4,3457,0,'d81');
+INSERT INTO items VALUES(NULL,'Wall 21',6,624,0,'270');
+INSERT INTO items VALUES(NULL,'Wall 22',6,625,0,'271');
+INSERT INTO items VALUES(NULL,'Wall 23',6,626,0,'272');
+INSERT INTO items VALUES(NULL,'Wall 24',6,627,0,'273');
+INSERT INTO items VALUES(NULL,'Wall 25',6,628,0,'274');
+INSERT INTO items VALUES(NULL,'Wall 26',6,629,0,'275');
+INSERT INTO items VALUES(NULL,'Wall 27',6,630,0,'276');
+INSERT INTO items VALUES(NULL,'Wall 1',7,631,0,'277');
+INSERT INTO items VALUES(NULL,'Wall 2',7,632,0,'278');
+INSERT INTO items VALUES(NULL,'Wall 3',7,633,0,'279');
+INSERT INTO items VALUES(NULL,'Mast 1',8,15959,0,'3e57');
+INSERT INTO items VALUES(NULL,'Dragon Prow 8',9,15958,0,'3e56');
+INSERT INTO items VALUES(NULL,'Tiller Man 12',10,15957,0,'3e55');
+INSERT INTO items VALUES(NULL,'Wood 5',11,7045,0,'1b85');
+INSERT INTO items VALUES(NULL,'Wood 4',11,7044,0,'1b84');
+INSERT INTO items VALUES(NULL,'Wood 7',11,7047,0,'1b87');
+INSERT INTO items VALUES(NULL,'Tiller Man 11',10,15956,0,'3e54');
+INSERT INTO items VALUES(NULL,'Wood 1',11,7041,0,'1b81');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 12',12,7040,0,'1b80');
+INSERT INTO items VALUES(NULL,'Wood 3',11,7043,0,'1b83');
+INSERT INTO items VALUES(NULL,'Brush 1 (N/S)',13,4977,0,'1371');
+INSERT INTO items VALUES(NULL,'Tiller Man 10',10,15955,0,'3e53');
+INSERT INTO items VALUES(NULL,'Wood 9',11,7049,0,'1b89');
+INSERT INTO items VALUES(NULL,'Wood 8',11,7048,0,'1b88');
+INSERT INTO items VALUES(NULL,'Tiller Man 9',10,15954,0,'3e52');
+INSERT INTO items VALUES(NULL,'Wall 4',7,634,0,'27a');
+INSERT INTO items VALUES(NULL,'Wall 5',7,635,0,'27b');
+INSERT INTO items VALUES(NULL,'Wall 6',7,636,0,'27c');
+INSERT INTO items VALUES(NULL,'Wall 28',6,637,0,'27d');
+INSERT INTO items VALUES(NULL,'Wall 29',6,638,0,'27e');
+INSERT INTO items VALUES(NULL,'Wall 30',6,639,0,'27f');
+INSERT INTO items VALUES(NULL,'Tiller Man 7',10,15952,0,'3e50');
+INSERT INTO items VALUES(NULL,'Brush 1 (W/E)',13,4976,0,'1370');
+INSERT INTO items VALUES(NULL,'Goblet 4',14,2507,0,'9cb');
+INSERT INTO items VALUES(NULL,'Ceramic Mug 4',14,2506,0,'9ca');
+INSERT INTO items VALUES(NULL,'Wood 14',11,7054,0,'1b8e');
+INSERT INTO items VALUES(NULL,'Wood 13',11,7053,0,'1b8d');
+INSERT INTO items VALUES(NULL,'Wood 15',11,7055,0,'1b8f');
+INSERT INTO items VALUES(NULL,'Wood 10',11,7050,0,'1b8a');
+INSERT INTO items VALUES(NULL,'Wood 12',11,7052,0,'1b8c');
+INSERT INTO items VALUES(NULL,'Wood 11',11,7051,0,'1b8b');
+INSERT INTO items VALUES(NULL,'buckler',16,7027,0,'verite_shields_buckler');
+INSERT INTO items VALUES(NULL,'plate helmet',18,5138,0,'valorite_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Fish 2',19,2509,0,'9cd');
+INSERT INTO items VALUES(NULL,'crescent blade',3,9921,0,'26c1');
+INSERT INTO items VALUES(NULL,'lance',20,9920,0,'26c0');
+INSERT INTO items VALUES(NULL,'repeating crossbow',21,9923,0,'26c3');
+INSERT INTO items VALUES(NULL,'composite bow',21,9922,0,'26c2');
+INSERT INTO items VALUES(NULL,'Small Wall 1',22,154,0,'9a');
+INSERT INTO items VALUES(NULL,'Small Wall 3',22,156,0,'9c');
+INSERT INTO items VALUES(NULL,'Small Wall 2',22,155,0,'9b');
+INSERT INTO items VALUES(NULL,'Small Wall 5',22,158,0,'9e');
+INSERT INTO items VALUES(NULL,'Small Wall 4',22,157,0,'9d');
+INSERT INTO items VALUES(NULL,'Small Wall 6',22,159,0,'9f');
+INSERT INTO items VALUES(NULL,'Waterfall 46',23,13593,0,'3519');
+INSERT INTO items VALUES(NULL,'Waterfall 45',23,13592,0,'3518');
+INSERT INTO items VALUES(NULL,'Waterfall 40',23,13587,0,'3513');
+INSERT INTO items VALUES(NULL,'Waterfall 39',23,13586,0,'3512');
+INSERT INTO items VALUES(NULL,'Waterfall 38',23,13585,0,'3511');
+INSERT INTO items VALUES(NULL,'Waterfall 37',23,13584,0,'3510');
+INSERT INTO items VALUES(NULL,'Waterfall 44',23,13591,0,'3517');
+INSERT INTO items VALUES(NULL,'Waterfall 43',23,13590,0,'3516');
+INSERT INTO items VALUES(NULL,'Waterfall 42',23,13589,0,'3515');
+INSERT INTO items VALUES(NULL,'Waterfall 41',23,13588,0,'3514');
+INSERT INTO items VALUES(NULL,'Bridle (N/S)',13,4980,0,'1374');
+INSERT INTO items VALUES(NULL,'Window 2',22,153,0,'99');
+INSERT INTO items VALUES(NULL,'Window 1',22,152,0,'98');
+INSERT INTO items VALUES(NULL,'Wall 2',22,145,0,'91');
+INSERT INTO items VALUES(NULL,'Wall 1',22,144,0,'90');
+INSERT INTO items VALUES(NULL,'Wall 4',22,147,0,'93');
+INSERT INTO items VALUES(NULL,'Wall 3',22,146,0,'92');
+INSERT INTO items VALUES(NULL,'Wall 6',22,149,0,'95');
+INSERT INTO items VALUES(NULL,'Wall 5',22,148,0,'94');
+INSERT INTO items VALUES(NULL,'Wall 8',22,151,0,'97');
+INSERT INTO items VALUES(NULL,'Wall 7',22,150,0,'96');
+INSERT INTO items VALUES(NULL,'bascinet',25,5132,0,'valorite_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 24',26,2040,0,'7f8');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 25',26,2041,0,'7f9');
+INSERT INTO items VALUES(NULL,'Waterfall 49',23,13596,0,'351c');
+INSERT INTO items VALUES(NULL,'Waterfall 48',23,13595,0,'351b');
+INSERT INTO items VALUES(NULL,'Waterfall 47',23,13594,0,'351a');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 17',26,2033,0,'7f1');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 22',26,2038,0,'7f6');
+INSERT INTO items VALUES(NULL,'Waterfall 52',23,13599,0,'351f');
+INSERT INTO items VALUES(NULL,'Waterfall 51',23,13598,0,'351e');
+INSERT INTO items VALUES(NULL,'Waterfall 50',23,13597,0,'351d');
+INSERT INTO items VALUES(NULL,'Horse Barding (W/E) (1/2)',13,4982,0,'1376');
+INSERT INTO items VALUES(NULL,'Gravestone 38',27,4479,0,'117f');
+INSERT INTO items VALUES(NULL,'Gravestone 37',27,4478,0,'117e');
+INSERT INTO items VALUES(NULL,'Gravestone 36',27,4477,0,'117d');
+INSERT INTO items VALUES(NULL,'Gravestone 35',27,4476,0,'117c');
+INSERT INTO items VALUES(NULL,'Gravestone 34',27,4475,0,'117b');
+INSERT INTO items VALUES(NULL,'Gravestone 33',27,4474,0,'117a');
+INSERT INTO items VALUES(NULL,'Gravestone 30',27,4471,0,'1177');
+INSERT INTO items VALUES(NULL,'Gravestone 29',27,4470,0,'1176');
+INSERT INTO items VALUES(NULL,'Gravestone 28',27,4469,0,'1175');
+INSERT INTO items VALUES(NULL,'Gravestone 27',27,4468,0,'1174');
+INSERT INTO items VALUES(NULL,'Gravestone 26',27,4467,0,'1173');
+INSERT INTO items VALUES(NULL,'Gravestone 25',27,4466,0,'1172');
+INSERT INTO items VALUES(NULL,'Gravestone 24',27,4465,0,'1171');
+INSERT INTO items VALUES(NULL,'Gravestone 23',27,4464,0,'1170');
+INSERT INTO items VALUES(NULL,'Gravestone 32',27,4473,0,'1179');
+INSERT INTO items VALUES(NULL,'Gravestone 31',27,4472,0,'1178');
+INSERT INTO items VALUES(NULL,'Magic Face 2 (W/E)',28,7924,0,'1ef4');
+INSERT INTO items VALUES(NULL,'Rock 32',29,13360,0,'3430');
+INSERT INTO items VALUES(NULL,'Forge (N/S) (1/3)',30,6534,0,'1986');
+INSERT INTO items VALUES(NULL,'Rock 33',29,13361,0,'3431');
+INSERT INTO items VALUES(NULL,'Rock 34',29,13362,0,'3432');
+INSERT INTO items VALUES(NULL,'Statue 3 (W/E)',31,4647,0,'1227');
+INSERT INTO items VALUES(NULL,'Roof 14',32,1570,0,'622');
+INSERT INTO items VALUES(NULL,'Rock 36',29,13364,0,'3434');
+INSERT INTO items VALUES(NULL,'Roof 13',32,1569,0,'621');
+INSERT INTO items VALUES(NULL,'Water 69',33,13512,0,'34c8');
+INSERT INTO items VALUES(NULL,'Water 70',33,13513,0,'34c9');
+INSERT INTO items VALUES(NULL,'Statue 1 (W/E)',31,4644,0,'1224');
+INSERT INTO items VALUES(NULL,'Water 63',33,13504,0,'34c0');
+INSERT INTO items VALUES(NULL,'Roof 19',32,1575,0,'627');
+INSERT INTO items VALUES(NULL,'Water 64',33,13506,0,'34c2');
+INSERT INTO items VALUES(NULL,'Water 65',33,13507,0,'34c3');
+INSERT INTO items VALUES(NULL,'Water 66',33,13508,0,'34c4');
+INSERT INTO items VALUES(NULL,'Water 67',33,13509,0,'34c5');
+INSERT INTO items VALUES(NULL,'Water 68',33,13511,0,'34c7');
+INSERT INTO items VALUES(NULL,'Arrows 2',34,3905,0,'f41');
+INSERT INTO items VALUES(NULL,'Arrows 1',34,3904,0,'f40');
+INSERT INTO items VALUES(NULL,'hatchet',35,3907,0,'f43');
+INSERT INTO items VALUES(NULL,'executioner''s axe',35,3909,0,'f45');
+INSERT INTO items VALUES(NULL,'Roof 17',32,1573,0,'625');
+INSERT INTO items VALUES(NULL,'battle axe',35,3911,0,'f47');
+INSERT INTO items VALUES(NULL,'axe',35,3913,0,'f49');
+INSERT INTO items VALUES(NULL,'Roof 16',32,1572,0,'624');
+INSERT INTO items VALUES(NULL,'Water 71',33,13514,0,'34ca');
+INSERT INTO items VALUES(NULL,'platemail legs',36,5137,0,'bronze_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'double axe',35,3915,0,'f4b');
+INSERT INTO items VALUES(NULL,'bardiche',3,3917,0,'f4d');
+INSERT INTO items VALUES(NULL,'crossbow',21,3919,0,'f4f');
+INSERT INTO items VALUES(NULL,'Lava 11',37,6732,0,'1a4c');
+INSERT INTO items VALUES(NULL,'Glow (like a star)',28,14276,0,'37c4');
+INSERT INTO items VALUES(NULL,'ringmail leggings',39,5104,0,'dull_copper_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'bascinet',40,5132,0,'bronze_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Wall 21',41,915,0,'393');
+INSERT INTO items VALUES(NULL,'Wall 20',41,914,0,'392');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',42,5103,0,'bronze_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'Wall 18',41,912,0,'390');
+INSERT INTO items VALUES(NULL,'Archway 1',41,919,0,'397');
+INSERT INTO items VALUES(NULL,'Wall 24',41,918,0,'396');
+INSERT INTO items VALUES(NULL,'Wall 23',41,917,0,'395');
+INSERT INTO items VALUES(NULL,'Wall 22',41,916,0,'394');
+INSERT INTO items VALUES(NULL,'Archway 3',41,921,0,'399');
+INSERT INTO items VALUES(NULL,'Archway 2',41,920,0,'398');
+INSERT INTO items VALUES(NULL,'Sparkle (red)',28,14154,0,'374a');
+INSERT INTO items VALUES(NULL,'Archway 6',41,924,0,'39c');
+INSERT INTO items VALUES(NULL,'Archway 5',41,923,0,'39b');
+INSERT INTO items VALUES(NULL,'Archway 4',41,922,0,'39a');
+INSERT INTO items VALUES(NULL,'Archway 9',41,927,0,'39f');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',43,5103,0,'valorite_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'Archway 7',41,925,0,'39d');
+INSERT INTO items VALUES(NULL,'Lava 9',37,6723,0,'1a43');
+INSERT INTO items VALUES(NULL,'Lava 10',37,6727,0,'1a47');
+INSERT INTO items VALUES(NULL,'Death Vortex',28,14284,0,'37cc');
+INSERT INTO items VALUES(NULL,'Lava 36',44,12973,0,'32ad');
+INSERT INTO items VALUES(NULL,'Hops 4',45,6817,0,'1aa1');
+INSERT INTO items VALUES(NULL,'Hops 3',45,6816,0,'1aa0');
+INSERT INTO items VALUES(NULL,'Hops cones',45,6818,0,'1aa2');
+INSERT INTO items VALUES(NULL,'Lighthouse (2/29)',46,6821,0,'1aa5');
+INSERT INTO items VALUES(NULL,'Lighthouse (1/29)',46,6820,0,'1aa4');
+INSERT INTO items VALUES(NULL,'Battlement 2',47,377,0,'179');
+INSERT INTO items VALUES(NULL,'Pillar 4',47,376,0,'178');
+INSERT INTO items VALUES(NULL,'Pillar 3',47,375,0,'177');
+INSERT INTO items VALUES(NULL,'Pillar 2',47,374,0,'176');
+INSERT INTO items VALUES(NULL,'Pillar 1',47,373,0,'175');
+INSERT INTO items VALUES(NULL,'Smal Wall 5',47,372,0,'174');
+INSERT INTO items VALUES(NULL,'Battlement 1',47,371,0,'173');
+INSERT INTO items VALUES(NULL,'Top 2',47,370,0,'172');
+INSERT INTO items VALUES(NULL,'Top 1',47,369,0,'171');
+INSERT INTO items VALUES(NULL,'Arch 5',47,368,0,'170');
+INSERT INTO items VALUES(NULL,'chainmail coif',48,5051,0,'13bb');
+INSERT INTO items VALUES(NULL,'Hanging Chainmail Leggings (N/S)',30,5052,0,'13bc');
+INSERT INTO items VALUES(NULL,'chainmail tunic',48,5055,0,'13bf');
+INSERT INTO items VALUES(NULL,'Hanging Chainmail Tunic (N/S)',30,5053,0,'13bd');
+INSERT INTO items VALUES(NULL,'chainmail leggings',48,5054,0,'13be');
+INSERT INTO items VALUES(NULL,'Tree 1 (3/4)',4,3395,0,'d43');
+INSERT INTO items VALUES(NULL,'Lighthouse (7/29)',46,6826,0,'1aaa');
+INSERT INTO items VALUES(NULL,'Lighthouse (9/29)',46,6828,0,'1aac');
+INSERT INTO items VALUES(NULL,'Lighthouse (8/29)',46,6827,0,'1aab');
+INSERT INTO items VALUES(NULL,'Lighthouse (10/29)',46,6829,0,'1aad');
+INSERT INTO items VALUES(NULL,'Tree 1 (2/4)',4,3394,0,'d42');
+INSERT INTO items VALUES(NULL,'Edge 2',47,383,0,'17f');
+INSERT INTO items VALUES(NULL,'Edge 1',47,382,0,'17e');
+INSERT INTO items VALUES(NULL,'Battlement 6',47,381,0,'17d');
+INSERT INTO items VALUES(NULL,'Battlement 5',47,380,0,'17c');
+INSERT INTO items VALUES(NULL,'Battlement 4',47,379,0,'17b');
+INSERT INTO items VALUES(NULL,'Battlement 3',47,378,0,'17a');
+INSERT INTO items VALUES(NULL,'Pony Tail',49,8253,0,'203d');
+INSERT INTO items VALUES(NULL,'Long Hair',49,8252,0,'203c');
+INSERT INTO items VALUES(NULL,'Short Hair',49,8251,0,'203b');
+INSERT INTO items VALUES(NULL,'Tree 1 (1/4)',4,3393,0,'d41');
+INSERT INTO items VALUES(NULL,'bow',21,5042,0,'13b2');
+INSERT INTO items VALUES(NULL,'war axe',35,5040,0,'13b0');
+INSERT INTO items VALUES(NULL,'scimitar',3,5046,0,'13b6');
+INSERT INTO items VALUES(NULL,'club',5,5044,0,'13b4');
+INSERT INTO items VALUES(NULL,'Wall 6',50,516,0,'204');
+INSERT INTO items VALUES(NULL,'viking sword',3,5049,0,'13b9');
+INSERT INTO items VALUES(NULL,'Brambles 2',45,3392,0,'d40');
+INSERT INTO items VALUES(NULL,'Leaves 1 (3/15)',4,3399,0,'d47');
+INSERT INTO items VALUES(NULL,'Keyring 4',51,5995,0,'176b');
+INSERT INTO items VALUES(NULL,'Keyring 3',51,5994,0,'176a');
+INSERT INTO items VALUES(NULL,'Rusty Iron Key',51,4115,0,'1013');
+INSERT INTO items VALUES(NULL,'Leaves 1 (2/15)',4,3398,0,'d46');
+INSERT INTO items VALUES(NULL,'Lava 1',52,13371,0,'343b');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (W/E) (1/4)',53,4817,0,'12d1');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (N/S) (5/5)',53,4816,0,'12d0');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (W/E) (3/4)',53,4819,0,'12d3');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (W/E) (2/4)',53,4818,0,'12d2');
+INSERT INTO items VALUES(NULL,'Statue 4 (1/3)',54,4821,0,'12d5');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (W/E) (4/4)',53,4820,0,'12d4');
+INSERT INTO items VALUES(NULL,'Statue 4 (2/3)',54,4823,0,'12d7');
+INSERT INTO items VALUES(NULL,'Blood 6',55,4655,0,'122f');
+INSERT INTO items VALUES(NULL,'Statue 5 (N/S)',54,4825,0,'12d9');
+INSERT INTO items VALUES(NULL,'Statue 5 (W/E)',54,4824,0,'12d8');
+INSERT INTO items VALUES(NULL,'Roof 22',32,1578,0,'62a');
+INSERT INTO items VALUES(NULL,'ringmail tunic',56,5100,0,'merkite_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Cut Cloth (W/E)',57,5992,0,'1768');
+INSERT INTO items VALUES(NULL,'Keyring 2',51,5993,0,'1769');
+INSERT INTO items VALUES(NULL,'Folded Cloth 2 (N/S)',57,5986,0,'1762');
+INSERT INTO items VALUES(NULL,'Folded Cloth 3 (N/S)',57,5987,0,'1763');
+INSERT INTO items VALUES(NULL,'Folded Cloth 4 (W/E)',57,5984,0,'1760');
+INSERT INTO items VALUES(NULL,'Folded Cloth 1 (N/S)',57,5985,0,'1761');
+INSERT INTO items VALUES(NULL,'Cut Cloth (N/S)',57,5990,0,'1766');
+INSERT INTO items VALUES(NULL,'Cloth (N/S)',57,5991,0,'1767');
+INSERT INTO items VALUES(NULL,'Folded Cloth 4 (N/S)',57,5988,0,'1764');
+INSERT INTO items VALUES(NULL,'Blood 2',55,4651,0,'122b');
+INSERT INTO items VALUES(NULL,'Blood 1',55,4650,0,'122a');
+INSERT INTO items VALUES(NULL,'Bear Mask (W/E)',58,5446,0,'1546');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 1 (W/NW)',59,1683,0,'693');
+INSERT INTO items VALUES(NULL,'Skull Cap (W/E)',58,5444,0,'1544');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 1 (W/SW)',59,1681,0,'691');
+INSERT INTO items VALUES(NULL,'Body Sash (W/E)',60,5442,0,'1542');
+INSERT INTO items VALUES(NULL,'Rattan Door (S/SE)',61,1687,0,'697');
+INSERT INTO items VALUES(NULL,'Bandana (W/E)',58,5440,0,'1540');
+INSERT INTO items VALUES(NULL,'Rattan Door (S/SW)',61,1685,0,'695');
+INSERT INTO items VALUES(NULL,'Rattan Door (S/NW)',61,1689,0,'699');
+INSERT INTO items VALUES(NULL,'Deer Mask (W/E)',58,5448,0,'1548');
+INSERT INTO items VALUES(NULL,'Tribal Mask (N/S)',58,5449,0,'1549');
+INSERT INTO items VALUES(NULL,'Wood 6',11,7046,0,'1b86');
+INSERT INTO items VALUES(NULL,'Oak Tree 1',4,3290,0,'cda');
+INSERT INTO items VALUES(NULL,'Wave 36',62,8134,0,'1fc6');
+INSERT INTO items VALUES(NULL,'chainmail coif',63,5051,0,'shadow_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Forge (W/E) (3/3)',30,6530,0,'1982');
+INSERT INTO items VALUES(NULL,'helmet',64,5130,0,'golden_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Cypress Tree 4 Leaves 1',4,3330,0,'d02');
+INSERT INTO items VALUES(NULL,'Rattan Door (S/NE)',61,1691,0,'69b');
+INSERT INTO items VALUES(NULL,'Barrel 3',65,5453,0,'154d');
+INSERT INTO items VALUES(NULL,'Rattan Door (W/NE)',61,1695,0,'69f');
+INSERT INTO items VALUES(NULL,'Tribal Mask 2 (W/E)',58,5452,0,'154c');
+INSERT INTO items VALUES(NULL,'Rattan Door (W/SE)',61,1693,0,'69d');
+INSERT INTO items VALUES(NULL,'Tribal Mask (W/E)',58,5450,0,'154a');
+INSERT INTO items VALUES(NULL,'Lighthouse (4/29)',46,6823,0,'1aa7');
+INSERT INTO items VALUES(NULL,'Lighthouse (3/29)',46,6822,0,'1aa6');
+INSERT INTO items VALUES(NULL,'Wall 10',66,600,0,'258');
+INSERT INTO items VALUES(NULL,'Wall 11',66,601,0,'259');
+INSERT INTO items VALUES(NULL,'Window 1',66,594,0,'252');
+INSERT INTO items VALUES(NULL,'Window 2',66,595,0,'253');
+INSERT INTO items VALUES(NULL,'Wall 5',66,592,0,'250');
+INSERT INTO items VALUES(NULL,'Wall 6',66,593,0,'251');
+INSERT INTO items VALUES(NULL,'Wall 8',66,598,0,'256');
+INSERT INTO items VALUES(NULL,'Wall 9',66,599,0,'257');
+INSERT INTO items VALUES(NULL,'Window 3',66,596,0,'254');
+INSERT INTO items VALUES(NULL,'Wall 7',66,597,0,'255');
+INSERT INTO items VALUES(NULL,'Long Cannon (S/N) (3/3)',67,3725,0,'e8d');
+INSERT INTO items VALUES(NULL,'Lava 6',44,12939,0,'328b');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 9',68,7761,0,'1e51');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 8',68,7760,0,'1e50');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 1',68,7763,0,'1e53');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 3',68,7765,0,'1e55');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 2',68,7764,0,'1e54');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 5',68,7767,0,'1e57');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 4',68,7766,0,'1e56');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 7',68,7769,0,'1e59');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 6',68,7768,0,'1e58');
+INSERT INTO items VALUES(NULL,'heater shield',69,7030,0,'golden_shields_heater');
+INSERT INTO items VALUES(NULL,'Wall 13',66,603,0,'25b');
+INSERT INTO items VALUES(NULL,'Wall 1',6,604,0,'25c');
+INSERT INTO items VALUES(NULL,'Wall 12',66,602,0,'25a');
+INSERT INTO items VALUES(NULL,'Wall 4',6,607,0,'25f');
+INSERT INTO items VALUES(NULL,'Wall 2',6,605,0,'25d');
+INSERT INTO items VALUES(NULL,'Wall 3',6,606,0,'25e');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 8',68,7770,0,'1e5a');
+INSERT INTO items VALUES(NULL,'Ankh of Sacrifice (N/S) (1/2)',70,7772,0,'1e5c');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 9',68,7771,0,'1e5b');
+INSERT INTO items VALUES(NULL,'Message Board (N/S)',71,7774,0,'1e5e');
+INSERT INTO items VALUES(NULL,'Ankh of Sacrifice (N/S) (2/2)',70,7773,0,'1e5d');
+INSERT INTO items VALUES(NULL,'Message Board (W/E)',71,7775,0,'1e5f');
+INSERT INTO items VALUES(NULL,'Catapult 33',72,5747,0,'1673');
+INSERT INTO items VALUES(NULL,'Lantern Post (N/S)',73,2592,0,'a20');
+INSERT INTO items VALUES(NULL,'Lantern (On)',73,2594,0,'a22');
+INSERT INTO items VALUES(NULL,'Lantern (Off)',73,2597,0,'a25');
+INSERT INTO items VALUES(NULL,'Candle 2 (Off)',73,2598,0,'a26');
+INSERT INTO items VALUES(NULL,'Small Candlabra (Off)',73,2599,0,'a27');
+INSERT INTO items VALUES(NULL,'Candle 1 (Off)',73,2600,0,'a28');
+INSERT INTO items VALUES(NULL,'Big Candlabra (Off)',73,2601,0,'a29');
+INSERT INTO items VALUES(NULL,'Splash 4',74,13616,0,'3530');
+INSERT INTO items VALUES(NULL,'Lever 1 (N/S)',75,4243,0,'1093');
+INSERT INTO items VALUES(NULL,'Balista 191',76,16298,0,'3faa');
+INSERT INTO items VALUES(NULL,'Balista 192',76,16299,0,'3fab');
+INSERT INTO items VALUES(NULL,'Balista 193',76,16300,0,'3fac');
+INSERT INTO items VALUES(NULL,'Balista 194',76,16301,0,'3fad');
+INSERT INTO items VALUES(NULL,'Balista 195',76,16302,0,'3fae');
+INSERT INTO items VALUES(NULL,'Balista 196',76,16303,0,'3faf');
+INSERT INTO items VALUES(NULL,'metal shield',77,7035,0,'bronze_shields_shield');
+INSERT INTO items VALUES(NULL,'Stool 1',78,2602,0,'a2a');
+INSERT INTO items VALUES(NULL,'Stool 2',78,2603,0,'a2b');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (N/S) 1',79,2604,0,'a2c');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (N/S) 2',79,2605,0,'a2d');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (N/S) 3',79,2606,0,'a2e');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (N/S) 4',79,2607,0,'a2f');
+INSERT INTO items VALUES(NULL,'Balista 181',76,16288,0,'3fa0');
+INSERT INTO items VALUES(NULL,'Balista 182',76,16289,0,'3fa1');
+INSERT INTO items VALUES(NULL,'Balista 183',76,16290,0,'3fa2');
+INSERT INTO items VALUES(NULL,'Balista 184',76,16291,0,'3fa3');
+INSERT INTO items VALUES(NULL,'Balista 185',76,16292,0,'3fa4');
+INSERT INTO items VALUES(NULL,'Balista 186',76,16293,0,'3fa5');
+INSERT INTO items VALUES(NULL,'Balista 187',76,16294,0,'3fa6');
+INSERT INTO items VALUES(NULL,'Balista 188',76,16295,0,'3fa7');
+INSERT INTO items VALUES(NULL,'Balista 189',76,16296,0,'3fa8');
+INSERT INTO items VALUES(NULL,'Balista 190',76,16297,0,'3fa9');
+INSERT INTO items VALUES(NULL,'Crossbow Bolts 1',34,7164,0,'1bfc');
+INSERT INTO items VALUES(NULL,'Crossbow Bolt',34,7163,0,'1bfb');
+INSERT INTO items VALUES(NULL,'Silver Ingots 2 (N/S)',80,7162,0,'1bfa');
+INSERT INTO items VALUES(NULL,'Crossbow Bolts 2',34,7165,0,'1bfd');
+INSERT INTO items VALUES(NULL,'Magical Sparkles',28,4435,0,'1153');
+INSERT INTO items VALUES(NULL,'Silver Ingots 1 (N/S)',80,7161,0,'1bf9');
+INSERT INTO items VALUES(NULL,'Silver Ingot (N/S)',80,7160,0,'1bf8');
+INSERT INTO items VALUES(NULL,'Iron Ingots 1 (N/S)',80,7155,0,'1bf3');
+INSERT INTO items VALUES(NULL,'Iron Ingot (N/S)',80,7154,0,'1bf2');
+INSERT INTO items VALUES(NULL,'Iron Ingots 2 (W/E)',80,7153,0,'1bf1');
+INSERT INTO items VALUES(NULL,'Iron Ingots 1 (W/E)',80,7152,0,'1bf0');
+INSERT INTO items VALUES(NULL,'Silver Ingots 2 (W/E)',80,7159,0,'1bf7');
+INSERT INTO items VALUES(NULL,'Silver Ingots 1 (W/E)',80,7158,0,'1bf6');
+INSERT INTO items VALUES(NULL,'Silver Ingot (W/E)',80,7157,0,'1bf5');
+INSERT INTO items VALUES(NULL,'Iron Ingots 2 (N/S)',80,7156,0,'1bf4');
+INSERT INTO items VALUES(NULL,'Water 47',33,13478,0,'34a6');
+INSERT INTO items VALUES(NULL,'Water 48',33,13479,0,'34a7');
+INSERT INTO items VALUES(NULL,'Water 45',33,13476,0,'34a4');
+INSERT INTO items VALUES(NULL,'Water 46',33,13477,0,'34a5');
+INSERT INTO items VALUES(NULL,'Water 43',33,13474,0,'34a2');
+INSERT INTO items VALUES(NULL,'Water 44',33,13475,0,'34a3');
+INSERT INTO items VALUES(NULL,'Water 41',33,13472,0,'34a0');
+INSERT INTO items VALUES(NULL,'Water 42',33,13473,0,'34a1');
+INSERT INTO items VALUES(NULL,'Water 49',33,13480,0,'34a8');
+INSERT INTO items VALUES(NULL,'Water 50',33,13481,0,'34a9');
+INSERT INTO items VALUES(NULL,'plate helmet',81,5138,0,'shadow_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Rock 15',29,13487,0,'34af');
+INSERT INTO items VALUES(NULL,'Rock 13',29,13485,0,'34ad');
+INSERT INTO items VALUES(NULL,'Rock 14',29,13486,0,'34ae');
+INSERT INTO items VALUES(NULL,'Water 52',33,13483,0,'34ab');
+INSERT INTO items VALUES(NULL,'Rock 7',29,13484,0,'34ac');
+INSERT INTO items VALUES(NULL,'Water 51',33,13482,0,'34aa');
+INSERT INTO items VALUES(NULL,'metal shield',69,7035,0,'golden_shields_shield');
+INSERT INTO items VALUES(NULL,'close helmet',64,5128,0,'golden_helmets_close');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 27',26,2043,0,'7fb');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 28',26,2044,0,'7fc');
+INSERT INTO items VALUES(NULL,'Wall 18',82,8588,0,'218c');
+INSERT INTO items VALUES(NULL,'Wall 17',82,8587,0,'218b');
+INSERT INTO items VALUES(NULL,'Wall 16',82,8586,0,'218a');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 26',26,2042,0,'7fa');
+INSERT INTO items VALUES(NULL,'Wall 21',82,8591,0,'218f');
+INSERT INTO items VALUES(NULL,'Wall 20',82,8590,0,'218e');
+INSERT INTO items VALUES(NULL,'Wall 19',82,8589,0,'218d');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 3',26,2047,0,'7ff');
+INSERT INTO items VALUES(NULL,'two handed axe',35,5187,0,'1443');
+INSERT INTO items VALUES(NULL,'Lava 5',37,6701,0,'1a2d');
+INSERT INTO items VALUES(NULL,'heater shield',83,7030,0,'dull_copper_shields_heater');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 1',26,2045,0,'7fd');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 2',26,2046,0,'7fe');
+INSERT INTO items VALUES(NULL,'plate armor',36,7172,0,'bronze_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Lava 4',37,6696,0,'1a28');
+INSERT INTO items VALUES(NULL,'Roof 45',84,8578,0,'2182');
+INSERT INTO items VALUES(NULL,'Roof 44',84,8577,0,'2181');
+INSERT INTO items VALUES(NULL,'Roof 43',84,8576,0,'2180');
+INSERT INTO items VALUES(NULL,'Roof 50',84,8583,0,'2187');
+INSERT INTO items VALUES(NULL,'Roof 49',84,8582,0,'2186');
+INSERT INTO items VALUES(NULL,'Roof 48',84,8581,0,'2185');
+INSERT INTO items VALUES(NULL,'Roof 47',84,8580,0,'2184');
+INSERT INTO items VALUES(NULL,'Wall 15',82,8585,0,'2189');
+INSERT INTO items VALUES(NULL,'Wall 14',82,8584,0,'2188');
+INSERT INTO items VALUES(NULL,'Balista 36',76,6338,0,'18c2');
+INSERT INTO items VALUES(NULL,'Balista 37',76,6339,0,'18c3');
+INSERT INTO items VALUES(NULL,'Balista 34',76,6336,0,'18c0');
+INSERT INTO items VALUES(NULL,'Balista 35',76,6337,0,'18c1');
+INSERT INTO items VALUES(NULL,'Field of Blades',28,14240,0,'37a0');
+INSERT INTO items VALUES(NULL,'Balista 40',76,6342,0,'18c6');
+INSERT INTO items VALUES(NULL,'Balista 41',76,6343,0,'18c7');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 2 (W/E) (2/3)',78,2915,0,'b63');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 2 (W/E) (1/3)',78,2914,0,'b62');
+INSERT INTO items VALUES(NULL,'Wooden Bench 2 (W/E) (3/3)',78,2913,0,'b61');
+INSERT INTO items VALUES(NULL,'Wooden Bench 2 (W/E) (2/3)',78,2912,0,'b60');
+INSERT INTO items VALUES(NULL,'Wooden Bench 2 (N/S) (3/3)',78,2919,0,'b67');
+INSERT INTO items VALUES(NULL,'Wooden Bench 2 (N/S) (2/3)',78,2918,0,'b66');
+INSERT INTO items VALUES(NULL,'Wooden Bench 2 (N/S) (1/3)',78,2917,0,'b65');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 2 (W/E) (3/3)',78,2916,0,'b64');
+INSERT INTO items VALUES(NULL,'Wall 2',85,345,0,'159');
+INSERT INTO items VALUES(NULL,'Wall 1',85,344,0,'158');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 2 (N/S) (2/3)',78,2921,0,'b69');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 2 (N/S) (1/3)',78,2920,0,'b68');
+INSERT INTO items VALUES(NULL,'Mast 8',8,16093,0,'3edd');
+INSERT INTO items VALUES(NULL,'Sail 8',86,16094,0,'3ede');
+INSERT INTO items VALUES(NULL,'Sail 10',86,16095,0,'3edf');
+INSERT INTO items VALUES(NULL,'Sail 18',86,16092,0,'3edc');
+INSERT INTO items VALUES(NULL,'Hanging Studded Sleeves (W/E)',57,5086,0,'13de');
+INSERT INTO items VALUES(NULL,'Hanging Studded Leggings (W/E)',57,5087,0,'13df');
+INSERT INTO items VALUES(NULL,'Gang Plank 5',87,16084,0,'3ed4');
+INSERT INTO items VALUES(NULL,'Gang Plank 6',87,16085,0,'3ed5');
+INSERT INTO items VALUES(NULL,'Mast 7',8,16080,0,'3ed0');
+INSERT INTO items VALUES(NULL,'Spar 7',88,16081,0,'3ed1');
+INSERT INTO items VALUES(NULL,'Spar 8',88,16082,0,'3ed2');
+INSERT INTO items VALUES(NULL,'Gang Plank 4',87,16083,0,'3ed3');
+INSERT INTO items VALUES(NULL,'Sandstone Table 1 (W/E) (2/3)',89,2924,0,'b6c');
+INSERT INTO items VALUES(NULL,'Sandstone Table 1 (W/E) (1/3)',89,2923,0,'b6b');
+INSERT INTO items VALUES(NULL,'Window 1',85,348,0,'15c');
+INSERT INTO items VALUES(NULL,'Wall 4',85,347,0,'15b');
+INSERT INTO items VALUES(NULL,'Wall 1',47,350,0,'15e');
+INSERT INTO items VALUES(NULL,'Window 2',85,349,0,'15d');
+INSERT INTO items VALUES(NULL,'Wooden Table 1 (W/E) (1/2)',89,2926,0,'b6e');
+INSERT INTO items VALUES(NULL,'Wall 2',47,351,0,'15f');
+INSERT INTO items VALUES(NULL,'Balista 96',76,16203,0,'3f4b');
+INSERT INTO items VALUES(NULL,'Hanging Studded Leggings (N/S)',57,5080,0,'13d8');
+INSERT INTO items VALUES(NULL,'Hanging Studded Tunic (N/S)',57,5081,0,'13d9');
+INSERT INTO items VALUES(NULL,'Hanging Leather Leggings (W/E)',57,5072,0,'13d0');
+INSERT INTO items VALUES(NULL,'Hanging Leather Sleeves (W/E)',57,5073,0,'13d1');
+INSERT INTO items VALUES(NULL,'Hanging Studded Sleeves (N/S)',57,5079,0,'13d7');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 28',26,2072,0,'818');
+INSERT INTO items VALUES(NULL,'Boots (W/E)',90,5899,0,'170b');
+INSERT INTO items VALUES(NULL,'Boots (W/E)',90,5900,0,'170c');
+INSERT INTO items VALUES(NULL,'Sandals (N/S)',90,5901,0,'170d');
+INSERT INTO items VALUES(NULL,'Sandals (W/E)',90,5902,0,'170e');
+INSERT INTO items VALUES(NULL,'Shoes (N/S)',90,5903,0,'170f');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 20',26,2064,0,'810');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 21',26,2065,0,'811');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 22',26,2066,0,'812');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 23',26,2067,0,'813');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 24',26,2068,0,'814');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 25',26,2069,0,'815');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 26',26,2070,0,'816');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 27',26,2071,0,'817');
+INSERT INTO items VALUES(NULL,'Water 30',33,13461,0,'3495');
+INSERT INTO items VALUES(NULL,'Pillow 11',91,5037,0,'13ad');
+INSERT INTO items VALUES(NULL,'Teleport',92,8341,0,'2095');
+INSERT INTO items VALUES(NULL,'Telekinesis',92,8340,0,'2094');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 9',93,2077,0,'81d');
+INSERT INTO items VALUES(NULL,'Wall of Stone',92,8343,0,'2097');
+INSERT INTO items VALUES(NULL,'Magic Unlock',92,8342,0,'2096');
+INSERT INTO items VALUES(NULL,'Fireball',92,8337,0,'2091');
+INSERT INTO items VALUES(NULL,'Bless',92,8336,0,'2090');
+INSERT INTO items VALUES(NULL,'Balista 45',76,6347,0,'18cb');
+INSERT INTO items VALUES(NULL,'Poison',92,8339,0,'2093');
+INSERT INTO items VALUES(NULL,'Balista 46',76,6348,0,'18cc');
+INSERT INTO items VALUES(NULL,'Magic Lock',92,8338,0,'2092');
+INSERT INTO items VALUES(NULL,'Tree Pieces 1 (5/5)',4,3419,0,'d5b');
+INSERT INTO items VALUES(NULL,'Balista 47',76,6349,0,'18cd');
+INSERT INTO items VALUES(NULL,'Balista 48',76,6350,0,'18ce');
+INSERT INTO items VALUES(NULL,'Resurrection',94,8039,0,'1f67');
+INSERT INTO items VALUES(NULL,'Explosion 1',28,14000,0,'36b0');
+INSERT INTO items VALUES(NULL,'chainmail tunic',95,5055,0,'golden_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 18',26,2034,0,'7f2');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 19',26,2035,0,'7f3');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 16',26,2032,0,'7f0');
+INSERT INTO items VALUES(NULL,'Explosion 2',28,14013,0,'36bd');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 23',26,2039,0,'7f7');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 20',26,2036,0,'7f4');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 21',26,2037,0,'7f5');
+INSERT INTO items VALUES(NULL,'Leaves 4 (9/10)',4,3471,0,'d8f');
+INSERT INTO items VALUES(NULL,'Leaves 4 (7/10)',4,3469,0,'d8d');
+INSERT INTO items VALUES(NULL,'Mana Drain',92,8350,0,'209e');
+INSERT INTO items VALUES(NULL,'Lightning',92,8349,0,'209d');
+INSERT INTO items VALUES(NULL,'Recall',92,8351,0,'209f');
+INSERT INTO items VALUES(NULL,'Wall 9',96,568,0,'238');
+INSERT INTO items VALUES(NULL,'Wall 10',96,569,0,'239');
+INSERT INTO items VALUES(NULL,'Wall 5',96,564,0,'234');
+INSERT INTO items VALUES(NULL,'Wall 6',96,565,0,'235');
+INSERT INTO items VALUES(NULL,'Wall 7',96,566,0,'236');
+INSERT INTO items VALUES(NULL,'bascinet',64,5132,0,'golden_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Wall 1',96,560,0,'230');
+INSERT INTO items VALUES(NULL,'Wall 2',96,561,0,'231');
+INSERT INTO items VALUES(NULL,'Wall 3',96,562,0,'232');
+INSERT INTO items VALUES(NULL,'Wall 4',96,563,0,'233');
+INSERT INTO items VALUES(NULL,'Greater Heal',92,8348,0,'209c');
+INSERT INTO items VALUES(NULL,'nose helmet',97,5134,0,'verite_helmets_nose');
+INSERT INTO items VALUES(NULL,'Wall 1',98,9535,0,'253f');
+INSERT INTO items VALUES(NULL,'Round Shield (Silver w. a Cross) (W/E)',99,5499,0,'157b');
+INSERT INTO items VALUES(NULL,'Catapult 99',72,5813,0,'16b5');
+INSERT INTO items VALUES(NULL,'Wall Sconce (W/E) (On)',73,2562,0,'a02');
+INSERT INTO items VALUES(NULL,'Wall Sconce (N/S) (Off)',73,2560,0,'a00');
+INSERT INTO items VALUES(NULL,'Wall Sconce (W/E) (Empty)',73,2561,0,'a01');
+INSERT INTO items VALUES(NULL,'Wall Torch (W/E) (Empty)',73,2566,0,'a06');
+INSERT INTO items VALUES(NULL,'Wall Torch (W/E) (On)',73,2567,0,'a07');
+INSERT INTO items VALUES(NULL,'Wall Torch (W/E) (Off)',73,2565,0,'a05');
+INSERT INTO items VALUES(NULL,'Round Shield (Gold w. a Cross) (W/E)',99,5501,0,'157d');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 38',100,7355,0,'1cbb');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 39',100,7356,0,'1cbc');
+INSERT INTO items VALUES(NULL,'Platform 1',101,1981,0,'7bd');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 37',100,7354,0,'1cba');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 42',100,7359,0,'1cbf');
+INSERT INTO items VALUES(NULL,'Carpeted Rostrum 3',102,1980,0,'7bc');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 40',100,7357,0,'1cbd');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 41',100,7358,0,'1cbe');
+INSERT INTO items VALUES(NULL,'Balista 228',76,16335,0,'3fcf');
+INSERT INTO items VALUES(NULL,'Stone Oven 1 (N/S) (2/2)',103,2353,0,'931');
+INSERT INTO items VALUES(NULL,'Stone Oven 1 (N/S) (1/2)',103,2352,0,'930');
+INSERT INTO items VALUES(NULL,'Stone Fireplace 1 (W/E) (1/2)',103,2359,0,'937');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 3 (W/E) (2/2)',103,2358,0,'936');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 3 (W/E) (1/2)',103,2357,0,'935');
+INSERT INTO items VALUES(NULL,'Balista 223',76,16330,0,'3fca');
+INSERT INTO items VALUES(NULL,'Stone Fountain (15/16) (Not Animated)',104,5977,0,'1759');
+INSERT INTO items VALUES(NULL,'Wall Torch (N/S) (Empty)',73,2571,0,'a0b');
+INSERT INTO items VALUES(NULL,'Wall Torch (N/S) (On)',73,2572,0,'a0c');
+INSERT INTO items VALUES(NULL,'Wall Torch (N/S) (Off)',73,2570,0,'a0a');
+INSERT INTO items VALUES(NULL,'Candle 1 (On)',73,2575,0,'a0f');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 29',100,7346,0,'1cb2');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 30',100,7347,0,'1cb3');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 19',105,1972,0,'7b4');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 20',105,1973,0,'7b5');
+INSERT INTO items VALUES(NULL,'Cave Steps 6',106,1970,0,'7b2');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 18',105,1971,0,'7b3');
+INSERT INTO items VALUES(NULL,'Cave Steps 4',106,1968,0,'7b0');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 32',100,7349,0,'1cb5');
+INSERT INTO items VALUES(NULL,'Balista 219',76,16326,0,'3fc6');
+INSERT INTO items VALUES(NULL,'Balista 220',76,16327,0,'3fc7');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 35',100,7352,0,'1cb8');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 36',100,7353,0,'1cb9');
+INSERT INTO items VALUES(NULL,'Balista 215',76,16322,0,'3fc2');
+INSERT INTO items VALUES(NULL,'Balista 216',76,16323,0,'3fc3');
+INSERT INTO items VALUES(NULL,'Cave Steps 8',106,1976,0,'7b8');
+INSERT INTO items VALUES(NULL,'Cave Steps 9',106,1977,0,'7b9');
+INSERT INTO items VALUES(NULL,'Board (W/E)',107,7130,0,'1bda');
+INSERT INTO items VALUES(NULL,'Boards 2 (W/E)',107,7132,0,'1bdc');
+INSERT INTO items VALUES(NULL,'Boards 1 (W/E)',107,7131,0,'1bdb');
+INSERT INTO items VALUES(NULL,'Logs 1 (W/E)',107,7134,0,'1bde');
+INSERT INTO items VALUES(NULL,'Log (W/E)',107,7133,0,'1bdd');
+INSERT INTO items VALUES(NULL,'Logs 2 (W/E)',107,7135,0,'1bdf');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (6/9)',108,6154,0,'180a');
+INSERT INTO items VALUES(NULL,'Gas Trap 3',109,4412,0,'113c');
+INSERT INTO items VALUES(NULL,'Gas Trap 2',109,4411,0,'113b');
+INSERT INTO items VALUES(NULL,'Gas Trap 1',109,4410,0,'113a');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E; falling) 1',109,4415,0,'113f');
+INSERT INTO items VALUES(NULL,'Gas Trap 5',109,4414,0,'113e');
+INSERT INTO items VALUES(NULL,'Gas Trap 4',109,4413,0,'113d');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 20',110,1943,0,'797');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 19',110,1942,0,'796');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 18',110,1941,0,'795');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 17',110,1940,0,'794');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 16',110,1939,0,'793');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 15',110,1938,0,'792');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 14',110,1937,0,'791');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 13',110,1936,0,'790');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 22',110,1945,0,'799');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 21',110,1944,0,'798');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E) 7',109,4409,0,'1139');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E) 6',109,4408,0,'1138');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E) 1',109,4403,0,'1133');
+INSERT INTO items VALUES(NULL,'Dart Trap (W/E) 3',109,4402,0,'1132');
+INSERT INTO items VALUES(NULL,'Dart Trap (W/E) 2',109,4401,0,'1131');
+INSERT INTO items VALUES(NULL,'Dart Trap (W/E) 1',109,4400,0,'1130');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E) 5',109,4407,0,'1137');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E) 4',109,4406,0,'1136');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E) 3',109,4405,0,'1135');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E) 2',109,4404,0,'1134');
+INSERT INTO items VALUES(NULL,'Feather',34,7121,0,'1bd1');
+INSERT INTO items VALUES(NULL,'Feathers 2',34,7123,0,'1bd3');
+INSERT INTO items VALUES(NULL,'Feathers 1',34,7122,0,'1bd2');
+INSERT INTO items VALUES(NULL,'Shafts 1',34,7125,0,'1bd5');
+INSERT INTO items VALUES(NULL,'Shaft',34,7124,0,'1bd4');
+INSERT INTO items VALUES(NULL,'Board (N/S)',107,7127,0,'1bd7');
+INSERT INTO items VALUES(NULL,'Shafts 2',34,7126,0,'1bd6');
+INSERT INTO items VALUES(NULL,'Boards 2 (N/S)',107,7129,0,'1bd9');
+INSERT INTO items VALUES(NULL,'Boards 1 (N/S)',107,7128,0,'1bd8');
+INSERT INTO items VALUES(NULL,'Cave Steps 3',106,1951,0,'79f');
+INSERT INTO items VALUES(NULL,'Cave Steps 2',106,1950,0,'79e');
+INSERT INTO items VALUES(NULL,'Cave Steps 1',106,1949,0,'79d');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 25',110,1948,0,'79c');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 24',110,1947,0,'79b');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 23',110,1946,0,'79a');
+INSERT INTO items VALUES(NULL,'chainmail coif',111,5051,0,'dull_copper_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Obsidian',112,3977,0,'f89');
+INSERT INTO items VALUES(NULL,'Nightshade',112,3976,0,'f88');
+INSERT INTO items VALUES(NULL,'Ginseng',112,3973,0,'f85');
+INSERT INTO items VALUES(NULL,'Garlic',112,3972,0,'f84');
+INSERT INTO items VALUES(NULL,'Eyes of Newt',112,3975,0,'f87');
+INSERT INTO items VALUES(NULL,'Mandrake Root',112,3974,0,'f86');
+INSERT INTO items VALUES(NULL,'Fertile Dirt',112,3969,0,'f81');
+INSERT INTO items VALUES(NULL,'Daemon Bone',112,3968,0,'f80');
+INSERT INTO items VALUES(NULL,'Executioners cap',112,3971,0,'f83');
+INSERT INTO items VALUES(NULL,'Dragon''s Blood',112,3970,0,'f82');
+INSERT INTO items VALUES(NULL,'Ankh 1',70,2,0,'2');
+INSERT INTO items VALUES(NULL,'Pillory 9',113,4741,0,'1285');
+INSERT INTO items VALUES(NULL,'Flour Mill 1 (W/E) (1/2)',114,6432,0,'1920');
+INSERT INTO items VALUES(NULL,'Flour Mill 2 (W/E) (1/2)',114,6433,0,'1921');
+INSERT INTO items VALUES(NULL,'Flour Mill 1 (W/E) (2/2)',114,6434,0,'1922');
+INSERT INTO items VALUES(NULL,'Flour Mill 2 (W/E) (2/2)',114,6435,0,'1923');
+INSERT INTO items VALUES(NULL,'Serpent''s Scale',112,3982,0,'f8e');
+INSERT INTO items VALUES(NULL,'Spider''s Silk',112,3981,0,'f8d');
+INSERT INTO items VALUES(NULL,'Volcanic Ash',112,3983,0,'f8f');
+INSERT INTO items VALUES(NULL,'Pig Iron',112,3978,0,'f8a');
+INSERT INTO items VALUES(NULL,'Sulfurous Ash',112,3980,0,'f8c');
+INSERT INTO items VALUES(NULL,'Pumice',112,3979,0,'f8b');
+INSERT INTO items VALUES(NULL,'Flour Mill 3 (W/E) (2/2)',114,6438,0,'1926');
+INSERT INTO items VALUES(NULL,'Skeletal Mount',115,9751,0,'2617');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (W/E) 5',116,7517,0,'1d5d');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (W/E) 1',116,7518,0,'1d5e');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (W/E) 2',116,7519,0,'1d5f');
+INSERT INTO items VALUES(NULL,'helmet',25,5130,0,'valorite_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (W/E) 2',116,7514,0,'1d5a');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (W/E) 3',116,7515,0,'1d5b');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 8',12,6666,0,'1a0a');
+INSERT INTO items VALUES(NULL,'Shield (Gold w. a Snake) (N/S)',99,5496,0,'1578');
+INSERT INTO items VALUES(NULL,'ringmail tunic',43,5100,0,'valorite_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (W/E) 3',116,7508,0,'1d54');
+INSERT INTO items VALUES(NULL,'Chains 1',113,6663,0,'1a07');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 4',12,6660,0,'1a04');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 5',12,6661,0,'1a05');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (W/E) 5',116,7504,0,'1d50');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 3',12,6659,0,'1a03');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (W/E) 1',116,7506,0,'1d52');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 1',12,6657,0,'1a01');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (W/E) 7',116,7512,0,'1d58');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (W/E) 1',116,7513,0,'1d59');
+INSERT INTO items VALUES(NULL,'Chains 2',113,6664,0,'1a08');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 7',12,6665,0,'1a09');
+INSERT INTO items VALUES(NULL,'Oval Shield (Silver w. a Snake) (W/E)',99,5491,0,'1573');
+INSERT INTO items VALUES(NULL,'Shield (Gold w. a Star) (W/E)',99,5489,0,'1571');
+INSERT INTO items VALUES(NULL,'platemail gloves',117,5140,0,'golden_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Shield (Silver w. a Snake) (W/E)',99,5495,0,'1577');
+INSERT INTO items VALUES(NULL,'Oval Shield (Gold w. a Snake) (W/E)',99,5493,0,'1575');
+INSERT INTO items VALUES(NULL,'Vase 1',118,2885,0,'b45');
+INSERT INTO items VALUES(NULL,'Water Trough (W/E) (2/2)',13,2884,0,'b44');
+INSERT INTO items VALUES(NULL,'Vase 3',118,2887,0,'b47');
+INSERT INTO items VALUES(NULL,'Vase 2',118,2886,0,'b46');
+INSERT INTO items VALUES(NULL,'Water Trough (N/S) (1/2)',13,2881,0,'b41');
+INSERT INTO items VALUES(NULL,'Counter (W/E) (1/2)',89,2880,0,'b40');
+INSERT INTO items VALUES(NULL,'Water Trough (W/E) (1/2)',13,2883,0,'b43');
+INSERT INTO items VALUES(NULL,'Water Trough (N/S) (2/2)',13,2882,0,'b42');
+INSERT INTO items VALUES(NULL,'Writing Table 1',89,2889,0,'b49');
+INSERT INTO items VALUES(NULL,'Vase 4',118,2888,0,'b48');
+INSERT INTO items VALUES(NULL,'Wall 30',98,16123,0,'3efb');
+INSERT INTO items VALUES(NULL,'Wall 31',98,16124,0,'3efc');
+INSERT INTO items VALUES(NULL,'Wall 29',98,16122,0,'3efa');
+INSERT INTO items VALUES(NULL,'Wall 34',98,16127,0,'3eff');
+INSERT INTO items VALUES(NULL,'Wall 32',98,16125,0,'3efd');
+INSERT INTO items VALUES(NULL,'Wall 33',98,16126,0,'3efe');
+INSERT INTO items VALUES(NULL,'Juggernaut',115,9746,0,'2612');
+INSERT INTO items VALUES(NULL,'katana',3,5119,0,'13ff');
+INSERT INTO items VALUES(NULL,'large battle axe',35,5115,0,'13fb');
+INSERT INTO items VALUES(NULL,'heavy crossbow',21,5116,0,'13fc');
+INSERT INTO items VALUES(NULL,'Wall 21',98,16114,0,'3ef2');
+INSERT INTO items VALUES(NULL,'Wall 22',98,16115,0,'3ef3');
+INSERT INTO items VALUES(NULL,'Horde Demon',115,9745,0,'2611');
+INSERT INTO items VALUES(NULL,'Wall 25',98,16118,0,'3ef6');
+INSERT INTO items VALUES(NULL,'Small Wall 11',22,8640,0,'21c0');
+INSERT INTO items VALUES(NULL,'Wall 23',98,16116,0,'3ef4');
+INSERT INTO items VALUES(NULL,'Wall 24',98,16117,0,'3ef5');
+INSERT INTO items VALUES(NULL,'Wall 27',98,16120,0,'3ef8');
+INSERT INTO items VALUES(NULL,'Wall 28',98,16121,0,'3ef9');
+INSERT INTO items VALUES(NULL,'Fancy Wooden Chair 1',78,2894,0,'b4e');
+INSERT INTO items VALUES(NULL,'Fancy Wooden Chair 2',78,2895,0,'b4f');
+INSERT INTO items VALUES(NULL,'Writing Table 2',89,2890,0,'b4a');
+INSERT INTO items VALUES(NULL,'Writing Table 4',89,2892,0,'b4c');
+INSERT INTO items VALUES(NULL,'Writing Table 3',89,2891,0,'b4b');
+INSERT INTO items VALUES(NULL,'Golem',115,9744,0,'2610');
+INSERT INTO items VALUES(NULL,'shepherd''s crook',119,5108,0,'13f4');
+INSERT INTO items VALUES(NULL,'ringmail leggings',38,5104,0,'13f0');
+INSERT INTO items VALUES(NULL,'gnarled staff',119,5112,0,'13f8');
+INSERT INTO items VALUES(NULL,'Goblet 2',14,2483,0,'9b3');
+INSERT INTO items VALUES(NULL,'Flour Mill 1 (N/S) (1/2)',114,6444,0,'192c');
+INSERT INTO items VALUES(NULL,'Flour Mill 2 (N/S) (1/2)',114,6445,0,'192d');
+INSERT INTO items VALUES(NULL,'Flour Mill 1 (N/S) (2/2)',114,6446,0,'192e');
+INSERT INTO items VALUES(NULL,'Water 7',33,13428,0,'3474');
+INSERT INTO items VALUES(NULL,'Water 8',33,13429,0,'3475');
+INSERT INTO items VALUES(NULL,'Iron Gate 1 (W/SW)',120,2096,0,'830');
+INSERT INTO items VALUES(NULL,'Water 10',33,13431,0,'3477');
+INSERT INTO items VALUES(NULL,'Water 3',33,13424,0,'3470');
+INSERT INTO items VALUES(NULL,'Water 4',33,13425,0,'3471');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 20',121,2100,0,'834');
+INSERT INTO items VALUES(NULL,'Fence 1',122,2101,0,'835');
+INSERT INTO items VALUES(NULL,'Wall 2',123,255,0,'ff');
+INSERT INTO items VALUES(NULL,'Fence 4',122,2104,0,'838');
+INSERT INTO items VALUES(NULL,'Gate (S/SW)',124,2105,0,'839');
+INSERT INTO items VALUES(NULL,'Water 11',33,13432,0,'3478');
+INSERT INTO items VALUES(NULL,'Water 12',33,13433,0,'3479');
+INSERT INTO items VALUES(NULL,'Pear 2',19,5933,0,'172d');
+INSERT INTO items VALUES(NULL,'Jester Hat',58,5934,0,'172e');
+INSERT INTO items VALUES(NULL,'Limes',19,5931,0,'172b');
+INSERT INTO items VALUES(NULL,'ringmail leggings',125,5104,0,'golden_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'Lime',19,5930,0,'172a');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 2 (S/SE)',126,8175,0,'1fef');
+INSERT INTO items VALUES(NULL,'Wall 6',127,972,0,'3cc');
+INSERT INTO items VALUES(NULL,'Lemon',19,5928,0,'1728');
+INSERT INTO items VALUES(NULL,'Lemons',19,5929,0,'1729');
+INSERT INTO items VALUES(NULL,'Coconut 3',19,5926,0,'1726');
+INSERT INTO items VALUES(NULL,'Bunch of Dates',19,5927,0,'1727');
+INSERT INTO items VALUES(NULL,'Coconut 1 (N/S)',19,5924,0,'1724');
+INSERT INTO items VALUES(NULL,'Coconut 2',19,5925,0,'1725');
+INSERT INTO items VALUES(NULL,'Banana 3 (N/S)',19,5922,0,'1722');
+INSERT INTO items VALUES(NULL,'Coconut 1 (W/E)',19,5923,0,'1723');
+INSERT INTO items VALUES(NULL,'Banana 2 (W/E)',19,5920,0,'1720');
+INSERT INTO items VALUES(NULL,'Banana 3 (W/E)',19,5921,0,'1721');
+INSERT INTO items VALUES(NULL,'Water 16',33,13437,0,'347d');
+INSERT INTO items VALUES(NULL,'Water 17',33,13438,0,'347e');
+INSERT INTO items VALUES(NULL,'Water 18',33,13439,0,'347f');
+INSERT INTO items VALUES(NULL,'Gate (S/NE)',124,2111,0,'83f');
+INSERT INTO items VALUES(NULL,'Water 13',33,13434,0,'347a');
+INSERT INTO items VALUES(NULL,'Water 14',33,13435,0,'347b');
+INSERT INTO items VALUES(NULL,'Water 15',33,13436,0,'347c');
+INSERT INTO items VALUES(NULL,'platemail',36,5141,0,'bronze_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Banner 1 (W/E) 3',128,5512,0,'1588');
+INSERT INTO items VALUES(NULL,'Banner 2 (W/E) 1',128,5513,0,'1589');
+INSERT INTO items VALUES(NULL,'Shield (Silver w. Sword) (N/S) 1',99,5506,0,'1582');
+INSERT INTO items VALUES(NULL,'Shield (Silver w. Sword) (N/S) 2',99,5507,0,'1583');
+INSERT INTO items VALUES(NULL,'Round Shield (Gold) (N/S)',99,5504,0,'1580');
+INSERT INTO items VALUES(NULL,'Round Shield (Gold) (W/E)',99,5505,0,'1581');
+INSERT INTO items VALUES(NULL,'Banner 1 (W/E) 1',128,5510,0,'1586');
+INSERT INTO items VALUES(NULL,'Banner 1 (W/E) 2',128,5511,0,'1587');
+INSERT INTO items VALUES(NULL,'Shield (Gold w. Sword) (N/S) 1',99,5508,0,'1584');
+INSERT INTO items VALUES(NULL,'Shield (Gold w. Sword) (N/S) 2',99,5509,0,'1585');
+INSERT INTO items VALUES(NULL,'Banner 2 (W/E) 3',128,5515,0,'158b');
+INSERT INTO items VALUES(NULL,'Banner 3 (W/E) 1',128,5516,0,'158c');
+INSERT INTO items VALUES(NULL,'Banner 2 (W/E) 2',128,5514,0,'158a');
+INSERT INTO items VALUES(NULL,'Banner Hanger (W/E)',128,5519,0,'158f');
+INSERT INTO items VALUES(NULL,'Banner 3 (W/E) 2',128,5517,0,'158d');
+INSERT INTO items VALUES(NULL,'Banner 3 (W/E) 3',128,5518,0,'158e');
+INSERT INTO items VALUES(NULL,'Wooden Planks 27',129,1244,0,'4dc');
+INSERT INTO items VALUES(NULL,'Wooden Planks 26',129,1243,0,'4db');
+INSERT INTO items VALUES(NULL,'Wooden Planks 25',129,1242,0,'4da');
+INSERT INTO items VALUES(NULL,'Wooden Planks 30',129,1247,0,'4df');
+INSERT INTO items VALUES(NULL,'Wooden Planks 29',129,1246,0,'4de');
+INSERT INTO items VALUES(NULL,'Wooden Planks 28',129,1245,0,'4dd');
+INSERT INTO items VALUES(NULL,'Wall 13',130,451,0,'1c3');
+INSERT INTO items VALUES(NULL,'Wall 12',130,450,0,'1c2');
+INSERT INTO items VALUES(NULL,'Wall 11',130,449,0,'1c1');
+INSERT INTO items VALUES(NULL,'Wall 10',130,448,0,'1c0');
+INSERT INTO items VALUES(NULL,'Window 4',130,455,0,'1c7');
+INSERT INTO items VALUES(NULL,'Window 3',130,454,0,'1c6');
+INSERT INTO items VALUES(NULL,'Window 2',130,453,0,'1c5');
+INSERT INTO items VALUES(NULL,'Window 1',130,452,0,'1c4');
+INSERT INTO items VALUES(NULL,'Small Wall 2',130,457,0,'1c9');
+INSERT INTO items VALUES(NULL,'Small Wall 1',130,456,0,'1c8');
+INSERT INTO items VALUES(NULL,'Stone Fireplace 2 (W/E) (2/2)',103,2393,0,'959');
+INSERT INTO items VALUES(NULL,'Field of Poison (N/S) 1',28,14613,0,'3915');
+INSERT INTO items VALUES(NULL,'Wooden Planks 24',129,1241,0,'4d9');
+INSERT INTO items VALUES(NULL,'Wooden Planks 23',129,1240,0,'4d8');
+INSERT INTO items VALUES(NULL,'Wooden Planks 18',129,1235,0,'4d3');
+INSERT INTO items VALUES(NULL,'Wooden Planks 17',129,1234,0,'4d2');
+INSERT INTO items VALUES(NULL,'close helmet',131,5128,0,'shadow_helmets_close');
+INSERT INTO items VALUES(NULL,'Wooden Planks 15',129,1232,0,'4d0');
+INSERT INTO items VALUES(NULL,'Wooden Planks 22',129,1239,0,'4d7');
+INSERT INTO items VALUES(NULL,'Wooden Planks 21',129,1238,0,'4d6');
+INSERT INTO items VALUES(NULL,'Wooden Planks 20',129,1237,0,'4d5');
+INSERT INTO items VALUES(NULL,'Wooden Planks 19',129,1236,0,'4d4');
+INSERT INTO items VALUES(NULL,'Pole 2',130,460,0,'1cc');
+INSERT INTO items VALUES(NULL,'Pole 1',130,459,0,'1cb');
+INSERT INTO items VALUES(NULL,'Small Wall 9',47,458,0,'1ca');
+INSERT INTO items VALUES(NULL,'Wall 1',132,463,0,'1cf');
+INSERT INTO items VALUES(NULL,'Pole 4',130,462,0,'1ce');
+INSERT INTO items VALUES(NULL,'Pole 3',130,461,0,'1cd');
+INSERT INTO items VALUES(NULL,'Wall 8',133,534,0,'216');
+INSERT INTO items VALUES(NULL,'Wall 9',133,535,0,'217');
+INSERT INTO items VALUES(NULL,'Wall 6',133,532,0,'214');
+INSERT INTO items VALUES(NULL,'Wall 7',133,533,0,'215');
+INSERT INTO items VALUES(NULL,'Wall 4',133,530,0,'212');
+INSERT INTO items VALUES(NULL,'Wall 5',133,531,0,'213');
+INSERT INTO items VALUES(NULL,'Wall 2',133,528,0,'210');
+INSERT INTO items VALUES(NULL,'Wall 3',133,529,0,'211');
+INSERT INTO items VALUES(NULL,'Snowdrops 1',134,3208,0,'c88');
+INSERT INTO items VALUES(NULL,'Champion Flowers 3',134,3209,0,'c89');
+INSERT INTO items VALUES(NULL,'Wall 10',133,536,0,'218');
+INSERT INTO items VALUES(NULL,'Wall 11',133,537,0,'219');
+INSERT INTO items VALUES(NULL,'Spit 2 (W/E) (2/2)',135,7829,0,'1e95');
+INSERT INTO items VALUES(NULL,'Tiller 5',136,15970,0,'3e62');
+INSERT INTO items VALUES(NULL,'Spit 1 (N/S) (2/2)',135,7831,0,'1e97');
+INSERT INTO items VALUES(NULL,'Spit (W/E) (1/2)',135,7830,0,'1e96');
+INSERT INTO items VALUES(NULL,'Skinned Deer (W/E)',135,7825,0,'1e91');
+INSERT INTO items VALUES(NULL,'Skinned Deer (N/S)',135,7824,0,'1e90');
+INSERT INTO items VALUES(NULL,'Skinned Rabbit (W/E)',135,7827,0,'1e93');
+INSERT INTO items VALUES(NULL,'Tiller 6',136,15971,0,'3e63');
+INSERT INTO items VALUES(NULL,'Cannon Balls',67,3700,0,'e74');
+INSERT INTO items VALUES(NULL,'Spit (N/S) (1/2)',135,7833,0,'1e99');
+INSERT INTO items VALUES(NULL,'Tiller 4',136,15968,0,'3e60');
+INSERT INTO items VALUES(NULL,'Ship 5',137,15974,0,'3e66');
+INSERT INTO items VALUES(NULL,'Ship 6',137,15975,0,'3e67');
+INSERT INTO items VALUES(NULL,'Hold 1',138,15972,0,'3e64');
+INSERT INTO items VALUES(NULL,'Hatch 1',139,15973,0,'3e65');
+INSERT INTO items VALUES(NULL,'Wall 3',82,543,0,'21f');
+INSERT INTO items VALUES(NULL,'Foxglove Flowers 2',134,3210,0,'c8a');
+INSERT INTO items VALUES(NULL,'Wall 1',82,541,0,'21d');
+INSERT INTO items VALUES(NULL,'Wall 2',82,542,0,'21e');
+INSERT INTO items VALUES(NULL,'White Poppies',134,3213,0,'c8d');
+INSERT INTO items VALUES(NULL,'Snowdrops 2',134,3214,0,'c8e');
+INSERT INTO items VALUES(NULL,'Hedge 1',45,3215,0,'c8f');
+INSERT INTO items VALUES(NULL,'Wall 12',133,538,0,'21a');
+INSERT INTO items VALUES(NULL,'plate armor',18,7172,0,'valorite_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Wall 17',98,9552,0,'2550');
+INSERT INTO items VALUES(NULL,'Small Wall 2',140,96,0,'60');
+INSERT INTO items VALUES(NULL,'Wall 19',98,9554,0,'2552');
+INSERT INTO items VALUES(NULL,'Wall 20',98,9555,0,'2553');
+INSERT INTO items VALUES(NULL,'ringmail tunic',125,5100,0,'golden_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Small Wall 4',140,98,0,'62');
+INSERT INTO items VALUES(NULL,'Hook 5',141,7838,0,'1e9e');
+INSERT INTO items VALUES(NULL,'Hook 4',141,7837,0,'1e9d');
+INSERT INTO items VALUES(NULL,'Hook 6',141,7839,0,'1e9f');
+INSERT INTO items VALUES(NULL,'Hook 1',141,7834,0,'1e9a');
+INSERT INTO items VALUES(NULL,'Rock 30',29,13358,0,'342e');
+INSERT INTO items VALUES(NULL,'Hook 3',141,7836,0,'1e9c');
+INSERT INTO items VALUES(NULL,'Hook 2',141,7835,0,'1e9b');
+INSERT INTO items VALUES(NULL,'Roof 3',142,1597,0,'63d');
+INSERT INTO items VALUES(NULL,'Smaller Wall 3',140,101,0,'65');
+INSERT INTO items VALUES(NULL,'Untidy Gray Bed (N/S) (1/2)',91,2664,0,'a68');
+INSERT INTO items VALUES(NULL,'Untidy Gray Bed (W/E) (2/2) (Pillow)',91,2665,0,'a69');
+INSERT INTO items VALUES(NULL,'Untidy Gray Bed (N/S) (2/2) (Pillow)',91,2662,0,'a66');
+INSERT INTO items VALUES(NULL,'Untidy Gray Bed (N/S) (2/2)',91,2663,0,'a67');
+INSERT INTO items VALUES(NULL,'White Bed (W/E) (2/2)',91,2656,0,'a60');
+INSERT INTO items VALUES(NULL,'White Bed (W/E) (1/2)',91,2657,0,'a61');
+INSERT INTO items VALUES(NULL,'Gray Bed (W/E) (1/2)',91,2658,0,'a62');
+INSERT INTO items VALUES(NULL,'Gray Bed (N/S) (2/2)',91,2659,0,'a63');
+INSERT INTO items VALUES(NULL,'Mass Curse',92,8365,0,'20ad');
+INSERT INTO items VALUES(NULL,'Pickaxe (W/E)',80,3717,0,'e85');
+INSERT INTO items VALUES(NULL,'Carpet 7',143,2755,0,'ac3');
+INSERT INTO items VALUES(NULL,'Carpet 6',143,2754,0,'ac2');
+INSERT INTO items VALUES(NULL,'Carpet 5',143,2753,0,'ac1');
+INSERT INTO items VALUES(NULL,'Carpet 4',143,2752,0,'ac0');
+INSERT INTO items VALUES(NULL,'Carpet 2',144,2759,0,'ac7');
+INSERT INTO items VALUES(NULL,'Stone Step 4',145,2328,0,'918');
+INSERT INTO items VALUES(NULL,'Carpet 9',143,2757,0,'ac5');
+INSERT INTO items VALUES(NULL,'Carpet 8',143,2756,0,'ac4');
+INSERT INTO items VALUES(NULL,'Stone Step 1',145,2325,0,'915');
+INSERT INTO items VALUES(NULL,'Blood 26',55,7386,0,'1cda');
+INSERT INTO items VALUES(NULL,'Blood 27',55,7387,0,'1cdb');
+INSERT INTO items VALUES(NULL,'Blood 28',55,7388,0,'1cdc');
+INSERT INTO items VALUES(NULL,'Dirt Patch 1',146,2321,0,'911');
+INSERT INTO items VALUES(NULL,'Body 1',147,7390,0,'1cde');
+INSERT INTO items VALUES(NULL,'Legs 1',147,7391,0,'1cdf');
+INSERT INTO items VALUES(NULL,'Dirt Patch 2',146,2322,0,'912');
+INSERT INTO items VALUES(NULL,'Folded Blanket 2',91,2669,0,'a6d');
+INSERT INTO items VALUES(NULL,'Folded Blanket 3',91,2670,0,'a6e');
+INSERT INTO items VALUES(NULL,'Folded Blanket 4',91,2671,0,'a6f');
+INSERT INTO items VALUES(NULL,'Untidy Gray Bed (W/E) (2/2)',91,2666,0,'a6a');
+INSERT INTO items VALUES(NULL,'Untidy Gray Bed (W/E) (1/2)',91,2667,0,'a6b');
+INSERT INTO items VALUES(NULL,'Folded Blanket 1',91,2668,0,'a6c');
+INSERT INTO items VALUES(NULL,'Blood 24',55,7384,0,'1cd8');
+INSERT INTO items VALUES(NULL,'Blood 25',55,7385,0,'1cd9');
+INSERT INTO items VALUES(NULL,'Carpet 5',144,2762,0,'aca');
+INSERT INTO items VALUES(NULL,'Small Fish 3',148,3544,0,'dd8');
+INSERT INTO items VALUES(NULL,'Carpet 10',144,2767,0,'acf');
+INSERT INTO items VALUES(NULL,'Carpet 9',144,2766,0,'ace');
+INSERT INTO items VALUES(NULL,'Carpet 8',144,2765,0,'acd');
+INSERT INTO items VALUES(NULL,'Blood 16',55,7376,0,'1cd0');
+INSERT INTO items VALUES(NULL,'Blood 17',55,7377,0,'1cd1');
+INSERT INTO items VALUES(NULL,'Blood 18',55,7378,0,'1cd2');
+INSERT INTO items VALUES(NULL,'Blood 19',55,7379,0,'1cd3');
+INSERT INTO items VALUES(NULL,'Blood 20',55,7380,0,'1cd4');
+INSERT INTO items VALUES(NULL,'Blood 21',55,7381,0,'1cd5');
+INSERT INTO items VALUES(NULL,'Blood 22',55,7382,0,'1cd6');
+INSERT INTO items VALUES(NULL,'Blood 23',55,7383,0,'1cd7');
+INSERT INTO items VALUES(NULL,'Strong Box',65,3712,0,'e80');
+INSERT INTO items VALUES(NULL,'Invisibility',92,8363,0,'20ab');
+INSERT INTO items VALUES(NULL,'Sack of Flour (W/E)',114,4153,0,'1039');
+INSERT INTO items VALUES(NULL,'Rock 27',29,13353,0,'3429');
+INSERT INTO items VALUES(NULL,'Sail 4',86,15978,0,'3e6a');
+INSERT INTO items VALUES(NULL,'Spar 2',88,15982,0,'3e6e');
+INSERT INTO items VALUES(NULL,'Wall 19',41,913,0,'391');
+INSERT INTO items VALUES(NULL,'Wall 5',149,170,0,'aa');
+INSERT INTO items VALUES(NULL,'Roof 21',150,1584,0,'630');
+INSERT INTO items VALUES(NULL,'Wall 7',149,172,0,'ac');
+INSERT INTO items VALUES(NULL,'Wall 6',149,171,0,'ab');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 1',149,174,0,'ae');
+INSERT INTO items VALUES(NULL,'Wall 8',149,173,0,'ad');
+INSERT INTO items VALUES(NULL,'Roof 22',150,1585,0,'631');
+INSERT INTO items VALUES(NULL,'Altar 3',151,4624,0,'1210');
+INSERT INTO items VALUES(NULL,'Roof 23',152,1587,0,'633');
+INSERT INTO items VALUES(NULL,'Roof 24',152,1588,0,'634');
+INSERT INTO items VALUES(NULL,'Arch 2',140,110,0,'6e');
+INSERT INTO items VALUES(NULL,'Roof 24',32,1590,0,'636');
+INSERT INTO items VALUES(NULL,'Roof 2',142,1596,0,'63c');
+INSERT INTO items VALUES(NULL,'Roof 1',153,1591,0,'637');
+INSERT INTO items VALUES(NULL,'Stone Face (W/E; w. fire) 1',109,4369,0,'1111');
+INSERT INTO items VALUES(NULL,'Stone Face (W/E) 2',109,4368,0,'1110');
+INSERT INTO items VALUES(NULL,'Stone Face (W/E; w. fire) 3',109,4371,0,'1113');
+INSERT INTO items VALUES(NULL,'Stone Face (W/E; w. fire) 2',109,4370,0,'1112');
+INSERT INTO items VALUES(NULL,'Stone Face (W/E; w. fire) 5',109,4373,0,'1115');
+INSERT INTO items VALUES(NULL,'Stone Face (W/E; w. fire) 4',109,4372,0,'1114');
+INSERT INTO items VALUES(NULL,'Saw Trap (W/E) 2',109,4375,0,'1117');
+INSERT INTO items VALUES(NULL,'Saw Trap (W/E) 1',109,4374,0,'1116');
+INSERT INTO items VALUES(NULL,'Saw Trap (W/E) 4',109,4377,0,'1119');
+INSERT INTO items VALUES(NULL,'Loose Grain',13,5193,0,'1449');
+INSERT INTO items VALUES(NULL,'Stone Throne 2',78,4633,0,'1219');
+INSERT INTO items VALUES(NULL,'Small Wall 8',22,161,0,'a1');
+INSERT INTO items VALUES(NULL,'Small Wall 7',22,160,0,'a0');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',22,163,0,'a3');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',22,162,0,'a2');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',22,165,0,'a5');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',22,164,0,'a4');
+INSERT INTO items VALUES(NULL,'Iron Gate 1 (S/SW)',120,2084,0,'824');
+INSERT INTO items VALUES(NULL,'Wall 1',149,166,0,'a6');
+INSERT INTO items VALUES(NULL,'Wall 4',149,169,0,'a9');
+INSERT INTO items VALUES(NULL,'Wall 3',149,168,0,'a8');
+INSERT INTO items VALUES(NULL,'Saw Trap (W/E) 5',109,4378,0,'111a');
+INSERT INTO items VALUES(NULL,'bone armor',154,5199,0,'144f');
+INSERT INTO items VALUES(NULL,'Spike Trap (N/S) 2',109,4380,0,'111c');
+INSERT INTO items VALUES(NULL,'Spike Trap (N/S) 1',109,4379,0,'111b');
+INSERT INTO items VALUES(NULL,'Spike Trap (N/S) 4',109,4382,0,'111e');
+INSERT INTO items VALUES(NULL,'Spike Trap (N/S) 3',109,4381,0,'111d');
+INSERT INTO items VALUES(NULL,'Spike Trap (N/S) 5',109,4383,0,'111f');
+INSERT INTO items VALUES(NULL,'Pitcher of Ale 2',155,8086,0,'1f96');
+INSERT INTO items VALUES(NULL,'Pitcher of Cider 1',155,8087,0,'1f97');
+INSERT INTO items VALUES(NULL,'Glass of Water 4',155,8084,0,'1f94');
+INSERT INTO items VALUES(NULL,'Pitcher of Ale 1',155,8085,0,'1f95');
+INSERT INTO items VALUES(NULL,'Glass of Water 2',155,8082,0,'1f92');
+INSERT INTO items VALUES(NULL,'Glass of Water 3',155,8083,0,'1f93');
+INSERT INTO items VALUES(NULL,'Glass of Wine 4',155,8080,0,'1f90');
+INSERT INTO items VALUES(NULL,'Glass of Water 1',155,8081,0,'1f91');
+INSERT INTO items VALUES(NULL,'Pitcher of Cider 2',155,8088,0,'1f98');
+INSERT INTO items VALUES(NULL,'Pitcher of Liquor 1',155,8089,0,'1f99');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (N/S) 5',116,7547,0,'1d7b');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (N/S) 1',116,7548,0,'1d7c');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (N/S) 4',116,7546,0,'1d7a');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (N/S) 4',116,7551,0,'1d7f');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (N/S) 2',116,7549,0,'1d7d');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (N/S) 3',116,7550,0,'1d7e');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (N/S) 2',116,7538,0,'1d72');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (N/S) 3',116,7539,0,'1d73');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (N/S) 5',116,7536,0,'1d70');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (N/S) 1',116,7537,0,'1d71');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (N/S) 6',116,7542,0,'1d76');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (N/S) 1',116,7543,0,'1d77');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (N/S) 4',116,7540,0,'1d74');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (N/S) 5',116,7541,0,'1d75');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (N/S) 2',116,7544,0,'1d78');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (N/S) 3',116,7545,0,'1d79');
+INSERT INTO items VALUES(NULL,'Jester Suit (N/S)',1,8095,0,'1f9f');
+INSERT INTO items VALUES(NULL,'Pitcher of Water 3',155,8093,0,'1f9d');
+INSERT INTO items VALUES(NULL,'Pitcher of Water 4',155,8094,0,'1f9e');
+INSERT INTO items VALUES(NULL,'Pitcher of Wine 1',155,8091,0,'1f9b');
+INSERT INTO items VALUES(NULL,'Pitcher of Wine 2',155,8092,0,'1f9c');
+INSERT INTO items VALUES(NULL,'Pitcher of Liquor 2',155,8090,0,'1f9a');
+INSERT INTO items VALUES(NULL,'Open Sack of Flour (W/E)',114,4154,0,'103a');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',47,409,0,'199');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',47,408,0,'198');
+INSERT INTO items VALUES(NULL,'Column 2',47,405,0,'195');
+INSERT INTO items VALUES(NULL,'Big Candlabra (On)',73,2854,0,'b26');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',47,407,0,'197');
+INSERT INTO items VALUES(NULL,'Column 3',47,406,0,'196');
+INSERT INTO items VALUES(NULL,'Arch 7',47,401,0,'191');
+INSERT INTO items VALUES(NULL,'Arch 6',47,400,0,'190');
+INSERT INTO items VALUES(NULL,'Lamp Post 1 (Off)',73,2849,0,'b21');
+INSERT INTO items VALUES(NULL,'Lamp Post 1 (On)',73,2848,0,'b20');
+INSERT INTO items VALUES(NULL,'Archway 8',41,926,0,'39e');
+INSERT INTO items VALUES(NULL,'Supports 3',156,414,0,'19e');
+INSERT INTO items VALUES(NULL,'Supports 2',156,413,0,'19d');
+INSERT INTO items VALUES(NULL,'Wooden Chair 1',78,2862,0,'b2e');
+INSERT INTO items VALUES(NULL,'Wooden Bench 1 (N/S)',78,2861,0,'b2d');
+INSERT INTO items VALUES(NULL,'Wooden Bench 1 (W/E)',78,2860,0,'b2c');
+INSERT INTO items VALUES(NULL,'Supports 1',156,412,0,'19c');
+INSERT INTO items VALUES(NULL,'Post 1',156,411,0,'19b');
+INSERT INTO items VALUES(NULL,'Iron Gate 2 (W/SE)',157,2132,0,'854');
+INSERT INTO items VALUES(NULL,'Iron Gate 2 (W/NE)',157,2134,0,'856');
+INSERT INTO items VALUES(NULL,'Iron Gate 2 (S/NW)',157,2128,0,'850');
+INSERT INTO items VALUES(NULL,'Iron Gate 2 (S/NE)',157,2130,0,'852');
+INSERT INTO items VALUES(NULL,'Lava 4',52,13401,0,'3459');
+INSERT INTO items VALUES(NULL,'Iron Gate 2 (W/SW)',157,2136,0,'858');
+INSERT INTO items VALUES(NULL,'Wall 1',158,6,0,'6');
+INSERT INTO items VALUES(NULL,'Fence 2',122,2141,0,'85d');
+INSERT INTO items VALUES(NULL,'Fence 3',122,2142,0,'85e');
+INSERT INTO items VALUES(NULL,'Fence 4',122,2143,0,'85f');
+INSERT INTO items VALUES(NULL,'Iron Gate 2 (W/NW)',157,2138,0,'85a');
+INSERT INTO items VALUES(NULL,'Fence 1',122,2140,0,'85c');
+INSERT INTO items VALUES(NULL,'platemail gloves',159,5140,0,'agapite_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Decorative Feathers 1',34,3578,0,'dfa');
+INSERT INTO items VALUES(NULL,'Roof 1',32,1557,0,'615');
+INSERT INTO items VALUES(NULL,'Deer (W/E)',160,7784,0,'1e68');
+INSERT INTO items VALUES(NULL,'kite shield',77,7028,0,'bronze_shields_kite');
+INSERT INTO items VALUES(NULL,'Lava 6',161,4870,0,'1306');
+INSERT INTO items VALUES(NULL,'Lava 5',161,4864,0,'1300');
+INSERT INTO items VALUES(NULL,'Flagstones 3',162,1278,0,'4fe');
+INSERT INTO items VALUES(NULL,'Flagstones 2',162,1277,0,'4fd');
+INSERT INTO items VALUES(NULL,'Flagstones 4',162,1279,0,'4ff');
+INSERT INTO items VALUES(NULL,'Red Floor 8',163,1274,0,'4fa');
+INSERT INTO items VALUES(NULL,'Flagstones 1',162,1276,0,'4fc');
+INSERT INTO items VALUES(NULL,'Red Floor 9',163,1275,0,'4fb');
+INSERT INTO items VALUES(NULL,'Balista 6',76,6308,0,'18a4');
+INSERT INTO items VALUES(NULL,'Balista 7',76,6309,0,'18a5');
+INSERT INTO items VALUES(NULL,'Balista 8',76,6310,0,'18a6');
+INSERT INTO items VALUES(NULL,'Balista 9',76,6311,0,'18a7');
+INSERT INTO items VALUES(NULL,'Marble Floor 4',164,1176,0,'498');
+INSERT INTO items VALUES(NULL,'Balista 3',76,6305,0,'18a1');
+INSERT INTO items VALUES(NULL,'Balista 4',76,6306,0,'18a2');
+INSERT INTO items VALUES(NULL,'Balista 5',76,6307,0,'18a3');
+INSERT INTO items VALUES(NULL,'Blue Floor 4',165,1172,0,'494');
+INSERT INTO items VALUES(NULL,'Marble Floor 1',164,1173,0,'495');
+INSERT INTO items VALUES(NULL,'Marble Floor 2',164,1174,0,'496');
+INSERT INTO items VALUES(NULL,'Marble Floor 3',164,1175,0,'497');
+INSERT INTO items VALUES(NULL,'Balista 10',76,6312,0,'18a8');
+INSERT INTO items VALUES(NULL,'Blue Floor 1',165,1169,0,'491');
+INSERT INTO items VALUES(NULL,'Blue Floor 2',165,1170,0,'492');
+INSERT INTO items VALUES(NULL,'Blue Floor 3',165,1171,0,'493');
+INSERT INTO items VALUES(NULL,'Wall 1',156,421,0,'1a5');
+INSERT INTO items VALUES(NULL,'Battlement 7',47,420,0,'1a4');
+INSERT INTO items VALUES(NULL,'Wall 3',156,423,0,'1a7');
+INSERT INTO items VALUES(NULL,'Wall 2',156,422,0,'1a6');
+INSERT INTO items VALUES(NULL,'Supports 6',156,417,0,'1a1');
+INSERT INTO items VALUES(NULL,'Supports 5',156,416,0,'1a0');
+INSERT INTO items VALUES(NULL,'Post 2',156,419,0,'1a3');
+INSERT INTO items VALUES(NULL,'Supports 7',156,418,0,'1a2');
+INSERT INTO items VALUES(NULL,'Wall 4',156,425,0,'1a9');
+INSERT INTO items VALUES(NULL,'Post 3',156,424,0,'1a8');
+INSERT INTO items VALUES(NULL,'Balista 15',76,6317,0,'18ad');
+INSERT INTO items VALUES(NULL,'Balista 16',76,6318,0,'18ae');
+INSERT INTO items VALUES(NULL,'Balista 17',76,6319,0,'18af');
+INSERT INTO items VALUES(NULL,'Balista 12',76,6314,0,'18aa');
+INSERT INTO items VALUES(NULL,'Balista 13',76,6315,0,'18ab');
+INSERT INTO items VALUES(NULL,'Balista 14',76,6316,0,'18ac');
+INSERT INTO items VALUES(NULL,'Sandstone Paver 1',166,1181,0,'49d');
+INSERT INTO items VALUES(NULL,'Sandstone Paver 2',166,1182,0,'49e');
+INSERT INTO items VALUES(NULL,'Sandstone Paver 3',166,1183,0,'49f');
+INSERT INTO items VALUES(NULL,'chainmail coif',167,5051,0,'valorite_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Blue Floor 5',165,1179,0,'49b');
+INSERT INTO items VALUES(NULL,'Grey Slate Floor 1',168,1180,0,'49c');
+INSERT INTO items VALUES(NULL,'Red Floor 7',163,1273,0,'4f9');
+INSERT INTO items VALUES(NULL,'Red Floor 6',163,1272,0,'4f8');
+INSERT INTO items VALUES(NULL,'Lava 7',161,4876,0,'130c');
+INSERT INTO items VALUES(NULL,'Red Floor 3',163,1269,0,'4f5');
+INSERT INTO items VALUES(NULL,'Red Floor 2',163,1268,0,'4f4');
+INSERT INTO items VALUES(NULL,'Red Floor 5',163,1271,0,'4f7');
+INSERT INTO items VALUES(NULL,'Red Floor 4',163,1270,0,'4f6');
+INSERT INTO items VALUES(NULL,'Blue Floor 13',165,1265,0,'4f1');
+INSERT INTO items VALUES(NULL,'Blue Floor 12',165,1264,0,'4f0');
+INSERT INTO items VALUES(NULL,'Red Floor 1',163,1267,0,'4f3');
+INSERT INTO items VALUES(NULL,'Blue Floor 14',165,1266,0,'4f2');
+INSERT INTO items VALUES(NULL,'Dresser (N/S) 1',79,2620,0,'a3c');
+INSERT INTO items VALUES(NULL,'bascinet',97,5132,0,'verite_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Column 1',169,679,0,'2a7');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (W/E) 7',79,2618,0,'a3a');
+INSERT INTO items VALUES(NULL,'Window 2',156,430,0,'1ae');
+INSERT INTO items VALUES(NULL,'Window 1',156,429,0,'1ad');
+INSERT INTO items VALUES(NULL,'Window 3',156,431,0,'1af');
+INSERT INTO items VALUES(NULL,'Wall 5',156,426,0,'1aa');
+INSERT INTO items VALUES(NULL,'Wall 7',156,428,0,'1ac');
+INSERT INTO items VALUES(NULL,'Wall 6',156,427,0,'1ab');
+INSERT INTO items VALUES(NULL,'Small Wall 3',170,675,0,'2a3');
+INSERT INTO items VALUES(NULL,'Wall 4',169,672,0,'2a0');
+INSERT INTO items VALUES(NULL,'Small Wall 1',170,673,0,'2a1');
+INSERT INTO items VALUES(NULL,'Lighthouse (6/29)',46,6825,0,'1aa9');
+INSERT INTO items VALUES(NULL,'Lighthouse (5/29)',46,6824,0,'1aa8');
+INSERT INTO items VALUES(NULL,'Blood 14',171,7423,0,'1cff');
+INSERT INTO items VALUES(NULL,'Blood 12',171,7421,0,'1cfd');
+INSERT INTO items VALUES(NULL,'Blood 13',171,7422,0,'1cfe');
+INSERT INTO items VALUES(NULL,'Blood 10',171,7419,0,'1cfb');
+INSERT INTO items VALUES(NULL,'Blood 11',171,7420,0,'1cfc');
+INSERT INTO items VALUES(NULL,'Blood 9',171,7418,0,'1cfa');
+INSERT INTO items VALUES(NULL,'Candle of Love (Off)',172,7190,0,'1c16');
+INSERT INTO items VALUES(NULL,'Candle of Love (On)',172,7188,0,'1c14');
+INSERT INTO items VALUES(NULL,'Book of Truth',172,7187,0,'1c13');
+INSERT INTO items VALUES(NULL,'Bell of Courage',172,7186,0,'1c12');
+INSERT INTO items VALUES(NULL,'Oil Flask (Exploding)',173,7193,0,'1c19');
+INSERT INTO items VALUES(NULL,'Oil Flask',173,7192,0,'1c18');
+INSERT INTO items VALUES(NULL,'Armoire 2 (N/S) (Closed)',79,2639,0,'a4f');
+INSERT INTO items VALUES(NULL,'Slab of Bacon (N/S)',19,2422,0,'976');
+INSERT INTO items VALUES(NULL,'Armoire 1 (N/S) (Closed)',79,2637,0,'a4d');
+INSERT INTO items VALUES(NULL,'Armoire 2 (N/S) (Open)',79,2638,0,'a4e');
+INSERT INTO items VALUES(NULL,'Dresser (W/E) 8',79,2635,0,'a4b');
+INSERT INTO items VALUES(NULL,'Armoire 1 (N/S) (Open)',79,2636,0,'a4c');
+INSERT INTO items VALUES(NULL,'Dresser (W/E) 7',79,2634,0,'a4a');
+INSERT INTO items VALUES(NULL,'Slice of Bacon (W/E)',19,2425,0,'979');
+INSERT INTO items VALUES(NULL,'Slice of Bacon (N/S)',19,2424,0,'978');
+INSERT INTO items VALUES(NULL,'Display Case 5 Frame (3/8)',174,2725,0,'aa5');
+INSERT INTO items VALUES(NULL,'Display Case 5 Frame (4/8)',174,2724,0,'aa4');
+INSERT INTO items VALUES(NULL,'Display Case 5 Frame (7/8)',174,2721,0,'aa1');
+INSERT INTO items VALUES(NULL,'Display Case 5 Frame (6/8)',174,2720,0,'aa0');
+INSERT INTO items VALUES(NULL,'Display Case 5 Frame (1/8)',174,2723,0,'aa3');
+INSERT INTO items VALUES(NULL,'Display Case 5 Frame (8/8)',174,2722,0,'aa2');
+INSERT INTO items VALUES(NULL,'Cut Hair',175,3582,0,'dfe');
+INSERT INTO items VALUES(NULL,'Barber Scissors (N/S)',175,3581,0,'dfd');
+INSERT INTO items VALUES(NULL,'Wig 1 (N/S)',175,3583,0,'dff');
+INSERT INTO items VALUES(NULL,'Rug 1',176,2729,0,'aa9');
+INSERT INTO items VALUES(NULL,'Leaves 4 (1/10)',4,3463,0,'d87');
+INSERT INTO items VALUES(NULL,'Barber Scissors (W/E)',175,3580,0,'dfc');
+INSERT INTO items VALUES(NULL,'Decorative Feathers 2',34,3579,0,'dfb');
+INSERT INTO items VALUES(NULL,'Blood 5',171,7414,0,'1cf6');
+INSERT INTO items VALUES(NULL,'Blood 6',171,7415,0,'1cf7');
+INSERT INTO items VALUES(NULL,'Blood 3',171,7412,0,'1cf4');
+INSERT INTO items VALUES(NULL,'Blood 4',171,7413,0,'1cf5');
+INSERT INTO items VALUES(NULL,'Blood 1',171,7410,0,'1cf2');
+INSERT INTO items VALUES(NULL,'Blood 2',171,7411,0,'1cf3');
+INSERT INTO items VALUES(NULL,'Brain ',147,7408,0,'1cf0');
+INSERT INTO items VALUES(NULL,'Blood 29',55,7409,0,'1cf1');
+INSERT INTO items VALUES(NULL,'Balista 29',76,6331,0,'18bb');
+INSERT INTO items VALUES(NULL,'Blood 7',171,7416,0,'1cf8');
+INSERT INTO items VALUES(NULL,'Blood 8',171,7417,0,'1cf9');
+INSERT INTO items VALUES(NULL,'Rug 6',176,2734,0,'aae');
+INSERT INTO items VALUES(NULL,'Rug 5',176,2733,0,'aad');
+INSERT INTO items VALUES(NULL,'Rug 7',176,2735,0,'aaf');
+INSERT INTO items VALUES(NULL,'Rug 2',176,2730,0,'aaa');
+INSERT INTO items VALUES(NULL,'Pile of Wool 1',57,3576,0,'df8');
+INSERT INTO items VALUES(NULL,'Rug 4',176,2732,0,'aac');
+INSERT INTO items VALUES(NULL,'Rug 3',176,2731,0,'aab');
+INSERT INTO items VALUES(NULL,'Wand 4',177,3573,0,'df5');
+INSERT INTO items VALUES(NULL,'Wand 3',177,3572,0,'df4');
+INSERT INTO items VALUES(NULL,'Knitting (W/E)',57,3575,0,'df7');
+INSERT INTO items VALUES(NULL,'Knitting (N/S)',57,3574,0,'df6');
+INSERT INTO items VALUES(NULL,'black staff',119,3568,0,'df0');
+INSERT INTO items VALUES(NULL,'Wand 2',177,3571,0,'df3');
+INSERT INTO items VALUES(NULL,'Wand 1',177,3570,0,'df2');
+INSERT INTO items VALUES(NULL,'Dresser (W/E) 3',79,2630,0,'a46');
+INSERT INTO items VALUES(NULL,'Dresser (W/E) 4',79,2631,0,'a47');
+INSERT INTO items VALUES(NULL,'Dresser (W/E) 1',79,2628,0,'a44');
+INSERT INTO items VALUES(NULL,'Dresser (W/E) 2',79,2629,0,'a45');
+INSERT INTO items VALUES(NULL,'Dresser (N/S) 7',79,2626,0,'a42');
+INSERT INTO items VALUES(NULL,'Dresser (N/S) 8',79,2627,0,'a43');
+INSERT INTO items VALUES(NULL,'Dresser (N/S) 5',79,2624,0,'a40');
+INSERT INTO items VALUES(NULL,'Dresser (N/S) 6',79,2625,0,'a41');
+INSERT INTO items VALUES(NULL,'Dresser (W/E) 5',79,2632,0,'a48');
+INSERT INTO items VALUES(NULL,'Dresser (W/E) 6',79,2633,0,'a49');
+INSERT INTO items VALUES(NULL,'Window 1',169,685,0,'2ad');
+INSERT INTO items VALUES(NULL,'Window 2',169,686,0,'2ae');
+INSERT INTO items VALUES(NULL,'Column 2',170,683,0,'2ab');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (W/E) 3',79,2614,0,'a36');
+INSERT INTO items VALUES(NULL,'Catapult 56',72,5770,0,'168a');
+INSERT INTO items VALUES(NULL,'Catapult 58',72,5772,0,'168c');
+INSERT INTO items VALUES(NULL,'Catapult 57',72,5771,0,'168b');
+INSERT INTO items VALUES(NULL,'Catapult 60',72,5774,0,'168e');
+INSERT INTO items VALUES(NULL,'Catapult 59',72,5773,0,'168d');
+INSERT INTO items VALUES(NULL,'ringmail gloves',178,5099,0,'shadow_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Catapult 61',72,5775,0,'168f');
+INSERT INTO items VALUES(NULL,'Column 1',170,682,0,'2aa');
+INSERT INTO items VALUES(NULL,'Border 10',179,4924,0,'133c');
+INSERT INTO items VALUES(NULL,'Grape Bunch 2',19,3354,0,'d1a');
+INSERT INTO items VALUES(NULL,'chainmail tunic',63,5055,0,'shadow_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Stone Face (small w. fire) 3',109,4345,0,'10f9');
+INSERT INTO items VALUES(NULL,'Stone Face (small w. fire) 2',109,4344,0,'10f8');
+INSERT INTO items VALUES(NULL,'Catapult 47',72,5761,0,'1681');
+INSERT INTO items VALUES(NULL,'Catapult 46',72,5760,0,'1680');
+INSERT INTO items VALUES(NULL,'Catapult 49',72,5763,0,'1683');
+INSERT INTO items VALUES(NULL,'Catapult 48',72,5762,0,'1682');
+INSERT INTO items VALUES(NULL,'Catapult 51',72,5765,0,'1685');
+INSERT INTO items VALUES(NULL,'Green Potion',180,3850,0,'potion_poison');
+INSERT INTO items VALUES(NULL,'Catapult 53',72,5767,0,'1687');
+INSERT INTO items VALUES(NULL,'Catapult 52',72,5766,0,'1686');
+INSERT INTO items VALUES(NULL,'Catapult 55',72,5769,0,'1689');
+INSERT INTO items VALUES(NULL,'Catapult 54',72,5768,0,'1688');
+INSERT INTO items VALUES(NULL,'platemail arms',181,5136,0,'verite_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'Telescope (17/66)',182,5225,0,'1469');
+INSERT INTO items VALUES(NULL,'Stone Face (small w. fire) 1',109,4343,0,'10f7');
+INSERT INTO items VALUES(NULL,'Telescope (13/66)',182,5221,0,'1465');
+INSERT INTO items VALUES(NULL,'Telescope (12/66)',182,5220,0,'1464');
+INSERT INTO items VALUES(NULL,'Telescope (15/66)',182,5223,0,'1467');
+INSERT INTO items VALUES(NULL,'Telescope (14/66)',182,5222,0,'1466');
+INSERT INTO items VALUES(NULL,'Telescope (9/66)',182,5217,0,'1461');
+INSERT INTO items VALUES(NULL,'Telescope (8/66)',182,5216,0,'1460');
+INSERT INTO items VALUES(NULL,'buckler',183,7027,0,'merkite_shields_buckler');
+INSERT INTO items VALUES(NULL,'Telescope (10/66)',182,5218,0,'1462');
+INSERT INTO items VALUES(NULL,'short spear',20,5123,0,'1403');
+INSERT INTO items VALUES(NULL,'Wall 8',184,58,0,'3a');
+INSERT INTO items VALUES(NULL,'Telescope (22/66)',182,5230,0,'146e');
+INSERT INTO items VALUES(NULL,'Telescope (21/66)',182,5229,0,'146d');
+INSERT INTO items VALUES(NULL,'Telescope (23/66)',182,5231,0,'146f');
+INSERT INTO items VALUES(NULL,'Telescope (18/66)',182,5226,0,'146a');
+INSERT INTO items VALUES(NULL,'Telescope (20/66)',182,5228,0,'146c');
+INSERT INTO items VALUES(NULL,'Telescope (19/66)',182,5227,0,'146b');
+INSERT INTO items VALUES(NULL,'Fur 6 (N/S) (2/2)',185,8056,0,'1f78');
+INSERT INTO items VALUES(NULL,'Fur 6 (W/E) (1/2)',185,8057,0,'1f79');
+INSERT INTO items VALUES(NULL,'Fur 5 (N/S) (2/2)',185,8052,0,'1f74');
+INSERT INTO items VALUES(NULL,'Fur 5 (W/E) (1/2)',185,8053,0,'1f75');
+INSERT INTO items VALUES(NULL,'Fur 5 (W/E) (2/2)',185,8054,0,'1f76');
+INSERT INTO items VALUES(NULL,'Fur 6 (N/S) (1/2)',185,8055,0,'1f77');
+INSERT INTO items VALUES(NULL,'Scroll 8 (W/E)',186,8048,0,'1f70');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',178,5103,0,'shadow_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'Fur 5 (N/S) (1/2)',185,8051,0,'1f73');
+INSERT INTO items VALUES(NULL,'Rock 5',29,13450,0,'348a');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (W/E) 3',116,7450,0,'1d1a');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (W/E) 4',116,7451,0,'1d1b');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (W/E) 5',116,7452,0,'1d1c');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (W/E) 1',116,7453,0,'1d1d');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (W/E) 2',116,7454,0,'1d1e');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (W/E) 3',116,7455,0,'1d1f');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (W/E) 1',116,7448,0,'1d18');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (W/E) 2',116,7449,0,'1d19');
+INSERT INTO items VALUES(NULL,'Border 8',179,4918,0,'1336');
+INSERT INTO items VALUES(NULL,'Blood 31',171,7440,0,'1d10');
+INSERT INTO items VALUES(NULL,'Blood 32',171,7441,0,'1d11');
+INSERT INTO items VALUES(NULL,'Blood 33',171,7442,0,'1d12');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (W/E) 1',116,7443,0,'1d13');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (W/E) 2',116,7444,0,'1d14');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (W/E) 3',116,7445,0,'1d15');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (W/E) 4',116,7446,0,'1d16');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (W/E) 5',116,7447,0,'1d17');
+INSERT INTO items VALUES(NULL,'Border 7',179,4915,0,'1333');
+INSERT INTO items VALUES(NULL,'Glass of Cider 2',155,8062,0,'1f7e');
+INSERT INTO items VALUES(NULL,'Fur 6 (W/E) (2/2)',185,8058,0,'1f7a');
+INSERT INTO items VALUES(NULL,'Doublet (W/E)',1,8060,0,'1f7c');
+INSERT INTO items VALUES(NULL,'platemail gloves',187,5140,0,'merkite_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Balista 27',76,6329,0,'18b9');
+INSERT INTO items VALUES(NULL,'Balista 26',76,6328,0,'18b8');
+INSERT INTO items VALUES(NULL,'plate armor',81,7172,0,'shadow_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Juka Warrior',115,9759,0,'261f');
+INSERT INTO items VALUES(NULL,'Display Case 3 (N/S)',174,2826,0,'b0a');
+INSERT INTO items VALUES(NULL,'Tiller 3',136,15967,0,'3e5f');
+INSERT INTO items VALUES(NULL,'Tiller 2',136,15966,0,'3e5e');
+INSERT INTO items VALUES(NULL,'Display Case 3 (W/E) Frame',174,2827,0,'b0b');
+INSERT INTO items VALUES(NULL,'Sail 3',86,15964,0,'3e5c');
+INSERT INTO items VALUES(NULL,'Sail 2',86,15963,0,'3e5b');
+INSERT INTO items VALUES(NULL,'Mast 2',8,15962,0,'3e5a');
+INSERT INTO items VALUES(NULL,'Display Case 5 (9/9)',174,2831,0,'b0f');
+INSERT INTO items VALUES(NULL,'Balista 20',76,6322,0,'18b2');
+INSERT INTO items VALUES(NULL,'Display Case 1 (2/3)',174,2817,0,'b01');
+INSERT INTO items VALUES(NULL,'Display Case 1 (1/3)',174,2816,0,'b00');
+INSERT INTO items VALUES(NULL,'Display Case 2 Frame (1/3)',174,2819,0,'b03');
+INSERT INTO items VALUES(NULL,'Display Case 1 (3/3)',174,2818,0,'b02');
+INSERT INTO items VALUES(NULL,'Display Case 2 Frame (3/3)',174,2821,0,'b05');
+INSERT INTO items VALUES(NULL,'Display Case 2 Frame (2/3)',174,2820,0,'b04');
+INSERT INTO items VALUES(NULL,'Display Case 2 (2/3)',174,2823,0,'b07');
+INSERT INTO items VALUES(NULL,'Display Case 2 (1/3)',174,2822,0,'b06');
+INSERT INTO items VALUES(NULL,'Display Case 3 (W/E)',174,2825,0,'b09');
+INSERT INTO items VALUES(NULL,'Display Case 2 (3/3)',174,2824,0,'b08');
+INSERT INTO items VALUES(NULL,'Wall 7',188,502,0,'1f6');
+INSERT INTO items VALUES(NULL,'Sail 1',86,15961,0,'3e59');
+INSERT INTO items VALUES(NULL,'Spar 1',88,15960,0,'3e58');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',189,48,0,'30');
+INSERT INTO items VALUES(NULL,'Rock 3',29,13448,0,'3488');
+INSERT INTO items VALUES(NULL,'Wall 5',184,55,0,'37');
+INSERT INTO items VALUES(NULL,'Wall 4',184,54,0,'36');
+INSERT INTO items VALUES(NULL,'Wall 3',188,498,0,'1f2');
+INSERT INTO items VALUES(NULL,'Wall 2',184,52,0,'34');
+INSERT INTO items VALUES(NULL,'Fence 2',190,2168,0,'878');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 21',121,2166,0,'876');
+INSERT INTO items VALUES(NULL,'Fence 1',190,2167,0,'877');
+INSERT INTO items VALUES(NULL,'Gate (W/NE)',191,2164,0,'874');
+INSERT INTO items VALUES(NULL,'Rock 35',29,13363,0,'3433');
+INSERT INTO items VALUES(NULL,'Gate (W/SE)',191,2162,0,'872');
+INSERT INTO items VALUES(NULL,'Rock 37',29,13365,0,'3435');
+INSERT INTO items VALUES(NULL,'Gate (W/NW)',191,2160,0,'870');
+INSERT INTO items VALUES(NULL,'Ship 41',137,16054,0,'3eb6');
+INSERT INTO items VALUES(NULL,'Hold 4',138,16055,0,'3eb7');
+INSERT INTO items VALUES(NULL,'Prow 6',9,16052,0,'3eb4');
+INSERT INTO items VALUES(NULL,'Ship 40',137,16053,0,'3eb5');
+INSERT INTO items VALUES(NULL,'Ship 39',137,16050,0,'3eb2');
+INSERT INTO items VALUES(NULL,'Stern 1',192,16051,0,'3eb3');
+INSERT INTO items VALUES(NULL,'Deck 12',193,16048,0,'3eb0');
+INSERT INTO items VALUES(NULL,'Ship 38',137,16049,0,'3eb1');
+INSERT INTO items VALUES(NULL,'Stern 2',192,16056,0,'3eb8');
+INSERT INTO items VALUES(NULL,'Hatch 4',139,16057,0,'3eb9');
+INSERT INTO items VALUES(NULL,'chainmail coif',194,5051,0,'agapite_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Tiller 10',136,16063,0,'3ebf');
+INSERT INTO items VALUES(NULL,'Short Beard',195,8255,0,'203f');
+INSERT INTO items VALUES(NULL,'Tiller 8',136,16061,0,'3ebd');
+INSERT INTO items VALUES(NULL,'Rudder 5',196,16062,0,'3ebe');
+INSERT INTO items VALUES(NULL,'Rudder 3',196,16059,0,'3ebb');
+INSERT INTO items VALUES(NULL,'Rudder 4',196,16060,0,'3ebc');
+INSERT INTO items VALUES(NULL,'Prow 7',9,16058,0,'3eba');
+INSERT INTO items VALUES(NULL,'Rail (W/E) 2',197,2175,0,'87f');
+INSERT INTO items VALUES(NULL,'Wooden Ramp 4',198,2173,0,'87d');
+INSERT INTO items VALUES(NULL,'Rail (W/E) 1',197,2174,0,'87e');
+INSERT INTO items VALUES(NULL,'Wooden Ramp 2',198,2171,0,'87b');
+INSERT INTO items VALUES(NULL,'Wooden Ramp 3',198,2172,0,'87c');
+INSERT INTO items VALUES(NULL,'Wooden Ramp 1',198,2170,0,'87a');
+INSERT INTO items VALUES(NULL,'Carpet 6',199,4253,0,'109d');
+INSERT INTO items VALUES(NULL,'Carpet 7',199,4254,0,'109e');
+INSERT INTO items VALUES(NULL,'Carpet 8',199,4255,0,'109f');
+INSERT INTO items VALUES(NULL,'Carpet 3',199,4250,0,'109a');
+INSERT INTO items VALUES(NULL,'Carpet 4',199,4251,0,'109b');
+INSERT INTO items VALUES(NULL,'Carpet 5',199,4252,0,'109c');
+INSERT INTO items VALUES(NULL,'Paralyze',94,8018,0,'1f52');
+INSERT INTO items VALUES(NULL,'Tree 2 (3/3)',4,3462,0,'d86');
+INSERT INTO items VALUES(NULL,'Magic Reflection',94,8016,0,'1f50');
+INSERT INTO items VALUES(NULL,'Lever 2 (N/S)',75,4244,0,'1094');
+INSERT INTO items VALUES(NULL,'Lever 3 (N/S)',75,4245,0,'1095');
+INSERT INTO items VALUES(NULL,'Mind Blast',94,8017,0,'1f51');
+INSERT INTO items VALUES(NULL,'Switch (W/E) (On)',75,4240,0,'1090');
+INSERT INTO items VALUES(NULL,'Switch (N/S) (On)',75,4241,0,'1091');
+INSERT INTO items VALUES(NULL,'Switch (N/S) (Off)',75,4242,0,'1092');
+INSERT INTO items VALUES(NULL,'Red Moongate',200,3546,0,'dda');
+INSERT INTO items VALUES(NULL,'Vines 3 (4/4)',4,3459,0,'d83');
+INSERT INTO items VALUES(NULL,'Carpet 1',199,4248,0,'1098');
+INSERT INTO items VALUES(NULL,'Carpet 2',199,4249,0,'1099');
+INSERT INTO items VALUES(NULL,'Explosion',94,8023,0,'1f57');
+INSERT INTO items VALUES(NULL,'Summon Creature',94,8020,0,'1f54');
+INSERT INTO items VALUES(NULL,'Dispel Scroll',94,8021,0,'1f55');
+INSERT INTO items VALUES(NULL,'Wall 8',158,13,0,'d');
+INSERT INTO items VALUES(NULL,'Border 3',179,4903,0,'1327');
+INSERT INTO items VALUES(NULL,'Border 2',179,4900,0,'1324');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 7',149,180,0,'b4');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 8',149,181,0,'b5');
+INSERT INTO items VALUES(NULL,'Small Wall 1',149,182,0,'b6');
+INSERT INTO items VALUES(NULL,'Small Wall 2',149,183,0,'b7');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 3',149,176,0,'b0');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 4',149,177,0,'b1');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 5',149,178,0,'b2');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 6',149,179,0,'b3');
+INSERT INTO items VALUES(NULL,'Balista 42',76,6344,0,'18c8');
+INSERT INTO items VALUES(NULL,'Balista 43',76,6345,0,'18c9');
+INSERT INTO items VALUES(NULL,'Small Wall 3',149,184,0,'b8');
+INSERT INTO items VALUES(NULL,'Window 1',149,185,0,'b9');
+INSERT INTO items VALUES(NULL,'Tattered Banner 5',201,1068,0,'42c');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',149,189,0,'bd');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',149,190,0,'be');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',149,191,0,'bf');
+INSERT INTO items VALUES(NULL,'Balista 44',76,6346,0,'18ca');
+INSERT INTO items VALUES(NULL,'Balista 49',76,6351,0,'18cf');
+INSERT INTO items VALUES(NULL,'Window 2',149,186,0,'ba');
+INSERT INTO items VALUES(NULL,'Window w. Bar 1',149,187,0,'bb');
+INSERT INTO items VALUES(NULL,'Window w. Bar 2',149,188,0,'bc');
+INSERT INTO items VALUES(NULL,'Field of Energy (W/E)',28,14678,0,'3956');
+INSERT INTO items VALUES(NULL,'Mud 2',202,7682,0,'1e02');
+INSERT INTO items VALUES(NULL,'Border 4',179,4906,0,'132a');
+INSERT INTO items VALUES(NULL,'Border 5',179,4909,0,'132d');
+INSERT INTO items VALUES(NULL,'Green Potion',180,3850,0,'potion_lesserpoison');
+INSERT INTO items VALUES(NULL,'Tattered Banner 7',201,1070,0,'42e');
+INSERT INTO items VALUES(NULL,'Footprints 1',202,7683,0,'1e03');
+INSERT INTO items VALUES(NULL,'Roof 4',203,6460,0,'193c');
+INSERT INTO items VALUES(NULL,'Tattered Banner 6',201,1069,0,'42d');
+INSERT INTO items VALUES(NULL,'Roof 2',203,6458,0,'193a');
+INSERT INTO items VALUES(NULL,'Roof 5',203,6461,0,'193d');
+INSERT INTO items VALUES(NULL,'Raw Bird (N/S)',19,2490,0,'9ba');
+INSERT INTO items VALUES(NULL,'Roast Pig (W/E)',19,2491,0,'9bb');
+INSERT INTO items VALUES(NULL,'Roast Pig (N/S)',19,2492,0,'9bc');
+INSERT INTO items VALUES(NULL,'Silverware 1 (W/E)',14,2493,0,'9bd');
+INSERT INTO items VALUES(NULL,'Silverware 1 (N/S)',14,2494,0,'9be');
+INSERT INTO items VALUES(NULL,'Goblet 3',14,2495,0,'9bf');
+INSERT INTO items VALUES(NULL,'Vines 3 (1/4)',4,3456,0,'d80');
+INSERT INTO items VALUES(NULL,'Dragon Prow 6',9,15944,0,'3e48');
+INSERT INTO items VALUES(NULL,'Cooked Bird (W/E)',19,2488,0,'9b8');
+INSERT INTO items VALUES(NULL,'Raw Bird (W/E)',19,2489,0,'9b9');
+INSERT INTO items VALUES(NULL,'Moloch Demon',115,9742,0,'260e');
+INSERT INTO items VALUES(NULL,'Belt Pouch (N/S)',65,2480,0,'9b0');
+INSERT INTO items VALUES(NULL,'Basket 2',65,2481,0,'9b1');
+INSERT INTO items VALUES(NULL,'Backpack (N/S)',65,2482,0,'9b2');
+INSERT INTO items VALUES(NULL,'Statue 4 (3/3)',54,4822,0,'12d6');
+INSERT INTO items VALUES(NULL,'Eggshells',14,2484,0,'9b4');
+INSERT INTO items VALUES(NULL,'Eggs',19,2485,0,'9b5');
+INSERT INTO items VALUES(NULL,'Fried Eggs',19,2486,0,'9b6');
+INSERT INTO items VALUES(NULL,'Cooked Bird (W/E)',19,2487,0,'9b7');
+INSERT INTO items VALUES(NULL,'Exodus Minion',115,9739,0,'260b');
+INSERT INTO items VALUES(NULL,'Exodus Overseer',115,9740,0,'260c');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (N/S) 5',116,7225,0,'1c39');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (N/S) 4',116,7224,0,'1c38');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (N/S) 1',116,7221,0,'1c35');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (N/S) 6',116,7220,0,'1c34');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (N/S) 3',116,7223,0,'1c37');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (N/S) 2',116,7222,0,'1c36');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (N/S) 3',116,7217,0,'1c31');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (N/S) 2',116,7216,0,'1c30');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (N/S) 5',116,7219,0,'1c33');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (N/S) 4',116,7218,0,'1c32');
+INSERT INTO items VALUES(NULL,'platemail gloves',181,5140,0,'verite_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Wooden Door 2 (S/NE)',204,1723,0,'6bb');
+INSERT INTO items VALUES(NULL,'Wooden Door 2 (W/NE)',204,1727,0,'6bf');
+INSERT INTO items VALUES(NULL,'Wooden Door 2 (W/SE)',204,1725,0,'6bd');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 4 (W/E) (1/2)',103,2385,0,'951');
+INSERT INTO items VALUES(NULL,'Stone Fireplace 2 (W/E) (1/2)',103,2387,0,'953');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 4 (W/E) (2/2)',103,2386,0,'952');
+INSERT INTO items VALUES(NULL,'chainmail leggings',205,5054,0,'copper_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 3',116,7230,0,'1c3e');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 2',116,7229,0,'1c3d');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 4',116,7231,0,'1c3f');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (N/S) 6',116,7226,0,'1c3a');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 1',116,7228,0,'1c3c');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (N/S) 7',116,7227,0,'1c3b');
+INSERT INTO items VALUES(NULL,'Wooden Door 1 (W/NW)',206,1715,0,'6b3');
+INSERT INTO items VALUES(NULL,'Wooden Door 1 (W/SW)',206,1713,0,'6b1');
+INSERT INTO items VALUES(NULL,'Flax 4',45,6812,0,'1a9c');
+INSERT INTO items VALUES(NULL,'Wooden Door 2 (S/SE)',204,1719,0,'6b7');
+INSERT INTO items VALUES(NULL,'Wooden Door 2 (S/SW)',204,1717,0,'6b5');
+INSERT INTO items VALUES(NULL,'Wooden Door 2 (S/NW)',204,1721,0,'6b9');
+INSERT INTO items VALUES(NULL,'Cloth (W/E)',57,5989,0,'1765');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 4 (N/S) (1/2)',103,2399,0,'95f');
+INSERT INTO items VALUES(NULL,'Flax 3',45,6811,0,'1a9b');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E; falling) 3',109,4417,0,'1141');
+INSERT INTO items VALUES(NULL,'Reveal',94,8028,0,'1f5c');
+INSERT INTO items VALUES(NULL,'Mass Curse',94,8026,0,'1f5a');
+INSERT INTO items VALUES(NULL,'buckler',207,7027,0,'iron_shields_buckler');
+INSERT INTO items VALUES(NULL,'platemail gorget',208,5139,0,'copper_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Whip 2',113,5743,0,'166f');
+INSERT INTO items VALUES(NULL,'Whip 1',113,5742,0,'166e');
+INSERT INTO items VALUES(NULL,'Shackle ',113,5741,0,'166d');
+INSERT INTO items VALUES(NULL,'Covered Table (W/E) (3/3)',89,5740,0,'166c');
+INSERT INTO items VALUES(NULL,'Covered Table (W/E) (2/3)',89,5739,0,'166b');
+INSERT INTO items VALUES(NULL,'Covered Table (W/E) (1/3)',89,5738,0,'166a');
+INSERT INTO items VALUES(NULL,'Hops 1',45,6814,0,'1a9e');
+INSERT INTO items VALUES(NULL,'Leaves 4 (4/10)',4,3466,0,'d8a');
+INSERT INTO items VALUES(NULL,'Energy Field',94,8030,0,'1f5e');
+INSERT INTO items VALUES(NULL,'Gas Trap 9',109,4424,0,'1148');
+INSERT INTO items VALUES(NULL,'Flax 5',45,6813,0,'1a9d');
+INSERT INTO items VALUES(NULL,'Covered Table (N/S) (3/3)',89,5737,0,'1669');
+INSERT INTO items VALUES(NULL,'Covered Table (N/S) (2/3)',89,5736,0,'1668');
+INSERT INTO items VALUES(NULL,'Covered Table (N/S) (1/3)',89,5735,0,'1667');
+INSERT INTO items VALUES(NULL,'Catapult 31',72,5734,0,'1666');
+INSERT INTO items VALUES(NULL,'Catapult 30',72,5733,0,'1665');
+INSERT INTO items VALUES(NULL,'Catapult 29',72,5732,0,'1664');
+INSERT INTO items VALUES(NULL,'Catapult 28',72,5731,0,'1663');
+INSERT INTO items VALUES(NULL,'Catapult 27',72,5730,0,'1662');
+INSERT INTO items VALUES(NULL,'Catapult 26',72,5729,0,'1661');
+INSERT INTO items VALUES(NULL,'Catapult 25',72,5728,0,'1660');
+INSERT INTO items VALUES(NULL,'Roof 12',84,1425,0,'591');
+INSERT INTO items VALUES(NULL,'Roof 11',84,1424,0,'590');
+INSERT INTO items VALUES(NULL,'Roof 14',84,1427,0,'593');
+INSERT INTO items VALUES(NULL,'Roof 13',84,1426,0,'592');
+INSERT INTO items VALUES(NULL,'Roof 1',209,1429,0,'595');
+INSERT INTO items VALUES(NULL,'Roof 15',84,1428,0,'594');
+INSERT INTO items VALUES(NULL,'Roof 3',209,1431,0,'597');
+INSERT INTO items VALUES(NULL,'Roof 2',209,1430,0,'596');
+INSERT INTO items VALUES(NULL,'Roof 5',209,1433,0,'599');
+INSERT INTO items VALUES(NULL,'Roof 4',209,1432,0,'598');
+INSERT INTO items VALUES(NULL,'Solen Queen',115,9730,0,'2602');
+INSERT INTO items VALUES(NULL,'Solen Warrior',115,9731,0,'2603');
+INSERT INTO items VALUES(NULL,'close helmet',24,5128,0,'1408');
+INSERT INTO items VALUES(NULL,'Vise (W/E)',107,6648,0,'19f8');
+INSERT INTO items VALUES(NULL,'Cooper''s Bench (N/S) (1/2)',107,6649,0,'19f9');
+INSERT INTO items VALUES(NULL,'Vise (N/S)',107,6644,0,'19f4');
+INSERT INTO items VALUES(NULL,'Woodworker''s Bench (W/E) (1/3)',107,6645,0,'19f5');
+INSERT INTO items VALUES(NULL,'Woodworker''s Bench (W/E) (2/3)',107,6646,0,'19f6');
+INSERT INTO items VALUES(NULL,'Woodworker''s Bench (W/E) (3/3)',107,6647,0,'19f7');
+INSERT INTO items VALUES(NULL,'mace',5,5127,0,'1407');
+INSERT INTO items VALUES(NULL,'Woodworker''s Bench (N/S) (1/3)',107,6641,0,'19f1');
+INSERT INTO items VALUES(NULL,'Woodworker''s Bench (N/S) (2/3)',107,6642,0,'19f2');
+INSERT INTO items VALUES(NULL,'Woodworker''s Bench (N/S) (3/3)',107,6643,0,'19f3');
+INSERT INTO items VALUES(NULL,'Deer Mask (N/S)',58,5447,0,'1547');
+INSERT INTO items VALUES(NULL,'Roof 6',209,1434,0,'59a');
+INSERT INTO items VALUES(NULL,'Roof 8',209,1436,0,'59c');
+INSERT INTO items VALUES(NULL,'Roof 7',209,1435,0,'59b');
+INSERT INTO items VALUES(NULL,'Roof 10',209,1438,0,'59e');
+INSERT INTO items VALUES(NULL,'Roof 9',209,1437,0,'59d');
+INSERT INTO items VALUES(NULL,'Roof 11',209,1439,0,'59f');
+INSERT INTO items VALUES(NULL,'Skull Cap (N/S)',58,5443,0,'1543');
+INSERT INTO items VALUES(NULL,'Flour Mill 3 (N/S) (2/2)',114,6450,0,'1932');
+INSERT INTO items VALUES(NULL,'bascinet',24,5132,0,'140c');
+INSERT INTO items VALUES(NULL,'helmet',24,5130,0,'140a');
+INSERT INTO items VALUES(NULL,'Body Sash (N/S)',60,5441,0,'1541');
+INSERT INTO items VALUES(NULL,'Flour Mill 3 (N/S) (1/2)',114,6449,0,'1931');
+INSERT INTO items VALUES(NULL,'nose helmet',24,5134,0,'140e');
+INSERT INTO items VALUES(NULL,'Cooper''s Bench (W/E) (2/2)',107,6652,0,'19fc');
+INSERT INTO items VALUES(NULL,'Crank (N/S)',114,6448,0,'1930');
+INSERT INTO items VALUES(NULL,'platemail gorget',210,5139,0,'iron_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Invisibility',94,8024,0,'1f58');
+INSERT INTO items VALUES(NULL,'Mark',94,8025,0,'1f59');
+INSERT INTO items VALUES(NULL,'Leaves 4 (3/10)',4,3465,0,'d89');
+INSERT INTO items VALUES(NULL,'Leaves 4 (2/10)',4,3464,0,'d88');
+INSERT INTO items VALUES(NULL,'Poison Field',94,8019,0,'1f53');
+INSERT INTO items VALUES(NULL,'Rotating Crank (N/S)',114,6452,0,'1934');
+INSERT INTO items VALUES(NULL,'Energy Bolt',94,8022,0,'1f56');
+INSERT INTO items VALUES(NULL,'Rug 23',176,7647,0,'1ddf');
+INSERT INTO items VALUES(NULL,'Rug 22',176,7646,0,'1dde');
+INSERT INTO items VALUES(NULL,'Rug 21',176,7645,0,'1ddd');
+INSERT INTO items VALUES(NULL,'Rug 20',176,7644,0,'1ddc');
+INSERT INTO items VALUES(NULL,'Rug 19',176,7643,0,'1ddb');
+INSERT INTO items VALUES(NULL,'Rug 18',176,7642,0,'1dda');
+INSERT INTO items VALUES(NULL,'Paralyze Field',94,8027,0,'1f5b');
+INSERT INTO items VALUES(NULL,'Leaves 4 (8/10)',4,3470,0,'d8e');
+INSERT INTO items VALUES(NULL,'Flamestrike',94,8031,0,'1f5f');
+INSERT INTO items VALUES(NULL,'Leaves 4 (5/10)',4,3467,0,'d8b');
+INSERT INTO items VALUES(NULL,'Chain Lightning',94,8029,0,'1f5d');
+INSERT INTO items VALUES(NULL,'Rug 15',176,7639,0,'1dd7');
+INSERT INTO items VALUES(NULL,'Rug 14',176,7638,0,'1dd6');
+INSERT INTO items VALUES(NULL,'Rug 13',176,7637,0,'1dd5');
+INSERT INTO items VALUES(NULL,'Rug 12',176,7636,0,'1dd4');
+INSERT INTO items VALUES(NULL,'Rug 11',176,7635,0,'1dd3');
+INSERT INTO items VALUES(NULL,'Marble Bench 2 (W/E) (2/3)',78,7634,0,'1dd2');
+INSERT INTO items VALUES(NULL,'Marble Bench 2 (W/E) (3/3)',78,7633,0,'1dd1');
+INSERT INTO items VALUES(NULL,'Marble Bench 2 (W/E) (1/3)',78,7632,0,'1dd0');
+INSERT INTO items VALUES(NULL,'Rug 17',176,7641,0,'1dd9');
+INSERT INTO items VALUES(NULL,'Rug 16',176,7640,0,'1dd8');
+INSERT INTO items VALUES(NULL,'Tree 2 (1/3)',4,3460,0,'d84');
+INSERT INTO items VALUES(NULL,'Ship 11',137,15998,0,'3e7e');
+INSERT INTO items VALUES(NULL,'Ship 10',137,15997,0,'3e7d');
+INSERT INTO items VALUES(NULL,'Ship 12',137,15999,0,'3e7f');
+INSERT INTO items VALUES(NULL,'heater shield',77,7030,0,'bronze_shields_heater');
+INSERT INTO items VALUES(NULL,'Ship 9',137,15996,0,'3e7c');
+INSERT INTO items VALUES(NULL,'Ship 8',137,15995,0,'3e7b');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (N/S) 2',116,7478,0,'1d36');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (N/S) 3',116,7479,0,'1d37');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (N/S) 5',116,7476,0,'1d34');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (N/S) 1',116,7477,0,'1d35');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (N/S) 3',116,7474,0,'1d32');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (N/S) 4',116,7475,0,'1d33');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (N/S) 1',116,7472,0,'1d30');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 1 (N/S) 2',116,7473,0,'1d31');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (W/E) 5',116,7463,0,'1d27');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (N/S) 4',116,7480,0,'1d38');
+INSERT INTO items VALUES(NULL,'Body in Wooden Coffin 2 (N/S) 5',116,7481,0,'1d39');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (N/S) 1',116,7487,0,'1d3f');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (N/S) 4',116,7485,0,'1d3d');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (N/S) 5',116,7486,0,'1d3e');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (N/S) 2',116,7483,0,'1d3b');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (N/S) 3',116,7484,0,'1d3c');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (N/S) 1',116,7482,0,'1d3a');
+INSERT INTO items VALUES(NULL,'Lava 6',52,10980,0,'2ae4');
+INSERT INTO items VALUES(NULL,'Lava 7',52,10981,0,'2ae5');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E; falling) 1',109,4426,0,'114a');
+INSERT INTO items VALUES(NULL,'Ship 7',137,15993,0,'3e79');
+INSERT INTO items VALUES(NULL,'Rudder 2',196,15992,0,'3e78');
+INSERT INTO items VALUES(NULL,'Fork (S/N)',14,2468,0,'9a4');
+INSERT INTO items VALUES(NULL,'Tiller 7',136,15989,0,'3e75');
+INSERT INTO items VALUES(NULL,'Sail 12',86,15988,0,'3e74');
+INSERT INTO items VALUES(NULL,'Tiller 9',136,15991,0,'3e77');
+INSERT INTO items VALUES(NULL,'platemail gloves',18,5140,0,'valorite_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Sail 7',86,15985,0,'3e71');
+INSERT INTO items VALUES(NULL,'Spar 3',88,15984,0,'3e70');
+INSERT INTO items VALUES(NULL,'Sail 9',86,15987,0,'3e73');
+INSERT INTO items VALUES(NULL,'Mast 6',8,15986,0,'3e72');
+INSERT INTO items VALUES(NULL,'Deck 2',193,15994,0,'3e7a');
+INSERT INTO items VALUES(NULL,'Bottle of Ale 2',155,2464,0,'9a0');
+INSERT INTO items VALUES(NULL,'Cooper''s Bench (W/E) (1/2)',107,6651,0,'19fb');
+INSERT INTO items VALUES(NULL,'Tribal Mask 2 (N/S)',58,5451,0,'154b');
+INSERT INTO items VALUES(NULL,'platemail legs',208,5137,0,'copper_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'Border 14',179,4936,0,'1348');
+INSERT INTO items VALUES(NULL,'Marble Bench 1 (N/S)',78,1113,0,'459');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',211,1104,0,'450');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',211,1105,0,'451');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',211,1106,0,'452');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',211,1107,0,'453');
+INSERT INTO items VALUES(NULL,'Border 13',179,4933,0,'1345');
+INSERT INTO items VALUES(NULL,'Arch 12',132,481,0,'1e1');
+INSERT INTO items VALUES(NULL,'Arch 11',132,480,0,'1e0');
+INSERT INTO items VALUES(NULL,'Arch 14',132,483,0,'1e3');
+INSERT INTO items VALUES(NULL,'Arch 13',132,482,0,'1e2');
+INSERT INTO items VALUES(NULL,'Arch 16',132,485,0,'1e5');
+INSERT INTO items VALUES(NULL,'Arch 15',132,484,0,'1e4');
+INSERT INTO items VALUES(NULL,'Battlement 2',132,487,0,'1e7');
+INSERT INTO items VALUES(NULL,'Battlement 1',132,486,0,'1e6');
+INSERT INTO items VALUES(NULL,'Small Wall 2',132,489,0,'1e9');
+INSERT INTO items VALUES(NULL,'Small Wall 1',132,488,0,'1e8');
+INSERT INTO items VALUES(NULL,'Wooden Boards 24',212,1212,0,'4bc');
+INSERT INTO items VALUES(NULL,'Wooden Boards 23',212,1211,0,'4bb');
+INSERT INTO items VALUES(NULL,'Wooden Boards 26',212,1214,0,'4be');
+INSERT INTO items VALUES(NULL,'Wooden Boards 25',212,1213,0,'4bd');
+INSERT INTO items VALUES(NULL,'Nightshade (N/S)',213,6374,0,'18e6');
+INSERT INTO items VALUES(NULL,'Wooden Boards 27',212,1215,0,'4bf');
+INSERT INTO items VALUES(NULL,'close helmet',214,5128,0,'merkite_helmets_close');
+INSERT INTO items VALUES(NULL,'Iron Gate 1 (W/NW)',120,2098,0,'832');
+INSERT INTO items VALUES(NULL,'Nails (N/S)',107,4143,0,'102f');
+INSERT INTO items VALUES(NULL,'Treasure (12/41)',215,6987,0,'1b4b');
+INSERT INTO items VALUES(NULL,'Small Wall 3',132,490,0,'1ea');
+INSERT INTO items VALUES(NULL,'Wooden Boards 20',212,1208,0,'4b8');
+INSERT INTO items VALUES(NULL,'Tiny Wall 9',47,492,0,'1ec');
+INSERT INTO items VALUES(NULL,'Small Wall 4',132,491,0,'1eb');
+INSERT INTO items VALUES(NULL,'Tiny Wall 11',47,494,0,'1ee');
+INSERT INTO items VALUES(NULL,'Tiny Wall 10',47,493,0,'1ed');
+INSERT INTO items VALUES(NULL,'Tiny Wall 12',47,495,0,'1ef');
+INSERT INTO items VALUES(NULL,'Wooden Boards 13',212,1201,0,'4b1');
+INSERT INTO items VALUES(NULL,'Wooden Boards 12',212,1200,0,'4b0');
+INSERT INTO items VALUES(NULL,'Wooden Boards 15',212,1203,0,'4b3');
+INSERT INTO items VALUES(NULL,'Wooden Boards 14',212,1202,0,'4b2');
+INSERT INTO items VALUES(NULL,'Wooden Boards 17',212,1205,0,'4b5');
+INSERT INTO items VALUES(NULL,'Wooden Boards 16',212,1204,0,'4b4');
+INSERT INTO items VALUES(NULL,'Wooden Boards 19',212,1207,0,'4b7');
+INSERT INTO items VALUES(NULL,'Wooden Boards 18',212,1206,0,'4b6');
+INSERT INTO items VALUES(NULL,'Marble Bench 1 (W/E)',78,1114,0,'45a');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 1 (N/S)',78,1115,0,'45b');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 1 (W/E)',78,1116,0,'45c');
+INSERT INTO items VALUES(NULL,'Empty Sandstone Fireplace (W/E) (1/2)',103,1117,0,'45d');
+INSERT INTO items VALUES(NULL,'Empty Sandstone Fireplace (W/E) (2/2)',103,1118,0,'45e');
+INSERT INTO items VALUES(NULL,'Boulder 1 (1/3)',216,4943,0,'134f');
+INSERT INTO items VALUES(NULL,'Balista 30',76,6332,0,'18bc');
+INSERT INTO items VALUES(NULL,'Fishing Net 7',148,3539,0,'dd3');
+INSERT INTO items VALUES(NULL,'Yew Tree 8',4,4797,0,'12bd');
+INSERT INTO items VALUES(NULL,'Field of Paralysis (W/E)',28,14713,0,'3979');
+INSERT INTO items VALUES(NULL,'Dirty Plate 1',14,2478,0,'9ae');
+INSERT INTO items VALUES(NULL,'platemail',159,5141,0,'agapite_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Pitcher of Milk 1',155,2477,0,'9ad');
+INSERT INTO items VALUES(NULL,'Rudder 1',196,15990,0,'3e76');
+INSERT INTO items VALUES(NULL,'Wooden Box (N/S)',65,2474,0,'9aa');
+INSERT INTO items VALUES(NULL,'Oar (N/S) (1/2)',114,7718,0,'1e26');
+INSERT INTO items VALUES(NULL,'Bushel',65,2476,0,'9ac');
+INSERT INTO items VALUES(NULL,'Metal Chest (N/S)',65,2475,0,'9ab');
+INSERT INTO items VALUES(NULL,'Seaweed 1',45,3514,0,'dba');
+INSERT INTO items VALUES(NULL,'Lilypad 6',45,3516,0,'dbc');
+INSERT INTO items VALUES(NULL,'Seaweed 2',45,3515,0,'dbb');
+INSERT INTO items VALUES(NULL,'Lilypads 2',45,3518,0,'dbe');
+INSERT INTO items VALUES(NULL,'Lilypad 7',45,3517,0,'dbd');
+INSERT INTO items VALUES(NULL,'Fishing Pole (N/S)',148,3519,0,'dbf');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 Lid (W/E) 2',116,7257,0,'1c59');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 Lid (W/E) 1',116,7256,0,'1c58');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 10',116,7251,0,'1c53');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 9',116,7250,0,'1c52');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 8',116,7249,0,'1c51');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 7',116,7248,0,'1c50');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 14',116,7255,0,'1c57');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 13',116,7254,0,'1c56');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 12',116,7253,0,'1c55');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 11',116,7252,0,'1c54');
+INSERT INTO items VALUES(NULL,'Carpet 8',217,2785,0,'ae1');
+INSERT INTO items VALUES(NULL,'Carpet 7',217,2784,0,'ae0');
+INSERT INTO items VALUES(NULL,'Carpet 1',218,2787,0,'ae3');
+INSERT INTO items VALUES(NULL,'Carpet 9',217,2786,0,'ae2');
+INSERT INTO items VALUES(NULL,'Carpet 3',218,2789,0,'ae5');
+INSERT INTO items VALUES(NULL,'Carpet 2',218,2788,0,'ae4');
+INSERT INTO items VALUES(NULL,'Carpet 5',218,2791,0,'ae7');
+INSERT INTO items VALUES(NULL,'Carpet 4',218,2790,0,'ae6');
+INSERT INTO items VALUES(NULL,'Carpet 7',218,2793,0,'ae9');
+INSERT INTO items VALUES(NULL,'Carpet 6',218,2792,0,'ae8');
+INSERT INTO items VALUES(NULL,'White Double Bed (N/S) (4/4)',91,2699,0,'a8b');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed (W/E) (1/4)',91,2700,0,'a8c');
+INSERT INTO items VALUES(NULL,'White Double Bed (N/S) (3/4)',91,2698,0,'a8a');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed 1 (W/E) (4/4)',91,2703,0,'a8f');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed (W/E) (2/4)',91,2701,0,'a8d');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed 1 (W/E) (3/4)',91,2702,0,'a8e');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 Lid (N/S) 1',116,7260,0,'1c5c');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 Lid (W/E) 4',116,7259,0,'1c5b');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 Lid (W/E) 3',116,7258,0,'1c5a');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 Lid (N/S) 4',116,7263,0,'1c5f');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 Lid (N/S) 3',116,7262,0,'1c5e');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 Lid (N/S) 2',116,7261,0,'1c5d');
+INSERT INTO items VALUES(NULL,'Hedge 4',45,3513,0,'db9');
+INSERT INTO items VALUES(NULL,'Hedge 3',45,3512,0,'db8');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed (N/S) (2/4)',91,3505,0,'db1');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed (N/S) (1/4)',91,3504,0,'db0');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed 1 (N/S) (4/4)',91,3507,0,'db3');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed 1 (N/S) (3/4)',91,3506,0,'db2');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed 2 (N/S) (4/4)',91,3509,0,'db5');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed 2 (N/S) (3/4)',91,3508,0,'db4');
+INSERT INTO items VALUES(NULL,'Double Bed 2 (N/S) (3/4)',91,2690,0,'a82');
+INSERT INTO items VALUES(NULL,'Double Bed 2 (N/S) (4/4)',91,2691,0,'a83');
+INSERT INTO items VALUES(NULL,'Double Bed 1 (N/S) (3/4)',91,2688,0,'a80');
+INSERT INTO items VALUES(NULL,'Double Bed 1 (N/S) (4/4)',91,2689,0,'a81');
+INSERT INTO items VALUES(NULL,'White Double Bed (W/E) (3/4)',91,2694,0,'a86');
+INSERT INTO items VALUES(NULL,'White Double Bed (W/E) (4/4)',91,2695,0,'a87');
+INSERT INTO items VALUES(NULL,'White Double Bed (W/E) (1/4)',91,2692,0,'a84');
+INSERT INTO items VALUES(NULL,'White Double Bed (W/E) (2/4)',91,2693,0,'a85');
+INSERT INTO items VALUES(NULL,'White Double Bed (N/S) (1/4)',91,2696,0,'a88');
+INSERT INTO items VALUES(NULL,'White Double Bed (N/S) (2/4)',91,2697,0,'a89');
+INSERT INTO items VALUES(NULL,'Carpet 8',218,2794,0,'aea');
+INSERT INTO items VALUES(NULL,'Carpet 1',219,2796,0,'aec');
+INSERT INTO items VALUES(NULL,'Carpet 9',218,2795,0,'aeb');
+INSERT INTO items VALUES(NULL,'Carpet 3',219,2798,0,'aee');
+INSERT INTO items VALUES(NULL,'Carpet 2',219,2797,0,'aed');
+INSERT INTO items VALUES(NULL,'Carpet 4',219,2799,0,'aef');
+INSERT INTO items VALUES(NULL,'Fishing Net 8',148,3540,0,'dd4');
+INSERT INTO items VALUES(NULL,'Orc (W/E)',160,7787,0,'1e6b');
+INSERT INTO items VALUES(NULL,'Agility',94,7989,0,'1f35');
+INSERT INTO items VALUES(NULL,'Polar Bear (W/E)',160,7788,0,'1e6c');
+INSERT INTO items VALUES(NULL,'Catapult 7',72,5710,0,'164e');
+INSERT INTO items VALUES(NULL,'Catapult 6',72,5709,0,'164d');
+INSERT INTO items VALUES(NULL,'Catapult 8',72,5711,0,'164f');
+INSERT INTO items VALUES(NULL,'Catapult 3',72,5706,0,'164a');
+INSERT INTO items VALUES(NULL,'Catapult 5',72,5708,0,'164c');
+INSERT INTO items VALUES(NULL,'Catapult 4',72,5707,0,'164b');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 1',2,7790,0,'1e6e');
+INSERT INTO items VALUES(NULL,'Blood 30',55,5701,0,'1645');
+INSERT INTO items VALUES(NULL,'Light Source',220,5703,0,'1647');
+INSERT INTO items VALUES(NULL,'Dark Source',220,5702,0,'1646');
+INSERT INTO items VALUES(NULL,'Shackles 3',113,5696,0,'1640');
+INSERT INTO items VALUES(NULL,'Catapult 2',72,5705,0,'1649');
+INSERT INTO items VALUES(NULL,'Catapult 1',72,5704,0,'1648');
+INSERT INTO items VALUES(NULL,'Grasses 14',45,3259,0,'cbb');
+INSERT INTO items VALUES(NULL,'Roof 1',221,1401,0,'579');
+INSERT INTO items VALUES(NULL,'Roof 19',222,1400,0,'578');
+INSERT INTO items VALUES(NULL,'Grasses 15',45,3260,0,'cbc');
+INSERT INTO items VALUES(NULL,'Wall 4',223,204,0,'cc');
+INSERT INTO items VALUES(NULL,'Arrow Loop 2',223,203,0,'cb');
+INSERT INTO items VALUES(NULL,'Arrow Loop 1',223,202,0,'ca');
+INSERT INTO items VALUES(NULL,'Roof 11',222,1392,0,'570');
+INSERT INTO items VALUES(NULL,'Roof 18',222,1399,0,'577');
+INSERT INTO items VALUES(NULL,'Arch 4',223,207,0,'cf');
+INSERT INTO items VALUES(NULL,'Arch 3',223,206,0,'ce');
+INSERT INTO items VALUES(NULL,'Arch 2',223,205,0,'cd');
+INSERT INTO items VALUES(NULL,'Roof 3',152,1537,0,'601');
+INSERT INTO items VALUES(NULL,'kite shield',207,7028,0,'iron_shields_kite');
+INSERT INTO items VALUES(NULL,'Roof 2',152,1536,0,'600');
+INSERT INTO items VALUES(NULL,'Roll of String (N/S)',224,5153,0,'1421');
+INSERT INTO items VALUES(NULL,'Roll of String (W/E)',224,5152,0,'1420');
+INSERT INTO items VALUES(NULL,'Beeswax 1 (N/S)',224,5155,0,'1423');
+INSERT INTO items VALUES(NULL,'Beeswax 1 (W/E)',224,5154,0,'1422');
+INSERT INTO items VALUES(NULL,'Beeswax 2 (N/S)',224,5157,0,'1425');
+INSERT INTO items VALUES(NULL,'Beeswax 2 (W/E)',224,5156,0,'1424');
+INSERT INTO items VALUES(NULL,'Beeswax 2 (N/S)',224,5159,0,'1427');
+INSERT INTO items VALUES(NULL,'Beeswax 3 (W/E)',224,5158,0,'1426');
+INSERT INTO items VALUES(NULL,'Dipping Stick (N/S)',224,5161,0,'1429');
+INSERT INTO items VALUES(NULL,'Dipping Stick (W/E)',224,5160,0,'1428');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (16/16) (Not Animated)',104,6610,0,'19d2');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (16/16)',104,6611,0,'19d3');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (14/16)',104,6608,0,'19d0');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (15/16)',104,6609,0,'19d1');
+INSERT INTO items VALUES(NULL,'Stone Bench 1 (W/E) (1/3)',78,4615,0,'1207');
+INSERT INTO items VALUES(NULL,'Bookcase 2 (N/S)',225,2712,0,'a98');
+INSERT INTO items VALUES(NULL,'Stone Table (W/E) (3/3)',89,4614,0,'1206');
+INSERT INTO items VALUES(NULL,'Stone Table (N/S) (1/3)',89,4609,0,'1201');
+INSERT INTO items VALUES(NULL,'Cot (N/S) (2/2)',226,4608,0,'1200');
+INSERT INTO items VALUES(NULL,'Wall 3',223,201,0,'c9');
+INSERT INTO items VALUES(NULL,'Wall 2',223,200,0,'c8');
+INSERT INTO items VALUES(NULL,'Folded Rich Sheet 1',91,2708,0,'a94');
+INSERT INTO items VALUES(NULL,'Roof 4',221,1404,0,'57c');
+INSERT INTO items VALUES(NULL,'Edge 2',149,194,0,'c2');
+INSERT INTO items VALUES(NULL,'Edge 1',149,193,0,'c1');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',149,192,0,'c0');
+INSERT INTO items VALUES(NULL,'Wall 1',223,199,0,'c7');
+INSERT INTO items VALUES(NULL,'Roof 1',227,1407,0,'57f');
+INSERT INTO items VALUES(NULL,'Column',223,197,0,'c5');
+INSERT INTO items VALUES(NULL,'Roof 5',221,1405,0,'57d');
+INSERT INTO items VALUES(NULL,'Pot of Wax 1',224,5162,0,'142a');
+INSERT INTO items VALUES(NULL,'Candle 3 (On)',73,5164,0,'142c');
+INSERT INTO items VALUES(NULL,'Pot of Wax 2',224,5163,0,'142b');
+INSERT INTO items VALUES(NULL,'Candle 3 (Off)',73,5167,0,'142f');
+INSERT INTO items VALUES(NULL,'helmet',97,5130,0,'verite_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (W/E) 4',116,7509,0,'1d55');
+INSERT INTO items VALUES(NULL,'Strength',94,7996,0,'1f3c');
+INSERT INTO items VALUES(NULL,'Fireball',94,7998,0,'1f3e');
+INSERT INTO items VALUES(NULL,'Spilled Dirt 2',202,7678,0,'1dfe');
+INSERT INTO items VALUES(NULL,'Spilled Dirt 1',202,7677,0,'1dfd');
+INSERT INTO items VALUES(NULL,'Spilled Dirt 3',202,7679,0,'1dff');
+INSERT INTO items VALUES(NULL,'Rug 12',228,7674,0,'1dfa');
+INSERT INTO items VALUES(NULL,'Rug 14',228,7676,0,'1dfc');
+INSERT INTO items VALUES(NULL,'Rug 13',228,7675,0,'1dfb');
+INSERT INTO items VALUES(NULL,'Feeblemind',94,7984,0,'1f30');
+INSERT INTO items VALUES(NULL,'Magic Arrow',94,7986,0,'1f32');
+INSERT INTO items VALUES(NULL,'Rug 11',228,7673,0,'1df9');
+INSERT INTO items VALUES(NULL,'Cunning',94,7990,0,'1f36');
+INSERT INTO items VALUES(NULL,'Rug 7',228,7669,0,'1df5');
+INSERT INTO items VALUES(NULL,'Rug 6',228,7668,0,'1df4');
+INSERT INTO items VALUES(NULL,'Rug 9',228,7671,0,'1df7');
+INSERT INTO items VALUES(NULL,'Rug 8',228,7670,0,'1df6');
+INSERT INTO items VALUES(NULL,'Rug 3',228,7665,0,'1df1');
+INSERT INTO items VALUES(NULL,'Rug 2',228,7664,0,'1df0');
+INSERT INTO items VALUES(NULL,'Rug 5',228,7667,0,'1df3');
+INSERT INTO items VALUES(NULL,'platemail',18,5141,0,'valorite_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Ore Cart (W/E) (2/3)',80,6792,0,'1a88');
+INSERT INTO items VALUES(NULL,'Ore Cart (N/S) (3/3)',80,6790,0,'1a86');
+INSERT INTO items VALUES(NULL,'Ore Cart (W/E) (1/3)',80,6791,0,'1a87');
+INSERT INTO items VALUES(NULL,'Small Wall 4',170,676,0,'2a4');
+INSERT INTO items VALUES(NULL,'Ore Cart (N/S) (1/3)',80,6786,0,'1a82');
+INSERT INTO items VALUES(NULL,'Ore Cart (N/S) (2/3)',80,6787,0,'1a83');
+INSERT INTO items VALUES(NULL,'Ore Cart (W/E) (3/3)',80,6795,0,'1a8b');
+INSERT INTO items VALUES(NULL,'platemail',208,5141,0,'copper_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Wood 18',11,7058,0,'1b92');
+INSERT INTO items VALUES(NULL,'Wood 19',11,7059,0,'1b93');
+INSERT INTO items VALUES(NULL,'Cattails 2',45,3256,0,'cb8');
+INSERT INTO items VALUES(NULL,'Wood 16',11,7056,0,'1b90');
+INSERT INTO items VALUES(NULL,'Grasses 12',45,3257,0,'cb9');
+INSERT INTO items VALUES(NULL,'Wood 17',11,7057,0,'1b91');
+INSERT INTO items VALUES(NULL,'Wood 22',11,7062,0,'1b96');
+INSERT INTO items VALUES(NULL,'Wood 23',11,7063,0,'1b97');
+INSERT INTO items VALUES(NULL,'Wood 20',11,7060,0,'1b94');
+INSERT INTO items VALUES(NULL,'Sandstone Fireplace (N/S) (1/2)',103,1147,0,'47b');
+INSERT INTO items VALUES(NULL,'Rock 11',216,4973,0,'136d');
+INSERT INTO items VALUES(NULL,'Rock 9',216,4971,0,'136b');
+INSERT INTO items VALUES(NULL,'Rock 10',216,4972,0,'136c');
+INSERT INTO items VALUES(NULL,'Rock 8',216,4970,0,'136a');
+INSERT INTO items VALUES(NULL,'Wood 21',11,7061,0,'1b95');
+INSERT INTO items VALUES(NULL,'Scroll 6 (W/E)',186,3642,0,'e3a');
+INSERT INTO items VALUES(NULL,'Rock 4',216,4966,0,'1366');
+INSERT INTO items VALUES(NULL,'Rock 5',216,4967,0,'1367');
+INSERT INTO items VALUES(NULL,'Rock 2',216,4964,0,'1364');
+INSERT INTO items VALUES(NULL,'Rock 3',216,4965,0,'1365');
+INSERT INTO items VALUES(NULL,'Boulder 8 (2/2)',216,4962,0,'1362');
+INSERT INTO items VALUES(NULL,'Rock 1',216,4963,0,'1363');
+INSERT INTO items VALUES(NULL,'Boulder 7 (2/2)',216,4960,0,'1360');
+INSERT INTO items VALUES(NULL,'Sandstone Fireplace (W/E) (1/2)',103,1141,0,'475');
+INSERT INTO items VALUES(NULL,'Rock 6',216,4968,0,'1368');
+INSERT INTO items VALUES(NULL,'Rock 7',216,4969,0,'1369');
+INSERT INTO items VALUES(NULL,'Wall Sconce (W/E) (On)',73,2557,0,'9fd');
+INSERT INTO items VALUES(NULL,'Muffins 1',19,2554,0,'9fa');
+INSERT INTO items VALUES(NULL,'Wall Sconce (W/E) (Off)',73,2555,0,'9fb');
+INSERT INTO items VALUES(NULL,'Wall Sconce (W/E) (Empty)',73,2556,0,'9fc');
+INSERT INTO items VALUES(NULL,'Sparkle (blue & gold) 1',28,14170,0,'375a');
+INSERT INTO items VALUES(NULL,'Wall 3',169,671,0,'29f');
+INSERT INTO items VALUES(NULL,'Merchants Guild (W/E)',229,3082,0,'c0a');
+INSERT INTO items VALUES(NULL,'Bank (N/S)',230,3083,0,'c0b');
+INSERT INTO items VALUES(NULL,'Bank (W/E)',230,3084,0,'c0c');
+INSERT INTO items VALUES(NULL,'Theatre (N/S)',230,3085,0,'c0d');
+INSERT INTO items VALUES(NULL,'Theatre (W/E)',230,3086,0,'c0e');
+INSERT INTO items VALUES(NULL,'Wall 4',211,666,0,'29a');
+INSERT INTO items VALUES(NULL,'Field of Fire (W/E)',28,14742,0,'3996');
+INSERT INTO items VALUES(NULL,'Fork (N/S)',14,2548,0,'9f4');
+INSERT INTO items VALUES(NULL,'Fork (W/E)',14,2549,0,'9f5');
+INSERT INTO items VALUES(NULL,'Knife (N/S)',14,2550,0,'9f6');
+INSERT INTO items VALUES(NULL,'Knife (W/E)',14,2551,0,'9f7');
+INSERT INTO items VALUES(NULL,'Pitcher of Milk 2',155,2544,0,'9f0');
+INSERT INTO items VALUES(NULL,'Cut of Raw Rips',19,2545,0,'9f1');
+INSERT INTO items VALUES(NULL,'Cut of Rips',19,2546,0,'9f2');
+INSERT INTO items VALUES(NULL,'Pan',14,2547,0,'9f3');
+INSERT INTO items VALUES(NULL,'Spoon (N/S)',14,2552,0,'9f8');
+INSERT INTO items VALUES(NULL,'Spoon (W/E)',14,2553,0,'9f9');
+INSERT INTO items VALUES(NULL,'Fighters Guild (W/E)',229,3080,0,'c08');
+INSERT INTO items VALUES(NULL,'Merchants Guild (N/S)',229,3081,0,'c09');
+INSERT INTO items VALUES(NULL,'Wall 2',211,664,0,'298');
+INSERT INTO items VALUES(NULL,'Wall 3',211,665,0,'299');
+INSERT INTO items VALUES(NULL,'Assassins Guild (W/E)',229,3072,0,'c00');
+INSERT INTO items VALUES(NULL,'Tinkers Guild (N/S)',229,3073,0,'c01');
+INSERT INTO items VALUES(NULL,'Tinkers Guild (W/E)',229,3074,0,'c02');
+INSERT INTO items VALUES(NULL,'Warriors Guild (N/S)',229,3075,0,'c03');
+INSERT INTO items VALUES(NULL,'Warriors Guild (W/E)',229,3076,0,'c04');
+INSERT INTO items VALUES(NULL,'Cavalry Guild (N/S)',229,3077,0,'c05');
+INSERT INTO items VALUES(NULL,'Cavalry Guild (W/E)',229,3078,0,'c06');
+INSERT INTO items VALUES(NULL,'Fighters Guild (N/S)',229,3079,0,'c07');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 15',100,7281,0,'1c71');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 14',100,7280,0,'1c70');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 17',100,7283,0,'1c73');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 16',100,7282,0,'1c72');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 19',100,7285,0,'1c75');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 18',100,7284,0,'1c74');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 21',100,7287,0,'1c77');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 20',100,7286,0,'1c76');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 23',100,7289,0,'1c79');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 22',100,7288,0,'1c78');
+INSERT INTO items VALUES(NULL,'Balista 119',76,16226,0,'3f62');
+INSERT INTO items VALUES(NULL,'Roof 5',227,1411,0,'583');
+INSERT INTO items VALUES(NULL,'Roof 18',231,1791,0,'6ff');
+INSERT INTO items VALUES(NULL,'Roof 17',231,1790,0,'6fe');
+INSERT INTO items VALUES(NULL,'platemail',181,5141,0,'verite_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Balista 125',76,16232,0,'3f68');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 24',100,7290,0,'1c7a');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 26',100,7292,0,'1c7c');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 25',100,7291,0,'1c7b');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 2 (W/E) (2/3)',100,7294,0,'1c7e');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 2 (W/E) (1/3)',100,7293,0,'1c7d');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 2 (W/E) (3/3)',100,7295,0,'1c7f');
+INSERT INTO items VALUES(NULL,'Portcullis (W/E)',232,1782,0,'6f6');
+INSERT INTO items VALUES(NULL,'Portcullis (N/S)',232,1781,0,'6f5');
+INSERT INTO items VALUES(NULL,'Wooden Door 4 (W/NW)',233,1779,0,'6f3');
+INSERT INTO items VALUES(NULL,'Wooden Door 4 (W/SW)',233,1777,0,'6f1');
+INSERT INTO items VALUES(NULL,'Wall 11',149,8663,0,'21d7');
+INSERT INTO items VALUES(NULL,'Wall 10',149,8662,0,'21d6');
+INSERT INTO items VALUES(NULL,'Wall 9',149,8661,0,'21d5');
+INSERT INTO items VALUES(NULL,'Fence 8',234,8660,0,'21d4');
+INSERT INTO items VALUES(NULL,'Fence 7',234,8659,0,'21d3');
+INSERT INTO items VALUES(NULL,'Fence 6',234,8658,0,'21d2');
+INSERT INTO items VALUES(NULL,'Fence 5',234,8657,0,'21d1');
+INSERT INTO items VALUES(NULL,'Tiny Wall 8',149,8656,0,'21d0');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 9',149,8665,0,'21d9');
+INSERT INTO items VALUES(NULL,'Wall 12',149,8664,0,'21d8');
+INSERT INTO items VALUES(NULL,'ringmail leggings',235,5104,0,'agapite_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'Banner 6 (N/S) 2',128,5676,0,'162c');
+INSERT INTO items VALUES(NULL,'Swamp 3',236,12815,0,'320f');
+INSERT INTO items VALUES(NULL,'Swamp 2',236,12814,0,'320e');
+INSERT INTO items VALUES(NULL,'Swamp 1',236,12813,0,'320d');
+INSERT INTO items VALUES(NULL,'Forge (E/W) (1/3)',30,6558,0,'199e');
+INSERT INTO items VALUES(NULL,'Banner 8 (N/S) 1',128,5679,0,'162f');
+INSERT INTO items VALUES(NULL,'Swamp 2',237,12810,0,'320a');
+INSERT INTO items VALUES(NULL,'Banner 6 (N/S) 3',128,5677,0,'162d');
+INSERT INTO items VALUES(NULL,'Smaller Wall 7',238,8671,0,'21df');
+INSERT INTO items VALUES(NULL,'Smaller Wall 6',238,8670,0,'21de');
+INSERT INTO items VALUES(NULL,'Smaller Wall 5',238,8669,0,'21dd');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 12',149,8668,0,'21dc');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 11',149,8667,0,'21db');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 10',149,8666,0,'21da');
+INSERT INTO items VALUES(NULL,'Banner 3 (N/S) 1',128,5667,0,'1623');
+INSERT INTO items VALUES(NULL,'Banner 2 (N/S) 3',128,5666,0,'1622');
+INSERT INTO items VALUES(NULL,'Banner 2 (N/S) 2',128,5665,0,'1621');
+INSERT INTO items VALUES(NULL,'Banner 2 (N/S) 1',128,5664,0,'1620');
+INSERT INTO items VALUES(NULL,'Banner 4 (N/S) 1',128,5671,0,'1627');
+INSERT INTO items VALUES(NULL,'Banner Hanger (N/S)',128,5670,0,'1626');
+INSERT INTO items VALUES(NULL,'Banner 3 (N/S) 3',128,5669,0,'1625');
+INSERT INTO items VALUES(NULL,'Banner 3 (N/S) 2',128,5668,0,'1624');
+INSERT INTO items VALUES(NULL,'Banner 5 (N/S) 1',128,5673,0,'1629');
+INSERT INTO items VALUES(NULL,'Banner 4 (N/S) 2',128,5672,0,'1628');
+INSERT INTO items VALUES(NULL,'Swamp 1',237,12809,0,'3209');
+INSERT INTO items VALUES(NULL,'Hay 1',45,6802,0,'1a92');
+INSERT INTO items VALUES(NULL,'Roof 3',222,1369,0,'559');
+INSERT INTO items VALUES(NULL,'Roof 2',222,1368,0,'558');
+INSERT INTO items VALUES(NULL,'Roof 2',150,1365,0,'555');
+INSERT INTO items VALUES(NULL,'Roof 1',150,1364,0,'554');
+INSERT INTO items VALUES(NULL,'Roof 4',150,1367,0,'557');
+INSERT INTO items VALUES(NULL,'Roof 3',150,1366,0,'556');
+INSERT INTO items VALUES(NULL,'Cave Floor 21',239,1361,0,'551');
+INSERT INTO items VALUES(NULL,'Roof 1',222,1360,0,'550');
+INSERT INTO items VALUES(NULL,'Cave Floor 23',239,1363,0,'553');
+INSERT INTO items VALUES(NULL,'Cave Floor 22',239,1362,0,'552');
+INSERT INTO items VALUES(NULL,'Hay 4',45,6805,0,'1a95');
+INSERT INTO items VALUES(NULL,'war hammer',5,5177,0,'1439');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E) 7',109,4505,0,'1199');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E) 6',109,4504,0,'1198');
+INSERT INTO items VALUES(NULL,'Wheat Sprout 2',213,7871,0,'1ebf');
+INSERT INTO items VALUES(NULL,'Toolkit 2 (W/E)',240,7866,0,'1eba');
+INSERT INTO items VALUES(NULL,'Toolkit 2 (N/S)',240,7867,0,'1ebb');
+INSERT INTO items VALUES(NULL,'Iron Ore 1',80,6583,0,'19b7');
+INSERT INTO items VALUES(NULL,'Covered Counter (N/S) (1/2)',89,4497,0,'1191');
+INSERT INTO items VALUES(NULL,'Covered Counter (W/E) (2/2)',89,4496,0,'1190');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E) 1',109,4499,0,'1193');
+INSERT INTO items VALUES(NULL,'Covered Counter (N/S) (2/2)',89,4498,0,'1192');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E) 3',109,4501,0,'1195');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E) 2',109,4500,0,'1194');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E) 5',109,4503,0,'1197');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E) 4',109,4502,0,'1196');
+INSERT INTO items VALUES(NULL,'Magic Untrap',94,7994,0,'1f3a');
+INSERT INTO items VALUES(NULL,'ringmail gloves',42,5099,0,'bronze_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Roof 8',150,1374,0,'55e');
+INSERT INTO items VALUES(NULL,'Roof 7',150,1373,0,'55d');
+INSERT INTO items VALUES(NULL,'Roof 9',150,1375,0,'55f');
+INSERT INTO items VALUES(NULL,'Roof 4',222,1370,0,'55a');
+INSERT INTO items VALUES(NULL,'Roof 5',150,1372,0,'55c');
+INSERT INTO items VALUES(NULL,'Roof 5',222,1371,0,'55b');
+INSERT INTO items VALUES(NULL,'Hay 5',45,6806,0,'1a96');
+INSERT INTO items VALUES(NULL,'Barrel Staves 4',107,7860,0,'1eb4');
+INSERT INTO items VALUES(NULL,'Unfinished Barrel',107,7861,0,'1eb5');
+INSERT INTO items VALUES(NULL,'Brazier 3',73,6587,0,'19bb');
+INSERT INTO items VALUES(NULL,'Empty Toolkit 2',240,7863,0,'1eb7');
+INSERT INTO items VALUES(NULL,'Burned Food',19,7856,0,'1eb0');
+INSERT INTO items VALUES(NULL,'Barrel Staves 1',107,7857,0,'1eb1');
+INSERT INTO items VALUES(NULL,'Barrel Staves 2',107,7858,0,'1eb2');
+INSERT INTO items VALUES(NULL,'Barrel Staves 3',107,7859,0,'1eb3');
+INSERT INTO items VALUES(NULL,'Floor Spikes (W/E) 1',109,4506,0,'119a');
+INSERT INTO items VALUES(NULL,'Floor Spikes (W/E) 3',109,4508,0,'119c');
+INSERT INTO items VALUES(NULL,'Floor Spikes (W/E) 2',109,4507,0,'119b');
+INSERT INTO items VALUES(NULL,'Floor Spikes (W/E) 5',109,4510,0,'119e');
+INSERT INTO items VALUES(NULL,'Floor Spikes (W/E) 4',109,4509,0,'119d');
+INSERT INTO items VALUES(NULL,'Floor Spikes (W/E) 6',109,4511,0,'119f');
+INSERT INTO items VALUES(NULL,'Dagges 3',241,890,0,'37a');
+INSERT INTO items VALUES(NULL,'Leaves 1 (7/15)',4,3403,0,'d4b');
+INSERT INTO items VALUES(NULL,'Dagges 5',241,892,0,'37c');
+INSERT INTO items VALUES(NULL,'Dagges 4',241,891,0,'37b');
+INSERT INTO items VALUES(NULL,'Dagges 6',241,893,0,'37d');
+INSERT INTO items VALUES(NULL,'Leaves 1 (10/15)',4,3406,0,'d4e');
+INSERT INTO items VALUES(NULL,'Wall 1',41,895,0,'37f');
+INSERT INTO items VALUES(NULL,'Barrel 2',65,4014,0,'fae');
+INSERT INTO items VALUES(NULL,'Border 12',179,4930,0,'1342');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',39,5103,0,'dull_copper_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'Nightshade Root (N/S)',213,6376,0,'18e8');
+INSERT INTO items VALUES(NULL,'Magic Lock',94,7999,0,'1f3f');
+INSERT INTO items VALUES(NULL,'Dagges 2',241,889,0,'379');
+INSERT INTO items VALUES(NULL,'Dagges 1',241,888,0,'378');
+INSERT INTO items VALUES(NULL,'Leaves 1 (5/15)',4,3401,0,'d49');
+INSERT INTO items VALUES(NULL,'Leaves 1 (4/15)',4,3400,0,'d48');
+INSERT INTO items VALUES(NULL,'Statue 6',31,7960,0,'1f18');
+INSERT INTO items VALUES(NULL,'Green Magical Crystal',186,7961,0,'1f19');
+INSERT INTO items VALUES(NULL,'Wall 10',241,881,0,'371');
+INSERT INTO items VALUES(NULL,'Wall 9',241,880,0,'370');
+INSERT INTO items VALUES(NULL,'Patch 2',241,883,0,'373');
+INSERT INTO items VALUES(NULL,'Patch 1',241,882,0,'372');
+INSERT INTO items VALUES(NULL,'Patch 4',241,885,0,'375');
+INSERT INTO items VALUES(NULL,'Patch 3',241,884,0,'374');
+INSERT INTO items VALUES(NULL,'Patch 6',241,887,0,'377');
+INSERT INTO items VALUES(NULL,'Patch 5',241,886,0,'376');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (8/9)',108,6129,0,'17f1');
+INSERT INTO items VALUES(NULL,'Wooden Boards 22',212,1210,0,'4ba');
+INSERT INTO items VALUES(NULL,'Empty Vat (8/9)',242,5342,0,'14de');
+INSERT INTO items VALUES(NULL,'Empty Vat (7/9)',242,5341,0,'14dd');
+INSERT INTO items VALUES(NULL,'Empty Vat (6/9)',242,5340,0,'14dc');
+INSERT INTO items VALUES(NULL,'Empty Vat (5/9)',242,5339,0,'14db');
+INSERT INTO items VALUES(NULL,'Empty Vat 1 (3/9)',242,5338,0,'14da');
+INSERT INTO items VALUES(NULL,'Garlic (W/E)',213,6369,0,'18e1');
+INSERT INTO items VALUES(NULL,'Garlic (N/S)',213,6370,0,'18e2');
+INSERT INTO items VALUES(NULL,'Garlic Bulb (W/E)',213,6371,0,'18e3');
+INSERT INTO items VALUES(NULL,'Garlic Bulb (N/S)',213,6372,0,'18e4');
+INSERT INTO items VALUES(NULL,'Nightshade (W/E)',213,6373,0,'18e5');
+INSERT INTO items VALUES(NULL,'Balista 158',76,16265,0,'3f89');
+INSERT INTO items VALUES(NULL,'Balista 157',76,16264,0,'3f88');
+INSERT INTO items VALUES(NULL,'Ship 1',137,15935,0,'3e3f');
+INSERT INTO items VALUES(NULL,'Balista 152',76,16259,0,'3f83');
+INSERT INTO items VALUES(NULL,'Cauldron (N/S)',14,2420,0,'974');
+INSERT INTO items VALUES(NULL,'Balista 150',76,16257,0,'3f81');
+INSERT INTO items VALUES(NULL,'Balista 149',76,16256,0,'3f80');
+INSERT INTO items VALUES(NULL,'Balista 156',76,16263,0,'3f87');
+INSERT INTO items VALUES(NULL,'Balista 155',76,16262,0,'3f86');
+INSERT INTO items VALUES(NULL,'Balista 154',76,16261,0,'3f85');
+INSERT INTO items VALUES(NULL,'Balista 153',76,16260,0,'3f84');
+INSERT INTO items VALUES(NULL,'Empty Vat (1/9)',242,5335,0,'14d7');
+INSERT INTO items VALUES(NULL,'Part 4',243,5334,0,'14d6');
+INSERT INTO items VALUES(NULL,'Part 3',243,5333,0,'14d5');
+INSERT INTO items VALUES(NULL,'Part 2',243,5332,0,'14d4');
+INSERT INTO items VALUES(NULL,'Part 1',243,5331,0,'14d3');
+INSERT INTO items VALUES(NULL,'Part 4',244,5330,0,'14d2');
+INSERT INTO items VALUES(NULL,'Part 3',244,5329,0,'14d1');
+INSERT INTO items VALUES(NULL,'Part 2',244,5328,0,'14d0');
+INSERT INTO items VALUES(NULL,'Empty Vat (4/9)',242,5337,0,'14d9');
+INSERT INTO items VALUES(NULL,'Empty Vat 1 (2/9)',242,5336,0,'14d8');
+INSERT INTO items VALUES(NULL,'Balista 161',76,16268,0,'3f8c');
+INSERT INTO items VALUES(NULL,'Balista 160',76,16267,0,'3f8b');
+INSERT INTO items VALUES(NULL,'Balista 159',76,16266,0,'3f8a');
+INSERT INTO items VALUES(NULL,'Balista 164',76,16271,0,'3f8f');
+INSERT INTO items VALUES(NULL,'Balista 163',76,16270,0,'3f8e');
+INSERT INTO items VALUES(NULL,'Balista 162',76,16269,0,'3f8d');
+INSERT INTO items VALUES(NULL,'Statue 6 (3/3)',54,10912,0,'2aa0');
+INSERT INTO items VALUES(NULL,'platemail arms',18,5136,0,'valorite_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'Dupre',245,8272,0,'2050');
+INSERT INTO items VALUES(NULL,'Wooden Boards 21',212,1209,0,'4b9');
+INSERT INTO items VALUES(NULL,'Ginseng (N/S)',213,6378,0,'18ea');
+INSERT INTO items VALUES(NULL,'Ginseng Root (N/S)',213,6379,0,'18eb');
+INSERT INTO items VALUES(NULL,'Ginseng Root (W/E)',213,6380,0,'18ec');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 1 (N/S) (2/2)',103,2260,0,'8d4');
+INSERT INTO items VALUES(NULL,'Arch 11',223,216,0,'d8');
+INSERT INTO items VALUES(NULL,'Arch 12',223,217,0,'d9');
+INSERT INTO items VALUES(NULL,'Arch 9',223,214,0,'d6');
+INSERT INTO items VALUES(NULL,'Arch 10',223,215,0,'d7');
+INSERT INTO items VALUES(NULL,'Arch 7',223,212,0,'d4');
+INSERT INTO items VALUES(NULL,'Arch 8',223,213,0,'d5');
+INSERT INTO items VALUES(NULL,'Buttress 1',223,210,0,'d2');
+INSERT INTO items VALUES(NULL,'Buttress 2',223,211,0,'d3');
+INSERT INTO items VALUES(NULL,'Arch 5',223,208,0,'d0');
+INSERT INTO items VALUES(NULL,'Arch 6',223,209,0,'d1');
+INSERT INTO items VALUES(NULL,'Unlabeled 19',246,1053,0,'41d');
+INSERT INTO items VALUES(NULL,'Unlabeled 20',246,1054,0,'41e');
+INSERT INTO items VALUES(NULL,'Gruesome Standard 1',201,1055,0,'41f');
+INSERT INTO items VALUES(NULL,'Long Cannon (E/W) (1/3)',67,3726,0,'e8e');
+INSERT INTO items VALUES(NULL,'Long Cannon (S/N) (1/3)',67,3723,0,'e8b');
+INSERT INTO items VALUES(NULL,'Unlabeled 16',246,1050,0,'41a');
+INSERT INTO items VALUES(NULL,'Unlabeled 17',246,1051,0,'41b');
+INSERT INTO items VALUES(NULL,'Unlabeled 18',246,1052,0,'41c');
+INSERT INTO items VALUES(NULL,'Empty Sandstone Fireplace (N/S) (1/2)',103,1119,0,'45f');
+INSERT INTO items VALUES(NULL,'Small Wall 4',223,223,0,'df');
+INSERT INTO items VALUES(NULL,'Small Wall 2',223,221,0,'dd');
+INSERT INTO items VALUES(NULL,'Small Wall 3',223,222,0,'de');
+INSERT INTO items VALUES(NULL,'Pillar',223,219,0,'db');
+INSERT INTO items VALUES(NULL,'Small Wall 1',223,220,0,'dc');
+INSERT INTO items VALUES(NULL,'Arch 13',223,218,0,'da');
+INSERT INTO items VALUES(NULL,'Unlabeled 10',246,1044,0,'414');
+INSERT INTO items VALUES(NULL,'Unlabeled 11',246,1045,0,'415');
+INSERT INTO items VALUES(NULL,'Unlabeled 12',246,1046,0,'416');
+INSERT INTO items VALUES(NULL,'Unlabeled 13',246,1047,0,'417');
+INSERT INTO items VALUES(NULL,'Unlabeled 6',246,1040,0,'410');
+INSERT INTO items VALUES(NULL,'Unlabeled 7',246,1041,0,'411');
+INSERT INTO items VALUES(NULL,'ringmail leggings',56,5104,0,'merkite_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'Unlabeled 9',246,1043,0,'413');
+INSERT INTO items VALUES(NULL,'Sandstone Corner 2',93,4996,0,'1384');
+INSERT INTO items VALUES(NULL,'Sandstone Corner 3',93,4997,0,'1385');
+INSERT INTO items VALUES(NULL,'Sandstone Corner 4',93,4998,0,'1386');
+INSERT INTO items VALUES(NULL,'Unlabeled 14',246,1048,0,'418');
+INSERT INTO items VALUES(NULL,'Unlabeled 15',246,1049,0,'419');
+INSERT INTO items VALUES(NULL,'Sandstone Corner 1',93,4995,0,'1383');
+INSERT INTO items VALUES(NULL,'Dirty Pot 3',14,2527,0,'9df');
+INSERT INTO items VALUES(NULL,'Dirty Pot 2',14,2525,0,'9dd');
+INSERT INTO items VALUES(NULL,'Dirty Frypan',14,2526,0,'9de');
+INSERT INTO items VALUES(NULL,'Plate of Food 4',14,2523,0,'9db');
+INSERT INTO items VALUES(NULL,'Dirty Pot 1',14,2524,0,'9dc');
+INSERT INTO items VALUES(NULL,'Dirty Plate 2',14,2522,0,'9da');
+INSERT INTO items VALUES(NULL,'Ruined Bed 1 (N/S) (3/3)',247,3115,0,'c2b');
+INSERT INTO items VALUES(NULL,'Ruined Painting',247,3116,0,'c2c');
+INSERT INTO items VALUES(NULL,'Ruined Bed 1 (N/S) (2/3)',247,3114,0,'c2a');
+INSERT INTO items VALUES(NULL,'Debris 3',247,3119,0,'c2f');
+INSERT INTO items VALUES(NULL,'Debris 1',247,3117,0,'c2d');
+INSERT INTO items VALUES(NULL,'Debris 2',247,3118,0,'c2e');
+INSERT INTO items VALUES(NULL,'Tuscany Pine',4,7038,0,'1b7e');
+INSERT INTO items VALUES(NULL,'Plate of Food 2',14,2520,0,'9d8');
+INSERT INTO items VALUES(NULL,'Plate of Food 3',14,2521,0,'9d9');
+INSERT INTO items VALUES(NULL,'Pitcher',14,2518,0,'9d6');
+INSERT INTO items VALUES(NULL,'Plate',14,2519,0,'9d7');
+INSERT INTO items VALUES(NULL,'Silverware 2 (N/S)',14,2516,0,'9d4');
+INSERT INTO items VALUES(NULL,'Silverware 2 (W/E)',14,2517,0,'9d5');
+INSERT INTO items VALUES(NULL,'Peach 1',19,2514,0,'9d2');
+INSERT INTO items VALUES(NULL,'Ham (N/S)',19,2515,0,'9d3');
+INSERT INTO items VALUES(NULL,'Apple',19,2512,0,'9d0');
+INSERT INTO items VALUES(NULL,'Grape Bunch 1',19,2513,0,'9d1');
+INSERT INTO items VALUES(NULL,'Broken Dresser (N/S) (1/2)',247,3106,0,'c22');
+INSERT INTO items VALUES(NULL,'Broken Dresser (N/S) (2/2)',247,3107,0,'c23');
+INSERT INTO items VALUES(NULL,'Broken Dresser (W/E) (1/2)',247,3104,0,'c20');
+INSERT INTO items VALUES(NULL,'Broken Dresser (W/E) (2/2)',247,3105,0,'c21');
+INSERT INTO items VALUES(NULL,'Ruined Bed 1 (W/E) (1/3)',247,3110,0,'c26');
+INSERT INTO items VALUES(NULL,'Ruined Bed 1 (W/E) (2/3)',247,3111,0,'c27');
+INSERT INTO items VALUES(NULL,'Broken Furniture (N/S)',247,3108,0,'c24');
+INSERT INTO items VALUES(NULL,'Broken Furniture (W/E)',247,3109,0,'c25');
+INSERT INTO items VALUES(NULL,'Ruined Bed 1 (W/E) (3/3)',247,3112,0,'c28');
+INSERT INTO items VALUES(NULL,'Ruined Bed 1 (N/S) (1/3)',247,3113,0,'c29');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 7',100,7321,0,'1c99');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 1 (N/S) (3/3)',100,7320,0,'1c98');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 1 (N/S) (2/3)',100,7319,0,'1c97');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 1 (N/S) (1/3)',100,7318,0,'1c96');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 6',100,7317,0,'1c95');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 5',100,7316,0,'1c94');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 4',100,7315,0,'1c93');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 3',100,7314,0,'1c92');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 2',100,7313,0,'1c91');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 1',100,7312,0,'1c90');
+INSERT INTO items VALUES(NULL,'Wooden Door 3 (S/NE)',248,1755,0,'6db');
+INSERT INTO items VALUES(NULL,'platemail',187,5141,0,'merkite_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Wooden Door 3 (W/SE)',248,1757,0,'6dd');
+INSERT INTO items VALUES(NULL,'Wooden Door 3 (W/NE)',248,1759,0,'6df');
+INSERT INTO items VALUES(NULL,'Dartboard 1 (W/E)',249,7727,0,'1e2f');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 13',100,7327,0,'1c9f');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 12',100,7326,0,'1c9e');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 11',100,7325,0,'1c9d');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 10',100,7324,0,'1c9c');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 9',100,7323,0,'1c9b');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 8',100,7322,0,'1c9a');
+INSERT INTO items VALUES(NULL,'Metal Door 2 (W/SW)',250,1745,0,'6d1');
+INSERT INTO items VALUES(NULL,'Metal Door 2 (W/NW)',250,1747,0,'6d3');
+INSERT INTO items VALUES(NULL,'Wooden Door 3 (S/SW)',248,1749,0,'6d5');
+INSERT INTO items VALUES(NULL,'Wooden Door 3 (S/SE)',248,1751,0,'6d7');
+INSERT INTO items VALUES(NULL,'Wooden Door 3 (S/NW)',248,1753,0,'6d9');
+INSERT INTO items VALUES(NULL,'Fire Steed',115,8503,0,'21f1');
+INSERT INTO items VALUES(NULL,'Roof 27',231,8688,0,'21f0');
+INSERT INTO items VALUES(NULL,'Flask 29',173,6214,0,'1846');
+INSERT INTO items VALUES(NULL,'Hourglass',173,6160,0,'1810');
+INSERT INTO items VALUES(NULL,'Hourglass (Animated)',173,6161,0,'1811');
+INSERT INTO items VALUES(NULL,'Oars (N/S)',114,7722,0,'1e2a');
+INSERT INTO items VALUES(NULL,'Swamp 3',251,12846,0,'322e');
+INSERT INTO items VALUES(NULL,'Swamp 2',251,12845,0,'322d');
+INSERT INTO items VALUES(NULL,'Plate of Cookies',19,5644,0,'160c');
+INSERT INTO items VALUES(NULL,'Swamp 4',251,12847,0,'322f');
+INSERT INTO items VALUES(NULL,'Swamp 26',236,12842,0,'322a');
+INSERT INTO items VALUES(NULL,'Swamp 1',251,12844,0,'322c');
+INSERT INTO items VALUES(NULL,'Banner 9 (N/S) 1',128,5647,0,'160f');
+INSERT INTO items VALUES(NULL,'Raw Leg of Lamb',19,5641,0,'1609');
+INSERT INTO items VALUES(NULL,'Chicken Leg',19,5640,0,'1608');
+INSERT INTO items VALUES(NULL,'Swamp 25',236,12841,0,'3229');
+INSERT INTO items VALUES(NULL,'Swamp 24',236,12840,0,'3228');
+INSERT INTO items VALUES(NULL,'Bowl of Peas 2',19,5633,0,'1601');
+INSERT INTO items VALUES(NULL,'Swamp 21',236,12836,0,'3224');
+INSERT INTO items VALUES(NULL,'Swamp 23',236,12839,0,'3227');
+INSERT INTO items VALUES(NULL,'Swamp 22',236,12838,0,'3226');
+INSERT INTO items VALUES(NULL,'Swamp 18',236,12833,0,'3221');
+INSERT INTO items VALUES(NULL,'Swamp 17',236,12832,0,'3220');
+INSERT INTO items VALUES(NULL,'Swamp 20',236,12835,0,'3223');
+INSERT INTO items VALUES(NULL,'Swamp 19',236,12834,0,'3222');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 1',173,6173,0,'181d');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 2',173,6174,0,'181e');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 3',173,6175,0,'181f');
+INSERT INTO items VALUES(NULL,'Wave 30',62,8128,0,'1fc0');
+INSERT INTO items VALUES(NULL,'Sand Vortex',115,9750,0,'2616');
+INSERT INTO items VALUES(NULL,'Ridgeback',115,9749,0,'2615');
+INSERT INTO items VALUES(NULL,'Quagmire',115,9748,0,'2614');
+INSERT INTO items VALUES(NULL,'Plague Beast',115,9747,0,'2613');
+INSERT INTO items VALUES(NULL,'Wave 35',62,8133,0,'1fc5');
+INSERT INTO items VALUES(NULL,'Cave Floor 5',239,1343,0,'53f');
+INSERT INTO items VALUES(NULL,'Cave Floor 4',239,1342,0,'53e');
+INSERT INTO items VALUES(NULL,'Cave Floor 3',239,1341,0,'53d');
+INSERT INTO items VALUES(NULL,'Cave Floor 2',239,1340,0,'53c');
+INSERT INTO items VALUES(NULL,'Cave Floor 1',239,1339,0,'53b');
+INSERT INTO items VALUES(NULL,'Bricks 12',252,1338,0,'53a');
+INSERT INTO items VALUES(NULL,'Wall 23',127,992,0,'3e0');
+INSERT INTO items VALUES(NULL,'Curse',94,8007,0,'1f47');
+INSERT INTO items VALUES(NULL,'Telekinesis',94,8001,0,'1f41');
+INSERT INTO items VALUES(NULL,'Unlock',94,8003,0,'1f43');
+INSERT INTO items VALUES(NULL,'Vat w. Water 1 (5/6)',242,5461,0,'1555');
+INSERT INTO items VALUES(NULL,'Bricks 9',252,1335,0,'537');
+INSERT INTO items VALUES(NULL,'Dark Sandstone Floor 8',253,1334,0,'536');
+INSERT INTO items VALUES(NULL,'Dark Sandstone Floor 7',253,1333,0,'535');
+INSERT INTO items VALUES(NULL,'Dark Sandstone Floor 6',253,1332,0,'534');
+INSERT INTO items VALUES(NULL,'Dark Sandstone Floor 5',253,1331,0,'533');
+INSERT INTO items VALUES(NULL,'Dark Sandstone Floor 4',253,1330,0,'532');
+INSERT INTO items VALUES(NULL,'Dark Sandstone Floor 3',253,1329,0,'531');
+INSERT INTO items VALUES(NULL,'Dark Sandstone Floor 2',253,1328,0,'530');
+INSERT INTO items VALUES(NULL,'Bricks 11',252,1337,0,'539');
+INSERT INTO items VALUES(NULL,'Bricks 10',252,1336,0,'538');
+INSERT INTO items VALUES(NULL,'Balista 76',76,6406,0,'1906');
+INSERT INTO items VALUES(NULL,'Balista 77',76,6407,0,'1907');
+INSERT INTO items VALUES(NULL,'Balista 74',76,6404,0,'1904');
+INSERT INTO items VALUES(NULL,'Balista 75',76,6405,0,'1905');
+INSERT INTO items VALUES(NULL,'Tree Pieces 2 (1/5)',4,3438,0,'d6e');
+INSERT INTO items VALUES(NULL,'Balista 72',76,6402,0,'1902');
+INSERT INTO items VALUES(NULL,'Tree Pieces 2 (2/5)',4,3439,0,'d6f');
+INSERT INTO items VALUES(NULL,'Vines 2 (1/4)',4,3434,0,'d6a');
+INSERT INTO items VALUES(NULL,'Vines 2 (3/4)',4,3436,0,'d6c');
+INSERT INTO items VALUES(NULL,'Balista 73',76,6403,0,'1903');
+INSERT INTO items VALUES(NULL,'Sandstone Table 2 (N/S) (3/3)',89,7612,0,'1dbc');
+INSERT INTO items VALUES(NULL,'Sandstone Table 2 (N/S) (1/3)',89,7611,0,'1dbb');
+INSERT INTO items VALUES(NULL,'Sandstone Table 2 (W/E) (1/3)',89,7614,0,'1dbe');
+INSERT INTO items VALUES(NULL,'Sandstone Table 2 (N/S) (2/3)',89,7613,0,'1dbd');
+INSERT INTO items VALUES(NULL,'Sandstone Table 2 (W/E) (3/3)',89,7615,0,'1dbf');
+INSERT INTO items VALUES(NULL,'Balista 71',76,6401,0,'1901');
+INSERT INTO items VALUES(NULL,'Hay 2',45,6803,0,'1a93');
+INSERT INTO items VALUES(NULL,'Energy',28,14360,0,'3818');
+INSERT INTO items VALUES(NULL,'Leg (right) 2',147,7601,0,'1db1');
+INSERT INTO items VALUES(NULL,'Arm (left) 2',147,7600,0,'1db0');
+INSERT INTO items VALUES(NULL,'Broken Barrel 1',107,7603,0,'1db3');
+INSERT INTO items VALUES(NULL,'Leg (left) 2',147,7602,0,'1db2');
+INSERT INTO items VALUES(NULL,'Broken Barrel 3',107,7605,0,'1db5');
+INSERT INTO items VALUES(NULL,'Broken Barrel 2',107,7604,0,'1db4');
+INSERT INTO items VALUES(NULL,'Barrel Hoops 3',107,7607,0,'1db7');
+INSERT INTO items VALUES(NULL,'Broken Barrel 4',107,7606,0,'1db6');
+INSERT INTO items VALUES(NULL,'leather cap',254,7609,0,'1db9');
+INSERT INTO items VALUES(NULL,'Barrel Lid',107,7608,0,'1db8');
+INSERT INTO items VALUES(NULL,'Leaves 2 (14/14)',4,3433,0,'d69');
+INSERT INTO items VALUES(NULL,'Leaves 2 (13/14)',4,3432,0,'d68');
+INSERT INTO items VALUES(NULL,'ringmail tunic',255,5100,0,'iron_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Leaves 2 (10/14)',4,3429,0,'d65');
+INSERT INTO items VALUES(NULL,'Leaves 2 (9/14)',4,3428,0,'d64');
+INSERT INTO items VALUES(NULL,'Leaves 2 (12/14)',4,3431,0,'d67');
+INSERT INTO items VALUES(NULL,'Leaves 2 (11/14)',4,3430,0,'d66');
+INSERT INTO items VALUES(NULL,'Leaves 2 (6/14)',4,3425,0,'d61');
+INSERT INTO items VALUES(NULL,'Leaves 2 (5/14)',4,3424,0,'d60');
+INSERT INTO items VALUES(NULL,'Leaves 2 (8/14)',4,3427,0,'d63');
+INSERT INTO items VALUES(NULL,'Leaves 2 (7/14)',4,3426,0,'d62');
+INSERT INTO items VALUES(NULL,'Lockpicks (N/S)',256,5374,0,'14fe');
+INSERT INTO items VALUES(NULL,'Lockpicks (W/E)',256,5373,0,'14fd');
+INSERT INTO items VALUES(NULL,'Seive',257,5375,0,'14ff');
+INSERT INTO items VALUES(NULL,'Furled Rope (N/S)',141,5370,0,'14fa');
+INSERT INTO items VALUES(NULL,'Lockpick (E/W)',256,5372,0,'14fc');
+INSERT INTO items VALUES(NULL,'Lockpick (W/E)',256,5371,0,'14fb');
+INSERT INTO items VALUES(NULL,'Skeleton 3',12,7568,0,'1d90');
+INSERT INTO items VALUES(NULL,'Skeleton 4',12,7569,0,'1d91');
+INSERT INTO items VALUES(NULL,'Blood on a Wall 1',55,7570,0,'1d92');
+INSERT INTO items VALUES(NULL,'Blood on a Wall 2',55,7571,0,'1d93');
+INSERT INTO items VALUES(NULL,'Blood on a Wall 3',55,7572,0,'1d94');
+INSERT INTO items VALUES(NULL,'Blood on a Wall 4',55,7573,0,'1d95');
+INSERT INTO items VALUES(NULL,'Blood on a Wall 5',55,7574,0,'1d96');
+INSERT INTO items VALUES(NULL,'Ankh of Sacrifice (W/E) (1/2)',70,7575,0,'1d97');
+INSERT INTO items VALUES(NULL,'Ankh of Sacrifice (W/E) (2/2)',70,7576,0,'1d98');
+INSERT INTO items VALUES(NULL,'Spike Trap 1',109,7577,0,'1d99');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (N/S) (1/5)',89,2954,0,'b8a');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (N/S) (3/5)',89,2956,0,'b8c');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (N/S) (2/5)',89,2955,0,'b8b');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (N/S) (5/5)',89,2958,0,'b8e');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (N/S) (4/5)',89,2957,0,'b8d');
+INSERT INTO items VALUES(NULL,'Wooden Table 5 (N/S)',89,2959,0,'b8f');
+INSERT INTO items VALUES(NULL,'Anchor (N/S)',141,5369,0,'14f9');
+INSERT INTO items VALUES(NULL,'Furled Rope (W/E)',141,5368,0,'14f8');
+INSERT INTO items VALUES(NULL,'Blade Spirits',94,8013,0,'1f4d');
+INSERT INTO items VALUES(NULL,'Spyglass (W/E)',258,5365,0,'14f5');
+INSERT INTO items VALUES(NULL,'Ship Model (W/E)',258,5364,0,'14f4');
+INSERT INTO items VALUES(NULL,'Anchor (W/E)',141,5367,0,'14f7');
+INSERT INTO items VALUES(NULL,'Spyglass (N/S)',258,5366,0,'14f6');
+INSERT INTO items VALUES(NULL,'Ship Plans (N/S)',258,5361,0,'14f1');
+INSERT INTO items VALUES(NULL,'Deed (W/E)',258,5360,0,'14f0');
+INSERT INTO items VALUES(NULL,'Ship Model (N/S)',258,5363,0,'14f3');
+INSERT INTO items VALUES(NULL,'Ship Plans (W/E)',258,5362,0,'14f2');
+INSERT INTO items VALUES(NULL,'Incognito',94,8015,0,'1f4f');
+INSERT INTO items VALUES(NULL,'Wooden Table 3 (N/S) (2/2)',89,2953,0,'b89');
+INSERT INTO items VALUES(NULL,'Wooden Table 3 (N/S) (1/2)',89,2952,0,'b88');
+INSERT INTO items VALUES(NULL,'Wooden Table 1 (N/S) (1/2)',89,2945,0,'b81');
+INSERT INTO items VALUES(NULL,'Sandstone Table 1 (N/S) (3/3)',89,2944,0,'b80');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (N/S) (1/5)',89,2947,0,'b83');
+INSERT INTO items VALUES(NULL,'Wooden Table 1 (N/S) (2/2)',89,2946,0,'b82');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (N/S) (3/5)',89,2949,0,'b85');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (N/S) (2/5)',89,2948,0,'b84');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (N/S) (5/5)',89,2951,0,'b87');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (N/S) (4/5)',89,2950,0,'b86');
+INSERT INTO items VALUES(NULL,'Spike Trap 2',109,7578,0,'1d9a');
+INSERT INTO items VALUES(NULL,'Spike Trap 3',109,7579,0,'1d9b');
+INSERT INTO items VALUES(NULL,'Spike Trap 4',109,7580,0,'1d9c');
+INSERT INTO items VALUES(NULL,'Spike Trap 5',109,7581,0,'1d9d');
+INSERT INTO items VALUES(NULL,'Spike Trap 6',109,7582,0,'1d9e');
+INSERT INTO items VALUES(NULL,'Torso 3',147,7583,0,'1d9f');
+INSERT INTO items VALUES(NULL,'metal shield',16,7035,0,'verite_shields_shield');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 14',202,6964,0,'1b34');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 15',202,6965,0,'1b35');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 16',202,6966,0,'1b36');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 17',202,6967,0,'1b37');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 10',202,6960,0,'1b30');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 11',202,6961,0,'1b31');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 12',202,6962,0,'1b32');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 13',202,6963,0,'1b33');
+INSERT INTO items VALUES(NULL,'platemail gorget',36,5139,0,'bronze_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 18',202,6968,0,'1b38');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 19',202,6969,0,'1b39');
+INSERT INTO items VALUES(NULL,'ringmail tunic',39,5100,0,'dull_copper_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Treasure (22/41)',215,6998,0,'1b56');
+INSERT INTO items VALUES(NULL,'Lava 20',44,12957,0,'329d');
+INSERT INTO items VALUES(NULL,'Balista 83',76,6413,0,'190d');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 23',202,6973,0,'1b3d');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 24',202,6974,0,'1b3e');
+INSERT INTO items VALUES(NULL,'Treasure (1/41)',215,6975,0,'1b3f');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 20',202,6970,0,'1b3a');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 21',202,6971,0,'1b3b');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 22',202,6972,0,'1b3c');
+INSERT INTO items VALUES(NULL,'Treasure (23/41)',215,6999,0,'1b57');
+INSERT INTO items VALUES(NULL,'Balista 82',76,6412,0,'190c');
+INSERT INTO items VALUES(NULL,'Balista 80',76,6410,0,'190a');
+INSERT INTO items VALUES(NULL,'helmet',259,5130,0,'dull_copper_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Wave 40',62,8138,0,'1fca');
+INSERT INTO items VALUES(NULL,'Juka Mage',115,9758,0,'261e');
+INSERT INTO items VALUES(NULL,'metal shield',83,7035,0,'dull_copper_shields_shield');
+INSERT INTO items VALUES(NULL,'Pier 4',141,937,0,'3a9');
+INSERT INTO items VALUES(NULL,'Pier 3',141,936,0,'3a8');
+INSERT INTO items VALUES(NULL,'Archway 10',41,928,0,'3a0');
+INSERT INTO items VALUES(NULL,'Rope 2',141,935,0,'3a7');
+INSERT INTO items VALUES(NULL,'Rope 1',141,934,0,'3a6');
+INSERT INTO items VALUES(NULL,'Pier 1',141,933,0,'3a5');
+INSERT INTO items VALUES(NULL,'Pier 4',141,940,0,'3ac');
+INSERT INTO items VALUES(NULL,'Pier 3',141,939,0,'3ab');
+INSERT INTO items VALUES(NULL,'Pier 2',141,938,0,'3aa');
+INSERT INTO items VALUES(NULL,'Pier 6',141,942,0,'3ae');
+INSERT INTO items VALUES(NULL,'Pier 5',141,941,0,'3ad');
+INSERT INTO items VALUES(NULL,'Twigs 1',11,7068,0,'1b9c');
+INSERT INTO items VALUES(NULL,'Treasure (18/41)',215,6993,0,'1b51');
+INSERT INTO items VALUES(NULL,'close helmet',259,5128,0,'dull_copper_helmets_close');
+INSERT INTO items VALUES(NULL,'platemail',117,5141,0,'golden_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Bear',115,8399,0,'20cf');
+INSERT INTO items VALUES(NULL,'Female (naked)',115,8398,0,'20ce');
+INSERT INTO items VALUES(NULL,'Male (naked)',115,8397,0,'20cd');
+INSERT INTO items VALUES(NULL,'Troll (big)',115,8396,0,'20cc');
+INSERT INTO items VALUES(NULL,'Ogre (big)',115,8395,0,'20cb');
+INSERT INTO items VALUES(NULL,'Lizardman (big)',115,8394,0,'20ca');
+INSERT INTO items VALUES(NULL,'Wood 26',11,7066,0,'1b9a');
+INSERT INTO items VALUES(NULL,'Arch 3',123,1087,0,'43f');
+INSERT INTO items VALUES(NULL,'Arch 1',123,1085,0,'43d');
+INSERT INTO items VALUES(NULL,'Arch 2',123,1086,0,'43e');
+INSERT INTO items VALUES(NULL,'Arch 4',260,1083,0,'43b');
+INSERT INTO items VALUES(NULL,'Arch 5',260,1084,0,'43c');
+INSERT INTO items VALUES(NULL,'Short Cannon (S/N) (1/2)',67,3695,0,'e6f');
+INSERT INTO items VALUES(NULL,'Arch 3',260,1082,0,'43a');
+INSERT INTO items VALUES(NULL,'Spinning Wheel (W/E)',57,4121,0,'1019');
+INSERT INTO items VALUES(NULL,'Spinning Wheel (N/S)',57,4117,0,'1015');
+INSERT INTO items VALUES(NULL,'Spinning Wheel (N/S) (Animated)',57,4118,0,'1016');
+INSERT INTO items VALUES(NULL,'Iron Key',51,4112,0,'1010');
+INSERT INTO items VALUES(NULL,'Keyring 1',51,4113,0,'1011');
+INSERT INTO items VALUES(NULL,'Magic Key',51,4114,0,'1012');
+INSERT INTO items VALUES(NULL,'Circle 8',92,8391,0,'20c7');
+INSERT INTO items VALUES(NULL,'Circle 7',92,8390,0,'20c6');
+INSERT INTO items VALUES(NULL,'Circle 6',92,8389,0,'20c5');
+INSERT INTO items VALUES(NULL,'Circle 5',92,8388,0,'20c4');
+INSERT INTO items VALUES(NULL,'Circle 4',92,8387,0,'20c3');
+INSERT INTO items VALUES(NULL,'Circle 3',92,8386,0,'20c2');
+INSERT INTO items VALUES(NULL,'Circle 2',92,8385,0,'20c1');
+INSERT INTO items VALUES(NULL,'Circle 1',92,8384,0,'20c0');
+INSERT INTO items VALUES(NULL,'Gorilla (big)',115,8393,0,'20c9');
+INSERT INTO items VALUES(NULL,'Ettin (big)',115,8392,0,'20c8');
+INSERT INTO items VALUES(NULL,'Spinning Wheel (S/N) (Animated)',57,4125,0,'101d');
+INSERT INTO items VALUES(NULL,'Pile of Wool 2',57,4127,0,'101f');
+INSERT INTO items VALUES(NULL,'Spinning Wheel (W/E) (Animated)',57,4122,0,'101a');
+INSERT INTO items VALUES(NULL,'Spinning Wheel (S/N)',57,4124,0,'101c');
+INSERT INTO items VALUES(NULL,'Rune 5',261,3688,0,'e68');
+INSERT INTO items VALUES(NULL,'Arch 1',260,1080,0,'438');
+INSERT INTO items VALUES(NULL,'Arch 2',260,1081,0,'439');
+INSERT INTO items VALUES(NULL,'Rune 3',261,3682,0,'e62');
+INSERT INTO items VALUES(NULL,'Curtain 8',82,1077,0,'435');
+INSERT INTO items VALUES(NULL,'Curtain 5',82,1074,0,'432');
+INSERT INTO items VALUES(NULL,'Rune 4',261,3685,0,'e65');
+INSERT INTO items VALUES(NULL,'Decorated Wall 3',82,1072,0,'430');
+INSERT INTO items VALUES(NULL,'Decorated Wall 4',82,1073,0,'431');
+INSERT INTO items VALUES(NULL,'Tongs (N/S)',30,4028,0,'fbc');
+INSERT INTO items VALUES(NULL,'Tongs (W/E)',30,4027,0,'fbb');
+INSERT INTO items VALUES(NULL,'Pen & Ink (W/E)',262,4031,0,'fbf');
+INSERT INTO items VALUES(NULL,'Book 7 (W/E)',263,4030,0,'fbe');
+INSERT INTO items VALUES(NULL,'Book 7 (N/S)',263,4029,0,'fbd');
+INSERT INTO items VALUES(NULL,'Twigs 3',11,7070,0,'1b9e');
+INSERT INTO items VALUES(NULL,'Snake Plant',45,3241,0,'ca9');
+INSERT INTO items VALUES(NULL,'Banana Tree (small) ',4,3240,0,'ca8');
+INSERT INTO items VALUES(NULL,'Fern 4',45,3235,0,'ca3');
+INSERT INTO items VALUES(NULL,'Keg',65,3711,0,'e7f');
+INSERT INTO items VALUES(NULL,'Fern - large',45,3233,0,'ca1');
+INSERT INTO items VALUES(NULL,'Fern 2',45,3232,0,'ca0');
+INSERT INTO items VALUES(NULL,'Rushes',45,3239,0,'ca7');
+INSERT INTO items VALUES(NULL,'Ponytail Palm',264,3238,0,'ca6');
+INSERT INTO items VALUES(NULL,'Pampass Grass 1',45,3237,0,'ca5');
+INSERT INTO items VALUES(NULL,'Fern 5',45,3236,0,'ca4');
+INSERT INTO items VALUES(NULL,'Flower 11',134,3149,0,'c4d');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 17',105,1864,0,'748');
+INSERT INTO items VALUES(NULL,'Cotton 1',45,3151,0,'c4f');
+INSERT INTO items VALUES(NULL,'Flower 8',134,3146,0,'c4a');
+INSERT INTO items VALUES(NULL,'Flower 9',134,3147,0,'c4b');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 5',121,1865,0,'749');
+INSERT INTO items VALUES(NULL,'Small Forge',30,4017,0,'fb1');
+INSERT INTO items VALUES(NULL,'Anvil (W/E)',30,4016,0,'fb0');
+INSERT INTO items VALUES(NULL,'Forged Metal (W/E)',30,4023,0,'fb7');
+INSERT INTO items VALUES(NULL,'Horse Shoes',30,4022,0,'fb6');
+INSERT INTO items VALUES(NULL,'Sledge Hammer (N/S)',30,4021,0,'fb5');
+INSERT INTO items VALUES(NULL,'Sledge Hammer (W/E)',30,4020,0,'fb4');
+INSERT INTO items VALUES(NULL,'Forged Metal (N/S)',30,4024,0,'fb8');
+INSERT INTO items VALUES(NULL,'Beekeper (W/E)',230,3140,0,'c44');
+INSERT INTO items VALUES(NULL,'Flower 3',134,3141,0,'c45');
+INSERT INTO items VALUES(NULL,'Flower 4',134,3142,0,'c46');
+INSERT INTO items VALUES(NULL,'Flower 5',134,3143,0,'c47');
+INSERT INTO items VALUES(NULL,'Dried Onions 2',265,3136,0,'c40');
+INSERT INTO items VALUES(NULL,'Dried Herbs 1',265,3137,0,'c41');
+INSERT INTO items VALUES(NULL,'Dried Herbs 2',265,3138,0,'c42');
+INSERT INTO items VALUES(NULL,'Beekeper (N/S)',230,3139,0,'c43');
+INSERT INTO items VALUES(NULL,'Flower 6',134,3144,0,'c48');
+INSERT INTO items VALUES(NULL,'Flower 7',134,3145,0,'c49');
+INSERT INTO items VALUES(NULL,'Grasses 1',45,3244,0,'cac');
+INSERT INTO items VALUES(NULL,'Banana Tree 2',4,3243,0,'cab');
+INSERT INTO items VALUES(NULL,'Banana Tree 1',4,3242,0,'caa');
+INSERT INTO items VALUES(NULL,'Grasses 4',45,3247,0,'caf');
+INSERT INTO items VALUES(NULL,'Grasses 3',45,3246,0,'cae');
+INSERT INTO items VALUES(NULL,'Grasses 2',45,3245,0,'cad');
+INSERT INTO items VALUES(NULL,'Block 16',113,4730,0,'127a');
+INSERT INTO items VALUES(NULL,'Block 18',113,4732,0,'127c');
+INSERT INTO items VALUES(NULL,'Pillory 1',113,4733,0,'127d');
+INSERT INTO items VALUES(NULL,'Pillory 3',113,4735,0,'127f');
+INSERT INTO items VALUES(NULL,'Fire Field',92,8347,0,'209b');
+INSERT INTO items VALUES(NULL,'platemail legs',81,5137,0,'shadow_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'Catapult 110',72,5824,0,'16c0');
+INSERT INTO items VALUES(NULL,'Catapult 111',72,5825,0,'16c1');
+INSERT INTO items VALUES(NULL,'Catapult 112',72,5826,0,'16c2');
+INSERT INTO items VALUES(NULL,'Catapult 113',72,5827,0,'16c3');
+INSERT INTO items VALUES(NULL,'Catapult 114',72,5828,0,'16c4');
+INSERT INTO items VALUES(NULL,'Catapult 115',72,5829,0,'16c5');
+INSERT INTO items VALUES(NULL,'Catapult 116',72,5830,0,'16c6');
+INSERT INTO items VALUES(NULL,'Catapult 117',72,5831,0,'16c7');
+INSERT INTO items VALUES(NULL,'Catapult 118',72,5832,0,'16c8');
+INSERT INTO items VALUES(NULL,'Catapult 119',72,5833,0,'16c9');
+INSERT INTO items VALUES(NULL,'metal shield',266,7035,0,'valorite_shields_shield');
+INSERT INTO items VALUES(NULL,'Pipe Cactus',45,3381,0,'d35');
+INSERT INTO items VALUES(NULL,'Flask 9',173,6194,0,'1832');
+INSERT INTO items VALUES(NULL,'Flask 10',173,6195,0,'1833');
+INSERT INTO items VALUES(NULL,'Flask 7',173,6192,0,'1830');
+INSERT INTO items VALUES(NULL,'Flask 8',173,6193,0,'1831');
+INSERT INTO items VALUES(NULL,'Flask 13',173,6198,0,'1836');
+INSERT INTO items VALUES(NULL,'Flask 14',173,6199,0,'1837');
+INSERT INTO items VALUES(NULL,'Flask 11',173,6196,0,'1834');
+INSERT INTO items VALUES(NULL,'Flask 12',173,6197,0,'1835');
+INSERT INTO items VALUES(NULL,'Flask 15',173,6200,0,'1838');
+INSERT INTO items VALUES(NULL,'Flask 16',173,6201,0,'1839');
+INSERT INTO items VALUES(NULL,'Swamp 6',267,12876,0,'324c');
+INSERT INTO items VALUES(NULL,'Swamp 5',267,12875,0,'324b');
+INSERT INTO items VALUES(NULL,'Swamp 29',251,12874,0,'324a');
+INSERT INTO items VALUES(NULL,'Swamp 2',267,12879,0,'324f');
+INSERT INTO items VALUES(NULL,'Swamp 1',267,12878,0,'324e');
+INSERT INTO items VALUES(NULL,'Swamp 7',267,12877,0,'324d');
+INSERT INTO items VALUES(NULL,'Catapult 120',72,5834,0,'16ca');
+INSERT INTO items VALUES(NULL,'Catapult 121',72,5835,0,'16cb');
+INSERT INTO items VALUES(NULL,'Catapult 122',72,5836,0,'16cc');
+INSERT INTO items VALUES(NULL,'Catapult 123',72,5837,0,'16cd');
+INSERT INTO items VALUES(NULL,'Catapult 124',72,5838,0,'16ce');
+INSERT INTO items VALUES(NULL,'Catapult 125',72,5839,0,'16cf');
+INSERT INTO items VALUES(NULL,'Ophidian Warrior (3d)',115,9645,0,'25ad');
+INSERT INTO items VALUES(NULL,'Swamp 28',251,12873,0,'3249');
+INSERT INTO items VALUES(NULL,'Swamp 27',251,12872,0,'3248');
+INSERT INTO items VALUES(NULL,'Small Wall 1',156,8538,0,'215a');
+INSERT INTO items VALUES(NULL,'Small Wall 2',156,8539,0,'215b');
+INSERT INTO items VALUES(NULL,'Small Wall 3',156,8540,0,'215c');
+INSERT INTO items VALUES(NULL,'Swamp 22',251,12867,0,'3243');
+INSERT INTO items VALUES(NULL,'Swamp 21',251,12866,0,'3242');
+INSERT INTO items VALUES(NULL,'Swamp 20',251,12865,0,'3241');
+INSERT INTO items VALUES(NULL,'Swamp 26',251,12871,0,'3247');
+INSERT INTO items VALUES(NULL,'Swamp 25',251,12870,0,'3246');
+INSERT INTO items VALUES(NULL,'Swamp 24',251,12869,0,'3245');
+INSERT INTO items VALUES(NULL,'Swamp 23',251,12868,0,'3244');
+INSERT INTO items VALUES(NULL,'Flask 18',173,6203,0,'183b');
+INSERT INTO items VALUES(NULL,'Flask 19',173,6204,0,'183c');
+INSERT INTO items VALUES(NULL,'Flask 17',173,6202,0,'183a');
+INSERT INTO items VALUES(NULL,'Flask 22',173,6207,0,'183f');
+INSERT INTO items VALUES(NULL,'Flask 20',173,6205,0,'183d');
+INSERT INTO items VALUES(NULL,'Flask 21',173,6206,0,'183e');
+INSERT INTO items VALUES(NULL,'Telescope (43/66)',182,5251,0,'1483');
+INSERT INTO items VALUES(NULL,'Telescope (42/66)',182,5250,0,'1482');
+INSERT INTO items VALUES(NULL,'Telescope (41/66)',182,5249,0,'1481');
+INSERT INTO items VALUES(NULL,'Telescope (40/66)',182,5248,0,'1480');
+INSERT INTO items VALUES(NULL,'Telescope (47/66)',182,5255,0,'1487');
+INSERT INTO items VALUES(NULL,'Telescope (46/66)',182,5254,0,'1486');
+INSERT INTO items VALUES(NULL,'Telescope (45/66)',182,5253,0,'1485');
+INSERT INTO items VALUES(NULL,'Telescope (44/66)',182,5252,0,'1484');
+INSERT INTO items VALUES(NULL,'Telescope (49/66)',182,5257,0,'1489');
+INSERT INTO items VALUES(NULL,'Telescope (48/66)',182,5256,0,'1488');
+INSERT INTO items VALUES(NULL,'Stone Paver 2',268,1306,0,'51a');
+INSERT INTO items VALUES(NULL,'Stone Paver 4',268,1308,0,'51c');
+INSERT INTO items VALUES(NULL,'Stone Paver 3',268,1307,0,'51b');
+INSERT INTO items VALUES(NULL,'Stone Paver 6',268,1310,0,'51e');
+INSERT INTO items VALUES(NULL,'Stone Paver 5',268,1309,0,'51d');
+INSERT INTO items VALUES(NULL,'Fancy Dress (W/E)',1,7935,0,'1eff');
+INSERT INTO items VALUES(NULL,'Stone Paver 7',268,1311,0,'51f');
+INSERT INTO items VALUES(NULL,'Block 6',113,4720,0,'1270');
+INSERT INTO items VALUES(NULL,'Block 7',113,4721,0,'1271');
+INSERT INTO items VALUES(NULL,'Block 8',113,4722,0,'1272');
+INSERT INTO items VALUES(NULL,'Telescope (52/66)',182,5260,0,'148c');
+INSERT INTO items VALUES(NULL,'Telescope (51/66)',182,5259,0,'148b');
+INSERT INTO items VALUES(NULL,'Telescope (50/66)',182,5258,0,'148a');
+INSERT INTO items VALUES(NULL,'Block 9',113,4723,0,'1273');
+INSERT INTO items VALUES(NULL,'chainmail coif',205,5051,0,'copper_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Telescope (55/66)',182,5263,0,'148f');
+INSERT INTO items VALUES(NULL,'Telescope (54/66)',182,5262,0,'148e');
+INSERT INTO items VALUES(NULL,'Telescope (53/66)',182,5261,0,'148d');
+INSERT INTO items VALUES(NULL,'Block 10',113,4724,0,'1274');
+INSERT INTO items VALUES(NULL,'Block 11',113,4725,0,'1275');
+INSERT INTO items VALUES(NULL,'Arch 19',223,229,0,'e5');
+INSERT INTO items VALUES(NULL,'Arch 18',223,228,0,'e4');
+INSERT INTO items VALUES(NULL,'Small Wall 6',223,231,0,'e7');
+INSERT INTO items VALUES(NULL,'Small Wall 5',223,230,0,'e6');
+INSERT INTO items VALUES(NULL,'Arch 15',223,225,0,'e1');
+INSERT INTO items VALUES(NULL,'Arch 14',223,224,0,'e0');
+INSERT INTO items VALUES(NULL,'Arch 17',223,227,0,'e3');
+INSERT INTO items VALUES(NULL,'Arch 16',223,226,0,'e2');
+INSERT INTO items VALUES(NULL,'plate armor',269,7172,0,'dull_copper_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Wall 3',260,250,0,'fa');
+INSERT INTO items VALUES(NULL,'kryss',20,5121,0,'1401');
+INSERT INTO items VALUES(NULL,'Wall 4',260,251,0,'fb');
+INSERT INTO items VALUES(NULL,'Stone Paver 1',268,1305,0,'519');
+INSERT INTO items VALUES(NULL,'Cobblestones 4',270,1304,0,'518');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 8',121,1868,0,'74c');
+INSERT INTO items VALUES(NULL,'Marble Floor 3',271,1297,0,'511');
+INSERT INTO items VALUES(NULL,'Green Marble Floor 2',271,1296,0,'510');
+INSERT INTO items VALUES(NULL,'Marble Floor 5',271,1299,0,'513');
+INSERT INTO items VALUES(NULL,'Marble Floor 4',271,1298,0,'512');
+INSERT INTO items VALUES(NULL,'Cobblestones 1',270,1301,0,'515');
+INSERT INTO items VALUES(NULL,'Marble Floor 6',271,1300,0,'514');
+INSERT INTO items VALUES(NULL,'Cobblestones 3',270,1303,0,'517');
+INSERT INTO items VALUES(NULL,'Cobblestones 2',270,1302,0,'516');
+INSERT INTO items VALUES(NULL,'Roof 15',32,1571,0,'623');
+INSERT INTO items VALUES(NULL,'Statue 2 (W/E)',31,4646,0,'1226');
+INSERT INTO items VALUES(NULL,'Statue 5',31,4645,0,'1225');
+INSERT INTO items VALUES(NULL,'Roof 12',32,1568,0,'620');
+INSERT INTO items VALUES(NULL,'Pedestal',31,4643,0,'1223');
+INSERT INTO items VALUES(NULL,'Wall Carving 2 (3/3)',53,4642,0,'1222');
+INSERT INTO items VALUES(NULL,'Wall Carving 2 (2/3)',53,4641,0,'1221');
+INSERT INTO items VALUES(NULL,'Wall Carving 2 (1/3)',53,4640,0,'1220');
+INSERT INTO items VALUES(NULL,'Roof 21',32,1577,0,'629');
+INSERT INTO items VALUES(NULL,'Roof 20',32,1576,0,'628');
+INSERT INTO items VALUES(NULL,'Statue 4 (W/E)',31,4648,0,'1228');
+INSERT INTO items VALUES(NULL,'Banner 23 (N/S)',128,5565,0,'15bd');
+INSERT INTO items VALUES(NULL,'Banner 24 (W/E)',128,5566,0,'15be');
+INSERT INTO items VALUES(NULL,'Banner 24 (N/S)',128,5567,0,'15bf');
+INSERT INTO items VALUES(NULL,'Banner 22 (W/E)',128,5562,0,'15ba');
+INSERT INTO items VALUES(NULL,'Banner 22 (N/S)',128,5563,0,'15bb');
+INSERT INTO items VALUES(NULL,'Banner 23 (W/E)',128,5564,0,'15bc');
+INSERT INTO items VALUES(NULL,'buckler',272,7027,0,'agapite_shields_buckler');
+INSERT INTO items VALUES(NULL,'Mushrooms 4',273,3343,0,'d0f');
+INSERT INTO items VALUES(NULL,'Mushrooms 3',273,3342,0,'d0e');
+INSERT INTO items VALUES(NULL,'Mushrooms 2',273,3341,0,'d0d');
+INSERT INTO items VALUES(NULL,'Mushrooms 1',273,3340,0,'d0c');
+INSERT INTO items VALUES(NULL,'Lilypads 1',45,3339,0,'d0b');
+INSERT INTO items VALUES(NULL,'Lilypad 5',45,3338,0,'d0a');
+INSERT INTO items VALUES(NULL,'Banner 19 (W/E)',128,5556,0,'15b4');
+INSERT INTO items VALUES(NULL,'Banner 19 (N/S)',128,5557,0,'15b5');
+INSERT INTO items VALUES(NULL,'Banner 20 (W/E)',128,5558,0,'15b6');
+INSERT INTO items VALUES(NULL,'Banner 20 (N/S)',128,5559,0,'15b7');
+INSERT INTO items VALUES(NULL,'Banner 17 (W/E)',128,5552,0,'15b0');
+INSERT INTO items VALUES(NULL,'Banner 17 (N/S)',128,5553,0,'15b1');
+INSERT INTO items VALUES(NULL,'Banner 18 (W/E)',128,5554,0,'15b2');
+INSERT INTO items VALUES(NULL,'Banner 18 (N/S)',128,5555,0,'15b3');
+INSERT INTO items VALUES(NULL,'platemail gorget',181,5139,0,'verite_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Banner 21 (W/E)',128,5560,0,'15b8');
+INSERT INTO items VALUES(NULL,'Banner 21 (N/S)',128,5561,0,'15b9');
+INSERT INTO items VALUES(NULL,'Roof 22',222,1580,0,'62c');
+INSERT INTO items VALUES(NULL,'Roof 21',222,1579,0,'62b');
+INSERT INTO items VALUES(NULL,'Blood 5',55,4654,0,'122e');
+INSERT INTO items VALUES(NULL,'Blood 4',55,4653,0,'122d');
+INSERT INTO items VALUES(NULL,'Blood 3',55,4652,0,'122c');
+INSERT INTO items VALUES(NULL,'Roof 20',150,1583,0,'62f');
+INSERT INTO items VALUES(NULL,'Roof 24',222,1582,0,'62e');
+INSERT INTO items VALUES(NULL,'Roof 23',222,1581,0,'62d');
+INSERT INTO items VALUES(NULL,'Lilypad 2',45,3335,0,'d07');
+INSERT INTO items VALUES(NULL,'Lilypad 1',45,3334,0,'d06');
+INSERT INTO items VALUES(NULL,'Reeds',45,3333,0,'d05');
+INSERT INTO items VALUES(NULL,'Water Plants',45,3332,0,'d04');
+INSERT INTO items VALUES(NULL,'Cypress Tree 4 Leaves 2',4,3331,0,'d03');
+INSERT INTO items VALUES(NULL,'Bloody Bandages 1',274,3618,0,'e22');
+INSERT INTO items VALUES(NULL,'Cypress Tree 4',4,3329,0,'d01');
+INSERT INTO items VALUES(NULL,'Cypress Tree 3 Leaves 2',4,3328,0,'d00');
+INSERT INTO items VALUES(NULL,'Lilypad 4',45,3337,0,'d09');
+INSERT INTO items VALUES(NULL,'Lilypad 3',45,3336,0,'d08');
+INSERT INTO items VALUES(NULL,'close helmet',275,5128,0,'agapite_helmets_close');
+INSERT INTO items VALUES(NULL,'Balista 94',76,16201,0,'3f49');
+INSERT INTO items VALUES(NULL,'Balista 93',76,16200,0,'3f48');
+INSERT INTO items VALUES(NULL,'Balista 92',76,16199,0,'3f47');
+INSERT INTO items VALUES(NULL,'Balista 91',76,16198,0,'3f46');
+INSERT INTO items VALUES(NULL,'Balista 90',76,16197,0,'3f45');
+INSERT INTO items VALUES(NULL,'Balista 89',76,16196,0,'3f44');
+INSERT INTO items VALUES(NULL,'Balista 88',76,16195,0,'3f43');
+INSERT INTO items VALUES(NULL,'Balista 87',76,16194,0,'3f42');
+INSERT INTO items VALUES(NULL,'Balista 86',76,16193,0,'3f41');
+INSERT INTO items VALUES(NULL,'Balista 85',76,16192,0,'3f40');
+INSERT INTO items VALUES(NULL,'Roof 46',84,8579,0,'2183');
+INSERT INTO items VALUES(NULL,'Scroll 5 (N/S)',186,3832,0,'ef8');
+INSERT INTO items VALUES(NULL,'Balista 100',76,16207,0,'3f4f');
+INSERT INTO items VALUES(NULL,'Balista 99',76,16206,0,'3f4e');
+INSERT INTO items VALUES(NULL,'Balista 98',76,16205,0,'3f4d');
+INSERT INTO items VALUES(NULL,'Balista 97',76,16204,0,'3f4c');
+INSERT INTO items VALUES(NULL,'Wheel of Cheese',19,2430,0,'97e');
+INSERT INTO items VALUES(NULL,'Balista 95',76,16202,0,'3f4a');
+INSERT INTO items VALUES(NULL,'Scroll 6 (N/S)',186,3833,0,'ef9');
+INSERT INTO items VALUES(NULL,'Harm',94,7992,0,'1f38');
+INSERT INTO items VALUES(NULL,'Water 33',33,13464,0,'3498');
+INSERT INTO items VALUES(NULL,'Water 34',33,13465,0,'3499');
+INSERT INTO items VALUES(NULL,'Water 31',33,13462,0,'3496');
+INSERT INTO items VALUES(NULL,'Water 32',33,13463,0,'3497');
+INSERT INTO items VALUES(NULL,'Water 29',33,13460,0,'3494');
+INSERT INTO items VALUES(NULL,'platemail legs',210,5137,0,'iron_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'Water 27',33,13458,0,'3492');
+INSERT INTO items VALUES(NULL,'Water 28',33,13459,0,'3493');
+INSERT INTO items VALUES(NULL,'Water 25',33,13456,0,'3490');
+INSERT INTO items VALUES(NULL,'Water 26',33,13457,0,'3491');
+INSERT INTO items VALUES(NULL,'Bone 2',12,6930,0,'1b12');
+INSERT INTO items VALUES(NULL,'Jaw Bone 1',12,6931,0,'1b13');
+INSERT INTO items VALUES(NULL,'Bone Pile 8',12,6928,0,'1b10');
+INSERT INTO items VALUES(NULL,'Bone 1',12,6929,0,'1b11');
+INSERT INTO items VALUES(NULL,'Pelvis Bone 2',12,6934,0,'1b16');
+INSERT INTO items VALUES(NULL,'Rib Cage 1',12,6935,0,'1b17');
+INSERT INTO items VALUES(NULL,'Jaw Bone 2',12,6932,0,'1b14');
+INSERT INTO items VALUES(NULL,'Pelvis Bone 1',12,6933,0,'1b15');
+INSERT INTO items VALUES(NULL,'Rib Cage 2',12,6936,0,'1b18');
+INSERT INTO items VALUES(NULL,'Bone Shards 1',12,6937,0,'1b19');
+INSERT INTO items VALUES(NULL,'Archprotection',92,8345,0,'2099');
+INSERT INTO items VALUES(NULL,'Archcure',92,8344,0,'2098');
+INSERT INTO items VALUES(NULL,'Cot (W/E) (1/2)',226,4605,0,'11fd');
+INSERT INTO items VALUES(NULL,'Cot (W/E) (2/2)',226,4606,0,'11fe');
+INSERT INTO items VALUES(NULL,'Cot (N/S) (1/2)',226,4607,0,'11ff');
+INSERT INTO items VALUES(NULL,'Lava 3',37,6691,0,'1a23');
+INSERT INTO items VALUES(NULL,'Fur 3 (N/S)',185,4602,0,'11fa');
+INSERT INTO items VALUES(NULL,'Fur 4 (N/S)',185,4603,0,'11fb');
+INSERT INTO items VALUES(NULL,'Bamboo Stool',78,4604,0,'11fc');
+INSERT INTO items VALUES(NULL,'Spine 1',12,6939,0,'1b1b');
+INSERT INTO items VALUES(NULL,'Spine 2',12,6940,0,'1b1c');
+INSERT INTO items VALUES(NULL,'Bone Shards 2',12,6938,0,'1b1a');
+INSERT INTO items VALUES(NULL,'Curse',92,8346,0,'209a');
+INSERT INTO items VALUES(NULL,'Skeleton with Meat 1',12,6941,0,'1b1d');
+INSERT INTO items VALUES(NULL,'Skeleton with Meat 2',12,6942,0,'1b1e');
+INSERT INTO items VALUES(NULL,'Water 40',33,13471,0,'349f');
+INSERT INTO items VALUES(NULL,'Water 38',33,13469,0,'349d');
+INSERT INTO items VALUES(NULL,'Water 39',33,13470,0,'349e');
+INSERT INTO items VALUES(NULL,'Water 36',33,13467,0,'349b');
+INSERT INTO items VALUES(NULL,'Water 37',33,13468,0,'349c');
+INSERT INTO items VALUES(NULL,'Water 35',33,13466,0,'349a');
+INSERT INTO items VALUES(NULL,'Fur 1 (W/E)',185,4596,0,'11f4');
+INSERT INTO items VALUES(NULL,'Fur 2 (W/E)',185,4597,0,'11f5');
+INSERT INTO items VALUES(NULL,'Fur 3 (W/E)',185,4598,0,'11f6');
+INSERT INTO items VALUES(NULL,'Fur 4 (W/E)',185,4599,0,'11f7');
+INSERT INTO items VALUES(NULL,'Hammock (W/E) (1/2)',226,4592,0,'11f0');
+INSERT INTO items VALUES(NULL,'Hammock (W/E) (2/2)',226,4593,0,'11f1');
+INSERT INTO items VALUES(NULL,'Hammock (N/S) (1/2)',226,4594,0,'11f2');
+INSERT INTO items VALUES(NULL,'Hammock (N/S) (2/2)',226,4595,0,'11f3');
+INSERT INTO items VALUES(NULL,'Fur 1 (N/S)',185,4600,0,'11f8');
+INSERT INTO items VALUES(NULL,'Fur 2 (N/S)',185,4601,0,'11f9');
+INSERT INTO items VALUES(NULL,'Wall 3',127,969,0,'3c9');
+INSERT INTO items VALUES(NULL,'Wall 2',127,968,0,'3c8');
+INSERT INTO items VALUES(NULL,'Wall 15',276,965,0,'3c5');
+INSERT INTO items VALUES(NULL,'Wall 14',276,964,0,'3c4');
+INSERT INTO items VALUES(NULL,'Wall 1',127,967,0,'3c7');
+INSERT INTO items VALUES(NULL,'Wall 16',276,966,0,'3c6');
+INSERT INTO items VALUES(NULL,'Wall 11',276,961,0,'3c1');
+INSERT INTO items VALUES(NULL,'Wall 10',276,960,0,'3c0');
+INSERT INTO items VALUES(NULL,'Wall 13',276,963,0,'3c3');
+INSERT INTO items VALUES(NULL,'Wall 12',276,962,0,'3c2');
+INSERT INTO items VALUES(NULL,'Ankh 2',70,3,0,'3');
+INSERT INTO items VALUES(NULL,'Sapling 1',4,3305,0,'ce9');
+INSERT INTO items VALUES(NULL,'Full Apron (W/E)',60,5438,0,'153e');
+INSERT INTO items VALUES(NULL,'Wall 8',127,974,0,'3ce');
+INSERT INTO items VALUES(NULL,'Wall 7',127,973,0,'3cd');
+INSERT INTO items VALUES(NULL,'Wall 9',127,975,0,'3cf');
+INSERT INTO items VALUES(NULL,'Wall 4',127,970,0,'3ca');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 2 (S/SW)',126,8173,0,'1fed');
+INSERT INTO items VALUES(NULL,'Wall 5',127,971,0,'3cb');
+INSERT INTO items VALUES(NULL,'platemail arms',36,5136,0,'bronze_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'Full Apron (N/S)',60,5437,0,'153d');
+INSERT INTO items VALUES(NULL,'Pipe Cactus (Flowers)',45,3382,0,'d36');
+INSERT INTO items VALUES(NULL,'Wall 6',277,337,0,'151');
+INSERT INTO items VALUES(NULL,'Half Apron (W/E)',60,5436,0,'153c');
+INSERT INTO items VALUES(NULL,'Wall 5',277,336,0,'150');
+INSERT INTO items VALUES(NULL,'Wall 8',277,339,0,'153');
+INSERT INTO items VALUES(NULL,'Wall 7',277,338,0,'152');
+INSERT INTO items VALUES(NULL,'Paralyze Field',92,8366,0,'20ae');
+INSERT INTO items VALUES(NULL,'Window 2',277,341,0,'155');
+INSERT INTO items VALUES(NULL,'Reveal',92,8367,0,'20af');
+INSERT INTO items VALUES(NULL,'Explosion',92,8362,0,'20aa');
+INSERT INTO items VALUES(NULL,'Pan of Cookies',19,5643,0,'160b');
+INSERT INTO items VALUES(NULL,'Mark',92,8364,0,'20ac');
+INSERT INTO items VALUES(NULL,'Window 1',277,340,0,'154');
+INSERT INTO items VALUES(NULL,'Half Apron (N/S)',60,5435,0,'153b');
+INSERT INTO items VALUES(NULL,'Window 4',277,343,0,'157');
+INSERT INTO items VALUES(NULL,'Catapult 14',72,5717,0,'1655');
+INSERT INTO items VALUES(NULL,'Window 3',277,342,0,'156');
+INSERT INTO items VALUES(NULL,'Full Jars 4',173,3659,0,'e4b');
+INSERT INTO items VALUES(NULL,'Jars 1',173,3660,0,'e4c');
+INSERT INTO items VALUES(NULL,'Wood Curls',107,4152,0,'1038');
+INSERT INTO items VALUES(NULL,'Full Jars 3',173,3658,0,'e4a');
+INSERT INTO items VALUES(NULL,'Jars 4',173,3663,0,'e4f');
+INSERT INTO items VALUES(NULL,'Jars 2',173,3661,0,'e4d');
+INSERT INTO items VALUES(NULL,'Jars 3',173,3662,0,'e4e');
+INSERT INTO items VALUES(NULL,'Smoothing Plane (N/S)',107,4146,0,'1032');
+INSERT INTO items VALUES(NULL,'Smoothing Plane (W/E)',107,4147,0,'1033');
+INSERT INTO items VALUES(NULL,'Jointing Plane (N/S)',107,4144,0,'1030');
+INSERT INTO items VALUES(NULL,'Jointing Plane (W/E)',107,4145,0,'1031');
+INSERT INTO items VALUES(NULL,'Hay 3',13,4150,0,'1036');
+INSERT INTO items VALUES(NULL,'Hay 4',13,4151,0,'1037');
+INSERT INTO items VALUES(NULL,'Saw (N/S)',107,4148,0,'1034');
+INSERT INTO items VALUES(NULL,'Saw (W/E)',107,4149,0,'1035');
+INSERT INTO items VALUES(NULL,'Energy Bolt',92,8361,0,'20a9');
+INSERT INTO items VALUES(NULL,'Dispel',92,8360,0,'20a8');
+INSERT INTO items VALUES(NULL,'Paralyze',92,8357,0,'20a5');
+INSERT INTO items VALUES(NULL,'Mind Blast',92,8356,0,'20a4');
+INSERT INTO items VALUES(NULL,'Summon Creature',92,8359,0,'20a7');
+INSERT INTO items VALUES(NULL,'Poison Field',92,8358,0,'20a6');
+INSERT INTO items VALUES(NULL,'Dispel Field',92,8353,0,'20a1');
+INSERT INTO items VALUES(NULL,'Blade Spirits',92,8352,0,'20a0');
+INSERT INTO items VALUES(NULL,'Magic Reflection',92,8355,0,'20a3');
+INSERT INTO items VALUES(NULL,'Incognito',92,8354,0,'20a2');
+INSERT INTO items VALUES(NULL,'Wooden Metal Chest (W/E)',65,3650,0,'e42');
+INSERT INTO items VALUES(NULL,'Wooden Metal Chest (N/S)',65,3651,0,'e43');
+INSERT INTO items VALUES(NULL,'Golden Metal Chest (W/E)',65,3648,0,'e40');
+INSERT INTO items VALUES(NULL,'Golden Metal Chest (N/S)',65,3649,0,'e41');
+INSERT INTO items VALUES(NULL,'Empty Jars 3',173,3654,0,'e46');
+INSERT INTO items VALUES(NULL,'Empty Jars 4',173,3655,0,'e47');
+INSERT INTO items VALUES(NULL,'Empty Jars 1',173,3652,0,'e44');
+INSERT INTO items VALUES(NULL,'Empty Jars 2',173,3653,0,'e45');
+INSERT INTO items VALUES(NULL,'Bread 1',19,4155,0,'103b');
+INSERT INTO items VALUES(NULL,'Bread 2',19,4156,0,'103c');
+INSERT INTO items VALUES(NULL,'Full Jars 1',173,3656,0,'e48');
+INSERT INTO items VALUES(NULL,'Full Jars 2',173,3657,0,'e49');
+INSERT INTO items VALUES(NULL,'Cookie Mix',19,4159,0,'103f');
+INSERT INTO items VALUES(NULL,'Dough',19,4157,0,'103d');
+INSERT INTO items VALUES(NULL,'Flour Sifter',114,4158,0,'103e');
+INSERT INTO items VALUES(NULL,'bascinet',278,5132,0,'iron_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Vines 6',45,3309,0,'ced');
+INSERT INTO items VALUES(NULL,'Spider Tree',4,3273,0,'cc9');
+INSERT INTO items VALUES(NULL,'Juniper Bush',45,3272,0,'cc8');
+INSERT INTO items VALUES(NULL,'Grasses 17',45,3269,0,'cc5');
+INSERT INTO items VALUES(NULL,'Pampass Grass 2',45,3268,0,'cc4');
+INSERT INTO items VALUES(NULL,'Weed',45,3271,0,'cc7');
+INSERT INTO items VALUES(NULL,'Grasses 18',45,3270,0,'cc6');
+INSERT INTO items VALUES(NULL,'Orfluer Flowers 3',134,3265,0,'cc1');
+INSERT INTO items VALUES(NULL,'Orfluer Flowers 2',134,3264,0,'cc0');
+INSERT INTO items VALUES(NULL,'Muck',45,3267,0,'cc3');
+INSERT INTO items VALUES(NULL,'Glass Pitcher 1',279,4086,0,'ff6');
+INSERT INTO items VALUES(NULL,'Onions',213,3183,0,'c6f');
+INSERT INTO items VALUES(NULL,'platemail arms',81,5136,0,'shadow_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'Onion 2',19,3182,0,'c6e');
+INSERT INTO items VALUES(NULL,'Pumpkin 2',19,3179,0,'c6b');
+INSERT INTO items VALUES(NULL,'Pumpkin 3',19,3180,0,'c6c');
+INSERT INTO items VALUES(NULL,'Pumpkin 1',19,3178,0,'c6a');
+INSERT INTO items VALUES(NULL,'platemail',210,5141,0,'iron_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Sprouts 1',213,3176,0,'c68');
+INSERT INTO items VALUES(NULL,'Sprouts 2',213,3177,0,'c69');
+INSERT INTO items VALUES(NULL,'Gourd 3',19,3174,0,'c66');
+INSERT INTO items VALUES(NULL,'Gourd 4',19,3175,0,'c67');
+INSERT INTO items VALUES(NULL,'Gourd 1',19,3172,0,'c64');
+INSERT INTO items VALUES(NULL,'Gourd 2',19,3173,0,'c65');
+INSERT INTO items VALUES(NULL,'Turnip 2',19,3170,0,'c62');
+INSERT INTO items VALUES(NULL,'Turnip 3',19,3171,0,'c63');
+INSERT INTO items VALUES(NULL,'Vines 3',45,3168,0,'c60');
+INSERT INTO items VALUES(NULL,'Turnip 1',19,3169,0,'c61');
+INSERT INTO items VALUES(NULL,'Tree (gray) Leaves 1',4,3278,0,'cce');
+INSERT INTO items VALUES(NULL,'Tree (gray)',4,3277,0,'ccd');
+INSERT INTO items VALUES(NULL,'Tree (gray) Leaves 2',4,3279,0,'ccf');
+INSERT INTO items VALUES(NULL,'Tree (brown)',4,3274,0,'cca');
+INSERT INTO items VALUES(NULL,'Tree (light brown)',4,3276,0,'ccc');
+INSERT INTO items VALUES(NULL,'Tree (dark brown)',4,3275,0,'ccb');
+INSERT INTO items VALUES(NULL,'nose helmet',40,5134,0,'bronze_helmets_nose');
+INSERT INTO items VALUES(NULL,'chainmail tunic',280,5055,0,'bronze_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (9/9)',108,6121,0,'17e9');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (8/9)',108,6120,0,'17e8');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (7/9)',108,6119,0,'17e7');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (6/9)',108,6118,0,'17e6');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (5/9)',108,6117,0,'17e5');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (4/9)',108,6116,0,'17e4');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (3/9)',108,6115,0,'17e3');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (2/9)',108,6114,0,'17e2');
+INSERT INTO items VALUES(NULL,'Teleporter 3 (1/9)',108,6113,0,'17e1');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (9/9)',108,6112,0,'17e0');
+INSERT INTO items VALUES(NULL,'Roof 14',222,1395,0,'573');
+INSERT INTO items VALUES(NULL,'platemail legs',181,5137,0,'verite_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'Roof 13',222,1394,0,'572');
+INSERT INTO items VALUES(NULL,'Roof 12',222,1393,0,'571');
+INSERT INTO items VALUES(NULL,'Roof 17',222,1398,0,'576');
+INSERT INTO items VALUES(NULL,'Roof 16',222,1397,0,'575');
+INSERT INTO items VALUES(NULL,'Roof 15',222,1396,0,'574');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (6/9)',108,6127,0,'17ef');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (5/9)',108,6126,0,'17ee');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (4/9)',108,6125,0,'17ed');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (3/9)',108,6124,0,'17ec');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (2/9)',108,6123,0,'17eb');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (1/9)',108,6122,0,'17ea');
+INSERT INTO items VALUES(NULL,'Swamp 28',236,12906,0,'326a');
+INSERT INTO items VALUES(NULL,'Roof 3',203,6459,0,'193b');
+INSERT INTO items VALUES(NULL,'Swamp 30',236,12908,0,'326c');
+INSERT INTO items VALUES(NULL,'Swamp 29',236,12907,0,'326b');
+INSERT INTO items VALUES(NULL,'Swamp 32',236,12910,0,'326e');
+INSERT INTO items VALUES(NULL,'Swamp 31',236,12909,0,'326d');
+INSERT INTO items VALUES(NULL,'Roof 6',203,6462,0,'193e');
+INSERT INTO items VALUES(NULL,'Swamp 33',236,12911,0,'326f');
+INSERT INTO items VALUES(NULL,'Catapult 86',72,5800,0,'16a8');
+INSERT INTO items VALUES(NULL,'Catapult 87',72,5801,0,'16a9');
+INSERT INTO items VALUES(NULL,'Catapult 84',72,5798,0,'16a6');
+INSERT INTO items VALUES(NULL,'Catapult 85',72,5799,0,'16a7');
+INSERT INTO items VALUES(NULL,'Catapult 82',72,5796,0,'16a4');
+INSERT INTO items VALUES(NULL,'Catapult 83',72,5797,0,'16a5');
+INSERT INTO items VALUES(NULL,'Catapult 80',72,5794,0,'16a2');
+INSERT INTO items VALUES(NULL,'Catapult 81',72,5795,0,'16a3');
+INSERT INTO items VALUES(NULL,'Catapult 78',72,5792,0,'16a0');
+INSERT INTO items VALUES(NULL,'Catapult 79',72,5793,0,'16a1');
+INSERT INTO items VALUES(NULL,'Skullcandle (N/S) (On)',73,6232,0,'1858');
+INSERT INTO items VALUES(NULL,'Small Wall 9',22,8638,0,'21be');
+INSERT INTO items VALUES(NULL,'Tiny Wall 13',22,8637,0,'21bd');
+INSERT INTO items VALUES(NULL,'Small Wall 10',22,8639,0,'21bf');
+INSERT INTO items VALUES(NULL,'Scales (N/S)',173,6225,0,'1851');
+INSERT INTO items VALUES(NULL,'Scales (W/E)',173,6226,0,'1852');
+INSERT INTO items VALUES(NULL,'Skullcandle (W/E) (Off)',73,6227,0,'1853');
+INSERT INTO items VALUES(NULL,'Skullcandle (W/E) (On)',73,6228,0,'1854');
+INSERT INTO items VALUES(NULL,'Skullcandle (N/S) (Off)',73,6231,0,'1857');
+INSERT INTO items VALUES(NULL,'Roof 18',281,8562,0,'2172');
+INSERT INTO items VALUES(NULL,'Roof 19',281,8563,0,'2173');
+INSERT INTO items VALUES(NULL,'Roof 16',281,8560,0,'2170');
+INSERT INTO items VALUES(NULL,'Roof 17',281,8561,0,'2171');
+INSERT INTO items VALUES(NULL,'Roof 22',281,8566,0,'2176');
+INSERT INTO items VALUES(NULL,'Roof 23',281,8567,0,'2177');
+INSERT INTO items VALUES(NULL,'Roof 20',281,8564,0,'2174');
+INSERT INTO items VALUES(NULL,'Roof 21',281,8565,0,'2175');
+INSERT INTO items VALUES(NULL,'Roof 16',209,8568,0,'2178');
+INSERT INTO items VALUES(NULL,'Roof 17',209,8569,0,'2179');
+INSERT INTO items VALUES(NULL,'Catapult 93',72,5807,0,'16af');
+INSERT INTO items VALUES(NULL,'Catapult 91',72,5805,0,'16ad');
+INSERT INTO items VALUES(NULL,'Catapult 92',72,5806,0,'16ae');
+INSERT INTO items VALUES(NULL,'Catapult 89',72,5803,0,'16ab');
+INSERT INTO items VALUES(NULL,'Catapult 90',72,5804,0,'16ac');
+INSERT INTO items VALUES(NULL,'Catapult 88',72,5802,0,'16aa');
+INSERT INTO items VALUES(NULL,'Swamp 18',237,12897,0,'3261');
+INSERT INTO items VALUES(NULL,'Swamp 17',237,12896,0,'3260');
+INSERT INTO items VALUES(NULL,'Swamp 20',237,12899,0,'3263');
+INSERT INTO items VALUES(NULL,'Swamp 19',237,12898,0,'3262');
+INSERT INTO items VALUES(NULL,'Swamp 22',237,12901,0,'3265');
+INSERT INTO items VALUES(NULL,'Swamp 21',237,12900,0,'3264');
+INSERT INTO items VALUES(NULL,'Swamp 24',237,12903,0,'3267');
+INSERT INTO items VALUES(NULL,'Swamp 23',237,12902,0,'3266');
+INSERT INTO items VALUES(NULL,'Swamp 27',236,12905,0,'3269');
+INSERT INTO items VALUES(NULL,'Swamp 25',237,12904,0,'3268');
+INSERT INTO items VALUES(NULL,'Roof 1',203,6457,0,'1939');
+INSERT INTO items VALUES(NULL,'Roof 19',209,8571,0,'217b');
+INSERT INTO items VALUES(NULL,'Roof 20',209,8572,0,'217c');
+INSERT INTO items VALUES(NULL,'Roof 18',209,8570,0,'217a');
+INSERT INTO items VALUES(NULL,'Roof 23',209,8575,0,'217f');
+INSERT INTO items VALUES(NULL,'Roof 21',209,8573,0,'217d');
+INSERT INTO items VALUES(NULL,'Roof 22',209,8574,0,'217e');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 2 (N/S) (3/3)',78,2922,0,'b6a');
+INSERT INTO items VALUES(NULL,'Tiny Wall 5',22,8625,0,'21b1');
+INSERT INTO items VALUES(NULL,'Post 2',82,8624,0,'21b0');
+INSERT INTO items VALUES(NULL,'Tiny Wall 7',22,8627,0,'21b3');
+INSERT INTO items VALUES(NULL,'Tiny Wall 6',22,8626,0,'21b2');
+INSERT INTO items VALUES(NULL,'Tiny Wall 9',22,8629,0,'21b5');
+INSERT INTO items VALUES(NULL,'Tiny Wall 8',22,8628,0,'21b4');
+INSERT INTO items VALUES(NULL,'Tiny Wall 11',22,8631,0,'21b7');
+INSERT INTO items VALUES(NULL,'Tiny Wall 10',22,8630,0,'21b6');
+INSERT INTO items VALUES(NULL,'Tiny Wall 12',22,8632,0,'21b8');
+INSERT INTO items VALUES(NULL,'Empty Vials (N/S)',173,6235,0,'185b');
+INSERT INTO items VALUES(NULL,'Empty Vials (W/E)',173,6236,0,'185c');
+INSERT INTO items VALUES(NULL,'Full Vials (N/S)',173,6237,0,'185d');
+INSERT INTO items VALUES(NULL,'Full Vials (W/E)',173,6238,0,'185e');
+INSERT INTO items VALUES(NULL,'Wooden Table 1 (W/E) (2/2)',89,2927,0,'b6f');
+INSERT INTO items VALUES(NULL,'Sandstone Table 1 (W/E) (3/3)',89,2925,0,'b6d');
+INSERT INTO items VALUES(NULL,'Treasure (41/41)',215,7019,0,'1b6b');
+INSERT INTO items VALUES(NULL,'Treasure (40/41)',215,7018,0,'1b6a');
+INSERT INTO items VALUES(NULL,'Wall Cracks 4',282,7023,0,'1b6f');
+INSERT INTO items VALUES(NULL,'Roof 1',152,1535,0,'5ff');
+INSERT INTO items VALUES(NULL,'Red Communication Crystal',283,7888,0,'1ed0');
+INSERT INTO items VALUES(NULL,'Magic Face 1 (N/S)',28,7897,0,'1ed9');
+INSERT INTO items VALUES(NULL,'Roof 7',152,1541,0,'605');
+INSERT INTO items VALUES(NULL,'Roof 6',152,1540,0,'604');
+INSERT INTO items VALUES(NULL,'Roof 9',152,1543,0,'607');
+INSERT INTO items VALUES(NULL,'Roof 8',152,1542,0,'606');
+INSERT INTO items VALUES(NULL,'Stone Bench 1 (W/E) (3/3)',78,4617,0,'1209');
+INSERT INTO items VALUES(NULL,'Stone Bench 1 (W/E) (2/3)',78,4616,0,'1208');
+INSERT INTO items VALUES(NULL,'Roof 5',152,1539,0,'603');
+INSERT INTO items VALUES(NULL,'Roof 4',152,1538,0,'602');
+INSERT INTO items VALUES(NULL,'Stone Table (W/E) (2/3)',89,4613,0,'1205');
+INSERT INTO items VALUES(NULL,'Stone Table (W/E) (1/3)',89,4612,0,'1204');
+INSERT INTO items VALUES(NULL,'Blue Moongate',200,3948,0,'moongate');
+INSERT INTO items VALUES(NULL,'chainmail tunic',284,5055,0,'verite_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Roof 11',152,1545,0,'609');
+INSERT INTO items VALUES(NULL,'Roof 10',152,1544,0,'608');
+INSERT INTO items VALUES(NULL,'Stone Table (N/S) (3/3)',89,4611,0,'1203');
+INSERT INTO items VALUES(NULL,'Stone Table (N/S) (2/3)',89,4610,0,'1202');
+INSERT INTO items VALUES(NULL,'plate helmet',269,5138,0,'dull_copper_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Cactus 5',45,3370,0,'d2a');
+INSERT INTO items VALUES(NULL,'Cactus 6',45,3372,0,'d2c');
+INSERT INTO items VALUES(NULL,'Cactus 5 (Flowers)',45,3371,0,'d2b');
+INSERT INTO items VALUES(NULL,'Cactus 7',45,3374,0,'d2e');
+INSERT INTO items VALUES(NULL,'Cactus 6 (Flowers)',45,3373,0,'d2d');
+INSERT INTO items VALUES(NULL,'Cactus 7 (Flowers)',45,3375,0,'d2f');
+INSERT INTO items VALUES(NULL,'Boulder 4 (1/3)',216,4951,0,'1357');
+INSERT INTO items VALUES(NULL,'Boulder 3 (2/2)',216,4950,0,'1356');
+INSERT INTO items VALUES(NULL,'Roof 16',152,1550,0,'60e');
+INSERT INTO items VALUES(NULL,'Roof 15',152,1549,0,'60d');
+INSERT INTO items VALUES(NULL,'Roof 17',152,1551,0,'60f');
+INSERT INTO items VALUES(NULL,'Roof 12',152,1546,0,'60a');
+INSERT INTO items VALUES(NULL,'Roof 14',152,1548,0,'60c');
+INSERT INTO items VALUES(NULL,'Roof 13',152,1547,0,'60b');
+INSERT INTO items VALUES(NULL,'Altar 1',151,4622,0,'120e');
+INSERT INTO items VALUES(NULL,'Altar 2',151,4623,0,'120f');
+INSERT INTO items VALUES(NULL,'Cactus 4 (Flowers)',45,3369,0,'d29');
+INSERT INTO items VALUES(NULL,'Cactus 4',45,3368,0,'d28');
+INSERT INTO items VALUES(NULL,'Grapevines 7',285,3361,0,'d21');
+INSERT INTO items VALUES(NULL,'Grapevines 6',285,3360,0,'d20');
+INSERT INTO items VALUES(NULL,'Grapevines 9',285,3363,0,'d23');
+INSERT INTO items VALUES(NULL,'Grapevines 8',285,3362,0,'d22');
+INSERT INTO items VALUES(NULL,'Cactus 1',45,3365,0,'d25');
+INSERT INTO items VALUES(NULL,'Grapevines 10',285,3364,0,'d24');
+INSERT INTO items VALUES(NULL,'Cactus 3',45,3367,0,'d27');
+INSERT INTO items VALUES(NULL,'Cactus 2',45,3366,0,'d26');
+INSERT INTO items VALUES(NULL,'Ship 25',137,16028,0,'3e9c');
+INSERT INTO items VALUES(NULL,'Ship 24',137,16027,0,'3e9b');
+INSERT INTO items VALUES(NULL,'Prow 5',9,16026,0,'3e9a');
+INSERT INTO items VALUES(NULL,'Ship 28',137,16031,0,'3e9f');
+INSERT INTO items VALUES(NULL,'Ship 27',137,16030,0,'3e9e');
+INSERT INTO items VALUES(NULL,'Ship 26',137,16029,0,'3e9d');
+INSERT INTO items VALUES(NULL,'Balista 122',76,16229,0,'3f65');
+INSERT INTO items VALUES(NULL,'Balista 121',76,16228,0,'3f64');
+INSERT INTO items VALUES(NULL,'Balista 124',76,16231,0,'3f67');
+INSERT INTO items VALUES(NULL,'Balista 123',76,16230,0,'3f66');
+INSERT INTO items VALUES(NULL,'Balista 118',76,16225,0,'3f61');
+INSERT INTO items VALUES(NULL,'Balista 117',76,16224,0,'3f60');
+INSERT INTO items VALUES(NULL,'Balista 120',76,16227,0,'3f63');
+INSERT INTO items VALUES(NULL,'Roof 3',221,1403,0,'57b');
+INSERT INTO items VALUES(NULL,'Balista 126',76,16233,0,'3f69');
+INSERT INTO items VALUES(NULL,'Roof 2',221,1402,0,'57a');
+INSERT INTO items VALUES(NULL,'Beehive',224,2330,0,'91a');
+INSERT INTO items VALUES(NULL,'Arch 1',223,198,0,'c6');
+INSERT INTO items VALUES(NULL,'Roof 6',221,1406,0,'57e');
+INSERT INTO items VALUES(NULL,'Balista 131',76,16238,0,'3f6e');
+INSERT INTO items VALUES(NULL,'Balista 130',76,16237,0,'3f6d');
+INSERT INTO items VALUES(NULL,'Balista 132',76,16239,0,'3f6f');
+INSERT INTO items VALUES(NULL,'Balista 127',76,16234,0,'3f6a');
+INSERT INTO items VALUES(NULL,'Balista 129',76,16236,0,'3f6c');
+INSERT INTO items VALUES(NULL,'Balista 128',76,16235,0,'3f6b');
+INSERT INTO items VALUES(NULL,'Hatch 2',139,16019,0,'3e93');
+INSERT INTO items VALUES(NULL,'Hold 2',138,16018,0,'3e92');
+INSERT INTO items VALUES(NULL,'Ship 22',137,16017,0,'3e91');
+INSERT INTO items VALUES(NULL,'Ship 21',137,16016,0,'3e90');
+INSERT INTO items VALUES(NULL,'Prow 4',9,16023,0,'3e97');
+INSERT INTO items VALUES(NULL,'Prow 3',9,16022,0,'3e96');
+INSERT INTO items VALUES(NULL,'Prow 3',9,16021,0,'3e95');
+INSERT INTO items VALUES(NULL,'Ship 23',137,16020,0,'3e94');
+INSERT INTO items VALUES(NULL,'Deck 7',193,16024,0,'3e98');
+INSERT INTO items VALUES(NULL,'chainmail tunic',286,5055,0,'merkite_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Bees 1',224,2331,0,'91b');
+INSERT INTO items VALUES(NULL,'kite shield',15,7032,0,'1b78');
+INSERT INTO items VALUES(NULL,'heater shield',16,7030,0,'verite_shields_heater');
+INSERT INTO items VALUES(NULL,'Crumbling Floor 7',109,7025,0,'1b71');
+INSERT INTO items VALUES(NULL,'bronze shield',15,7026,0,'1b72');
+INSERT INTO items VALUES(NULL,'buckler',15,7027,0,'1b73');
+INSERT INTO items VALUES(NULL,'kite shield',15,7028,0,'1b74');
+INSERT INTO items VALUES(NULL,'heater shield',15,7030,0,'1b76');
+INSERT INTO items VALUES(NULL,'Bamboo Table (W/E) (3/3)',89,4571,0,'11db');
+INSERT INTO items VALUES(NULL,'Log Table (W/E) (1/3)',89,4572,0,'11dc');
+INSERT INTO items VALUES(NULL,'Bamboo Table (W/E) (2/3)',89,4570,0,'11da');
+INSERT INTO items VALUES(NULL,'Log Table (N/S) (1/3)',89,4575,0,'11df');
+INSERT INTO items VALUES(NULL,'Log Table (W/E) (2/3)',89,4573,0,'11dd');
+INSERT INTO items VALUES(NULL,'Log Table (W/E) (3/3)',89,4574,0,'11de');
+INSERT INTO items VALUES(NULL,'Part 3',287,5297,0,'14b1');
+INSERT INTO items VALUES(NULL,'Part 2',287,5296,0,'14b0');
+INSERT INTO items VALUES(NULL,'Part 1',288,5299,0,'14b3');
+INSERT INTO items VALUES(NULL,'Part 4',287,5298,0,'14b2');
+INSERT INTO items VALUES(NULL,'Part 3',288,5301,0,'14b5');
+INSERT INTO items VALUES(NULL,'Part 2',288,5300,0,'14b4');
+INSERT INTO items VALUES(NULL,'Part 1',289,5303,0,'14b7');
+INSERT INTO items VALUES(NULL,'Part 4',288,5302,0,'14b6');
+INSERT INTO items VALUES(NULL,'Part 3',289,5305,0,'14b9');
+INSERT INTO items VALUES(NULL,'Part 2',289,5304,0,'14b8');
+INSERT INTO items VALUES(NULL,'Platform 5',101,1985,0,'7c1');
+INSERT INTO items VALUES(NULL,'Dartboard 2 (W/E)',249,7729,0,'1e31');
+INSERT INTO items VALUES(NULL,'Platform 4',101,1984,0,'7c0');
+INSERT INTO items VALUES(NULL,'wooden shield',15,7034,0,'1b7a');
+INSERT INTO items VALUES(NULL,'metal shield',15,7035,0,'1b7b');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 9',12,7036,0,'1b7c');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 10',12,7037,0,'1b7d');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 19',100,7333,0,'1ca5');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 11',12,7039,0,'1b7f');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 18',100,7332,0,'1ca4');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 17',100,7331,0,'1ca3');
+INSERT INTO items VALUES(NULL,'Platform 8',101,1988,0,'7c4');
+INSERT INTO items VALUES(NULL,'Part 4',289,5306,0,'14ba');
+INSERT INTO items VALUES(NULL,'Part 2',290,5308,0,'14bc');
+INSERT INTO items VALUES(NULL,'Part 1',290,5307,0,'14bb');
+INSERT INTO items VALUES(NULL,'Part 4',290,5310,0,'14be');
+INSERT INTO items VALUES(NULL,'Part 3',290,5309,0,'14bd');
+INSERT INTO items VALUES(NULL,'Part 1',291,5311,0,'14bf');
+INSERT INTO items VALUES(NULL,'Platform 10',101,1990,0,'7c6');
+INSERT INTO items VALUES(NULL,'Walkable Double Bed (N/S) (1/4)',91,4562,0,'11d2');
+INSERT INTO items VALUES(NULL,'Walkable Double Bed (N/S) (2/4)',91,4563,0,'11d3');
+INSERT INTO items VALUES(NULL,'Walkable Double Bed (W/E) (3/4)',91,4560,0,'11d0');
+INSERT INTO items VALUES(NULL,'Walkable Double Bed (W/E) (4/4)',91,4561,0,'11d1');
+INSERT INTO items VALUES(NULL,'Bamboo Table (N/S) (1/3)',89,4566,0,'11d6');
+INSERT INTO items VALUES(NULL,'Bamboo Table (N/S) (2/3)',89,4567,0,'11d7');
+INSERT INTO items VALUES(NULL,'Walkable Double Bed (N/S) (3/4)',91,4564,0,'11d4');
+INSERT INTO items VALUES(NULL,'Walkable Double Bed (N/S) (4/4)',91,4565,0,'11d5');
+INSERT INTO items VALUES(NULL,'Bamboo Table (N/S) (3/3)',89,4568,0,'11d8');
+INSERT INTO items VALUES(NULL,'Bamboo Table (W/E) (1/3)',89,4569,0,'11d9');
+INSERT INTO items VALUES(NULL,'plate armor',117,7172,0,'golden_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Wave 31',62,8129,0,'1fc1');
+INSERT INTO items VALUES(NULL,'Wave 32',62,8130,0,'1fc2');
+INSERT INTO items VALUES(NULL,'Wave 33',62,8131,0,'1fc3');
+INSERT INTO items VALUES(NULL,'Wave 34',62,8132,0,'1fc4');
+INSERT INTO items VALUES(NULL,'Wall 25',127,994,0,'3e2');
+INSERT INTO items VALUES(NULL,'Wall 24',127,993,0,'3e1');
+INSERT INTO items VALUES(NULL,'Wave 37',62,8135,0,'1fc7');
+INSERT INTO items VALUES(NULL,'Wave 38',62,8136,0,'1fc8');
+INSERT INTO items VALUES(NULL,'Wave 39',62,8137,0,'1fc9');
+INSERT INTO items VALUES(NULL,'Sawmp Dragon',115,9753,0,'2619');
+INSERT INTO items VALUES(NULL,'Sphinx',115,9752,0,'2618');
+INSERT INTO items VALUES(NULL,'Treasure (33/41)',215,7011,0,'1b63');
+INSERT INTO items VALUES(NULL,'Treasure (32/41)',215,7010,0,'1b62');
+INSERT INTO items VALUES(NULL,'Century Plant 2',45,3377,0,'d31');
+INSERT INTO items VALUES(NULL,'Treasure (31/41)',215,7009,0,'1b61');
+INSERT INTO items VALUES(NULL,'Treasure (30/41)',215,7008,0,'1b60');
+INSERT INTO items VALUES(NULL,'Treasure (37/41)',215,7015,0,'1b67');
+INSERT INTO items VALUES(NULL,'Treasure (36/41)',215,7014,0,'1b66');
+INSERT INTO items VALUES(NULL,'Treasure (35/41)',215,7013,0,'1b65');
+INSERT INTO items VALUES(NULL,'Treasure (34/41)',215,7012,0,'1b64');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 2',292,1007,0,'3ef');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 1',292,1006,0,'3ee');
+INSERT INTO items VALUES(NULL,'Meer Warrior',115,9757,0,'261d');
+INSERT INTO items VALUES(NULL,'Meer Mage',115,9756,0,'261c');
+INSERT INTO items VALUES(NULL,'Plague Beast Lord',115,9755,0,'261b');
+INSERT INTO items VALUES(NULL,'Swarm',115,9754,0,'261a');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 9',105,1856,0,'740');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 10',105,1857,0,'741');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 11',105,1858,0,'742');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 12',105,1859,0,'743');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 13',105,1860,0,'744');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 14',105,1861,0,'745');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 15',105,1862,0,'746');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 16',105,1863,0,'747');
+INSERT INTO items VALUES(NULL,'Wall 1',260,248,0,'f8');
+INSERT INTO items VALUES(NULL,'Wall 2',260,249,0,'f9');
+INSERT INTO items VALUES(NULL,'Clock Parts (N/S)',240,4176,0,'1050');
+INSERT INTO items VALUES(NULL,'Axle with Gears (W/E)',240,4177,0,'1051');
+INSERT INTO items VALUES(NULL,'Axle with Gears (N/S)',240,4178,0,'1052');
+INSERT INTO items VALUES(NULL,'Gears (W/E)',240,4179,0,'1053');
+INSERT INTO items VALUES(NULL,'Gears (N/S)',240,4180,0,'1054');
+INSERT INTO items VALUES(NULL,'Hinge (W/E)',240,4181,0,'1055');
+INSERT INTO items VALUES(NULL,'Hinge (W/E)',240,4182,0,'1056');
+INSERT INTO items VALUES(NULL,'Sextant (W/E)',240,4183,0,'1057');
+INSERT INTO items VALUES(NULL,'Sextant (N/S)',240,4184,0,'1058');
+INSERT INTO items VALUES(NULL,'Sextant Parts (W/E)',240,4185,0,'1059');
+INSERT INTO items VALUES(NULL,'Crystal Ball 1',293,3629,0,'e2d');
+INSERT INTO items VALUES(NULL,'Crystal Ball 2',293,3630,0,'e2e');
+INSERT INTO items VALUES(NULL,'Crystal Ball 3',293,3631,0,'e2f');
+INSERT INTO items VALUES(NULL,'Bottle 6',173,3626,0,'e2a');
+INSERT INTO items VALUES(NULL,'Bottle 7',173,3627,0,'e2b');
+INSERT INTO items VALUES(NULL,'Bottle 8',173,3628,0,'e2c');
+INSERT INTO items VALUES(NULL,'chainmail coif',286,5051,0,'merkite_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Protection',94,7995,0,'1f3b');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 6',121,1866,0,'74a');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 7',121,1867,0,'74b');
+INSERT INTO items VALUES(NULL,'Window 1',260,252,0,'fc');
+INSERT INTO items VALUES(NULL,'Window 2',260,253,0,'fd');
+INSERT INTO items VALUES(NULL,'Wall 1',123,254,0,'fe');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 11',121,1871,0,'74f');
+INSERT INTO items VALUES(NULL,'Bless',94,7997,0,'1f3d');
+INSERT INTO items VALUES(NULL,'Wall 5',158,10,0,'a');
+INSERT INTO items VALUES(NULL,'Bottle 1',173,3621,0,'e25');
+INSERT INTO items VALUES(NULL,'Bottle 2',173,3622,0,'e26');
+INSERT INTO items VALUES(NULL,'hair dye',173,3623,0,'e27');
+INSERT INTO items VALUES(NULL,'Bloody Bandages 2',294,3616,0,'e20');
+INSERT INTO items VALUES(NULL,'Clean Bandages 2',294,3617,0,'e21');
+INSERT INTO items VALUES(NULL,'platemail gloves',208,5140,0,'copper_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Bloody Water',274,3619,0,'e23');
+INSERT INTO items VALUES(NULL,'Bottle 4',173,3624,0,'e28');
+INSERT INTO items VALUES(NULL,'Bottle 5',173,3625,0,'e29');
+INSERT INTO items VALUES(NULL,'Sextant Parts (N/S)',240,4186,0,'105a');
+INSERT INTO items VALUES(NULL,'Axle (W/E)',240,4187,0,'105b');
+INSERT INTO items VALUES(NULL,'Axle (N/S)',240,4188,0,'105c');
+INSERT INTO items VALUES(NULL,'Springs (W/E)',240,4189,0,'105d');
+INSERT INTO items VALUES(NULL,'Springs (N/S)',240,4190,0,'105e');
+INSERT INTO items VALUES(NULL,'Upright Loom 1 (W/E) (1/2)',57,4191,0,'105f');
+INSERT INTO items VALUES(NULL,'Willow Leaves 1',4,3303,0,'ce7');
+INSERT INTO items VALUES(NULL,'Willow Tree ',4,3302,0,'ce6');
+INSERT INTO items VALUES(NULL,'Walnut Tree 2 Leaves 2',4,3301,0,'ce5');
+INSERT INTO items VALUES(NULL,'Walnut Tree 2 Leaves 1',4,3300,0,'ce4');
+INSERT INTO items VALUES(NULL,'Walnut Tree 2',4,3299,0,'ce3');
+INSERT INTO items VALUES(NULL,'Walnut Tree 1 Leaves 2',4,3298,0,'ce2');
+INSERT INTO items VALUES(NULL,'Walnut Tree 1 Leaves 1',4,3297,0,'ce1');
+INSERT INTO items VALUES(NULL,'Walnut Tree 1',4,3296,0,'ce0');
+INSERT INTO items VALUES(NULL,'Pewter Mug 1',279,4095,0,'fff');
+INSERT INTO items VALUES(NULL,'Skull Mug 4',279,4094,0,'ffe');
+INSERT INTO items VALUES(NULL,'Skull Mug 3',279,4093,0,'ffd');
+INSERT INTO items VALUES(NULL,'Skull Mug 2',279,4092,0,'ffc');
+INSERT INTO items VALUES(NULL,'Skull Mug 1',279,4091,0,'ffb');
+INSERT INTO items VALUES(NULL,'Bucket of Water',19,4090,0,'ffa');
+INSERT INTO items VALUES(NULL,'Willow Leaves 2',4,3304,0,'ce8');
+INSERT INTO items VALUES(NULL,'Dirt 5',202,12792,0,'31f8');
+INSERT INTO items VALUES(NULL,'Dirt 6',202,12793,0,'31f9');
+INSERT INTO items VALUES(NULL,'Dirt 3',202,12790,0,'31f6');
+INSERT INTO items VALUES(NULL,'Dirt 4',202,12791,0,'31f7');
+INSERT INTO items VALUES(NULL,'Dirt 1',202,12788,0,'31f4');
+INSERT INTO items VALUES(NULL,'Dirt 2',202,12789,0,'31f5');
+INSERT INTO items VALUES(NULL,'Lava 9',44,12942,0,'328e');
+INSERT INTO items VALUES(NULL,'Vines 8',45,3311,0,'cef');
+INSERT INTO items VALUES(NULL,'Vines 7',45,3310,0,'cee');
+INSERT INTO items VALUES(NULL,'Lava 8',44,12941,0,'328d');
+INSERT INTO items VALUES(NULL,'Vines 5',45,3308,0,'cec');
+INSERT INTO items VALUES(NULL,'Vines 4',45,3307,0,'ceb');
+INSERT INTO items VALUES(NULL,'Pitcher of Water 2',19,4089,0,'ff9');
+INSERT INTO items VALUES(NULL,'Pitcher of Water 1',19,4088,0,'ff8');
+INSERT INTO items VALUES(NULL,'Glass Pitcher 2',279,4087,0,'ff7');
+INSERT INTO items VALUES(NULL,'Lava 7',44,12940,0,'328c');
+INSERT INTO items VALUES(NULL,'Book 6',263,4084,0,'ff4');
+INSERT INTO items VALUES(NULL,'Book 5',263,4083,0,'ff3');
+INSERT INTO items VALUES(NULL,'Book 4',263,4082,0,'ff2');
+INSERT INTO items VALUES(NULL,'Book 3',263,4081,0,'ff1');
+INSERT INTO items VALUES(NULL,'Book 2',263,4080,0,'ff0');
+INSERT INTO items VALUES(NULL,'Window 1',127,989,0,'3dd');
+INSERT INTO items VALUES(NULL,'Wave 25',62,8123,0,'1fbb');
+INSERT INTO items VALUES(NULL,'Wave 24',62,8122,0,'1fba');
+INSERT INTO items VALUES(NULL,'Beef Carcass 1 (W/E)',19,6258,0,'1872');
+INSERT INTO items VALUES(NULL,'Dirt 8',202,12795,0,'31fb');
+INSERT INTO items VALUES(NULL,'Dirt 7',202,12794,0,'31fa');
+INSERT INTO items VALUES(NULL,'Wall 21',127,987,0,'3db');
+INSERT INTO items VALUES(NULL,'Wave 27',62,8125,0,'1fbd');
+INSERT INTO items VALUES(NULL,'Dark Wooden Plank 4',295,1996,0,'7cc');
+INSERT INTO items VALUES(NULL,'Doublet (N/S)',1,8059,0,'1f7b');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 2 (N/S) (1/3)',100,7341,0,'1cad');
+INSERT INTO items VALUES(NULL,'Gold Wire',240,6264,0,'1878');
+INSERT INTO items VALUES(NULL,'Wall 2',158,7,0,'7');
+INSERT INTO items VALUES(NULL,'Dark Wooden Plank 6',295,1998,0,'7ce');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 25',100,7339,0,'1cab');
+INSERT INTO items VALUES(NULL,'buckler',266,7027,0,'valorite_shields_buckler');
+INSERT INTO items VALUES(NULL,'Bar 3',279,6426,0,'191a');
+INSERT INTO items VALUES(NULL,'Lava 10',44,12943,0,'328f');
+INSERT INTO items VALUES(NULL,'Bar 5',279,6428,0,'191c');
+INSERT INTO items VALUES(NULL,'Bar 4',279,6427,0,'191b');
+INSERT INTO items VALUES(NULL,'Bar 7',279,6430,0,'191e');
+INSERT INTO items VALUES(NULL,'Bar 6',279,6429,0,'191d');
+INSERT INTO items VALUES(NULL,'Lava 5',44,12938,0,'328a');
+INSERT INTO items VALUES(NULL,'Bar 8',279,6431,0,'191f');
+INSERT INTO items VALUES(NULL,'Iron Wire',240,6262,0,'1876');
+INSERT INTO items VALUES(NULL,'Silver Wire',240,6263,0,'1877');
+INSERT INTO items VALUES(NULL,'Beef Carcass 2 (W/E)',19,6260,0,'1874');
+INSERT INTO items VALUES(NULL,'chainmail leggings',111,5054,0,'dull_copper_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Beef Carcass 2 (N/S)',19,6259,0,'1873');
+INSERT INTO items VALUES(NULL,'Virtue Stone 8',172,6256,0,'1870');
+INSERT INTO items VALUES(NULL,'Beef Carcass 1 (N/S)',19,6257,0,'1871');
+INSERT INTO items VALUES(NULL,'ringmail leggings',42,5104,0,'bronze_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'Copper Wire',240,6265,0,'1879');
+INSERT INTO items VALUES(NULL,'Black Bear',115,8472,0,'2118');
+INSERT INTO items VALUES(NULL,'Big Cat',115,8473,0,'2119');
+INSERT INTO items VALUES(NULL,'Woven Mat (W/E) (1/2)',185,4584,0,'11e8');
+INSERT INTO items VALUES(NULL,'Spilled Flour 2',114,6271,0,'187f');
+INSERT INTO items VALUES(NULL,'Spilled Flour 1',114,6270,0,'187e');
+INSERT INTO items VALUES(NULL,'Bar 2',279,6425,0,'1919');
+INSERT INTO items VALUES(NULL,'Bar 1',279,6424,0,'1918');
+INSERT INTO items VALUES(NULL,'Lava 4',44,12937,0,'3289');
+INSERT INTO items VALUES(NULL,'Lava 3',44,12936,0,'3288');
+INSERT INTO items VALUES(NULL,'Lava 2',44,12935,0,'3287');
+INSERT INTO items VALUES(NULL,'Bar Corner 1',279,6416,0,'1910');
+INSERT INTO items VALUES(NULL,'Bar Corner 4',279,6419,0,'1913');
+INSERT INTO items VALUES(NULL,'Swamp 46',237,12932,0,'3284');
+INSERT INTO items VALUES(NULL,'Swamp 45',237,12931,0,'3283');
+INSERT INTO items VALUES(NULL,'Towel',91,6420,0,'1914');
+INSERT INTO items VALUES(NULL,'Swamp 43',237,12929,0,'3281');
+INSERT INTO items VALUES(NULL,'Swamp 42',237,12928,0,'3280');
+INSERT INTO items VALUES(NULL,'Summon Blue Moongate 2',200,6903,0,'1af7');
+INSERT INTO items VALUES(NULL,'Summon Blue Moongate 1',200,6899,0,'1af3');
+INSERT INTO items VALUES(NULL,'Bird',115,8474,0,'211a');
+INSERT INTO items VALUES(NULL,'Cat',115,8475,0,'211b');
+INSERT INTO items VALUES(NULL,'Dog',115,8476,0,'211c');
+INSERT INTO items VALUES(NULL,'Eagle',115,8477,0,'211d');
+INSERT INTO items VALUES(NULL,'Grizzly Bear',115,8478,0,'211e');
+INSERT INTO items VALUES(NULL,'Horse 1',115,8479,0,'211f');
+INSERT INTO items VALUES(NULL,'Grass Mat (N/S) (1/2)',185,4578,0,'11e2');
+INSERT INTO items VALUES(NULL,'Rail (W/E) 6',197,2179,0,'883');
+INSERT INTO items VALUES(NULL,'Wave 17',62,8115,0,'1fb3');
+INSERT INTO items VALUES(NULL,'Rail (W/E) 4',197,2177,0,'881');
+INSERT INTO items VALUES(NULL,'Rail (W/E) 3',197,2176,0,'880');
+INSERT INTO items VALUES(NULL,'Rail (N/S) 4',197,2183,0,'887');
+INSERT INTO items VALUES(NULL,'Rail (N/S) 3',197,2182,0,'886');
+INSERT INTO items VALUES(NULL,'Rail (N/S) 2',197,2181,0,'885');
+INSERT INTO items VALUES(NULL,'Wave 16',62,8114,0,'1fb2');
+INSERT INTO items VALUES(NULL,'Rail (N/S) 6',197,2185,0,'889');
+INSERT INTO items VALUES(NULL,'Rail (N/S) 5',197,2184,0,'888');
+INSERT INTO items VALUES(NULL,'Wave 15',62,8113,0,'1fb1');
+INSERT INTO items VALUES(NULL,'Wall 17',127,983,0,'3d7');
+INSERT INTO items VALUES(NULL,'Wave 21',62,8119,0,'1fb7');
+INSERT INTO items VALUES(NULL,'Wave 20',62,8118,0,'1fb6');
+INSERT INTO items VALUES(NULL,'Wall 12',127,978,0,'3d2');
+INSERT INTO items VALUES(NULL,'Heal',94,7985,0,'1f31');
+INSERT INTO items VALUES(NULL,'Wave 18',62,8116,0,'1fb4');
+INSERT INTO items VALUES(NULL,'Night Sight',94,7987,0,'1f33');
+INSERT INTO items VALUES(NULL,'Weaken',94,7988,0,'1f34');
+INSERT INTO items VALUES(NULL,'close helmet',97,5128,0,'verite_helmets_close');
+INSERT INTO items VALUES(NULL,'Rug 10',228,7672,0,'1df8');
+INSERT INTO items VALUES(NULL,'Cure',94,7991,0,'1f37');
+INSERT INTO items VALUES(NULL,'Fence 2',296,2187,0,'88b');
+INSERT INTO items VALUES(NULL,'Fence 1',296,2186,0,'88a');
+INSERT INTO items VALUES(NULL,'Magic Trap',94,7993,0,'1f39');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (W/E) (3/5)',89,2937,0,'b79');
+INSERT INTO items VALUES(NULL,'Tan Horse',115,9630,0,'259e');
+INSERT INTO items VALUES(NULL,'Rug 4',228,7666,0,'1df2');
+INSERT INTO items VALUES(NULL,'Waterfall 20',23,13567,0,'34ff');
+INSERT INTO items VALUES(NULL,'Guillotine 6',113,4713,0,'1269');
+INSERT INTO items VALUES(NULL,'Guillotine 5',113,4712,0,'1268');
+INSERT INTO items VALUES(NULL,'Roof 16',297,1641,0,'669');
+INSERT INTO items VALUES(NULL,'Roof 15',297,1640,0,'668');
+INSERT INTO items VALUES(NULL,'Shackles 2',113,4707,0,'1263');
+INSERT INTO items VALUES(NULL,'Roof 13',297,1638,0,'666');
+INSERT INTO items VALUES(NULL,'Roof 12',297,1637,0,'665');
+INSERT INTO items VALUES(NULL,'Roof 11',297,1636,0,'664');
+INSERT INTO items VALUES(NULL,'Wall Carving 7 (3/3)',53,4711,0,'1267');
+INSERT INTO items VALUES(NULL,'Wall Carving 7 (2/3)',53,4710,0,'1266');
+INSERT INTO items VALUES(NULL,'Roof 8',297,1633,0,'661');
+INSERT INTO items VALUES(NULL,'Roof 7',297,1632,0,'660');
+INSERT INTO items VALUES(NULL,'Bar Corner 2',279,6417,0,'1911');
+INSERT INTO items VALUES(NULL,'Lava 1',44,12934,0,'3286');
+INSERT INTO items VALUES(NULL,'Bowl of Corn 1',19,5626,0,'15fa');
+INSERT INTO items VALUES(NULL,'Bowl of Lettuce 1',19,5627,0,'15fb');
+INSERT INTO items VALUES(NULL,'Bowl of Peas 1',19,5628,0,'15fc');
+INSERT INTO items VALUES(NULL,'Pewter Bowl',14,5629,0,'15fd');
+INSERT INTO items VALUES(NULL,'Swamp 47',237,12933,0,'3285');
+INSERT INTO items VALUES(NULL,'Bowl of Corn 2',19,5631,0,'15ff');
+INSERT INTO items VALUES(NULL,'Bar Corner 3',279,6418,0,'1912');
+INSERT INTO items VALUES(NULL,'Pillow 16',91,6421,0,'1915');
+INSERT INTO items VALUES(NULL,'Swamp 44',237,12930,0,'3282');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 7',4,4804,0,'12c4');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 8',4,4805,0,'12c5');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 9',4,4806,0,'12c6');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 10',4,4807,0,'12c7');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 3',4,4800,0,'12c0');
+INSERT INTO items VALUES(NULL,'Massage Table (2/2)',91,6423,0,'1917');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 5',4,4802,0,'12c2');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 6',4,4803,0,'12c3');
+INSERT INTO items VALUES(NULL,'Massage Table (1/2)',91,6422,0,'1916');
+INSERT INTO items VALUES(NULL,'Scaffold (W/E) (1/2)',298,4808,0,'12c8');
+INSERT INTO items VALUES(NULL,'Scaffold (W/E) (2/2)',298,4809,0,'12c9');
+INSERT INTO items VALUES(NULL,'Wooden Bowl',14,5624,0,'15f8');
+INSERT INTO items VALUES(NULL,'Bowl of Carrots 1',19,5625,0,'15f9');
+INSERT INTO items VALUES(NULL,'Banner 49 (W/E)',128,5616,0,'15f0');
+INSERT INTO items VALUES(NULL,'Banner 49 (N/S)',128,5617,0,'15f1');
+INSERT INTO items VALUES(NULL,'Banner 50 (W/E)',128,5618,0,'15f2');
+INSERT INTO items VALUES(NULL,'Banner 50 (N/S)',128,5619,0,'15f3');
+INSERT INTO items VALUES(NULL,'Banner 51 (W/E)',128,5620,0,'15f4');
+INSERT INTO items VALUES(NULL,'Banner 51 (N/S)',128,5621,0,'15f5');
+INSERT INTO items VALUES(NULL,'Block 2',113,4716,0,'126c');
+INSERT INTO items VALUES(NULL,'Block 1',113,4715,0,'126b');
+INSERT INTO items VALUES(NULL,'Roof 21',297,1646,0,'66e');
+INSERT INTO items VALUES(NULL,'Roof 20',297,1645,0,'66d');
+INSERT INTO items VALUES(NULL,'Roof 19',297,1644,0,'66c');
+INSERT INTO items VALUES(NULL,'Block 5',113,4719,0,'126f');
+INSERT INTO items VALUES(NULL,'Block 4',113,4718,0,'126e');
+INSERT INTO items VALUES(NULL,'Block 3',113,4717,0,'126d');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (N/S) (2/5)',53,4813,0,'12cd');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (N/S) (3/5)',53,4814,0,'12ce');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (N/S) (4/5)',53,4815,0,'12cf');
+INSERT INTO items VALUES(NULL,'Bust (W/E)',31,4810,0,'12ca');
+INSERT INTO items VALUES(NULL,'Bust (N/S)',31,4811,0,'12cb');
+INSERT INTO items VALUES(NULL,'Wall Carving 8 (N/S) (1/5)',53,4812,0,'12cc');
+INSERT INTO items VALUES(NULL,'Wall 38',98,16131,0,'3f03');
+INSERT INTO items VALUES(NULL,'Wall 37',98,16130,0,'3f02');
+INSERT INTO items VALUES(NULL,'Wall 36',98,16129,0,'3f01');
+INSERT INTO items VALUES(NULL,'Wall 35',98,16128,0,'3f00');
+INSERT INTO items VALUES(NULL,'Wall 41',98,16134,0,'3f06');
+INSERT INTO items VALUES(NULL,'Wall 40',98,16133,0,'3f05');
+INSERT INTO items VALUES(NULL,'Wall 39',98,16132,0,'3f04');
+INSERT INTO items VALUES(NULL,'Wood 2',11,7042,0,'1b82');
+INSERT INTO items VALUES(NULL,'chainmail coif',95,5051,0,'golden_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'kite shield',183,7028,0,'merkite_shields_kite');
+INSERT INTO items VALUES(NULL,'Books 4',263,7716,0,'1e24');
+INSERT INTO items VALUES(NULL,'Books 5',263,7717,0,'1e25');
+INSERT INTO items VALUES(NULL,'Treasure (20/41)',215,6996,0,'1b54');
+INSERT INTO items VALUES(NULL,'Treasure (21/41)',215,6997,0,'1b55');
+INSERT INTO items VALUES(NULL,'Book 8',263,7712,0,'1e20');
+INSERT INTO items VALUES(NULL,'Books 1',263,7713,0,'1e21');
+INSERT INTO items VALUES(NULL,'Books 2',263,7714,0,'1e22');
+INSERT INTO items VALUES(NULL,'Rail (W/E) 5',197,2178,0,'882');
+INSERT INTO items VALUES(NULL,'Oar (W/E) (1/2)',114,7720,0,'1e28');
+INSERT INTO items VALUES(NULL,'Oar (W/E) (2/2)',114,7721,0,'1e29');
+INSERT INTO items VALUES(NULL,'Treasure (23/41)',215,7000,0,'1b58');
+INSERT INTO items VALUES(NULL,'Treasure (24/41)',215,7001,0,'1b59');
+INSERT INTO items VALUES(NULL,'Gazer (3d)',115,9615,0,'258f');
+INSERT INTO items VALUES(NULL,'Stone Gargoyle',115,9614,0,'258e');
+INSERT INTO items VALUES(NULL,'Gargoyle (3d)',115,9613,0,'258d');
+INSERT INTO items VALUES(NULL,'Roof 39',84,1513,0,'5e9');
+INSERT INTO items VALUES(NULL,'Roof 38',84,1512,0,'5e8');
+INSERT INTO items VALUES(NULL,'Evil Mage',115,9610,0,'258a');
+INSERT INTO items VALUES(NULL,'Roof 35',84,1509,0,'5e5');
+INSERT INTO items VALUES(NULL,'Roof 34',84,1508,0,'5e4');
+INSERT INTO items VALUES(NULL,'Roof 37',84,1511,0,'5e7');
+INSERT INTO items VALUES(NULL,'platemail gorget',269,5139,0,'dull_copper_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Roof 31',84,1505,0,'5e1');
+INSERT INTO items VALUES(NULL,'Roof 30',84,1504,0,'5e0');
+INSERT INTO items VALUES(NULL,'Roof 33',84,1507,0,'5e3');
+INSERT INTO items VALUES(NULL,'Roof 32',84,1506,0,'5e2');
+INSERT INTO items VALUES(NULL,'Boulder Trap 5',109,4538,0,'11ba');
+INSERT INTO items VALUES(NULL,'Boulder Trap 6',109,4539,0,'11bb');
+INSERT INTO items VALUES(NULL,'Rail (N/S) 1',197,2180,0,'884');
+INSERT INTO items VALUES(NULL,'Dungeon Ramp (N/S)',299,4541,0,'11bd');
+INSERT INTO items VALUES(NULL,'Carpet 4',217,2781,0,'add');
+INSERT INTO items VALUES(NULL,'Dungeon Ramp (S/N)',299,4543,0,'11bf');
+INSERT INTO items VALUES(NULL,'Globe 2',258,4168,0,'1048');
+INSERT INTO items VALUES(NULL,'Carpet 5',217,2782,0,'ade');
+INSERT INTO items VALUES(NULL,'Ice Fiend Daemon',115,9607,0,'2587');
+INSERT INTO items VALUES(NULL,'Elder Daemon',115,9606,0,'2586');
+INSERT INTO items VALUES(NULL,'Black Gate Daemon',115,9605,0,'2585');
+INSERT INTO items VALUES(NULL,'Daemon (3d)',115,9604,0,'2584');
+INSERT INTO items VALUES(NULL,'Cougar',115,9603,0,'2583');
+INSERT INTO items VALUES(NULL,'Corpser (3d)',115,9602,0,'2582');
+INSERT INTO items VALUES(NULL,'Centaur',115,9601,0,'2581');
+INSERT INTO items VALUES(NULL,'Billy Goat',115,9600,0,'2580');
+INSERT INTO items VALUES(NULL,'Roof 20',222,1519,0,'5ef');
+INSERT INTO items VALUES(NULL,'Roof 40',84,1514,0,'5ea');
+INSERT INTO items VALUES(NULL,'Roof 42',84,1516,0,'5ec');
+INSERT INTO items VALUES(NULL,'Roof 41',84,1515,0,'5eb');
+INSERT INTO items VALUES(NULL,'Treasure (29/41)',215,7007,0,'1b5f');
+INSERT INTO items VALUES(NULL,'Broken Armoire (N/S)',247,3091,0,'c13');
+INSERT INTO items VALUES(NULL,'Treasure (28/41)',215,7005,0,'1b5d');
+INSERT INTO items VALUES(NULL,'Treasure (26/41)',215,7003,0,'1b5b');
+INSERT INTO items VALUES(NULL,'Treasure (27/41)',215,7004,0,'1b5c');
+INSERT INTO items VALUES(NULL,'Oars (W/E)',114,7723,0,'1e2b');
+INSERT INTO items VALUES(NULL,'Broken Armoire (W/E)',247,3090,0,'c12');
+INSERT INTO items VALUES(NULL,'Broken Chair 1 (N/S)',247,3088,0,'c10');
+INSERT INTO items VALUES(NULL,'Boulder Trap 3',109,4536,0,'11b8');
+INSERT INTO items VALUES(NULL,'Boulder Trap 4',109,4537,0,'11b9');
+INSERT INTO items VALUES(NULL,'Floor Saw (W/E) 5',109,4528,0,'11b0');
+INSERT INTO items VALUES(NULL,'Floor Saw (N/S) 1',109,4529,0,'11b1');
+INSERT INTO items VALUES(NULL,'Floor Saw (N/S) 2',109,4530,0,'11b2');
+INSERT INTO items VALUES(NULL,'Floor Saw (N/S) 3',109,4531,0,'11b3');
+INSERT INTO items VALUES(NULL,'Floor Saw (N/S) 4',109,4532,0,'11b4');
+INSERT INTO items VALUES(NULL,'Floor Saw (N/S) 5',109,4533,0,'11b5');
+INSERT INTO items VALUES(NULL,'Boulder Trap 1',109,4534,0,'11b6');
+INSERT INTO items VALUES(NULL,'Boulder Trap 2',109,4535,0,'11b7');
+INSERT INTO items VALUES(NULL,'Wave 6',62,8104,0,'1fa8');
+INSERT INTO items VALUES(NULL,'Wave 7',62,8105,0,'1fa9');
+INSERT INTO items VALUES(NULL,'Wave 4',62,8102,0,'1fa6');
+INSERT INTO items VALUES(NULL,'Wave 5',62,8103,0,'1fa7');
+INSERT INTO items VALUES(NULL,'Wave 2',62,8100,0,'1fa4');
+INSERT INTO items VALUES(NULL,'Wave 3',62,8101,0,'1fa5');
+INSERT INTO items VALUES(NULL,'Tunic (W/E)',1,8098,0,'1fa2');
+INSERT INTO items VALUES(NULL,'Wave 1',62,8099,0,'1fa3');
+INSERT INTO items VALUES(NULL,'Jester Suit (W/E)',1,8096,0,'1fa0');
+INSERT INTO items VALUES(NULL,'Tunic (N/S)',1,8097,0,'1fa1');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 2',100,7265,0,'1c61');
+INSERT INTO items VALUES(NULL,'Lava 41',44,13645,0,'354d');
+INSERT INTO items VALUES(NULL,'Lava 42',44,13646,0,'354e');
+INSERT INTO items VALUES(NULL,'Lava 43',44,13647,0,'354f');
+INSERT INTO items VALUES(NULL,'Lava 8',300,13642,0,'354a');
+INSERT INTO items VALUES(NULL,'Lava 9',300,13643,0,'354b');
+INSERT INTO items VALUES(NULL,'Lava 10',300,13644,0,'354c');
+INSERT INTO items VALUES(NULL,'Wave 13',62,8111,0,'1faf');
+INSERT INTO items VALUES(NULL,'Wave 11',62,8109,0,'1fad');
+INSERT INTO items VALUES(NULL,'Wave 12',62,8110,0,'1fae');
+INSERT INTO items VALUES(NULL,'Wave 9',62,8107,0,'1fab');
+INSERT INTO items VALUES(NULL,'Wave 10',62,8108,0,'1fac');
+INSERT INTO items VALUES(NULL,'Wave 8',62,8106,0,'1faa');
+INSERT INTO items VALUES(NULL,'Lava 5',300,13639,0,'3547');
+INSERT INTO items VALUES(NULL,'Lava 6',300,13640,0,'3548');
+INSERT INTO items VALUES(NULL,'Lava 7',300,13641,0,'3549');
+INSERT INTO items VALUES(NULL,'Spinning Wheel (E/W)',57,4260,0,'10a4');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 25',301,1896,0,'768');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 1',302,1897,0,'769');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 19',301,1890,0,'762');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 20',301,1891,0,'763');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 17',301,1888,0,'760');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 18',301,1889,0,'761');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 23',301,1894,0,'766');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 24',301,1895,0,'767');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 21',301,1892,0,'764');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 22',301,1893,0,'765');
+INSERT INTO items VALUES(NULL,'Clean Bandages 1',274,3817,0,'ee9');
+INSERT INTO items VALUES(NULL,'Grave 6',27,3816,0,'ee8');
+INSERT INTO items VALUES(NULL,'Pile of Hides 1 (W/E)',57,4216,0,'1078');
+INSERT INTO items VALUES(NULL,'Pile of Hides 1 (N/S)',57,4217,0,'1079');
+INSERT INTO items VALUES(NULL,'Spiderweb 3',303,3813,0,'ee5');
+INSERT INTO items VALUES(NULL,'Spiderweb 2',303,3812,0,'ee4');
+INSERT INTO items VALUES(NULL,'Painting 12',304,3815,0,'ee7');
+INSERT INTO items VALUES(NULL,'Spiderweb 4',303,3814,0,'ee6');
+INSERT INTO items VALUES(NULL,'Grave 4',27,3809,0,'ee1');
+INSERT INTO items VALUES(NULL,'Grave 3',27,3808,0,'ee0');
+INSERT INTO items VALUES(NULL,'Spiderweb 1',303,3811,0,'ee3');
+INSERT INTO items VALUES(NULL,'Grave 5',27,3810,0,'ee2');
+INSERT INTO items VALUES(NULL,'Wig 6 (N/S)',175,3597,0,'e0d');
+INSERT INTO items VALUES(NULL,'Wig 6 (W/E)',175,3598,0,'e0e');
+INSERT INTO items VALUES(NULL,'Wig 5 (N/S)',175,3595,0,'e0b');
+INSERT INTO items VALUES(NULL,'Wig 5 (W/E)',175,3596,0,'e0c');
+INSERT INTO items VALUES(NULL,'Wig 4 (W/E)',175,3594,0,'e0a');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 3',302,1899,0,'76b');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 4',302,1900,0,'76c');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 2',302,1898,0,'76a');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 7',302,1903,0,'76f');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 5',302,1901,0,'76d');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 6',302,1902,0,'76e');
+INSERT INTO items VALUES(NULL,'Wig Stand 2 (W/E)',175,3592,0,'e08');
+INSERT INTO items VALUES(NULL,'Wig 4 (N/S)',175,3593,0,'e09');
+INSERT INTO items VALUES(NULL,'Wig Stand 1 (W/E)',175,3590,0,'e06');
+INSERT INTO items VALUES(NULL,'Wig Stand 2 (N/S)',175,3591,0,'e07');
+INSERT INTO items VALUES(NULL,'Wig 3 (W/E)',175,3588,0,'e04');
+INSERT INTO items VALUES(NULL,'Wig Stand 1 (N/S)',175,3589,0,'e05');
+INSERT INTO items VALUES(NULL,'Wig 2 (W/E)',175,3586,0,'e02');
+INSERT INTO items VALUES(NULL,'Wig 3 (N/S)',175,3587,0,'e03');
+INSERT INTO items VALUES(NULL,'Wig 1 (W/E)',175,3584,0,'e00');
+INSERT INTO items VALUES(NULL,'Wig 2 (N/S)',175,3585,0,'e01');
+INSERT INTO items VALUES(NULL,'Small Wall 3',140,97,0,'61');
+INSERT INTO items VALUES(NULL,'Gold Coin',305,3821,0,'eed');
+INSERT INTO items VALUES(NULL,'Stretched Hide 4 (N/S) (1/2)',57,4221,0,'107d');
+INSERT INTO items VALUES(NULL,'Gold Coins 2',305,3823,0,'eef');
+INSERT INTO items VALUES(NULL,'Copper Coin',305,3818,0,'eea');
+INSERT INTO items VALUES(NULL,'Stretched Hide 3 (N/S)',57,4220,0,'107c');
+INSERT INTO items VALUES(NULL,'Copper Coins 2',305,3820,0,'eec');
+INSERT INTO items VALUES(NULL,'Copper Coins 1',305,3819,0,'eeb');
+INSERT INTO items VALUES(NULL,'Vat w. Vines 2 (6/6)',242,5413,0,'1525');
+INSERT INTO items VALUES(NULL,'Carpet 8',306,2776,0,'ad8');
+INSERT INTO items VALUES(NULL,'Broken Chair 4 (W/E)',247,3101,0,'c1d');
+INSERT INTO items VALUES(NULL,'Shovel (N/S)',80,3898,0,'f3a');
+INSERT INTO items VALUES(NULL,'Horse Dung 1',13,3899,0,'f3b');
+INSERT INTO items VALUES(NULL,'Horse Dung 2',13,3900,0,'f3c');
+INSERT INTO items VALUES(NULL,'chainmail leggings',280,5054,0,'bronze_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Polar Bear',115,8417,0,'20e1');
+INSERT INTO items VALUES(NULL,'Orc',115,8416,0,'20e0');
+INSERT INTO items VALUES(NULL,'Rat Man',115,8419,0,'20e3');
+INSERT INTO items VALUES(NULL,'Rabbit (big)',115,8418,0,'20e2');
+INSERT INTO items VALUES(NULL,'Serpent',115,8421,0,'20e5');
+INSERT INTO items VALUES(NULL,'Scorpion',115,8420,0,'20e4');
+INSERT INTO items VALUES(NULL,'Skeleton',115,8423,0,'20e7');
+INSERT INTO items VALUES(NULL,'Sheep',115,8422,0,'20e6');
+INSERT INTO items VALUES(NULL,'Banister 17',307,2238,0,'8be');
+INSERT INTO items VALUES(NULL,'Banister 16',307,2237,0,'8bd');
+INSERT INTO items VALUES(NULL,'Banister 18',307,2239,0,'8bf');
+INSERT INTO items VALUES(NULL,'Banister 13',307,2234,0,'8ba');
+INSERT INTO items VALUES(NULL,'Banister 15',307,2236,0,'8bc');
+INSERT INTO items VALUES(NULL,'Banister 14',307,2235,0,'8bb');
+INSERT INTO items VALUES(NULL,'Wolf',115,8426,0,'20ea');
+INSERT INTO items VALUES(NULL,'Zombie',115,8428,0,'20ec');
+INSERT INTO items VALUES(NULL,'Wooly Sheep',115,8427,0,'20eb');
+INSERT INTO items VALUES(NULL,'Banister 12',307,2233,0,'8b9');
+INSERT INTO items VALUES(NULL,'Banister 11',307,2232,0,'8b8');
+INSERT INTO items VALUES(NULL,'Bull 1',115,8431,0,'20ef');
+INSERT INTO items VALUES(NULL,'Banister 8',307,2229,0,'8b5');
+INSERT INTO items VALUES(NULL,'Banister 7',307,2228,0,'8b4');
+INSERT INTO items VALUES(NULL,'Banister 10',307,2231,0,'8b7');
+INSERT INTO items VALUES(NULL,'Banister 9',307,2230,0,'8b6');
+INSERT INTO items VALUES(NULL,'Banister 4',307,2225,0,'8b1');
+INSERT INTO items VALUES(NULL,'Banister 3',307,2224,0,'8b0');
+INSERT INTO items VALUES(NULL,'Banister 6',307,2227,0,'8b3');
+INSERT INTO items VALUES(NULL,'Banister 5',307,2226,0,'8b2');
+INSERT INTO items VALUES(NULL,'Diamond 5',308,3888,0,'f30');
+INSERT INTO items VALUES(NULL,'Twig (N/S)',13,3889,0,'f31');
+INSERT INTO items VALUES(NULL,'Twig (W/E)',13,3890,0,'f32');
+INSERT INTO items VALUES(NULL,'Hay 1',13,3892,0,'f34');
+INSERT INTO items VALUES(NULL,'Hay 2',13,3893,0,'f35');
+INSERT INTO items VALUES(NULL,'Sheaf of Hay 1',13,3894,0,'f36');
+INSERT INTO items VALUES(NULL,'Saddle (N/S)',13,3895,0,'f37');
+INSERT INTO items VALUES(NULL,'Saddle (W/E)',13,3896,0,'f38');
+INSERT INTO items VALUES(NULL,'Shovel (W/E)',80,3897,0,'f39');
+INSERT INTO items VALUES(NULL,'Hay 3',45,6804,0,'1a94');
+INSERT INTO items VALUES(NULL,'Roof 4',281,1477,0,'5c5');
+INSERT INTO items VALUES(NULL,'Water 7',309,6051,0,'17a3');
+INSERT INTO items VALUES(NULL,'Water 6',309,6050,0,'17a2');
+INSERT INTO items VALUES(NULL,'Water 5',309,6049,0,'17a1');
+INSERT INTO items VALUES(NULL,'Water 4',309,6048,0,'17a0');
+INSERT INTO items VALUES(NULL,'Water 11',309,6055,0,'17a7');
+INSERT INTO items VALUES(NULL,'Water 10',309,6054,0,'17a6');
+INSERT INTO items VALUES(NULL,'Water 9',309,6053,0,'17a5');
+INSERT INTO items VALUES(NULL,'Water 8',309,6052,0,'17a4');
+INSERT INTO items VALUES(NULL,'Water 13',309,6057,0,'17a9');
+INSERT INTO items VALUES(NULL,'Water 12',309,6056,0,'17a8');
+INSERT INTO items VALUES(NULL,'Vat w. Vines 1 (6/6)',242,5412,0,'1524');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',310,5103,0,'verite_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'String of Shells 5',311,4049,0,'fd1');
+INSERT INTO items VALUES(NULL,'String of Shells 4',311,4048,0,'fd0');
+INSERT INTO items VALUES(NULL,'String of Shells 7',311,4051,0,'fd3');
+INSERT INTO items VALUES(NULL,'String of Shells 6',311,4050,0,'fd2');
+INSERT INTO items VALUES(NULL,'Tapestry 4 (1/2)',304,4053,0,'fd5');
+INSERT INTO items VALUES(NULL,'String of Shells 8',311,4052,0,'fd4');
+INSERT INTO items VALUES(NULL,'Tapestry 5 (1/2)',304,4055,0,'fd7');
+INSERT INTO items VALUES(NULL,'Tapestry 4 (2/2)',304,4054,0,'fd6');
+INSERT INTO items VALUES(NULL,'Tapestry 6 (1/2)',304,4057,0,'fd9');
+INSERT INTO items VALUES(NULL,'Tapestry 5 (2/2)',304,4056,0,'fd8');
+INSERT INTO items VALUES(NULL,'Water 16',309,6060,0,'17ac');
+INSERT INTO items VALUES(NULL,'Water 15',309,6059,0,'17ab');
+INSERT INTO items VALUES(NULL,'Water 14',309,6058,0,'17aa');
+INSERT INTO items VALUES(NULL,'Water 19',309,6063,0,'17af');
+INSERT INTO items VALUES(NULL,'Water 18',309,6062,0,'17ae');
+INSERT INTO items VALUES(NULL,'Water 17',309,6061,0,'17ad');
+INSERT INTO items VALUES(NULL,'Tapestry 6 (2/2)',304,4058,0,'fda');
+INSERT INTO items VALUES(NULL,'Tapestry 7 (2/2)',304,4060,0,'fdc');
+INSERT INTO items VALUES(NULL,'Tapestry 7 (1/2)',304,4059,0,'fdb');
+INSERT INTO items VALUES(NULL,'Tapestry 8 (2/2)',304,4062,0,'fde');
+INSERT INTO items VALUES(NULL,'Tapestry 8 (1/2)',304,4061,0,'fdd');
+INSERT INTO items VALUES(NULL,'Tapestry 9 (1/2)',304,4063,0,'fdf');
+INSERT INTO items VALUES(NULL,'Spam',114,4164,0,'1044');
+INSERT INTO items VALUES(NULL,'Silver Coins 2',305,3826,0,'ef2');
+INSERT INTO items VALUES(NULL,'Empty Scroll (N/S)',186,3827,0,'ef3');
+INSERT INTO items VALUES(NULL,'Fishing Net 1',148,3528,0,'dc8');
+INSERT INTO items VALUES(NULL,'Fishing Net 2',148,3529,0,'dc9');
+INSERT INTO items VALUES(NULL,'Scroll 2 (N/S)',186,3829,0,'ef5');
+INSERT INTO items VALUES(NULL,'Ruined Bed 2 (N/S) (1/4)',247,6296,0,'1898');
+INSERT INTO items VALUES(NULL,'Ruined Bed 2 (N/S) (2/4)',247,6297,0,'1899');
+INSERT INTO items VALUES(NULL,'Ruined Bed 2 (W/E) (1/4)',247,6292,0,'1894');
+INSERT INTO items VALUES(NULL,'Ruined Bed 2 (W/E) (2/4)',247,6293,0,'1895');
+INSERT INTO items VALUES(NULL,'Ruined Bed 2 (W/E) (3/4)',247,6294,0,'1896');
+INSERT INTO items VALUES(NULL,'Ruined Bed 2 (W/E) (4/4)',247,6295,0,'1897');
+INSERT INTO items VALUES(NULL,'Frenzied Ostard',115,8502,0,'2136');
+INSERT INTO items VALUES(NULL,'Forest Ostard',115,8503,0,'2137');
+INSERT INTO items VALUES(NULL,'Ophidian Queen',115,8500,0,'2134');
+INSERT INTO items VALUES(NULL,'Desert Ostard',115,8501,0,'2135');
+INSERT INTO items VALUES(NULL,'Ophidian Mage',115,8498,0,'2132');
+INSERT INTO items VALUES(NULL,'Ophidian Warrior',115,8499,0,'2133');
+INSERT INTO items VALUES(NULL,'Bullfrog',115,8496,0,'2130');
+INSERT INTO items VALUES(NULL,'Lizard',115,8497,0,'2131');
+INSERT INTO items VALUES(NULL,'Pile of Skulls 4',12,6875,0,'1adb');
+INSERT INTO items VALUES(NULL,'Pile of Skulls 5',12,6876,0,'1adc');
+INSERT INTO items VALUES(NULL,'Pile of Skulls 3',12,6874,0,'1ada');
+INSERT INTO items VALUES(NULL,'Pile of Skulls 8',12,6879,0,'1adf');
+INSERT INTO items VALUES(NULL,'Pile of Skulls 6',12,6877,0,'1add');
+INSERT INTO items VALUES(NULL,'Pile of Skulls 7',12,6878,0,'1ade');
+INSERT INTO items VALUES(NULL,'Balista 1',76,6303,0,'189f');
+INSERT INTO items VALUES(NULL,'Ruined Bed 2 (N/S) (3/4)',247,6298,0,'189a');
+INSERT INTO items VALUES(NULL,'Ruined Bed 2 (N/S) (4/4)',247,6299,0,'189b');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 4',4,4801,0,'12c1');
+INSERT INTO items VALUES(NULL,'Donuts',19,6867,0,'1ad3');
+INSERT INTO items VALUES(NULL,'Lighthouse (29/29)',46,6864,0,'1ad0');
+INSERT INTO items VALUES(NULL,'Window 1',158,14,0,'e');
+INSERT INTO items VALUES(NULL,'Keg (W/E)',249,6871,0,'1ad7');
+INSERT INTO items VALUES(NULL,'Nest with Eggs',312,6868,0,'1ad4');
+INSERT INTO items VALUES(NULL,'Nest',312,6869,0,'1ad5');
+INSERT INTO items VALUES(NULL,'Pile of Skulls 1',12,6872,0,'1ad8');
+INSERT INTO items VALUES(NULL,'Pile of Skulls 2',12,6873,0,'1ad9');
+INSERT INTO items VALUES(NULL,'Stars 1',313,8511,0,'213f');
+INSERT INTO items VALUES(NULL,'Oak Tree 2 Leaves 1',4,3294,0,'cde');
+INSERT INTO items VALUES(NULL,'Oak Tree 2 Leaves 2',4,3295,0,'cdf');
+INSERT INTO items VALUES(NULL,'Water 7',314,6044,0,'179c');
+INSERT INTO items VALUES(NULL,'Water 6',314,6043,0,'179b');
+INSERT INTO items VALUES(NULL,'Water 5',314,6042,0,'179a');
+INSERT INTO items VALUES(NULL,'Water 3',309,6047,0,'179f');
+INSERT INTO items VALUES(NULL,'Water 2',309,6046,0,'179e');
+INSERT INTO items VALUES(NULL,'Water 1',309,6045,0,'179d');
+INSERT INTO items VALUES(NULL,'Oak Tree 1 Leaves 2',4,3292,0,'cdc');
+INSERT INTO items VALUES(NULL,'Roof 14',297,1639,0,'667');
+INSERT INTO items VALUES(NULL,'Shackles 1',113,4706,0,'1262');
+INSERT INTO items VALUES(NULL,'Smaller Wall 2',140,100,0,'64');
+INSERT INTO items VALUES(NULL,'Guillotine 8',113,4705,0,'1261');
+INSERT INTO items VALUES(NULL,'Water 4',314,6041,0,'1799');
+INSERT INTO items VALUES(NULL,'Water 3',314,6040,0,'1798');
+INSERT INTO items VALUES(NULL,'Roof 10',297,1635,0,'663');
+INSERT INTO items VALUES(NULL,'Water 2',314,6039,0,'1797');
+INSERT INTO items VALUES(NULL,'Water 1',314,6038,0,'1796');
+INSERT INTO items VALUES(NULL,'Roof 9',297,1634,0,'662');
+INSERT INTO items VALUES(NULL,'Wall Carving 7 (1/3)',53,4709,0,'1265');
+INSERT INTO items VALUES(NULL,'Fireball (small)',28,14052,0,'36e4');
+INSERT INTO items VALUES(NULL,'Panther (3d)',115,9653,0,'25b5');
+INSERT INTO items VALUES(NULL,'Frenzied Ostard (3d)',115,9652,0,'25b4');
+INSERT INTO items VALUES(NULL,'Rat Man (3d)',115,9655,0,'25b7');
+INSERT INTO items VALUES(NULL,'Pixie',115,9654,0,'25b6');
+INSERT INTO items VALUES(NULL,'Orc Shaman',115,9649,0,'25b1');
+INSERT INTO items VALUES(NULL,'Orc Lord',115,9648,0,'25b0');
+INSERT INTO items VALUES(NULL,'Forest Ostard (3d)',115,9651,0,'25b3');
+INSERT INTO items VALUES(NULL,'Desert Ostard (3d)',115,9650,0,'25b2');
+INSERT INTO items VALUES(NULL,'Giant Scorpion',115,9657,0,'25b9');
+INSERT INTO items VALUES(NULL,'Rotting Corpse',115,9656,0,'25b8');
+INSERT INTO items VALUES(NULL,'Roof 3',297,1610,0,'64a');
+INSERT INTO items VALUES(NULL,'Bandana (N/S)',58,5439,0,'153f');
+INSERT INTO items VALUES(NULL,'Roof 25',152,1612,0,'64c');
+INSERT INTO items VALUES(NULL,'Roof 4',297,1611,0,'64b');
+INSERT INTO items VALUES(NULL,'Roof 27',152,1614,0,'64e');
+INSERT INTO items VALUES(NULL,'Roof 26',152,1613,0,'64d');
+INSERT INTO items VALUES(NULL,'Long Pants (W/E)',315,5434,0,'153a');
+INSERT INTO items VALUES(NULL,'Roof 25',32,1615,0,'64f');
+INSERT INTO items VALUES(NULL,'Bowl of Carrots 2',19,5630,0,'15fe');
+INSERT INTO items VALUES(NULL,'Statue 2 (N/S) (2/3)',54,4770,0,'12a2');
+INSERT INTO items VALUES(NULL,'Statue 2 (N/S) (3/3)',54,4771,0,'12a3');
+INSERT INTO items VALUES(NULL,'Statue 1 (N/S) (3/3)',54,4768,0,'12a0');
+INSERT INTO items VALUES(NULL,'Statue 1 (N/S) (1/3)',54,4769,0,'12a1');
+INSERT INTO items VALUES(NULL,'Tarot 2',293,4774,0,'12a6');
+INSERT INTO items VALUES(NULL,'Tarot 3',293,4775,0,'12a7');
+INSERT INTO items VALUES(NULL,'Statue 2 (N/S) (1/3)',54,4772,0,'12a4');
+INSERT INTO items VALUES(NULL,'Tarot 1',293,4773,0,'12a5');
+INSERT INTO items VALUES(NULL,'Tarot 4',293,4776,0,'12a8');
+INSERT INTO items VALUES(NULL,'Tarot 5',293,4777,0,'12a9');
+INSERT INTO items VALUES(NULL,'Skeleton Mage',115,9662,0,'25be');
+INSERT INTO items VALUES(NULL,'Ogre',115,8415,0,'20df');
+INSERT INTO items VALUES(NULL,'Giant Snake',115,9663,0,'25bf');
+INSERT INTO items VALUES(NULL,'Sea Horse',115,9658,0,'25ba');
+INSERT INTO items VALUES(NULL,'Skeleton (3d)',115,9660,0,'25bc');
+INSERT INTO items VALUES(NULL,'Nameless One',115,9659,0,'25bb');
+INSERT INTO items VALUES(NULL,'Fishing Weight 1',148,3531,0,'dcb');
+INSERT INTO items VALUES(NULL,'Horse',115,8413,0,'20dd');
+INSERT INTO items VALUES(NULL,'Fishing Weight 2',148,3532,0,'dcc');
+INSERT INTO items VALUES(NULL,'Harpy',115,8412,0,'20dc');
+INSERT INTO items VALUES(NULL,'Tarot 7',293,4779,0,'12ab');
+INSERT INTO items VALUES(NULL,'Tarot 8',293,4780,0,'12ac');
+INSERT INTO items VALUES(NULL,'Tarot 6',293,4778,0,'12aa');
+INSERT INTO items VALUES(NULL,'Statue 3 (3/3)',54,4783,0,'12af');
+INSERT INTO items VALUES(NULL,'Statue 3 (2/3)',54,4782,0,'12ae');
+INSERT INTO items VALUES(NULL,'Crocodile',115,8410,0,'20da');
+INSERT INTO items VALUES(NULL,'Wall Carving 4 (W/E) (1/2)',53,4673,0,'1241');
+INSERT INTO items VALUES(NULL,'Gold Belt (N/S)',60,5430,0,'1536');
+INSERT INTO items VALUES(NULL,'Wall Carving 6 (W/E)',53,4675,0,'1243');
+INSERT INTO items VALUES(NULL,'Wall Carving 4 (W/E) (2/2)',53,4674,0,'1242');
+INSERT INTO items VALUES(NULL,'Guillotine 2',113,4677,0,'1245');
+INSERT INTO items VALUES(NULL,'Wall Carving 6 (N/S)',53,4676,0,'1244');
+INSERT INTO items VALUES(NULL,'Skirt (W/E)',315,5425,0,'1531');
+INSERT INTO items VALUES(NULL,'Cloak (W/E)',60,5424,0,'1530');
+INSERT INTO items VALUES(NULL,'Roof 2',297,1609,0,'649');
+INSERT INTO items VALUES(NULL,'Iron Maiden 1',113,4680,0,'1248');
+INSERT INTO items VALUES(NULL,'Long Pants (N/S)',315,5433,0,'1539');
+INSERT INTO items VALUES(NULL,'Kilt (W/E)',315,5432,0,'1538');
+INSERT INTO items VALUES(NULL,'Banner 36 (W/E)',128,5590,0,'15d6');
+INSERT INTO items VALUES(NULL,'Banner 36 (N/S)',128,5591,0,'15d7');
+INSERT INTO items VALUES(NULL,'Banner 35 (W/E)',128,5588,0,'15d4');
+INSERT INTO items VALUES(NULL,'Banner 35 (N/S)',128,5589,0,'15d5');
+INSERT INTO items VALUES(NULL,'Banner 34 (W/E)',128,5586,0,'15d2');
+INSERT INTO items VALUES(NULL,'Banner 34 (N/S)',128,5587,0,'15d3');
+INSERT INTO items VALUES(NULL,'Banner 33 (W/E)',128,5584,0,'15d0');
+INSERT INTO items VALUES(NULL,'Banner 33 (N/S)',128,5585,0,'15d1');
+INSERT INTO items VALUES(NULL,'Banner 37 (W/E)',128,5592,0,'15d8');
+INSERT INTO items VALUES(NULL,'Banner 37 (N/S)',128,5593,0,'15d9');
+INSERT INTO items VALUES(NULL,'Small Palm 4',264,3228,0,'c9c');
+INSERT INTO items VALUES(NULL,'Waterfall 1',23,13525,0,'34d5');
+INSERT INTO items VALUES(NULL,'Banner 40 (N/S)',128,5599,0,'15df');
+INSERT INTO items VALUES(NULL,'Banner 39 (N/S)',128,5597,0,'15dd');
+INSERT INTO items VALUES(NULL,'Banner 40 (W/E)',128,5598,0,'15de');
+INSERT INTO items VALUES(NULL,'Banner 38 (N/S)',128,5595,0,'15db');
+INSERT INTO items VALUES(NULL,'Banner 39 (W/E)',128,5596,0,'15dc');
+INSERT INTO items VALUES(NULL,'Banner 38 (W/E)',128,5594,0,'15da');
+INSERT INTO items VALUES(NULL,'Wall 2',277,333,0,'14d');
+INSERT INTO items VALUES(NULL,'Wall 3',277,334,0,'14e');
+INSERT INTO items VALUES(NULL,'Edge 2',316,331,0,'14b');
+INSERT INTO items VALUES(NULL,'Small Palm 2',264,3226,0,'c9a');
+INSERT INTO items VALUES(NULL,'Wall 1',277,332,0,'14c');
+INSERT INTO items VALUES(NULL,'Roof 6',281,1479,0,'5c7');
+INSERT INTO items VALUES(NULL,'Roof 5',281,1478,0,'5c6');
+INSERT INTO items VALUES(NULL,'Spilled Dirt 4',202,7680,0,'1e00');
+INSERT INTO items VALUES(NULL,'Roof 3',281,1476,0,'5c4');
+INSERT INTO items VALUES(NULL,'Roof 2',281,1475,0,'5c3');
+INSERT INTO items VALUES(NULL,'Roof 1',281,1474,0,'5c2');
+INSERT INTO items VALUES(NULL,'Roof 15',231,1473,0,'5c1');
+INSERT INTO items VALUES(NULL,'Roof 14',231,1472,0,'5c0');
+INSERT INTO items VALUES(NULL,'Stain 2',202,7688,0,'1e08');
+INSERT INTO items VALUES(NULL,'Stain 3',202,7689,0,'1e09');
+INSERT INTO items VALUES(NULL,'Roof 8',281,1481,0,'5c9');
+INSERT INTO items VALUES(NULL,'Roof 7',281,1480,0,'5c8');
+INSERT INTO items VALUES(NULL,'Wall 8',96,567,0,'237');
+INSERT INTO items VALUES(NULL,'Stain 5',202,7691,0,'1e0b');
+INSERT INTO items VALUES(NULL,'Roof 14',281,1487,0,'5cf');
+INSERT INTO items VALUES(NULL,'Roof 13',281,1486,0,'5ce');
+INSERT INTO items VALUES(NULL,'Stain 4',202,7690,0,'1e0a');
+INSERT INTO items VALUES(NULL,'Roof 11',281,1484,0,'5cc');
+INSERT INTO items VALUES(NULL,'Roof 10',281,1483,0,'5cb');
+INSERT INTO items VALUES(NULL,'Roof 9',281,1482,0,'5ca');
+INSERT INTO items VALUES(NULL,'Stain 8',202,7694,0,'1e0e');
+INSERT INTO items VALUES(NULL,'Yellow Potion',180,3852,0,'potion_greaterheal');
+INSERT INTO items VALUES(NULL,'Wheat Sprout 1',213,7870,0,'1ebe');
+INSERT INTO items VALUES(NULL,'Cedar Needles 1',4,3287,0,'cd7');
+INSERT INTO items VALUES(NULL,'kite shield',69,7028,0,'golden_shields_kite');
+INSERT INTO items VALUES(NULL,'Smaller Wall 5',140,103,0,'67');
+INSERT INTO items VALUES(NULL,'Tree (brown) Leaves 1',4,3281,0,'cd1');
+INSERT INTO items VALUES(NULL,'Spiderweb 2 (2/5)',303,4286,0,'10be');
+INSERT INTO items VALUES(NULL,'Spiderweb 2 (1/5)',303,4285,0,'10bd');
+INSERT INTO items VALUES(NULL,'Spiderweb 2 (3/5)',303,4287,0,'10bf');
+INSERT INTO items VALUES(NULL,'Spiderweb 1 (3/5)',303,4282,0,'10ba');
+INSERT INTO items VALUES(NULL,'Spiderweb 1 (5/5)',303,4284,0,'10bc');
+INSERT INTO items VALUES(NULL,'Spiderweb 1 (4/5)',303,4283,0,'10bb');
+INSERT INTO items VALUES(NULL,'Small Palm 5',264,3229,0,'c9d');
+INSERT INTO items VALUES(NULL,'Roof 22',297,1647,0,'66f');
+INSERT INTO items VALUES(NULL,'Wall 11',317,744,0,'2e8');
+INSERT INTO items VALUES(NULL,'Wall 12',317,745,0,'2e9');
+INSERT INTO items VALUES(NULL,'Wall 5',317,738,0,'2e2');
+INSERT INTO items VALUES(NULL,'Wall 6',317,739,0,'2e3');
+INSERT INTO items VALUES(NULL,'Wall 3',317,736,0,'2e0');
+INSERT INTO items VALUES(NULL,'Wall 4',317,737,0,'2e1');
+INSERT INTO items VALUES(NULL,'Wall 9',317,742,0,'2e6');
+INSERT INTO items VALUES(NULL,'Wall 10',317,743,0,'2e7');
+INSERT INTO items VALUES(NULL,'Wall 7',317,740,0,'2e4');
+INSERT INTO items VALUES(NULL,'Wall 8',317,741,0,'2e5');
+INSERT INTO items VALUES(NULL,'Roof 17',297,1642,0,'66a');
+INSERT INTO items VALUES(NULL,'Hanging Pole (N/S) (3/3)',318,4273,0,'10b1');
+INSERT INTO items VALUES(NULL,'Hanging Pole (N/S) (2/3)',318,4272,0,'10b0');
+INSERT INTO items VALUES(NULL,'Spiderweb 1 (2/5)',303,4281,0,'10b9');
+INSERT INTO items VALUES(NULL,'Lava 60',44,13664,0,'3560');
+INSERT INTO items VALUES(NULL,'Lava 61',44,13665,0,'3561');
+INSERT INTO items VALUES(NULL,'Wall 14',317,747,0,'2eb');
+INSERT INTO items VALUES(NULL,'Wall 5',317,748,0,'2ec');
+INSERT INTO items VALUES(NULL,'Wall 13',317,746,0,'2ea');
+INSERT INTO items VALUES(NULL,'Patch 1',317,751,0,'2ef');
+INSERT INTO items VALUES(NULL,'Post 2',22,326,0,'146');
+INSERT INTO items VALUES(NULL,'Marble Stairs 1',319,1801,0,'709');
+INSERT INTO items VALUES(NULL,'Post 3',22,327,0,'147');
+INSERT INTO items VALUES(NULL,'Roof 19',231,1792,0,'700');
+INSERT INTO items VALUES(NULL,'Wooden Beam 4',316,324,0,'144');
+INSERT INTO items VALUES(NULL,'Dress Form (W/E)',57,3783,0,'ec7');
+INSERT INTO items VALUES(NULL,'Dress Form (N/S)',57,3782,0,'ec6');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (W/E) (4/5)',89,2931,0,'b73');
+INSERT INTO items VALUES(NULL,'cleaver',3,3779,0,'ec3');
+INSERT INTO items VALUES(NULL,'Music Sheet 4',320,3776,0,'ec0');
+INSERT INTO items VALUES(NULL,'Wooden Beam 2',316,322,0,'142');
+INSERT INTO items VALUES(NULL,'ringmail gloves',56,5099,0,'merkite_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Painting 12',304,3785,0,'ec9');
+INSERT INTO items VALUES(NULL,'Wooden Beam 3',316,323,0,'143');
+INSERT INTO items VALUES(NULL,'Dragon',115,8406,0,'20d6');
+INSERT INTO items VALUES(NULL,'Arch 5',316,320,0,'140');
+INSERT INTO items VALUES(NULL,'Earth Elemental',115,8407,0,'20d7');
+INSERT INTO items VALUES(NULL,'Wooden Beam 1',316,321,0,'141');
+INSERT INTO items VALUES(NULL,'Deer',115,8404,0,'20d4');
+INSERT INTO items VALUES(NULL,'Yellow Potion',180,3852,0,'potion_lesserheal');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 3',26,2019,0,'7e3');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 2',26,2018,0,'7e2');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 1',26,2017,0,'7e1');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 19',121,2016,0,'7e0');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 7',26,2023,0,'7e7');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 6',26,2022,0,'7e6');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 5',26,2021,0,'7e5');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 4',26,2020,0,'7e4');
+INSERT INTO items VALUES(NULL,'Corpser',115,8402,0,'20d2');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 9',26,2025,0,'7e9');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 8',26,2024,0,'7e8');
+INSERT INTO items VALUES(NULL,'Demon',115,8403,0,'20d3');
+INSERT INTO items VALUES(NULL,'Bones 6',12,3791,0,'ecf');
+INSERT INTO items VALUES(NULL,'Bones 5',12,3790,0,'ece');
+INSERT INTO items VALUES(NULL,'Bones 4',12,3789,0,'ecd');
+INSERT INTO items VALUES(NULL,'Bones 3',12,3788,0,'ecc');
+INSERT INTO items VALUES(NULL,'Bones 2',12,3787,0,'ecb');
+INSERT INTO items VALUES(NULL,'Bones 1',12,3786,0,'eca');
+INSERT INTO items VALUES(NULL,'Swamp 8',236,12821,0,'3215');
+INSERT INTO items VALUES(NULL,'Chicken',115,8401,0,'20d1');
+INSERT INTO items VALUES(NULL,'Swamp 9',236,12822,0,'3216');
+INSERT INTO items VALUES(NULL,'Swamp 10',236,12823,0,'3217');
+INSERT INTO items VALUES(NULL,'Marble Stairs 5',319,1805,0,'70d');
+INSERT INTO items VALUES(NULL,'Marble Stairs 6',319,1806,0,'70e');
+INSERT INTO items VALUES(NULL,'Marble Stairs 7',319,1807,0,'70f');
+INSERT INTO items VALUES(NULL,'Marble Stairs 2',319,1802,0,'70a');
+INSERT INTO items VALUES(NULL,'Marble Stairs 3',319,1803,0,'70b');
+INSERT INTO items VALUES(NULL,'Marble Stairs 4',319,1804,0,'70c');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 12',26,2028,0,'7ec');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 11',26,2027,0,'7eb');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 10',26,2026,0,'7ea');
+INSERT INTO items VALUES(NULL,'Checkers 2',249,3611,0,'e1b');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 15',26,2031,0,'7ef');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 14',26,2030,0,'7ee');
+INSERT INTO items VALUES(NULL,'Bridge (N/S) 13',26,2029,0,'7ed');
+INSERT INTO items VALUES(NULL,'Swamp 6',236,12819,0,'3213');
+INSERT INTO items VALUES(NULL,'Ball of Yarn 1',57,3613,0,'e1d');
+INSERT INTO items VALUES(NULL,'Guillotine 7',113,4704,0,'1260');
+INSERT INTO items VALUES(NULL,'Ball of Yarn 3',57,3615,0,'e1f');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 2 (N/S) (2/2)',103,2271,0,'8df');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 2 (N/S) (1/2)',103,2270,0,'8de');
+INSERT INTO items VALUES(NULL,'Stone Chimney 2 (N/S) (2/2)',321,2269,0,'8dd');
+INSERT INTO items VALUES(NULL,'Stone Chimney 2 (N/S) (1/2)',321,2268,0,'8dc');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 2 (W/E) (2/2)',103,2267,0,'8db');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 2 (W/E) (1/2)',103,2266,0,'8da');
+INSERT INTO items VALUES(NULL,'Window 2',170,662,0,'296');
+INSERT INTO items VALUES(NULL,'order shield',15,7108,0,'1bc4');
+INSERT INTO items VALUES(NULL,'Stone Trigger 2',75,7104,0,'1bc0');
+INSERT INTO items VALUES(NULL,'Stone Trigger 3',75,7105,0,'1bc1');
+INSERT INTO items VALUES(NULL,'order shield',15,7107,0,'1bc3');
+INSERT INTO items VALUES(NULL,'Star Sapphire 2',308,3867,0,'f1b');
+INSERT INTO items VALUES(NULL,'Ruby 4',308,3868,0,'f1c');
+INSERT INTO items VALUES(NULL,'Ruby 3',308,3866,0,'f1a');
+INSERT INTO items VALUES(NULL,'Sapphire 4',308,3871,0,'f1f');
+INSERT INTO items VALUES(NULL,'Ruby 5',308,3869,0,'f1d');
+INSERT INTO items VALUES(NULL,'Tourmaline 2',308,3870,0,'f1e');
+INSERT INTO items VALUES(NULL,'Mages'' Guild (W/E)',229,3048,0,'be8');
+INSERT INTO items VALUES(NULL,'Sorcerers'' Guild (N/S)',229,3049,0,'be9');
+INSERT INTO items VALUES(NULL,'Wall 1',211,663,0,'297');
+INSERT INTO items VALUES(NULL,'Traders'' Guild (W/E)',229,3042,0,'be2');
+INSERT INTO items VALUES(NULL,'Cooks'' Guild (N/S)',229,3043,0,'be3');
+INSERT INTO items VALUES(NULL,'Provisioners Guild (W/E)',229,3040,0,'be0');
+INSERT INTO items VALUES(NULL,'Traders'' Guild (N/S)',229,3041,0,'be1');
+INSERT INTO items VALUES(NULL,'Healers'' Guild (W/E)',229,3046,0,'be6');
+INSERT INTO items VALUES(NULL,'Mages'' Guild (N/S)',229,3047,0,'be7');
+INSERT INTO items VALUES(NULL,'Cooks'' Guild (W/E)',229,3044,0,'be4');
+INSERT INTO items VALUES(NULL,'Healers'' Guild (N/S)',229,3045,0,'be5');
+INSERT INTO items VALUES(NULL,'Waterfall 12',23,13559,0,'34f7');
+INSERT INTO items VALUES(NULL,'Stone Chimney 1 (W/E) (2/2)',321,2262,0,'8d6');
+INSERT INTO items VALUES(NULL,'Stone Chimney 1 (W/E) (1/2)',321,2261,0,'8d5');
+INSERT INTO items VALUES(NULL,'Waterfall 9',23,13556,0,'34f4');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 1 (N/S) (1/2)',103,2259,0,'8d3');
+INSERT INTO items VALUES(NULL,'Stone Chimney 1 (N/S) (2/2)',321,2258,0,'8d2');
+INSERT INTO items VALUES(NULL,'Stone Chimney 1 (N/S) (1/2)',321,2257,0,'8d1');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 1 (W/E) (2/2)',103,2256,0,'8d0');
+INSERT INTO items VALUES(NULL,'Stone Chimney 2 (W/E) (2/2)',321,2265,0,'8d9');
+INSERT INTO items VALUES(NULL,'Stone Chimney 2 (W/E) (1/2)',321,2264,0,'8d8');
+INSERT INTO items VALUES(NULL,'Cards 5',249,3609,0,'e19');
+INSERT INTO items VALUES(NULL,'Illusionists'' Guild (N/S)',229,3051,0,'beb');
+INSERT INTO items VALUES(NULL,'Illusionists'' Guild (W/E)',229,3052,0,'bec');
+INSERT INTO items VALUES(NULL,'Sorcerers'' Guild (W/E)',229,3050,0,'bea');
+INSERT INTO items VALUES(NULL,'Archers Guild (N/S)',229,3055,0,'bef');
+INSERT INTO items VALUES(NULL,'Miners'' Guild (N/S)',229,3053,0,'bed');
+INSERT INTO items VALUES(NULL,'Miners'' Guild (W/E)',229,3054,0,'bee');
+INSERT INTO items VALUES(NULL,'Tourmaline 1',308,3864,0,'f18');
+INSERT INTO items VALUES(NULL,'Sapphire 3',308,3865,0,'f19');
+INSERT INTO items VALUES(NULL,'Sapphire 2',308,3858,0,'f12');
+INSERT INTO items VALUES(NULL,'Ruby 1',308,3859,0,'f13');
+INSERT INTO items VALUES(NULL,'Emerald 1',308,3856,0,'f10');
+INSERT INTO items VALUES(NULL,'Sapphire 1',308,3857,0,'f11');
+INSERT INTO items VALUES(NULL,'Amethyst 1',308,3862,0,'f16');
+INSERT INTO items VALUES(NULL,'Amethyst 2',308,3863,0,'f17');
+INSERT INTO items VALUES(NULL,'Ruby 2',308,3860,0,'f14');
+INSERT INTO items VALUES(NULL,'Citrine 1',308,3861,0,'f15');
+INSERT INTO items VALUES(NULL,'Cards 4',249,3608,0,'e18');
+INSERT INTO items VALUES(NULL,'ringmail leggings',255,5104,0,'iron_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'Snow 9',322,6089,0,'17c9');
+INSERT INTO items VALUES(NULL,'Snow 8',322,6088,0,'17c8');
+INSERT INTO items VALUES(NULL,'Snow 1',322,6081,0,'17c1');
+INSERT INTO items VALUES(NULL,'Snow 4',323,6080,0,'17c0');
+INSERT INTO items VALUES(NULL,'Snow 3',322,6083,0,'17c3');
+INSERT INTO items VALUES(NULL,'Snow 2',322,6082,0,'17c2');
+INSERT INTO items VALUES(NULL,'Snow 5',322,6085,0,'17c5');
+INSERT INTO items VALUES(NULL,'Snow 4',322,6084,0,'17c4');
+INSERT INTO items VALUES(NULL,'Snow 7',322,6087,0,'17c7');
+INSERT INTO items VALUES(NULL,'Snow 6',322,6086,0,'17c6');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (1/15)',324,9020,0,'233c');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (2/15)',324,9021,0,'233d');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (3/15)',324,9022,0,'233e');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (4/15)',324,9023,0,'233f');
+INSERT INTO items VALUES(NULL,'Snow 10',322,6090,0,'17ca');
+INSERT INTO items VALUES(NULL,'Snow 12',322,6092,0,'17cc');
+INSERT INTO items VALUES(NULL,'Snow 11',322,6091,0,'17cb');
+INSERT INTO items VALUES(NULL,'Snow 6',323,6094,0,'17ce');
+INSERT INTO items VALUES(NULL,'Snow 5',323,6093,0,'17cd');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (1/9)',108,6095,0,'17cf');
+INSERT INTO items VALUES(NULL,'Wall 4',316,298,0,'12a');
+INSERT INTO items VALUES(NULL,'Wall 5',316,299,0,'12b');
+INSERT INTO items VALUES(NULL,'Wall 6',316,300,0,'12c');
+INSERT INTO items VALUES(NULL,'Wall 7',316,301,0,'12d');
+INSERT INTO items VALUES(NULL,'Wall 8',316,302,0,'12e');
+INSERT INTO items VALUES(NULL,'Wall 9',316,303,0,'12f');
+INSERT INTO items VALUES(NULL,'Rope (W/E)',325,10000,0,'2710');
+INSERT INTO items VALUES(NULL,'Rope (N/S)',325,10001,0,'2711');
+INSERT INTO items VALUES(NULL,'nose helmet',64,5134,0,'golden_helmets_nose');
+INSERT INTO items VALUES(NULL,'Tourmaline 3',308,3872,0,'f20');
+INSERT INTO items VALUES(NULL,'Lighthouse (15/29)',46,6842,0,'1aba');
+INSERT INTO items VALUES(NULL,'Lighthouse (16/29)',46,6843,0,'1abb');
+INSERT INTO items VALUES(NULL,'Lighthouse (17/29)',46,6844,0,'1abc');
+INSERT INTO items VALUES(NULL,'Lighthouse (18/29)',46,6845,0,'1abd');
+INSERT INTO items VALUES(NULL,'Lighthouse (19/29)',46,6846,0,'1abe');
+INSERT INTO items VALUES(NULL,'Column 3',326,288,0,'120');
+INSERT INTO items VALUES(NULL,'Arch 6',326,289,0,'121');
+INSERT INTO items VALUES(NULL,'Arch 7',326,290,0,'122');
+INSERT INTO items VALUES(NULL,'Arch 8',326,291,0,'123');
+INSERT INTO items VALUES(NULL,'Arch 9',326,292,0,'124');
+INSERT INTO items VALUES(NULL,'Edge 1',326,293,0,'125');
+INSERT INTO items VALUES(NULL,'Edge 2',326,294,0,'126');
+INSERT INTO items VALUES(NULL,'Wall 1',316,295,0,'127');
+INSERT INTO items VALUES(NULL,'Wall 2',316,296,0,'128');
+INSERT INTO items VALUES(NULL,'Wall 3',316,297,0,'129');
+INSERT INTO items VALUES(NULL,'Lighthouse (14/29)',46,6841,0,'1ab9');
+INSERT INTO items VALUES(NULL,'Lighthouse (11/29)',46,6832,0,'1ab0');
+INSERT INTO items VALUES(NULL,'Lighthouse (12/29)',46,6835,0,'1ab3');
+INSERT INTO items VALUES(NULL,'Lighthouse (13/29)',46,6838,0,'1ab6');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (13/16) (Not Animated)',104,6633,0,'19e9');
+INSERT INTO items VALUES(NULL,'Pillow 13',91,5690,0,'163a');
+INSERT INTO items VALUES(NULL,'Forge (N/S) (3/3)',30,6542,0,'198e');
+INSERT INTO items VALUES(NULL,'Roof 11',327,1454,0,'5ae');
+INSERT INTO items VALUES(NULL,'Forge (N/S) (2/3)',30,6538,0,'198a');
+INSERT INTO items VALUES(NULL,'Small Fish 2',148,3543,0,'dd7');
+INSERT INTO items VALUES(NULL,'Timber Wolf',115,9683,0,'25d3');
+INSERT INTO items VALUES(NULL,'Silver Wolf',115,9682,0,'25d2');
+INSERT INTO items VALUES(NULL,'Gray Wolf',115,9681,0,'25d1');
+INSERT INTO items VALUES(NULL,'Dire Wolf',115,9680,0,'25d0');
+INSERT INTO items VALUES(NULL,'Air Elemental (3d)',115,9687,0,'25d7');
+INSERT INTO items VALUES(NULL,'Acid Elemental',115,9686,0,'25d6');
+INSERT INTO items VALUES(NULL,'Zombie (3d)',115,9685,0,'25d5');
+INSERT INTO items VALUES(NULL,'Wyvern',115,9684,0,'25d4');
+INSERT INTO items VALUES(NULL,'Fire Elemental (3d)',115,9689,0,'25d9');
+INSERT INTO items VALUES(NULL,'Blood Elemental',115,9688,0,'25d8');
+INSERT INTO items VALUES(NULL,'Platform 3',101,1983,0,'7bf');
+INSERT INTO items VALUES(NULL,'Vat w. Vines (1/6)',242,5406,0,'151e');
+INSERT INTO items VALUES(NULL,'Decorative Armor 2 (N/S)',328,5405,0,'151d');
+INSERT INTO items VALUES(NULL,'Vat w. Vines 1 (2/6)',242,5407,0,'151f');
+INSERT INTO items VALUES(NULL,'Decorative Armor 3 (N/S)',328,5402,0,'151a');
+INSERT INTO items VALUES(NULL,'Decorative Armor 1 (N/S)',328,5404,0,'151c');
+INSERT INTO items VALUES(NULL,'Decorative Armor 4 (N/S)',328,5403,0,'151b');
+INSERT INTO items VALUES(NULL,'Platform 2',101,1982,0,'7be');
+INSERT INTO items VALUES(NULL,'Carpeted Rostrum 2',102,1979,0,'7bb');
+INSERT INTO items VALUES(NULL,'Snow Elemental',115,9692,0,'25dc');
+INSERT INTO items VALUES(NULL,'Poison Elemental (3d)',115,9691,0,'25db');
+INSERT INTO items VALUES(NULL,'Ice Elemental (3d)',115,9690,0,'25da');
+INSERT INTO items VALUES(NULL,'Water Elemental',115,9693,0,'25dd');
+INSERT INTO items VALUES(NULL,'Carpeted Rostrum 1',102,1978,0,'7ba');
+INSERT INTO items VALUES(NULL,'Ruby 6',308,3882,0,'f2a');
+INSERT INTO items VALUES(NULL,'Balista 226',76,16333,0,'3fcd');
+INSERT INTO items VALUES(NULL,'Balista 227',76,16334,0,'3fce');
+INSERT INTO items VALUES(NULL,'Balista 224',76,16331,0,'3fcb');
+INSERT INTO items VALUES(NULL,'Balista 225',76,16332,0,'3fcc');
+INSERT INTO items VALUES(NULL,'Plain Shirt (W/E)',1,5400,0,'1518');
+INSERT INTO items VALUES(NULL,'Cloak (N/S)',60,5397,0,'1515');
+INSERT INTO items VALUES(NULL,'Serpents Crest (W/E)',99,5396,0,'1514');
+INSERT INTO items VALUES(NULL,'Plain Shirt (N/S)',1,5399,0,'1517');
+INSERT INTO items VALUES(NULL,'Skirt (N/S)',315,5398,0,'1516');
+INSERT INTO items VALUES(NULL,'Part 4',329,5393,0,'1511');
+INSERT INTO items VALUES(NULL,'Part 3',329,5392,0,'1510');
+INSERT INTO items VALUES(NULL,'Decorative Armor 4 (N/S)',328,5395,0,'1513');
+INSERT INTO items VALUES(NULL,'Decorative Armor 3 (N/S)',328,5394,0,'1512');
+INSERT INTO items VALUES(NULL,'Waterfall 7',23,13554,0,'34f2');
+INSERT INTO items VALUES(NULL,'kite shield',266,7028,0,'valorite_shields_kite');
+INSERT INTO items VALUES(NULL,'metal shield',207,7035,0,'iron_shields_shield');
+INSERT INTO items VALUES(NULL,'Roof 6',327,1449,0,'5a9');
+INSERT INTO items VALUES(NULL,'Roof 5',327,1448,0,'5a8');
+INSERT INTO items VALUES(NULL,'Wall 15',6,618,0,'26a');
+INSERT INTO items VALUES(NULL,'Wood 25',11,7065,0,'1b99');
+INSERT INTO items VALUES(NULL,'Wall 20',6,623,0,'26f');
+INSERT INTO items VALUES(NULL,'Wall 19',6,622,0,'26e');
+INSERT INTO items VALUES(NULL,'Wall 18',6,621,0,'26d');
+INSERT INTO items VALUES(NULL,'Roof 13',209,1441,0,'5a1');
+INSERT INTO items VALUES(NULL,'Roof 12',209,1440,0,'5a0');
+INSERT INTO items VALUES(NULL,'Roof 15',209,1443,0,'5a3');
+INSERT INTO items VALUES(NULL,'Roof 14',209,1442,0,'5a2');
+INSERT INTO items VALUES(NULL,'Roof 2',327,1445,0,'5a5');
+INSERT INTO items VALUES(NULL,'Roof 1',327,1444,0,'5a4');
+INSERT INTO items VALUES(NULL,'Roof 4',327,1447,0,'5a7');
+INSERT INTO items VALUES(NULL,'Roof 3',327,1446,0,'5a6');
+INSERT INTO items VALUES(NULL,'Oar (N/S) (2/2)',114,7719,0,'1e27');
+INSERT INTO items VALUES(NULL,'Treasure (19/41)',215,6995,0,'1b53');
+INSERT INTO items VALUES(NULL,'Treasure (17/41)',215,6992,0,'1b50');
+INSERT INTO items VALUES(NULL,'Books 3',263,7715,0,'1e23');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 21',105,1974,0,'7b6');
+INSERT INTO items VALUES(NULL,'Cave Steps 7',106,1975,0,'7b7');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 27',100,7344,0,'1cb0');
+INSERT INTO items VALUES(NULL,'Wall 8',6,611,0,'263');
+INSERT INTO items VALUES(NULL,'Wall 7',6,610,0,'262');
+INSERT INTO items VALUES(NULL,'Wall 6',6,609,0,'261');
+INSERT INTO items VALUES(NULL,'Wall 5',6,608,0,'260');
+INSERT INTO items VALUES(NULL,'Wall 12',6,615,0,'267');
+INSERT INTO items VALUES(NULL,'Wall 11',6,614,0,'266');
+INSERT INTO items VALUES(NULL,'Wall 10',6,613,0,'265');
+INSERT INTO items VALUES(NULL,'Wall 9',6,612,0,'264');
+INSERT INTO items VALUES(NULL,'Roof 7',327,1450,0,'5aa');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 33',100,7350,0,'1cb6');
+INSERT INTO items VALUES(NULL,'Wall 14',6,617,0,'269');
+INSERT INTO items VALUES(NULL,'Wall 13',6,616,0,'268');
+INSERT INTO items VALUES(NULL,'Troll (W/E)',160,7789,0,'1e6d');
+INSERT INTO items VALUES(NULL,'Roof 10',327,1453,0,'5ad');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 2',2,7791,0,'1e6f');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 34',100,7351,0,'1cb7');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 31',100,7348,0,'1cb4');
+INSERT INTO items VALUES(NULL,'Cave Steps 5',106,1969,0,'7b1');
+INSERT INTO items VALUES(NULL,'Giant Frog',115,9612,0,'258c');
+INSERT INTO items VALUES(NULL,'Balista 217',76,16324,0,'3fc4');
+INSERT INTO items VALUES(NULL,'Evil Mage Boss',115,9611,0,'258b');
+INSERT INTO items VALUES(NULL,'Cocoon 3',303,4316,0,'10dc');
+INSERT INTO items VALUES(NULL,'Cocoon 2',303,4315,0,'10db');
+INSERT INTO items VALUES(NULL,'Cocoon 1',303,4314,0,'10da');
+INSERT INTO items VALUES(NULL,'Balista 218',76,16325,0,'3fc5');
+INSERT INTO items VALUES(NULL,'Web (Cocoon)',303,4317,0,'10dd');
+INSERT INTO items VALUES(NULL,'Balista 213',76,16320,0,'3fc0');
+INSERT INTO items VALUES(NULL,'Stone Fireplace 1 (W/E) (2/2)',103,2365,0,'93d');
+INSERT INTO items VALUES(NULL,'Battlement 7',330,712,0,'2c8');
+INSERT INTO items VALUES(NULL,'Battlement 8',330,713,0,'2c9');
+INSERT INTO items VALUES(NULL,'Battlement 6',330,711,0,'2c7');
+INSERT INTO items VALUES(NULL,'Arch 9',170,704,0,'2c0');
+INSERT INTO items VALUES(NULL,'Dragon Scale 2',240,9906,0,'26b2');
+INSERT INTO items VALUES(NULL,'Dragon Scale 3',240,9907,0,'26b3');
+INSERT INTO items VALUES(NULL,'Dragon Scale 1',240,9905,0,'26b1');
+INSERT INTO items VALUES(NULL,'Dragon Scale 6',240,9910,0,'26b6');
+INSERT INTO items VALUES(NULL,'Zoogi Fungus',331,9911,0,'26b7');
+INSERT INTO items VALUES(NULL,'Dragon Scale 4',240,9908,0,'26b4');
+INSERT INTO items VALUES(NULL,'Dragon Scale 5',240,9909,0,'26b5');
+INSERT INTO items VALUES(NULL,'Waterfall 31',23,13578,0,'350a');
+INSERT INTO items VALUES(NULL,'Waterfall 32',23,13579,0,'350b');
+INSERT INTO items VALUES(NULL,'Waterfall 33',23,13580,0,'350c');
+INSERT INTO items VALUES(NULL,'Waterfall 34',23,13581,0,'350d');
+INSERT INTO items VALUES(NULL,'Waterfall 35',23,13582,0,'350e');
+INSERT INTO items VALUES(NULL,'Waterfall 36',23,13583,0,'350f');
+INSERT INTO items VALUES(NULL,'Small Web 2',303,4307,0,'10d3');
+INSERT INTO items VALUES(NULL,'Small Web 1',303,4306,0,'10d2');
+INSERT INTO items VALUES(NULL,'Spiderweb 6 (4/4)',303,4305,0,'10d1');
+INSERT INTO items VALUES(NULL,'Spiderweb 6 (3/4)',303,4304,0,'10d0');
+INSERT INTO items VALUES(NULL,'Small Web 6',303,4311,0,'10d7');
+INSERT INTO items VALUES(NULL,'Small Web 5',303,4310,0,'10d6');
+INSERT INTO items VALUES(NULL,'Small Web 4',303,4309,0,'10d5');
+INSERT INTO items VALUES(NULL,'Small Web 3',303,4308,0,'10d4');
+INSERT INTO items VALUES(NULL,'Roof 36',84,1510,0,'5e6');
+INSERT INTO items VALUES(NULL,'French Bread',19,2444,0,'98c');
+INSERT INTO items VALUES(NULL,'Egg Case',303,4313,0,'10d9');
+INSERT INTO items VALUES(NULL,'Egg Case Web',303,4312,0,'10d8');
+INSERT INTO items VALUES(NULL,'Jug of Cider 3',155,2445,0,'98d');
+INSERT INTO items VALUES(NULL,'Jug of Cider 2',155,2446,0,'98e');
+INSERT INTO items VALUES(NULL,'Waterfall 29',23,13576,0,'3508');
+INSERT INTO items VALUES(NULL,'Waterfall 30',23,13577,0,'3509');
+INSERT INTO items VALUES(NULL,'scythe',3,9914,0,'26ba');
+INSERT INTO items VALUES(NULL,'Waterfall 14',23,13561,0,'34f9');
+INSERT INTO items VALUES(NULL,'bladed staff',3,9917,0,'26bd');
+INSERT INTO items VALUES(NULL,'pike',20,9918,0,'26be');
+INSERT INTO items VALUES(NULL,'Waterfall 21',23,13568,0,'3500');
+INSERT INTO items VALUES(NULL,'Waterfall 22',23,13569,0,'3501');
+INSERT INTO items VALUES(NULL,'Waterfall 23',23,13570,0,'3502');
+INSERT INTO items VALUES(NULL,'Waterfall 24',23,13571,0,'3503');
+INSERT INTO items VALUES(NULL,'Waterfall 25',23,13572,0,'3504');
+INSERT INTO items VALUES(NULL,'Waterfall 26',23,13573,0,'3505');
+INSERT INTO items VALUES(NULL,'Waterfall 27',23,13574,0,'3506');
+INSERT INTO items VALUES(NULL,'Waterfall 28',23,13575,0,'3507');
+INSERT INTO items VALUES(NULL,'Battlement 12',330,717,0,'2cd');
+INSERT INTO items VALUES(NULL,'Small Wall 1',330,718,0,'2ce');
+INSERT INTO items VALUES(NULL,'Small Wall 2',330,719,0,'2cf');
+INSERT INTO items VALUES(NULL,'Battlement 9',330,714,0,'2ca');
+INSERT INTO items VALUES(NULL,'Battlement 10',330,715,0,'2cb');
+INSERT INTO items VALUES(NULL,'Battlement 11',330,716,0,'2cc');
+INSERT INTO items VALUES(NULL,'Waterfall 13',23,13560,0,'34f8');
+INSERT INTO items VALUES(NULL,'Dungeon Ramp (W/E)',299,4540,0,'11bc');
+INSERT INTO items VALUES(NULL,'Dungeon Ramp (E/W)',299,4542,0,'11be');
+INSERT INTO items VALUES(NULL,'Painting 10',304,3752,0,'ea8');
+INSERT INTO items VALUES(NULL,'Painting 3',304,3745,0,'ea1');
+INSERT INTO items VALUES(NULL,'Painting 2',304,3744,0,'ea0');
+INSERT INTO items VALUES(NULL,'Painting 5',304,3747,0,'ea3');
+INSERT INTO items VALUES(NULL,'Painting 4',304,3746,0,'ea2');
+INSERT INTO items VALUES(NULL,'Painting 7',304,3749,0,'ea5');
+INSERT INTO items VALUES(NULL,'Painting 6',304,3748,0,'ea4');
+INSERT INTO items VALUES(NULL,'Painting 9',304,3751,0,'ea7');
+INSERT INTO items VALUES(NULL,'Painting 8',304,3750,0,'ea6');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 16',332,1839,0,'72f');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 14',332,1837,0,'72d');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 15',332,1838,0,'72e');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 12',332,1835,0,'72b');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 13',332,1836,0,'72c');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 11',332,1834,0,'72a');
+INSERT INTO items VALUES(NULL,'Balista 238',76,16345,0,'3fd9');
+INSERT INTO items VALUES(NULL,'Balista 237',76,16344,0,'3fd8');
+INSERT INTO items VALUES(NULL,'Balista 236',76,16343,0,'3fd7');
+INSERT INTO items VALUES(NULL,'Balista 235',76,16342,0,'3fd6');
+INSERT INTO items VALUES(NULL,'Balista 234',76,16341,0,'3fd5');
+INSERT INTO items VALUES(NULL,'Balista 233',76,16340,0,'3fd4');
+INSERT INTO items VALUES(NULL,'Balista 232',76,16339,0,'3fd3');
+INSERT INTO items VALUES(NULL,'Balista 231',76,16338,0,'3fd2');
+INSERT INTO items VALUES(NULL,'Balista 230',76,16337,0,'3fd1');
+INSERT INTO items VALUES(NULL,'Balista 229',76,16336,0,'3fd0');
+INSERT INTO items VALUES(NULL,'Tapestry 1 (1/2)',304,3754,0,'eaa');
+INSERT INTO items VALUES(NULL,'Tapestry 2 (1/2)',304,3756,0,'eac');
+INSERT INTO items VALUES(NULL,'Tapestry 1 (2/2)',304,3755,0,'eab');
+INSERT INTO items VALUES(NULL,'Tapestry 3 (1/2)',304,3758,0,'eae');
+INSERT INTO items VALUES(NULL,'Tapestry 2 (2/2)',304,3757,0,'ead');
+INSERT INTO items VALUES(NULL,'Tapestry 3 (2/2)',304,3759,0,'eaf');
+INSERT INTO items VALUES(NULL,'Elephant Ear Plant',45,3223,0,'c97');
+INSERT INTO items VALUES(NULL,'Balista 244',76,16351,0,'3fdf');
+INSERT INTO items VALUES(NULL,'Balista 243',76,16350,0,'3fde');
+INSERT INTO items VALUES(NULL,'Balista 242',76,16349,0,'3fdd');
+INSERT INTO items VALUES(NULL,'Balista 241',76,16348,0,'3fdc');
+INSERT INTO items VALUES(NULL,'Balista 240',76,16347,0,'3fdb');
+INSERT INTO items VALUES(NULL,'Balista 239',76,16346,0,'3fda');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 7',332,1830,0,'726');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 8',332,1831,0,'727');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 5',332,1828,0,'724');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 6',332,1829,0,'725');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 3',332,1826,0,'722');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 4',332,1827,0,'723');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 1',332,1824,0,'720');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 2',332,1825,0,'721');
+INSERT INTO items VALUES(NULL,'Date Palm',264,3222,0,'c96');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 9',332,1832,0,'728');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 10',332,1833,0,'729');
+INSERT INTO items VALUES(NULL,'Gravestone 12',27,4453,0,'1165');
+INSERT INTO items VALUES(NULL,'Gravestone 13',27,4454,0,'1166');
+INSERT INTO items VALUES(NULL,'Gravestone 14',27,4455,0,'1167');
+INSERT INTO items VALUES(NULL,'Stone Rail 13',333,2298,0,'8fa');
+INSERT INTO items VALUES(NULL,'Rail 2',333,2300,0,'8fc');
+INSERT INTO items VALUES(NULL,'Rail 1',333,2299,0,'8fb');
+INSERT INTO items VALUES(NULL,'Gravestone 15',27,4456,0,'1168');
+INSERT INTO items VALUES(NULL,'Gravestone 16',27,4457,0,'1169');
+INSERT INTO items VALUES(NULL,'Coconut Palm',264,3221,0,'c95');
+INSERT INTO items VALUES(NULL,'Refuse 4',334,7074,0,'1ba2');
+INSERT INTO items VALUES(NULL,'Refuse 5',334,7075,0,'1ba3');
+INSERT INTO items VALUES(NULL,'Refuse 2',334,7072,0,'1ba0');
+INSERT INTO items VALUES(NULL,'Refuse 3',334,7073,0,'1ba1');
+INSERT INTO items VALUES(NULL,'Refuse 8',334,7078,0,'1ba6');
+INSERT INTO items VALUES(NULL,'Refuse 9',334,7079,0,'1ba7');
+INSERT INTO items VALUES(NULL,'Refuse 6',334,7076,0,'1ba4');
+INSERT INTO items VALUES(NULL,'Refuse 7',334,7077,0,'1ba5');
+INSERT INTO items VALUES(NULL,'Vial of Blood',112,3965,0,'f7d');
+INSERT INTO items VALUES(NULL,'Bone',112,3966,0,'f7e');
+INSERT INTO items VALUES(NULL,'Refuse 10',334,7080,0,'1ba8');
+INSERT INTO items VALUES(NULL,'Refuse 11',334,7081,0,'1ba9');
+INSERT INTO items VALUES(NULL,'Black Pearl',112,3962,0,'f7a');
+INSERT INTO items VALUES(NULL,'Blood Moss',112,3963,0,'f7b');
+INSERT INTO items VALUES(NULL,'Bloodspawn',112,3964,0,'f7c');
+INSERT INTO items VALUES(NULL,'Blacksmith (W/E)',230,3016,0,'bc8');
+INSERT INTO items VALUES(NULL,'Painter (N/S)',230,3017,0,'bc9');
+INSERT INTO items VALUES(NULL,'Bulrushes',45,3220,0,'c94');
+INSERT INTO items VALUES(NULL,'Tavern (W/E)',230,3012,0,'bc4');
+INSERT INTO items VALUES(NULL,'Reagent Shop (N/S)',230,3013,0,'bc5');
+INSERT INTO items VALUES(NULL,'Reagent Shop (W/E)',230,3014,0,'bc6');
+INSERT INTO items VALUES(NULL,'Blacksmith (N/S)',230,3015,0,'bc7');
+INSERT INTO items VALUES(NULL,'Armourer (W/E)',230,3008,0,'bc0');
+INSERT INTO items VALUES(NULL,'Jeweler (N/S)',230,3009,0,'bc1');
+INSERT INTO items VALUES(NULL,'Jeweler (W/E)',230,3010,0,'bc2');
+INSERT INTO items VALUES(NULL,'Tavern (N/S)',230,3011,0,'bc3');
+INSERT INTO items VALUES(NULL,'Boulder 8 (1/2)',216,4961,0,'1361');
+INSERT INTO items VALUES(NULL,'Stone Rail 12',333,2297,0,'8f9');
+INSERT INTO items VALUES(NULL,'Stone Rail 11',333,2296,0,'8f8');
+INSERT INTO items VALUES(NULL,'Gravestone 22',27,4463,0,'116f');
+INSERT INTO items VALUES(NULL,'Gravestone 17',27,4458,0,'116a');
+INSERT INTO items VALUES(NULL,'Gravestone 18',27,4459,0,'116b');
+INSERT INTO items VALUES(NULL,'Gravestone 19',27,4460,0,'116c');
+INSERT INTO items VALUES(NULL,'Stone Rail 8',333,2289,0,'8f1');
+INSERT INTO items VALUES(NULL,'Stone Rail 7',333,2288,0,'8f0');
+INSERT INTO items VALUES(NULL,'Sandstone Rail 1',333,2291,0,'8f3');
+INSERT INTO items VALUES(NULL,'Stone Rail 9',333,2290,0,'8f2');
+INSERT INTO items VALUES(NULL,'Sandstone Rail 3',333,2293,0,'8f5');
+INSERT INTO items VALUES(NULL,'Sandstone Rail 2',333,2292,0,'8f4');
+INSERT INTO items VALUES(NULL,'Stone Rail 10',333,2295,0,'8f7');
+INSERT INTO items VALUES(NULL,'Sandstone Rail 4',333,2294,0,'8f6');
+INSERT INTO items VALUES(NULL,'Dartboard 1 (N/S)',249,7726,0,'1e2e');
+INSERT INTO items VALUES(NULL,'Bowyer (N/S)',230,3021,0,'bcd');
+INSERT INTO items VALUES(NULL,'Bowyer (W/E)',230,3022,0,'bce');
+INSERT INTO items VALUES(NULL,'Wooden Sign (N/S)',335,3023,0,'bcf');
+INSERT INTO items VALUES(NULL,'Painter (W/E)',230,3018,0,'bca');
+INSERT INTO items VALUES(NULL,'Provisioner (N/S)',230,3019,0,'bcb');
+INSERT INTO items VALUES(NULL,'Provisioner (W/E)',230,3020,0,'bcc');
+INSERT INTO items VALUES(NULL,'Refuse 13',334,7083,0,'1bab');
+INSERT INTO items VALUES(NULL,'Refuse 14',334,7084,0,'1bac');
+INSERT INTO items VALUES(NULL,'Refuse 12',334,7082,0,'1baa');
+INSERT INTO items VALUES(NULL,'Refuse 17',334,7087,0,'1baf');
+INSERT INTO items VALUES(NULL,'Blackmoor',112,3961,0,'f79');
+INSERT INTO items VALUES(NULL,'Refuse 15',334,7085,0,'1bad');
+INSERT INTO items VALUES(NULL,'Refuse 16',334,7086,0,'1bae');
+INSERT INTO items VALUES(NULL,'Rack of Canvases 4',262,3956,0,'f74');
+INSERT INTO items VALUES(NULL,'Dishing Stump (N/S)',173,6245,0,'1865');
+INSERT INTO items VALUES(NULL,'Rack of Canvases 6',262,3958,0,'f76');
+INSERT INTO items VALUES(NULL,'Rack of Canvases 1',262,3953,0,'f71');
+INSERT INTO items VALUES(NULL,'Rack of Canvases 2',262,3954,0,'f72');
+INSERT INTO items VALUES(NULL,'Rack of Canvases 3',262,3955,0,'f73');
+INSERT INTO items VALUES(NULL,'Treasure (25/41)',215,7002,0,'1b5a');
+INSERT INTO items VALUES(NULL,'Wall 4',170,660,0,'294');
+INSERT INTO items VALUES(NULL,'Yellow Potion',180,3852,0,'potion_heal');
+INSERT INTO items VALUES(NULL,'Glow',28,14265,0,'37b9');
+INSERT INTO items VALUES(NULL,'heater shield',266,7030,0,'valorite_shields_heater');
+INSERT INTO items VALUES(NULL,'Blade Plant',45,3219,0,'c93');
+INSERT INTO items VALUES(NULL,'Small Wall 2',326,267,0,'10b');
+INSERT INTO items VALUES(NULL,'Small Wall 3',326,268,0,'10c');
+INSERT INTO items VALUES(NULL,'Sparkle (blue) 2',28,14201,0,'3779');
+INSERT INTO items VALUES(NULL,'Small Wall 1',326,266,0,'10a');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',260,271,0,'10f');
+INSERT INTO items VALUES(NULL,'Small Wall 4',326,269,0,'10d');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',260,270,0,'10e');
+INSERT INTO items VALUES(NULL,'Lava 5',52,6773,0,'1a75');
+INSERT INTO items VALUES(NULL,'Lava 19',37,6769,0,'1a71');
+INSERT INTO items VALUES(NULL,'chainmail leggings',167,5054,0,'valorite_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Window 1',326,264,0,'108');
+INSERT INTO items VALUES(NULL,'Window 2',326,265,0,'109');
+INSERT INTO items VALUES(NULL,'Window 1',123,258,0,'102');
+INSERT INTO items VALUES(NULL,'Window 2',123,259,0,'103');
+INSERT INTO items VALUES(NULL,'Wall 3',123,256,0,'100');
+INSERT INTO items VALUES(NULL,'Wall 4',123,257,0,'101');
+INSERT INTO items VALUES(NULL,'Wall 3',326,262,0,'106');
+INSERT INTO items VALUES(NULL,'Wall 4',326,263,0,'107');
+INSERT INTO items VALUES(NULL,'Wall 1',326,260,0,'104');
+INSERT INTO items VALUES(NULL,'Wall 2',326,261,0,'105');
+INSERT INTO items VALUES(NULL,'Leaves 1 (14/15)',4,3410,0,'d52');
+INSERT INTO items VALUES(NULL,'Wall 1',169,669,0,'29d');
+INSERT INTO items VALUES(NULL,'Wall 2',169,670,0,'29e');
+INSERT INTO items VALUES(NULL,'Arch Cure',94,8005,0,'1f45');
+INSERT INTO items VALUES(NULL,'Window 1',211,667,0,'29b');
+INSERT INTO items VALUES(NULL,'Window 2',211,668,0,'29c');
+INSERT INTO items VALUES(NULL,'Wooden Table 12 (W/E) (2/2)',89,7592,0,'1da8');
+INSERT INTO items VALUES(NULL,'Pillow 5',91,5031,0,'13a7');
+INSERT INTO items VALUES(NULL,'Pillow 4',91,5030,0,'13a6');
+INSERT INTO items VALUES(NULL,'Pillow 3',91,5029,0,'13a5');
+INSERT INTO items VALUES(NULL,'Pillow 2',91,5028,0,'13a4');
+INSERT INTO items VALUES(NULL,'Statue 2 (W/E) (3/3)',54,5027,0,'13a3');
+INSERT INTO items VALUES(NULL,'Statue 2 (W/E) (1/3)',54,5026,0,'13a2');
+INSERT INTO items VALUES(NULL,'Statue 2 (W/E) (2/3)',54,5025,0,'13a1');
+INSERT INTO items VALUES(NULL,'Statue 1 (W/E) (3/3)',54,5024,0,'13a0');
+INSERT INTO items VALUES(NULL,'Bedroll 6',91,7975,0,'1f27');
+INSERT INTO items VALUES(NULL,'Pillow 7',91,5033,0,'13a9');
+INSERT INTO items VALUES(NULL,'Pillow 6',91,5032,0,'13a8');
+INSERT INTO items VALUES(NULL,'Bedroll 3',91,7972,0,'1f24');
+INSERT INTO items VALUES(NULL,'Arm (right) 1',147,7586,0,'1da2');
+INSERT INTO items VALUES(NULL,'Pillow 12',91,5038,0,'13ae');
+INSERT INTO items VALUES(NULL,'Leg (left) 1',147,7587,0,'1da3');
+INSERT INTO items VALUES(NULL,'Pillow 10',91,5036,0,'13ac');
+INSERT INTO items VALUES(NULL,'Pillow 9',91,5035,0,'13ab');
+INSERT INTO items VALUES(NULL,'Pillow 8',91,5034,0,'13aa');
+INSERT INTO items VALUES(NULL,'Leg (right) 1',147,7588,0,'1da4');
+INSERT INTO items VALUES(NULL,'Vines 1 (3/3)',4,3414,0,'d56');
+INSERT INTO items VALUES(NULL,'Tree Pieces 1 (1/5)',4,3415,0,'d57');
+INSERT INTO items VALUES(NULL,'Lord Blackthorn',115,9721,0,'25f9');
+INSERT INTO items VALUES(NULL,'Adranath',115,9720,0,'25f8');
+INSERT INTO items VALUES(NULL,'Dirty Pot 5',14,2535,0,'9e7');
+INSERT INTO items VALUES(NULL,'Round Shield (Gold w. a Cross) (N/S)',99,5500,0,'157c');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 1 (W/SE)',59,1677,0,'68d');
+INSERT INTO items VALUES(NULL,'Round Shield (Silver w. a Cross) (N/S)',99,5498,0,'157a');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 1 (W/NE)',59,1679,0,'68f');
+INSERT INTO items VALUES(NULL,'Round Shield (Silver) (W/E)',99,5503,0,'157f');
+INSERT INTO items VALUES(NULL,'Round Shield (Silver) (N/S)',99,5502,0,'157e');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 1 (S/NE)',59,1675,0,'68b');
+INSERT INTO items VALUES(NULL,'Pillory 18',113,4750,0,'128e');
+INSERT INTO items VALUES(NULL,'Pillory 17',113,4749,0,'128d');
+INSERT INTO items VALUES(NULL,'Pillory 19',113,4751,0,'128f');
+INSERT INTO items VALUES(NULL,'Pillory 14',113,4746,0,'128a');
+INSERT INTO items VALUES(NULL,'Pillory 16',113,4748,0,'128c');
+INSERT INTO items VALUES(NULL,'Pillory 15',113,4747,0,'128b');
+INSERT INTO items VALUES(NULL,'Stone Fountain (13/16) (Not Animated)',104,5975,0,'1757');
+INSERT INTO items VALUES(NULL,'Stone Fountain (9/16) (Not Animated)',104,5973,0,'1755');
+INSERT INTO items VALUES(NULL,'Stone Fountain (11/16) (Not Animated)',104,5971,0,'1753');
+INSERT INTO items VALUES(NULL,'chainmail leggings',95,5054,0,'golden_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Captain Dasha',115,9722,0,'25fa');
+INSERT INTO items VALUES(NULL,'Warlord Kabur',115,9724,0,'25fc');
+INSERT INTO items VALUES(NULL,'Dawn',115,9723,0,'25fb');
+INSERT INTO items VALUES(NULL,'heater shield',272,7030,0,'agapite_shields_heater');
+INSERT INTO items VALUES(NULL,'Pillory 8',113,4740,0,'1284');
+INSERT INTO items VALUES(NULL,'Pillory 11',113,4743,0,'1287');
+INSERT INTO items VALUES(NULL,'Pillory 10',113,4742,0,'1286');
+INSERT INTO items VALUES(NULL,'Pillory 5',113,4737,0,'1281');
+INSERT INTO items VALUES(NULL,'Pillory 4',113,4736,0,'1280');
+INSERT INTO items VALUES(NULL,'Pillory 7',113,4739,0,'1283');
+INSERT INTO items VALUES(NULL,'Pillory 6',113,4738,0,'1282');
+INSERT INTO items VALUES(NULL,'Folded Cloth 3 (W/E)',57,5983,0,'175f');
+INSERT INTO items VALUES(NULL,'Folded Cloth 2 (W/E)',57,5982,0,'175e');
+INSERT INTO items VALUES(NULL,'Folded Cloth 1 (W/E)',57,5981,0,'175d');
+INSERT INTO items VALUES(NULL,'Pillory 13',113,4745,0,'1289');
+INSERT INTO items VALUES(NULL,'Pillory 12',113,4744,0,'1288');
+INSERT INTO items VALUES(NULL,'Shield (Gold w. a Snake) (W/E)',99,5497,0,'1579');
+INSERT INTO items VALUES(NULL,'Lava 1',161,4846,0,'12ee');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 1 (S/NW)',59,1673,0,'689');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 1 (S/SW)',59,1669,0,'685');
+INSERT INTO items VALUES(NULL,'Oval Shield (Silver w. a Snake) (N/S)',99,5490,0,'1572');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 1 (S/SE)',59,1671,0,'687');
+INSERT INTO items VALUES(NULL,'Shield (Gold w. a Star) (N/S)',99,5488,0,'1570');
+INSERT INTO items VALUES(NULL,'Metal Door (W/SW)',336,1665,0,'681');
+INSERT INTO items VALUES(NULL,'Shield (Silver w. a Snake) (N/S)',99,5494,0,'1576');
+INSERT INTO items VALUES(NULL,'Metal Door (W/NW)',336,1667,0,'683');
+INSERT INTO items VALUES(NULL,'Oval Shield (Gold w. a Snake) (N/S)',99,5492,0,'1574');
+INSERT INTO items VALUES(NULL,'Brazier 4',73,7979,0,'1f2b');
+INSERT INTO items VALUES(NULL,'Create Food',94,7983,0,'1f2f');
+INSERT INTO items VALUES(NULL,'Reactive Armor',94,7981,0,'1f2d');
+INSERT INTO items VALUES(NULL,'Wall 3',66,590,0,'24e');
+INSERT INTO items VALUES(NULL,'Wall 2',66,589,0,'24d');
+INSERT INTO items VALUES(NULL,'Wall 4',66,591,0,'24f');
+INSERT INTO items VALUES(NULL,'Arch 6',238,586,0,'24a');
+INSERT INTO items VALUES(NULL,'Wall 1',66,588,0,'24c');
+INSERT INTO items VALUES(NULL,'Leaves 3 (10/13)',4,3452,0,'d7c');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 7',68,7759,0,'1e4f');
+INSERT INTO items VALUES(NULL,'Flax 1',45,6809,0,'1a99');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 5',68,7757,0,'1e4d');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 6',68,7758,0,'1e4e');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 3',68,7755,0,'1e4b');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 4',68,7756,0,'1e4c');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 2',68,7754,0,'1e4a');
+INSERT INTO items VALUES(NULL,'Carpeted Rostrum 4',102,1991,0,'7c7');
+INSERT INTO items VALUES(NULL,'Arch 1',238,581,0,'245');
+INSERT INTO items VALUES(NULL,'Wall 4',238,580,0,'244');
+INSERT INTO items VALUES(NULL,'Arch 3',238,583,0,'247');
+INSERT INTO items VALUES(NULL,'Arch 2',238,582,0,'246');
+INSERT INTO items VALUES(NULL,'Wall 1',238,577,0,'241');
+INSERT INTO items VALUES(NULL,'Wall 3',238,579,0,'243');
+INSERT INTO items VALUES(NULL,'Wall 2',238,578,0,'242');
+INSERT INTO items VALUES(NULL,'Arch 5',238,585,0,'249');
+INSERT INTO items VALUES(NULL,'Arch 4',238,584,0,'248');
+INSERT INTO items VALUES(NULL,'Window 1',170,661,0,'295');
+INSERT INTO items VALUES(NULL,'Wall 2',170,658,0,'292');
+INSERT INTO items VALUES(NULL,'Wall 3',170,659,0,'293');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 7',337,7750,0,'1e46');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 8',337,7751,0,'1e47');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 5',337,7748,0,'1e44');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 6',337,7749,0,'1e45');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 3',337,7746,0,'1e42');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 4',337,7747,0,'1e43');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 1',337,7744,0,'1e40');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 2',337,7745,0,'1e41');
+INSERT INTO items VALUES(NULL,'Wall 1',170,657,0,'291');
+INSERT INTO items VALUES(NULL,'Rug (W/E) 9',337,7752,0,'1e48');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 1',68,7753,0,'1e49');
+INSERT INTO items VALUES(NULL,'Splash 3',74,13615,0,'352f');
+INSERT INTO items VALUES(NULL,'Splash 1',74,13613,0,'352d');
+INSERT INTO items VALUES(NULL,'Splash 2',74,13614,0,'352e');
+INSERT INTO items VALUES(NULL,'Stone Face (small w. fire) 4',109,4346,0,'10fa');
+INSERT INTO items VALUES(NULL,'Stone Face (N/S) 1',109,4348,0,'10fc');
+INSERT INTO items VALUES(NULL,'Stone Face (small w. fire) 5',109,4347,0,'10fb');
+INSERT INTO items VALUES(NULL,'Stone Face (N/S; w. fire) 1',109,4350,0,'10fe');
+INSERT INTO items VALUES(NULL,'Stone Face (N/S) 2',109,4349,0,'10fd');
+INSERT INTO items VALUES(NULL,'ringmail tunic',235,5100,0,'agapite_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Stone Face (N/S; w. fire) 2',109,4351,0,'10ff');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',170,678,0,'2a6');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (W/E) 8',79,2619,0,'a3b');
+INSERT INTO items VALUES(NULL,'bascinet',131,5132,0,'shadow_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',170,677,0,'2a5');
+INSERT INTO items VALUES(NULL,'Small Wall 2',170,674,0,'2a2');
+INSERT INTO items VALUES(NULL,'Dresser (N/S) 4',79,2623,0,'a3f');
+INSERT INTO items VALUES(NULL,'Dresser (N/S) 3',79,2622,0,'a3e');
+INSERT INTO items VALUES(NULL,'Dresser (N/S) 2',79,2621,0,'a3d');
+INSERT INTO items VALUES(NULL,'Column 2',169,680,0,'2a8');
+INSERT INTO items VALUES(NULL,'Column 3',169,681,0,'2a9');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (N/S) 8',79,2611,0,'a33');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (N/S) 7',79,2610,0,'a32');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (N/S) 6',79,2609,0,'a31');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (N/S) 5',79,2608,0,'a30');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (W/E) 4',79,2615,0,'a37');
+INSERT INTO items VALUES(NULL,'Column 3',170,684,0,'2ac');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (W/E) 2',79,2613,0,'a35');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (W/E) 1',79,2612,0,'a34');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (W/E) 6',79,2617,0,'a39');
+INSERT INTO items VALUES(NULL,'Chest of Drawers (W/E) 5',79,2616,0,'a38');
+INSERT INTO items VALUES(NULL,'Waterfall 59',23,13606,0,'3526');
+INSERT INTO items VALUES(NULL,'Waterfall 60',23,13607,0,'3527');
+INSERT INTO items VALUES(NULL,'Waterfall 57',23,13604,0,'3524');
+INSERT INTO items VALUES(NULL,'Waterfall 58',23,13605,0,'3525');
+INSERT INTO items VALUES(NULL,'Waterfall 55',23,13602,0,'3522');
+INSERT INTO items VALUES(NULL,'Waterfall 56',23,13603,0,'3523');
+INSERT INTO items VALUES(NULL,'Waterfall 53',23,13600,0,'3520');
+INSERT INTO items VALUES(NULL,'Waterfall 54',23,13601,0,'3521');
+INSERT INTO items VALUES(NULL,'Garbage 4',338,4337,0,'10f1');
+INSERT INTO items VALUES(NULL,'Garbage 3',338,4336,0,'10f0');
+INSERT INTO items VALUES(NULL,'Pile of Garbage (N/S)',338,4339,0,'10f3');
+INSERT INTO items VALUES(NULL,'Pile of Garbage (W/E)',338,4338,0,'10f2');
+INSERT INTO items VALUES(NULL,'Stone Face (small) 1',109,4341,0,'10f5');
+INSERT INTO items VALUES(NULL,'Waterfall 70',23,13608,0,'3528');
+INSERT INTO items VALUES(NULL,'Stone Face (small) 2',109,4342,0,'10f6');
+INSERT INTO items VALUES(NULL,'Sheaf of Wheat',114,7869,0,'1ebd');
+INSERT INTO items VALUES(NULL,'kite shield',16,7028,0,'verite_shields_kite');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 7',339,1961,0,'7a9');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 6',339,1960,0,'7a8');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 5',339,1959,0,'7a7');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 4',339,1958,0,'7a6');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 3',339,1957,0,'7a5');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 2',339,1956,0,'7a4');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 1',339,1955,0,'7a3');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 16',121,1954,0,'7a2');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 15',121,1953,0,'7a1');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 14',121,1952,0,'7a0');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 13',339,1967,0,'7af');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 12',339,1966,0,'7ae');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 11',339,1965,0,'7ad');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 10',339,1964,0,'7ac');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 9',339,1963,0,'7ab');
+INSERT INTO items VALUES(NULL,'Dungeon Stairs 8',339,1962,0,'7aa');
+INSERT INTO items VALUES(NULL,'ringmail tunic',310,5100,0,'verite_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E; falling) 4',109,4418,0,'1142');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E; falling) 5',109,4419,0,'1143');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E; falling) 2',109,4416,0,'1140');
+INSERT INTO items VALUES(NULL,'Roof 16',231,1789,0,'6fd');
+INSERT INTO items VALUES(NULL,'Gas Trap 7',109,4422,0,'1146');
+INSERT INTO items VALUES(NULL,'Gas Trap 8',109,4423,0,'1147');
+INSERT INTO items VALUES(NULL,'Axe Trap (W/E; falling) 6',109,4420,0,'1144');
+INSERT INTO items VALUES(NULL,'Gas Trap 6',109,4421,0,'1145');
+INSERT INTO items VALUES(NULL,'Water 59',33,13499,0,'34bb');
+INSERT INTO items VALUES(NULL,'Water 58',33,13498,0,'34ba');
+INSERT INTO items VALUES(NULL,'Gas Trap 10',109,4425,0,'1149');
+INSERT INTO items VALUES(NULL,'Water 62',33,13503,0,'34bf');
+INSERT INTO items VALUES(NULL,'Water 61',33,13502,0,'34be');
+INSERT INTO items VALUES(NULL,'Water 60',33,13501,0,'34bd');
+INSERT INTO items VALUES(NULL,'Tailor (W/E)',230,2982,0,'ba6');
+INSERT INTO items VALUES(NULL,'Tinker (N/S)',230,2983,0,'ba7');
+INSERT INTO items VALUES(NULL,'Bakery (W/E)',230,2980,0,'ba4');
+INSERT INTO items VALUES(NULL,'Tailor (N/S)',230,2981,0,'ba5');
+INSERT INTO items VALUES(NULL,'Metal Signpost 4 (W/E)',340,2978,0,'ba2');
+INSERT INTO items VALUES(NULL,'Bakery (N/S)',230,2979,0,'ba3');
+INSERT INTO items VALUES(NULL,'Metal Signpost 3 (W/E)',340,2976,0,'ba0');
+INSERT INTO items VALUES(NULL,'Metal Signpost 4 (N/S)',340,2977,0,'ba1');
+INSERT INTO items VALUES(NULL,'Tinker (W/E)',230,2984,0,'ba8');
+INSERT INTO items VALUES(NULL,'Butcher (N/S)',230,2985,0,'ba9');
+INSERT INTO items VALUES(NULL,'broadsword',3,3934,0,'f5e');
+INSERT INTO items VALUES(NULL,'mace',5,3932,0,'f5c');
+INSERT INTO items VALUES(NULL,'Med Long Beard',195,8268,0,'204c');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E; falling) 2',109,4427,0,'114b');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E; falling) 3',109,4428,0,'114c');
+INSERT INTO items VALUES(NULL,'Water 57',33,13497,0,'34b9');
+INSERT INTO items VALUES(NULL,'Water 56',33,13496,0,'34b8');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E; falling) 6',109,4431,0,'114f');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E; falling) 4',109,4429,0,'114d');
+INSERT INTO items VALUES(NULL,'Axe Trap (N/E; falling) 5',109,4430,0,'114e');
+INSERT INTO items VALUES(NULL,'Rock 8',29,13491,0,'34b3');
+INSERT INTO items VALUES(NULL,'Rock 12',29,13490,0,'34b2');
+INSERT INTO items VALUES(NULL,'Rock 11',29,13489,0,'34b1');
+INSERT INTO items VALUES(NULL,'Rock 10',29,13488,0,'34b0');
+INSERT INTO items VALUES(NULL,'Water 55',33,13495,0,'34b7');
+INSERT INTO items VALUES(NULL,'Water 54',33,13494,0,'34b6');
+INSERT INTO items VALUES(NULL,'Water 53',33,13493,0,'34b5');
+INSERT INTO items VALUES(NULL,'Rock 9',29,13492,0,'34b4');
+INSERT INTO items VALUES(NULL,'war fork',20,5124,0,'f51');
+INSERT INTO items VALUES(NULL,'Woodworker (N/S)',230,2991,0,'baf');
+INSERT INTO items VALUES(NULL,'Mage (N/S)',230,2989,0,'bad');
+INSERT INTO items VALUES(NULL,'Healer (W/E)',230,2990,0,'bae');
+INSERT INTO items VALUES(NULL,'Healer (N/S)',230,2987,0,'bab');
+INSERT INTO items VALUES(NULL,'Healer (W/E)',230,2988,0,'bac');
+INSERT INTO items VALUES(NULL,'Butcher (W/E)',230,2986,0,'baa');
+INSERT INTO items VALUES(NULL,'Leaves 4 (6/10)',4,3468,0,'d8c');
+INSERT INTO items VALUES(NULL,'Wall 12',41,906,0,'38a');
+INSERT INTO items VALUES(NULL,'Wall 13',41,907,0,'38b');
+INSERT INTO items VALUES(NULL,'Wall 14',41,908,0,'38c');
+INSERT INTO items VALUES(NULL,'Wall 15',41,909,0,'38d');
+INSERT INTO items VALUES(NULL,'Wall 16',41,910,0,'38e');
+INSERT INTO items VALUES(NULL,'Wall 17',41,911,0,'38f');
+INSERT INTO items VALUES(NULL,'Leaves 1 (1/15)',4,3397,0,'d45');
+INSERT INTO items VALUES(NULL,'Wall 2',41,896,0,'380');
+INSERT INTO items VALUES(NULL,'Wall 3',41,897,0,'381');
+INSERT INTO items VALUES(NULL,'Wall 4',41,898,0,'382');
+INSERT INTO items VALUES(NULL,'Wall 5',41,899,0,'383');
+INSERT INTO items VALUES(NULL,'Wall 6',41,900,0,'384');
+INSERT INTO items VALUES(NULL,'Wall 7',41,901,0,'385');
+INSERT INTO items VALUES(NULL,'Wall 8',41,902,0,'386');
+INSERT INTO items VALUES(NULL,'Wall 9',41,903,0,'387');
+INSERT INTO items VALUES(NULL,'Wall 10',41,904,0,'388');
+INSERT INTO items VALUES(NULL,'Wall 11',41,905,0,'389');
+INSERT INTO items VALUES(NULL,'platemail legs',117,5137,0,'golden_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'Training Dummy (W/E)',341,4212,0,'1074');
+INSERT INTO items VALUES(NULL,'Arch 2',47,365,0,'16d');
+INSERT INTO items VALUES(NULL,'Arch 3',47,366,0,'16e');
+INSERT INTO items VALUES(NULL,'Arch 4',47,367,0,'16f');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (6/15)',324,9025,0,'2341');
+INSERT INTO items VALUES(NULL,'Small Wall 3',47,362,0,'16a');
+INSERT INTO items VALUES(NULL,'Small Wall 4',47,363,0,'16b');
+INSERT INTO items VALUES(NULL,'Arch 1',47,364,0,'16c');
+INSERT INTO items VALUES(NULL,'Wall 22',82,8592,0,'2190');
+INSERT INTO items VALUES(NULL,'Wall 23',82,8593,0,'2191');
+INSERT INTO items VALUES(NULL,'Wall 24',82,8594,0,'2192');
+INSERT INTO items VALUES(NULL,'Wall 25',82,8595,0,'2193');
+INSERT INTO items VALUES(NULL,'Wall 26',82,8596,0,'2194');
+INSERT INTO items VALUES(NULL,'Wall 27',82,8597,0,'2195');
+INSERT INTO items VALUES(NULL,'Wall 28',82,8598,0,'2196');
+INSERT INTO items VALUES(NULL,'Wall 29',82,8599,0,'2197');
+INSERT INTO items VALUES(NULL,'Lava 13',37,6742,0,'1a56');
+INSERT INTO items VALUES(NULL,'Lava 12',37,6737,0,'1a51');
+INSERT INTO items VALUES(NULL,'Long Beard',195,8254,0,'203e');
+INSERT INTO items VALUES(NULL,'chainmail coif',342,5051,0,'iron_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Lava 14',37,6747,0,'1a5b');
+INSERT INTO items VALUES(NULL,'Small Wall 1',47,360,0,'168');
+INSERT INTO items VALUES(NULL,'Small Wall 2',47,361,0,'169');
+INSERT INTO items VALUES(NULL,'Small Wall 1',85,356,0,'164');
+INSERT INTO items VALUES(NULL,'Small Wall 2',85,357,0,'165');
+INSERT INTO items VALUES(NULL,'Small Wall 3',85,358,0,'166');
+INSERT INTO items VALUES(NULL,'Small Wall 4',85,359,0,'167');
+INSERT INTO items VALUES(NULL,'Wall 3',47,352,0,'160');
+INSERT INTO items VALUES(NULL,'Wall 4',47,353,0,'161');
+INSERT INTO items VALUES(NULL,'Window 1',47,354,0,'162');
+INSERT INTO items VALUES(NULL,'Window 2',47,355,0,'163');
+INSERT INTO items VALUES(NULL,'Lava 27',44,12964,0,'32a4');
+INSERT INTO items VALUES(NULL,'Terathan Avenger (3d)',115,9674,0,'25ca');
+INSERT INTO items VALUES(NULL,'Small Palm 3',264,3227,0,'c9b');
+INSERT INTO items VALUES(NULL,'Border 15',179,4939,0,'134b');
+INSERT INTO items VALUES(NULL,'Lava 29',44,12966,0,'32a6');
+INSERT INTO items VALUES(NULL,'Lava 30',44,12967,0,'32a7');
+INSERT INTO items VALUES(NULL,'Fern 1',45,3231,0,'c9f');
+INSERT INTO items VALUES(NULL,'O''Hii Tree ',4,3230,0,'c9e');
+INSERT INTO items VALUES(NULL,'Lava 26',44,12963,0,'32a3');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 16',26,2060,0,'80c');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 15',26,2059,0,'80b');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 14',26,2058,0,'80a');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 19',26,2063,0,'80f');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 18',26,2062,0,'80e');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 17',26,2061,0,'80d');
+INSERT INTO items VALUES(NULL,'Hanging Leather Leggings (N/S)',57,5065,0,'13c9');
+INSERT INTO items VALUES(NULL,'Hanging Leather Sleeves (N/S)',57,5064,0,'13c8');
+INSERT INTO items VALUES(NULL,'leather sleeves',254,5061,0,'13c5');
+INSERT INTO items VALUES(NULL,'leather gorget',254,5063,0,'13c7');
+INSERT INTO items VALUES(NULL,'leather gloves',254,5062,0,'13c6');
+INSERT INTO items VALUES(NULL,'Hanging Chainmail Leggings (W/E)',30,5057,0,'13c1');
+INSERT INTO items VALUES(NULL,'Hanging Chainmail Tunic (W/E)',30,5058,0,'13c2');
+INSERT INTO items VALUES(NULL,'Hanging Leather Sleeves (W/E)',57,5071,0,'13cf');
+INSERT INTO items VALUES(NULL,'Hanging Leather Tunic (N/S)',57,5066,0,'13ca');
+INSERT INTO items VALUES(NULL,'leather tunic',254,5068,0,'13cc');
+INSERT INTO items VALUES(NULL,'leather leggings',254,5067,0,'13cb');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 13',26,2057,0,'809');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 12',26,2056,0,'808');
+INSERT INTO items VALUES(NULL,'Backgammon Board 1',249,3612,0,'e1c');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 7',26,2051,0,'803');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 6',26,2050,0,'802');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 5',26,2049,0,'801');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 4',26,2048,0,'800');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 11',26,2055,0,'807');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 10',26,2054,0,'806');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 9',26,2053,0,'805');
+INSERT INTO items VALUES(NULL,'Bridge (W/E) 8',26,2052,0,'804');
+INSERT INTO items VALUES(NULL,'Lard',135,7818,0,'1e8a');
+INSERT INTO items VALUES(NULL,'Tiny Wall 6',189,50,0,'32');
+INSERT INTO items VALUES(NULL,'Rock 16',216,6005,0,'1775');
+INSERT INTO items VALUES(NULL,'Rock 15',216,6004,0,'1774');
+INSERT INTO items VALUES(NULL,'Rock 18',216,6007,0,'1777');
+INSERT INTO items VALUES(NULL,'Rock 17',216,6006,0,'1776');
+INSERT INTO items VALUES(NULL,'Rock 12',216,6001,0,'1771');
+INSERT INTO items VALUES(NULL,'Rock 14',216,6003,0,'1773');
+INSERT INTO items VALUES(NULL,'Rock 13',216,6002,0,'1772');
+INSERT INTO items VALUES(NULL,'Rock 20',216,6009,0,'1779');
+INSERT INTO items VALUES(NULL,'Rock 19',216,6008,0,'1778');
+INSERT INTO items VALUES(NULL,'Bow and Arrows (N/S) 1',343,5468,0,'155c');
+INSERT INTO items VALUES(NULL,'Bow and Arrows (W/E) 1',343,5470,0,'155e');
+INSERT INTO items VALUES(NULL,'Bow and Arrows (N/S) 2',343,5469,0,'155d');
+INSERT INTO items VALUES(NULL,'Bow and Arrows (W/E) 2',343,5471,0,'155f');
+INSERT INTO items VALUES(NULL,'Vat w. Water 2 (1/6)',242,5457,0,'1551');
+INSERT INTO items VALUES(NULL,'Vat w. Water 1 (1/6)',242,5456,0,'1550');
+INSERT INTO items VALUES(NULL,'Vat w. Water (3/6)',242,5459,0,'1553');
+INSERT INTO items VALUES(NULL,'Vat w. Water (2/6)',242,5458,0,'1552');
+INSERT INTO items VALUES(NULL,'bascinet',259,5132,0,'dull_copper_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Vat w. Water (4/6)',242,5460,0,'1554');
+INSERT INTO items VALUES(NULL,'Vat w. Water 2 (5/6)',242,5462,0,'1556');
+INSERT INTO items VALUES(NULL,'Vat w. Water (6/6)',242,5464,0,'1558');
+INSERT INTO items VALUES(NULL,'Grass 2',344,6014,0,'177e');
+INSERT INTO items VALUES(NULL,'Grass 1',344,6013,0,'177d');
+INSERT INTO items VALUES(NULL,'Grass 3',344,6015,0,'177f');
+INSERT INTO items VALUES(NULL,'Rock 21',216,6010,0,'177a');
+INSERT INTO items VALUES(NULL,'Rock 23',216,6012,0,'177c');
+INSERT INTO items VALUES(NULL,'Rock 22',216,6011,0,'177b');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 6',12,6662,0,'1a06');
+INSERT INTO items VALUES(NULL,'Wall 2',50,512,0,'200');
+INSERT INTO items VALUES(NULL,'Wall 5',50,515,0,'203');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (W/E) 6',116,7511,0,'1d57');
+INSERT INTO items VALUES(NULL,'Hanging Skeleton 2',12,6658,0,'1a02');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (W/E) 6',116,7505,0,'1d51');
+INSERT INTO items VALUES(NULL,'Lava 34',44,12971,0,'32ab');
+INSERT INTO items VALUES(NULL,'Lava 35',44,12972,0,'32ac');
+INSERT INTO items VALUES(NULL,'Leaves 2 (1/14)',4,3420,0,'d5c');
+INSERT INTO items VALUES(NULL,'Gold Coins 1',305,3822,0,'eee');
+INSERT INTO items VALUES(NULL,'Leaves 2 (2/14)',4,3421,0,'d5d');
+INSERT INTO items VALUES(NULL,'Stretched Hide 4 (N/S) (2/2)',57,4222,0,'107e');
+INSERT INTO items VALUES(NULL,'Stretched Hide 2 (N/S)',57,4219,0,'107b');
+INSERT INTO items VALUES(NULL,'Leaves 2 (3/14)',4,3422,0,'d5e');
+INSERT INTO items VALUES(NULL,'Stretched Hide 1 (N/S)',57,4218,0,'107a');
+INSERT INTO items VALUES(NULL,'Curtain 4',82,559,0,'22f');
+INSERT INTO items VALUES(NULL,'Curtain 3',82,558,0,'22e');
+INSERT INTO items VALUES(NULL,'Curtain 2',82,557,0,'22d');
+INSERT INTO items VALUES(NULL,'Curtain 1',82,556,0,'22c');
+INSERT INTO items VALUES(NULL,'Wall 13',82,555,0,'22b');
+INSERT INTO items VALUES(NULL,'Wall 12',82,554,0,'22a');
+INSERT INTO items VALUES(NULL,'Forge (S/N) (3/3)',30,6554,0,'199a');
+INSERT INTO items VALUES(NULL,'Banner 6 (N/S) 1',128,5675,0,'162b');
+INSERT INTO items VALUES(NULL,'Balista 249',76,16356,0,'3fe4');
+INSERT INTO items VALUES(NULL,'Leaves 1',4,6943,0,'1b1f');
+INSERT INTO items VALUES(NULL,'Banner 5 (N/S) 2',128,5674,0,'162a');
+INSERT INTO items VALUES(NULL,'Banner 7 (N/S) 1',128,5678,0,'162e');
+INSERT INTO items VALUES(NULL,'Wall 11',82,553,0,'229');
+INSERT INTO items VALUES(NULL,'Wall 10',82,552,0,'228');
+INSERT INTO items VALUES(NULL,'Wall 9',82,551,0,'227');
+INSERT INTO items VALUES(NULL,'Wall 8',82,550,0,'226');
+INSERT INTO items VALUES(NULL,'Catapult 50',72,5764,0,'1684');
+INSERT INTO items VALUES(NULL,'Wall 7',82,547,0,'223');
+INSERT INTO items VALUES(NULL,'Wall 6',82,546,0,'222');
+INSERT INTO items VALUES(NULL,'Wall 5',82,545,0,'221');
+INSERT INTO items VALUES(NULL,'Wall 4',82,544,0,'220');
+INSERT INTO items VALUES(NULL,'Necklace (Long)',60,4233,0,'1089');
+INSERT INTO items VALUES(NULL,'Tree 1 (4/4)',4,3396,0,'d44');
+INSERT INTO items VALUES(NULL,'Bowl of Flour',19,2590,0,'a1e');
+INSERT INTO items VALUES(NULL,'Hanging Lantern 2 (Off)',73,2589,0,'a1d');
+INSERT INTO items VALUES(NULL,'Lantern Post (W/E)',73,2591,0,'a1f');
+INSERT INTO items VALUES(NULL,'Hanging Lantern 2 (On)',73,2586,0,'a1a');
+INSERT INTO items VALUES(NULL,'nose helmet',131,5134,0,'shadow_helmets_nose');
+INSERT INTO items VALUES(NULL,'Skinned Goat (W/E)',135,7817,0,'1e89');
+INSERT INTO items VALUES(NULL,'Hanging Lantern 1 (On)',73,2581,0,'a15');
+INSERT INTO items VALUES(NULL,'Torch (On)',73,2578,0,'a12');
+INSERT INTO items VALUES(NULL,'Dirty Plate 3',14,2585,0,'a19');
+INSERT INTO items VALUES(NULL,'Hanging Lantern 1 (Off)',73,2584,0,'a18');
+INSERT INTO items VALUES(NULL,'Arrow',34,3903,0,'f3f');
+INSERT INTO items VALUES(NULL,'Chicken',135,7815,0,'1e87');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 21',100,7335,0,'1ca7');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 20',100,7334,0,'1ca6');
+INSERT INTO items VALUES(NULL,'Platform 7',101,1987,0,'7c3');
+INSERT INTO items VALUES(NULL,'Platform 6',101,1986,0,'7c2');
+INSERT INTO items VALUES(NULL,'Platform 9',101,1989,0,'7c5');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 16',100,7330,0,'1ca2');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 15',100,7329,0,'1ca1');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 14',100,7328,0,'1ca0');
+INSERT INTO items VALUES(NULL,'Dark Wooden Plank 1',295,1993,0,'7c9');
+INSERT INTO items VALUES(NULL,'Carpeted Rostrum 5',102,1992,0,'7c8');
+INSERT INTO items VALUES(NULL,'Lord British Throne (1/2)',78,5414,0,'1526');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 23',100,7337,0,'1ca9');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 22',100,7336,0,'1ca8');
+INSERT INTO items VALUES(NULL,'Lord British Throne (2/2)',78,5415,0,'1527');
+INSERT INTO items VALUES(NULL,'Statue 6 (1/3)',54,10910,0,'2a9e');
+INSERT INTO items VALUES(NULL,'Statue 6 (2/3)',54,10911,0,'2a9f');
+INSERT INTO items VALUES(NULL,'Vat w. Vines 2 (2/6)',242,5408,0,'1520');
+INSERT INTO items VALUES(NULL,'Vat w. Vines (3/6)',242,5409,0,'1521');
+INSERT INTO items VALUES(NULL,'Vat w. Vines (4/6)',242,5410,0,'1522');
+INSERT INTO items VALUES(NULL,'Vat w. Vines (5/6)',242,5411,0,'1523');
+INSERT INTO items VALUES(NULL,'Troll',115,8425,0,'20e9');
+INSERT INTO items VALUES(NULL,'Forge (S/N) (1/3)',30,6546,0,'1992');
+INSERT INTO items VALUES(NULL,'Slime',115,8424,0,'20e8');
+INSERT INTO items VALUES(NULL,'Doppleganger',115,9741,0,'260d');
+INSERT INTO items VALUES(NULL,'Forge (S/N) (2/3)',30,6550,0,'1996');
+INSERT INTO items VALUES(NULL,'Dark Wooden Plank 2',295,1994,0,'7ca');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 2 (N/S) (3/3)',100,7343,0,'1caf');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 2 (N/S) (2/3)',100,7342,0,'1cae');
+INSERT INTO items VALUES(NULL,'Dark Wooden Plank 3',295,1995,0,'7cb');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 26',100,7340,0,'1cac');
+INSERT INTO items VALUES(NULL,'Dark Wooden Plank 5',295,1997,0,'7cd');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 24',100,7338,0,'1caa');
+INSERT INTO items VALUES(NULL,'Dark Wooden Plank 7',295,1999,0,'7cf');
+INSERT INTO items VALUES(NULL,'Mushroom 4',109,4392,0,'1128');
+INSERT INTO items VALUES(NULL,'Mushroom 5',109,4393,0,'1129');
+INSERT INTO items VALUES(NULL,'plate helmet',181,5138,0,'verite_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Spike Trap (N/S) 6',109,4384,0,'1120');
+INSERT INTO items VALUES(NULL,'Spike Trap (N/S) 7',109,4385,0,'1121');
+INSERT INTO items VALUES(NULL,'Trigger 1',109,4386,0,'1122');
+INSERT INTO items VALUES(NULL,'Trigger 2',109,4387,0,'1123');
+INSERT INTO items VALUES(NULL,'Trigger 3',109,4388,0,'1124');
+INSERT INTO items VALUES(NULL,'Mushroom 1',109,4389,0,'1125');
+INSERT INTO items VALUES(NULL,'Mushroom 2',109,4390,0,'1126');
+INSERT INTO items VALUES(NULL,'Mushroom 3',109,4391,0,'1127');
+INSERT INTO items VALUES(NULL,'Copper Ingot (N/S)',80,7142,0,'1be6');
+INSERT INTO items VALUES(NULL,'Copper Ingots 1 (N/S)',80,7143,0,'1be7');
+INSERT INTO items VALUES(NULL,'Copper Ingots 1 (W/E)',80,7140,0,'1be4');
+INSERT INTO items VALUES(NULL,'Copper Ingots 2 (W/E)',80,7141,0,'1be5');
+INSERT INTO items VALUES(NULL,'Logs 2 (N/S)',107,7138,0,'1be2');
+INSERT INTO items VALUES(NULL,'Copper Ingot (W/E)',80,7139,0,'1be3');
+INSERT INTO items VALUES(NULL,'Log (N/S)',107,7136,0,'1be0');
+INSERT INTO items VALUES(NULL,'Logs 1 (N/S)',107,7137,0,'1be1');
+INSERT INTO items VALUES(NULL,'Copper Ingots 2 (N/S)',80,7144,0,'1be8');
+INSERT INTO items VALUES(NULL,'Gold Ingot (W/E)',80,7145,0,'1be9');
+INSERT INTO items VALUES(NULL,'Iron Ingot (W/E)',80,7151,0,'1bef');
+INSERT INTO items VALUES(NULL,'Gold Ingots 1 (N/S)',80,7149,0,'1bed');
+INSERT INTO items VALUES(NULL,'Gold Ingots 2 (N/S)',80,7150,0,'1bee');
+INSERT INTO items VALUES(NULL,'Gold Ingots 2 (W/E)',80,7147,0,'1beb');
+INSERT INTO items VALUES(NULL,'Gold Ingot (N/S)',80,7148,0,'1bec');
+INSERT INTO items VALUES(NULL,'Gold Ingots 1 (W/E)',80,7146,0,'1bea');
+INSERT INTO items VALUES(NULL,'Mushroom 6',109,4394,0,'112a');
+INSERT INTO items VALUES(NULL,'Dart Trap (N/S; fitting) ',109,4395,0,'112b');
+INSERT INTO items VALUES(NULL,'Dart Trap (N/S) 1',109,4396,0,'112c');
+INSERT INTO items VALUES(NULL,'Dart Trap (N/S) 2',109,4397,0,'112d');
+INSERT INTO items VALUES(NULL,'Dart Trap (N/S) 3',109,4398,0,'112e');
+INSERT INTO items VALUES(NULL,'Dart Trap (W/E; fitting) ',109,4399,0,'112f');
+INSERT INTO items VALUES(NULL,'close helmet',345,5128,0,'copper_helmets_close');
+INSERT INTO items VALUES(NULL,'Rack 16',113,4701,0,'125d');
+INSERT INTO items VALUES(NULL,'Black Potion',180,3846,0,'potion_nightsight');
+INSERT INTO items VALUES(NULL,'Bird (big)',115,8430,0,'20ee');
+INSERT INTO items VALUES(NULL,'Air Elemental',115,8429,0,'20ed');
+INSERT INTO items VALUES(NULL,'Wall 4',277,335,0,'14f');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (W/E) (4/5)',89,2938,0,'b7a');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (W/E) (5/5)',89,2939,0,'b7b');
+INSERT INTO items VALUES(NULL,'Wooden Table 5 (W/E)',89,2940,0,'b7c');
+INSERT INTO items VALUES(NULL,'Wooden Table 6 (W/E)',89,2941,0,'b7d');
+INSERT INTO items VALUES(NULL,'Sandstone Table 1 (N/S) (1/3)',89,2942,0,'b7e');
+INSERT INTO items VALUES(NULL,'Sandstone Table 1 (N/S) (2/3)',89,2943,0,'b7f');
+INSERT INTO items VALUES(NULL,'Edge 1',316,330,0,'14a');
+INSERT INTO items VALUES(NULL,'Lava 5',37,6706,0,'1a32');
+INSERT INTO items VALUES(NULL,'Lava 6',37,6711,0,'1a37');
+INSERT INTO items VALUES(NULL,'Wall 26',98,16119,0,'3ef7');
+INSERT INTO items VALUES(NULL,'platemail gorget',18,5139,0,'valorite_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (W/E) (1/5)',89,2928,0,'b70');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (W/E) (2/5)',89,2929,0,'b71');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (W/E) (3/5)',89,2930,0,'b72');
+INSERT INTO items VALUES(NULL,'Post 1',22,325,0,'145');
+INSERT INTO items VALUES(NULL,'Wooden Table 2 (W/E) (5/5)',89,2932,0,'b74');
+INSERT INTO items VALUES(NULL,'Wooden Table 3 (W/E) (1/2)',89,2933,0,'b75');
+INSERT INTO items VALUES(NULL,'Wooden Table 3 (W/E) (2/2)',89,2934,0,'b76');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (W/E) (1/5)',89,2935,0,'b77');
+INSERT INTO items VALUES(NULL,'Wooden Table 4 (W/E) (2/5)',89,2936,0,'b78');
+INSERT INTO items VALUES(NULL,'Lava 7',37,6715,0,'1a3b');
+INSERT INTO items VALUES(NULL,'Lava 8',37,6719,0,'1a3f');
+INSERT INTO items VALUES(NULL,'Post 4',22,328,0,'148');
+INSERT INTO items VALUES(NULL,'Arch 6',316,329,0,'149');
+INSERT INTO items VALUES(NULL,'Tinker Tools',240,7868,0,'1ebc');
+INSERT INTO items VALUES(NULL,'Iron Ore 2',80,6584,0,'19b8');
+INSERT INTO items VALUES(NULL,'Iron Ore 3',80,6585,0,'19b9');
+INSERT INTO items VALUES(NULL,'Ship 45',137,16103,0,'3ee7');
+INSERT INTO items VALUES(NULL,'Ship 44',137,16102,0,'3ee6');
+INSERT INTO items VALUES(NULL,'Ship 43',137,16101,0,'3ee5');
+INSERT INTO items VALUES(NULL,'Ship 42',137,16100,0,'3ee4');
+INSERT INTO items VALUES(NULL,'Sail 15',86,16099,0,'3ee3');
+INSERT INTO items VALUES(NULL,'Mast 9',8,16098,0,'3ee2');
+INSERT INTO items VALUES(NULL,'Sail 14',86,16097,0,'3ee1');
+INSERT INTO items VALUES(NULL,'Sail 11',86,16096,0,'3ee0');
+INSERT INTO items VALUES(NULL,'Ship 46',137,16105,0,'3ee9');
+INSERT INTO items VALUES(NULL,'Iron Gate 1 (W/NE)',120,2094,0,'82e');
+INSERT INTO items VALUES(NULL,'Iron Gate 1 (S/NE)',120,2090,0,'82a');
+INSERT INTO items VALUES(NULL,'Iron Gate 1 (W/SE)',120,2092,0,'82c');
+INSERT INTO items VALUES(NULL,'Hanging Ringmail Sleeves (N/S)',30,5097,0,'13e9');
+INSERT INTO items VALUES(NULL,'Hanging Ringmail Tunic (W/E)',30,5096,0,'13e8');
+INSERT INTO items VALUES(NULL,'Smith''s Hammer (W/E)',30,5091,0,'13e3');
+INSERT INTO items VALUES(NULL,'Hanging Studded Tunic (W/E)',57,5088,0,'13e0');
+INSERT INTO items VALUES(NULL,'Hanging Ringmail Tunic (N/S)',30,5095,0,'13e7');
+INSERT INTO items VALUES(NULL,'Hanging Ringmail Leggings (W/E)',30,5094,0,'13e6');
+INSERT INTO items VALUES(NULL,'Hanging Ringmail Leggings (N/S)',30,5093,0,'13e5');
+INSERT INTO items VALUES(NULL,'Smith''s Hammer (N/S)',30,5092,0,'13e4');
+INSERT INTO items VALUES(NULL,'butcher knife',3,5110,0,'13f6');
+INSERT INTO items VALUES(NULL,'helmet',345,5130,0,'copper_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Ship 49',137,16108,0,'3eec');
+INSERT INTO items VALUES(NULL,'Ship 48',137,16107,0,'3eeb');
+INSERT INTO items VALUES(NULL,'Ship 47',137,16106,0,'3eea');
+INSERT INTO items VALUES(NULL,'Treasure (11/41)',215,6986,0,'1b4a');
+INSERT INTO items VALUES(NULL,'ringmail tunic',38,5100,0,'13ec');
+INSERT INTO items VALUES(NULL,'ringmail gloves',38,5099,0,'13eb');
+INSERT INTO items VALUES(NULL,'Hanging Ringmail Sleeves (W/E)',30,5098,0,'13ea');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',38,5103,0,'13ef');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 8',337,7741,0,'1e3d');
+INSERT INTO items VALUES(NULL,'Iron Gate 1 (S/NW)',120,2088,0,'828');
+INSERT INTO items VALUES(NULL,'Roof 29',84,1503,0,'5df');
+INSERT INTO items VALUES(NULL,'Iron Gate 1 (S/SE)',120,2086,0,'826');
+INSERT INTO items VALUES(NULL,'Fence 1',346,2081,0,'821');
+INSERT INTO items VALUES(NULL,'Fence 3',346,2083,0,'823');
+INSERT INTO items VALUES(NULL,'Fence 2',346,2082,0,'822');
+INSERT INTO items VALUES(NULL,'Roof 27',84,1501,0,'5dd');
+INSERT INTO items VALUES(NULL,'Treasure (16/41)',215,6991,0,'1b4f');
+INSERT INTO items VALUES(NULL,'Floppy Hat',58,5907,0,'1713');
+INSERT INTO items VALUES(NULL,'Thigh Boots (W/E)',90,5906,0,'1712');
+INSERT INTO items VALUES(NULL,'Thigh Boots (N/S)',90,5905,0,'1711');
+INSERT INTO items VALUES(NULL,'Shoes (W/E)',90,5904,0,'1710');
+INSERT INTO items VALUES(NULL,'Straw Hat',58,5911,0,'1717');
+INSERT INTO items VALUES(NULL,'Tall Straw Hat',58,5910,0,'1716');
+INSERT INTO items VALUES(NULL,'Cap',58,5909,0,'1715');
+INSERT INTO items VALUES(NULL,'Wide-brim Hat',58,5908,0,'1714');
+INSERT INTO items VALUES(NULL,'Bonnet',58,5913,0,'1719');
+INSERT INTO items VALUES(NULL,'Wizard''s Hat',58,5912,0,'1718');
+INSERT INTO items VALUES(NULL,'Jesters Cap',58,5916,0,'171c');
+INSERT INTO items VALUES(NULL,'Tricorne Hat',58,5915,0,'171b');
+INSERT INTO items VALUES(NULL,'Feathered Hat',58,5914,0,'171a');
+INSERT INTO items VALUES(NULL,'Banana 2 (N/S)',19,5919,0,'171f');
+INSERT INTO items VALUES(NULL,'Banana 1 (W/E)',19,5918,0,'171e');
+INSERT INTO items VALUES(NULL,'Banana 1 (N/S)',19,5917,0,'171d');
+INSERT INTO items VALUES(NULL,'Wall 1',189,26,0,'1a');
+INSERT INTO items VALUES(NULL,'Wall 3',189,28,0,'1c');
+INSERT INTO items VALUES(NULL,'Wall 2',189,27,0,'1b');
+INSERT INTO items VALUES(NULL,'Wall 5',189,30,0,'1e');
+INSERT INTO items VALUES(NULL,'Wall 4',189,29,0,'1d');
+INSERT INTO items VALUES(NULL,'Wall 6',189,31,0,'1f');
+INSERT INTO items VALUES(NULL,'heater shield',347,7030,0,'copper_shields_heater');
+INSERT INTO items VALUES(NULL,'plate armor',181,7172,0,'verite_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Small Wall 2',158,17,0,'11');
+INSERT INTO items VALUES(NULL,'Small Wall 1',158,16,0,'10');
+INSERT INTO items VALUES(NULL,'Small Wall 4',158,19,0,'13');
+INSERT INTO items VALUES(NULL,'Small Wall 3',158,18,0,'12');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',158,21,0,'15');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',158,20,0,'14');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',158,23,0,'17');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',158,22,0,'16');
+INSERT INTO items VALUES(NULL,'Tiny Wall 6',158,25,0,'19');
+INSERT INTO items VALUES(NULL,'Tiny Wall 5',158,24,0,'18');
+INSERT INTO items VALUES(NULL,'Tiller Man 8',10,15953,0,'3e51');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 2',337,7735,0,'1e37');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 1',337,7734,0,'1e36');
+INSERT INTO items VALUES(NULL,'Treasure (5/41)',215,6979,0,'1b43');
+INSERT INTO items VALUES(NULL,'Window 4',50,522,0,'20a');
+INSERT INTO items VALUES(NULL,'Lava 28',44,12965,0,'32a5');
+INSERT INTO items VALUES(NULL,'Small Wall 2',50,524,0,'20c');
+INSERT INTO items VALUES(NULL,'Small Wall 1',50,523,0,'20b');
+INSERT INTO items VALUES(NULL,'Lava 23',44,12960,0,'32a0');
+INSERT INTO items VALUES(NULL,'Lava 24',44,12961,0,'32a1');
+INSERT INTO items VALUES(NULL,'Lava 25',44,12962,0,'32a2');
+INSERT INTO items VALUES(NULL,'Wall 1',133,527,0,'20f');
+INSERT INTO items VALUES(NULL,'Treasure (7/41)',215,6981,0,'1b45');
+INSERT INTO items VALUES(NULL,'Lava 31',44,12968,0,'32a8');
+INSERT INTO items VALUES(NULL,'Lava 32',44,12969,0,'32a9');
+INSERT INTO items VALUES(NULL,'Treasure (6/41)',215,6980,0,'1b44');
+INSERT INTO items VALUES(NULL,'Treasure (9/41)',215,6983,0,'1b47');
+INSERT INTO items VALUES(NULL,'Iron Ore 4',80,6586,0,'19ba');
+INSERT INTO items VALUES(NULL,'Plucked Chicken',135,7819,0,'1e8b');
+INSERT INTO items VALUES(NULL,'Pig''s Feet (W/E)',135,7820,0,'1e8c');
+INSERT INTO items VALUES(NULL,'Dartboard 2 (N/S)',249,7728,0,'1e30');
+INSERT INTO items VALUES(NULL,'Pig''s Head (W/E)',135,7823,0,'1e8f');
+INSERT INTO items VALUES(NULL,'Empty Toolkit 1',240,7862,0,'1eb6');
+INSERT INTO items VALUES(NULL,'Pig''s Feet (N/S)',135,7821,0,'1e8d');
+INSERT INTO items VALUES(NULL,'Pig''s Head (N/S)',135,7822,0,'1e8e');
+INSERT INTO items VALUES(NULL,'Wall 3',50,513,0,'201');
+INSERT INTO items VALUES(NULL,'Lava 37',44,12974,0,'32ae');
+INSERT INTO items VALUES(NULL,'Lava 38',44,12975,0,'32af');
+INSERT INTO items VALUES(NULL,'Wall 4',50,514,0,'202');
+INSERT INTO items VALUES(NULL,'Wall 7',50,517,0,'205');
+INSERT INTO items VALUES(NULL,'Lava 33',44,12970,0,'32aa');
+INSERT INTO items VALUES(NULL,'Window 1',50,519,0,'207');
+INSERT INTO items VALUES(NULL,'Wall 8',50,518,0,'206');
+INSERT INTO items VALUES(NULL,'Window 3',50,521,0,'209');
+INSERT INTO items VALUES(NULL,'Window 2',50,520,0,'208');
+INSERT INTO items VALUES(NULL,'Small Palm 1',264,3225,0,'c99');
+INSERT INTO items VALUES(NULL,'Fan Plant',45,3224,0,'c98');
+INSERT INTO items VALUES(NULL,'Water 9',33,13430,0,'3476');
+INSERT INTO items VALUES(NULL,'Fence 2',122,2102,0,'836');
+INSERT INTO items VALUES(NULL,'Fence 3',122,2103,0,'837');
+INSERT INTO items VALUES(NULL,'Water 5',33,13426,0,'3472');
+INSERT INTO items VALUES(NULL,'Toolkit 1 (W/E)',240,7864,0,'1eb8');
+INSERT INTO items VALUES(NULL,'Water 6',33,13427,0,'3473');
+INSERT INTO items VALUES(NULL,'Toolkit 1 (N/S)',240,7865,0,'1eb9');
+INSERT INTO items VALUES(NULL,'Skinned Goat (N/S)',135,7816,0,'1e88');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',125,5103,0,'golden_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 21',2,7810,0,'1e82');
+INSERT INTO items VALUES(NULL,'Bird 1 (N/S)',135,7811,0,'1e83');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 19',2,7808,0,'1e80');
+INSERT INTO items VALUES(NULL,'Unfinished Woodwork 20',2,7809,0,'1e81');
+INSERT INTO items VALUES(NULL,'Bird 2 (W/E)',135,7814,0,'1e86');
+INSERT INTO items VALUES(NULL,'Balista 200',76,16307,0,'3fb3');
+INSERT INTO items VALUES(NULL,'Bird 1 (W/E)',135,7812,0,'1e84');
+INSERT INTO items VALUES(NULL,'Bird 2 (N/S)',135,7813,0,'1e85');
+INSERT INTO items VALUES(NULL,'Double Bed (N/S) (2/4)',91,2687,0,'a7f');
+INSERT INTO items VALUES(NULL,'Double Bed (N/S) (1/4)',91,2686,0,'a7e');
+INSERT INTO items VALUES(NULL,'Double Bed 2 (W/E) (4/4)',91,2685,0,'a7d');
+INSERT INTO items VALUES(NULL,'Double Bed 2 (W/E) (3/4)',91,2684,0,'a7c');
+INSERT INTO items VALUES(NULL,'Double Bed 1 (W/E) (4/4)',91,2683,0,'a7b');
+INSERT INTO items VALUES(NULL,'Double Bed 1 (W/E) (3/4)',91,2682,0,'a7a');
+INSERT INTO items VALUES(NULL,'Stone Oven 1 (W/E) (1/2)',103,2347,0,'92b');
+INSERT INTO items VALUES(NULL,'Stone Oven 1 (W/E) (2/2)',103,2348,0,'92c');
+INSERT INTO items VALUES(NULL,'Double Bed (W/E) (2/4)',91,2681,0,'a79');
+INSERT INTO items VALUES(NULL,'Double Bed (W/E) (1/4)',91,2680,0,'a78');
+INSERT INTO items VALUES(NULL,'Empty Double Bed (N/S) (4/4)',91,2679,0,'a77');
+INSERT INTO items VALUES(NULL,'Empty Double Bed (N/S) (3/4)',91,2678,0,'a76');
+INSERT INTO items VALUES(NULL,'Empty Double Bed (N/S) (2/4)',91,2677,0,'a75');
+INSERT INTO items VALUES(NULL,'Empty Double Bed (N/S) (1/4)',91,2676,0,'a74');
+INSERT INTO items VALUES(NULL,'Empty Double Bed (W/E) (4/4)',91,2675,0,'a73');
+INSERT INTO items VALUES(NULL,'Empty Double Bed (W/E) (3/4)',91,2674,0,'a72');
+INSERT INTO items VALUES(NULL,'Empty Double Bed (W/E) (2/4)',91,2673,0,'a71');
+INSERT INTO items VALUES(NULL,'Empty Double Bed (W/E) (1/4)',91,2672,0,'a70');
+INSERT INTO items VALUES(NULL,'Grapevines 11',285,15634,0,'3d12');
+INSERT INTO items VALUES(NULL,'Peach 2',19,5932,0,'172c');
+INSERT INTO items VALUES(NULL,'platemail arms',269,5136,0,'dull_copper_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'Bees 2',224,2339,0,'923');
+INSERT INTO items VALUES(NULL,'Knife (E/W)',14,2469,0,'9a5');
+INSERT INTO items VALUES(NULL,'Cooper''s Bench (N/S) (2/2)',107,6650,0,'19fa');
+INSERT INTO items VALUES(NULL,'Balista 206',76,16313,0,'3fb9');
+INSERT INTO items VALUES(NULL,'Balista 205',76,16312,0,'3fb8');
+INSERT INTO items VALUES(NULL,'Blood 9',55,7369,0,'1cc9');
+INSERT INTO items VALUES(NULL,'Blood 8',55,7368,0,'1cc8');
+INSERT INTO items VALUES(NULL,'Balista 198',76,16305,0,'3fb1');
+INSERT INTO items VALUES(NULL,'Balista 197',76,16304,0,'3fb0');
+INSERT INTO items VALUES(NULL,'Blood 7',55,7367,0,'1cc7');
+INSERT INTO items VALUES(NULL,'Balista 199',76,16306,0,'3fb2');
+INSERT INTO items VALUES(NULL,'Balista 202',76,16309,0,'3fb5');
+INSERT INTO items VALUES(NULL,'Balista 201',76,16308,0,'3fb4');
+INSERT INTO items VALUES(NULL,'Balista 204',76,16311,0,'3fb7');
+INSERT INTO items VALUES(NULL,'Balista 203',76,16310,0,'3fb6');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 10',110,1933,0,'78d');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 11',110,1934,0,'78e');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 12',110,1935,0,'78f');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 7',110,1930,0,'78a');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 8',110,1931,0,'78b');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 9',110,1932,0,'78c');
+INSERT INTO items VALUES(NULL,'Glass Pitcher (empty)',14,2471,0,'9a7');
+INSERT INTO items VALUES(NULL,'Cannon Ball',67,3699,0,'e73');
+INSERT INTO items VALUES(NULL,'metal shield',347,7035,0,'copper_shields_shield');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 1',110,1924,0,'784');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 2',110,1925,0,'785');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 3',110,1926,0,'786');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 4',110,1927,0,'787');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 24',302,1920,0,'780');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 25',302,1921,0,'781');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 12',121,1922,0,'782');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 13',121,1923,0,'783');
+INSERT INTO items VALUES(NULL,'Short Cannon (E/W) (2/2)',67,3698,0,'e72');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 5',110,1928,0,'788');
+INSERT INTO items VALUES(NULL,'Stone 2 Stairs 6',110,1929,0,'789');
+INSERT INTO items VALUES(NULL,'Rotating Head',28,7967,0,'1f1f');
+INSERT INTO items VALUES(NULL,'Blood 14',55,7374,0,'1cce');
+INSERT INTO items VALUES(NULL,'Blood 13',55,7373,0,'1ccd');
+INSERT INTO items VALUES(NULL,'Balista 209',76,16316,0,'3fbc');
+INSERT INTO items VALUES(NULL,'Blood 15',55,7375,0,'1ccf');
+INSERT INTO items VALUES(NULL,'Blood 10',55,7370,0,'1cca');
+INSERT INTO items VALUES(NULL,'Balista 210',76,16317,0,'3fbd');
+INSERT INTO items VALUES(NULL,'Blood 12',55,7372,0,'1ccc');
+INSERT INTO items VALUES(NULL,'Blood 11',55,7371,0,'1ccb');
+INSERT INTO items VALUES(NULL,'Bolt of Cloth 7',57,3995,0,'f9b');
+INSERT INTO items VALUES(NULL,'Bolt of Cloth 8',57,3996,0,'f9c');
+INSERT INTO items VALUES(NULL,'Bolt of Cloth 6',57,3994,0,'f9a');
+INSERT INTO items VALUES(NULL,'Scissors (W/E)',57,3999,0,'f9f');
+INSERT INTO items VALUES(NULL,'Sewing Kit',57,3997,0,'f9d');
+INSERT INTO items VALUES(NULL,'Scissors (N/S)',57,3998,0,'f9e');
+INSERT INTO items VALUES(NULL,'Purple Magical Crystal',186,7964,0,'1f1c');
+INSERT INTO items VALUES(NULL,'helmet',40,5130,0,'bronze_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Leaves 1 (9/15)',4,3405,0,'d4d');
+INSERT INTO items VALUES(NULL,'Stone Face (W/E) 1',109,4367,0,'110f');
+INSERT INTO items VALUES(NULL,'Telescope (6/66)',182,5214,0,'145e');
+INSERT INTO items VALUES(NULL,'Spike Trap (W/E) 6',109,4365,0,'110d');
+INSERT INTO items VALUES(NULL,'Spike Trap (W/E) 7',109,4366,0,'110e');
+INSERT INTO items VALUES(NULL,'Spike Trap (W/E) 4',109,4363,0,'110b');
+INSERT INTO items VALUES(NULL,'Spike Trap (W/E) 5',109,4364,0,'110c');
+INSERT INTO items VALUES(NULL,'Telescope (3/66)',182,5211,0,'145b');
+INSERT INTO items VALUES(NULL,'Spike Trap (W/E) 3',109,4362,0,'110a');
+INSERT INTO items VALUES(NULL,'Brush 2 (W/E)',13,4979,0,'1373');
+INSERT INTO items VALUES(NULL,'Brush 2 (N/S)',13,4978,0,'1372');
+INSERT INTO items VALUES(NULL,'Bridle (W/E)',13,4981,0,'1375');
+INSERT INTO items VALUES(NULL,'Long Cannon (W/E) (1/3)',67,3732,0,'e94');
+INSERT INTO items VALUES(NULL,'Horse Barding (W/E) (2/2)',13,4983,0,'1377');
+INSERT INTO items VALUES(NULL,'Dog Hound',115,9608,0,'2588');
+INSERT INTO items VALUES(NULL,'Long Cannon (W/E) (3/3)',67,3734,0,'e96');
+INSERT INTO items VALUES(NULL,'Dead Wood',112,3984,0,'f90');
+INSERT INTO items VALUES(NULL,'Wyrm''s Heart',112,3985,0,'f91');
+INSERT INTO items VALUES(NULL,'Bolt of Cloth 2',57,3990,0,'f96');
+INSERT INTO items VALUES(NULL,'Bolt of Cloth 3',57,3991,0,'f97');
+INSERT INTO items VALUES(NULL,'Bolt of Cloth 1',57,3989,0,'f95');
+INSERT INTO items VALUES(NULL,'Bolt of Cloth 4',57,3992,0,'f98');
+INSERT INTO items VALUES(NULL,'Bolt of Cloth 5',57,3993,0,'f99');
+INSERT INTO items VALUES(NULL,'buckler',347,7027,0,'copper_shields_buckler');
+INSERT INTO items VALUES(NULL,'Saw Trap (N/S) 4',109,4358,0,'1106');
+INSERT INTO items VALUES(NULL,'bone gloves',154,5205,0,'1455');
+INSERT INTO items VALUES(NULL,'bone helmet',154,5206,0,'1456');
+INSERT INTO items VALUES(NULL,'Saw Trap (N/S) 3',109,4357,0,'1105');
+INSERT INTO items VALUES(NULL,'Stone Face (N/S; w. fire) 5',109,4354,0,'1102');
+INSERT INTO items VALUES(NULL,'Saw Trap (N/S) 1',109,4355,0,'1103');
+INSERT INTO items VALUES(NULL,'bone leggings',154,5202,0,'1452');
+INSERT INTO items VALUES(NULL,'Stone Face (N/S; w. fire) 4',109,4353,0,'1101');
+INSERT INTO items VALUES(NULL,'Telescope (1/66)',182,5209,0,'1459');
+INSERT INTO items VALUES(NULL,'Spike Trap (W/E) 1',109,4360,0,'1108');
+INSERT INTO items VALUES(NULL,'Spike Trap (W/E) 2',109,4361,0,'1109');
+INSERT INTO items VALUES(NULL,'Gate (S/SE)',124,2107,0,'83b');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 14',292,1019,0,'3fb');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 15',292,1020,0,'3fc');
+INSERT INTO items VALUES(NULL,'Gate (S/NW)',124,2109,0,'83d');
+INSERT INTO items VALUES(NULL,'Balista 207',76,16314,0,'3fba');
+INSERT INTO items VALUES(NULL,'Balista 208',76,16315,0,'3fbb');
+INSERT INTO items VALUES(NULL,'Balista 211',76,16318,0,'3fbe');
+INSERT INTO items VALUES(NULL,'Balista 212',76,16319,0,'3fbf');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (N/S) 4',116,7495,0,'1d47');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (N/S) 3',116,7494,0,'1d46');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (N/S) 2',116,7493,0,'1d45');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (N/S) 1',116,7492,0,'1d44');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (N/S) 5',116,7491,0,'1d43');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (N/S) 4',116,7490,0,'1d42');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (N/S) 3',116,7489,0,'1d41');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (N/S) 2',116,7488,0,'1d40');
+INSERT INTO items VALUES(NULL,'Lava 1',37,6681,0,'1a19');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (N/S) 6',116,7497,0,'1d49');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (N/S) 5',116,7496,0,'1d48');
+INSERT INTO items VALUES(NULL,'Rustic Wooden Chair 2',78,2907,0,'b5b');
+INSERT INTO items VALUES(NULL,'Rustic Wooden Chair 3',78,2908,0,'b5c');
+INSERT INTO items VALUES(NULL,'Arcane Demon',115,9733,0,'2605');
+INSERT INTO items VALUES(NULL,'Rustic Wooden Chair 1',78,2906,0,'b5a');
+INSERT INTO items VALUES(NULL,'Wooden Bench 2 (W/E) (1/3)',78,2911,0,'b5f');
+INSERT INTO items VALUES(NULL,'Rustic Wooden Chair 4',78,2909,0,'b5d');
+INSERT INTO items VALUES(NULL,'Foot Stool',78,2910,0,'b5e');
+INSERT INTO items VALUES(NULL,'ringmail gloves',43,5099,0,'valorite_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Potted Tree 1',4,4552,0,'11c8');
+INSERT INTO items VALUES(NULL,'Ankh 3',70,4,0,'4');
+INSERT INTO items VALUES(NULL,'Plain Wooden Chair 3',78,2904,0,'b58');
+INSERT INTO items VALUES(NULL,'Plain Wooden Chair 4',78,2905,0,'b59');
+INSERT INTO items VALUES(NULL,'Simple Wooden Chair 1',78,2898,0,'b52');
+INSERT INTO items VALUES(NULL,'Simple Wooden Chair 2',78,2899,0,'b53');
+INSERT INTO items VALUES(NULL,'Fancy Wooden Chair 3',78,2896,0,'b50');
+INSERT INTO items VALUES(NULL,'Fancy Wooden Chair 4',78,2897,0,'b51');
+INSERT INTO items VALUES(NULL,'Plain Wooden Chair 1',78,2902,0,'b56');
+INSERT INTO items VALUES(NULL,'Plain Wooden Chair 2',78,2903,0,'b57');
+INSERT INTO items VALUES(NULL,'Simple Wooden Chair 3',78,2900,0,'b54');
+INSERT INTO items VALUES(NULL,'Simple Wooden Chair 4',78,2901,0,'b55');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (W/E) 4',116,7503,0,'1d4f');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (W/E) 3',116,7502,0,'1d4e');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (W/E) 2',116,7501,0,'1d4d');
+INSERT INTO items VALUES(NULL,'Lava 2',37,6686,0,'1a1e');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (N/S) 8',116,7499,0,'1d4b');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (N/S) 7',116,7498,0,'1d4a');
+INSERT INTO items VALUES(NULL,'Tamberine with Ribbon',320,3742,0,'e9e');
+INSERT INTO items VALUES(NULL,'Tamberine',320,3741,0,'e9d');
+INSERT INTO items VALUES(NULL,'plate helmet',187,5138,0,'merkite_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Curtain 7',82,1076,0,'434');
+INSERT INTO items VALUES(NULL,'Water 2',33,13423,0,'346f');
+INSERT INTO items VALUES(NULL,'Water 1',33,13422,0,'346e');
+INSERT INTO items VALUES(NULL,'Iron Gate 2 (S/SW)',157,2124,0,'84c');
+INSERT INTO items VALUES(NULL,'Fence 3',348,2123,0,'84b');
+INSERT INTO items VALUES(NULL,'Fence 2',348,2122,0,'84a');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 10',292,1015,0,'3f7');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 7',292,1012,0,'3f4');
+INSERT INTO items VALUES(NULL,'Telescope (5/66)',182,5213,0,'145d');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 5',292,1010,0,'3f2');
+INSERT INTO items VALUES(NULL,'Telescope (7/66)',182,5215,0,'145f');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 6',292,1011,0,'3f3');
+INSERT INTO items VALUES(NULL,'Recall Rune (3)',349,7958,0,'1f16');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 3',292,1008,0,'3f0');
+INSERT INTO items VALUES(NULL,'Recall Rune (4)',349,7959,0,'1f17');
+INSERT INTO items VALUES(NULL,'ringmail gloves',350,5099,0,'copper_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 4',292,1009,0,'3f1');
+INSERT INTO items VALUES(NULL,'Recall Rune (1)',349,7956,0,'1f14');
+INSERT INTO items VALUES(NULL,'Telescope (2/66)',182,5210,0,'145a');
+INSERT INTO items VALUES(NULL,'Gate (W/NE)',124,2119,0,'847');
+INSERT INTO items VALUES(NULL,'Gate (W/SE)',124,2117,0,'845');
+INSERT INTO items VALUES(NULL,'Recall Rune (2)',349,7957,0,'1f15');
+INSERT INTO items VALUES(NULL,'Gate (W/NW)',124,2115,0,'843');
+INSERT INTO items VALUES(NULL,'Lava 10',161,13410,0,'3462');
+INSERT INTO items VALUES(NULL,'Gate (W/SW)',124,2113,0,'841');
+INSERT INTO items VALUES(NULL,'Morning Glory 6',134,7954,0,'1f12');
+INSERT INTO items VALUES(NULL,'Telescope (4/66)',182,5212,0,'145c');
+INSERT INTO items VALUES(NULL,'Fence 1',348,2121,0,'849');
+INSERT INTO items VALUES(NULL,'Morning Glory 4',134,7952,0,'1f10');
+INSERT INTO items VALUES(NULL,'Morning Glory 5',134,7953,0,'1f11');
+INSERT INTO items VALUES(NULL,'Banner 8 (W/E) 3',128,5533,0,'159d');
+INSERT INTO items VALUES(NULL,'Banner 8 (W/E) 2',128,5530,0,'159a');
+INSERT INTO items VALUES(NULL,'Banner 7 (W/E) 3',128,5532,0,'159c');
+INSERT INTO items VALUES(NULL,'Banner 7 (W/E) 2',128,5531,0,'159b');
+INSERT INTO items VALUES(NULL,'Stone Fountain (9/16)',104,5945,0,'1739');
+INSERT INTO items VALUES(NULL,'Stone Fountain (8/16)',104,5944,0,'1738');
+INSERT INTO items VALUES(NULL,'Stone Fountain (1/16)',104,5937,0,'1731');
+INSERT INTO items VALUES(NULL,'Stone Fountain (3/16)',104,5939,0,'1733');
+INSERT INTO items VALUES(NULL,'Stone Fountain (2/16)',104,5938,0,'1732');
+INSERT INTO items VALUES(NULL,'Stone Fountain (5/16)',104,5941,0,'1735');
+INSERT INTO items VALUES(NULL,'Stone Fountain (4/16)',104,5940,0,'1734');
+INSERT INTO items VALUES(NULL,'Stone Fountain (7/16)',104,5943,0,'1737');
+INSERT INTO items VALUES(NULL,'Stone Fountain (6/16)',104,5942,0,'1736');
+INSERT INTO items VALUES(NULL,'Banner 6 (W/E) 2',128,5525,0,'1595');
+INSERT INTO items VALUES(NULL,'Banner 6 (W/E) 1',128,5524,0,'1594');
+INSERT INTO items VALUES(NULL,'Banner 6 (W/E) 3',128,5526,0,'1596');
+INSERT INTO items VALUES(NULL,'Banner 4 (W/E) 2',128,5521,0,'1591');
+INSERT INTO items VALUES(NULL,'Banner 4 (W/E) 1',128,5520,0,'1590');
+INSERT INTO items VALUES(NULL,'Banner 5 (W/E) 2',128,5523,0,'1593');
+INSERT INTO items VALUES(NULL,'Banner 5 (W/E) 1',128,5522,0,'1592');
+INSERT INTO items VALUES(NULL,'Keg (N/S)',249,6870,0,'1ad6');
+INSERT INTO items VALUES(NULL,'Banner 8 (W/E) 1',128,5529,0,'1599');
+INSERT INTO items VALUES(NULL,'Banner 7 (W/E) 1',128,5528,0,'1598');
+INSERT INTO items VALUES(NULL,'Empty Vat (9/9)',242,5343,0,'14df');
+INSERT INTO items VALUES(NULL,'Stone Fountain (10/16)',104,5946,0,'173a');
+INSERT INTO items VALUES(NULL,'Stone Fountain (12/16)',104,5948,0,'173c');
+INSERT INTO items VALUES(NULL,'Stone Fountain (11/16)',104,5947,0,'173b');
+INSERT INTO items VALUES(NULL,'Stone Fountain (14/16)',104,5950,0,'173e');
+INSERT INTO items VALUES(NULL,'Stone Fountain (13/16)',104,5949,0,'173d');
+INSERT INTO items VALUES(NULL,'Stone Fountain (15/16)',104,5951,0,'173f');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',330,728,0,'2d8');
+INSERT INTO items VALUES(NULL,'Pot 2',14,2529,0,'9e1');
+INSERT INTO items VALUES(NULL,'Pot 1',14,2528,0,'9e0');
+INSERT INTO items VALUES(NULL,'Pot 3',14,2531,0,'9e3');
+INSERT INTO items VALUES(NULL,'Pot 4',14,2532,0,'9e4');
+INSERT INTO items VALUES(NULL,'Wall 4',130,442,0,'1ba');
+INSERT INTO items VALUES(NULL,'Wall 5',130,443,0,'1bb');
+INSERT INTO items VALUES(NULL,'Wall 6',130,444,0,'1bc');
+INSERT INTO items VALUES(NULL,'Wall 7',130,445,0,'1bd');
+INSERT INTO items VALUES(NULL,'Wall 8',130,446,0,'1be');
+INSERT INTO items VALUES(NULL,'Wall 9',130,447,0,'1bf');
+INSERT INTO items VALUES(NULL,'Dirty Pot 4',14,2534,0,'9e6');
+INSERT INTO items VALUES(NULL,'Sandstone Fireplace (W/E) (2/2)',103,1161,0,'489');
+INSERT INTO items VALUES(NULL,'Sandstone Fireplace (N/S) (2/2)',103,1154,0,'482');
+INSERT INTO items VALUES(NULL,'Window 4',156,432,0,'1b0');
+INSERT INTO items VALUES(NULL,'Tiny Wall 5',47,433,0,'1b1');
+INSERT INTO items VALUES(NULL,'Tiny Wall 6',47,434,0,'1b2');
+INSERT INTO items VALUES(NULL,'Tiny Wall 7',47,435,0,'1b3');
+INSERT INTO items VALUES(NULL,'Tiny Wall 8',47,436,0,'1b4');
+INSERT INTO items VALUES(NULL,'Post 1',130,437,0,'1b5');
+INSERT INTO items VALUES(NULL,'Wall 1',130,438,0,'1b6');
+INSERT INTO items VALUES(NULL,'Wall 2',130,439,0,'1b7');
+INSERT INTO items VALUES(NULL,'Wall 3',130,440,0,'1b8');
+INSERT INTO items VALUES(NULL,'Post 2',130,441,0,'1b9');
+INSERT INTO items VALUES(NULL,'Sarcophagus (N/S) 28',100,7345,0,'1cb1');
+INSERT INTO items VALUES(NULL,'kite shield',347,7028,0,'copper_shields_kite');
+INSERT INTO items VALUES(NULL,'Field of Poison (W/E)',28,14624,0,'3920');
+INSERT INTO items VALUES(NULL,'Bricks 7',252,1256,0,'4e8');
+INSERT INTO items VALUES(NULL,'Bricks 8',252,1257,0,'4e9');
+INSERT INTO items VALUES(NULL,'Wooden Planks 31',129,1248,0,'4e0');
+INSERT INTO items VALUES(NULL,'Wooden Planks 32',129,1249,0,'4e1');
+INSERT INTO items VALUES(NULL,'Bricks 1',252,1250,0,'4e2');
+INSERT INTO items VALUES(NULL,'Bricks 2',252,1251,0,'4e3');
+INSERT INTO items VALUES(NULL,'Bricks 3',252,1252,0,'4e4');
+INSERT INTO items VALUES(NULL,'Bricks 4',252,1253,0,'4e5');
+INSERT INTO items VALUES(NULL,'Bricks 5',252,1254,0,'4e6');
+INSERT INTO items VALUES(NULL,'Bricks 6',252,1255,0,'4e7');
+INSERT INTO items VALUES(NULL,'Dirt 10',202,13002,0,'32ca');
+INSERT INTO items VALUES(NULL,'Blue Floor 6',165,1258,0,'4ea');
+INSERT INTO items VALUES(NULL,'Blue Floor 7',165,1259,0,'4eb');
+INSERT INTO items VALUES(NULL,'Blue Floor 8',165,1260,0,'4ec');
+INSERT INTO items VALUES(NULL,'Blue Floor 9',165,1261,0,'4ed');
+INSERT INTO items VALUES(NULL,'Blue Floor 10',165,1262,0,'4ee');
+INSERT INTO items VALUES(NULL,'Blue Floor 11',165,1263,0,'4ef');
+INSERT INTO items VALUES(NULL,'Balista 151',76,16258,0,'3f82');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',56,5103,0,'merkite_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'leather bustier',254,7178,0,'1c0a');
+INSERT INTO items VALUES(NULL,'chainmail leggings',342,5054,0,'iron_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Wall 5',98,9539,0,'2543');
+INSERT INTO items VALUES(NULL,'Rug 8',351,2746,0,'aba');
+INSERT INTO items VALUES(NULL,'Wall 3',98,9537,0,'2541');
+INSERT INTO items VALUES(NULL,'Rug 10',351,2748,0,'abc');
+INSERT INTO items VALUES(NULL,'Carpet 1',143,2749,0,'abd');
+INSERT INTO items VALUES(NULL,'Carpet 2',143,2750,0,'abe');
+INSERT INTO items VALUES(NULL,'Wall 7',98,9541,0,'2545');
+INSERT INTO items VALUES(NULL,'Saw Trap (N/S) 5',109,4359,0,'1107');
+INSERT INTO items VALUES(NULL,'Wall 10',98,9545,0,'2549');
+INSERT INTO items VALUES(NULL,'Wall 9',98,9544,0,'2548');
+INSERT INTO items VALUES(NULL,'Saw Trap (N/S) 2',109,4356,0,'1104');
+INSERT INTO items VALUES(NULL,'Muffin',19,2538,0,'9ea');
+INSERT INTO items VALUES(NULL,'Jar of Honey',19,2540,0,'9ec');
+INSERT INTO items VALUES(NULL,'Muffins 1',19,2539,0,'9eb');
+INSERT INTO items VALUES(NULL,'Stone Face (N/S; w. fire) 3',109,4352,0,'1100');
+INSERT INTO items VALUES(NULL,'Mug of Ale 1',19,2542,0,'9ee');
+INSERT INTO items VALUES(NULL,'bone arms',154,5203,0,'1453');
+INSERT INTO items VALUES(NULL,'Lava 49',44,13653,0,'3555');
+INSERT INTO items VALUES(NULL,'Kettle',14,2541,0,'9ed');
+INSERT INTO items VALUES(NULL,'plate armor',17,7172,0,'1c04');
+INSERT INTO items VALUES(NULL,'leather armor',254,7174,0,'1c06');
+INSERT INTO items VALUES(NULL,'Lava 48',44,13652,0,'3554');
+INSERT INTO items VALUES(NULL,'leather shorts',254,7168,0,'1c00');
+INSERT INTO items VALUES(NULL,'Mug of Ale 2',19,2543,0,'9ef');
+INSERT INTO items VALUES(NULL,'leather skirt',254,7176,0,'1c08');
+INSERT INTO items VALUES(NULL,'Wall 13',98,9548,0,'254c');
+INSERT INTO items VALUES(NULL,'Wall 12',98,9547,0,'254b');
+INSERT INTO items VALUES(NULL,'Wall 11',98,9546,0,'254a');
+INSERT INTO items VALUES(NULL,'Rug 1',351,2739,0,'ab3');
+INSERT INTO items VALUES(NULL,'Rug 2',351,2740,0,'ab4');
+INSERT INTO items VALUES(NULL,'Wall 16',98,9551,0,'254f');
+INSERT INTO items VALUES(NULL,'Wall 15',98,9550,0,'254e');
+INSERT INTO items VALUES(NULL,'Wall 14',98,9549,0,'254d');
+INSERT INTO items VALUES(NULL,'Rug 6',351,2744,0,'ab8');
+INSERT INTO items VALUES(NULL,'Rug 7',351,2745,0,'ab9');
+INSERT INTO items VALUES(NULL,'Lava 53',44,13657,0,'3559');
+INSERT INTO items VALUES(NULL,'Lava 52',44,13656,0,'3558');
+INSERT INTO items VALUES(NULL,'Embers',352,3561,0,'de9');
+INSERT INTO items VALUES(NULL,'Head 2',147,7401,0,'1ce9');
+INSERT INTO items VALUES(NULL,'Torso 2',147,7400,0,'1ce8');
+INSERT INTO items VALUES(NULL,'Body Part 1',147,7395,0,'1ce3');
+INSERT INTO items VALUES(NULL,'Leg 1',147,7394,0,'1ce2');
+INSERT INTO items VALUES(NULL,'Head 1',147,7393,0,'1ce1');
+INSERT INTO items VALUES(NULL,'Torso 1',147,7392,0,'1ce0');
+INSERT INTO items VALUES(NULL,'Legs 3',147,7399,0,'1ce7');
+INSERT INTO items VALUES(NULL,'Body 2',147,7398,0,'1ce6');
+INSERT INTO items VALUES(NULL,'Arm 2',147,7397,0,'1ce5');
+INSERT INTO items VALUES(NULL,'Legs 2',147,7396,0,'1ce4');
+INSERT INTO items VALUES(NULL,'Armoire 1 (W/E) (Closed)',79,2641,0,'a51');
+INSERT INTO items VALUES(NULL,'Armoire 1 (W/E) (Open)',79,2640,0,'a50');
+INSERT INTO items VALUES(NULL,'Armoire 2 (W/E) (Closed)',79,2643,0,'a53');
+INSERT INTO items VALUES(NULL,'Armoire 2 (W/E) (Open)',79,2642,0,'a52');
+INSERT INTO items VALUES(NULL,'Bedroll 1 (W/E) (Open)',91,2645,0,'a55');
+INSERT INTO items VALUES(NULL,'Bedroll 2',91,2647,0,'a57');
+INSERT INTO items VALUES(NULL,'Bedroll 1 (N/S) (Open)',91,2646,0,'a56');
+INSERT INTO items VALUES(NULL,'Bedroll 1 (N/S) (Closed)',91,2649,0,'a59');
+INSERT INTO items VALUES(NULL,'Bedroll 1 (W/E) (Closed)',91,2648,0,'a58');
+INSERT INTO items VALUES(NULL,'plate helmet',117,5138,0,'golden_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'chainmail tunic',167,5055,0,'valorite_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Beige Bed (N/S) (1/2)',91,2650,0,'a5a');
+INSERT INTO items VALUES(NULL,'Gray Bed (N/S) (1/2)',91,2652,0,'a5c');
+INSERT INTO items VALUES(NULL,'Beige Bed (N/S) (2/2)',91,2651,0,'a5b');
+INSERT INTO items VALUES(NULL,'White Bed (N/S) (2/2)',91,2654,0,'a5e');
+INSERT INTO items VALUES(NULL,'Gray Bed (W/E) (2/2)',91,2653,0,'a5d');
+INSERT INTO items VALUES(NULL,'White Bed (N/S) (1/2)',91,2655,0,'a5f');
+INSERT INTO items VALUES(NULL,'Leg 2',147,7404,0,'1cec');
+INSERT INTO items VALUES(NULL,'Burned Wood',352,3562,0,'dea');
+INSERT INTO items VALUES(NULL,'Body Part 2',147,7402,0,'1cea');
+INSERT INTO items VALUES(NULL,'Entrails ',147,7407,0,'1cef');
+INSERT INTO items VALUES(NULL,'Liver ',147,7406,0,'1cee');
+INSERT INTO items VALUES(NULL,'Heart ',147,7405,0,'1ced');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',235,5103,0,'agapite_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'Telescope (35/66)',182,5243,0,'147b');
+INSERT INTO items VALUES(NULL,'Telescope (36/66)',182,5244,0,'147c');
+INSERT INTO items VALUES(NULL,'Telescope (34/66)',182,5242,0,'147a');
+INSERT INTO items VALUES(NULL,'Telescope (39/66)',182,5247,0,'147f');
+INSERT INTO items VALUES(NULL,'Telescope (37/66)',182,5245,0,'147d');
+INSERT INTO items VALUES(NULL,'Telescope (38/66)',182,5246,0,'147e');
+INSERT INTO items VALUES(NULL,'Catapult 68',72,5782,0,'1696');
+INSERT INTO items VALUES(NULL,'Catapult 69',72,5783,0,'1697');
+INSERT INTO items VALUES(NULL,'Catapult 66',72,5780,0,'1694');
+INSERT INTO items VALUES(NULL,'Catapult 67',72,5781,0,'1695');
+INSERT INTO items VALUES(NULL,'Catapult 64',72,5778,0,'1692');
+INSERT INTO items VALUES(NULL,'Catapult 65',72,5779,0,'1693');
+INSERT INTO items VALUES(NULL,'Catapult 62',72,5776,0,'1690');
+INSERT INTO items VALUES(NULL,'Catapult 63',72,5777,0,'1691');
+INSERT INTO items VALUES(NULL,'Catapult 70',72,5784,0,'1698');
+INSERT INTO items VALUES(NULL,'Catapult 71',72,5785,0,'1699');
+INSERT INTO items VALUES(NULL,'Fizzle',28,14133,0,'3735');
+INSERT INTO items VALUES(NULL,'Catapult 77',72,5791,0,'169f');
+INSERT INTO items VALUES(NULL,'Catapult 75',72,5789,0,'169d');
+INSERT INTO items VALUES(NULL,'Catapult 76',72,5790,0,'169e');
+INSERT INTO items VALUES(NULL,'Catapult 73',72,5787,0,'169b');
+INSERT INTO items VALUES(NULL,'Catapult 74',72,5788,0,'169c');
+INSERT INTO items VALUES(NULL,'Catapult 72',72,5786,0,'169a');
+INSERT INTO items VALUES(NULL,'Telescope (26/66)',182,5234,0,'1472');
+INSERT INTO items VALUES(NULL,'Telescope (27/66)',182,5235,0,'1473');
+INSERT INTO items VALUES(NULL,'Telescope (24/66)',182,5232,0,'1470');
+INSERT INTO items VALUES(NULL,'Telescope (25/66)',182,5233,0,'1471');
+INSERT INTO items VALUES(NULL,'Telescope (30/66)',182,5238,0,'1476');
+INSERT INTO items VALUES(NULL,'Telescope (31/66)',182,5239,0,'1477');
+INSERT INTO items VALUES(NULL,'Telescope (28/66)',182,5236,0,'1474');
+INSERT INTO items VALUES(NULL,'Telescope (29/66)',182,5237,0,'1475');
+INSERT INTO items VALUES(NULL,'Telescope (32/66)',182,5240,0,'1478');
+INSERT INTO items VALUES(NULL,'Telescope (33/66)',182,5241,0,'1479');
+INSERT INTO items VALUES(NULL,'Glass of Milk 2',155,8074,0,'1f8a');
+INSERT INTO items VALUES(NULL,'Glass of Milk 4',155,8076,0,'1f8c');
+INSERT INTO items VALUES(NULL,'Glass of Milk 3',155,8075,0,'1f8b');
+INSERT INTO items VALUES(NULL,'Glass of Wine 2',155,8078,0,'1f8e');
+INSERT INTO items VALUES(NULL,'Glass of Wine 1',155,8077,0,'1f8d');
+INSERT INTO items VALUES(NULL,'Glass of Wine 3',155,8079,0,'1f8f');
+INSERT INTO items VALUES(NULL,'Tattered Banner 4',201,1067,0,'42b');
+INSERT INTO items VALUES(NULL,'Small Wall 1',189,36,0,'24');
+INSERT INTO items VALUES(NULL,'Small Wall 2',189,37,0,'25');
+INSERT INTO items VALUES(NULL,'Small Wall 3',189,38,0,'26');
+INSERT INTO items VALUES(NULL,'Small Wall 4',189,39,0,'27');
+INSERT INTO items VALUES(NULL,'Wall 7',189,32,0,'20');
+INSERT INTO items VALUES(NULL,'Wall 8',189,33,0,'21');
+INSERT INTO items VALUES(NULL,'Window 1',189,34,0,'22');
+INSERT INTO items VALUES(NULL,'Window 2',189,35,0,'23');
+INSERT INTO items VALUES(NULL,'Arch 1',189,40,0,'28');
+INSERT INTO items VALUES(NULL,'Arch 2',189,41,0,'29');
+INSERT INTO items VALUES(NULL,'Glass 1',14,8065,0,'1f81');
+INSERT INTO items VALUES(NULL,'Glass of Cider 4',155,8064,0,'1f80');
+INSERT INTO items VALUES(NULL,'Glass 3',14,8067,0,'1f83');
+INSERT INTO items VALUES(NULL,'Glass 2',14,8066,0,'1f82');
+INSERT INTO items VALUES(NULL,'Glass of Liquor 1',155,8069,0,'1f85');
+INSERT INTO items VALUES(NULL,'Glass 4',14,8068,0,'1f84');
+INSERT INTO items VALUES(NULL,'Glass of Liquor 3',155,8071,0,'1f87');
+INSERT INTO items VALUES(NULL,'Glass of Liquor 2',155,8070,0,'1f86');
+INSERT INTO items VALUES(NULL,'Glass of Milk 1',155,8073,0,'1f89');
+INSERT INTO items VALUES(NULL,'Glass of Liquor 4',155,8072,0,'1f88');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',189,45,0,'2d');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',189,46,0,'2e');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',189,47,0,'2f');
+INSERT INTO items VALUES(NULL,'Arch 3',189,42,0,'2a');
+INSERT INTO items VALUES(NULL,'Arch 4',189,43,0,'2b');
+INSERT INTO items VALUES(NULL,'Arch 5',189,44,0,'2c');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 7',116,7529,0,'1d69');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 6',116,7528,0,'1d68');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 3',116,7525,0,'1d65');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 2',116,7524,0,'1d64');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 5',116,7527,0,'1d67');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 4',116,7526,0,'1d66');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (W/E) 4',116,7521,0,'1d61');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (W/E) 3',116,7520,0,'1d60');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 1',116,7523,0,'1d63');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (W/E) 5',116,7522,0,'1d62');
+INSERT INTO items VALUES(NULL,'Counter (N/S) (2/2)',89,2877,0,'b3d');
+INSERT INTO items VALUES(NULL,'Counter (W/E) (2/2)',89,2878,0,'b3e');
+INSERT INTO items VALUES(NULL,'Counter (N/S) (1/2)',89,2879,0,'b3f');
+INSERT INTO items VALUES(NULL,'Nightstand (W/E) (2/2)',89,2872,0,'b38');
+INSERT INTO items VALUES(NULL,'Nightstand (N/S) (1/2)',89,2868,0,'b34');
+INSERT INTO items VALUES(NULL,'Nightstand (W/E) (1/2)',89,2869,0,'b35');
+INSERT INTO items VALUES(NULL,'Nightstand (N/S) (2/2)',89,2871,0,'b37');
+INSERT INTO items VALUES(NULL,'Wooden Chair 3',78,2864,0,'b30');
+INSERT INTO items VALUES(NULL,'Wooden Chair 4',78,2865,0,'b31');
+INSERT INTO items VALUES(NULL,'Wooden Throne 1',78,2866,0,'b32');
+INSERT INTO items VALUES(NULL,'Wooden Throne 2',78,2867,0,'b33');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (N/S) 3',116,7534,0,'1d6e');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (N/S) 2',116,7533,0,'1d6d');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (N/S) 4',116,7535,0,'1d6f');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 8',116,7530,0,'1d6a');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (N/S) 1',116,7532,0,'1d6c');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (W/E) 9',116,7531,0,'1d6b');
+INSERT INTO items VALUES(NULL,'platemail arms',208,5136,0,'copper_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'Ship 36',137,16041,0,'3ea9');
+INSERT INTO items VALUES(NULL,'Ship 35',137,16040,0,'3ea8');
+INSERT INTO items VALUES(NULL,'Ship 30',137,16035,0,'3ea3');
+INSERT INTO items VALUES(NULL,'Deck 8',193,16033,0,'3ea1');
+INSERT INTO items VALUES(NULL,'Ship 29',137,16032,0,'3ea0');
+INSERT INTO items VALUES(NULL,'Ship 34',137,16039,0,'3ea7');
+INSERT INTO items VALUES(NULL,'Ship 33',137,16038,0,'3ea6');
+INSERT INTO items VALUES(NULL,'Ship 32',137,16037,0,'3ea5');
+INSERT INTO items VALUES(NULL,'Ship 31',137,16036,0,'3ea4');
+INSERT INTO items VALUES(NULL,'Wooden Planks 16',129,1233,0,'4d1');
+INSERT INTO items VALUES(NULL,'Small Wall 5',47,386,0,'182');
+INSERT INTO items VALUES(NULL,'Small Wall 6',47,387,0,'183');
+INSERT INTO items VALUES(NULL,'Edge 3',47,384,0,'180');
+INSERT INTO items VALUES(NULL,'Edge 4',47,385,0,'181');
+INSERT INTO items VALUES(NULL,'Edge 5',47,390,0,'186');
+INSERT INTO items VALUES(NULL,'Edge 6',47,391,0,'187');
+INSERT INTO items VALUES(NULL,'Small Wall 7',47,388,0,'184');
+INSERT INTO items VALUES(NULL,'Dragon Prow 1',9,15939,0,'3e43');
+INSERT INTO items VALUES(NULL,'Lava 3',52,13390,0,'344e');
+INSERT INTO items VALUES(NULL,'Edge 7',47,392,0,'188');
+INSERT INTO items VALUES(NULL,'Edge 8',47,393,0,'189');
+INSERT INTO items VALUES(NULL,'Gate (W/SW)',191,2158,0,'86e');
+INSERT INTO items VALUES(NULL,'Dragon Prow 7',9,15945,0,'3e49');
+INSERT INTO items VALUES(NULL,'Deck 10',193,16044,0,'3eac');
+INSERT INTO items VALUES(NULL,'Ship 37',137,16043,0,'3eab');
+INSERT INTO items VALUES(NULL,'Deck 9',193,16042,0,'3eaa');
+INSERT INTO items VALUES(NULL,'Hold 3',138,16047,0,'3eaf');
+INSERT INTO items VALUES(NULL,'Hatch 3',139,16046,0,'3eae');
+INSERT INTO items VALUES(NULL,'Deck 11',193,16045,0,'3ead');
+INSERT INTO items VALUES(NULL,'Tiller Man 4',10,15949,0,'3e4d');
+INSERT INTO items VALUES(NULL,'Arch 3',85,396,0,'18c');
+INSERT INTO items VALUES(NULL,'Tiller Man 6',10,15951,0,'3e4f');
+INSERT INTO items VALUES(NULL,'Arch 1',85,394,0,'18a');
+INSERT INTO items VALUES(NULL,'Arch 6',85,399,0,'18f');
+INSERT INTO items VALUES(NULL,'Tiller Man 1',10,15946,0,'3e4a');
+INSERT INTO items VALUES(NULL,'Arch 4',85,397,0,'18d');
+INSERT INTO items VALUES(NULL,'Tiller Man 3',10,15948,0,'3e4c');
+INSERT INTO items VALUES(NULL,'Fence 6',122,2145,0,'861');
+INSERT INTO items VALUES(NULL,'Fence 5',122,2144,0,'860');
+INSERT INTO items VALUES(NULL,'Lava 2',52,13383,0,'3447');
+INSERT INTO items VALUES(NULL,'Fence 1',353,2146,0,'862');
+INSERT INTO items VALUES(NULL,'Fence 4',353,2149,0,'865');
+INSERT INTO items VALUES(NULL,'Fence 3',353,2148,0,'864');
+INSERT INTO items VALUES(NULL,'Gate (S/SW)',191,2150,0,'866');
+INSERT INTO items VALUES(NULL,'Iron Maiden 3',113,4682,0,'124a');
+INSERT INTO items VALUES(NULL,'Iron Maiden 5',113,4684,0,'124c');
+INSERT INTO items VALUES(NULL,'Iron Maiden 4',113,4683,0,'124b');
+INSERT INTO items VALUES(NULL,'Rack 1',113,4686,0,'124e');
+INSERT INTO items VALUES(NULL,'Iron Maiden 6',113,4685,0,'124d');
+INSERT INTO items VALUES(NULL,'Rack 2',113,4687,0,'124f');
+INSERT INTO items VALUES(NULL,'Gate (S/SE)',191,2152,0,'868');
+INSERT INTO items VALUES(NULL,'Ear of Corn 2',19,3200,0,'c80');
+INSERT INTO items VALUES(NULL,'Ear of Corn 3',19,3201,0,'c81');
+INSERT INTO items VALUES(NULL,'platemail gloves',36,5140,0,'bronze_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Ear of Corn 4',19,3202,0,'c82');
+INSERT INTO items VALUES(NULL,'Border 1',179,4894,0,'131e');
+INSERT INTO items VALUES(NULL,'Champion Flowers 1',134,3203,0,'c83');
+INSERT INTO items VALUES(NULL,'Foxglove Flowers 1',134,3204,0,'c84');
+INSERT INTO items VALUES(NULL,'Orfluer Flowers 1',134,3205,0,'c85');
+INSERT INTO items VALUES(NULL,'Red Poppies',134,3206,0,'c86');
+INSERT INTO items VALUES(NULL,'Champion Flowers 2',134,3207,0,'c87');
+INSERT INTO items VALUES(NULL,'Wall 3',158,8,0,'8');
+INSERT INTO items VALUES(NULL,'Lava 8',161,4882,0,'1312');
+INSERT INTO items VALUES(NULL,'Lava 9',161,4888,0,'1318');
+INSERT INTO items VALUES(NULL,'heater shield',354,7030,0,'shadow_shields_heater');
+INSERT INTO items VALUES(NULL,'Skeleton Knight',115,9661,0,'25bd');
+INSERT INTO items VALUES(NULL,'Field of Energy (N/S)',28,14662,0,'3946');
+INSERT INTO items VALUES(NULL,'Spit 1 (W/E) (2/2)',135,7828,0,'1e94');
+INSERT INTO items VALUES(NULL,'Fish (W/E)',160,7785,0,'1e69');
+INSERT INTO items VALUES(NULL,'Skinned Rabbit (N/S)',135,7826,0,'1e92');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (W/E) 4',116,7211,0,'1c2b');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (W/E) 5',116,7212,0,'1c2c');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (W/E) 3',116,7210,0,'1c2a');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (N/S) 1',116,7215,0,'1c2f');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (W/E) 6',116,7213,0,'1c2d');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (W/E) 7',116,7214,0,'1c2e');
+INSERT INTO items VALUES(NULL,'Spit 2 (N/S) (2/2)',135,7832,0,'1e98');
+INSERT INTO items VALUES(NULL,'Ham (w/e)',19,2505,0,'9c9');
+INSERT INTO items VALUES(NULL,'Jug of Cider 1',155,2504,0,'9c8');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (W/E) 1',116,7202,0,'1c22');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (W/E) 2',116,7203,0,'1c23');
+INSERT INTO items VALUES(NULL,'platemail arms',210,5136,0,'iron_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (W/E) 5',116,7206,0,'1c26');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (W/E) 6',116,7207,0,'1c27');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (W/E) 3',116,7204,0,'1c24');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 1 (W/E) 4',116,7205,0,'1c25');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (W/E) 1',116,7208,0,'1c28');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 2 (W/E) 2',116,7209,0,'1c29');
+INSERT INTO items VALUES(NULL,'Stone Fireplace 2 (N/S) (2/2)',103,2407,0,'967');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 4 (N/S) (2/2)',103,2400,0,'960');
+INSERT INTO items VALUES(NULL,'Stone Fireplace 2 (N/S) (1/2)',103,2401,0,'961');
+INSERT INTO items VALUES(NULL,'Fish 1',19,2508,0,'9cc');
+INSERT INTO items VALUES(NULL,'platemail gorget',159,5139,0,'agapite_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Fish 3',19,2510,0,'9ce');
+INSERT INTO items VALUES(NULL,'Kilt (N/S)',315,5431,0,'1537');
+INSERT INTO items VALUES(NULL,'Wall Carving 3 (W/E) (3/3)',53,4672,0,'1240');
+INSERT INTO items VALUES(NULL,'Gold Belt (N/S)',60,5429,0,'1535');
+INSERT INTO items VALUES(NULL,'Guillotine 4',113,4679,0,'1247');
+INSERT INTO items VALUES(NULL,'Guillotine 3',113,4678,0,'1246');
+INSERT INTO items VALUES(NULL,'Sapling 2',4,3306,0,'cea');
+INSERT INTO items VALUES(NULL,'Iron Maiden 2',113,4681,0,'1249');
+INSERT INTO items VALUES(NULL,'Roof 1',297,1608,0,'648');
+INSERT INTO items VALUES(NULL,'Banner 13 (N/S) 2',128,5656,0,'1618');
+INSERT INTO items VALUES(NULL,'White Flowers 1',134,3211,0,'c8b');
+INSERT INTO items VALUES(NULL,'White Flowers 2',134,3212,0,'c8c');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 1 (W/E) 1',116,7500,0,'1d4c');
+INSERT INTO items VALUES(NULL,'Banner 11 (N/S) 2',128,5652,0,'1614');
+INSERT INTO items VALUES(NULL,'Banner 12 (N/S) 1',128,5653,0,'1615');
+INSERT INTO items VALUES(NULL,'Orc Mask (N/S)',58,5147,0,'141b');
+INSERT INTO items VALUES(NULL,'Orc Mask (W/E)',58,5148,0,'141c');
+INSERT INTO items VALUES(NULL,'Catapult 38',72,5752,0,'1678');
+INSERT INTO items VALUES(NULL,'Catapult 39',72,5753,0,'1679');
+INSERT INTO items VALUES(NULL,'Catapult 34',72,5748,0,'1674');
+INSERT INTO items VALUES(NULL,'Catapult 35',72,5749,0,'1675');
+INSERT INTO items VALUES(NULL,'Catapult 36',72,5750,0,'1676');
+INSERT INTO items VALUES(NULL,'Catapult 37',72,5751,0,'1677');
+INSERT INTO items VALUES(NULL,'Catapult 32',72,5746,0,'1672');
+INSERT INTO items VALUES(NULL,'Plate of Food 1',14,2479,0,'9af');
+INSERT INTO items VALUES(NULL,'Wall 18',98,9553,0,'2551');
+INSERT INTO items VALUES(NULL,'Catapult 43',72,5757,0,'167d');
+INSERT INTO items VALUES(NULL,'Catapult 44',72,5758,0,'167e');
+INSERT INTO items VALUES(NULL,'Catapult 45',72,5759,0,'167f');
+INSERT INTO items VALUES(NULL,'Catapult 40',72,5754,0,'167a');
+INSERT INTO items VALUES(NULL,'Catapult 41',72,5755,0,'167b');
+INSERT INTO items VALUES(NULL,'Catapult 42',72,5756,0,'167c');
+INSERT INTO items VALUES(NULL,'platemail arms',17,5136,0,'1410');
+INSERT INTO items VALUES(NULL,'platemail legs',17,5137,0,'1411');
+INSERT INTO items VALUES(NULL,'plate helmet',17,5138,0,'1412');
+INSERT INTO items VALUES(NULL,'platemail gorget',17,5139,0,'1413');
+INSERT INTO items VALUES(NULL,'platemail gloves',17,5140,0,'1414');
+INSERT INTO items VALUES(NULL,'platemail',17,5141,0,'1415');
+INSERT INTO items VALUES(NULL,'Drum',320,3740,0,'e9c');
+INSERT INTO items VALUES(NULL,'Scroll 8 (N/S)',186,8047,0,'1f6f');
+INSERT INTO items VALUES(NULL,'Scroll 7 (W/E)',186,8046,0,'1f6e');
+INSERT INTO items VALUES(NULL,'Scroll 7 (N/S)',186,8045,0,'1f6d');
+INSERT INTO items VALUES(NULL,'Summon Water Elemental',94,8044,0,'1f6c');
+INSERT INTO items VALUES(NULL,'Summon Fire Elemental',94,8043,0,'1f6b');
+INSERT INTO items VALUES(NULL,'Summon Earth Elemental',94,8042,0,'1f6a');
+INSERT INTO items VALUES(NULL,'Mortar & Pestle',173,3739,0,'e9b');
+INSERT INTO items VALUES(NULL,'Summon Daemon',94,8041,0,'1f69');
+INSERT INTO items VALUES(NULL,'Summon Air Elemental',94,8040,0,'1f68');
+INSERT INTO items VALUES(NULL,'Smaller Wall 4',238,768,0,'300');
+INSERT INTO items VALUES(NULL,'Energy Vortex',94,8038,0,'1f66');
+INSERT INTO items VALUES(NULL,'Earthquake',94,8037,0,'1f65');
+INSERT INTO items VALUES(NULL,'Polymorph',94,8036,0,'1f64');
+INSERT INTO items VALUES(NULL,'Meteor Swarm',94,8035,0,'1f63');
+INSERT INTO items VALUES(NULL,'Mass Dispel',94,8034,0,'1f62');
+INSERT INTO items VALUES(NULL,'Mana Vampire',94,8033,0,'1f61');
+INSERT INTO items VALUES(NULL,'Gate Travel',94,8032,0,'1f60');
+INSERT INTO items VALUES(NULL,'kite shield',354,7028,0,'shadow_shields_kite');
+INSERT INTO items VALUES(NULL,'plate armor',208,7172,0,'copper_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Blood 24',171,7433,0,'1d09');
+INSERT INTO items VALUES(NULL,'Blood 23',171,7432,0,'1d08');
+INSERT INTO items VALUES(NULL,'Blood 18',171,7427,0,'1d03');
+INSERT INTO items VALUES(NULL,'Blood 17',171,7426,0,'1d02');
+INSERT INTO items VALUES(NULL,'Blood 16',171,7425,0,'1d01');
+INSERT INTO items VALUES(NULL,'Blood 15',171,7424,0,'1d00');
+INSERT INTO items VALUES(NULL,'Blood 22',171,7431,0,'1d07');
+INSERT INTO items VALUES(NULL,'Blood 21',171,7430,0,'1d06');
+INSERT INTO items VALUES(NULL,'Blood 20',171,7429,0,'1d05');
+INSERT INTO items VALUES(NULL,'Blood 19',171,7428,0,'1d04');
+INSERT INTO items VALUES(NULL,'chainmail tunic',194,5055,0,'agapite_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'buckler',83,7027,0,'dull_copper_shields_buckler');
+INSERT INTO items VALUES(NULL,'Rug 14',351,7652,0,'1de4');
+INSERT INTO items VALUES(NULL,'Rug 15',351,7653,0,'1de5');
+INSERT INTO items VALUES(NULL,'Rug 16',351,7654,0,'1de6');
+INSERT INTO items VALUES(NULL,'Rug 17',351,7655,0,'1de7');
+INSERT INTO items VALUES(NULL,'Rug 24',176,7648,0,'1de0');
+INSERT INTO items VALUES(NULL,'Rug 11',351,7649,0,'1de1');
+INSERT INTO items VALUES(NULL,'Rug 12',351,7650,0,'1de2');
+INSERT INTO items VALUES(NULL,'Rug 13',351,7651,0,'1de3');
+INSERT INTO items VALUES(NULL,'Rug 18',351,7656,0,'1de8');
+INSERT INTO items VALUES(NULL,'Rug 19',351,7657,0,'1de9');
+INSERT INTO items VALUES(NULL,'Blood 27',171,7436,0,'1d0c');
+INSERT INTO items VALUES(NULL,'Blood 26',171,7435,0,'1d0b');
+INSERT INTO items VALUES(NULL,'Blood 25',171,7434,0,'1d0a');
+INSERT INTO items VALUES(NULL,'Blood 30',171,7439,0,'1d0f');
+INSERT INTO items VALUES(NULL,'Blood 29',171,7438,0,'1d0e');
+INSERT INTO items VALUES(NULL,'Blood 28',171,7437,0,'1d0d');
+INSERT INTO items VALUES(NULL,'Rug 23',351,7661,0,'1ded');
+INSERT INTO items VALUES(NULL,'Rug 24',351,7662,0,'1dee');
+INSERT INTO items VALUES(NULL,'Rug 1',228,7663,0,'1def');
+INSERT INTO items VALUES(NULL,'Rug 20',351,7658,0,'1dea');
+INSERT INTO items VALUES(NULL,'Rug 21',351,7659,0,'1deb');
+INSERT INTO items VALUES(NULL,'Rug 22',351,7660,0,'1dec');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (2/16)',104,6596,0,'19c4');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (6/16)',104,6600,0,'19c8');
+INSERT INTO items VALUES(NULL,'Sail 16',86,16074,0,'3eca');
+INSERT INTO items VALUES(NULL,'Sail 17',86,16076,0,'3ecc');
+INSERT INTO items VALUES(NULL,'Mast 5',8,16075,0,'3ecb');
+INSERT INTO items VALUES(NULL,'Spar 5',88,16078,0,'3ece');
+INSERT INTO items VALUES(NULL,'Spar 4',88,16077,0,'3ecd');
+INSERT INTO items VALUES(NULL,'Spar 6',88,16079,0,'3ecf');
+INSERT INTO items VALUES(NULL,'Display Case 5 (7/9)',174,2838,0,'b16');
+INSERT INTO items VALUES(NULL,'Display Case 5 (8/9)',174,2839,0,'b17');
+INSERT INTO items VALUES(NULL,'Display Case 5 (5/9)',174,2836,0,'b14');
+INSERT INTO items VALUES(NULL,'Display Case 5 (6/9)',174,2837,0,'b15');
+INSERT INTO items VALUES(NULL,'Display Case 5 (3/9)',174,2834,0,'b12');
+INSERT INTO items VALUES(NULL,'Display Case 5 (4/9)',174,2835,0,'b13');
+INSERT INTO items VALUES(NULL,'Display Case 5 (1/9)',174,2832,0,'b10');
+INSERT INTO items VALUES(NULL,'Display Case 5 (2/9)',174,2833,0,'b11');
+INSERT INTO items VALUES(NULL,'Rock 28',29,13356,0,'342c');
+INSERT INTO items VALUES(NULL,'Prow 1',9,15976,0,'3e68');
+INSERT INTO items VALUES(NULL,'Prow 2',9,15977,0,'3e69');
+INSERT INTO items VALUES(NULL,'Rock 31',29,13359,0,'342f');
+INSERT INTO items VALUES(NULL,'Display Case 5 Frame (2/8)',174,2840,0,'b18');
+INSERT INTO items VALUES(NULL,'Rock 29',29,13357,0,'342d');
+INSERT INTO items VALUES(NULL,'platemail gloves',210,5140,0,'iron_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Sail 5',86,15979,0,'3e6b');
+INSERT INTO items VALUES(NULL,'Mast 3',8,15980,0,'3e6c');
+INSERT INTO items VALUES(NULL,'Small Candlabra (On)',73,2845,0,'b1d');
+INSERT INTO items VALUES(NULL,'Rock 26',29,13352,0,'3428');
+INSERT INTO items VALUES(NULL,'Prow 8',9,15983,0,'3e6f');
+INSERT INTO items VALUES(NULL,'Sail 6',86,15981,0,'3e6d');
+INSERT INTO items VALUES(NULL,'Candle 2 (On)',73,2842,0,'b1a');
+INSERT INTO items VALUES(NULL,'Rock 22',29,13347,0,'3423');
+INSERT INTO items VALUES(NULL,'Rock 21',29,13346,0,'3422');
+INSERT INTO items VALUES(NULL,'Rock 20',29,13345,0,'3421');
+INSERT INTO items VALUES(NULL,'Rock 25',29,13351,0,'3427');
+INSERT INTO items VALUES(NULL,'Rock 24',29,13350,0,'3426');
+INSERT INTO items VALUES(NULL,'Rock 23',29,13348,0,'3424');
+INSERT INTO items VALUES(NULL,'Tiller 11',136,16065,0,'3ec1');
+INSERT INTO items VALUES(NULL,'Deck 13',193,16064,0,'3ec0');
+INSERT INTO items VALUES(NULL,'Tiller 13',136,16067,0,'3ec3');
+INSERT INTO items VALUES(NULL,'Tiller 12',136,16066,0,'3ec2');
+INSERT INTO items VALUES(NULL,'Tiller 15',136,16069,0,'3ec5');
+INSERT INTO items VALUES(NULL,'Tiller 14',136,16068,0,'3ec4');
+INSERT INTO items VALUES(NULL,'Tiller 16',136,16070,0,'3ec6');
+INSERT INTO items VALUES(NULL,'Sail 13',86,16073,0,'3ec9');
+INSERT INTO items VALUES(NULL,'Mast 4',8,16072,0,'3ec8');
+INSERT INTO items VALUES(NULL,'helmet',214,5130,0,'merkite_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 1 (W/E) 4',116,7516,0,'1d5c');
+INSERT INTO items VALUES(NULL,'Iron Gate 2 (S/SE)',157,2126,0,'84e');
+INSERT INTO items VALUES(NULL,'Carpet 1',144,2758,0,'ac6');
+INSERT INTO items VALUES(NULL,'Refuse 27',334,7098,0,'1bba');
+INSERT INTO items VALUES(NULL,'Dirt Patch 4',146,2324,0,'914');
+INSERT INTO items VALUES(NULL,'nose helmet',259,5134,0,'dull_copper_helmets_nose');
+INSERT INTO items VALUES(NULL,'Stone Step 3',145,2327,0,'917');
+INSERT INTO items VALUES(NULL,'Stone Step 2',145,2326,0,'916');
+INSERT INTO items VALUES(NULL,'Arm 1',147,7389,0,'1cdd');
+INSERT INTO items VALUES(NULL,'Dirt Patch 3',146,2323,0,'913');
+INSERT INTO items VALUES(NULL,'bascinet',275,5132,0,'agapite_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Earrings 1',60,4231,0,'1087');
+INSERT INTO items VALUES(NULL,'Bracelet 1',60,4230,0,'1086');
+INSERT INTO items VALUES(NULL,'Necklace (S-Shape)',60,4229,0,'1085');
+INSERT INTO items VALUES(NULL,'Unbaked Pizza',19,4227,0,'1083');
+INSERT INTO items VALUES(NULL,'Pile of Hides 2 (N/S)',57,4226,0,'1082');
+INSERT INTO items VALUES(NULL,'Pile of Hides 2 (W/E)',57,4225,0,'1081');
+INSERT INTO items VALUES(NULL,'Stretched Hide 5 (N/S) (2/2)',57,4224,0,'1080');
+INSERT INTO items VALUES(NULL,'Balista 32',76,6334,0,'18be');
+INSERT INTO items VALUES(NULL,'Balista 31',76,6333,0,'18bd');
+INSERT INTO items VALUES(NULL,'Balista 33',76,6335,0,'18bf');
+INSERT INTO items VALUES(NULL,'Balista 28',76,6330,0,'18ba');
+INSERT INTO items VALUES(NULL,'Roof 18',297,1643,0,'66b');
+INSERT INTO items VALUES(NULL,'Necklace (Round)',60,4232,0,'1088');
+INSERT INTO items VALUES(NULL,'Arch 2',211,1100,0,'44c');
+INSERT INTO items VALUES(NULL,'Arch 1',211,1099,0,'44b');
+INSERT INTO items VALUES(NULL,'Arch 5',169,1098,0,'44a');
+INSERT INTO items VALUES(NULL,'Border 11',179,4927,0,'133f');
+INSERT INTO items VALUES(NULL,'Arch 5',211,1103,0,'44f');
+INSERT INTO items VALUES(NULL,'Arch 4',211,1102,0,'44e');
+INSERT INTO items VALUES(NULL,'Arch 3',211,1101,0,'44d');
+INSERT INTO items VALUES(NULL,'Window 2',184,60,0,'3c');
+INSERT INTO items VALUES(NULL,'Window 1',184,59,0,'3b');
+INSERT INTO items VALUES(NULL,'Wall 1',50,511,0,'1ff');
+INSERT INTO items VALUES(NULL,'Small Wall 3',184,63,0,'3f');
+INSERT INTO items VALUES(NULL,'Small Wall 2',184,62,0,'3e');
+INSERT INTO items VALUES(NULL,'Small Wall 1',184,61,0,'3d');
+INSERT INTO items VALUES(NULL,'Long Cannon (E/W) (2/3)',67,3727,0,'e8f');
+INSERT INTO items VALUES(NULL,'Arch 4',169,1097,0,'449');
+INSERT INTO items VALUES(NULL,'Arch 3',169,1096,0,'448');
+INSERT INTO items VALUES(NULL,'Border 9',179,4921,0,'1339');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',123,1091,0,'443');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',123,1090,0,'442');
+INSERT INTO items VALUES(NULL,'Arch 5',123,1089,0,'441');
+INSERT INTO items VALUES(NULL,'Arch 4',123,1088,0,'440');
+INSERT INTO items VALUES(NULL,'Arch 2',169,1095,0,'447');
+INSERT INTO items VALUES(NULL,'Arch 1',169,1094,0,'446');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',123,1093,0,'445');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',123,1092,0,'444');
+INSERT INTO items VALUES(NULL,'Switch (W/E) (Off)',75,4239,0,'108f');
+INSERT INTO items VALUES(NULL,'Lever 3 (W/E)',75,4238,0,'108e');
+INSERT INTO items VALUES(NULL,'Lever 2 (W/E)',75,4237,0,'108d');
+INSERT INTO items VALUES(NULL,'Lever 1 (W/E)',75,4236,0,'108c');
+INSERT INTO items VALUES(NULL,'Beads',60,4235,0,'108b');
+INSERT INTO items VALUES(NULL,'Ring 1',60,4234,0,'108a');
+INSERT INTO items VALUES(NULL,'Balista 23',76,6325,0,'18b5');
+INSERT INTO items VALUES(NULL,'Balista 22',76,6324,0,'18b4');
+INSERT INTO items VALUES(NULL,'Balista 25',76,6327,0,'18b7');
+INSERT INTO items VALUES(NULL,'Balista 24',76,6326,0,'18b6');
+INSERT INTO items VALUES(NULL,'Balista 19',76,6321,0,'18b1');
+INSERT INTO items VALUES(NULL,'Balista 18',76,6320,0,'18b0');
+INSERT INTO items VALUES(NULL,'Balista 21',76,6323,0,'18b3');
+INSERT INTO items VALUES(NULL,'Long Cannon (S/N) (2/3)',67,3724,0,'e8c');
+INSERT INTO items VALUES(NULL,'Wall 7',184,57,0,'39');
+INSERT INTO items VALUES(NULL,'Wall 6',184,56,0,'38');
+INSERT INTO items VALUES(NULL,'Wall 9',188,504,0,'1f8');
+INSERT INTO items VALUES(NULL,'Wall 10',188,505,0,'1f9');
+INSERT INTO items VALUES(NULL,'Wall 1',184,51,0,'33');
+INSERT INTO items VALUES(NULL,'Wall 6',188,501,0,'1f5');
+INSERT INTO items VALUES(NULL,'Tiny Wall 5',189,49,0,'31');
+INSERT INTO items VALUES(NULL,'Wall 8',188,503,0,'1f7');
+INSERT INTO items VALUES(NULL,'Wall 1',188,496,0,'1f0');
+INSERT INTO items VALUES(NULL,'Wall 2',188,497,0,'1f1');
+INSERT INTO items VALUES(NULL,'Wall 3',184,53,0,'35');
+INSERT INTO items VALUES(NULL,'Wall 4',188,499,0,'1f3');
+INSERT INTO items VALUES(NULL,'Wooden Planks 4',129,1188,0,'4a4');
+INSERT INTO items VALUES(NULL,'Wooden Boards 1',212,1189,0,'4a5');
+INSERT INTO items VALUES(NULL,'Wooden Boards 2',212,1190,0,'4a6');
+INSERT INTO items VALUES(NULL,'Wooden Boards 3',212,1191,0,'4a7');
+INSERT INTO items VALUES(NULL,'Sandstone Paver 4',166,1184,0,'4a0');
+INSERT INTO items VALUES(NULL,'Wooden Planks 1',129,1185,0,'4a1');
+INSERT INTO items VALUES(NULL,'Wooden Planks 2',129,1186,0,'4a2');
+INSERT INTO items VALUES(NULL,'Wooden Planks 3',129,1187,0,'4a3');
+INSERT INTO items VALUES(NULL,'Wooden Boards 4',212,1192,0,'4a8');
+INSERT INTO items VALUES(NULL,'Wooden Boards 5',212,1193,0,'4a9');
+INSERT INTO items VALUES(NULL,'Balista 70',76,6400,0,'1900');
+INSERT INTO items VALUES(NULL,'Mud 1',202,7681,0,'1e01');
+INSERT INTO items VALUES(NULL,'Footprints 4',202,7686,0,'1e06');
+INSERT INTO items VALUES(NULL,'Stain 1',202,7687,0,'1e07');
+INSERT INTO items VALUES(NULL,'Dog',115,8405,0,'20d5');
+INSERT INTO items VALUES(NULL,'Footprints 2',202,7684,0,'1e04');
+INSERT INTO items VALUES(NULL,'Falling Coins',28,7878,0,'1ec6');
+INSERT INTO items VALUES(NULL,'Footprints 3',202,7685,0,'1e05');
+INSERT INTO items VALUES(NULL,'Etherial Warriors',115,9609,0,'2589');
+INSERT INTO items VALUES(NULL,'Carpet 7',144,2764,0,'acc');
+INSERT INTO items VALUES(NULL,'Pickpocket Dip (Animated)',256,7873,0,'1ec1');
+INSERT INTO items VALUES(NULL,'Carpet 6',144,2763,0,'acb');
+INSERT INTO items VALUES(NULL,'Pickpocket Dip',256,7872,0,'1ec0');
+INSERT INTO items VALUES(NULL,'Small Fish 4',148,3545,0,'dd9');
+INSERT INTO items VALUES(NULL,'Wooden Boards 9',212,1197,0,'4ad');
+INSERT INTO items VALUES(NULL,'Wooden Boards 10',212,1198,0,'4ae');
+INSERT INTO items VALUES(NULL,'Wooden Boards 11',212,1199,0,'4af');
+INSERT INTO items VALUES(NULL,'Wooden Boards 6',212,1194,0,'4aa');
+INSERT INTO items VALUES(NULL,'Wooden Boards 7',212,1195,0,'4ab');
+INSERT INTO items VALUES(NULL,'Wooden Boards 8',212,1196,0,'4ac');
+INSERT INTO items VALUES(NULL,'Window 2',158,15,0,'f');
+INSERT INTO items VALUES(NULL,'Field of Paralysis (N/S)',28,14695,0,'3967');
+INSERT INTO items VALUES(NULL,'Fishing Net 6',148,3538,0,'dd2');
+INSERT INTO items VALUES(NULL,'Scarecrow (W/E)',257,7733,0,'1e35');
+INSERT INTO items VALUES(NULL,'Rat (big)',115,8400,0,'20d0');
+INSERT INTO items VALUES(NULL,'Fishing Net 4',148,3536,0,'dd0');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 1',116,7242,0,'1c4a');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 2',116,7243,0,'1c4b');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 3',116,7244,0,'1c4c');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 4',116,7245,0,'1c4d');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 5',116,7246,0,'1c4e');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (N/S) 6',116,7247,0,'1c4f');
+INSERT INTO items VALUES(NULL,'Small Fish 1',148,3542,0,'dd6');
+INSERT INTO items VALUES(NULL,'Fishing Net 9',148,3541,0,'dd5');
+INSERT INTO items VALUES(NULL,'Scarecrow (N/S)',257,7732,0,'1e34');
+INSERT INTO items VALUES(NULL,'Lava 11',161,13416,0,'3468');
+INSERT INTO items VALUES(NULL,'Small Crate 1 (N/S)',65,2473,0,'9a9');
+INSERT INTO items VALUES(NULL,'Metal Box (N/S)',65,2472,0,'9a8');
+INSERT INTO items VALUES(NULL,'Display Case 1 Frame (1/3)',174,2813,0,'afd');
+INSERT INTO items VALUES(NULL,'Display Case 1 Frame (2/3)',174,2814,0,'afe');
+INSERT INTO items VALUES(NULL,'Display Case 1 Frame (3/3)',174,2815,0,'aff');
+INSERT INTO items VALUES(NULL,'Knife (S/N)',14,2470,0,'9a6');
+INSERT INTO items VALUES(NULL,'Bottle of Ale 3',155,2465,0,'9a1');
+INSERT INTO items VALUES(NULL,'Carpet 14',143,2810,0,'afa');
+INSERT INTO items VALUES(NULL,'Fork (E/W)',14,2467,0,'9a3');
+INSERT INTO items VALUES(NULL,'Bottle of Ale 4',155,2466,0,'9a2');
+INSERT INTO items VALUES(NULL,'Dartboard 3 (W/E)',249,7731,0,'1e33');
+INSERT INTO items VALUES(NULL,'Stone Fireplace 1 (N/S) (2/2)',103,2379,0,'94b');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 13',116,7240,0,'1c48');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 14',116,7241,0,'1c49');
+INSERT INTO items VALUES(NULL,'Dartboard 3 (N/S)',249,7730,0,'1e32');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 5',116,7232,0,'1c40');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 6',116,7233,0,'1c41');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 7',116,7234,0,'1c42');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 8',116,7235,0,'1c43');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 9',116,7236,0,'1c44');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 10',116,7237,0,'1c45');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 11',116,7238,0,'1c46');
+INSERT INTO items VALUES(NULL,'Wooden Coffin 3 (W/E) 12',116,7239,0,'1c47');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 3 (N/S) (2/2)',103,2372,0,'944');
+INSERT INTO items VALUES(NULL,'Stone Fireplace 1 (N/S) (1/2)',103,2373,0,'945');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 3 (N/S) (1/2)',103,2371,0,'943');
+INSERT INTO items VALUES(NULL,'Carpet 12',143,2808,0,'af8');
+INSERT INTO items VALUES(NULL,'Carpet 13',143,2809,0,'af9');
+INSERT INTO items VALUES(NULL,'Carpet 9',219,2804,0,'af4');
+INSERT INTO items VALUES(NULL,'Carpet 10',219,2805,0,'af5');
+INSERT INTO items VALUES(NULL,'Carpet 10',143,2806,0,'af6');
+INSERT INTO items VALUES(NULL,'Carpet 11',143,2807,0,'af7');
+INSERT INTO items VALUES(NULL,'Carpet 5',219,2800,0,'af0');
+INSERT INTO items VALUES(NULL,'Carpet 6',219,2801,0,'af1');
+INSERT INTO items VALUES(NULL,'Carpet 7',219,2802,0,'af2');
+INSERT INTO items VALUES(NULL,'Carpet 8',219,2803,0,'af3');
+INSERT INTO items VALUES(NULL,'Pear Tree 1',355,3492,0,'da4');
+INSERT INTO items VALUES(NULL,'Pear Tree 1 Foliage 1',355,3493,0,'da5');
+INSERT INTO items VALUES(NULL,'Pear Tree 1 Foliage 2',355,3494,0,'da6');
+INSERT INTO items VALUES(NULL,'Pear Tree 1 Foliage 3',355,3495,0,'da7');
+INSERT INTO items VALUES(NULL,'Peach Tree 2',355,3488,0,'da0');
+INSERT INTO items VALUES(NULL,'Peach Tree 2 Foliage 1',355,3489,0,'da1');
+INSERT INTO items VALUES(NULL,'Peach Tree 2 Foliage 2',355,3490,0,'da2');
+INSERT INTO items VALUES(NULL,'Peach Tree 2 Foliage 3',355,3491,0,'da3');
+INSERT INTO items VALUES(NULL,'Pear Tree 2',355,3496,0,'da8');
+INSERT INTO items VALUES(NULL,'Pear Tree 2 Foliage 1',355,3497,0,'da9');
+INSERT INTO items VALUES(NULL,'Wooden Door 2 (W/SW)',204,1729,0,'6c1');
+INSERT INTO items VALUES(NULL,'Wooden Door 2 (W/NW)',204,1731,0,'6c3');
+INSERT INTO items VALUES(NULL,'Bookcase 1 (W/E)',225,2713,0,'a99');
+INSERT INTO items VALUES(NULL,'Metal Door 2 (S/SW)',250,1733,0,'6c5');
+INSERT INTO items VALUES(NULL,'Metal Door 2 (S/SE)',250,1735,0,'6c7');
+INSERT INTO items VALUES(NULL,'Folded Rich Sheet 2',91,2709,0,'a95');
+INSERT INTO items VALUES(NULL,'Metal Door 2 (S/NW)',250,1737,0,'6c9');
+INSERT INTO items VALUES(NULL,'Bookcase 1 (N/S)',225,2711,0,'a97');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed 2 (W/E) (4/4)',91,2705,0,'a91');
+INSERT INTO items VALUES(NULL,'Untidy Double Bed 2 (W/E) (3/4)',91,2704,0,'a90');
+INSERT INTO items VALUES(NULL,'Folded Blanket 2',91,2707,0,'a93');
+INSERT INTO items VALUES(NULL,'Folded Sheet 1',91,2706,0,'a92');
+INSERT INTO items VALUES(NULL,'Tree Stump 2',4,3501,0,'dad');
+INSERT INTO items VALUES(NULL,'Wheat 8',45,3502,0,'dae');
+INSERT INTO items VALUES(NULL,'Wheat 9',45,3503,0,'daf');
+INSERT INTO items VALUES(NULL,'Pear Tree 2 Foliage 2',355,3498,0,'daa');
+INSERT INTO items VALUES(NULL,'Pear Tree 2 Foliage 3',355,3499,0,'dab');
+INSERT INTO items VALUES(NULL,'Tree Stump 1',4,3500,0,'dac');
+INSERT INTO items VALUES(NULL,'Green Communication Crystal',283,7885,0,'1ecd');
+INSERT INTO items VALUES(NULL,'Pylon',47,7884,0,'1ecc');
+INSERT INTO items VALUES(NULL,'platemail gloves',269,5140,0,'dull_copper_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Metal Door 2 (S/NE)',250,1739,0,'6cb');
+INSERT INTO items VALUES(NULL,'Metal Door 2 (W/SE)',250,1741,0,'6cd');
+INSERT INTO items VALUES(NULL,'Pylon',238,7882,0,'1eca');
+INSERT INTO items VALUES(NULL,'Metal Door 2 (W/NE)',250,1743,0,'6cf');
+INSERT INTO items VALUES(NULL,'Empty Bookcase (W/E)',225,2718,0,'a9e');
+INSERT INTO items VALUES(NULL,'Empty Bookcase (N/S)',225,2717,0,'a9d');
+INSERT INTO items VALUES(NULL,'Display Case 5 Frame (5/8)',174,2719,0,'a9f');
+INSERT INTO items VALUES(NULL,'Bookcase 2 (W/E)',225,2714,0,'a9a');
+INSERT INTO items VALUES(NULL,'Bookcase 3 (W/E)',225,2716,0,'a9c');
+INSERT INTO items VALUES(NULL,'Bookcase 3 (N/S)',225,2715,0,'a9b');
+INSERT INTO items VALUES(NULL,'Roof 10',84,1423,0,'58f');
+INSERT INTO items VALUES(NULL,'Roof 8',84,1421,0,'58d');
+INSERT INTO items VALUES(NULL,'Roof 9',84,1422,0,'58e');
+INSERT INTO items VALUES(NULL,'Roof 6',84,1419,0,'58b');
+INSERT INTO items VALUES(NULL,'Roof 7',84,1420,0,'58c');
+INSERT INTO items VALUES(NULL,'Roof 5',84,1418,0,'58a');
+INSERT INTO items VALUES(NULL,'pickaxe',80,3718,0,'e86');
+INSERT INTO items VALUES(NULL,'pitchfork',20,3719,0,'e87');
+INSERT INTO items VALUES(NULL,'halberd',3,5183,0,'143f');
+INSERT INTO items VALUES(NULL,'Catapult 17',72,5720,0,'1658');
+INSERT INTO items VALUES(NULL,'Catapult 18',72,5721,0,'1659');
+INSERT INTO items VALUES(NULL,'maul',5,5179,0,'143b');
+INSERT INTO items VALUES(NULL,'Catapult 11',72,5714,0,'1652');
+INSERT INTO items VALUES(NULL,'Catapult 12',72,5715,0,'1653');
+INSERT INTO items VALUES(NULL,'Catapult 9',72,5712,0,'1650');
+INSERT INTO items VALUES(NULL,'Catapult 10',72,5713,0,'1651');
+INSERT INTO items VALUES(NULL,'Catapult 15',72,5718,0,'1656');
+INSERT INTO items VALUES(NULL,'Catapult 16',72,5719,0,'1657');
+INSERT INTO items VALUES(NULL,'Catapult 13',72,5716,0,'1654');
+INSERT INTO items VALUES(NULL,'Empty Tub',65,3715,0,'e83');
+INSERT INTO items VALUES(NULL,'Roof 1',84,1414,0,'586');
+INSERT INTO items VALUES(NULL,'Roof 2',84,1415,0,'587');
+INSERT INTO items VALUES(NULL,'Roof 6',227,1412,0,'584');
+INSERT INTO items VALUES(NULL,'Roof 7',227,1413,0,'585');
+INSERT INTO items VALUES(NULL,'Roof 4',227,1410,0,'582');
+INSERT INTO items VALUES(NULL,'Unlabeled 8',246,1042,0,'412');
+INSERT INTO items VALUES(NULL,'Roof 2',227,1408,0,'580');
+INSERT INTO items VALUES(NULL,'Roof 3',227,1409,0,'581');
+INSERT INTO items VALUES(NULL,'Roof 3',84,1416,0,'588');
+INSERT INTO items VALUES(NULL,'Roof 4',84,1417,0,'589');
+INSERT INTO items VALUES(NULL,'Candle 5 (Off)',73,5175,0,'1437');
+INSERT INTO items VALUES(NULL,'Candle 5 (On)',73,5172,0,'1434');
+INSERT INTO items VALUES(NULL,'Candle 4 (Off)',73,5171,0,'1433');
+INSERT INTO items VALUES(NULL,'Candle 4 (On)',73,5168,0,'1430');
+INSERT INTO items VALUES(NULL,'Stain 6',202,7692,0,'1e0c');
+INSERT INTO items VALUES(NULL,'Catapult 20',72,5723,0,'165b');
+INSERT INTO items VALUES(NULL,'Catapult 21',72,5724,0,'165c');
+INSERT INTO items VALUES(NULL,'Catapult 19',72,5722,0,'165a');
+INSERT INTO items VALUES(NULL,'Catapult 24',72,5727,0,'165f');
+INSERT INTO items VALUES(NULL,'Catapult 22',72,5725,0,'165d');
+INSERT INTO items VALUES(NULL,'Catapult 23',72,5726,0,'165e');
+INSERT INTO items VALUES(NULL,'Roof 12',281,1485,0,'5cd');
+INSERT INTO items VALUES(NULL,'Potted Cactus 1',134,7695,0,'1e0f');
+INSERT INTO items VALUES(NULL,'quarter staff',119,3721,0,'e89');
+INSERT INTO items VALUES(NULL,'Stain 7',202,7693,0,'1e0d');
+INSERT INTO items VALUES(NULL,'Millstone 6',114,6280,0,'1888');
+INSERT INTO items VALUES(NULL,'Peach Tree 1 Foliage 1',355,3485,0,'d9d');
+INSERT INTO items VALUES(NULL,'Peach Tree 1 Foliage 2',355,3486,0,'d9e');
+INSERT INTO items VALUES(NULL,'Peach Tree 1 Foliage 3',355,3487,0,'d9f');
+INSERT INTO items VALUES(NULL,'Apple Tree 2 Foliage 2',355,3482,0,'d9a');
+INSERT INTO items VALUES(NULL,'Apple Tree 2 Foliage 3',355,3483,0,'d9b');
+INSERT INTO items VALUES(NULL,'Peach Tree 1',355,3484,0,'d9c');
+INSERT INTO items VALUES(NULL,'Hedge 2',45,3216,0,'c90');
+INSERT INTO items VALUES(NULL,'Winnowing Basket',114,6274,0,'1882');
+INSERT INTO items VALUES(NULL,'Apple Tree 2',355,3480,0,'d98');
+INSERT INTO items VALUES(NULL,'Apple Tree 2 Foliage 1',355,3481,0,'d99');
+INSERT INTO items VALUES(NULL,'Apple Tree 1',355,3476,0,'d94');
+INSERT INTO items VALUES(NULL,'Apple Tree 1 Foliage 1',355,3477,0,'d95');
+INSERT INTO items VALUES(NULL,'Apple Tree 1 Foliage 2',355,3478,0,'d96');
+INSERT INTO items VALUES(NULL,'Apple Tree 1 Foliage 3',355,3479,0,'d97');
+INSERT INTO items VALUES(NULL,'Leaves 4 (10/10)',4,3472,0,'d90');
+INSERT INTO items VALUES(NULL,'Vines 4 (1/3)',4,3473,0,'d91');
+INSERT INTO items VALUES(NULL,'Vines 4 (2/3)',4,3474,0,'d92');
+INSERT INTO items VALUES(NULL,'Vines 4 (3/3)',4,3475,0,'d93');
+INSERT INTO items VALUES(NULL,'Fish 4',19,2511,0,'9cf');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (W/E) 3',116,7466,0,'1d2a');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (W/E) 5',116,7468,0,'1d2c');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (W/E) 4',116,7467,0,'1d2b');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (W/E) 7',116,7470,0,'1d2e');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (W/E) 6',116,7469,0,'1d2d');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (W/E) 8',116,7471,0,'1d2f');
+INSERT INTO items VALUES(NULL,'Wall of Stone',94,8004,0,'1f44');
+INSERT INTO items VALUES(NULL,'Arch Protection',94,8006,0,'1f46');
+INSERT INTO items VALUES(NULL,'Poison',94,8000,0,'1f40');
+INSERT INTO items VALUES(NULL,'Teleport',94,8002,0,'1f42');
+INSERT INTO items VALUES(NULL,'Greater Heal',94,8009,0,'1f49');
+INSERT INTO items VALUES(NULL,'Fire Field',94,8008,0,'1f48');
+INSERT INTO items VALUES(NULL,'metal shield',354,7035,0,'shadow_shields_shield');
+INSERT INTO items VALUES(NULL,'Dispel Field',94,8014,0,'1f4e');
+INSERT INTO items VALUES(NULL,'Lightning',94,8010,0,'1f4a');
+INSERT INTO items VALUES(NULL,'Recall',94,8012,0,'1f4c');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (W/E) 5',116,7457,0,'1d21');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (W/E) 4',116,7456,0,'1d20');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (W/E) 1',116,7459,0,'1d23');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 1 (W/E) 6',116,7458,0,'1d22');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (W/E) 3',116,7461,0,'1d25');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (W/E) 2',116,7460,0,'1d24');
+INSERT INTO items VALUES(NULL,'Wall 3',85,346,0,'15a');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 2 (W/E) 4',116,7462,0,'1d26');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (W/E) 2',116,7465,0,'1d29');
+INSERT INTO items VALUES(NULL,'Body in Stone Coffin 3 (W/E) 1',116,7464,0,'1d28');
+INSERT INTO items VALUES(NULL,'close helmet',40,5128,0,'bronze_helmets_close');
+INSERT INTO items VALUES(NULL,'chainmail leggings',286,5054,0,'merkite_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Wall 20',127,986,0,'3da');
+INSERT INTO items VALUES(NULL,'Tree Pieces 1 (2/5)',4,3416,0,'d58');
+INSERT INTO items VALUES(NULL,'Tree Pieces 1 (3/5)',4,3417,0,'d59');
+INSERT INTO items VALUES(NULL,'Stone Bench 2 (W/E)',78,15872,0,'3e00');
+INSERT INTO items VALUES(NULL,'Field of Poison (N/S) 2',28,15874,0,'3e02');
+INSERT INTO items VALUES(NULL,'ringmail tunic',42,5100,0,'bronze_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'chainmail tunic',111,5055,0,'dull_copper_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Leaves 1 (12/15)',4,3408,0,'d50');
+INSERT INTO items VALUES(NULL,'Leaves 1 (13/15)',4,3409,0,'d51');
+INSERT INTO items VALUES(NULL,'Robe (N/S)',1,7939,0,'1f03');
+INSERT INTO items VALUES(NULL,'Leaves 1 (15/15)',4,3411,0,'d53');
+INSERT INTO items VALUES(NULL,'Bead Necklace',60,7941,0,'1f05');
+INSERT INTO items VALUES(NULL,'Vines 1 (2/3)',4,3413,0,'d55');
+INSERT INTO items VALUES(NULL,'Earrings 2',60,7943,0,'1f07');
+INSERT INTO items VALUES(NULL,'kite shield',83,7028,0,'dull_copper_shields_kite');
+INSERT INTO items VALUES(NULL,'Bracelet 2',60,7942,0,'1f06');
+INSERT INTO items VALUES(NULL,'heater shield',207,7030,0,'iron_shields_heater');
+INSERT INTO items VALUES(NULL,'Crank (W/E)',114,6436,0,'1924');
+INSERT INTO items VALUES(NULL,'Flour Mill 3 (W/E) (1/2)',114,6437,0,'1925');
+INSERT INTO items VALUES(NULL,'platemail arms',117,5136,0,'golden_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'Arch 10',132,479,0,'1df');
+INSERT INTO items VALUES(NULL,'Arch 8',132,477,0,'1dd');
+INSERT INTO items VALUES(NULL,'Arch 9',132,478,0,'1de');
+INSERT INTO items VALUES(NULL,'Arch 6',132,475,0,'1db');
+INSERT INTO items VALUES(NULL,'Arch 7',132,476,0,'1dc');
+INSERT INTO items VALUES(NULL,'Pillar',132,474,0,'1da');
+INSERT INTO items VALUES(NULL,'Mandrake (W/E)',213,6367,0,'18df');
+INSERT INTO items VALUES(NULL,'Mandrake Root (W/E)',213,6366,0,'18de');
+INSERT INTO items VALUES(NULL,'Mandrake Root (N/S)',213,6365,0,'18dd');
+INSERT INTO items VALUES(NULL,'Boulder 6 (1/3)',216,4956,0,'135c');
+INSERT INTO items VALUES(NULL,'Boulder 5 (2/2)',216,4955,0,'135b');
+INSERT INTO items VALUES(NULL,'Boulder 5 (1/2)',216,4954,0,'135a');
+INSERT INTO items VALUES(NULL,'Sandstone Oven (N/S) (2/2)',103,1135,0,'46f');
+INSERT INTO items VALUES(NULL,'Sandstone Oven (N/S) (1/2)',103,1130,0,'46a');
+INSERT INTO items VALUES(NULL,'Boulder 7 (1/2)',216,4959,0,'135f');
+INSERT INTO items VALUES(NULL,'Boulder 6 (3/3)',216,4958,0,'135e');
+INSERT INTO items VALUES(NULL,'Boulder 6 (2/3)',216,4957,0,'135d');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (W/E) 5',116,7510,0,'1d56');
+INSERT INTO items VALUES(NULL,'Wall w. Bar 2',149,175,0,'af');
+INSERT INTO items VALUES(NULL,'Boulder 4 (3/3)',216,4953,0,'1359');
+INSERT INTO items VALUES(NULL,'Boulder 4 (2/3)',216,4952,0,'1358');
+INSERT INTO items VALUES(NULL,'Boulder 2 (2/3)',216,4947,0,'1353');
+INSERT INTO items VALUES(NULL,'Boulder 2 (1/3)',216,4946,0,'1352');
+INSERT INTO items VALUES(NULL,'Boulder 1 (3/3)',216,4945,0,'1351');
+INSERT INTO items VALUES(NULL,'Boulder 1 (2/3)',216,4944,0,'1350');
+INSERT INTO items VALUES(NULL,'Sandstone Oven (W/E) (1/2)',103,1121,0,'461');
+INSERT INTO items VALUES(NULL,'Empty Sandstone Fireplace (N/S) (2/2)',103,1120,0,'460');
+INSERT INTO items VALUES(NULL,'Boulder 3 (1/2)',216,4949,0,'1355');
+INSERT INTO items VALUES(NULL,'Sandstone Oven (W/E) (2/2)',103,1122,0,'462');
+INSERT INTO items VALUES(NULL,'Arch 2',132,470,0,'1d6');
+INSERT INTO items VALUES(NULL,'Arch 3',132,471,0,'1d7');
+INSERT INTO items VALUES(NULL,'Window 2',132,468,0,'1d4');
+INSERT INTO items VALUES(NULL,'Arch 1',132,469,0,'1d5');
+INSERT INTO items VALUES(NULL,'Wall 4',132,466,0,'1d2');
+INSERT INTO items VALUES(NULL,'Window 1',132,467,0,'1d3');
+INSERT INTO items VALUES(NULL,'Wall 2',132,464,0,'1d0');
+INSERT INTO items VALUES(NULL,'Wall 3',132,465,0,'1d1');
+INSERT INTO items VALUES(NULL,'Balista 53',76,6355,0,'18d3');
+INSERT INTO items VALUES(NULL,'Balista 52',76,6354,0,'18d2');
+INSERT INTO items VALUES(NULL,'Balista 51',76,6353,0,'18d1');
+INSERT INTO items VALUES(NULL,'Balista 50',76,6352,0,'18d0');
+INSERT INTO items VALUES(NULL,'Arch 4',132,472,0,'1d8');
+INSERT INTO items VALUES(NULL,'Arch 5',132,473,0,'1d9');
+INSERT INTO items VALUES(NULL,'Necklace 5',60,7946,0,'1f0a');
+INSERT INTO items VALUES(NULL,'Wall 6',241,877,0,'36d');
+INSERT INTO items VALUES(NULL,'Wall 7',241,878,0,'36e');
+INSERT INTO items VALUES(NULL,'Wooden Planks 7',129,1224,0,'4c8');
+INSERT INTO items VALUES(NULL,'Wooden Planks 8',129,1225,0,'4c9');
+INSERT INTO items VALUES(NULL,'Wooden Planks 5',129,1222,0,'4c6');
+INSERT INTO items VALUES(NULL,'Wooden Planks 6',129,1223,0,'4c7');
+INSERT INTO items VALUES(NULL,'Wooden Logs 4',356,1220,0,'4c4');
+INSERT INTO items VALUES(NULL,'Wooden Logs 5',356,1221,0,'4c5');
+INSERT INTO items VALUES(NULL,'Wooden Logs 2',356,1218,0,'4c2');
+INSERT INTO items VALUES(NULL,'Wooden Logs 3',356,1219,0,'4c3');
+INSERT INTO items VALUES(NULL,'Wooden Boards 28',212,1216,0,'4c0');
+INSERT INTO items VALUES(NULL,'Wooden Logs 1',356,1217,0,'4c1');
+INSERT INTO items VALUES(NULL,'Morning Glory 3',134,7951,0,'1f0f');
+INSERT INTO items VALUES(NULL,'Field of Fire (N/S) 1',28,14732,0,'398c');
+INSERT INTO items VALUES(NULL,'Skeleton in Wooden Coffin 2 (W/E) 2',116,7507,0,'1d53');
+INSERT INTO items VALUES(NULL,'Deck 1',193,15969,0,'3e61');
+INSERT INTO items VALUES(NULL,'Wooden Planks 14',129,1231,0,'4cf');
+INSERT INTO items VALUES(NULL,'Wooden Planks 12',129,1229,0,'4cd');
+INSERT INTO items VALUES(NULL,'Wooden Planks 13',129,1230,0,'4ce');
+INSERT INTO items VALUES(NULL,'Wooden Planks 10',129,1227,0,'4cb');
+INSERT INTO items VALUES(NULL,'Wooden Planks 11',129,1228,0,'4cc');
+INSERT INTO items VALUES(NULL,'Wooden Planks 9',129,1226,0,'4ca');
+INSERT INTO items VALUES(NULL,'Sparkle (blue) 1',28,14138,0,'373a');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 13',100,7279,0,'1c6f');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 11',100,7277,0,'1c6d');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 12',100,7278,0,'1c6e');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 9',100,7275,0,'1c6b');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 10',100,7276,0,'1c6c');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 8',100,7274,0,'1c6a');
+INSERT INTO items VALUES(NULL,'Green Potion',180,3850,0,'potion_greaterpoison');
+INSERT INTO items VALUES(NULL,'Spiderweb 1 (1/5)',303,4280,0,'10b8');
+INSERT INTO items VALUES(NULL,'Carpet 6',217,2783,0,'adf');
+INSERT INTO items VALUES(NULL,'Broken Chair 2 (N/S)',247,3097,0,'c19');
+INSERT INTO items VALUES(NULL,'Covered Chair (W/E)',247,3096,0,'c18');
+INSERT INTO items VALUES(NULL,'Carpet 2',217,2779,0,'adb');
+INSERT INTO items VALUES(NULL,'Carpet 3',217,2780,0,'adc');
+INSERT INTO items VALUES(NULL,'Carpet 1',217,2778,0,'ada');
+INSERT INTO items VALUES(NULL,'Wall 7',7,641,0,'281');
+INSERT INTO items VALUES(NULL,'Wall 31',6,640,0,'280');
+INSERT INTO items VALUES(NULL,'Broken Chair 1 (W/E)',247,3089,0,'c11');
+INSERT INTO items VALUES(NULL,'Wall 8',7,642,0,'282');
+INSERT INTO items VALUES(NULL,'Covered Chair (N/S)',247,3095,0,'c17');
+INSERT INTO items VALUES(NULL,'Damaged Books',247,3094,0,'c16');
+INSERT INTO items VALUES(NULL,'Ruined Bookcase (W/E)',247,3093,0,'c15');
+INSERT INTO items VALUES(NULL,'Ruined Bookcase (N/S)',247,3092,0,'c14');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 1 (W/E) (1/3)',100,7270,0,'1c66');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 1 (W/E) (2/3)',100,7271,0,'1c67');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 5',100,7268,0,'1c64');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 6',100,7269,0,'1c65');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 3',100,7266,0,'1c62');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 4',100,7267,0,'1c63');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 1',100,7264,0,'1c60');
+INSERT INTO items VALUES(NULL,'Carpet 4',144,2761,0,'ac9');
+INSERT INTO items VALUES(NULL,'Sarcophagus Lid 1 (W/E) (3/3)',100,7272,0,'1c68');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 7',100,7273,0,'1c69');
+INSERT INTO items VALUES(NULL,'ringmail tunic',178,5100,0,'shadow_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Saw Trap (W/E) 3',109,4376,0,'1118');
+INSERT INTO items VALUES(NULL,'Carpet 6',306,2774,0,'ad6');
+INSERT INTO items VALUES(NULL,'Carpet 7',306,2775,0,'ad7');
+INSERT INTO items VALUES(NULL,'Carpet 4',306,2772,0,'ad4');
+INSERT INTO items VALUES(NULL,'Carpet 5',306,2773,0,'ad5');
+INSERT INTO items VALUES(NULL,'Carpet 2',306,2770,0,'ad2');
+INSERT INTO items VALUES(NULL,'Carpet 3',144,2760,0,'ac8');
+INSERT INTO items VALUES(NULL,'Carpet 11',144,2768,0,'ad0');
+INSERT INTO items VALUES(NULL,'Carpet 1',306,2769,0,'ad1');
+INSERT INTO items VALUES(NULL,'Broken Chair 3 (W/E)',247,3100,0,'c1c');
+INSERT INTO items VALUES(NULL,'Broken Chair 3 (N/S)',247,3099,0,'c1b');
+INSERT INTO items VALUES(NULL,'Broken Chair 2 (W/E)',247,3098,0,'c1a');
+INSERT INTO items VALUES(NULL,'Broken Clock',247,3103,0,'c1f');
+INSERT INTO items VALUES(NULL,'Broken Chair 4 (N/S)',247,3102,0,'c1e');
+INSERT INTO items VALUES(NULL,'Carpet 9',306,2777,0,'ad9');
+INSERT INTO items VALUES(NULL,'platemail legs',269,5137,0,'dull_copper_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'Roof 24',231,8685,0,'21ed');
+INSERT INTO items VALUES(NULL,'Roof 25',231,8686,0,'21ee');
+INSERT INTO items VALUES(NULL,'Roof 26',231,8687,0,'21ef');
+INSERT INTO items VALUES(NULL,'Roof 21',231,8682,0,'21ea');
+INSERT INTO items VALUES(NULL,'Roof 22',231,8683,0,'21eb');
+INSERT INTO items VALUES(NULL,'Roof 23',231,8684,0,'21ec');
+INSERT INTO items VALUES(NULL,'Lilypad 9',45,3522,0,'dc2');
+INSERT INTO items VALUES(NULL,'Lilypad 10',45,3523,0,'dc3');
+INSERT INTO items VALUES(NULL,'Fishing Pole (W/E)',148,3520,0,'dc0');
+INSERT INTO items VALUES(NULL,'Lilypad 8',45,3521,0,'dc1');
+INSERT INTO items VALUES(NULL,'Wooden Door 1 (S/NW)',206,1705,0,'6a9');
+INSERT INTO items VALUES(NULL,'Rattan Door (W/NW)',61,1699,0,'6a3');
+INSERT INTO items VALUES(NULL,'Rattan Door (W/SW)',61,1697,0,'6a1');
+INSERT INTO items VALUES(NULL,'Wooden Door 1 (S/SE)',206,1703,0,'6a7');
+INSERT INTO items VALUES(NULL,'Wooden Door 1 (S/SW)',206,1701,0,'6a5');
+INSERT INTO items VALUES(NULL,'Small Wall 8',238,8676,0,'21e4');
+INSERT INTO items VALUES(NULL,'Wall 4',238,8677,0,'21e5');
+INSERT INTO items VALUES(NULL,'Wall 6',238,8678,0,'21e6');
+INSERT INTO items VALUES(NULL,'Wall 7',238,8679,0,'21e7');
+INSERT INTO items VALUES(NULL,'Smaller Wall 8',238,8672,0,'21e0');
+INSERT INTO items VALUES(NULL,'Small Wall 5',238,8673,0,'21e1');
+INSERT INTO items VALUES(NULL,'Small Wall 6',238,8674,0,'21e2');
+INSERT INTO items VALUES(NULL,'Small Wall 7',238,8675,0,'21e3');
+INSERT INTO items VALUES(NULL,'Fishing Weight 5',148,3535,0,'dcf');
+INSERT INTO items VALUES(NULL,'Fishing Weight 3',148,3533,0,'dcd');
+INSERT INTO items VALUES(NULL,'Fishing Weight 4',148,3534,0,'dce');
+INSERT INTO items VALUES(NULL,'Wall 8',238,8680,0,'21e8');
+INSERT INTO items VALUES(NULL,'Roof 20',231,8681,0,'21e9');
+INSERT INTO items VALUES(NULL,'Fishing Net 3',148,3530,0,'dca');
+INSERT INTO items VALUES(NULL,'helmet',131,5130,0,'shadow_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Wooden Door 1 (S/NE)',206,1707,0,'6ab');
+INSERT INTO items VALUES(NULL,'Wooden Door 1 (W/NE)',206,1711,0,'6af');
+INSERT INTO items VALUES(NULL,'Wooden Door 1 (W/SE)',206,1709,0,'6ad');
+INSERT INTO items VALUES(NULL,'Wall 2',149,167,0,'a7');
+INSERT INTO items VALUES(NULL,'chainmail leggings',63,5054,0,'shadow_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Cave Floor 24',239,1386,0,'56a');
+INSERT INTO items VALUES(NULL,'Roof 6',222,1387,0,'56b');
+INSERT INTO items VALUES(NULL,'Roof 7',222,1388,0,'56c');
+INSERT INTO items VALUES(NULL,'Roof 8',222,1389,0,'56d');
+INSERT INTO items VALUES(NULL,'Roof 9',222,1390,0,'56e');
+INSERT INTO items VALUES(NULL,'Roof 10',222,1391,0,'56f');
+INSERT INTO items VALUES(NULL,'Banner 8 (N/S) 2',128,5680,0,'1630');
+INSERT INTO items VALUES(NULL,'Banner 7 (N/S) 2',128,5681,0,'1631');
+INSERT INTO items VALUES(NULL,'Banner 7 (N/S) 3',128,5682,0,'1632');
+INSERT INTO items VALUES(NULL,'Banner 8 (N/S) 3',128,5683,0,'1633');
+INSERT INTO items VALUES(NULL,'Shield (Silver w. Sword) (W/E) 1',99,5684,0,'1634');
+INSERT INTO items VALUES(NULL,'Shield (Silver w. Sword) (W/E) 2',99,5685,0,'1635');
+INSERT INTO items VALUES(NULL,'Shield (Gold w. Sword) (W/E) 1',99,5686,0,'1636');
+INSERT INTO items VALUES(NULL,'Shield (Gold w. Sword) (W/E) 2',99,5687,0,'1637');
+INSERT INTO items VALUES(NULL,'Swamp 11',236,12824,0,'3218');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (15/16) (Not Animated)',104,6635,0,'19eb');
+INSERT INTO items VALUES(NULL,'Covered Counter (W/E) (1/2)',89,4495,0,'118f');
+INSERT INTO items VALUES(NULL,'Wooden Table 9',89,4493,0,'118d');
+INSERT INTO items VALUES(NULL,'Wooden Table 10',89,4494,0,'118e');
+INSERT INTO items VALUES(NULL,'Wooden Table 7',89,4491,0,'118b');
+INSERT INTO items VALUES(NULL,'Wooden Table 8',89,4492,0,'118c');
+INSERT INTO items VALUES(NULL,'Forest',357,13178,0,'337a');
+INSERT INTO items VALUES(NULL,'Roof 18',150,1384,0,'568');
+INSERT INTO items VALUES(NULL,'Roof 19',150,1385,0,'569');
+INSERT INTO items VALUES(NULL,'Roof 10',150,1376,0,'560');
+INSERT INTO items VALUES(NULL,'Roof 11',150,1377,0,'561');
+INSERT INTO items VALUES(NULL,'Roof 12',150,1378,0,'562');
+INSERT INTO items VALUES(NULL,'Roof 13',150,1379,0,'563');
+INSERT INTO items VALUES(NULL,'Roof 14',150,1380,0,'564');
+INSERT INTO items VALUES(NULL,'Roof 15',150,1381,0,'565');
+INSERT INTO items VALUES(NULL,'Roof 16',150,1382,0,'566');
+INSERT INTO items VALUES(NULL,'Roof 17',150,1383,0,'567');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (11/16) (Not Animated)',104,6629,0,'19e5');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (9/16) (Not Animated)',104,6631,0,'19e7');
+INSERT INTO items VALUES(NULL,'Gravestone 43',27,4484,0,'1184');
+INSERT INTO items VALUES(NULL,'Gravestone 41',27,4482,0,'1182');
+INSERT INTO items VALUES(NULL,'Gravestone 42',27,4483,0,'1183');
+INSERT INTO items VALUES(NULL,'Gravestone 39',27,4480,0,'1180');
+INSERT INTO items VALUES(NULL,'Gravestone 40',27,4481,0,'1181');
+INSERT INTO items VALUES(NULL,'Swamp 15',236,12829,0,'321d');
+INSERT INTO items VALUES(NULL,'Swamp 16',236,12830,0,'321e');
+INSERT INTO items VALUES(NULL,'Pillow 14',91,5691,0,'163b');
+INSERT INTO items VALUES(NULL,'Pillow 15',91,5692,0,'163c');
+INSERT INTO items VALUES(NULL,'Swamp 12',236,12826,0,'321a');
+INSERT INTO items VALUES(NULL,'Swamp 13',236,12827,0,'321b');
+INSERT INTO items VALUES(NULL,'Swamp 14',236,12828,0,'321c');
+INSERT INTO items VALUES(NULL,'Arch 4',184,72,0,'48');
+INSERT INTO items VALUES(NULL,'Arch 5',184,73,0,'49');
+INSERT INTO items VALUES(NULL,'Arch 2',184,70,0,'46');
+INSERT INTO items VALUES(NULL,'Arch 3',184,71,0,'47');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',184,68,0,'44');
+INSERT INTO items VALUES(NULL,'Arch 1',184,69,0,'45');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',184,66,0,'42');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',184,67,0,'43');
+INSERT INTO items VALUES(NULL,'Small Wall 4',184,64,0,'40');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',184,65,0,'41');
+INSERT INTO items VALUES(NULL,'Painting 11',304,3784,0,'ec8');
+INSERT INTO items VALUES(NULL,'Treasure (13/41)',215,6988,0,'1b4c');
+INSERT INTO items VALUES(NULL,'Archedge 2',184,79,0,'4f');
+INSERT INTO items VALUES(NULL,'Archwall 4',184,77,0,'4d');
+INSERT INTO items VALUES(NULL,'Archedge 1',184,78,0,'4e');
+INSERT INTO items VALUES(NULL,'Archwall 2',184,75,0,'4b');
+INSERT INTO items VALUES(NULL,'Archwall 3',184,76,0,'4c');
+INSERT INTO items VALUES(NULL,'Archwall 1',184,74,0,'4a');
+INSERT INTO items VALUES(NULL,'nose helmet',345,5134,0,'copper_helmets_nose');
+INSERT INTO items VALUES(NULL,'Treasure (15/41)',215,6990,0,'1b4e');
+INSERT INTO items VALUES(NULL,'Flax 2',45,6810,0,'1a9a');
+INSERT INTO items VALUES(NULL,'Balista 175',76,16282,0,'3f9a');
+INSERT INTO items VALUES(NULL,'Balista 176',76,16283,0,'3f9b');
+INSERT INTO items VALUES(NULL,'Balista 177',76,16284,0,'3f9c');
+INSERT INTO items VALUES(NULL,'Balista 178',76,16285,0,'3f9d');
+INSERT INTO items VALUES(NULL,'Balista 179',76,16286,0,'3f9e');
+INSERT INTO items VALUES(NULL,'Balista 180',76,16287,0,'3f9f');
+INSERT INTO items VALUES(NULL,'Hops 2',45,6815,0,'1a9f');
+INSERT INTO items VALUES(NULL,'Wooden Table 11 (N/S) (1/2)',89,7593,0,'1da9');
+INSERT INTO items VALUES(NULL,'kite shield',272,7028,0,'agapite_shields_kite');
+INSERT INTO items VALUES(NULL,'Bedroll 4',91,7973,0,'1f25');
+INSERT INTO items VALUES(NULL,'Head 3',147,7584,0,'1da0');
+INSERT INTO items VALUES(NULL,'Arm (left) 1',147,7585,0,'1da1');
+INSERT INTO items VALUES(NULL,'Blank Sign (N/S)',335,7977,0,'1f29');
+INSERT INTO items VALUES(NULL,'Blank Sign (W/E)',335,7976,0,'1f28');
+INSERT INTO items VALUES(NULL,'Wooden Table 11 (W/E) (1/2)',89,7589,0,'1da5');
+INSERT INTO items VALUES(NULL,'Wooden Table 11 (W/E) (2/2)',89,7590,0,'1da6');
+INSERT INTO items VALUES(NULL,'Wooden Table 12 (W/E) (1/2)',89,7591,0,'1da7');
+INSERT INTO items VALUES(NULL,'Small Pedestal',31,7978,0,'1f2a');
+INSERT INTO items VALUES(NULL,'Clumsy',94,7982,0,'1f2e');
+INSERT INTO items VALUES(NULL,'Wooden Table 11 (N/S) (2/2)',89,7594,0,'1daa');
+INSERT INTO items VALUES(NULL,'Wooden Table 12 (N/S) (1/2)',89,7595,0,'1dab');
+INSERT INTO items VALUES(NULL,'Wooden Table 12 (N/S) (2/2)',89,7596,0,'1dac');
+INSERT INTO items VALUES(NULL,'Body 3',147,7597,0,'1dad');
+INSERT INTO items VALUES(NULL,'Head 4',147,7598,0,'1dae');
+INSERT INTO items VALUES(NULL,'Arm (right) 2',147,7599,0,'1daf');
+INSERT INTO items VALUES(NULL,'Balista 173',76,16280,0,'3f98');
+INSERT INTO items VALUES(NULL,'Balista 174',76,16281,0,'3f99');
+INSERT INTO items VALUES(NULL,'Balista 165',76,16272,0,'3f90');
+INSERT INTO items VALUES(NULL,'Balista 166',76,16273,0,'3f91');
+INSERT INTO items VALUES(NULL,'Balista 167',76,16274,0,'3f92');
+INSERT INTO items VALUES(NULL,'Balista 168',76,16275,0,'3f93');
+INSERT INTO items VALUES(NULL,'Balista 169',76,16276,0,'3f94');
+INSERT INTO items VALUES(NULL,'Balista 170',76,16277,0,'3f95');
+INSERT INTO items VALUES(NULL,'Balista 171',76,16278,0,'3f96');
+INSERT INTO items VALUES(NULL,'Balista 172',76,16279,0,'3f97');
+INSERT INTO items VALUES(NULL,'Part 2',358,5348,0,'14e4');
+INSERT INTO items VALUES(NULL,'Part 3',358,5349,0,'14e5');
+INSERT INTO items VALUES(NULL,'Part 4',358,5350,0,'14e6');
+INSERT INTO items VALUES(NULL,'Hitching Post (W/E)',13,5351,0,'14e7');
+INSERT INTO items VALUES(NULL,'Bucket',114,5344,0,'14e0');
+INSERT INTO items VALUES(NULL,'Empty Vat 2 (2/9)',242,5345,0,'14e1');
+INSERT INTO items VALUES(NULL,'Empty Vat 2 (3/9)',242,5346,0,'14e2');
+INSERT INTO items VALUES(NULL,'Part 1',358,5347,0,'14e3');
+INSERT INTO items VALUES(NULL,'Hitching Post (N/S)',13,5352,0,'14e8');
+INSERT INTO items VALUES(NULL,'Moulding Board (N/S)',114,5353,0,'14e9');
+INSERT INTO items VALUES(NULL,'Field of Fire (N/S) 2',28,15911,0,'3e27');
+INSERT INTO items VALUES(NULL,'Dirt 9',202,13001,0,'32c9');
+INSERT INTO items VALUES(NULL,'GM Robe',245,8271,0,'204f');
+INSERT INTO items VALUES(NULL,'Vandyke',195,8269,0,'204d');
+INSERT INTO items VALUES(NULL,'Death Shroud',245,8270,0,'204e');
+INSERT INTO items VALUES(NULL,'Med Short Beard',195,8267,0,'204b');
+INSERT INTO items VALUES(NULL,'Krisna Hair',49,8266,0,'204a');
+INSERT INTO items VALUES(NULL,'Fireball (large)',28,14036,0,'36d4');
+INSERT INTO items VALUES(NULL,'Rolled Map (N/S)',258,5357,0,'14ed');
+INSERT INTO items VALUES(NULL,'Rolled Map (W/E)',258,5358,0,'14ee');
+INSERT INTO items VALUES(NULL,'Deed (N/S)',258,5359,0,'14ef');
+INSERT INTO items VALUES(NULL,'Moulding Board (W/E)',114,5354,0,'14ea');
+INSERT INTO items VALUES(NULL,'Map (N/S)',258,5355,0,'14eb');
+INSERT INTO items VALUES(NULL,'Map (W/E)',258,5356,0,'14ec');
+INSERT INTO items VALUES(NULL,'Ginseng (W/E)',213,6377,0,'18e9');
+INSERT INTO items VALUES(NULL,'Buns hair',49,8262,0,'2046');
+INSERT INTO items VALUES(NULL,'Afro',49,8263,0,'2047');
+INSERT INTO items VALUES(NULL,'Mohawk',49,8260,0,'2044');
+INSERT INTO items VALUES(NULL,'Pageboy',49,8261,0,'2045');
+INSERT INTO items VALUES(NULL,'Lord British',245,8258,0,'2042');
+INSERT INTO items VALUES(NULL,'Lord Blackthorne',245,8259,0,'2043');
+INSERT INTO items VALUES(NULL,'Goatee',195,8256,0,'2040');
+INSERT INTO items VALUES(NULL,'Mustache',195,8257,0,'2041');
+INSERT INTO items VALUES(NULL,'Receding Hair',49,8264,0,'2048');
+INSERT INTO items VALUES(NULL,'2 pig-tails',49,8265,0,'2049');
+INSERT INTO items VALUES(NULL,'Onion 1',19,3181,0,'c6d');
+INSERT INTO items VALUES(NULL,'Balista 64',76,6394,0,'18fa');
+INSERT INTO items VALUES(NULL,'Balista 66',76,6396,0,'18fc');
+INSERT INTO items VALUES(NULL,'Balista 65',76,6395,0,'18fb');
+INSERT INTO items VALUES(NULL,'Balista 68',76,6398,0,'18fe');
+INSERT INTO items VALUES(NULL,'Balista 67',76,6397,0,'18fd');
+INSERT INTO items VALUES(NULL,'Balista 69',76,6399,0,'18ff');
+INSERT INTO items VALUES(NULL,'Mandrake (N/S)',213,6368,0,'18e0');
+INSERT INTO items VALUES(NULL,'Balista 55',76,6385,0,'18f1');
+INSERT INTO items VALUES(NULL,'Balista 54',76,6384,0,'18f0');
+INSERT INTO items VALUES(NULL,'Balista 57',76,6387,0,'18f3');
+INSERT INTO items VALUES(NULL,'Balista 56',76,6386,0,'18f2');
+INSERT INTO items VALUES(NULL,'Balista 59',76,6389,0,'18f5');
+INSERT INTO items VALUES(NULL,'Balista 58',76,6388,0,'18f4');
+INSERT INTO items VALUES(NULL,'Balista 61',76,6391,0,'18f7');
+INSERT INTO items VALUES(NULL,'Balista 60',76,6390,0,'18f6');
+INSERT INTO items VALUES(NULL,'Balista 63',76,6393,0,'18f9');
+INSERT INTO items VALUES(NULL,'Balista 62',76,6392,0,'18f8');
+INSERT INTO items VALUES(NULL,'platemail arms',159,5136,0,'agapite_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'ringmail leggings',310,5104,0,'verite_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'Waterfall 19',23,13566,0,'34fe');
+INSERT INTO items VALUES(NULL,'Waterfall 18',23,13565,0,'34fd');
+INSERT INTO items VALUES(NULL,'Waterfall 17',23,13564,0,'34fc');
+INSERT INTO items VALUES(NULL,'Waterfall 16',23,13563,0,'34fb');
+INSERT INTO items VALUES(NULL,'Waterfall 15',23,13562,0,'34fa');
+INSERT INTO items VALUES(NULL,'Long Cannon (N/S) (1/3)',67,3729,0,'e91');
+INSERT INTO items VALUES(NULL,'Long Cannon (E/W) (3/3)',67,3728,0,'e90');
+INSERT INTO items VALUES(NULL,'Long Cannon (N/S) (3/3)',67,3731,0,'e93');
+INSERT INTO items VALUES(NULL,'Long Cannon (N/S) (2/3)',67,3730,0,'e92');
+INSERT INTO items VALUES(NULL,'Long Cannon (W/E) (2/3)',67,3733,0,'e95');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 21',292,1026,0,'402');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 20',292,1025,0,'401');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 19',292,1024,0,'400');
+INSERT INTO items VALUES(NULL,'Horse Barding (N/S) (2/2)',13,4985,0,'1379');
+INSERT INTO items VALUES(NULL,'Horse Barding (N/S) (1/2)',13,4984,0,'1378');
+INSERT INTO items VALUES(NULL,'platemail arms',187,5136,0,'merkite_armor_plate_arms');
+INSERT INTO items VALUES(NULL,'platemail gloves',81,5140,0,'shadow_armor_plate_gloves');
+INSERT INTO items VALUES(NULL,'Leg of Lamb',19,5642,0,'160a');
+INSERT INTO items VALUES(NULL,'Forge (W/E) (2/3)',30,6526,0,'197e');
+INSERT INTO items VALUES(NULL,'Unlabeled 5',246,1039,0,'40f');
+INSERT INTO items VALUES(NULL,'Unlabeled 4',246,1038,0,'40e');
+INSERT INTO items VALUES(NULL,'Unlabeled 3',246,1037,0,'40d');
+INSERT INTO items VALUES(NULL,'Unlabeled 2',246,1036,0,'40c');
+INSERT INTO items VALUES(NULL,'Unlabeled 1',246,1035,0,'40b');
+INSERT INTO items VALUES(NULL,'Painting 1',304,3743,0,'e9f');
+INSERT INTO items VALUES(NULL,'Forge (W/E) (1/3)',30,6522,0,'197a');
+INSERT INTO items VALUES(NULL,'Nightshade Root (W/E)',213,6375,0,'18e7');
+INSERT INTO items VALUES(NULL,'Cake',19,2537,0,'9e9');
+INSERT INTO items VALUES(NULL,'Dirty Pan',14,2536,0,'9e8');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 40',100,7309,0,'1c8d');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 41',100,7310,0,'1c8e');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 42',100,7311,0,'1c8f');
+INSERT INTO items VALUES(NULL,'Frypan 2',14,2530,0,'9e2');
+INSERT INTO items VALUES(NULL,'Pot 5',14,2533,0,'9e5');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 37',100,7306,0,'1c8a');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 38',100,7307,0,'1c8b');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 39',100,7308,0,'1c8c');
+INSERT INTO items VALUES(NULL,'Peg Board (N/S)',359,3129,0,'c39');
+INSERT INTO items VALUES(NULL,'Flower 2',134,3128,0,'c38');
+INSERT INTO items VALUES(NULL,'Ship 2',137,15936,0,'3e40');
+INSERT INTO items VALUES(NULL,'Sheets 5',247,3125,0,'c35');
+INSERT INTO items VALUES(NULL,'Sheets 4',247,3124,0,'c34');
+INSERT INTO items VALUES(NULL,'Flower 1',134,3127,0,'c37');
+INSERT INTO items VALUES(NULL,'Sheets 6',247,3126,0,'c36');
+INSERT INTO items VALUES(NULL,'Sheets 1',247,3121,0,'c31');
+INSERT INTO items VALUES(NULL,'Debris 4',247,3120,0,'c30');
+INSERT INTO items VALUES(NULL,'Sheets 3',247,3123,0,'c33');
+INSERT INTO items VALUES(NULL,'Sheets 2',247,3122,0,'c32');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 35',100,7304,0,'1c88');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 36',100,7305,0,'1c89');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 31',100,7300,0,'1c84');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 32',100,7301,0,'1c85');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 33',100,7302,0,'1c86');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 34',100,7303,0,'1c87');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 27',100,7296,0,'1c80');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 28',100,7297,0,'1c81');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 29',100,7298,0,'1c82');
+INSERT INTO items VALUES(NULL,'Sarcophagus (W/E) 30',100,7299,0,'1c83');
+INSERT INTO items VALUES(NULL,'Dried Flowers 4',265,3134,0,'c3e');
+INSERT INTO items VALUES(NULL,'Dried Flowers 3',265,3133,0,'c3d');
+INSERT INTO items VALUES(NULL,'Dried Onions 1',265,3135,0,'c3f');
+INSERT INTO items VALUES(NULL,'Peg Board (W/E)',359,3130,0,'c3a');
+INSERT INTO items VALUES(NULL,'Dried Flowers 2',265,3132,0,'c3c');
+INSERT INTO items VALUES(NULL,'Dried Flowers 1',265,3131,0,'c3b');
+INSERT INTO items VALUES(NULL,'Ship 4',137,15938,0,'3e42');
+INSERT INTO items VALUES(NULL,'skinning knife',3,3780,0,'ec4');
+INSERT INTO items VALUES(NULL,'Plough (N/S) (2/2)',257,5378,0,'1502');
+INSERT INTO items VALUES(NULL,'Plough (N/S) (1/2)',257,5379,0,'1503');
+INSERT INTO items VALUES(NULL,'Plough (W/E) (1/2)',257,5376,0,'1500');
+INSERT INTO items VALUES(NULL,'Plough (W/E) (2/2)',257,5377,0,'1501');
+INSERT INTO items VALUES(NULL,'Column 1',47,404,0,'194');
+INSERT INTO items VALUES(NULL,'Harrow (W/E) (1/2)',257,5382,0,'1506');
+INSERT INTO items VALUES(NULL,'Lamp Post 3 (On)',73,2853,0,'b25');
+INSERT INTO items VALUES(NULL,'Roof 6',142,1619,0,'653');
+INSERT INTO items VALUES(NULL,'Lamp Post 3 (Off)',73,2852,0,'b24');
+INSERT INTO items VALUES(NULL,'Harrow (N/S) (1/2)',257,5380,0,'1504');
+INSERT INTO items VALUES(NULL,'Lamp Post 2 (On)',73,2851,0,'b23');
+INSERT INTO items VALUES(NULL,'Harrow (N/S) (2/2)',257,5381,0,'1505');
+INSERT INTO items VALUES(NULL,'Lamp Post 2 (Off)',73,2850,0,'b22');
+INSERT INTO items VALUES(NULL,'Arch 9',47,403,0,'193');
+INSERT INTO items VALUES(NULL,'Arch 8',47,402,0,'192');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',255,5103,0,'iron_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'Explosion 3',28,14027,0,'36cb');
+INSERT INTO items VALUES(NULL,'Bowl of Lettuce 2',19,5632,0,'1600');
+INSERT INTO items VALUES(NULL,'Large Pewter Bowl',14,5635,0,'1603');
+INSERT INTO items VALUES(NULL,'Bowl of Potatoes 2',19,5634,0,'1602');
+INSERT INTO items VALUES(NULL,'Large Wooden Bowl',14,5637,0,'1605');
+INSERT INTO items VALUES(NULL,'Bowl of Stew',19,5636,0,'1604');
+INSERT INTO items VALUES(NULL,'Raw Chicken Leg',19,5639,0,'1607');
+INSERT INTO items VALUES(NULL,'Tomato Soup',19,5638,0,'1606');
+INSERT INTO items VALUES(NULL,'Swamp 7',251,12850,0,'3232');
+INSERT INTO items VALUES(NULL,'Swamp 8',251,12851,0,'3233');
+INSERT INTO items VALUES(NULL,'Swamp 5',251,12848,0,'3230');
+INSERT INTO items VALUES(NULL,'Swamp 6',251,12849,0,'3231');
+INSERT INTO items VALUES(NULL,'Swamp 10',251,12854,0,'3236');
+INSERT INTO items VALUES(NULL,'Swamp 11',251,12855,0,'3237');
+INSERT INTO items VALUES(NULL,'Swamp 9',251,12852,0,'3234');
+INSERT INTO items VALUES(NULL,'Banner 14 (N/S) 1',128,5657,0,'1619');
+INSERT INTO items VALUES(NULL,'Banner 12 (N/S) 2',128,5654,0,'1616');
+INSERT INTO items VALUES(NULL,'Banner 13 (N/S) 1',128,5655,0,'1617');
+INSERT INTO items VALUES(NULL,'Swamp 12',251,12856,0,'3238');
+INSERT INTO items VALUES(NULL,'Swamp 13',251,12857,0,'3239');
+INSERT INTO items VALUES(NULL,'Banner 10 (N/S) 2',128,5650,0,'1612');
+INSERT INTO items VALUES(NULL,'Banner 11 (N/S) 1',128,5651,0,'1613');
+INSERT INTO items VALUES(NULL,'Banner 9 (N/S) 2',128,5648,0,'1610');
+INSERT INTO items VALUES(NULL,'Banner 10 (N/S) 1',128,5649,0,'1611');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (10/16)',104,6604,0,'19cc');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (9/16)',104,6603,0,'19cb');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (8/16)',104,6602,0,'19ca');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (13/16)',104,6607,0,'19cf');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (12/16)',104,6606,0,'19ce');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (11/16)',104,6605,0,'19cd');
+INSERT INTO items VALUES(NULL,'Wall 4',98,9538,0,'2542');
+INSERT INTO items VALUES(NULL,'Rug 9',351,2747,0,'abb');
+INSERT INTO items VALUES(NULL,'Wall 2',98,9536,0,'2540');
+INSERT INTO items VALUES(NULL,'Wall 8',98,9543,0,'2547');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (1/16)',104,6595,0,'19c3');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (5/16)',104,6599,0,'19c7');
+INSERT INTO items VALUES(NULL,'Carpet 3',143,2751,0,'abf');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (3/16)',104,6597,0,'19c5');
+INSERT INTO items VALUES(NULL,'Waterfall 11',23,13558,0,'34f6');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (7/16)',104,6601,0,'19c9');
+INSERT INTO items VALUES(NULL,'Wall 6',98,9540,0,'2544');
+INSERT INTO items VALUES(NULL,'Waterfall 10',23,13557,0,'34f5');
+INSERT INTO items VALUES(NULL,'Swamp 15',251,12859,0,'323b');
+INSERT INTO items VALUES(NULL,'Swamp 16',251,12860,0,'323c');
+INSERT INTO items VALUES(NULL,'Swamp 14',251,12858,0,'323a');
+INSERT INTO items VALUES(NULL,'Swamp 19',251,12863,0,'323f');
+INSERT INTO items VALUES(NULL,'Swamp 17',251,12861,0,'323d');
+INSERT INTO items VALUES(NULL,'Swamp 18',251,12862,0,'323e');
+INSERT INTO items VALUES(NULL,'Banner 1 (N/S) 3',128,5663,0,'161f');
+INSERT INTO items VALUES(NULL,'Waterfall 8',23,13555,0,'34f3');
+INSERT INTO items VALUES(NULL,'Banner 1 (N/S) 1',128,5661,0,'161d');
+INSERT INTO items VALUES(NULL,'Banner 1 (N/S) 2',128,5662,0,'161e');
+INSERT INTO items VALUES(NULL,'Banner 15 (N/S) 1',128,5659,0,'161b');
+INSERT INTO items VALUES(NULL,'Banner 15 (N/S) 2',128,5660,0,'161c');
+INSERT INTO items VALUES(NULL,'Banner 14 (N/S) 2',128,5658,0,'161a');
+INSERT INTO items VALUES(NULL,'Waterfall 6',23,13553,0,'34f1');
+INSERT INTO items VALUES(NULL,'Waterfall 5',23,13552,0,'34f0');
+INSERT INTO items VALUES(NULL,'Cave Floor 8',239,1346,0,'542');
+INSERT INTO items VALUES(NULL,'Cave Floor 8',239,1347,0,'543');
+INSERT INTO items VALUES(NULL,'Cave Floor 6',239,1344,0,'540');
+INSERT INTO items VALUES(NULL,'Cave Floor 7',239,1345,0,'541');
+INSERT INTO items VALUES(NULL,'Cave Floor 11',239,1350,0,'546');
+INSERT INTO items VALUES(NULL,'Cave Floor 12',239,1351,0,'547');
+INSERT INTO items VALUES(NULL,'Cave Floor 9',239,1348,0,'544');
+INSERT INTO items VALUES(NULL,'Cave Floor 10',239,1349,0,'545');
+INSERT INTO items VALUES(NULL,'Cave Floor 13',239,1352,0,'548');
+INSERT INTO items VALUES(NULL,'Cave Floor 14',239,1353,0,'549');
+INSERT INTO items VALUES(NULL,'Roof 6',297,1631,0,'65f');
+INSERT INTO items VALUES(NULL,'Part 1',360,5386,0,'150a');
+INSERT INTO items VALUES(NULL,'Roof 6',153,1627,0,'65b');
+INSERT INTO items VALUES(NULL,'Cave Floor 16',239,1355,0,'54b');
+INSERT INTO items VALUES(NULL,'Cave Floor 17',239,1356,0,'54c');
+INSERT INTO items VALUES(NULL,'Cave Floor 15',239,1354,0,'54a');
+INSERT INTO items VALUES(NULL,'Cave Floor 20',239,1359,0,'54f');
+INSERT INTO items VALUES(NULL,'Pylon',223,7883,0,'1ecb');
+INSERT INTO items VALUES(NULL,'Cave Floor 18',239,1357,0,'54d');
+INSERT INTO items VALUES(NULL,'Cave Floor 19',239,1358,0,'54e');
+INSERT INTO items VALUES(NULL,'Roof 5',153,1626,0,'65a');
+INSERT INTO items VALUES(NULL,'Marble Table (W/E) (2/3)',89,7622,0,'1dc6');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 3 (N/S) (1/3)',78,7623,0,'1dc7');
+INSERT INTO items VALUES(NULL,'Marble Table (W/E) (1/3)',89,7620,0,'1dc4');
+INSERT INTO items VALUES(NULL,'Marble Table (W/E) (3/3)',89,7621,0,'1dc5');
+INSERT INTO items VALUES(NULL,'Marble Table (N/S) (3/3)',89,7618,0,'1dc2');
+INSERT INTO items VALUES(NULL,'Marble Table (N/S) (2/3)',89,7619,0,'1dc3');
+INSERT INTO items VALUES(NULL,'Sandstone Table 2 (W/E) (2/3)',89,7616,0,'1dc0');
+INSERT INTO items VALUES(NULL,'Marble Table (N/S) (1/3)',89,7617,0,'1dc1');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 3 (N/S) (3/3)',78,7624,0,'1dc8');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 3 (N/S) (2/3)',78,7625,0,'1dc9');
+INSERT INTO items VALUES(NULL,'Ring 2',60,7945,0,'1f09');
+INSERT INTO items VALUES(NULL,'Necklace 4',60,7944,0,'1f08');
+INSERT INTO items VALUES(NULL,'Wall 1',241,872,0,'368');
+INSERT INTO items VALUES(NULL,'Wall 2',241,873,0,'369');
+INSERT INTO items VALUES(NULL,'Plain Dress (N/S)',1,7937,0,'1f01');
+INSERT INTO items VALUES(NULL,'Fancy Dress (N/S)',1,7936,0,'1f00');
+INSERT INTO items VALUES(NULL,'Plain Dress (W/E)',1,7938,0,'1f02');
+INSERT INTO items VALUES(NULL,'Robe (W/E)',1,7940,0,'1f04');
+INSERT INTO items VALUES(NULL,'Swamp 7',236,12820,0,'3214');
+INSERT INTO items VALUES(NULL,'metal shield',183,7035,0,'merkite_shields_shield');
+INSERT INTO items VALUES(NULL,'Wall 8',241,879,0,'36f');
+INSERT INTO items VALUES(NULL,'Tree Pieces 1 (4/5)',4,3418,0,'d5a');
+INSERT INTO items VALUES(NULL,'Orc Helm (W/E)',58,7948,0,'1f0c');
+INSERT INTO items VALUES(NULL,'orc helm',58,7947,0,'1f0b');
+INSERT INTO items VALUES(NULL,'Wall 4',241,875,0,'36b');
+INSERT INTO items VALUES(NULL,'Wall 5',241,876,0,'36c');
+INSERT INTO items VALUES(NULL,'Leaves 2 (4/14)',4,3423,0,'d5f');
+INSERT INTO items VALUES(NULL,'Wall 3',241,874,0,'36a');
+INSERT INTO items VALUES(NULL,'Marble Bench 2 (N/S) (2/3)',78,7631,0,'1dcf');
+INSERT INTO items VALUES(NULL,'Marble Bench 2 (N/S) (1/3)',78,7629,0,'1dcd');
+INSERT INTO items VALUES(NULL,'Marble Bench 2 (N/S) (3/3)',78,7630,0,'1dce');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 3 (W/E) (3/3)',78,7627,0,'1dcb');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 3 (W/E) (2/3)',78,7628,0,'1dcc');
+INSERT INTO items VALUES(NULL,'Sandstone Bench 3 (W/E) (1/3)',78,7626,0,'1dca');
+INSERT INTO items VALUES(NULL,'Wooden Chair 2',78,2863,0,'b2f');
+INSERT INTO items VALUES(NULL,'Supports 4',156,415,0,'19f');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',47,410,0,'19a');
+INSERT INTO items VALUES(NULL,'Swamp 4',236,12816,0,'3210');
+INSERT INTO items VALUES(NULL,'Treasure (3/41)',215,6977,0,'1b41');
+INSERT INTO items VALUES(NULL,'Swamp 5',236,12817,0,'3211');
+INSERT INTO items VALUES(NULL,'Treasure (2/41)',215,6976,0,'1b40');
+INSERT INTO items VALUES(NULL,'Treasure (4/41)',215,6978,0,'1b42');
+INSERT INTO items VALUES(NULL,'Rug 8',176,2736,0,'ab0');
+INSERT INTO items VALUES(NULL,'Rug 9',176,2737,0,'ab1');
+INSERT INTO items VALUES(NULL,'Rug 10',176,2738,0,'ab2');
+INSERT INTO items VALUES(NULL,'Rug 3',351,2741,0,'ab5');
+INSERT INTO items VALUES(NULL,'Flower 10',134,3148,0,'c4c');
+INSERT INTO items VALUES(NULL,'Rug 4',351,2742,0,'ab6');
+INSERT INTO items VALUES(NULL,'Rug 5',351,2743,0,'ab7');
+INSERT INTO items VALUES(NULL,'Wall 5',188,500,0,'1f4');
+INSERT INTO items VALUES(NULL,'Window 2',140,94,0,'5e');
+INSERT INTO items VALUES(NULL,'Window 1',140,93,0,'5d');
+INSERT INTO items VALUES(NULL,'Small Wall 1',140,95,0,'5f');
+INSERT INTO items VALUES(NULL,'Wall 4',140,90,0,'5a');
+INSERT INTO items VALUES(NULL,'Wall 6',140,92,0,'5c');
+INSERT INTO items VALUES(NULL,'Wall 5',140,91,0,'5b');
+INSERT INTO items VALUES(NULL,'Balista 38',76,6340,0,'18c4');
+INSERT INTO items VALUES(NULL,'Wall 3',140,89,0,'59');
+INSERT INTO items VALUES(NULL,'Wall 2',140,88,0,'58');
+INSERT INTO items VALUES(NULL,'Edge 4',184,85,0,'55');
+INSERT INTO items VALUES(NULL,'Edge 3',184,84,0,'54');
+INSERT INTO items VALUES(NULL,'Wall 1',140,87,0,'57');
+INSERT INTO items VALUES(NULL,'Edge 5',184,86,0,'56');
+INSERT INTO items VALUES(NULL,'Archedge 4',184,81,0,'51');
+INSERT INTO items VALUES(NULL,'Archedge 3',184,80,0,'50');
+INSERT INTO items VALUES(NULL,'Edge 2',184,83,0,'53');
+INSERT INTO items VALUES(NULL,'Edge 1',184,82,0,'52');
+INSERT INTO items VALUES(NULL,'Fishing Net 5',148,3537,0,'dd1');
+INSERT INTO items VALUES(NULL,'Mana Vampire',92,8372,0,'20b4');
+INSERT INTO items VALUES(NULL,'Mass Dispel',92,8373,0,'20b5');
+INSERT INTO items VALUES(NULL,'Meteor Swarm',92,8374,0,'20b6');
+INSERT INTO items VALUES(NULL,'Polymorph',92,8375,0,'20b7');
+INSERT INTO items VALUES(NULL,'Chain Lightning',92,8368,0,'20b0');
+INSERT INTO items VALUES(NULL,'Energy Field',92,8369,0,'20b1');
+INSERT INTO items VALUES(NULL,'Flamestrike',92,8370,0,'20b2');
+INSERT INTO items VALUES(NULL,'Gate Travel',92,8371,0,'20b3');
+INSERT INTO items VALUES(NULL,'Earthquake',92,8376,0,'20b8');
+INSERT INTO items VALUES(NULL,'Energy Vortex',92,8377,0,'20b9');
+INSERT INTO items VALUES(NULL,'Fish Heads 1',148,7705,0,'1e19');
+INSERT INTO items VALUES(NULL,'Raw Fish 4',148,7704,0,'1e18');
+INSERT INTO items VALUES(NULL,'Gruesome Standard 4',201,1065,0,'429');
+INSERT INTO items VALUES(NULL,'Gruesome Standard 3',201,1064,0,'428');
+INSERT INTO items VALUES(NULL,'Pouch',65,3705,0,'e79');
+INSERT INTO items VALUES(NULL,'Basin',65,3704,0,'e78');
+INSERT INTO items VALUES(NULL,'Potted Cactus 6',134,7700,0,'1e14');
+INSERT INTO items VALUES(NULL,'Pillow 1',91,5015,0,'1397');
+INSERT INTO items VALUES(NULL,'Gruesome Standard 2',201,1056,0,'420');
+INSERT INTO items VALUES(NULL,'Small Wall 1',82,1059,0,'423');
+INSERT INTO items VALUES(NULL,'Decorated Wall 2',82,1058,0,'422');
+INSERT INTO items VALUES(NULL,'Small Wall 3',82,1061,0,'425');
+INSERT INTO items VALUES(NULL,'Small Wall 2',82,1060,0,'424');
+INSERT INTO items VALUES(NULL,'Backpack',65,3701,0,'e75');
+INSERT INTO items VALUES(NULL,'Tattered Banner 1',201,1062,0,'426');
+INSERT INTO items VALUES(NULL,'Potted Cactus 3',134,7697,0,'1e11');
+INSERT INTO items VALUES(NULL,'Potted Cactus 2',134,7696,0,'1e10');
+INSERT INTO items VALUES(NULL,'Summon Earth',92,8381,0,'20bd');
+INSERT INTO items VALUES(NULL,'Summon Fire',92,8382,0,'20be');
+INSERT INTO items VALUES(NULL,'Summon Water',92,8383,0,'20bf');
+INSERT INTO items VALUES(NULL,'Resurrection',92,8378,0,'20ba');
+INSERT INTO items VALUES(NULL,'Summon Air',92,8379,0,'20bb');
+INSERT INTO items VALUES(NULL,'Summon Daemon',92,8380,0,'20bc');
+INSERT INTO items VALUES(NULL,'plate helmet',210,5138,0,'iron_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Metal Chest (W/E)',65,3708,0,'e7c');
+INSERT INTO items VALUES(NULL,'Statue 1 (W/E) (1/3)',54,5023,0,'139f');
+INSERT INTO items VALUES(NULL,'Statue 1 (W/E) (2/3)',54,5022,0,'139e');
+INSERT INTO items VALUES(NULL,'Statue 4 (N/S)',31,5021,0,'139d');
+INSERT INTO items VALUES(NULL,'Statue 3 (N/S)',31,5020,0,'139c');
+INSERT INTO items VALUES(NULL,'Statue 2 (N/S)',31,5019,0,'139b');
+INSERT INTO items VALUES(NULL,'Statue 1 (N/S)',31,5018,0,'139a');
+INSERT INTO items VALUES(NULL,'Wooden Box (W/E)',65,3709,0,'e7d');
+INSERT INTO items VALUES(NULL,'Kindling',294,3553,0,'de1');
+INSERT INTO items VALUES(NULL,'Campfire',352,3555,0,'de3');
+INSERT INTO items VALUES(NULL,'Wheat 3',45,3159,0,'c57');
+INSERT INTO items VALUES(NULL,'Wheat 2',45,3158,0,'c56');
+INSERT INTO items VALUES(NULL,'Wheat 1',45,3157,0,'c55');
+INSERT INTO items VALUES(NULL,'Cotton 6',45,3156,0,'c54');
+INSERT INTO items VALUES(NULL,'Cotton 5',45,3155,0,'c53');
+INSERT INTO items VALUES(NULL,'Cotton 4',45,3154,0,'c52');
+INSERT INTO items VALUES(NULL,'Cotton 3',45,3153,0,'c51');
+INSERT INTO items VALUES(NULL,'Cotton 2',45,3152,0,'c50');
+INSERT INTO items VALUES(NULL,'chainmail leggings',194,5054,0,'agapite_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Wheat 5',45,3161,0,'c59');
+INSERT INTO items VALUES(NULL,'Wheat 4',45,3160,0,'c58');
+INSERT INTO items VALUES(NULL,'Vines 2',45,3167,0,'c5f');
+INSERT INTO items VALUES(NULL,'Vines 1',45,3166,0,'c5e');
+INSERT INTO items VALUES(NULL,'Watermelon 2',19,3165,0,'c5d');
+INSERT INTO items VALUES(NULL,'Watermelon 1',19,3164,0,'c5c');
+INSERT INTO items VALUES(NULL,'Wheat 7',45,3163,0,'c5b');
+INSERT INTO items VALUES(NULL,'Wheat 6',45,3162,0,'c5a');
+INSERT INTO items VALUES(NULL,'Wall 35',82,8618,0,'21aa');
+INSERT INTO items VALUES(NULL,'Wall 36',82,8619,0,'21ab');
+INSERT INTO items VALUES(NULL,'Wall 37',82,8620,0,'21ac');
+INSERT INTO items VALUES(NULL,'Wall 38',82,8621,0,'21ad');
+INSERT INTO items VALUES(NULL,'Wall 39',82,8622,0,'21ae');
+INSERT INTO items VALUES(NULL,'Post 1',82,8623,0,'21af');
+INSERT INTO items VALUES(NULL,'Wooden Door 4 (S/SE)',233,1767,0,'6e7');
+INSERT INTO items VALUES(NULL,'Wooden Door 4 (S/SW)',233,1765,0,'6e5');
+INSERT INTO items VALUES(NULL,'Wooden Door 3 (W/NW)',248,1763,0,'6e3');
+INSERT INTO items VALUES(NULL,'Wooden Door 3 (W/SW)',248,1761,0,'6e1');
+INSERT INTO items VALUES(NULL,'Wooden Door 4 (S/NW)',233,1769,0,'6e9');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (9/9)',108,6157,0,'180d');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (8/9)',108,6156,0,'180c');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (7/9)',108,6155,0,'180b');
+INSERT INTO items VALUES(NULL,'buckler',77,7027,0,'bronze_shields_buckler');
+INSERT INTO items VALUES(NULL,'ringmail gloves',235,5099,0,'agapite_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Wall 33',82,8616,0,'21a8');
+INSERT INTO items VALUES(NULL,'Wall 34',82,8617,0,'21a9');
+INSERT INTO items VALUES(NULL,'Wall 30',82,8613,0,'21a5');
+INSERT INTO items VALUES(NULL,'Wall 31',82,8614,0,'21a6');
+INSERT INTO items VALUES(NULL,'Wall 32',82,8615,0,'21a7');
+INSERT INTO items VALUES(NULL,'Catapult 131',72,5845,0,'16d5');
+INSERT INTO items VALUES(NULL,'Catapult 130',72,5844,0,'16d4');
+INSERT INTO items VALUES(NULL,'Catapult 133',72,5847,0,'16d7');
+INSERT INTO items VALUES(NULL,'Catapult 132',72,5846,0,'16d6');
+INSERT INTO items VALUES(NULL,'Catapult 127',72,5841,0,'16d1');
+INSERT INTO items VALUES(NULL,'Catapult 126',72,5840,0,'16d0');
+INSERT INTO items VALUES(NULL,'Catapult 129',72,5843,0,'16d3');
+INSERT INTO items VALUES(NULL,'Catapult 128',72,5842,0,'16d2');
+INSERT INTO items VALUES(NULL,'Catapult 135',72,5849,0,'16d9');
+INSERT INTO items VALUES(NULL,'Catapult 134',72,5848,0,'16d8');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (3/9)',108,6151,0,'1807');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (2/9)',108,6150,0,'1806');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (1/9)',108,6149,0,'1805');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (9/9)',108,6148,0,'1804');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (8/9)',108,6147,0,'1803');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (7/9)',108,6146,0,'1802');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (6/9)',108,6145,0,'1801');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (5/9)',108,6144,0,'1800');
+INSERT INTO items VALUES(NULL,'Death Vortex',28,14217,0,'3789');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (5/9)',108,6153,0,'1809');
+INSERT INTO items VALUES(NULL,'Teleporter 6 (4/9)',108,6152,0,'1808');
+INSERT INTO items VALUES(NULL,'Wooden Door 4 (W/NE)',233,1775,0,'6ef');
+INSERT INTO items VALUES(NULL,'Wooden Door 4 (W/SE)',233,1773,0,'6ed');
+INSERT INTO items VALUES(NULL,'Wooden Door 4 (S/NE)',233,1771,0,'6eb');
+INSERT INTO items VALUES(NULL,'Vines 2 (4/4)',4,3437,0,'d6d');
+INSERT INTO items VALUES(NULL,'Telescope (66/66)',182,5274,0,'149a');
+INSERT INTO items VALUES(NULL,'Part 1',361,5279,0,'149f');
+INSERT INTO items VALUES(NULL,'Vines 2 (2/4)',4,3435,0,'d6b');
+INSERT INTO items VALUES(NULL,'Swamp 9',237,12888,0,'3258');
+INSERT INTO items VALUES(NULL,'Swamp 10',237,12889,0,'3259');
+INSERT INTO items VALUES(NULL,'Goblets',279,6466,0,'1942');
+INSERT INTO items VALUES(NULL,'Tankards',279,6467,0,'1943');
+INSERT INTO items VALUES(NULL,'Swamp 3',237,12882,0,'3252');
+INSERT INTO items VALUES(NULL,'Glass Mugs',279,6465,0,'1941');
+INSERT INTO items VALUES(NULL,'Swamp 5',237,12884,0,'3254');
+INSERT INTO items VALUES(NULL,'Swamp 6',237,12885,0,'3255');
+INSERT INTO items VALUES(NULL,'Swamp 7',237,12886,0,'3256');
+INSERT INTO items VALUES(NULL,'Swamp 8',237,12887,0,'3257');
+INSERT INTO items VALUES(NULL,'Brazier 2',73,6570,0,'19aa');
+INSERT INTO items VALUES(NULL,'Fire',28,6571,0,'19ab');
+INSERT INTO items VALUES(NULL,'Bear Mask (N/S)',58,5445,0,'1545');
+INSERT INTO items VALUES(NULL,'Balista 221',76,16328,0,'3fc8');
+INSERT INTO items VALUES(NULL,'Telescope (56/66)',182,5264,0,'1490');
+INSERT INTO items VALUES(NULL,'Decorated Wall 1',82,1057,0,'421');
+INSERT INTO items VALUES(NULL,'Telescope (58/66)',182,5266,0,'1492');
+INSERT INTO items VALUES(NULL,'Telescope (59/66)',182,5267,0,'1493');
+INSERT INTO items VALUES(NULL,'Telescope (60/66)',182,5268,0,'1494');
+INSERT INTO items VALUES(NULL,'Telescope (61/66)',182,5269,0,'1495');
+INSERT INTO items VALUES(NULL,'Telescope (62/66)',182,5270,0,'1496');
+INSERT INTO items VALUES(NULL,'Telescope (63/66)',182,5271,0,'1497');
+INSERT INTO items VALUES(NULL,'Telescope (64/66)',182,5272,0,'1498');
+INSERT INTO items VALUES(NULL,'Telescope (65/66)',182,5273,0,'1499');
+INSERT INTO items VALUES(NULL,'Short Cannon (E/W) (1/2)',67,3697,0,'e71');
+INSERT INTO items VALUES(NULL,'Short Cannon (S/N) (2/2)',67,3696,0,'e70');
+INSERT INTO items VALUES(NULL,'Barrel 1',65,3703,0,'e77');
+INSERT INTO items VALUES(NULL,'Balista 222',76,16329,0,'3fc9');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 9',121,1869,0,'74d');
+INSERT INTO items VALUES(NULL,'longsword',3,5048,0,'13b8');
+INSERT INTO items VALUES(NULL,'Bag',65,3702,0,'e76');
+INSERT INTO items VALUES(NULL,'Tattered Banner 2',201,1063,0,'427');
+INSERT INTO items VALUES(NULL,'Swamp 11',237,12890,0,'325a');
+INSERT INTO items VALUES(NULL,'Swamp 12',237,12891,0,'325b');
+INSERT INTO items VALUES(NULL,'Swamp 13',237,12892,0,'325c');
+INSERT INTO items VALUES(NULL,'Swamp 14',237,12893,0,'325d');
+INSERT INTO items VALUES(NULL,'Swamp 15',237,12894,0,'325e');
+INSERT INTO items VALUES(NULL,'Swamp 16',237,12895,0,'325f');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 10',121,1870,0,'74e');
+INSERT INTO items VALUES(NULL,'Wall Carving 3 (W/E) (1/3)',53,4669,0,'123d');
+INSERT INTO items VALUES(NULL,'Wall Carving 3 (W/E) (2/3)',53,4670,0,'123e');
+INSERT INTO items VALUES(NULL,'Wall Carving 5 (W/E) (1/3)',53,4666,0,'123a');
+INSERT INTO items VALUES(NULL,'Wall Carving 5 (W/E) (2/3)',53,4667,0,'123b');
+INSERT INTO items VALUES(NULL,'Wall Carving 5 (W/E) (3/3)',53,4668,0,'123c');
+INSERT INTO items VALUES(NULL,'Stone Paver 12',268,1316,0,'524');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 1',93,1317,0,'525');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 2',93,1318,0,'526');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 3',93,1319,0,'527');
+INSERT INTO items VALUES(NULL,'Stone Paver 8',268,1312,0,'520');
+INSERT INTO items VALUES(NULL,'Stone Paver 9',268,1313,0,'521');
+INSERT INTO items VALUES(NULL,'Stone Paver 10',268,1314,0,'522');
+INSERT INTO items VALUES(NULL,'Stone Paver 11',268,1315,0,'523');
+INSERT INTO items VALUES(NULL,'Hanging Net 3',148,7845,0,'1ea5');
+INSERT INTO items VALUES(NULL,'Hanging Net 2',148,7844,0,'1ea4');
+INSERT INTO items VALUES(NULL,'Hanging Net 4',148,7846,0,'1ea6');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 4',93,1320,0,'528');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 5',93,1321,0,'529');
+INSERT INTO items VALUES(NULL,'Hanging Net 1',148,7843,0,'1ea3');
+INSERT INTO items VALUES(NULL,'Rope 2',148,7842,0,'1ea2');
+INSERT INTO items VALUES(NULL,'Wall Carving 4 (N/S) (1/2)',53,4660,0,'1234');
+INSERT INTO items VALUES(NULL,'Wall Carving 4 (N/S) (2/2)',53,4661,0,'1235');
+INSERT INTO items VALUES(NULL,'Wall Carving 5 (N/S) (1/3)',53,4663,0,'1237');
+INSERT INTO items VALUES(NULL,'Guillotine 1',113,4656,0,'1230');
+INSERT INTO items VALUES(NULL,'Wall Carving 3 (N/S) (1/3)',53,4657,0,'1231');
+INSERT INTO items VALUES(NULL,'Wall Carving 3 (N/S) (2/3)',53,4658,0,'1232');
+INSERT INTO items VALUES(NULL,'Wall Carving 3 (N/S) (3/3)',53,4659,0,'1233');
+INSERT INTO items VALUES(NULL,'Wall Carving 5 (N/S) (2/3)',53,4664,0,'1238');
+INSERT INTO items VALUES(NULL,'Wall Carving 5 (N/S) (3/3)',53,4665,0,'1239');
+INSERT INTO items VALUES(NULL,'Legs 4',147,7403,0,'1ceb');
+INSERT INTO items VALUES(NULL,'Dark Sandstone Floor 1',253,1327,0,'52f');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 6',93,1322,0,'52a');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 7',93,1323,0,'52b');
+INSERT INTO items VALUES(NULL,'Sandstone Floor 8',93,1324,0,'52c');
+INSERT INTO items VALUES(NULL,'Winch (W/E) (Animated)',141,7853,0,'1ead');
+INSERT INTO items VALUES(NULL,'Winch (W/E)',141,7852,0,'1eac');
+INSERT INTO items VALUES(NULL,'Raw Cotton 1',57,3567,0,'def');
+INSERT INTO items VALUES(NULL,'Tree Pieces 2 (5/5)',4,3442,0,'d72');
+INSERT INTO items VALUES(NULL,'Leaves 3 (1/13)',4,3443,0,'d73');
+INSERT INTO items VALUES(NULL,'Tree Pieces 2 (3/5)',4,3440,0,'d70');
+INSERT INTO items VALUES(NULL,'Tree Pieces 2 (4/5)',4,3441,0,'d71');
+INSERT INTO items VALUES(NULL,'Leaves 3 (4/13)',4,3446,0,'d76');
+INSERT INTO items VALUES(NULL,'Leaves 3 (5/13)',4,3447,0,'d77');
+INSERT INTO items VALUES(NULL,'Leaves 3 (2/13)',4,3444,0,'d74');
+INSERT INTO items VALUES(NULL,'Leaves 3 (3/13)',4,3445,0,'d75');
+INSERT INTO items VALUES(NULL,'Leaves 3 (6/13)',4,3448,0,'d78');
+INSERT INTO items VALUES(NULL,'Leaves 3 (7/13)',4,3449,0,'d79');
+INSERT INTO items VALUES(NULL,'Body 6',147,7564,0,'1d8c');
+INSERT INTO items VALUES(NULL,'Body 5',147,7563,0,'1d8b');
+INSERT INTO items VALUES(NULL,'Body 4',147,7562,0,'1d8a');
+INSERT INTO items VALUES(NULL,'Skeleton 2',12,7567,0,'1d8f');
+INSERT INTO items VALUES(NULL,'Skeleton 1',12,7566,0,'1d8e');
+INSERT INTO items VALUES(NULL,'Body 7',147,7565,0,'1d8d');
+INSERT INTO items VALUES(NULL,'Balista 114',76,16221,0,'3f5d');
+INSERT INTO items VALUES(NULL,'Balista 115',76,16222,0,'3f5e');
+INSERT INTO items VALUES(NULL,'Balista 116',76,16223,0,'3f5f');
+INSERT INTO items VALUES(NULL,'Bedroll 5',91,7974,0,'1f26');
+INSERT INTO items VALUES(NULL,'Balista 112',76,16219,0,'3f5b');
+INSERT INTO items VALUES(NULL,'Balista 113',76,16220,0,'3f5c');
+INSERT INTO items VALUES(NULL,'Balista 214',76,16321,0,'3fc1');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 3',116,7555,0,'1d83');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 2',116,7554,0,'1d82');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 1',116,7553,0,'1d81');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 2 (N/S) 5',116,7552,0,'1d80');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 7',116,7559,0,'1d87');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 6',116,7558,0,'1d86');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 5',116,7557,0,'1d85');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 4',116,7556,0,'1d84');
+INSERT INTO items VALUES(NULL,'Balista 105',76,16212,0,'3f54');
+INSERT INTO items VALUES(NULL,'Balista 106',76,16213,0,'3f55');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 9',116,7561,0,'1d89');
+INSERT INTO items VALUES(NULL,'Skeleton in Stone Coffin 3 (N/S) 8',116,7560,0,'1d88');
+INSERT INTO items VALUES(NULL,'Balista 101',76,16208,0,'3f50');
+INSERT INTO items VALUES(NULL,'Balista 102',76,16209,0,'3f51');
+INSERT INTO items VALUES(NULL,'Balista 103',76,16210,0,'3f52');
+INSERT INTO items VALUES(NULL,'Balista 104',76,16211,0,'3f53');
+INSERT INTO items VALUES(NULL,'Leaves 3 (9/13)',4,3451,0,'d7b');
+INSERT INTO items VALUES(NULL,'Tattered Banner 3',201,1066,0,'42a');
+INSERT INTO items VALUES(NULL,'Leaves 3 (8/13)',4,3450,0,'d7a');
+INSERT INTO items VALUES(NULL,'Leaves 3 (13/13)',4,3455,0,'d7f');
+INSERT INTO items VALUES(NULL,'Leaves 3 (11/13)',4,3453,0,'d7d');
+INSERT INTO items VALUES(NULL,'Water Tub',65,3707,0,'e7b');
+INSERT INTO items VALUES(NULL,'Picnic Basket',65,3706,0,'e7a');
+INSERT INTO items VALUES(NULL,'Part 2',362,5288,0,'14a8');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 9',202,6959,0,'1b2f');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 8',202,6958,0,'1b2e');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 7',202,6957,0,'1b2d');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 6',202,6956,0,'1b2c');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 5',202,6955,0,'1b2b');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 4',202,6954,0,'1b2a');
+INSERT INTO items VALUES(NULL,'Part 2',361,5280,0,'14a0');
+INSERT INTO items VALUES(NULL,'Part 3',361,5281,0,'14a1');
+INSERT INTO items VALUES(NULL,'Part 4',361,5282,0,'14a2');
+INSERT INTO items VALUES(NULL,'Part 1',363,5283,0,'14a3');
+INSERT INTO items VALUES(NULL,'Part 2',363,5284,0,'14a4');
+INSERT INTO items VALUES(NULL,'Part 3',363,5285,0,'14a5');
+INSERT INTO items VALUES(NULL,'Part 4',363,5286,0,'14a6');
+INSERT INTO items VALUES(NULL,'Part 1',362,5287,0,'14a7');
+INSERT INTO items VALUES(NULL,'Small Crate 1 (W/E)',65,3710,0,'e7e');
+INSERT INTO items VALUES(NULL,'Tattered Banner 8',201,1071,0,'42f');
+INSERT INTO items VALUES(NULL,'Wooden Signpost 1 (W/E)',340,2968,0,'b98');
+INSERT INTO items VALUES(NULL,'Wooden Signpost 2 (N/S)',340,2969,0,'b99');
+INSERT INTO items VALUES(NULL,'Library (W/E)',230,2966,0,'b96');
+INSERT INTO items VALUES(NULL,'Wooden Signpost 1 (N/S)',340,2967,0,'b97');
+INSERT INTO items VALUES(NULL,'Bench (N/S) (2/2)',78,2964,0,'b94');
+INSERT INTO items VALUES(NULL,'Library (N/S)',230,2965,0,'b95');
+INSERT INTO items VALUES(NULL,'Bench (N/S) (2/2)',78,2962,0,'b92');
+INSERT INTO items VALUES(NULL,'Bench (W/E) (1/2)',78,2963,0,'b93');
+INSERT INTO items VALUES(NULL,'Wooden Table 6 (N/S)',89,2960,0,'b90');
+INSERT INTO items VALUES(NULL,'Bench (N/S) (1/2)',78,2961,0,'b91');
+INSERT INTO items VALUES(NULL,'Harm',92,8331,0,'208b');
+INSERT INTO items VALUES(NULL,'Magic Trap',92,8332,0,'208c');
+INSERT INTO items VALUES(NULL,'Cure',92,8330,0,'208a');
+INSERT INTO items VALUES(NULL,'Strength',92,8335,0,'208f');
+INSERT INTO items VALUES(NULL,'Magic Untrap',92,8333,0,'208d');
+INSERT INTO items VALUES(NULL,'Protection',92,8334,0,'208e');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 1',202,6951,0,'1b27');
+INSERT INTO items VALUES(NULL,'Leaves 8',4,6950,0,'1b26');
+INSERT INTO items VALUES(NULL,'Leaves 7',4,6949,0,'1b25');
+INSERT INTO items VALUES(NULL,'Leaves 6',4,6948,0,'1b24');
+INSERT INTO items VALUES(NULL,'Leaves 5',4,6947,0,'1b23');
+INSERT INTO items VALUES(NULL,'Leaves 4',4,6946,0,'1b22');
+INSERT INTO items VALUES(NULL,'Leaves 3',4,6945,0,'1b21');
+INSERT INTO items VALUES(NULL,'Leaves 2',4,6944,0,'1b20');
+INSERT INTO items VALUES(NULL,'Part 4',362,5290,0,'14aa');
+INSERT INTO items VALUES(NULL,'Part 1',364,5291,0,'14ab');
+INSERT INTO items VALUES(NULL,'Part 2',364,5292,0,'14ac');
+INSERT INTO items VALUES(NULL,'Part 3',364,5293,0,'14ad');
+INSERT INTO items VALUES(NULL,'Part 4',364,5294,0,'14ae');
+INSERT INTO items VALUES(NULL,'Part 1',287,5295,0,'14af');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 2',202,6952,0,'1b28');
+INSERT INTO items VALUES(NULL,'Agility',92,8328,0,'2088');
+INSERT INTO items VALUES(NULL,'Cunning',92,8329,0,'2089');
+INSERT INTO items VALUES(NULL,'Feeblemind',92,8322,0,'2082');
+INSERT INTO items VALUES(NULL,'Heal',92,8323,0,'2083');
+INSERT INTO items VALUES(NULL,'Clumsy',92,8320,0,'2080');
+INSERT INTO items VALUES(NULL,'Create Food',92,8321,0,'2081');
+INSERT INTO items VALUES(NULL,'Reactive Armor',92,8326,0,'2086');
+INSERT INTO items VALUES(NULL,'Weaken',92,8327,0,'2087');
+INSERT INTO items VALUES(NULL,'Magic Arrow',92,8324,0,'2084');
+INSERT INTO items VALUES(NULL,'Night Sight',92,8325,0,'2085');
+INSERT INTO items VALUES(NULL,'Metal Signpost 3 (N/S)',340,2975,0,'b9f');
+INSERT INTO items VALUES(NULL,'Metal Signpost 2 (N/S)',340,2973,0,'b9d');
+INSERT INTO items VALUES(NULL,'Metal Signpost 2 (W/E)',340,2974,0,'b9e');
+INSERT INTO items VALUES(NULL,'Metal Signpost 1 (N/S)',340,2971,0,'b9b');
+INSERT INTO items VALUES(NULL,'Metal Signpost 1 (W/E)',340,2972,0,'b9c');
+INSERT INTO items VALUES(NULL,'Wooden Signpost 2 (W/E)',340,2970,0,'b9a');
+INSERT INTO items VALUES(NULL,'Surcoat (W/E)',1,8190,0,'1ffe');
+INSERT INTO items VALUES(NULL,'Surcoat (N/S)',1,8189,0,'1ffd');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 2 (W/NW)',126,8187,0,'1ffb');
+INSERT INTO items VALUES(NULL,'Balista 39',76,6341,0,'18c5');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 2 (W/SW)',126,8185,0,'1ff9');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 2 (W/NE)',126,8183,0,'1ff7');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 2 (W/SE)',126,8181,0,'1ff5');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 2 (S/NE)',126,8179,0,'1ff3');
+INSERT INTO items VALUES(NULL,'Barred Metal Door 2 (S/NW)',126,8177,0,'1ff1');
+INSERT INTO items VALUES(NULL,'heater shield',183,7030,0,'merkite_shields_heater');
+INSERT INTO items VALUES(NULL,'Gold Key',51,4111,0,'100f');
+INSERT INTO items VALUES(NULL,'Copper Key',51,4110,0,'100e');
+INSERT INTO items VALUES(NULL,'Sheaf of Hay 3',13,4109,0,'100d');
+INSERT INTO items VALUES(NULL,'Sheaf of Hay 2',13,4108,0,'100c');
+INSERT INTO items VALUES(NULL,'Archery Butte (N/S)',365,4107,0,'100b');
+INSERT INTO items VALUES(NULL,'Archery Butte (W/E)',365,4106,0,'100a');
+INSERT INTO items VALUES(NULL,'chainmail tunic',205,5055,0,'copper_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Morning Glory 2',134,7950,0,'1f0e');
+INSERT INTO items VALUES(NULL,'Morning Glory 1',134,7949,0,'1f0d');
+INSERT INTO items VALUES(NULL,'Basin',274,4105,0,'1009');
+INSERT INTO items VALUES(NULL,'Wash Basin',274,4104,0,'1008');
+INSERT INTO items VALUES(NULL,'Half Full Jar',173,4103,0,'1007');
+INSERT INTO items VALUES(NULL,'Full Jar',173,4102,0,'1006');
+INSERT INTO items VALUES(NULL,'Empty Jar',173,4101,0,'1005');
+INSERT INTO items VALUES(NULL,'Barrel Trap',109,4100,0,'1004');
+INSERT INTO items VALUES(NULL,'Spittoon',279,4099,0,'1003');
+INSERT INTO items VALUES(NULL,'Pewter Mug 4',279,4098,0,'1002');
+INSERT INTO items VALUES(NULL,'Pewter Mug 3',279,4097,0,'1001');
+INSERT INTO items VALUES(NULL,'Pewter Mug 2',279,4096,0,'1000');
+INSERT INTO items VALUES(NULL,'Tree Stump 6',4,3673,0,'e59');
+INSERT INTO items VALUES(NULL,'Tree Stump 5',4,3672,0,'e58');
+INSERT INTO items VALUES(NULL,'close helmet',25,5128,0,'valorite_helmets_close');
+INSERT INTO items VALUES(NULL,'Tree Stump 4',4,3671,0,'e57');
+INSERT INTO items VALUES(NULL,'Tree Stump 3',4,3670,0,'e56');
+INSERT INTO items VALUES(NULL,'Rune 2',261,3679,0,'e5f');
+INSERT INTO items VALUES(NULL,'Rune 1',261,3676,0,'e5c');
+INSERT INTO items VALUES(NULL,'Pen & Ink (N/S)',262,4032,0,'fc0');
+INSERT INTO items VALUES(NULL,'Paints and Brush',262,4033,0,'fc1');
+INSERT INTO items VALUES(NULL,'Shell 1',311,4036,0,'fc4');
+INSERT INTO items VALUES(NULL,'Shell 2',311,4037,0,'fc5');
+INSERT INTO items VALUES(NULL,'Shell 3',311,4038,0,'fc6');
+INSERT INTO items VALUES(NULL,'Shell 4',311,4039,0,'fc7');
+INSERT INTO items VALUES(NULL,'Shell 5',311,4040,0,'fc8');
+INSERT INTO items VALUES(NULL,'Shell 6',311,4041,0,'fc9');
+INSERT INTO items VALUES(NULL,'nose helmet',275,5134,0,'agapite_helmets_nose');
+INSERT INTO items VALUES(NULL,'Canteloupe 1',19,3193,0,'c79');
+INSERT INTO items VALUES(NULL,'Carrots 2',19,3192,0,'c78');
+INSERT INTO items VALUES(NULL,'Head of Lettuce 2',19,3185,0,'c71');
+INSERT INTO items VALUES(NULL,'Head of Lettuce 1',19,3184,0,'c70');
+INSERT INTO items VALUES(NULL,'Squash 2',19,3187,0,'c73');
+INSERT INTO items VALUES(NULL,'Squash 1',19,3186,0,'c72');
+INSERT INTO items VALUES(NULL,'Honeydew Melon 2',19,3189,0,'c75');
+INSERT INTO items VALUES(NULL,'Honeydew Melon 1',19,3188,0,'c74');
+INSERT INTO items VALUES(NULL,'Carrots 1',19,3191,0,'c77');
+INSERT INTO items VALUES(NULL,'Carrots',213,3190,0,'c76');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (6/9)',108,6109,0,'17dd');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (7/9)',108,6110,0,'17de');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (8/9)',108,6111,0,'17df');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (3/9)',108,6106,0,'17da');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (4/9)',108,6107,0,'17db');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (5/9)',108,6108,0,'17dc');
+INSERT INTO items VALUES(NULL,'Shell 7',311,4042,0,'fca');
+INSERT INTO items VALUES(NULL,'Shell 8',311,4043,0,'fcb');
+INSERT INTO items VALUES(NULL,'Shell 9',311,4044,0,'fcc');
+INSERT INTO items VALUES(NULL,'String of Shells 1',311,4045,0,'fcd');
+INSERT INTO items VALUES(NULL,'String of Shells 2',311,4046,0,'fce');
+INSERT INTO items VALUES(NULL,'String of Shells 3',311,4047,0,'fcf');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (1/9)',108,6104,0,'17d8');
+INSERT INTO items VALUES(NULL,'Teleporter 2 (2/9)',108,6105,0,'17d9');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (6/9)',108,6100,0,'17d4');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (7/9)',108,6101,0,'17d5');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (8/9)',108,6102,0,'17d6');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (9/9)',108,6103,0,'17d7');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (2/9)',108,6096,0,'17d0');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (3/9)',108,6097,0,'17d1');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (4/9)',108,6098,0,'17d2');
+INSERT INTO items VALUES(NULL,'Teleporter 1 (5/9)',108,6099,0,'17d3');
+INSERT INTO items VALUES(NULL,'Canteloupe 2',19,3194,0,'c7a');
+INSERT INTO items VALUES(NULL,'Head of Cabbage 2',19,3196,0,'c7c');
+INSERT INTO items VALUES(NULL,'Head of Cabbage 1',19,3195,0,'c7b');
+INSERT INTO items VALUES(NULL,'Corn Stalk 2',213,3198,0,'c7e');
+INSERT INTO items VALUES(NULL,'Corn Stalk 1',213,3197,0,'c7d');
+INSERT INTO items VALUES(NULL,'Ear of Corn 1',19,3199,0,'c7f');
+INSERT INTO items VALUES(NULL,'Catapult 106',72,5820,0,'16bc');
+INSERT INTO items VALUES(NULL,'Catapult 105',72,5819,0,'16bb');
+INSERT INTO items VALUES(NULL,'Catapult 104',72,5818,0,'16ba');
+INSERT INTO items VALUES(NULL,'Catapult 109',72,5823,0,'16bf');
+INSERT INTO items VALUES(NULL,'Catapult 108',72,5822,0,'16be');
+INSERT INTO items VALUES(NULL,'Catapult 107',72,5821,0,'16bd');
+INSERT INTO items VALUES(NULL,'chainmail coif',284,5051,0,'verite_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Roof 23',327,8527,0,'214f');
+INSERT INTO items VALUES(NULL,'Roof 22',327,8526,0,'214e');
+INSERT INTO items VALUES(NULL,'Roof 21',327,8525,0,'214d');
+INSERT INTO items VALUES(NULL,'Roof 20',327,8524,0,'214c');
+INSERT INTO items VALUES(NULL,'Roof 19',327,8523,0,'214b');
+INSERT INTO items VALUES(NULL,'Roof 18',327,8522,0,'214a');
+INSERT INTO items VALUES(NULL,'Flask 5',173,6190,0,'182e');
+INSERT INTO items VALUES(NULL,'Flask 4',173,6189,0,'182d');
+INSERT INTO items VALUES(NULL,'Flask 6',173,6191,0,'182f');
+INSERT INTO items VALUES(NULL,'Flask 1',173,6186,0,'182a');
+INSERT INTO items VALUES(NULL,'Flask 3',173,6188,0,'182c');
+INSERT INTO items VALUES(NULL,'Flask 2',173,6187,0,'182b');
+INSERT INTO items VALUES(NULL,'Catapult 97',72,5811,0,'16b3');
+INSERT INTO items VALUES(NULL,'Catapult 96',72,5810,0,'16b2');
+INSERT INTO items VALUES(NULL,'Catapult 95',72,5809,0,'16b1');
+INSERT INTO items VALUES(NULL,'Catapult 94',72,5808,0,'16b0');
+INSERT INTO items VALUES(NULL,'Catapult 101',72,5815,0,'16b7');
+INSERT INTO items VALUES(NULL,'Catapult 100',72,5814,0,'16b6');
+INSERT INTO items VALUES(NULL,'Treasure (38/41)',215,7016,0,'1b68');
+INSERT INTO items VALUES(NULL,'Catapult 98',72,5812,0,'16b4');
+INSERT INTO items VALUES(NULL,'Catapult 103',72,5817,0,'16b9');
+INSERT INTO items VALUES(NULL,'Catapult 102',72,5816,0,'16b8');
+INSERT INTO items VALUES(NULL,'Flask Stand',173,6185,0,'1829');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 12',173,6184,0,'1828');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 9',173,6181,0,'1825');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 8',173,6180,0,'1824');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 11',173,6183,0,'1827');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 10',173,6182,0,'1826');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 5',173,6177,0,'1821');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 4',173,6176,0,'1820');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 7',173,6179,0,'1823');
+INSERT INTO items VALUES(NULL,'Alchemical Symbol 6',173,6178,0,'1822');
+INSERT INTO items VALUES(NULL,'Stars 6',313,8516,0,'2144');
+INSERT INTO items VALUES(NULL,'Stars 5',313,8515,0,'2143');
+INSERT INTO items VALUES(NULL,'Stars 4',313,8514,0,'2142');
+INSERT INTO items VALUES(NULL,'Stars 3',313,8513,0,'2141');
+INSERT INTO items VALUES(NULL,'Stars 2',313,8512,0,'2140');
+INSERT INTO items VALUES(NULL,'Balista 2',76,6304,0,'18a0');
+INSERT INTO items VALUES(NULL,'Roof 17',327,8521,0,'2149');
+INSERT INTO items VALUES(NULL,'Roof 16',327,8520,0,'2148');
+INSERT INTO items VALUES(NULL,'Swamp 32',237,12918,0,'3276');
+INSERT INTO items VALUES(NULL,'Swamp 33',237,12919,0,'3277');
+INSERT INTO items VALUES(NULL,'Swamp 30',237,12916,0,'3274');
+INSERT INTO items VALUES(NULL,'Swamp 21',237,12917,0,'3275');
+INSERT INTO items VALUES(NULL,'Swamp 28',237,12914,0,'3272');
+INSERT INTO items VALUES(NULL,'Swamp 29',237,12915,0,'3273');
+INSERT INTO items VALUES(NULL,'Swamp 26',237,12912,0,'3270');
+INSERT INTO items VALUES(NULL,'Swamp 27',237,12913,0,'3271');
+INSERT INTO items VALUES(NULL,'Rotating Crank (W/E)',114,6440,0,'1928');
+INSERT INTO items VALUES(NULL,'Swamp 34',237,12920,0,'3278');
+INSERT INTO items VALUES(NULL,'Swamp 35',237,12921,0,'3279');
+INSERT INTO items VALUES(NULL,'Balista 11',76,6313,0,'18a9');
+INSERT INTO items VALUES(NULL,'Wall 10',22,8646,0,'21c6');
+INSERT INTO items VALUES(NULL,'Wall 11',22,8647,0,'21c7');
+INSERT INTO items VALUES(NULL,'Small Wall 15',22,8644,0,'21c4');
+INSERT INTO items VALUES(NULL,'Wall 9',22,8645,0,'21c5');
+INSERT INTO items VALUES(NULL,'Small Wall 13',22,8642,0,'21c2');
+INSERT INTO items VALUES(NULL,'Small Wall 14',22,8643,0,'21c3');
+INSERT INTO items VALUES(NULL,'ringmail gloves',255,5099,0,'iron_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Small Wall 12',22,8641,0,'21c1');
+INSERT INTO items VALUES(NULL,'Wall 12',22,8648,0,'21c8');
+INSERT INTO items VALUES(NULL,'Wall 13',22,8649,0,'21c9');
+INSERT INTO items VALUES(NULL,'Swamp 41',237,12927,0,'327f');
+INSERT INTO items VALUES(NULL,'Swamp 39',237,12925,0,'327d');
+INSERT INTO items VALUES(NULL,'Swamp 40',237,12926,0,'327e');
+INSERT INTO items VALUES(NULL,'Swamp 37',237,12923,0,'327b');
+INSERT INTO items VALUES(NULL,'Swamp 38',237,12924,0,'327c');
+INSERT INTO items VALUES(NULL,'Flour Mill 2 (N/S) (2/2)',114,6447,0,'192f');
+INSERT INTO items VALUES(NULL,'Swamp 36',237,12922,0,'327a');
+INSERT INTO items VALUES(NULL,'ringmail gloves',125,5099,0,'golden_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Tiny Wall 7',149,8655,0,'21cf');
+INSERT INTO items VALUES(NULL,'Tiny Wall 5',149,8653,0,'21cd');
+INSERT INTO items VALUES(NULL,'Tiny Wall 6',149,8654,0,'21ce');
+INSERT INTO items VALUES(NULL,'Wall 15',22,8651,0,'21cb');
+INSERT INTO items VALUES(NULL,'Wall 16',22,8652,0,'21cc');
+INSERT INTO items VALUES(NULL,'Wall 14',22,8650,0,'21ca');
+INSERT INTO items VALUES(NULL,'Stone Throne 4',78,4635,0,'121b');
+INSERT INTO items VALUES(NULL,'Roof 4',153,1594,0,'63a');
+INSERT INTO items VALUES(NULL,'Roof 1',142,1595,0,'63b');
+INSERT INTO items VALUES(NULL,'Stone Throne 3',78,4634,0,'121a');
+INSERT INTO items VALUES(NULL,'Wall Carving 1 (3/3)',53,4639,0,'121f');
+INSERT INTO items VALUES(NULL,'Roof 4',142,1598,0,'63e');
+INSERT INTO items VALUES(NULL,'Wall Carving 1 (1/3)',53,4637,0,'121d');
+INSERT INTO items VALUES(NULL,'Wall Carving 1 (2/3)',53,4638,0,'121e');
+INSERT INTO items VALUES(NULL,'Smaller Wall 6',140,104,0,'68');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',140,105,0,'69');
+INSERT INTO items VALUES(NULL,'Wooden Logs 10',356,1288,0,'508');
+INSERT INTO items VALUES(NULL,'Wooden Logs 11',356,1289,0,'509');
+INSERT INTO items VALUES(NULL,'Wooden Logs 8',356,1286,0,'506');
+INSERT INTO items VALUES(NULL,'Wooden Logs 9',356,1287,0,'507');
+INSERT INTO items VALUES(NULL,'Wooden Logs 6',356,1284,0,'504');
+INSERT INTO items VALUES(NULL,'Wooden Logs 7',356,1285,0,'505');
+INSERT INTO items VALUES(NULL,'Flagstones 3',366,1282,0,'502');
+INSERT INTO items VALUES(NULL,'Flagstones 4',366,1283,0,'503');
+INSERT INTO items VALUES(NULL,'Flagstones 1',366,1280,0,'500');
+INSERT INTO items VALUES(NULL,'Flagstones 2',366,1281,0,'501');
+INSERT INTO items VALUES(NULL,'Altar 5',151,4626,0,'1212');
+INSERT INTO items VALUES(NULL,'Altar 6',151,4627,0,'1213');
+INSERT INTO items VALUES(NULL,'Roof 23',150,1586,0,'632');
+INSERT INTO items VALUES(NULL,'Altar 4',151,4625,0,'1211');
+INSERT INTO items VALUES(NULL,'Altar 9',151,4630,0,'1216');
+INSERT INTO items VALUES(NULL,'Roof 23',32,1589,0,'635');
+INSERT INTO items VALUES(NULL,'Altar 7',151,4628,0,'1214');
+INSERT INTO items VALUES(NULL,'Altar 8',151,4629,0,'1215');
+INSERT INTO items VALUES(NULL,'Roof 2',153,1592,0,'638');
+INSERT INTO items VALUES(NULL,'Roof 3',153,1593,0,'639');
+INSERT INTO items VALUES(NULL,'Stone Throne 1',78,4632,0,'1218');
+INSERT INTO items VALUES(NULL,'ringmail gloves',310,5099,0,'verite_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'Green Marble Floor 1',271,1295,0,'50f');
+INSERT INTO items VALUES(NULL,'Marble Floor 1',271,1293,0,'50d');
+INSERT INTO items VALUES(NULL,'Marble Floor 2',271,1294,0,'50e');
+INSERT INTO items VALUES(NULL,'Gray Wooden Logs 1',356,1291,0,'50b');
+INSERT INTO items VALUES(NULL,'Gray Wooden Logs 2',356,1292,0,'50c');
+INSERT INTO items VALUES(NULL,'Wooden Logs 12',356,1290,0,'50a');
+INSERT INTO items VALUES(NULL,'Banner 28 (N/S)',128,5575,0,'15c7');
+INSERT INTO items VALUES(NULL,'Banner 28 (W/E)',128,5574,0,'15c6');
+INSERT INTO items VALUES(NULL,'Banner 27 (N/S)',128,5573,0,'15c5');
+INSERT INTO items VALUES(NULL,'Banner 27 (W/E)',128,5572,0,'15c4');
+INSERT INTO items VALUES(NULL,'Banner 26 (N/S)',128,5571,0,'15c3');
+INSERT INTO items VALUES(NULL,'Banner 26 (W/E)',128,5570,0,'15c2');
+INSERT INTO items VALUES(NULL,'Banner 25 (N/S)',128,5569,0,'15c1');
+INSERT INTO items VALUES(NULL,'Banner 25 (W/E)',128,5568,0,'15c0');
+INSERT INTO items VALUES(NULL,'Banner 29 (N/S)',128,5577,0,'15c9');
+INSERT INTO items VALUES(NULL,'Banner 29 (W/E)',128,5576,0,'15c8');
+INSERT INTO items VALUES(NULL,'Vines 1 (1/3)',4,3412,0,'d54');
+INSERT INTO items VALUES(NULL,'Mushrooms 9',273,3348,0,'d14');
+INSERT INTO items VALUES(NULL,'Mushrooms 10',273,3349,0,'d15');
+INSERT INTO items VALUES(NULL,'Mushrooms 11',273,3350,0,'d16');
+INSERT INTO items VALUES(NULL,'Mushrooms 12',273,3351,0,'d17');
+INSERT INTO items VALUES(NULL,'Mushrooms 5',273,3344,0,'d10');
+INSERT INTO items VALUES(NULL,'Mushrooms 6',273,3345,0,'d11');
+INSERT INTO items VALUES(NULL,'Mushrooms 7',273,3346,0,'d12');
+INSERT INTO items VALUES(NULL,'Mushrooms 8',273,3347,0,'d13');
+INSERT INTO items VALUES(NULL,'Mushrooms 13',273,3352,0,'d18');
+INSERT INTO items VALUES(NULL,'Mushrooms 14',273,3353,0,'d19');
+INSERT INTO items VALUES(NULL,'Balista 144',76,16251,0,'3f7b');
+INSERT INTO items VALUES(NULL,'Balista 145',76,16252,0,'3f7c');
+INSERT INTO items VALUES(NULL,'Balista 143',76,16250,0,'3f7a');
+INSERT INTO items VALUES(NULL,'Balista 148',76,16255,0,'3f7f');
+INSERT INTO items VALUES(NULL,'Balista 146',76,16253,0,'3f7d');
+INSERT INTO items VALUES(NULL,'Balista 147',76,16254,0,'3f7e');
+INSERT INTO items VALUES(NULL,'Banner 32 (N/S)',128,5583,0,'15cf');
+INSERT INTO items VALUES(NULL,'Banner 32 (W/E)',128,5582,0,'15ce');
+INSERT INTO items VALUES(NULL,'Banner 31 (N/S)',128,5581,0,'15cd');
+INSERT INTO items VALUES(NULL,'Banner 31 (W/E)',128,5580,0,'15cc');
+INSERT INTO items VALUES(NULL,'Banner 30 (N/S)',128,5579,0,'15cb');
+INSERT INTO items VALUES(NULL,'Banner 30 (W/E)',128,5578,0,'15ca');
+INSERT INTO items VALUES(NULL,'Balista 141',76,16248,0,'3f78');
+INSERT INTO items VALUES(NULL,'Balista 142',76,16249,0,'3f79');
+INSERT INTO items VALUES(NULL,'Balista 135',76,16242,0,'3f72');
+INSERT INTO items VALUES(NULL,'Balista 136',76,16243,0,'3f73');
+INSERT INTO items VALUES(NULL,'Balista 133',76,16240,0,'3f70');
+INSERT INTO items VALUES(NULL,'Balista 134',76,16241,0,'3f71');
+INSERT INTO items VALUES(NULL,'Balista 139',76,16246,0,'3f76');
+INSERT INTO items VALUES(NULL,'Balista 140',76,16247,0,'3f77');
+INSERT INTO items VALUES(NULL,'Balista 137',76,16244,0,'3f74');
+INSERT INTO items VALUES(NULL,'Balista 138',76,16245,0,'3f75');
+INSERT INTO items VALUES(NULL,'Grapevines 3',285,3357,0,'d1d');
+INSERT INTO items VALUES(NULL,'Grapevines 4',285,3358,0,'d1e');
+INSERT INTO items VALUES(NULL,'Grapevines 5',285,3359,0,'d1f');
+INSERT INTO items VALUES(NULL,'plate armor',159,7172,0,'agapite_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Grapevines 1',285,3355,0,'d1b');
+INSERT INTO items VALUES(NULL,'Grapevines 2',285,3356,0,'d1c');
+INSERT INTO items VALUES(NULL,'Bone Pile 6',12,6926,0,'1b0e');
+INSERT INTO items VALUES(NULL,'Bone Pile 5',12,6925,0,'1b0d');
+INSERT INTO items VALUES(NULL,'Bone Pile 7',12,6927,0,'1b0f');
+INSERT INTO items VALUES(NULL,'Bone Pile 2',12,6922,0,'1b0a');
+INSERT INTO items VALUES(NULL,'Bone Pile 4',12,6924,0,'1b0c');
+INSERT INTO items VALUES(NULL,'Bone Pile 3',12,6923,0,'1b0b');
+INSERT INTO items VALUES(NULL,'Ship 13',137,16000,0,'3e80');
+INSERT INTO items VALUES(NULL,'Ship 14',137,16001,0,'3e81');
+INSERT INTO items VALUES(NULL,'Deck 3',193,16003,0,'3e83');
+INSERT INTO items VALUES(NULL,'Gang Plank 1',87,16004,0,'3e84');
+INSERT INTO items VALUES(NULL,'Ship 15',137,16005,0,'3e85');
+INSERT INTO items VALUES(NULL,'Gang Plank 2',87,16006,0,'3e86');
+INSERT INTO items VALUES(NULL,'Ship 16',137,16007,0,'3e87');
+INSERT INTO items VALUES(NULL,'Deck 4',193,16008,0,'3e88');
+INSERT INTO items VALUES(NULL,'Gang Plank 3',87,16009,0,'3e89');
+INSERT INTO items VALUES(NULL,'Rock 16',29,13452,0,'348c');
+INSERT INTO items VALUES(NULL,'Rock 6',29,13451,0,'348b');
+INSERT INTO items VALUES(NULL,'Rock 18',29,13454,0,'348e');
+INSERT INTO items VALUES(NULL,'Rock 17',29,13453,0,'348d');
+INSERT INTO items VALUES(NULL,'Rock 19',29,13455,0,'348f');
+INSERT INTO items VALUES(NULL,'Part 1',244,5327,0,'14cf');
+INSERT INTO items VALUES(NULL,'Part 3',367,5325,0,'14cd');
+INSERT INTO items VALUES(NULL,'Part 4',367,5326,0,'14ce');
+INSERT INTO items VALUES(NULL,'Part 1',367,5323,0,'14cb');
+INSERT INTO items VALUES(NULL,'Part 2',367,5324,0,'14cc');
+INSERT INTO items VALUES(NULL,'Part 4',368,5322,0,'14ca');
+INSERT INTO items VALUES(NULL,'Lava 40',44,12977,0,'32b1');
+INSERT INTO items VALUES(NULL,'Lava 39',44,12976,0,'32b0');
+INSERT INTO items VALUES(NULL,'Rock 4',29,13449,0,'3489');
+INSERT INTO items VALUES(NULL,'Ship 17',137,16010,0,'3e8a');
+INSERT INTO items VALUES(NULL,'Deck 5',193,16011,0,'3e8b');
+INSERT INTO items VALUES(NULL,'Ship 18',137,16012,0,'3e8c');
+INSERT INTO items VALUES(NULL,'Ship 19',137,16013,0,'3e8d');
+INSERT INTO items VALUES(NULL,'Ship 20',137,16014,0,'3e8e');
+INSERT INTO items VALUES(NULL,'Deck 6',193,16015,0,'3e8f');
+INSERT INTO items VALUES(NULL,'Water 20',33,13441,0,'3481');
+INSERT INTO items VALUES(NULL,'Water 19',33,13440,0,'3480');
+INSERT INTO items VALUES(NULL,'Water 22',33,13443,0,'3483');
+INSERT INTO items VALUES(NULL,'Water 21',33,13442,0,'3482');
+INSERT INTO items VALUES(NULL,'Water 24',33,13445,0,'3485');
+INSERT INTO items VALUES(NULL,'Water 23',33,13444,0,'3484');
+INSERT INTO items VALUES(NULL,'Rock 2',29,13447,0,'3487');
+INSERT INTO items VALUES(NULL,'Rock 1',29,13446,0,'3486');
+INSERT INTO items VALUES(NULL,'Bone Pile 1',12,6921,0,'1b09');
+INSERT INTO items VALUES(NULL,'Floor Cracks 8',282,6920,0,'1b08');
+INSERT INTO items VALUES(NULL,'Floor Cracks 5',282,6917,0,'1b05');
+INSERT INTO items VALUES(NULL,'Floor Cracks 4',282,6916,0,'1b04');
+INSERT INTO items VALUES(NULL,'Floor Cracks 7',282,6919,0,'1b07');
+INSERT INTO items VALUES(NULL,'Floor Cracks 6',282,6918,0,'1b06');
+INSERT INTO items VALUES(NULL,'Floor Cracks 1',282,6913,0,'1b01');
+INSERT INTO items VALUES(NULL,'Floor Cracks 3',282,6915,0,'1b03');
+INSERT INTO items VALUES(NULL,'Floor Cracks 2',282,6914,0,'1b02');
+INSERT INTO items VALUES(NULL,'Part 4',369,5318,0,'14c6');
+INSERT INTO items VALUES(NULL,'Part 1',368,5319,0,'14c7');
+INSERT INTO items VALUES(NULL,'Part 2',369,5316,0,'14c4');
+INSERT INTO items VALUES(NULL,'Part 3',369,5317,0,'14c5');
+INSERT INTO items VALUES(NULL,'Part 4',291,5314,0,'14c2');
+INSERT INTO items VALUES(NULL,'Part 1',369,5315,0,'14c3');
+INSERT INTO items VALUES(NULL,'Part 2',291,5312,0,'14c0');
+INSERT INTO items VALUES(NULL,'Part 3',291,5313,0,'14c1');
+INSERT INTO items VALUES(NULL,'Part 2',368,5320,0,'14c8');
+INSERT INTO items VALUES(NULL,'Part 3',368,5321,0,'14c9');
+INSERT INTO items VALUES(NULL,'Wall 5',276,955,0,'3bb');
+INSERT INTO items VALUES(NULL,'Wall 6',276,956,0,'3bc');
+INSERT INTO items VALUES(NULL,'Giant Beetle',115,9743,0,'260f');
+INSERT INTO items VALUES(NULL,'Wall 4',276,954,0,'3ba');
+INSERT INTO items VALUES(NULL,'Wall 9',276,959,0,'3bf');
+INSERT INTO items VALUES(NULL,'Chariot',115,9738,0,'260a');
+INSERT INTO items VALUES(NULL,'Wall 7',276,957,0,'3bd');
+INSERT INTO items VALUES(NULL,'Wall 8',276,958,0,'3be');
+INSERT INTO items VALUES(NULL,'Solen Worker',115,9732,0,'2604');
+INSERT INTO items VALUES(NULL,'Fence 1',234,947,0,'3b3');
+INSERT INTO items VALUES(NULL,'Betrayer',115,9734,0,'2606');
+INSERT INTO items VALUES(NULL,'Bogling',115,9735,0,'2607');
+INSERT INTO items VALUES(NULL,'Fence 4',234,950,0,'3b6');
+INSERT INTO items VALUES(NULL,'Wall 1',276,951,0,'3b7');
+INSERT INTO items VALUES(NULL,'Fence 2',234,948,0,'3b4');
+INSERT INTO items VALUES(NULL,'Fence 3',234,949,0,'3b5');
+INSERT INTO items VALUES(NULL,'Wall 2',276,952,0,'3b8');
+INSERT INTO items VALUES(NULL,'Wall 3',276,953,0,'3b9');
+INSERT INTO items VALUES(NULL,'Bog Thing',115,9736,0,'2608');
+INSERT INTO items VALUES(NULL,'Chaos Demon',115,9737,0,'2609');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 13',301,1884,0,'75c');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 12',301,1883,0,'75b');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 11',301,1882,0,'75a');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 16',301,1887,0,'75f');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 15',301,1886,0,'75e');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 14',301,1885,0,'75d');
+INSERT INTO items VALUES(NULL,'Stone Trigger 1',75,7103,0,'1bbf');
+INSERT INTO items VALUES(NULL,'Nails (W/E)',107,4142,0,'102e');
+INSERT INTO items VALUES(NULL,'Moulding Planes (W/E)',107,4141,0,'102d');
+INSERT INTO items VALUES(NULL,'Refuse 30',334,7101,0,'1bbd');
+INSERT INTO items VALUES(NULL,'Hammer 1',107,4138,0,'102a');
+INSERT INTO items VALUES(NULL,'Moulding Planes (N/S)',107,4140,0,'102c');
+INSERT INTO items VALUES(NULL,'Hammer 2',107,4139,0,'102b');
+INSERT INTO items VALUES(NULL,'Refuse 29',334,7100,0,'1bbc');
+INSERT INTO items VALUES(NULL,'Refuse 28',334,7099,0,'1bbb');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 4',301,1875,0,'753');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 3',301,1874,0,'752');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 2',301,1873,0,'751');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 1',301,1872,0,'750');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 8',301,1879,0,'757');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 7',301,1878,0,'756');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 6',301,1877,0,'755');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 5',301,1876,0,'754');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 10',301,1881,0,'759');
+INSERT INTO items VALUES(NULL,'Stone 1 Stairs 9',301,1880,0,'758');
+INSERT INTO items VALUES(NULL,'Arrow Shafts 2',34,4133,0,'1025');
+INSERT INTO items VALUES(NULL,'Arrow Shafts 1',34,4132,0,'1024');
+INSERT INTO items VALUES(NULL,'Chisels (W/E)',107,4135,0,'1027');
+INSERT INTO items VALUES(NULL,'Chisels (N/S)',107,4134,0,'1026');
+INSERT INTO items VALUES(NULL,'Decorative Feathers 4',34,4129,0,'1021');
+INSERT INTO items VALUES(NULL,'Decorative Feathers 3',34,4128,0,'1020');
+INSERT INTO items VALUES(NULL,'Arrow Fletching 2',34,4131,0,'1023');
+INSERT INTO items VALUES(NULL,'Arrow Fletching 1',34,4130,0,'1022');
+INSERT INTO items VALUES(NULL,'Dovetail Saw (W/E)',107,4137,0,'1029');
+INSERT INTO items VALUES(NULL,'Dovetail Saw (N/S)',107,4136,0,'1028');
+INSERT INTO items VALUES(NULL,'Liche',115,8440,0,'20f8');
+INSERT INTO items VALUES(NULL,'Liche Lord',115,8441,0,'20f9');
+INSERT INTO items VALUES(NULL,'Grasses 13',45,3258,0,'cba');
+INSERT INTO items VALUES(NULL,'Poppies 2',134,3263,0,'cbf');
+INSERT INTO items VALUES(NULL,'Grasses 16',45,3261,0,'cbd');
+INSERT INTO items VALUES(NULL,'Poppies 1',134,3262,0,'cbe');
+INSERT INTO items VALUES(NULL,'Bull 2',115,8432,0,'20f0');
+INSERT INTO items VALUES(NULL,'Dolphin',115,8433,0,'20f1');
+INSERT INTO items VALUES(NULL,'Eagle (big)',115,8434,0,'20f2');
+INSERT INTO items VALUES(NULL,'Fire Elemental',115,8435,0,'20f3');
+INSERT INTO items VALUES(NULL,'Gazer',115,8436,0,'20f4');
+INSERT INTO items VALUES(NULL,'Gorilla',115,8437,0,'20f5');
+INSERT INTO items VALUES(NULL,'Llama',115,8438,0,'20f6');
+INSERT INTO items VALUES(NULL,'Cougar',115,8439,0,'20f7');
+INSERT INTO items VALUES(NULL,'Scroll 3 (W/E)',186,3639,0,'e37');
+INSERT INTO items VALUES(NULL,'Scroll 2 (W/E)',186,3638,0,'e36');
+INSERT INTO items VALUES(NULL,'Scroll 1 (W/E)',186,3637,0,'e35');
+INSERT INTO items VALUES(NULL,'Empty Scroll (W/E)',186,3636,0,'e34');
+INSERT INTO items VALUES(NULL,'Brazier 1',73,3633,0,'e31');
+INSERT INTO items VALUES(NULL,'Crystal Ball 4',293,3632,0,'e30');
+INSERT INTO items VALUES(NULL,'Scroll 5 (W/E)',186,3641,0,'e39');
+INSERT INTO items VALUES(NULL,'Scroll 4 (W/E)',186,3640,0,'e38');
+INSERT INTO items VALUES(NULL,'Ankh 4',70,5,0,'5');
+INSERT INTO items VALUES(NULL,'Grasses 7',45,3250,0,'cb2');
+INSERT INTO items VALUES(NULL,'Grasses 8',45,3251,0,'cb3');
+INSERT INTO items VALUES(NULL,'Grasses 5',45,3248,0,'cb0');
+INSERT INTO items VALUES(NULL,'Grasses 6',45,3249,0,'cb1');
+INSERT INTO items VALUES(NULL,'Grasses 11',45,3254,0,'cb6');
+INSERT INTO items VALUES(NULL,'Cattails 1',45,3255,0,'cb7');
+INSERT INTO items VALUES(NULL,'Grasses 9',45,3252,0,'cb4');
+INSERT INTO items VALUES(NULL,'Grasses 10',45,3253,0,'cb5');
+INSERT INTO items VALUES(NULL,'Reaper',115,8442,0,'20fa');
+INSERT INTO items VALUES(NULL,'Sea Serpent',115,8443,0,'20fb');
+INSERT INTO items VALUES(NULL,'Snake 1',115,8444,0,'20fc');
+INSERT INTO items VALUES(NULL,'Spider',115,8445,0,'20fd');
+INSERT INTO items VALUES(NULL,'Snake 2',115,8446,0,'20fe');
+INSERT INTO items VALUES(NULL,'Walrus',115,8447,0,'20ff');
+INSERT INTO items VALUES(NULL,'Small Crate 2 (N/S)',65,3647,0,'e3f');
+INSERT INTO items VALUES(NULL,'Small Crate 2 (W/E)',65,3646,0,'e3e');
+INSERT INTO items VALUES(NULL,'Big Crate (N/S)',65,3645,0,'e3d');
+INSERT INTO items VALUES(NULL,'Big Crate (W/E)',65,3644,0,'e3c');
+INSERT INTO items VALUES(NULL,'Spellbook (W/E)',186,3643,0,'e3b');
+INSERT INTO items VALUES(NULL,'close helmet',278,5128,0,'iron_helmets_close');
+INSERT INTO items VALUES(NULL,'Chessmen 4',249,4008,0,'fa8');
+INSERT INTO items VALUES(NULL,'Dyes',57,4009,0,'fa9');
+INSERT INTO items VALUES(NULL,'Cards 6',249,4002,0,'fa2');
+INSERT INTO items VALUES(NULL,'Cards 7',249,4003,0,'fa3');
+INSERT INTO items VALUES(NULL,'Spool of Thread (N/S)',57,4000,0,'fa0');
+INSERT INTO items VALUES(NULL,'Spool of Thread (W/E)',57,4001,0,'fa1');
+INSERT INTO items VALUES(NULL,'Game Board',249,4006,0,'fa6');
+INSERT INTO items VALUES(NULL,'Dice and Cup',249,4007,0,'fa7');
+INSERT INTO items VALUES(NULL,'Checkers 3',249,4004,0,'fa4');
+INSERT INTO items VALUES(NULL,'Checkers 4',249,4005,0,'fa5');
+INSERT INTO items VALUES(NULL,'plate helmet',159,5138,0,'agapite_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (1/9)',108,6140,0,'17fc');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (4/9)',108,6143,0,'17ff');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (2/9)',108,6141,0,'17fd');
+INSERT INTO items VALUES(NULL,'Teleporter 5 (3/9)',108,6142,0,'17fe');
+INSERT INTO items VALUES(NULL,'Refuse 24',334,7095,0,'1bb7');
+INSERT INTO items VALUES(NULL,'Refuse 22',334,7093,0,'1bb5');
+INSERT INTO items VALUES(NULL,'Refuse 21',334,7092,0,'1bb4');
+INSERT INTO items VALUES(NULL,'Dying Tub',57,4011,0,'fab');
+INSERT INTO items VALUES(NULL,'Fire Pit',352,4012,0,'fac');
+INSERT INTO items VALUES(NULL,'Anvil (N/S)',30,4015,0,'faf');
+INSERT INTO items VALUES(NULL,'Backgammon Board 2',249,4013,0,'fad');
+INSERT INTO items VALUES(NULL,'Refuse 20',334,7090,0,'1bb2');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (9/9)',108,6130,0,'17f2');
+INSERT INTO items VALUES(NULL,'Teleporter 4 (7/9)',108,6128,0,'17f0');
+INSERT INTO items VALUES(NULL,'Refuse 18',334,7088,0,'1bb0');
+INSERT INTO items VALUES(NULL,'Heating Stand (W/E) (On)',173,6218,0,'184a');
+INSERT INTO items VALUES(NULL,'Heating Stand (N/S) (On)',173,6222,0,'184e');
+INSERT INTO items VALUES(NULL,'Heating Stand (N/S) (Off)',173,6221,0,'184d');
+INSERT INTO items VALUES(NULL,'Heating Stand (W/E) (Off)',173,6217,0,'1849');
+INSERT INTO items VALUES(NULL,'Flask 31',173,6216,0,'1848');
+INSERT INTO items VALUES(NULL,'Flask 26',173,6211,0,'1843');
+INSERT INTO items VALUES(NULL,'Flask 25',173,6210,0,'1842');
+INSERT INTO items VALUES(NULL,'Flask 24',173,6209,0,'1841');
+INSERT INTO items VALUES(NULL,'Flask 23',173,6208,0,'1840');
+INSERT INTO items VALUES(NULL,'Flask 30',173,6215,0,'1847');
+INSERT INTO items VALUES(NULL,'platemail gorget',81,5139,0,'shadow_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Flask 28',173,6213,0,'1845');
+INSERT INTO items VALUES(NULL,'Flask 27',173,6212,0,'1844');
+INSERT INTO items VALUES(NULL,'Swamp 3',267,12880,0,'3250');
+INSERT INTO items VALUES(NULL,'Entrance (N/S) (2/2)',6,8553,0,'2169');
+INSERT INTO items VALUES(NULL,'Entrance (N/S) (1/2)',6,8552,0,'2168');
+INSERT INTO items VALUES(NULL,'Swamp 4',267,12881,0,'3251');
+INSERT INTO items VALUES(NULL,'Entrance (W/E) (2/2)',6,8551,0,'2167');
+INSERT INTO items VALUES(NULL,'Entrance (W/E) (1/2)',6,8550,0,'2166');
+INSERT INTO items VALUES(NULL,'Swamp 4',237,12883,0,'3253');
+INSERT INTO items VALUES(NULL,'Lava 3',300,12952,0,'3298');
+INSERT INTO items VALUES(NULL,'Lava 4',300,12953,0,'3299');
+INSERT INTO items VALUES(NULL,'Balista 78',76,6408,0,'1908');
+INSERT INTO items VALUES(NULL,'Balista 79',76,6409,0,'1909');
+INSERT INTO items VALUES(NULL,'Lava 15',44,12948,0,'3294');
+INSERT INTO items VALUES(NULL,'Lava 16',44,12949,0,'3295');
+INSERT INTO items VALUES(NULL,'Lava 1',300,12950,0,'3296');
+INSERT INTO items VALUES(NULL,'Lava 2',300,12951,0,'3297');
+INSERT INTO items VALUES(NULL,'Lava 11',44,12944,0,'3290');
+INSERT INTO items VALUES(NULL,'Lava 12',44,12945,0,'3291');
+INSERT INTO items VALUES(NULL,'Lava 13',44,12946,0,'3292');
+INSERT INTO items VALUES(NULL,'Lava 14',44,12947,0,'3293');
+INSERT INTO items VALUES(NULL,'Bar Door (W/E)',279,6415,0,'190f');
+INSERT INTO items VALUES(NULL,'Lava 21',44,12958,0,'329e');
+INSERT INTO items VALUES(NULL,'Lava 22',44,12959,0,'329f');
+INSERT INTO items VALUES(NULL,'Bar Door (N/S)',279,6414,0,'190e');
+INSERT INTO items VALUES(NULL,'Balista 81',76,6411,0,'190b');
+INSERT INTO items VALUES(NULL,'Lava 17',44,12954,0,'329a');
+INSERT INTO items VALUES(NULL,'Lava 18',44,12955,0,'329b');
+INSERT INTO items VALUES(NULL,'Lava 19',44,12956,0,'329c');
+INSERT INTO items VALUES(NULL,'Roof 7',32,1563,0,'61b');
+INSERT INTO items VALUES(NULL,'Roof 8',32,1564,0,'61c');
+INSERT INTO items VALUES(NULL,'Block 17',113,4731,0,'127b');
+INSERT INTO items VALUES(NULL,'Roof 6',32,1562,0,'61a');
+INSERT INTO items VALUES(NULL,'Roof 11',32,1567,0,'61f');
+INSERT INTO items VALUES(NULL,'Pillory 2',113,4734,0,'127e');
+INSERT INTO items VALUES(NULL,'Roof 9',32,1565,0,'61d');
+INSERT INTO items VALUES(NULL,'Roof 10',32,1566,0,'61e');
+INSERT INTO items VALUES(NULL,'Magic Face 2 (N/S)',28,7906,0,'1ee2');
+INSERT INTO items VALUES(NULL,'nose helmet',278,5134,0,'iron_helmets_nose');
+INSERT INTO items VALUES(NULL,'Orc (3d)',115,9646,0,'25ae');
+INSERT INTO items VALUES(NULL,'Orc Captain',115,9647,0,'25af');
+INSERT INTO items VALUES(NULL,'Ophidian Knight',115,9642,0,'25aa');
+INSERT INTO items VALUES(NULL,'Ophidian Mage (3d)',115,9643,0,'25ab');
+INSERT INTO items VALUES(NULL,'Ophidian Queen (3d)',115,9644,0,'25ac');
+INSERT INTO items VALUES(NULL,'Block 14',113,4728,0,'1278');
+INSERT INTO items VALUES(NULL,'Block 15',113,4729,0,'1279');
+INSERT INTO items VALUES(NULL,'Roof 4',32,1560,0,'618');
+INSERT INTO items VALUES(NULL,'Roof 5',32,1561,0,'619');
+INSERT INTO items VALUES(NULL,'platemail',81,5141,0,'shadow_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Roof 20',152,1554,0,'612');
+INSERT INTO items VALUES(NULL,'Roof 21',152,1555,0,'613');
+INSERT INTO items VALUES(NULL,'Roof 18',152,1552,0,'610');
+INSERT INTO items VALUES(NULL,'Roof 19',152,1553,0,'611');
+INSERT INTO items VALUES(NULL,'Roof 2',32,1558,0,'616');
+INSERT INTO items VALUES(NULL,'Roof 3',32,1559,0,'617');
+INSERT INTO items VALUES(NULL,'Roof 22',152,1556,0,'614');
+INSERT INTO items VALUES(NULL,'Block 13',113,4727,0,'1277');
+INSERT INTO items VALUES(NULL,'buckler',354,7027,0,'shadow_shields_buckler');
+INSERT INTO items VALUES(NULL,'Carpet 3',306,2771,0,'ad3');
+INSERT INTO items VALUES(NULL,'Ogre Lord',115,9640,0,'25a8');
+INSERT INTO items VALUES(NULL,'Ophidian Archmage',115,9641,0,'25a9');
+INSERT INTO items VALUES(NULL,'Telescope (57/66)',182,5265,0,'1491');
+INSERT INTO items VALUES(NULL,'Liche (3d)',115,9636,0,'25a4');
+INSERT INTO items VALUES(NULL,'Liche Lord (3d)',115,9637,0,'25a5');
+INSERT INTO items VALUES(NULL,'Mongbat (3d)',115,9638,0,'25a6');
+INSERT INTO items VALUES(NULL,'Mummy',115,9639,0,'25a7');
+INSERT INTO items VALUES(NULL,'Kirin',115,9632,0,'25a0');
+INSERT INTO items VALUES(NULL,'Komodo Dragon',115,9633,0,'25a1');
+INSERT INTO items VALUES(NULL,'Kraken',115,9634,0,'25a2');
+INSERT INTO items VALUES(NULL,'Snow Leopard',115,9635,0,'25a3');
+INSERT INTO items VALUES(NULL,'Magic Face 1 (W/E)',28,7916,0,'1eec');
+INSERT INTO items VALUES(NULL,'ringmail sleeves',350,5103,0,'copper_armor_ring_sleeves');
+INSERT INTO items VALUES(NULL,'Banner 13 (W/E) 2',128,5545,0,'15a9');
+INSERT INTO items VALUES(NULL,'Banner 13 (W/E) 1',128,5544,0,'15a8');
+INSERT INTO items VALUES(NULL,'Banner 11 (W/E) 2',128,5541,0,'15a5');
+INSERT INTO items VALUES(NULL,'Banner 11 (W/E) 1',128,5540,0,'15a4');
+INSERT INTO items VALUES(NULL,'Banner 12 (W/E) 2',128,5543,0,'15a7');
+INSERT INTO items VALUES(NULL,'Banner 12 (W/E) 1',128,5542,0,'15a6');
+INSERT INTO items VALUES(NULL,'Banner 9 (W/E) 2',128,5537,0,'15a1');
+INSERT INTO items VALUES(NULL,'Banner 9 (W/E) 1',128,5536,0,'15a0');
+INSERT INTO items VALUES(NULL,'Banner 10 (W/E) 2',128,5539,0,'15a3');
+INSERT INTO items VALUES(NULL,'Banner 10 (W/E) 1',128,5538,0,'15a2');
+INSERT INTO items VALUES(NULL,'Yucca 2',4,3384,0,'d38');
+INSERT INTO items VALUES(NULL,'Turnip 4',19,3385,0,'d39');
+INSERT INTO items VALUES(NULL,'platemail gorget',117,5139,0,'golden_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'Yucca 1',4,3383,0,'d37');
+INSERT INTO items VALUES(NULL,'Morning Glories',134,3380,0,'d34');
+INSERT INTO items VALUES(NULL,'Grasses 19',45,3378,0,'d32');
+INSERT INTO items VALUES(NULL,'Grasses 20',45,3379,0,'d33');
+INSERT INTO items VALUES(NULL,'Century Plant 1',45,3376,0,'d30');
+INSERT INTO items VALUES(NULL,'Roof 18',32,1574,0,'626');
+INSERT INTO items VALUES(NULL,'Canvas 3',262,3943,0,'f67');
+INSERT INTO items VALUES(NULL,'Banner 16 (W/E)',128,5550,0,'15ae');
+INSERT INTO items VALUES(NULL,'Banner 15 (W/E) 2',128,5549,0,'15ad');
+INSERT INTO items VALUES(NULL,'Banner 16 (N/S)',128,5551,0,'15af');
+INSERT INTO items VALUES(NULL,'Banner 14 (W/E) 1',128,5546,0,'15aa');
+INSERT INTO items VALUES(NULL,'Banner 15 (W/E) 1',128,5548,0,'15ac');
+INSERT INTO items VALUES(NULL,'Banner 14 (W/E) 2',128,5547,0,'15ab');
+INSERT INTO items VALUES(NULL,'Brambles 1',45,3391,0,'d3f');
+INSERT INTO items VALUES(NULL,'Fallen Branch 3',4,3389,0,'d3d');
+INSERT INTO items VALUES(NULL,'Fallen Branch 1',4,3387,0,'d3b');
+INSERT INTO items VALUES(NULL,'Fallen Branch 2',4,3388,0,'d3c');
+INSERT INTO items VALUES(NULL,'Turnip 5',19,3386,0,'d3a');
+INSERT INTO items VALUES(NULL,'Forge (E/W) (2/3)',30,6562,0,'19a2');
+INSERT INTO items VALUES(NULL,'Wall Cracks 1',282,7020,0,'1b6c');
+INSERT INTO items VALUES(NULL,'Roof 11',370,1530,0,'5fa');
+INSERT INTO items VALUES(NULL,'Roof 12',370,1531,0,'5fb');
+INSERT INTO items VALUES(NULL,'Roof 13',370,1532,0,'5fc');
+INSERT INTO items VALUES(NULL,'Roof 14',370,1533,0,'5fd');
+INSERT INTO items VALUES(NULL,'Roof 15',370,1534,0,'5fe');
+INSERT INTO items VALUES(NULL,'Wall Cracks 3',282,7022,0,'1b6e');
+INSERT INTO items VALUES(NULL,'Wall Cracks 2',282,7021,0,'1b6d');
+INSERT INTO items VALUES(NULL,'Forge (E/W) (3/3)',30,6566,0,'19a6');
+INSERT INTO items VALUES(NULL,'Waterfall 2',23,13549,0,'34ed');
+INSERT INTO items VALUES(NULL,'Waterfall 3',23,13550,0,'34ee');
+INSERT INTO items VALUES(NULL,'Green Potion',180,3850,0,'potion_deadlypoison');
+INSERT INTO items VALUES(NULL,'Slab of Bacon (W/E)',19,2423,0,'977');
+INSERT INTO items VALUES(NULL,'Cauldron (W/E)',14,2421,0,'975');
+INSERT INTO items VALUES(NULL,'Roof 9',370,1528,0,'5f8');
+INSERT INTO items VALUES(NULL,'Roof 10',370,1529,0,'5f9');
+INSERT INTO items VALUES(NULL,'Treasure (39/41)',215,7017,0,'1b69');
+INSERT INTO items VALUES(NULL,'platemail legs',187,5137,0,'merkite_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'Roof 1',370,1520,0,'5f0');
+INSERT INTO items VALUES(NULL,'Roof 2',370,1521,0,'5f1');
+INSERT INTO items VALUES(NULL,'Roof 3',370,1522,0,'5f2');
+INSERT INTO items VALUES(NULL,'Roof 4',370,1523,0,'5f3');
+INSERT INTO items VALUES(NULL,'Roof 5',370,1524,0,'5f4');
+INSERT INTO items VALUES(NULL,'Roof 6',370,1525,0,'5f5');
+INSERT INTO items VALUES(NULL,'Roof 7',370,1526,0,'5f6');
+INSERT INTO items VALUES(NULL,'Roof 8',370,1527,0,'5f7');
+INSERT INTO items VALUES(NULL,'Stew',19,2416,0,'970');
+INSERT INTO items VALUES(NULL,'Stone Harpy',115,9620,0,'2594');
+INSERT INTO items VALUES(NULL,'Headless (3d)',115,9621,0,'2595');
+INSERT INTO items VALUES(NULL,'Hell Hound',115,9622,0,'2596');
+INSERT INTO items VALUES(NULL,'Hellcat',115,9623,0,'2597');
+INSERT INTO items VALUES(NULL,'Efreet',115,9616,0,'2590');
+INSERT INTO items VALUES(NULL,'Ghoul (3d)',115,9617,0,'2591');
+INSERT INTO items VALUES(NULL,'Silverback Gorilla',115,9618,0,'2592');
+INSERT INTO items VALUES(NULL,'Great Worm',115,9619,0,'2593');
+INSERT INTO items VALUES(NULL,'Dappled Brown Horse',115,9624,0,'2598');
+INSERT INTO items VALUES(NULL,'Dappled Gray Horse',115,9625,0,'2599');
+INSERT INTO items VALUES(NULL,'Wave 26',62,8124,0,'1fbc');
+INSERT INTO items VALUES(NULL,'Window 2',127,990,0,'3de');
+INSERT INTO items VALUES(NULL,'Window 3',127,991,0,'3df');
+INSERT INTO items VALUES(NULL,'Wave 29',62,8127,0,'1fbf');
+INSERT INTO items VALUES(NULL,'Wave 28',62,8126,0,'1fbe');
+INSERT INTO items VALUES(NULL,'Wall 22',127,988,0,'3dc');
+INSERT INTO items VALUES(NULL,'Training Dummy (N/S)',341,4208,0,'1070');
+INSERT INTO items VALUES(NULL,'Dragon Prow 2',9,15940,0,'3e44');
+INSERT INTO items VALUES(NULL,'Dragon Prow 3',9,15941,0,'3e45');
+INSERT INTO items VALUES(NULL,'Dragon Prow 4',9,15942,0,'3e46');
+INSERT INTO items VALUES(NULL,'Small Wall 4',238,764,0,'2fc');
+INSERT INTO items VALUES(NULL,'Small Wall 3',238,763,0,'2fb');
+INSERT INTO items VALUES(NULL,'Small Wall 2',238,762,0,'2fa');
+INSERT INTO items VALUES(NULL,'Dragon Prow 5',9,15943,0,'3e47');
+INSERT INTO items VALUES(NULL,'Woven Mat (W/E) (2/2)',185,4585,0,'11e9');
+INSERT INTO items VALUES(NULL,'Smaller Wall 3',238,767,0,'2ff');
+INSERT INTO items VALUES(NULL,'Smaller Wall 2',238,766,0,'2fe');
+INSERT INTO items VALUES(NULL,'Smaller Wall 1',238,765,0,'2fd');
+INSERT INTO items VALUES(NULL,'Grass Mat (W/E) (2/2)',185,4581,0,'11e5');
+INSERT INTO items VALUES(NULL,'Grass Mat (W/E) (1/2)',185,4580,0,'11e4');
+INSERT INTO items VALUES(NULL,'Woven Mat (N/S) (2/2)',185,4583,0,'11e7');
+INSERT INTO items VALUES(NULL,'Woven Mat (N/S) (1/2)',185,4582,0,'11e6');
+INSERT INTO items VALUES(NULL,'Log Table (N/S) (3/3)',89,4577,0,'11e1');
+INSERT INTO items VALUES(NULL,'Log Table (N/S) (2/3)',89,4576,0,'11e0');
+INSERT INTO items VALUES(NULL,'Grass Mat (N/S) (2/2)',185,4579,0,'11e3');
+INSERT INTO items VALUES(NULL,'Ship 3',137,15937,0,'3e41');
+INSERT INTO items VALUES(NULL,'Wall 14',127,980,0,'3d4');
+INSERT INTO items VALUES(NULL,'Wall 15',127,981,0,'3d5');
+INSERT INTO items VALUES(NULL,'Wall 16',127,982,0,'3d6');
+INSERT INTO items VALUES(NULL,'Wave 14',62,8112,0,'1fb0');
+INSERT INTO items VALUES(NULL,'Wall 10',127,976,0,'3d0');
+INSERT INTO items VALUES(NULL,'Wall 11',127,977,0,'3d1');
+INSERT INTO items VALUES(NULL,'Wave 19',62,8117,0,'1fb5');
+INSERT INTO items VALUES(NULL,'Wall 13',127,979,0,'3d3');
+INSERT INTO items VALUES(NULL,'Wave 23',62,8121,0,'1fb9');
+INSERT INTO items VALUES(NULL,'Wave 22',62,8120,0,'1fb8');
+INSERT INTO items VALUES(NULL,'Wall 18',127,984,0,'3d8');
+INSERT INTO items VALUES(NULL,'Wall 19',127,985,0,'3d9');
+INSERT INTO items VALUES(NULL,'Silver Steed',115,9629,0,'259d');
+INSERT INTO items VALUES(NULL,'Gate (S/NW)',191,2154,0,'86a');
+INSERT INTO items VALUES(NULL,'Imp',115,9631,0,'259f');
+INSERT INTO items VALUES(NULL,'Dark Brown Horse',115,9626,0,'259a');
+INSERT INTO items VALUES(NULL,'Dark Steed',115,9627,0,'259b');
+INSERT INTO items VALUES(NULL,'Nightmare',115,9628,0,'259c');
+INSERT INTO items VALUES(NULL,'Gate (S/NE)',191,2156,0,'86c');
+INSERT INTO items VALUES(NULL,'Patch 5',317,755,0,'2f3');
+INSERT INTO items VALUES(NULL,'Patch 4',317,754,0,'2f2');
+INSERT INTO items VALUES(NULL,'Patch 3',317,753,0,'2f1');
+INSERT INTO items VALUES(NULL,'Patch 2',317,752,0,'2f0');
+INSERT INTO items VALUES(NULL,'Patch 6',317,756,0,'2f4');
+INSERT INTO items VALUES(NULL,'Small Stone Fireplace (N/S) (1/2)',103,4590,0,'11ee');
+INSERT INTO items VALUES(NULL,'Small Stone Fireplace (W/E) (2/2)',103,4589,0,'11ed');
+INSERT INTO items VALUES(NULL,'Small Wall 1',238,761,0,'2f9');
+INSERT INTO items VALUES(NULL,'Small Stone Fireplace (N/S) (2/2)',103,4591,0,'11ef');
+INSERT INTO items VALUES(NULL,'Straw Pillow (W/E)',185,4586,0,'11ea');
+INSERT INTO items VALUES(NULL,'Small Stone Fireplace (W/E) (1/2)',103,4588,0,'11ec');
+INSERT INTO items VALUES(NULL,'Straw Pillow (N/S)',185,4587,0,'11eb');
+INSERT INTO items VALUES(NULL,'Arch 6',330,127,0,'7f');
+INSERT INTO items VALUES(NULL,'Arch 5',330,126,0,'7e');
+INSERT INTO items VALUES(NULL,'Arch 4',330,125,0,'7d');
+INSERT INTO items VALUES(NULL,'Arch 3',330,124,0,'7c');
+INSERT INTO items VALUES(NULL,'Arch 2',330,123,0,'7b');
+INSERT INTO items VALUES(NULL,'Arch 1',330,122,0,'7a');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 22',302,1918,0,'77e');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 21',302,1917,0,'77d');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 23',302,1919,0,'77f');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 18',302,1914,0,'77a');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 20',302,1916,0,'77c');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 19',302,1915,0,'77b');
+INSERT INTO items VALUES(NULL,'Smaller Wall 1',140,99,0,'63');
+INSERT INTO items VALUES(NULL,'Spinning Wheel (E/W) (Animated)',57,4261,0,'10a5');
+INSERT INTO items VALUES(NULL,'Carpet 9',199,4256,0,'10a0');
+INSERT INTO items VALUES(NULL,'Carpet 10',199,4257,0,'10a1');
+INSERT INTO items VALUES(NULL,'Carpet 11',199,4258,0,'10a2');
+INSERT INTO items VALUES(NULL,'Carpet 12',199,4259,0,'10a3');
+INSERT INTO items VALUES(NULL,'Clock (N/S)',240,4172,0,'104c');
+INSERT INTO items VALUES(NULL,'Clock (W/E)',240,4171,0,'104b');
+INSERT INTO items VALUES(NULL,'Loom Bench (N/S)',78,4170,0,'104a');
+INSERT INTO items VALUES(NULL,'Clock Parts (W/E)',240,4175,0,'104f');
+INSERT INTO items VALUES(NULL,'Clock Frame (N/S)',240,4174,0,'104e');
+INSERT INTO items VALUES(NULL,'Clock Frame (W/E)',240,4173,0,'104d');
+INSERT INTO items VALUES(NULL,'Spellbook (N/S)',186,3834,0,'efa');
+INSERT INTO items VALUES(NULL,'Bottle 9',173,3835,0,'efb');
+INSERT INTO items VALUES(NULL,'Bottle 10',173,3836,0,'efc');
+INSERT INTO items VALUES(NULL,'Bottle 11',173,3837,0,'efd');
+INSERT INTO items VALUES(NULL,'Bottle 12',173,3838,0,'efe');
+INSERT INTO items VALUES(NULL,'hair dye',173,3839,0,'eff');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 13',302,1909,0,'775');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 12',302,1908,0,'774');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 15',302,1911,0,'777');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 14',302,1910,0,'776');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 9',302,1905,0,'771');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 8',302,1904,0,'770');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 11',302,1907,0,'773');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 10',302,1906,0,'772');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 17',302,1913,0,'779');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 16',302,1912,0,'778');
+INSERT INTO items VALUES(NULL,'Stone Column',140,119,0,'77');
+INSERT INTO items VALUES(NULL,'Battlement 5',140,118,0,'76');
+INSERT INTO items VALUES(NULL,'Battlement 4',140,117,0,'75');
+INSERT INTO items VALUES(NULL,'Battlement 3',140,116,0,'74');
+INSERT INTO items VALUES(NULL,'Battlement 2',140,115,0,'73');
+INSERT INTO items VALUES(NULL,'Battlement 1',140,114,0,'72');
+INSERT INTO items VALUES(NULL,'Arch 5',140,113,0,'71');
+INSERT INTO items VALUES(NULL,'Arch 4',140,112,0,'70');
+INSERT INTO items VALUES(NULL,'Edge 2',140,121,0,'79');
+INSERT INTO items VALUES(NULL,'Edge 1',140,120,0,'78');
+INSERT INTO items VALUES(NULL,'Rolling Pin',114,4163,0,'1043');
+INSERT INTO items VALUES(NULL,'Unbaked Pie',19,4162,0,'1042');
+INSERT INTO items VALUES(NULL,'Baked Pie',19,4161,0,'1041');
+INSERT INTO items VALUES(NULL,'Pizza',19,4160,0,'1040');
+INSERT INTO items VALUES(NULL,'Globe 1',258,4167,0,'1047');
+INSERT INTO items VALUES(NULL,'Open Sack of Flour (N/S)',114,4166,0,'1046');
+INSERT INTO items VALUES(NULL,'Sack of Flour (N/S)',114,4165,0,'1045');
+INSERT INTO items VALUES(NULL,'Silver Coin',305,3824,0,'ef0');
+INSERT INTO items VALUES(NULL,'Silver Coins 1',305,3825,0,'ef1');
+INSERT INTO items VALUES(NULL,'Loom Bench (W/E)',78,4169,0,'1049');
+INSERT INTO items VALUES(NULL,'Telescope (11/66)',182,5219,0,'1463');
+INSERT INTO items VALUES(NULL,'Scroll 1 (N/S)',186,3828,0,'ef4');
+INSERT INTO items VALUES(NULL,'Scroll 3 (N/S)',186,3830,0,'ef6');
+INSERT INTO items VALUES(NULL,'Scroll 4 (N/S)',186,3831,0,'ef7');
+INSERT INTO items VALUES(NULL,'Mana Drain',94,8011,0,'1f4b');
+INSERT INTO items VALUES(NULL,'Hanging Pole (W/E) (2/3)',318,4269,0,'10ad');
+INSERT INTO items VALUES(NULL,'Hanging Pole (W/E) (3/3)',318,4270,0,'10ae');
+INSERT INTO items VALUES(NULL,'Hanging Pole (N/S) (1/3)',318,4271,0,'10af');
+INSERT INTO items VALUES(NULL,'Short Cannon (W/E) (1/2)',67,3691,0,'e6b');
+INSERT INTO items VALUES(NULL,'Hanging Pole (W/E) (1/3)',318,4268,0,'10ac');
+INSERT INTO items VALUES(NULL,'Oak Tree 2',4,3293,0,'cdd');
+INSERT INTO items VALUES(NULL,'Wall 17',6,620,0,'26c');
+INSERT INTO items VALUES(NULL,'Smaller Wall 4',140,102,0,'66');
+INSERT INTO items VALUES(NULL,'Short Cannon (W/E) (2/2)',67,3692,0,'e6c');
+INSERT INTO items VALUES(NULL,'Oak Tree 1 Leaves 1',4,3291,0,'cdb');
+INSERT INTO items VALUES(NULL,'Wall 16',6,619,0,'26b');
+INSERT INTO items VALUES(NULL,'Short Cannon (N/S) (1/2)',67,3693,0,'e6d');
+INSERT INTO items VALUES(NULL,'Wood 24',11,7064,0,'1b98');
+INSERT INTO items VALUES(NULL,'Short Cannon (N/S) (2/2)',67,3694,0,'e6e');
+INSERT INTO items VALUES(NULL,'Harrow (W/E) (2/2)',257,5383,0,'1507');
+INSERT INTO items VALUES(NULL,'Thieves Guild (W/E)',229,3068,0,'bfc');
+INSERT INTO items VALUES(NULL,'Thieves Guild (N/S)',229,3067,0,'bfb');
+INSERT INTO items VALUES(NULL,'Tailors Guild (W/E)',229,3066,0,'bfa');
+INSERT INTO items VALUES(NULL,'Lizardman',115,8414,0,'20de');
+INSERT INTO items VALUES(NULL,'Grizzly Bear',115,8411,0,'20db');
+INSERT INTO items VALUES(NULL,'Assassins Guild (N/S)',229,3071,0,'bff');
+INSERT INTO items VALUES(NULL,'Rogues Guild (W/E)',229,3070,0,'bfe');
+INSERT INTO items VALUES(NULL,'Rogues Guild (N/S)',229,3069,0,'bfd');
+INSERT INTO items VALUES(NULL,'Chessmen 2',249,3603,0,'e13');
+INSERT INTO items VALUES(NULL,'Chessmen 1',249,3602,0,'e12');
+INSERT INTO items VALUES(NULL,'Cards 1',249,3605,0,'e15');
+INSERT INTO items VALUES(NULL,'Chessmen 3',249,3604,0,'e14');
+INSERT INTO items VALUES(NULL,'Cards 3',249,3607,0,'e17');
+INSERT INTO items VALUES(NULL,'Cards 2',249,3606,0,'e16');
+INSERT INTO items VALUES(NULL,'Bear (N/S)',160,7776,0,'1e60');
+INSERT INTO items VALUES(NULL,'Deer (N/S)',160,7777,0,'1e61');
+INSERT INTO items VALUES(NULL,'Winch (N/S) (Animated)',141,7849,0,'1ea9');
+INSERT INTO items VALUES(NULL,'Fish (N/S)',160,7778,0,'1e62');
+INSERT INTO items VALUES(NULL,'Winch (N/S)',141,7848,0,'1ea8');
+INSERT INTO items VALUES(NULL,'Arch 2',85,395,0,'18b');
+INSERT INTO items VALUES(NULL,'Gorilla (N/S)',160,7779,0,'1e63');
+INSERT INTO items VALUES(NULL,'Tiller Man 5',10,15950,0,'3e4e');
+INSERT INTO items VALUES(NULL,'Orc (N/S)',160,7780,0,'1e64');
+INSERT INTO items VALUES(NULL,'Polar Bear (N/S)',160,7781,0,'1e65');
+INSERT INTO items VALUES(NULL,'Tree 1 Leaves 1',4,3284,0,'cd4');
+INSERT INTO items VALUES(NULL,'Tree 1 Leaves 2',4,3285,0,'cd5');
+INSERT INTO items VALUES(NULL,'Cedar Tree 1',4,3286,0,'cd6');
+INSERT INTO items VALUES(NULL,'Wall 6',158,11,0,'b');
+INSERT INTO items VALUES(NULL,'Tree (brown)',4,3280,0,'cd0');
+INSERT INTO items VALUES(NULL,'Troll (N/S)',160,7782,0,'1e66');
+INSERT INTO items VALUES(NULL,'Tree (brown) Leaves 2',4,3282,0,'cd2');
+INSERT INTO items VALUES(NULL,'Tree 1',4,3283,0,'cd3');
+INSERT INTO items VALUES(NULL,'Raw Cotton 2',57,3577,0,'df9');
+INSERT INTO items VALUES(NULL,'Bear (W/E)',160,7783,0,'1e67');
+INSERT INTO items VALUES(NULL,'Cedar Tree 2',4,3288,0,'cd8');
+INSERT INTO items VALUES(NULL,'Cedar Needles 2',4,3289,0,'cd9');
+INSERT INTO items VALUES(NULL,'Tiller Man 2',10,15947,0,'3e4b');
+INSERT INTO items VALUES(NULL,'Rope 1',148,7841,0,'1ea1');
+INSERT INTO items VALUES(NULL,'Arch 5',85,398,0,'18e');
+INSERT INTO items VALUES(NULL,'Hook 7',141,7840,0,'1ea0');
+INSERT INTO items VALUES(NULL,'Fishermens Guild (N/S)',229,3059,0,'bf3');
+INSERT INTO items VALUES(NULL,'Seamens Guild (W/E)',229,3058,0,'bf2');
+INSERT INTO items VALUES(NULL,'Seamens Guild (N/S)',229,3057,0,'bf1');
+INSERT INTO items VALUES(NULL,'Archers Guild (W/E)',229,3056,0,'bf0');
+INSERT INTO items VALUES(NULL,'Shipwrights Guild (N/S)',229,3063,0,'bf7');
+INSERT INTO items VALUES(NULL,'Sailors Guild (W/E)',229,3062,0,'bf6');
+INSERT INTO items VALUES(NULL,'Sailors Guild (N/S)',229,3061,0,'bf5');
+INSERT INTO items VALUES(NULL,'Fishermens Guild (W/E)',229,3060,0,'bf4');
+INSERT INTO items VALUES(NULL,'Checkers 1',249,3610,0,'e1a');
+INSERT INTO items VALUES(NULL,'Tailors Guild (N/S)',229,3065,0,'bf9');
+INSERT INTO items VALUES(NULL,'Shipwrights Guild (W/E)',229,3064,0,'bf8');
+INSERT INTO items VALUES(NULL,'Ball of Yarn 2',57,3614,0,'e1e');
+INSERT INTO items VALUES(NULL,'Fence 2',353,2147,0,'863');
+INSERT INTO items VALUES(NULL,'Ettin',115,8408,0,'20d8');
+INSERT INTO items VALUES(NULL,'Gargoyle',115,8409,0,'20d9');
+INSERT INTO items VALUES(NULL,'Frypan 1',14,2431,0,'97f');
+INSERT INTO items VALUES(NULL,'Wooden Ladder (W/E) 2',371,2208,0,'8a0');
+INSERT INTO items VALUES(NULL,'Wooden Ladder (W/E) 3',371,2209,0,'8a1');
+INSERT INTO items VALUES(NULL,'Wooden Ladder (N/S) 1',371,2210,0,'8a2');
+INSERT INTO items VALUES(NULL,'Wooden Ladder (N/S) 2',371,2211,0,'8a3');
+INSERT INTO items VALUES(NULL,'Wooden Ladder (N/S) 3',371,2212,0,'8a4');
+INSERT INTO items VALUES(NULL,'Rope Ladder (W/E)',372,2213,0,'8a5');
+INSERT INTO items VALUES(NULL,'Rope Ladder (N/S)',372,2214,0,'8a6');
+INSERT INTO items VALUES(NULL,'Citrine 2',308,3875,0,'f23');
+INSERT INTO items VALUES(NULL,'Amethyst 3',308,3874,0,'f22');
+INSERT INTO items VALUES(NULL,'Star Sapphire 3',308,3873,0,'f21');
+INSERT INTO items VALUES(NULL,'Wedge of Cheese (big)',19,2429,0,'97d');
+INSERT INTO items VALUES(NULL,'Diamond 2',308,3879,0,'f27');
+INSERT INTO items VALUES(NULL,'Diamond 1',308,3878,0,'f26');
+INSERT INTO items VALUES(NULL,'Amber',308,3877,0,'f25');
+INSERT INTO items VALUES(NULL,'Citrine 3',308,3876,0,'f24');
+INSERT INTO items VALUES(NULL,'Wedge of Cheese (small)',19,2428,0,'97c');
+INSERT INTO items VALUES(NULL,'Diamond 4',308,3881,0,'f29');
+INSERT INTO items VALUES(NULL,'Diamond 3',308,3880,0,'f28');
+INSERT INTO items VALUES(NULL,'helmet',278,5130,0,'iron_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Fish Steak',19,2427,0,'97b');
+INSERT INTO items VALUES(NULL,'Raw Fish Steak',19,2426,0,'97a');
+INSERT INTO items VALUES(NULL,'Citrine 4',308,3884,0,'f2c');
+INSERT INTO items VALUES(NULL,'Ruby 7',308,3883,0,'f2b');
+INSERT INTO items VALUES(NULL,'Wall 7',158,12,0,'c');
+INSERT INTO items VALUES(NULL,'Emerald 2',308,3887,0,'f2f');
+INSERT INTO items VALUES(NULL,'Amethyst 4',308,3886,0,'f2e');
+INSERT INTO items VALUES(NULL,'Tourmaline 4',308,3885,0,'f2d');
+INSERT INTO items VALUES(NULL,'Banister 1',307,2222,0,'8ae');
+INSERT INTO items VALUES(NULL,'Banister 2',307,2223,0,'8af');
+INSERT INTO items VALUES(NULL,'Virtue Stone 2',172,6250,0,'186a');
+INSERT INTO items VALUES(NULL,'Virtue Stone 4',172,6252,0,'186c');
+INSERT INTO items VALUES(NULL,'Virtue Stone 3',172,6251,0,'186b');
+INSERT INTO items VALUES(NULL,'Virtue Stone 6',172,6254,0,'186e');
+INSERT INTO items VALUES(NULL,'Virtue Stone 5',172,6253,0,'186d');
+INSERT INTO items VALUES(NULL,'ringmail leggings',43,5104,0,'valorite_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'Virtue Stone 7',172,6255,0,'186f');
+INSERT INTO items VALUES(NULL,'Water Elemental',115,8459,0,'210b');
+INSERT INTO items VALUES(NULL,'Headless',115,8458,0,'210a');
+INSERT INTO items VALUES(NULL,'Smoke',28,14120,0,'3728');
+INSERT INTO items VALUES(NULL,'Dishing Stump (W/E)',173,6246,0,'1866');
+INSERT INTO items VALUES(NULL,'Virtue Stone 1',172,6249,0,'1869');
+INSERT INTO items VALUES(NULL,'Ghoul',115,8457,0,'2109');
+INSERT INTO items VALUES(NULL,'Mountain Goat',115,8456,0,'2108');
+INSERT INTO items VALUES(NULL,'Cow',115,8451,0,'2103');
+INSERT INTO items VALUES(NULL,'Panther',115,8450,0,'2102');
+INSERT INTO items VALUES(NULL,'Pig',115,8449,0,'2101');
+INSERT INTO items VALUES(NULL,'Wisp',115,8448,0,'2100');
+INSERT INTO items VALUES(NULL,'Human Female',115,8455,0,'2107');
+INSERT INTO items VALUES(NULL,'Human Male',115,8454,0,'2106');
+INSERT INTO items VALUES(NULL,'Daemon 2 (big)',115,8453,0,'2105');
+INSERT INTO items VALUES(NULL,'Daemon 1 (big)',115,8452,0,'2104');
+INSERT INTO items VALUES(NULL,'Rattan Ladder (W/E) 2',373,2202,0,'89a');
+INSERT INTO items VALUES(NULL,'Rattan Ladder (N/S) 1',373,2203,0,'89b');
+INSERT INTO items VALUES(NULL,'Rattan Ladder (N/S) 2',373,2204,0,'89c');
+INSERT INTO items VALUES(NULL,'Rattan Ladder (N/S) 3',373,2205,0,'89d');
+INSERT INTO items VALUES(NULL,'Rattan Ladder (W/E) 3',373,2206,0,'89e');
+INSERT INTO items VALUES(NULL,'Wooden Ladder (W/E) 1',371,2207,0,'89f');
+INSERT INTO items VALUES(NULL,'Wall 4',158,9,0,'9');
+INSERT INTO items VALUES(NULL,'Rattan Ladder (W/E) 1',373,2201,0,'899');
+INSERT INTO items VALUES(NULL,'platemail gorget',187,5139,0,'merkite_armor_plate_gorget');
+INSERT INTO items VALUES(NULL,'platemail',269,5141,0,'dull_copper_armor_plate_male');
+INSERT INTO items VALUES(NULL,'Lava 16',37,6757,0,'1a65');
+INSERT INTO items VALUES(NULL,'Curtain 6',82,1075,0,'433');
+INSERT INTO items VALUES(NULL,'Grass 7',374,6024,0,'1788');
+INSERT INTO items VALUES(NULL,'Grass 8',374,6025,0,'1789');
+INSERT INTO items VALUES(NULL,'Grass 4',344,6016,0,'1780');
+INSERT INTO items VALUES(NULL,'Grass 5',344,6017,0,'1781');
+INSERT INTO items VALUES(NULL,'Grass 1',374,6018,0,'1782');
+INSERT INTO items VALUES(NULL,'Grass 2',374,6019,0,'1783');
+INSERT INTO items VALUES(NULL,'Grass 3',374,6020,0,'1784');
+INSERT INTO items VALUES(NULL,'Grass 4',374,6021,0,'1785');
+INSERT INTO items VALUES(NULL,'Grass 5',374,6022,0,'1786');
+INSERT INTO items VALUES(NULL,'Grass 6',374,6023,0,'1787');
+INSERT INTO items VALUES(NULL,'Sticks ',11,7067,0,'1b9b');
+INSERT INTO items VALUES(NULL,'Gorilla (W/E)',160,7786,0,'1e6a');
+INSERT INTO items VALUES(NULL,'Metal Door (W/SE)',336,1661,0,'67d');
+INSERT INTO items VALUES(NULL,'Metal Door (W/NE)',336,1663,0,'67f');
+INSERT INTO items VALUES(NULL,'Roof 9',327,1452,0,'5ac');
+INSERT INTO items VALUES(NULL,'Metal Door (S/NE)',336,1659,0,'67b');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 2',4,4799,0,'12bf');
+INSERT INTO items VALUES(NULL,'Yew Tree Leaves 1',4,4798,0,'12be');
+INSERT INTO items VALUES(NULL,'Roof 8',327,1451,0,'5ab');
+INSERT INTO items VALUES(NULL,'Yew Tree 7',4,4796,0,'12bc');
+INSERT INTO items VALUES(NULL,'Yew Tree 6',4,4795,0,'12bb');
+INSERT INTO items VALUES(NULL,'Yew Tree 5',4,4794,0,'12ba');
+INSERT INTO items VALUES(NULL,'Refuse 1',334,7071,0,'1b9f');
+INSERT INTO items VALUES(NULL,'Lava 17',37,6761,0,'1a69');
+INSERT INTO items VALUES(NULL,'Twigs 2',11,7069,0,'1b9d');
+INSERT INTO items VALUES(NULL,'Terathan Queen (3d)',115,9675,0,'25cb');
+INSERT INTO items VALUES(NULL,'Terathan Warrior (3d)',115,9676,0,'25cc');
+INSERT INTO items VALUES(NULL,'Roof 12',327,1455,0,'5af');
+INSERT INTO items VALUES(NULL,'Wolf (3d)',115,9679,0,'25cf');
+INSERT INTO items VALUES(NULL,'Titan (3d)',115,9677,0,'25cd');
+INSERT INTO items VALUES(NULL,'Unicorn',115,9678,0,'25ce');
+INSERT INTO items VALUES(NULL,'Metal Door (S/NW)',336,1657,0,'679');
+INSERT INTO items VALUES(NULL,'Roof 27',297,1652,0,'674');
+INSERT INTO items VALUES(NULL,'Metal Door (S/SW)',336,1653,0,'675');
+INSERT INTO items VALUES(NULL,'Metal Door (S/SE)',336,1655,0,'677');
+INSERT INTO items VALUES(NULL,'Roof 23',297,1648,0,'670');
+INSERT INTO items VALUES(NULL,'Roof 24',297,1649,0,'671');
+INSERT INTO items VALUES(NULL,'Roof 25',297,1650,0,'672');
+INSERT INTO items VALUES(NULL,'Roof 26',297,1651,0,'673');
+INSERT INTO items VALUES(NULL,'Swamp Tentacles',115,9672,0,'25c8');
+INSERT INTO items VALUES(NULL,'Terathan Drone (3d)',115,9673,0,'25c9');
+INSERT INTO items VALUES(NULL,'Silver Serpent',115,9666,0,'25c2');
+INSERT INTO items VALUES(NULL,'Black Widow Spider',115,9667,0,'25c3');
+INSERT INTO items VALUES(NULL,'Giant Ice Snake',115,9664,0,'25c0');
+INSERT INTO items VALUES(NULL,'Giant Lava Snake',115,9665,0,'25c1');
+INSERT INTO items VALUES(NULL,'Giant Spider',115,9670,0,'25c6');
+INSERT INTO items VALUES(NULL,'Ghost',115,9671,0,'25c7');
+INSERT INTO items VALUES(NULL,'Dread Spider',115,9668,0,'25c4');
+INSERT INTO items VALUES(NULL,'Frost Spider',115,9669,0,'25c5');
+INSERT INTO items VALUES(NULL,'Yew Tree 2',4,4791,0,'12b7');
+INSERT INTO items VALUES(NULL,'Yew Tree 1',4,4790,0,'12b6');
+INSERT INTO items VALUES(NULL,'Mallet and Chisel',262,4787,0,'12b3');
+INSERT INTO items VALUES(NULL,'Scaffold (N/S) (2/2)',298,4786,0,'12b2');
+INSERT INTO items VALUES(NULL,'Scaffold (N/S) (1/2)',298,4785,0,'12b1');
+INSERT INTO items VALUES(NULL,'Statue 3 (1/3)',54,4784,0,'12b0');
+INSERT INTO items VALUES(NULL,'Yew Tree 4',4,4793,0,'12b9');
+INSERT INTO items VALUES(NULL,'Yew Tree 3',4,4792,0,'12b8');
+INSERT INTO items VALUES(NULL,'Balista 84',76,16191,0,'3f3f');
+INSERT INTO items VALUES(NULL,'ringmail gloves',39,5099,0,'dull_copper_armor_ring_gloves');
+INSERT INTO items VALUES(NULL,'mace',5,5181,0,'143d');
+INSERT INTO items VALUES(NULL,'Rack 9',113,4694,0,'1256');
+INSERT INTO items VALUES(NULL,'Rack 10',113,4695,0,'1257');
+INSERT INTO items VALUES(NULL,'Rack 7',113,4692,0,'1254');
+INSERT INTO items VALUES(NULL,'Rack 8',113,4693,0,'1255');
+INSERT INTO items VALUES(NULL,'Rack 5',113,4690,0,'1252');
+INSERT INTO items VALUES(NULL,'Rack 6',113,4691,0,'1253');
+INSERT INTO items VALUES(NULL,'Rack 3',113,4688,0,'1250');
+INSERT INTO items VALUES(NULL,'Rack 4',113,4689,0,'1251');
+INSERT INTO items VALUES(NULL,'Rack 11',113,4696,0,'1258');
+INSERT INTO items VALUES(NULL,'Rack 12',113,4697,0,'1259');
+INSERT INTO items VALUES(NULL,'Runebook ',186,8901,0,'22c5');
+INSERT INTO items VALUES(NULL,'Guillotine 6',113,4703,0,'125f');
+INSERT INTO items VALUES(NULL,'Short Pants (N/S)',315,5422,0,'152e');
+INSERT INTO items VALUES(NULL,'Short Pants (W/E)',315,5423,0,'152f');
+INSERT INTO items VALUES(NULL,'Guillotine 5',113,4702,0,'125e');
+INSERT INTO items VALUES(NULL,'Rack 14',113,4699,0,'125b');
+INSERT INTO items VALUES(NULL,'Rack 15',113,4700,0,'125c');
+INSERT INTO items VALUES(NULL,'Rack 13',113,4698,0,'125a');
+INSERT INTO items VALUES(NULL,'Fern 3',45,3234,0,'ca2');
+INSERT INTO items VALUES(NULL,'Roof 25',84,1499,0,'5db');
+INSERT INTO items VALUES(NULL,'Roof 26',84,1500,0,'5dc');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 9',337,7742,0,'1e3e');
+INSERT INTO items VALUES(NULL,'Roof 24',84,1498,0,'5da');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 7',337,7740,0,'1e3c');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 6',337,7739,0,'1e3b');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 5',337,7738,0,'1e3a');
+INSERT INTO items VALUES(NULL,'Roof 28',84,1502,0,'5de');
+INSERT INTO items VALUES(NULL,'Flower 12',134,3150,0,'c4e');
+INSERT INTO items VALUES(NULL,'plate helmet',208,5138,0,'copper_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Roof 17',84,1490,0,'5d2');
+INSERT INTO items VALUES(NULL,'Roof 18',84,1491,0,'5d3');
+INSERT INTO items VALUES(NULL,'Roof 15',281,1488,0,'5d0');
+INSERT INTO items VALUES(NULL,'Roof 16',84,1489,0,'5d1');
+INSERT INTO items VALUES(NULL,'Roof 20',84,1494,0,'5d6');
+INSERT INTO items VALUES(NULL,'Roof 21',84,1495,0,'5d7');
+INSERT INTO items VALUES(NULL,'Roof 19',84,1492,0,'5d4');
+INSERT INTO items VALUES(NULL,'Treasure (8/41)',215,6982,0,'1b46');
+INSERT INTO items VALUES(NULL,'Treasure (10/41)',215,6984,0,'1b48');
+INSERT INTO items VALUES(NULL,'Roof 22',84,1496,0,'5d8');
+INSERT INTO items VALUES(NULL,'Roof 23',84,1497,0,'5d9');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 4',337,7737,0,'1e39');
+INSERT INTO items VALUES(NULL,'Rug (N/S) 3',337,7736,0,'1e38');
+INSERT INTO items VALUES(NULL,'Balista 111',76,16218,0,'3f5a');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 18',292,1023,0,'3ff');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 16',292,1021,0,'3fd');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 17',292,1022,0,'3fe');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 13',292,1018,0,'3fa');
+INSERT INTO items VALUES(NULL,'Wall 1',317,734,0,'2de');
+INSERT INTO items VALUES(NULL,'Potted Tree 2',4,4553,0,'11c9');
+INSERT INTO items VALUES(NULL,'Wall 2',317,735,0,'2df');
+INSERT INTO items VALUES(NULL,'Crumbling Floor 4',109,4547,0,'11c3');
+INSERT INTO items VALUES(NULL,'Crumbling Floor 3',109,4546,0,'11c2');
+INSERT INTO items VALUES(NULL,'Crumbling Floor 2',109,4545,0,'11c1');
+INSERT INTO items VALUES(NULL,'Crumbling Floor 1',109,4544,0,'11c0');
+INSERT INTO items VALUES(NULL,'Empty Flower Pot 2',134,4551,0,'11c7');
+INSERT INTO items VALUES(NULL,'Empty Flower Pot 1',134,4550,0,'11c6');
+INSERT INTO items VALUES(NULL,'Crumbling Floor 6',109,4549,0,'11c5');
+INSERT INTO items VALUES(NULL,'Crumbling Floor 5',109,4548,0,'11c4');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 11',292,1016,0,'3f8');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 12',292,1017,0,'3f9');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 9',292,1014,0,'3f6');
+INSERT INTO items VALUES(NULL,'Sandstone Stairs 8',292,1013,0,'3f5');
+INSERT INTO items VALUES(NULL,'cutlass',3,5185,0,'1441');
+INSERT INTO items VALUES(NULL,'Small Wall 8',330,725,0,'2d5');
+INSERT INTO items VALUES(NULL,'Small Wall 7',330,724,0,'2d4');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',330,727,0,'2d7');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',330,726,0,'2d6');
+INSERT INTO items VALUES(NULL,'Small Wall 4',330,721,0,'2d1');
+INSERT INTO items VALUES(NULL,'Small Wall 3',330,720,0,'2d0');
+INSERT INTO items VALUES(NULL,'Small Wall 6',330,723,0,'2d3');
+INSERT INTO items VALUES(NULL,'Small Wall 5',330,722,0,'2d2');
+INSERT INTO items VALUES(NULL,'Flower Pot 3',134,4556,0,'11cc');
+INSERT INTO items VALUES(NULL,'Flower Pot 2',134,4555,0,'11cb');
+INSERT INTO items VALUES(NULL,'Flower Pot 1',134,4554,0,'11ca');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',330,729,0,'2d9');
+INSERT INTO items VALUES(NULL,'Walkable Double Bed (W/E) (2/4)',91,4559,0,'11cf');
+INSERT INTO items VALUES(NULL,'Walkable Double Bed (W/E) (1/4)',91,4558,0,'11ce');
+INSERT INTO items VALUES(NULL,'Sandstone Fountain (4/16)',104,6598,0,'19c6');
+INSERT INTO items VALUES(NULL,'Gravestone 8',27,3803,0,'edb');
+INSERT INTO items VALUES(NULL,'Gravestone 9',27,3804,0,'edc');
+INSERT INTO items VALUES(NULL,'Gravestone 7',27,3802,0,'eda');
+INSERT INTO items VALUES(NULL,'Grave 2',27,3807,0,'edf');
+INSERT INTO items VALUES(NULL,'Gravestone 10',27,3805,0,'edd');
+INSERT INTO items VALUES(NULL,'Gravestone 11',27,3806,0,'ede');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 2',121,1823,0,'71f');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 1',121,1822,0,'71e');
+INSERT INTO items VALUES(NULL,'Marble Stairs 21',319,1821,0,'71d');
+INSERT INTO items VALUES(NULL,'Marble Stairs 20',319,1820,0,'71c');
+INSERT INTO items VALUES(NULL,'Marble Stairs 19',319,1819,0,'71b');
+INSERT INTO items VALUES(NULL,'Marble Stairs 18',319,1818,0,'71a');
+INSERT INTO items VALUES(NULL,'Lava 51',44,13655,0,'3557');
+INSERT INTO items VALUES(NULL,'Lava 50',44,13654,0,'3556');
+INSERT INTO items VALUES(NULL,'Spiderweb 4 (3/4)',303,4296,0,'10c8');
+INSERT INTO items VALUES(NULL,'Spiderweb 4 (4/4)',303,4297,0,'10c9');
+INSERT INTO items VALUES(NULL,'Lava 47',44,13651,0,'3553');
+INSERT INTO items VALUES(NULL,'Lava 46',44,13650,0,'3552');
+INSERT INTO items VALUES(NULL,'Lava 45',44,13649,0,'3551');
+INSERT INTO items VALUES(NULL,'Lava 44',44,13648,0,'3550');
+INSERT INTO items VALUES(NULL,'Spiderweb 3 (1/4)',303,4290,0,'10c2');
+INSERT INTO items VALUES(NULL,'Spiderweb 3 (2/4)',303,4291,0,'10c3');
+INSERT INTO items VALUES(NULL,'Spiderweb 2 (4/5)',303,4288,0,'10c0');
+INSERT INTO items VALUES(NULL,'Spiderweb 2 (5/5)',303,4289,0,'10c1');
+INSERT INTO items VALUES(NULL,'Spiderweb 4 (1/4)',303,4294,0,'10c6');
+INSERT INTO items VALUES(NULL,'Spiderweb 4 (2/4)',303,4295,0,'10c7');
+INSERT INTO items VALUES(NULL,'Spiderweb 3 (3/4)',303,4292,0,'10c4');
+INSERT INTO items VALUES(NULL,'Spiderweb 3 (4/4)',303,4293,0,'10c5');
+INSERT INTO items VALUES(NULL,'Stretched Hide 2 (W/E)',57,4202,0,'106a');
+INSERT INTO items VALUES(NULL,'Stretched Hide 4 (W/E) (1/2)',57,4204,0,'106c');
+INSERT INTO items VALUES(NULL,'Stretched Hide 3 (W/E)',57,4203,0,'106b');
+INSERT INTO items VALUES(NULL,'Stretched Hide 5 (W/E) (1/2)',57,4206,0,'106e');
+INSERT INTO items VALUES(NULL,'Stretched Hide 4 (W/E) (2/2)',57,4205,0,'106d');
+INSERT INTO items VALUES(NULL,'Stretched Hide 5 (W/E) (2/2)',57,4207,0,'106f');
+INSERT INTO items VALUES(NULL,'Marble Stairs 17',319,1817,0,'719');
+INSERT INTO items VALUES(NULL,'Marble Stairs 16',319,1816,0,'718');
+INSERT INTO items VALUES(NULL,'Marble Stairs 15',319,1815,0,'717');
+INSERT INTO items VALUES(NULL,'Marble Stairs 14',319,1814,0,'716');
+INSERT INTO items VALUES(NULL,'Marble Stairs 13',319,1813,0,'715');
+INSERT INTO items VALUES(NULL,'Marble Stairs 12',319,1812,0,'714');
+INSERT INTO items VALUES(NULL,'Marble Stairs 11',319,1811,0,'713');
+INSERT INTO items VALUES(NULL,'Marble Stairs 10',319,1810,0,'712');
+INSERT INTO items VALUES(NULL,'Marble Stairs 9',319,1809,0,'711');
+INSERT INTO items VALUES(NULL,'Marble Stairs 8',319,1808,0,'710');
+INSERT INTO items VALUES(NULL,'Bones 9',12,3794,0,'ed2');
+INSERT INTO items VALUES(NULL,'Grave 1',27,3795,0,'ed3');
+INSERT INTO items VALUES(NULL,'Bones 7',12,3792,0,'ed0');
+INSERT INTO items VALUES(NULL,'Bones 8',12,3793,0,'ed1');
+INSERT INTO items VALUES(NULL,'Gravestone 3',27,3798,0,'ed6');
+INSERT INTO items VALUES(NULL,'Gravestone 4',27,3799,0,'ed7');
+INSERT INTO items VALUES(NULL,'Gravestone 1',27,3796,0,'ed4');
+INSERT INTO items VALUES(NULL,'Gravestone 2',27,3797,0,'ed5');
+INSERT INTO items VALUES(NULL,'Balista 109',76,16216,0,'3f58');
+INSERT INTO items VALUES(NULL,'Gravestone 5',27,3800,0,'ed8');
+INSERT INTO items VALUES(NULL,'Gravestone 6',27,3801,0,'ed9');
+INSERT INTO items VALUES(NULL,'Translocation Powd',331,9912,0,'26b8');
+INSERT INTO items VALUES(NULL,'Balista 110',76,16217,0,'3f59');
+INSERT INTO items VALUES(NULL,'Stretched Hide 1 (W/E)',57,4201,0,'1069');
+INSERT INTO items VALUES(NULL,'Cut Up Leather (W/E)',57,4200,0,'1068');
+INSERT INTO items VALUES(NULL,'Plant Bowl',331,9913,0,'26b9');
+INSERT INTO items VALUES(NULL,'ringmail tunic',350,5100,0,'copper_armor_ring_tunic');
+INSERT INTO items VALUES(NULL,'Upright Loom 1 (N/S) (1/2)',57,4193,0,'1061');
+INSERT INTO items VALUES(NULL,'Upright Loom 1 (W/E) (2/2)',57,4192,0,'1060');
+INSERT INTO items VALUES(NULL,'Upright Loom 2 (W/E) (1/2)',57,4195,0,'1063');
+INSERT INTO items VALUES(NULL,'Upright Loom 1 (N/S) (2/2)',57,4194,0,'1062');
+INSERT INTO items VALUES(NULL,'Upright Loom 2 (N/S) (1/2)',57,4197,0,'1065');
+INSERT INTO items VALUES(NULL,'Upright Loom 2 (W/E) (2/2)',57,4196,0,'1064');
+INSERT INTO items VALUES(NULL,'Cut Up Leather (N/S)',57,4199,0,'1067');
+INSERT INTO items VALUES(NULL,'Upright Loom 2 (N/S) (2/2)',57,4198,0,'1066');
+INSERT INTO items VALUES(NULL,'Lava 59',44,13663,0,'355f');
+INSERT INTO items VALUES(NULL,'Lava 58',44,13662,0,'355e');
+INSERT INTO items VALUES(NULL,'Lava 57',44,13661,0,'355d');
+INSERT INTO items VALUES(NULL,'Lava 56',44,13660,0,'355c');
+INSERT INTO items VALUES(NULL,'Lava 55',44,13659,0,'355b');
+INSERT INTO items VALUES(NULL,'Lava 54',44,13658,0,'355a');
+INSERT INTO items VALUES(NULL,'Spiderweb 5 (2/4)',303,4299,0,'10cb');
+INSERT INTO items VALUES(NULL,'Spiderweb 5 (3/4)',303,4300,0,'10cc');
+INSERT INTO items VALUES(NULL,'Spiderweb 5 (1/4)',303,4298,0,'10ca');
+INSERT INTO items VALUES(NULL,'Spiderweb 6 (2/4)',303,4303,0,'10cf');
+INSERT INTO items VALUES(NULL,'Balista 107',76,16214,0,'3f56');
+INSERT INTO items VALUES(NULL,'Spiderweb 5 (4/4)',303,4301,0,'10cd');
+INSERT INTO items VALUES(NULL,'Spiderweb 6 (1/4)',303,4302,0,'10ce');
+INSERT INTO items VALUES(NULL,'Balista 108',76,16215,0,'3f57');
+INSERT INTO items VALUES(NULL,'Cypress Tree 3 Leaves 1',4,3327,0,'cff');
+INSERT INTO items VALUES(NULL,'Cypress Tree 2 Leaves 2',4,3325,0,'cfd');
+INSERT INTO items VALUES(NULL,'Cypress Tree 3',4,3326,0,'cfe');
+INSERT INTO items VALUES(NULL,'Cypress Tree 2',4,3323,0,'cfb');
+INSERT INTO items VALUES(NULL,'Cypress Tree 2 Leaves 1',4,3324,0,'cfc');
+INSERT INTO items VALUES(NULL,'Cypress Tree 1 Leaves 2',4,3322,0,'cfa');
+INSERT INTO items VALUES(NULL,'platemail legs',159,5137,0,'agapite_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'Barters'' Guild (W/E)',229,3038,0,'bde');
+INSERT INTO items VALUES(NULL,'Barters'' Guild (N/S)',229,3037,0,'bdd');
+INSERT INTO items VALUES(NULL,'Provisioners Guild (N/S)',229,3039,0,'bdf');
+INSERT INTO items VALUES(NULL,'Weapons Guild (W/E)',229,3034,0,'bda');
+INSERT INTO items VALUES(NULL,'Bardic Guild (W/E)',229,3036,0,'bdc');
+INSERT INTO items VALUES(NULL,'Bardic Guild (N/S)',229,3035,0,'bdb');
+INSERT INTO items VALUES(NULL,'Leaves 3 (12/13)',4,3454,0,'d7e');
+INSERT INTO items VALUES(NULL,'Cypress Tree 1',4,3320,0,'cf8');
+INSERT INTO items VALUES(NULL,'Cypress Tree 1 Leaves 1',4,3321,0,'cf9');
+INSERT INTO items VALUES(NULL,'Fallen Log (W/E) 2',4,3318,0,'cf6');
+INSERT INTO items VALUES(NULL,'Fallen Log (W/E) 3',4,3319,0,'cf7');
+INSERT INTO items VALUES(NULL,'Fallen Log (N/S) 2',4,3316,0,'cf4');
+INSERT INTO items VALUES(NULL,'Fallen Log (W/E) 1',4,3317,0,'cf5');
+INSERT INTO items VALUES(NULL,'Vines 11',45,3314,0,'cf2');
+INSERT INTO items VALUES(NULL,'Fallen Log (N/S) 1',4,3315,0,'cf3');
+INSERT INTO items VALUES(NULL,'Vines 9',45,3312,0,'cf0');
+INSERT INTO items VALUES(NULL,'Vines 10',45,3313,0,'cf1');
+INSERT INTO items VALUES(NULL,'Armourers'' Guild (N/S)',229,3029,0,'bd5');
+INSERT INTO items VALUES(NULL,'Armaments Guild (W/E)',229,3028,0,'bd4');
+INSERT INTO items VALUES(NULL,'Blacksmiths'' Guild (N/S)',229,3031,0,'bd7');
+INSERT INTO items VALUES(NULL,'Armourers'' Guild (W/E)',229,3030,0,'bd6');
+INSERT INTO items VALUES(NULL,'Brass Sign (N/S)',335,3025,0,'bd1');
+INSERT INTO items VALUES(NULL,'Wooden Sign (W/E)',335,3024,0,'bd0');
+INSERT INTO items VALUES(NULL,'Armaments Guild (N/S)',229,3027,0,'bd3');
+INSERT INTO items VALUES(NULL,'Brass Sign (W/E)',335,3026,0,'bd2');
+INSERT INTO items VALUES(NULL,'Weapons Guild (N/S)',229,3033,0,'bd9');
+INSERT INTO items VALUES(NULL,'Blacksmiths'' Guild (W/E)',229,3032,0,'bd8');
+INSERT INTO items VALUES(NULL,'Part 3',362,5289,0,'14a9');
+INSERT INTO items VALUES(NULL,'Snow 3',323,6079,0,'17bf');
+INSERT INTO items VALUES(NULL,'Snow 1',323,6077,0,'17bd');
+INSERT INTO items VALUES(NULL,'Snow 2',323,6078,0,'17be');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',140,106,0,'6a');
+INSERT INTO items VALUES(NULL,'Banister 21',307,2242,0,'8c2');
+INSERT INTO items VALUES(NULL,'Banister 22',307,2243,0,'8c3');
+INSERT INTO items VALUES(NULL,'Banister 19',307,2240,0,'8c0');
+INSERT INTO items VALUES(NULL,'Banister 20',307,2241,0,'8c1');
+INSERT INTO items VALUES(NULL,'Banister 25',307,2246,0,'8c6');
+INSERT INTO items VALUES(NULL,'Banister 26',307,2247,0,'8c7');
+INSERT INTO items VALUES(NULL,'Banister 23',307,2244,0,'8c4');
+INSERT INTO items VALUES(NULL,'Banister 24',307,2245,0,'8c5');
+INSERT INTO items VALUES(NULL,'Banister 27',307,2248,0,'8c8');
+INSERT INTO items VALUES(NULL,'Banister 28',307,2249,0,'8c9');
+INSERT INTO items VALUES(NULL,'Book 1',263,4079,0,'fef');
+INSERT INTO items VALUES(NULL,'Pentagram 8',375,4077,0,'fed');
+INSERT INTO items VALUES(NULL,'Pentagram 9',375,4078,0,'fee');
+INSERT INTO items VALUES(NULL,'Pentagram 6',375,4075,0,'feb');
+INSERT INTO items VALUES(NULL,'Pentagram 7',375,4076,0,'fec');
+INSERT INTO items VALUES(NULL,'Pentagram 5',375,4074,0,'fea');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',140,107,0,'6b');
+INSERT INTO items VALUES(NULL,'Bottle 18',173,3844,0,'f04');
+INSERT INTO items VALUES(NULL,'Orange Potion',376,3847,0,'f07');
+INSERT INTO items VALUES(NULL,'Black Potion',376,3846,0,'f06');
+INSERT INTO items VALUES(NULL,'Bottle 15',173,3841,0,'f01');
+INSERT INTO items VALUES(NULL,'Bottle 14',173,3840,0,'f00');
+INSERT INTO items VALUES(NULL,'Bottle 17',173,3843,0,'f03');
+INSERT INTO items VALUES(NULL,'Bottle 16',173,3842,0,'f02');
+INSERT INTO items VALUES(NULL,'White Potion',376,3849,0,'f09');
+INSERT INTO items VALUES(NULL,'Blue Potion',376,3848,0,'f08');
+INSERT INTO items VALUES(NULL,'Telescope (16/66)',182,5224,0,'1468');
+INSERT INTO items VALUES(NULL,'Edging 1',377,2251,0,'8cb');
+INSERT INTO items VALUES(NULL,'Edging 2',377,2252,0,'8cc');
+INSERT INTO items VALUES(NULL,'Banister 29',307,2250,0,'8ca');
+INSERT INTO items VALUES(NULL,'Empty Stone Fireplace 1 (W/E) (1/2)',103,2255,0,'8cf');
+INSERT INTO items VALUES(NULL,'Edging 3',377,2253,0,'8cd');
+INSERT INTO items VALUES(NULL,'Edging 4',377,2254,0,'8ce');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',140,108,0,'6c');
+INSERT INTO items VALUES(NULL,'plate armor',187,7172,0,'merkite_armor_plate_female');
+INSERT INTO items VALUES(NULL,'double bladed staff',20,9919,0,'26bf');
+INSERT INTO items VALUES(NULL,'Water 22',309,6066,0,'17b2');
+INSERT INTO items VALUES(NULL,'Water 20',309,6064,0,'17b0');
+INSERT INTO items VALUES(NULL,'Water 21',309,6065,0,'17b1');
+INSERT INTO items VALUES(NULL,'Empty Bottle',173,3854,0,'f0e');
+INSERT INTO items VALUES(NULL,'Purple Potion',376,3853,0,'f0d');
+INSERT INTO items VALUES(NULL,'Star Sapphire 1',308,3855,0,'f0f');
+INSERT INTO items VALUES(NULL,'Green Potion',376,3850,0,'f0a');
+INSERT INTO items VALUES(NULL,'Yellow Potion',376,3852,0,'f0c');
+INSERT INTO items VALUES(NULL,'Red Potion',376,3851,0,'f0b');
+INSERT INTO items VALUES(NULL,'Arch 1',140,109,0,'6d');
+INSERT INTO items VALUES(NULL,'Pentagram 1',375,4070,0,'fe6');
+INSERT INTO items VALUES(NULL,'Pentagram 2',375,4071,0,'fe7');
+INSERT INTO items VALUES(NULL,'Tapestry 11 (2/2)',304,4068,0,'fe4');
+INSERT INTO items VALUES(NULL,'Tapestry 10 (2/2)',304,4066,0,'fe2');
+INSERT INTO items VALUES(NULL,'Tapestry 11 (1/2)',304,4067,0,'fe3');
+INSERT INTO items VALUES(NULL,'Tapestry 9 (2/2)',304,4064,0,'fe0');
+INSERT INTO items VALUES(NULL,'Tapestry 10 (1/2)',304,4065,0,'fe1');
+INSERT INTO items VALUES(NULL,'Pentagram 3',375,4072,0,'fe8');
+INSERT INTO items VALUES(NULL,'Pentagram 4',375,4073,0,'fe9');
+INSERT INTO items VALUES(NULL,'Millstone 8',114,6282,0,'188a');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (10/15)',324,9029,0,'2345');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (9/15)',324,9028,0,'2344');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (12/15)',324,9031,0,'2347');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (11/15)',324,9030,0,'2346');
+INSERT INTO items VALUES(NULL,'Arch 3',140,111,0,'6f');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (5/15)',324,9024,0,'2340');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (8/15)',324,9027,0,'2343');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (7/15)',324,9026,0,'2342');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (14/15)',324,9033,0,'2349');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (13/15)',324,9032,0,'2348');
+INSERT INTO items VALUES(NULL,'Terathan Warrior',115,8490,0,'212a');
+INSERT INTO items VALUES(NULL,'Terathan Matriarch',115,8492,0,'212c');
+INSERT INTO items VALUES(NULL,'Terathan Drone',115,8491,0,'212b');
+INSERT INTO items VALUES(NULL,'Titan',115,8494,0,'212e');
+INSERT INTO items VALUES(NULL,'Cyclops',115,8493,0,'212d');
+INSERT INTO items VALUES(NULL,'Giant Toad',115,8495,0,'212f');
+INSERT INTO items VALUES(NULL,'Leaves 1 (8/15)',4,3404,0,'d4c');
+INSERT INTO items VALUES(NULL,'Fire Column',28,14089,0,'3709');
+INSERT INTO items VALUES(NULL,'Millstone 7',114,6281,0,'1889');
+INSERT INTO items VALUES(NULL,'Millstone 5',114,6279,0,'1887');
+INSERT INTO items VALUES(NULL,'Millstone 4',114,6278,0,'1886');
+INSERT INTO items VALUES(NULL,'Millstone 3',114,6277,0,'1885');
+INSERT INTO items VALUES(NULL,'Millstone 2',114,6276,0,'1884');
+INSERT INTO items VALUES(NULL,'Millstone 1',114,6275,0,'1883');
+INSERT INTO items VALUES(NULL,'chainmail leggings',284,5054,0,'verite_armor_chain_leggings');
+INSERT INTO items VALUES(NULL,'Spilled Flour 4',114,6273,0,'1881');
+INSERT INTO items VALUES(NULL,'Spilled Flour 3',114,6272,0,'1880');
+INSERT INTO items VALUES(NULL,'Horse 3',115,8481,0,'2121');
+INSERT INTO items VALUES(NULL,'Horse 2',115,8480,0,'2120');
+INSERT INTO items VALUES(NULL,'Rat',115,8483,0,'2123');
+INSERT INTO items VALUES(NULL,'Wolf',115,8482,0,'2122');
+INSERT INTO items VALUES(NULL,'Rabbit',115,8485,0,'2125');
+INSERT INTO items VALUES(NULL,'Horse 4',115,8484,0,'2124');
+INSERT INTO items VALUES(NULL,'Packllama',115,8487,0,'2127');
+INSERT INTO items VALUES(NULL,'Packhorse',115,8486,0,'2126');
+INSERT INTO items VALUES(NULL,'Lighthouse (28/29)',46,6863,0,'1acf');
+INSERT INTO items VALUES(NULL,'Serpent Pillar (15/15)',324,9034,0,'234a');
+INSERT INTO items VALUES(NULL,'Leaves 1 (6/15)',4,3402,0,'d4a');
+INSERT INTO items VALUES(NULL,'Wall 13',316,307,0,'133');
+INSERT INTO items VALUES(NULL,'Wall 12',316,306,0,'132');
+INSERT INTO items VALUES(NULL,'Wall 11',316,305,0,'131');
+INSERT INTO items VALUES(NULL,'Wall 10',316,304,0,'130');
+INSERT INTO items VALUES(NULL,'Wall 17',316,311,0,'137');
+INSERT INTO items VALUES(NULL,'Wall 16',316,310,0,'136');
+INSERT INTO items VALUES(NULL,'Wall 15',316,309,0,'135');
+INSERT INTO items VALUES(NULL,'Wall 14',316,308,0,'134');
+INSERT INTO items VALUES(NULL,'Wall 19',316,313,0,'139');
+INSERT INTO items VALUES(NULL,'Wall 18',316,312,0,'138');
+INSERT INTO items VALUES(NULL,'Summon Red Moongate 2',200,6889,0,'1ae9');
+INSERT INTO items VALUES(NULL,'Summon Red Moongate 1',200,6885,0,'1ae5');
+INSERT INTO items VALUES(NULL,'Skull 5',12,6884,0,'1ae4');
+INSERT INTO items VALUES(NULL,'Skull 2',12,6881,0,'1ae1');
+INSERT INTO items VALUES(NULL,'Skull 1',12,6880,0,'1ae0');
+INSERT INTO items VALUES(NULL,'Skull 4',12,6883,0,'1ae3');
+INSERT INTO items VALUES(NULL,'Skull 3',12,6882,0,'1ae2');
+INSERT INTO items VALUES(NULL,'Boulder 2 (3/3)',216,4948,0,'1354');
+INSERT INTO items VALUES(NULL,'Arch 1',316,316,0,'13c');
+INSERT INTO items VALUES(NULL,'Window 2',316,315,0,'13b');
+INSERT INTO items VALUES(NULL,'Window 1',316,314,0,'13a');
+INSERT INTO items VALUES(NULL,'Arch 4',316,319,0,'13f');
+INSERT INTO items VALUES(NULL,'Arch 3',316,318,0,'13e');
+INSERT INTO items VALUES(NULL,'Arch 2',316,317,0,'13d');
+INSERT INTO items VALUES(NULL,'Leaves 1 (11/15)',4,3407,0,'d4f');
+INSERT INTO items VALUES(NULL,'Arch 9',330,136,0,'88');
+INSERT INTO items VALUES(NULL,'Arch 10',330,137,0,'89');
+INSERT INTO items VALUES(NULL,'Wall 3',330,130,0,'82');
+INSERT INTO items VALUES(NULL,'Window 1',330,131,0,'83');
+INSERT INTO items VALUES(NULL,'Wall 1',330,128,0,'80');
+INSERT INTO items VALUES(NULL,'Wall 2',330,129,0,'81');
+INSERT INTO items VALUES(NULL,'Arch 7',330,134,0,'86');
+INSERT INTO items VALUES(NULL,'Arch 8',330,135,0,'87');
+INSERT INTO items VALUES(NULL,'Wall 4',330,132,0,'84');
+INSERT INTO items VALUES(NULL,'Window 2',330,133,0,'85');
+INSERT INTO items VALUES(NULL,'Arch 12',330,139,0,'8b');
+INSERT INTO items VALUES(NULL,'Arch 13',330,140,0,'8c');
+INSERT INTO items VALUES(NULL,'Arch 11',330,138,0,'8a');
+INSERT INTO items VALUES(NULL,'Window 4',330,143,0,'8f');
+INSERT INTO items VALUES(NULL,'Window 3',330,141,0,'8d');
+INSERT INTO items VALUES(NULL,'Arch 14',330,142,0,'8e');
+INSERT INTO items VALUES(NULL,'Hedge (untrimmed) 2',45,3218,0,'c92');
+INSERT INTO items VALUES(NULL,'Small Wall 8',47,389,0,'185');
+INSERT INTO items VALUES(NULL,'Banner 46 (W/E)',128,5610,0,'15ea');
+INSERT INTO items VALUES(NULL,'Banner 47 (W/E)',128,5612,0,'15ec');
+INSERT INTO items VALUES(NULL,'Banner 46 (N/S)',128,5611,0,'15eb');
+INSERT INTO items VALUES(NULL,'Banner 48 (W/E)',128,5614,0,'15ee');
+INSERT INTO items VALUES(NULL,'Banner 47 (N/S)',128,5613,0,'15ed');
+INSERT INTO items VALUES(NULL,'Banner 48 (N/S)',128,5615,0,'15ef');
+INSERT INTO items VALUES(NULL,'Roof 24',150,1622,0,'656');
+INSERT INTO items VALUES(NULL,'Roof 25',150,1623,0,'657');
+INSERT INTO items VALUES(NULL,'Roof 7',221,1620,0,'654');
+INSERT INTO items VALUES(NULL,'Roof 8',221,1621,0,'655');
+INSERT INTO items VALUES(NULL,'Roof 5',142,1618,0,'652');
+INSERT INTO items VALUES(NULL,'Transparent Dirt 3',202,6953,0,'1b29');
+INSERT INTO items VALUES(NULL,'Roof 26',32,1616,0,'650');
+INSERT INTO items VALUES(NULL,'Roof 27',32,1617,0,'651');
+INSERT INTO items VALUES(NULL,'Decorative Armor 1 (W/E)',328,5384,0,'1508');
+INSERT INTO items VALUES(NULL,'Decorative Armor 2 (W/E)',328,5385,0,'1509');
+INSERT INTO items VALUES(NULL,'Roof 8',227,1624,0,'658');
+INSERT INTO items VALUES(NULL,'Roof 9',227,1625,0,'659');
+INSERT INTO items VALUES(NULL,'Scroll 9 (N/S)',186,8049,0,'1f71');
+INSERT INTO items VALUES(NULL,'Scroll 9 (W/E)',186,8050,0,'1f72');
+INSERT INTO items VALUES(NULL,'buckler',69,7027,0,'golden_shields_buckler');
+INSERT INTO items VALUES(NULL,'Part 2',360,5387,0,'150b');
+INSERT INTO items VALUES(NULL,'Part 3',360,5388,0,'150c');
+INSERT INTO items VALUES(NULL,'Roof 26',222,1629,0,'65d');
+INSERT INTO items VALUES(NULL,'Roof 5',297,1630,0,'65e');
+INSERT INTO items VALUES(NULL,'Part 2',329,5391,0,'150f');
+INSERT INTO items VALUES(NULL,'Roof 25',222,1628,0,'65c');
+INSERT INTO items VALUES(NULL,'Part 4',360,5389,0,'150d');
+INSERT INTO items VALUES(NULL,'Part 1',329,5390,0,'150e');
+INSERT INTO items VALUES(NULL,'Banner 41 (N/S)',128,5601,0,'15e1');
+INSERT INTO items VALUES(NULL,'Banner 41 (W/E)',128,5600,0,'15e0');
+INSERT INTO items VALUES(NULL,'Banner 42 (N/S)',128,5603,0,'15e3');
+INSERT INTO items VALUES(NULL,'Banner 42 (W/E)',128,5602,0,'15e2');
+INSERT INTO items VALUES(NULL,'Banner 43 (N/S)',128,5605,0,'15e5');
+INSERT INTO items VALUES(NULL,'Banner 43 (W/E)',128,5604,0,'15e4');
+INSERT INTO items VALUES(NULL,'Banner 44 (N/S)',128,5607,0,'15e7');
+INSERT INTO items VALUES(NULL,'Banner 44 (W/E)',128,5606,0,'15e6');
+INSERT INTO items VALUES(NULL,'Banner 45 (N/S)',128,5609,0,'15e9');
+INSERT INTO items VALUES(NULL,'Banner 45 (W/E)',128,5608,0,'15e8');
+INSERT INTO items VALUES(NULL,'Roof 11',231,1469,0,'5bd');
+INSERT INTO items VALUES(NULL,'Roof 12',231,1470,0,'5be');
+INSERT INTO items VALUES(NULL,'Roof 13',231,1471,0,'5bf');
+INSERT INTO items VALUES(NULL,'Roof 8',231,1466,0,'5ba');
+INSERT INTO items VALUES(NULL,'Roof 9',231,1467,0,'5bb');
+INSERT INTO items VALUES(NULL,'Roof 10',231,1468,0,'5bc');
+INSERT INTO items VALUES(NULL,'Cooked Fish 3',19,7710,0,'1e1e');
+INSERT INTO items VALUES(NULL,'Cooked Fish 2',19,7709,0,'1e1d');
+INSERT INTO items VALUES(NULL,'bascinet',214,5132,0,'merkite_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'Sliced Ham',19,7711,0,'1e1f');
+INSERT INTO items VALUES(NULL,'Fish Heads 2',148,7706,0,'1e1a');
+INSERT INTO items VALUES(NULL,'Cooked Fish 1',19,7708,0,'1e1c');
+INSERT INTO items VALUES(NULL,'Fish Heads 3',148,7707,0,'1e1b');
+INSERT INTO items VALUES(NULL,'Roof 2',231,1460,0,'5b4');
+INSERT INTO items VALUES(NULL,'Roof 3',231,1461,0,'5b5');
+INSERT INTO items VALUES(NULL,'Roof 4',231,1462,0,'5b6');
+INSERT INTO items VALUES(NULL,'Roof 5',231,1463,0,'5b7');
+INSERT INTO items VALUES(NULL,'Roof 13',327,1456,0,'5b0');
+INSERT INTO items VALUES(NULL,'Roof 14',327,1457,0,'5b1');
+INSERT INTO items VALUES(NULL,'Roof 15',327,1458,0,'5b2');
+INSERT INTO items VALUES(NULL,'Roof 1',231,1459,0,'5b3');
+INSERT INTO items VALUES(NULL,'Raw Fish 1',148,7701,0,'1e15');
+INSERT INTO items VALUES(NULL,'Stretched Hide 5 (N/S) (1/2)',57,4223,0,'107f');
+INSERT INTO items VALUES(NULL,'Raw Fish 3',148,7703,0,'1e17');
+INSERT INTO items VALUES(NULL,'Raw Fish 2',148,7702,0,'1e16');
+INSERT INTO items VALUES(NULL,'Roof 6',231,1464,0,'5b8');
+INSERT INTO items VALUES(NULL,'Roof 7',231,1465,0,'5b9');
+INSERT INTO items VALUES(NULL,'Potted Cactus 5',134,7699,0,'1e13');
+INSERT INTO items VALUES(NULL,'Potted Cactus 4',134,7698,0,'1e12');
+INSERT INTO items VALUES(NULL,'Bottle of Liquor 4',155,2462,0,'99e');
+INSERT INTO items VALUES(NULL,'Bottle of Liquor 3',155,2461,0,'99d');
+INSERT INTO items VALUES(NULL,'Bottle of Ale 1',155,2463,0,'99f');
+INSERT INTO items VALUES(NULL,'Goblet 1',14,2458,0,'99a');
+INSERT INTO items VALUES(NULL,'Bottle of Liquor 2',155,2460,0,'99c');
+INSERT INTO items VALUES(NULL,'Bottle of Liquor 1',155,2459,0,'99b');
+INSERT INTO items VALUES(NULL,'Floor Spikes (N/S) 2',109,4513,0,'11a1');
+INSERT INTO items VALUES(NULL,'Floor Spikes (N/S) 1',109,4512,0,'11a0');
+INSERT INTO items VALUES(NULL,'Floor Spikes (N/S) 4',109,4515,0,'11a3');
+INSERT INTO items VALUES(NULL,'Floor Spikes (N/S) 3',109,4514,0,'11a2');
+INSERT INTO items VALUES(NULL,'Floor Spikes (N/S) 6',109,4517,0,'11a5');
+INSERT INTO items VALUES(NULL,'Floor Spikes (N/S) 5',109,4516,0,'11a4');
+INSERT INTO items VALUES(NULL,'Gas Trap 12',109,4519,0,'11a7');
+INSERT INTO items VALUES(NULL,'Gas Trap 11',109,4518,0,'11a6');
+INSERT INTO items VALUES(NULL,'Gas Trap 14',109,4521,0,'11a9');
+INSERT INTO items VALUES(NULL,'Gas Trap 13',109,4520,0,'11a8');
+INSERT INTO items VALUES(NULL,'Arch 8',170,703,0,'2bf');
+INSERT INTO items VALUES(NULL,'Arch 7',170,702,0,'2be');
+INSERT INTO items VALUES(NULL,'Arch 6',170,701,0,'2bd');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',169,700,0,'2bc');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',169,699,0,'2bb');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',169,698,0,'2ba');
+INSERT INTO items VALUES(NULL,'Ceramic Mug 1',14,2453,0,'995');
+INSERT INTO items VALUES(NULL,'Pear 1',19,2452,0,'994');
+INSERT INTO items VALUES(NULL,'Ceramic Mug 3',14,2455,0,'997');
+INSERT INTO items VALUES(NULL,'Ceramic Mug 2',14,2454,0,'996');
+INSERT INTO items VALUES(NULL,'Tray (N/S)',14,2449,0,'991');
+INSERT INTO items VALUES(NULL,'Basket 1',65,2448,0,'990');
+INSERT INTO items VALUES(NULL,'Fruit Basket',19,2451,0,'993');
+INSERT INTO items VALUES(NULL,'Tray (W/E)',14,2450,0,'992');
+INSERT INTO items VALUES(NULL,'nose helmet',25,5134,0,'valorite_helmets_nose');
+INSERT INTO items VALUES(NULL,'Mug 2',14,2457,0,'999');
+INSERT INTO items VALUES(NULL,'Mug 1',14,2456,0,'998');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',169,697,0,'2b9');
+INSERT INTO items VALUES(NULL,'Tiny Wall 6',170,696,0,'2b8');
+INSERT INTO items VALUES(NULL,'Tiny Wall 5',170,695,0,'2b7');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',170,694,0,'2b6');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',170,693,0,'2b5');
+INSERT INTO items VALUES(NULL,'Arch 5',170,692,0,'2b4');
+INSERT INTO items VALUES(NULL,'Arch 4',170,691,0,'2b3');
+INSERT INTO items VALUES(NULL,'Arch 3',170,690,0,'2b2');
+INSERT INTO items VALUES(NULL,'Arch 2',170,689,0,'2b1');
+INSERT INTO items VALUES(NULL,'Arch 1',170,688,0,'2b0');
+INSERT INTO items VALUES(NULL,'Gas Trap 15',109,4522,0,'11aa');
+INSERT INTO items VALUES(NULL,'Floor Saw (W/E) 1',109,4524,0,'11ac');
+INSERT INTO items VALUES(NULL,'Gas Trap 16',109,4523,0,'11ab');
+INSERT INTO items VALUES(NULL,'Floor Saw (W/E) 3',109,4526,0,'11ae');
+INSERT INTO items VALUES(NULL,'Floor Saw (W/E) 2',109,4525,0,'11ad');
+INSERT INTO items VALUES(NULL,'Floor Saw (W/E) 4',109,4527,0,'11af');
+INSERT INTO items VALUES(NULL,'Music Sheet 1',320,3773,0,'ebd');
+INSERT INTO items VALUES(NULL,'Music Sheet 2',320,3774,0,'ebe');
+INSERT INTO items VALUES(NULL,'Music Sheet 3',320,3775,0,'ebf');
+INSERT INTO items VALUES(NULL,'Music Stand 6',320,3770,0,'eba');
+INSERT INTO items VALUES(NULL,'Music Stand 7',320,3771,0,'ebb');
+INSERT INTO items VALUES(NULL,'Music Stand 8',320,3772,0,'ebc');
+INSERT INTO items VALUES(NULL,'Barrel Hoops 1',107,4321,0,'10e1');
+INSERT INTO items VALUES(NULL,'Barrel Hoops 2',107,4322,0,'10e2');
+INSERT INTO items VALUES(NULL,'Dough Bowl',114,4323,0,'10e3');
+INSERT INTO items VALUES(NULL,'Draw Knife',107,4324,0,'10e4');
+INSERT INTO items VALUES(NULL,'Froe',107,4325,0,'10e5');
+INSERT INTO items VALUES(NULL,'Inshave',107,4326,0,'10e6');
+INSERT INTO items VALUES(NULL,'Scorp',107,4327,0,'10e7');
+INSERT INTO items VALUES(NULL,'Small Wooden Spoon',14,4328,0,'10e8');
+INSERT INTO items VALUES(NULL,'Large Wooden Spoon',14,4329,0,'10e9');
+INSERT INTO items VALUES(NULL,'Batwing',112,3960,0,'f78');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 17',121,2010,0,'7da');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 18',121,2015,0,'7df');
+INSERT INTO items VALUES(NULL,'nose helmet',214,5134,0,'merkite_helmets_nose');
+INSERT INTO items VALUES(NULL,'Garbage 1',338,4334,0,'10ee');
+INSERT INTO items VALUES(NULL,'Garbage 2',338,4335,0,'10ef');
+INSERT INTO items VALUES(NULL,'Lute (W/E)',320,3764,0,'eb4');
+INSERT INTO items VALUES(NULL,'Music Stand 1',320,3765,0,'eb5');
+INSERT INTO items VALUES(NULL,'Music Stand 2',320,3766,0,'eb6');
+INSERT INTO items VALUES(NULL,'Music Stand 3',320,3767,0,'eb7');
+INSERT INTO items VALUES(NULL,'Standing Harp',320,3761,0,'eb1');
+INSERT INTO items VALUES(NULL,'Harp',320,3762,0,'eb2');
+INSERT INTO items VALUES(NULL,'Lute (N/S)',320,3763,0,'eb3');
+INSERT INTO items VALUES(NULL,'Music Stand 4',320,3768,0,'eb8');
+INSERT INTO items VALUES(NULL,'Music Stand 5',320,3769,0,'eb9');
+INSERT INTO items VALUES(NULL,'Dark Wooden Plank 8',295,2000,0,'7d0');
+INSERT INTO items VALUES(NULL,'Stone Rail 1',333,2007,0,'7d7');
+INSERT INTO items VALUES(NULL,'Stone Rail 2',333,2008,0,'7d8');
+INSERT INTO items VALUES(NULL,'Balista 245',76,16352,0,'3fe0');
+INSERT INTO items VALUES(NULL,'Balista 246',76,16353,0,'3fe1');
+INSERT INTO items VALUES(NULL,'Balista 247',76,16354,0,'3fe2');
+INSERT INTO items VALUES(NULL,'Balista 248',76,16355,0,'3fe3');
+INSERT INTO items VALUES(NULL,'Glass of Cider 1',155,8061,0,'1f7d');
+INSERT INTO items VALUES(NULL,'Glass of Cider 3',155,8063,0,'1f7f');
+INSERT INTO items VALUES(NULL,'Armourer (N/S)',230,3007,0,'bbf');
+INSERT INTO items VALUES(NULL,'Fletcher (W/E)',230,3006,0,'bbe');
+INSERT INTO items VALUES(NULL,'Fletcher (N/S)',230,3005,0,'bbd');
+INSERT INTO items VALUES(NULL,'Bard (W/E)',230,3004,0,'bbc');
+INSERT INTO items VALUES(NULL,'Bard (N/S)',230,3003,0,'bbb');
+INSERT INTO items VALUES(NULL,'Barber Shop (W/E)',230,3002,0,'bba');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 18',332,1841,0,'731');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 17',332,1840,0,'730');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 20',332,1843,0,'733');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 19',332,1842,0,'732');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 22',332,1845,0,'735');
+INSERT INTO items VALUES(NULL,'Light Wood Stairs 21',332,1844,0,'734');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 4',121,1847,0,'737');
+INSERT INTO items VALUES(NULL,'Stone 3 Stairs 3',121,1846,0,'736');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 2',105,1849,0,'739');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 1',105,1848,0,'738');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 3',105,1850,0,'73a');
+INSERT INTO items VALUES(NULL,'Refuse 23',334,7094,0,'1bb6');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 5',105,1852,0,'73c');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 4',105,1851,0,'73b');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 7',105,1854,0,'73e');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 6',105,1853,0,'73d');
+INSERT INTO items VALUES(NULL,'Refuse 19',334,7089,0,'1bb1');
+INSERT INTO items VALUES(NULL,'Dark Wood Stairs 8',105,1855,0,'73f');
+INSERT INTO items VALUES(NULL,'Refuse 26',334,7097,0,'1bb9');
+INSERT INTO items VALUES(NULL,'Refuse 25',334,7096,0,'1bb8');
+INSERT INTO items VALUES(NULL,'Barber Shop (N/S)',230,3001,0,'bb9');
+INSERT INTO items VALUES(NULL,'Stables (W/E)',230,3000,0,'bb8');
+INSERT INTO items VALUES(NULL,'Stables (N/S)',230,2999,0,'bb7');
+INSERT INTO items VALUES(NULL,'Shipwright (W/E)',230,2998,0,'bb6');
+INSERT INTO items VALUES(NULL,'Shipwright (N/S)',230,2997,0,'bb5');
+INSERT INTO items VALUES(NULL,'Inn (W/E)',230,2996,0,'bb4');
+INSERT INTO items VALUES(NULL,'Inn (N/S)',230,2995,0,'bb3');
+INSERT INTO items VALUES(NULL,'Customs (W/E)',230,2994,0,'bb2');
+INSERT INTO items VALUES(NULL,'Customs (N/S)',230,2993,0,'bb1');
+INSERT INTO items VALUES(NULL,'Woodworker (W/E)',230,2992,0,'bb0');
+INSERT INTO items VALUES(NULL,'Stalagmites 3',378,2276,0,'8e4');
+INSERT INTO items VALUES(NULL,'Stalagmites 4',378,2277,0,'8e5');
+INSERT INTO items VALUES(NULL,'Flowstone 3',378,2278,0,'8e6');
+INSERT INTO items VALUES(NULL,'Stalagmites 5',378,2279,0,'8e7');
+INSERT INTO items VALUES(NULL,'Stalagmites 1',378,2272,0,'8e0');
+INSERT INTO items VALUES(NULL,'Stalagmites 2',378,2273,0,'8e1');
+INSERT INTO items VALUES(NULL,'Flowstone 1',378,2274,0,'8e2');
+INSERT INTO items VALUES(NULL,'Flowstone 2',378,2275,0,'8e3');
+INSERT INTO items VALUES(NULL,'Flowstone 4',378,2280,0,'8e8');
+INSERT INTO items VALUES(NULL,'Stalagmites 6',378,2281,0,'8e9');
+INSERT INTO items VALUES(NULL,'Canvas 5',262,3945,0,'f69');
+INSERT INTO items VALUES(NULL,'Canvas 4',262,3944,0,'f68');
+INSERT INTO items VALUES(NULL,'Block 12',113,4726,0,'1276');
+INSERT INTO items VALUES(NULL,'Canvas 2',262,3942,0,'f66');
+INSERT INTO items VALUES(NULL,'Canvas 1',262,3941,0,'f65');
+INSERT INTO items VALUES(NULL,'Torch (W/E) (Off)',73,3940,0,'f64');
+INSERT INTO items VALUES(NULL,'spear',20,3938,0,'f62');
+INSERT INTO items VALUES(NULL,'longsword',3,3937,0,'f61');
+INSERT INTO items VALUES(NULL,'Stone Rail 4',333,2285,0,'8ed');
+INSERT INTO items VALUES(NULL,'Stone Rail 5',333,2286,0,'8ee');
+INSERT INTO items VALUES(NULL,'Stone Rail 6',333,2287,0,'8ef');
+INSERT INTO items VALUES(NULL,'Waterfall 4',23,13551,0,'34ef');
+INSERT INTO items VALUES(NULL,'Stalagmites 7',378,2282,0,'8ea');
+INSERT INTO items VALUES(NULL,'Stone Rail 2',333,2283,0,'8eb');
+INSERT INTO items VALUES(NULL,'Stone Rail 3',333,2284,0,'8ec');
+INSERT INTO items VALUES(NULL,'Empty Vials',173,3620,0,'e24');
+INSERT INTO items VALUES(NULL,'Hedge (untrimmed) 1',45,3217,0,'c91');
+INSERT INTO items VALUES(NULL,'helmet',275,5130,0,'agapite_helmets_helmet');
+INSERT INTO items VALUES(NULL,'Torch (N/S) (Off)',73,3947,0,'f6b');
+INSERT INTO items VALUES(NULL,'Canvas 6',262,3946,0,'f6a');
+INSERT INTO items VALUES(NULL,'Brimstone',112,3967,0,'f7f');
+INSERT INTO items VALUES(NULL,'Lava 18',37,6765,0,'1a6d');
+INSERT INTO items VALUES(NULL,'Sparkle (blue & gold) 2',28,14186,0,'376a');
+INSERT INTO items VALUES(NULL,'chainmail tunic',342,5055,0,'iron_armor_chain_tunic');
+INSERT INTO items VALUES(NULL,'Fire Snake',28,14068,0,'36f4');
+INSERT INTO items VALUES(NULL,'platemail legs',18,5137,0,'valorite_armor_plate_leggings');
+INSERT INTO items VALUES(NULL,'metal shield',272,7035,0,'agapite_shields_shield');
+INSERT INTO items VALUES(NULL,'Pillory 22',113,4754,0,'1292');
+INSERT INTO items VALUES(NULL,'Lava 15',37,6752,0,'1a60');
+INSERT INTO items VALUES(NULL,'Pillory 23',113,4755,0,'1293');
+INSERT INTO items VALUES(NULL,'Pillory 20',113,4752,0,'1290');
+INSERT INTO items VALUES(NULL,'Pillory 21',113,4753,0,'1291');
+INSERT INTO items VALUES(NULL,'Post',379,4758,0,'1296');
+INSERT INTO items VALUES(NULL,'Road Sign 1',379,4759,0,'1297');
+INSERT INTO items VALUES(NULL,'Pillory 24',113,4756,0,'1294');
+INSERT INTO items VALUES(NULL,'Pillory 25',113,4757,0,'1295');
+INSERT INTO items VALUES(NULL,'Arch 4',326,277,0,'115');
+INSERT INTO items VALUES(NULL,'Arch 3',326,276,0,'114');
+INSERT INTO items VALUES(NULL,'Tiny Wall 1',326,279,0,'117');
+INSERT INTO items VALUES(NULL,'Arch 5',326,278,0,'116');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',260,273,0,'111');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',260,272,0,'110');
+INSERT INTO items VALUES(NULL,'Arch 2',326,275,0,'113');
+INSERT INTO items VALUES(NULL,'Arch 1',326,274,0,'112');
+INSERT INTO items VALUES(NULL,'Tiny Wall 3',326,281,0,'119');
+INSERT INTO items VALUES(NULL,'Tiny Wall 2',326,280,0,'118');
+INSERT INTO items VALUES(NULL,'Lighthouse (20/29)',46,6849,0,'1ac1');
+INSERT INTO items VALUES(NULL,'Lighthouse (22/29)',46,6855,0,'1ac7');
+INSERT INTO items VALUES(NULL,'Lighthouse (21/29)',46,6852,0,'1ac4');
+INSERT INTO items VALUES(NULL,'ringmail leggings',350,5104,0,'copper_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'Column 1',326,286,0,'11e');
+INSERT INTO items VALUES(NULL,'Column 3',260,285,0,'11d');
+INSERT INTO items VALUES(NULL,'Column 2',326,287,0,'11f');
+INSERT INTO items VALUES(NULL,'Tiny Wall 4',326,282,0,'11a');
+INSERT INTO items VALUES(NULL,'Column 2',260,284,0,'11c');
+INSERT INTO items VALUES(NULL,'Column 1',260,283,0,'11b');
+INSERT INTO items VALUES(NULL,'Display Case 3 (N/S) Frame',174,2828,0,'b0c');
+INSERT INTO items VALUES(NULL,'Border 6',179,4912,0,'1330');
+INSERT INTO items VALUES(NULL,'Tiller 1',136,15965,0,'3e5d');
+INSERT INTO items VALUES(NULL,'Display Case 4 (W/E)',174,2830,0,'b0e');
+INSERT INTO items VALUES(NULL,'Display Case 4 (N/S)',174,2829,0,'b0d');
+INSERT INTO items VALUES(NULL,'Gravestone 20',27,4461,0,'116d');
+INSERT INTO items VALUES(NULL,'Gravestone 21',27,4462,0,'116e');
+INSERT INTO items VALUES(NULL,'Spoon (S/N)',14,2499,0,'9c3');
+INSERT INTO items VALUES(NULL,'Spoon (E/W)',14,2498,0,'9c2');
+INSERT INTO items VALUES(NULL,'Lighthouse (25/29)',46,6860,0,'1acc');
+INSERT INTO items VALUES(NULL,'Lighthouse (24/29)',46,6859,0,'1acb');
+INSERT INTO items VALUES(NULL,'Lighthouse (23/29)',46,6858,0,'1aca');
+INSERT INTO items VALUES(NULL,'Sausage (N/S)',19,2497,0,'9c1');
+INSERT INTO items VALUES(NULL,'Lighthouse (27/29)',46,6862,0,'1ace');
+INSERT INTO items VALUES(NULL,'Lighthouse (26/29)',46,6861,0,'1acd');
+INSERT INTO items VALUES(NULL,'Sausage (W/E)',19,2496,0,'9c0');
+INSERT INTO items VALUES(NULL,'Bottle of Wine 1',155,2503,0,'9c7');
+INSERT INTO items VALUES(NULL,'Bottle of Wine 2',155,2502,0,'9c6');
+INSERT INTO items VALUES(NULL,'Stone Bench 2 (N/S)',78,15871,0,'3dff');
+INSERT INTO items VALUES(NULL,'Bottle of Wine 3',155,2501,0,'9c5');
+INSERT INTO items VALUES(NULL,'Water 75',33,13524,0,'34d4');
+INSERT INTO items VALUES(NULL,'Bottle of Wine 4',155,2500,0,'9c4');
+INSERT INTO items VALUES(NULL,'Water 72',33,13521,0,'34d1');
+INSERT INTO items VALUES(NULL,'Lava 3',161,4858,0,'12fa');
+INSERT INTO items VALUES(NULL,'Lava 4',161,4862,0,'12fe');
+INSERT INTO items VALUES(NULL,'Water 74',33,13523,0,'34d3');
+INSERT INTO items VALUES(NULL,'Water 73',33,13522,0,'34d2');
+INSERT INTO items VALUES(NULL,'chainmail coif',280,5051,0,'bronze_armor_chain_coif');
+INSERT INTO items VALUES(NULL,'Road Sign 6',379,4764,0,'129c');
+INSERT INTO items VALUES(NULL,'Stone Fountain (16/16) (Not Animated)',104,5952,0,'1740');
+INSERT INTO items VALUES(NULL,'Stone Fountain (16/16)',104,5953,0,'1741');
+INSERT INTO items VALUES(NULL,'Lava 2',161,4852,0,'12f4');
+INSERT INTO items VALUES(NULL,'Road Sign 4',379,4762,0,'129a');
+INSERT INTO items VALUES(NULL,'Statue 1 (N/S) (2/3)',54,4767,0,'129f');
+INSERT INTO items VALUES(NULL,'Road Sign 7',379,4765,0,'129d');
+INSERT INTO items VALUES(NULL,'bascinet',345,5132,0,'copper_helmets_bascinet');
+INSERT INTO items VALUES(NULL,'plate armor',210,7172,0,'iron_armor_plate_female');
+INSERT INTO items VALUES(NULL,'Axe and Spears (N/S) (1/2)',343,5480,0,'1568');
+INSERT INTO items VALUES(NULL,'Axe and Spears (N/S) (2/2)',343,5481,0,'1569');
+INSERT INTO items VALUES(NULL,'Road Sign 2',379,4760,0,'1298');
+INSERT INTO items VALUES(NULL,'Road Sign 3',379,4761,0,'1299');
+INSERT INTO items VALUES(NULL,'Axe (N/S) 1',343,5472,0,'1560');
+INSERT INTO items VALUES(NULL,'Axe (N/S) 2',343,5473,0,'1561');
+INSERT INTO items VALUES(NULL,'Axe (W/E) 1',343,5474,0,'1562');
+INSERT INTO items VALUES(NULL,'Axe (W/E) 2',343,5475,0,'1563');
+INSERT INTO items VALUES(NULL,'Swords (N/S) (1/2)',343,5476,0,'1564');
+INSERT INTO items VALUES(NULL,'Swords (N/S) (2/2)',343,5477,0,'1565');
+INSERT INTO items VALUES(NULL,'Swords (W/E) (1/2)',343,5478,0,'1566');
+INSERT INTO items VALUES(NULL,'Swords (W/E) (2/2)',343,5479,0,'1567');
+INSERT INTO items VALUES(NULL,'Treasure (14/41)',215,6989,0,'1b4d');
+INSERT INTO items VALUES(NULL,'Rack of Canvases 5',262,3957,0,'f75');
+INSERT INTO items VALUES(NULL,'ringmail leggings',178,5104,0,'shadow_armor_ring_leggings');
+INSERT INTO items VALUES(NULL,'plate helmet',36,5138,0,'bronze_armor_plate_helmet');
+INSERT INTO items VALUES(NULL,'Explosion Ball',28,14078,0,'36fe');
+INSERT INTO items VALUES(NULL,'Road Sign 5',379,4763,0,'129b');
+INSERT INTO items VALUES(NULL,'Axe and Spears (W/E) (1/2)',343,5482,0,'156a');
+INSERT INTO items VALUES(NULL,'Axe and Spears (W/E) (2/2)',343,5483,0,'156b');
+INSERT INTO items VALUES(NULL,'Round Shield (Silver and Gold) (N/S)',99,5484,0,'156c');
+INSERT INTO items VALUES(NULL,'Round Shield (Silver and Gold) (W/E)',99,5485,0,'156d');
+INSERT INTO items VALUES(NULL,'Shield (Silver w. a Star) (N/S)',99,5486,0,'156e');
+INSERT INTO items VALUES(NULL,'Shield (Silver w. a Star) (W/E)',99,5487,0,'156f');
+INSERT INTO items VALUES(NULL,'Road Sign 8',379,4766,0,'129e');
+INSERT INTO items VALUES(NULL,'Tree 2 (2/3)',4,3461,0,'d85');
+INSERT INTO categories VALUES(270,'Cobblestones',380,0);
+INSERT INTO categories VALUES(103,'Fireplaces & Ovens',382,0);
+INSERT INTO categories VALUES(154,'Bone',383,0);
+INSERT INTO categories VALUES(256,'Thieve',384,0);
+INSERT INTO categories VALUES(78,'Chairs',382,0);
+INSERT INTO categories VALUES(267,'Treestump',385,0);
+INSERT INTO categories VALUES(251,'Splash',385,0);
+INSERT INTO categories VALUES(262,'Artist',384,0);
+INSERT INTO categories VALUES(345,'Helmets',387,0);
+INSERT INTO categories VALUES(324,'Serpent Pillar',388,0);
+INSERT INTO categories VALUES(387,'Copper',383,0);
+INSERT INTO categories VALUES(207,'Shields',389,0);
+INSERT INTO categories VALUES(150,'Red Stone Roof',390,0);
+INSERT INTO categories VALUES(378,'Flowstones & Stalagmites',382,0);
+INSERT INTO categories VALUES(159,'Platemail',391,0);
+INSERT INTO categories VALUES(377,'Edging',392,0);
+INSERT INTO categories VALUES(196,'Rudder',393,0);
+INSERT INTO categories VALUES(319,'Marble',394,0);
+INSERT INTO categories VALUES(361,'Honesty (W/E)',395,0);
+INSERT INTO categories VALUES(12,'Bones',396,0);
+INSERT INTO categories VALUES(183,'Shields',397,0);
+INSERT INTO categories VALUES(135,'Butcher',384,0);
+INSERT INTO categories VALUES(141,'Docks',381,0);
+INSERT INTO categories VALUES(203,'Stone Tile Roof',390,0);
+INSERT INTO categories VALUES(395,'Shrines',382,0);
+INSERT INTO categories VALUES(133,'Bamboo Wall',398,0);
+INSERT INTO categories VALUES(386,'Ground Tiles',0,0);
+INSERT INTO categories VALUES(180,'Potions',399,0);
+INSERT INTO categories VALUES(38,'Ringmail',383,0);
+INSERT INTO categories VALUES(327,'Thatch Roof',390,0);
+INSERT INTO categories VALUES(79,'Furniture',382,0);
+INSERT INTO categories VALUES(13,'Stablemaster',384,0);
+INSERT INTO categories VALUES(388,'Misc',0,0);
+INSERT INTO categories VALUES(399,'Equipment',0,0);
+INSERT INTO categories VALUES(127,'Sandstone Wall 2',398,0);
+INSERT INTO categories VALUES(70,'Ankhs',382,0);
+INSERT INTO categories VALUES(376,'Potions',173,0);
+INSERT INTO categories VALUES(63,'Chainmail',400,0);
+INSERT INTO categories VALUES(10,'Tiller Man',393,0);
+INSERT INTO categories VALUES(31,'Small Statues',54,0);
+INSERT INTO categories VALUES(384,'Professions',0,0);
+INSERT INTO categories VALUES(155,'Drinks',399,0);
+INSERT INTO categories VALUES(98,'Round Jungle Wall',398,0);
+INSERT INTO categories VALUES(6,'Cave Wall',398,0);
+INSERT INTO categories VALUES(193,'Deck',393,0);
+INSERT INTO categories VALUES(244,'Humility (W/E)',395,0);
+INSERT INTO categories VALUES(333,'Rail',401,0);
+INSERT INTO categories VALUES(220,'Light & Dark Source',388,0);
+INSERT INTO categories VALUES(104,'Fountains',388,0);
+INSERT INTO categories VALUES(402,'Carpets',382,0);
+INSERT INTO categories VALUES(218,'Carpet - Dark Red',402,0);
+INSERT INTO categories VALUES(343,'Decorative Weapons',382,0);
+INSERT INTO categories VALUES(222,'Beige Stone Roof',390,0);
+INSERT INTO categories VALUES(232,'Portcullis',126,0);
+INSERT INTO categories VALUES(88,'Spar',393,0);
+INSERT INTO categories VALUES(358,'Chaos',395,0);
+INSERT INTO categories VALUES(3,'Swords',403,0);
+INSERT INTO categories VALUES(372,'Rope Ladder',394,0);
+INSERT INTO categories VALUES(282,'Cracks',381,0);
+INSERT INTO categories VALUES(124,'Wooden Gate 1',126,0);
+INSERT INTO categories VALUES(146,'Dirt Patches',386,0);
+INSERT INTO categories VALUES(346,'Iron Fence 1',401,0);
+INSERT INTO categories VALUES(2,'Unfinished Woodwork',107,0);
+INSERT INTO categories VALUES(328,'Decorative Armor',382,0);
+INSERT INTO categories VALUES(219,'Carpet - Blue 3',402,0);
+INSERT INTO categories VALUES(330,'Stone Wall 3',398,0);
+INSERT INTO categories VALUES(359,'Peg Board',382,0);
+INSERT INTO categories VALUES(112,'Reagents',173,0);
+INSERT INTO categories VALUES(231,'Tile Roof',390,0);
+INSERT INTO categories VALUES(22,'Log Wall',398,0);
+INSERT INTO categories VALUES(368,'Honor (W/E)',395,0);
+INSERT INTO categories VALUES(131,'Helmets',400,0);
+INSERT INTO categories VALUES(24,'Helmets',383,0);
+INSERT INTO categories VALUES(134,'Flowers',404,0);
+INSERT INTO categories VALUES(349,'Runes',186,0);
+INSERT INTO categories VALUES(298,'Scaffold',388,0);
+INSERT INTO categories VALUES(205,'Chainmail',387,0);
+INSERT INTO categories VALUES(165,'Blue Floor',380,0);
+INSERT INTO categories VALUES(400,'Shadow',383,0);
+INSERT INTO categories VALUES(228,'Rug - Gray',402,0);
+INSERT INTO categories VALUES(1,'Torso',405,0);
+INSERT INTO categories VALUES(240,'Tinker',384,0);
+INSERT INTO categories VALUES(94,'Scrolls',186,0);
+INSERT INTO categories VALUES(81,'Platemail',400,0);
+INSERT INTO categories VALUES(366,'Flagstones (sandstone)',380,0);
+INSERT INTO categories VALUES(326,'Marble Wall 1',398,0);
+INSERT INTO categories VALUES(170,'Marble Wall 2',398,0);
+INSERT INTO categories VALUES(21,'Bows',403,0);
+INSERT INTO categories VALUES(396,'Dungeon',0,0);
+INSERT INTO categories VALUES(128,'Banners',382,0);
+INSERT INTO categories VALUES(413,'Dull Copper',383,0);
+INSERT INTO categories VALUES(339,'Dungeon',394,0);
+INSERT INTO categories VALUES(118,'Vases',382,0);
+INSERT INTO categories VALUES(123,'With Bar',326,0);
+INSERT INTO categories VALUES(115,'Figurines',388,0);
+INSERT INTO categories VALUES(99,'Decorative Shields',382,0);
+INSERT INTO categories VALUES(252,'Bricks',380,0);
+INSERT INTO categories VALUES(289,'Valor (W/E)',395,0);
+INSERT INTO categories VALUES(117,'Platemail',406,0);
+INSERT INTO categories VALUES(347,'Shields',387,0);
+INSERT INTO categories VALUES(167,'Chainmail',407,0);
+INSERT INTO categories VALUES(95,'Chainmail',406,0);
+INSERT INTO categories VALUES(303,'Spiderwebs',396,0);
+INSERT INTO categories VALUES(208,'Platemail',387,0);
+INSERT INTO categories VALUES(247,'Broken Furniture',382,0);
+INSERT INTO categories VALUES(221,'Brown Stone Roof',390,0);
+INSERT INTO categories VALUES(215,'Treasure',388,0);
+INSERT INTO categories VALUES(213,'Growing',404,0);
+INSERT INTO categories VALUES(382,'Decoration',0,0);
+INSERT INTO categories VALUES(369,'Spirituality (N/S)',395,0);
+INSERT INTO categories VALUES(37,'Misc',408,0);
+INSERT INTO categories VALUES(149,'Wooden Wall 2',398,0);
+INSERT INTO categories VALUES(158,'Wooden Wall 1',398,0);
+INSERT INTO categories VALUES(54,'Statues',382,0);
+INSERT INTO categories VALUES(401,'Fences',381,0);
+INSERT INTO categories VALUES(125,'Ringmail',406,0);
+INSERT INTO categories VALUES(334,'Refuse',386,0);
+INSERT INTO categories VALUES(201,'Orc Camp Decoration',388,0);
+INSERT INTO categories VALUES(236,'Swamp',386,0);
+INSERT INTO categories VALUES(76,'Balista',388,0);
+INSERT INTO categories VALUES(57,'Tailorer',384,0);
+INSERT INTO categories VALUES(175,'Barber',384,0);
+INSERT INTO categories VALUES(391,'Agapite',383,0);
+INSERT INTO categories VALUES(96,'Tent - Green',398,0);
+INSERT INTO categories VALUES(192,'Stern',393,0);
+INSERT INTO categories VALUES(237,'Border',236,0);
+INSERT INTO categories VALUES(48,'Chainmail',383,0);
+INSERT INTO categories VALUES(278,'Helmets',389,0);
+INSERT INTO categories VALUES(151,'Altar',396,0);
+INSERT INTO categories VALUES(261,'Glowing Runes',382,0);
+INSERT INTO categories VALUES(322,'Edges',323,0);
+INSERT INTO categories VALUES(116,'Coffins',396,0);
+INSERT INTO categories VALUES(30,'Blacksmith',384,0);
+INSERT INTO categories VALUES(34,'Fletcher',384,0);
+INSERT INTO categories VALUES(45,'Plants',404,0);
+INSERT INTO categories VALUES(357,'Misc',386,0);
+INSERT INTO categories VALUES(367,'Honor (N/S)',395,0);
+INSERT INTO categories VALUES(173,'Alchemist',384,0);
+INSERT INTO categories VALUES(119,'Staves',403,0);
+INSERT INTO categories VALUES(383,'Armor',0,0);
+INSERT INTO categories VALUES(186,'Mage',384,0);
+INSERT INTO categories VALUES(273,'Mushrooms',404,0);
+INSERT INTO categories VALUES(394,'Stairs',381,0);
+INSERT INTO categories VALUES(277,'Fancy',316,0);
+INSERT INTO categories VALUES(351,'Rug - Green',402,0);
+INSERT INTO categories VALUES(385,'Misc',236,0);
+INSERT INTO categories VALUES(211,'With Bar',170,0);
+INSERT INTO categories VALUES(266,'Shields',407,0);
+INSERT INTO categories VALUES(404,'Vegetation',0,0);
+INSERT INTO categories VALUES(56,'Ringmail',397,0);
+INSERT INTO categories VALUES(280,'Chainmail',409,0);
+INSERT INTO categories VALUES(80,'Miner',384,0);
+INSERT INTO categories VALUES(271,'Marble Floor 2',380,0);
+INSERT INTO categories VALUES(164,'Marble Floor 1',380,0);
+INSERT INTO categories VALUES(296,'Wooden Fence 5',401,0);
+INSERT INTO categories VALUES(190,'Wooden Fence 4',401,0);
+INSERT INTO categories VALUES(353,'Wooden Fence 3',401,0);
+INSERT INTO categories VALUES(122,'Wooden Fence 2',401,0);
+INSERT INTO categories VALUES(234,'Wooden Fence 1',401,0);
+INSERT INTO categories VALUES(106,'Cave',394,0);
+INSERT INTO categories VALUES(26,'Suspension Bridge',381,0);
+INSERT INTO categories VALUES(194,'Chainmail',391,0);
+INSERT INTO categories VALUES(187,'Platemail',397,0);
+INSERT INTO categories VALUES(313,'Stars',386,0);
+INSERT INTO categories VALUES(179,'Border',408,0);
+INSERT INTO categories VALUES(43,'Ringmail',407,0);
+INSERT INTO categories VALUES(75,'Switches & Levers',388,0);
+INSERT INTO categories VALUES(89,'Tables',382,0);
+INSERT INTO categories VALUES(102,'Carpeted Rostrum',394,0);
+INSERT INTO categories VALUES(144,'Carpet - Red',402,0);
+INSERT INTO categories VALUES(198,'Wooden Ramp',394,0);
+INSERT INTO categories VALUES(5,'Maces',403,0);
+INSERT INTO categories VALUES(365,'Archery Butte',388,0);
+INSERT INTO categories VALUES(304,'Paintings & Tapestry',382,0);
+INSERT INTO categories VALUES(212,'Wooden Boards',380,0);
+INSERT INTO categories VALUES(29,'Rocks',410,0);
+INSERT INTO categories VALUES(317,'Tent - Light Blue',398,0);
+INSERT INTO categories VALUES(226,'Hammock & Cot',382,0);
+INSERT INTO categories VALUES(342,'Chainmail',389,0);
+INSERT INTO categories VALUES(312,'Birds Nest',388,0);
+INSERT INTO categories VALUES(20,'Fencing',403,0);
+INSERT INTO categories VALUES(405,'Clothes',0,0);
+INSERT INTO categories VALUES(255,'Ringmail',389,0);
+INSERT INTO categories VALUES(279,'Bar',382,0);
+INSERT INTO categories VALUES(362,'Compassion (W/E)',395,0);
+INSERT INTO categories VALUES(284,'Chainmail',411,0);
+INSERT INTO categories VALUES(389,'Iron',383,0);
+INSERT INTO categories VALUES(243,'Humility (N/S)',395,0);
+INSERT INTO categories VALUES(229,'Guild Signs',412,0);
+INSERT INTO categories VALUES(101,'Platform',394,0);
+INSERT INTO categories VALUES(74,'Splash',410,0);
+INSERT INTO categories VALUES(293,'Gipsy',384,0);
+INSERT INTO categories VALUES(105,'Dark Wood',394,0);
+INSERT INTO categories VALUES(18,'Platemail',407,0);
+INSERT INTO categories VALUES(249,'Barkeeper',384,0);
+INSERT INTO categories VALUES(86,'Sail',393,0);
+INSERT INTO categories VALUES(174,'Display Case',382,0);
+INSERT INTO categories VALUES(97,'Helmets',411,0);
+INSERT INTO categories VALUES(23,'Waterfall',410,0);
+INSERT INTO categories VALUES(130,'Hide Wall',398,0);
+INSERT INTO categories VALUES(254,'Leather',383,0);
+INSERT INTO categories VALUES(412,'Signs',0,0);
+INSERT INTO categories VALUES(375,'Pentagram',396,0);
+INSERT INTO categories VALUES(172,'Quest Items',388,0);
+INSERT INTO categories VALUES(129,'Wooden Planks',380,0);
+INSERT INTO categories VALUES(137,'Ship',393,0);
+INSERT INTO categories VALUES(188,'Tent - Blue',398,0);
+INSERT INTO categories VALUES(281,'Wooden Shingle',390,0);
+INSERT INTO categories VALUES(363,'Honesty (N/S)',395,0);
+INSERT INTO categories VALUES(398,'Walls',381,0);
+INSERT INTO categories VALUES(195,'Beards',399,0);
+INSERT INTO categories VALUES(39,'Ringmail',413,0);
+INSERT INTO categories VALUES(16,'Shields',411,0);
+INSERT INTO categories VALUES(332,'Light Wood',394,0);
+INSERT INTO categories VALUES(242,'Vat',388,0);
+INSERT INTO categories VALUES(224,'Beekeper',384,0);
+INSERT INTO categories VALUES(60,'Accessories',405,0);
+INSERT INTO categories VALUES(47,'Sandstone Wall 1',398,0);
+INSERT INTO categories VALUES(161,'Lava',408,0);
+INSERT INTO categories VALUES(355,'Fruit Trees',404,0);
+INSERT INTO categories VALUES(46,'Lighthouse',388,0);
+INSERT INTO categories VALUES(17,'Platemail',383,0);
+INSERT INTO categories VALUES(380,'Floors',381,0);
+INSERT INTO categories VALUES(350,'Ringmail',387,0);
+INSERT INTO categories VALUES(390,'Roofs',381,0);
+INSERT INTO categories VALUES(69,'Shields',406,0);
+INSERT INTO categories VALUES(67,'Cannon',388,0);
+INSERT INTO categories VALUES(352,'Campfire',382,0);
+INSERT INTO categories VALUES(411,'Verite',383,0);
+INSERT INTO categories VALUES(8,'Mast',393,0);
+INSERT INTO categories VALUES(42,'Ringmail',409,0);
+INSERT INTO categories VALUES(32,'Green Tent Roof',390,0);
+INSERT INTO categories VALUES(184,'Brick Wall',398,0);
+INSERT INTO categories VALUES(52,'Blob',37,0);
+INSERT INTO categories VALUES(287,'Justice (W/E)',395,0);
+INSERT INTO categories VALUES(335,'Blank Signs',412,0);
+INSERT INTO categories VALUES(109,'Traps',396,0);
+INSERT INTO categories VALUES(238,'Dungeon Wall',398,0);
+INSERT INTO categories VALUES(49,'Hair',399,0);
+INSERT INTO categories VALUES(27,'Graveyard',396,0);
+INSERT INTO categories VALUES(253,'Dark Sandstone Floor',380,0);
+INSERT INTO categories VALUES(92,'Spellicons',388,0);
+INSERT INTO categories VALUES(25,'Helmets',407,0);
+INSERT INTO categories VALUES(142,'Marble Roof 2',390,0);
+INSERT INTO categories VALUES(406,'Golden',383,0);
+INSERT INTO categories VALUES(7,'Ruined Stone Wall',398,0);
+INSERT INTO categories VALUES(153,'Marble Roof 1',390,0);
+INSERT INTO categories VALUES(202,'Dirt',386,0);
+INSERT INTO categories VALUES(290,'Valor (N/S)',395,0);
+INSERT INTO categories VALUES(309,'Border',314,0);
+INSERT INTO categories VALUES(337,'Bearskin Rug',402,0);
+INSERT INTO categories VALUES(283,'Comm. Crystals',388,0);
+INSERT INTO categories VALUES(371,'Wooden Ladder',394,0);
+INSERT INTO categories VALUES(40,'Helmets',409,0);
+INSERT INTO categories VALUES(265,'Dried Vegetation',404,0);
+INSERT INTO categories VALUES(93,'Sandstone Floor',380,0);
+INSERT INTO categories VALUES(258,'Mapmaker',384,0);
+INSERT INTO categories VALUES(329,'Sacrifice (N/S)',395,0);
+INSERT INTO categories VALUES(28,'Animations',0,0);
+INSERT INTO categories VALUES(35,'Axes',403,0);
+INSERT INTO categories VALUES(87,'Gang Plank',393,0);
+INSERT INTO categories VALUES(148,'Fisher',384,0);
+INSERT INTO categories VALUES(320,'Musician',384,0);
+INSERT INTO categories VALUES(276,'Ruined Sandstone Wall',398,0);
+INSERT INTO categories VALUES(66,'Fancy',47,0);
+INSERT INTO categories VALUES(41,'Wrecked',316,0);
+INSERT INTO categories VALUES(111,'Chainmail',413,0);
+INSERT INTO categories VALUES(72,'Catapult',388,0);
+INSERT INTO categories VALUES(318,'Hanging Pole',382,0);
+INSERT INTO categories VALUES(4,'Trees',404,0);
+INSERT INTO categories VALUES(285,'Fruits',404,0);
+INSERT INTO categories VALUES(230,'Vendor Signs',412,0);
+INSERT INTO categories VALUES(292,'Sandstone 2',394,0);
+INSERT INTO categories VALUES(302,'Sandstone 1',394,0);
+INSERT INTO categories VALUES(250,'Metal Door 2',126,0);
+INSERT INTO categories VALUES(336,'Metal Door 1',126,0);
+INSERT INTO categories VALUES(260,'Fancy',326,0);
+INSERT INTO categories VALUES(197,'Wooden Rail',392,0);
+INSERT INTO categories VALUES(321,'Chimneys',382,0);
+INSERT INTO categories VALUES(189,'Stone Wall 1',398,0);
+INSERT INTO categories VALUES(245,'Special',405,0);
+INSERT INTO categories VALUES(140,'Stone Wall 2',398,0);
+INSERT INTO categories VALUES(132,'Stone Wall 5',398,0);
+INSERT INTO categories VALUES(223,'Stone Wall 4',398,0);
+INSERT INTO categories VALUES(136,'Tiller',393,0);
+INSERT INTO categories VALUES(315,'Legs',405,0);
+INSERT INTO categories VALUES(77,'Shields',409,0);
+INSERT INTO categories VALUES(272,'Shields',391,0);
+INSERT INTO categories VALUES(263,'Books',399,0);
+INSERT INTO categories VALUES(11,'Wood',404,0);
+INSERT INTO categories VALUES(360,'Sacrifice (W/E)',395,0);
+INSERT INTO categories VALUES(36,'Platemail',409,0);
+INSERT INTO categories VALUES(331,'Plant Growing',388,0);
+INSERT INTO categories VALUES(181,'Platemail',411,0);
+INSERT INTO categories VALUES(61,'Rattan Door',126,0);
+INSERT INTO categories VALUES(90,'Footwear',405,0);
+INSERT INTO categories VALUES(316,'Plaster Wall 1',398,0);
+INSERT INTO categories VALUES(379,'Road Signs',412,0);
+INSERT INTO categories VALUES(50,'Plaster Wall 2',398,0);
+INSERT INTO categories VALUES(156,'Rattan Wall',398,0);
+INSERT INTO categories VALUES(323,'Snow',386,0);
+INSERT INTO categories VALUES(51,'Keys',388,0);
+INSERT INTO categories VALUES(58,'Headwear',405,0);
+INSERT INTO categories VALUES(370,'Log Roof',390,0);
+INSERT INTO categories VALUES(248,'Wooden Door 3',126,0);
+INSERT INTO categories VALUES(204,'Wooden Door 2',126,0);
+INSERT INTO categories VALUES(206,'Wooden Door 1',126,0);
+INSERT INTO categories VALUES(91,'Bedroom',382,0);
+INSERT INTO categories VALUES(233,'Wooden Door 4',126,0);
+INSERT INTO categories VALUES(397,'Merkite',383,0);
+INSERT INTO categories VALUES(407,'valorite',383,0);
+INSERT INTO categories VALUES(275,'Helmets',391,0);
+INSERT INTO categories VALUES(64,'Helmets',406,0);
+INSERT INTO categories VALUES(145,'Stone Step',394,0);
+INSERT INTO categories VALUES(310,'Ringmail',411,0);
+INSERT INTO categories VALUES(381,'Buildings',0,0);
+INSERT INTO categories VALUES(227,'Slate Roof 1',390,0);
+INSERT INTO categories VALUES(209,'Slate Roof 2',390,0);
+INSERT INTO categories VALUES(108,'Teleporter',388,0);
+INSERT INTO categories VALUES(9,'Prow',393,0);
+INSERT INTO categories VALUES(274,'Healer',384,0);
+INSERT INTO categories VALUES(166,'Sandstone Paver',380,0);
+INSERT INTO categories VALUES(214,'Helmets',397,0);
+INSERT INTO categories VALUES(301,'Stone 1',394,0);
+INSERT INTO categories VALUES(110,'Stone 2',394,0);
+INSERT INTO categories VALUES(121,'Stone 3',394,0);
+INSERT INTO categories VALUES(85,'Patterned',47,0);
+INSERT INTO categories VALUES(200,'Moongates',388,0);
+INSERT INTO categories VALUES(259,'Helmets',413,0);
+INSERT INTO categories VALUES(374,'Edges',344,0);
+INSERT INTO categories VALUES(53,'Wall Carvings',382,0);
+INSERT INTO categories VALUES(160,'Trophies',382,0);
+INSERT INTO categories VALUES(126,'Doors',381,0);
+INSERT INTO categories VALUES(55,'Blood',396,0);
+INSERT INTO categories VALUES(73,'Lightsources',382,0);
+INSERT INTO categories VALUES(162,'Flagstones (gray)',380,0);
+INSERT INTO categories VALUES(307,'Wooden Banister',392,0);
+INSERT INTO categories VALUES(291,'Spirituality (W/E)',395,0);
+INSERT INTO categories VALUES(373,'Rattan Ladder',394,0);
+INSERT INTO categories VALUES(294,'Misc',399,0);
+INSERT INTO categories VALUES(83,'Shields',413,0);
+INSERT INTO categories VALUES(409,'Bronze',383,0);
+INSERT INTO categories VALUES(341,'Training Dummy',388,0);
+INSERT INTO categories VALUES(168,'Grey Slate Floor',380,0);
+INSERT INTO categories VALUES(403,'Weapons',0,0);
+INSERT INTO categories VALUES(354,'Shields',400,0);
+INSERT INTO categories VALUES(171,'Blood Pentagramm',396,0);
+INSERT INTO categories VALUES(356,'Wooden Logs',380,0);
+INSERT INTO categories VALUES(62,'Waves',33,0);
+INSERT INTO categories VALUES(410,'Misc',33,0);
+INSERT INTO categories VALUES(340,'Sign Posts',412,0);
+INSERT INTO categories VALUES(344,'Grass',386,0);
+INSERT INTO categories VALUES(264,'Palms',404,0);
+INSERT INTO categories VALUES(147,'Bodies and Body Parts',396,0);
+INSERT INTO categories VALUES(191,'Wooden Gate 2',126,0);
+INSERT INTO categories VALUES(169,'Fancy',170,0);
+INSERT INTO categories VALUES(68,'Polar Bearskin Rug',402,0);
+INSERT INTO categories VALUES(308,'Jeweler',384,0);
+INSERT INTO categories VALUES(286,'Chainmail',397,0);
+INSERT INTO categories VALUES(182,'Telescope',388,0);
+INSERT INTO categories VALUES(338,'Cook',384,0);
+INSERT INTO categories VALUES(299,'Dungeon Ramp',394,0);
+INSERT INTO categories VALUES(325,'Rope',388,0);
+INSERT INTO categories VALUES(114,'Baker',384,0);
+INSERT INTO categories VALUES(100,'Sarcophagus',396,0);
+INSERT INTO categories VALUES(82,'Palisade Wall',398,0);
+INSERT INTO categories VALUES(15,'Shields',383,0);
+INSERT INTO categories VALUES(288,'Justice (N/S)',395,0);
+INSERT INTO categories VALUES(246,'Unlabeled',386,0);
+INSERT INTO categories VALUES(268,'Stone Paver',380,0);
+INSERT INTO categories VALUES(33,'Water',386,0);
+INSERT INTO categories VALUES(59,'Barred Metal Door 1',126,0);
+INSERT INTO categories VALUES(84,'Palm Frond Roof',390,0);
+INSERT INTO categories VALUES(216,'Rocks',0,0);
+INSERT INTO categories VALUES(65,'Containers',399,0);
+INSERT INTO categories VALUES(143,'Carpet - Blue 1',402,0);
+INSERT INTO categories VALUES(364,'Compassion (N/S)',395,0);
+INSERT INTO categories VALUES(306,'Carpet - Blue 2',402,0);
+INSERT INTO categories VALUES(348,'Iron Fence 2',401,0);
+INSERT INTO categories VALUES(138,'Hold',393,0);
+INSERT INTO categories VALUES(408,'Lava',386,0);
+INSERT INTO categories VALUES(210,'Platemail',389,0);
+INSERT INTO categories VALUES(199,'Carpet - Gray',402,0);
+INSERT INTO categories VALUES(314,'Not animated',33,0);
+INSERT INTO categories VALUES(163,'Red Floor',380,0);
+INSERT INTO categories VALUES(152,'Blue Tent Roof',390,0);
+INSERT INTO categories VALUES(269,'Platemail',413,0);
+INSERT INTO categories VALUES(107,'Carpenter',384,0);
+INSERT INTO categories VALUES(120,'Iron Gate 1',126,0);
+INSERT INTO categories VALUES(157,'Iron Gate 2',126,0);
+INSERT INTO categories VALUES(311,'Shells',382,0);
+INSERT INTO categories VALUES(393,'Boat Parts',0,0);
+INSERT INTO categories VALUES(44,'Border',300,0);
+INSERT INTO categories VALUES(185,'Mats & Furs',382,0);
+INSERT INTO categories VALUES(113,'Torture',396,0);
+INSERT INTO categories VALUES(295,'Dark Wooden Planks',380,0);
+INSERT INTO categories VALUES(297,'Gray Tent Roof',390,0);
+INSERT INTO categories VALUES(71,'Message Boards',388,0);
+INSERT INTO categories VALUES(300,'Not animated',408,0);
+INSERT INTO categories VALUES(239,'Cave Floor',380,0);
+INSERT INTO categories VALUES(178,'Ringmail',400,0);
+INSERT INTO categories VALUES(177,'Wands',186,0);
+INSERT INTO categories VALUES(257,'Peasant',384,0);
+INSERT INTO categories VALUES(14,'Kitchen',382,0);
+INSERT INTO categories VALUES(225,'Bookcases',382,0);
+INSERT INTO categories VALUES(139,'Hatch',393,0);
+INSERT INTO categories VALUES(241,'Tent - Light Gray',398,0);
+INSERT INTO categories VALUES(305,'Coins',399,0);
+INSERT INTO categories VALUES(392,'Banisters',381,0);
+INSERT INTO categories VALUES(19,'Food',399,0);
+INSERT INTO categories VALUES(176,'Rug - Brown',402,0);
+INSERT INTO categories VALUES(217,'Carpet - Brown',402,0);
+INSERT INTO categories VALUES(235,'Ringmail',391,0);
Added: trunk/WPGM/map0.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/map0.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/map1.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/map1.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/map2.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/map2.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/map3.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/map3.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/map4.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/map4.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/options.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/options.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/search.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/search.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/sqlite.dll
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/sqlite.dll
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/sqlite.exe
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/sqlite.exe
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/table.sql
===================================================================
--- trunk/WPGM/table.sql 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/table.sql 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,34 @@
+
+CREATE TABLE categories (
+ id INTEGER PRIMARY KEY,
+ name varchar(255) NULL,
+ parent int NOT NULL,
+ type int
+);
+
+CREATE TABLE items (
+ id INTEGER PRIMARY KEY,
+ name varchar(255) NULL,
+ parent int NOT NULL,
+ artid int,
+ color int,
+ addid varchar(255)
+);
+
+CREATE TABLE locationcategories (
+ id INTEGER PRIMARY KEY,
+ name varchar(255) NULL,
+ parent int NOT NULL,
+ type int
+);
+
+CREATE TABLE locations (
+ id INTEGER PRIMARY KEY,
+ name varchar(255) NULL,
+ parent INT NOT NULL,
+ posx INT NOT NULL,
+ posy INT NOT NULL,
+ posz INT NOT NULL,
+ posmap INT NOT NULL,
+ location varchar(255)
+);
\ No newline at end of file
Added: trunk/WPGM/test.bmp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/test.bmp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/uCenter.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/uCenter.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/uCenter.dfm
===================================================================
--- trunk/WPGM/uCenter.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uCenter.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,71 @@
+object frmCenter: TfrmCenter
+ Left = 536
+ Top = 411
+ BorderStyle = bsToolWindow
+ Caption = 'Center Map'
+ ClientHeight = 101
+ ClientWidth = 140
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Label1: TLabel
+ Left = 66
+ Top = 42
+ Width = 6
+ Height = 20
+ Caption = ','
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -16
+ Font.Name = 'MS Sans Serif'
+ Font.Style = [fsBold]
+ ParentFont = False
+ end
+ object Button1: TButton
+ Left = 8
+ Top = 70
+ Width = 75
+ Height = 22
+ Caption = '&Center'
+ TabOrder = 0
+ OnClick = Button1Click
+ end
+ object Map: TComboBox
+ Left = 8
+ Top = 8
+ Width = 121
+ Height = 21
+ Style = csDropDownList
+ ItemHeight = 13
+ ItemIndex = 0
+ TabOrder = 1
+ Text = 'Felucca'
+ Items.Strings = (
+ 'Felucca'
+ 'Trammel'
+ 'Ilshenar'
+ 'Malas')
+ end
+ object X: TEdit
+ Left = 8
+ Top = 40
+ Width = 57
+ Height = 21
+ TabOrder = 2
+ Text = 'X'
+ end
+ object Y: TEdit
+ Left = 72
+ Top = 40
+ Width = 57
+ Height = 21
+ TabOrder = 3
+ Text = 'Y'
+ end
+end
Added: trunk/WPGM/uCenter.pas
===================================================================
--- trunk/WPGM/uCenter.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uCenter.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,40 @@
+unit uCenter;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls;
+
+type
+ TfrmCenter = class(TForm)
+ Button1: TButton;
+ Map: TComboBox;
+ X: TEdit;
+ Y: TEdit;
+ Label1: TLabel;
+ procedure Button1Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ frmCenter: TfrmCenter;
+
+implementation
+
+uses Main;
+
+{$R *.dfm}
+
+procedure TfrmCenter.Button1Click(Sender: TObject);
+begin
+ MapCenterX := StrToIntDef(X.Text, MapCenterX);
+ MapCenterY := StrToIntDef(Y.Text, MapCenterY);
+ MapCenterMap := Map.ItemIndex;
+ frmMain.pbMap.Invalidate;
+end;
+
+end.
Added: trunk/WPGM/uCenter.~dfm
===================================================================
--- trunk/WPGM/uCenter.~dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uCenter.~dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,71 @@
+object frmCenter: TfrmCenter
+ Left = 536
+ Top = 411
+ BorderStyle = bsToolWindow
+ Caption = 'Center Map'
+ ClientHeight = 101
+ ClientWidth = 140
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Label1: TLabel
+ Left = 66
+ Top = 42
+ Width = 6
+ Height = 20
+ Caption = ','
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -16
+ Font.Name = 'MS Sans Serif'
+ Font.Style = [fsBold]
+ ParentFont = False
+ end
+ object Button1: TButton
+ Left = 8
+ Top = 70
+ Width = 75
+ Height = 22
+ Caption = '&Center'
+ TabOrder = 0
+ OnClick = Button1Click
+ end
+ object Map: TComboBox
+ Left = 8
+ Top = 8
+ Width = 121
+ Height = 21
+ Style = csDropDownList
+ ItemHeight = 13
+ ItemIndex = 0
+ TabOrder = 1
+ Text = 'Felucca'
+ Items.Strings = (
+ 'Felucca'
+ 'Trammel'
+ 'Ilshenar'
+ 'Malas')
+ end
+ object X: TEdit
+ Left = 8
+ Top = 40
+ Width = 57
+ Height = 21
+ TabOrder = 2
+ Text = 'X'
+ end
+ object Y: TEdit
+ Left = 72
+ Top = 40
+ Width = 57
+ Height = 21
+ TabOrder = 3
+ Text = 'Y'
+ end
+end
Added: trunk/WPGM/uCenter.~pas
===================================================================
--- trunk/WPGM/uCenter.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uCenter.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,39 @@
+unit uCenter;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls;
+
+type
+ TfrmCenter = class(TForm)
+ Button1: TButton;
+ Map: TComboBox;
+ X: TEdit;
+ Y: TEdit;
+ Label1: TLabel;
+ procedure Button1Click(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ frmCenter: TfrmCenter;
+
+implementation
+
+uses Main;
+
+{$R *.dfm}
+
+procedure TfrmCenter.Button1Click(Sender: TObject);
+begin
+ MapCenterX := StrToIntDef(X.Text, MapCenterX);
+ MapCenterY := StrToIntDef(Y.Text, MapCenterY);
+
+end;
+
+end.
Added: trunk/WPGM/uChooseHue.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/uChooseHue.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/uChooseHue.ddp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/uChooseHue.ddp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/uChooseHue.dfm
===================================================================
--- trunk/WPGM/uChooseHue.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uChooseHue.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,79 @@
+object frmChooseHue: TfrmChooseHue
+ Left = 364
+ Top = 284
+ BorderStyle = bsDialog
+ Caption = 'Chose Hue'
+ ClientHeight = 394
+ ClientWidth = 404
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ OnShow = FormShow
+ PixelsPerInch = 96
+ TextHeight = 13
+ object lblId: TLabel
+ Left = 8
+ Top = 336
+ Width = 12
+ Height = 13
+ Caption = 'Id:'
+ end
+ object lblName: TLabel
+ Left = 80
+ Top = 336
+ Width = 31
+ Height = 13
+ Caption = 'Name:'
+ end
+ object pbHueSelection: TPaintBox32
+ Left = 8
+ Top = 8
+ Width = 384
+ Height = 320
+ TabOrder = 0
+ OnMouseDown = pbHueSelectionMouseDown
+ OnPaintBuffer = pbHueSelectionPaintBuffer
+ end
+ object btnOk: TButton
+ Left = 8
+ Top = 360
+ Width = 75
+ Height = 25
+ Caption = 'Ok'
+ ModalResult = 1
+ TabOrder = 1
+ end
+ object btnCancel: TButton
+ Left = 88
+ Top = 360
+ Width = 75
+ Height = 25
+ Caption = 'Cancel'
+ ModalResult = 2
+ TabOrder = 2
+ end
+ object tbHue: TTrackBar
+ Left = 169
+ Top = 360
+ Width = 224
+ Height = 25
+ Max = 31
+ Frequency = 2
+ Position = 31
+ TabOrder = 3
+ OnChange = tbHueChange
+ end
+ object pbHuePreview: TPaintBox32
+ Left = 264
+ Top = 333
+ Width = 128
+ Height = 18
+ TabOrder = 4
+ OnPaintBuffer = pbHuePreviewPaintBuffer
+ end
+end
Added: trunk/WPGM/uChooseHue.pas
===================================================================
--- trunk/WPGM/uChooseHue.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uChooseHue.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,120 @@
+unit uChooseHue;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, GR32_Image, ComCtrls;
+
+type
+ TfrmChooseHue = class(TForm)
+ pbHueSelection: TPaintBox32;
+ btnOk: TButton;
+ btnCancel: TButton;
+ tbHue: TTrackBar;
+ lblId: TLabel;
+ lblName: TLabel;
+ pbHuePreview: TPaintBox32;
+ procedure pbHueSelectionPaintBuffer(Sender: TObject);
+ procedure tbHueChange(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure pbHueSelectionMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure pbHuePreviewPaintBuffer(Sender: TObject);
+ procedure FormShow(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ ColorId: Word;
+ end;
+
+var
+ frmChooseHue: TfrmChooseHue;
+
+implementation
+
+uses Main, GR32, Math;
+
+{$R *.dfm}
+
+procedure TfrmChooseHue.pbHueSelectionPaintBuffer(Sender: TObject);
+var
+ hue, xhue, yhue: Word;
+begin
+ for xhue := 0 to 46 do
+ for yhue := 0 to 63 do begin
+ hue := 1 + xhue * 64 + yhue; // First hue: 0x01
+
+ if Hue <= $BB7 then
+ // Fill a 6x6 picture
+ pbHueSelection.Buffer.FillRect(xhue * 6, yhue * 5,
+ xhue * 6 + 5, yhue * 5 + 4, Main.Hues.getColor(Hue, tbHue.Position));
+ end;
+end;
+
+procedure TfrmChooseHue.tbHueChange(Sender: TObject);
+begin
+ pbHueSelection.Invalidate;
+end;
+
+procedure TfrmChooseHue.FormCreate(Sender: TObject);
+begin
+ ColorId := 1;
+ lblId.Caption := Format('Id: 0x%x', [ColorId]);
+ lblName.Caption := Format('Name: %s', [Main.Hues.getHue(ColorId).Name]);
+end;
+
+procedure TfrmChooseHue.pbHueSelectionMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+var
+ xhue, yhue, hue: word;
+begin
+ xhue := x div 6;
+ yhue := y div 5;
+
+ // The black border doesnt trigger anything
+ if x mod 6 = 5 then
+ exit;
+
+ if y mod 5 = 4 then
+ exit;
+
+ hue := 1 + xhue * 64 + yhue;
+
+ if Main.Hues.getHue(hue) = nil then
+ exit;
+
+ ColorId := Hue;
+ lblId.Caption := Format('Id: 0x%x', [ColorId]);
+ lblName.Caption := Format('Name: %s', [Main.Hues.getHue(ColorId).Name + #0]);
+ pbHuePreview.Invalidate;
+end;
+
+procedure TfrmChooseHue.pbHuePreviewPaintBuffer(Sender: TObject);
+var
+ i: Integer;
+ Width: Integer;
+ Hue: Word;
+begin
+ Hue := ColorId;
+
+ if Hue = 0 then begin
+ pbHuePreview.Buffer.Clear(clGray32);
+ exit;
+ end;
+
+ Width := Ceil(pbHuePreview.Width / 32.0);
+ for i := 0 to 31 do
+ begin
+ pbHuePreview.Buffer.FillRect(i * Width, 0, (i + 1) * Width,
+ pbHuePreview.Height, Hues.getColor(Hue, i));
+ end;
+end;
+
+procedure TfrmChooseHue.FormShow(Sender: TObject);
+begin
+ pbHuePreview.Invalidate;
+end;
+
+end.
Added: trunk/WPGM/uChooseHue.~ddp
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/uChooseHue.~ddp
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/uChooseHue.~dfm
===================================================================
--- trunk/WPGM/uChooseHue.~dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uChooseHue.~dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,79 @@
+object frmChooseHue: TfrmChooseHue
+ Left = 364
+ Top = 284
+ BorderStyle = bsDialog
+ Caption = 'Chose Hue'
+ ClientHeight = 394
+ ClientWidth = 404
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ OnCreate = FormCreate
+ OnShow = FormShow
+ PixelsPerInch = 96
+ TextHeight = 13
+ object lblId: TLabel
+ Left = 8
+ Top = 336
+ Width = 12
+ Height = 13
+ Caption = 'Id:'
+ end
+ object lblName: TLabel
+ Left = 80
+ Top = 336
+ Width = 31
+ Height = 13
+ Caption = 'Name:'
+ end
+ object pbHueSelection: TPaintBox32
+ Left = 8
+ Top = 8
+ Width = 384
+ Height = 320
+ TabOrder = 0
+ OnMouseDown = pbHueSelectionMouseDown
+ OnPaintBuffer = pbHueSelectionPaintBuffer
+ end
+ object btnOk: TButton
+ Left = 8
+ Top = 360
+ Width = 75
+ Height = 25
+ Caption = 'Ok'
+ ModalResult = 1
+ TabOrder = 1
+ end
+ object btnCancel: TButton
+ Left = 88
+ Top = 360
+ Width = 75
+ Height = 25
+ Caption = 'Cancel'
+ ModalResult = 2
+ TabOrder = 2
+ end
+ object tbHue: TTrackBar
+ Left = 169
+ Top = 360
+ Width = 224
+ Height = 25
+ Max = 31
+ Frequency = 2
+ Position = 31
+ TabOrder = 3
+ OnChange = tbHueChange
+ end
+ object pbHuePreview: TPaintBox32
+ Left = 264
+ Top = 333
+ Width = 128
+ Height = 18
+ TabOrder = 4
+ OnPaintBuffer = pbHuePreviewPaintBuffer
+ end
+end
Added: trunk/WPGM/uChooseHue.~pas
===================================================================
--- trunk/WPGM/uChooseHue.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uChooseHue.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,119 @@
+unit uChooseHue;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, GR32_Image, ComCtrls;
+
+type
+ TfrmChooseHue = class(TForm)
+ pbHueSelection: TPaintBox32;
+ btnOk: TButton;
+ btnCancel: TButton;
+ tbHue: TTrackBar;
+ lblId: TLabel;
+ lblName: TLabel;
+ pbHuePreview: TPaintBox32;
+ procedure pbHueSelectionPaintBuffer(Sender: TObject);
+ procedure tbHueChange(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure pbHueSelectionMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+ procedure pbHuePreviewPaintBuffer(Sender: TObject);
+ procedure FormShow(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ ColorId: Word;
+ end;
+
+var
+ frmChooseHue: TfrmChooseHue;
+
+implementation
+
+uses Main, GR32, Math;
+
+{$R *.dfm}
+
+procedure TfrmChooseHue.pbHueSelectionPaintBuffer(Sender: TObject);
+var
+ hue, xhue, yhue: Word;
+begin
+ for xhue := 0 to 46 do
+ for yhue := 0 to 63 do begin
+ hue := 1 + xhue * 64 + yhue; // First hue: 0x01
+
+ if Hue <= $BB7 then
+ // Fill a 6x6 picture
+ pbHueSelection.Buffer.FillRect(xhue * 6, yhue * 5,
+ xhue * 6 + 5, yhue * 5 + 4, Main.Hues.getColor(Hue, tbHue.Position));
+ end;
+end;
+
+procedure TfrmChooseHue.tbHueChange(Sender: TObject);
+begin
+ pbHueSelection.Invalidate;
+end;
+
+procedure TfrmChooseHue.FormCreate(Sender: TObject);
+begin
+ ColorId := 1;
+ lblId.Caption := Format('Id: 0x%x', [ColorId]);
+ lblName.Caption := Format('Name: %s', [Main.Hues.getHue(ColorId).Name]);
+end;
+
+procedure TfrmChooseHue.pbHueSelectionMouseDown(Sender: TObject;
+ Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+var
+ xhue, yhue, hue: word;
+begin
+ xhue := x div 6;
+ yhue := y div 5;
+
+ // The black border doesnt trigger anything
+ if x mod 6 = 5 then
+ exit;
+
+ if y mod 5 = 4 then
+ exit;
+
+ hue := 1 + xhue * 64 + yhue;
+
+ if Hue >
+
+ ColorId := Hue;
+ lblId.Caption := Format('Id: 0x%x', [ColorId]);
+ lblName.Caption := Format('Name: %s', [Main.Hues.getHue(ColorId).Name + #0]);
+ pbHuePreview.Invalidate;
+end;
+
+procedure TfrmChooseHue.pbHuePreviewPaintBuffer(Sender: TObject);
+var
+ i: Integer;
+ Width: Integer;
+ Hue: Word;
+begin
+ Hue := ColorId;
+
+ if Hue = 0 then begin
+ pbHuePreview.Buffer.Clear(clGray32);
+ exit;
+ end;
+
+ Width := Ceil(pbHuePreview.Width / 32.0);
+ for i := 0 to 31 do
+ begin
+ pbHuePreview.Buffer.FillRect(i * Width, 0, (i + 1) * Width,
+ pbHuePreview.Height, Hues.getColor(Hue, i));
+ end;
+end;
+
+procedure TfrmChooseHue.FormShow(Sender: TObject);
+begin
+ pbHuePreview.Invalidate;
+end;
+
+end.
Added: trunk/WPGM/uConfig.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/uConfig.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/uConfig.pas
===================================================================
--- trunk/WPGM/uConfig.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uConfig.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,104 @@
+unit uConfig;
+
+interface
+
+uses IniFiles, Registry;
+
+type TConfig = class
+ private
+ IniCache: TMemIniFile;
+
+ public
+ constructor Create;
+ destructor Destroy; override;
+ function Load( FileName: String ): Boolean;
+ function Save: Boolean;
+ procedure setString(Name: String; Value: String);
+ function getString(Name: String; Default: String): String;
+ procedure setBool(Name: String; Value: Boolean);
+ function getBool(Name: String; Default: Boolean): Boolean;
+ procedure setInt(Name: String; Value: Integer);
+ function getInt(Name: String; Default: Integer): Integer;
+end;
+
+implementation
+
+uses SysUtils, UOUtilities, Forms, Windows;
+
+constructor TConfig.Create;
+begin
+ inherited Create;
+
+ IniCache := nil;
+end;
+
+destructor TConfig.Destroy;
+begin
+ IniCache.Free;
+ inherited Destroy;
+end;
+
+function TConfig.Load( FileName: String ): Boolean;
+begin
+ Result := False;
+
+ try
+ IniCache := TMemIniFile.Create(FileName);
+ except
+ FreeAndNil( IniCache );
+ end;
+end;
+
+function TConfig.Save: Boolean;
+begin
+ Result := false;
+
+ if IniCache = nil then
+ exit;
+
+ try
+ IniCache.UpdateFile;
+ except
+ end;
+end;
+
+procedure TConfig.setString(Name: String; Value: String);
+begin
+ IniCache.WriteString('General', Name, Value);
+end;
+
+function TConfig.getString(Name: String; Default: String): String;
+begin
+ if not IniCache.ValueExists('General', Name) then
+ IniCache.WriteString('General', Name, Default);
+
+ Result := IniCache.ReadString('General', Name, Default);
+end;
+
+procedure TConfig.setBool(Name: String; Value: Boolean);
+begin
+ IniCache.WriteBool('General', Name, Value);
+end;
+
+function TConfig.getBool(Name: String; Default: Boolean): Boolean;
+begin
+ if not IniCache.ValueExists('General', Name) then
+ IniCache.WriteBool('Geneal', Name, Default);
+
+ Result := IniCache.ReadBool('General', Name, Default);
+end;
+
+procedure TConfig.setInt(Name: String; Value: Integer);
+begin
+ IniCache.WriteInteger('General', Name, Value);
+end;
+
+function TConfig.getInt(Name: String; Default: Integer): Integer;
+begin
+ if not IniCache.ValueExists('General', Name) then
+ IniCache.WriteInteger('General', Name, Default);
+
+ Result := IniCache.ReadInteger('General', Name, Default);
+end;
+
+end.
Added: trunk/WPGM/uConfig.~pas
===================================================================
--- trunk/WPGM/uConfig.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uConfig.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,105 @@
+unit uConfig;
+
+interface
+
+uses IniFiles, Registry;
+
+type TConfig = class
+ private
+ IniCache: TMemIniFile;
+
+ public
+ constructor Create;
+ destructor Destroy; override;
+ function Load( FileName: String ): Boolean;
+ function Save: Boolean;
+ procedure setString(Name: String; Value: String);
+ function getString(Name: String; Default: String): String;
+ procedure setBool(Name: String; Value: Boolean);
+ function getBool(Name: String; Default: Boolean): Boolean;
+ procedure setInt(Name: String; Value: Integer);
+ function getInt(Name: String; Default: Integer): Integer;
+end;
+
+implementation
+
+uses SysUtils, UOUtilities, Forms, Windows;
+
+constructor TConfig.Create;
+begin
+ inherited Create;
+
+ IniCache := nil;
+end;
+
+destructor TConfig.Destroy;
+begin
+ IniCache.Free;
+
+ inherited Destroy;
+end;
+
+function TConfig.Load( FileName: String ): Boolean;
+begin
+ Result := False;
+
+ try
+ IniCache := TMemIniFile.Create(FileName);
+ except
+ FreeAndNil( IniCache );
+ end;
+end;
+
+function TConfig.Save: Boolean;
+begin
+ Result := false;
+
+ if IniCache = nil then
+ exit;
+
+ try
+ IniCache.UpdateFile;
+ except
+ end;
+end;
+
+procedure TConfig.setString(Name: String; Value: String);
+begin
+ IniCache.WriteString('General', Name, Value);
+end;
+
+function TConfig.getString(Name: String; Default: String): String;
+begin
+ if not IniCache.ValueExists('General', Name) then
+ IniCache.WriteString('General', Name, Default);
+
+ Result := IniCache.ReadString('General', Name, Default);
+end;
+
+procedure TConfig.setBool(Name: String; Value: Boolean);
+begin
+ IniCache.WriteBool('General', Name, Value);
+end;
+
+function TConfig.getBool(Name: String; Default: Boolean): Boolean;
+begin
+ if not IniCache.ValueExists('General', Name) then
+ IniCache.WriteBool('Geneal', Name, Default);
+
+ Result := IniCache.ReadBool('General', Name, Default);
+end;
+
+procedure TConfig.setInt(Name: String; Value: Integer);
+begin
+ IniCache.WriteInteger('General', Name, Value);
+end;
+
+function TConfig.getInt(Name: String; Default: Integer): Integer;
+begin
+ if not IniCache.ValueExists('General', Name) then
+ IniCache.WriteInteger('General', Name, Default);
+
+ Result := IniCache.ReadInteger('General', Name, Default);
+end;
+
+end.
Added: trunk/WPGM/uPatternColor.dcu
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/uPatternColor.dcu
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/uPatternColor.dfm
===================================================================
--- trunk/WPGM/uPatternColor.dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uPatternColor.dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,87 @@
+object frmPatternColor: TfrmPatternColor
+ Left = 513
+ Top = 261
+ BorderIcons = [biSystemMenu, biMinimize]
+ BorderStyle = bsDialog
+ Caption = 'Pattern Tilecolor'
+ ClientHeight = 380
+ ClientWidth = 415
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Shape1: TShape
+ Left = 168
+ Top = 216
+ Width = 65
+ Height = 65
+ end
+ object Image1: TImage
+ Left = 184
+ Top = 240
+ Width = 105
+ Height = 105
+ end
+ object Image2: TImage
+ Left = 200
+ Top = 256
+ Width = 105
+ Height = 105
+ end
+ object RadioButton1: TRadioButton
+ Left = 8
+ Top = 8
+ Width = 41
+ Height = 17
+ Caption = '2x2'
+ Checked = True
+ TabOrder = 0
+ TabStop = True
+ end
+ object RadioButton2: TRadioButton
+ Left = 104
+ Top = 8
+ Width = 41
+ Height = 17
+ Caption = '3x3'
+ TabOrder = 1
+ end
+ object RadioButton3: TRadioButton
+ Left = 192
+ Top = 8
+ Width = 41
+ Height = 17
+ Caption = '4x4'
+ TabOrder = 2
+ end
+ object Button1: TButton
+ Left = 8
+ Top = 216
+ Width = 75
+ Height = 25
+ Caption = '&Tile'
+ TabOrder = 3
+ end
+ object ImgView321: TImgView32
+ Left = 8
+ Top = 32
+ Width = 225
+ Height = 169
+ Scale = 1.000000000000000000
+ ScrollBars.ShowHandleGrip = True
+ ScrollBars.Style = rbsDefault
+ SizeGrip = sgNone
+ OverSize = 0
+ TabOrder = 4
+ end
+ object Timer1: TTimer
+ OnTimer = Timer1Timer
+ Left = 120
+ Top = 184
+ end
+end
Added: trunk/WPGM/uPatternColor.pas
===================================================================
--- trunk/WPGM/uPatternColor.pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uPatternColor.pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,74 @@
+unit uPatternColor;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, ExtCtrls, GR32_Image, GR32, GR32_Layers;
+
+type
+ TfrmPatternColor = class(TForm)
+ RadioButton1: TRadioButton;
+ RadioButton2: TRadioButton;
+ RadioButton3: TRadioButton;
+ Button1: TButton;
+ Timer1: TTimer;
+ ImgView321: TImgView32;
+ Image1: TImage;
+ Image2: TImage;
+ Shape1: TShape;
+ procedure Timer1Timer(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ frmPatternColor: TfrmPatternColor;
+
+implementation
+
+{$R *.dfm}
+
+uses UOArt, Main;
+
+procedure TfrmPatternColor.Timer1Timer(Sender: TObject);
+var
+ Layer: TBitmapLayer;
+
+begin
+ Image1.Picture.Assign(Main.Art.GetTIle($50d, 0));
+ Image1.Transparent := True;
+ Image1.Picture.Bitmap.TransparentColor := clBtnFace;
+ Image1.Picture.Bitmap.Transparent := True;
+
+ ImgView321.Scale := 1.0;
+ ImgView321.Centered := True;
+ ImgView321.Bitmap.SetSize(66, 66);
+ ImgView321.Bitmap.Draw(0, 0, Main.Art.GetTile($50d, 0));
+ ImgView321.Bitmap.Draw(22, 22, Main.Art.GetTile($50d, 0));
+
+ Layer := ImgView321.Layers.Add(TBitmapLayer) as TBitmapLayer;
+ Layer.Bitmap := Main.Art.GetTile($50d, 0);
+ Layer.AlphaHit := True;
+
+ Layer := ImgView321.Layers.Add(TBitmapLayer) as TBitmapLayer;
+ Layer.Bitmap := Main.Art.GetTile($50d, 0);
+ Layer.AlphaHit := True;
+
+ Layer := ImgView321.Layers.Add(TBitmapLayer) as TBitmapLayer;
+ Layer.Bitmap := Main.Art.GetTile($50d, 0);
+ Layer.AlphaHit := True;
+
+ Layer := ImgView321.Layers.Add(TBitmapLayer) as TBitmapLayer;
+ Layer.Bitmap := Main.Art.GetTile($50d, 0);
+ Layer.AlphaHit := True;
+
+{ Image322.Bitmap := Main.Art.GetTile($50d, 0);
+ Image323.Bitmap := Main.Art.GetTile($50d, 0); }
+
+ Timer1.Enabled := False;
+end;
+
+end.
Added: trunk/WPGM/uPatternColor.~dfm
===================================================================
--- trunk/WPGM/uPatternColor.~dfm 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uPatternColor.~dfm 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,87 @@
+object frmPatternColor: TfrmPatternColor
+ Left = 513
+ Top = 261
+ BorderIcons = [biSystemMenu, biMinimize]
+ BorderStyle = bsDialog
+ Caption = 'Pattern Tilecolor'
+ ClientHeight = 380
+ ClientWidth = 415
+ Color = clBtnFace
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ OldCreateOrder = False
+ PixelsPerInch = 96
+ TextHeight = 13
+ object Shape1: TShape
+ Left = 168
+ Top = 216
+ Width = 65
+ Height = 65
+ end
+ object Image1: TImage
+ Left = 184
+ Top = 240
+ Width = 105
+ Height = 105
+ end
+ object Image2: TImage
+ Left = 200
+ Top = 256
+ Width = 105
+ Height = 105
+ end
+ object RadioButton1: TRadioButton
+ Left = 8
+ Top = 8
+ Width = 41
+ Height = 17
+ Caption = '2x2'
+ Checked = True
+ TabOrder = 0
+ TabStop = True
+ end
+ object RadioButton2: TRadioButton
+ Left = 104
+ Top = 8
+ Width = 41
+ Height = 17
+ Caption = '3x3'
+ TabOrder = 1
+ end
+ object RadioButton3: TRadioButton
+ Left = 192
+ Top = 8
+ Width = 41
+ Height = 17
+ Caption = '4x4'
+ TabOrder = 2
+ end
+ object Button1: TButton
+ Left = 8
+ Top = 216
+ Width = 75
+ Height = 25
+ Caption = '&Tile'
+ TabOrder = 3
+ end
+ object ImgView321: TImgView32
+ Left = 8
+ Top = 32
+ Width = 225
+ Height = 169
+ Scale = 1.000000000000000000
+ ScrollBars.ShowHandleGrip = True
+ ScrollBars.Style = rbsDefault
+ SizeGrip = sgNone
+ OverSize = 0
+ TabOrder = 4
+ end
+ object Timer1: TTimer
+ OnTimer = Timer1Timer
+ Left = 120
+ Top = 184
+ end
+end
Added: trunk/WPGM/uPatternColor.~pas
===================================================================
--- trunk/WPGM/uPatternColor.~pas 2007-06-14 17:50:59 UTC (rev 6816)
+++ trunk/WPGM/uPatternColor.~pas 2007-06-15 07:30:36 UTC (rev 6817)
@@ -0,0 +1,72 @@
+unit uPatternColor;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, ExtCtrls, GR32_Image, GR32, GR32_Layers;
+
+type
+ TfrmPatternColor = class(TForm)
+ RadioButton1: TRadioButton;
+ RadioButton2: TRadioButton;
+ RadioButton3: TRadioButton;
+ Button1: TButton;
+ Timer1: TTimer;
+ ImgView321: TImgView32;
+ Image1: TImage;
+ Image2: TImage;
+ Shape1: TShape;
+ procedure Timer1Timer(Sender: TObject);
+ private
+ { Private declarations }
+ public
+ { Public declarations }
+ end;
+
+var
+ frmPatternColor: TfrmPatternColor;
+
+implementation
+
+{$R *.dfm}
+
+uses UOArt, Main;
+
+procedure TfrmPatternColor.Timer1Timer(Sender: TObject);
+var
+ Layer: TBitmapLayer;
+
+begin
+ Image1.Picture.Assign(Main.Art.GetTIle($50d, 0));
+
+
+ ImgView321.Scale := 1.0;
+ ImgView321.Centered := True;
+ ImgView321.Bitmap.SetSize(66, 66);
+ ImgView321.Bitmap.Draw(0, 0, Main.Art.GetTile($50d, 0));
+ ImgView321.Bitmap.Draw(22, 22, Main.Art.GetTile($50d, 0));
+
+ Layer := ImgView321.Layers.Add(TBitmapLayer) as TBitmapLayer;
+ Layer.Bitmap := Main.Art.GetTile($50d, 0);
+ Layer.AlphaHit := True;
+
+ Layer := ImgView321.Layers.Add(TBitmapLayer) as TBitmapLayer;
+ Layer.Bitmap := Main.Art.GetTile($50d, 0);
+ Layer.AlphaHit := True;
+
+ Layer := ImgView321.Layers.Add(TBitmapLayer) as TBitmapLayer;
+ Layer.Bitmap := Main.Art.GetTile($50d, 0);
+ Layer.AlphaHit := True;
+
+ Layer := ImgView321.Layers.Add(TBitmapLayer) as TBitmapLayer;
+ Layer.Bitmap := Main.Art.GetTile($50d, 0);
+ Layer.AlphaHit := True;
+
+{ Image322.Bitmap := Main.Art.GetTile($50d, 0);
+ Image323.Bitmap := Main.Art.GetTile($50d, 0); }
+
+ Timer1.Enabled := False;
+end;
+
+end.
Added: trunk/WPGM/wolfpack.ico
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/wolfpack.ico
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/wpgm-2004-08-19.zip
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/wpgm-2004-08-19.zip
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/WPGM/wpgm-2004-08-21.zip
===================================================================
(Binary files differ)
Property changes on: trunk/WPGM/wpgm-2004-08-21.zip
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
More information about the Wolfpack-svn
mailing list